diff --git a/archive/0TheSpy/Seaside.txt b/archive/0TheSpy/Seaside.txt new file mode 100644 index 00000000..c1c51b87 --- /dev/null +++ b/archive/0TheSpy/Seaside.txt @@ -0,0 +1,166772 @@ +Project Path: arc_0TheSpy_Seaside_ty13_qoj + +Source Tree: + +```txt +arc_0TheSpy_Seaside_ty13_qoj +├── README.md +├── Seaside.sln +└── SpyCustom + ├── Aimbot.cpp + ├── Aimbot.hpp + ├── ConVars.cpp + ├── Config.hpp + ├── EventListener.hpp + ├── GetVfunc.hpp + ├── Hooks.hpp + ├── Interfaces.cpp + ├── Interfaces.hpp + ├── KeyValues.cpp + ├── Menu.hpp + ├── NetVarManager.cpp + ├── NetVarManager.hpp + ├── Options.hpp + ├── Other.cpp + ├── Other.hpp + ├── PatternScan.cpp + ├── PatternScan.hpp + ├── PlayerInventory.cpp + ├── PlayerInventory.hpp + ├── ProtoParse.h + ├── ProtobuffMessages.h + ├── Singleton.hpp + ├── SkinChanger.hpp + ├── Skinchanger.cpp + ├── SpyCustom.vcxproj + ├── SpyCustom.vcxproj.filters + ├── SpyCustom.vcxproj.user + ├── VMT.hpp + ├── XorStr.hpp + ├── checksum_md5.cpp + ├── detours.h + ├── detours.lib + ├── dllmain.cpp + ├── imgui + │ ├── imconfig.h + │ ├── imgui.cpp + │ ├── imgui.h + │ ├── imgui_draw.cpp + │ ├── imgui_impl_dx9.cpp + │ ├── imgui_impl_dx9.h + │ ├── imgui_impl_win32.cpp + │ ├── imgui_impl_win32.h + │ ├── imgui_internal.h + │ ├── imgui_tables.cpp + │ ├── imgui_widgets.cpp + │ ├── imstb_rectpack.h + │ ├── imstb_textedit.h + │ └── imstb_truetype.h + ├── inventory_changer.h + ├── netvars.cpp + ├── netvars.hpp + ├── pbwrap.hpp + ├── protobuffs.cpp + ├── protobuffs.hpp + ├── proxies.hpp + ├── resources.h + ├── sdk + │ ├── AnalogCode.h + │ ├── BuildGroup.h + │ ├── Button.h + │ ├── ButtonCode.h + │ ├── CGameUI.h + │ ├── CheckButton.h + │ ├── ClientNetMessage.h + │ ├── Color.h + │ ├── Controls.h + │ ├── Cursor.h + │ ├── Dar.h + │ ├── EditablePanel.h + │ ├── FileOpenDialog.h + │ ├── FocusNavGroup.h + │ ├── Frame.h + │ ├── GameEventListener.h + │ ├── GameEventManager.h + │ ├── HTML.h + │ ├── IAppSystem.h + │ ├── IBorder.h + │ ├── IClientLeafSystem.h + │ ├── IClientPanel.h + │ ├── ICollideable.h + │ ├── IColorCorrection.h + │ ├── IEffects.h + │ ├── IEngineSound.h + │ ├── IEngineVgui.h + │ ├── IGameSystem.h + │ ├── IGameUI.h + │ ├── IHTML.h + │ ├── IImage.h + │ ├── IInput.h + │ ├── IKeyValuesSystem.h + │ ├── ILocalize.h + │ ├── IMesh.h + │ ├── IPanel.h + │ ├── IScheme.h + │ ├── ISurface.h + │ ├── ISystem.h + │ ├── IVGUI.h + │ ├── IVguiMatInfo.h + │ ├── IVguiMatInfoVar.h + │ ├── Image.h + │ ├── InputEnums.h + │ ├── KeyBindingMap.h + │ ├── KeyCode.h + │ ├── Label.h + │ ├── ListPanel.h + │ ├── MaterialSystemUtil.h + │ ├── Menu.h + │ ├── MenuItem.h + │ ├── MessageMap.h + │ ├── MouseCode.h + │ ├── PHandle.h + │ ├── Panel.h + │ ├── PanelAnimationVar.h + │ ├── ParticleSphereRenderer.h + │ ├── RichText.h + │ ├── SndInfo.h + │ ├── SteamCommon.h + │ ├── TextEntry.h + │ ├── TextImage.h + │ ├── ToggleButton.h + │ ├── Tooltip.h + │ ├── UtlSortVector.h + │ ├── UtlStringMap.h + │ ├── VGUI.h + │ ├── animationlayer.h + │ ├── annotations.h + │ ├── baseclientstate.h + │ ├── baseentity.h + │ ├── baseentity_shared.h + │ ├── basehandle.h + │ ├── basetypes.h + │ ├── baseviewport.h + │ ├── beam_flags.h + │ ├── bitbuf.h + │ ├── bittools.h + │ ├── bitvec.h + │ ├── bone_accessor.h + │ ├── bone_merge_cache.h + │ ├── bspfile.h + │ ├── bspflags.h + │ ├── bumpvects.h + │ ├── byteswap.h + │ ├── c_baseanimating.h + │ ├── c_baseanimatingoverlay.h + │ ├── c_basecombatcharacter.h + │ ├── c_baseentity.h + │ ├── c_baseflex.h + │ ├── c_baseplayer.h + │ ├── c_basetempentity.h + │ ├── c_input.h + │ ├── c_pixel_visibility.h + │ ├── c_playerlocaldata.h + │ ├── c_recipientfilter.h + │ ├── c_te_legacytempents.h + │ ├── cdll_client_int.h + │ ├── cdll_int.h + │ ├── cdll_util.h + │ ├── checksum_crc.h + │ ├── checksum_md5.h + │ ├── client_class.h + │ ├── client_render_handle.h + │ ├── client_thinklist.h + │ ├── client_virtualreality.h + │ ├── cliententitylist.h + │ ├── clientleafsystem.h + │ ├── clientmode_shared.h + │ ├── cmodel.h + │ ├── collisionproperty.h + │ ├── commandmenu.h + │ ├── commonmacros.h + │ ├── compressed_light_cube.h + │ ├── compressed_vector.h + │ ├── const.h + │ ├── convar.h + │ ├── coordsize.h + │ ├── cs_achievementdefs.h + │ ├── cs_shareddefs.h + │ ├── cs_view_scene.h + │ ├── cs_weapon_parse.h + │ ├── datamap.h + │ ├── dbg.h + │ ├── dbgflag.h + │ ├── deformations.h + │ ├── dlight.h + │ ├── dmattributetypes.h + │ ├── dmelementhandle.h + │ ├── dmxattribute.h + │ ├── dmxelement.h + │ ├── dmxloader.h + │ ├── dt_common.h + │ ├── dt_recv.h + │ ├── dt_send.h + │ ├── econ_item_constants.h + │ ├── econ_item_interface.h + │ ├── econ_item_schema.h + │ ├── econ_item_view.h + │ ├── edict.h + │ ├── ehandle.h + │ ├── eiface.h + │ ├── enginetrace.h + │ ├── entitylist.h + │ ├── entitylist_base.h + │ ├── expressioncalculator.h + │ ├── exprevaluator.h + │ ├── fasttimer.h + │ ├── filesystem.h + │ ├── filesystem_passthru.h + │ ├── flashlighteffect.h + │ ├── fltx4.h + │ ├── functors.h + │ ├── fx.h + │ ├── game_item_schema.h + │ ├── gameconsole.h + │ ├── gamemovement.h + │ ├── gamerules.h + │ ├── gamerules_register.h + │ ├── gamestringpool.h + │ ├── gametrace.h + │ ├── generichash.h + │ ├── globalvars_base.h + │ ├── glow_outline_effect.h + │ ├── groundlink.h + │ ├── htmlmessages.h + │ ├── hud.h + │ ├── hud_basechat.h + │ ├── hud_element_helper.h + │ ├── hudelement.h + │ ├── hudtexturehandle.h + │ ├── ichromehtmlwrapper.h + │ ├── iclassmap.h + │ ├── iclient.h + │ ├── icliententity.h + │ ├── icliententityinternal.h + │ ├── icliententitylist.h + │ ├── iclientmode.h + │ ├── iclientnetworkable.h + │ ├── iclientrenderable.h + │ ├── iclientshadowmgr.h + │ ├── iclientthinkable.h + │ ├── iclientunknown.h + │ ├── iclientvirtualreality.h + │ ├── icommandline.h + │ ├── iconvar.h + │ ├── icvar.h + │ ├── idatacache.h + │ ├── iefx.h + │ ├── ienginetrace.h + │ ├── ifilelist.h + │ ├── igameconsole.h + │ ├── igameevents.h + │ ├── igamemovement.h + │ ├── igametypes.h + │ ├── iglobalvarsbase.h + │ ├── ihandleentity.h + │ ├── iinputsystem.h + │ ├── imageformat.h + │ ├── imaterial.h + │ ├── imaterialsystem.h + │ ├── imaterialsystemhardwareconfig.h + │ ├── imdlcache.h + │ ├── imovehelper.h + │ ├── inetchannel.h + │ ├── inetchannelinfo.h + │ ├── inetmessage.h + │ ├── inetmsghandler.h + │ ├── inetworksystem.h + │ ├── interface.h + │ ├── interpolatedvar.h + │ ├── iprediction.h + │ ├── ipredictionsystem.h + │ ├── irecipientfilter.h + │ ├── iscenetokenprocessor.h + │ ├── iserverentity.h + │ ├── iservernetworkable.h + │ ├── iserverplugin.h + │ ├── iserverunknown.h + │ ├── ishadowmgr.h + │ ├── ispatialpartition.h + │ ├── isteamapplist.h + │ ├── isteamapps.h + │ ├── isteamclient.h + │ ├── isteamcontroller.h + │ ├── isteamfriends.h + │ ├── isteamgamecoordinator.h + │ ├── isteamhtmlsurface.h + │ ├── isteamhttp.h + │ ├── isteaminventory.h + │ ├── isteammatchmaking.h + │ ├── isteammusic.h + │ ├── isteammusicremote.h + │ ├── isteamnetworking.h + │ ├── isteamremotestorage.h + │ ├── isteamscreenshots.h + │ ├── isteamugc.h + │ ├── isteamunifiedmessages.h + │ ├── isteamuser.h + │ ├── isteamuserstats.h + │ ├── isteamutils.h + │ ├── isteamvideo.h + │ ├── istudiorender.h + │ ├── item_selection_criteria.h + │ ├── itempents.h + │ ├── itexture.h + │ ├── itoolentity.h + │ ├── ivdebugoverlay.h + │ ├── iviewport.h + │ ├── iviewrender.h + │ ├── iviewrender_beams.h + │ ├── ivmodelinfo.h + │ ├── ivmodelrender.h + │ ├── ivrenderview.h + │ ├── jobthread.h + │ ├── keyvalues.h + │ ├── l2cache.h + │ ├── lerp_functions.h + │ ├── lightdesc.h + │ ├── localflexcontroller.h + │ ├── logging.h + │ ├── matchmakingtypes.h + │ ├── math_pfns.h + │ ├── mathlib.h + │ ├── mem.h + │ ├── memalloc.h + │ ├── memdbgoff.h + │ ├── memdbgon.h + │ ├── mempool.h + │ ├── meshreader.h + │ ├── meshutils.h + │ ├── messagebox.h + │ ├── minidump.h + │ ├── modelloader.h + │ ├── modes.h + │ ├── mouthinfo.h + │ ├── netmessages.h + │ ├── networkstringtabledefs.h + │ ├── networkvar.h + │ ├── panel2d.h + │ ├── particle_iterators.h + │ ├── particle_parse.h + │ ├── particle_property.h + │ ├── particle_property_inlines.h + │ ├── particle_util.h + │ ├── particledraw.h + │ ├── particlemgr.h + │ ├── particles.h + │ ├── particles_new.h + │ ├── particles_simple.h + │ ├── platform.h + │ ├── playernet_vars.h + │ ├── precipitation_shared.h + │ ├── predictable_entity.h + │ ├── predictableid.h + │ ├── predictioncopy.h + │ ├── protocol.h + │ ├── qlimits.h + │ ├── ragdoll.h + │ ├── ragdoll_shared.h + │ ├── random.h + │ ├── rangecheckedvar.h + │ ├── recvproxy.h + │ ├── refcount.h + │ ├── sceneentity_shared.h + │ ├── sdk_hud_chat.h + │ ├── seemath.h + │ ├── sendproxy.h + │ ├── sequence_Transitioner.h + │ ├── shake.h + │ ├── shared_classnames.h + │ ├── shareddefs.h + │ ├── shattersurfacetypes.h + │ ├── smartptr.h + │ ├── soundflags.h + │ ├── ssemath.h + │ ├── steam.h + │ ├── steam_api.h + │ ├── steam_api_internal.h + │ ├── steamclientpublic.h + │ ├── steamhttpenums.h + │ ├── steamtypes.h + │ ├── steamuniverse.h + │ ├── string_t.h + │ ├── stringpool.h + │ ├── strtools.h + │ ├── studio.h + │ ├── tempentity.h + │ ├── texture_group_names.h + │ ├── threadtools.h + │ ├── tier1.h + │ ├── tier2.h + │ ├── tier2_logging.h + │ ├── tier3.h + │ ├── timedevent.h + │ ├── timeutils.h + │ ├── tokenset.h + │ ├── touchlink.h + │ ├── trace.h + │ ├── tslist.h + │ ├── uniqueid.h + │ ├── usercmd.h + │ ├── userid.h + │ ├── utlblockmemory.h + │ ├── utlbuffer.h + │ ├── utldelegate.h + │ ├── utldict.h + │ ├── utlenvelope.h + │ ├── utlfixedmemory.h + │ ├── utlflags.h + │ ├── utlhandletable.h + │ ├── utlhash.h + │ ├── utlintrusivelist.h + │ ├── utllinkedlist.h + │ ├── utlmap.h + │ ├── utlmemory.h + │ ├── utlobjectreference.h + │ ├── utlpriorityqueue.h + │ ├── utlqueue.h + │ ├── utlrbtree.h + │ ├── utlsoacontainer.h + │ ├── utlstack.h + │ ├── utlstring.h + │ ├── utlsymbol.h + │ ├── utlsymbollarge.h + │ ├── utltshash.h + │ ├── utlvector.h + │ ├── valve_minmax_on.h + │ ├── valve_off.h + │ ├── valve_on.h + │ ├── vcollide.h + │ ├── vcrmode.h + │ ├── vector.h + │ ├── vector2d.h + │ ├── vector4d.h + │ ├── vertexcolor.h + │ ├── vgui_basepanel.h + │ ├── vguitextwindow.h + │ ├── view_shared.h + │ ├── viewport_panel_names.h + │ ├── viewrender.h + │ ├── vmatrix.h + │ ├── volumeculler.h + │ ├── vphysics_interface.h + │ ├── vpkparser.h + │ ├── vplane.h + │ ├── vprof.h + │ ├── vprof_sn.h + │ ├── vprof_telemetry.h + │ ├── vstdlib.h + │ ├── vtf.h + │ ├── wchartypes.h + │ ├── weapon_parse.h + │ ├── win32consoleio.h + │ ├── worldsize.h + │ ├── xboxstubs.h + │ └── zip_uncompressed.h + ├── textinputcombobox.cpp + └── vmt_smart_hook.hpp + +``` + +`README.md`: + +```md +# Seaside +CS:GO internal visual cheat https://www.unknowncheats.me/forum/cs-go-releases/448796-seaside-changer.html + +Video: +[![Showcase](https://i.ytimg.com/vi_webp/CuVaV-KSfqs/maxresdefault.webp)](https://www.youtube.com/watch?v=CuVaV-KSfqs) + + +``` + +`Seaside.sln`: + +```sln + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30320.27 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpyCustom", "SpyCustom\SpyCustom.vcxproj", "{BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Debug|x64.ActiveCfg = Debug|x64 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Debug|x64.Build.0 = Debug|x64 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Debug|x86.ActiveCfg = Debug|Win32 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Debug|x86.Build.0 = Debug|Win32 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Release|x64.ActiveCfg = Release|x64 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Release|x64.Build.0 = Release|x64 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Release|x86.ActiveCfg = Release|Win32 + {BDE23281-B75D-4FB2-9B8E-08E1AE0A9BBD}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C4B46335-3AD6-41D0-ADFF-4B3A78A3AD4A} + EndGlobalSection +EndGlobal + +``` + +`SpyCustom/Aimbot.cpp`: + +```cpp +#include "Aimbot.hpp" + +///autowall +/* +bool IsBreakableEntity(C_BaseEntity* pEntity) +{ + // @ida isbreakableentity: 55 8B EC 51 56 8B F1 85 F6 74 68 + + // skip invalid entities + if (pEntity == nullptr) + return false; + + const int iHealth = ((C_BasePlayer*)pEntity)->GetHealth(); + + // first check to see if it's already broken + if (iHealth < 0 && pEntity->IsMaxHealth() > 0) + return true; + + if (pEntity->GetTakeDamage() != DAMAGE_YES) + { + const char* szClassName = pEntity->GetClientClass()->GetName(); + if (!strcmp(szClassName, XorStr("func_brush"))) + return false; + } + + const int nCollisionGroup = pEntity->GetCollisionGroup(); + + if (nCollisionGroup != COLLISION_GROUP_PUSHAWAY && nCollisionGroup != COLLISION_GROUP_BREAKABLE_GLASS && nCollisionGroup != COLLISION_GROUP_NONE) + return false; + + if (iHealth > 200) + return false; + + IMultiplayerPhysics* pPhysicsInterface = dynamic_cast(pEntity); + if (pPhysicsInterface != nullptr) + { + if (pPhysicsInterface->GetMultiplayerPhysicsMode() != PHYSICS_MULTIPLAYER_SOLID) + return false; + } + else + { + const char* szClassName = pEntity->GetClientClass()->GetName(); + + if (!strcmp(szClassName, XorStr("func_breakable")) || !strcmp(szClassName, XorStr("func_breakable_surf"))) + { + if (!strcmp(szClassName, XorStr("func_breakable_surf"))) + { + CBreakableSurface* pSurface = static_cast(pEntity); + + // don't try to break it if it has already been broken + if (pSurface->IsBroken()) + return false; + } + } + else if (pEntity->PhysicsSolidMaskForEntity() & CONTENTS_PLAYERCLIP) + { + // hostages and players use CONTENTS_PLAYERCLIP, so we can use it to ignore them + return false; + } + } + + IBreakableWithPropData* pBreakableInterface = dynamic_cast(pEntity); + if (pBreakableInterface != nullptr) + { + // bullets don't damage it - ignore + if (pBreakableInterface->GetDmgModBullet() <= 0.0f) + return false; + } + + return true; +} + +void ScaleDamage(int iHitGroup, C_BaseEntity* pEntity, float flWeaponArmorRatio, float& flDamage) +{ + const bool bHeavyArmor = pEntity->HasHeavyArmor(); + const int iArmor = pEntity->GetArmor(); + + static ConVar* mp_damage_scale_ct_head = iff.g_pCVar->FindVar(XorStr("mp_damage_scale_ct_head")); + static ConVar* mp_damage_scale_t_head = iff.g_pCVar->FindVar(XorStr("mp_damage_scale_t_head")); + + static ConVar* mp_damage_scale_ct_body = iff.g_pCVar->FindVar(XorStr("mp_damage_scale_ct_body")); + static ConVar* mp_damage_scale_t_body = iff.g_pCVar->FindVar(XorStr("mp_damage_scale_t_body")); + + const float flHeadScale = ((C_BasePlayer*)pEntity)->GetTeam() == TEAM_CT ? mp_damage_scale_ct_head->GetFloat() : ((C_BasePlayer*)pEntity)->GetTeam() == TEAM_TERRORIST ? mp_damage_scale_t_head->GetFloat() : 1.0f; + const float flBodyScale = ((C_BasePlayer*)pEntity)->GetTeam() == TEAM_CT ? mp_damage_scale_ct_body->GetFloat() : ((C_BasePlayer*)pEntity)->GetTeam() == TEAM_TERRORIST ? mp_damage_scale_t_body->GetFloat() : 1.0f; + + switch (iHitGroup) + { + case HITGROUP_HEAD: + flDamage *= (bHeavyArmor ? 2.0f : 4.0f) * flHeadScale; + break; + case HITGROUP_STOMACH: + flDamage *= 1.25f * flBodyScale; + break; + case HITGROUP_CHEST: + case HITGROUP_LEFTARM: + case HITGROUP_RIGHTARM: + flDamage *= flBodyScale; + break; + case HITGROUP_LEFTLEG: + case HITGROUP_RIGHTLEG: + flDamage *= 0.75f * flBodyScale; + break; + default: + break; + } + + // check is armored + if (iArmor > 0 && ((iHitGroup == HITGROUP_HEAD && pEntity->HasHelmet()) || (iHitGroup >= HITGROUP_GENERIC && iHitGroup <= HITGROUP_RIGHTARM))) + { + float flArmorScale = 1.0f, flArmorBonusRatio = 0.5f, flArmorRatio = flWeaponArmorRatio * 0.5f; + + if (bHeavyArmor) + { + flArmorScale = 0.33f; + flArmorBonusRatio = 0.33f; + flArmorRatio *= 0.5f; + } + + float flNewDamage = flDamage * flArmorRatio; + + if (bHeavyArmor) + flNewDamage *= 0.85f; + + if (((flDamage - flDamage * flArmorRatio) * (flArmorScale * flArmorBonusRatio)) > iArmor) + flNewDamage = flDamage - iArmor / flArmorBonusRatio; + + flDamage = flNewDamage; + } +} + +bool TraceToExit(CGameTrace& enterTrace, CGameTrace& exitTrace, Vector vecPosition, Vector vecDirection) +{ + float flDistance = 0.0f; + int iStartContents = 0; + + while (flDistance <= 90.0f) + { + // add extra distance to our ray + flDistance += 4.0f; + + // multiply the direction vector to the distance so we go outwards, add our position to it + Vector vecStart = vecPosition + vecDirection * flDistance; + + if (!iStartContents) + iStartContents = iff.g_pEnginetrace->GetPointContents(vecStart, MASK_SHOT_HULL | CONTENTS_HITBOX, nullptr); + + const int iCurrentContents = iff.g_pEnginetrace->GetPointContents(vecStart, MASK_SHOT_HULL | CONTENTS_HITBOX, nullptr); + + if (!(iCurrentContents & MASK_SHOT_HULL) || (iCurrentContents & CONTENTS_HITBOX && iCurrentContents != iStartContents)) + { + // setup our end position by deducting the direction by the extra added distance + const Vector vecEnd = vecStart - (vecDirection * 4.0f); + + // trace ray to world + Ray_t rayWorld; rayWorld.Init(vecStart, vecEnd); + iff.g_pEnginetrace->TraceRay(rayWorld, MASK_SHOT_HULL | CONTENTS_HITBOX, nullptr, &exitTrace); + + // check if a hitbox is in-front of our enemy and if they are behind of a solid wall + if (exitTrace.startsolid && exitTrace.surface.flags & SURF_HITBOX) + { + // trace ray to entity + Ray_t ray; ray.Init(vecStart, vecPosition); + CTraceFilter filter(exitTrace.m_pEnt); + + iff.g_pEnginetrace->TraceRay(ray, MASK_SHOT_HULL, &filter, &exitTrace); + + if (exitTrace.DidHit() && !exitTrace.startsolid) + { + vecStart = exitTrace.vecEnd; + return true; + } + + continue; + } + + if (exitTrace.DidHit() && !exitTrace.startsolid) + { + if (IsBreakableEntity(enterTrace.m_pEnt) && IsBreakableEntity(exitTrace.m_pEnt)) + return true; + + if (enterTrace.surface.flags & SURF_NODRAW || (!(exitTrace.surface.flags & SURF_NODRAW) && exitTrace.plane.normal.DotProduct(vecDirection) <= 1.0f)) + { + const float flMultiplier = exitTrace.fraction * 4.0f; + vecStart -= vecDirection * flMultiplier; + return true; + } + + continue; + } + + if (!exitTrace.DidHit() || exitTrace.startsolid) + { + if (enterTrace.m_pEnt != nullptr && enterTrace.m_pEnt->GetIndex() != 0 && IsBreakableEntity(enterTrace.m_pEnt)) + { + // did hit breakable non world entity + exitTrace = enterTrace; + exitTrace.vecEnd = vecStart + vecDirection; + return true; + } + + continue; + } + } + } + + return false; +} + +bool HandleBulletPenetration(CBaseEntity* pLocal, CCSWeaponInfo* pWeaponData, surfacedata_t* pEnterSurfaceData, FireBulletData_t& data) +{ + static ConVar* ff_damage_reduction_bullets = iff.g_pCVar->FindVar(XorStr("ff_damage_reduction_bullets")); + static ConVar* ff_damage_bullet_penetration = iff.g_pCVar->FindVar(XorStr("ff_damage_bullet_penetration")); + + const float flReductionDamage = ff_damage_reduction_bullets->GetFloat(); + const float flPenetrateDamage = ff_damage_bullet_penetration->GetFloat(); + + const MaterialHandle_t hEnterMaterial = pEnterSurfaceData->game.hMaterial; + const float flEnterPenetrationModifier = pEnterSurfaceData->game.flPenetrationModifier; + const bool bIsSolidSurf = ((data.enterTrace.contents >> 3) & CONTENTS_SOLID); + const bool bIsLightSurf = ((data.enterTrace.surface.flags >> 7) & SURF_LIGHT); + + CGameTrace exitTrace = { }; + + if (data.iPenetrateCount <= 0 || + (!data.iPenetrateCount && !bIsLightSurf && !bIsSolidSurf && hEnterMaterial != CHAR_TEX_GRATE && hEnterMaterial != CHAR_TEX_GLASS) || + (pWeaponData->m_flPenetration <= 0.0f) || + (!TraceToExit(data.enterTrace, exitTrace, data.enterTrace.vecEnd, data.vecDirection) && !(I::EngineTrace->GetPointContents(data.enterTrace.vecEnd, MASK_SHOT_HULL, nullptr) & MASK_SHOT_HULL))) + return false; + + const surfacedata_t* pExitSurfaceData = I::PhysicsProps->GetSurfaceData(exitTrace.surface.surfaceProps); + const MaterialHandle_t hExitMaterial = pExitSurfaceData->game.hMaterial; + const float flExitPenetrationModifier = pExitSurfaceData->game.flPenetrationModifier; + + float flDamageLostModifier = 0.16f; + float flPenetrationModifier = 0.0f; + + if (hEnterMaterial == CHAR_TEX_GRATE || hEnterMaterial == CHAR_TEX_GLASS) + { + flDamageLostModifier = 0.05f; + flPenetrationModifier = 3.0f; + } + else if (bIsSolidSurf || bIsLightSurf) + { + flDamageLostModifier = 0.16f; + flPenetrationModifier = 1.0f; + } + else if (hEnterMaterial == CHAR_TEX_FLESH && (((C_BasePlayer*)pLocal)->GetTeam() == ((C_BasePlayer*)data.enterTrace.m_pEnt)->GetTeam() && flReductionDamage == 0.0f)) + { + if (flPenetrateDamage == 0.0f) + return false; + + // shoot through teammates + flDamageLostModifier = 0.16f; + flPenetrationModifier = flPenetrateDamage; + } + else + { + flDamageLostModifier = 0.16f; + flPenetrationModifier = (flEnterPenetrationModifier + flExitPenetrationModifier) * 0.5f; + } + + if (hEnterMaterial == hExitMaterial) + { + if (hExitMaterial == CHAR_TEX_CARDBOARD || hExitMaterial == CHAR_TEX_WOOD) + flPenetrationModifier = 3.0f; + else if (hExitMaterial == CHAR_TEX_PLASTIC) + flPenetrationModifier = 2.0f; + } + + const float flTraceDistance = (exitTrace.vecEnd - data.enterTrace.vecEnd).LengthSqr(); + + // penetration modifier + const float flModifier = std::max(0.0f, 1.0f / flPenetrationModifier); + + // this calculates how much damage we've lost depending on thickness of the wall, our penetration, damage, and the modifiers set earlier + const float flLostDamage = (data.flCurrentDamage * flDamageLostModifier + std::max(0.0f, 3.75f / pWeaponData->flPenetration) * (flModifier * 3.0f)) + ((flModifier * flTraceDistance) / 24.0f); + + // did we loose too much damage? + if (flLostDamage > data.flCurrentDamage) + return false; + + // we can't use any of the damage that we've lost + if (flLostDamage > 0.0f) + data.flCurrentDamage -= flLostDamage; + + // do we still have enough damage to deal? + if (data.flCurrentDamage < 1.0f) + return false; + + data.vecPosition = exitTrace.vecEnd; + --data.iPenetrateCount; + return true; +} + + +void ClipTraceToPlayers(const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int fMask, ITraceFilter* pFilter, CGameTrace* pTrace) +{ + CGameTrace trace = { }; + float flSmallestFraction = pTrace->fraction; + + Ray_t ray; ray.Init(vecAbsStart, vecAbsEnd); + + for (int i = 1; i < I::Globals->nMaxClients; i++) + { + CBaseEntity* pEntity = I::ClientEntityList->Get(i); + + if (pEntity == nullptr || !pEntity->IsAlive() || pEntity->IsDormant()) + continue; + + if (pFilter != nullptr && !pFilter->ShouldHitEntity(pEntity, fMask)) + continue; + + ICollideable* pCollideable = pEntity->GetCollideable(); + + if (pCollideable == nullptr) + continue; + + // get bounding box + const Vector vecMin = pCollideable->OBBMins_(); + const Vector vecMax = pCollideable->OBBMaxs_(); + + // calculate world space center + const Vector vecCenter = (vecMax + vecMin) * 0.5f; + const Vector vecPosition = vecCenter + pEntity->GetAbsOrigin(); + + Vector vecTo = vecPosition - vecAbsStart; + Vector vecDirection = vecAbsEnd - vecAbsStart; + const float flLength = vecDirection.NormalizeInPlace(); + + const float flRangeAlong = vecDirection.DotProduct(vecTo); + float flRange = 0.0f; + + // calculate distance to ray + if (flRangeAlong < 0.0f) + // off start point + flRange = -vecTo.Length(); + else if (flRangeAlong > flLength) + // off end point + flRange = -(vecPosition - vecAbsEnd).Length(); + else + // within ray bounds + flRange = (vecPosition - (vecDirection * flRangeAlong + vecAbsStart)).Length(); + + if (flRange < 0.0f || flRange > 60.0f) + continue; + + I::EngineTrace->ClipRayToEntity(ray, fMask | CONTENTS_HITBOX, pEntity, &trace); + + if (trace.fraction < flSmallestFraction) + { + // we shortened the ray - save off the trace + *pTrace = trace; + flSmallestFraction = trace.fraction; + } + } +} + + +bool SimulateFireBullet(C_BaseEntity* pLocal, C_BaseAttributableItem* pWeapon, FireBulletData_t& data) +{ + CCSWeaponInfo* pWeaponData = iff.g_pWeaponSystem->GetWpnData((ItemDefinitionIndex)pWeapon->GetItemDefinitionIndex()); + + if (pWeaponData == nullptr) + return false; + + float flMaxRange = pWeaponData->m_flRange; + + // the total number of surfaces any bullet can penetrate in a single flight is capped at 4 + data.iPenetrateCount = 4; + // set our current damage to what our gun's initial damage reports it will do + data.flCurrentDamage = static_cast(pWeaponData->m_iDamage); + + float flTraceLenght = 0.0f; + CTraceFilter filter(pLocal); + + while (data.iPenetrateCount > 0 && data.flCurrentDamage >= 1.0f) + { + // max bullet range + flMaxRange -= flTraceLenght; + + // end position of bullet + const Vector vecEnd = data.vecPosition + data.vecDirection * flMaxRange; + + Ray_t ray; ray.Init(data.vecPosition, vecEnd); + iff.g_pEnginetrace->TraceRay(ray, MASK_SHOT_HULL | CONTENTS_HITBOX, &filter, &data.enterTrace); + + // check for player hitboxes extending outside their collision bounds + ClipTraceToPlayers(data.vecPosition, vecEnd + data.vecDirection * 40.0f, MASK_SHOT_HULL | CONTENTS_HITBOX, &filter, &data.enterTrace); + + surfacedata_t* pEnterSurfaceData = I::PhysicsProps->GetSurfaceData(data.enterTrace.surface.surfaceProps); + const float flEnterPenetrationModifier = pEnterSurfaceData->game.flPenetrationModifier; + + // we didn't hit anything, stop tracing shoot + if (data.enterTrace.fraction == 1.0f) + break; + + // calculate the damage based on the distance the bullet traveled + flTraceLenght += data.enterTrace.fraction * flMaxRange; + data.flCurrentDamage *= std::powf(pWeaponData->m_flRangeModifier, flTraceLenght / MAX_DAMAGE); + + // check is actually can shoot through + if (flTraceLenght > 3000.0f || flEnterPenetrationModifier < 0.1f) + break; + + // check is can do damage + if (data.enterTrace.hitgroup != HITGROUP_GENERIC && data.enterTrace.hitgroup != HITGROUP_GEAR && pLocal->IsEnemy(data.enterTrace.m_pEnt)) + { + // we got target - scale damage + ScaleDamage(data.enterTrace.hitgroup, data.enterTrace.m_pEnt, pWeaponData->m_flArmorRatio, data.flCurrentDamage); + return true; + } + + // calling handlebulletpenetration here reduces our penetration pounter, and if it returns true, we can't shoot through it + if (!HandleBulletPenetration(pLocal, pWeaponData, pEnterSurfaceData, data)) + break; + } + + return false; +} + +float GetDamage(C_BaseEntity* pLocal, const Vector& vecPoint, FireBulletData_t& dataOut) +{ + const Vector vecPosition = pLocal->GetViewPos(); + + // setup data + FireBulletData_t data = { }; + data.vecPosition = vecPosition; + data.vecDirection = (vecPoint - vecPosition).Normalized(); + + auto wep = ((C_BaseCombatCharacter*)pLocal)->GetActiveWeapon(); + C_BaseAttributableItem* pWeapon = (C_BaseAttributableItem*)iff.g_pEntityList->GetClientEntityFromHandle(wep); + + if (pWeapon == nullptr) + return -1.0f; + + if (!SimulateFireBullet(pLocal, pWeapon, data)) + return -1.0f; + + dataOut = data; + return data.flCurrentDamage; +} + +bool ScanDamage(CBaseEntity* pLocal, Vector vecStart, Vector vecEnd) +{ + CGameTrace trace = { }; + if (1) //C::Get(Vars.bAimAutoWall) + { + FireBulletData_t data = { }; + + // get autowall damage and data from it + float flDamage = GetDamage(pLocal, vecEnd, data); + + // check for minimal damage + if (flDamage < 1);// C::Get(Vars.iAimMinimalDamage)) + return false; + + // copy trace from autowall + trace = data.enterTrace; + } + + //Traced target + CBaseEntity* pEntity = trace.m_pEnt; + + //Check the traced target is vailed + if (pEntity == nullptr || !pEntity->IsAlive() || pEntity->IsDormant() || !pEntity->IsPlayer() || pEntity->HasImmunity() || !pLocal->IsEnemy(pEntity)) + { + return false; + } + + //We can shot the target + return true; +} +*/ + + + +C_BasePlayer* GetBestTarget(CUserCmd* cmd) +{ + static C_CS_PlayerResource** g_player_resource = C_CS_PlayerResource::GetPlayerResource(); + + float ofov = g_Options.aimbotfov; + float nfov = 0; + C_BasePlayer* player = nullptr; + + for (int iPlayer = 0; iPlayer < iff.g_pGlobals->maxClients; iPlayer++) + { + auto pCSPlayer = reinterpret_cast(iff.g_pEntityList->GetClientEntity(iPlayer)); + if (!pCSPlayer) + continue; + if (pCSPlayer == iff.pLocal || pCSPlayer->GetTeam() == iff.pLocal->GetTeam()) + continue; + if (pCSPlayer->IsDormant()) + continue; + if (!((*g_player_resource)->IsAlive()[iPlayer] && pCSPlayer->GetHealth() > 0)) + continue; + if (pCSPlayer->HasImmunity()) + continue; + Vector eyepos = iff.pLocal->GetViewPos(); + Vector enemyheadpos = pCSPlayer->GetBonePosition(8); + + // If the enemy is not visible, do the scan damage + if (!iff.pLocal->IsVisible(pCSPlayer, enemyheadpos)) + { + //if (!ScanDamage(iff.pLocal, eyepos, enemyheadpos)) + continue; + } + + Vector angleTo = CalcAngle(eyepos, enemyheadpos); + angleTo.Clamp(); + if (g_Options.rcs) { + Vector myangles; + iff.g_pEngineClient->GetViewAngles(myangles); + nfov = myangles.DistTo(angleTo); + } + else + nfov = cmd->viewangles.DistTo(angleTo); + if (nfov < ofov) + { + ofov = nfov; + player = pCSPlayer; + } + } + + //printfdbg("Best target %x\n", player); + return player; +} + +void AimBot(CUserCmd* cmd) +{ + static C_CS_PlayerResource** g_player_resource = C_CS_PlayerResource::GetPlayerResource(); + + if (!iff.g_pEngineClient->IsConnected() || !iff.g_pEngineClient->IsInGame()) + return; + if (!iff.pLocal) + return; + if (!(*g_player_resource)->IsAlive()[iff.pLocal->GetIndex()]) + return; + C_BasePlayer* target = GetBestTarget(cmd); + if (target) + { + //player_info_t pinfo; + //iff.g_pEngineClient->GetPlayerInfo(target->GetIndex(), &pinfo); + //printfdbg("Best target %x %s\n", target, pinfo.name); + Vector eyepos = iff.pLocal->GetViewPos(); + Vector targethead = target->GetBonePosition(8); + Vector viewangles = CalcAngle(eyepos, targethead); + viewangles.Clamp(); + Vector delta = cmd->viewangles - viewangles; + delta.Clamp(); + Vector finalAng = cmd->viewangles - delta;// / (variables::aimbot_smoothing * 20); + finalAng.Clamp(); finalAng.Normalize(); + // if (variables::aimbot_isvisiblecheck && csgo::local_player->can_see_player_pos(target, target->get_eye_pos())) + // { + // cmd->viewangles = finalAng; + // interfaces::engine->set_view_angles(cmd->viewangles); + // } + // else if (!variables::aimbot_isvisiblecheck) + // { + + //rcs + if (g_Options.rcs) { + Vector aimPunchAngles = iff.pLocal->GetAimPunchAngle(); + Vector newAngles = (finalAng - aimPunchAngles * 2); + newAngles.Clamp(); newAngles.Normalize(); + cmd->viewangles = newAngles; + } + else + cmd->viewangles = finalAng; + + if (!g_Options.silentaim) + iff.g_pEngineClient->SetViewAngles((QAngle&)finalAng); + if (g_Options.aimbotautoshoot) + cmd->buttons |= IN_ATTACK; + //} + } +} + + +``` + +`SpyCustom/Aimbot.hpp`: + +```hpp +#pragma once + + +#include "sdk/c_baseentity.h" +#include "Interfaces.hpp" +#include "Options.hpp" + + +// autowall objects structure +struct FireBulletData_t +{ + Vector vecPosition = { }; + Vector vecDirection = { }; + CGameTrace enterTrace = { }; + float flCurrentDamage = 0.0f; + int iPenetrateCount = 0; +}; + +bool IsBreakableEntity(CBaseEntity* pEntity); +void ScaleDamage(int iHitGroup, CBaseEntity* pEntity, float flWeaponArmorRatio, float& flDamage); +bool TraceToExit(CGameTrace& enterTrace, CGameTrace& exitTrace, Vector vecPosition, Vector vecDirection); +bool HandleBulletPenetration(CBaseEntity* pLocal, CCSWeaponInfo* pWeaponData, surfacedata_t* pEnterSurfaceData, FireBulletData_t& data); +void ClipTraceToPlayers(const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int fMask, ITraceFilter* pFilter, CGameTrace* pTrace); +bool SimulateFireBullet(C_BaseEntity* pLocal, C_BaseAttributableItem* pWeapon, FireBulletData_t& data); +float GetDamage(C_BaseEntity* pLocal, const Vector& vecPoint, FireBulletData_t& dataOut); +bool ScanDamage(CBaseEntity* pLocal, Vector vecStart, Vector vecEnd); + +C_BasePlayer* GetBestTarget(CUserCmd* cmd); +void AimBot(CUserCmd* cmd); + + +``` + +`SpyCustom/ConVars.cpp`: + +```cpp +#include "sdk/convar.h" +#include + +#include "Interfaces.hpp" + + +static void V_strncpy(char* pDest, char const* pSrc, int maxLen) +{ + strncpy(pDest, pSrc, maxLen); + if (maxLen > 0) + { + pDest[maxLen - 1] = 0; + } +} + +static int V_snprintf(char* pDest, int maxLen, const char* pFormat, ...) +{ + va_list marker; + + va_start(marker, pFormat); +#ifdef _WIN32 + int len = _vsnprintf(pDest, maxLen, pFormat, marker); +#elif POSIX + int len = vsnprintf(pDest, maxLen, pFormat, marker); +#else +#error "define vsnprintf type." +#endif + va_end(marker); + + if (len < 0) + { + len = maxLen; + pDest[maxLen - 1] = 0; + } + + return len; +} + +CUtlBinaryBlock::CUtlBinaryBlock(int growSize, int initSize) +{ + MEM_ALLOC_CREDIT(); + m_Memory.Init(growSize, initSize); + + m_nActualLength = 0; +} + +CUtlBinaryBlock::CUtlBinaryBlock(void* pMemory, int nSizeInBytes, int nInitialLength) : m_Memory((unsigned char*)pMemory, nSizeInBytes) +{ + m_nActualLength = nInitialLength; +} + +CUtlBinaryBlock::CUtlBinaryBlock(const void* pMemory, int nSizeInBytes) : m_Memory((const unsigned char*)pMemory, nSizeInBytes) +{ + m_nActualLength = nSizeInBytes; +} + +CUtlBinaryBlock::CUtlBinaryBlock(const CUtlBinaryBlock& src) +{ + Set(src.Get(), src.Length()); +} + +void CUtlBinaryBlock::SetLength(int nLength) +{ + MEM_ALLOC_CREDIT(); + Assert(!m_Memory.IsReadOnly()); + + m_nActualLength = nLength; + if (nLength > m_Memory.NumAllocated()) + { + int nOverFlow = nLength - m_Memory.NumAllocated(); + m_Memory.Grow(nOverFlow); + + if (nLength > m_Memory.NumAllocated()) + { + m_nActualLength = m_Memory.NumAllocated(); + } + } + +#ifdef _DEBUG + if (m_Memory.NumAllocated() > m_nActualLength) + { + memset(((char*)m_Memory.Base()) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength); + } +#endif +} + +void CUtlBinaryBlock::Set(const void* pValue, int nLen) +{ + Assert(!m_Memory.IsReadOnly()); + + if (!pValue) + { + nLen = 0; + } + + SetLength(nLen); + + if (m_nActualLength) + { + if (((const char*)m_Memory.Base()) >= ((const char*)pValue) + nLen || + ((const char*)m_Memory.Base()) + m_nActualLength <= ((const char*)pValue)) + { + memcpy(m_Memory.Base(), pValue, m_nActualLength); + } + else + { + memmove(m_Memory.Base(), pValue, m_nActualLength); + } + } +} + +CUtlString::CUtlString() +{ +} + +CUtlString::CUtlString(const char* pString) +{ + Set(pString); +} + +CUtlString::CUtlString(const CUtlString& string) +{ + Set(string.Get()); +} + +CUtlString::CUtlString(void* pMemory, int nSizeInBytes, int nInitialLength) : m_Storage(pMemory, nSizeInBytes, nInitialLength) +{ +} + +CUtlString::CUtlString(const void* pMemory, int nSizeInBytes) : m_Storage(pMemory, nSizeInBytes) +{ +} + +void CUtlString::Set(const char* pValue) +{ + Assert(!m_Storage.IsReadOnly()); + int nLen = pValue ? Q_strlen(pValue) + 1 : 0; + m_Storage.Set(pValue, nLen); +} + +const char* CUtlString::Get() const +{ + if (m_Storage.Length() == 0) + { + return ""; + } + + return reinterpret_cast(m_Storage.Get()); +} + +ConCommandBase* ConCommandBase::s_pConCommandBases = NULL; +IConCommandBaseAccessor* ConCommandBase::s_pAccessor = NULL; +static int s_nCVarFlag = 0; +static int s_nDLLIdentifier = -1; +static bool s_bRegistered = false; + +class CDefaultAccessor : public IConCommandBaseAccessor +{ +public: + virtual bool RegisterConCommandBase(ConCommandBase* pVar) + { + iff.g_pCVar->RegisterConCommand(pVar); + return true; + } +}; + +static CDefaultAccessor s_DefaultAccessor; + +void ConVar_Register(int nCVarFlag, IConCommandBaseAccessor* pAccessor) +{ + if (!iff.g_pCVar || s_bRegistered) + return; + + Assert(s_nDLLIdentifier < 0); + s_bRegistered = true; + s_nCVarFlag = nCVarFlag; + s_nDLLIdentifier = iff.g_pCVar->AllocateDLLIdentifier(); + + ConCommandBase* pCur, * pNext; + + ConCommandBase::s_pAccessor = pAccessor ? pAccessor : &s_DefaultAccessor; + pCur = ConCommandBase::s_pConCommandBases; + while (pCur) + { + pNext = pCur->m_pNext; + pCur->AddFlags(s_nCVarFlag); + pCur->Init(); + pCur = pNext; + } + + ConCommandBase::s_pConCommandBases = NULL; +} + +void ConVar_Unregister() +{ + if (!iff.g_pCVar || !s_bRegistered) + return; + + Assert(s_nDLLIdentifier >= 0); + iff.g_pCVar->UnregisterConCommands(s_nDLLIdentifier); + s_nDLLIdentifier = -1; + s_bRegistered = false; +} + + +ConCommandBase::ConCommandBase(void) +{ + m_bRegistered = false; + m_pszName = NULL; + m_pszHelpString = NULL; + + m_nFlags = 0; + m_pNext = NULL; +} + +ConCommandBase::ConCommandBase(const char* pName, const char* pHelpString , int flags ) +{ + Create(pName, pHelpString, flags); +} + +ConCommandBase::~ConCommandBase(void) +{ +} + +bool ConCommandBase::IsCommand(void) const +{ + return true; +} + + +CVarDLLIdentifier_t ConCommandBase::GetDLLIdentifier() const +{ + return s_nDLLIdentifier; +} + + +void ConCommandBase::Create(const char* pName, const char* pHelpString , int flags ) +{ + static char* empty_string = (char*)""; + + m_bRegistered = false; + + Assert(pName); + m_pszName = pName; + m_pszHelpString = pHelpString ? pHelpString : empty_string; + + m_nFlags = flags; + +#ifdef ALLOW_DEVELOPMENT_CVARS + m_nFlags &= ~FCVAR_DEVELOPMENTONLY; +#endif + + if (!(m_nFlags & FCVAR_UNREGISTERED)) + { + m_pNext = s_pConCommandBases; + s_pConCommandBases = this; + } + else + { + m_pNext = NULL; + } + + if (s_pAccessor) + { + Init(); + } +} + + +void ConCommandBase::Init() +{ + if (s_pAccessor) + { + s_pAccessor->RegisterConCommandBase(this); + } +} + +void ConCommandBase::Shutdown() +{ + if (iff.g_pCVar) + { + iff.g_pCVar->UnregisterConCommand(this); + } +} + + +const char* ConCommandBase::GetName(void) const +{ + return m_pszName; +} + + +bool ConCommandBase::IsFlagSet(int flag) const +{ + return (flag & m_nFlags) ? true : false; +} + +void ConCommandBase::AddFlags(int flags) +{ + m_nFlags |= flags; + +#ifdef ALLOW_DEVELOPMENT_CVARS + m_nFlags &= ~FCVAR_DEVELOPMENTONLY; +#endif +} + +void ConCommandBase::RemoveFlags(int flags) +{ + m_nFlags &= ~flags; +} + + +int ConCommandBase::GetFlags(void) const +{ + return m_nFlags; +} + + +const ConCommandBase* ConCommandBase::GetNext(void) const +{ + return m_pNext; +} + +ConCommandBase* ConCommandBase::GetNext(void) +{ + return m_pNext; +} + + +char* ConCommandBase::CopyString(const char* from) +{ + int len; + char* to; + + len = V_strlen(from); + if (len <= 0) + { + to = new char[1]; + to[0] = 0; + } + else + { + to = new char[len + 1]; + Q_strncpy(to, from, len + 1); + } + return to; +} + +const char* ConCommandBase::GetHelpText(void) const +{ + return m_pszHelpString; +} + +bool ConCommandBase::IsRegistered(void) const +{ + return m_bRegistered; +} + + +struct characterset_t +{ + char set[256]; +}; + +static characterset_t s_BreakSet; +static bool s_bBuiltBreakSet = false; + + + +void CCommand::Reset() +{ + m_nArgc = 0; + m_nArgv0Size = 0; + m_pArgSBuffer[0] = 0; +} + +characterset_t* CCommand::DefaultBreakSet() +{ + return &s_BreakSet; +} + +int DefaultCompletionFunc(const char* partial, char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]) +{ + return 0; +} + + +ConCommand::ConCommand(const char* pName, FnCommandCallbackVoid_t callback, const char* pHelpString , int flags , FnCommandCompletionCallback completionFunc ) +{ + m_fnCommandCallbackV1 = callback; + m_bUsingNewCommandCallback = false; + m_bUsingCommandCallbackInterface = false; + m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc; + m_bHasCompletionCallback = completionFunc != 0 ? true : false; + + BaseClass::Create(pName, pHelpString, flags); +} + +ConCommand::ConCommand(const char* pName, FnCommandCallback_t callback, const char* pHelpString , int flags , FnCommandCompletionCallback completionFunc ) +{ + m_fnCommandCallback = callback; + m_bUsingNewCommandCallback = true; + m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc; + m_bHasCompletionCallback = completionFunc != 0 ? true : false; + m_bUsingCommandCallbackInterface = false; + + BaseClass::Create(pName, pHelpString, flags); +} + +ConCommand::ConCommand(const char* pName, ICommandCallback* pCallback, const char* pHelpString , int flags , ICommandCompletionCallback* pCompletionCallback ) +{ + m_pCommandCallback = pCallback; + m_bUsingNewCommandCallback = false; + m_pCommandCompletionCallback = pCompletionCallback; + m_bHasCompletionCallback = (pCompletionCallback != 0); + m_bUsingCommandCallbackInterface = true; + + BaseClass::Create(pName, pHelpString, flags); +} + +ConCommand::~ConCommand(void) +{ +} + + +bool ConCommand::IsCommand(void) const +{ + return true; +} + + +void ConCommand::Dispatch(const CCommand& command) +{ + if (m_bUsingNewCommandCallback) + { + if (m_fnCommandCallback) + { + (*m_fnCommandCallback)(command); + return; + } + } + else if (m_bUsingCommandCallbackInterface) + { + if (m_pCommandCallback) + { + m_pCommandCallback->CommandCallback(command); + return; + } + } + else + { + if (m_fnCommandCallbackV1) + { + (*m_fnCommandCallbackV1)(); + return; + } + } + + AssertMsg(0, ("Encountered ConCommand '%s' without a callback!\n", GetName())); +} + + +int ConCommand::AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) +{ + if (m_bUsingCommandCallbackInterface) + { + if (!m_pCommandCompletionCallback) + return 0; + return m_pCommandCompletionCallback->CommandCompletionCallback(partial, commands); + } + + Assert(m_fnCompletionCallback); + if (!m_fnCompletionCallback) + return 0; + + char rgpchCommands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]; + int iret = (m_fnCompletionCallback)(partial, rgpchCommands); + for (int i = 0; i < iret; ++i) + { + CUtlString str = rgpchCommands[i]; + commands.AddToTail(str); + } + return iret; +} + + +bool ConCommand::CanAutoComplete(void) +{ + return m_bHasCompletionCallback; +} + + + +ConVar::ConVar(const char* pName, const char* pDefaultValue, int flags ) +{ + Create(pName, pDefaultValue, flags); +} + +ConVar::ConVar(const char* pName, const char* pDefaultValue, int flags, const char* pHelpString) +{ + Create(pName, pDefaultValue, flags, pHelpString); +} + +ConVar::ConVar(const char* pName, const char* pDefaultValue, int flags, const char* pHelpString, bool bMin, float fMin, bool bMax, float fMax) +{ + Create(pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax); +} + +ConVar::ConVar(const char* pName, const char* pDefaultValue, int flags, const char* pHelpString, FnChangeCallback_t callback) +{ + Create(pName, pDefaultValue, flags, pHelpString, false, 0.0, false, 0.0, callback); +} + +ConVar::ConVar(const char* pName, const char* pDefaultValue, int flags, const char* pHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t callback) +{ + Create(pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax, callback); +} + + +ConVar::~ConVar(void) +{ + if (m_Value.m_pszString) { + delete[] m_Value.m_pszString; + m_Value.m_pszString = NULL; + } +} + + +void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke) +{ + if (callback) { + if (m_fnChangeCallbacks.GetOffset(callback) != -1) { + m_fnChangeCallbacks.AddToTail(callback); + if (bInvoke) + callback(this, m_Value.m_pszString, m_Value.m_fValue); + } + else { + } + } + else { + } +} + +bool ConVar::IsFlagSet(int flag) const +{ + return (flag & m_pParent->m_nFlags) ? true : false; +} + +const char* ConVar::GetHelpText(void) const +{ + return m_pParent->m_pszHelpString; +} + +void ConVar::AddFlags(int flags) +{ + m_pParent->m_nFlags |= flags; + +#ifdef ALLOW_DEVELOPMENT_CVARS + m_pParent->m_nFlags &= ~FCVAR_DEVELOPMENTONLY; +#endif +} + +bool ConVar::IsRegistered(void) const +{ + return m_pParent->m_bRegistered; +} + +const char* ConVar::GetName(void) const +{ + return m_pParent->m_pszName; +} + +bool ConVar::IsCommand(void) const +{ + return false; +} + +void ConVar::Init() +{ + BaseClass::Init(); +} + +void ConVar::InternalSetValue(const char* value) +{ + printfdbg("Executed ConVar::InternalSetValue to %s\n", value); + + float fNewValue; + char tempVal[32]; + char* val; + + auto temp = *(uint32_t*)&m_Value.m_fValue ^ (uint32_t)this; + float flOldValue = *(float*)(&temp); + + val = (char*)value; + fNewValue = (float)atof(value); + + if (ClampValue(fNewValue)) { + snprintf(tempVal, sizeof(tempVal), "%f", fNewValue); + val = tempVal; + } + + + *(uint32_t*)&m_Value.m_fValue = *(uint32_t*)&fNewValue ^ (uint32_t)this; + *(uint32_t*)&m_Value.m_nValue = (uint32_t)fNewValue ^ (uint32_t)this; + + if (!(m_nFlags & FCVAR_NEVER_AS_STRING)) { + ChangeStringValue(val, flOldValue); + } +} + +void ConVar::ChangeStringValue(const char* tempVal, float flOldValue) +{ + printfdbg("Executed ConVar::ChangeStringValue (tempVal %s; flOldValue %f)\n", tempVal, flOldValue); + + char* pszOldValue = (char*)stackalloc(m_Value.m_StringLength); + memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_StringLength); + + int len = strlen(tempVal) + 1; + + if (len > m_Value.m_StringLength) { + if (m_Value.m_pszString) { + delete[] m_Value.m_pszString; + } + + m_Value.m_pszString = new char[len]; + m_Value.m_StringLength = len; + } + + memcpy(m_Value.m_pszString, std::to_string(this->GetFloat()).c_str(), len); + + for (int i = 0; i < m_fnChangeCallbacks.Count(); i++) { + m_fnChangeCallbacks[i](this, pszOldValue, flOldValue); + } + + if (iff.g_pCVar) + iff.g_pCVar->CallGlobalChangeCallbacks(this, pszOldValue, flOldValue); +} + +void ConVar::InternalSetColorValue(Color cValue) +{ + int color = (int)cValue.GetRawColor(); + InternalSetIntValue(color); +} + +bool ConVar::ClampValue(float& value) +{ + if (m_bHasMin && (value < m_fMinVal)) + { + value = m_fMinVal; + return true; + } + + if (m_bHasMax && (value > m_fMaxVal)) + { + value = m_fMaxVal; + return true; + } + + return false; +} + + + +void ConVar::InternalSetFloatValue(float fNewValue) +{ + printfdbg("Executed ConVar::InternalSetFloatValue to %f\n",fNewValue); + + if (fNewValue == m_Value.m_fValue) + return; + + ClampValue(fNewValue); + + float flOldValue = m_Value.m_fValue; + *(uint32_t*)&m_Value.m_fValue = *(uint32_t*)&fNewValue ^ (uint32_t)this; + *(uint32_t*)&m_Value.m_nValue = (uint32_t)fNewValue ^ (uint32_t)this; + + if (!(m_nFlags & FCVAR_NEVER_AS_STRING)) { + char tempVal[32]; + snprintf(tempVal, sizeof(tempVal), "%f", m_Value.m_fValue); + ChangeStringValue(tempVal, flOldValue); + } + else { + } +} + +void ConVar::InternalSetIntValue(int nValue) +{ + printfdbg("Executed ConVar::InternalSetIntValue to %d\n",nValue); + + if (nValue == ((int)m_Value.m_nValue ^ (int)this)) + return; + + float fValue = (float)nValue; + if (ClampValue(fValue)) { + nValue = (int)(fValue); + } + + float flOldValue = m_Value.m_fValue; + *(uint32_t*)&m_Value.m_fValue = *(uint32_t*)&fValue ^ (uint32_t)this; + *(uint32_t*)&m_Value.m_nValue = *(uint32_t*)&nValue ^ (uint32_t)this; + + if (!(m_nFlags & FCVAR_NEVER_AS_STRING)) { + char tempVal[32]; + snprintf(tempVal, sizeof(tempVal), "%d", m_Value.m_nValue); + ChangeStringValue(tempVal, flOldValue); + } + else { + } +} + +void ConVar::Create(const char* pName, const char* pDefaultValue, int flags , + const char* pHelpString , bool bMin , float fMin , + bool bMax , float fMax , FnChangeCallback_t callback ) +{ + static const char* empty_string = ""; + + m_pParent = this; + + m_pszDefaultValue = pDefaultValue ? pDefaultValue : empty_string; + + m_Value.m_StringLength = strlen(m_pszDefaultValue) + 1; + m_Value.m_pszString = new char[m_Value.m_StringLength]; + memcpy(m_Value.m_pszString, m_pszDefaultValue, m_Value.m_StringLength); + + m_bHasMin = bMin; + m_fMinVal = fMin; + m_bHasMax = bMax; + m_fMaxVal = fMax; + + if (callback) + m_fnChangeCallbacks.AddToTail(callback); + + float value = (float)atof(m_Value.m_pszString); + + *(uint32_t*)&m_Value.m_fValue = *(uint32_t*)&value ^ (uint32_t)this; + *(uint32_t*)&m_Value.m_nValue = *(uint32_t*)&value ^ (uint32_t)this; + + BaseClass::Create(pName, pHelpString, flags); +} + +void ConVar::SetValue(const char* value) +{ + printfdbg("Executed ConVar::SetValue to %s\n",value); + ConVar* var = (ConVar*)m_pParent; + var->InternalSetValue(value); +} + +void ConVar::SetValue(float value) +{ + printfdbg("Executed ConVar::SetValue to %f\n", value); + ConVar* var = (ConVar*)m_pParent; + var->InternalSetFloatValue(value); +} + +void ConVar::SetValue(int value) +{ + printfdbg("Executed ConVar::SetValue to %d\n", value); + ConVar* var = (ConVar*)m_pParent; + var->InternalSetIntValue(value); +} + +void ConVar::SetValue(Color value) +{ + ConVar* var = (ConVar*)m_pParent; + var->InternalSetColorValue(value); +} + + +int ConVar::GetFlags(void) const +{ + return m_pParent->m_nFlags; +} + +int ConVar::GetSplitScreenPlayerSlot(void) const +{ + return 0; +} + +const char* ConVar::GetBaseName(void) const +{ + return m_pParent->m_pszName; +} + +void ConVar::Revert(void) +{ + ConVar* var = (ConVar*)m_pParent; + var->SetValue(var->m_pszDefaultValue); +} + +bool ConVar::GetMin(float& minVal) const +{ + minVal = m_pParent->m_fMinVal; + return m_pParent->m_bHasMin; +} + +bool ConVar::GetMax(float& maxVal) const +{ + maxVal = m_pParent->m_fMaxVal; + return m_pParent->m_bHasMax; +} + +const char* ConVar::GetDefault(void) const +{ + return m_pParent->m_pszDefaultValue; +} + +class CEmptyConVar : public ConVar +{ +public: + CEmptyConVar() : ConVar("", "0") {} + virtual void SetValue(const char* pValue) {} + virtual void SetValue(float flValue) {} + virtual void SetValue(int nValue) {} + virtual const char* GetName(void) const { return ""; } + virtual bool IsFlagSet(int nFlags) const { return false; } +}; + +static CEmptyConVar s_EmptyConVar; + +ConVarRef::ConVarRef(const char* pName) +{ + Init(pName, false); +} + +ConVarRef::ConVarRef(const char* pName, bool bIgnoreMissing) +{ + Init(pName, bIgnoreMissing); +} + +void ConVarRef::Init(const char* pName, bool bIgnoreMissing) +{ + m_pConVar = iff.g_pCVar ? iff.g_pCVar->FindVar(pName) : &s_EmptyConVar; + if (!m_pConVar) + { + m_pConVar = &s_EmptyConVar; + } + m_pConVarState = static_cast(m_pConVar); + if (!IsValid()) + { + static bool bFirst = true; + if (iff.g_pCVar || bFirst) + { + if (!bIgnoreMissing) + { + printfdbg("ConVarRef %s doesn't point to an existing ConVar\n", pName); + } + bFirst = false; + } + } +} + +ConVarRef::ConVarRef(IConVar* pConVar) +{ + m_pConVar = pConVar ? pConVar : &s_EmptyConVar; + m_pConVarState = static_cast(m_pConVar); +} + +bool ConVarRef::IsValid() const +{ + return m_pConVar != &s_EmptyConVar; +} + + +void ConVar_PrintFlags(const ConCommandBase* var) +{ + bool any = false; + if (var->IsFlagSet(FCVAR_GAMEDLL)) + { + iff.myConMsg(" game"); + any = true; + } + + if (var->IsFlagSet(FCVAR_CLIENTDLL)) + { + iff.myConMsg(" client"); + any = true; + } + + if (var->IsFlagSet(FCVAR_ARCHIVE)) + { + iff.myConMsg(" archive"); + any = true; + } + + if (var->IsFlagSet(FCVAR_NOTIFY)) + { + iff.myConMsg(" notify"); + any = true; + } + + if (var->IsFlagSet(FCVAR_SPONLY)) + { + iff.myConMsg(" singleplayer"); + any = true; + } + + if (var->IsFlagSet(FCVAR_NOT_CONNECTED)) + { + iff.myConMsg(" notconnected"); + any = true; + } + + if (var->IsFlagSet(FCVAR_CHEAT)) + { + iff.myConMsg(" cheat"); + any = true; + } + + if (var->IsFlagSet(FCVAR_REPLICATED)) + { + iff.myConMsg(" replicated"); + any = true; + } + + if (var->IsFlagSet(FCVAR_SERVER_CAN_EXECUTE)) + { + iff.myConMsg(" server_can_execute"); + any = true; + } + + if (var->IsFlagSet(FCVAR_CLIENTCMD_CAN_EXECUTE)) + { + iff.myConMsg(" clientcmd_can_execute"); + any = true; + } + + if (any) + { + iff.myConMsg("\n"); + } +} + + +``` + +`SpyCustom/Config.hpp`: + +```hpp +#ifndef CONFIG +#define CONFIG +#pragma once + +#include "Options.hpp" +#include "Singleton.hpp" + +#include +#include + + +#include +namespace fs = std::filesystem; + +static std::time_t to_time_t(FILETIME ft) +{ + std::time_t ret = 0; + ULARGE_INTEGER ull; + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + ret = (ull.QuadPart / 10000000ULL - 11644473600ULL); + return ret; +} + +std::vector HexToBytes(const std::string& hex) { + std::vector res; + + for (auto i = 0u; i < hex.length(); i += 2) { + std::string byteString = hex.substr(i, 2); + char byte = (char)strtol(byteString.c_str(), NULL, 16); + res.push_back(byte); + } + + return res; +} +std::string BytesToString(unsigned char* data, int len) { + constexpr char hexmap[] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + std::string res(len * 2, ' '); + for (int i = 0; i < len; ++i) { + res[2 * i] = hexmap[(data[i] & 0xF0) >> 4]; + res[2 * i + 1] = hexmap[data[i] & 0x0F]; + } + return res; +} +std::vector Split(const std::string& str, const char* delim) { + std::vector res; + char* pTempStr = _strdup(str.c_str()); + char* context = NULL; + char* pWord = strtok_s(pTempStr, delim, &context); + while (pWord != NULL) { + res.push_back(pWord); + pWord = strtok_s(NULL, delim, &context); + } + + free(pTempStr); + + return res; +} + +using namespace std; + +class Config : public Singleton { +public: + + std::vector configs = { }; + std::vector times = { }; + + bool file_exists(std::string filename) { + std::ifstream ifile(filename); + return (bool)ifile; + } + + void Create(char* name) { + string newname = string(name) + ".ss"; + if (!file_exists(newname)) { + ofstream newcfg; + newcfg.open(newname); + newcfg.close(); + } + Refresh(); + } + + void Delete(int selected) { + string name = configs[selected]; + if (remove(name.c_str()) != 0) + { + printfdbg("Error deleting file %s\n", name.c_str()); + } + Refresh(); + } + + void Save(int selected, char* new_name) { + + string name = configs[selected]; + string newname = string(new_name) + ".ss"; + + std::ofstream fout(name.c_str(), std::ios::binary); + const auto sz = sizeof(Options); + const auto var_sz = sizeof(Var); + const auto cnt = sz / var_sz; + for (auto i = 0; i < cnt; i++) { + const auto el = &(*(Var*)(&g_Options)) + i; + auto name = el->name; + auto val = el->value; + auto sizeof_val = el->size; + fout << name << "\t" << BytesToString((unsigned char*)*(int*)&val, sizeof_val) << std::endl; + } + fout.close(); + + rename(name.c_str(), newname.c_str()); + Refresh(); + + if (opt.autoconfig == selected) + { + ofstream autoload; + autoload.open("seaside_autoload"); + autoload << Config::Get().configs[selected]; + autoload.close(); + } + } + + + void Load(int selected) { + + opt.loading = 1; + string name = configs[selected]; + + if (file_exists(name.c_str()) ) { + std::ifstream fin(name.c_str(), std::ios::binary); + std::stringstream ss; + ss << fin.rdbuf(); + + + auto lines = Split(ss.str(), "\n"); + + for (auto line : lines) { + auto data = Split(line, "\t"); + const auto sz = sizeof(Options); + const auto var_sz = sizeof(Var); + const auto cnt = sz / var_sz; + for (auto i = 0; i < cnt; i++) { + const auto& el = &(*(Var*)(&g_Options)) + i; + if (data[0] == el->name) { + auto bytes = HexToBytes(data[1]); + memcpy(*(void**)&el->value, bytes.data(), el->size); + } + } + } + fin.close(); + + OnLoadCfg(); + } + + else PlaySoundA((char*)"null", opt.hModuleGlobal, SND_ASYNC); + } + + void OpenFolder() { + ShellExecute(NULL, NULL, "", NULL, NULL, SW_SHOWNORMAL); + } + + void Refresh() { + configs.clear(); times.clear(); + std::string search_path = "*.ss"; + WIN32_FIND_DATA fd; + HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); + std::string vremya; + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + configs.push_back(fd.cFileName); + time_t epoch = to_time_t(fd.ftLastWriteTime); + time_t creation = to_time_t(fd.ftCreationTime); + if (epoch != creation) + vremya = asctime(localtime(&epoch)); + else + vremya = "empty"; + times.push_back(vremya); + printfdbg("fn %s %s", fd.cFileName, vremya.c_str()); + } + } while (::FindNextFile(hFind, &fd)); + ::FindClose(hFind); + } + + + } + + void FindAutoexec() { + if (opt.autoconfig != -1) { + ifstream loadcfg("seaside_autoload"); + if (loadcfg.is_open()) + { + string line; + getline(loadcfg, line); + + for (int i = 0; i < Config::Get().configs.size(); i++) + if (Config::Get().configs[i] == line) + opt.autoconfig = i; + + } + else opt.autoconfig = -1; + } + } + +}; + + +#endif + +``` + +`SpyCustom/EventListener.hpp`: + +```hpp +#ifndef EVENTLISTEN +#define EVENTLISTEN +#pragma once + +#pragma comment( lib, "Winmm.lib" ) + +#include "Interfaces.hpp" +#include "sdk/c_baseentity.h" +#include "Options.hpp" + + +struct bullet +{ + bullet(int userID, Vector pos, int dmg, bool hs, float curtime) + { + this->userid = userid; + this->hs = hs; + this->curtime = curtime; + this->time = curtime + 0.0f; + this->pos = pos; + this->dmg = dmg; + } + int userid; + bool hs; + float time; + float curtime; + Vector pos; + int dmg; +}; +std::vector bulletdata; + +#define PI 3.14159265 + +class EventListener : public IGameEventListener2 +{ +public: + EventListener() + { + if (!iff.g_pGameEvents->AddListener(this, "bullet_impact", false)) + printfdbg("Can't add listener bullet_impact\n"); + + + if (!iff.g_pGameEvents->AddListener(this, "player_hurt", false)) + printfdbg("Can't add listener player_hurt\n"); + + + if (!iff.g_pGameEvents->AddListener(this, "vote_cast", false)) + printfdbg("Can't add listener vote_cast\n"); + + + if (!iff.g_pGameEvents->AddListener(this, "game_newmap", false)) + printfdbg("Can't add listener game_newmap\n"); + + + printfdbg("Event Listener created\n"); + + } + + ~EventListener() + { + iff.g_pGameEvents->RemoveListener(this); + } + + int GetEventDebugID() override + { + return EVENT_DEBUG_ID_INIT; + } + + virtual void FireGameEvent(IGameEvent* event) + { + + if (*g_Options.hitmarker || *g_Options.hitsound) { + if (!strcmp(event->GetName(), "player_hurt")) + { + short hitgroup = event->GetInt("hitgroup"); + short attacker = event->GetInt("attacker"); + short userid = event->GetInt("userid"); + short dmg_health = event->GetInt("dmg_health"); + + if (iff.g_pEngineClient->GetPlayerForUserID(attacker) == iff.g_pEngineClient->GetLocalPlayer()) { + + int pid = iff.g_pEngineClient->GetPlayerForUserID(userid); + C_BasePlayer* pEntity = (C_BasePlayer*)iff.g_pEntityList->GetClientEntity(pid); + Vector pos = pEntity->GetBonePosition(8); + + if (hitgroup == 1) + { + if (*g_Options.hitsound) { + //iff.g_pEngineClient->ExecuteClientCmd("play hitsound_crit.wav"); + char pathtosnd[MAX_PATH] = "play "; + strcat(pathtosnd, g_Options.hspath.value->mystring); + iff.g_pEngineClient->ExecuteClientCmd(pathtosnd); + } + + if (*g_Options.hitmarker) + bulletdata.push_back(bullet(userid, pos, dmg_health, 1, iff.g_pGlobals->curtime)); + } + else + { + if (*g_Options.hitsound) { + char pathtosnd[MAX_PATH] = "play "; + strcat(pathtosnd, g_Options.obpath.value->mystring); + iff.g_pEngineClient->ExecuteClientCmd(pathtosnd); + } + + if (*g_Options.hitmarker) + bulletdata.push_back(bullet(userid, pos, dmg_health, 0, iff.g_pGlobals->curtime)); + } + + + } + } + } + + + if (!strcmp(event->GetName(), "bullet_impact")) + { + + short userid = event->GetInt("userid"); + int localplayer = iff.g_pEngineClient->GetLocalPlayer(); + + + if (iff.g_pEngineClient->GetPlayerForUserID(userid) == localplayer) { + + + float x = event->GetFloat("x"); + float y = event->GetFloat("y"); + float z = event->GetFloat("z"); + + C_BasePlayer* pEntity = (C_BasePlayer*)iff.g_pEntityList->GetClientEntity(localplayer); + Vector src = pEntity->GetOrigin() + pEntity->GetViewOffset(); + Vector dst = { x,y,z }; + + Vector ang = pEntity->GetAngles(); + + ang.x -= 90.0f; ang.y -= 90.0f; + + static float margin = 3.0f; + static float coeff = 1.5f; + src.x += cos(ang.x * PI / 180) * margin * sin(ang.y * PI / 180) + cos(ang.y * PI / 180) * margin * coeff; + src.y += -cos(ang.x * PI / 180) * margin * cos(ang.y * PI / 180) + sin(ang.y * PI / 180) * margin * coeff; + src.z += sin(ang.x * PI / 180) * margin; + + + if (*g_Options.beamtrace) { + + BeamInfo_t beamInfo; + beamInfo.m_nType = *g_Options.beamtype; + beamInfo.m_pszModelName = g_Options.beampath.value->mystring; + + beamInfo.m_nModelIndex = -1; + beamInfo.m_flHaloScale = 0.0f; + beamInfo.m_pStartEnt = pEntity; + beamInfo.m_pEndEnt = NULL; + + beamInfo.m_vecEnd = dst; + beamInfo.m_vecStart = src; + beamInfo.m_flLife = *g_Options.beamlife; + beamInfo.m_flFadeLength = *g_Options.beamfadelength; + beamInfo.m_flAmplitude = *g_Options.beamamplitude; + beamInfo.m_nSegments = *g_Options.beamsegments; + beamInfo.m_bRenderable = true; + + beamInfo.m_flSpeed = *g_Options.beamspeed; + beamInfo.m_nStartFrame = *g_Options.beamstartframe; + beamInfo.m_flFrameRate = *g_Options.beamframerate; + beamInfo.m_flWidth = *g_Options.beamwidth; + beamInfo.m_flEndWidth = *g_Options.beamwidth; + + beamInfo.m_flBlue = g_Options.beamcolor.value->b * 255.0f; + beamInfo.m_flGreen = g_Options.beamcolor.value->g * 255.0f; + beamInfo.m_flRed = g_Options.beamcolor.value->r * 255.0f; + beamInfo.m_flBrightness = g_Options.beamcolor.value->a * 255.0f; + + beamInfo.m_nFlags = *g_Options.beamflags; + Beam_t* myBeam = iff.g_pViewRenderBeams->CreateBeamPoints(beamInfo); + if (myBeam) iff.g_pViewRenderBeams->DrawBeam(myBeam); + else + { + } + } + + + if (*g_Options.attacheffects) { + + switch (g_Options.effects.value->type) { + + case 0: + { + switch (g_Options.effects.value->selectedc) + { + case 0: + { + iff.g_pEffects->Smoke(dst, -1, g_Options.effects.value->fx_fsize, g_Options.effects.value->fx_fspeed); + break; + } + case 2: + { + iff.g_pEffects->Dust(dst, Vector(0.0f, 0.0f, 1.0f), g_Options.effects.value->fx_fsize, g_Options.effects.value->fx_fspeed); + break; + } + case 1: + { + iff.g_pEffects->Sparks(dst, g_Options.effects.value->fx_magnitude, g_Options.effects.value->fx_traillength); + break; + } + case 3: + { + iff.g_pEffects->MuzzleFlash(dst, CalcAngle(dst, src), g_Options.effects.value->fx_fsize, g_Options.effects.value->fx_itype); + break; + } + case 4: + { + iff.g_pEffects->MetalSparks(dst, Vector( 0.0f, 0.0f, 0.0f ) ); + break; + } + case 6: + { + iff.g_pEffects->Ricochet(dst, Vector(0.0f, 0.0f, 1.0f)); + break; + } + case 5: + { + iff.g_pEffects->EnergySplash(dst, src, g_Options.effects.value->fx_bexplosive); + break; + } + + } + break; + } + + case 1: + { + CEffectData asscock; + asscock.m_fFlags = g_Options.effects.value->fflags; + asscock.m_vOrigin = dst; + asscock.m_vStart = src; + asscock.m_vNormal.Init(0.0f, 0.0f, 1.0f); + asscock.m_flScale = g_Options.effects.value->fscale; + asscock.m_nColor = g_Options.effects.value->icolors; + asscock.m_flMagnitude = g_Options.effects.value->fmagtinude; + asscock.m_flRadius = g_Options.effects.value->fradius; + iff.DispatchEffect(opt.DispatchEffect.at(g_Options.effects.value->selectedc).c_str(), asscock); + + break; + } + + + + case 2: + { + switch (g_Options.effects.value->selectedc) + { + case 0: + { + CTeslaInfo teslaInfo; + teslaInfo.m_flBeamWidth = g_Options.effects.value->fbeamwidth; + teslaInfo.m_flRadius = g_Options.effects.value->teslaradius; + teslaInfo.m_nEntIndex = -1; + teslaInfo.m_vColor.Init(g_Options.effects.value->teslacolor[0], g_Options.effects.value->teslacolor[1], g_Options.effects.value->teslacolor[2]); + teslaInfo.m_vPos = dst; + teslaInfo.m_flTimeVisible = g_Options.effects.value->fltimevisible; + teslaInfo.m_nBeams = g_Options.effects.value->ibeams; + teslaInfo.m_pszSpriteName = g_Options.effects.value->szSpriteName; + iff.FX_Tesla(teslaInfo); + + break; + } + + + + case 1: + { + + dlight_t* pDlight = iff.g_pEfx->CL_AllocDlight(1); + pDlight->origin = dst; + pDlight->radius = g_Options.effects.value->frad; + pDlight->color.r = g_Options.effects.value->dlightcolor[0]*255.0f; + pDlight->color.g = g_Options.effects.value->dlightcolor[1] * 255.0f; + pDlight->color.b = g_Options.effects.value->dlightcolor[2] * 255.0f; + + pDlight->color.exponent = 5; + pDlight->die = iff.g_pGlobals->curtime + g_Options.effects.value->fdie; + pDlight->decay = 0; + pDlight->key = g_Options.effects.value->key; + pDlight->style = g_Options.effects.value->style; + + + + break; + } + + + + + } + break; + } + + + + + + + + } + + } + + + } + + } + + + + + if (*g_Options.votereveal) { + if (!strcmp(event->GetName(), "vote_cast")) + { + int vote = event->GetInt("vote_option"); + int id = event->GetInt("entityid"); + short team = event->GetInt("team"); + if (iff.g_ClientMode->m_pChatElement) + { + player_info_t pinfo; + iff.g_pEngineClient->GetPlayerInfo(id, &pinfo); + + if (pinfo.name) { + char team_byte[3]; + if (team == 2) memcpy(team_byte, " \x07", 3); //red + else + if (team == 3) memcpy(team_byte, " \x0B", 3); //blu + else + memcpy(team_byte, " \x08", 3); //gray + + printfdbg("%d %s voted %d\n", team, pinfo.name, vote); + iff.g_ClientMode->m_pChatElement->ChatPrintf_v(0, 0, std::string(""). + //append(" \x06"). + append(team_byte). + append(pinfo.name). + append(" \x01"). + append("voted"). + append((vote == 0 ? std::string(" \x04").append("YES") : std::string(" \x02").append("NO"))).c_str()); + } + } + } + } + + if (!strcmp(event->GetName(), "game_newmap")) + { + printfdbg("game_newmap\n"); + OnLevelInit(); + } + + + + + + } +}; + + + +#endif + +``` + +`SpyCustom/GetVfunc.hpp`: + +```hpp +#ifndef GETVFUNC +#define GETVFUNC + +#pragma once + +inline void**& getvtable(void* inst, size_t offset = 0) +{ + return *reinterpret_cast((size_t)inst + offset); +} + +inline const void** getvtable(const void* inst, size_t offset = 0) +{ + return *reinterpret_cast((size_t)inst + offset); +} + +template +inline Fn getvfunc(const void* inst, size_t index, size_t offset = 0) +{ + return reinterpret_cast(getvtable(inst, offset)[index]); +} + + +template +Fn get_vfunc(void* class_base, const size_t index) +{ + return (*reinterpret_cast(class_base))[index]; +} + +#include +#include +inline char* MakeControlChars(char str[1024]) { + char name[1024]; + strcpy(name, str); + for (int i = 0; i < 1024; i++) + { + if (name[i] == 0x5C && name[i + 1] == 0x78) + { + char controlchar[3]; controlchar[0] = name[i + 2]; controlchar[1] = name[i + 3]; controlchar[2] = 0x0; + short x = std::stoul(controlchar, nullptr, 16); + name[i] = x; + for (int j = i + 4; j < 1024; j++) + { + name[j - 3] = name[j]; + if (name[j] == 0x0) + break; + } + } + if (name[i] == 0x0) + break; + } + + return name; +} + + + +#endif +``` + +`SpyCustom/Hooks.hpp`: + +```hpp +#pragma once + +#include "sdk/particles.h" +#include "ProtobuffMessages.h" +#include "Aimbot.hpp" + +VMTHook* SoundHook = nullptr; +void __fastcall hkEmitSound1(void* _this, int edx, IRecipientFilter& filter, int iEntIndex, int iChannel, char* pSoundEntry, unsigned int nSoundEntryHash, const char* pSample, float flVolume, int nSeed, float flAttenuation, int iFlags, int iPitch, const Vector* pOrigin, const Vector* pDirection, void* pUtlVecOrigins, bool bUpdatePositions, float soundtime, int speakerentity, int unk) { + static auto ofunc = SoundHook->GetOriginal(5); + + if (*g_Options.soundhook_count) { + soundlist vv = GetCfgWavpathBySoundHash(nSoundEntryHash); + + if (vv.cfgindex != -1) + { + Sounds ff = g_Options.models.value->arr[vv.cfgindex].sounds[vv.sndindex]; + return ofunc(iff.g_pEngineSound, edx, filter, iEntIndex, iChannel, pSoundEntry, -1, ff.wavpath, ff.volume, nSeed, flAttenuation, 0, ff.pitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity, unk); + } + } + + return ofunc(iff.g_pEngineSound, edx, filter, iEntIndex, iChannel, pSoundEntry, nSoundEntryHash, pSample, flVolume, nSeed, flAttenuation, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity, unk); + +} + +VMTHook* DMEHook = nullptr; + +void replacemat(int d) +{ + IMaterial* material; + + if (g_Options.materials.value->arr[d].customtextureselected != -1) + if (g_Options.customtextures.value->arr[g_Options.materials.value->arr[d].customtextureselected].texturelink != nullptr) + material = (IMaterial*)g_Options.customtextures.value->arr[g_Options.materials.value->arr[d].customtextureselected].texturelink; + else material = iff.g_pMaterialSystem->FindMaterial("__err", TEXTURE_GROUP_MODEL); + else + material = iff.g_pMaterialSystem->FindMaterial(g_Options.materials.value->arr[d].texture, TEXTURE_GROUP_MODEL); + material->SetMaterialVarFlag(MATERIAL_VAR_WIREFRAME, g_Options.materials.value->arr[d].wireframe); + material->SetMaterialVarFlag(MATERIAL_VAR_IGNOREZ, g_Options.materials.value->arr[d].ignorez); + material->SetMaterialVarFlag(MATERIAL_VAR_NO_DRAW, g_Options.materials.value->arr[d].nodraw); + material->ColorModulate(g_Options.materials.value->arr[d].coloralpha.x, g_Options.materials.value->arr[d].coloralpha.y, g_Options.materials.value->arr[d].coloralpha.z); + material->AlphaModulate(g_Options.materials.value->arr[d].coloralpha.w); + iff.g_pMdlRender->ForcedMaterialOverride(material); +} + +void __stdcall DrawModelExecute(IMatRenderContext* ctx, const DrawModelState_t& state, const ModelRenderInfo_t& pInfo, matrix3x4_t* pCustomBoneToWorld) +{ + static auto ofunc = DMEHook->GetOriginal(21); + + if (iff.g_pMdlRender->IsForcedMaterialOverride() || opt.loading || !*g_Options.dmeloop_count) + return ofunc(iff.g_pMdlRender, ctx, state, pInfo, pCustomBoneToWorld); + + + const char* szName = iff.g_pMdlInfo->GetModelName(pInfo.pModel); + + if (g_Options.materials.value->arr[3].active) + if (strstr(szName, "player/legacy/t") != nullptr) + replacemat(3); + + if (g_Options.materials.value->arr[4].active) + if (strstr(szName, "player/legacy/ct") != nullptr) + replacemat(4); + + if (strstr(szName, "weapons/v_")) { + int namehash = fnv2::hashRuntime(szName); + + + bool is_arm = strstr(szName, "arms") != nullptr; + bool is_sleeve = strstr(szName, "sleeve") != nullptr; + bool is_wep = !is_arm && !is_sleeve; + + + for (int d = 0; d < g_Options.materials.value->itemcount; d++) + { + + if (d == 1 && !is_arm) continue; + if (d == 2 && !is_sleeve) continue; + if (d == 0 && !is_wep) continue; + + if (d == 3 || d == 4) continue; + if ((d > 2 && d != 5) && namehash != g_Options.materials.value->arr[d].model_hash) continue; + + if (d == 5 && !strstr(szName, "knife")) continue; + + if (g_Options.materials.value->arr[d].active) { + replacemat(d); + } + } + } + + ofunc(iff.g_pMdlRender, ctx, state, pInfo, pCustomBoneToWorld); + + iff.g_pMdlRender->ForcedMaterialOverride(nullptr); +} + + +typedef const void(__thiscall* pParticleCollectionSimulate)(void*); +pParticleCollectionSimulate oParticleCollectionSimulate; +void __fastcall hkParticleCollectionSimulate(CParticleCollection* thisPtr, void* edx) +{ + + static auto original = reinterpret_cast(oParticleCollectionSimulate); + + if (!g_Options.worldcoloractive || !iff.g_pEngineClient->IsConnected()) + { + original(thisPtr); + return; + } + + original(thisPtr); + + CParticleCollection* root_colection = thisPtr; + while (root_colection->m_pParent) + root_colection = root_colection->m_pParent; + + const char* root_name = root_colection->m_pDef.m_pObject->m_Name.buffer; + + for (int i = 0; i < thisPtr->m_nActiveParticles; i++) + { + float* pColor = thisPtr->m_ParticleAttributes.FloatAttributePtr(PARTICLE_ATTRIBUTE_TINT_RGB, i); + pColor[0] = g_Options.smokeskycolor.value->r; + pColor[4] = g_Options.smokeskycolor.value->g; + pColor[8] = g_Options.smokeskycolor.value->b; + float* pAlpha = thisPtr->m_ParticleAttributes.FloatAttributePtr(PARTICLE_ATTRIBUTE_ALPHA, i); + *pAlpha = g_Options.smokeskycolor.value->a; + } + +} + + + +VMTHook* CacheHook = nullptr; +MDLHandle_t __fastcall hkFindMDL(void* ecx, void* edx, char* FilePath) +{ + static auto oFindMDL = CacheHook->GetOriginal(10); + + + if (g_Options.models.value->arr[2].active && strstr(FilePath, "models/weapons/v_models/arms") && !strstr(FilePath, "gloves")) + { + printfdbg("Replacing %s with %s\n", FilePath, g_Options.models.value->arr[2].vmodel_repl); + sprintf(FilePath, g_Options.models.value->arr[2].vmodel_repl); + } + + if (g_Options.models.value->arr[3].active && strstr(FilePath, "models/weapons/v_knife")) + { + printfdbg("Replacing %s with %s\n", FilePath, g_Options.models.value->arr[3].vmodel_repl); + sprintf(FilePath, g_Options.models.value->arr[3].vmodel_repl); + } + + for (int i = 4; i < g_Options.models.value->itemcount; i++) + { + if (g_Options.models.value->arr[i].active && g_Options.models.value->arr[i].findMDLmethode && strstr(FilePath, g_Options.models.value->arr[i].vmodel_orig)) + { + printfdbg("Replacing %s with %s\n", FilePath, g_Options.models.value->arr[i].vmodel_repl); + sprintf(FilePath, g_Options.models.value->arr[i].vmodel_repl); + } + } + + + return oFindMDL(ecx, FilePath); +} + + + +VMTHook* ClientModeHook = nullptr; +static void __stdcall hkdoPostScreenEffects(void* param) noexcept +{ + static auto ofunc = ClientModeHook->GetOriginal(44); + + int localplayer_index = iff.g_pEngineClient->GetLocalPlayer(); + C_BasePlayer* localplayer = static_cast(iff.g_pEntityList->GetClientEntity(localplayer_index)); + + if (*g_Options.entityloop_count) { + if (iff.g_pEngineClient->IsInGame()) + { + for (int i = iff.g_pEngineClient->GetMaxClients() + 1; i <= iff.g_pEntityList->GetHighestEntityIndex(); ++i) + { + C_BasePlayer* pEntity = (C_BasePlayer*)iff.g_pEntityList->GetClientEntity(i); + + if (!pEntity) + continue; + + bool bDormant = pEntity->IsDormant(); + + if (bDormant) + continue; + + int cfgindex = GetCfgIndexByClassId(fnv2::hashRuntime(pEntity->GetClientClass()->GetName())); + + if (cfgindex != -1) + { + if (g_Options.models.value->arr[cfgindex].active_scale) + pEntity->GetModelScale() = g_Options.models.value->arr[cfgindex].scale; + + if (g_Options.models.value->arr[cfgindex].active_w) + { + char* model = g_Options.models.value->arr[cfgindex].wmodel_repl; + pEntity->SetModelIndex(iff.g_pMdlInfo->GetModelIndex(model)); + if (const auto modelprecache = iff.g_pNetworkStringTableContainer->FindTable("modelprecache")) + modelprecache->AddString(false, model); + } + } + + + } + } + } + + + for (int i = 0; i < iff.g_GlowObjectManager->m_GlowObjectDefinitions.Count(); i++) + { + CGlowObjectManager::GlowObjectDefinition_t& glow = iff.g_GlowObjectManager->m_GlowObjectDefinitions[i]; + + if (glow.m_nNextFreeSlot != CGlowObjectManager::GlowObjectDefinition_t::ENTRY_IN_USE) + continue; + + if (!glow.m_pEntity) + continue; + + if (fnv2::hash(glow.m_pEntity->GetClientClass()->GetName()) == fnv2::hash("CCSPlayer")) + { + if (localplayer->GetTeam() != ((C_BasePlayer*)glow.m_pEntity)->GetTeam() && g_Options.glowObjects.value->arr[0].enabled) + { + memcpy(&glow.m_vGlowColor, &g_Options.glowObjects.value->arr[0].color, sizeof(float) * 4); + glow.m_bRenderWhenOccluded = true; + glow.m_bRenderWhenUnoccluded = false; + glow.m_flGlowAlphaMax = g_Options.glowObjects.value->arr[0].alphamax; + glow.m_nRenderStyle = g_Options.glowObjects.value->arr[0].glowstyle; + glow.m_bFullBloomRender = false; + glow.m_nFullBloomStencilTestValue = 0; + } + + if (localplayer->GetTeam() == ((C_BasePlayer*)glow.m_pEntity)->GetTeam() && g_Options.glowObjects.value->arr[1].enabled) + { + memcpy(&glow.m_vGlowColor, &g_Options.glowObjects.value->arr[1].color, sizeof(float) * 4); + glow.m_bRenderWhenOccluded = true; + glow.m_bRenderWhenUnoccluded = false; + glow.m_flGlowAlphaMax = g_Options.glowObjects.value->arr[1].alphamax; + glow.m_nRenderStyle = g_Options.glowObjects.value->arr[1].glowstyle; + glow.m_bFullBloomRender = false; + glow.m_nFullBloomStencilTestValue = 0; + } + } + } + + if (g_Options.flashalpha != 255.0f) + { + localplayer->GetFlashMaxAlpha() = g_Options.flashalpha; + } + + ofunc(iff.g_ClientMode, param); +} + +void __stdcall hkOverrideView(CViewSetup* vsView) { + + static auto ofunc = ClientModeHook->GetOriginal(18); + + C_BasePlayer* localplayer = static_cast(iff.g_pEntityList->GetClientEntity(iff.g_pEngineClient->GetLocalPlayer())); + if (iff.g_pEngineClient->IsInGame() && localplayer) + { + + if (!localplayer->IsScoped()) + vsView->fov = g_Options.fov; + + auto ViewModel = reinterpret_cast(iff.g_pEntityList->GetClientEntityFromHandle(localplayer->GetViewModel())); + if (ViewModel) + { + Vector eyeAng = vsView->angles; + eyeAng.x += g_Options.viewmodel_ang_x; + eyeAng.y += g_Options.viewmodel_ang_y; + eyeAng.z += g_Options.viewmodel_ang_z; + ViewModel->GetAbsAngles() = eyeAng; + } + } + + + ofunc(vsView); +} + + + +VMTHook* VGUISurfHook = nullptr; +void __fastcall hkLockCursor(void* _this) +{ + static auto ofunc = VGUISurfHook->GetOriginal(67); + + if (opt.show) { + iff.g_pVGuiSurface->UnlockCursor(); + iff.g_pInputSystem->ResetInputState(); + return; + } + + ofunc(iff.g_pVGuiSurface); +} + + +VMTHook* FileSystemHook = nullptr; + +int __stdcall hkGetUnverifiedFileHashes(void* _this, void* someclass, int nMaxFiles) +{ + return 0; +} + + + +enum class account_status_t : int +{ + none = 0, + not_identifying, + awaiting_cooldown, + eligible, + eligible_with_takeover, + elevated, + account_cooldown +}; + +typedef const int(__thiscall* pGetAccountData)(void*); +pGetAccountData oGetAccountData; +int __fastcall hkGetAccountData(void* _this, void* edx) noexcept +{ + const auto ret = oGetAccountData(_this); + + account_status_t& account_status = *reinterpret_cast(ret + 24); + static const bool is_originally_prime_account = account_status == account_status_t::elevated; + if (!is_originally_prime_account) + { + account_status = g_Options.prime ? account_status_t::elevated : account_status_t::none; + } + + return ret; + +} + + +typedef const void(__thiscall* pShutdown)(void*, void*, const char*); +pShutdown oShutdown; +void __fastcall hkShutdown(void* thisptr, void* unk1, void* unk2, const char* reason) noexcept +{ + printfdbg("shutdown (%x) HOOKED %s\n", thisptr, reason); + + if (*g_Options.discmsg_active) { + printfdbg("set new reason %s\n", g_Options.discmsg.value->mystring); + char customreason[256] = "#"; + strcat_s(customreason, MakeControlChars(g_Options.discmsg.value->mystring)); + + oShutdown(thisptr, nullptr, customreason); + } + else + oShutdown(thisptr, nullptr, reason); +} + + +typedef const bool(__thiscall* pSendNetMsg)(void*, INetMessage*, bool, bool); +pSendNetMsg oSendNetMsg; +bool __fastcall hkSendNetMsg(void* channel, uint32_t, INetMessage* msg, bool reliable, bool voice) +{ + if (*g_Options.debugstuff) + { + int type = msg->GetType(); + if (type != net_Tick && type != svc_SendTable) + //printfdbg("NetMessage %s %s\n", msg->GetName(), msg->ToString()); + iff.myConMsg("[Seaside] NetMessage %s %s\n", msg->GetName(), msg->ToString()); + } + + if (*g_Options.changing_name && msg->GetType() == net_SetConVar) + { + if (*g_Options.changing_name > 1) { + *g_Options.changing_name = 0; + printfdbg("Blocking net_SetConVar packet\n"); + return false; + } + + *g_Options.changing_name += 1; + } + + return oSendNetMsg(channel, msg, reliable, voice); +} + +inline void HookNetchannel() +{ + //iff.g_pClientState->m_NetChannel + DWORD ptrShutdown = *((DWORD*)iff.g_pEngineClient->GetNetChannelInfo()) + 36 * 4; + DWORD addrShutdown = *(DWORD*)ptrShutdown; + oShutdown = (pShutdown)DetourFunction( + (PBYTE)(addrShutdown), + (PBYTE)hkShutdown); + printfdbg("Netchannel:Shutdown detoured at %x\n", addrShutdown); + + DWORD ptrSendNetMsg = *((DWORD*)iff.g_pEngineClient->GetNetChannelInfo()) + 40 * 4; + DWORD addrSendNetMsg = *(DWORD*)ptrSendNetMsg; + oSendNetMsg = (pSendNetMsg)DetourFunction( + (PBYTE)(addrSendNetMsg), + (PBYTE)hkSendNetMsg); + printfdbg("Netchannel:SendNetMsg detoured at %x\n", addrSendNetMsg); + + opt.netchannedlhooked = 1; +} + +float oldtick = 0; int c4id = 0; + +float scaleDamageArmor(float flDamage, int armor_value) +{ + float flArmorRatio = 0.5f; + float flArmorBonus = 0.5f; + if (armor_value > 0) { + float flNew = flDamage * flArmorRatio; + float flArmor = (flDamage - flNew) * flArmorBonus; + + if (flArmor > static_cast(armor_value)) { + flArmor = static_cast(armor_value) * (1.f / flArmorBonus); + flNew = flDamage - flArmor; + } + + flDamage = flNew; + } + return flDamage; +} + +namespace prediction { + void start(CUserCmd* cmd, C_BasePlayer* localplayer); + void end(C_BasePlayer* localplayer); + + inline CMoveData m_MoveData; + inline float m_flOldCurtime; + inline float m_flOldFrametime; + inline int* m_pPredictionRandomSeed; +}; + +void prediction::start(CUserCmd* cmd, C_BasePlayer* localplayer) +{ + if (!m_pPredictionRandomSeed) + m_pPredictionRandomSeed = *reinterpret_cast(FindPatternV2("client.dll", "8B 0D ? ? ? ? BA ? ? ? ? E8 ? ? ? ? 83 C4 04") + 2); + *m_pPredictionRandomSeed = MD5_PseudoRandom(cmd->command_number) & 0x7FFFFFFF; // cmd->random_seed & 0x7FFFFFFF; + m_flOldCurtime = iff.g_pGlobals->curtime; + m_flOldFrametime = iff.g_pGlobals->frametime; + iff.g_pGlobals->curtime = localplayer->GetTickBase() * iff.g_pGlobals->interval_per_tick; + iff.g_pGlobals->frametime = iff.g_pGlobals->interval_per_tick; + iff.g_pGameMovement->StartTrackPredictionErrors(localplayer); + memset(&m_MoveData, 0, sizeof(m_MoveData)); + iff.g_pMoveHelper->SetHost_v((CBaseEntity*)localplayer); + iff.g_pPrediction->SetupMove_v(localplayer, cmd, iff.g_pMoveHelper, &m_MoveData); + iff.g_pGameMovement->ProcessMovement(localplayer, &m_MoveData); + iff.g_pPrediction->FinishMove_v(localplayer, cmd, &m_MoveData); +} + +void prediction::end(C_BasePlayer* localplayer) +{ + iff.g_pGameMovement->FinishTrackPredictionErrors(localplayer); + iff.g_pMoveHelper->SetHost_v(nullptr); + *m_pPredictionRandomSeed = -1; + iff.g_pGlobals->curtime = m_flOldCurtime; + iff.g_pGlobals->frametime = m_flOldFrametime; +} + + +void fastStop(C_BasePlayer* localplayer, int flags, CUserCmd* cmd) noexcept +{ + if (!localplayer || localplayer->GetLifeState() != LIFE_ALIVE) + return; + if (localplayer->GetMoveType() == MOVETYPE_NOCLIP || localplayer->GetMoveType() == MOVETYPE_LADDER || !(flags & FL_ONGROUND) || cmd->buttons & IN_JUMP) + return; + if (cmd->buttons & (IN_MOVELEFT | IN_MOVERIGHT | IN_FORWARD | IN_BACK)) + return; + + const auto velocity = localplayer->GetVelocity(); + const auto speed = velocity.length2D(); + if (speed < 15.0f) + return; + + Vector direction = velocity.toAngle(); + direction.y = cmd->viewangles.y - direction.y; + + const auto negatedDirection = Vector::fromAngle(direction) * -speed; + cmd->forwardmove = negatedDirection.x; + cmd->sidemove = negatedDirection.y; +} + +void FastLadder(C_BasePlayer* localplayer, CUserCmd* cmd) +{ + static bool checkkkk = false; + float Up_down; + + Vector angle; + iff.g_pEngineClient->GetViewAngles(angle); + auto oldangles = cmd->viewangles; + if (localplayer->GetMoveType() == MOVETYPE_LADDER) + { + if (angle.x < 15) + Up_down = -89; + else Up_down = 89; + if (cmd->buttons & IN_FORWARD) + { + cmd->viewangles.x = Up_down; + if (oldangles.y > 135 && oldangles.y <= 180) + { + cmd->viewangles.y = 90.0f; + cmd->buttons |= IN_MOVELEFT; + } + else if (oldangles.y <= 135 && oldangles.y >= 90) + { + cmd->viewangles.y = 179.0f; + cmd->buttons |= IN_MOVERIGHT; + } + else if (oldangles.y <= -135 && oldangles.y >= -180.0f) + { + cmd->viewangles.y = -90.f; + cmd->buttons |= IN_MOVERIGHT; + } + else if (oldangles.y <= 90 && oldangles.y >= 45) + { + cmd->viewangles.y = 0; + cmd->buttons |= IN_MOVELEFT; + } + else if (oldangles.y >= -90 && oldangles.y <= -45) + { + cmd->viewangles.y = -0; + cmd->buttons |= IN_MOVERIGHT; + } + else if (oldangles.y <= -90 && oldangles.y >= -135) + { + cmd->viewangles.y = -179.0; + cmd->buttons |= IN_MOVELEFT; + } + else if (oldangles.y <= 45 && oldangles.y > 0) + { + cmd->viewangles.y = 90; + cmd->buttons |= IN_MOVERIGHT; + } + else if (oldangles.y <= -0 && oldangles.y >= -45) + { + cmd->viewangles.y = -90; + cmd->buttons |= IN_MOVELEFT; + } + } + } + //duck on edge of ladder?? + if (localplayer->GetMoveType() == MOVETYPE_LADDER && !checkkkk) + { + checkkkk = true; + } + if (localplayer->GetMoveType() != MOVETYPE_LADDER && checkkkk) + { + cmd->buttons |= IN_DUCK; + checkkkk = false; + } + +} + + +bool bSendPacket = 1; +bool __stdcall hkCreateMove2(float frame_time, CUserCmd* pCmd); + +__declspec(naked) bool __stdcall hkCreateMove(float frame_time, CUserCmd* pCmd) +{ + __asm + { + push ebp + mov ebp, esp + mov bSendPacket, bl + } + + hkCreateMove2(frame_time, pCmd); + +__asm{ + mov bl, bSendPacket + pop ebp + ret 0x08 + } +} + + +bool __stdcall hkCreateMove2(float frame_time, CUserCmd* pCmd) +{ + static auto ofunc = ClientModeHook->GetOriginal(24); + + short localid = iff.g_pEngineClient->GetLocalPlayer(); + C_BasePlayer* localplayer = static_cast(iff.g_pEntityList->GetClientEntity(localid)); + + iff.pLocal = localplayer; + + if (!localplayer) return ofunc(frame_time, pCmd); + + if (g_Options.rcs) localplayer->GetViewPunchAngle() = Vector(0, 0, 0); + + if (!pCmd->command_number) return ofunc(frame_time, pCmd); + + const auto pre_flags = localplayer->GetFlags(); + + bool interval = !((pCmd->tick_count + 1) % 10); + + if (g_Options.faststop) + fastStop(localplayer, pre_flags, pCmd); + if (g_Options.fastladder) + FastLadder(localplayer, pCmd); + if (g_Options.slidewalk) + pCmd->buttons ^= IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT; + if (g_Options.fastduck) + pCmd->buttons |= IN_BULLRUSH; + + if (g_Options.bunnyhop && iff.g_pInputSystem->IsButtonDown(KEY_SPACE) && localplayer->GetMoveType() != MOVETYPE_LADDER) + if (!(pre_flags & FL_ONGROUND) && pCmd->buttons & (IN_JUMP)) + { + pCmd->buttons &= ~(IN_JUMP); + + if (g_Options.autostrafe) { + if (pCmd->mousedx < 0) + pCmd->sidemove = -450.0f; + if (pCmd->mousedx > 0) + pCmd->sidemove = 450.0f; + } + } + + if (*g_Options.c4timer && *(C_GameRulesProxy**)iff.GameRulesProxy) { + bool isbombplanted = (*(C_GameRulesProxy**)iff.GameRulesProxy)->IsBombPlanted(); + if (localplayer && isbombplanted) + { + float tick = localplayer->GetTickBase() * iff.g_pGlobals->interval_per_tick; + + if (!c4id) + for (int i = iff.g_pEngineClient->GetMaxClients() + 1; i <= iff.g_pEntityList->GetHighestEntityIndex() + 1; i++) + { + auto entityList = iff.g_pEntityList->GetClientEntity(i); + if (entityList && _tcsstr(entityList->GetClientClass()->GetName(), "CPlantedC4") != NULL && tick < ((CPlantedC4*)entityList)->GetC4Blow()) + { + printfdbg("Found PlantedC4 %d (%f %f)\n", i, tick, ((CPlantedC4*)entityList)->GetC4Blow()); + c4id = i; + break; + } + } + + if (c4id) { + float C4Blow = ((CPlantedC4*)iff.g_pEntityList->GetClientEntity(c4id))->GetC4Blow(); + + if (interval) + { + //calc damage + const auto damagePercentage = 1.0f; + auto flDamage = 500.f; // 500 - default, if radius is not written on the map https://i.imgur.com/mUSaTHj.png + auto flBombRadius = flDamage * 3.5f; + auto flDistanceToLocalPlayer = ( + (iff.g_pEntityList->GetClientEntity(c4id)->GetAbsOrigin() + ((C_BaseEntity*)iff.g_pEntityList->GetClientEntity(c4id))->GetViewOffset()) - + (localplayer->GetAbsOrigin() + localplayer->GetViewOffset()) ).Length();// + auto fSigma = flBombRadius / 3.0f; + auto fGaussianFalloff = exp(-flDistanceToLocalPlayer * flDistanceToLocalPlayer / (2.0f * fSigma * fSigma)); + auto flAdjustedDamage = flDamage * fGaussianFalloff * damagePercentage; + flAdjustedDamage = scaleDamageArmor(flAdjustedDamage, localplayer->GetArmorValue()); + int healthleft = localplayer->GetHealth() - flAdjustedDamage; + + char str[0x100] = ""; + //snprintf(str, 0x100, "C4 %d HP %d", (int)(C4Blow - tick), healthleft < 1 ? "ff0000" : "00ff00", healthleft); + //iff.HudUniqueAlerts->GetPanel2D()->ShowAlert_v(str, false); + snprintf(str, 0x100, " C4 explode in %.*f sec\x0", healthleft < 1 ? "ff0000" : "ffff00", 1, C4Blow - tick); + TextMsg(str); + } + } + } + else if (c4id) c4id = 0; + } + + if (*g_Options.rankreveal && (pCmd->buttons & IN_SCORE) != 0) + iff.g_pClient->DispatchUserMessage(CS_UM_ServerRankRevealAll, 0, 0, nullptr); + + + if (g_Options.speclist && interval && localplayer->GetHealth() > 0) + { + string spectatorList = "Spectating you:\n \n"; + bool isSomeoneSpectatingYou = false; + for (short i = 1; i < iff.g_pEngineClient->GetMaxClients() + 1; i++) + { + if (i == localid) continue; + + C_BasePlayer* Entity = (C_BasePlayer*)iff.g_pEntityList->GetClientEntity(i); + if (Entity && Entity->GetLifeState() == LIFE_DEAD && Entity->GetHealth() < 1 && !Entity->IsDormant() && Entity->GetObserverTarget() == localid) + { + isSomeoneSpectatingYou = true; + + player_info_t pinfo; + iff.g_pEngineClient->GetPlayerInfo(i, &pinfo); + + spectatorList.append(pinfo.name).append("\n"); + } + } + if (isSomeoneSpectatingYou) ShowMenu(spectatorList); + } + + /* + if (localplayer && g_Options.predict) + { + prediction::start(pCmd, localplayer); + auto post_flags = localplayer->GetFlags(); + if ((post_flags & FL_ONGROUND || post_flags & FL_PARTIALGROUND) && !(pre_flags & FL_ONGROUND || pre_flags & FL_PARTIALGROUND)) //predicting that we're gonna hit the ground + { + pCmd->buttons |= IN_DUCK; + pCmd->buttons &= IN_JUMP; + } + prediction::end(localplayer); + } + */ + + if (g_Options.blockbot) { + // Get our ground entity. + auto pGroundEntity = iff.g_pEntityList->GetClientEntityFromHandle(localplayer->GetGroundEntity()); + + // Check if there's a player under us. + if (pGroundEntity && _tcsstr(pGroundEntity->GetClientClass()->GetName(), "CCSPlayer")) + { + Vector viewAngles; + iff.g_pEngineClient->GetViewAngles(viewAngles); + Vector localpos = localplayer->GetAbsOrigin(); + Vector entpos = pGroundEntity->GetAbsOrigin(); + Vector delta = localpos - entpos; + float deltaXold = delta[0]; float deltaYold = delta[1]; + delta[0] = deltaXold * cos(viewAngles[1] * PI / 180) + deltaYold * sin(viewAngles[1] * PI / 180); + delta[1] = -deltaXold * sin(viewAngles[1] * PI / 180) + deltaYold * cos(viewAngles[1] * PI / 180); + pCmd->forwardmove = std::clamp(-delta[0] * 40, -450.f, 450.f); + pCmd->sidemove = std::clamp(delta[1] * 40, -450.f, 450.f); + } + } + + if (g_Options.rcs) { + Vector aimPunchAngles = localplayer->GetAimPunchAngle(); + Vector currentViewAngles; iff.g_pEngineClient->GetViewAngles(currentViewAngles); + Vector newAngles = (currentViewAngles - aimPunchAngles * 2); + newAngles.Clamp(); newAngles.Normalize(); + pCmd->viewangles = newAngles; + //localplayer->GetViewPunchAngle() = Vector(0, 0, 0); + } + + + if (g_Options.fakelag) + { + auto choked = iff.g_pClientState->m_nChokedCommands; + + if (choked < g_Options.fakelag) + bSendPacket = 0; + else + bSendPacket = 1; + } + + + /* + if (!iff.g_pClientState->m_nChokedCommands) + { + static bool flip_movement = false; + + if (pCmd->forwardmove == 0.0f && !(pCmd->buttons & (int)IN_JUMP)) + { + pCmd->forwardmove += flip_movement ? -1.01f : 1.01f; + }//nonsense + flip_movement = !flip_movement; + } + */ + + if (g_Options.aimbot) + if (g_Options.aimbotautoshoot || iff.g_pInputSystem->IsButtonDown(MOUSE_LEFT)) + AimBot(pCmd); + + pCmd->viewangles.Clamp(); + pCmd->viewangles.Normalize(); + pCmd->forwardmove = std::clamp(pCmd->forwardmove, -450.f, 450.f); + pCmd->sidemove = std::clamp(pCmd->sidemove, -450.f, 450.f); + pCmd->upmove = std::clamp(pCmd->upmove, -320.f, 320.f); + + //return ofunc(frame_time, pCmd); + + return false; +} + + + +typedef const __int64(__cdecl* pDevMsg)(_In_z_ _Printf_format_string_ char const* const _Format, ...); +pDevMsg oDevMsg; //(char* a1, int a2, char a3) +__int64 __cdecl hkDevMsg(_In_z_ _Printf_format_string_ char const* const _Format, ...) +{ + int _Result; + va_list _ArgList; + __crt_va_start(_ArgList, _Format); + if (*g_Options.debugstuff) { + iff.myConMsg("[Seaside] DevMsg: "); + iff.myConMsg(_Format, _ArgList); + } + printfdbg("DevMsg: "); + _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList); + __crt_va_end(_ArgList); + return oDevMsg(_Format, NULL, _ArgList); +} + +typedef const __int64(__cdecl* pDevWarningMsg)(_In_z_ _Printf_format_string_ char const* const _Format, ...); +pDevMsg oDevWarningMsg; +__int64 __cdecl hkDevWarningMsg(_In_z_ _Printf_format_string_ char const* const _Format, ...) +{ + int _Result; + va_list _ArgList; + __crt_va_start(_ArgList, _Format); + if (*g_Options.debugstuff) { + iff.myConMsg("[Seaside] DevWarningMsg: "); + iff.myConMsg(_Format, _ArgList); + } + printfdbg("DevWarningMsg: "); + _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList); + __crt_va_end(_ArgList); + return oDevWarningMsg(_Format, NULL, _ArgList); +} + +int msgcount = 0; + +//sv_show_usermessage 2 for local server //https://www.unknowncheats.me/forum/counterstrike-global-offensive/492173-dispatchusermessage-client-call.html +bool __fastcall hkDispatchUserMessage(void* thisptr, void*, int msg_type, int32 nFlags, int size, bf_read& msg_data) +{ + printfdbg("DispatchUserMessage type %d flags %d size %d data -> %x\n", msg_type, nFlags, size, &msg_data); + if (*g_Options.debugstuff) { + iff.myConMsg("[Seaside] DispatchUserMessage type %d flags %d size %d data -> %x\n", msg_type, nFlags, size, &msg_data); + } + + static auto ofunc = ClientHook->GetOriginal(38); + + /* //read chat example + if (msg_type == CS_UM_SayText2) + { + bf_read read = bf_read(reinterpret_cast(&msg_data), size); + auto unk1 = read.ReadByte(); + auto ent_index = read.ReadByte(); + char databuf[1024]; + read.ReadBytes(databuf, 3); + char msg_name[1024] = ""; + read.ReadBytes(msg_name, read.ReadByte()); + read.ReadByte(); // \" + char player_name[1024] = ""; + read.ReadBytes(player_name, read.ReadByte()); + read.ReadByte(); // \" + char message[1024] = ""; + read.ReadBytes(message, read.ReadByte()); + } + */ + + return ofunc(thisptr,msg_type,nFlags,size, &msg_data); +} + +//static auto element = FindHudElement("CCSGO_HudRadar"); //money from radarbase? +typedef const int(__fastcall* pGetPlayerMoney)(void* _this, void* edx, int ent_index); +pGetPlayerMoney oGetPlayerMoney; +int __fastcall hkGetPlayerMoney(void* this_, void* edx, int ent_index) +{ + static C_CS_PlayerResource** g_player_resource = C_CS_PlayerResource::GetPlayerResource(); + auto player = iff.g_pEntityList->GetClientEntity(ent_index); + auto localplayer = ((C_BasePlayer*)iff.g_pEntityList->GetClientEntity(iff.g_pEngineClient->GetLocalPlayer())); + + if (!*g_Options.moneyreveal || !player || !localplayer || !(*g_player_resource) || ((C_BasePlayer*)player)->GetTeam() == localplayer->GetTeam() ) return oGetPlayerMoney(this_, edx, ent_index); + + if (player->IsDormant()) + { + int money = (*g_player_resource)->GetMatchStats_CashEarned_Total()[ent_index] - (*g_player_resource)->GetTotalCashSpent()[ent_index]; + money += iff.g_pCVar->FindVar("mp_startmoney")->GetInt(); + int maxmoney = iff.g_pCVar->FindVar("mp_maxmoney")->GetInt(); + if (money > maxmoney) money = maxmoney; + // printfdbg("Dormant %d Money %d (cash earned %d, total spent %d)\n", ent_index, money, (*g_player_resource)->GetMatchStats_CashEarned_Total()[ent_index], (*g_player_resource)->GetTotalCashSpent()[ent_index] ); + return money; + } + else + { + // printfdbg("NotDormant %d Money %d\n", ent_index, ((C_BasePlayer*)player)->GetAccount()); + return ((C_BasePlayer*)player)->GetAccount(); + } +} + +VMTHook* ViewRenderHook = nullptr; + +void __fastcall hkRenderSmokeOverlay(uintptr_t ecx, uintptr_t edx, bool a1) +{ + static auto oRenderSmokeOverlay = ViewRenderHook->GetOriginal(41); + if (!g_Options.wfsmoke) + oRenderSmokeOverlay(ecx, a1); + else *reinterpret_cast(std::uintptr_t(iff.g_ViewRender) + 0x588) = 0.0f; +} +``` + +`SpyCustom/Interfaces.cpp`: + +```cpp +#include "Interfaces.hpp" +#include "PatternScan.hpp" +#include "Options.hpp" + +IF iff; + +void* IF::GetInterface(const char* dllname, const char* interfacename) +{ + tCreateInterface CreateInterface = (tCreateInterface)GetProcAddress(GetModuleHandleA(dllname), "CreateInterface"); + int returnCode = 0; + void* ointerface = CreateInterface(interfacename, &returnCode); + printfdbg("Interface %s: %x\n", interfacename, ointerface); + return ointerface; +} + +PVOID FindHudElement(const char* name) +{ + static void* pointer1 = (void*)(FindPatternV2("client.dll", "B9 ? ? ? ? E8 ? ? ? ? 8B 5D 08") + 1); + static void* pThis = *reinterpret_cast(pointer1); + static void* pointer2 = (void*)(FindPatternV2("client.dll", "55 8B EC 53 8B 5D 08 56 57 8B F9 33 F6 39 77 28")); + static auto find_hud_element + = reinterpret_cast( + pointer2 + ); + + void* ret = (void*)find_hud_element(pThis, name); + printfdbg("HUD Element %s: %x\n", name, ret); + return ret; +} + + +#define VTBL(classptr) (*(DWORD*)classptr) +#define PVFN_(classptr, offset) (VTBL(classptr) + offset) +#define VFN_(classptr, offset) *(DWORD*)PVFN_(classptr, offset) +#define VFN(classptr, offset) VFN_(classptr, (offset * sizeof(void*))) + + +void IF::Init() +{ + g_pEntityList = (IClientEntityList*)GetInterface("client.dll", "VClientEntityList003"); + g_pGameUI = (CGameUI*)GetInterface("client.dll", "GameUI011"); + g_pVGuiPanel = (vgui::IPanel*)GetInterface("vgui2.dll", "VGUI_Panel009"); + g_pGameEvents = (CGameEventManager*)GetInterface("engine.dll", "GAMEEVENTSMANAGER002"); + g_pEngineClient = (IVEngineClient*)GetInterface("engine.dll", "VEngineClient014"); + g_pEnginetrace = (IEngineTrace*)GetInterface("engine.dll", "EngineTraceClient004"); + g_pEnginevgui = (IEngineVGui*)GetInterface("engine.dll", "VEngineVGui001"); + g_pVGui = (vgui::IVGui*)GetInterface("vgui2.dll", "VGUI_ivgui008"); + g_pClient = (IBaseClientDLL*)GetInterface("client.dll", "VClient018"); + g_pMdlInfo = (IVModelInfoClient*)GetInterface("engine.dll", "VModelInfoClient004"); + g_pMdlRender = (IVModelRender*)GetInterface("engine.dll", "VEngineModel016"); + g_pMaterialSystem = (IMaterialSystem*)GetInterface("materialsystem.dll", "VMaterialSystem080"); + g_pCVar = (ICvar*)GetInterface("vstdlib.dll", "VEngineCvar007"); + g_pVGuiSystem = (vgui::ISystem*)GetInterface("vgui2.dll", "VGUI_System010"); + g_pVGuiSchemeManager = (vgui::ISchemeManager*)GetInterface("vgui2.dll", "VGUI_Scheme010"); + g_pVGuiInput = (vgui::IInput*)GetInterface("vgui2.dll", "VGUI_Input005"); + g_pFullFileSystem = (IFileSystem*)GetInterface("filesystem_stdio.dll", "VFileSystem017"); + g_pGameConsole = (IGameConsole*)GetInterface("client.dll", "GameConsole004"); + g_pEfx = (IVEfx*)GetInterface("engine.dll", "VEngineEffects001"); + g_pPhysProps = (IPhysicsSurfaceProps*)GetInterface("vphysics.dll", "VPhysicsSurfaceProps001"); + g_pRenderView = (IVRenderView*)GetInterface("engine.dll", "VEngineRenderView014"); + g_pDebugOverlay = (IVDebugOverlay*)GetInterface("engine.dll", "VDebugOverlay004"); + g_pEffects = (IEffects*)GetInterface("client.dll", "IEffects001"); + g_pStudioRender = (IStudioRender*)GetInterface("studiorender.dll", "VStudioRender026"); + g_pPrediction = (CPrediction*)GetInterface("client.dll", "VClientPrediction001"); + g_pGameTypes = (IGameTypes*)GetInterface("client.dll", "VENGINE_GAMETYPES_VERSION002"); + g_pGameMovement = (IGameMovement*)GetInterface("client.dll", "GameMovement001"); + + typedef PVOID(__cdecl* oKeyValuesSystem)(); + oKeyValuesSystem pkeyValuesSystem = (oKeyValuesSystem)GetProcAddress(GetModuleHandleA("vstdlib.dll"), "KeyValuesSystem"); + keyValuesSystem = (IKeyValuesSystem*)pkeyValuesSystem(); + + printfdbg("KeyValuesSystem = %x\n", keyValuesSystem); + + myConMsg = (CONMSGPROC)GetProcAddress(GetModuleHandleA("tier0.dll"), "?ConMsg@@YAXPBDZZ"); + myConColorMsg = (CONCOLORMSGPROC)GetProcAddress(GetModuleHandleA("tier0.dll"), "?ConColorMsg@@YAXABVColor@@PBDZZ"); + + g_pGlobals = **(CGlobalVarsBase***)(FindPatternV2("client.dll", "A1 ? ? ? ? 5E 8B 40 10") + 1); + g_pInput = *(CInput**)(FindPatternV2("client.dll", "B9 ? ? ? ? F3 0F 11 04 24 FF 50 10") + 1); + g_pViewRenderBeams = *(IViewRenderBeams**)(FindPatternV2("client.dll", "B9 ?? ?? ?? ?? A1 ?? ?? ?? ?? FF 10 A1 ?? ?? ?? ?? B9") + 0x1); + + printfdbg("g_pGlobals = %x\n", g_pGlobals); + printfdbg("g_pInput = %x\n", g_pInput); + printfdbg("g_pViewRenderBeams = %x\n", g_pViewRenderBeams); + + FX_Tesla = (FX_TeslaFn)FindPatternV2("client.dll", "55 8B EC 81 EC ? ? ? ? 56 57 8B F9 8B 47 18"); + + printfdbg("FX_TeslaFn %x\n", FX_Tesla); + + BloodSprayFn = (FX_BloodSprayFn)FindPatternV2("client.dll", "55 8B EC 8B 4D 08 F3 0F 10 51 ? 8D"); + + printfdbg("FX_BloodSprayFn %x\n", BloodSprayFn); + + DispatchEffect = (FXDispatchEffect)FindPatternV2("client.dll", "55 8B EC 83 E4 F8 83 EC 20 56 57 8B F9 C7 44 24"); + + printfdbg("DispatchEffect %x\n", DispatchEffect); + + g_pChatElement = (CHudChat*)FindHudElement("CHudChat"); + + printfdbg("Chat element %x\n", g_pChatElement); + + LoadFromFile = (void*)FindPatternV2("client.dll", "55 8B EC 83 EC 0C 53 8B 5D 08 56 8B F1 3B"); + + printfdbg("LoadFromFile %x\n", LoadFromFile); + + g_pD3DDevice9 = **(IDirect3DDevice9***)(FindPatternV2("shaderapidx9.dll", "A1 ? ? ? ? 50 8B 08 FF 51 0C") + 1); + + printfdbg("g_pD3DDevice9 %x\n", g_pD3DDevice9); + + g_pMemAlloc = *(IMemAlloc**)(GetProcAddress(GetModuleHandle("tier0.dll"), "g_pMemAlloc")); + + printfdbg("g_pMemAlloc %x\n", g_pMemAlloc); + + g_pClientState = **reinterpret_cast(getvfunc(g_pEngineClient, 12) + 0x10); + + printfdbg("g_pClientState %x\n", g_pClientState); + + CHudElement* g_pHudElement = (CHudElement*)FindHudElement("CCSGO_HudDeathNotice"); + + printfdbg("Hud element %x\n", g_pHudElement); + + auto SteamClient = ((ISteamClient * (__cdecl*)(void))GetProcAddress(GetModuleHandleA("steam_api.dll"), "SteamClient"))(); + g_SteamGameCoordinator = (ISteamGameCoordinator*)SteamClient->GetISteamGenericInterface((HSteamUser)1, (HSteamPipe)1, "SteamGameCoordinator001"); + g_SteamUser = SteamClient->GetISteamUser((HSteamUser)1, (HSteamPipe)1, "SteamUser019"); + + printfdbg("SteamClient %X\n", SteamClient); + printfdbg("g_SteamGameCoordinator %X\n", g_SteamGameCoordinator); + printfdbg("g_SteamUser %X\n", g_SteamUser); + + g_pClientLeafSystem = (IClientLeafSystem*)GetInterface("client.dll", "ClientLeafSystem002"); + + printfdbg("g_pClientLeafSystem %x\n", g_pClientLeafSystem); + + g_pNetworkStringTableContainer = (INetworkStringTableContainer*)GetInterface("engine.dll", "VEngineClientStringTable001"); + + printfdbg("g_pNetworkStringTableContainer %x\n", g_pNetworkStringTableContainer); + + getPlayerViewmodelArmConfigForPlayerModel = relativeToAbsolute(FindPatternV2("client.dll", "E8 ? ? ? ? 89 87 ? ? ? ? 6A") + 1); + + g_pMdlCache = (IMDLCache*)GetInterface("datacache.dll", "MDLCache004"); + g_pEngineSound = (IEngineSound*)GetInterface("engine.dll", "IEngineSoundClient003"); + + g_pClientShadowMgr = *(IClientShadowMgr**)(FindPatternV2("client.dll", "A1 ? ? ? ? FF 90 ? ? ? ? 6A 00 6A 00") + 1); + + printfdbg("g_pClientShadowMgr %x\n", g_pClientShadowMgr); + + g_ViewRender = *(CCSViewRender**)(FindPatternV2("client.dll", "A1 ? ? ? ? B9 ? ? ? ? C7 05 ? ? ? ? ? ? ? ? FF 10") + 1); + + printfdbg("g_ViewRender %x\n", g_ViewRender); + + g_ClientMode = **(ClientModeShared***)((*(DWORD**)g_pClient)[10] + 0x5); + + printfdbg("g_ClientMode %x\n", g_ClientMode); + + g_pInputSystem = (IInputSystem*)GetInterface("inputsystem.dll", "InputSystemVersion001"); + g_pVGuiSurface = (vgui::ISurface*)GetInterface("vguimatsurface.dll", "VGUI_Surface031"); + + fn_get_account_data = relativeToAbsolute(FindPatternV2("client.dll", "E8 ? ? ? ? 85 C0 74 EE") + 1); + + printfdbg("fn_get_account_data %x\n", fn_get_account_data); + + ParticleCollectionSimulateAdr = relativeToAbsolute(FindPatternV2("client.dll", "E8 ? ? ? ? 8B 0E 83 C1 10") + 1); + + printfdbg("ParticleCollectionSimulateAdr %x\n", ParticleCollectionSimulateAdr); + + HudUniqueAlerts = (CHudElement*)FindHudElement("CCSGO_HudUniqueAlerts"); + + GameRulesProxy = *(C_GameRulesProxy**)(FindPatternV2("client.dll", "A1 ? ? ? ? 85 C0 0F 84 ? ? ? ? 80 B8 ? ? ? ? ? 74 7A")+1); //C_GameRulesProxy + dwRadarBase = FindPatternV2("client.dll", "A1 ? ? ? ? 8B 0C B0 8B 01 FF 50 ? 46 3B 35 ? ? ? ? 7C EA 8B 0D") + 1; + g_pMoveHelper = **reinterpret_cast(FindPatternV2("client.dll", "8B 0D ? ? ? ? 8B 46 08 68") + 2); + g_GlowObjectManager = *(CGlowObjectManager**)(FindPatternV2("client.dll", "0F 11 05 ? ? ? ? 83 C8 01") + 3); + printfdbg("g_GlowObjectManager %x\n", g_GlowObjectManager); + + OverheadInfo = (void*)(FindPatternV2("client.dll", "E8 ? ? ? ? 3B C6 5E 5F") + 5); + pLocal = 0; + + g_pWeaponSystem = *reinterpret_cast(FindPatternV2("client.dll", "8B 35 ? ? ? ? FF 10 0F B7 C0") + 0x2); +} + + +auto is_code_ptr(void* ptr) -> bool +{ + constexpr const DWORD protect_flags = PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; + + MEMORY_BASIC_INFORMATION out; + VirtualQuery(ptr, &out, sizeof out); + + return out.Type + && !(out.Protect & (PAGE_GUARD | PAGE_NOACCESS)) + && out.Protect & protect_flags; +} + + +const char* GetVisibleValue(const char* cvar) +{ + PVOID addr = iff.g_pCVar->FindVar(cvar); + if (!addr) return 0; + char dummy[255]; + memcpy(dummy, *(PVOID*)PVOID(*(int*)&addr + 0x24), 255); + return dummy; +} + +float GetVisibleFloat(const char* cvar) +{ + return std::stof(GetVisibleValue(cvar)); +} + + +void SetFloatUnrestricted(const char* cvar, float value) +{ + PVOID addr = iff.g_pCVar->FindVar(cvar); + if (!addr) + { + printfdbg("Can't find cvar %s\n", cvar); + + PlaySoundA((char*)"null", opt.hModuleGlobal, SND_ASYNC); + return; + } + float valX = value; + int valXX = *(int*)&valX ^ (DWORD)addr; + memcpy(PVOID(*(int*)&addr + 0x2C), &valXX, sizeof(valXX)); +} + +void SetIntUnrestricted(const char* cvar, int value) +{ + PVOID addr = iff.g_pCVar->FindVar(cvar); + if (!addr) + { + printfdbg("Can't find cvar %s\n", cvar); + + PlaySoundA((char*)"null", opt.hModuleGlobal, SND_ASYNC); + return; + } + int valXX = value ^ (DWORD)addr; + memcpy(PVOID(*(int*)&addr + 0x30), &valXX, sizeof(valXX)); +} + +void SetValueUnrestricted(const char* cvar, float value) +{ + printfdbg("Set %s to %f\n", cvar, value); + + SetFloatUnrestricted(cvar, value); + SetIntUnrestricted(cvar, (int)value); +} + + +void NETSetConVar(const char* cvarname, const char* cvarvalue) +{ + //__asm pushad + + char name[1024]; char value[1024]; + strcpy(name, cvarname); + strcpy(value, cvarvalue); + static void* pvSetConVar = (void*)FindPatternV2(("engine.dll"), ("8D 4C 24 1C E8 ? ? ? ? 56")); + printfdbg("NETSetConVar %s %s\n", cvarname, value); + + if (pvSetConVar) { + Invoke_NET_SetConVar(pvSetConVar, cvarname, value); + } + + //__asm popad +} + +void TextMsg(std::string text) +{ + if (iff.g_pClient) { + char message[0x100] = "\x08\x04\x1A"; + BYTE textsize = (BYTE)text.length(); + memcpy(&message[3], &textsize, 1); + memcpy(&message[4], text.c_str(), textsize); + memcpy(&message[4 + textsize], "\x1A\x00\x1A\x00\x1A\x00\x1A\x00", 8); + iff.g_pClient->DispatchUserMessage(CS_UM_TextMsg, 0, textsize + 12, &message); + } +} + +void ShowMenu(std::string text) +{ + if (iff.g_pClient) { + char message[0x1000] = "\x08\x80\x02\x10\x0A\x1A"; + text.append("\x0A \x0A->\x00"); + BYTE textsize = (BYTE)text.length(); + memcpy(&message[6], &textsize, 1); + memcpy(&message[7], text.c_str(), textsize); + iff.g_pClient->DispatchUserMessage(CS_UM_ShowMenu, 0, textsize + 7, &message); + } +} + + + +bool VoiceRecordStart(const char* pUncompressedFile) +{ + typedef bool(__cdecl* Voice_RecordStartFn)(const char*, const char*, const char*); + static Voice_RecordStartFn Voice_RecordStart = Voice_RecordStartFn(FindPatternV2("engine.dll", "55 8B EC 83 EC 0C 83 3D ?? ?? ?? ?? ?? 56 57")); + + //const char* WavSound = "MyCustomPathToMyFile.wav"; + + //m_FileDuration = Utils.GetWavFileDuration(WavSound); + //m_FilePlayEndTime = I::Globals->curtime + m_FileDuration; + + //iff.g_pCVar->FindVar("sv_voicecodec")->SetValue("vaudio_celt"); + iff.g_pEngineClient->ExecuteClientCmd("voice_loopback 1"); + return Voice_RecordStart(pUncompressedFile, nullptr, nullptr); +} + +``` + +`SpyCustom/Interfaces.hpp`: + +```hpp +#ifndef INTERFACES +#define INTERFACES +#pragma once + +#define DEBUG + +#ifdef DEBUG +#define printfdbg(data, ...) printf(XorStr(data), __VA_ARGS__) +#else +#define printfdbg(...) +#endif + +#define CLIENT_DLL + +#include "GetVfunc.hpp" + +#include +#include +#include "sdk/icliententitylist.h" +#include "sdk/CGameUI.h" +#include "sdk/GameEventManager.h" +#include "sdk/cdll_int.h" +#include "sdk/ISurface.h" +#include "sdk/IEngineVgui.h" +#include "sdk/ivmodelinfo.h" +#include "sdk/idatacache.h" +#include "sdk/ILocalize.h" +#include "sdk/IGameUI.h" +#include "sdk/dt_recv.h" +#include "sdk/client_class.h" +#include "sdk/enginetrace.h" +#include "sdk/gameconsole.h" +#include "sdk/ivrenderview.h" +#include "sdk/ivdebugoverlay.h" +#include "sdk/vphysics_interface.h" +#include "sdk/iefx.h" +#include "sdk/c_input.h" +#include "sdk/IEffects.h" +#include "sdk/iviewrender_beams.h" +#include "sdk/sdk_hud_chat.h" +#include "sdk/fx.h" +#include "sdk/globalvars_base.h" +#include "sdk/IInput.h" +#include "sdk/icliententity.h" +#include "sdk/iclient.h" +#include "sdk/cdll_int.h" +#include "sdk/baseclientstate.h" +#include "imgui/imgui_impl_dx9.h" +#include "sdk/flashlighteffect.h" +#include "sdk/inetchannel.h" +#include "sdk/animationlayer.h" +#include "sdk/clientleafsystem.h" +#include "sdk/filesystem.h" +#include "sdk/modelloader.h" +#include "sdk/IEngineSound.h" +#include "sdk/iclientshadowmgr.h" +#include "sdk/cs_view_scene.h" +#include "sdk/iclientmode.h" +#include "sdk/itexture.h" +#include "sdk/precipitation_shared.h" +#include "sdk/iinputsystem.h" +#include "sdk/vpkparser.h" +#include "sdk/itempents.h" +#include "sdk/c_te_legacytempents.h" +#include "sdk/iglobalvarsbase.h" +#include "sdk/iprediction.h" +#include "sdk/inetmessage.h" +#include "sdk/ClientNetMessage.h" +#include "sdk/clientmode_shared.h" +#include "sdk/isteamclient.h" +#include "sdk/isteamgamecoordinator.h" +#include "sdk/gamerules.h" +#include "sdk/igametypes.h" +#include "sdk/gamemovement.h" +#include "sdk/glow_outline_effect.h" +#include "sdk/cs_weapon_parse.h" + +#include "XorStr.hpp" + +PVOID FindHudElement(const char* name); + +auto is_code_ptr(void* ptr) -> bool; + +class IF { +public: + IClientEntityList* g_pEntityList = nullptr; + CGameUI* g_pGameUI = nullptr; + vgui::IPanel* g_pVGuiPanel = nullptr; + CGameEventManager* g_pGameEvents = nullptr; + IVEngineClient* g_pEngineClient = nullptr; + vgui::ISurface* g_pVGuiSurface = nullptr; + IEngineVGui* g_pEnginevgui = nullptr; + vgui::IVGui* g_pVGui = nullptr; + IBaseClientDLL* g_pClient = nullptr; + IVModelInfoClient* g_pMdlInfo = nullptr; + IVModelRender* g_pMdlRender = nullptr; + IMaterialSystem* g_pMaterialSystem = nullptr; + IKeyValuesSystem* keyValuesSystem = nullptr; + ICvar* g_pCVar = nullptr; + vgui::ISystem* g_pVGuiSystem = nullptr; + vgui::ISchemeManager* g_pVGuiSchemeManager = nullptr; + vgui::IInput* g_pVGuiInput = nullptr; + IFileSystem* g_pFullFileSystem = nullptr; + vgui::ILocalize* g_pVGuiLocalize = nullptr; + IEngineTrace* g_pEnginetrace = nullptr; + IVEfx* g_pEfx = nullptr; + IGameConsole* g_pGameConsole = nullptr; + IPhysicsSurfaceProps* g_pPhysProps = nullptr; + IVRenderView* g_pRenderView = nullptr; + IVDebugOverlay* g_pDebugOverlay = nullptr; + CGlobalVarsBase* g_pGlobals = nullptr; + CInput* g_pInput = nullptr; + IEffects* g_pEffects = nullptr; + IViewRenderBeams* g_pViewRenderBeams = nullptr; + IStudioRender* g_pStudioRender = nullptr; + CHudChat* g_pChatElement = nullptr; + using FX_TeslaFn = void(__thiscall*)(CTeslaInfo&); + FX_TeslaFn FX_Tesla = nullptr; + using FX_BloodSprayFn = bool(__cdecl*)(const CEffectData&); + FX_BloodSprayFn BloodSprayFn = nullptr; + using FXDispatchEffect = int(__fastcall*)(const char* name, const CEffectData&); + FXDispatchEffect DispatchEffect = nullptr; + void Init(); + void* GetInterface(const char* dllname, const char* interfacename); + typedef void(__cdecl* CONMSGPROC)(const char*, ...); + CONMSGPROC myConMsg = nullptr; + typedef void(__cdecl* CONCOLORMSGPROC)(Color& clr, const char*, ...); + CONCOLORMSGPROC myConColorMsg = nullptr; + PVOID LoadFromFile = nullptr; + IDirect3DDevice9* g_pD3DDevice9 = nullptr; + IMemAlloc* g_pMemAlloc = nullptr; + ISteamGameCoordinator* g_SteamGameCoordinator = nullptr; + ISteamUser* g_SteamUser = nullptr; + CClientState* g_pClientState = nullptr; + CHudElement* g_pHudElement = nullptr; + IClientLeafSystem* g_pClientLeafSystem = nullptr; + INetworkStringTableContainer* g_pNetworkStringTableContainer = nullptr; + std::add_pointer_t getPlayerViewmodelArmConfigForPlayerModel; + std::add_pointer_t fn_get_account_data; + IMDLCache* g_pMdlCache = nullptr; + IModelLoader* g_ModelLoader = nullptr; + IEngineSound* g_pEngineSound = nullptr; + IClientShadowMgr* g_pClientShadowMgr = nullptr; + CCSViewRender* g_ViewRender = nullptr; + ClientModeShared* g_ClientMode = nullptr; + IInputSystem* g_pInputSystem = nullptr; + ITempEnts* g_pTempEnts = nullptr; + DWORD ParticleCollectionSimulateAdr = 0; + CPrediction* g_pPrediction = nullptr; + IGameTypes* g_pGameTypes = nullptr; + CHudElement* HudUniqueAlerts = nullptr; + C_GameRulesProxy* GameRulesProxy = nullptr; //C_GameRulesProxy + DWORD dwRadarBase = NULL; + IMoveHelper* g_pMoveHelper = NULL; //CMoveHelperClient + IGameMovement* g_pGameMovement = NULL; + CGlowObjectManager* g_GlowObjectManager = NULL; + void* OverheadInfo = NULL; + C_BasePlayer* pLocal = NULL; + IWeaponSystem* g_pWeaponSystem = NULL; + +}; + + + + +extern IF iff; + +typedef void* (__cdecl* tCreateInterface)(const char* name, int* returnCode); + +template +static constexpr auto relativeToAbsolute(uintptr_t address) noexcept +{ + return (T)(address + 4 + *reinterpret_cast(address)); +} + + +namespace vgui { + inline vgui::IInput* input() + { + return iff.g_pVGuiInput; + } + + inline vgui::ISchemeManager* scheme() + { + return iff.g_pVGuiSchemeManager; + } + + inline vgui::ISurface* surface() + { + return iff.g_pVGuiSurface; + } + + inline vgui::ISystem* system() + { + return iff.g_pVGuiSystem; + } + + inline vgui::IVGui* ivgui() + { + return iff.g_pVGui; + } + + inline vgui::IPanel* ipanel() + { + return iff.g_pVGuiPanel; + } +} + + +class ICvar2 : public ICvar +{ +public: + ConVar* FindVar2(const char* var) + { + printfdbg("Trying to find var %s\n", var); + typedef ConVar* (*oFindVar)(void*, const char*); + return getvfunc(this, 16)(this, var); + } + + template + void ConsoleColorPrintf2(const Color& MsgColor, const char* szMsgFormat, Values... Parameters) + { + printfdbg("Trying to print %s\n", szMsgFormat); + typedef void(*oConsoleColorPrintf)(void*, const Color&, const char*, ...); + return getvfunc(this, 25)(this, MsgColor, szMsgFormat, Parameters...); + } +}; + +struct model_t +{ + void* fnHandle; + char szName[260]; + __int32 nLoadFlags; + __int32 nServerCount; + __int32 type; + __int32 flags; + Vector vecMins; + Vector vecMaxs; + float radius; + char pad[0x1C]; +}; + + +void AngleVectors(const Vector& angles, Vector* forward, Vector* right, Vector* up); + + + + +static int random(int min, int max) noexcept +{ + return rand() % (max - min + 1) + min; +} + + +enum Sequence +{ + SEQUENCE_DEFAULT_DRAW = 0, + SEQUENCE_DEFAULT_IDLE1 = 1, + SEQUENCE_DEFAULT_IDLE2 = 2, + SEQUENCE_DEFAULT_LIGHT_MISS1 = 3, + SEQUENCE_DEFAULT_LIGHT_MISS2 = 4, + SEQUENCE_DEFAULT_HEAVY_MISS1 = 9, + SEQUENCE_DEFAULT_HEAVY_HIT1 = 10, + SEQUENCE_DEFAULT_HEAVY_BACKSTAB = 11, + SEQUENCE_DEFAULT_LOOKAT01 = 12, + + SEQUENCE_BUTTERFLY_DRAW = 0, + SEQUENCE_BUTTERFLY_DRAW2 = 1, + SEQUENCE_BUTTERFLY_LOOKAT01 = 13, + SEQUENCE_BUTTERFLY_LOOKAT03 = 15, + + SEQUENCE_FALCHION_IDLE1 = 1, + SEQUENCE_FALCHION_HEAVY_MISS1 = 8, + SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP = 9, + SEQUENCE_FALCHION_LOOKAT01 = 12, + SEQUENCE_FALCHION_LOOKAT02 = 13, + + SEQUENCE_DAGGERS_IDLE1 = 1, + SEQUENCE_DAGGERS_LIGHT_MISS1 = 2, + SEQUENCE_DAGGERS_LIGHT_MISS5 = 6, + SEQUENCE_DAGGERS_HEAVY_MISS2 = 11, + SEQUENCE_DAGGERS_HEAVY_MISS1 = 12, + + SEQUENCE_BOWIE_IDLE1 = 1, +}; + + +void SetValueUnrestricted(const char* cvar, float value); +void SetIntUnrestricted(const char* cvar, int value); +void SetFloatUnrestricted(const char* cvar, float value); +float GetVisibleFloat(const char* cvar); +const char* GetVisibleValue(const char* cvar); + +static __declspec(naked) void __cdecl Invoke_NET_SetConVar(void* pfn, const char* cvar, const char* value) +{ + __asm + { + push ebp + mov ebp, esp + and esp, 0FFFFFFF8h + sub esp, 44h + push ebx + push esi + push edi + mov edi, cvar + mov esi, value + jmp pfn + } +} + +void NETSetConVar(const char* name, const char* value); + +void TextMsg(std::string text); +void ShowMenu(std::string text); +std::string GetName(int id); + +bool VoiceRecordStart(const char* pUncompressedFile); + + +#endif + +``` + +`SpyCustom/KeyValues.cpp`: + +```cpp +#include "sdk/keyvalues.h" +#include "sdk/IKeyValuesSystem.h" + +#include "Interfaces.hpp" + +void V_strncpy(char* pDest, char const* pSrc, int maxLen) +{ + strncpy(pDest, pSrc, maxLen); + if (maxLen > 0) + { + pDest[maxLen - 1] = 0; + } +} + +char* V_strncat(char* pDest, const char* pSrc, size_t destBufferSize, int max_chars_to_copy) +{ + size_t charstocopy = (size_t)0; + + size_t len = strlen(pDest); + size_t srclen = strlen(pSrc); + if (max_chars_to_copy <= COPY_ALL_CHARACTERS) + charstocopy = srclen; + else + charstocopy = (size_t)min(max_chars_to_copy, (int)srclen); + + if (len + charstocopy >= destBufferSize) + charstocopy = destBufferSize - len - 1; + + if ((int)charstocopy <= 0) + return pDest; + + ANALYZE_SUPPRESS(6059); + char* pOut = strncat(pDest, pSrc, charstocopy); + return pOut; +} + + +int _V_strcmp(const char* file, int line, const char* s1, const char* s2) +{ + return strcmp(s1, s2); +} + +int V_strncmp(const char* s1, const char* s2, int count) +{ + while (count > 0) + { + if (*s1 != *s2) + return (unsigned char)*s1 < (unsigned char)*s2 ? -1 : 1; + if (*s1 == '\0') + return 0; + s1++; + s2++; + count--; + } + + return 0; +} + +int V_stricmp(const char* str1, const char* str2) +{ + if (str1 == str2) + { + return 0; + } + const unsigned char* s1 = (const unsigned char*)str1; + const unsigned char* s2 = (const unsigned char*)str2; + for (; *s1; ++s1, ++s2) + { + if (*s1 != *s2) + { + unsigned char c1 = *s1 | 0x20; + unsigned char c2 = *s2 | 0x20; + if (c1 != c2 || (unsigned char)(c1 - 'a') > ('z' - 'a')) + { + if ((c1 | c2) >= 0x80) return stricmp((const char*)s1, (const char*)s2); + if ((unsigned char)(c1 - 'a') > ('z' - 'a')) c1 = *s1; + if ((unsigned char)(c2 - 'a') > ('z' - 'a')) c2 = *s2; + return c1 > c2 ? 1 : -1; + } + } + } + return *s2 ? -1 : 0; +} + +class CLeakTrack +{ +public: + CLeakTrack() + { + } + ~CLeakTrack() + { + if (keys.Count() != 0) + { + Assert(0); + } + } + + struct kve + { + KeyValues* kv; + char name[256]; + }; + + void AddKv(KeyValues* kv, char const* name) + { + kve k; + V_strncpy(k.name, name ? name : "NULL", sizeof(k.name)); + k.kv = kv; + + keys.AddToTail(k); + } + + void RemoveKv(KeyValues* kv) + { + int c = keys.Count(); + for (int i = 0; i < c; i++) + { + if (keys[i].kv == kv) + { + keys.Remove(i); + break; + } + } + } + + CUtlVector< kve > keys; +}; + + +static CLeakTrack track; + +void KeyValues::Init() +{ + m_iKeyName = 0; + m_iKeyNameCaseSensitive1 = 0; + m_iKeyNameCaseSensitive2 = 0; + m_iDataType = TYPE_NONE; + + m_pSub = NULL; + m_pPeer = NULL; + m_pChain = NULL; + + m_sValue = NULL; + m_wsValue = NULL; + m_pValue = NULL; + + m_bHasEscapeSequences = 0; +} + +void KeyValues::SetName(const char* setName) +{ + HKeySymbol hCaseSensitiveKeyName = INVALID_KEY_SYMBOL, hCaseInsensitiveKeyName = INVALID_KEY_SYMBOL; + hCaseSensitiveKeyName = iff.keyValuesSystem->GetSymbolForStringCaseSensitive(hCaseInsensitiveKeyName, setName); + + m_iKeyName = hCaseInsensitiveKeyName; + SPLIT_3_BYTES_INTO_1_AND_2(m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2, hCaseSensitiveKeyName); +} + +KeyValues::KeyValues(const char* setName) +{ + TRACK_KV_ADD(this, setName); + Init(); + SetName(setName); +} + +void* KeyValues::operator new(size_t iAllocSize) +{ + MEM_ALLOC_CREDIT(); + return iff.keyValuesSystem->AllocKeyValuesMemory(iAllocSize); +} + +void KeyValues::operator delete(void* pMem) +{ + iff.keyValuesSystem->FreeKeyValuesMemory((KeyValues*)pMem); +} + +#define TRACK_KV_ADD( ptr, name ) track.AddKv( ptr, name ) +#define TRACK_KV_REMOVE( ptr ) track.RemoveKv( ptr ) + + +KeyValues::~KeyValues() +{ + TRACK_KV_REMOVE(this); + RemoveEverything(); +} + +void KeyValues::RemoveEverything() +{ + KeyValues* dat; + KeyValues* datNext = NULL; + for (dat = m_pSub; dat != NULL; dat = datNext) + { + datNext = dat->m_pPeer; + dat->m_pPeer = NULL; + delete dat; + } + + for (dat = m_pPeer; dat && dat != this; dat = datNext) + { + datNext = dat->m_pPeer; + dat->m_pPeer = NULL; + delete dat; + } + + delete[] m_sValue; + m_sValue = NULL; + delete[] m_wsValue; + m_wsValue = NULL; +} + +char CUtlCharConversion::FindConversion(const char* pString, int* pLength) +{ + for (int i = 0; i < m_nCount; ++i) + { + if (!Q_strcmp(pString, m_pReplacements[(unsigned char)m_pList[i]].m_pReplacementString)) + { + *pLength = m_pReplacements[(unsigned char)m_pList[i]].m_nLength; + return m_pList[i]; + } + } + + *pLength = 0; + return '\0'; +} + +CUtlCharConversion::CUtlCharConversion(char nEscapeChar, const char* pDelimiter, int nCount, ConversionArray_t* pArray) +{ + m_nEscapeChar = nEscapeChar; + m_pDelimiter = pDelimiter; + m_nCount = nCount; + m_nDelimiterLength = Q_strlen(pDelimiter); + m_nMaxConversionLength = 0; + + memset(m_pReplacements, 0, sizeof(m_pReplacements)); + + for (int i = 0; i < nCount; ++i) + { + m_pList[i] = pArray[i].m_nActualChar; + ConversionInfo_t& info = m_pReplacements[(unsigned char)m_pList[i]]; + Assert(info.m_pReplacementString == 0); + info.m_pReplacementString = pArray[i].m_pReplacementString; + info.m_nLength = Q_strlen(info.m_pReplacementString); + if (info.m_nLength > m_nMaxConversionLength) + { + m_nMaxConversionLength = info.m_nLength; + } + } +} + +bool CUtlBuffer::OnGetOverflow(int nSize) +{ + return (this->*m_GetOverflowFunc)(nSize); +} + + +class CUtlCStringConversion : public CUtlCharConversion +{ +public: + CUtlCStringConversion(char nEscapeChar, const char* pDelimiter, int nCount, ConversionArray_t* pArray); + + virtual char FindConversion(const char* pString, int* pLength); + +private: + char m_pConversion[256]; +}; + +CUtlCStringConversion::CUtlCStringConversion(char nEscapeChar, const char* pDelimiter, int nCount, ConversionArray_t* pArray) : + CUtlCharConversion(nEscapeChar, pDelimiter, nCount, pArray) +{ + memset(m_pConversion, 0x0, sizeof(m_pConversion)); + for (int i = 0; i < nCount; ++i) + { + m_pConversion[(unsigned char)pArray[i].m_pReplacementString[0]] = pArray[i].m_nActualChar; + } +} + +char CUtlCStringConversion::FindConversion(const char* pString, int* pLength) +{ + char c = m_pConversion[(unsigned char)pString[0]]; + *pLength = (c != '\0') ? 1 : 0; + return c; +} + +bool CUtlBuffer::OnPutOverflow(int nSize) +{ + return (this->*m_PutOverflowFunc)(nSize); +} + +void CUtlBuffer::SetOverflowFuncs(UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc) +{ + m_GetOverflowFunc = getFunc; + m_PutOverflowFunc = putFunc; +} + +void CUtlBuffer::Get(void* pMem, int size) +{ + if (size > 0 && CheckGet(size)) + { + int Index = m_Get - m_nOffset; + Assert(m_Memory.IsIdxValid(Index) && m_Memory.IsIdxValid(Index + size - 1)); + + memcpy(pMem, &m_Memory[Index], size); + m_Get += size; + } +} + +void CUtlBuffer::GetString(char* pString, int nMaxChars) +{ + if (!IsValid()) + { + *pString = 0; + return; + } + + if (nMaxChars == 0) + { + nMaxChars = INT_MAX; + } + + int nLen = PeekStringLength(); + + if (IsText()) + { + EatWhiteSpace(); + } + + if (nLen == 0) + { + *pString = 0; + m_Error |= GET_OVERFLOW; + return; + } + + if (nLen <= nMaxChars) + { + Get(pString, nLen - 1); + pString[nLen - 1] = 0; + } + else + { + Get(pString, nMaxChars - 1); + pString[nMaxChars - 1] = 0; + SeekGet(SEEK_CURRENT, nLen - 1 - nMaxChars); + } + + if (!IsText()) + { + VerifyEquals(GetChar(), 0); + } +} + + +bool CUtlBuffer::CheckPut(int nSize) +{ + if ((m_Error & PUT_OVERFLOW) || IsReadOnly()) + return false; + + if ((m_Put < m_nOffset) || (m_Memory.NumAllocated() < m_Put - m_nOffset + nSize)) + { + if (!OnPutOverflow(nSize)) + { + m_Error |= PUT_OVERFLOW; + return false; + } + } + return true; +} + +char CUtlCharConversion::GetEscapeChar() const +{ + return m_nEscapeChar; +} + +int CUtlCharConversion::MaxConversionLength() const +{ + return m_nMaxConversionLength; +} + + +char CUtlBuffer::GetDelimitedCharInternal(CUtlCharConversion* pConv) +{ + char c = GetChar(); + if (c == pConv->GetEscapeChar()) + { + int nLength = pConv->MaxConversionLength(); + if (!CheckArbitraryPeekGet(0, nLength)) + return '\0'; + + c = pConv->FindConversion((const char*)PeekGet(), &nLength); + SeekGet(SEEK_CURRENT, nLength); + } + + return c; +} + +bool CUtlBuffer::PutOverflow(int nSize) +{ + MEM_ALLOC_CREDIT(); + + if (m_Memory.IsExternallyAllocated()) + { + if (!IsGrowable()) + return false; + + m_Memory.ConvertToGrowableMemory(0); + } + + while (Size() < m_Put - m_nOffset + nSize) + { + m_Memory.Grow(); + } + + return true; +} + +bool CUtlBuffer::GetOverflow(int nSize) +{ + return false; +} + +bool CUtlBuffer::PeekStringMatch(int nOffset, const char* pString, int nLen) +{ + if (!CheckPeekGet(nOffset, nLen)) + return false; + return !Q_strncmp((const char*)PeekGet(nOffset), pString, nLen); +} + +int CUtlBuffer::PeekWhiteSpace(int nOffset) +{ + if (!IsText() || !IsValid()) + return 0; + + while (CheckPeekGet(nOffset, sizeof(char))) + { + if (!isspace(*(unsigned char*)PeekGet(nOffset))) + break; + nOffset += sizeof(char); + } + + return nOffset; +} + +bool CUtlBuffer::CheckArbitraryPeekGet(int nOffset, int& nIncrement) +{ + if (TellGet() + nOffset >= TellMaxPut()) + { + nIncrement = 0; + return false; + } + + if (TellGet() + nOffset + nIncrement > TellMaxPut()) + { + nIncrement = TellMaxPut() - TellGet() - nOffset; + } + + CheckPeekGet(nOffset, nIncrement); + int nMaxGet = TellMaxPut() - TellGet(); + if (nMaxGet < nIncrement) + { + nIncrement = nMaxGet; + } + return (nIncrement != 0); +} + + + +int CUtlBuffer::PeekStringLength() +{ + if (!IsValid()) + return 0; + + int nOffset = 0; + if (IsText()) + { + nOffset = PeekWhiteSpace(nOffset); + } + + int nStartingOffset = nOffset; + + do + { + int nPeekAmount = 128; + + if (!CheckArbitraryPeekGet(nOffset, nPeekAmount)) + { + if (nOffset == nStartingOffset) + return 0; + return nOffset - nStartingOffset + 1; + } + + const char* pTest = (const char*)PeekGet(nOffset); + + if (!IsText()) + { + for (int i = 0; i < nPeekAmount; ++i) + { + if (pTest[i] == 0) + return (i + nOffset - nStartingOffset + 1); + } + } + else + { + for (int i = 0; i < nPeekAmount; ++i) + { + if (isspace((unsigned char)pTest[i]) || (pTest[i] == 0)) + return (i + nOffset - nStartingOffset + 1); + } + } + + nOffset += nPeekAmount; + + } while (true); +} + + +class CUtlNoEscConversion : public CUtlCharConversion +{ +public: + CUtlNoEscConversion(char nEscapeChar, const char* pDelimiter, int nCount, ConversionArray_t* pArray) : + CUtlCharConversion(nEscapeChar, pDelimiter, nCount, pArray) {} + + virtual char FindConversion(const char* pString, int* pLength) { *pLength = 0; return 0; } +}; + +BEGIN_CUSTOM_CHAR_CONVERSION(CUtlCStringConversion, s_StringCharConversion, (char*)"\"", '\\') + { '\n', (char*)"n" }, + { '\t', (char*)"t" }, + { '\v', (char*)"v" }, + { '\b', (char*)"b" }, + { '\r', (char*)"r" }, + { '\f', (char*)"f" }, + { '\a', (char*)"a" }, + { '\\', (char*)"\\" }, + { '\?', (char*)"\?" }, + { '\'', (char*)"\'" }, + { '\"', (char*)"\"" }, +END_CUSTOM_CHAR_CONVERSION(CUtlCStringConversion, s_StringCharConversion, (char*)"\"", '\\') + +CUtlCharConversion* GetCStringCharConversion() +{ + return &s_StringCharConversion; +} + +BEGIN_CUSTOM_CHAR_CONVERSION(CUtlNoEscConversion, s_NoEscConversion, (char*)"\"", 0x7F) + { + 0x7F, (char*)"" + }, +END_CUSTOM_CHAR_CONVERSION(CUtlNoEscConversion, s_NoEscConversion, (char*)"\"", 0x7F) + +CUtlCharConversion* GetNoEscCharConversion() +{ + return &s_NoEscConversion; +} + + +const char* CUtlCharConversion::GetDelimiter() const +{ + return m_pDelimiter; +} + +int CUtlCharConversion::GetDelimiterLength() const +{ + return m_nDelimiterLength; +} + +void CUtlBuffer::AddNullTermination(int m) +{ + if (m_Put > m_nMaxPut) + { + if (!IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0)) + { + if (CheckPut(1)) + { + int Index = m_Put - m_nOffset; + Assert(m_Memory.IsIdxValid(Index)); + if (Index >= 0) + { + m_Memory[Index] = 0; + } + } + else + { + m_Error &= ~PUT_OVERFLOW; + } + } + m_nMaxPut = m_Put; + } +} + +CUtlBuffer::CUtlBuffer(int growSize, int initSize, int nFlags) : + m_Error(0) +{ + MEM_ALLOC_CREDIT(); + m_Memory.Init(growSize, initSize); + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_nOffset = 0; + m_Flags = nFlags; + if ((initSize != 0) && !IsReadOnly()) + { + m_nMaxPut = -1; + AddNullTermination(0); + } + else + { + m_nMaxPut = 0; + } + SetOverflowFuncs(&CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow); +} + +CUtlBuffer::CUtlBuffer(const void* pBuffer, int nSize, int nFlags) : + m_Memory((unsigned char*)pBuffer, nSize), m_Error(0) +{ + Assert(nSize != 0); + + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_nOffset = 0; + m_Flags = nFlags; + if (IsReadOnly()) + { + m_nMaxPut = nSize; + } + else + { + m_nMaxPut = -1; + AddNullTermination(0); + } + SetOverflowFuncs(&CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow); +} + + +void CUtlBuffer::GetDelimitedString(CUtlCharConversion* pConv, char* pString, int nMaxChars) +{ + if (!IsText() || !pConv) + { + GetString(pString, nMaxChars); + return; + } + + if (!IsValid()) + { + *pString = 0; + return; + } + + if (nMaxChars == 0) + { + nMaxChars = INT_MAX; + } + + EatWhiteSpace(); + if (!PeekStringMatch(0, pConv->GetDelimiter(), pConv->GetDelimiterLength())) + return; + + SeekGet(SEEK_CURRENT, pConv->GetDelimiterLength()); + + int nRead = 0; + while (IsValid()) + { + if (PeekStringMatch(0, pConv->GetDelimiter(), pConv->GetDelimiterLength())) + { + SeekGet(SEEK_CURRENT, pConv->GetDelimiterLength()); + break; + } + + char c = GetDelimitedCharInternal(pConv); + + if (nRead < nMaxChars) + { + pString[nRead] = c; + ++nRead; + } + } + + if (nRead >= nMaxChars) + { + nRead = nMaxChars - 1; + } + pString[nRead] = '\0'; +} + +void CUtlBuffer::EatWhiteSpace() +{ + if (IsText() && IsValid()) + { + while (CheckGet(sizeof(char))) + { + if (!isspace(*(const unsigned char*)PeekGet())) + break; + m_Get += sizeof(char); + } + } +} +bool CUtlBuffer::EatCPPComment() +{ + if (IsText() && IsValid()) + { + const char* pPeek = (const char*)PeekGet(2 * sizeof(char), 0); + if (!pPeek || (pPeek[0] != '/') || (pPeek[1] != '/')) + return false; + + m_Get += 2; + + for (char c = GetChar(); IsValid(); c = GetChar()) + { + if (c == '\n') + break; + } + return true; + } + return false; +} + +bool CUtlBuffer::CheckGet(int nSize) +{ + if (m_Error & GET_OVERFLOW) + return false; + + if (TellMaxPut() < m_Get + nSize) + { + m_Error |= GET_OVERFLOW; + return false; + } + + if ((m_Get < m_nOffset) || (m_Memory.NumAllocated() < m_Get - m_nOffset + nSize)) + { + if (!OnGetOverflow(nSize)) + { + m_Error |= GET_OVERFLOW; + return false; + } + } + + return true; +} + + +bool CUtlBuffer::CheckPeekGet(int nOffset, int nSize) +{ + if (m_Error & GET_OVERFLOW) + return false; + + bool bOk = CheckGet(nOffset + nSize); + m_Error &= ~GET_OVERFLOW; + return bOk; +} + +const void* CUtlBuffer::PeekGet(int nMaxSize, int nOffset) +{ + if (!CheckPeekGet(nOffset, nMaxSize)) + return NULL; + + int Index = m_Get + nOffset - m_nOffset; + Assert(m_Memory.IsIdxValid(Index) && m_Memory.IsIdxValid(Index + nMaxSize - 1)); + + return &m_Memory[Index]; +} + +void CUtlBuffer::SeekGet(SeekType_t type, int offset) +{ + switch (type) + { + case SEEK_HEAD: + m_Get = offset; + break; + + case SEEK_CURRENT: + m_Get += offset; + break; + + case SEEK_TAIL: + m_Get = m_nMaxPut - offset; + break; + } + + if (m_Get > m_nMaxPut) + { + m_Error |= GET_OVERFLOW; + } + else + { + m_Error &= ~GET_OVERFLOW; + if (m_Get < m_nOffset || m_Get >= m_nOffset + Size()) + { + OnGetOverflow(-1); + } + } +} + + + +void KeyValues::Clear(void) +{ + delete m_pSub; + m_pSub = NULL; + m_iDataType = TYPE_NONE; +} + +void KeyValues::deleteThis() +{ + delete this; +} + + +KeyValues* KeyValues::CreateKey(const char* keyName) +{ + KeyValues* dat = new KeyValues(keyName); + dat->UsesEscapeSequences(m_bHasEscapeSequences != 0); + AddSubKey(dat); + return dat; +} + + +void KeyValues::AddSubKey(KeyValues* pSubkey) +{ + Assert(pSubkey->m_pPeer == NULL); + + if (m_pSub == NULL) + { + m_pSub = pSubkey; + } + else + { + KeyValues* pTempDat = m_pSub; + while (pTempDat->GetNextKey() != NULL) + { + pTempDat = pTempDat->GetNextKey(); + } + + pTempDat->SetNextKey(pSubkey); + } +} + + +void KeyValues::RemoveSubKey(KeyValues* subKey) +{ + if (!subKey) + return; + + if (m_pSub == subKey) + { + m_pSub = subKey->m_pPeer; + } + else + { + KeyValues* kv = m_pSub; + while (kv->m_pPeer) + { + if (kv->m_pPeer == subKey) + { + kv->m_pPeer = subKey->m_pPeer; + break; + } + + kv = kv->m_pPeer; + } + } + + subKey->m_pPeer = NULL; +} + +static char* s_LastFileLoadingFrom = ( char*)"unknown"; + + +void KeyValues::UsesEscapeSequences(bool state) +{ + m_bHasEscapeSequences = state; +} + + +int V_snprintf(char* pDest, int maxLen, char const* pFormat, ...) +{ + Assert(maxLen >= 0); + AssertValidWritePtr(pDest, maxLen); + va_list marker; + + va_start(marker, pFormat); +#ifdef _WIN32 + int len = _vsnprintf(pDest, maxLen, pFormat, marker); +#elif defined _LINUX || defined __APPLE__ + int len = vsnprintf(pDest, maxLen, pFormat, marker); +#else +#error "define vsnprintf type." +#endif + va_end(marker); + + if (len < 0) + { + len = maxLen; + pDest[maxLen - 1] = 0; + } + + return len; +} + + +int V_vsnprintf(char* pDest, int maxLen, char const* pFormat, va_list params) +{ + Assert(maxLen > 0); + AssertValidWritePtr(pDest, maxLen); + int len = _vsnprintf(pDest, maxLen, pFormat, params); + + if (len < 0) + { + len = maxLen; + pDest[maxLen - 1] = 0; + } + + return len; +} + +KeyValues* KeyValues::FindKey(int keySymbol) const +{ + for (KeyValues* dat = m_pSub; dat != NULL; dat = dat->m_pPeer) + { + if (dat->m_iKeyName == keySymbol) + return dat; + } + + return NULL; +} + + +int (*KeyValues::s_pfGetSymbolForString)(const char* name, bool bCreate) = &KeyValues::GetSymbolForStringClassic; +const char* (*KeyValues::s_pfGetStringForSymbol)(int symbol) = &KeyValues::GetStringForSymbolClassic; +CKeyValuesGrowableStringTable* KeyValues::s_pGrowableStringTable = NULL; + +int KeyValues::GetSymbolForStringClassic(const char* name, bool bCreate) +{ + return iff.keyValuesSystem->GetSymbolForString(name, bCreate); +} + +const char* KeyValues::GetStringForSymbolClassic(int symbol) +{ + return iff.keyValuesSystem->GetStringForSymbol(symbol); +} + +KeyValues* KeyValues::GetNextTrueSubKey() +{ + KeyValues* pRet = m_pPeer; + while (pRet && pRet->m_iDataType != TYPE_NONE) + pRet = pRet->m_pPeer; + + return pRet; +} + + +KeyValues* KeyValues::FindKey(const char* keyName, bool bCreate) +{ + if (!keyName || !keyName[0]) + return this; + + char szBuf[256]; + const char* subStr = strchr(keyName, '/'); + const char* searchStr = keyName; + + if (subStr) + { + int size = subStr - keyName; + Q_memcpy(szBuf, keyName, size); + szBuf[size] = 0; + searchStr = szBuf; + } + + HKeySymbol iSearchStr = s_pfGetSymbolForString(searchStr, bCreate); + + if (iSearchStr == INVALID_KEY_SYMBOL) + { + return NULL; + } + + KeyValues* lastItem = NULL; + KeyValues* dat; + for (dat = m_pSub; dat != NULL; dat = dat->m_pPeer) + { + lastItem = dat; + + if (dat->m_iKeyName == iSearchStr) + { + break; + } + } + + if (!dat && m_pChain) + { + dat = m_pChain->FindKey(keyName, false); + } + + if (!dat) + { + if (bCreate) + { + dat = new KeyValues(searchStr); + dat->UsesEscapeSequences(m_bHasEscapeSequences != 0); + if (lastItem) + { + lastItem->m_pPeer = dat; + } + else + { + m_pSub = dat; + } + dat->m_pPeer = NULL; + + m_iDataType = TYPE_NONE; + } + else + { + return NULL; + } + } + + if (subStr) + { + return dat->FindKey(subStr + 1, bCreate); + } + + return dat; +} + +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 = Q_strlen(value); + dat->m_sValue = new char[len + 1]; + Q_memcpy(dat->m_sValue, value, len + 1); + + dat->m_iDataType = TYPE_STRING; + } +} + + +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: + Q_snprintf(buf, sizeof(buf), "%f", dat->m_flValue); + SetString(keyName, buf); + break; + case TYPE_INT: + case TYPE_PTR: + Q_snprintf(buf, sizeof(buf), "%d", dat->m_iValue); + SetString(keyName, buf); + break; + case TYPE_UINT64: + Q_snprintf(buf, sizeof(buf), "%lld", *((uint64*)(dat->m_sValue))); + SetString(keyName, buf); + break; + + case TYPE_WSTRING: + { + char wideBuf[512]; + int result = Q_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 char* KeyValues::GetName(void) const +{ + return iff.keyValuesSystem->GetStringForSymbol(m_iKeyName); +} + +int KeyValues::GetNameSymbol() const +{ + return m_iKeyName; +} + +bool KeyValues::LoadFromFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID) +{ + Assert(filesystem); + Assert(IsX360() || (IsPC() && _heapchk() == _HEAPOK)); + + FileHandle_t f = iff.g_pFullFileSystem->Open(resourceName, "rb", pathID); + if (!f) + return false; + + s_LastFileLoadingFrom = (char*)resourceName; + + int fileSize = filesystem->Size(f); + unsigned bufSize = ((IFileSystem*)filesystem)->GetOptimalReadSize(f, fileSize + 1); + + char* buffer = (char*)((IFileSystem*)filesystem)->AllocOptimalReadBuffer(f, bufSize); + Assert(buffer); + + bool bRetOK = (((IFileSystem*)filesystem)->ReadEx(buffer, bufSize, fileSize, f) != 0); + + filesystem->Close(f); + + if (bRetOK) + { + buffer[fileSize] = 0; + bRetOK = LoadFromBuffer(resourceName, buffer, filesystem); + } + + ((IFileSystem*)filesystem)->FreeOptimalReadBuffer(buffer); + + return bRetOK; +} + +void KeyValues::SetNextKey(KeyValues* pDat) +{ + m_pPeer = pDat; +} + +void KeyValues::CopySubkeys(KeyValues* pParent) const +{ + KeyValues* pPrev = NULL; + for (KeyValues* sub = m_pSub; sub != NULL; sub = sub->m_pPeer) + { + KeyValues* dat = sub->MakeCopy(); + + if (pPrev) + pPrev->m_pPeer = dat; + else + pParent->m_pSub = dat; + dat->m_pPeer = NULL; + pPrev = dat; + } +} + +KeyValues* KeyValues::MakeCopy(void) const +{ + KeyValues* newKeyValue = new KeyValues(GetName()); + + newKeyValue->m_iDataType = m_iDataType; + switch (m_iDataType) + { + case TYPE_STRING: + { + if (m_sValue) + { + int len = Q_strlen(m_sValue); + Assert(!newKeyValue->m_sValue); + newKeyValue->m_sValue = new char[len + 1]; + Q_memcpy(newKeyValue->m_sValue, m_sValue, len + 1); + } + } + break; + case TYPE_WSTRING: + { + if (m_wsValue) + { + int len = wcslen(m_wsValue); + newKeyValue->m_wsValue = new wchar_t[len + 1]; + Q_memcpy(newKeyValue->m_wsValue, m_wsValue, (len + 1) * sizeof(wchar_t)); + } + } + break; + + case TYPE_INT: + newKeyValue->m_iValue = m_iValue; + break; + + case TYPE_FLOAT: + newKeyValue->m_flValue = m_flValue; + break; + + case TYPE_PTR: + newKeyValue->m_pValue = m_pValue; + break; + + case TYPE_COLOR: + newKeyValue->m_Color[0] = m_Color[0]; + newKeyValue->m_Color[1] = m_Color[1]; + newKeyValue->m_Color[2] = m_Color[2]; + newKeyValue->m_Color[3] = m_Color[3]; + break; + + case TYPE_UINT64: + newKeyValue->m_sValue = new char[sizeof(uint64)]; + Q_memcpy(newKeyValue->m_sValue, m_sValue, sizeof(uint64)); + break; + }; + + CopySubkeys(newKeyValue); + return newKeyValue; +} + + + +const int MAX_ERROR_STACK = 64; +class CKeyValuesErrorStack +{ +public: + CKeyValuesErrorStack() : m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0) {} + + void SetFilename(const char* pFilename) + { + m_pFilename = pFilename; + m_maxErrorIndex = 0; + } + + int Push(int symName) + { + if (m_errorIndex < MAX_ERROR_STACK) + { + m_errorStack[m_errorIndex] = symName; + } + m_errorIndex++; + m_maxErrorIndex = max(m_maxErrorIndex, (m_errorIndex - 1)); + return m_errorIndex - 1; + } + + void Pop() + { + m_errorIndex--; + Assert(m_errorIndex >= 0); + } + + void Reset(int stackLevel, int symName) + { + Assert(stackLevel >= 0 && stackLevel < m_errorIndex); + m_errorStack[stackLevel] = symName; + } + + void ReportError(const char* pError) + { + printfdbg("KeyValues Error: %s in file %s\n", pError, m_pFilename); + for (int i = 0; i < m_maxErrorIndex; i++) + { + if (m_errorStack[i] != INVALID_KEY_SYMBOL) + { + if (i < m_errorIndex) + { + printfdbg("%s, ", iff.keyValuesSystem->GetStringForSymbol(m_errorStack[i])); + } + else + { + printfdbg("(*%s*), ", iff.keyValuesSystem->GetStringForSymbol(m_errorStack[i])); + } + } + } + printfdbg("\n"); + } + +private: + int m_errorStack[MAX_ERROR_STACK]; + const char* m_pFilename; + int m_errorIndex; + int m_maxErrorIndex; +} g_KeyValuesErrorStack; + + +class CKeyErrorContext +{ +public: + CKeyErrorContext(KeyValues* pKv) + { + Init(pKv->GetNameSymbol()); + } + + ~CKeyErrorContext() + { + g_KeyValuesErrorStack.Pop(); + } + CKeyErrorContext(int symName) + { + Init(symName); + } + void Reset(int symName) + { + g_KeyValuesErrorStack.Reset(m_stackLevel, symName); + } +private: + void Init(int symName) + { + m_stackLevel = g_KeyValuesErrorStack.Push(symName); + } + + int m_stackLevel; +}; + + +void KeyValues::RecursiveLoadFromBuffer(char const* resourceName, CUtlBuffer& buf) +{ + CKeyErrorContext errorReport(this); + bool wasQuoted; + bool wasConditional; + CKeyErrorContext errorKey(INVALID_KEY_SYMBOL); + while (1) + { + bool bAccepted = true; + + const char* name = ReadToken(buf, wasQuoted, wasConditional); + + if (!name) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got EOF instead of keyname"); + break; + } + + if (!*name) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got empty keyname"); + break; + } + + if (*name == '}' && !wasQuoted) + break; + + KeyValues* dat = CreateKey(name); + + errorKey.Reset(dat->GetNameSymbol()); + + const char* value = ReadToken(buf, wasQuoted, wasConditional); + + if (wasConditional && value) + { + bAccepted = EvaluateConditional(value); + + value = ReadToken(buf, wasQuoted, wasConditional); + } + + if (!value) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got NULL key"); + break; + } + + if (*value == '}' && !wasQuoted) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got } in key"); + break; + } + + if (*value == '{' && !wasQuoted) + { + errorKey.Reset(INVALID_KEY_SYMBOL); + dat->RecursiveLoadFromBuffer(resourceName, buf); + } + else + { + if (wasConditional) + { + g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got conditional between key and value"); + break; + } + + if (dat->m_sValue) + { + delete[] dat->m_sValue; + dat->m_sValue = NULL; + } + + int len = Q_strlen(value); + + char* pIEnd; + char* pFEnd; + const char* pSEnd = value + len; + + int ival = strtol(value, &pIEnd, 10); + float fval = (float)strtod(value, &pFEnd); + + if (*value == 0) + { + dat->m_iDataType = TYPE_STRING; + } + else if ((18 == len) && (value[0] == '0') && (value[1] == 'x')) + { + int64 retVal = 0; + for (int i = 2; i < 2 + 16; i++) + { + char digit = value[i]; + if (digit >= 'a') + digit -= 'a' - ('9' + 1); + else + if (digit >= 'A') + digit -= 'A' - ('9' + 1); + retVal = (retVal * 16) + (digit - '0'); + } + dat->m_sValue = new char[sizeof(uint64)]; + *((uint64*)dat->m_sValue) = retVal; + dat->m_iDataType = TYPE_UINT64; + } + else if ((pFEnd > pIEnd) && (pFEnd == pSEnd)) + { + dat->m_flValue = fval; + dat->m_iDataType = TYPE_FLOAT; + } + else if (pIEnd == pSEnd) + { + dat->m_iValue = ival; + dat->m_iDataType = TYPE_INT; + } + else + { + dat->m_iDataType = TYPE_STRING; + } + + if (dat->m_iDataType == TYPE_STRING) + { + dat->m_sValue = new char[len + 1]; + Q_memcpy(dat->m_sValue, value, len + 1); + } + + int prevPos = buf.TellGet(); + const char* peek = ReadToken(buf, wasQuoted, wasConditional); + if (wasConditional) + { + bAccepted = EvaluateConditional(peek); + } + else + { + buf.SeekGet(CUtlBuffer::SEEK_HEAD, prevPos); + } + } + + if (!bAccepted) + { + this->RemoveSubKey(dat); + dat->deleteThis(); + dat = NULL; + } + } +} + + +void KeyValues::AppendIncludedKeys(CUtlVector< KeyValues* >& includedKeys) +{ + int includeCount = includedKeys.Count(); + int i; + for (i = 0; i < includeCount; i++) + { + KeyValues* kv = includedKeys[i]; + Assert(kv); + + KeyValues* insertSpot = this; + while (insertSpot->GetNextKey()) + { + insertSpot = insertSpot->GetNextKey(); + } + + insertSpot->SetNextKey(kv); + } +} + +void KeyValues::RecursiveMergeKeyValues(KeyValues* baseKV) +{ + for (KeyValues* baseChild = baseKV->m_pSub; baseChild != NULL; baseChild = baseChild->m_pPeer) + { + bool bFoundMatch = false; + + for (KeyValues* newChild = m_pSub; newChild != NULL; newChild = newChild->m_pPeer) + { + if (!Q_strcmp(baseChild->GetName(), newChild->GetName())) + { + newChild->RecursiveMergeKeyValues(baseChild); + bFoundMatch = true; + break; + } + } + + if (!bFoundMatch) + { + KeyValues* dat = baseChild->MakeCopy(); + Assert(dat); + AddSubKey(dat); + } + } +} + +bool KeyValues::EvaluateConditional(const char* str) +{ + bool bResult = false; + bool bXboxUI = IsX360(); + + if (bXboxUI) + { + bResult = !Q_stricmp("[$X360]", str); + } + else + { + bResult = !Q_stricmp("[$WIN32]", str); + } + + return bResult; +} + +void KeyValues::MergeBaseKeys(CUtlVector< KeyValues* >& baseKeys) +{ + int includeCount = baseKeys.Count(); + int i; + for (i = 0; i < includeCount; i++) + { + KeyValues* kv = baseKeys[i]; + Assert(kv); + + RecursiveMergeKeyValues(kv); + } +} + + +void KeyValues::ParseIncludedKeys(char const* resourceName, const char* filetoinclude, + IBaseFileSystem* pFileSystem, const char* pPathID, CUtlVector< KeyValues* >& includedKeys) +{ + Assert(resourceName); + Assert(filetoinclude); + Assert(pFileSystem); + if (!pFileSystem) + { + return; + } + char fullpath[512]; + Q_strncpy(fullpath, resourceName, sizeof(fullpath)); + bool done = false; + int len = Q_strlen(fullpath); + while (!done) + { + if (len <= 0) + { + break; + } + + if (fullpath[len - 1] == '\\' || + fullpath[len - 1] == '/') + { + break; + } + + fullpath[len - 1] = 0; + --len; + } + + Q_strncat(fullpath, filetoinclude, sizeof(fullpath), COPY_ALL_CHARACTERS); + + KeyValues* newKV = new KeyValues(fullpath); + + newKV->UsesEscapeSequences(m_bHasEscapeSequences != 0); + + if (newKV->LoadFromFile(pFileSystem, fullpath, pPathID)) + { + includedKeys.AddToTail(newKV); + } + else + { + printfdbg("KeyValues::ParseIncludedKeys: Couldn't load included keyvalue file %s\n", fullpath); + newKV->deleteThis(); + } + +} + + + + + + + int V_UnicodeToUTF8(const wchar_t* pUnicode, char* pUTF8, int cubDestSizeInBytes) + { + AssertValidReadPtr(pUnicode); + + if (cubDestSizeInBytes > 0) + { + pUTF8[0] = 0; + } + +#ifdef _WIN32 + int cchResult = WideCharToMultiByte(CP_UTF8, 0, pUnicode, -1, pUTF8, cubDestSizeInBytes, NULL, NULL); +#elif POSIX + int cchResult = 0; + if (pUnicode && pUTF8) + cchResult = wcstombs(pUTF8, pUnicode, cubDestSizeInBytes) + 1; +#endif + + if (cubDestSizeInBytes > 0) + { + pUTF8[cubDestSizeInBytes - 1] = 0; + } + + return cchResult; + } + + + +#define KEYVALUES_TOKEN_SIZE 1024 +static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE]; + +#pragma warning (disable:4706) +const char* KeyValues::ReadToken(CUtlBuffer& buf, bool& wasQuoted, bool& wasConditional) +{ + wasQuoted = false; + wasConditional = false; + + if (!buf.IsValid()) + return NULL; + + while (true) + { + buf.EatWhiteSpace(); + if (!buf.IsValid()) + return NULL; + + if (!buf.EatCPPComment()) + break; + } + + const char* c = (const char*)buf.PeekGet(sizeof(char), 0); + if (!c) + return NULL; + + if (*c == '\"') + { + wasQuoted = true; + buf.GetDelimitedString(m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(), + s_pTokenBuf, KEYVALUES_TOKEN_SIZE); + return s_pTokenBuf; + } + + if (*c == '{' || *c == '}') + { + s_pTokenBuf[0] = *c; + s_pTokenBuf[1] = 0; + buf.SeekGet(CUtlBuffer::SEEK_CURRENT, 1); + return s_pTokenBuf; + } + + bool bReportedError = false; + bool bConditionalStart = false; + int nCount = 0; + while (c = (const char*)buf.PeekGet(sizeof(char), 0)) + { + if (*c == 0) + break; + + if (*c == '"' || *c == '{' || *c == '}') + break; + + if (*c == '[') + bConditionalStart = true; + + if (*c == ']' && bConditionalStart) + { + wasConditional = true; + } + + if (isspace(*c)) + break; + + if (nCount < (KEYVALUES_TOKEN_SIZE - 1)) + { + s_pTokenBuf[nCount++] = *c; + } + else if (!bReportedError) + { + bReportedError = true; + g_KeyValuesErrorStack.ReportError(" ReadToken overflow"); + } + + buf.SeekGet(CUtlBuffer::SEEK_CURRENT, 1); + } + s_pTokenBuf[nCount] = 0; + return s_pTokenBuf; +} +#pragma warning (default:4706) + + +bool KeyValues::LoadFromBuffer(char const* resourceName, CUtlBuffer& buf, IBaseFileSystem* pFileSystem, const char* pPathID) +{ + KeyValues* pPreviousKey = NULL; + KeyValues* pCurrentKey = this; + CUtlVector< KeyValues* > includedKeys; + CUtlVector< KeyValues* > baseKeys; + bool wasQuoted; + bool wasConditional; + g_KeyValuesErrorStack.SetFilename(resourceName); + do + { + bool bAccepted = true; + + const char* s = ReadToken(buf, wasQuoted, wasConditional); + if (!buf.IsValid() || !s || *s == 0) + break; + + if (!Q_stricmp(s, "#include")) + { + s = ReadToken(buf, wasQuoted, wasConditional); + if (!s || *s == 0) + { + g_KeyValuesErrorStack.ReportError("#include is NULL "); + } + else + { + ParseIncludedKeys(resourceName, s, pFileSystem, pPathID, includedKeys); + } + + continue; + } + else if (!Q_stricmp(s, "#base")) + { + s = ReadToken(buf, wasQuoted, wasConditional); + if (!s || *s == 0) + { + g_KeyValuesErrorStack.ReportError("#base is NULL "); + } + else + { + ParseIncludedKeys(resourceName, s, pFileSystem, pPathID, baseKeys); + } + + continue; + } + + if (!pCurrentKey) + { + pCurrentKey = new KeyValues(s); + Assert(pCurrentKey); + + pCurrentKey->UsesEscapeSequences(m_bHasEscapeSequences != 0); + + if (pPreviousKey) + { + pPreviousKey->SetNextKey(pCurrentKey); + } + } + else + { + pCurrentKey->SetName(s); + } + + s = ReadToken(buf, wasQuoted, wasConditional); + + if (wasConditional) + { + bAccepted = EvaluateConditional(s); + + s = ReadToken(buf, wasQuoted, wasConditional); + } + + if (s && *s == '{' && !wasQuoted) + { + pCurrentKey->RecursiveLoadFromBuffer(resourceName, buf); + } + else + { + g_KeyValuesErrorStack.ReportError("LoadFromBuffer: missing {"); + } + + if (!bAccepted) + { + if (pPreviousKey) + { + pPreviousKey->SetNextKey(NULL); + } + pCurrentKey->Clear(); + } + else + { + pPreviousKey = pCurrentKey; + pCurrentKey = NULL; + } + } while (buf.IsValid()); + + AppendIncludedKeys(includedKeys); + { + int i; + for (i = includedKeys.Count() - 1; i > 0; i--) + { + KeyValues* kv = includedKeys[i]; + kv->deleteThis(); + } + } + + MergeBaseKeys(baseKeys); + { + int i; + for (i = baseKeys.Count() - 1; i >= 0; i--) + { + KeyValues* kv = baseKeys[i]; + kv->deleteThis(); + } + } + + g_KeyValuesErrorStack.SetFilename(""); + + return true; +} + + +bool KeyValues::LoadFromBuffer(char const* resourceName, const char* pBuffer, IBaseFileSystem* pFileSystem, const char* pPathID) +{ + if (!pBuffer) + return true; + + int nLen = Q_strlen(pBuffer); + CUtlBuffer buf(pBuffer, nLen, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER); + return LoadFromBuffer(resourceName, buf, pFileSystem, pPathID); +} + +``` + +`SpyCustom/Menu.hpp`: + +```hpp +#pragma once + +LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +struct vertex { + FLOAT x, y, z, + rhw; + DWORD color; +}; + +void DrawCircle(IDirect3DDevice9* p_Device, float x, float y, float rad, float rotate, int resolution, DWORD color) +{ + vector circle(resolution + 2); + float angle = rotate * PI / 180; + + circle[0].x = x - rad; + circle[0].y = y; + circle[0].z = 0; + circle[0].rhw = 1; + circle[0].color = color; + + for (int i = 1; i < resolution + 2; i++) + { + circle[i].x = (float)(x - rad * cos(PI * ((i - 1) / (resolution / 2.0f)))); + circle[i].y = (float)(y - rad * sin(PI * ((i - 1) / (resolution / 2.0f)))); + circle[i].z = 0; + circle[i].rhw = 1; + circle[i].color = color; + } + + // Rotate matrix + int _res = resolution + 2; + for (int i = 0; i < _res; i++) + { + circle[i].x = x + cos(angle) * (circle[i].x - x) - sin(angle) * (circle[i].y - y); + circle[i].y = y + sin(angle) * (circle[i].x - x) + cos(angle) * (circle[i].y - y); + } + + p_Device->CreateVertexBuffer((resolution + 2) * sizeof(vertex), D3DUSAGE_WRITEONLY, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &v_buffer, NULL); + + VOID* pVertices; + v_buffer->Lock(0, (resolution + 2) * sizeof(vertex), (void**)&pVertices, 0); + memcpy(pVertices, &circle[0], (resolution + 2) * sizeof(vertex)); + v_buffer->Unlock(); + + p_Device->SetTexture(0, NULL); + p_Device->SetPixelShader(NULL); + p_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + p_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + p_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + p_Device->SetStreamSource(0, v_buffer, 0, sizeof(vertex)); + p_Device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + p_Device->DrawPrimitive(D3DPT_LINESTRIP, 0, resolution); + if (v_buffer != NULL) v_buffer->Release(); +} + +IMaterial* CreateMaterial(std::string matname, std::string mat_data = "") +{ + KeyValues* keyValues = new KeyValues(matname.c_str()); + keyValues->Init(); + keyValues->LoadFromBuffer(matname.c_str(), mat_data.c_str()); + IMaterial* newmat = iff.g_pMaterialSystem->CreateMaterial(matname.c_str(), keyValues); + printfdbg("Material %s created\n", matname.c_str()); + return newmat; +} + +void wfsmoke(bool on = 1) noexcept +{ + constexpr std::array smokeMaterials{ + "particle/vistasmokev1/vistasmokev1_emods", + "particle/vistasmokev1/vistasmokev1_emods_impactdust", + "particle/vistasmokev1/vistasmokev1_fire", + "particle/vistasmokev1/vistasmokev1_smokegrenade" + }; + + if (on) + { + if (!*g_Options.wfsmoke) return; + + for (const auto mat : smokeMaterials) { + const auto material = iff.g_pMaterialSystem->FindMaterial(mat, TEXTURE_GROUP_PARTICLE); + material->SetMaterialVarFlag(MATERIAL_VAR_WIREFRAME, true); + } + } + else + { + for (const auto mat : smokeMaterials) { + const auto material = iff.g_pMaterialSystem->FindMaterial(mat, TEXTURE_GROUP_PARTICLE); + material->SetMaterialVarFlag(MATERIAL_VAR_WIREFRAME, false); + } + } +} + +void colorWorld(bool on = 1) noexcept +{ + + if (on) { + if (!*g_Options.worldcoloractive) return; + + iff.g_pCVar->FindVar("r_drawspecificstaticprop")->SetValue(false); + + for (MaterialHandle_t h = iff.g_pMaterialSystem->FirstMaterial(); h != iff.g_pMaterialSystem->InvalidMaterial(); h = iff.g_pMaterialSystem->NextMaterial(h)) { + IMaterial* pMaterial = iff.g_pMaterialSystem->GetMaterial(h); + if (!pMaterial || !pMaterial->IsPrecached()) + continue; + const char* textureGroup = pMaterial->GetTextureGroupName(); + if (strstr(textureGroup, "World textures")) + pMaterial->ColorModulate(g_Options.worldcolor.value->r, g_Options.worldcolor.value->g, g_Options.worldcolor.value->b); + if (strstr(textureGroup, "StaticProp")) + pMaterial->ColorModulate(g_Options.staticpropcolor.value->r, g_Options.staticpropcolor.value->g, g_Options.staticpropcolor.value->b); + if (strstr(textureGroup, "SkyBox")) + pMaterial->ColorModulate(g_Options.staticpropcolor.value->r, g_Options.staticpropcolor.value->g, g_Options.staticpropcolor.value->b); + if (strstr(textureGroup, "Model")) + pMaterial->ColorModulate(g_Options.modelcolor.value->r, g_Options.modelcolor.value->g, g_Options.modelcolor.value->b); + + } + + } + else + { + iff.g_pCVar->FindVar("r_drawspecificstaticprop")->SetValue(true); + + for (MaterialHandle_t h = iff.g_pMaterialSystem->FirstMaterial(); h != iff.g_pMaterialSystem->InvalidMaterial(); h = iff.g_pMaterialSystem->NextMaterial(h)) { + IMaterial* pMaterial = iff.g_pMaterialSystem->GetMaterial(h); + if (!pMaterial || !pMaterial->IsPrecached()) + continue; + const char* textureGroup = pMaterial->GetTextureGroupName(); + if (strstr(textureGroup, "World textures")) + pMaterial->ColorModulate(1.0f, 1.0f, 1.0f); + if (strstr(textureGroup, "StaticProp")) + pMaterial->ColorModulate(1.0f, 1.0f, 1.0f); + if (strstr(textureGroup, "Model")) + pMaterial->ColorModulate(1.0f, 1.0f, 1.0f); + } + + } +} + +void ResetMisc() +{ + float f0 = 0, fm1 = -1.0f, f1 = 1.0f, f60 = 60.0f, f90 = 90.0f, f600 = 600.0f; + SetValueUnrestricted("r_aspectratio", 0); memcpy(g_Options.aspectratio, &f0, 4); + SetValueUnrestricted("mat_postprocess_enable", 1); memcpy(g_Options.postproc, &f0, 4); + SetValueUnrestricted("cl_csm_enabled", 1); memcpy(g_Options.shadows, &f0, 4); + SetValueUnrestricted("mat_fullbright", 0); memcpy(g_Options.fullbright, &f0, 4); + SetValueUnrestricted("mat_drawgray", 0); memcpy(g_Options.drawgray, &f0, 4); + SetValueUnrestricted("mat_showlowresimage", 0); memcpy(g_Options.showlowresimage, &f0, 4); + SetValueUnrestricted("viewmodel_offset_x", 1.0f); memcpy(g_Options.viewmodel_x, &f1, 4); + SetValueUnrestricted("viewmodel_offset_y", 1.0f); memcpy(g_Options.viewmodel_y, &f1, 4); + SetValueUnrestricted("viewmodel_offset_z", -1.0f); memcpy(g_Options.viewmodel_z, &fm1, 4); + memcpy(g_Options.viewmodel_ang_x, &f0, 4); + memcpy(g_Options.viewmodel_ang_y, &f0, 4); + memcpy(g_Options.viewmodel_ang_z, &f0, 4); + memcpy(g_Options.fov, &f90, 4); + SetValueUnrestricted("viewmodel_fov", 60.0f); memcpy(g_Options.viewmodel_fov, &f60, 4); + memcpy(g_Options.viewmodel_moving, &f0, 4); + SetValueUnrestricted("cl_viewmodel_shift_left_amt", GetVisibleFloat("cl_viewmodel_shift_left_amt")); + SetValueUnrestricted("cl_viewmodel_shift_right_amt", GetVisibleFloat("cl_viewmodel_shift_right_amt")); + SetValueUnrestricted("cl_bob_lower_amt", GetVisibleFloat("cl_bob_lower_amt")); + SetValueUnrestricted("cl_bobamt_lat", GetVisibleFloat("cl_bobamt_lat")); + SetValueUnrestricted("cl_bobamt_vert", GetVisibleFloat("cl_bobamt_vert")); + SetValueUnrestricted("cl_wpn_sway_scale", GetVisibleFloat("cl_wpn_sway_scale")); + iff.g_pCVar->FindVar("cl_ragdoll_gravity")->SetValue(600.0f); memcpy(g_Options.ragdollgravity, &f600, 4); + SetValueUnrestricted("cl_phys_timescale", 1.0f); memcpy(g_Options.ragdolltime, &f1, 4); + + if (g_Options.overhead) + { + DWORD oldProtect = 0; + VirtualProtect(iff.OverheadInfo, 2, PAGE_EXECUTE_READWRITE, &oldProtect); + BYTE ovbytes[2] = { 0x3B, 0xC6 }; + memcpy(iff.OverheadInfo, ovbytes, 2); + VirtualProtect(iff.OverheadInfo, 2, oldProtect, NULL); + } + + if (g_Options.nochokelimit) + { + auto clMoveChokeClamp = FindPatternV2("engine.dll", "B8 ? ? ? ? 3B F0 0F 4F F0 89 5D FC") + 1; + unsigned long protect = 0; + VirtualProtect((void*)clMoveChokeClamp, 4, PAGE_EXECUTE_READWRITE, &protect); + *(std::uint32_t*)clMoveChokeClamp = 15; + VirtualProtect((void*)clMoveChokeClamp, 4, protect, &protect); + } + + if (g_Options.wfsmoke) + wfsmoke(0); +} + +void RefreshThread(int* skinid) +{ + int localskinid = *skinid; + *skinid = 0; + iff.g_pClientState->ForceFullUpdate(); + Sleep(350); + + *skinid = localskinid; + iff.g_pClientState->ForceFullUpdate(); + opt.needupdate = 1; + ProtoFeatures.SendClientHello(); + ProtoFeatures.SendMatchmakingClient2GCHello(); +} + +struct float3 colorConverter(int hexValue) +{ + float3 rgbColor; + rgbColor.b = ((hexValue >> 16) & 0xFF) / 255.0; + rgbColor.g = ((hexValue >> 8) & 0xFF) / 255.0; + rgbColor.r = ((hexValue) & 0xFF) / 255.0; + return rgbColor; +} + +extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +WNDPROC oWndProc; +static HWND window = NULL; +LRESULT __stdcall WndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + if (true && ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam)) + return true; + return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam); +} + +#include "imgui/imgui_internal.h" + +ImFont* ifont; ImFont* ifontBD; ImFont* ifontmini; +void InitImGui(LPDIRECT3DDEVICE9 pDevice) +{ + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags = ImGuiConfigFlags_NoMouseCursorChange; + auto a = ImFontConfig(); + a.FontBuilderFlags = 1 << 7 | 1 << 4 | 1 << 5; + ifontBD = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeuib.ttf", 14); + ifont = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\arial.ttf", 14); + ifontmini = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\arial.ttf", 12); + ImGuiStyle* style = &ImGui::GetStyle(); + style->WindowMenuButtonPosition = 2; + style->WindowTitleAlign = ImVec2(0.00f, 1.2f); + style->WindowRounding = 6; + + float alpha = 0.7f; // other colors -> imgui_widgets.cpp +#ifdef OLDSTYLE + alpha = 1.0f; +#endif + style->Colors[ImGuiCol_FrameBg] = ImVec4(0.463f, 0.463f, 0.463f, alpha); //1 + style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->Colors[ImGuiCol_TitleBg] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->Colors[ImGuiCol_WindowBg] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->Colors[ImGuiCol_Button] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->ButtonTextAlign = ImVec2(0.1f, 0.5f); + style->TabRounding = 0; + style->TabBorderSize = 1; + style->Colors[ImGuiCol_Tab] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->WindowPadding = ImVec2(20.0f, 20.0f); + style->ItemSpacing = ImVec2(7.0f, 15.0f); + style->Colors[ImGuiCol_Border] = ImVec4(0.757f, 0.757f, 0.757f, alpha); + style->Colors[ImGuiCol_CheckMark] = ImVec4(1.0f, 1.0f, 1.0f, alpha); + style->Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.757f, 0.757f, 0.757f, alpha); + style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.757f, 0.757f, 0.757f, alpha); + style->Colors[ImGuiCol_HeaderHovered] = ImVec4(1.0f, 0.612f, 0, alpha); + style->Colors[ImGuiCol_HeaderActive] = ImVec4(1.0f, 0.612f, 0, alpha); + style->Colors[ImGuiCol_Header] = ImVec4(1.0f, 0.612f, 0, alpha); + style->Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.424f, 0.424f, 0.424f, alpha); + style->Colors[ImGuiCol_SliderGrab] = ImVec4(0.424f, 0.424f, 0.424f, alpha); + style->Colors[ImGuiCol_PopupBg] = ImVec4(0.635f, 0.635f, 0.635f, alpha); + style->ScrollbarRounding = 0; + style->SelectableTextAlign = ImVec2(0, 0); + + ImGui_ImplWin32_Init(window); + ImGui_ImplDX9_Init(pDevice); + + printfdbg("Imgui initiated\n"); +} +bool init = false; + + + +ID3DXFont* font; +VMTHook* D3DHook = nullptr; + + +void DisableElements(bool check, bool dis) +{ + if (!check) { + if (dis) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + + if (!dis) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + } +} + +long __stdcall hkEndScene(IDirect3DDevice9* pDevice) +{ + static auto oEndScene = D3DHook->GetOriginal(42); + + + if (!init) + { + D3DDEVICE_CREATION_PARAMETERS params; + pDevice->GetCreationParameters(¶ms); + window = params.hFocusWindow; + oWndProc = (WNDPROC)SetWindowLongPtr(window, GWL_WNDPROC, (LONG_PTR)WndProc); +#ifdef DEBUG + cout << "oWndProc " << oWndProc << endl; +#endif + InitImGui(pDevice); + init = true; + } + + + if (opt.show) { + + ImGui_ImplDX9_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + ImGuiStyle* style = &ImGui::GetStyle(); + + ImGui::PushFont(ifontBD); + + ImGui::SetNextWindowSize(ImVec2{ 650, 455 }); + + ImGui::Begin(XorStr("Spy's Seaside"), 0, ImGuiWindowFlags_NoResize); + + + ImGui::PushFont(ifont); + ImGui::BeginTabBar("1"); + + if (ImGui::BeginTabItem("Effects")) + { + + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + ImGui::Columns(2, nullptr, false); + + ImGui::Checkbox("Bullet trace beam", g_Options.beamtrace); + + DisableElements(*g_Options.beamtrace, 1); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 20.0f); + if (ImGui::BeginTable("ssplit", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextRow(); ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::TextInputComboBox("Path to .vmt", g_Options.beampath.value->mystring, 255, opt.spriteslist, 0); + ImGui::InputInt("Beam type", g_Options.beamtype, 0, 0); + ImGui::InputFloat("Width", g_Options.beamwidth, 0, 0); + ImGui::InputFloat("Amplitude", g_Options.beamamplitude, 0, 0); + ImGui::InputFloat("Halo scale", g_Options.beamhaloscale, 0, 0); + ImGui::InputFloat("Start frame", g_Options.beamstartframe, 0, 0); + ImGui::InputInt("Segments", g_Options.beamsegments, 0, 0); + + ImGui::TableNextColumn(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.0f); + ImGui::ColorEdit4("##BeamColor", (float*)g_Options.beamcolor.value.get(), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_AlphaBar); + ImGui::SameLine(); + ImGui::Text("Color/Alpha"); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputFloat("Life##beam", g_Options.beamlife, 0, 0); + ImGui::InputFloat("End width", g_Options.beamendwidth, 0, 0); + ImGui::InputFloat("Speed##beam", g_Options.beamspeed, 0, 0); + ImGui::InputFloat("Fade length", g_Options.beamfadelength, 0, 0); + ImGui::InputFloat("Framerate", g_Options.beamframerate, 0, 0); + ImGui::InputInt("Flags", g_Options.beamflags, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + + ImGui::EndTable(); + } + + DisableElements(*g_Options.beamtrace, 0); + + ImGui::NextColumn(); + + ImGui::Checkbox("Bullet impact effect", g_Options.attacheffects); + + DisableElements(g_Options.attacheffects, 1); + + if (ImGui::BeginTable("split", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextRow(); ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Interface", opt.EffTypes.at(g_Options.effects.value->type).c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < opt.EffTypes.size(); n++) + { + bool selected = (g_Options.effects.value->type == n); + if (ImGui::Selectable(opt.EffTypes.at(n).c_str(), selected, 0, ImVec2(0, 0), false)) + { + g_Options.effects.value->type = n; + g_Options.effects.value->selectedc = 0; + } + if (selected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Name", opt.Map.at(opt.EffTypes.at(g_Options.effects.value->type)).at(g_Options.effects.value->selectedc).c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < opt.Map.at(opt.EffTypes.at(g_Options.effects.value->type)).size(); n++) + { + bool selected = (g_Options.effects.value->selectedc == n); + if (ImGui::Selectable(opt.Map.at(opt.EffTypes.at(g_Options.effects.value->type)).at(n).c_str(), selected, 0, ImVec2(0, 0), false)) + g_Options.effects.value->selectedc = n; + if (selected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + ImGui::TableNextColumn(); + + + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() - 25.0f, ImGui::GetCursorPosY() - 20.0f)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; + style->ItemSpacing = ImVec2(7.0f, 2.0f); + if (ImGui::BeginChild("ChildR", ImVec2(135, 100), true, window_flags | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + switch (g_Options.effects.value->type) + { + case (0): + { + switch (g_Options.effects.value->selectedc) + { + case 0: + case 2: + { + ImGui::InputFloat("Size", &g_Options.effects.value->fx_fsize, 0, 0); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputFloat("Speed", &g_Options.effects.value->fx_fspeed, 0, 0); + break; + } + case 1: + { + ImGui::InputInt("Magnitude", &g_Options.effects.value->fx_magnitude, 0, 0); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputInt("Trail length", &g_Options.effects.value->fx_traillength, 0, 0); + break; + } + case 3: + { + ImGui::InputFloat("Scale", &g_Options.effects.value->fx_fsize, 0, 0); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputInt("Type", &g_Options.effects.value->fx_itype, 0, 0); + break; + } + case 4: + case 6: + { + break; + } + case 5: + { + ImGui::Checkbox("Explosive", &g_Options.effects.value->fx_bexplosive); + break; + } + + } + break; + } + + case (1): + { + ImGui::InputInt("Colors", &g_Options.effects.value->icolors, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputFloat("Magnitude", &g_Options.effects.value->fmagtinude, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputFloat("Scale##de", &g_Options.effects.value->fscale, 0, 0); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputInt("Flags##de", &g_Options.effects.value->fflags, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputFloat("Radius", &g_Options.effects.value->fradius, 0, 0); + + break; + } + + case (2): + { + switch (g_Options.effects.value->selectedc) + { + case (0): + { + ImGui::InputFloat("Beam width", &g_Options.effects.value->fbeamwidth, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputFloat("Time visible", &g_Options.effects.value->fltimevisible, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + ImGui::ColorEdit3("##teslacolor", (float*)g_Options.effects.value->teslacolor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputFloat("Radius##tesla", &g_Options.effects.value->teslaradius, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputInt("Beams", &g_Options.effects.value->ibeams, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputText("Sprite name", g_Options.effects.value->szSpriteName, 256); + break; + } + case (1): + { + ImGui::InputFloat("Die", &g_Options.effects.value->fdie, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputInt("Style", &g_Options.effects.value->style, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + ImGui::ColorEdit3("##dlightcolor", (float*)g_Options.effects.value->dlightcolor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + ImGui::InputFloat("Radius##dlight", &g_Options.effects.value->frad, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputInt("Key", &g_Options.effects.value->key, 0, 0); ImGui::InvisibleButton("##ib", ImVec2(0, 10.0f)); + ImGui::InputFloat("Decay", &g_Options.effects.value->decay, 0, 0); + + break; + } + + } + + break; + } + + } + + + ImGui::EndChild(); + } + DisableElements(g_Options.attacheffects, 0); + + ImGui::EndTable(); + } + + + if (ImGui::BeginTable("sssplit", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextRow(); ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::Checkbox("Hit sound", g_Options.hitsound); + DisableElements(*g_Options.hitsound, 1); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 13.0f); + ImGui::InputText("Head shot", g_Options.hspath.value->mystring, 256); + DisableElements(*g_Options.hitsound, 0); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 13.0f); + ImGui::Checkbox("Flashlight (L)", g_Options.flashlightON); + DisableElements(*g_Options.flashlightON, 1); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 7.0f); + ImGui::TextInputComboBox("Path to .vmt ", g_Options.flashlightTexture.value->mystring, 255, opt.flashlightlist, 0); + DisableElements(*g_Options.flashlightON, 0); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 13.0f); + ImGui::Checkbox("Nightvision (N)", g_Options.nvgsON); + + ImGui::TableNextColumn(); + + ImGui::Checkbox("Hit marker", g_Options.hitmarker); + DisableElements(*g_Options.hitsound, 1); + ImGui::InputText("Other bone", g_Options.obpath.value->mystring, 256); + DisableElements(*g_Options.hitsound, 0); + DisableElements(*g_Options.flashlightON, 1); + ImGui::Checkbox("Cast shadows", g_Options.flashlightShadows); + ImGui::InputFloat("Flaslight FOV", g_Options.flashlightFOV, 0, 0); + DisableElements(*g_Options.flashlightON, 0); + + ImGui::EndTable(); + } + + ImGui::Columns(1, nullptr, false); + + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("World")) + { + + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + + ImGui::Columns(2, nullptr, false); + + + if (ImGui::Checkbox("Skybox", g_Options.skyboxactive)) + { + if (g_Options.skyboxactive) + { + iff.g_pCVar->FindVar("sv_skyname")->SetValue((char*)g_Options.skyboxtemp.value.get()); + iff.g_pCVar->FindVar("r_3dsky")->SetValue(false); + } + else iff.g_pCVar->FindVar("r_3dsky")->SetValue(true); + } + + DisableElements(*g_Options.skyboxactive, 1); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + ImGui::PushItemWidth(170.0f); + ImGui::TextInputComboBox("##W1", (char*)g_Options.skyboxtemp.value.get(), 255, opt.skyboxitems, 0); + ImGui::PopItemWidth(); + ImGui::SameLine(); + if (ImGui::Button("Apply##W1", ImVec2(70, 22))) + { + iff.g_pCVar->FindVar("sv_skyname")->SetValue((char*)g_Options.skyboxtemp.value.get()); + } + + DisableElements(*g_Options.skyboxactive, 0); + + if (ImGui::Checkbox("Weather", g_Options.weatheractive)) + { + if (!*g_Options.weatheractive) iff.g_pClientState->ForceFullUpdate(); + + iff.g_pCVar->FindVar("r_rainlength")->SetValue(*g_Options.rainlength); + iff.g_pCVar->FindVar("r_rainspeed")->SetValue(*g_Options.rainspeed); + iff.g_pCVar->FindVar("r_rainradius")->SetValue(*g_Options.rainradius); + iff.g_pCVar->FindVar("cl_windspeed")->SetValue(*g_Options.windspeed); + iff.g_pCVar->FindVar("r_rainwidth")->SetValue(*g_Options.rainwidth); + iff.g_pCVar->FindVar("r_RainSideVel")->SetValue(*g_Options.rainsidevel); + iff.g_pCVar->FindVar("r_rainalpha")->SetValue(*g_Options.rainalpha); + } + + DisableElements(*g_Options.weatheractive, 1); + + if (ImGui::BeginTable("##Weather", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextRow(); ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::InputInt("Precipitation type", g_Options.weathertype, 0, 0); + + if (ImGui::InputFloat("Length", g_Options.rainlength, 0, 0)) + iff.g_pCVar->FindVar("r_rainlength")->SetValue(*g_Options.rainlength); + if (ImGui::InputFloat("Speed", g_Options.rainspeed, 0, 0)) + iff.g_pCVar->FindVar("r_rainspeed")->SetValue(*g_Options.rainspeed); + if (ImGui::InputFloat("Radius", g_Options.rainradius, 0, 0)) + iff.g_pCVar->FindVar("r_rainradius")->SetValue(*g_Options.rainradius); + + ImGui::TableNextColumn(); + + if (ImGui::InputFloat("Wind speed", g_Options.windspeed, 0, 0)) + iff.g_pCVar->FindVar("cl_windspeed")->SetValue(*g_Options.windspeed); + if (ImGui::InputFloat("Width", g_Options.rainwidth, 0, 0)) + iff.g_pCVar->FindVar("r_rainwidth")->SetValue(*g_Options.rainwidth); + if (ImGui::InputFloat("Side velocity", g_Options.rainsidevel, 0, 0)) + iff.g_pCVar->FindVar("r_RainSideVel")->SetValue(*g_Options.rainsidevel); + if (ImGui::InputFloat("Alpha", g_Options.rainalpha, 0, 0)) + iff.g_pCVar->FindVar("r_rainalpha")->SetValue(*g_Options.rainalpha); + + ImGui::EndTable(); + } + + DisableElements(*g_Options.weatheractive, 0); + + ImGui::NextColumn(); + + + + + if (ImGui::BeginTable("##Fog", 4, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextColumn(); + + if (ImGui::Checkbox("Fog", g_Options.fogactive)) + { + if (g_Options.fogactive) + { + SetValueUnrestricted("fog_enable", 1); + SetValueUnrestricted("fog_enableskybox", 1); + SetValueUnrestricted("fog_override", 1); + iff.g_pCVar->FindVar("fog_color")->SetValue( + std::string(""). + append(to_string(g_Options.fogcolor.value->r * 255)). + append(" "). + append(to_string(g_Options.fogcolor.value->g * 255)). + append(" "). + append(to_string(g_Options.fogcolor.value->b * 255)). + append(" ").c_str() + ); + iff.g_pCVar->FindVar("fog_colorskybox")->SetValue( + std::string(""). + append(std::to_string(g_Options.fogcolor.value->r * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->g * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->b * 255)). + append(" ").c_str() + ); + SetValueUnrestricted("fog_maxdensity", g_Options.fogdensity); + SetValueUnrestricted("fog_maxdensityskybox", g_Options.fogdensity); + SetValueUnrestricted("fog_start", g_Options.fogstart); + SetValueUnrestricted("fog_startskybox", g_Options.fogstart); + SetValueUnrestricted("fog_end", g_Options.fogend); + SetValueUnrestricted("fog_endskybox", g_Options.fogend); + } + else + SetValueUnrestricted("fog_override", 0); + } + + ImGui::TableNextColumn(); + + DisableElements(*g_Options.fogactive, 1); + + if (ImGui::ColorEdit3("##MyColor##W1", (float*)g_Options.fogcolor.value.get(), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf)) + { + iff.g_pCVar->FindVar("fog_color")->SetValue( + std::string(""). + append(std::to_string(g_Options.fogcolor.value->r * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->g * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->b * 255)). + append(" ").c_str() + ); + + iff.g_pCVar->FindVar("fog_colorskybox")->SetValue( + std::string(""). + append(std::to_string(g_Options.fogcolor.value->r * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->g * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->b * 255)). + append(" ").c_str() + ); + + } + + ImGui::EndTable(); + } + + + ImGui::PushItemWidth(252.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + + if (ImGui::SliderFloat("Max density", g_Options.fogdensity, 0.0f, 1.0f)) + { + iff.g_pCVar->FindVar("fog_maxdensity")->SetValue(g_Options.fogdensity); + iff.g_pCVar->FindVar("fog_maxdensityskybox")->SetValue(g_Options.fogdensity); + } + + if (ImGui::SliderFloat("Start", g_Options.fogstart, 0.0f, 5000.0f)) + { + iff.g_pCVar->FindVar("fog_start")->SetValue(g_Options.fogstart); + iff.g_pCVar->FindVar("fog_startskybox")->SetValue(g_Options.fogstart); + } + if (ImGui::SliderFloat("End", g_Options.fogend, 0.0f, 5000.0f)) + { + iff.g_pCVar->FindVar("fog_end")->SetValue(g_Options.fogend); + iff.g_pCVar->FindVar("fog_endskybox")->SetValue(g_Options.fogend); + } + + DisableElements(*g_Options.fogactive, 0); + + ImGui::InvisibleButton("##W4", ImVec2(0, 0.0f)); + + if (ImGui::SliderFloat("Tonemap scale", g_Options.tonemapscale, 0.001f, 1.0f)) + SetValueUnrestricted("mat_force_tonemap_scale", g_Options.tonemapscale); + ImGui::PopItemWidth(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + if (ImGui::Checkbox("Colorize map textures ", g_Options.worldcoloractive)) + { + if (*g_Options.worldcoloractive) colorWorld(); + else colorWorld(0); + } + + DisableElements(*g_Options.worldcoloractive, 1); + + ImGui::SameLine(); + if (ImGui::Button("Modulate", ImVec2(70, 22))) + colorWorld(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 20.0f); + if (ImGui::BeginTable("##Colorworld", 4, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 3.0f); + ImGui::Text("World"); + ImGui::ColorEdit3("##W1", (float*)g_Options.worldcolor.value.get(), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImGui::TableNextColumn(); + ImGui::Text("Prop/Sky"); + ImGui::ColorEdit3("##W2", (float*)g_Options.staticpropcolor.value.get(), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImGui::TableNextColumn(); + ImGui::Text("Particles"); + ImGui::ColorEdit4("##W4", (float*)g_Options.smokeskycolor.value.get(), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_AlphaBar); + + + ImGui::TableNextColumn(); + ImGui::Text("Model"); + ImGui::ColorEdit3("##W3", (float*)g_Options.modelcolor.value.get(), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImGui::EndTable(); + } + + DisableElements(*g_Options.worldcoloractive, 0); + + + + + ImGui::Columns(1, nullptr, false); + + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Models")) + { + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + static int selectedwep = 0; + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f); + + if (ImGui::BeginTable("##Models", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextRow(); + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + + + ImGui::PushItemWidth(170.0f); + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Item", g_Options.models.value->arr[selectedwep].name)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < g_Options.models.value->itemcount; n++) + { + g_Options.models.value->arr[n].isSelected = (selectedwep == n); + if (ImGui::Selectable(g_Options.models.value->arr[n].name, g_Options.models.value->arr[n].isSelected, 0, ImVec2(0, 0), false)) + selectedwep = n; + if (g_Options.models.value->arr[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + ImGui::PopItemWidth(); + + ImGui::SameLine(); + + if (ImGui::Button("Update", ImVec2(70, 22))) + iff.g_pClientState->ForceFullUpdate(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.0f); + + if (ImGui::Checkbox("Set viewmodel ", &g_Options.models.value->arr[selectedwep].active)) + { + if (!g_Options.models.value->arr[selectedwep].active) { + g_Options.models.value->arr[selectedwep].vmodel_hash = fnv2::hash(g_Options.models.value->arr[selectedwep].vmodel_orig); + } + + if (g_Options.models.value->arr[selectedwep].active) { + g_Options.models.value->arr[selectedwep].vmodel_hash = fnv2::hash(g_Options.models.value->arr[selectedwep].vmodel_repl); + } + + if (selectedwep < 2) + { + + if (g_Options.models.value->arr[selectedwep].active) + *g_Options.playerloop_count += 1; + else *g_Options.playerloop_count -= 1; + + printfdbg("pl count %d\n", *g_Options.playerloop_count); + } + + + } + ImGui::SameLine(); + DisableElements(selectedwep > 2 ? true : false, 1); + ImGui::Checkbox("Via FindMDL hook", &g_Options.models.value->arr[selectedwep].findMDLmethode); + DisableElements(selectedwep > 2 ? true : false, 0); + ImGui::PushItemWidth(170.0f); + + DisableElements(g_Options.models.value->arr[selectedwep].active,1); + ImGui::InputText("Path to .mdl##viewmodel", g_Options.models.value->arr[selectedwep].vmodel_repl_temp, 256); + DisableElements(g_Options.models.value->arr[selectedwep].active, 0); + + ImGui::PopItemWidth(); + + ImGui::SameLine(); + if (ImGui::Button("Apply##viewmodel", ImVec2(70, 22))) + { + if (const auto modelprecache = iff.g_pNetworkStringTableContainer->FindTable("modelprecache")) + modelprecache->AddString(false, g_Options.models.value->arr[selectedwep].vmodel_repl_temp); + + if (selectedwep > 2) { + for (int i = 0; i < 20; i++) + strcpy(g_Options.models.value->arr[selectedwep].seqs[i].seq_orig_def, ""); + + opt.needtogetseqact = selectedwep; + } + + strcpy(g_Options.models.value->arr[selectedwep].vmodel_repl, g_Options.models.value->arr[selectedwep].vmodel_repl_temp); + g_Options.models.value->arr[selectedwep].vmodel_hash = fnv2::hashRuntime(g_Options.models.value->arr[selectedwep].vmodel_repl); + } + + + ImGui::TableNextColumn(); + + DisableElements(selectedwep == 2 ? false : true, 1); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + + if (ImGui::Checkbox("Set scale", &g_Options.models.value->arr[selectedwep].active_scale)) + { + if (g_Options.models.value->arr[selectedwep].active_scale) + *g_Options.entityloop_count += 1; + else *g_Options.entityloop_count -= 1; + + printfdbg("el count %d\n", *g_Options.entityloop_count); + } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 30.0f); + + DisableElements(g_Options.models.value->arr[selectedwep].active_scale, 1); + ImGui::PushItemWidth(252.0f); + ImGui::SliderFloat("##scale", &g_Options.models.value->arr[selectedwep].scale, 0.0f, 10.0f); + ImGui::PopItemWidth(); + DisableElements(g_Options.models.value->arr[selectedwep].active_scale, 0); + + DisableElements(selectedwep == 2 ? false : true, 0); + + DisableElements(selectedwep > 2 ? true : false, 1); + + if (ImGui::Checkbox("Set worldmodel", &g_Options.models.value->arr[selectedwep].active_w)) + { + + if (g_Options.models.value->arr[selectedwep].active_w) + *g_Options.entityloop_count += 1; + else *g_Options.entityloop_count -= 1; + + printfdbg("el count %d\n", *g_Options.entityloop_count); + + } + + ImGui::PushItemWidth(170.0f); + DisableElements(g_Options.models.value->arr[selectedwep].active_w, 1); + ImGui::InputText("Path to .mdl##worldmodel", g_Options.models.value->arr[selectedwep].wmodel_repl_temp, 256); + DisableElements(g_Options.models.value->arr[selectedwep].active_w, 0); + ImGui::PopItemWidth(); + + ImGui::SameLine(); + if (ImGui::Button("Apply##worldmodel", ImVec2(70, 22))) + { + strcpy(g_Options.models.value->arr[selectedwep].wmodel_repl, g_Options.models.value->arr[selectedwep].wmodel_repl_temp); + g_Options.models.value->arr[selectedwep].wmodel_hash = fnv2::hashRuntime(g_Options.models.value->arr[selectedwep].wmodel_repl); + } + + DisableElements(selectedwep > 2 ? true : false, 0); + + + + ImGui::EndTable(); + } + + + + ImGui::Columns(2, nullptr, false); + + DisableElements(selectedwep > 2 ? true : false, 1); + if (ImGui::Checkbox("Set animations", &g_Options.models.value->arr[selectedwep].seq_active)) + opt.needtogetseqact = selectedwep; + DisableElements(selectedwep > 2 ? true : false, 0); + + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 20.0f); + + DisableElements(g_Options.models.value->arr[selectedwep].seq_active, 1); + + static char ccc[20][5] = { "##0","##1","##2","##3","##4","##5","##6","##7","##8","##9","##10","##11","##12","##13","##14","##15","##16","##17","##18","##19" }; + + static ImGuiTableFlags flags = ImGuiTableFlags_None; + + static ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; + + style->ItemSpacing = ImVec2(7.0f, 2.0f); + if (ImGui::BeginChild("ChildR", ImVec2(252, 150), true, window_flags | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() - 10.0f, ImGui::GetCursorPosY() - 10.0f)); + if (ImGui::BeginTable("split", 2, flags | ImGuiTableFlags_NoSavedSettings)) + { + for (int i = 0; i < 20; i++) + { + char buf[32]; + sprintf(buf, "%01d:", i); + ImGui::TableNextColumn(); + ImGui::Text(buf); + ImGui::SameLine(); + ImGui::Text(g_Options.models.value->arr[selectedwep].seqs[i].seq_orig_def); + + ImGui::TableNextColumn(); + + ImGui::PushItemWidth(100.0f); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo(ccc[i], g_Options.models.value->arr[selectedwep].seqs[g_Options.models.value->arr[selectedwep].seqs[i].seq_repl].seq_repl_def_preview)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < 20; n++) + { + g_Options.models.value->arr[selectedwep].seqs[i].isSelected[n] = (g_Options.models.value->arr[selectedwep].seqs[i].seq_repl == n); + if (ImGui::Selectable(g_Options.models.value->arr[selectedwep].seqs[n].seq_repl_def_preview, g_Options.models.value->arr[selectedwep].seqs[i].isSelected[n], 0, ImVec2(0, 0), false)) + g_Options.models.value->arr[selectedwep].seqs[i].seq_repl = n; + if (g_Options.models.value->arr[selectedwep].seqs[i].isSelected[n]) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + ImGui::PopItemWidth(); + + } + ImGui::EndTable(); + } + + ImGui::EndChild(); + } + + DisableElements(g_Options.models.value->arr[selectedwep].seq_active, 0); + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + + + ImGui::NextColumn(); + + + + static const char sss[20][6] = { "##0s","##1s","##2s","##3s","##4s","##5s","##6s","##7s","##8s","##9s","##10s", + "##11s","##12s","##13s","##14s","##15s","##16s","##17s","##18s","##19s" }; + + static const char sss1[5][6] = { "##0v","##1v","##2v","##3v","##4v" }; + static const char sss2[5][6] = { "##0p","##1p","##2p","##3p","##4p" }; + + DisableElements(selectedwep > 3 ? true : false, 1); + if (ImGui::Checkbox("Set sounds", &g_Options.models.value->arr[selectedwep].sound_active)) + { + if (g_Options.models.value->arr[selectedwep].sound_active) + *g_Options.soundhook_count += 1; + else *g_Options.soundhook_count -= 1; + + printfdbg("sh count %d\n", *g_Options.soundhook_count); + + } + DisableElements(selectedwep > 3 ? true : false, 0); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 20.0f); + + DisableElements(g_Options.models.value->arr[selectedwep].sound_active, 1); + + + + style->ItemSpacing = ImVec2(7.0f, 2.0f); + if (ImGui::BeginChild("ChildS", ImVec2(252, 150), true, ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoScrollbar)) { + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() - 10.0f, ImGui::GetCursorPosY() - 10.0f)); + if (ImGui::BeginTable("splits", 2, ImGuiTableFlags_NoSavedSettings)) + { + for (int i = 0; i < g_Options.models.value->arr[selectedwep].soundcount; i++) + { + + ImGui::TableNextColumn(); + + + ImGui::Text(g_Options.models.value->arr[selectedwep].sounds[i].name); + + ImGui::InvisibleButton("##xz", ImVec2(0, 14.0f)); + ImGui::Text("Pitch"); + ImGui::SameLine(); + ImGui::InputInt((char*)sss2[i], &g_Options.models.value->arr[selectedwep].sounds[i].pitch, 0, 0); + + + ImGui::TableNextColumn(); + + ImGui::PushItemWidth(106.0f); + ImGui::InputText((char*)sss[i], g_Options.models.value->arr[selectedwep].sounds[i].wavpath, 255); + ImGui::PopItemWidth(); + + ImGui::Text("Volume"); + ImGui::SameLine(); + + ImGui::PushItemWidth(56.0f); + ImGui::InputFloat((char*)sss1[i], &g_Options.models.value->arr[selectedwep].sounds[i].volume, 0, 0); + + + ImGui::PopItemWidth(); + + } + ImGui::EndTable(); + } + + ImGui::EndChild(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + DisableElements(g_Options.models.value->arr[selectedwep].sound_active, 0); + + + ImGui::Columns(1, nullptr, false); + + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Materials")) + { + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + + ImGui::Columns(2, nullptr, false); + static int selectedwep = 0; + + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + + ImGui::PushItemWidth(170.0f); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Item", g_Options.materials.value->arr[selectedwep].name)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < g_Options.materials.value->itemcount; n++) + { + g_Options.materials.value->arr[n].isSelected = (selectedwep == n); + if (ImGui::Selectable(g_Options.materials.value->arr[n].name, g_Options.materials.value->arr[n].isSelected, 0, ImVec2(0, 0), false)) + selectedwep = n; + if (g_Options.materials.value->arr[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + ImGui::PopItemWidth(); + + ImGui::SameLine(); + + if (ImGui::Checkbox("Active##S1", &g_Options.materials.value->arr[selectedwep].active)) + { + if (g_Options.materials.value->arr[selectedwep].active) + *g_Options.dmeloop_count += 1; + else *g_Options.dmeloop_count -= 1; + + printfdbg("dl count %d\n", *g_Options.dmeloop_count); + } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 20.0f); + + DisableElements(g_Options.materials.value->arr[selectedwep].active, 1); + + ImGui::PushItemWidth(170.0f); + ImGui::TextInputComboBox("Texture", g_Options.materials.value->arr[selectedwep].texture_temp, 255, opt.dmeitems, 0); + ImGui::PopItemWidth(); + + ImGui::SameLine(); + + if (ImGui::Button("Apply", ImVec2(70, 22))) + { + if (strstr(g_Options.materials.value->arr[selectedwep].texture_temp, "(0)")) + g_Options.materials.value->arr[selectedwep].customtextureselected = 0; + else if (strstr(g_Options.materials.value->arr[selectedwep].texture_temp, "(1)")) + g_Options.materials.value->arr[selectedwep].customtextureselected = 1; + else if (strstr(g_Options.materials.value->arr[selectedwep].texture_temp, "(2)")) + g_Options.materials.value->arr[selectedwep].customtextureselected = 2; + else if (strstr(g_Options.materials.value->arr[selectedwep].texture_temp, "(3)")) + g_Options.materials.value->arr[selectedwep].customtextureselected = 3; + else if (strstr(g_Options.materials.value->arr[selectedwep].texture_temp, "(4)")) + g_Options.materials.value->arr[selectedwep].customtextureselected = 4; + else g_Options.materials.value->arr[selectedwep].customtextureselected = -1; + + printfdbg("Custom texture selected? %d\n", g_Options.materials.value->arr[selectedwep].customtextureselected); + strcpy(g_Options.materials.value->arr[selectedwep].texture, g_Options.materials.value->arr[selectedwep].texture_temp); + } + + + ImGui::NextColumn(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f); + + if (ImGui::BeginTable("##tablexz", 2)) + { + ImGui::TableNextRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Wireframe", &g_Options.materials.value->arr[selectedwep].wireframe); + ImGui::Checkbox("Ignore Z", &g_Options.materials.value->arr[selectedwep].ignorez); + ImGui::TableNextColumn(); + ImGui::Checkbox("No draw", &g_Options.materials.value->arr[selectedwep].nodraw); + ImGui::ColorEdit4("MyColor##0", (float*)&g_Options.materials.value->arr[selectedwep].coloralpha, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_AlphaBar); + ImGui::SameLine(); + ImGui::Text("Color/Alpha"); + + ImGui::EndTable(); + } + + DisableElements(g_Options.materials.value->arr[selectedwep].active, 0); + + ImGui::Columns(1, nullptr, false); + ImGui::Separator(); + + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); + + static int item_current_idx = 0; + + ImGui::InputTextMultiline("KeyValue", g_Options.customtextures.value->arr[item_current_idx].keyvalue, 0x1000, ImVec2(467, 200), ImGuiInputTextFlags_AllowTabInput); + + ImGui::SameLine(); + + ImVec2 savepos = ImGui::GetCursorPos(); + + + style->ItemSpacing = ImVec2(7.0f, 2.0f); + if (ImGui::BeginListBox("Custom textures", ImVec2(98, 100))) + { + ImGui::PushFont(ifontmini); + for (int n = 0; n < 5; n++) + { + g_Options.customtextures.value->arr[n].IsSelected = (item_current_idx == n); + if (ImGui::Selectable(g_Options.customtextures.value->arr[n].Preview, g_Options.customtextures.value->arr[n].IsSelected, 0, ImVec2(0, 0), true)) + item_current_idx = n; + + if (g_Options.customtextures.value->arr[n].IsSelected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + ImGui::PushFont(ifont); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + + savepos.y += 130.0f; + ImGui::SetCursorPos(savepos); + + ImGui::PushItemWidth(100.0f); + ImGui::InputText("Name", g_Options.customtextures.value->arr[item_current_idx].Name, 256); + ImGui::PopItemWidth(); + + savepos.y += 40.0f; + ImGui::SetCursorPos(savepos); + + if (ImGui::Button("Apply##refresh", ImVec2(70, 22))) + { + if (g_Options.customtextures.value->arr[item_current_idx].Name[0] == 0x0 && g_Options.customtextures.value->arr[item_current_idx].keyvalue[0] == 0x0) + { + char newpreview[256] = "("; + strcat_s(newpreview, to_string(item_current_idx).c_str()); + strcat_s(newpreview, ") null"); + strcpy(g_Options.customtextures.value->arr[item_current_idx].Preview, newpreview); + g_Options.customtextures.value->arr[item_current_idx].texturelink = nullptr; + } + else + { + char newpreview[256] = "("; + strcat_s(newpreview, to_string(item_current_idx).c_str()); + strcat_s(newpreview, ") "); + strcat_s(newpreview, g_Options.customtextures.value->arr[item_current_idx].Name); + strcpy(g_Options.customtextures.value->arr[item_current_idx].Preview, newpreview); + + g_Options.customtextures.value->arr[item_current_idx].texturelink = CreateMaterial( + string(g_Options.customtextures.value->arr[item_current_idx].Name), + string(g_Options.customtextures.value->arr[item_current_idx].keyvalue)); + } + + opt.dmeitems.at(item_current_idx) = g_Options.customtextures.value->arr[item_current_idx].Preview; + + + } + + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + } + + + if (ImGui::BeginTabItem("Inventory")) + { + + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + + static int selectedwep = 0; + ImGui::Text("Item"); + ImGui::SameLine(); + ImGui::PushItemWidth(390.0f); + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("##label1", g_Options.weapons.value->arr[selectedwep].name)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < g_Options.weapons.value->weaponzcount; n++) + { + g_Options.weapons.value->arr[n].isSelected = (selectedwep == n); + if (ImGui::Selectable(g_Options.weapons.value->arr[n].name, g_Options.weapons.value->arr[n].isSelected, 0, ImVec2(0, 0), false)) + selectedwep = n; + if (g_Options.weapons.value->arr[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + ImGui::SameLine(); + + ImGui::Checkbox("Active##S1", &g_Options.weapons.value->arr[selectedwep].active); + + ImGui::SameLine(); + if (ImGui::Button("Update", ImVec2(70, 22))) { + CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)RefreshThread, &g_Options.weapons.value->arr[selectedwep].skinid, 0, 0); + } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + + DisableElements(g_Options.weapons.value->arr[selectedwep].active, 1); + + ImGui::Columns(2, nullptr, false); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + ImGui::PushItemWidth(252.0f); + if (ImGui::BeginCombo("Paint kit ID", opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + + for (int n = 0; n < opt.sc_skins.size(); n++) + { + opt.sc_skins[n].isSelected = (g_Options.weapons.value->arr[selectedwep].skinidc == n); + if (ImGui::Selectable(opt.sc_skins[n].Preview.c_str(), opt.sc_skins[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].skinidc = n; + g_Options.weapons.value->arr[selectedwep].skinid = opt.sc_skins[n].id; + + + g_Options.weapons.value->arr[selectedwep].rarity = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].rarity; + g_Options.weapons.value->arr[selectedwep].pearl = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].pearl; + g_Options.weapons.value->arr[selectedwep].color1 = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color1; + g_Options.weapons.value->arr[selectedwep].color2 = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color2; + g_Options.weapons.value->arr[selectedwep].color3 = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color3; + g_Options.weapons.value->arr[selectedwep].color4 = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color4; + } + + if (opt.sc_skins[n].isSelected) + ImGui::SetItemDefaultFocus(); + + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + ImGui::PopItemWidth(); + + + + if (ImGui::BeginTable("##table1", 2)) + { + ImGui::TableNextRow(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::InputInt("Seed", &g_Options.weapons.value->arr[selectedwep].seed, 0); + ImGui::InputInt("StatTrak(tm)", &g_Options.weapons.value->arr[selectedwep].stattrak, 0); + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Quality", qualities[g_Options.weapons.value->arr[selectedwep].qualityc].name.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < qualities.size(); n++) + { + qualities[n].isSelected = (g_Options.weapons.value->arr[selectedwep].quality == qualities[n].defindex); + if (ImGui::Selectable(qualities[n].name.c_str(), qualities[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].qualityc = n; + g_Options.weapons.value->arr[selectedwep].quality = qualities[n].defindex; + } + + if (qualities[n].isSelected) + { + ImGui::SetItemDefaultFocus(); + } + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + + ImGui::TableNextColumn(); + + float thisy = ImGui::GetCursorPosY(); + ImGui::SetCursorPosY(thisy - 20.0f); + ImGui::Text("Custom colors"); + ImGui::SetCursorPosY(thisy); + + float3 color1 = colorConverter(opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color1); + if (ImGui::ColorEdit3("##Custom colors", (float*)&color1, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf)) + { + int color1int = 0xFF000000 + ((int)(color1.b * 255) << 16) | ((int)(color1.g * 255) << 8) | (int)(color1.r * 255); + opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color1 = color1int; + CPaintKit* pk = (CPaintKit*)opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].link; + pk->color1 = color1int; + g_Options.weapons.value->arr[selectedwep].color1 = color1int; + } + ImGui::SameLine(); + float3 color2 = colorConverter(opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color2); + if (ImGui::ColorEdit3("##Color2", (float*)&color2, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf)) + { + int color2int = 0xFF000000 + ((int)(color2.b * 255) << 16) | ((int)(color2.g * 255) << 8) | (int)(color2.r * 255); + opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color2 = color2int; + CPaintKit* pk = (CPaintKit*)opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].link; + pk->color2 = color2int; + g_Options.weapons.value->arr[selectedwep].color2 = color2int; + } + ImGui::SameLine(); + float3 color3 = colorConverter(opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color3); + if (ImGui::ColorEdit3("##Color3", (float*)&color3, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf)) + { + int color3int = 0xFF000000 + ((int)(color3.b * 255) << 16) | ((int)(color3.g * 255) << 8) | (int)(color3.r * 255); + opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color3 = color3int; + CPaintKit* pk = (CPaintKit*)opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].link; + pk->color3 = color3int; + g_Options.weapons.value->arr[selectedwep].color3 = color3int; + } + ImGui::SameLine(); + float3 color4 = colorConverter(opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color4); + if (ImGui::ColorEdit3("##Color4", (float*)&color4, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf)) + { + int color4int = 0xFF000000 + ((int)(color4.b * 255) << 16) | ((int)(color4.g * 255) << 8) | (int)(color4.r * 255); + opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].color4 = color4int; + CPaintKit* pk = (CPaintKit*)opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].link; + pk->color4 = color4int; + g_Options.weapons.value->arr[selectedwep].color4 = color4int; + } + ImGui::Checkbox("Freeze count", &g_Options.weapons.value->arr[selectedwep].ownerunk); + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Rarity", rarities[opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].rarity].name.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < rarities.size(); n++) + { + rarities[n].isSelected = (opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].rarity == rarities[n].defindex); + if (ImGui::Selectable(rarities[n].name.c_str(), rarities[n].isSelected, 0, ImVec2(0, 0), false)) + { + opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].rarity = rarities[n].defindex; + CPaintKit* pk = (CPaintKit*)opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].link; + pk->rarity = rarities[n].defindex; + g_Options.weapons.value->arr[selectedwep].rarity = rarities[n].defindex; + } + + if (rarities[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + + + ImGui::EndTable(); + + } + + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 5.0f); + + ImGui::PushItemWidth(252.0f); + ImGui::SliderFloat("Wear", &g_Options.weapons.value->arr[selectedwep].wear, 0.0f, 1.0f); + if (ImGui::SliderFloat("Pearlescent", &opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].pearl, 0.0f, 255.0f)) + { + CPaintKit* pk = (CPaintKit*)opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].link; + pk->pearlescent = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].pearl; + g_Options.weapons.value->arr[selectedwep].pearl = opt.sc_skins[g_Options.weapons.value->arr[selectedwep].skinidc].pearl; + } + ImGui::PopItemWidth(); + + + if (ImGui::BeginTable("##table3", 2)) + { + ImGui::TableNextRow(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + + bool disabledDefIndex = (selectedwep > 5) && (selectedwep < (g_Options.weapons.value->weaponzcount - 1)) ? false : true; + bool disabledKFIcon = ((selectedwep > 0) && (selectedwep < 6)) || (selectedwep == g_Options.weapons.value->weaponzcount - 1) ? false : true; + + DisableElements(disabledDefIndex, 1); + + + if (selectedwep == 0) { + if (ImGui::BeginCombo("Definition", knives[g_Options.weapons.value->arr[selectedwep].modelcount].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + + for (int n = 0; n < knives.size(); n++) + { + knives[n].isSelected = (g_Options.weapons.value->arr[selectedwep].modelcount == n); + if (ImGui::Selectable(knives[n].Preview.c_str(), knives[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].modelcount = n; + g_Options.weapons.value->arr[selectedwep].modeldefindex = knives[n].defindex; + strcpy(g_Options.weapons.value->arr[selectedwep].model, knives[n].viewmodel.c_str()); + strcpy(g_Options.weapons.value->arr[selectedwep].worldmodel, knives[n].worldmodel.c_str()); + + } + + if (knives[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + } + else if (selectedwep == 1) + { + if (ImGui::BeginCombo("Definition", gloves[g_Options.weapons.value->arr[selectedwep].modelcount].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < gloves.size(); n++) + { + gloves[n].isSelected = (g_Options.weapons.value->arr[selectedwep].modelcount == n); + if (ImGui::Selectable(gloves[n].Preview.c_str(), gloves[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].modelcount = n; + g_Options.weapons.value->arr[selectedwep].modeldefindex = gloves[n].defindex; + strcpy(g_Options.weapons.value->arr[selectedwep].model, gloves[n].viewmodel.c_str()); + strcpy(g_Options.weapons.value->arr[selectedwep].worldmodel, gloves[n].worldmodel.c_str()); + } + if (gloves[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + } + else if (selectedwep == 2 || selectedwep == 3) + { + if (ImGui::BeginCombo("Definition", agents[g_Options.weapons.value->arr[selectedwep].modelcount].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < agents.size(); n++) + { + agents[n].isSelected = (g_Options.weapons.value->arr[selectedwep].modelcount == n); + if (ImGui::Selectable(agents[n].Preview.c_str(), agents[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].modelcount = n; + g_Options.weapons.value->arr[selectedwep].modeldefindex = agents[n].defindex; + strcpy(g_Options.weapons.value->arr[selectedwep].model, agents[n].viewmodel.c_str()); + + } + if (agents[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + } + + else if (selectedwep == 4) + { + if (ImGui::BeginCombo("Definition", medals[g_Options.weapons.value->arr[selectedwep].modelcount].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < medals.size(); n++) + { + medals[n].isSelected = (g_Options.weapons.value->arr[selectedwep].modelcount == n); + if (ImGui::Selectable(medals[n].Preview.c_str(), medals[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].modelcount = n; + g_Options.weapons.value->arr[selectedwep].modeldefindex = medals[n].defindex; + } + if (medals[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + } + else if (selectedwep == 5) + { + if (ImGui::BeginCombo("Definition", musickits[g_Options.weapons.value->arr[selectedwep].modelcount].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < musickits.size(); n++) + { + musickits[n].isSelected = (g_Options.weapons.value->arr[selectedwep].modelcount == n); + if (ImGui::Selectable(musickits[n].Preview.c_str(), musickits[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].modelcount = n; + g_Options.weapons.value->arr[selectedwep].modeldefindex = musickits[n].defindex; + + } + if (musickits[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + } + else if (selectedwep == (g_Options.weapons.value->weaponzcount - 1)) + { + if (ImGui::InputInt("Definition", &g_Options.weapons.value->arr[selectedwep].defindex, 0, 0)) + g_Options.weapons.value->arr[selectedwep].modeldefindex = g_Options.weapons.value->arr[selectedwep].defindex; + } + else + { + ImGui::BeginCombo("Definition", "Disabled"); + ImGui::EndCombo; + } + + style->WindowPadding = ImVec2(20.f, 20.0f); + + DisableElements(disabledDefIndex, 0); + + ImGui::TableNextColumn(); + + DisableElements(disabledKFIcon, 1); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Killfeed icon", g_Options.weapons.value->arr[selectedwep].killfeediconreplace)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < opt.killfeedicons.size(); n++) + { + if (ImGui::Selectable(opt.killfeedicons[n].c_str(), false, 0, ImVec2(0, 0), false)) + { + strcpy(g_Options.weapons.value->arr[selectedwep].killfeediconreplace, opt.killfeedicons[n].c_str()); + if (n > 0) + g_Options.weapons.value->arr[selectedwep].killfeediconactive = 1; + else + g_Options.weapons.value->arr[selectedwep].killfeediconactive = 0; + } + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + DisableElements(disabledKFIcon, 0); + + ImGui::EndTable(); + } + + + ImGui::NextColumn(); + + + static int stickerselected = 0; + style->ItemSpacing = ImVec2(7.0f, 2.0f); + if (ImGui::BeginListBox("Stickers##lb", ImVec2(251.0f, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + ImGui::PushFont(ifontmini); + for (int n = 0; n < 5; n++) + { + g_Options.weapons.value->arr[selectedwep].stickers[n].isselected = (stickerselected == n); + if (ImGui::Selectable(g_Options.weapons.value->arr[selectedwep].stickers[n].name, + g_Options.weapons.value->arr[selectedwep].stickers[n].isselected, 0, ImVec2(0, 0), true)) { + stickerselected = n; + } + + if (g_Options.weapons.value->arr[selectedwep].stickers[n].isselected) + ImGui::SetItemDefaultFocus(); + } + ImGui::PushFont(ifont); + ImGui::EndListBox(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + + ImGui::InvisibleButton("##invis", ImVec2(0, 10.0f)); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 5.0f); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + ImGui::PushItemWidth(252.0f); + + if (ImGui::BeginCombo("Sticker ID", opt.sc_stickers[g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].stickerc].Preview.c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + + for (int n = 0; n < opt.sc_stickers.size(); n++) + { + opt.sc_stickers[n].isSelected = (g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].stickerc == n); + if (ImGui::Selectable(opt.sc_stickers[n].Preview.c_str(), opt.sc_stickers[n].isSelected, 0, ImVec2(0, 0), false)) + { + g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].stickerc = n; + g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].stickerid = opt.sc_stickers[n].id; + + char newname[64] = "("; + strcat_s(newname, to_string(stickerselected).c_str()); + strcat_s(newname, ") "); + strcat_s(newname, opt.sc_stickers[g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].stickerc].Name.c_str()); + + strcpy(g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].name, + newname); + } + if (opt.sc_stickers[n].isSelected) + ImGui::SetItemDefaultFocus(); + + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + ImGui::PopItemWidth(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 7.0f); + + + ImGui::PushItemWidth(252.0f); + ImGui::SliderFloat("Wear##st", &g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].wear, 0, 1.0f); + ImGui::SliderFloat("Scale##st", &g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].scale, 2.0f, 0.0f); + ImGui::SliderFloat("Rotation##st", &g_Options.weapons.value->arr[selectedwep].stickers[stickerselected].rotation, 0, 360.0f); + ImGui::PopItemWidth(); + + if (ImGui::BeginTable("##table5", 2)) + { + ImGui::TableNextRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::InputText("Name tag", g_Options.weapons.value->arr[selectedwep].nametag, 32); + ImGui::TableNextColumn(); + ImGui::InputText("Desc tag", g_Options.weapons.value->arr[selectedwep].desctag, 32); + + ImGui::EndTable(); + } + + ImGui::Columns(1, nullptr, false); + + DisableElements(g_Options.weapons.value->arr[selectedwep].active, 0); + + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Profile")) + { + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + + if (ImGui::BeginTable("##tablexz", 4)) + { + ImGui::TableNextRow(); ImGui::TableNextRow(); + + ImGui::TableNextRow(); ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 20.0f); + ImGui::TextInputComboBox("Name", g_Options.playername.value->mystring, 1024, opt.names, 0); + ImGui::InputText("Clan tag", g_Options.playerclan.value->mystring, 1024); + + DisableElements(*g_Options.discmsg_active, 1); + ImGui::InputText("Disconnect msg", g_Options.discmsg.value->mystring, 1024); + DisableElements(*g_Options.discmsg_active, 0); + + ImGui::TableNextColumn(); + if (ImGui::Button("Apply##name", ImVec2(70, 22))) + { + ConVar* nameConvar = iff.g_pCVar->FindVar("name"); + *(int*)((DWORD)&nameConvar->m_fnChangeCallbacks.m_Size) = 0; + printfdbg("m_fnChangeCallbacks %x\n", (DWORD)&nameConvar->m_fnChangeCallbacks.m_Size); + //nameConvar->SetValue(MakeControlChars(g_Options.playername.value->mystring)); + *g_Options.changing_name = 1; + + NETSetConVar("name", MakeControlChars(g_Options.playername.value->mystring)); + + } + + if (ImGui::Button("Apply##clan", ImVec2(70, 22))) + { + char* newclan = MakeControlChars(g_Options.playerclan.value->mystring); + static auto fnClantagChanged = (int(__fastcall*)(const char*, const char*))FindPatternV2("engine.dll", "53 56 57 8B DA 8B F9 FF 15"); + fnClantagChanged(newclan, newclan); + } + + ImGui::Checkbox("Active##discmsg", g_Options.discmsg_active); + + ImGui::TableNextColumn(); + + ImGui::Checkbox("Set score", g_Options.fakescore); + + + DisableElements(g_Options.fakescore, 1); + + ImGui::InputInt("Score", g_Options.score, 0); + ImGui::InputInt("MVPs", g_Options.MVPs, 0); + + ImGui::TableNextColumn(); + + ImGui::InputInt("Kills", g_Options.kills, 0); + ImGui::InputInt("Assists", g_Options.assists, 0); + ImGui::InputInt("Deaths", g_Options.deaths, 0); + + DisableElements(g_Options.fakescore, 0); + + ImGui::EndTable(); + } + + + + ImGui::Separator(); + + + if (ImGui::BeginTable("##tablexz", 4)) + { + ImGui::TableNextRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Set MM info", g_Options.profile_active); + ImGui::TableNextColumn(); + if (ImGui::Button("Update##ranks", ImVec2(70, 22))) + { + g_Options.rankz.value->selectedrank = 2; + ProtoFeatures.SendMatchmakingClient2GCHello(); + ProtoFeatures.SendClientGcRankUpdate(); + } + ImGui::EndTable(); + } + + DisableElements(g_Options.profile_active, 1); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + + if (ImGui::BeginTable("##tablexz", 4)) + { + ImGui::TableNextRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + static int selectedrank_this = 0; + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Rank Type", g_Options.rankz.value->arr[selectedrank_this].Name)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < 3; n++) + { + if (ImGui::Selectable(g_Options.rankz.value->arr[n].Name, g_Options.rankz.value->arr[n].isselected, 0, ImVec2(0, 0), false)) + selectedrank_this = n; + + if (g_Options.rankz.value->arr[n].isselected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + ImGui::InputInt("Rank", &g_Options.rankz.value->arr[selectedrank_this].rank, 0); + ImGui::InputInt("Wins", &g_Options.rankz.value->arr[selectedrank_this].wins, 0); + + ImGui::TableNextColumn(); + + ImGui::Checkbox("Prime", g_Options.prime); + + ImGui::InputInt("level", g_Options.level, 0); + ImGui::InputInt("XP", g_Options.xp, 0); + + ImGui::TableNextColumn(); + + ImGui::InputInt("Leader", g_Options.comleader, 0); + ImGui::InputInt("Teacher", g_Options.comteacher, 0); + ImGui::InputInt("Friendly", g_Options.comfriendly, 0); + + ImGui::TableNextColumn(); + + ImGui::Checkbox("VAC ban", g_Options.vacban); + ImGui::InputInt("Ban reason", g_Options.banreason, 0); + ImGui::InputInt("Ban duration", g_Options.banduration, 0); + + DisableElements(g_Options.profile_active, 0); + ImGui::EndTable(); + } + + ImGui::EndChild(); + } + + ImGui::EndTabItem(); + + } + + + if (ImGui::BeginTabItem("Player")) + { + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + ImGui::Text("Set ConVar"); + ImGui::SameLine(); + + static char cvarbuf[255] = ""; + ImGui::PushItemWidth(200.0f); + ImGui::InputText("##Set ConVar", cvarbuf, 255); + ImGui::SameLine(); + static float floatbuf = 0; + + ImGui::PushItemWidth(200.0f); + ImGui::InputFloat("Value##f", &floatbuf); + ImGui::SameLine(); + if (ImGui::Button("Apply", ImVec2(70, 22))) + { + SetValueUnrestricted(cvarbuf, floatbuf); + } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 10.0f); + ImGui::Separator(); + + ImGui::Columns(3, nullptr, false); + + // + style->ItemSpacing = ImVec2(7.0f, 5.0f); //10 + ImGui::Checkbox("Spectator list", g_Options.speclist); + ImGui::Checkbox("Vote reveal", g_Options.votereveal); + ImGui::Checkbox("Rank reveal", g_Options.rankreveal); + ImGui::Checkbox("Money reveal", g_Options.moneyreveal); + ImGui::Checkbox("Fast duck", g_Options.fastduck); + ImGui::Checkbox("Fast stop", g_Options.faststop); + ImGui::Checkbox("Fast ladder", g_Options.fastladder); + ImGui::Checkbox("Slide walk", g_Options.slidewalk); + + //ImGui::NextColumn(); + + /* + if (ImGui::Checkbox("No postprocessing", g_Options.postproc)) + SetValueUnrestricted("mat_postprocess_enable", !g_Options.postproc); + + if (ImGui::Checkbox("No shadows", g_Options.shadows)) + SetValueUnrestricted("cl_csm_enabled", !g_Options.shadows); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + static string types[3] = { "0", "1", "2" }; + if (ImGui::BeginCombo("Fullbright", types[g_Options.fullbright].c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < 3; n++) + { + bool selected = (g_Options.fullbright == n); + if (ImGui::Selectable(types[n].c_str(), false, 0, ImVec2(0, 0), false)) + { + memcpy(g_Options.fullbright, &n, 4); + SetValueUnrestricted("mat_fullbright", g_Options.fullbright); + } + if (selected) + ImGui::SetItemDefaultFocus(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + if (ImGui::Checkbox("Gray world", g_Options.drawgray)) + SetValueUnrestricted("mat_drawgray", g_Options.drawgray); + + if (ImGui::Checkbox("Low res world", g_Options.showlowresimage)) + SetValueUnrestricted("mat_showlowresimage", g_Options.showlowresimage); + */ + + ImGui::NextColumn(); + + style->ItemSpacing = ImVec2(7.0f, 5.0f); //10 + ImGui::Checkbox("C4 timer", g_Options.c4timer); + ImGui::Checkbox("Block bot", g_Options.blockbot); + style->ItemSpacing = ImVec2(7.0f, 19.0f); //17 + + if (ImGui::SliderFloat("Viewmodel pos X", g_Options.viewmodel_x, -90.0f, 90.0f)) + SetValueUnrestricted("viewmodel_offset_x", g_Options.viewmodel_x); + if (ImGui::SliderFloat("Viewmodel pos Y", g_Options.viewmodel_y, -90.0f, 90.0f)) + SetValueUnrestricted("viewmodel_offset_y", g_Options.viewmodel_y); + if (ImGui::SliderFloat("Viewmodel pos Z", g_Options.viewmodel_z, -90.0f, 90.0f)) + SetValueUnrestricted("viewmodel_offset_z", g_Options.viewmodel_z); + + ImGui::SliderFloat("FOV", g_Options.fov, 0, 360); + + ImGui::NextColumn(); + + style->ItemSpacing = ImVec2(7.0f, 5.0f); //10 + + ImGui::Checkbox("Bunny hop", g_Options.bunnyhop); + DisableElements(*g_Options.bunnyhop, 1); + ImGui::Checkbox("Auto strafe", g_Options.autostrafe); + DisableElements(*g_Options.bunnyhop, 0); + style->ItemSpacing = ImVec2(7.0f, 19.0f); //17 + + ImGui::SliderFloat("Viewmodel ang X", g_Options.viewmodel_ang_x, -180.0f, 180.0f); + ImGui::SliderFloat("Viewmodel ang Y", g_Options.viewmodel_ang_y, -180.0f, 180.0f); + ImGui::SliderFloat("Viewmodel ang Z", g_Options.viewmodel_ang_z, -180.0f, 180.0f); + + /* + if (ImGui::SliderFloat("Aspect Ratio", g_Options.aspectratio, 0, 25.0f)) + SetValueUnrestricted("r_aspectratio", g_Options.aspectratio); + + if (ImGui::InputFloat("Ragdoll Gravity", g_Options.ragdollgravity)) + iff.g_pCVar->FindVar("cl_ragdoll_gravity")->SetValue(g_Options.ragdollgravity); + + if (ImGui::InputFloat("Ragdoll Timescale", g_Options.ragdolltime)) + SetValueUnrestricted("cl_phys_timescale", g_Options.ragdolltime); + + if (ImGui::SliderFloat("Viewmodel FOV", g_Options.viewmodel_fov, 0, 180.0f)) + SetValueUnrestricted("viewmodel_fov", g_Options.viewmodel_fov); + + */ + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 67.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f); + if (ImGui::Button("Reset", ImVec2(70, 22))) + ResetMisc(); + + ImGui::Columns(1, nullptr, false); + + ImGui::EndChild(); + } + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Rage")) + { + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + ImGui::Columns(3, nullptr, false); + + //if (ImGui::Button("Voicerecord", ImVec2(70, 22))) + // printfdbg("VoiceRecordStart: %d\n", VoiceRecordStart("test.wav")); + + static int selectedglow = 0; + + + if (ImGui::Checkbox("Overhead info/Radar", g_Options.overhead)) + { + if (g_Options.overhead) + { + DWORD oldProtect = 0; + VirtualProtect(iff.OverheadInfo, 2, PAGE_EXECUTE_READWRITE, &oldProtect); + BYTE ovbytes[2] = { 0x90, 0x90 }; + memcpy(iff.OverheadInfo, ovbytes, 2); + VirtualProtect(iff.OverheadInfo, 2, oldProtect, NULL); + } + else + { + DWORD oldProtect = 0; + VirtualProtect(iff.OverheadInfo, 2, PAGE_EXECUTE_READWRITE, &oldProtect); + BYTE ovbytes[2] = { 0x3B, 0xC6 }; + memcpy(iff.OverheadInfo, ovbytes, 2); + VirtualProtect(iff.OverheadInfo, 2, oldProtect, NULL); + } + } + + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Glow", g_Options.glowObjects.value->arr[selectedglow].name)) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < g_Options.glowObjects.value->itemcount; n++) + { + g_Options.glowObjects.value->arr[n].isSelected = (selectedglow == n); + if (ImGui::Selectable(g_Options.glowObjects.value->arr[n].name, g_Options.glowObjects.value->arr[n].isSelected, 0, ImVec2(0, 0), false)) + selectedglow = n; + if (g_Options.glowObjects.value->arr[n].isSelected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + DisableElements(g_Options.glowObjects.value->arr[selectedglow].enabled, 1); + + ImGui::SliderFloat("Thickness", &g_Options.glowObjects.value->arr[selectedglow].alphamax, 0.0f, 1.0f); + + DisableElements(g_Options.glowObjects.value->arr[selectedglow].enabled, 0); + + ImGui::SliderFloat("Flashbang alpha", g_Options.flashalpha, 0.0f, 255.0f); + + ImGui::SliderInt("Fake lag", g_Options.fakelag, 0, 63); + + ImGui::Checkbox("Aimbot", g_Options.aimbot); + ImGui::Checkbox("Silent aim", g_Options.silentaim); + + ImGui::NextColumn(); + + if (ImGui::Checkbox("No Recoil", g_Options.rcs)) + { + if (g_Options.rcs) + SetValueUnrestricted("view_recoil_tracking", 0.0f); + else + SetValueUnrestricted("view_recoil_tracking", 0.45f); + } + + ImGui::Checkbox("Active", &g_Options.glowObjects.value->arr[selectedglow].enabled); + ImGui::SameLine(); + + DisableElements(g_Options.glowObjects.value->arr[selectedglow].enabled, 1); + ImGui::ColorEdit4("Color", (float*)&g_Options.glowObjects.value->arr[selectedglow].color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_AlphaBar); + + style->WindowPadding = ImVec2(5.0f, 5.0f); + if (ImGui::BeginCombo("Style", opt.GlowStyles.at(g_Options.glowObjects.value->arr[selectedglow].glowstyle).c_str())) + { + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + for (int n = 0; n < opt.GlowStyles.size(); n++) + { + bool selected = (g_Options.glowObjects.value->arr[selectedglow].glowstyle == n); + if (ImGui::Selectable(opt.GlowStyles.at(n).c_str(), selected, 0, ImVec2(0, 0), false)) + { + g_Options.glowObjects.value->arr[selectedglow].glowstyle = n; + } + if (selected) + ImGui::SetItemDefaultFocus(); + } + + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + ImGui::EndCombo(); + } + style->WindowPadding = ImVec2(20.f, 20.0f); + + DisableElements(g_Options.glowObjects.value->arr[selectedglow].enabled, 0); + + if (ImGui::Checkbox("Wireframe smoke", g_Options.wfsmoke)) + { + if (g_Options.wfsmoke) + wfsmoke(1); else wfsmoke(0); + } + + if (ImGui::Checkbox("No choked ticks limit", g_Options.nochokelimit)) + { + if (g_Options.nochokelimit) + { + auto clMoveChokeClamp = FindPatternV2("engine.dll", "B8 ? ? ? ? 3B F0 0F 4F F0 89 5D FC") + 1; + unsigned long protect = 0; + VirtualProtect((void*)clMoveChokeClamp, 4, PAGE_EXECUTE_READWRITE, &protect); + *(std::uint32_t*)clMoveChokeClamp = 62; + VirtualProtect((void*)clMoveChokeClamp, 4, protect, &protect); + } + else + { + auto clMoveChokeClamp = FindPatternV2("engine.dll", "B8 ? ? ? ? 3B F0 0F 4F F0 89 5D FC") + 1; + unsigned long protect = 0; + VirtualProtect((void*)clMoveChokeClamp, 4, PAGE_EXECUTE_READWRITE, &protect); + *(std::uint32_t*)clMoveChokeClamp = 15; + VirtualProtect((void*)clMoveChokeClamp, 4, protect, &protect); + } + } + + + // ImGui::Checkbox("Ping spike", g_Options.pingspike); + + ImGui::SliderFloat("Aimbot FOV", g_Options.aimbotfov, 0.0f, 360.0f); + ImGui::Checkbox("Auto shoot", g_Options.aimbotautoshoot); + + + ImGui::NextColumn(); //3 + + + ImGui::EndChild(); + } + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("About")) + { + static ImVec4 colwhite = { 0.8f, 0.8f, 0.8f, 1.0f }; + + style->ChildBorderSize = 0; style->WindowPadding = ImVec2(20.0f, 5.0f); + if (ImGui::BeginChild("ChildTab", ImVec2(665, 350), true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + style->ChildBorderSize = 1; style->WindowPadding = ImVec2(20.0f, 20.0f); + + ImGui::Columns(2, nullptr, false); + + ImGui::TextColored(colwhite, XorStr("Seaside")); + ImGui::Text(XorStr("Build October 13, 2023")); + ImGui::InvisibleButton("##inv", ImVec2(0, 0)); + ImGui::TextColored(colwhite, XorStr("Developer")); + ImGui::Text(XorStr("0TheSpy")); + ImGui::InvisibleButton("##inv", ImVec2(0, 0)); + ImGui::TextColored(colwhite, XorStr("Check for updates")); + ImGui::Text(XorStr("unknowncheats.me")); + + ImGui::InvisibleButton("##inv", ImVec2(0, 24)); + + if (ImGui::Button("Unhook", ImVec2(70, 22))) + opt.unhook = true; + + ImGui::SameLine(); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 20); + if (ImGui::Checkbox("Output debug messages", g_Options.debugstuff)) + { + if (*g_Options.debugstuff.value) + { + SetValueUnrestricted("developer", 1); + SetValueUnrestricted("sv_show_usermessage", 2); + } + else + { + SetValueUnrestricted("developer", 0); + SetValueUnrestricted("sv_show_usermessage", 0); + } + } + + ImGui::NextColumn(); + + static int selected = 0; + static char name[255] = ""; + + style->ItemSpacing = ImVec2(7.0f, 2.0f); + if (ImGui::BeginListBox("##cfgs", ImVec2(251.0f, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + ImGui::PushFont(ifontmini); + if (ImGui::BeginTable("split", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings )) + { + ImGui::TableSetColumnWidth(0, 10); + ImGui::TableSetColumnWidth(1, 80); + + for (int n = 0; n < Config::Get().configs.size(); n++) + { + bool isselected = selected == n; + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::Text(opt.autoconfig == n ? " *" : " "); + ImGui::TableNextColumn(); + + if (ImGui::Selectable(Config::Get().configs[n].c_str(), isselected, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, 0), true)) { + selected = n; + string namewithoutss = Config::Get().configs[n].substr(0, Config::Get().configs[n].size() - 3); + memcpy(name, namewithoutss.c_str(), 255); + } + ImGui::TableNextColumn(); + ImGui::Text(Config::Get().times[n].c_str()); + + if (isselected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndTable(); + } + ImGui::PushFont(ifont); + ImGui::EndListBox(); + } + style->ItemSpacing = ImVec2(7.0f, 15.0f); + + ImGui::InvisibleButton("##invis", ImVec2(0, 10.0f)); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 5.0f); + + ImGui::PushItemWidth(130.0f); + ImGui::InputText("File name", name, 255); + ImGui::PopItemWidth(); + ImGui::SameLine(); + bool isloadonstartup = opt.autoconfig == selected; + if (ImGui::Checkbox("Load on startup", &isloadonstartup)) + { + if (isloadonstartup) + { + ofstream autoload; + autoload.open("seaside_autoload"); + autoload << Config::Get().configs[selected]; + autoload.close(); + opt.autoconfig = selected; + } + else + { + if (remove("seaside_autoload") != 0) + perror("Error deleting file"); + else + { + puts("File successfully deleted"); + opt.autoconfig = -1; + + + + } + } + } + + if (ImGui::BeginTable("##tablexz", 2)) + { + ImGui::TableNextRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + + if (ImGui::Button("Create", ImVec2(70, 22))) + { + Config::Get().Create(name); + + Config::Get().FindAutoexec(); + + } + + DisableElements(Config::Get().configs.size(), 1); + if (ImGui::Button("Save", ImVec2(70, 22))) + Config::Get().Save(selected, name); + DisableElements(Config::Get().configs.size(), 0); + + if (ImGui::Button("Refresh", ImVec2(70, 22))) + { + Config::Get().Refresh(); + Config::Get().FindAutoexec(); + } + + ImGui::TableNextColumn(); + + DisableElements(Config::Get().configs.size(), 1); + + if (ImGui::Button("Delete", ImVec2(70, 22))) + { + Config::Get().Delete(selected); + if (selected >= Config::Get().configs.size()) selected = 0; + if (selected == opt.autoconfig) opt.autoconfig = -1; + + Config::Get().FindAutoexec(); + } + + if (ImGui::Button("Load", ImVec2(70, 22))) + Config::Get().Load(selected); + DisableElements(Config::Get().configs.size(), 0); + + if (ImGui::Button("Folder", ImVec2(70, 22))) + Config::Get().OpenFolder(); + + ImGui::EndTable(); + } + ImGui::Columns(1, nullptr, false); + + ImGui::TextColored(colwhite, " Author does not take any responsibility for bans caused by this software"); + ImGui::TextColored(colwhite, " Please use VAC Bypass for better protection"); + + ImGui::EndChild(); + } + + + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + ImGui::End(); + ImGui::EndFrame(); + ImGui::Render(); + ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); + } + + if (*g_Options.hitmarker && iff.g_pEngineClient->IsInGame()) { + iff.g_pDebugOverlay->ClearAllOverlays(); + for (int i = 0; i < bulletdata.size(); i++) { + Vector pos = bulletdata[i].pos; + float delta = bulletdata[i].time - bulletdata[i].curtime; + pos.z += delta * 35; + int alpha = 255; + if (bulletdata[i].time >= bulletdata[i].curtime + 0.70f) + alpha = int(850.0f * (-(delta - 1.0f))); + if (alpha < 0) alpha = 0; + if (!bulletdata[i].hs) + iff.g_pDebugOverlay->AddTextOverlayRGB(pos, 0, 0.09, 255, 50, 50, alpha, std::to_string(bulletdata[i].dmg).c_str()); + else + iff.g_pDebugOverlay->AddTextOverlayRGB(pos, 0, 0.09, 0, 255, 0, alpha, std::to_string(bulletdata[i].dmg).c_str()); + if (delta >= 1.000f) + bulletdata.erase(bulletdata.begin() + i); + bulletdata[i].time += iff.g_pGlobals->curtime - bulletdata[i].time; + } + } + + if (g_Options.aimbot && g_Options.aimbotfov <= 90) + { + if (iff.g_pEngineClient->IsInGame() && iff.pLocal && iff.pLocal->GetHealth() > 0) { + int width = 0, height = 0; + iff.g_pEngineClient->GetScreenSize(width, height); + + float radius = tanf(DEG2RAD(g_Options.aimbotfov) / 2) / tanf(DEG2RAD(g_Options.fov) / 2) * (width / 1.0f); + radius = radius * 0.75; //aspect ratio fix + + DrawCircle(pDevice, width / 2.0f, height / 2.0f, + radius, 0, 360, D3DCOLOR_ARGB(50, 255, 255, 0)); + } + } + + return oEndScene(pDevice); +} + + +``` + +`SpyCustom/NetVarManager.cpp`: + +```cpp +#include "NetVarManager.hpp" +#include + +#ifdef DUMP_NETVARS +#define IF_DUMPING(...) __VA_ARGS__ +#else +#define IF_DUMPING(...) +#endif + +IF_DUMPING(static FILE* s_fp;) + +netvar_manager::netvar_manager() +{ + IF_DUMPING(fopen_s(&s_fp, "netvar_dump.txt", "w");) + for (auto clazz = iff.g_pClient->GetAllClasses(); clazz; clazz = clazz->m_pNext) + if (clazz->m_pRecvTable) + dump_recursive(clazz->m_pNetworkName, clazz->m_pRecvTable, 0); + IF_DUMPING(fclose(s_fp);) +} + +auto netvar_manager::dump_recursive(const char* base_class, RecvTable* table, const std::uint16_t offset) -> void +{ + for (auto i = 0; i < table->m_nProps; ++i) + { + const auto prop_ptr = &table->m_pProps[i]; + + if (!prop_ptr || isdigit(prop_ptr->m_pVarName[0])) + continue; + + if (fnv::hash_runtime(prop_ptr->m_pVarName) == FNV("baseclass")) + continue; + + if (prop_ptr->m_RecvType == DPT_DataTable && + prop_ptr->m_pDataTable != nullptr && + prop_ptr->m_pDataTable->m_pNetTableName[0] == 'D') + { + dump_recursive(base_class, prop_ptr->m_pDataTable, std::uint16_t(offset + prop_ptr->m_Offset)); + } + + char hash_name[256]; + + strcpy_s(hash_name, base_class); + strcat_s(hash_name, "->"); + strcat_s(hash_name, prop_ptr->m_pVarName); + + const auto hash = fnv::hash_runtime(hash_name); + const auto total_offset = std::uint16_t(offset + prop_ptr->m_Offset); + + IF_DUMPING(fprintf(s_fp, "%s\t0x%04X\t%s\n", base_class, total_offset, prop_ptr->m_pVarName);) + + m_props[hash] = + { + prop_ptr, + total_offset + }; + } +} +``` + +`SpyCustom/NetVarManager.hpp`: + +```hpp +#ifndef NETVARMGR +#define NETVARMGR +#pragma once + +#include "sdk/cdll_int.h" +#include "sdk/dt_recv.h" +#include "sdk/client_class.h" +#include + +#include "Interfaces.hpp" + + +#include + +namespace detail +{ + template + struct size_dependant_data + { + using type = Type; + constexpr static auto k_offset_basis = OffsetBasis; + constexpr static auto k_prime = Prime; + }; + + template + struct size_selector; + + template <> + struct size_selector<32> + { + using type = size_dependant_data; + }; + + template <> + struct size_selector<64> + { + using type = size_dependant_data; + }; + + template + class fnv_hash + { + private: + using data_t = typename size_selector::type; + + public: + using hash = typename data_t::type; + + private: + constexpr static auto k_offset_basis = data_t::k_offset_basis; + constexpr static auto k_prime = data_t::k_prime; + + public: + template + static __forceinline constexpr auto hash_constexpr(const char(&str)[N], const std::size_t size = N) -> hash + { + return static_cast(1ull * (size == 1 + ? (k_offset_basis ^ str[0]) + : (hash_constexpr(str, size - 1) ^ str[size - 1])) * k_prime); + } + + static auto __forceinline hash_runtime(const char* str) -> hash + { + auto result = k_offset_basis; + do + { + result ^= *str++; + result *= k_prime; + } while (*(str - 1) != '\0'); + + return result; + } + }; +} + +namespace fnv2 { + constexpr uint32_t offsetBasis = 0x811c9dc5; + constexpr uint32_t prime = 0x1000193; + + constexpr uint32_t hash(const char* str, const uint32_t value = offsetBasis) noexcept + { + return *str ? hash(str + 1, (value ^ *str) * static_cast(prime)) : value; + } + + constexpr uint32_t hashRuntime(const char* str) noexcept + { + auto value = offsetBasis; + + while (*str) { + value ^= *str++; + value *= prime; + } + return value; + } +} + +using fnv = ::detail::fnv_hash; + +#define FNV(str) (std::integral_constant::value) + + +#include +#include + +class netvar_manager +{ +private: + struct stored_data + { + RecvProp* prop_ptr; + std::uint16_t class_relative_offset; + }; + +public: + static auto get() -> const netvar_manager& + { + static netvar_manager instance; + return instance; + } + + auto get_offset(const fnv::hash hash) const -> std::uint16_t + { + return m_props.at(hash).class_relative_offset; + } + + auto get_prop(const fnv::hash hash) const -> RecvProp* + { + return m_props.at(hash).prop_ptr; + } + + __declspec(noinline) static auto get_offset_by_hash(const fnv::hash hash) -> std::uint16_t + { + return get().get_offset(hash); + } + + template + static auto get_offset_by_hash_cached() -> std::uint16_t + { + static auto offset = std::uint16_t(0); + if (!offset) + offset = get_offset_by_hash(Hash); + return offset; + } + +private: + netvar_manager(); + auto dump_recursive(const char* base_class, RecvTable* table, std::uint16_t offset) -> void; + +private: + std::map m_props; +}; + + +#define PNETVAR_OFFSET(funcname, class_name, var_name, offset, ...) \ +auto funcname() -> std::add_pointer_t<__VA_ARGS__> \ +{ \ + constexpr auto hash = fnv::hash_constexpr(class_name "->" var_name); \ + const auto addr = std::uintptr_t(this) + offset + netvar_manager::get_offset_by_hash_cached(); \ + return reinterpret_cast>(addr); \ +} + +#define PNETVAR(funcname, class_name, var_name, ...) \ + PNETVAR_OFFSET(funcname, class_name, var_name, 0, __VA_ARGS__) + +#define NETVAR_OFFSET(funcname, class_name, var_name, offset, ...) \ +auto funcname() -> std::add_lvalue_reference_t<__VA_ARGS__> \ +{ \ + constexpr auto hash = fnv::hash_constexpr(class_name "->" var_name); \ + const auto addr = std::uintptr_t(this) + offset + netvar_manager::get_offset_by_hash_cached(); \ + return *reinterpret_cast>(addr); \ +} + +#define NETVAR(funcname, class_name, var_name, ...) \ + NETVAR_OFFSET(funcname, class_name, var_name, 0, __VA_ARGS__) + +#define NETPROP(funcname, class_name, var_name) \ +static auto funcname() -> RecvProp* \ +{ \ + constexpr auto hash = fnv::hash_constexpr(class_name "->" var_name); \ + static RecvProp* prop_ptr; \ + if(!prop_ptr) prop_ptr = netvar_manager::get().get_prop(hash); \ + return prop_ptr; \ +} + +class recv_prop_hook +{ +public: + recv_prop_hook(RecvProp* prop, const RecvVarProxyFn proxy_fn) : + m_property(prop), + m_original_proxy_fn(prop->m_ProxyFn) + { + set_proxy_function(proxy_fn); + } + + ~recv_prop_hook() + { + m_property->m_ProxyFn = m_original_proxy_fn; + } + + auto get_original_function() const -> RecvVarProxyFn + { + return m_original_proxy_fn; + } + + auto set_proxy_function(const RecvVarProxyFn proxy_fn) const -> void + { + m_property->m_ProxyFn = proxy_fn; + } + +private: + RecvProp* m_property; + RecvVarProxyFn m_original_proxy_fn; +}; + + + +#endif + +``` + +`SpyCustom/Options.hpp`: + +```hpp +#ifndef OPTIONS +#define OPTIONS +#pragma once + +#include +#include +#include +#include + +#define A( s ) #s +#define OPTION(type, var, val) Var var = {A(var), val} + + +template +class Var { +public: + std::string name; + std::shared_ptr value; + int32_t size; + Var(std::string name, T v) : name(name) { + value = std::make_shared(v); + size = sizeof(T); + } + operator T() { return *value; } + operator T* () { return &*value; } + operator T() const { return *value; } +}; + + +class float3 +{ +public: + float3() { r = 1.0f; g = 1.0f; b = 1.0f; a = 1.0f; } + float3(float r, float g, float b) + { + this->r = r; + this->g = g; + this->b = b; + } + float3(float r, float g, float b, float a) + { + this->r = r; + this->g = g; + this->b = b; + this->a = a; + } + float r = 1.0f; + float g = 1.0f; + float b = 1.0f; + float a = 1.0f; +}; + +class char256 +{ +public: + char256(std::string s) + { + strcpy(mystring, s.c_str()); + } + char mystring[256]; +}; + +class char1024 +{ +public: + char1024(std::string s) + { + strcpy(mystring, s.c_str()); + } + char mystring[1024]; +}; + +class sticker +{ +public: + bool isselected = 1; + char name[256] = "null"; + int stickerid = 0; + float wear = 0; + float rotation = 0; + float scale = 1.0f; + int stickerc = 0; + +}; + + +class Glow +{ +public: + Glow() {}; + Glow(char name1[256]) + { + strcpy(name, name1); + } + Glow(char name1[256], float3 color1) + { + strcpy(name, name1); + color = color1; + } + char name[256]; + bool enabled = false; + float3 color = { 1.f, 1.f, 1.f, 1.f }; + float alphamax = .5f; + int glowstyle = 0; + bool fullbloomrender = false; + bool isSelected = false; +}; + +class glowobjects +{ +public: + glowobjects() + { + int i = 0; + arr[i] = Glow("Enemies", float3(1.f, 0, 0, 1.f)); i++; + arr[i] = Glow("Allies", float3(0, 1.f, 0, 1.f)); i++; + itemcount = i; + } + Glow arr[64]; + int itemcount = 0; +}; + + +class weapon +{ +public: + weapon() {}; + weapon(char name1[256], int defindex1, char killfeedicon1[256]) + { + strcpy(name, name1); + strcpy(killfeedicon, killfeedicon1); + defindex = defindex1; + strcpy(killfeediconreplace, killfeedicon1); + + strcpy(stickers[0].name, "(0) null"); + strcpy(stickers[1].name, "(1) null"); + strcpy(stickers[2].name, "(2) null"); + strcpy(stickers[3].name, "(3) null"); + strcpy(stickers[4].name, "(4) null"); + modeldefindex = defindex; + } + char name[256] = ""; + int defindex = 0; + char killfeedicon[256] = ""; + + bool active = 0; + int skinid = 0; + int skinidc = 0; + int seed = 0; + int stattrak = -1; + bool ownerunk = 0; + float wear = 0; + int quality = 0; + int qualityc = 0; + char nametag[256] = ""; + char desctag[256] = ""; + char model[256] = ""; + char worldmodel[256] = ""; + int modeldefindex = 0; + bool modelactive = 0; + int modelcount = 0; + char killfeediconreplace[256] = ""; + bool killfeediconactive = 0; + + int rarity = 0; + int color1 = 0; + int color2 = 0; + int color3 = 0; + int color4 = 0; + float pearl = 0; + DWORD link = 0; + + sticker stickers[5]; + + + int isSelected = 0; +}; + + + +class weaponz +{ +public: + weaponz() + { + int i = 0; + arr[i] = weapon((char*)"Knife", WEAPON_KNIFE_T, (char*)"knife_t"); i++; + arr[i] = weapon((char*)"Glove", GLOVE_STUDDED_BLOODHOUND, (char*)"not_available"); i++; + arr[i] = weapon((char*)"Agent T", 5036, (char*)"not_available"); i++; + arr[i] = weapon((char*)"Agent CT", 5037, (char*)"not_available"); i++; + arr[i] = weapon((char*)"Medal", 1331, (char*)"not_available"); i++; + arr[i] = weapon((char*)"Music Kit", 1314, (char*)"not_available"); i++; + + arr[i] = weapon((char*)"AK-47", WEAPON_AK47, (char*)"ak47"); i++; + arr[i] = weapon((char*)"C4 Explosive", WEAPON_C4, (char*)"c4"); i++; + + arr[i] = weapon((char*)"Desert Eagle", WEAPON_DEAGLE, (char*)"deagle"); i++; + arr[i] = weapon((char*)"Dual Berettas", WEAPON_ELITE, (char*)"elite"); i++; + arr[i] = weapon((char*)"Five-SeveN", WEAPON_FIVESEVEN, (char*)"fiveseven"); i++; + arr[i] = weapon((char*)"Glock-18", WEAPON_GLOCK, (char*)"glock"); i++; + arr[i] = weapon((char*)"AUG", WEAPON_AUG, (char*)"aug"); i++; + arr[i] = weapon((char*)"AWP", WEAPON_AWP, (char*)"awp"); i++; + arr[i] = weapon((char*)"FAMAS", WEAPON_FAMAS, (char*)"famas"); i++; + arr[i] = weapon((char*)"G3SG1", WEAPON_G3SG1, (char*)"g3sg1"); i++; + arr[i] = weapon((char*)"Galil AR", WEAPON_GALILAR, (char*)"galilar"); i++; + arr[i] = weapon((char*)"M249", WEAPON_M249, (char*)"m249"); i++; + + arr[i] = weapon((char*)"M4A4", WEAPON_M4A1, (char*)"m4a1"); i++; + arr[i] = weapon((char*)"MAC-10", WEAPON_MAC10, (char*)"mac10"); i++; + arr[i] = weapon((char*)"P90", WEAPON_P90, (char*)"p90"); i++; + arr[i] = weapon((char*)"UMP-45", WEAPON_UMP45, (char*)"ump45"); i++; + arr[i] = weapon((char*)"XM1014", WEAPON_XM1014, (char*)"xm1014"); i++; + arr[i] = weapon((char*)"PP-Bizon", WEAPON_BIZON, (char*)"bizon"); i++; + arr[i] = weapon((char*)"MAG-7", WEAPON_MAG7, (char*)"mag7"); i++; + arr[i] = weapon((char*)"Negev", WEAPON_NEGEV, (char*)"negev"); i++; + arr[i] = weapon((char*)"Sawed-Off", WEAPON_SAWEDOFF, (char*)"sawedoff"); i++; + + arr[i] = weapon((char*)"Tec-9", WEAPON_TEC9, (char*)"tec9"); i++; + arr[i] = weapon((char*)"P2000", WEAPON_HKP2000, (char*)"hkp2000"); i++; + arr[i] = weapon((char*)"MP7", WEAPON_MP7, (char*)"mp7"); i++; + arr[i] = weapon((char*)"MP9", WEAPON_MP9, (char*)"mp9"); i++; + arr[i] = weapon((char*)"Nova", WEAPON_NOVA, (char*)"nova"); i++; + arr[i] = weapon((char*)"P250", WEAPON_P250, (char*)"p250"); i++; + arr[i] = weapon((char*)"SCAR-20", WEAPON_SCAR20, (char*)"scar20"); i++; + arr[i] = weapon((char*)"SG 553", WEAPON_SG553, (char*)"sg556"); i++; + arr[i] = weapon((char*)"SSG 08", WEAPON_SSG08, (char*)"ssg08"); i++; + + arr[i] = weapon((char*)"M4A1-S", WEAPON_M4A1_SILENCER, (char*)"m4a1_silencer"); i++; + arr[i] = weapon((char*)"USP-S", WEAPON_USP_SILENCER, (char*)"usp_silencer"); i++; + + arr[i] = weapon((char*)"CZ75-Auto", WEAPON_CZ75A, (char*)"cz75a"); i++; + arr[i] = weapon((char*)"RB Revolver", WEAPON_REVOLVER, (char*)"revolver"); i++; + + arr[i] = weapon((char*)"Custom item", 0, (char*)"not_available"); i++; + + weaponzcount = i; + } + + + weapon arr[64]; + int weaponzcount; +}; + + +class Rank +{ +public: + Rank() {}; + Rank(char Name1[256]) + { + strcpy(Name, Name1); + } + char Name[256] = ""; + int rank = 0; + int wins = 0; + int isselected = 0; +}; + +class Rankz +{ +public: + Rankz() + { + arr[0] = Rank((char*)"Competitive MM"); + arr[1] = Rank((char*)"Wingman"); + arr[2] = Rank((char*)"Danger Zone"); + } + Rank arr[3]; + int selectedrank = 0; +}; + + +#include "NetVarManager.hpp" + +class DME +{ +public: + DME() + { + }; + DME(char name1[256], int cust1 = -1) + { + strcpy(name, name1); + customtextureselected = cust1; + } + DME(char name1[256], char texture1[256], char model[256], int cust1 = -1) + { + strcpy(name, name1); + strcpy(texture, texture1); + strcpy(texture_temp, texture1); + model_hash = fnv2::hashRuntime(model); + customtextureselected = cust1; + } + + DME(char name[256], char prefab[32], int cust1 = -1) + { + strcpy(this->name, name); + strcpy(this->prefab, prefab); + customtextureselected = cust1; + } + + char texture_temp[256] = ""; + char texture[256] = ""; + char prefab[32]; + int model_hash = 0; + char name[256] = ""; + bool active = 0; + bool wireframe = 0; + bool nodraw = 0; + bool flat = 0; + bool ignorez = 0; + ImVec4 coloralpha = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + bool isSelected = 0; + int customtextureselected = -1; +}; + +class DMEs +{ +public: + DMEs() + { + int i = 0; + arr[i] = DME((char*)"Weapons", (char*)"(0) water", (char*)"", 0); i++; + arr[i] = DME((char*)"Glove", (char*)"(0) water", (char*)"", 0); i++; + arr[i] = DME((char*)"Sleeve", (char*)"(0) water", (char*)"", 0); i++; + arr[i] = DME((char*)"Agent T", (char*)"(0) water", (char*)"", 0); i++; + arr[i] = DME((char*)"Agent CT", (char*)"(0) water", (char*)"", 0); i++; + arr[i] = DME((char*)"Knife", (char*)"(0) water", (char*)"", 0); i++; + + arr[i] = DME((char*)"AK-47"); i++; + arr[i] = DME((char*)"C4 Explosive"); i++; + arr[i] = DME((char*)"Desert Eagle"); i++; + arr[i] = DME((char*)"Dual Berettas"); i++; + arr[i] = DME((char*)"Five-SeveN"); i++; + arr[i] = DME((char*)"Glock-18"); i++; + arr[i] = DME((char*)"AUG"); i++; + arr[i] = DME((char*)"AWP"); i++; + arr[i] = DME((char*)"FAMAS"); i++; + arr[i] = DME((char*)"G3SG1"); i++; + arr[i] = DME((char*)"Galil AR"); i++; + arr[i] = DME((char*)"M249"); i++; + arr[i] = DME((char*)"M4A4"); i++; + arr[i] = DME((char*)"MAC-10"); i++; + arr[i] = DME((char*)"P-90"); i++; + arr[i] = DME((char*)"UMP-45"); i++; + arr[i] = DME((char*)"XM1014"); i++; + arr[i] = DME((char*)"PP-Bizon"); i++; + arr[i] = DME((char*)"MAG-7"); i++; + arr[i] = DME((char*)"Negev"); i++; + arr[i] = DME((char*)"Sawed-Off"); i++; + arr[i] = DME((char*)"Tec-9"); i++; + arr[i] = DME((char*)"P2000"); i++; + arr[i] = DME((char*)"MP7"); i++; + arr[i] = DME((char*)"MP9"); i++; + arr[i] = DME((char*)"Nova"); i++; + arr[i] = DME((char*)"P250"); i++; + arr[i] = DME((char*)"SCAR-20"); i++; + arr[i] = DME((char*)"SG 553"); i++; + arr[i] = DME((char*)"SSG 08"); i++; + + itemcount = i; + }; + + int itemcount = 0; + DME arr[64]; +}; + + +class Customtexture +{ +public: + Customtexture() {}; + Customtexture(int id) + { + char preview1[64] = "("; + strcat_s(preview1, std::to_string(id).c_str()); + strcat_s(preview1, ") "); + strcat_s(preview1, "null"); + strcpy(Preview, preview1); + } + Customtexture(char name1[256], char keyvalue1[0x1000], int id) + { + strcpy(Name, name1); + char preview1[64] = "("; + strcat_s(preview1, std::to_string(id).c_str()); + strcat_s(preview1, ") "); + strcat_s(preview1, name1 ); + strcpy(Preview, preview1); + strcpy(keyvalue, keyvalue1); + } + char keyvalue[0x1000] = ""; + char Name[256] = ""; + char Preview[256] = ""; + bool IsSelected = 0; + + void* texturelink = nullptr; +}; + +class Customtextures +{ +public: + Customtextures() + { + int i = 0; + char buf[0x1000] = "\"Refract\"\n{\n\t\"$model\" 1\n\t\"$refractamount\" \"2.0\"\n\t\"$refracttint\" \"[0 1 1 100]\"\n\t\"$dudvmap\" \"dev/water_dudv\"\n\t\"$normalmap\" \"dev/water_normal\"\n\t\"$surfaceprop\" \"water\"\n\t\"$bumpframe\" \"0\"\n\t\"Proxies\"\n\t{\n\t\t\"AnimatedTexture\"\n\t\t{\n\t\t\t\"animatedtexturevar\" \"$normalmap\"\n\t\t\t\"animatedtextureframenumvar\" \"$bumpframe\"\n\t\t\t\"animatedtextureframerate\" 30.00\n\t\t}\n\t\t\"TextureScroll\"\n\t\t{\n\t\t\t\"texturescrollvar\" \"$bumptransform\"\n\t\t\t\"texturescrollrate\" .05\n\t\t\t\"texturescrollangle\" 45.00\n\t\t}\n\t}\n}"; + arr[i] = Customtexture((char*)"water", buf, i); i++; + arr[i] = Customtexture(i); i++; + arr[i] = Customtexture(i); i++; + arr[i] = Customtexture(i); i++; + arr[i] = Customtexture(i); i++; + count = i; + } + Customtexture arr[5]; + int count = 0; +}; + + +class Seqs +{ +public: + Seqs() {}; + int seq_orig = 0; + char seq_orig_def[32] = ""; + int seq_repl = 0; + char seq_repl_def[32] = ""; + + char seq_repl_def_preview[32] = ""; + + bool isSelected[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +}; + +class Sounds +{ +public: + Sounds() {}; + char name[32] = ""; + int hash = 0; + char wavpath[256] = "ui/beep07.wav"; + int pitch = 100; + float volume = 1.0f; +}; + +class Model +{ +public: + Model() {}; + + Model(char name[32]) + { + strcpy(this->name, name); + }; + + Model(char name[32], int defindex, char classid[32], char prefab[32]) + { + this->defindex = defindex; + strcpy(this->name, name); + strcpy(this->classid, classid); + strcpy(this->prefab, prefab); + }; + + Model(char name[32], int defindex, char classid[256], char vmodel_orig[32], bool s) + { + this->defindex = defindex; + strcpy(this->name, name); + strcpy(this->vmodel_orig, vmodel_orig); + strcpy(vmodel_repl_temp, vmodel_orig); + strcpy(vmodel_repl, vmodel_orig); + strcpy(this->classid, classid); + }; + + Model(char name[32], char vmodel[32]) + { + strcpy(this->name, name); + strcpy(this->vmodel_repl_temp, vmodel); + strcpy(this->vmodel_repl, vmodel); + }; + + bool findMDLmethode = false; + + char name[32] = ""; + + char vmodel_orig[256] = ""; + + char vmodel_repl_temp[256] = ""; + char wmodel_repl_temp[256] = ""; + + char vmodel_repl[256] = ""; + char wmodel_repl[256] = ""; + + int vmodel_hash = 0; + int wmodel_hash = 0; + + int defindex = 0; + bool active = 0; + bool active_w = 0; + bool active_scale = 0; + float scale = 1.0f; + + bool seq_active = 0; + Seqs seqs[20]; + + char classid[32] = ""; + + char prefab[32] = ""; + Sounds sounds[5]; + int soundcount = 0; + bool sound_active = 0; + + bool isSelected = 0; +}; + +class Models +{ +public: + Models() { + int i = 0; + + arr[i] = Model((char*)"Agent T", (char*)"models/player/zombie.mdl"); i++; + arr[i] = Model((char*)"Agent CT",(char*)"models/player/zombie.mdl"); i++; + arr[i] = Model((char*)"Arms"); i++; + + arr[i] = Model((char*)"Knife", WEAPON_KNIFE_T, (char*)"CKnife", (char*)"models/weapons/v_knife_default_t.mdl", 1); i++; + + arr[i] = Model((char*)"AK-47", WEAPON_AK47, (char*)"CAK47", (char*)"weapon_ak47_prefab"); i++; + arr[i] = Model((char*)"C4 Explosive", WEAPON_C4, (char*)"CC4", (char*)"c4"); i++; + arr[i] = Model((char*)"Desert Eagle", WEAPON_DEAGLE, (char*)"CWeaponDeagle", (char*)"weapon_deagle_prefab"); i++; + arr[i] = Model((char*)"Dual Berettas", WEAPON_ELITE, (char*)"CWeaponElite", (char*)"weapon_elite_prefab"); i++; + arr[i] = Model((char*)"Five-SeveN", WEAPON_FIVESEVEN, (char*)"CWeaponFiveSeven", (char*)"weapon_fiveseven_prefab"); i++; + arr[i] = Model((char*)"Glock-18", WEAPON_GLOCK, (char*)"CWeaponGlock", (char*)"weapon_glock_prefab"); i++; + arr[i] = Model((char*)"AUG", WEAPON_AUG, (char*)"CWeaponAug", (char*)"weapon_aug_prefab"); i++; + arr[i] = Model((char*)"AWP", WEAPON_AWP, (char*)"CWeaponAWP", (char*)"weapon_awp_prefab"); i++; + arr[i] = Model((char*)"FAMAS", WEAPON_FAMAS, (char*)"CWeaponFamas", (char*)"weapon_famas_prefab"); i++; + arr[i] = Model((char*)"G3SG1", WEAPON_G3SG1, (char*)"CWeaponG3SG1", (char*)"weapon_g3sg1_prefab"); i++; + arr[i] = Model((char*)"Galil AR", WEAPON_GALILAR, (char*)"CWeaponGalilAR", (char*)"weapon_galilar_prefab"); i++; + arr[i] = Model((char*)"M249", WEAPON_M249, (char*)"CWeaponM249", (char*)"weapon_m249_prefab"); i++; + arr[i] = Model((char*)"M4A4", WEAPON_M4A1, (char*)"CWeaponM4A1", (char*)"weapon_m4a1_prefab"); i++; + arr[i] = Model((char*)"MAC-10", WEAPON_MAC10, (char*)"CWeaponMAC10", (char*)"weapon_mac10_prefab"); i++; + arr[i] = Model((char*)"P-90", WEAPON_P90, (char*)"CWeaponP90", (char*)"weapon_p90_prefab"); i++; + arr[i] = Model((char*)"UMP-45", WEAPON_UMP45, (char*)"CWeaponUMP45", (char*)"weapon_ump45_prefab"); i++; + arr[i] = Model((char*)"XM1014", WEAPON_XM1014, (char*)"CWeaponXM1014", (char*)"weapon_xm1014_prefab"); i++; + arr[i] = Model((char*)"PP-Bizon", WEAPON_BIZON, (char*)"CWeaponBizon", (char*)"weapon_bizon_prefab"); i++; + arr[i] = Model((char*)"MAG-7", WEAPON_MAG7, (char*)"CWeaponMag7", (char*)"weapon_mag7_prefab"); i++; + arr[i] = Model((char*)"Negev", WEAPON_NEGEV, (char*)"CWeaponNegev", (char*)"weapon_negev_prefab"); i++; + arr[i] = Model((char*)"Sawed-Off", WEAPON_SAWEDOFF, (char*)"CWeaponSawedoff", (char*)"weapon_sawedoff_prefab"); i++; + arr[i] = Model((char*)"Tec-9", WEAPON_TEC9, (char*)"CWeaponTec9", (char*)"weapon_tec9_prefab"); i++; + arr[i] = Model((char*)"P2000", WEAPON_HKP2000, (char*)"CWeaponHKP2000", (char*)"weapon_hkp2000_prefab"); i++; + arr[i] = Model((char*)"MP7", WEAPON_MP7, (char*)"CWeaponMP7", (char*)"weapon_mp7_prefab"); i++; + arr[i] = Model((char*)"MP9", WEAPON_MP9, (char*)"CWeaponMP9", (char*)"weapon_mp9_prefab"); i++; + arr[i] = Model((char*)"Nova", WEAPON_NOVA, (char*)"CWeaponNOVA", (char*)"weapon_nova_prefab"); i++; + arr[i] = Model((char*)"P250", WEAPON_P250, (char*)"CWeaponP250", (char*)"weapon_p250_prefab"); i++; + arr[i] = Model((char*)"SCAR-20", WEAPON_SCAR20, (char*)"CWeaponSCAR20", (char*)"weapon_scar20_prefab"); i++; + arr[i] = Model((char*)"SG 553", WEAPON_SG553, (char*)"CWeaponSG556", (char*)"weapon_sg556_prefab"); i++; + arr[i] = Model((char*)"SSG 08", WEAPON_SSG08, (char*)"CWeaponSSG08", (char*)"weapon_ssg08_prefab"); i++; + + + + + itemcount = i; + } + Model arr[64]; + int itemcount = 0; +}; + + +class Effects +{ +public: + Effects() {}; + int type = 2; + int selectedc = 0; + + int fx_magnitude = 1; + int fx_traillength = 1; + float fx_fsize = 5.0f; + float fx_fspeed = 1.0f; + int fx_itype = 1; + bool fx_bexplosive = false; + + int icolors = 0; + int fflags = 0; + float fscale = 1.0f; + float fmagtinude = 1.0f; + float fradius = 1.0f; + + float fbeamwidth = 1.0f; + float teslaradius = 5.0f; + float teslacolor[3] = { 1.0f,0,0 }; + float fltimevisible = 0.75f; + int ibeams = 3; + char szSpriteName[256] = "sprites/physbeam.vmt"; + float dlightcolor[3] = { 1.0f,0,0 }; + float fdie = 0.1f; + float frad = 500.0f; + int style = 1; + int key = 1; + float decay = 0.0f; +}; + + +inline Vector CalcAngle(register const Vector& src, register const Vector& dst) +{ + Vector angles; + Vector delta = src - dst; + float hyp = sqrt(delta.x * delta.x + delta.y * delta.y); + angles.x = atan(delta.z / hyp) * (180.0f / pi_v); + angles.y = atanf(delta.y / delta.x) * (180.0f / pi_v) + !((*(DWORD*)&delta.x) >> 31 & 1) * 180.0f; + angles.z = 0.0f; + return angles; +} + +class Options +{ +public: + OPTION(bool, attacheffects, false); + OPTION(Effects, effects, Effects()); + OPTION(bool, beamtrace, false); + + OPTION(int, beamtype, 0); + OPTION(float3, beamcolor, float3(0.95f, 0.20f, 0.0f, 1.0f)); + + OPTION(char256, beampath, char256("sprites/purplelaser1.vmt")); + OPTION(float, beamlife, 1.0f); + + OPTION(float, beamwidth, 2.5f); + OPTION(float, beamendwidth, 2.5f); + + OPTION(float, beamhaloscale, 0.0f); + OPTION(float, beamfadelength, 0.3f); + + OPTION(float, beamamplitude, 5.0f); + OPTION(float, beamstartframe, 0.0f); + + OPTION(float, beamspeed, 0.3f); + OPTION(float, beamframerate, 1.0f); + + OPTION(int, beamsegments, 2); + OPTION(int, beamflags, 0x8300); + + OPTION(bool, hitsound, false); + OPTION(char256, hspath, char256("hitsound_crit.wav")); + OPTION(char256, obpath, char256("hitsound_cod.wav")); + + OPTION(bool, hitmarker, false); + + OPTION(bool, flashlightON, false); + OPTION(bool, flashlightShadows, false); + OPTION(float, flashlightFOV, 45.0f); + OPTION(float, flashlightLinearAtten, 1000.0f); + OPTION(float, flashlightFarZ, 1000.0f); + OPTION(char256, flashlightTexture, char256("effects/flashlight001")); + OPTION(bool, nvgsON, false); + OPTION(bool, fogactive, false); + OPTION(float3, fogcolor, float3(0,0,0) ); + OPTION(float, fogdensity, 0); + OPTION(float, fogstart, 0); + OPTION(float, fogend, 0); + OPTION(float, tonemapscale, 1.0f); + OPTION(bool, skyboxactive, false); + OPTION(char256, skyboxtemp, char256("sky_day02_05")); + + OPTION(bool, weatheractive, false); + OPTION(int, weathertype, 1); + OPTION(float, windspeed, 0); + OPTION(float, rainalpha, 0.4f); + OPTION(float, rainlength, 0.1f); + OPTION(float, rainwidth, 0.5f); + OPTION(float, rainsidevel, 130.0f); + OPTION(float, rainradius, 1500.0f); + OPTION(float, rainspeed, 600.0f); + + OPTION(bool, worldcoloractive, false); + OPTION(float3, worldcolor, float3(1.0f, 1.0f, 1.0f)); + OPTION(float3, staticpropcolor, float3(1.0f, 1.0f, 1.0f)); + OPTION(float3, modelcolor, float3(1.0f, 1.0f, 1.0f)); + OPTION(float3, smokeskycolor, float3(1.0f, 1.0f, 1.0f)); + OPTION(Models, models, Models()); + OPTION(int, soundhook_count, 0); + OPTION(int, entityloop_count, 0); + OPTION(int, playerloop_count, 0); + OPTION(DMEs, materials, DMEs()); + OPTION(Customtextures, customtextures, Customtextures()); + OPTION(bool, dme_gettextures, false); + OPTION(int, dmeloop_count, 0); + OPTION(weaponz, weapons, weaponz()); + OPTION(char1024, playername, char1024("Your name")); + OPTION(char1024, playerclan, char1024("Your tag")); + + OPTION(bool, discmsg_active, false); + OPTION(char1024, discmsg, char1024("SFUI_QMM_ERROR_VacBanned")); + + OPTION(bool, profile_active, false); + OPTION(bool, prime, false); + + OPTION(Rankz, rankz, Rankz()); + + OPTION(int, level, 0); + OPTION(int, xp, 0); + + OPTION(int, comleader, 0); + OPTION(int, comteacher, 0); + OPTION(int, comfriendly, 0); + + OPTION(bool, fakescore, 0); + OPTION(int, MVPs, 0); + OPTION(int, score, 0); + OPTION(int, kills, 0); + OPTION(int, assists, 0); + OPTION(int, deaths, 0); + + OPTION(bool, vacban, 0); + OPTION(int, banreason, 0); + OPTION(int, banduration, 0); + + OPTION(bool, votereveal, 0); + + OPTION(bool, postproc, false); + OPTION(float, fov, 90.0f); + OPTION(float, viewmodel_fov, 60.0f); + OPTION(float, viewmodel_x, 1.0f); + OPTION(float, viewmodel_y, 1.0f); + OPTION(float, viewmodel_z, -1.0f); + OPTION(float, viewmodel_ang_x, 0.0f); + OPTION(float, viewmodel_ang_y, 0.0f); + OPTION(float, viewmodel_ang_z, 0.0f); + OPTION(bool, lefthand, false); + OPTION(bool, viewmodel_moving, false); + OPTION(float, aspectratio, 0.0f); + OPTION(bool, shadows, false); + OPTION(float, ragdollgravity, 600.0f); + OPTION(float, ragdolltime, 1.0f); + OPTION(int, fullbright, 0); + OPTION(bool, drawgray, 0); + OPTION(bool, showlowresimage, 0); + + OPTION(bool, bunnyhop, 0); + OPTION(bool, autostrafe, 0); + OPTION(bool, slidewalk, 0); + OPTION(bool, fastduck, 0); + OPTION(int, changing_name, 0); + OPTION(bool, c4timer, 0); + OPTION(bool, rankreveal, 0); + OPTION(bool, speclist, 0); + OPTION(bool, debugstuff, 0); + OPTION(bool, faststop, 0); + OPTION(bool, moneyreveal, 0); + + OPTION(bool, predict, 0); + OPTION(bool, blockbot, 0); + OPTION(bool, fastladder, 0); + + OPTION(bool, rcs, 0); + OPTION(glowobjects, glowObjects, glowobjects()); + OPTION(bool, overhead, 0); + + OPTION(float, flashalpha, 255.0f); + OPTION(bool, wfsmoke, 0); + OPTION(int, fakelag, 0); + + OPTION(bool, backtrack, 0); + OPTION(bool, pingspike, 0); + OPTION(bool, nochokelimit, 0); + + OPTION(bool, aimbot, 0); + OPTION(bool, silentaim, 0); + OPTION(bool, aimbotautoshoot, 0); + OPTION(float, aimbotfov, 0.0f); +}; + +inline Options g_Options; +inline bool g_Unload; + +struct skin +{ + skin(bool active1, int skinid1, int seed1, int stattrak1, bool ownerunk1, float wear1, int quality1, char nametag1[256]) + { + active = active1; + skinid = skinid1; + seed = seed1; + stattrak = stattrak1; + ownerunk = ownerunk1; + wear = wear1; + quality = quality1; + strcpy(nametag, nametag1); + }; + + bool active = 0; + int skinid = 0; + int skinidc = 0; + int seed = 0; + int stattrak = -1; + bool ownerunk = 0; + float wear = 0; + int quality = 0; + int qualityc = 0; + char nametag[256] = ""; + char model[256] = ""; + char worldmodel[256] = ""; + int modeldefindex = 0; + bool modelactive = 0; + int modelcount = 0; + char killfeedicon[256] = ""; + char killfeediconorigin[256] = ""; + bool killfeediconactive = 0; +}; + + + + +class Options_my +{ +public: + + std::vector IEffects = { + "Smoke", + "Sparks", + "Dust", + "MuzzleFlash", + "MetalSparks", + "EnergySplash", + "Ricochet" + }; + + std::vector DispatchEffect = { + "Explosion", + "WaterSurfaceExplosion", + "HelicopterMegaBomb", + "CS_HolidayLight", + "ManhackSparks", + "watersplash", + "watersplashquiet", + "gunshotsplash", + "HunterDamage", + "MuzzleFlash", + "Smoke", + "GunshipImpact", + "BoltImpact", + "csblood", + "GlassImpact", + "RPGShotDown", + "WheelDust", + "Error" + }; + + std::vector OtherEff = { + "Tesla", + "DLight" + }; + + std::vector EffTypes = { + "CEffectsClient", + "CTEEffectDispatch", + "Other" + }; + + std::vector GlowStyles = { + "Default", + "RimGlow3D", + "Edge_Highlight", + "Edge_Highlight_Pulse" + }; + + std::map> Map = { + {"CEffectsClient", IEffects}, + {"CTEEffectDispatch", DispatchEffect}, + {"Other", OtherEff}, + }; + + + HMODULE hModuleGlobal = NULL; + + int needtogetseqact = 0; + bool netchannedlhooked = 0; + + bool disconnected = 0; + bool needupdate = 0; + bool loading = 0; + bool unhook = 0; + + std::vector names = { + "\\x10\\xAD\\xAD\\xAD" + }; + + std::vector skyboxitems = { + "sky_day02_05", + "cs_baggage_skybox_", + "cs_tibet", + "vietnam", + "sky_lunacy", + "embassy", + "italy", + "jungle", + "office", + "sky_cs15_daylight01_hdr", + "sky_cs15_daylight02_hdr", + "nukeblank", + "dustblank", + "sky_venice", + "sky_cs15_daylight03_hdr", + "sky_cs15_daylight04_hdr", + "sky_csgo_cloudy01", + "sky_csgo_night02", + "sky_csgo_night02b", + "vertigo", + "vertigoblue_hdr", + "sky_dust", + "sky_hr_aztec", + "sky_l4d_rural02_ldr", + "vertigo_hdr", + "sky_csgo_night_flat" + }; + + std::vector spriteslist = { + "sprites/purplelaser1.vmt", + "sprites/physbeam.vmt", + "sprites/purpleglow1.vmt", + "sprites/blueglow1.vmt", + "sprites/white.vmt", + "sprites/radio.vmt", + "sprites/gunsmoke.vmt", + "sprites/bubble.vmt" + }; + + + std::vector flashlightlist = { + "effects/flashlight_border", + "effects/flashlight_freezecam", + "effects/flashlight_inspect", + "effects/flashlight_security001", + "effects/flashlight001", + "effects/flashlight001_improved", + "effects/flashlight001_intro", + "effects/flashlight002", + "effects/autumn_access_denied_color", + "effects/coopphoenixloadingscreen", + "effects/combinemuzzle1", + "sprites/purpleglow1", + }; + + std::vector dmeitems = { + "(0) water", + "(1) null", + "(2) null", + "(3) null", + "(4) null", + "models/extras/speech_info", + "models/gibs/glass/glass", + "models/inventory_items/cologne_prediction/cologne_prediction_glass", + "models/inventory_items/contributor_map_tokens/contributor_charset_color", + "models/inventory_items/dogtags/dogtags", + "models/inventory_items/dogtags/dogtags_lightray", + "models/inventory_items/dogtags/dogtags_outline", + "models/inventory_items/dreamhack_trophies/dreamhack_star_blur", + "models/inventory_items/hydra_crystal/hydra_crystal", + "models/inventory_items/hydra_crystal/hydra_crystal_detail", + "models/inventory_items/music_kit/darude_01/mp3_detail", + "models/inventory_items/payback_gold_01/payback_gold_01", + "models/inventory_items/phoenix_gold_01/phoenix_gold_01", + "models/inventory_items/service_medal_2015/glass", + "models/inventory_items/service_medal_2016/glass_lvl4", + "models/inventory_items/sticker_inspect/sticker_backing", + "models/inventory_items/trophy_majors/crystal_blue", + "models/inventory_items/trophy_majors/crystal_clear", + "models/inventory_items/trophy_majors/gloss", + "models/inventory_items/trophy_majors/gold", + "models/inventory_items/trophy_majors/gold_dust", + "models/inventory_items/trophy_majors/silver_winners", + "models/inventory_items/vanguard_gold/vanguard_gold_detail", + "models/inventory_items/wildfire_gold/wildfire_gold_detail", + "models/player/ct_fbi/ct_fbi_glass", + "models/player/t_guerilla/t_guerilla", + "models/props_foliage/urban_tree03_branches", + "models/props_shacks/fishing_net01", + "models/weapons/customization/stickers/cologne2014/esl_c" + }; + + + + std::vector killfeedicons = { + "Default" + }; + + + + char sc_selectedweapon[256]; + bool sc_active1 = false; + int sc_seed1 = 0; + int sc_stattrak1 = 0; + bool sc_unk1 = false; + char sc_selectedskin[256]; + + struct stickerstruct + { + stickerstruct(int id1, std::string Name1, int count1) + { + id = id1; + Name = Name1; + count = count1; + Preview = std::to_string(id).append(": ").append(Name1); + } + int id; + std::string Name; + int count; + bool isSelected; + std::string Preview; + }; + + std::vector sc_stickers = + { + + }; + + struct skinstruct + { + skinstruct(int id1, std::string Name1, int count1, int rarity1, int color11, int color21, int color31, int color41, float pearl1, DWORD link1) + { + id = id1; + Name = Name1; + isSelected = 0; + count = count1; + Preview = std::to_string(id).append(": ").append(Name1); + rarity = rarity1; + color1 = color11; + color2 = color21; + color3 = color31; + color4 = color41; + pearl = pearl1; + link = link1; + } + int id; + std::string Name; + bool isSelected; + int count; + std::string Preview; + int rarity; + int color1; + int color2; + int color3; + int color4; + float pearl; + DWORD link; + }; + + std::vector sc_skins = + { + + }; + + struct selectedweapon + { + selectedweapon(std::string Name1, std::string icon1) + { + Name = Name1; + isSelected = 0; + icon = icon1; + }; + std::string Name; + std::string icon; + bool isSelected; + }; + + bool show = false; + int autoconfig = -1; +}; + +inline Options_my opt; + + +#define SOUND_ENTRY_HASH_SEED 0x444F5441 + +inline uint32 GenerateSoundEntryHash(char const* pSoundEntry) +{ + int nSoundEntryLength = strlen(pSoundEntry); + char* pSoundEntryLowerCase = (char*)stackalloc(nSoundEntryLength + 1); + + for (int nIndex = 0; nIndex < nSoundEntryLength; nIndex++) + pSoundEntryLowerCase[nIndex] = tolower(pSoundEntry[nIndex]); + + const uint32 nMagicNumber = 0x5bd1e995; + + uint32 nSoundHash = SOUND_ENTRY_HASH_SEED ^ nSoundEntryLength; + + unsigned char* pData = (unsigned char*)pSoundEntryLowerCase; + + while (nSoundEntryLength >= 4) + { + uint32 nLittleDWord = LittleDWord(*(uint32*)pData); + + nLittleDWord *= nMagicNumber; + nLittleDWord ^= nLittleDWord >> 24; + nLittleDWord *= nMagicNumber; + + nSoundHash *= nMagicNumber; + nSoundHash ^= nLittleDWord; + + pData += 4; + nSoundEntryLength -= 4; + } + + switch (nSoundEntryLength) + { + case 3: nSoundHash ^= pData[2] << 16; + case 2: nSoundHash ^= pData[1] << 8; + case 1: nSoundHash ^= pData[0]; + nSoundHash *= nMagicNumber; + }; + + nSoundHash ^= nSoundHash >> 13; + nSoundHash *= nMagicNumber; + nSoundHash ^= nSoundHash >> 15; + + return nSoundHash; +} + + +inline int GetCfgIndexByClassId(int ClassID) { + for (int i = 0; i < g_Options.models.value->itemcount; i++) + { + if (fnv2::hash(g_Options.models.value->arr[i].classid) == ClassID) + return i; + } + return -1; +} + + +inline int GetCfgIndexByPrefab(int Prefab) { + for (int i = 4; i < g_Options.models.value->itemcount; i++) + { + if (fnv2::hash(g_Options.models.value->arr[i].prefab) == Prefab) + return i; + } + return -1; +} + + +inline int GetCfgIndex(int item_definition_index) +{ + for (int i = 0; i < g_Options.weapons.value->weaponzcount; i++) + { + if (g_Options.weapons.value->arr[i].defindex == item_definition_index) + return i; + } + return -1; +} + +inline int GetCfgIndex2(int item_definition_index) +{ + for (int i = 2; i < g_Options.models.value->itemcount; i++) + { + if (g_Options.models.value->arr[i].defindex == item_definition_index) + return i; + } + return -1; +} + + +struct soundlist +{ + soundlist(int cfgindex = 0, int sndindex = 0) + { + this->cfgindex = cfgindex; + this->sndindex = sndindex; + } + int cfgindex = 0; + int sndindex = 0; +}; + +inline soundlist GetCfgWavpathBySoundHash(int Hash) { + for (int i = 3; i < g_Options.models.value->itemcount; i++) + { + for (int j = 0; j < g_Options.models.value->arr[i].soundcount; j++) + if (g_Options.models.value->arr[i].sounds[j].hash == Hash) + if (g_Options.models.value->arr[i].sound_active) + return soundlist(i, j); + else return soundlist(-1, 0); + } + return soundlist(-1, 0); +} + + + +void OnLoadCfg(); +void OnLevelInit(); + + + + + + + + +#endif + +``` + +`SpyCustom/Other.cpp`: + +```cpp +#include "Other.hpp" +#include "PatternScan.hpp" + + + +void UpdateFlashLight(CFlashlightEffect* pFlashLight, const Vector& vecPos, const Vector& vecForward, const Vector& vecRight, const Vector& vecUp) +{ + typedef void(__thiscall* UpdateLight_t)(void*, int, const Vector&, const Vector&, const Vector&, const Vector&, float, float, float, bool, const char*); + + static UpdateLight_t oUpdateLight = NULL; + + if (!oUpdateLight) + { + DWORD callInstruction = FindPatternV2("client.dll", "E8 ? ?? ? ? 8B 06 F3 0F 10 46"); + DWORD relativeAddress = *(DWORD*)(callInstruction + 1); + DWORD nextInstruction = callInstruction + 5; + oUpdateLight = (UpdateLight_t)(nextInstruction + relativeAddress); + } + + oUpdateLight(pFlashLight, pFlashLight->m_nEntIndex, vecPos, vecForward, vecRight, vecUp, + pFlashLight->m_flFov, pFlashLight->m_flFarZ, pFlashLight->m_flLinearAtten, pFlashLight->m_bCastsShadows, + pFlashLight->m_textureName); +} + + +CFlashlightEffect* CreateFlashLight(int nEntIndex, const char* pszTextureName, float flFov, float flFarZ, float flLinearAtten) +{ + + CFlashlightEffect* pFlashLight = reinterpret_cast(iff.g_pMemAlloc->Alloc(sizeof(CFlashlightEffect))); + + if (!pFlashLight) + return NULL; + + static DWORD oConstructor = FindPatternV2("client.dll", "55 8B EC F3 0F 10 45 ? B8"); + + __asm + { + movss xmm3, flFov + mov ecx, pFlashLight + push flLinearAtten + push flFarZ + push pszTextureName + push nEntIndex + call oConstructor + } + pFlashLight->m_bIsOn = true; + + + return pFlashLight; +} + +void DestroyFlashLight(CFlashlightEffect* pFlashLight) +{ + static DWORD oDestructor = FindPatternV2("client.dll", "56 8B F1 E8 ? ? ? ? 8B 4E 28"); + + __asm + { + mov ecx, pFlashLight + push ecx + call oDestructor + } + +} + +void AngleVectors(const Vector& angles, Vector* forward, Vector* right, Vector* up) +{ + 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); + + 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; + } +} + + +static bool ssToggleButton(ButtonCode_t code) +{ + static int buttonPressedTick = 0; + if (iff.g_pInputSystem->IsButtonDown(code) && (GetTickCount64() - buttonPressedTick) > 300) + { + buttonPressedTick = GetTickCount64(); + return true; + } + return false; +} + +void FlashlightRun(C_BasePlayer* local) +{ + static CFlashlightEffect* pFlashLight = NULL; + + if (opt.disconnected) + { + printfdbg("nullify pFlashlight bc disconnected\n"); + pFlashLight = NULL; + opt.disconnected = 0; + } + + if (ssToggleButton(KEY_L)) + { + if (!pFlashLight) + { + printfdbg("creating fl\n"); + pFlashLight = CreateFlashLight(local->GetIndex(), g_Options.flashlightTexture.value->mystring, *g_Options.flashlightFOV, *g_Options.flashlightFarZ, *g_Options.flashlightLinearAtten); + iff.g_pEngineClient->ExecuteClientCmd("play items/flashlight1.wav"); + } + else + { + printfdbg("destroying fl\n"); + DestroyFlashLight(pFlashLight); + pFlashLight = NULL; + iff.g_pEngineClient->ExecuteClientCmd("play items/flashlight1.wav"); + } + } + + if (pFlashLight) + { + Vector f, r, u; + Vector viewAngles; + + iff.g_pEngineClient->GetViewAngles(viewAngles); + AngleVectors(viewAngles, &f, &r, &u); + + pFlashLight->m_bIsOn = true; + pFlashLight->m_bCastsShadows = *g_Options.flashlightShadows; + pFlashLight->m_flFov = *g_Options.flashlightFOV; + + UpdateFlashLight(pFlashLight, local->GetOrigin() + local->GetViewOffset(), f, r, u); + + } +} + + +#define DRAW_SCREEN_EFFECT(material) \ +{ \ + const auto drawFunction = relativeToAbsolute(FindPatternV2("client.dll", "E8 ? ? ? ? 83 C4 0C 8D 4D F8") + 1); \ + int w, h; \ + iff.g_pVGuiSurface->GetScreenSize(w, h); \ + __asm { \ + __asm push h \ + __asm push w \ + __asm push 0 \ + __asm xor edx, edx \ + __asm mov ecx, material \ + __asm call drawFunction \ + __asm add esp, 12 \ + } \ +} + +void NightvisionRun(C_BasePlayer* local) { + + static int m_flNightVisionAlpha = NetvarSys::Get().GetOffset("DT_CSPlayer", "m_flFlashDuration") - 0x1C; + + if (ssToggleButton(KEY_N) ) + { + if (!local->GetNightvision()) + { + local->GetNightvision() = true; + *(float*)(uintptr_t(local) + m_flNightVisionAlpha) = 1.0f; + iff.g_pEngineClient->ExecuteClientCmd("play items/nvg_on.wav"); + + } + else + { + local->GetNightvision() = false; + *(float*)(uintptr_t(local) + m_flNightVisionAlpha) = 0; + iff.g_pEngineClient->ExecuteClientCmd("play items/nvg_off.wav"); + } + } +} + + +void do_precipitation() { + static void* rain_networkable = nullptr; + C_Precipitation* rain_ent = (C_Precipitation*)iff.g_pEntityList->GetClientEntity(MAX_EDICTS - 1); + static ClientClass* precipitation_client_class = nullptr; + + + + + if (!iff.g_pEngineClient->IsInGame() || !iff.g_pEngineClient->IsConnected()) { + rain_networkable = rain_ent = nullptr; + return; + } + + int localplayer_index = iff.g_pEngineClient->GetLocalPlayer(); + C_BasePlayer* localplayer = static_cast(iff.g_pEntityList->GetClientEntity(localplayer_index)); + if (!localplayer) return; + + if (!(localplayer->GetLifeState() == LIFE_ALIVE && localplayer->GetHealth() > 0)) + return; + + + + if (!precipitation_client_class) { + for (auto pclass = iff.g_pClient->GetAllClasses(); pclass && !precipitation_client_class; pclass = pclass->m_pNext) + if (strstr(pclass->GetName(), "CPrecipitation")) + { + printfdbg("class found %x\n", pclass); + precipitation_client_class = pclass; + } + + } + + + else { + if (!rain_ent && precipitation_client_class && precipitation_client_class->m_pCreateFn) { + + printfdbg("Creating precipitation\n"); + + rain_networkable = ((void* (*)(int, int))precipitation_client_class->m_pCreateFn)(MAX_EDICTS - 1, 0); + + if (rain_networkable) { + rain_ent = (C_Precipitation*)iff.g_pEntityList->GetClientEntity(MAX_EDICTS - 1); + + rain_ent->GetPrecipitationType() = (PrecipitationType_t)*g_Options.weathertype; + + rain_ent->PreDataUpdate(DataUpdateType_t::DATA_UPDATE_CREATED); + rain_ent->OnPreDataChanged(DataUpdateType_t::DATA_UPDATE_CREATED); + + rain_ent->GetMins() = Vector(-32767.0f, -32767.0f, -32767.0f); + rain_ent->GetMaxs() = Vector(32767.0f, 32767.0f, 32767.0f); + + auto collid = rain_ent->GetCollideable(); + collid->OBBMins_() = Vector(-32767.0f, -32767.0f, -32767.0f); + collid->OBBMaxs_() = Vector(32767.0f, 32767.0f, 32767.0f); + + rain_ent->OnDataChanged(DataUpdateType_t::DATA_UPDATE_CREATED); + rain_ent->PostDataUpdate(DataUpdateType_t::DATA_UPDATE_CREATED); + + printfdbg("Created precipitation %x\n", rain_ent); + } + } + } + +} + + + +``` + +`SpyCustom/Other.hpp`: + +```hpp +#ifndef OTHER +#define OTHER +#pragma once + +#include "Interfaces.hpp" +#include "Options.hpp" + +#include "sdk/c_baseentity.h" + +void FlashlightRun(C_BasePlayer* local); +void NightvisionRun(C_BasePlayer* local); + +void do_precipitation(); + +#endif OTHER +``` + +`SpyCustom/PatternScan.cpp`: + +```cpp +#include "PatternScan.hpp" + + +DWORD WaitOnModuleHandle(std::string moduleName) +{ + DWORD ModuleHandle = NULL; + while (!ModuleHandle) + { + ModuleHandle = (DWORD)GetModuleHandle(moduleName.c_str()); + if (!ModuleHandle) + Sleep(50); + } + return ModuleHandle; +} + +DWORD FindPatternV2_(std::string moduleName, std::string pattern) +{ + const char* pat = pattern.c_str(); + DWORD firstMatch = 0; + DWORD rangeStart = (DWORD)GetModuleHandleA(moduleName.c_str()); + MODULEINFO miModInfo; GetModuleInformation(GetCurrentProcess(), (HMODULE)rangeStart, &miModInfo, sizeof(MODULEINFO)); + DWORD rangeEnd = rangeStart + miModInfo.SizeOfImage; + for (DWORD pCur = rangeStart; pCur < rangeEnd; pCur++) + { + if (!*pat) { + printfdbg("FP %s: Found %s at %x\n", moduleName.c_str(), pattern.c_str(), firstMatch); + return firstMatch; + } + + if (*(PBYTE)pat == '\?' || *(BYTE*)pCur == getByte(pat)) + { + if (!firstMatch) + firstMatch = pCur; + + if (!pat[2]) { + printfdbg("FP %s: Found %s at %x\n", moduleName.c_str(), pattern.c_str(), firstMatch); + return firstMatch; + } + + if (*(PWORD)pat == '\?\?' || *(PBYTE)pat != '\?') + pat += 3; + + else + pat += 2; + } + else + { + pat = pattern.c_str(); + firstMatch = 0; + } + } + printfdbg("FP %s: Nothing found! %s\n", moduleName.c_str(), pattern.c_str()); + return NULL; +} + +bool bCompare(const BYTE* Data, const BYTE* Mask, const char* szMask) +{ + for (; *szMask; ++szMask, ++Mask, ++Data) + { + if (*szMask == 'x' && *Mask != *Data) + { + return false; + } + } + return (*szMask) == 0; +} + +DWORD FindPattern(std::string moduleName, BYTE* Mask, char* szMask) +{ + DWORD Address = WaitOnModuleHandle(moduleName.c_str()); + MODULEINFO ModInfo; GetModuleInformation(GetCurrentProcess(), (HMODULE)Address, &ModInfo, sizeof(MODULEINFO)); + DWORD Length = ModInfo.SizeOfImage; + for (DWORD c = 0; c < Length; c += 1) + { + if (bCompare((BYTE*)(Address + c), Mask, szMask)) + { + return (DWORD)(Address + c); + } + } + return 0; +} + +``` + +`SpyCustom/PatternScan.hpp`: + +```hpp +#ifndef PATTERNSCAN +#define PATTERNSCAN +#pragma once + +#include +#include +#include +#include "XorStr.hpp" +#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 getByte( x ) (getBits(x[0]) << 4 | getBits(x[1])) + +#define FindPatternV2(data1, data2) FindPatternV2_(XorStr(data1), XorStr(data2)) + +DWORD WaitOnModuleHandle(std::string moduleName); +DWORD FindPatternV2_(std::string moduleName, std::string pattern); +bool bCompare(const BYTE* Data, const BYTE* Mask, const char* szMask); +DWORD FindPattern(std::string moduleName, BYTE* Mask, char* szMask); + +#include "Interfaces.hpp" + +#endif + + +``` + +`SpyCustom/PlayerInventory.cpp`: + +```cpp +#include "PlayerInventory.hpp" + + +void CSharedObjectTypeCache::AddObject(void* obj) +{ + typedef void(__thiscall* tOriginal)(void*, void*); + getvfunc(this, 1)(this, obj); +} + +void CSharedObjectTypeCache::RemoveObject(void* obj) +{ + typedef void(__thiscall* tOriginal)(void*, void*); + getvfunc(this, 3)(this, obj); +} + +std::vector CSharedObjectTypeCache::GetEconItems() +{ + std::vector ret; + + auto size = *reinterpret_cast(this + 0x18); + + auto data = *reinterpret_cast(this + 0x4); + + for (size_t i = 0; i < size; i++) + ret.push_back(reinterpret_cast(data[i])); + + return ret; +} + + +template +void CEconItem::SetAttributeValue(int index, TYPE val) +{ + auto v15 = (DWORD*)GetItemSchema(); + auto v16 = *(DWORD*)(v15[72] + 4 * index); + + static auto fnSetDynamicAttributeValue + = reinterpret_cast( + FindPatternV2("client.dll", "55 8B EC 83 E4 F8 83 EC 3C 53 8B 5D 08 56 57 6A 00") + ); + + fnSetDynamicAttributeValue(this, v16, &val); +} + + + + +int C_EconItemDefinition::get_equipped_position() +{ + return *reinterpret_cast(reinterpret_cast(this) + 0x24C); +} + +const char* C_EconItemDefinition::get_world_model_name() +{ + return *reinterpret_cast(uintptr_t(this) + 0x9C); +} + + + + + +uint32_t* CEconItem::GetAccountID() +{ + return reinterpret_cast(this + 0x1C); +} +uint64_t* CEconItem::GetItemID() +{ + return reinterpret_cast(this + 0x8); +} + +uint64_t* CEconItem::GetOriginalID() +{ + return reinterpret_cast(this + 0x10); +} + +uint16_t* CEconItem::GetDefIndex() +{ + return reinterpret_cast(this + 0x24); +} + +uint32_t* CEconItem::GetInventory() +{ + return reinterpret_cast(this + 0x20); +} + +unsigned char* CEconItem::GetFlags() +{ + return reinterpret_cast(this + 0x30); +} + +unsigned short* CEconItem::GetEconItemData() +{ + return reinterpret_cast(this + 0x26); +} + + + +C_EconItemDefinition* C_EconItemView::get_static_data() +{ + static auto fn = reinterpret_cast(FindPatternV2("client.dll", "55 8B EC 51 53 8B D9 8B ? ? ? ? ? 56 57 8B ? ? ? ? ? 85 FF 74 16")); + + return fn(this); +} + + +CEconItem* C_EconItemView::get_soc_data() +{ + static auto fn = reinterpret_cast(FindPatternV2("client.dll", "55 8B EC 83 E4 F0 83 EC 18 56 8B F1 57 8B 86")); + + return fn(this); +} + + + +void CPlayerInventory::RemoveItem(uint64_t ID) +{ + static auto fnRemoveItem + = reinterpret_cast( + FindPatternV2("client.dll", "55 8B EC 83 E4 F8 56 57 FF 75 0C 8B F1") + ); + + fnRemoveItem(this, ID); +} + +CSharedObjectTypeCache* CPlayerInventory::GetBaseTypeCache() +{ + static auto fnGCSDK_CGCClient_FindSOCache + = reinterpret_cast( + FindPatternV2("client.dll", "55 8B EC 83 E4 F8 83 EC 1C 0F 10 45 08") + ); + + static auto fnGCSDK_CSharedObjectCache_CreateBaseTypeCache + = reinterpret_cast( + FindPatternV2("client.dll", "55 8B EC 51 53 56 8B D9 8D 45 08") + ); + + static auto g_GCClientSystem = **reinterpret_cast(FindPatternV2("client.dll", "8B 0D ? ? ? ? 6A 00 83 EC 10") + 0x2); + auto SOCahce = fnGCSDK_CGCClient_FindSOCache(g_GCClientSystem + 0x60, *reinterpret_cast(this + 0x8), *reinterpret_cast(this + 0x10), 0); + + return fnGCSDK_CSharedObjectCache_CreateBaseTypeCache(SOCahce, 1); +} + +void CPlayerInventory::RemoveItem(CEconItem* item) +{ + RemoveItem(*item->GetItemID()); + GetBaseTypeCache()->RemoveObject(item); +} + +void CPlayerInventory::ClearInventory() +{ + auto BaseTypeCache = this->GetBaseTypeCache(); + auto items = BaseTypeCache->GetEconItems(); + for (auto item : items) + { + RemoveItem(*item->GetItemID()); + BaseTypeCache->RemoveObject(item); + } +} + +uint32_t CPlayerInventory::GetSteamID() +{ + return *reinterpret_cast(this + 0x8); +} + +CUtlVector< C_EconItemView* >* CPlayerInventory::GetInventoryItems() +{ + return reinterpret_cast*>(this + 0x2C); +} + +bool CPlayerInventory::AddEconItem(CEconItem* item, int a3, int a4, char a5) +{ + static auto fnAddEconItem + = reinterpret_cast( + FindPatternV2("client.dll", "55 8B EC 83 E4 F8 A1 ? ? ? ? 83 EC 14 53 56 57 8B F9 8B 08") + ); + + GetBaseTypeCache()->AddObject(item); + + + auto ret = fnAddEconItem(this, item, a3, a4, a5); + + return ret; +} + + +CPlayerInventory* CSInventoryManager::GetLocalPlayerInventory() +{ + static auto local_inventory_offset = *reinterpret_cast(FindPatternV2("client.dll", "8B 8B ? ? ? ? E8 ? ? ? ? 89 44 24 18") + 0x2); + return *reinterpret_cast(this + local_inventory_offset); +} + +CEconItem* CreateEconItem() +{ + static auto fnCreateSharedObjectSubclass_EconItem_ + = reinterpret_cast( + *reinterpret_cast(FindPatternV2("client.dll", "C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? E8 ? ? ? ? 83 F8 FF 75 09 8D 45 E4 50 E8 ? ? ? ? 8D 45 E4 C7 45 ? ? ? ? ? 50 C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? E8 ? ? ? ? 83 F8 FF 75 09 8D 45 E4 50 E8 ? ? ? ? 8D 45 E4 C7 45 ? ? ? ? ? 50 C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? E8 ? ? ? ? 83 F8 FF 75 09 8D 45 E4 50 E8 ? ? ? ? 8D 45 E4 C7 45 ? ? ? ? ? 50 C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? E8 ? ? ? ? 83 F8 FF 75 09 8D 45 E4 50 E8 ? ? ? ? 8D 45 E4") + 3) + ); + return fnCreateSharedObjectSubclass_EconItem_(); +} +uintptr_t GetItemSchema() +{ + static auto fnGetItemSchema + = reinterpret_cast( + FindPatternV2("client.dll", "A1 ? ? ? ? 85 C0 75 53") + ); + return fnGetItemSchema(); +} + +``` + +`SpyCustom/PlayerInventory.hpp`: + +```hpp +#ifndef PLAYERINV +#define PLAYERINV +#pragma once + +#include "PatternScan.hpp" +#include "Interfaces.hpp" + +#include "sdk/utlvector.h" +#include "stdint.h" +#include + +#include "sdk/icliententity.h" + + + +enum ItemQuality +{ + ITEM_QUALITY_DEFAULT, + ITEM_QUALITY_GENUINE, + ITEM_QUALITY_VINTAGE, + ITEM_QUALITY_UNUSUAL, + ITEM_QUALITY_SKIN, + ITEM_QUALITY_COMMUNITY, + ITEM_QUALITY_DEVELOPER, + ITEM_QUALITY_SELFMADE, + ITEM_QUALITY_CUSTOMIZED, + ITEM_QUALITY_STRANGE, + ITEM_QUALITY_COMPLETED, + ITEM_QUALITY_UNK2, + ITEM_QUALITY_TOURNAMENT +}; + +enum ItemRarity +{ + ITEM_RARITY_DEFAULT, + ITEM_RARITY_COMMON, + ITEM_RARITY_UNCOMMON, + ITEM_RARITY_RARE, + ITEM_RARITY_MYTHICAL, + ITEM_RARITY_LEGENDARY, + ITEM_RARITY_ANCIENT, + ITEM_RARITY_IMMORTAL +}; + +class CEconItem +{ + unsigned short* GetEconItemData(); + void UpdateEquippedState(unsigned int state); +public: + uint32_t* GetInventory(); + uint32_t* GetAccountID(); + uint16_t* GetDefIndex(); + uint64_t* GetItemID(); + uint64_t* GetOriginalID(); + unsigned char* GetFlags(); + void SetQuality(ItemQuality quality); + void SetRarity(ItemRarity rarity); + void SetOrigin(int origin); + void SetLevel(int level); + void SetInUse(bool in_use); + void SetCustomName(const char* name); + void SetCustomDesc(const char* name); + void SetPaintSeed(float seed); + void SetPaintKit(float kit); + void SetPaintWear(float wear); + void SetStatTrak(int val); + void AddSticker(int index, int kit, float wear, float scale, float rotation); + + template + void SetAttributeValue(int index, TYPE val); + +}; + +class C_EconItemDefinition +{ +public: + int get_equipped_position(); + const char* get_world_model_name(); +}; + +class C_EconItemView +{ +private: + using str_32 = char[32]; +public: + int32_t m_bInitialized; + int16_t m_iItemDefinitionIndex; + int32_t m_iEntityLevel; + int32_t m_iAccountID; + int32_t m_iItemIDLow; + int32_t m_iItemIDHigh; + int32_t m_iEntityQuality; + str_32 m_iCustomName; + + CUtlVector& m_CustomMaterials(); + CUtlVector& m_VisualsDataProcessors(); + + C_EconItemDefinition* get_static_data(); + CEconItem* get_soc_data(); +}; + + +class CSharedObjectTypeCache +{ +public: + void AddObject(void* obj); + void RemoveObject(void* obj); + std::vector GetEconItems(); +}; + + +class CPlayerInventory +{ +public: + void RemoveItem(uint64_t ID); + void RemoveItem(CEconItem* item); + void ClearInventory(); + CSharedObjectTypeCache* GetBaseTypeCache(); + uint32_t GetSteamID(); + CUtlVector* GetInventoryItems(); + bool AddEconItem(CEconItem* item, int a3, int a4, char a5); +}; + + +class CSInventoryManager +{ +public: + CPlayerInventory* GetLocalPlayerInventory(); +}; + + +uintptr_t GetItemSchema(); +CEconItem* CreateEconItem(); + + + + +#endif +``` + +`SpyCustom/ProtoParse.h`: + +```h +#pragma once +#include +#include +#include + +#define MAKE_TAG(FIELD_NUMBER, TYPE) static_cast(((FIELD_NUMBER) << kTagTypeBits) | (TYPE)) + +#define make_struct(_name_, _size_) \ + struct _name_ : ProtoWriter { \ + constexpr static size_t MAX_FIELD = _size_; \ + _name_() : ProtoWriter(MAX_FIELD) {} \ + _name_(void* data, size_t size) : ProtoWriter(data, size, MAX_FIELD) {} \ + _name_(std::string data) : ProtoWriter(data, MAX_FIELD) {} + +#define make_field(_name_, _id_, _type_) \ + constexpr static Tag _name_ = { _id_, _type_ }; \ + void clear_##_name_() { this->clear(_name_); } \ + bool has_##_name_() { return this->has(_name_); } \ + Field get_##_name_() { return this->get(_name_); } \ + std::vector getAll_##_name_() { return this->getAll(_name_); } \ + \ + void add_##_name_(std::string v) { this->add(_name_, v); } \ + template void add_##_name_(T v) { this->add(_name_, v); } \ + void replace_##_name_(std::string v) { this->replace(_name_, v); } \ + void replace_##_name_(std::string v, uint32_t index) { this->replace(_name_, v, index); } \ + template void replace_##_name_(T v) { this->replace(_name_, v); } \ + template void replace_##_name_(T v, uint32_t index) { this->replace(_name_, v, index); } \ + template T get_##_name_() { return std::move( T(this->get(_name_).String()) ); } + + +struct Tag +{ + unsigned field; + unsigned type; +}; + +enum FieldType { + TYPE_DOUBLE = 1, + TYPE_FLOAT = 2, + TYPE_INT64 = 3, + TYPE_UINT64 = 4, + TYPE_INT32 = 5, + TYPE_FIXED64 = 6, + TYPE_FIXED32 = 7, + TYPE_BOOL = 8, + TYPE_STRING = 9, + TYPE_GROUP = 10, + TYPE_MESSAGE = 11, + TYPE_BYTES = 12, + TYPE_UINT32 = 13, + TYPE_ENUM = 14, + TYPE_SFIXED32 = 15, + TYPE_SFIXED64 = 16, + TYPE_SINT32 = 17, + TYPE_SINT64 = 18, + MAX_FIELD_TYPE = 18, +}; + +struct Field +{ + friend class ProtoWriter; +public: + inline Field& operator=(const Field& f); + + Field() : tag({ 0,0 }), value(""), full("") { } + Field(unsigned field, unsigned type, std::string value, std::string full); + + Field(Tag tag, std::string value); + Field(unsigned field, unsigned type, std::string value); + + template + Field(Tag tag, T value); + + template + Field(unsigned field, unsigned type, T value); + +public: + static Field ReadField(void* data, size_t& bytesRead); + +public: + inline float Float(); + inline double Double(); + inline int32_t Int32(); + inline int64_t Int64(); + inline uint32_t UInt32(); + inline uint64_t UInt64(); + inline uint32_t Fixed32(); + inline uint64_t Fixed64(); + inline int32_t SFixed32(); + inline int64_t SFixed64(); + inline bool Bool(); + inline std::string String(); + +private: + Tag tag; + std::string value; + std::string full; + + static std::string getBytesVarint32(uint32_t value); + static std::string getBytesVarint64(uint64_t value); + static uint32_t readVarUint32(void* data, size_t& bytesRead); + static uint64_t readVarUint64(void* data, size_t& bytesRead); + + enum WireType { + WIRETYPE_VARINT = 0, + WIRETYPE_FIXED64 = 1, + WIRETYPE_LENGTH_DELIMITED = 2, + WIRETYPE_START_GROUP = 3, + WIRETYPE_END_GROUP = 4, + WIRETYPE_FIXED32 = 5, + }; + + constexpr static WireType kWireTypeForFieldType[FieldType::MAX_FIELD_TYPE + 1] = { + static_cast(-1), + WIRETYPE_FIXED64, + WIRETYPE_FIXED32, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + WIRETYPE_FIXED64, + WIRETYPE_FIXED32, + WIRETYPE_VARINT, + WIRETYPE_LENGTH_DELIMITED, + WIRETYPE_START_GROUP, + WIRETYPE_LENGTH_DELIMITED, + WIRETYPE_LENGTH_DELIMITED, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + WIRETYPE_FIXED32, + WIRETYPE_FIXED64, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + }; + + constexpr static int kTagTypeBits = 3; + constexpr static uint32_t kTagTypeMask = (1 << kTagTypeBits) - 1; + constexpr static int kMaxVarintBytes = 10; + constexpr static int kMaxVarint32Bytes = 5; +}; + +class ProtoWriter +{ +public: + inline ProtoWriter(); + inline ProtoWriter(size_t maxFields); + inline ProtoWriter(void* data, size_t size, size_t maxFields); + inline ProtoWriter(std::string dataStr, size_t maxFields); + +public: + inline void add(Field field); + inline void replace(Field field); + inline void replace(Field field, uint32_t index); + inline void clear(unsigned fieldId); + inline bool has(unsigned fieldId); + inline Field get(unsigned fieldId); + inline std::vector getAll(unsigned fieldId); + +public: + inline void add(Tag tag, std::string value); + inline void replace(Tag tag, std::string value); + inline void replace(Tag tag, std::string value, uint32_t index); + inline void clear(Tag tag); + inline bool has(Tag tag); + inline Field get(Tag tag); + inline std::vector getAll(Tag tag); + + template + inline void add(Tag tag, T value); + + template + inline void replace(Tag tag, T value); + + template + inline void replace(Tag tag, T value, uint32_t index); + + + std::string serialize(); + void print(); + +private: + std::vector> fields; +}; + +#pragma region Helper Functions +std::string Field::getBytesVarint32(uint32_t value) +{ + uint8_t bytes[kMaxVarint32Bytes]; + int size = 0; + while (value > 0x7F) { + bytes[size++] = (static_cast(value) & 0x7F) | 0x80; + value >>= 7; + } + bytes[size++] = static_cast(value) & 0x7F; + return std::string{ reinterpret_cast(&bytes[0]), (size_t)size }; +} + +std::string Field::getBytesVarint64(uint64_t value) +{ + uint8_t bytes[kMaxVarintBytes]; + int size = 0; + while (value > 0x7F) { + bytes[size++] = (static_cast(value) & 0x7F) | 0x80; + value >>= 7; + } + bytes[size++] = static_cast(value) & 0x7F; + return std::string{ reinterpret_cast(&bytes[0]), (size_t)size }; +} + +uint32_t Field::readVarUint32(void* data, size_t& bytesRead) +{ + auto ptr = reinterpret_cast(data); + auto value = 0u; + auto bytes = 0u; + + do { + value |= static_cast(*ptr & 0x7f) << (7 * bytes); + bytes++; + } while (*(ptr++) & 0x80 && bytes <= 5); + + bytesRead = bytes; + return value; +} + +uint64_t Field::readVarUint64(void* data, size_t& bytesRead) +{ + auto ptr = reinterpret_cast(data); + auto value = 0ull; + auto bytes = 0u; + + do + { + value |= static_cast(*ptr & 0x7f) << (7 * bytes); + bytes++; + } while (*(ptr++) & 0x80 && bytes <= 10); + + bytesRead = bytes; + + return value; +} + +Field Field::ReadField(void* data, size_t& bytesRead) +{ + unsigned field = *reinterpret_cast(data); + unsigned type = field & kTagTypeMask; + + if (field == 0xffff) { + bytesRead = 0; + return Field(); + } + + if (field & 0x80) { + field = ((field & 0x7f) | ((field & 0xff00) >> 1)) >> kTagTypeBits; + bytesRead = 2; + } + else { + field = (field & 0xff) >> kTagTypeBits; + bytesRead = 1; + } + + size_t length, sizeDelimited; + std::string value, full; + switch (type) + { + case WIRETYPE_VARINT: + readVarUint64((void*)((ptrdiff_t)data + bytesRead), length); + value = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytesRead)), length }; + full = std::string{ reinterpret_cast(data), bytesRead + length }; + bytesRead += length; + break; + case WIRETYPE_FIXED64: + value = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytesRead)), 8 }; + full = std::string{ reinterpret_cast(data), bytesRead + 8 }; + bytesRead += 8; + break; + case WIRETYPE_LENGTH_DELIMITED: + sizeDelimited = readVarUint32((void*)((ptrdiff_t)data + bytesRead), length); + value = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytesRead)), length + sizeDelimited }; + full = std::string{ reinterpret_cast(data), bytesRead + length + sizeDelimited }; + bytesRead += length + sizeDelimited; + break; + case WIRETYPE_START_GROUP: + throw("WIRETYPE_START_GROUP unrealised"); + break; + case WIRETYPE_END_GROUP: + throw("WIRETYPE_END_GROUP unrealised"); + break; + case WIRETYPE_FIXED32: + value = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytesRead)), 4 }; + full = std::string{ reinterpret_cast(data), bytesRead + 4 }; + bytesRead += 4; + break; + default: + throw("Unknown type %i", type); + break; + } + + + return Field(field, type, value, full); +} + +#pragma endregion + +#pragma region Field Definition +Field& Field::operator=(const Field& f) { + this->tag = f.tag; + this->value = f.value; + this->full = f.full; + return *this; +} + +Field::Field(unsigned field, unsigned type, std::string value, std::string full) { + this->tag = { field, type }; + this->value = value; + this->full = full; +} + +template +Field::Field(Tag tag, T value) { + auto wireType = kWireTypeForFieldType[tag.type]; + full = getBytesVarint32(MAKE_TAG(tag.field, wireType)); + + switch (wireType) { + case WIRETYPE_VARINT: + full += getBytesVarint64(static_cast(value)); + break; + case WIRETYPE_FIXED32: + full += std::string{ reinterpret_cast(&value), 4 }; + break; + case WIRETYPE_FIXED64: + full += std::string{ reinterpret_cast(&value), 8 }; + break; + } +} + +template +Field::Field(unsigned field, unsigned type, T value) { + auto wireType = kWireTypeForFieldType[type]; + tag = { field, (unsigned)wireType }; + full = getBytesVarint32(MAKE_TAG(field, wireType)); + + switch (wireType) { + case WIRETYPE_VARINT: + full += getBytesVarint64(static_cast(value)); + break; + case WIRETYPE_FIXED32: + full += std::string{ reinterpret_cast(&value), 4 }; + break; + case WIRETYPE_FIXED64: + full += std::string{ reinterpret_cast(&value), 8 }; + break; + } +} + +Field::Field(Tag tag, std::string value) { + auto wireType = kWireTypeForFieldType[tag.type]; + full = getBytesVarint32(MAKE_TAG(tag.field, wireType)); + full += getBytesVarint32(value.size()); + full += value; +} + +Field::Field(unsigned field, unsigned type, std::string value) { + auto wireType = kWireTypeForFieldType[type]; + tag = { field, (unsigned)wireType }; + full = getBytesVarint32(MAKE_TAG(field, wireType)); + full += getBytesVarint32(value.size()); + full += value; +} + + +float Field::Float() { + return *reinterpret_cast((void*)value.data()); +} +double Field::Double() { + return *reinterpret_cast((void*)value.data()); +} +int32_t Field::Int32() { + size_t bytesRead; + return static_cast(readVarUint64((void*)value.data(), bytesRead)); +} +int64_t Field::Int64() { + size_t bytesRead; + return readVarUint64((void*)value.data(), bytesRead); +} +uint32_t Field::UInt32() { + size_t bytesRead; + return readVarUint32((void*)value.data(), bytesRead); +} +uint64_t Field::UInt64() { + size_t bytesRead; + return readVarUint64((void*)value.data(), bytesRead); +} +uint32_t Field::Fixed32() { + return *reinterpret_cast((void*)value.data()); +} +uint64_t Field::Fixed64() { + return *reinterpret_cast((void*)value.data()); +} +int32_t Field::SFixed32() { + return *reinterpret_cast((void*)value.data()); +} +int64_t Field::SFixed64() { + return *reinterpret_cast((void*)value.data()); +} +bool Field::Bool() { + size_t bytesRead; + return !!readVarUint32((void*)value.data(), bytesRead); +} + +std::string Field::String() +{ + size_t bytesRead; + void* data = (void*)value.data(); + auto length = readVarUint32((void*)value.data(), bytesRead); + auto value = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytesRead)), length }; + return value; +} + +#pragma endregion + +#pragma region ProtoWriter Definition +ProtoWriter::ProtoWriter() +{ + +} + +ProtoWriter::ProtoWriter(size_t maxFields) +{ + size_t vector_size = maxFields + 1; + fields.resize(vector_size); + fields.reserve(vector_size); +} + +ProtoWriter::ProtoWriter(void* data, size_t size, size_t maxFields) : ProtoWriter(maxFields) +{ + size_t vector_size = maxFields + 1, + pos = 0, + bytesRead; + + if (data == nullptr) + return; + while (pos < size) { + auto field = Field::ReadField((void*)((ptrdiff_t)data + pos), bytesRead); + if (!bytesRead) break; + + auto index = field.tag.field; + if (index >= vector_size) throw("fields range error: field[%i]", index); + fields[index].push_back(field); + pos += bytesRead; + } +} + +ProtoWriter::ProtoWriter(std::string dataStr, size_t maxFields) : ProtoWriter((void*)dataStr.data(), dataStr.size(), maxFields) +{ + +} + +std::string ProtoWriter::serialize() +{ + std::string result; + for (auto& f0 : fields) { + for (auto& f1 : f0) { + result += f1.full; + } + } + return result; +} + +void ProtoWriter::print() +{ + auto data = serialize(); + void* mem = (void*)data.data(); + size_t size = data.size(); + int j = 0; + for (size_t i = 0; i <= size; ++i) { + printf("%.2X ", *(unsigned char*)((uintptr_t)mem + i)); + j++; + if (j == 16) + { + j = 0; + printf("\n"); + } + } + printf("\n"); +} + +void ProtoWriter::add(Field field) +{ + fields[field.tag.field].push_back(field); +} + +void ProtoWriter::replace(Field field) +{ + fields[field.tag.field].clear(); + fields[field.tag.field].push_back(field); +} + +void ProtoWriter::replace(Field field, uint32_t index) +{ + fields[field.tag.field][index] = field; +} + +void ProtoWriter::clear(unsigned fieldId) +{ + return fields[fieldId].clear(); +} + +bool ProtoWriter::has(unsigned fieldId) +{ + return fields[fieldId].size() > 0; +} + +Field ProtoWriter::get(unsigned fieldId) +{ + if (fields[fieldId].empty()) + return Field(); + return fields[fieldId][0]; +} + +std::vector ProtoWriter::getAll(unsigned fieldId) +{ + return fields[fieldId]; +} + +template +void ProtoWriter::add(Tag tag, T value) +{ + fields[tag.field].push_back(Field(tag, value)); +} + +template +void ProtoWriter::replace(Tag tag, T value) +{ + fields[tag.field].clear(); + fields[tag.field].push_back(Field(tag, value)); +} + +template +void ProtoWriter::replace(Tag tag, T value, uint32_t index) +{ + fields[tag.field][index] = Field(tag, value); +} + +void ProtoWriter::add(Tag tag, std::string value) +{ + fields[tag.field].push_back(Field(tag, value)); +} + +void ProtoWriter::replace(Tag tag, std::string value) +{ + fields[tag.field].clear(); + fields[tag.field].push_back(Field(tag, value)); +} + +void ProtoWriter::replace(Tag tag, std::string value, uint32_t index) +{ + fields[tag.field][index] = Field(tag, value); +} + +void ProtoWriter::clear(Tag tag) +{ + return fields[tag.field].clear(); +} + +bool ProtoWriter::has(Tag tag) +{ + return fields[tag.field].size() > 0; +} + +Field ProtoWriter::get(Tag tag) +{ + if (fields[tag.field].empty()) + return Field(); + return fields[tag.field][0]; +} + +std::vector ProtoWriter::getAll(Tag tag) +{ + return fields[tag.field]; +} + +#pragma endregion +``` + +`SpyCustom/ProtobuffMessages.h`: + +```h +#pragma once +#include "pbwrap.hpp" + +//https://github.com/SteamDatabase/Protobufs/blob/master/csgo/cstrike15_gcmessages.proto + +#define k_EMsgGCCStrike15_v2_MatchmakingGC2ClientReserve 9107 +#define k_EMsgGCClientWelcome 4004 +#define k_EMsgGCClientHello 4006 +#define k_EMsgGCAdjustItemEquippedState 1059 +#define k_EMsgGCCStrike15_v2_MatchmakingClient2GCHello 9109 +#define k_EMsgGCCStrike15_v2_MatchmakingGC2ClientHello 9110 +#define k_EMsgGCCStrike15_v2_ClientGCRankUpdate 9194 + +using namespace pbwrap; + +struct CMsgClientHello : pbmsg<8> { + PBMSG_CTOR; + PBFIELD(3, types::Uint32, client_session_need); +}; + +struct MatchmakingGC2ClientHello : pbmsg<20> { + struct PlayerRankingInfo : pbmsg<6> { + PBMSG_CTOR; + PBFIELD(1, types::Uint32, account_id); + PBFIELD(2, types::Uint32, rank_id); + PBFIELD(3, types::Uint32, wins); + PBFIELD(6, types::Uint32, rank_type_id); + }; + struct PlayerCommendationInfo : pbmsg<4> { + PBMSG_CTOR; + PBFIELD(1, types::Uint32, cmd_friendly); + PBFIELD(2, types::Uint32, cmd_teaching); + PBFIELD(4, types::Uint32, cmd_leader); + }; + + PBMSG_CTOR; + PBFIELD(7, PlayerRankingInfo, ranking); + PBFIELD(8, PlayerCommendationInfo, commendation); + PBFIELD(17, types::Int32, player_level); + PBFIELD(18, types::Int32, player_cur_xp); + PBFIELD(4, types::Uint32, penalty_seconds); + PBFIELD(5, types::Uint32, penalty_reason); + PBFIELD(6, types::Int32, vac_banned); +}; + +struct CMsgGCCStrike15_v2_ClientGCRankUpdate : pbmsg<1> { + PBMSG_CTOR; + PBFIELD(1, MatchmakingGC2ClientHello::PlayerRankingInfo, ranking); +}; + +struct CSOEconItemEquipped : pbmsg<2> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, new_class); + PBFIELD(2, types::Int32, new_slot); +}; + +struct CSOEconItemAttribute : pbmsg<3> { + PBMSG_CTOR; + PBFIELD(1, types::Uint32, def_index); + PBFIELD(2, types::Uint32, value); + PBFIELD(3, types::Bytes, value_bytes); +}; + +struct CSOEconItem : pbmsg<19> { + PBMSG_CTOR; + PBFIELD(1, types::Uint64, id); + PBFIELD(2, types::Uint32, account_id); + PBFIELD(3, types::Uint32, inventory); + PBFIELD(4, types::Int32, def_index); + PBFIELD(5, types::Uint32, quantity); + PBFIELD(6, types::Uint32, level); + PBFIELD(7, types::Uint32, quality); + PBFIELD(8, types::Uint32, flags); + PBFIELD(9, types::Uint32, origin); + PBFIELD(10, types::String, custom_name); + PBFIELD(11, types::String, custom_desc); + PBFIELD(12, CSOEconItemAttribute, attribute); + PBFIELD(14, types::Bool, in_use); + PBFIELD(15, types::Uint32, style); + PBFIELD(16, types::Uint64, original_id); + PBFIELD(18, CSOEconItemEquipped, equipped_state); + PBFIELD(19, types::Uint32, rarity); +}; + +struct CMsgClientWelcome : pbmsg<11> { + struct SubscribedType : pbmsg<2> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, type_id); + PBFIELD(2, CSOEconItem, object_data); + }; + + struct CMsgSOCacheSubscribed : pbmsg<4> { + PBMSG_CTOR; + PBFIELD(2, SubscribedType, objects); + }; + + PBMSG_CTOR; + PBFIELD(3, CMsgSOCacheSubscribed, outofdate_subscribed_caches); +}; + +struct CMsgAdjustItemEquippedState : pbmsg<4> { + PBMSG_CTOR; + PBFIELD(1, types::Uint64, item_id); + PBFIELD(2, types::Uint32, new_class); + PBFIELD(3, types::Uint32, new_slot); + PBFIELD(4, types::Bool, swap); +}; + +// https://github.com/SteamDatabase/Protobufs/blob/master/csgo/cstrike15_usermessages.proto + +struct CCSUsrMsg_HintText : pbmsg<1> { + PBMSG_CTOR; + PBFIELD(1, types::String, text); +}; + +struct CCSUsrMsg_KeyHintText : pbmsg<1> { + PBMSG_CTOR; + PBFIELD(1, types::String, hints); +}; + +struct CCSUsrMsg_HudText : pbmsg<1> { + PBMSG_CTOR; + PBFIELD(1, types::String, text); +}; + +struct CCSUsrMsg_TextMsg : pbmsg<3> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, msg_dst); + PBFIELD(3, types::String, params); +}; + +struct CCSUsrMsg_SayText : pbmsg<4> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, ent_idx); + PBFIELD(2, types::String, text); + PBFIELD(3, types::Bool, chat); + PBFIELD(4, types::Bool, textallchat); +}; + +struct CCSUsrMsg_SayText2 : pbmsg<5> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, ent_idx); + PBFIELD(2, types::Bool, chat); + PBFIELD(3, types::String, msg_name); + PBFIELD(4, types::String, params); + PBFIELD(5, types::Bool, textallchat); +}; + +struct CCSUsrMsg_RadioText : pbmsg<4> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, msg_dst); + PBFIELD(2, types::Int32, client); + PBFIELD(3, types::String, msg_name); + PBFIELD(4, types::String, params); +}; + +struct CMsgRGBA : pbmsg<4> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, r); + PBFIELD(2, types::Int32, g); + PBFIELD(3, types::Int32, b); + PBFIELD(4, types::Int32, a); +}; + +struct CMsgVector2D : pbmsg<2> { + PBMSG_CTOR; + PBFIELD(1, types::Float, x); + PBFIELD(2, types::Float, y); +}; + +struct CCSUsrMsg_HudMsg : pbmsg<11> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, channel); + PBFIELD(2, CMsgVector2D, pos); + PBFIELD(3, CMsgRGBA, clr1); + PBFIELD(4, CMsgRGBA, clr2); + PBFIELD(5, types::Int32, effect); + PBFIELD(6, types::Float, fade_in_time); + PBFIELD(7, types::Float, fade_out_time); + PBFIELD(9, types::Float, hold_time); + PBFIELD(10, types::Float, fx_time); + PBFIELD(11, types::String, text); +}; + +struct CCSUsrMsg_SendAudio : pbmsg<1> { + PBMSG_CTOR; + PBFIELD(1, types::String, radio_sound); +}; + +struct CMsgPlayerInfo : pbmsg<6> { + PBMSG_CTOR; + PBFIELD(1, types::String, name); + PBFIELD(2, types::Fixed64, xuid); + PBFIELD(3, types::Int32, userid); + PBFIELD(4, types::Fixed64, steamid); + PBFIELD(5, types::Bool, fakeplayer); + PBFIELD(6, types::Bool, ishltv); +}; + +struct CMsg_CVars : pbmsg<2> { + PBMSG_CTOR; + + struct CVar : pbmsg<2> { + PBMSG_CTOR; + PBFIELD(1, types::String, name); + PBFIELD(2, types::String, value); + }; + + PBFIELD(1, CMsg_CVars::CVar, cvars); +}; + +struct CNETMsg_SetConVar : pbmsg<1> { + PBMSG_CTOR; + PBFIELD(1, CMsg_CVars, convars); +}; + +struct CCSUsrMsg_ShowMenu : pbmsg<3> { + PBMSG_CTOR; + PBFIELD(1, types::Int32, bits_valid_slots); + PBFIELD(2, types::Int32, display_time); + PBFIELD(3, types::String, menu_string); +}; + +enum ECstrike15UserMessages { + CS_UM_VGUIMenu = 1, + CS_UM_Geiger = 2, + CS_UM_Train = 3, + CS_UM_HudText = 4, + CS_UM_SayText = 5, + CS_UM_SayText2 = 6, + CS_UM_TextMsg = 7, + CS_UM_HudMsg = 8, + CS_UM_ResetHud = 9, + CS_UM_GameTitle = 10, + CS_UM_Shake = 12, + CS_UM_Fade = 13, + CS_UM_Rumble = 14, + CS_UM_CloseCaption = 15, + CS_UM_CloseCaptionDirect = 16, + CS_UM_SendAudio = 17, + CS_UM_RawAudio = 18, + CS_UM_VoiceMask = 19, + CS_UM_RequestState = 20, + CS_UM_Damage = 21, + CS_UM_RadioText = 22, + CS_UM_HintText = 23, + CS_UM_KeyHintText = 24, + CS_UM_ProcessSpottedEntityUpdate = 25, + CS_UM_ReloadEffect = 26, + CS_UM_AdjustMoney = 27, + CS_UM_UpdateTeamMoney = 28, + CS_UM_StopSpectatorMode = 29, + CS_UM_KillCam = 30, + CS_UM_DesiredTimescale = 31, + CS_UM_CurrentTimescale = 32, + CS_UM_AchievementEvent = 33, + CS_UM_MatchEndConditions = 34, + CS_UM_DisconnectToLobby = 35, + CS_UM_PlayerStatsUpdate = 36, + CS_UM_DisplayInventory = 37, + CS_UM_WarmupHasEnded = 38, + CS_UM_ClientInfo = 39, + CS_UM_XRankGet = 40, + CS_UM_XRankUpd = 41, + CS_UM_CallVoteFailed = 45, + CS_UM_VoteStart = 46, + CS_UM_VotePass = 47, + CS_UM_VoteFailed = 48, + CS_UM_VoteSetup = 49, + CS_UM_ServerRankRevealAll = 50, + CS_UM_SendLastKillerDamageToClient = 51, + CS_UM_ServerRankUpdate = 52, + CS_UM_ItemPickup = 53, + CS_UM_ShowMenu = 54, + CS_UM_BarTime = 55, + CS_UM_AmmoDenied = 56, + CS_UM_MarkAchievement = 57, + CS_UM_MatchStatsUpdate = 58, + CS_UM_ItemDrop = 59, + CS_UM_GlowPropTurnOff = 60, + CS_UM_SendPlayerItemDrops = 61, + CS_UM_RoundBackupFilenames = 62, + CS_UM_SendPlayerItemFound = 63, + CS_UM_ReportHit = 64, + CS_UM_XpUpdate = 65, + CS_UM_QuestProgress = 66, + CS_UM_ScoreLeaderboardData = 67, + CS_UM_PlayerDecalDigitalSignature = 68, + CS_UM_WeaponSound = 69, + CS_UM_UpdateScreenHealthBar = 70, + CS_UM_EntityOutlineHighlight = 71, + CS_UM_SSUI = 72, + CS_UM_SurvivalStats = 73, + CS_UM_DisconnectToLobby2 = 74, + CS_UM_EndOfMatchAllPlayersData = 75, + CS_UM_RoundImpactScoreData = 79, + CS_UM_CurrentRoundOdds = 80, + CS_UM_DeepStats = 81, + CS_UM_UtilMsg = 82 +}; + +enum ECSUsrMsg_DisconnectToLobby_Action { + k_ECSUsrMsg_DisconnectToLobby_Action_Default = 0, + k_ECSUsrMsg_DisconnectToLobby_Action_GoQueue = 1 +}; + + +``` + +`SpyCustom/Singleton.hpp`: + +```hpp +#ifndef SINGLETON +#define SINGLETON +#pragma once + + +template +class Singleton +{ +protected: + Singleton() {} + ~Singleton() {} + + Singleton(const Singleton&) = delete; + Singleton& operator=(const Singleton&) = delete; + + Singleton(Singleton&&) = delete; + Singleton& operator=(Singleton&&) = delete; + +public: + static T& Get() + { + static T inst{}; + return inst; + } +}; + + +#endif + +``` + +`SpyCustom/SkinChanger.hpp`: + +```hpp +#ifndef SKINCHANGER +#define SKINCHANGER +#pragma once + +#include +#include + +#include "sdk/GameEventManager.h" +#include "VMT.hpp" +#include "Interfaces.hpp" +#include "Options.hpp" +#include "sdk/c_baseentity.h" +#include "PatternScan.hpp" + +extern VMTHook* GameEventManagerHook; +extern VMTHook* ClientHook; + +#include "NetVarManager.hpp" + +extern bool needupdate; + +#include "vmt_smart_hook.hpp" + + + +struct iitem +{ + iitem(int defindex1, std::string name1, std::string viewmodel1, std::string worldmodel1) + { + defindex = defindex1; + name = name1; + viewmodel = viewmodel1; + worldmodel = worldmodel1; + Preview = std::to_string(defindex1).append(": ").append(name1); + } + int defindex; + std::string name; + std::string viewmodel; + std::string worldmodel; + std::string Preview; + bool isSelected; +}; + + +/* +struct hud_weapons_t +{ + std::int32_t* get_weapon_count() + { + return reinterpret_cast(std::uintptr_t(this) + 0x80); + } +}; +*/ + +struct String_t +{ + char* szBuffer; + int nCapacity; + int _unknown; + int nLength; +}; + +class CEconItemRarityDefinition +{ +public: + int id; + int color; + String_t name; + String_t loc_key; + String_t loc_key_weapon; + String_t loot_list; + String_t recycle_list; + String_t drop_sound; + String_t endmatchitemrevealrarity; + String_t pointertosomething3; + void* pointertosomething4; + void* pointertosomething5; + char dumb10[8]; +}; + +class CStickerKit +{ +public: + int id; + int item_rarity; + String_t name; + String_t description; + String_t item_name; + String_t material_name; + String_t image_inventory; + int tournament_event_id; + int tournament_team_id; + int tournament_player_id; + bool is_custom_sticker_material; + float rotate_end; + float rotate_start; + float scale_min; + float scale_max; + float wear_min; + float wear_max; + String_t image_inventory2; + String_t image_inventory_large; + std::uint32_t pad0[4]; +}; + + +class CPaintKit +{ +public: + int nID; + String_t sName; + String_t sDescriptionString; + String_t sDescriptionTag; + String_t pad; + String_t pattern; + String_t pad1; + String_t sLogoMaterial; + int bBaseDiffuseOverride; + int rarity; + int nStyle; + int color1; + int color2; + int color3; + int color4; + int logoColor1; + int logoColor2; + int logoColor3; + int logoColor4; + float flWearDefault; + float flWearRemapMin; + float flWearRemapMax; + char nFixedSeed; + char uchPhongExponent; + char uchPhongAlbedoBoost; + char uchPhongIntensity; + float flPatternScale; + float flPatternOffsetXStart; + float flPatternOffsetXEnd; + float flPatternOffsetYStart; + float flPatternOffsetYEnd; + float flPatternRotateStart; + float flPatternRotateEnd; + float flLogoScale; + float flLogoOffsetX; + float flLogoOffsetY; + float flLogoRotation; + int bIgnoreWeaponSizeScale; + int nViewModelExponentOverrideSize; + int bOnlyFirstMaterial; + float pearlescent; + int sVmtPath[4]; + int kvVmtOverrides; +}; + + + + +struct EconItemQualityDefinition { + int id; + const char* name; + unsigned weight; + bool explicitMatchesOnly; + bool canSupportSet; + const char* hexColor; +}; + +extern std::vector rarities; +extern std::vector knives; +extern std::vector gloves; +extern std::vector agents; +extern std::vector medals; +extern std::vector musickits; +extern std::vector qualities; + +static inline auto is_knife(const int di) -> bool +{ + for (short i = 0; i < knives.size(); i++) + if (knives[i].defindex == di) return true; + return false; +} + +bool __fastcall hkFireEventClientSide(void* thisptr, void* edx, IGameEvent* event); +void __fastcall hkFrameStageNotify(IBaseClientDLL* thisptr, void* edx, ClientFrameStage_t stage); + + + + +class CCStrike15ItemSchema; +class CCStrike15ItemSystem +{ +public: + virtual CCStrike15ItemSchema* GetItemSchemaInterface() = 0; +}; + + +template +struct Node_t +{ + int nPreviousId; + int nNextId; + void* parent; + int type; + Key iPaintKitId; + Value value; +}; + +template +struct Head_t +{ + Node_t* pMemory; + int nAllocationCount; + int nGrowSize; + int nStartElement; + int nNextAvailable; + int _unknown; + int nLastElement; +}; + + +class CEconItemDefinition +{ +public: + + + VIRTUAL_METHOD(int, getWeaponId, 0, (), (this)) + VIRTUAL_METHOD(const char*, getItemBaseName, 2, (), (this)) + VIRTUAL_METHOD(const char*, getItemTypeName, 3, (), (this)) + VIRTUAL_METHOD(const char*, getPlayerDisplayModel, 6, (), (this)) + VIRTUAL_METHOD(const char*, getWorldDisplayModel, 7, (), (this)) + VIRTUAL_METHOD(std::uint8_t, getRarity, 12, (), (this)) + + char pad_0x0000[0x8]; + int32_t m_iItemDefinitionIndex; + char pad_0x000C[0x40]; + char* m_szHudName; + char pad_0x0050[0x4]; + char* m_szWeaponType; + char pad_0x0058[0x4]; + char* m_szWeaponDescription; + char pad_0x0060[0x34]; + char* m_szViewModel; + char pad_0x0098[0x4]; + char* m_szWorldModel; + char* m_szWorldModelDropped; + char pad_0x001[0x58]; + char* stickersdecalmdl; + char pad_0x002[0x0C]; + char* stickersdecalmdl1; + char* inventoryicon; + char pad_0x003[0xA4]; + char* m_szWeaponName1; + char pad_0x004[0x14]; + char* m_szWeaponName; + char pad_0x005[0x8]; + char* m_szWeaponName3; + char pad_0x01C4[0x27C]; +}; + + +void InitSkinChanger(); + + + + +template +struct UtlMemory { + T& operator[](int i) const noexcept { return memory[i]; }; + + T* memory; + int allocationCount; + int growSize; +}; + +template +struct UtlMap { + auto begin() const noexcept { return memory.memory; } + auto end() const noexcept { return memory.memory + numElements; } + + int find(Key key) const noexcept + { + auto curr = root; + + while (curr != -1) { + const auto el = memory[curr]; + + if (el.iPaintKitId < key) + curr = el.nNextId; + else if (el.iPaintKitId > key) + curr = el.nPreviousId; + else + break; + } + return curr; + } + void* lessFunc; + UtlMemory> memory; + int root; + int numElements; + int firstFree; + int lastAlloc; + Node_t* elements; +}; + +struct AlternateIconData { + String_t simpleName; + String_t largeSimpleName; + String_t iconURLSmall; + String_t iconURLLarge; + PAD(28) +}; + + + +template +class UtlVector { +public: + constexpr T& operator[](int i) noexcept { return memory[i]; }; + constexpr const T& operator[](int i) const noexcept { return memory[i]; }; + + T* memory; + int allocationCount; + int growSize; + int size; + T* elements; +}; + + +struct ItemListEntry { + int itemDef; + int paintKit; + PAD(20) + + auto weaponId() const noexcept + { + return itemDef; + } +}; + +class EconLootListDefinition { +public: + VIRTUAL_METHOD(const char*, getName, 0, (), (this)) + VIRTUAL_METHOD(const UtlVector&, getLootListContents, 1, (), (this)) +}; + +class EconItemSetDefinition { +public: + VIRTUAL_METHOD(const char*, getLocKey, 1, (), (this)) + VIRTUAL_METHOD(int, getItemCount, 4, (), (this)) + VIRTUAL_METHOD(int, getItemDef, 5, (int index), (this, index)) + VIRTUAL_METHOD(int, getItemPaintKit, 6, (int index), (this, index)) +}; + + + + +class CEconColorDefinition +{ +public: + int xz; + int xz2; +}; + +class CEconGraffitiTintDefinition +{ +public: + int xz; + int xz2; +}; + +class CEconMusicDefinition +{ +public: + int id; + char* name; + char* desc; + char* model; + char* music; +}; + +template +class MusicVector { +public: + constexpr T& operator[](int i) noexcept { return memory[i]; }; + constexpr const T& operator[](int i) const noexcept { return memory[i]; }; + + T* memory; + PAD(0xC) + int itemcount; +}; + +class ItemSchema { +public: + PAD(0x64) + UtlMap rars; + UtlMap qualities; + PAD(0x48) + UtlMap itemsSorted; + PAD(0x104) + UtlMap alternateIcons; + PAD(0x48) + UtlMap paintKits; + UtlMap stickerKits; + UtlMap sticker_kits_namekey; + int32_t pad6[24]; + UtlMap prefabs; + UtlVector colors; + UtlVector graffiti_tints; + int32_t pad7[20]; + MusicVector music_definitions; + + VIRTUAL_METHOD(CEconItemDefinition*, getItemDefinitionInterface, 4, (int id), (this, id)) + VIRTUAL_METHOD(int, getItemSetCount, 28, (), (this)) + VIRTUAL_METHOD(EconItemSetDefinition*, getItemSet, 29, (int index), (this, index)) + VIRTUAL_METHOD(EconLootListDefinition*, getLootList, 32, (int index), (this, index)) + VIRTUAL_METHOD(int, getLootListCount, 34, (), (this)) + VIRTUAL_METHOD(CEconItemDefinition*, getItemDefinitionByName, 42, (const char* name), (this, name)) +}; + + +class ItemSystem { +public: + VIRTUAL_METHOD(ItemSchema*, getItemSchema, 0, (), (this)) +}; + +extern std::add_pointer_t itemSystem; + +#endif + +``` + +`SpyCustom/Skinchanger.cpp`: + +```cpp +#include "SkinChanger.hpp" +#include "Other.hpp" + +VMTHook* GameEventManagerHook = nullptr; +VMTHook* ClientHook = nullptr; +std::vector rarities; +std::vector knives; +std::vector gloves; +std::vector agents; +std::vector medals; +std::vector musickits; +std::vector qualities; + +std::add_pointer_t itemSystem; + + + + +enum class EStickerAttributeType +{ + Index, + Wear, + Scale, + Rotation +}; + +static auto s_econ_item_interface_wrapper_offset = std::uint16_t(0); + +struct GetStickerAttributeBySlotIndexFloat +{ + static auto __fastcall hooked(void* thisptr, void*, const int slot, + const EStickerAttributeType attribute, const float unknown) -> float + { + auto item = reinterpret_cast(std::uintptr_t(thisptr) - s_econ_item_interface_wrapper_offset); + + const auto defindex = item->GetItemDefinitionIndex(); + + int config = GetCfgIndex(defindex); + + if (config != -1) + { + switch (attribute) + { + case EStickerAttributeType::Wear: + return g_Options.weapons.value->arr[config].stickers[slot].wear; + case EStickerAttributeType::Scale: + return g_Options.weapons.value->arr[config].stickers[slot].scale; + case EStickerAttributeType::Rotation: + return g_Options.weapons.value->arr[config].stickers[slot].rotation; + default: + break; + } + } + + return m_original(thisptr, nullptr, slot, attribute, unknown); + } + + static decltype(&hooked) m_original; +}; + +decltype(GetStickerAttributeBySlotIndexFloat::m_original) GetStickerAttributeBySlotIndexFloat::m_original; + +struct GetStickerAttributeBySlotIndexInt +{ + static auto __fastcall hooked(void* thisptr, void*, const int slot, + const EStickerAttributeType attribute, const int unknown) -> int + { + auto item = reinterpret_cast(std::uintptr_t(thisptr) - s_econ_item_interface_wrapper_offset); + + if (attribute == EStickerAttributeType::Index) + { + const auto defindex = item->GetItemDefinitionIndex(); + + int config = GetCfgIndex(defindex); + + if (config != -1) + return g_Options.weapons.value->arr[config].stickers[slot].stickerid; + } + + return m_original(thisptr, nullptr, slot, attribute, unknown); + } + + static decltype(&hooked) m_original; +}; + +decltype(GetStickerAttributeBySlotIndexInt::m_original) GetStickerAttributeBySlotIndexInt::m_original; + + +void ApplyStickers(C_BaseAttributableItem* item) +{ + if (!s_econ_item_interface_wrapper_offset) + s_econ_item_interface_wrapper_offset = netvar_manager::get().get_offset(FNV("CBaseAttributableItem->m_Item")) + 0xC; + + static vmt_multi_hook hook; + + const auto econ_item_interface_wrapper = std::uintptr_t(item) + s_econ_item_interface_wrapper_offset; + + if (hook.initialize_and_hook_instance(reinterpret_cast(econ_item_interface_wrapper))) + { + hook.apply_hook(4); + hook.apply_hook(5); + } +} + + +bool __fastcall hkFireEventClientSide(void* thisptr, void* edx, IGameEvent* event) +{ + static auto ofunc = GameEventManagerHook->GetOriginal(9); + if (event) { + if (!strcmp(event->GetName(), "player_death") && iff.g_pEngineClient->GetPlayerForUserID(event->GetInt("attacker")) == iff.g_pEngineClient->GetLocalPlayer()) + { + printfdbg("BE playerdeath with %s\n", event->GetString("weapon")); + + for (int i = 0; i < g_Options.weapons.value->weaponzcount; i++) + { + if (_tcsstr(g_Options.weapons.value->arr[i].killfeedicon, event->GetString("weapon"))) + { + if (g_Options.weapons.value->arr[i].active && g_Options.weapons.value->arr[i].killfeediconactive) + event->SetString("weapon", g_Options.weapons.value->arr[i].killfeediconreplace); + + if (!g_Options.weapons.value->arr[i].ownerunk && g_Options.weapons.value->arr[i].stattrak != -1) + g_Options.weapons.value->arr[i].stattrak += 1; + + + } + } + + } + } + + return ofunc(thisptr, edx, event); + +} + +C_CS_PlayerResource** g_player_resource = NULL; + +#include +bool Changer() +{ + /* + static bool initinterface = 0; + if (!initinterface) { + + const auto team_arr_prop = C_CS_PlayerResource::GetTeamProp(); + const auto team_prop = team_arr_prop->m_pDataTable->m_pProps; + const auto proxy_addr = std::uintptr_t(team_prop->m_ProxyFn); + g_player_resource = *reinterpret_cast(proxy_addr + 0x10); + printfdbg("g_player_resource initiated %x\n", g_player_resource); + + + //g_player_resource = C_CS_PlayerResource::GetPlayerResource(); + initinterface = 1; + } + */ + + static C_CS_PlayerResource** g_player_resource = C_CS_PlayerResource::GetPlayerResource(); + + if (!iff.g_pEngineClient->IsConnected()) { + return 0; + } + + int localplayer_index = iff.g_pEngineClient->GetLocalPlayer(); + C_BasePlayer* localplayer = static_cast(iff.g_pEntityList->GetClientEntity(localplayer_index)); + + if (!localplayer) + return 0; + + + auto player_resource = *g_player_resource; + + if (g_Options.weapons.value->arr[4].active) + player_resource->GetCoins()[localplayer_index] = g_Options.weapons.value->arr[4].modeldefindex; + + if (g_Options.weapons.value->arr[5].active) + player_resource->GetMusicKits()[localplayer_index] = g_Options.weapons.value->arr[5].modeldefindex; + + if (g_Options.profile_active) + { + int ranktype = player_resource->GetRankType()[localplayer_index]; + int selectedrank = 0; + if (ranktype == 7) selectedrank = 1; + if (ranktype == 10) selectedrank = 2; + + player_resource->GetRanks()[localplayer_index] = g_Options.rankz.value->arr[selectedrank].rank; + player_resource->GetWins()[localplayer_index] = g_Options.rankz.value->arr[selectedrank].wins; + + player_resource->GetLevel()[localplayer_index] = g_Options.level; + player_resource->GetComLeader()[localplayer_index] = g_Options.comleader; + player_resource->GetComTeacher()[localplayer_index] = g_Options.comteacher; + player_resource->GetComFriendly()[localplayer_index] = g_Options.comfriendly; + } + + if (g_Options.fakescore) + { + player_resource->GetMVPs()[localplayer_index] = g_Options.MVPs; + player_resource->GetScore()[localplayer_index] = g_Options.score; + player_resource->GetKills()[localplayer_index] = g_Options.kills; + player_resource->GetAssists()[localplayer_index] = g_Options.assists; + player_resource->GetDeaths()[localplayer_index] = g_Options.deaths; + } + + + int team = localplayer->GetTeam(); char* model = 0; + if (team == TEAM_TERRORIST && g_Options.weapons.value->arr[2].active && g_Options.weapons.value->arr[2].modelactive) + model = g_Options.weapons.value->arr[2].model; + if (team == TEAM_CT && g_Options.weapons.value->arr[3].active && g_Options.weapons.value->arr[3].modelactive) + model = g_Options.weapons.value->arr[3].model; + + + if (model != 0) { + localplayer->GetModelIndex() = iff.g_pMdlInfo->GetModelIndex(model); + if (const auto modelprecache = iff.g_pNetworkStringTableContainer->FindTable("modelprecache")) + { + modelprecache->AddString(false, model); + const auto viewmodelArmConfig = iff.getPlayerViewmodelArmConfigForPlayerModel(model); + modelprecache->AddString(false, viewmodelArmConfig[2]); + modelprecache->AddString(false, viewmodelArmConfig[3]); + + + } + + + const auto m_hRagdoll = (C_BaseEntity*)iff.g_pEntityList->GetClientEntityFromHandle(localplayer->Ragdoll()); + if (m_hRagdoll) + m_hRagdoll->GetModelIndex() = iff.g_pMdlInfo->GetModelIndex(model); + + } + + + if (localplayer->GetLifeState() != LIFE_ALIVE) + { + if (g_Options.weapons.value->arr[1].active && g_Options.weapons.value->arr[1].modelactive) { + auto destroyglove = iff.g_pEntityList->GetClientEntityFromHandle(localplayer->GetWearables()[0]); + if (destroyglove) { + destroyglove->GetClientNetworkable()->SetDestroyedOnRecreateEntities(); + destroyglove->GetClientNetworkable()->Release(); + printfdbg("destroyed glove\n"); + } + } + return 0; + } + + player_info_t localplayer_info; + if (!iff.g_pEngineClient->GetPlayerInfo(localplayer_index, &localplayer_info)) + return 0; + + CBaseHandle viewmodelHandle = localplayer->GetViewModel(); + + C_BaseViewModel* pViewModel = (C_BaseViewModel*)iff.g_pEntityList->GetClientEntityFromHandle(viewmodelHandle); + + const auto view_model_weapon = (C_BaseAttributableItem*)iff.g_pEntityList->GetClientEntityFromHandle(pViewModel->GetWeapon()); + + int idi = view_model_weapon->GetItemDefinitionIndex(); + if (idi == WEAPON_KNIFE) idi = WEAPON_KNIFE_T; + + int modelcfgindex = GetCfgIndex2(idi); + if (modelcfgindex != -1 && g_Options.models.value->arr[modelcfgindex].active) + { + char* model = g_Options.models.value->arr[modelcfgindex].vmodel_repl; + const auto override_model_index = iff.g_pMdlInfo->GetModelIndex(model); + view_model_weapon->SetModelIndex(override_model_index) ; + pViewModel->SetModelIndex(override_model_index) ; + if (const auto modelprecache = iff.g_pNetworkStringTableContainer->FindTable("modelprecache")) + { + modelprecache->AddString(false, model); + } + } + + int seqact = opt.needtogetseqact; + if (seqact) + { + int oldmodelindex = pViewModel->GetModelIndex(); + pViewModel->SetModelIndex(iff.g_pMdlInfo->GetModelIndex(g_Options.models.value->arr[seqact].vmodel_orig)); + for (int i = 0; i < 20; i++) + strcpy(g_Options.models.value->arr[seqact].seqs[i].seq_orig_def, (char*)pViewModel->GetSequenceActivity(i)); + pViewModel->SetModelIndex(iff.g_pMdlInfo->GetModelIndex(g_Options.models.value->arr[seqact].vmodel_repl)); + for (int i = 0; i < 20; i++) + { + strcpy(g_Options.models.value->arr[seqact].seqs[i].seq_repl_def, (char*)pViewModel->GetSequenceActivity(i)); + + char newpreview[32] = ""; + strcat_s(newpreview, std::to_string(i).c_str()); + strcat_s(newpreview, ": "); + strcat_s(newpreview, g_Options.models.value->arr[seqact].seqs[i].seq_repl_def); + strcpy(g_Options.models.value->arr[seqact].seqs[i].seq_repl_def_preview, newpreview); + } + pViewModel->SetModelIndex(oldmodelindex); + opt.needtogetseqact = 0; + } + + if (g_Options.weapons.value->arr[1].active && g_Options.weapons.value->arr[1].modelactive) + { + auto hWearables = localplayer->GetWearables(); + + static int glove_handle; + C_BaseAttributableItem* glove = (C_BaseAttributableItem*)iff.g_pEntityList->GetClientEntityFromHandle(hWearables[0] ); + + if (!glove) + { + C_BaseAttributableItem* our_glove = (C_BaseAttributableItem*)iff.g_pEntityList->GetClientEntityFromHandle(glove_handle); + + if (our_glove) + { + hWearables[0] = glove_handle; + glove = our_glove; + } + } + + if (!glove) + { + static std::add_pointer_t createWearable = nullptr; + + if (!createWearable) { + createWearable = []() -> decltype(createWearable) + { + for (auto clientClass = iff.g_pClient->GetAllClasses(); clientClass; clientClass = clientClass->m_pNext) + //if (clientClass->m_ClassID == 54) + if (_tcsstr(clientClass->GetName(), _T("CEconWearable")) != NULL) { + printfdbg("CEconWearable found\n"); + return (std::add_pointer_t)clientClass->m_pCreateFn; + } + return nullptr; + }(); + } + + + + const auto serial = rand() % 0x1000; + auto entry = iff.g_pEntityList->GetHighestEntityIndex() + 1; + + + for (int i = 65; i < iff.g_pEntityList->GetHighestEntityIndex(); i++) + { + auto pEntity = iff.g_pEntityList->GetClientEntity(i); + if (pEntity && _tcsstr(pEntity->GetClientClass()->GetName(), _T("CRopeKeyframe")) != NULL) + { + printfdbg("CRopeKeyframe found %d\n", i); + + entry = i; + break; + } + } + + + createWearable(entry, serial); + glove = (C_BaseAttributableItem*)iff.g_pEntityList->GetClientEntity(entry); + glove->initialized() = true; + hWearables[0] = entry | serial << 16; + + static int(__thiscall * equipWearable)(void* wearable, void* player) = reinterpret_cast(FindPatternV2("client.dll", "55 8B EC 83 EC 10 53 8B 5D 08 57 8B F9")); + equipWearable(glove, localplayer); + localplayer->body() = 1; + glove->SetModelIndex(iff.g_pMdlInfo->GetModelIndex(g_Options.weapons.value->arr[1].worldmodel)); + iff.g_pClientState->ForceFullUpdate(); + } + + if (glove) + { + glove->GetItemDefinitionIndex() = g_Options.weapons.value->arr[1].modeldefindex; + glove->GetItemIDHigh() = -1; + glove->GetAccountID() = localplayer_info.xuidlow; + glove->GetFallbackPaintKit() = g_Options.weapons.value->arr[1].skinid; + glove->GetFallbackSeed() = g_Options.weapons.value->arr[1].seed; + glove->GetFallbackWear() = g_Options.weapons.value->arr[1].wear; + static int(__thiscall* fnInitializeAttributes)(void* wearable) = reinterpret_cast(FindPatternV2("client.dll", "55 8B EC 83 E4 F8 83 EC 0C 53 56 8B F1 8B 86")); + fnInitializeAttributes(glove); + //iff.g_pClientLeafSystem->CreateRenderableHandle(glove); + //https://www.unknowncheats.me/forum/counterstrike-global-offensive/312102-itemschema-skins-glove-changer-stickers.html + } + } + + if (g_Options.weapons.value->arr[0].active && g_Options.weapons.value->arr[0].modelactive) + { + //May cause crash idk why + /* + static int lastmdlindex = -1; + int curmdlindex = pViewModel->GetModelIndex(); + if (lastmdlindex != curmdlindex) + { + lastmdlindex = curmdlindex; + int defindex = view_model_weapon->GetItemDefinitionIndex(); + + if (!is_knife(defindex)) { + for (int i = 0; i < 20; i++) + if (_tcsstr(pViewModel->GetSequenceActivity(i), "draw")) + { + printfdbg("SendViewModelMatchingSequence %d to %d (%d)", i, lastmdlindex, defindex); + pViewModel->SendViewModelMatchingSequence(i); break; + } + + } + } + */ + + if (view_model_weapon && is_knife(view_model_weapon->GetItemDefinitionIndex())) + { + const auto override_model_index = iff.g_pMdlInfo->GetModelIndex(g_Options.weapons.value->arr[0].model); + pViewModel->GetModelIndex() = override_model_index; + + } + } + + auto& weapons = localplayer->GetWeapons(); + + for (auto weapon_handle : weapons) + { + if (weapon_handle == INVALID_EHANDLE_INDEX) + break; + + C_BaseAttributableItem* weapon = static_cast(iff.g_pEntityList->GetClientEntityFromHandle(weapon_handle)); + + if (!weapon) + continue; + + short item_definition_index = weapon->GetItemDefinitionIndex(); + + if (item_definition_index == WEAPON_C4 && g_Options.weapons.value->arr[GetCfgIndex(item_definition_index)].active) + weapon->body() = 2; + + if (item_definition_index == 42) item_definition_index = 59; + + int configindex = GetCfgIndex(item_definition_index); + if (configindex == -1) continue; + + if (g_Options.weapons.value->arr[configindex].active) + { + if (is_knife(item_definition_index) && g_Options.weapons.value->arr[0].modelactive) + { + weapon->GetItemDefinitionIndex() = g_Options.weapons.value->arr[0].modeldefindex; + short mdlindex = iff.g_pMdlInfo->GetModelIndex(g_Options.weapons.value->arr[0].model); + if (mdlindex) { + weapon->GetModelIndex() = mdlindex; + //auto m_pWorld = (C_BaseEntity*)iff.g_pEntityList->GetClientEntityFromHandle(weapon->GetWeaponWorldModel()); + //m_pWorld->GetModelIndex() = mdlindex + 1; + } + } + weapon->GetItemIDHigh() = -1; + + if (!g_Options.weapons.value->arr[configindex].ownerunk) + weapon->GetAccountID() = localplayer_info.xuidlow; + weapon->GetEntityQuality() = g_Options.weapons.value->arr[configindex].quality; + snprintf(weapon->GetCustomName(), 32, "%s", g_Options.weapons.value->arr[configindex].nametag); + + weapon->GetFallbackPaintKit() = g_Options.weapons.value->arr[configindex].skinid; + weapon->GetFallbackSeed() = g_Options.weapons.value->arr[configindex].seed; + weapon->GetFallbackWear() = g_Options.weapons.value->arr[configindex].wear; + weapon->GetFallbackStatTrak() = g_Options.weapons.value->arr[configindex].stattrak; + + ApplyStickers(weapon); + + } + } + + + if (*g_Options.nvgsON) + NightvisionRun(localplayer); + + if (*g_Options.flashlightON) + FlashlightRun(localplayer); + + if (*g_Options.weatheractive) + do_precipitation(); + + return 1; +} + + + + +void __fastcall hkFrameStageNotify(IBaseClientDLL* thisptr, void* edx, ClientFrameStage_t stage) +{ + static auto oFrameStageNotify = ClientHook->GetOriginal(37); + + if ( (*g_Options.playerloop_count || *g_Options.entityloop_count) && stage == ClientFrameStage_t::FRAME_NET_UPDATE_POSTDATAUPDATE_END) + { + for (int i = 1; i < 65; i++) + { + C_BasePlayer* pEntity = (C_BasePlayer*)iff.g_pEntityList->GetClientEntity(i); + + if (i == iff.g_pEngineClient->GetLocalPlayer()) continue; + + if (!pEntity || pEntity->IsDormant()) + continue; + + int team = pEntity->GetTeam(); + if ((team < 2) || (team > 3)) continue; + team -= 2; + + if (g_Options.models.value->arr[team].active) { + + char* model = g_Options.models.value->arr[team].vmodel_repl; + + pEntity->GetModelIndex() = iff.g_pMdlInfo->GetModelIndex(model); + if (const auto modelprecache = iff.g_pNetworkStringTableContainer->FindTable("modelprecache")) + { + modelprecache->AddString(false, model); + const auto viewmodelArmConfig = iff.getPlayerViewmodelArmConfigForPlayerModel(model); + modelprecache->AddString(false, viewmodelArmConfig[2]); + modelprecache->AddString(false, viewmodelArmConfig[3]); + } + + const auto m_hRagdoll = (C_BaseEntity*)iff.g_pEntityList->GetClientEntityFromHandle(pEntity->Ragdoll()); + if (m_hRagdoll) + m_hRagdoll->SetModelIndex(iff.g_pMdlInfo->GetModelIndex(model)); + } + + if (g_Options.models.value->arr[team].active_scale) + pEntity->GetModelScale() = g_Options.models.value->arr[team].scale; + + } + } + + if (stage == ClientFrameStage_t::FRAME_NET_UPDATE_POSTDATAUPDATE_START) { + + Changer(); + + + if (opt.needupdate) { + static PVOID clear_hud_weapon_icon_ptr = relativeToAbsolute(FindPatternV2("client.dll", "E8 ? ? ? ? 8B F0 C6 44 24 ? ? C6 44 24") + 1); + static auto clearHudWeapon = reinterpret_cast(clear_hud_weapon_icon_ptr); + + auto element = FindHudElement("CCSGO_HudWeaponSelection"); + auto hud_weapons = reinterpret_cast(std::uintptr_t(element) - 0xA0); + + if (hud_weapons) { + for (int i = 0; i < *(hud_weapons + 32); i++) { + i = clearHudWeapon(hud_weapons, i); + } + } + + opt.needupdate = 0; + } + } + + oFrameStageNotify(thisptr, stage); +} + + + + +void InitSkinChanger() +{ + itemSystem = relativeToAbsolute(FindPatternV2("client.dll", "E8 ? ? ? ? 0F B7 0F") + 1); + + printfdbg("itemschema2 %x\n", itemSystem()->getItemSchema()); + + for (const auto& node : itemSystem()->getItemSchema()->itemsSorted) { + const auto item = node.value; + + if (std::strcmp(item->m_szWeaponType, "#CSGO_Type_Knife") == 0) + if (item->m_szWorldModel) + knives.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, item->m_szViewModel, item->m_szWorldModel)); + else knives.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, item->m_szViewModel, "")); + + if (std::strcmp(item->m_szWeaponType, "#CSGO_Type_Collectible") == 0) + medals.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, "", "")); + + if (std::strcmp(item->m_szWeaponType, "#Type_Hands") == 0) + if (item->m_szWorldModel) + gloves.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, item->m_szViewModel, item->m_szWorldModel)); + else gloves.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, item->m_szViewModel, "")); + + if (std::strcmp(item->m_szWeaponType, "#Type_CustomPlayer") == 0) + if (item->m_szWorldModel) + agents.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, item->m_szViewModel, item->m_szWorldModel)); + else agents.push_back(iitem(item->m_iItemDefinitionIndex, item->m_szWeaponName3, item->m_szViewModel, "")); + + } + + for (const auto& node : itemSystem()->getItemSchema()->qualities) { + const auto item = node.value; + qualities.push_back(iitem(item.id, item.name, "", "")); + } + + for (const auto& node : itemSystem()->getItemSchema()->rars) { + const auto item = node.value; + rarities.push_back(iitem(item.id, item.name.szBuffer, "", "")); + } + + auto musickitsS = itemSystem()->getItemSchema()->music_definitions; + + for (int i = (int)musickitsS.memory; i < (int)musickitsS.memory + musickitsS.itemcount * 0x18; i += 0x18) + { + CEconMusicDefinition* music = *(CEconMusicDefinition**)(i + 0x14); + musickits.push_back(iitem(music->id, music->name, "", "")); + } + + const auto& paintkitMap = itemSystem()->getItemSchema()->paintKits; + int paintkitcount = 0; + for (const auto& node : paintkitMap) { + const auto pKit = node.value; + opt.sc_skins.push_back(Options_my::skinstruct(pKit->nID, pKit->sName.szBuffer, paintkitcount, pKit->rarity, pKit->color1, pKit->color2, pKit->color3, pKit->color4, pKit->pearlescent, (DWORD)&pKit->nID)); + paintkitcount++; + } + + const auto& stickerMap = itemSystem()->getItemSchema()->stickerKits; + int stickercount = 0; + for (const auto& node : stickerMap) { + const auto stickerKit = node.value; + opt.sc_stickers.push_back(Options_my::stickerstruct(stickerKit->id, stickerKit->name.szBuffer, stickercount)); + stickercount++; + } + + printfdbg("counts %d %d %d %d %d %d %d\n", + knives.size(), gloves.size(), agents.size(), medals.size(), musickits.size(), opt.sc_skins.size(), opt.sc_stickers.size()); + + const auto& prefabMap = itemSystem()->getItemSchema()->prefabs; + for (const auto& node : prefabMap) { + KeyValues* kv = node.value; + int cfgindex = GetCfgIndexByPrefab(fnv2::hash(kv->GetName())); + if (cfgindex == -1) continue; + int soundcount = 0; + const char* vmodel_orig = kv->GetString("model_player"); + strcpy(g_Options.models.value->arr[cfgindex].vmodel_orig, vmodel_orig); + strcpy(g_Options.models.value->arr[cfgindex].vmodel_repl_temp, vmodel_orig); + strcpy(g_Options.models.value->arr[cfgindex].vmodel_repl, vmodel_orig); + + const char* wmodel_orig = kv->GetString("model_world"); + strcpy(g_Options.models.value->arr[cfgindex].wmodel_repl_temp, wmodel_orig); + strcpy(g_Options.models.value->arr[cfgindex].wmodel_repl, wmodel_orig); + + g_Options.materials.value->arr[cfgindex + 2].model_hash = fnv2::hash(vmodel_orig); + + + kv = kv->FindKey("visuals"); + if (kv) { + char* sound_single_shot = (char*)kv->GetString("sound_single_shot"); + if (sound_single_shot[0] != 0x0) { + strcpy(g_Options.models.value->arr[cfgindex].sounds[soundcount].name, sound_single_shot); + g_Options.models.value->arr[cfgindex].sounds[soundcount].hash = GenerateSoundEntryHash(sound_single_shot); + soundcount++; + } + + char* sound_single_shot_accurate = (char*)kv->GetString("sound_single_shot_accurate"); + if (sound_single_shot_accurate[0] != 0x0) { + strcpy(g_Options.models.value->arr[cfgindex].sounds[soundcount].name, sound_single_shot); + g_Options.models.value->arr[cfgindex].sounds[soundcount].hash = GenerateSoundEntryHash(sound_single_shot); + soundcount++; + } + + char* sound_special1 = (char*)kv->GetString("sound_special1"); + if (sound_special1[0] != 0x0) { + strcpy(g_Options.models.value->arr[cfgindex].sounds[soundcount].name, sound_special1); + g_Options.models.value->arr[cfgindex].sounds[soundcount].hash = GenerateSoundEntryHash(sound_special1); + soundcount++; + } + } + g_Options.models.value->arr[cfgindex].soundcount = soundcount; + } + + + c_vpk_archive pak01_archive; + if (pak01_archive.load("csgo/pak01_dir.vpk")) + for (auto const& pair : pak01_archive.files) + if (!pair.first.find("materials/panorama/images/icons/equipment")) + opt.killfeedicons.push_back(pair.first.substr(42, pair.first.length() - 46)); + + + g_Options.weapons.value->arr[0].modeldefindex = knives[0].defindex; + strcpy(g_Options.weapons.value->arr[0].model, knives[0].viewmodel.c_str()); + strcpy(g_Options.weapons.value->arr[0].worldmodel, knives[0].worldmodel.c_str()); + g_Options.weapons.value->arr[0].modelactive = 1; + + g_Options.weapons.value->arr[1].modeldefindex = gloves[0].defindex; + strcpy(g_Options.weapons.value->arr[1].model, gloves[0].viewmodel.c_str()); + strcpy(g_Options.weapons.value->arr[1].worldmodel, gloves[0].worldmodel.c_str()); + g_Options.weapons.value->arr[1].modelactive = 1; + + g_Options.weapons.value->arr[2].modeldefindex = agents[0].defindex; + strcpy(g_Options.weapons.value->arr[2].model, agents[0].viewmodel.c_str()); + g_Options.weapons.value->arr[2].modelactive = 1; + + g_Options.weapons.value->arr[3].modelcount = 1; + g_Options.weapons.value->arr[3].modeldefindex = agents[1].defindex; + strcpy(g_Options.weapons.value->arr[3].model, agents[1].viewmodel.c_str()); + g_Options.weapons.value->arr[3].modelactive = 1; + + g_Options.weapons.value->arr[4].modeldefindex = medals[0].defindex; + g_Options.weapons.value->arr[4].modelactive = 1; + + g_Options.weapons.value->arr[5].modeldefindex = musickits[0].defindex; + g_Options.weapons.value->arr[5].modelactive = 1; + + g_Options.models.value->arr[2].findMDLmethode = 1; + +} + +``` + +`SpyCustom/SpyCustom.vcxproj`: + +```vcxproj + + + + + Release + Win32 + + + + 16.0 + Win32Proj + {bde23281-b75d-4fb2-9b8e-08e1ae0a9bbd} + SpyCustom + 10.0 + Seaside + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v143 + true + MultiByte + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + C:\Program Files (x86)\GnuWin32\include;C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) + C:\Program Files (x86)\GnuWin32\lib;C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath) + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;SPYCUSTOM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + + + Windows + true + false + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;SPYCUSTOM_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + NotUsing + pch.h + stdcpp17 + + + Windows + true + true + false + false + Winmm.lib;%(AdditionalLibraryDirectories) + false + + + + + Level3 + true + _DEBUG;SPYCUSTOM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;SPYCUSTOM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +`SpyCustom/SpyCustom.vcxproj.filters`: + +```filters + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {99d6dc10-ba05-4949-84fb-2b274bb90ee8} + + + {cc8ba9e4-8d47-413e-8f49-530c07a99955} + + + {2d181d74-7735-45bf-841d-c3a395221030} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Protobuffs + + + Header Files\Protobuffs + + + Header Files\Protobuffs + + + Header Files\Protobuffs + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Header Files\sdk + + + Resource Files + + + Header Files\sdk + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Header Files\imgui + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + +``` + +`SpyCustom/SpyCustom.vcxproj.user`: + +```user + + + + +``` + +`SpyCustom/VMT.hpp`: + +```hpp +#pragma once + +#include +#include + +#include +#include "Interfaces.hpp" + +class VMTHook +{ +public: + VMTHook(void* classptr) + { + this->class_pointer = reinterpret_cast(classptr); + + int table_size = 0; + while (reinterpret_cast(*this->class_pointer)[table_size]) + table_size++; + + original_pointer = *this->class_pointer; + + new_table_pointer = new uintptr_t[sizeof(uintptr_t) * table_size]; + memcpy(new_table_pointer, original_pointer, sizeof(uintptr_t) * table_size); + } + + ~VMTHook() + { + RestoreOldTable(); + delete original_pointer; + delete new_table_pointer; + } + + void SwapPointer(size_t index, void* new_function) + { + printfdbg("Swapping pointer 0x%X to 0x%X\n", new_table_pointer[index], reinterpret_cast(new_function)); + new_table_pointer[index] = reinterpret_cast(new_function); + //printfdbg("Swapped pointer!\n"); + + } + + void ApplyNewTable() + { + printfdbg("Applying new table... (0x%X to 0x%X)\n", reinterpret_cast(*class_pointer), reinterpret_cast(new_table_pointer)); + * class_pointer = new_table_pointer; + //printfdbg("New table applyed!\n"); + } + + void RestoreOldTable() + { + printfdbg("Restoring old table... (0x%X to 0x%X)\n", reinterpret_cast(*class_pointer), reinterpret_cast(original_pointer)); + * class_pointer = original_pointer; + //printfdbg("Old table restored!\n"); + } + + template + T GetOriginal(size_t index) + { + return reinterpret_cast(original_pointer[index]); + } + +private: + uintptr_t** class_pointer = nullptr; + uintptr_t* original_pointer = nullptr; + uintptr_t* new_table_pointer = nullptr; +}; + +``` + +`SpyCustom/XorStr.hpp`: + +```hpp +#pragma once +#include +#include +#include + +#define BEGIN_NAMESPACE( x ) namespace x { +#define END_NAMESPACE } + +BEGIN_NAMESPACE(XorCompileTime) + +constexpr auto time = __TIME__; +constexpr auto seed = static_cast(time[7]) + static_cast(time[6]) * 10 + static_cast(time[4]) * 60 + static_cast(time[3]) * 600 + static_cast(time[1]) * 3600 + static_cast(time[0]) * 36000; + +template < int N > +struct RandomGenerator { +private: + static constexpr unsigned a = 16807; + static constexpr unsigned m = 2147483647; + + static constexpr unsigned s = RandomGenerator< N - 1 >::value; + static constexpr unsigned lo = a * (s & 0xFFFF); + static constexpr unsigned hi = a * (s >> 16); + static constexpr unsigned lo2 = lo + ((hi & 0x7FFF) << 16); + static constexpr unsigned hi2 = hi >> 15; + static constexpr unsigned lo3 = lo2 + hi; + +public: + static constexpr unsigned max = m; + static constexpr unsigned value = lo3 > m ? lo3 - m : lo3; +}; + +template <> +struct RandomGenerator< 0 > { + static constexpr unsigned value = seed; +}; + +template < int N, int M > +struct RandomInt { + static constexpr auto value = RandomGenerator< N + 1 >::value % M; +}; + +template < int N > +struct RandomChar { + static const char value = static_cast(1 + RandomInt< N, 0x7F - 1 >::value); +}; + +template < size_t N, int K > +struct XorString { +private: + const char _key; + std::array< char, N + 1 > _encrypted; + + constexpr char enc(char c) const { + return c ^ _key; + } + + char dec(char c) const { + return c ^ _key; + } + +public: + template < size_t... Is > + constexpr __forceinline XorString(const char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... } { + } + + __forceinline decltype(auto) decrypt(void) { + for (size_t i = 0; i < N; ++i) { + _encrypted[i] = dec(_encrypted[i]); + } + _encrypted[N] = '\0'; + return _encrypted.data(); + } +}; + +static auto w_printf = [](const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vprintf_s(fmt, args); + va_end(args); +}; + +static auto w_printf_s = [](const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vprintf_s(fmt, args); + va_end(args); +}; + +static auto w_sprintf = [](char* buf, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); +}; + +static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vsprintf_s(buf, buf_size, fmt, args); + va_end(args); +}; + +#ifdef NDEBUG +#define XorStr( s ) ( XorCompileTime::XorString< sizeof( s ) - 1, __COUNTER__ >( s, std::make_index_sequence< sizeof( s ) - 1>() ).decrypt() ) +#else +#define XorStr( s ) ( s ) +#endif + +END_NAMESPACE +``` + +`SpyCustom/checksum_md5.cpp`: + +```cpp +#include "sdk/checksum_md5.h" +#include +#include +//#include "tier1/strtools.h" +//#include "tier0/dbg.h" + +// memdbgon must be the last include file in a .cpp file!!! +//#include "tier0/memdbgon.h" + +// The four core functions - F1 is optimized somewhat +// #define F1(x, y, z) (x & y | ~x & z) +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +// This is the central step in the MD5 algorithm. +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +//----------------------------------------------------------------------------- +// Purpose: The core of the MD5 algorithm, this alters an existing MD5 hash to +// reflect the addition of 16 longwords of new data. MD5Update blocks +// the data and converts bytes into longwords for this routine. +// Input : buf[4] - +// in[16] - +// Output : static void +//----------------------------------------------------------------------------- +static void MD5Transform(unsigned int buf[4], unsigned int const in[16]) +{ + 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; +} + +//----------------------------------------------------------------------------- +// Purpose: Start MD5 accumulation. Set bit count to 0 and buffer to mysterious initialization constants. + +// Input : *ctx - +//----------------------------------------------------------------------------- +void MD5Init(MD5Context_t* ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Update context to reflect the concatenation of another buffer full of bytes. +// Input : *ctx - +// *buf - +// len - +//----------------------------------------------------------------------------- +void MD5Update(MD5Context_t* ctx, unsigned char const* buf, unsigned int len) +{ + unsigned int t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((unsigned int)len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) + { + unsigned char* p = (unsigned char*)ctx->in + t; + + t = 64 - t; + if (len < t) + { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +//----------------------------------------------------------------------------- +// Purpose: Final wrapup - pad to 64-byte boundary with the bit pattern +// 1 0* (64-bit count of bits processed, MSB-first) +// Input : digest[MD5_DIGEST_LENGTH] - +// *ctx - +//----------------------------------------------------------------------------- +void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5Context_t* ctx) +{ + unsigned count; + unsigned char* p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + //byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((unsigned int*)ctx->in)[14] = ctx->bits[0]; + ((unsigned int*)ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + //byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *hash - +// hashlen - +// Output : char +//----------------------------------------------------------------------------- +char* MD5_Print(unsigned char* hash, int hashlen) +{ + static char szReturn[64]; + + // Assert(hashlen <= 32); + + // Q_binarytohex(hash, hashlen, szReturn, sizeof(szReturn)); + return szReturn; +} + +//----------------------------------------------------------------------------- +// Purpose: generate pseudo random number from a seed number +// Input : seed number +// Output : pseudo random number +//----------------------------------------------------------------------------- +unsigned int MD5_PseudoRandom(unsigned int nSeed) +{ + MD5Context_t ctx; + unsigned char digest[MD5_DIGEST_LENGTH]; // The MD5 Hash + + memset(&ctx, 0, sizeof(ctx)); + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)&nSeed, sizeof(nSeed)); + MD5Final(digest, &ctx); + + return *(unsigned int*)(digest + 6); // use 4 middle bytes for random value +} +``` + +`SpyCustom/detours.h`: + +```h +#pragma once +#ifndef _DETOURS_H_ +#define _DETOURS_H_ + +#pragma comment(lib, "detours") + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[ 8 ]; +} GUID; +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif +#else +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID * const +#endif +#endif +#ifdef __cplusplus +extern "C" { +#endif + +#define DETOUR_INSTRUCTION_TARGET_NONE ((PBYTE)0) +#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PBYTE)~0ul) + +#define DETOUR_TRAMPOLINE_SIZE 32 +#define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 + +#define DETOUR_TRAMPOLINE(trampoline,target) \ +static PVOID __fastcall _Detours_GetVA_##target(VOID) \ +{ \ + return ⌖ \ +} \ +\ +__declspec(naked) trampoline \ +{ \ + __asm { nop };\ + __asm { nop };\ + __asm { call _Detours_GetVA_##target };\ + __asm { jmp eax };\ + __asm { ret };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ +} + +#define DETOUR_TRAMPOLINE_EMPTY(trampoline) \ +__declspec(naked) trampoline \ +{ \ + __asm { nop };\ + __asm { nop };\ + __asm { xor eax, eax };\ + __asm { mov eax, [eax] };\ + __asm { ret };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ +} + +#pragma pack(push, 8) +typedef struct _DETOUR_SECTION_HEADER +{ + DWORD cbHeaderSize; + DWORD nSignature; + DWORD nDataOffset; + DWORD cbDataSize; + + DWORD nOriginalImportVirtualAddress; + DWORD nOriginalImportSize; + DWORD nOriginalBoundImportVirtualAddress; + DWORD nOriginalBoundImportSize; + + DWORD nOriginalIatVirtualAddress; + DWORD nOriginalIatSize; + DWORD nOriginalSizeOfImage; + DWORD nReserve; +} DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; + +typedef struct _DETOUR_SECTION_RECORD +{ + DWORD cbBytes; + DWORD nReserved; + GUID guid; +} DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; +#pragma pack(pop) + +#define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ +{ \ + sizeof(DETOUR_SECTION_HEADER),\ + DETOUR_SECTION_HEADER_SIGNATURE,\ + sizeof(DETOUR_SECTION_HEADER),\ + (cbSectionSize),\ + \ + 0,\ + 0,\ + 0,\ + 0,\ + \ + 0,\ + 0,\ + 0,\ + 0,\ +} + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)(PVOID pContext, + PCHAR pszFile, + PCHAR *ppszOutFile); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)(PVOID pContext, + PCHAR pszOrigFile, + PCHAR pszFile, + PCHAR *ppszOutFile); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)(PVOID pContext, + DWORD nOrdinal, + PCHAR pszOrigSymbol, + PCHAR pszSymbol, + PCHAR *ppszOutSymbol); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FINAL_CALLBACK)(PVOID pContext); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_EXPORT_CALLBACK)(PVOID pContext, + DWORD nOrdinal, + PCHAR pszName, + PBYTE pbCode); + +typedef VOID * PDETOUR_BINARY; +typedef VOID * PDETOUR_LOADED_BINARY; + +PBYTE WINAPI DetourFunction(PBYTE pbTargetFunction, + PBYTE pbDetourFunction); + +BOOL WINAPI DetourFunctionWithEmptyTrampoline(PBYTE pbTrampoline, + PBYTE pbTarget, + PBYTE pbDetour); + +BOOL WINAPI DetourFunctionWithEmptyTrampolineEx(PBYTE pbTrampoline, + PBYTE pbTarget, + PBYTE pbDetour, + PBYTE *ppbRealTrampoline, + PBYTE *ppbRealTarget, + PBYTE *ppbRealDetour); + +BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, + PBYTE pbDetour); + +BOOL WINAPI DetourFunctionWithTrampolineEx(PBYTE pbTrampoline, + PBYTE pbDetour, + PBYTE *ppbRealTrampoline, + PBYTE *ppbRealTarget); + +BOOL WINAPI DetourRemove(PBYTE pbTrampoline, PBYTE pbDetour); + +PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction); +PBYTE WINAPI DetourGetFinalCode(PBYTE pbCode, BOOL fSkipJmp); + +PBYTE WINAPI DetourCopyInstruction(PBYTE pbDst, PBYTE pbSrc, PBYTE *ppbTarget); +PBYTE WINAPI DetourCopyInstructionEx(PBYTE pbDst, + PBYTE pbSrc, + PBYTE *ppbTarget, + LONG *plExtra); + +HMODULE WINAPI DetourEnumerateModules(HMODULE hModuleLast); +PBYTE WINAPI DetourGetEntryPoint(HMODULE hModule); +BOOL WINAPI DetourEnumerateExports(HMODULE hModule, + PVOID pContext, + PF_DETOUR_BINARY_EXPORT_CALLBACK pfExport); + +PBYTE WINAPI DetourFindPayload(HMODULE hModule, REFGUID rguid, DWORD *pcbData); +DWORD WINAPI DetourGetSizeOfPayloads(HMODULE hModule); + +BOOL WINAPI DetourBinaryBindA(PCHAR pszFile, PCHAR pszDll, PCHAR pszPath); +BOOL WINAPI DetourBinaryBindW(PWCHAR pwzFile, PWCHAR pwzDll, PWCHAR pwzPath); +#ifdef UNICODE +#define DetourBinaryBind DetourBinaryBindW +#else +#define DetourBinaryBind DetourBinaryBindA +#endif + +PDETOUR_BINARY WINAPI DetourBinaryOpen(HANDLE hFile); +PBYTE WINAPI DetourBinaryEnumeratePayloads(PDETOUR_BINARY pBinary, + GUID *pGuid, + DWORD *pcbData, + DWORD *pnIterator); +PBYTE WINAPI DetourBinaryFindPayload(PDETOUR_BINARY pBinary, + REFGUID rguid, + DWORD *pcbData); +PBYTE WINAPI DetourBinarySetPayload(PDETOUR_BINARY pBinary, + REFGUID rguid, + PBYTE pbData, + DWORD cbData); +BOOL WINAPI DetourBinaryDeletePayload(PDETOUR_BINARY pBinary, REFGUID rguid); +BOOL WINAPI DetourBinaryPurgePayloads(PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryResetImports(PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryEditImports(PDETOUR_BINARY pBinary, + PVOID pContext, + PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, + PF_DETOUR_BINARY_FILE_CALLBACK pfFile, + PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, + PF_DETOUR_BINARY_FINAL_CALLBACK pfFinal); +BOOL WINAPI DetourBinaryWrite(PDETOUR_BINARY pBinary, HANDLE hFile); +BOOL WINAPI DetourBinaryClose(PDETOUR_BINARY pBinary); + +LPTOP_LEVEL_EXCEPTION_FILTER WINAPI +DetourFirstChanceExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelFilter); + +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA) + (LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation); + +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW) + (LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation); + +BOOL WINAPI DetourCreateProcessWithDllA(LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, + LPCSTR lpDllName, + PDETOUR_CREATE_PROCESS_ROUTINEA + pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllW(LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, + LPCWSTR lpDllName, + PDETOUR_CREATE_PROCESS_ROUTINEW + pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDll DetourCreateProcessWithDllW +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW +#else +#define DetourCreateProcessWithDll DetourCreateProcessWithDllA +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA +#endif + +BOOL WINAPI DetourContinueProcessWithDllA(HANDLE hProcess, LPCSTR lpDllName); +BOOL WINAPI DetourContinueProcessWithDllW(HANDLE hProcess, LPCWSTR lpDllName); + +#ifdef UNICODE +#define DetourContinueProcessWithDll DetourContinueProcessWithDllW +#else +#define DetourContinueProcessWithDll DetourContinueProcessWithDllA +#endif +#ifdef __cplusplus +} +#endif + +#define ContinueProcessWithDll DetourContinueProcessWithDll +#define ContinueProcessWithDllA DetourContinueProcessWithDllA +#define ContinueProcessWithDllW DetourContinueProcessWithDllW +#define CreateProcessWithDll DetourCreateProcessWithDll +#define CreateProcessWithDllA DetourCreateProcessWithDllA +#define CreateProcessWithDllW DetourCreateProcessWithDllW +#define DETOUR_TRAMPOLINE_WO_TARGET DETOUR_TRAMPOLINE_EMPTY +#define DetourBinaryPurgePayload DetourBinaryPurgePayloads +#define DetourEnumerateExportsForInstance DetourEnumerateExports +#define DetourEnumerateInstances DetourEnumerateModules +#define DetourFindEntryPointForInstance DetourGetEntryPoint +#define DetourFindFinalCode DetourGetFinalCode +#define DetourFindPayloadInBinary DetourFindPayload +#define DetourGetSizeOfBinary DetourGetSizeOfPayloads +#define DetourRemoveWithTrampoline DetourRemove +#define PCREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINE +#define PCREATE_PROCESS_ROUTINEA PDETOUR_CREATE_PROCESS_ROUTINEA +#define PCREATE_PROCESS_ROUTINEW PDETOUR_CREATE_PROCESS_ROUTINEW +#ifdef __cplusplus +#ifdef DETOURS_INTERNAL + +#ifdef IMAGEAPI +typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(LPAPI_VERSION AppVersion); + +typedef BOOL (NTAPI *PF_SymInitialize)(IN HANDLE hProcess, + IN LPSTR UserSearchPath, + IN BOOL fInvadeProcess); +typedef DWORD (NTAPI *PF_SymSetOptions)(IN DWORD SymOptions); +typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); +typedef BOOL (NTAPI *PF_SymLoadModule)(IN HANDLE hProcess, + IN HANDLE hFile, + IN PSTR ImageName, + IN PSTR ModuleName, + IN DWORD BaseOfDll, + IN DWORD SizeOfDll); +typedef BOOL (NTAPI *PF_SymGetModuleInfo)(IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PIMAGEHLP_MODULE ModuleInfo); +typedef BOOL (NTAPI *PF_SymGetSymFromName)(IN HANDLE hProcess, + IN LPSTR Name, + OUT PIMAGEHLP_SYMBOL Symbol); +typedef BOOL (NTAPI *PF_BindImage)(IN LPSTR pszImageName, + IN LPSTR pszDllPath, + IN LPSTR pszSymbolPath); + +typedef struct _DETOUR_SYM_INFO +{ + HANDLE hProcess; + HMODULE hImageHlp; + PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; + PF_SymInitialize pfSymInitialize; + PF_SymSetOptions pfSymSetOptions; + PF_SymGetOptions pfSymGetOptions; + PF_SymLoadModule pfSymLoadModule; + PF_SymGetModuleInfo pfSymGetModuleInfo; + PF_SymGetSymFromName pfSymGetSymFromName; + PF_BindImage pfBindImage; +} DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; + +PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); + +#endif + +class CDetourEnableWriteOnCodePage +{ +public: + CDetourEnableWriteOnCodePage(PBYTE pbCode, LONG cbCode = DETOUR_TRAMPOLINE_SIZE) + { + m_pbCode = pbCode; + m_cbCode = cbCode; + m_dwOldPerm = 0; + m_hProcess = GetCurrentProcess(); + + if (m_pbCode && m_cbCode) { + if (!FlushInstructionCache(m_hProcess, pbCode, cbCode)) { + return; + } + if (!VirtualProtect(pbCode, + cbCode, + PAGE_EXECUTE_READWRITE, + &m_dwOldPerm)) { + return; + } + } + } + + ~CDetourEnableWriteOnCodePage() + { + if (m_dwOldPerm && m_pbCode && m_cbCode) { + DWORD dwTemp = 0; + if (!FlushInstructionCache(m_hProcess, m_pbCode, m_cbCode)) { + return; + } + if (!VirtualProtect(m_pbCode, m_cbCode, m_dwOldPerm, &dwTemp)) { + return; + } + } + } + + BOOL SetPermission(DWORD dwPerms) + { + if (m_dwOldPerm && m_pbCode && m_cbCode) { + m_dwOldPerm = dwPerms; + return TRUE; + } + return FALSE; + } + + BOOL IsValid(VOID) + { + return m_pbCode && m_cbCode && m_dwOldPerm; + } + +private: + HANDLE m_hProcess; + PBYTE m_pbCode; + LONG m_cbCode; + DWORD m_dwOldPerm; +}; + +inline PBYTE DetourGenMovEax(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xB8; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEbx(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBB; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEcx(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xB9; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEdx(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBA; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEsi(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBE; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEdi(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBF; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEbp(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBD; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEsp(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBC; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenPush(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0x68; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenPushad(PBYTE pbCode) +{ + *pbCode++ = 0x60; + return pbCode; +} + +inline PBYTE DetourGenPopad(PBYTE pbCode) +{ + *pbCode++ = 0x61; + return pbCode; +} + +inline PBYTE DetourGenJmp(PBYTE pbCode, PBYTE pbJmpDst, PBYTE pbJmpSrc = 0) +{ + if (pbJmpSrc == 0) { + pbJmpSrc = pbCode; + } + *pbCode++ = 0xE9; + *((INT32*&)pbCode)++ = pbJmpDst - (pbJmpSrc + 5); + return pbCode; +} + +inline PBYTE DetourGenCall(PBYTE pbCode, PBYTE pbJmpDst, PBYTE pbJmpSrc = 0) +{ + if (pbJmpSrc == 0) { + pbJmpSrc = pbCode; + } + *pbCode++ = 0xE8; + *((INT32*&)pbCode)++ = pbJmpDst - (pbJmpSrc + 5); + return pbCode; +} + +inline PBYTE DetourGenBreak(PBYTE pbCode) +{ + *pbCode++ = 0xcc; + return pbCode; +} + +inline PBYTE DetourGenRet(PBYTE pbCode) +{ + *pbCode++ = 0xc3; + return pbCode; +} + +inline PBYTE DetourGenNop(PBYTE pbCode) +{ + *pbCode++ = 0x90; + return pbCode; +} +#endif DETOURS_INTERAL +#endif + +#endif + +``` + +`SpyCustom/dllmain.cpp`: + +```cpp +#pragma once +#include +#include "Interfaces.hpp" +#include "NetVarManager.hpp" +#include "VMT.hpp" +#include "EventListener.hpp" +#include +#include "detours.h" +#pragma comment(lib, "detours.lib") +#include "imgui/imgui.h" +#include "imgui/imgui_impl_dx9.h" +#include "imgui/imgui_impl_win32.h" +#include +#include +#pragma comment(lib, "d3d9.lib") +#pragma comment(lib, "d3dx9.lib") +#include "Other.hpp" +#include "sdk/c_baseentity.h" +#include "PatternScan.hpp" +#include "SkinChanger.hpp" +#include "Config.hpp" +#include "protobuffs.hpp" +using namespace std; +#include "proxies.hpp" +#include "Hooks.hpp" +#include "Menu.hpp" +#include "SkinChanger.hpp" + +#include "resources.h" + +void OnLevelInit() +{ + if (g_Options.skyboxactive) + { + iff.g_pCVar->FindVar("sv_skyname")->SetValue((char*)g_Options.skyboxtemp.value.get()); + iff.g_pCVar->FindVar("r_3dsky")->SetValue(false); + } + + if (g_Options.fogactive) + { + SetValueUnrestricted("fog_enable", 1); + SetValueUnrestricted("fog_enableskybox", 1); + SetValueUnrestricted("fog_override", 1); + + iff.g_pCVar->FindVar("fog_color")->SetValue( + std::string(""). + append(std::to_string(g_Options.fogcolor.value->r * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->g * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->b * 255)). + append(" ").c_str() + ); + iff.g_pCVar->FindVar("fog_colorskybox")->SetValue( + std::string(""). + append(std::to_string(g_Options.fogcolor.value->r * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->g * 255)). + append(" "). + append(std::to_string(g_Options.fogcolor.value->b * 255)). + append(" ").c_str() + ); + SetValueUnrestricted("fog_maxdensity", g_Options.fogdensity); + SetValueUnrestricted("fog_maxdensityskybox", g_Options.fogdensity); + SetValueUnrestricted("fog_start", g_Options.fogstart); + SetValueUnrestricted("fog_startskybox", g_Options.fogstart); + SetValueUnrestricted("fog_end", g_Options.fogend); + SetValueUnrestricted("fog_endskybox", g_Options.fogend); + } + else iff.g_pCVar->FindVar("fog_override")->SetValue(false); + + iff.g_pCVar->FindVar("r_rainlength")->SetValue(*g_Options.rainlength); + iff.g_pCVar->FindVar("r_rainspeed")->SetValue(*g_Options.rainspeed); + iff.g_pCVar->FindVar("r_rainradius")->SetValue(*g_Options.rainradius); + iff.g_pCVar->FindVar("cl_windspeed")->SetValue(*g_Options.windspeed); + iff.g_pCVar->FindVar("r_rainwidth")->SetValue(*g_Options.rainwidth); + iff.g_pCVar->FindVar("r_RainSideVel")->SetValue(*g_Options.rainsidevel); + iff.g_pCVar->FindVar("r_rainalpha")->SetValue(*g_Options.rainalpha); + + SetValueUnrestricted("mat_force_tonemap_scale", g_Options.tonemapscale); + + SetValueUnrestricted("r_aspectratio", g_Options.aspectratio); + iff.g_pCVar->FindVar("mat_postprocess_enable")->SetValue(!g_Options.postproc); + iff.g_pCVar->FindVar("cl_csm_enabled")->SetValue(!g_Options.shadows); + iff.g_pCVar->FindVar("cl_ragdoll_gravity")->SetValue(g_Options.ragdollgravity); + SetValueUnrestricted("cl_phys_timescale", g_Options.ragdolltime); + SetValueUnrestricted("viewmodel_fov", g_Options.viewmodel_fov); + SetValueUnrestricted("viewmodel_offset_x", g_Options.viewmodel_x); + SetValueUnrestricted("viewmodel_offset_y", g_Options.viewmodel_y); + SetValueUnrestricted("viewmodel_offset_z", g_Options.viewmodel_z); + + if (g_Options.viewmodel_moving) + { + SetValueUnrestricted("cl_viewmodel_shift_left_amt", 0); + SetValueUnrestricted("cl_viewmodel_shift_right_amt", 0); + SetValueUnrestricted("cl_bob_lower_amt", 0); + SetValueUnrestricted("cl_bobamt_lat", 0); + SetValueUnrestricted("cl_bobamt_vert", 0); + SetValueUnrestricted("cl_wpn_sway_scale", 0); + } + + SetValueUnrestricted("mat_fullbright", g_Options.fullbright); + SetValueUnrestricted("mat_drawgray", g_Options.drawgray); + SetValueUnrestricted("mat_showlowresimage", g_Options.showlowresimage); + + if (g_Options.rcs) + SetValueUnrestricted("view_recoil_tracking", 0.0f); + + if (g_Options.overhead) + { + DWORD oldProtect = 0; + VirtualProtect(iff.OverheadInfo, 2, PAGE_EXECUTE_READWRITE, &oldProtect); + BYTE ovbytes[2] = { 0x90, 0x90 }; + memcpy(iff.OverheadInfo, ovbytes, 2); + VirtualProtect(iff.OverheadInfo, 2, oldProtect, NULL); + } + + if (g_Options.nochokelimit) + { + auto clMoveChokeClamp = FindPatternV2("engine.dll", "B8 ? ? ? ? 3B F0 0F 4F F0 89 5D FC") + 1; + unsigned long protect = 0; + VirtualProtect((void*)clMoveChokeClamp, 4, PAGE_EXECUTE_READWRITE, &protect); + *(std::uint32_t*)clMoveChokeClamp = 62; + VirtualProtect((void*)clMoveChokeClamp, 4, protect, &protect); + } + + colorWorld(); + + if (g_Options.wfsmoke) + wfsmoke(1); + +} + + +void OnLoadCfg() +{ + for (int i = 0; i < 5; i++) + { + if (g_Options.customtextures.value->arr[i].texturelink) { + g_Options.customtextures.value->arr[i].texturelink = CreateMaterial( + string(g_Options.customtextures.value->arr[i].Name), + string(g_Options.customtextures.value->arr[i].keyvalue)); + opt.dmeitems.at(i) = g_Options.customtextures.value->arr[i].Preview; + } + } + + OnLevelInit(); + + const auto& paintkitMap = itemSystem()->getItemSchema()->paintKits; + + for (int n = 0; n < g_Options.weapons.value->weaponzcount; n++) + { + CPaintKit* pk = (CPaintKit*)paintkitMap.memory[g_Options.weapons.value->arr[n].skinidc].value; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].link = (DWORD)pk; + pk->rarity = g_Options.weapons.value->arr[n].rarity; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].rarity = g_Options.weapons.value->arr[n].rarity; + pk->pearlescent = g_Options.weapons.value->arr[n].pearl; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].pearl = g_Options.weapons.value->arr[n].pearl; + pk->color1 = g_Options.weapons.value->arr[n].color1; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].color1 = g_Options.weapons.value->arr[n].color1; + pk->color2 = g_Options.weapons.value->arr[n].color2; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].color2 = g_Options.weapons.value->arr[n].color2; + pk->color3 = g_Options.weapons.value->arr[n].color3; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].color3 = g_Options.weapons.value->arr[n].color3; + pk->color4 = g_Options.weapons.value->arr[n].color4; + opt.sc_skins[g_Options.weapons.value->arr[n].skinidc].color4 = g_Options.weapons.value->arr[n].color4; + + } + + Sleep(100); + iff.g_pClientState->ForceFullUpdate(); + Sleep(100); + opt.needupdate = 1; + Sleep(100); + ProtoFeatures.SendClientHello(); + Sleep(100); + ProtoFeatures.SendMatchmakingClient2GCHello(); + Sleep(100); + + opt.loading = 0; +} + + + +DWORD WINAPI HackThread(HMODULE hModule) +{ + + while (!GetModuleHandleA("serverbrowser.dll")) + Sleep(1000); + +#ifdef DEBUG + AllocConsole(); + FILE* f; + freopen_s(&f, "CONOUT$", "w", stdout); + printfdbg("Cheat launched\n"); +#endif + + iff.Init(); + + opt.hModuleGlobal = hModule; + + NetvarSys::Get().Initialize(); + + void* ptrDevMsg = GetProcAddress(GetModuleHandleA("tier0.dll"), "?DevMsg@@YAXPBDZZ"); + printfdbg("DevMsg %x\n", ptrDevMsg); + + if (ptrDevMsg) + oDevMsg = (pDevMsg)DetourFunction( + (PBYTE)(ptrDevMsg), + (PBYTE)hkDevMsg); + + void* ptrDevWarningMsg = GetProcAddress(GetModuleHandleA("tier0.dll"), "?DevWarning@@YAXPBDZZ"); + printfdbg("DevWarningMsg %x\n", ptrDevWarningMsg); + + if (ptrDevWarningMsg) + oDevWarningMsg = (pDevWarningMsg)DetourFunction( + (PBYTE)(ptrDevWarningMsg), + (PBYTE)hkDevWarningMsg); + + DMEHook = new VMTHook(iff.g_pMdlRender); + DMEHook->SwapPointer(21, reinterpret_cast(DrawModelExecute)); + DMEHook->ApplyNewTable(); + + ViewRenderHook = new VMTHook(iff.g_ViewRender); + ViewRenderHook->SwapPointer(41, reinterpret_cast(hkRenderSmokeOverlay)); + ViewRenderHook->ApplyNewTable(); + + D3DHook = new VMTHook(iff.g_pD3DDevice9); + D3DHook->SwapPointer(42, reinterpret_cast(hkEndScene)); + D3DHook->ApplyNewTable(); + + GameEventManagerHook = new VMTHook(iff.g_pGameEvents); + GameEventManagerHook->SwapPointer(9, reinterpret_cast(hkFireEventClientSide)); + GameEventManagerHook->ApplyNewTable(); + + ProtoHook = new VMTHook(iff.g_SteamGameCoordinator); + ProtoHook->SwapPointer(0, reinterpret_cast(hkGCSendMessage)); + ProtoHook->SwapPointer(2, reinterpret_cast(hkGCRetrieveMessage)); + ProtoHook->ApplyNewTable(); + + CacheHook = new VMTHook(iff.g_pMdlCache); + CacheHook->SwapPointer(10, reinterpret_cast(hkFindMDL)); + CacheHook->ApplyNewTable(); + + SoundHook = new VMTHook(iff.g_pEngineSound); + SoundHook->SwapPointer(5, reinterpret_cast(hkEmitSound1)); + SoundHook->ApplyNewTable(); + + VGUISurfHook = new VMTHook(iff.g_pVGuiSurface); + VGUISurfHook->SwapPointer(67, reinterpret_cast(hkLockCursor)); + VGUISurfHook->ApplyNewTable(); + + ClientModeHook = new VMTHook(iff.g_ClientMode); + ClientModeHook->SwapPointer(44, reinterpret_cast(hkdoPostScreenEffects)); + ClientModeHook->SwapPointer(18, reinterpret_cast(hkOverrideView)); + ClientModeHook->SwapPointer(24, reinterpret_cast(hkCreateMove)); + ClientModeHook->ApplyNewTable(); + + printfdbg("CreateMove\n"); + + FileSystemHook = new VMTHook(iff.g_pFullFileSystem); + FileSystemHook->SwapPointer(101, reinterpret_cast(hkGetUnverifiedFileHashes)); + FileSystemHook->ApplyNewTable(); + + InitSkinChanger(); + + //crash + //oGetAccountData = (pGetAccountData)DetourFunction( + // (PBYTE)(iff.fn_get_account_data), + // (PBYTE)hkGetAccountData); + + oParticleCollectionSimulate = (pParticleCollectionSimulate)DetourFunction( + (PBYTE)(iff.ParticleCollectionSimulateAdr), + (PBYTE)hkParticleCollectionSimulate); + + Sleep(1000); + + ClientHook = new VMTHook(iff.g_pClient); + ClientHook->SwapPointer(37, reinterpret_cast(hkFrameStageNotify)); + ClientHook->SwapPointer(38, reinterpret_cast(hkDispatchUserMessage)); + ClientHook->ApplyNewTable(); + + iff.g_pGameConsole->Clear(); + + EventListener* eventListener = new EventListener(); + + Color color = { 255,255,0,255 }; + iff.g_pCVar->ConsoleColorPrintf(color, "Seaside loaded!\n"); + + ConVar* sv_skyname = iff.g_pCVar->FindVar("sv_skyname"); + + int proxyindex = 0; + for (ClientClass* pClass = iff.g_pClient->GetAllClasses(); pClass; pClass = pClass->m_pNext) { + if (!strcmp(pClass->m_pNetworkName, "CBaseViewModel")) { + RecvTable* pClassTable = pClass->m_pRecvTable; + for (int nIndex = 0; nIndex < pClassTable->m_nProps; nIndex++) { + RecvProp* pProp = &pClassTable->m_pProps[nIndex]; + if (!pProp || strcmp(pProp->m_pVarName, "m_nSequence")) + continue; + proxyindex = nIndex; + fnSequenceProxyFn = pProp->m_ProxyFn; + pProp->m_ProxyFn = (RecvVarProxyFn)SetViewModelSequence; + break; + } + break; + } + } + + Config::Get().Refresh(); + + ifstream loadcfg("seaside_autoload"); + if (loadcfg.is_open()) + { + printfdbg("autoload found\n"); + + string line; + getline(loadcfg, line); + + printfdbg("Trying to load %s CFG \n", line.c_str()); + + + for (int i = 0; i < Config::Get().configs.size(); i++) + if (Config::Get().configs[i] == line) + { + printfdbg("Loading %s CFG \n", line.c_str()); + opt.autoconfig = i; + } + + if (opt.autoconfig == -1) + { + printfdbg("Cannot find %s CFG \n", line.c_str()); + } + else + { + Sleep(1000); + Config::Get().Load(opt.autoconfig); + } + loadcfg.close(); + } + else + { + printfdbg("Autoload NOT found, creating material\n"); + g_Options.customtextures.value->arr[0].texturelink = CreateMaterial( + string(g_Options.customtextures.value->arr[0].Name), + string(g_Options.customtextures.value->arr[0].keyvalue)); + } + + if (!fs::is_directory("csgo/sound") || !fs::exists("csgo/sound")) { // Check if src folder exists + fs::create_directory("csgo/sound"); // create src folder + } + + ofstream loadcod("csgo/sound/hitsound_cod.wav", std::ios::binary); + if (loadcod) { + loadcod.write((char*)&hitsound_cod[0], sizeof(hitsound_cod)); + loadcod.close(); + } + ofstream loadcrit("csgo/sound/hitsound_crit.wav", std::ios::binary); + if (loadcrit) { + loadcrit.write((char*)&hitsound_crit[0], sizeof(hitsound_crit)); + loadcrit.close(); + } + + void* fn_getplmoney = (void*)FindPatternV2("client.dll", "55 8B EC 56 8B 75 08 83 FE 3F"); + if (fn_getplmoney) + oGetPlayerMoney = (pGetPlayerMoney)DetourFunction( + (PBYTE)(fn_getplmoney), + (PBYTE)hkGetPlayerMoney); + + while (!opt.unhook) + { + if (GetAsyncKeyState(VK_INSERT) & 1) + { + opt.show = !opt.show; + printfdbg("Show menu: %d\n", opt.show); + if (!opt.show) + iff.g_pInputSystem->EnableInput(1); + else + iff.g_pInputSystem->EnableInput(0); + } + + if (!opt.netchannedlhooked && iff.g_pEngineClient->IsConnected()) + HookNetchannel(); + + if (iff.g_pEngineClient->IsInGame()) { + if (!*g_Options.dme_gettextures) + { + IMaterial* mats[1]; + for (int i = 5; i < g_Options.materials.value->itemcount; i++) { + int mdlindex = iff.g_pMdlInfo->GetModelIndex(g_Options.models.value->arr[i - 2].vmodel_orig); + if (mdlindex != -1) { + model_t* pModel = (model_t*)iff.g_pMdlInfo->GetModel(mdlindex); + iff.g_pMdlInfo->GetModelMaterials(pModel, 1, mats); + const char* matname = mats[0]->GetName(); + if (g_Options.materials.value->arr[i].texture[0] == 0x0) + strcpy(g_Options.materials.value->arr[i].texture, matname); + if (g_Options.materials.value->arr[i].texture_temp[0] == 0x0) + strcpy(g_Options.materials.value->arr[i].texture_temp, matname); + } + } + printfdbg("Model materials dumped\n"); + *g_Options.dme_gettextures = true; + } + + + + } + else + { + opt.disconnected = 1; + } + + + + Sleep(20); + } + opt.show = false; + + + for (ClientClass* pClass = iff.g_pClient->GetAllClasses(); pClass; pClass = pClass->m_pNext) { + if (!strcmp(pClass->m_pNetworkName, "CBaseViewModel")) { + RecvTable* pClassTable = pClass->m_pRecvTable; + RecvProp* pProp = &pClassTable->m_pProps[proxyindex]; + pProp->m_ProxyFn = fnSequenceProxyFn; + } + } + + + if (iff.g_pEngineClient->IsConnected()) { + iff.g_pClientState->ForceFullUpdate(); + } + + iff.g_pInputSystem->EnableInput(1); + + iff.g_pCVar->FindVar("r_3dsky")->SetValue(true); + + sv_skyname->m_nFlags &= FCVAR_CHEAT; + sv_skyname->SetValue("sky_urb01"); + + iff.g_pCVar->FindVar("fog_override")->SetValue(0); + iff.g_pCVar->FindVar("mat_force_tonemap_scale")->SetValue(0.0f); + + SetValueUnrestricted("developer", 0); + SetValueUnrestricted("sv_show_usermessage", 0); + SetValueUnrestricted("view_recoil_tracking", 0.45f); + + ResetMisc(); + + DMEHook->RestoreOldTable(); + ViewRenderHook->RestoreOldTable(); + D3DHook->RestoreOldTable(); + ClientHook->RestoreOldTable(); + GameEventManagerHook->RestoreOldTable(); + ProtoHook->RestoreOldTable(); + CacheHook->RestoreOldTable(); + SoundHook->RestoreOldTable(); + VGUISurfHook->RestoreOldTable(); + ClientModeHook->RestoreOldTable(); + FileSystemHook->RestoreOldTable(); + if (opt.netchannedlhooked) { + DetourRemove(reinterpret_cast(oShutdown), reinterpret_cast(hkShutdown)); + DetourRemove(reinterpret_cast(oSendNetMsg), reinterpret_cast(hkSendNetMsg)); + } + + //DetourRemove(reinterpret_cast(oGetAccountData), reinterpret_cast(hkGetAccountData)); + DetourRemove(reinterpret_cast(oParticleCollectionSimulate), reinterpret_cast(hkParticleCollectionSimulate)); + + if (ptrDevMsg) + DetourRemove(reinterpret_cast(oDevMsg), reinterpret_cast(hkDevMsg)); + if (ptrDevWarningMsg) + DetourRemove(reinterpret_cast(oDevWarningMsg), reinterpret_cast(hkDevWarningMsg)); + + if (fn_getplmoney) + DetourRemove(reinterpret_cast(oGetPlayerMoney), reinterpret_cast(hkGetPlayerMoney)); + + ImGui_ImplDX9_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + SetWindowLongPtr(window, GWL_WNDPROC, (LONG_PTR)oWndProc); + + delete eventListener; + + ProtoFeatures.SendClientHello(); + ProtoFeatures.SendMatchmakingClient2GCHello(); + ProtoFeatures.SendClientGcRankUpdate(); + + + Sleep(1000); + +#ifdef DEBUG + if (f) fclose(f); + FreeConsole(); +#endif + FreeLibraryAndExitThread(hModule, 0); + return 0; +} + +BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + HANDLE hdl = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)HackThread, hModule, 0, nullptr); + if (hdl) CloseHandle(hdl); + break; + } + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + + +``` + +`SpyCustom/imgui/imconfig.h`: + +```h +//----------------------------------------------------------------------------- +// COMPILE-TIME OPTIONS FOR DEAR IMGUI +// 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 files to verify that the data structures your files are using are matching the ones imgui.cpp is using. +//----------------------------------------------------------------------------- + +#pragma once + +//#define OLDSTYLE + +//---- 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. +//#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 avoid using soon-to-be obsolete function/names. +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//---- Disable all of Dear ImGui or don't implement standard windows. +// It is very strongly recommended to NOT disable the demo windows during development. 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. Not recommended. +//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty. + +//---- 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. +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. +//#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_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite 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(). + +//---- 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_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) +// Requires 'stb_sprintf.h' to be available in the include path. 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. +// #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' + 'vcpkg integrate install'. +//#define IMGUI_ENABLE_FREETYPE + +//---- 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 \ + ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ + operator MyVec2() const { return MyVec2(x,y); } + +#define IM_VEC4_CLASS_EXTRA \ + 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); } +*/ + +//---- 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 +// (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: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), +// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) +// This adds a small runtime cost which is why it is not enabled by default. +//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + +//---- Debug Tools: Enable slower asserts +//#define IMGUI_DEBUG_PARANOID + +//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. +/* +namespace ImGui +{ + void MyFunction(const char* name, const MyMatrix44& v); +} +*/ + +``` + +`SpyCustom/imgui/imgui.cpp`: + +```cpp + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#include +#include +#if defined(_MSC_VER) && _MSC_VER <= 1500 +#include +#else +#include +#endif + +#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 +#else +#include +#endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif +#endif + +#if defined(__APPLE__) +#include +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4127) +#pragma warning (disable: 4996) +#if defined(_MSC_VER) && _MSC_VER >= 1922 +#pragma warning (disable: 5054) +#endif +#endif + +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wglobal-constructors" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wformat-pedantic" +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wdouble-promotion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +#define IMGUI_DEBUG_NAV_SCORING 0 +#define IMGUI_DEBUG_NAV_RECTS 0 +#define IMGUI_DEBUG_INI_SETTINGS 0 + +static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; +static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; + +static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; +static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; +static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; + +static void SetCurrentWindow(ImGuiWindow* window); +static void FindHoveredWindow(); +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); + +static ImRect GetViewportRect(); + +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); + +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); + +namespace ImGui +{ +static void NavUpdate(); +static void NavUpdateWindowing(); +static void NavUpdateWindowingOverlay(); +static void NavUpdateMoveResult(); +static void NavUpdateInitResult(); +static float NavUpdatePageUpPageDown(); +static inline void NavUpdateAnyRequestFlag(); +static void NavEndFrame(); +static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand); +static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel); +static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); +static ImVec2 NavCalcPreferredRefPos(); +static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); +static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); +static int FindWindowFocusIndex(ImGuiWindow* window); + +static void ErrorCheckNewFrameSanityChecks(); +static void ErrorCheckEndFrameSanityChecks(); + +static void UpdateSettings(); +static void UpdateMouseInputs(); +static void UpdateMouseWheel(); +static void UpdateTabFocus(); +static void UpdateDebugToolItemPicker(); +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, 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); + +} + +#ifndef GImGui +ImGuiContext* GImGui = NULL; +#endif + +#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 void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; +static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; +static void* GImAllocatorUserData = NULL; + +ImGuiStyle::ImGuiStyle() +{ + Alpha = 1.0f; + WindowPadding = ImVec2(8,8); + WindowRounding = 0.0f; + WindowBorderSize = 1.0f; + WindowMinSize = ImVec2(32,32); + WindowTitleAlign = ImVec2(0.0f,0.5f); + WindowMenuButtonPosition= ImGuiDir_Left; + ChildRounding = 0.0f; + ChildBorderSize = 1.0f; + PopupRounding = 0.0f; + PopupBorderSize = 1.0f; + FramePadding = ImVec2(4,3); + FrameRounding = 0.0f; + FrameBorderSize = 0.0f; + ItemSpacing = ImVec2(8,4); + ItemInnerSpacing = ImVec2(4,4); + CellPadding = ImVec2(4,2); + TouchExtraPadding = ImVec2(0,0); + IndentSpacing = 21.0f; + ColumnsMinSpacing = 6.0f; + ScrollbarSize = 14.0f; + ScrollbarRounding = 9.0f; + GrabMinSize = 10.0f; + GrabRounding = 0.0f; + LogSliderDeadzone = 4.0f; + TabRounding = 4.0f; + TabBorderSize = 0.0f; + TabMinWidthForCloseButton = 0.0f; + ColorButtonPosition = ImGuiDir_Right; + ButtonTextAlign = ImVec2(0.5f,0.5f); + SelectableTextAlign = ImVec2(0.0f,0.0f); + DisplayWindowPadding = ImVec2(19,19); + DisplaySafeAreaPadding = ImVec2(3,3); + MouseCursorScale = 1.0f; + AntiAliasedLines = true; + AntiAliasedLinesUseTex = true; + AntiAliasedFill = true; + CurveTessellationTol = 1.25f; + CircleSegmentMaxError = 1.60f; + + ImGui::StyleColorsDark(this); +} + +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); + TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); + DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); + MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); +} + +ImGuiIO::ImGuiIO() +{ + memset(this, 0, sizeof(*this)); + IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); + + ConfigFlags = ImGuiConfigFlags_None; + BackendFlags = ImGuiBackendFlags_None; + DisplaySize = ImVec2(-1.0f, -1.0f); + DeltaTime = 1.0f / 60.0f; + IniSavingRate = 5.0f; + IniFilename = "imgui.ini"; + LogFilename = "imgui_log.txt"; + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; + for (int i = 0; i < ImGuiKey_COUNT; i++) + KeyMap[i] = -1; + KeyRepeatDelay = 0.275f; + KeyRepeatRate = 0.050f; + UserData = NULL; + + Fonts = NULL; + FontGlobalScale = 1.0f; + FontDefault = NULL; + FontAllowUserScaling = false; + DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + + MouseDrawCursor = false; +#ifdef __APPLE__ + ConfigMacOSXBehaviors = true; +#else + ConfigMacOSXBehaviors = false; +#endif + ConfigInputTextCursorBlink = true; + ConfigWindowsResizeFromEdges = true; + ConfigWindowsMoveFromTitleBarOnly = false; + ConfigMemoryCompactTimer = 60.0f; + + BackendPlatformName = BackendRendererName = NULL; + BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; + SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + ClipboardUserData = NULL; + ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; + ImeWindowHandle = NULL; + + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); + MouseDragThreshold = 6.0f; + for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; +} + +void ImGuiIO::AddInputCharacter(unsigned int c) +{ + if (c != 0) + InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); +} + +void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) +{ + if (c == 0 && InputQueueSurrogate == 0) + return; + + if ((c & 0xFC00) == 0xD800) + { + if (InputQueueSurrogate != 0) + InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); + InputQueueSurrogate = c; + return; + } + + ImWchar cp = c; + if (InputQueueSurrogate != 0) + { + if ((c & 0xFC00) != 0xDC00) + InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); + else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) + cp = IM_UNICODE_CODEPOINT_INVALID; + else + cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); + InputQueueSurrogate = 0; + } + InputQueueCharacters.push_back(cp); +} + +void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +{ + while (*utf8_chars != 0) + { + unsigned int c = 0; + utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); + if (c != 0) + InputQueueCharacters.push_back((ImWchar)c); + } +} + +void ImGuiIO::ClearInputCharacters() +{ + InputQueueCharacters.resize(0); +} + +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); + 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; +} + +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); + } +} + +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; +} + +int ImStricmp(const char* str1, const char* str2) +{ + int d; + while ((d = toupper(*str2) - toupper(*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 = toupper(*str2) - toupper(*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) +{ + int n = 0; + while (*str++) n++; + return n; +} + +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) +{ + 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)toupper(*needle); + while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) + { + if (toupper(*haystack) == un0) + { + const char* b = needle + 1; + for (const char* a = haystack + 1; b < needle_end; a++, b++) + if (toupper(*a) != toupper(*b)) + break; + if (b == needle_end) + return haystack; + } + haystack++; + } + return NULL; +} + +void ImStrTrimBlanks(char* buf) +{ + char* p = buf; + while (p[0] == ' ' || p[0] == '\t') + p++; + char* p_start = p; + while (*p != 0) + p++; + while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) + p--; + if (p_start != buf) + memmove(buf, p_start, p - p_start); + buf[p - p_start] = 0; +} + +const char* ImStrSkipBlank(const char* str) +{ + while (str[0] == ' ' || str[0] == '\t') + str++; + return str; +} + +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +#ifdef IMGUI_USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "stb_sprintf.h" +#endif + +#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 + +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, +}; + +ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 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; +} + +ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 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; +} + +#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__) + 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 +} + +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 + +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; +} + +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; + + if (in_text_end == NULL) + in_text_end = in_text + wanted; + + 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; + + *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]; + + int e = 0; + e = (*out_char < mins[len]) << 6; + e |= ((*out_char >> 11) == 0x1b) << 7; + e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; + e |= (s[1] & 0xc0) >> 2; + e |= (s[2] & 0xc0) >> 4; + e |= (s[3] ) >> 6; + e ^= 0x2a; + e >>= shifte[len]; + + if (e) + { + 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); + if (c == 0) + break; + *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); + if (c == 0) + break; + char_count++; + } + return char_count; +} + +static inline int ImTextCharToUtf8(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; + } + return 0; +} + +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* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end) +{ + char* buf_out = buf; + const char* buf_end = buf + buf_size; + while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + *buf_out++ = (char)c; + else + buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c); + } + *buf_out = 0; + return (int)(buf_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; +} + +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; +} + +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; +} + +void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) +{ + if (s == 0.0f) + { + 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; + } +} + +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; +} + +void ImGuiStorage::BuildSortByKey() +{ + struct StaticFunc + { + static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) + { + if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; + if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1; + return 0; + } + }; + if (Data.Size > 1) + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); +} + +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; +} + +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; +} + +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; +} + +ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) +{ + if (default_filter) + { + ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); + Build(); + } + else + { + InputBuf[0] = 0; + CountGrep = 0; + } +} + +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] == '-') + { + if (ImStristr(text, text_end, f.b + 1, f.e) != NULL) + return false; + } + else + { + if (ImStristr(text, text_end, f.b, f.e) != NULL) + return true; + } + } + + if (CountGrep == 0) + return true; + + return false; +} + +#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); + + 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); +} + +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); + if (len <= 0) + { + va_end(args_copy); + return; + } + + 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); +} + +static bool GetSkipItemForListClipping() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems); +} + +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) + { + *out_items_display_start = 0; + *out_items_display_end = items_count; + return; + } + if (GetSkipItemForListClipping()) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } + + ImRect unclipped_rect = window->ClipRect; + if (g.NavMoveRequest) + unclipped_rect.Add(g.NavScoringRect); + if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) + unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max)); + + const ImVec2 pos = window->DC.CursorPos; + int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); + int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); + + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) + start--; + if (g.NavMoveRequest && 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; +} + +static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height) +{ + 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); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; + window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); + if (ImGuiOldColumns* columns = window->DC.CurrentColumns) + columns->LineMinY = window->DC.CursorPos.y; + 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->RowBgColorCounter += row_increase; + } +} + +ImGuiListClipper::ImGuiListClipper() +{ + memset(this, 0, sizeof(*this)); + ItemsCount = -1; +} + +ImGuiListClipper::~ImGuiListClipper() +{ + IM_ASSERT(ItemsCount == -1 && "Forgot to call End(), or to Step() until false?"); +} + +void ImGuiListClipper::Begin(int items_count, float items_height) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (ImGuiTable* table = g.CurrentTable) + if (table->IsInsideRow) + ImGui::TableEndRow(table); + + StartPosY = window->DC.CursorPos.y; + ItemsHeight = items_height; + ItemsCount = items_count; + ItemsFrozen = 0; + StepNo = 0; + DisplayStart = -1; + DisplayEnd = 0; +} + +void ImGuiListClipper::End() +{ + if (ItemsCount < 0) + return; + + if (ItemsCount < INT_MAX && DisplayStart >= 0) + SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight); + ItemsCount = -1; + StepNo = 3; +} + +bool ImGuiListClipper::Step() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImGuiTable* table = g.CurrentTable; + if (table && table->IsInsideRow) + ImGui::TableEndRow(table); + + if (ItemsCount == 0 || GetSkipItemForListClipping()) + { + End(); + return false; + } + + if (StepNo == 0) + { + if (table != NULL && !table->IsUnfrozenRows) + { + DisplayStart = ItemsFrozen; + DisplayEnd = ItemsFrozen + 1; + ItemsFrozen++; + return true; + } + + StartPosY = window->DC.CursorPos.y; + if (ItemsHeight <= 0.0f) + { + DisplayStart = ItemsFrozen; + DisplayEnd = ItemsFrozen + 1; + StepNo = 1; + return true; + } + + DisplayStart = DisplayEnd; + StepNo = 2; + } + + if (StepNo == 1) + { + IM_ASSERT(ItemsHeight <= 0.0f); + if (table) + { + const float pos_y1 = table->RowPosY1; + const float pos_y2 = table->RowPosY2; + ItemsHeight = pos_y2 - pos_y1; + window->DC.CursorPos.y = pos_y2; + } + else + { + ItemsHeight = window->DC.CursorPos.y - StartPosY; + } + IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); + StepNo = 2; + } + + if (DisplayEnd >= ItemsCount) + { + End(); + return false; + } + + if (StepNo == 2) + { + IM_ASSERT(ItemsHeight > 0.0f); + + int already_submitted = DisplayEnd; + ImGui::CalcListClipping(ItemsCount - already_submitted, ItemsHeight, &DisplayStart, &DisplayEnd); + DisplayStart += already_submitted; + DisplayEnd += already_submitted; + + if (DisplayStart > already_submitted) + SetCursorPosYAndSetupForPrevLine(StartPosY + (DisplayStart - ItemsFrozen) * ItemsHeight, ItemsHeight); + + StepNo = 3; + return true; + } + + if (StepNo == 3) + { + if (ItemsCount < INT_MAX) + SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight); + ItemsCount = -1; + return false; + } + + IM_ASSERT(0); + return false; +} + +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); + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} + +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; + while (count > 0) + { + ImGuiColorMod& backup = g.ColorStack.back(); + g.Style.Colors[backup.Col] = backup.BackupValue; + g.ColorStack.pop_back(); + count--; + } +} + +struct ImGuiStyleVarInfo +{ + ImGuiDataType Type; + ImU32 Count; + ImU32 Offset; + void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[] = +{ + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, +}; + +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); + IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarInfo[idx]; +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + { + ImGuiContext& g = *GImGui; + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + { + ImGuiContext& g = *GImGui; + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); +} + +void ImGui::PopStyleVar(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + ImGuiStyleMod& backup = g.StyleVarStack.back(); + const ImGuiStyleVarInfo* 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) +{ + 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"; +} + + +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; +} + +void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash, ImU32 customcol) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + 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); + text_display_end = text_end; + } + + if (text != text_display_end) + { + if (!customcol) + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); + else + window->DrawList->AddText(g.Font, g.FontSize, pos, customcol, 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); + + 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); + } +} + +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, ImU32 customcol) +{ + 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) + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + + 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); + + if (need_clipping) + { + ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); + + if (!customcol) + 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, customcol, text, text_display_end, 0.0f, &fine_clip_rect); + } + else + { + + if (!customcol) + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + else + draw_list->AddText(NULL, 0.0f, pos, customcol, 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) +{ + 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); +} + + +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, ImColor customcolor) +{ + 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, customcolor); + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_display_end); +} + + +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, ImU32 customcol) +{ + 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); + + if (text_size.x > pos_max.x - pos_min.x) + { + const ImFont* font = draw_list->_Data->Font; + const float font_size = draw_list->_Data->FontSize; + const char* text_end_ellipsis = NULL; + + ImWchar ellipsis_char = font->EllipsisChar; + int ellipsis_char_count = 1; + if (ellipsis_char == (ImWchar)-1) + { + ellipsis_char = (ImWchar)'.'; + ellipsis_char_count = 3; + } + const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); + + float ellipsis_glyph_width = glyph->X1; + float ellipsis_total_width = ellipsis_glyph_width; + + if (ellipsis_char_count > 1) + { + const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); + ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; + ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; + } + + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_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) + { + 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])) + { + text_end_ellipsis--; + text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; + } + + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + float ellipsis_x = pos_min.x + text_size_clipped_x; + if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) + for (int i = 0; i < ellipsis_char_count; i++) + { + if (!customcol) + font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); + else + font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), customcol, ellipsis_char); + + ellipsis_x += ellipsis_glyph_width; + } + } + else + { + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f), 0, customcol); + } + + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_end_full); +} + +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, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, 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, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, 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, ImDrawCornerFlags_All, 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); + } +} + +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL) +{ + memset(this, 0, sizeof(*this)); + 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 = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + LastFrameActive = -1; + LastTimeActive = -1.0f; + FontWindowScale = 1.0f; + SettingsOffset = -1; + DrawList = &DrawListInst; + DrawList->_Data = &context->DrawListSharedData; + DrawList->_OwnerName = Name; +} + +ImGuiWindow::~ImGuiWindow() +{ + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + for (int i = 0; i != ColumnsStorage.Size; i++) + ColumnsStorage[i].~ImGuiOldColumns(); +} + +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); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetID(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetID(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + ImGui::KeepAliveID(id); + 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(); +} + +void ImGui::GcCompactTransientMiscBuffers() +{ + ImGuiContext& g = *GImGui; + g.ItemFlagsStack.clear(); + g.GroupStack.clear(); + TableGcCompactSettings(); +} + +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) +{ + 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; + g.ActiveIdIsJustActivated = (g.ActiveId != id); + if (g.ActiveIdIsJustActivated) + { + g.ActiveIdTimer = 0.0f; + g.ActiveIdHasBeenPressedBefore = false; + g.ActiveIdHasBeenEditedBefore = false; + 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.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; + } + + g.ActiveIdUsingMouseWheel = false; + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingNavInputMask = 0x00; + g.ActiveIdUsingKeyInputMask = 0x00; +} + +void ImGui::ClearActiveID() +{ + SetActiveID(0, NULL); +} + +void ImGui::SetHoveredID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.HoveredId = id; + g.HoveredIdAllowOverlap = false; + g.HoveredIdUsingMouseWheel = 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; +} + +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) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); + IM_UNUSED(id); + g.ActiveIdHasBeenEditedThisFrame = true; + g.ActiveIdHasBeenEditedBefore = true; + g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; +} + +static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.NavWindow) + if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) + if (focused_root_window->WasActive && focused_root_window != window->RootWindow) + { + if (focused_root_window->Flags & ImGuiWindowFlags_Modal) + return false; + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return false; + } + return true; +} + +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavDisableMouseHover && !g.NavDisableHighlight) + return IsItemFocused(); + + if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); + + if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) + return false; + + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + + if (!IsWindowContentHoverable(window, flags)) + return false; + + if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + + if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) + return false; + return true; +} + +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow != window) + return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + return false; + if (!IsMouseHoveringRect(bb.Min, bb.Max)) + return false; + if (g.NavDisableMouseHover) + return false; + if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled)) + { + g.HoveredIdDisabled = true; + return false; + } + + if (id != 0) + { + SetHoveredID(id); + + 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(); + } + + return true; +} + +bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!bb.Overlaps(window->ClipRect)) + if (id == 0 || (id != g.ActiveId && id != g.NavId)) + if (clip_even_when_logged || !g.LogEnabled) + return true; + return false; +} + +void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) +{ + window->DC.LastItemId = item_id; + window->DC.LastItemStatusFlags = item_flags; + window->DC.LastItemRect = item_rect; +} + +bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + + const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; + window->DC.FocusCounterRegular++; + if (is_tab_stop) + window->DC.FocusCounterTabStop++; + + if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL) + { + g.FocusRequestNextWindow = window; + g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); + } + + if (g.FocusRequestCurrWindow == window) + { + if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular) + return true; + if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop) + { + g.NavJustTabbedId = id; + return true; + } + + if (g.ActiveId == id) + ClearActiveID(); + } + + return false; +} + +void ImGui::FocusableItemUnregister(ImGuiWindow* window) +{ + window->DC.FocusCounterRegular--; + window->DC.FocusCounterTabStop--; +} + +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) + { + wrap_pos_x = window->WorkRect.Max.x; + } + else if (wrap_pos_x > 0.0f) + { + wrap_pos_x += window->Pos.x - window->Scroll.x; + } + + return ImMax(wrap_pos_x - pos.x, 1.0f); +} + +void* ImGui::MemAlloc(size_t size) +{ + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations++; + return GImAllocatorAllocFunc(size, GImAllocatorUserData); +} + +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; +} + +ImGuiContext* ImGui::GetCurrentContext() +{ + return GImGui; +} + +void ImGui::SetCurrentContext(ImGuiContext* ctx) +{ +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); +#else + GImGui = ctx; +#endif +} + +void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) +{ + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; +} + +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +{ + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + if (GImGui == NULL) + SetCurrentContext(ctx); + Initialize(ctx); + return ctx; +} + +void ImGui::DestroyContext(ImGuiContext* ctx) +{ + if (ctx == NULL) + ctx = GImGui; + Shutdown(ctx); + if (GImGui == ctx) + SetCurrentContext(NULL); + IM_DELETE(ctx); +} + +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; +} + +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_; +} + +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]); +} + +ImGuiIO& ImGui::GetIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->IO; +} + +ImDrawData* ImGui::GetDrawData() +{ + ImGuiContext& g = *GImGui; + return g.DrawData.Valid ? &g.DrawData : NULL; +} + +double ImGui::GetTime() +{ + return GImGui->Time; +} + +int ImGui::GetFrameCount() +{ + return GImGui->FrameCount; +} + +ImDrawList* ImGui::GetBackgroundDrawList() +{ + return &GImGui->BackgroundDrawList; +} + +ImDrawList* ImGui::GetForegroundDrawList() +{ + return &GImGui->ForegroundDrawList; +} + +ImDrawListSharedData* ImGui::GetDrawListSharedData() +{ + return &GImGui->DrawListSharedData; +} + +void ImGui::StartMouseMovingWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + FocusWindow(window); + SetActiveID(window->MoveId, window); + g.NavDisableHighlight = true; + g.ActiveIdNoClearOnFocusLoss = true; + g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; + + 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; +} + +void ImGui::UpdateMouseMovingWindowNewFrame() +{ + ImGuiContext& g = *GImGui; + if (g.MovingWindow != NULL) + { + 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; + if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) + { + MarkIniSettingsDirty(moving_window); + SetWindowPos(moving_window, pos, ImGuiCond_Always); + } + FocusWindow(g.MovingWindow); + } + else + { + ClearActiveID(); + g.MovingWindow = NULL; + } + } + else + { + if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) + { + KeepAliveID(g.ActiveId); + if (!g.IO.MouseDown[0]) + ClearActiveID(); + } + } +} + +void ImGui::UpdateMouseMovingWindowEndFrame() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId != 0 || g.HoveredId != 0) + return; + + if (g.NavWindow && g.NavWindow->Appearing) + return; + + if (g.IO.MouseClicked[0]) + { + ImGuiWindow* root_window = g.HoveredRootWindow; + 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); + + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + + if (g.HoveredIdDisabled) + g.MovingWindow = NULL; + } + else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL) + { + FocusWindow(NULL); + } + } + + if (g.IO.MouseClicked[1]) + { + ImGuiWindow* modal = GetTopMostPopupModal(); + bool hovered_window_above_modal = g.HoveredWindow && IsWindowAbove(g.HoveredWindow, modal); + ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); + } +} + +static bool IsWindowActiveAndVisible(ImGuiWindow* window) +{ + return (window->Active) && (!window->Hidden); +} + +static void ImGui::UpdateMouseInputs() +{ + ImGuiContext& g = *GImGui; + + if (IsMousePosValid(&g.IO.MousePos)) + g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); + + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) + g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; + else + g.IO.MouseDelta = ImVec2(0.0f, 0.0f); + if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + g.IO.MousePosPrev = g.IO.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; + g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; + g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; + g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; + g.IO.MouseDoubleClicked[i] = false; + if (g.IO.MouseClicked[i]) + { + if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) + g.IO.MouseDoubleClicked[i] = true; + g.IO.MouseClickedTime[i] = -g.IO.MouseDoubleClickTime * 2.0f; + } + else + { + g.IO.MouseClickedTime[i] = g.Time; + } + g.IO.MouseClickedPos[i] = g.IO.MousePos; + g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i]; + g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (g.IO.MouseDown[i]) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); + g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); + g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); + } + if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i]) + g.IO.MouseDownWasDoubleClick[i] = false; + if (g.IO.MouseClicked[i]) + g.NavDisableMouseHover = false; + } +} + +static void StartLockWheelingWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.WheelingWindow == window) + return; + g.WheelingWindow = window; + g.WheelingWindowRefMousePos = g.IO.MousePos; + g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER; +} + +void ImGui::UpdateMouseWheel() +{ + ImGuiContext& g = *GImGui; + + if (g.WheelingWindow != NULL) + { + g.WheelingWindowTimer -= g.IO.DeltaTime; + if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) + g.WheelingWindowTimer = 0.0f; + if (g.WheelingWindowTimer <= 0.0f) + { + g.WheelingWindow = NULL; + g.WheelingWindowTimer = 0.0f; + } + } + + if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) + return; + + if ((g.ActiveId != 0 && g.ActiveIdUsingMouseWheel) || (g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrameUsingMouseWheel)) + return; + + ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; + if (!window || window->Collapsed) + return; + + if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) + { + StartLockWheelingWindow(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->Flags & ImGuiWindowFlags_ChildWindow)) + { + 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; + } + + const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; + if (wheel_y != 0.0f && !g.IO.KeyCtrl) + { + StartLockWheelingWindow(window); + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + 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); + } + } + + const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; + if (wheel_x != 0.0f && !g.IO.KeyCtrl) + { + StartLockWheelingWindow(window); + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + 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); + } + } +} + +void ImGui::UpdateTabFocus() +{ + ImGuiContext& g = *GImGui; + + g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); + if (g.ActiveId == 0 && g.FocusTabPressed) + { + g.FocusRequestNextWindow = g.NavWindow; + g.FocusRequestNextCounterRegular = INT_MAX; + if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) + g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); + else + g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0; + } + + g.FocusRequestCurrWindow = NULL; + g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX; + if (g.FocusRequestNextWindow != NULL) + { + ImGuiWindow* window = g.FocusRequestNextWindow; + g.FocusRequestCurrWindow = window; + if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1) + g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1); + if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1) + g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1); + g.FocusRequestNextWindow = NULL; + g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX; + } + + g.NavIdTabCounter = INT_MAX; +} + +void ImGui::UpdateHoveredWindowAndCaptureFlags() +{ + ImGuiContext& g = *GImGui; + + bool clear_hovered_windows = false; + FindHoveredWindow(); + + ImGuiWindow* modal_window = GetTopMostPopupModal(); + if (modal_window && g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) + clear_hovered_windows = true; + + if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) + clear_hovered_windows = true; + + int mouse_earliest_button_down = -1; + bool mouse_any_down = false; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + if (g.IO.MouseClicked[i]) + g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0); + mouse_any_down |= g.IO.MouseDown[i]; + if (g.IO.MouseDown[i]) + if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) + mouse_earliest_button_down = i; + } + const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; + + const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; + if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) + clear_hovered_windows = true; + + if (clear_hovered_windows) + g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + + if (g.WantCaptureMouseNextFrame != -1) + g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); + else + g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0); + + if (g.WantCaptureKeyboardNextFrame != -1) + g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + else + g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + g.IO.WantCaptureKeyboard = true; + + g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; +} + +ImGuiKeyModFlags ImGui::GetMergedKeyModFlags() +{ + ImGuiContext& g = *GImGui; + ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None; + if (g.IO.KeyCtrl) { key_mod_flags |= ImGuiKeyModFlags_Ctrl; } + if (g.IO.KeyShift) { key_mod_flags |= ImGuiKeyModFlags_Shift; } + if (g.IO.KeyAlt) { key_mod_flags |= ImGuiKeyModFlags_Alt; } + if (g.IO.KeySuper) { key_mod_flags |= ImGuiKeyModFlags_Super; } + return key_mod_flags; +} + +void ImGui::NewFrame() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + ImGuiContext& g = *GImGui; + + 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); + + ErrorCheckNewFrameSanityChecks(); + + UpdateSettings(); + + g.Time += g.IO.DeltaTime; + g.WithinFrameScope = true; + g.FrameCount += 1; + g.TooltipOverrideCount = 0; + g.WindowsActiveCount = 0; + g.MenusIdSubmittedThisFrame.resize(0); + + 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.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; + + g.IO.Fonts->Locked = true; + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); + g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); + g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError); + 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; + + g.BackgroundDrawList._ResetForNewFrame(); + g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID); + g.BackgroundDrawList.PushClipRectFullScreen(); + + g.ForegroundDrawList._ResetForNewFrame(); + g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID); + g.ForegroundDrawList.PushClipRectFullScreen(); + + g.DrawData.Clear(); + + if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) + KeepAliveID(g.DragDropPayload.SourceId); + + 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.HoveredIdPreviousFrameUsingMouseWheel = g.HoveredIdUsingMouseWheel; + g.HoveredId = 0; + g.HoveredIdAllowOverlap = false; + g.HoveredIdUsingMouseWheel = false; + g.HoveredIdDisabled = false; + + if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) + ClearActiveID(); + 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.ActiveIdUsingNavInputMask = 0x00; + g.ActiveIdUsingKeyInputMask = 0x00; + } + + g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; + g.DragDropAcceptIdCurr = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropWithinSource = false; + g.DragDropWithinTarget = false; + g.DragDropHoldJustPressedId = 0; + + g.IO.KeyMods = GetMergedKeyModFlags(); + memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) + g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; + + NavUpdate(); + + UpdateMouseInputs(); + + UpdateHoveredWindowAndCaptureFlags(); + + UpdateMouseMovingWindowNewFrame(); + + 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; + g.PlatformImePos = ImVec2(1.0f, 1.0f); + + UpdateMouseWheel(); + + UpdateTabFocus(); + + 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->BeginCount = 0; + window->Active = false; + window->WriteAccessed = false; + + if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) + GcCompactTransientWindowBuffers(window); + } + + 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)); + if (g.GcCompactAll) + GcCompactTransientMiscBuffers(); + g.GcCompactAll = false; + + if (g.NavWindow && !g.NavWindow->WasActive) + FocusTopMostWindowUnderOne(NULL, NULL); + + g.CurrentWindowStack.resize(0); + g.BeginPopupStack.resize(0); + g.ItemFlagsStack.resize(0); + g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_); + g.GroupStack.resize(0); + ClosePopupsOverWindow(g.NavWindow, false); + + UpdateDebugToolItemPicker(); + + g.WithinFrameScopeWithImplicitWindow = true; + SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); +} + +void ImGui::UpdateDebugToolItemPicker() +{ + ImGuiContext& g = *GImGui; + g.DebugItemPickerBreakId = 0; + if (g.DebugItemPickerActive) + { + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); + if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + g.DebugItemPickerActive = false; + if (ImGui::IsMouseClicked(0) && hovered_id) + { + g.DebugItemPickerBreakId = hovered_id; + g.DebugItemPickerActive = false; + } + ImGui::SetNextWindowBgAlpha(0.60f); + ImGui::BeginTooltip(); + ImGui::Text("HoveredId: 0x%08X", hovered_id); + ImGui::Text("Press ESC to abort picking."); + ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); + ImGui::EndTooltip(); + } +} + +void ImGui::Initialize(ImGuiContext* context) +{ + ImGuiContext& g = *context; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + { + 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; + g.SettingsHandlers.push_back(ini_handler); + } + +#ifdef IMGUI_HAS_TABLE + TableSettingsInstallHandler(context); +#endif + +#ifdef IMGUI_HAS_DOCK +#endif + + g.Initialized = true; +} + +void ImGui::Shutdown(ImGuiContext* context) +{ + ImGuiContext& g = *context; + if (g.IO.Fonts && g.FontAtlasOwnedByContext) + { + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + + if (!g.Initialized) + return; + + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + { + ImGuiContext* backup_context = GImGui; + SetCurrentContext(&g); + SaveIniSettingsToDisk(g.IO.IniFilename); + SetCurrentContext(backup_context); + } + + CallContextHooks(&g, ImGuiContextHookType_Shutdown); + + for (int i = 0; i < g.Windows.Size; i++) + IM_DELETE(g.Windows[i]); + g.Windows.clear(); + g.WindowsFocusOrder.clear(); + g.WindowsTempSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; + g.ColorStack.clear(); + g.StyleVarStack.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); + g.DrawDataBuilder.ClearFreeMemory(); + g.BackgroundDrawList._ClearFreeMemory(); + g.ForegroundDrawList._ClearFreeMemory(); + + g.TabBars.Clear(); + g.CurrentTabBarStack.clear(); + g.ShrinkWidthBuffer.clear(); + + g.Tables.Clear(); + g.CurrentTableStack.clear(); + g.DrawChannelsTempMergeBuffer.clear(); + + g.ClipboardHandlerData.clear(); + g.MenusIdSubmittedThisFrame.clear(); + g.InputTextState.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.Initialized = false; +} + +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; + if (count > 1) + 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 AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) +{ + draw_list->_PopUnusedDrawCmd(); + if (draw_list->CmdBuffer.Size == 0) + return; + + 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); + + if (sizeof(ImDrawIdx) == 2) + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + + out_list->push_back(draw_list); +} + +static void AddWindowToDrawData(ImVector* out_render_list, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.IO.MetricsRenderWindows++; + AddDrawListToDrawData(out_render_list, window->DrawList); + for (int i = 0; i < window->DC.ChildWindows.Size; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (IsWindowActiveAndVisible(child)) + AddWindowToDrawData(out_render_list, child); + } +} + +static void AddRootWindowToDrawData(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; + AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window); +} + +void ImDrawDataBuilder::FlattenIntoSingleLayer() +{ + int n = Layers[0].Size; + int size = n; + for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) + size += Layers[i].Size; + Layers[0].resize(size); + for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) + { + ImVector& layer = Layers[layer_n]; + if (layer.empty()) + continue; + memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); + n += layer.Size; + layer.resize(0); + } +} + +static void SetupDrawData(ImVector* draw_lists, ImDrawData* draw_data) +{ + ImGuiIO& io = ImGui::GetIO(); + draw_data->Valid = true; + draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; + draw_data->CmdListsCount = draw_lists->Size; + draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; + draw_data->DisplayPos = ImVec2(0.0f, 0.0f); + draw_data->DisplaySize = io.DisplaySize; + draw_data->FramebufferScale = io.DisplayFramebufferScale; + for (int n = 0; n < draw_lists->Size; n++) + { + draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; + } +} + +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(); +} + +void ImGui::EndFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + if (g.FrameCountEnded == g.FrameCount) + return; + IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePre); + + ErrorCheckEndFrameSanityChecks(); + + if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) + { + g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); + g.PlatformImeLastPos = g.PlatformImePos; + } + + g.WithinFrameScopeWithImplicitWindow = false; + if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) + g.CurrentWindow->Active = false; + End(); + + NavEndFrame(); + + 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(); + } + + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + g.DragDropWithinSource = true; + SetTooltip("..."); + g.DragDropWithinSource = false; + } + + g.WithinFrameScope = false; + g.FrameCountEnded = g.FrameCount; + + UpdateMouseMovingWindowEndFrame(); + + 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)) + continue; + AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); + } + + IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size); + g.Windows.swap(g.WindowsTempSortBuffer); + g.IO.MetricsActiveWindows = g.WindowsActiveCount; + + g.IO.Fonts->Locked = false; + + g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; + g.IO.InputQueueCharacters.resize(0); + memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePost); +} + +void ImGui::Render() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + if (g.FrameCountEnded != g.FrameCount) + EndFrame(); + g.FrameCountRendered = g.FrameCount; + g.IO.MetricsRenderWindows = 0; + g.DrawDataBuilder.Clear(); + + CallContextHooks(&g, ImGuiContextHookType_RenderPre); + + if (!g.BackgroundDrawList.VtxBuffer.empty()) + AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList); + + 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]; + 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])) + AddRootWindowToDrawData(windows_to_render_top_most[n]); + g.DrawDataBuilder.FlattenIntoSingleLayer(); + + if (g.IO.MouseDrawCursor) + RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); + + if (!g.ForegroundDrawList.VtxBuffer.empty()) + AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList); + + SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); + g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; + g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; + + CallContextHooks(&g, ImGuiContextHookType_RenderPost); +} + +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); + 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); + + text_size.x = IM_FLOOR(text_size.x + 0.99999f); + + return text_size; +} + +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_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (!window->Active || window->Hidden) + continue; + if (window->Flags & ImGuiWindowFlags_NoMouseInputs) + continue; + + ImRect bb(window->OuterRectClipped); + if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) + bb.Expand(padding_regular); + else + bb.Expand(padding_for_resize_from_edges); + if (!bb.Contains(g.IO.MousePos)) + continue; + + 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; + 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.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; + g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; +} + +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + 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; +} + +int ImGui::GetKeyIndex(ImGuiKey imgui_key) +{ + IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); + ImGuiContext& g = *GImGui; + return g.IO.KeyMap[imgui_key]; +} + +bool ImGui::IsKeyDown(int user_key_index) +{ + if (user_key_index < 0) + return false; + ImGuiContext& g = *GImGui; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDown[user_key_index]; +} + +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; +} + +int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) +{ + ImGuiContext& g = *GImGui; + if (key_index < 0) + return 0; + IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[key_index]; + return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); +} + +bool ImGui::IsKeyPressed(int user_key_index, bool repeat) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) + return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[user_key_index]; + if (t == 0.0f) + return true; + if (repeat && t > g.IO.KeyRepeatDelay) + return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + return false; +} + +bool ImGui::IsKeyReleased(int user_key_index) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; +} + +bool ImGui::IsMouseDown(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button]; +} + +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + const float t = g.IO.MouseDownDuration[button]; + if (t == 0.0f) + return true; + + if (repeat && t > g.IO.KeyRepeatDelay) + { + int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); + if (amount > 0) + return true; + } + return false; +} + +bool ImGui::IsMouseReleased(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button]; +} + +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDoubleClicked[button]; +} + +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; +} + +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.IO.MousePos; +} + +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + 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; +} + +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; +} + +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)); + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + return GImGui->MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + GImGui->MouseCursor = cursor_type; +} + +void ImGui::CaptureKeyboardFromApp(bool capture) +{ + GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; +} + +void ImGui::CaptureMouseFromApp(bool capture) +{ + GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; +} + +bool ImGui::IsItemActive() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + { + ImGuiWindow* window = g.CurrentWindow; + return g.ActiveId == window->DC.LastItemId; + } + return false; +} + +bool ImGui::IsItemActivated() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + { + ImGuiWindow* window = g.CurrentWindow; + if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId) + return true; + } + return false; +} + +bool ImGui::IsItemDeactivated() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated) + return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; + return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); +} + +bool ImGui::IsItemDeactivatedAfterEdit() +{ + ImGuiContext& g = *GImGui; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); +} + +bool ImGui::IsItemFocused() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (g.NavId != window->DC.LastItemId || g.NavId == 0) + return false; + return true; +} + +bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) +{ + return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); +} + +bool ImGui::IsItemToggledOpen() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; +} + +bool ImGui::IsItemToggledSelection() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentWindow->DC.LastItemStatusFlags & 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() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ClipRect.Overlaps(window->DC.LastItemRect); +} + +bool ImGui::IsItemEdited() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; +} + +void ImGui::SetItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.CurrentWindow->DC.LastItemId; + if (g.HoveredId == id) + g.HoveredIdAllowOverlap = true; + if (g.ActiveId == id) + g.ActiveIdAllowOverlap = true; +} + +void ImGui::SetItemUsingMouseWheel() +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.CurrentWindow->DC.LastItemId; + if (g.HoveredId == id) + g.HoveredIdUsingMouseWheel = true; + if (g.ActiveId == id) + g.ActiveIdUsingMouseWheel = true; +} + +ImVec2 ImGui::GetItemRectMin() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.GetSize(); +} + +static ImRect GetViewportRect() +{ + ImGuiContext& g = *GImGui; + return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); +} + +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); + + 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); + if (size.y <= 0.0f) + size.y = ImMax(content_avail.y + size.y, 4.0f); + SetNextWindowSize(size); + + if (name) + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%s_%08X", parent_window->Name, name, id); + else + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%08X", parent_window->Name, id); + + const float backup_border_size = g.Style.ChildBorderSize; + if (!border) + g.Style.ChildBorderSize = 0.0f; + bool ret = Begin(g.TempBuffer, NULL, flags); + g.Style.ChildBorderSize = backup_border_size; + + + ImGuiWindow* child_window = g.CurrentWindow; + child_window->ChildId = id; + child_window->AutoFitChildAxises = (ImS8)auto_fit_axises; + + if (child_window->BeginCount == 1) + parent_window->DC.CursorPos = child_window->Pos; + + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) + { + FocusWindow(child_window); + NavInitWindow(child_window, false); + SetActiveID(id + 1, child_window); + g.ActiveIdSource = ImGuiInputSource_Nav; + } + + + + + 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); + + g.WithinEndChild = true; + if (window->BeginCount > 1) + { + End(); + } + else + { + ImVec2 sz = window->Size; + if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) + 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.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + { + ItemAdd(bb, window->ChildId); + RenderNavHighlight(bb, window->ChildId); + + if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) + RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); + } + else + { + ItemAdd(bb, 0); + } + } + g.WithinEndChild = false; + g.LogLinePosY = -FLT_MAX; +} + +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 ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + window->Pos = ImVec2(60, 60); + + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) + { + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; + + if ((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); + } + + g.WindowsFocusOrder.push_back(window); + if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) + g.Windows.push_front(window); + else + g.Windows.push_back(window); + return window; +} + +static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) +{ + ImGuiContext& g = *GImGui; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + { + 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); + } + + if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + { + ImGuiWindow* window_for_height = window; + new_size = ImMax(new_size, g.Style.WindowMinSize); + new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); + } + 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; + ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight()); + ImVec2 size_pad = window->WindowPadding * 2.0f; + ImVec2 size_desired = size_contents + size_pad + size_decorations; + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + return size_desired; + } + else + { + 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) + size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); + + 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 - size_decorations.x < 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 - size_decorations.y < 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 GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) +{ + if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + return ImGuiCol_PopupBg; + if (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); + ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); + 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; +} + +struct ImGuiResizeGripDef +{ + ImVec2 CornerPosN; + ImVec2 InnerDir; + int AngleMin12, AngleMax12; +}; + +static const ImGuiResizeGripDef resize_grip_def[4] = +{ + { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, + { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, + { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, + { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, +}; + +struct ImGuiResizeBorderDef +{ + ImVec2 InnerDir; + ImVec2 CornerPosN1, CornerPosN2; + float OuterAngle; +}; + +static const ImGuiResizeBorderDef resize_border_def[4] = +{ + { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, + { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, + { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, + { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } +}; + +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 == 0) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } + if (border_n == 1) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } + if (border_n == 2) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } + if (border_n == 3) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } + IM_ASSERT(0); + return ImRect(); +} + +ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n) +{ + IM_ASSERT(n >= 0 && n <= 7); + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +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) + 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_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; + + ImVec2 pos_target(FLT_MAX, FLT_MAX); + ImVec2 size_target(FLT_MAX, FLT_MAX); + + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + + PushID("#RESIZE"); + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + + ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.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); + bool hovered, held; + ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + if (hovered || held) + g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; + + if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) + { + size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); + ret_auto_fit = true; + ClearActiveID(); + } + else if (held) + { + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); + ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX); + corner_target = ImClamp(corner_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); + } + 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++) + { + bool hovered, held; + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); + ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren); + if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) + { + g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + if (held) + *border_held = border_n; + } + if (held) + { + ImVec2 border_target = window->Pos; + ImVec2 border_posn; + if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX); + border_target = ImClamp(border_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); + } + } + PopID(); + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + + if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) + { + ImVec2 nav_resize_delta; + if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_NavGamepad) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); + if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) + { + const float NAV_RESIZE_SPEED = 600.0f; + nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size); + g.NavWindowingToggleLayer = false; + g.NavDisableMouseHover = true; + resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); + size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); + } + } + + 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 ClampWindowRect(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, ImDrawCornerFlags_All, 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.CornerPosN1) + 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.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); + } + 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); + } +} + + +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, 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; + + IM_ASSERT(window->BeginCount == 0); + window->SkipItems = false; + + const float window_rounding = window->WindowRounding; + const float window_border_size = window->WindowBorderSize; + if (window->Collapsed) + { + 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 + { + if (!(flags & ImGuiWindowFlags_NoBackground)) + { + ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); + 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) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); + } + + 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, ImDrawCornerFlags_Top); + } + + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + menu_bar_rect.ClipWith(window->Rect()); + 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, ImDrawCornerFlags_Top); + + 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); + } + + if (window->ScrollbarX) + Scrollbar(ImGuiAxis_X); + if (window->ScrollbarY) + Scrollbar(ImGuiAxis_Y); + + + if (!(flags & ImGuiWindowFlags_NoResize)) + { + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + 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(resize_grip_col[resize_grip_n]); + } + } + + RenderWindowOuterBorders(window); + } +} + +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); + + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + + 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; + } + + if (has_collapse_button) + if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos)) + window->WantCollapseToggle = true; + + if (has_close_button) + if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) + *p_open = false; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.ItemFlags = item_flags_backup; + + const char* UNSAVED_DOCUMENT_MARKER = "*"; + const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; + const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); + + 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); + 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); + } + + pad_l += 10.0f; + + 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); + RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); + if (flags & ImGuiWindowFlags_UnsavedDocument) + { + ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); + ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f)); + RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r); + } +} + +void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) +{ + window->ParentWindow = parent_window; + window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; + if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + window->RootWindow = parent_window->RootWindow; + 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; + } +} + +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'); + IM_ASSERT(g.WithinFrameScope); + IM_ASSERT(g.FrameCountEnded != g.FrameCount); + + ImGuiWindow* window = FindWindowByName(name); + + const bool window_just_created = (window == NULL); + if (window_just_created) + window = CreateNewWindow(name, flags); + + 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); + + bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); + window_just_activated_by_user |= (window != popup_ref.Window); + } + window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); + + if (first_begin_of_the_frame) + { + 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; + } + + ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); + 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)); + + if (window->IDStack.Size == 0) + window->IDStack.push_back(window->ID); + + g.CurrentWindowStack.push_back(window); + g.CurrentWindow = window; + window->DC.StackSizesOnBegin.SetToCurrentState(); + g.CurrentWindow = NULL; + + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + popup_ref.Window = window; + g.BeginPopupStack.push_back(popup_ref); + window->PopupId = popup_ref.PopupId; + } + + if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) + window->NavLastIds[0] = 0; + + if (first_begin_of_the_frame) + UpdateWindowParentAndRootLinks(window, flags, parent_window); + + 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) + { + 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); + + if (first_begin_of_the_frame) + { + const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); + 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; + + if (window->MemoryCompacted) + GcAwakeTransientWindowBuffers(window); + + bool window_title_visible_elsewhere = false; + if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) + 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; + } + + CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal); + if (window->HiddenFramesCanSkipItems > 0) + window->HiddenFramesCanSkipItems--; + if (window->HiddenFramesCannotSkipItems > 0) + window->HiddenFramesCannotSkipItems--; + if (window->HiddenFramesForRenderOnly > 0) + window->HiddenFramesForRenderOnly--; + + if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) + window->HiddenFramesCannotSkipItems = 1; + + 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); + } + } + + SetCurrentWindow(window); + + 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); + + window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); + window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; + + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) + { + 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.MouseDoubleClicked[0]) + window->WantCollapseToggle = true; + if (window->WantCollapseToggle) + { + window->Collapsed = !window->Collapsed; + MarkIniSettingsDirty(window); + FocusWindow(window); + } + } + else + { + window->Collapsed = false; + } + window->WantCollapseToggle = false; + + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal); + bool use_current_size_for_scrollbar_x = window_just_created; + bool use_current_size_for_scrollbar_y = window_just_created; + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + { + 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) + { + 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); + } + + window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); + window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + + if (window_just_activated_by_user) + { + window->AutoPosLastDirection = ImGuiDir_None; + if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) + window->Pos = g.BeginPopupStack.back().OpenPopupPos; + } + + 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); + 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); + + ImRect viewport_rect(GetViewportRect()); + + ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + ImRect visibility_rect(viewport_rect.Min + visibility_padding, viewport_rect.Max - visibility_padding); + + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f) + ClampWindowRect(window, visibility_rect); + window->Pos = ImFloor(window->Pos); + + window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + + 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; + } + + int border_held = -1; + ImU32 resize_grip_col[4] = {}; + const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; + 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; + + if (!window->Collapsed) + { + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; + 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; + 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); + } + + 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); + + window->InnerRect.Min.x = window->Pos.x; + window->InnerRect.Min.y = window->Pos.y + decoration_up_height; + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; + + 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); + + 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); + + 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()); + + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); + window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + + 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); + + const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; + const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); + if (dim_bg_for_modal || dim_bg_for_window_list) + { + const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); + window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); + } + + if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) + { + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (!bb.Contains(viewport_rect)) + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); + } + + { + bool render_decorations_in_parent = false; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) + if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0) + render_decorations_in_parent = true; + if (render_decorations_in_parent) + window->DrawList = parent_window->DrawList; + + 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); + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size); + + if (render_decorations_in_parent) + window->DrawList = &window->DrawListInst; + } + + if (g.NavWindowingTargetAnim == window) + { + float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (bb.Contains(viewport_rect)) + { + bb.Expand(-g.FontSize - 1.0f); + rounding = window->WindowRounding; + } + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + } + + 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->ScrollbarSizes.x)); + 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 - decoration_up_height - window->ScrollbarSizes.y)); + 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; + + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; + 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->ScrollbarSizes.x)); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + + window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffset.x = 0.0f; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.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.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; + window->DC.NavLayerActiveMaskNext = 0x00; + window->DC.NavHideHighlightOneFrame = false; + window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); + + window->DC.MenuBarAppending = false; + window->DC.MenuColumns.Update(3, 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.FocusCounterRegular = window->DC.FocusCounterTabStop = -1; + + window->DC.ItemWidth = window->ItemWidthDefault; + window->DC.TextWrapPos = -1.0f; + window->DC.ItemWidthStack.resize(0); + window->DC.TextWrapPosStack.resize(0); + + if (window->AutoFitFramesX > 0) + window->AutoFitFramesX--; + if (window->AutoFitFramesY > 0) + window->AutoFitFramesY--; + + if (want_focus) + { + FocusWindow(window); + NavInitWindow(window, false); + } + + 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); + + window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; + + SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId); +#endif + } + else + { + SetCurrentWindow(window); + } + + window->DC.ItemFlags = g.ItemFlagsStack.back(); + window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; + + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); + + window->WriteAccessed = false; + window->BeginCount++; + g.NextWindowData.ClearFlags(); + + if (first_begin_of_the_frame) + { + if (flags & ImGuiWindowFlags_ChildWindow) + { + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (!g.LogEnabled) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesCanSkipItems = 1; + + 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; + } + + if (style.Alpha <= 0.0f) + window->HiddenFramesCanSkipItems = 1; + + window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0); + + bool skip_items = false; + if (window->Collapsed || !window->Active || window->Hidden) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) + skip_items = true; + window->SkipItems = skip_items; + } + + return !window->SkipItems; +} + +void ImGui::End() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + 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); + + if (window->Flags & ImGuiWindowFlags_ChildWindow) + IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + + if (window->DC.CurrentColumns) + EndColumns(); + PopClipRect(); + + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) + LogFinish(); + + g.CurrentWindowStack.pop_back(); + if (window->Flags & ImGuiWindowFlags_Popup) + g.BeginPopupStack.pop_back(); + window->DC.StackSizesOnBegin.CompareWithCurrentState(); + SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); +} + +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.WindowsFocusOrder.back() == window) + return; + for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) + if (g.WindowsFocusOrder[i] == window) + { + memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); + g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; + break; + } +} + +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) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) + 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::FocusWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + if (g.NavWindow != window) + { + g.NavWindow = window; + if (window && g.NavDisableMouseHover) + g.NavMousePosDirty = true; + g.NavInitRequest = false; + g.NavId = window ? window->NavLastIds[0] : 0; + g.NavFocusScopeId = 0; + g.NavIdIsAlive = false; + g.NavLayer = ImGuiNavLayer_Main; + } + + ClosePopupsOverWindow(window, false); + + IM_ASSERT(window == NULL || window->RootWindow != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; + ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; + + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) + if (!g.ActiveIdNoClearOnFocusLoss) + ClearActiveID(); + + if (!window) + return; + + 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) +{ + ImGuiContext& g = *GImGui; + + int start_idx = g.WindowsFocusOrder.Size - 1; + if (under_this_window != NULL) + { + int under_this_window_idx = FindWindowFocusIndex(under_this_window); + if (under_this_window_idx != -1) + start_idx = under_this_window_idx - 1; + } + for (int i = start_idx; i >= 0; i--) + { + ImGuiWindow* window = g.WindowsFocusOrder[i]; + if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); + FocusWindow(focus_window); + return; + } + } + FocusWindow(NULL); +} + +void ImGui::SetCurrentFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(font && font->IsLoaded()); + 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; + ImGuiWindow* window = g.CurrentWindow; + ImGuiItemFlags item_flags = window->DC.ItemFlags; + IM_ASSERT(item_flags == g.ItemFlagsStack.back()); + if (enabled) + item_flags |= option; + else + item_flags &= ~option; + window->DC.ItemFlags = item_flags; + g.ItemFlagsStack.push_back(item_flags); +} + +void ImGui::PopItemFlag() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.ItemFlagsStack.Size > 1); + g.ItemFlagsStack.pop_back(); + window->DC.ItemFlags = g.ItemFlagsStack.back(); +} + +void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +{ + PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); +} + +void ImGui::PopAllowKeyboardFocus() +{ + 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(); +} + +bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) +{ + if (window->RootWindow == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + window = window->ParentWindow; + } + return false; +} + +bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below) +{ + ImGuiContext& g = *GImGui; + 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_AllowWhenOverlapped) == 0); + ImGuiContext& g = *GImGui; + + if (flags & ImGuiHoveredFlags_AnyWindow) + { + if (g.HoveredWindow == NULL) + return false; + } + else + { + switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) + { + case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: + if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) + return false; + break; + case ImGuiHoveredFlags_RootWindow: + if (g.HoveredWindow != g.CurrentWindow->RootWindow) + return false; + break; + case ImGuiHoveredFlags_ChildWindows: + if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) + return false; + break; + default: + if (g.HoveredWindow != g.CurrentWindow) + return false; + break; + } + } + + if (!IsWindowContentHoverable(g.HoveredWindow, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) + return false; + return true; +} + +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + + if (flags & ImGuiFocusedFlags_AnyWindow) + return g.NavWindow != NULL; + + IM_ASSERT(g.CurrentWindow); + switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows)) + { + case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows: + return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow; + case ImGuiFocusedFlags_RootWindow: + return g.NavWindow == g.CurrentWindow->RootWindow; + case ImGuiFocusedFlags_ChildWindows: + return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow); + default: + return g.NavWindow == g.CurrentWindow; + } +} + +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) +{ + if (cond && (window->SetWindowPosAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); + + const ImVec2 old_pos = window->Pos; + window->Pos = ImFloor(pos); + ImVec2 offset = window->Pos - old_pos; + window->DC.CursorPos += offset; + window->DC.CursorMaxPos += offset; + 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) +{ + if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); + window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + if (size.x > 0.0f) + { + window->AutoFitFramesX = 0; + window->SizeFull.x = IM_FLOOR(size.x); + } + else + { + window->AutoFitFramesX = 2; + window->AutoFitOnlyGrows = false; + } + if (size.y > 0.0f) + { + window->AutoFitFramesY = 0; + window->SizeFull.y = IM_FLOOR(size.y); + } + else + { + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } +} + +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) +{ + if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) + return; + window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + window->Collapsed = collapsed; +} + +void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) +{ + IM_ASSERT(window->HitTestHoleSize.x == 0); + window->HitTestHoleSize = ImVec2ih(size); + window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); +} + +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)); + 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)); + 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; +} + +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)); + 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::ActivateItem(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; +} + +void ImGui::PushFocusScope(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + g.FocusScopeStack.push_back(window->DC.NavFocusScopeIdCurrent); + window->DC.NavFocusScopeIdCurrent = id; +} + +void ImGui::PopFocusScope() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.FocusScopeStack.Size > 0); + window->DC.NavFocusScopeIdCurrent = g.FocusScopeStack.back(); + g.FocusScopeStack.pop_back(); +} + +void ImGui::SetKeyboardFocusHere(int offset) +{ + IM_ASSERT(offset >= -1); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + g.FocusRequestNextWindow = window; + g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset; + g.FocusRequestNextCounterTabStop = INT_MAX; +} + +void ImGui::SetItemDefaultFocus() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!window->Appearing) + return; + if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) + { + g.NavInitRequest = false; + g.NavInitResultId = g.NavWindow->DC.LastItemId; + g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); + NavUpdateAnyRequestFlag(); + if (!IsItemVisible()) + SetScrollHereY(); + } +} + +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->GetIDNoKeepAlive(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->GetIDNoKeepAlive(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->GetIDNoKeepAlive(ptr_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(int int_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(int_id); + window->IDStack.push_back(id); +} + +void ImGui::PushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->IDStack.push_back(id); +} + +ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) +{ + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); +#endif + return id; +} + +void ImGui::PopID() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + IM_ASSERT(window->IDStack.Size > 1); + 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)); +} + + +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; +} + +static void ImGui::ErrorCheckNewFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + if (true) IM_ASSERT(1); else IM_ASSERT(0); + + 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->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?"); + IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?"); + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); + 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); + for (int n = 0; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); + + if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); + + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; +} + +static void ImGui::ErrorCheckEndFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); + IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(key_mod_flags); + + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + 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!"); +} + +void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + ImGuiContext& g = *GImGui; + while (g.CurrentWindowStack.Size > 0) + { +#ifdef IMGUI_HAS_TABLE + 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(); + } +#endif + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window != NULL); + while (g.CurrentTabBar != NULL) + { + 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 > window->DC.StackSizesOnBegin.SizeOfGroupStack) + { + 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.ColorStack.Size > window->DC.StackSizesOnBegin.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.StyleVarStack.Size > window->DC.StackSizesOnBegin.SizeOfStyleVarStack) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); + PopStyleVar(); + } + while (g.FocusScopeStack.Size > window->DC.StackSizesOnBegin.SizeOfFocusScopeStack) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name); + PopFocusScope(); + } + if (g.CurrentWindowStack.Size == 1) + { + IM_ASSERT(g.CurrentWindow->IsFallbackWindow); + break; + } + IM_ASSERT(window == g.CurrentWindow); + 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(); + } + } +} + +void ImGuiStackSizes::SetToCurrentState() +{ + ImGuiContext& g = *GImGui; + 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; + SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; +} + +void ImGuiStackSizes::CompareWithCurrentState() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_UNUSED(window); + + IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!"); + + IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); + IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu 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!"); +} + + +void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + 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_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y); + + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); + 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); + 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; + + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + SameLine(); +} + +void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) +{ + ItemSize(bb.GetSize(), text_baseline_y); +} + +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (id != 0) + { + window->DC.NavLayerActiveMaskNext |= (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(window, nav_bb_arg ? *nav_bb_arg : bb, id); + +#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + if (id == g.DebugItemPickerBreakId) + { + IM_DEBUG_BREAK(); + g.DebugItemPickerBreakId = 0; + } +#endif + } + + window->DC.LastItemId = id; + window->DC.LastItemRect = bb; + window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0) + IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id); +#endif + + const bool is_clipped = IsClippedEx(bb, id, false); + if (is_clipped) + return false; + if (IsMouseHoveringRect(bb.Min, bb.Max)) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; + return true; +} + +void ImGui::SameLine(float offset_from_start_x, float spacing_w) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + 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; +} + +ImVec2 ImGui::GetCursorScreenPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos; +} + +void ImGui::SetCursorScreenPos(const ImVec2& pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->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); +} + +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); +} + +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); +} + +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; +} + +void ImGui::SetNextItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Width = item_width; +} + +void ImGui::PushItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); + 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); + 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(); +} + +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; +} + +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +{ + ImGuiWindow* window = GImGui->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; +} + +ImVec2 ImGui::GetContentRegionMax() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max - window->Pos; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x - window->Pos.x; + return mx; +} + +ImVec2 ImGui::GetContentRegionMaxAbs() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x; + return mx; +} + +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxAbs() - window->DC.CursorPos; +} + +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; +} + +float ImGui::GetWindowContentRegionWidth() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.GetWidth(); +} + +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.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; +} + +void ImGui::EndGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.GroupStack.Size > 0); + + ImGuiGroupData& group_data = g.GroupStack.back(); + IM_ASSERT(group_data.WindowID == window->ID); + + 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; + + if (!group_data.EmitItem) + { + g.GroupStack.pop_back(); + return; + } + + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); + ItemSize(group_bb.GetSize()); + ItemAdd(group_bb, 0); + + 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) + window->DC.LastItemId = g.ActiveId; + else if (group_contains_prev_active_id) + window->DC.LastItemId = g.ActiveIdPreviousFrame; + window->DC.LastItemRect = group_bb; + + if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; + + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated; + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; + + g.GroupStack.pop_back(); +} + + +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; + if (window->ScrollTarget.x < FLT_MAX) + { + float center_x_ratio = window->ScrollTargetCenterRatio.x; + float scroll_target_x = window->ScrollTarget.x; + float snap_x_min = 0.0f; + float snap_x_max = window->ScrollMax.x + window->Size.x; + if (window->ScrollTargetEdgeSnapDist.x > 0.0f) + scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio); + scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x); + } + if (window->ScrollTarget.y < FLT_MAX) + { + float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + float center_y_ratio = window->ScrollTargetCenterRatio.y; + float scroll_target_y = window->ScrollTarget.y; + float snap_y_min = 0.0f; + float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height; + if (window->ScrollTargetEdgeSnapDist.y > 0.0f) + scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio); + scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); + } + scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); + scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); + if (!window->Collapsed && !window->SkipItems) + { + scroll.x = ImMin(scroll.x, window->ScrollMax.x); + scroll.y = ImMin(scroll.y, window->ScrollMax.y); + } + return scroll; +} + +ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect) +{ + ImGuiContext& g = *GImGui; + ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); + ImVec2 delta_scroll; + if (!window_rect.Contains(item_rect)) + { + if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x) + SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f); + else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x) + SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f); + if (item_rect.Min.y < window_rect.Min.y) + SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f); + else if (item_rect.Max.y >= window_rect.Max.y) + SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f); + + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + delta_scroll = next_scroll - window->Scroll; + } + + if (window->Flags & ImGuiWindowFlags_ChildWindow) + delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll)); + + 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); +} + +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->Scroll.x); + 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); + local_y -= window->TitleBarHeight() + window->MenuBarHeight(); + window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); + 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); +} + +void ImGui::SetScrollHereX(float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_x = g.Style.ItemSpacing.x; + float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio); + SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); + + window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x); +} + +void ImGui::SetScrollHereY(float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_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); + + window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y); +} + +void ImGui::BeginTooltip() +{ + BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None); +} + +void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags) +{ + ImGuiContext& g = *GImGui; + + if (g.DragDropWithinSource || g.DragDropWithinTarget) + { + ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); + SetNextWindowPos(tooltip_pos); + SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); + tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip; + } + + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + window->Hidden = true; + window->HiddenFramesCanSkipItems = 1; + 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_flags); +} + +void ImGui::EndTooltip() +{ + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); + End(); +} + +void ImGui::SetTooltipV(const char* fmt, va_list args) +{ + BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); + TextV(fmt, args); + EndTooltip(); +} + +void ImGui::SetTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + SetTooltipV(fmt, args); + va_end(args); +} + +bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + if (popup_flags & ImGuiPopupFlags_AnyPopupId) + { + 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) + { + for (int n = 0; n < g.OpenPopupStack.Size; n++) + if (g.OpenPopupStack[n].PopupId == id) + return true; + return false; + } + else + { + 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."); + return IsPopupOpen(id, popup_flags); +} + +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; +} + +void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags); +} + +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(0u, ImGuiPopupFlags_AnyPopupId)) + return; + + ImGuiPopupData popup_ref; + popup_ref.PopupId = id; + popup_ref.Window = NULL; + popup_ref.SourceWindow = g.NavWindow; + 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("OpenPopupEx(0x%08X)\n", id); + if (g.OpenPopupStack.Size < current_stack_size + 1) + { + g.OpenPopupStack.push_back(popup_ref); + } + else + { + 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 + { + ClosePopupToLevel(current_stack_size, false); + g.OpenPopupStack.push_back(popup_ref); + } + + } +} + +void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size == 0) + return; + + int popup_count_to_keep = 0; + if (ref_window) + { + 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; + + 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 (popup_window->RootWindow == ref_window->RootWindow) + { + ref_window_is_descendent_of_popup = true; + break; + } + if (!ref_window_is_descendent_of_popup) + break; + } + } + if (popup_count_to_keep < g.OpenPopupStack.Size) + { + IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); + ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); + } +} + +void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + IMGUI_DEBUG_LOG_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); + + ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow; + ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; + g.OpenPopupStack.resize(remaining); + + if (restore_focus_to_window_under_popup) + { + if (focus_window && !focus_window->WasActive && popup_window) + { + FocusTopMostWindowUnderOne(popup_window, NULL); + } + else + { + if (g.NavLayer == ImGuiNavLayer_Main && focus_window) + focus_window = NavRestoreLastChildNavWindow(focus_window); + FocusWindow(focus_window); + } + } +} + +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; + + 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 == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) + close_parent = true; + if (!close_parent) + break; + popup_idx--; + } + IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); + ClosePopupToLevel(popup_idx, true); + + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; +} + +bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) +{ + + + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); + return false; + } + + char name[20]; + if (flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); + else + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); + + flags |= ImGuiWindowFlags_Popup; + bool is_open = Begin(name, NULL, flags); + if (!is_open) + EndPopup(); + + return is_open; +} + +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) + { + g.NextWindowData.ClearFlags(); + return false; + } + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); +} + +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(); + return false; + } + + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + SetNextWindowPos(g.IO.DisplaySize * 0.5f, 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)) + { + 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); + IM_ASSERT(g.BeginPopupStack.Size > 0); + + if (g.NavWindow == window) + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; + End(); + g.WithinEndChild = false; +} + +void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + { + ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; + IM_ASSERT(id != 0); + OpenPopupEx(id, popup_flags); + } +} + +bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + if (window->SkipItems) + return false; + ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; + IM_ASSERT(id != 0); + 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) +{ + ImGuiWindow* window = GImGui->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) +{ + ImGuiWindow* window = GImGui->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); +} + +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); + 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) + continue; + ImVec2 pos; + if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); + if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); + if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); + if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); + if (!r_outer.Contains(ImRect(pos, pos + size))) + continue; + *last_dir = dir; + return pos; + } + } + + 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) + 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 (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; + + pos.x = ImMax(pos.x, r_outer.Min.x); + pos.y = ImMax(pos.y, r_outer.Min.y); + + *last_dir = dir; + return pos; + } + } + + *last_dir = ImGuiDir_None; + + if (policy == ImGuiPopupPositionPolicy_Tooltip) + return ref_pos + ImVec2(2, 2); + + 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; +} + +ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window) +{ + IM_UNUSED(window); + ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; + ImRect r_screen = GetViewportRect(); + 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 = GetWindowAllowedExtentRect(window); + if (window->Flags & ImGuiWindowFlags_ChildMenu) + { + IM_ASSERT(g.CurrentWindow == window); + ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; + float horizontal_overlap = g.Style.ItemInnerSpacing.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); + 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) + { + ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); + } + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + float sc = g.Style.MouseCursorScale; + ImVec2 ref_pos = NavCalcPreferredRefPos(); + 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 * sc, ref_pos.y + 24 * sc); + return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); + } + IM_ASSERT(0); + return window->Pos; +} + +void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow); + IM_ASSERT(nav_layer == 0 || nav_layer == 1); + g.NavId = id; + g.NavFocusScopeId = focus_scope_id; + g.NavWindow->NavLastIds[nav_layer] = id; +} + +void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) +{ + ImGuiContext& g = *GImGui; + SetNavID(id, nav_layer, focus_scope_id); + g.NavWindow->NavRectRel[nav_layer] = rect_rel; + g.NavMousePosDirty = true; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; +} + +void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; + if (g.NavWindow != window) + g.NavInitRequest = false; + g.NavWindow = window; + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; + window->NavLastIds[nav_layer] = id; + if (window->DC.LastItemId == id) + window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); + + if (g.ActiveIdSource == ImGuiInputSource_Nav) + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; +} + +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 a0, float a1, float b0, float b1) +{ + if (a1 < b0) + return a1 - b0; + if (b1 < a0) + return a0 - b1; + return 0.0f; +} + +static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) +{ + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + { + r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); + r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); + } + else + { + r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); + r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); + } +} + +static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavLayer != window->DC.NavLayerCurrent) + return false; + + const ImRect& curr = g.NavScoringRect; + g.NavScoringCount++; + + 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); + } + + NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); + + 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)); + 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); + + 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); + + ImGuiDir quadrant; + float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; + if (dbx != 0.0f || dby != 0.0f) + { + dax = dbx; + day = dby; + dist_axial = dist_box; + quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + } + else if (dcx != 0.0f || dcy != 0.0f) + { + dax = dcx; + day = dcy; + dist_axial = dist_center; + quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + } + else + { + quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + } + +#if IMGUI_DEBUG_NAV_SCORING + char buf[128]; + if (IsMouseHoveringRect(cand.Min, cand.Max)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); + 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,150)); + draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); + } + else if (g.IO.KeyCtrl) + { + if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } + if (quadrant == g.NavMoveDir) + { + 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, 200)); + draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); + } + } +#endif + + bool new_best = false; + if (quadrant == g.NavMoveDir) + { + if (dist_box < result->DistBox) + { + result->DistBox = dist_box; + result->DistCenter = dist_center; + return true; + } + if (dist_box == result->DistBox) + { + if (dist_center < result->DistCenter) + { + result->DistCenter = dist_center; + new_best = true; + } + else if (dist_center == result->DistCenter) + { + if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) + new_best = true; + } + } + } + + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) + if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) + { + result->DistAxial = dist_axial; + new_best = true; + } + + return new_best; +} + +static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel) +{ + result->Window = window; + result->ID = id; + result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; + result->RectRel = nav_bb_rel; +} + +static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) +{ + ImGuiContext& g = *GImGui; + const ImGuiItemFlags item_flags = window->DC.ItemFlags; + const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); + + if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) + { + if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) + { + g.NavInitResultId = id; + g.NavInitResultRectRel = nav_bb_rel; + } + if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) + { + g.NavInitRequest = false; + NavUpdateAnyRequestFlag(); + } + } + + if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav))) + { + ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; +#if IMGUI_DEBUG_NAV_SCORING + if (!g.NavMoveRequest) + g.NavMoveDir = g.NavMoveDirLast; + bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; +#else + bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); +#endif + if (new_best) + NavApplyItemToResult(result, window, id, nav_bb_rel); + + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveRequestFlags & 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.NavMoveResultLocalVisibleSet, nav_bb)) + NavApplyItemToResult(&g.NavMoveResultLocalVisibleSet, window, id, nav_bb_rel); + } + + if (g.NavId == id) + { + g.NavWindow = window; + g.NavLayer = window->DC.NavLayerCurrent; + g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; + g.NavIdIsAlive = true; + g.NavIdTabCounter = window->DC.FocusCounterTabStop; + window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; + } +} + +bool ImGui::NavMoveRequestButNoResultYet() +{ + ImGuiContext& g = *GImGui; + return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; +} + +void ImGui::NavMoveRequestCancel() +{ + ImGuiContext& g = *GImGui; + g.NavMoveRequest = false; + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); + NavMoveRequestCancel(); + g.NavMoveDir = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; + g.NavMoveRequestFlags = move_flags; + g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; +} + +void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + + g.NavWrapRequestWindow = window; + g.NavWrapRequestFlags = move_flags; +} + +static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) +{ + ImGuiWindow* parent = nav_window; + while (parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + parent = parent->ParentWindow; + if (parent && parent != nav_window) + parent->NavLastChildNavWindow = nav_window; +} + +static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) + return window->NavLastChildNavWindow; + return window; +} + +static void NavRestoreLayer(ImGuiNavLayer layer) +{ + ImGuiContext& g = *GImGui; + g.NavLayer = layer; + if (layer == 0) + g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); + ImGuiWindow* window = g.NavWindow; + if (layer == 0 && window->NavLastIds[0] != 0) + ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]); + else + ImGui::NavInitWindow(window, true); +} + +static inline void ImGui::NavUpdateAnyRequestFlag() +{ + ImGuiContext& g = *GImGui; + g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); + if (g.NavAnyRequest) + IM_ASSERT(g.NavWindow != NULL); +} + +void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == g.NavWindow); + bool init_for_nav = false; + if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) + if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (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, 0); + g.NavInitRequest = true; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavInitResultRectRel = ImRect(); + NavUpdateAnyRequestFlag(); + } + else + { + g.NavId = window->NavLastIds[0]; + g.NavFocusScopeId = 0; + } +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) + { + if (IsMousePosValid(&g.IO.MousePos)) + return g.IO.MousePos; + return g.LastValidMousePos; + } + else + { + const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; + ImVec2 pos = g.NavWindow->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())); + ImRect visible_rect = GetViewportRect(); + return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); + } +} + +float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) +{ + ImGuiContext& g = *GImGui; + if (mode == ImGuiInputReadMode_Down) + return g.IO.NavInputs[n]; + + const float t = g.IO.NavInputsDownDuration[n]; + if (t < 0.0f && mode == ImGuiInputReadMode_Released) + return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); + if (t < 0.0f) + return 0.0f; + if (mode == ImGuiInputReadMode_Pressed) + return (t == 0.0f) ? 1.0f : 0.0f; + if (mode == ImGuiInputReadMode_Repeat) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f); + if (mode == ImGuiInputReadMode_RepeatSlow) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f); + if (mode == ImGuiInputReadMode_RepeatFast) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f); + return 0.0f; +} + +ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) +{ + ImVec2 delta(0.0f, 0.0f); + if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); + if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta *= slow_factor; + if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) + delta *= fast_factor; + return delta; +} + +static void ImGui::NavUpdate() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + io.WantSetMousePos = false; + g.NavWrapRequestWindow = NULL; + g.NavWrapRequestFlags = ImGuiNavMoveFlags_None; +#if 0 + if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); +#endif + + bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_NavGamepad) + { + if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f + || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f) + g.NavInputSource = ImGuiInputSource_NavGamepad; + } + + if (nav_keyboard_active) + { + #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0) + NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); + NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); + NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); + NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); + NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); + NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); + NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); + if (io.KeyCtrl) + io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; + if (io.KeyShift) + io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; + if (io.KeyAlt && !io.KeyCtrl) + io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; + #undef NAV_MAP_KEY + } + memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) + io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f; + + if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) + NavUpdateInitResult(); + g.NavInitRequest = false; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavJustMovedToId = 0; + + if (g.NavMoveRequest) + NavUpdateMoveResult(); + + if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) + { + IM_ASSERT(g.NavMoveRequest); + if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) + g.NavDisableHighlight = false; + g.NavMoveRequestForward = ImGuiNavForward_None; + } + + if (g.NavMousePosDirty && g.NavIdIsAlive) + { + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + { + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + { + io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); + io.WantSetMousePos = true; + } + } + g.NavMousePosDirty = false; + } + g.NavIdIsAlive = false; + g.NavJustTabbedId = 0; + IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); + + if (g.NavWindow) + NavSaveLastChildNavWindowIntoParent(g.NavWindow); + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) + g.NavWindow->NavLastChildNavWindow = NULL; + + NavUpdateWindowing(); + + 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); + + if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + { + IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n"); + if (g.ActiveId != 0) + { + if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) + ClearActiveID(); + } + else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) + { + ImGuiWindow* child_window = g.NavWindow; + ImGuiWindow* parent_window = g.NavWindow->ParentWindow; + IM_ASSERT(child_window->ChildId != 0); + FocusWindow(parent_window); + SetNavID(child_window->ChildId, 0, 0); + g.NavIdIsAlive = false; + if (g.NavDisableMouseHover) + g.NavMousePosDirty = true; + } + else if (g.OpenPopupStack.Size > 0) + { + if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); + } + else if (g.NavLayer != ImGuiNavLayer_Main) + { + NavRestoreLayer(ImGuiNavLayer_Main); + } + else + { + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = g.NavFocusScopeId = 0; + } + } + + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); + bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); + if (g.ActiveId == 0 && activate_pressed) + g.NavActivateId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) + g.NavActivateDownId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) + g.NavActivatePressedId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) + g.NavInputId = g.NavId; + } + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavDisableHighlight = true; + if (g.NavActivateId != 0) + IM_ASSERT(g.NavActivateDownId == g.NavActivateId); + g.NavMoveRequest = false; + + if (g.NavNextActivateId != 0) + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; + g.NavNextActivateId = 0; + + if (g.NavMoveRequestForward == ImGuiNavForward_None) + { + g.NavMoveDir = ImGuiDir_None; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; + if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } + } + g.NavMoveClipDir = g.NavMoveDir; + } + else + { + IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); + IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); + g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; + } + + float nav_scoring_rect_offset_y = 0.0f; + if (nav_keyboard_active) + nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(); + + if (g.NavMoveDir != ImGuiDir_None) + { + g.NavMoveRequest = true; + g.NavMoveRequestKeyMods = io.KeyMods; + g.NavMoveDirLast = g.NavMoveDir; + } + if (g.NavMoveRequest && g.NavId == 0) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); + g.NavInitRequest = g.NavInitRequestFromMove = true; + g.NavInitResultId = 0; + g.NavDisableHighlight = false; + } + NavUpdateAnyRequestFlag(); + + if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + { + ImGuiWindow* window = g.NavWindow; + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); + if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) + { + if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) + SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); + if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) + SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); + } + + ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f); + if (scroll_dir.x != 0.0f && window->ScrollbarX) + SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); + if (scroll_dir.y != 0.0f) + SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); + } + + g.NavMoveResultLocal.Clear(); + g.NavMoveResultLocalVisibleSet.Clear(); + g.NavMoveResultOther.Clear(); + + if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_NavGamepad && g.NavLayer == ImGuiNavLayer_Main) + { + ImGuiWindow* window = g.NavWindow; + ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); + if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n"); + float pad = window->CalcFontSize() * 0.5f; + window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); + window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel); + g.NavId = g.NavFocusScopeId = 0; + } + } + + ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); + g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); + g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y); + g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x); + g.NavScoringRect.Max.x = g.NavScoringRect.Min.x; + IM_ASSERT(!g.NavScoringRect.IsInverted()); + g.NavScoringCount = 0; +#if IMGUI_DEBUG_NAV_RECTS + if (g.NavWindow) + { + ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); + if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } + if (1) { ImU32 col = (!g.NavWindow->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 +} + +static void ImGui::NavUpdateInitResult() +{ + ImGuiContext& g = *GImGui; + if (!g.NavWindow) + return; + + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); + if (g.NavInitRequestFromMove) + SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); + else + SetNavID(g.NavInitResultId, g.NavLayer, 0); + g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; +} + +static void ImGui::NavUpdateMoveResult() +{ + ImGuiContext& g = *GImGui; + if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) + { + if (g.NavId != 0) + { + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + } + return; + } + + ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + + if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) + if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) + result = &g.NavMoveResultLocalVisibleSet; + + 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); + + if (g.NavLayer == ImGuiNavLayer_Main) + { + ImVec2 delta_scroll; + if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge) + { + float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; + delta_scroll.y = result->Window->Scroll.y - scroll_target; + SetScrollY(result->Window, scroll_target); + } + else + { + ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos); + delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs); + } + + result->RectRel.TranslateX(-delta_scroll.x); + result->RectRel.TranslateY(-delta_scroll.y); + } + + ClearActiveID(); + g.NavWindow = result->Window; + if (g.NavId != result->ID) + { + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods; + } + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); + SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); +} + +static float ImGui::NavUpdatePageUpPageDown() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL) + return 0.0f; + if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main) + return 0.0f; + + ImGuiWindow* window = g.NavWindow; + const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); + const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); + const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); + const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); + if (page_up_held != page_down_held || home_pressed != end_pressed) + { + if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) + { + if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) + SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); + else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) + 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(io.KeyMap[ImGuiKey_PageUp], true)) + { + nav_scoring_rect_offset_y = -page_offset_y; + g.NavMoveDir = ImGuiDir_Down; + g.NavMoveClipDir = ImGuiDir_Up; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) + { + nav_scoring_rect_offset_y = +page_offset_y; + g.NavMoveDir = ImGuiDir_Up; + g.NavMoveClipDir = ImGuiDir_Down; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (home_pressed) + { + nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Down; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; + } + else if (end_pressed) + { + nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Up; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; + } + return nav_scoring_rect_offset_y; + } + } + return 0.0f; +} + +static void ImGui::NavEndFrame() +{ + ImGuiContext& g = *GImGui; + + if (g.NavWindowingTarget != NULL) + NavUpdateWindowingOverlay(); + + ImGuiWindow* window = g.NavWrapRequestWindow; + ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags; + if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main) + { + IM_ASSERT(move_flags != 0); + ImRect bb_rel = window->NavRectRel[0]; + + ImGuiDir clip_dir = g.NavMoveDir; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = + ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(-bb_rel.GetHeight()); + clip_dir = ImGuiDir_Up; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(+bb_rel.GetHeight()); + clip_dir = ImGuiDir_Down; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = + ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(-bb_rel.GetWidth()); + clip_dir = ImGuiDir_Left; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(+bb_rel.GetWidth()); + clip_dir = ImGuiDir_Right; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + } +} + +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--) + if (g.WindowsFocusOrder[i] == window) + return i; + return -1; +} + +static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) +{ + 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) + g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; + g.NavWindowingToggleLayer = false; +} + +static void ImGui::NavUpdateWindowing() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* apply_focus_window = NULL; + bool apply_toggle_layer = false; + + ImGuiWindow* modal_window = GetTopMostPopupModal(); + bool allow_windowing = (modal_window == NULL); + if (!allow_windowing) + g.NavWindowingTarget = NULL; + + if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + g.NavWindowingTargetAnim = NULL; + } + + bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); + bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_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.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; + } + + g.NavWindowingTimer += g.IO.DeltaTime; + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); + if (focus_change_dir != 0) + { + NavUpdateWindowingHighlightWindow(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } + + if (!IsNavInputDown(ImGuiNavInput_Menu)) + { + g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); + if (g.NavWindowingToggleLayer && g.NavWindow) + apply_toggle_layer = true; + else if (!g.NavWindowingToggleLayer) + apply_focus_window = g.NavWindowingTarget; + g.NavWindowingTarget = NULL; + } + } + + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + if (IsKeyPressedMap(ImGuiKey_Tab, true)) + NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); + if (!g.IO.KeyCtrl) + apply_focus_window = g.NavWindowingTarget; + } + + if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) + g.NavWindowingToggleLayer = true; + if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) + if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) + apply_toggle_layer = true; + + if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) + { + ImVec2 move_delta; + if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_NavGamepad) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); + if (move_delta.x != 0.0f || move_delta.y != 0.0f) + { + const float NAV_MOVE_SPEED = 800.0f; + const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow; + SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always); + MarkIniSettingsDirty(moving_window); + g.NavDisableMouseHover = true; + } + } + + if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) + { + ClearActiveID(); + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); + ClosePopupsOverWindow(apply_focus_window, false); + FocusWindow(apply_focus_window); + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); + + if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + } + if (apply_focus_window) + g.NavWindowingTarget = NULL; + + if (apply_toggle_layer && g.NavWindow) + { + ImGuiWindow* new_nav_window = g.NavWindow; + while (new_nav_window->ParentWindow + && (new_nav_window->DC.NavLayerActiveMask & (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; + } + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + + const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + NavRestoreLayer(new_nav_layer); + } +} + +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return "(Popup)"; + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return "(Main menu bar)"; + return "(Untitled)"; +} + +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"); + SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(g.IO.DisplaySize * 0.5f, 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]; + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); + } + End(); + PopStyleVar(); +} + + +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)); +} + +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + bool source_drag_active = false; + ImGuiID source_id = 0; + ImGuiID source_parent_id = 0; + ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; + if (!(flags & ImGuiDragDropFlags_SourceExtern)) + { + source_id = window->DC.LastItemId; + if (source_id != 0 && g.ActiveId != source_id) + return false; + if (g.IO.MouseDown[mouse_button] == false) + return false; + + if (source_id == 0) + { + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + + source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); + bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(source_id, window); + FocusWindow(window); + } + if (g.ActiveId == source_id) + g.ActiveIdAllowOverlap = is_hovered; + } + else + { + g.ActiveIdAllowOverlap = false; + } + if (g.ActiveId != source_id) + return false; + source_parent_id = window->IDStack.back(); + source_drag_active = IsMouseDragging(mouse_button); + + g.ActiveIdUsingNavDirMask = ~(ImU32)0; + g.ActiveIdUsingNavInputMask = ~(ImU32)0; + g.ActiveIdUsingKeyInputMask = ~(ImU64)0; + } + 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)) + { + BeginTooltip(); + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + { + ImGuiWindow* tooltip_window = g.CurrentWindow; + tooltip_window->SkipItems = true; + tooltip_window->HiddenFramesCanSkipItems = 1; + } + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + window->DC.LastItemStatusFlags &= ~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(); + + if (g.DragDropPayload.DataFrameCount == -1) + ClearDragDrop(); + g.DragDropWithinSource = false; +} + +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); + + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + { + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) + { + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy(payload.Data, data, data_size); + } + else if (data_size > 0) + { + 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 (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; +} + +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) + return false; + + const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; + ImGuiID id = window->DC.LastItemId; + if (id == 0) + id = window->GetIDFromRectangle(display_rect); + 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); + IM_ASSERT(payload.DataFrameCount != -1); + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + 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) + { + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + } + + payload.Preview = was_accepted_previously; + flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + { + r.Expand(3.5f); + bool push_clip_rect = !window->ClipRect.Contains(r); + if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1)); + window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); + if (push_clip_rect) window->DrawList->PopClipRect(); + } + + g.DragDropAcceptFrameCount = g.FrameCount; + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + return &payload; +} + +const ImGuiPayload* ImGui::GetDragDropPayload() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive ? &g.DragDropPayload : NULL; +} + +void ImGui::EndDragDropTarget() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinTarget); + g.DragDropWithinTarget = false; +} + +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + va_list args; + va_start(args, fmt); + 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); + } + va_end(args); +} + +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)); + + 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 (;;) + { + 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)); +} + +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; +} + +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 +} + +void ImGui::LogToFile(int auto_open_depth, const char* filename) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + + 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; +} + +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(); +} + +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(); + PushAllowKeyboardFocus(false); + SetNextItemWidth(80.0f); + SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); + PopAllowKeyboardFocus(); + PopID(); + + if (log_to_tty) + LogToTTY(); + if (log_to_file) + LogToFile(); + if (log_to_clipboard) + LogToClipboard(); +} + + +void ImGui::UpdateSettings() +{ + ImGuiContext& g = *GImGui; + if (!g.SettingsLoaded) + { + IM_ASSERT(g.SettingsWindows.empty()); + if (g.IO.IniFilename) + LoadIniSettingsFromDisk(g.IO.IniFilename); + g.SettingsLoaded = true; + } + + 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; + 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; +} + +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + +#if !IMGUI_DEBUG_INI_SETTINGS + if (const char* p = strstr(name, "###")) + name = p; +#endif + const size_t name_len = strlen(name); + + 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); + + return settings; +} + +ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +{ + if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) + return settings; + return CreateNewWindowSettings(name); +} + +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; +} + +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; + LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); + IM_FREE(file_data); +} + +void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + 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; + + 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) + { + 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] == ']') + { + 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; + name_start++; + 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) + { + entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); + } + } + g.SettingsLoaded = true; + + memcpy(buf, ini_data, ini_size); + + 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); +} + +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(); +} + +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) +{ + ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); + ImGuiID id = settings->ID; + *settings = ImGuiWindowSettings(); + 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); } +} + +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) +{ + 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 = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); + if (!settings) + { + settings = ImGui::CreateNewWindowSettings(window->Name); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + } + IM_ASSERT(settings->ID == window->ID); + settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y); + settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y); + settings->Collapsed = window->Collapsed; + } + + buf->reserve(buf->size() + g.SettingsWindows.size() * 6); + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + { + 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"); + } +} + + + + +#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 + +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + 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 +static PasteboardRef main_clipboard = 0; + +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*) +{ + 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) + { + ImGuiContext& g = *GImGui; + 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 + +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + ImGuiContext& g = *GImGui; + 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 + +#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) + +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif + +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +{ + ImGuiIO& io = ImGui::GetIO(); + if (HWND hwnd = (HWND)io.ImeWindowHandle) + if (HIMC himc = ::ImmGetContext(hwnd)) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = x; + cf.ptCurrentPos.y = y; + cf.dwStyle = CFS_FORCE_POSITION; + ::ImmSetCompositionWindow(himc, &cf); + ::ImmReleaseContext(hwnd, himc); + } +} + +#else + +static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} + +#endif + +#ifndef IMGUI_DISABLE_METRICS_WINDOW + +static void MetricsHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +void ImGui::ShowMetricsWindow(bool* p_open) +{ + if (!Begin("Dear ImGui Metrics/Debugger", p_open)) + { + End(); + return; + } + + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + + Text("Dear ImGui %s", ImGui::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 active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); + Text("%d active allocations", io.MetricsActiveAllocations); + Separator(); + + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; + 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 }; + 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) + { + 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->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->LastFirstRowHeight); } + 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->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->LastFirstRowHeight); } + else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table->LastFirstRowHeight, 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(); + } + }; + + if (TreeNode("Tools")) + { + if (Button("Item Picker..")) + 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."); + + 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 ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh); + Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes); + + 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.GetSize(); table_n++) + { + ImGuiTable* table = g.Tables.GetByIndex(table_n); + if (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(); + } + } + + TreePop(); + } + + DebugNodeWindowsList(&g.Windows, "Windows"); + if (TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) + { + for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) + DebugNodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); + TreePop(); + } + + if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) + { + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + ImGuiWindow* window = g.OpenPopupStack[i].Window; + BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); + } + TreePop(); + } + + if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize())) + { + for (int n = 0; n < g.TabBars.GetSize(); n++) + DebugNodeTabBar(g.TabBars.GetByIndex(n), "TabBar"); + TreePop(); + } + +#ifdef IMGUI_HAS_TABLE + if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize())) + { + for (int n = 0; n < g.Tables.GetSize(); n++) + DebugNodeTable(g.Tables.GetByIndex(n)); + TreePop(); + } +#endif + +#ifdef IMGUI_HAS_DOCK + if (TreeNode("Docking")) + { + TreePop(); + } +#endif + + 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(""); + 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(); + } + +#ifdef IMGUI_HAS_TABLE + 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(); + } +#endif + +#ifdef IMGUI_HAS_DOCK +#endif + + 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("Internal state")) + { + const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); + + Text("WINDOWING"); + Indent(); + Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); + Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->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, input_source_names[g.ActiveIdSource]); + Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); + Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); + Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); + Unindent(); + + Text("NAV,FOCUS"); + Indent(); + Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); + Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); + Text("NavInputSource: %s", input_source_names[g.NavInputSource]); + Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); + Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); + 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(); + } + + 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); + } + } + } + +#ifdef IMGUI_HAS_TABLE + if (cfg->ShowTablesRects) + { + for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++) + { + ImGuiTable* table = g.Tables.GetByIndex(table_n); + if (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)); + } + } + } +#endif + +#ifdef IMGUI_HAS_DOCK + if (show_docking_nodes && g.IO.KeyCtrl) + { + } +#endif + + End(); +} + +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(); +} + +void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label) +{ + ImGuiContext& g = *GImGui; + 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"); + if (node_open) + TreePop(); + return; + } + + ImDrawList* fg_draw_list = GetForegroundDrawList(window); + if (window && IsItemHovered()) + 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(window, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes); + if (!pcmd_node_open) + continue; + + 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]); + } + + 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(window, draw_list, pcmd, true, false); + + ImGuiListClipper clipper; + clipper.Begin(pcmd->ElemCount / 3); + 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; + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); + fg_draw_list->Flags = backup_flags; + } + } + TreePop(); + } + TreePop(); +} + +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb) +{ + IM_ASSERT(show_mesh || show_aabb); + ImDrawList* fg_draw_list = GetForegroundDrawList(window); + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset; + + ImRect clip_rect = draw_cmd->ClipRect; + ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; + for (unsigned int idx_n = draw_cmd->IdxOffset; idx_n < draw_cmd->IdxOffset + draw_cmd->ElemCount; ) + { + 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) + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); + } + if (show_aabb) + { + fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); + fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); + } + fg_draw_list->Flags = backup_flags; +} + +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); + } + TreePop(); +} + +void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) +{ + 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*"); + IM_UNUSED(p); + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(tab_bar, "%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++) + { + const 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: %.1f, Width: %.1f/%.1f", + tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth); + PopID(); + } + 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->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); + BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); + BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); + if (!window->NavRectRel[0].IsInverted()) + BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); + else + BulletText("NavRectRel[0]: "); + 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) +{ + 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); +} + + +void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) +{ + if (!TreeNode(label, "%s (%d)", label, windows->Size)) + return; + Text("(In front-to-back order:)"); + for (int i = windows->Size - 1; i >= 0; i--) + { + PushID((*windows)[i]); + DebugNodeWindow((*windows)[i], "Window"); + PopID(); + } + TreePop(); +} + +#else + +void ImGui::ShowMetricsWindow(bool*) {} +void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} +void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {} +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} +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*) {} + +#endif + +#ifdef IMGUI_INCLUDE_IMGUI_USER_INL +#include "imgui_user.inl" +#endif + +#endif + +``` + +`SpyCustom/imgui/imgui.h`: + +```h +#pragma once + +#ifdef IMGUI_USER_CONFIG +#include IMGUI_USER_CONFIG +#endif +#if !defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H) +#include "imconfig.h" +#endif + +#ifndef IMGUI_DISABLE + +#include +#include +#include +#include + +#include +#include + +#define IMGUI_VERSION "1.81 WIP" +#define IMGUI_VERSION_NUM 18003 +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) +#define IMGUI_HAS_TABLE + +#ifndef IMGUI_API +#define IMGUI_API +#endif +#ifndef IMGUI_IMPL_API +#define IMGUI_IMPL_API IMGUI_API +#endif + +#ifndef IM_ASSERT +#include +#define IM_ASSERT(_EXPR) assert(_EXPR) +#endif +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) +#define IM_UNUSED(_VAR) ((void)(_VAR)) +#if (__cplusplus >= 201100) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201100) +#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) +#else +#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) +#endif + +#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__clang__) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#elif !defined(IMGUI_USE_STB_SPRINTF) && defined(__GNUC__) && defined(__MINGW32__) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +struct ImDrawChannel; +struct ImDrawCmd; +struct ImDrawData; +struct ImDrawList; +struct ImDrawListSharedData; +struct ImDrawListSplitter; +struct ImDrawVert; +struct ImFont; +struct ImFontAtlas; +struct ImFontBuilderIO; +struct ImFontConfig; +struct ImFontGlyph; +struct ImFontGlyphRangesBuilder; +struct ImColor; +struct ImGuiContext; +struct ImGuiIO; +struct ImGuiInputTextCallbackData; +struct ImGuiListClipper; +struct ImGuiOnceUponAFrame; +struct ImGuiPayload; +struct ImGuiSizeCallbackData; +struct ImGuiStorage; +struct ImGuiStyle; +struct ImGuiTableSortSpecs; +struct ImGuiTableColumnSortSpecs; +struct ImGuiTextBuffer; +struct ImGuiTextFilter; + +typedef int ImGuiCol; +typedef int ImGuiCond; +typedef int ImGuiDataType; +typedef int ImGuiDir; +typedef int ImGuiKey; +typedef int ImGuiNavInput; +typedef int ImGuiMouseButton; +typedef int ImGuiMouseCursor; +typedef int ImGuiSortDirection; +typedef int ImGuiStyleVar; +typedef int ImGuiTableBgTarget; +typedef int ImDrawCornerFlags; +typedef int ImDrawListFlags; +typedef int ImFontAtlasFlags; +typedef int ImGuiBackendFlags; +typedef int ImGuiButtonFlags; +typedef int ImGuiColorEditFlags; +typedef int ImGuiConfigFlags; +typedef int ImGuiComboFlags; +typedef int ImGuiDragDropFlags; +typedef int ImGuiFocusedFlags; +typedef int ImGuiHoveredFlags; +typedef int ImGuiInputTextFlags; +typedef int ImGuiKeyModFlags; +typedef int ImGuiPopupFlags; +typedef int ImGuiSelectableFlags; +typedef int ImGuiSliderFlags; +typedef int ImGuiTabBarFlags; +typedef int ImGuiTabItemFlags; +typedef int ImGuiTableFlags; +typedef int ImGuiTableColumnFlags; +typedef int ImGuiTableRowFlags; +typedef int ImGuiTreeNodeFlags; +typedef int ImGuiWindowFlags; + +#ifndef ImTextureID +typedef void* ImTextureID; +#endif +typedef unsigned int ImGuiID; +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); + +typedef unsigned short ImWchar16; +typedef unsigned int ImWchar32; +#ifdef IMGUI_USE_WCHAR32 +typedef ImWchar32 ImWchar; +#else +typedef ImWchar16 ImWchar; +#endif + +typedef signed char ImS8; +typedef unsigned char ImU8; +typedef signed short ImS16; +typedef unsigned short ImU16; +typedef signed int ImS32; +typedef unsigned int ImU32; +#if defined(_MSC_VER) && !defined(__clang__) +typedef signed __int64 ImS64; +typedef unsigned __int64 ImU64; +#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) +#include +typedef int64_t ImS64; +typedef uint64_t ImU64; +#else +typedef signed long long ImS64; +typedef unsigned long long ImU64; +#endif + +struct ImVec2 +{ + float x, y; + ImVec2() { x = y = 0.0f; } + ImVec2(float _x, float _y) { x = _x; y = _y; } + float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } + float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } +#ifdef IM_VEC2_CLASS_EXTRA + IM_VEC2_CLASS_EXTRA +#endif +}; + +struct ImVec4 +{ + float x, y, z, w; + ImVec4() { x = y = z = w = 0.0f; } + 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 +#endif +}; + +namespace ImGui +{ + IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); + IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); + IMGUI_API ImGuiContext* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiContext* ctx); + + IMGUI_API ImGuiIO& GetIO(); + IMGUI_API ImGuiStyle& GetStyle(); + IMGUI_API void NewFrame(); + IMGUI_API void EndFrame(); + IMGUI_API void Render(); + IMGUI_API ImDrawData* GetDrawData(); + + IMGUI_API void ShowDemoWindow(bool* p_open = NULL); + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); + IMGUI_API void ShowAboutWindow(bool* p_open = NULL); + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); + IMGUI_API bool ShowStyleSelector(const char* label); + IMGUI_API void ShowFontSelector(const char* label); + IMGUI_API void ShowUserGuide(); + IMGUI_API const char* GetVersion(); + + IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); + IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); + IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); + + IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void End(); + + 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(); + + IMGUI_API bool IsWindowAppearing(); + IMGUI_API bool IsWindowCollapsed(); + IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); + IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); + IMGUI_API ImDrawList* GetWindowDrawList(); + IMGUI_API ImVec2 GetWindowPos(); + IMGUI_API ImVec2 GetWindowSize(); + IMGUI_API float GetWindowWidth(); + IMGUI_API float GetWindowHeight(); + + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); + IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); + IMGUI_API void SetNextWindowContentSize(const ImVec2& size); + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); + IMGUI_API void SetNextWindowFocus(); + IMGUI_API void SetNextWindowBgAlpha(float alpha); + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); + IMGUI_API void SetWindowFocus(); + IMGUI_API void SetWindowFontScale(float scale); + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); + IMGUI_API void SetWindowFocus(const char* name); + + IMGUI_API ImVec2 GetContentRegionAvail(); + IMGUI_API ImVec2 GetContentRegionMax(); + IMGUI_API ImVec2 GetWindowContentRegionMin(); + IMGUI_API ImVec2 GetWindowContentRegionMax(); + IMGUI_API float GetWindowContentRegionWidth(); + + IMGUI_API float GetScrollX(); + IMGUI_API float GetScrollY(); + IMGUI_API void SetScrollX(float scroll_x); + IMGUI_API void SetScrollY(float scroll_y); + IMGUI_API float GetScrollMaxX(); + IMGUI_API float GetScrollMaxY(); + IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); + IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); + IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); + IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); + + IMGUI_API void PushFont(ImFont* font); + IMGUI_API void PopFont(); + IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); + IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); + IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); + IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); + IMGUI_API void PopAllowKeyboardFocus(); + IMGUI_API void PushButtonRepeat(bool repeat); + IMGUI_API void PopButtonRepeat(); + + IMGUI_API void PushItemWidth(float item_width); + IMGUI_API void PopItemWidth(); + IMGUI_API void SetNextItemWidth(float item_width); + IMGUI_API float CalcItemWidth(); + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); + IMGUI_API void PopTextWrapPos(); + + IMGUI_API ImFont* GetFont(); + IMGUI_API float GetFontSize(); + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); + IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); + IMGUI_API ImU32 GetColorU32(const ImVec4& col); + IMGUI_API ImU32 GetColorU32(ImU32 col); + IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); + + IMGUI_API void Separator(); + IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); + IMGUI_API void NewLine(); + IMGUI_API void Spacing(); + IMGUI_API void Dummy(const ImVec2& size); + IMGUI_API void Indent(float indent_w = 0.0f); + IMGUI_API void Unindent(float indent_w = 0.0f); + IMGUI_API void BeginGroup(); + IMGUI_API void EndGroup(); + IMGUI_API ImVec2 GetCursorPos(); + IMGUI_API float GetCursorPosX(); + IMGUI_API float GetCursorPosY(); + IMGUI_API void SetCursorPos(const ImVec2& local_pos); + IMGUI_API void SetCursorPosX(float local_x); + IMGUI_API void SetCursorPosY(float local_y); + IMGUI_API ImVec2 GetCursorStartPos(); + IMGUI_API ImVec2 GetCursorScreenPos(); + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); + IMGUI_API void AlignTextToFramePadding(); + IMGUI_API float GetTextLineHeight(); + IMGUI_API float GetTextLineHeightWithSpacing(); + IMGUI_API float GetFrameHeight(); + IMGUI_API float GetFrameHeightWithSpacing(); + + IMGUI_API void PushID(const char* str_id); + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); + IMGUI_API void PushID(const void* ptr_id); + IMGUI_API void PushID(int int_id); + IMGUI_API void PopID(); + IMGUI_API ImGuiID GetID(const char* str_id); + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); + IMGUI_API ImGuiID GetID(const void* ptr_id); + + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); + IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); + 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); + 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); + IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); + 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); + 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); + IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); + IMGUI_API bool SmallButton(const char* label); + IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); + IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); + 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(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)); + 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); + IMGUI_API bool RadioButton(const char* label, int* v, int v_button); + IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); + IMGUI_API void Bullet(); + + IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); + IMGUI_API void EndCombo(); + 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); + 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); + + 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); + 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); + 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, 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, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + 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); + + IMGUI_API bool TextInputComboBox(const char* id, char* buffer, size_t maxInputSize, const char* items[], size_t item_len, short showMaxItems); + IMGUI_API bool TextInputComboBox(const char* id, char* buffer, size_t maxInputSize, std::vector items, short showMaxItems); + 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); + + IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 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, ImVec2 size = ImVec2(0, 0)); + IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); + + IMGUI_API bool TreeNode(const char* label); + IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); + 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); + IMGUI_API void TreePush(const void* ptr_id = NULL); + IMGUI_API void TreePop(); + IMGUI_API float GetTreeNodeToLabelSpacing(); + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); + IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); + IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); + + IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0), bool ncolorhovered = 0); + IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); + + IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); + IMGUI_API void EndListBox(); + 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); + + 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)); + + 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); + + IMGUI_API bool BeginMenuBar(); + IMGUI_API void EndMenuBar(); + IMGUI_API bool BeginMainMenuBar(); + IMGUI_API void EndMainMenuBar(); + IMGUI_API bool BeginMenu(const char* label, bool enabled = true); + IMGUI_API void EndMenu(); + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); + + IMGUI_API void BeginTooltip(); + IMGUI_API void EndTooltip(); + IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); + IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); + + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void EndPopup(); + IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); + IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); + IMGUI_API void CloseCurrentPopup(); + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); + IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); + + 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(); + IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); + IMGUI_API bool TableNextColumn(); + IMGUI_API bool TableSetColumnIndex(int column_n); + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImU32 user_id = 0); + IMGUI_API void TableSetupScrollFreeze(int cols, int rows); + IMGUI_API void TableHeadersRow(); + IMGUI_API void TableHeader(const char* label); + IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); + IMGUI_API int TableGetColumnCount(); + IMGUI_API int TableGetColumnIndex(); + IMGUI_API int TableGetRowIndex(); + IMGUI_API const char* TableGetColumnName(int column_n = -1); + IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); + IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); + + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); + IMGUI_API void NextColumn(); + IMGUI_API int GetColumnIndex(); + IMGUI_API float GetColumnWidth(int column_index = -1); + IMGUI_API void SetColumnWidth(int column_index, float width); + IMGUI_API float GetColumnOffset(int column_index = -1); + IMGUI_API void SetColumnOffset(int column_index, float offset_x); + IMGUI_API int GetColumnsCount(); + + IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); + IMGUI_API void EndTabBar(); + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); + IMGUI_API void EndTabItem(); + IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); + IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); + + IMGUI_API void LogToTTY(int auto_open_depth = -1); + IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); + IMGUI_API void LogToClipboard(int auto_open_depth = -1); + IMGUI_API void LogFinish(); + IMGUI_API void LogButtons(); + IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); + + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); + IMGUI_API void EndDragDropSource(); + IMGUI_API bool BeginDragDropTarget(); + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); + IMGUI_API void EndDragDropTarget(); + IMGUI_API const ImGuiPayload* GetDragDropPayload(); + + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); + IMGUI_API void PopClipRect(); + + IMGUI_API void SetItemDefaultFocus(); + IMGUI_API void SetKeyboardFocusHere(int offset = 0); + + IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); + IMGUI_API bool IsItemActive(); + IMGUI_API bool IsItemFocused(); + IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); + IMGUI_API bool IsItemVisible(); + IMGUI_API bool IsItemEdited(); + IMGUI_API bool IsItemActivated(); + IMGUI_API bool IsItemDeactivated(); + IMGUI_API bool IsItemDeactivatedAfterEdit(); + IMGUI_API bool IsItemToggledOpen(); + IMGUI_API bool IsAnyItemHovered(); + IMGUI_API bool IsAnyItemActive(); + IMGUI_API bool IsAnyItemFocused(); + IMGUI_API ImVec2 GetItemRectMin(); + IMGUI_API ImVec2 GetItemRectMax(); + IMGUI_API ImVec2 GetItemRectSize(); + IMGUI_API void SetItemAllowOverlap(); + + IMGUI_API bool IsRectVisible(const ImVec2& size); + IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); + IMGUI_API double GetTime(); + IMGUI_API int GetFrameCount(); + IMGUI_API ImDrawList* GetBackgroundDrawList(); + IMGUI_API ImDrawList* GetForegroundDrawList(); + IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); + IMGUI_API const char* GetStyleColorName(ImGuiCol idx); + IMGUI_API void SetStateStorage(ImGuiStorage* storage); + IMGUI_API ImGuiStorage* GetStateStorage(); + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); + IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); + IMGUI_API void EndChildFrame(); + + IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + + 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); + + IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); + IMGUI_API bool IsKeyDown(int user_key_index); + IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); + IMGUI_API bool IsKeyReleased(int user_key_index); + IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); + IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); + + IMGUI_API bool IsMouseDown(ImGuiMouseButton button); + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); + IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); + IMGUI_API bool IsAnyMouseDown(); + IMGUI_API ImVec2 GetMousePos(); + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); + IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); + IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); + IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); + IMGUI_API ImGuiMouseCursor GetMouseCursor(); + IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); + IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); + + IMGUI_API const char* GetClipboardText(); + IMGUI_API void SetClipboardText(const char* text); + + IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); + IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); + IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); + IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); + + 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); + + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); + IMGUI_API void* MemAlloc(size_t size); + IMGUI_API void MemFree(void* ptr); + +} + +enum ImGuiWindowFlags_ +{ + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, + ImGuiWindowFlags_NoResize = 1 << 1, + ImGuiWindowFlags_NoMove = 1 << 2, + ImGuiWindowFlags_NoScrollbar = 1 << 3, + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, + ImGuiWindowFlags_NoCollapse = 1 << 5, + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, + ImGuiWindowFlags_NoBackground = 1 << 7, + ImGuiWindowFlags_NoSavedSettings = 1 << 8, + ImGuiWindowFlags_NoMouseInputs = 1 << 9, + ImGuiWindowFlags_MenuBar = 1 << 10, + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, + ImGuiWindowFlags_NoNavInputs = 1 << 18, + ImGuiWindowFlags_NoNavFocus = 1 << 19, + ImGuiWindowFlags_UnsavedDocument = 1 << 20, + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + + ImGuiWindowFlags_NavFlattened = 1 << 23, + ImGuiWindowFlags_ChildWindow = 1 << 24, + ImGuiWindowFlags_Tooltip = 1 << 25, + ImGuiWindowFlags_Popup = 1 << 26, + ImGuiWindowFlags_Modal = 1 << 27, + ImGuiWindowFlags_ChildMenu = 1 << 28 + +}; + +enum ImGuiInputTextFlags_ +{ + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, + ImGuiInputTextFlags_CharsUppercase = 1 << 2, + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, + ImGuiInputTextFlags_CallbackHistory = 1 << 7, + ImGuiInputTextFlags_CallbackAlways = 1 << 8, + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, + ImGuiInputTextFlags_AllowTabInput = 1 << 10, + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, + ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, + ImGuiInputTextFlags_ReadOnly = 1 << 14, + ImGuiInputTextFlags_Password = 1 << 15, + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, + ImGuiInputTextFlags_CharsScientific = 1 << 17, + ImGuiInputTextFlags_CallbackResize = 1 << 18, + ImGuiInputTextFlags_CallbackEdit = 1 << 19, + ImGuiInputTextFlags_Multiline = 1 << 20, + ImGuiInputTextFlags_NoMarkEdited = 1 << 21 +}; + +enum ImGuiTreeNodeFlags_ +{ + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, + ImGuiTreeNodeFlags_Framed = 1 << 1, + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, + ImGuiTreeNodeFlags_Leaf = 1 << 8, + ImGuiTreeNodeFlags_Bullet = 1 << 9, + ImGuiTreeNodeFlags_FramePadding = 1 << 10, + ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, + ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog +}; + +enum ImGuiPopupFlags_ +{ + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, + ImGuiPopupFlags_MouseButtonRight = 1, + ImGuiPopupFlags_MouseButtonMiddle = 2, + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, + ImGuiPopupFlags_NoOpenOverItems = 1 << 6, + ImGuiPopupFlags_AnyPopupId = 1 << 7, + ImGuiPopupFlags_AnyPopupLevel = 1 << 8, + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel +}; + +enum ImGuiSelectableFlags_ +{ + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, + ImGuiSelectableFlags_Disabled = 1 << 3, + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 +}; + +enum ImGuiComboFlags_ +{ + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, + ImGuiComboFlags_HeightSmall = 1 << 1, + ImGuiComboFlags_HeightRegular = 1 << 2, + ImGuiComboFlags_HeightLarge = 1 << 3, + ImGuiComboFlags_HeightLargest = 1 << 4, + ImGuiComboFlags_NoArrowButton = 1 << 5, + ImGuiComboFlags_NoPreview = 1 << 6, + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest +}; + +enum ImGuiTabBarFlags_ +{ + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, + ImGuiTabBarFlags_NoTooltip = 1 << 5, + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}; + +enum ImGuiTabItemFlags_ +{ + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, + ImGuiTabItemFlags_SetSelected = 1 << 1, + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, + ImGuiTabItemFlags_NoPushId = 1 << 3, + ImGuiTabItemFlags_NoTooltip = 1 << 4, + ImGuiTabItemFlags_NoReorder = 1 << 5, + ImGuiTabItemFlags_Leading = 1 << 6, + ImGuiTabItemFlags_Trailing = 1 << 7 +}; + +enum ImGuiTableFlags_ +{ + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, + ImGuiTableFlags_Reorderable = 1 << 1, + ImGuiTableFlags_Hideable = 1 << 2, + ImGuiTableFlags_Sortable = 1 << 3, + ImGuiTableFlags_NoSavedSettings = 1 << 4, + ImGuiTableFlags_ContextMenuInBody = 1 << 5, + ImGuiTableFlags_RowBg = 1 << 6, + ImGuiTableFlags_BordersInnerH = 1 << 7, + ImGuiTableFlags_BordersOuterH = 1 << 8, + ImGuiTableFlags_BordersInnerV = 1 << 9, + ImGuiTableFlags_BordersOuterV = 1 << 10, + ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, + ImGuiTableFlags_NoBordersInBody = 1 << 11, + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, + ImGuiTableFlags_SizingFixedFit = 1 << 13, + ImGuiTableFlags_SizingFixedSame = 2 << 13, + ImGuiTableFlags_SizingStretchProp = 3 << 13, + ImGuiTableFlags_SizingStretchSame = 4 << 13, + ImGuiTableFlags_NoHostExtendX = 1 << 16, + ImGuiTableFlags_NoHostExtendY = 1 << 17, + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, + ImGuiTableFlags_PreciseWidths = 1 << 19, + ImGuiTableFlags_NoClip = 1 << 20, + ImGuiTableFlags_PadOuterX = 1 << 21, + ImGuiTableFlags_NoPadOuterX = 1 << 22, + ImGuiTableFlags_NoPadInnerX = 1 << 23, + ImGuiTableFlags_ScrollX = 1 << 24, + ImGuiTableFlags_ScrollY = 1 << 25, + ImGuiTableFlags_SortMulti = 1 << 26, + ImGuiTableFlags_SortTristate = 1 << 27, + + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +#endif +}; + +enum ImGuiTableColumnFlags_ +{ + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_DefaultHide = 1 << 0, + ImGuiTableColumnFlags_DefaultSort = 1 << 1, + ImGuiTableColumnFlags_WidthStretch = 1 << 2, + ImGuiTableColumnFlags_WidthFixed = 1 << 3, + ImGuiTableColumnFlags_NoResize = 1 << 4, + ImGuiTableColumnFlags_NoReorder = 1 << 5, + ImGuiTableColumnFlags_NoHide = 1 << 6, + ImGuiTableColumnFlags_NoClip = 1 << 7, + ImGuiTableColumnFlags_NoSort = 1 << 8, + ImGuiTableColumnFlags_NoSortAscending = 1 << 9, + ImGuiTableColumnFlags_NoSortDescending = 1 << 10, + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 11, + ImGuiTableColumnFlags_PreferSortAscending = 1 << 12, + ImGuiTableColumnFlags_PreferSortDescending = 1 << 13, + ImGuiTableColumnFlags_IndentEnable = 1 << 14, + ImGuiTableColumnFlags_IndentDisable = 1 << 15, + + ImGuiTableColumnFlags_IsEnabled = 1 << 20, + ImGuiTableColumnFlags_IsVisible = 1 << 21, + ImGuiTableColumnFlags_IsSorted = 1 << 22, + ImGuiTableColumnFlags_IsHovered = 1 << 23, + + 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 + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +#endif +}; + +enum ImGuiTableRowFlags_ +{ + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0 +}; + +enum ImGuiTableBgTarget_ +{ + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, + ImGuiTableBgTarget_RowBg1 = 2, + ImGuiTableBgTarget_CellBg = 3 +}; + +enum ImGuiFocusedFlags_ +{ + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, + ImGuiFocusedFlags_RootWindow = 1 << 1, + ImGuiFocusedFlags_AnyWindow = 1 << 2, + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows +}; + +enum ImGuiHoveredFlags_ +{ + ImGuiHoveredFlags_None = 0, + ImGuiHoveredFlags_ChildWindows = 1 << 0, + ImGuiHoveredFlags_RootWindow = 1 << 1, + ImGuiHoveredFlags_AnyWindow = 1 << 2, + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows +}; + +enum ImGuiDragDropFlags_ +{ + ImGuiDragDropFlags_None = 0, + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, + ImGuiDragDropFlags_SourceExtern = 1 << 4, + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect +}; + +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" + +enum ImGuiDataType_ +{ + ImGuiDataType_S8, + ImGuiDataType_U8, + ImGuiDataType_S16, + ImGuiDataType_U16, + ImGuiDataType_S32, + ImGuiDataType_U32, + ImGuiDataType_S64, + ImGuiDataType_U64, + ImGuiDataType_Float, + ImGuiDataType_Double, + ImGuiDataType_COUNT +}; + +enum ImGuiDir_ +{ + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}; + +enum ImGuiSortDirection_ +{ + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, + ImGuiSortDirection_Descending = 2 +}; + +enum ImGuiKey_ +{ + ImGuiKey_Tab, + 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_KeyPadEnter, + ImGuiKey_A, + ImGuiKey_C, + ImGuiKey_V, + ImGuiKey_X, + ImGuiKey_Y, + ImGuiKey_Z, + ImGuiKey_COUNT +}; + +enum ImGuiKeyModFlags_ +{ + ImGuiKeyModFlags_None = 0, + ImGuiKeyModFlags_Ctrl = 1 << 0, + ImGuiKeyModFlags_Shift = 1 << 1, + ImGuiKeyModFlags_Alt = 1 << 2, + ImGuiKeyModFlags_Super = 1 << 3 +}; + +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_KeyMenu_, + ImGuiNavInput_KeyLeft_, + ImGuiNavInput_KeyRight_, + ImGuiNavInput_KeyUp_, + ImGuiNavInput_KeyDown_, + ImGuiNavInput_COUNT, + ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_ +}; + +enum ImGuiConfigFlags_ +{ + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, + ImGuiConfigFlags_NoMouse = 1 << 4, + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, + + ImGuiConfigFlags_IsSRGB = 1 << 20, + ImGuiConfigFlags_IsTouchScreen = 1 << 21 +}; + +enum ImGuiBackendFlags_ +{ + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, + ImGuiBackendFlags_HasMouseCursors = 1 << 1, + ImGuiBackendFlags_HasSetMousePos = 1 << 2, + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 +}; + +enum ImGuiCol_ +{ + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, + ImGuiCol_ChildBg, + ImGuiCol_PopupBg, + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, + 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, + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TableHeaderBg, + ImGuiCol_TableBorderStrong, + ImGuiCol_TableBorderLight, + ImGuiCol_TableRowBg, + ImGuiCol_TableRowBgAlt, + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, + ImGuiCol_NavWindowingHighlight, + ImGuiCol_NavWindowingDimBg, + ImGuiCol_ModalWindowDimBg, + ImGuiCol_COUNT +}; + +enum ImGuiStyleVar_ +{ + ImGuiStyleVar_Alpha, + ImGuiStyleVar_WindowPadding, + ImGuiStyleVar_WindowRounding, + ImGuiStyleVar_WindowBorderSize, + ImGuiStyleVar_WindowMinSize, + ImGuiStyleVar_WindowTitleAlign, + ImGuiStyleVar_ChildRounding, + ImGuiStyleVar_ChildBorderSize, + ImGuiStyleVar_PopupRounding, + ImGuiStyleVar_PopupBorderSize, + ImGuiStyleVar_FramePadding, + ImGuiStyleVar_FrameRounding, + ImGuiStyleVar_FrameBorderSize, + ImGuiStyleVar_ItemSpacing, + ImGuiStyleVar_ItemInnerSpacing, + ImGuiStyleVar_IndentSpacing, + ImGuiStyleVar_CellPadding, + ImGuiStyleVar_ScrollbarSize, + ImGuiStyleVar_ScrollbarRounding, + ImGuiStyleVar_GrabMinSize, + ImGuiStyleVar_GrabRounding, + ImGuiStyleVar_TabRounding, + ImGuiStyleVar_ButtonTextAlign, + ImGuiStyleVar_SelectableTextAlign, + ImGuiStyleVar_COUNT +}; + +enum ImGuiButtonFlags_ +{ + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, + ImGuiButtonFlags_MouseButtonRight = 1 << 1, + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, + + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft +}; + +enum ImGuiColorEditFlags_ +{ + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, + ImGuiColorEditFlags_NoPicker = 1 << 2, + ImGuiColorEditFlags_NoOptions = 1 << 3, + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, + ImGuiColorEditFlags_NoInputs = 1 << 5, + ImGuiColorEditFlags_NoTooltip = 1 << 6, + ImGuiColorEditFlags_NoLabel = 1 << 7, + ImGuiColorEditFlags_NoSidePreview = 1 << 8, + ImGuiColorEditFlags_NoDragDrop = 1 << 9, + ImGuiColorEditFlags_NoBorder = 1 << 10, + + ImGuiColorEditFlags_AlphaBar = 1 << 16, + ImGuiColorEditFlags_AlphaPreview = 1 << 17, + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, + ImGuiColorEditFlags_HDR = 1 << 19, + ImGuiColorEditFlags_DisplayRGB = 1 << 20, + ImGuiColorEditFlags_DisplayHSV = 1 << 21, + ImGuiColorEditFlags_DisplayHex = 1 << 22, + ImGuiColorEditFlags_Uint8 = 1 << 23, + ImGuiColorEditFlags_Float = 1 << 24, + ImGuiColorEditFlags_PickerHueBar = 1 << 25, + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, + ImGuiColorEditFlags_InputRGB = 1 << 27, + ImGuiColorEditFlags_InputHSV = 1 << 28, + + ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, + + 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 + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex +#endif +}; + +enum ImGuiSliderFlags_ +{ + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, + ImGuiSliderFlags_Logarithmic = 1 << 5, + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, + ImGuiSliderFlags_NoInput = 1 << 7, + ImGuiSliderFlags_InvalidMask_ = 0x7000000F + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp +#endif +}; + +enum ImGuiMouseButton_ +{ + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 +}; + +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, + ImGuiMouseCursor_ResizeAll, + ImGuiMouseCursor_ResizeNS, + ImGuiMouseCursor_ResizeEW, + ImGuiMouseCursor_ResizeNESW, + ImGuiMouseCursor_ResizeNWSE, + ImGuiMouseCursor_Hand, + ImGuiMouseCursor_NotAllowed, + ImGuiMouseCursor_COUNT +}; + +enum ImGuiCond_ +{ + ImGuiCond_None = 0, + ImGuiCond_Always = 1 << 0, + ImGuiCond_Once = 1 << 1, + ImGuiCond_FirstUseEver = 1 << 2, + ImGuiCond_Appearing = 1 << 3 +}; + +struct ImNewWrapper {}; +inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewWrapper, void*) {} +#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); } } + +template +struct ImVector +{ + int Size; + int Capacity; + T* Data; + + typedef T value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + 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); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) IM_FREE(Data); } + + 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 void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } + 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; } + 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 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 - 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; } +}; + +struct ImGuiStyle +{ + float Alpha; + ImVec2 WindowPadding; + float WindowRounding; + float WindowBorderSize; + ImVec2 WindowMinSize; + ImVec2 WindowTitleAlign; + ImGuiDir WindowMenuButtonPosition; + float ChildRounding; + float ChildBorderSize; + float PopupRounding; + float PopupBorderSize; + ImVec2 FramePadding; + float FrameRounding; + float FrameBorderSize; + ImVec2 ItemSpacing; + ImVec2 ItemInnerSpacing; + ImVec2 CellPadding; + ImVec2 TouchExtraPadding; + float IndentSpacing; + float ColumnsMinSpacing; + float ScrollbarSize; + float ScrollbarRounding; + float GrabMinSize; + float GrabRounding; + float LogSliderDeadzone; + float TabRounding; + float TabBorderSize; + float TabMinWidthForCloseButton; + ImGuiDir ColorButtonPosition; + ImVec2 ButtonTextAlign; + ImVec2 SelectableTextAlign; + ImVec2 DisplayWindowPadding; + ImVec2 DisplaySafeAreaPadding; + float MouseCursorScale; + bool AntiAliasedLines; + bool AntiAliasedLinesUseTex; + bool AntiAliasedFill; + float CurveTessellationTol; + float CircleSegmentMaxError; + ImVec4 Colors[ImGuiCol_COUNT]; + + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); +}; + +struct ImGuiIO +{ + ImGuiConfigFlags ConfigFlags; + ImGuiBackendFlags BackendFlags; + ImVec2 DisplaySize; + float DeltaTime; + float IniSavingRate; + const char* IniFilename; + const char* LogFilename; + float MouseDoubleClickTime; + float MouseDoubleClickMaxDist; + float MouseDragThreshold; + int KeyMap[ImGuiKey_COUNT]; + float KeyRepeatDelay; + float KeyRepeatRate; + void* UserData; + + ImFontAtlas*Fonts; + float FontGlobalScale; + bool FontAllowUserScaling; + ImFont* FontDefault; + ImVec2 DisplayFramebufferScale; + + bool MouseDrawCursor; + bool ConfigMacOSXBehaviors; + bool ConfigInputTextCursorBlink; + bool ConfigDragClickToInputText; + bool ConfigWindowsResizeFromEdges; + bool ConfigWindowsMoveFromTitleBarOnly; + float ConfigMemoryCompactTimer; + + const char* BackendPlatformName; + const char* BackendRendererName; + void* BackendPlatformUserData; + void* BackendRendererUserData; + void* BackendLanguageUserData; + + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + + void (*ImeSetInputScreenPosFn)(int x, int y); + void* ImeWindowHandle; + + ImVec2 MousePos; + bool MouseDown[5]; + float MouseWheel; + float MouseWheelH; + bool KeyCtrl; + bool KeyShift; + bool KeyAlt; + bool KeySuper; + bool KeysDown[512]; + float NavInputs[ImGuiNavInput_COUNT]; + + IMGUI_API void AddInputCharacter(unsigned int c); + IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); + IMGUI_API void AddInputCharactersUTF8(const char* str); + IMGUI_API void ClearInputCharacters(); + + bool WantCaptureMouse; + bool WantCaptureKeyboard; + bool WantTextInput; + bool WantSetMousePos; + bool WantSaveIniSettings; + bool NavActive; + bool NavVisible; + float Framerate; + int MetricsRenderVertices; + int MetricsRenderIndices; + int MetricsRenderWindows; + int MetricsActiveWindows; + int MetricsActiveAllocations; + ImVec2 MouseDelta; + + ImGuiKeyModFlags KeyMods; + ImVec2 MousePosPrev; + ImVec2 MouseClickedPos[5]; + double MouseClickedTime[5]; + bool MouseClicked[5]; + bool MouseDoubleClicked[5]; + bool MouseReleased[5]; + bool MouseDownOwned[5]; + bool MouseDownWasDoubleClick[5]; + float MouseDownDuration[5]; + float MouseDownDurationPrev[5]; + ImVec2 MouseDragMaxDistanceAbs[5]; + float MouseDragMaxDistanceSqr[5]; + float KeysDownDuration[512]; + float KeysDownDurationPrev[512]; + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + float PenPressure; + ImWchar16 InputQueueSurrogate; + ImVector InputQueueCharacters; + + IMGUI_API ImGuiIO(); +}; + +struct ImGuiInputTextCallbackData +{ + ImGuiInputTextFlags EventFlag; + ImGuiInputTextFlags Flags; + void* UserData; + + ImWchar EventChar; + ImGuiKey EventKey; + char* Buf; + int BufTextLen; + int BufSize; + bool BufDirty; + int CursorPos; + int SelectionStart; + int SelectionEnd; + + 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; } +}; + +struct ImGuiSizeCallbackData +{ + void* UserData; + ImVec2 Pos; + ImVec2 CurrentSize; + ImVec2 DesiredSize; +}; + +struct ImGuiPayload +{ + void* Data; + int DataSize; + + ImGuiID SourceId; + ImGuiID SourceParentId; + int DataFrameCount; + char DataType[32 + 1]; + bool Preview; + bool Delivery; + + 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; } +}; + +struct ImGuiTableColumnSortSpecs +{ + ImGuiID ColumnUserID; + ImS16 ColumnIndex; + ImS16 SortOrder; + ImGuiSortDirection SortDirection : 8; + + ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +struct ImGuiTableSortSpecs +{ + const ImGuiTableColumnSortSpecs* Specs; + int SpecsCount; + bool SpecsDirty; + + ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); + static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + static inline void ListBoxFooter() { EndListBox(); } + static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } + 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); + 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); + static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } + 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); + 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); + static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } + static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } + static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } + static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } + static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } + static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } + static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } + static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } + static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } + static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } +} +#endif + +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD +#ifdef IMGUI_USE_WCHAR32 +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF +#else +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF +#endif + +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; } +}; + +struct ImGuiTextFilter +{ + IMGUI_API ImGuiTextFilter(const char* default_filter = ""); + IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); + 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(); } + + 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; +}; + +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; } + 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); +}; + +struct ImGuiStorage +{ + 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; + + 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; + IMGUI_API void SetVoidPtr(ImGuiID key, void* val); + + 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); + + IMGUI_API void SetAllInt(int val); + + IMGUI_API void BuildSortByKey(); +}; + +struct ImGuiListClipper +{ + int DisplayStart; + int DisplayEnd; + + int ItemsCount; + int StepNo; + int ItemsFrozen; + float ItemsHeight; + float StartPosY; + + IMGUI_API ImGuiListClipper(); + IMGUI_API ~ImGuiListClipper(); + + IMGUI_API void Begin(int items_count, float items_height = -1.0f); + IMGUI_API void End(); + IMGUI_API bool Step(); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } +#endif +}; + +#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 +#define IM_COL32(R,G,B,A) (((ImU32)(A)<> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } + ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } + ImColor(const ImVec4& col) { Value = col; } + inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } + inline operator ImVec4() const { return Value; } + + 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); } +}; + +#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) +#endif + +#ifndef ImDrawCallback +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +#endif + +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) + +struct ImDrawCmd +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; + unsigned int IdxOffset; + unsigned int ElemCount; + ImDrawCallback UserCallback; + void* UserCallbackData; + + ImDrawCmd() { memset(this, 0, sizeof(*this)); } +}; + +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; +#endif + +#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +#else +IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; +#endif + +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; + +struct ImDrawChannel +{ + ImVector _CmdBuffer; + ImVector _IdxBuffer; +}; + + +struct ImDrawListSplitter +{ + int _Current; + int _Count; + ImVector _Channels; + + inline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); } + inline ~ImDrawListSplitter() { ClearFreeMemory(); } + inline void Clear() { _Current = 0; _Count = 1; } + 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); +}; + +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_None = 0, + ImDrawCornerFlags_TopLeft = 1 << 0, + ImDrawCornerFlags_TopRight = 1 << 1, + ImDrawCornerFlags_BotLeft = 1 << 2, + ImDrawCornerFlags_BotRight = 1 << 3, + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, + ImDrawCornerFlags_All = 0xF +}; + +enum ImDrawListFlags_ +{ + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, + ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, + ImDrawListFlags_AntiAliasedFill = 1 << 2, + ImDrawListFlags_AllowVtxOffset = 1 << 3 +}; + +struct ImDrawList +{ + ImVector CmdBuffer; + ImVector IdxBuffer; + ImVector VtxBuffer; + ImDrawListFlags Flags; + + unsigned int _VtxCurrentIdx; + const ImDrawListSharedData* _Data; + const char* _OwnerName; + ImDrawVert* _VtxWritePtr; + ImDrawIdx* _IdxWritePtr; + ImVector _ClipRectStack; + ImVector _TextureIdStack; + ImVector _Path; + ImDrawCmdHeader _CmdHeader; + ImDrawListSplitter _Splitter; + float _FringeScale; + + ImDrawList(const ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } + + ~ImDrawList() { _ClearFreeMemory(); } + IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); + 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); } + + 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, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); + IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + 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, bool closed, 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); + IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); + + 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, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + + 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, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); + IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); + IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + + IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); + IMGUI_API void AddDrawCmd(); + IMGUI_API ImDrawList* CloneOutput() const; + + inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } + inline void ChannelsMerge() { _Splitter.Merge(this); } + inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } + + 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); + 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); } + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + 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); } + inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } +#endif + + IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _ClearFreeMemory(); + IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _OnChangedClipRect(); + IMGUI_API void _OnChangedTextureID(); + IMGUI_API void _OnChangedVtxOffset(); +}; + +struct ImDrawData +{ + bool Valid; + ImDrawList** CmdLists; + int CmdListsCount; + int TotalIdxCount; + int TotalVtxCount; + ImVec2 DisplayPos; + ImVec2 DisplaySize; + ImVec2 FramebufferScale; + + ImDrawData() { Valid = false; Clear(); } + ~ImDrawData() { Clear(); } + void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } + IMGUI_API void DeIndexAllBuffers(); + IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); +}; + +struct ImFontConfig +{ + void* FontData; + int FontDataSize; + bool FontDataOwnedByAtlas; + int FontNo; + float SizePixels; + int OversampleH; + int OversampleV; + bool PixelSnapH; + ImVec2 GlyphExtraSpacing; + ImVec2 GlyphOffset; + const ImWchar* GlyphRanges; + float GlyphMinAdvanceX; + float GlyphMaxAdvanceX; + bool MergeMode; + unsigned int FontBuilderFlags; + float RasterizerMultiply; + ImWchar EllipsisChar; + + char Name[40]; + ImFont* DstFont; + + IMGUI_API ImFontConfig(); +}; + +struct ImFontGlyph +{ + unsigned int Colored : 1; + unsigned int Visible : 1; + unsigned int Codepoint : 30; + float AdvanceX; + float X0, Y0, X1, Y1; + float U0, V0, U1, V1; +}; + +struct ImFontGlyphRangesBuilder +{ + ImVector UsedChars; + + 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; } + inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } + inline void AddChar(ImWchar c) { SetBit(c); } + IMGUI_API void AddText(const char* text, const char* text_end = NULL); + IMGUI_API void AddRanges(const ImWchar* ranges); + IMGUI_API void BuildRanges(ImVector* out_ranges); +}; + +struct ImFontAtlasCustomRect +{ + unsigned short Width, Height; + unsigned short X, Y; + unsigned int GlyphID; + float GlyphAdvanceX; + ImVec2 GlyphOffset; + ImFont* 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; } +}; + +enum ImFontAtlasFlags_ +{ + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, + ImFontAtlasFlags_NoMouseCursors = 1 << 1, + ImFontAtlasFlags_NoBakedLines = 1 << 2 +}; + +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); + 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); + IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); + IMGUI_API void ClearInputData(); + IMGUI_API void ClearTexData(); + IMGUI_API void ClearFonts(); + IMGUI_API void Clear(); + + IMGUI_API bool Build(); + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); + bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } + void SetTexID(ImTextureID id) { TexID = id; } + + IMGUI_API const ImWchar* GetGlyphRangesDefault(); + IMGUI_API const ImWchar* GetGlyphRangesKorean(); + IMGUI_API const ImWchar* GetGlyphRangesJapanese(); + IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); + IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon(); + IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); + IMGUI_API const ImWchar* GetGlyphRangesThai(); + IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); + + 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]; } + + 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]); + + bool Locked; + ImFontAtlasFlags Flags; + ImTextureID TexID; + int TexDesiredWidth; + int TexGlyphPadding; + + unsigned char* TexPixelsAlpha8; + unsigned int* TexPixelsRGBA32; + int TexWidth; + int TexHeight; + ImVec2 TexUvScale; + ImVec2 TexUvWhitePixel; + ImVector Fonts; + ImVector CustomRects; + ImVector ConfigData; + ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; + + const ImFontBuilderIO* FontBuilderIO; + unsigned int FontBuilderFlags; + + int PackIdMouseCursors; + int PackIdLines; + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontAtlasCustomRect CustomRect; + typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; +#endif +}; + +struct ImFont +{ + ImVector IndexAdvanceX; + float FallbackAdvanceX; + float FontSize; + + ImVector IndexLookup; + ImVector Glyphs; + const ImFontGlyph* FallbackGlyph; + + ImFontAtlas* ContainerAtlas; + const ImFontConfig* ConfigData; + short ConfigDataCount; + ImWchar FallbackChar; + ImWchar EllipsisChar; + bool DirtyLookupTables; + float Scale; + float Ascent, Descent; + int MetricsTotalSurface; + ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; + + 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 : ""; } + + 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; + 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, ImVec2 pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, 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; + + 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); + IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); + IMGUI_API void SetFallbackChar(ImWchar c); + IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); +}; + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef IMGUI_INCLUDE_IMGUI_USER_H +#include "imgui_user.h" +#endif + +#endif + +``` + +`SpyCustom/imgui/imgui_draw.cpp`: + +```cpp +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui_internal.h" +#ifdef IMGUI_ENABLE_FREETYPE +#include "misc/freetype/imgui_freetype.h" +#endif + +#include +#if !defined(alloca) +#if defined(__GLIBC__) || defined(__sun) || defined(__APPLE__) || defined(__NEWLIB__) +#include +#elif defined(_WIN32) +#include +#if !defined(alloca) +#define alloca _alloca +#endif +#else +#include +#endif +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4127) +#pragma warning (disable: 4505) +#pragma warning (disable: 4996) +#endif + +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#endif +#if __has_warning("-Walloca") +#pragma clang diagnostic ignored "-Walloca" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wglobal-constructors" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wcomma" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wdouble-promotion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wstack-protector" +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +#ifdef IMGUI_STB_NAMESPACE +namespace IMGUI_STB_NAMESPACE +{ +#endif + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4456) +#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" +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +#ifndef STB_RECT_PACK_IMPLEMENTATION +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +#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 +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +#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)ImFloorStd(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 + +#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 +} +using namespace IMGUI_STB_NAMESPACE; +#endif + +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); + colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); + 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); + colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); + 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); +} + +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); + colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); + 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); +} + +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)); + } +} + +void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) +{ + if (CircleSegmentMaxError == max_error) + return; + CircleSegmentMaxError = max_error; + for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) + { + const float radius = (float)i; + const int segment_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError); + CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255); + } +} + +void ImDrawList::_ResetForNewFrame() +{ + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + + 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; + 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); +} + +void ImDrawList::_PopUnusedDrawCmd() +{ + if (CmdBuffer.Size == 0) + return; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); +} + +void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) +{ + 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(); +} + +#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) + +void ImDrawList::_OnChangedClipRect() +{ + 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); + + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) + { + CmdBuffer.pop_back(); + return; + } + + curr_cmd->ClipRect = _CmdHeader.ClipRect; +} + +void ImDrawList::_OnChangedTextureID() +{ + 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); + + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) + { + CmdBuffer.pop_back(); + return; + } + + curr_cmd->TextureId = _CmdHeader.TextureId; +} + +void ImDrawList::_OnChangedVtxOffset() +{ + _VtxCurrentIdx = 0; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + curr_cmd->VtxOffset = _CmdHeader.VtxOffset; +} + +void ImDrawList::PushClipRect(ImVec2 cr_min, 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(); +} + +void ImDrawList::PrimReserve(int idx_count, int vtx_count) +{ + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) + { + _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; +} + +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); +} + +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; +} + +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) +#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } while (0) + +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) +{ + if (points_count < 2) + return; + + const ImVec2 opaque_uv = _Data->TexUvWhitePixel; + const int count = closed ? points_count : points_count - 1; + const bool thick_line = (thickness > _FringeScale); + + if (Flags & ImDrawListFlags_AntiAliasedLines) + { + const float AA_SIZE = _FringeScale; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + + thickness = ImMax(thickness, 1.0f); + const int integer_thickness = (int)thickness; + const float fractional_thickness = thickness - integer_thickness; + + const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); + + 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); + + ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((use_texture || !thick_line) ? 3 : 5) * sizeof(ImVec2)); + ImVec2* temp_points = temp_normals + points_count; + + 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 (use_texture || !thick_line) + { + const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; + + 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; + } + + unsigned int idx1 = _VtxCurrentIdx; + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; + const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); + + 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_y *= half_draw_size; + + 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) + { + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); + _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); + _IdxWritePtr += 6; + } + else + { + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); + _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; + } + + idx1 = idx2; + } + + if (use_texture) + { + ImVec4 tex_uvs = _Data->TexUvLines[integer_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; + _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; + _VtxWritePtr += 2; + } + } + else + { + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; + _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; + _VtxWritePtr += 3; + } + } + } + else + { + const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + + 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); + } + + unsigned int idx1 = _VtxCurrentIdx; + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); + const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); + + 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; + + 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; + + _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; + } + + 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 + { + const int idx_count = count * 6; + const int vtx_count = count * 4; + 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; + } + } +} + +void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +{ + if (points_count < 3) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + if (Flags & ImDrawListFlags_AntiAliasedFill) + { + 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); + + 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; + } + + ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); + 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++) + { + 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; + + _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; + _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; + _VtxWritePtr += 2; + + _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 + { + 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::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius == 0.0f || a_min_of_12 > a_max_of_12) + { + _Path.push_back(center); + return; + } + +#if IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER != 1 + a_min_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; + a_max_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; +#endif + + _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); + for (int a = a_min_of_12; a <= a_max_of_12; a++) + { + const ImVec2& c = _Data->ArcFastVtx[a % IM_ARRAYSIZE(_Data->ArcFastVtx)]; + _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius)); + } +} + +void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius == 0.0f) + { + _Path.push_back(center); + return; + } + + _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)); + } +} + +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); +} + +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) + { + PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); + } + 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) + { + PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0); + } + 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)); + } +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners) +{ + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); + + if (rounding <= 0.0f || rounding_corners == 0) + { + PathLineTo(a); + PathLineTo(ImVec2(b.x, a.y)); + PathLineTo(b); + PathLineTo(ImVec2(a.x, b.y)); + } + else + { + const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; + const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; + const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; + const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? 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, false, thickness); +} + +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, 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, rounding_corners); + else + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, rounding_corners); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (rounding > 0.0f) + { + PathRect(p_min, p_max, rounding, rounding_corners); + PathFillConvex(col); + } + else + { + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); + } +} + +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, true, 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, true, 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.0f) + return; + + if (num_segments <= 0) + { + const int radius_idx = (int)radius; + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + num_segments = _Data->CircleSegmentCounts[radius_idx]; + else + num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); + } + else + { + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + } + + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + if (num_segments == 12) + PathArcToFast(center, radius - 0.5f, 0, 12 - 1); + else + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) + return; + + if (num_segments <= 0) + { + const int radius_idx = (int)radius; + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + num_segments = _Data->CircleSegmentCounts[radius_idx]; + else + num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); + } + else + { + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + } + + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + if (num_segments == 12) + PathArcToFast(center, radius, 0, 12 - 1); + else + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + PathFillConvex(col); +} + +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; + + 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, true, thickness); +} + +void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + 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); +} + +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, false, thickness); +} + +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, false, 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; + + if (font == NULL) + font = _Data->Font; + if (font_size == 0.0f) + font_size = _Data->FontSize; + + IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); + + 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, ImDrawCornerFlags rounding_corners) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) + { + AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); + return; + } + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + int vert_start_idx = VtxBuffer.Size; + PathRect(p_min, p_max, rounding, rounding_corners); + 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(); +} + + +void ImDrawListSplitter::ClearFreeMemory() +{ + for (int i = 0; i < _Channels.Size; i++) + { + if (i == _Current) + memset(&_Channels[i], 0, sizeof(_Channels[i])); + _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); + _Channels.resize(channels_count); + } + _Count = channels_count; + + 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) +{ + if (_Count <= 1) + return; + + SetCurrentChannel(draw_list, 0); + draw_list->_PopUnusedDrawCmd(); + + 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.pop_back(); + + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) + { + ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; + if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) + { + last_cmd->ElemCount += next_cmd->ElemCount; + idx_offset += next_cmd->ElemCount; + ch._CmdBuffer.erase(ch._CmdBuffer.Data); + } + } + 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); + + 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; + + if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) + draw_list->AddDrawCmd(); + + ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); + 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; + + 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; + + 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); + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); +} + +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; + } +} + +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); + } + } +} + +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); + } +} + +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); + } +} + +ImFontConfig::ImFontConfig() +{ + memset(this, 0, sizeof(*this)); + FontDataOwnedByAtlas = true; + OversampleH = 3; + OversampleV = 1; + GlyphMaxAdvanceX = FLT_MAX; + RasterizerMultiply = 1.0f; + EllipsisChar = (ImWchar)-1; +} + +const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; +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 " + "..- -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 " + "XX - 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 -XX X.X - X.X XX- X..X..XXX " + "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 -XXX 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...XXXXXX.XXXXXX...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......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] = +{ + { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, + { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, + { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, + { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, + { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, +}; + +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; + } + + 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; +} + +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; +} + +void ImFontAtlas::ClearFonts() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < Fonts.Size; i++) + IM_DELETE(Fonts[i]); + Fonts.clear(); +} + +void ImFontAtlas::Clear() +{ + ClearInputData(); + ClearTexData(); + ClearFonts(); +} + +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + if (TexPixelsAlpha8 == NULL) + { + if (ConfigData.empty()) + AddFontDefault(); + 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) +{ + 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); + + if (!font_cfg->MergeMode) + Fonts.push_back(IM_NEW(ImFont)); + else + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first 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; + + ClearTexData(); + return new_font_cfg.DstFont; +} + +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); + src += 5; + dst += 4; + } +} + +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); + + 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') + { + 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); +} + +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; + 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; +} + +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; +} + +void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +{ + IM_ASSERT(TexWidth > 0 && TexHeight > 0); + IM_ASSERT(rect->IsPacked()); + *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()!"); + + 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); +#endif + } + + 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) +{ + unsigned char* data = pixels + x + y * stride; + for (int j = h; j > 0; j--, data += stride) + for (int i = 0; i < w; i++) + data[i] = table[data[i]]; +} + +#ifdef IMGUI_ENABLE_STB_TRUETYPE +struct ImFontBuildSrcData +{ + stbtt_fontinfo FontInfo; + stbtt_pack_range PackRange; + stbrp_rect* Rects; + stbtt_packedchar* PackedChars; + const ImWchar* SrcRanges; + int DstIndex; + int GlyphsHighest; + int GlyphsCount; + ImBitVector GlyphsSet; + ImVector GlyphsList; +}; + +struct ImFontBuildDstData +{ + int SrcCount; + int GlyphsHighest; + int GlyphsCount; + ImBitVector GlyphsSet; +}; + +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); + + 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(); + + 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()); + + 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)); + + 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); + return false; + } + 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; + + 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) + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); + } + + 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)) + continue; + if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) + continue; + + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint); + dst_tmp.GlyphsSet.SetBit(codepoint); + total_glyphs_count++; + } + } + + 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(); + + 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()); + + 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; + + 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; + + 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; + } + } + + 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; + + 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); + + 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); + + 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); + } + + 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; + + 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); + + 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; + } + + stbtt_PackEnd(&spc); + buf_rects.clear(); + + 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; + + 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++) + { + 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); + } + } + + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + src_tmp_array[src_i].~ImFontBuildSrcData(); + + ImFontAtlasBuildFinish(atlas); + return true; +} + +const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() +{ + static ImFontBuilderIO io; + io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype; + return &io; +} + +#endif + +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); + + 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 = pack_rects[i].x; + user_rects[i].Y = 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)) + { + 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 + { + 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; + + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); + IM_ASSERT(r->IsPacked()); + for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) + { + 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); + + IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); + 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_BLACK_TRANS; + + 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_BLACK_TRANS; + } + + 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; + atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); + } +} + +void ImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + 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); + } + + 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); + } +} + +void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); + ImFontAtlasBuildRenderDefaultTexData(atlas); + ImFontAtlasBuildRenderLinesTexData(atlas); + + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; + if (r->Font == NULL || r->GlyphID == 0) + continue; + + 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); + } + + for (int i = 0; i < atlas->Fonts.Size; i++) + if (atlas->Fonts[i]->DirtyLookupTables) + atlas->Fonts[i]->BuildLookupTable(); + + for (int i = 0; i < atlas->Fonts.size(); i++) + { + ImFont* font = atlas->Fonts[i]; + if (font->EllipsisChar != (ImWchar)-1) + continue; + const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++) + if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) + { + font->EllipsisChar = ellipsis_variants[j]; + break; + } + } +} + +const ImWchar* ImFontAtlas::GetGlyphRangesDefault() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesKorean() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, + 0x3131, 0x3163, + 0xAC00, 0xD7A3, + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, + 0x2000, 0x206F, + 0x3000, 0x30FF, + 0x31F0, 0x31FF, + 0xFF00, 0xFFEF, + 0x4e00, 0x9FAF, + 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; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +{ + 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[] = + { + 0x0020, 0x00FF, + 0x2000, 0x206F, + 0x3000, 0x30FF, + 0x31F0, 0x31FF, + 0xFF00, 0xFFEF + }; + 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() +{ + 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[] = + { + 0x0020, 0x00FF, + 0x3000, 0x30FF, + 0x31F0, 0x31FF, + 0xFF00, 0xFFEF + }; + 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, + 0x0400, 0x052F, + 0x2DE0, 0x2DFF, + 0xA640, 0xA69F, + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesThai() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, + 0x2010, 0x205E, + 0x0E00, 0x0E7F, + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, + 0x0102, 0x0103, + 0x0110, 0x0111, + 0x0128, 0x0129, + 0x0168, 0x0169, + 0x01A0, 0x01A1, + 0x01AF, 0x01B0, + 0x1EA0, 0x1EF9, + 0, + }; + return &ranges[0]; +} + +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 (ImWchar c = ranges[0]; c <= ranges[1]; c++) + AddChar(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); +} + +ImFont::ImFont() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + FallbackChar = (ImWchar)'?'; + EllipsisChar = (ImWchar)-1; + 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; +} + +void ImFont::BuildLookupTable() +{ + int max_codepoint = 0; + for (int i = 0; i != Glyphs.Size; i++) + max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + + IM_ASSERT(Glyphs.Size < 0xFFFF); + 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; + + const int page_n = codepoint / 4096; + Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + } + + if (FindGlyph((ImWchar)' ')) + { + if (Glyphs.back().Codepoint != '\t') + 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); + } + + SetGlyphVisible((ImWchar)' ', false); + SetGlyphVisible((ImWchar)'\t', false); + + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; + for (int i = 0; i < max_codepoint + 1; i++) + if (IndexAdvanceX[i] < 0.0f) + IndexAdvanceX[i] = FallbackAdvanceX; +} + +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::SetFallbackChar(ImWchar c) +{ + FallbackChar = c; + BuildLookupTable(); +} + +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); +} + +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) + { + 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; + } + + if (cfg->PixelSnapH) + advance_x = IM_ROUND(advance_x); + + 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; + + 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); + unsigned int index_size = (unsigned int)IndexLookup.Size; + + if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) + return; + if (src >= index_size && dst >= index_size) + 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]; +} + +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +{ + float line_width = 0.0f; + float word_width = 0.0f; + float blank_width = 0.0f; + wrap_width /= scale; + + const char* word_end = text; + const char* prev_word_end = NULL; + bool inside_word = true; + + const char* s = text; + 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 == 0) + break; + + 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; + } + + inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"'); + } + + if (line_width + word_width > wrap_width) + { + if (word_width < wrap_width) + s = prev_word_end ? prev_word_end : word_end; + break; + } + + s = next_s; + } + + 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); + + 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) + { + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); + if (word_wrap_eol == s) + word_wrap_eol++; + } + + 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; + + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + 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 == 0) + break; + } + + 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; +} + +void ImFont::RenderChar(ImDrawList* draw_list, float size, 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; + pos.x = IM_FLOOR(pos.x); + pos.y = IM_FLOOR(pos.y); + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); +} + +void ImFont::RenderText(ImDrawList* draw_list, float size, 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); + + pos.x = IM_FLOOR(pos.x); + pos.y = IM_FLOOR(pos.y); + float x = pos.x; + float y = pos.y; + if (y > clip_rect.w) + return; + + const float scale = size / FontSize; + const float line_height = FontSize * scale; + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + const char* s = text_begin; + if (y + line_height < clip_rect.y && !word_wrap_enabled) + while (y + line_height < clip_rect.y && s < text_end) + { + s = (const char*)memchr(s, '\n', text_end - s); + s = s ? s + 1 : text_end; + y += line_height; + } + + 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; + + 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_current_idx = draw_list->_VtxCurrentIdx; + + const ImU32 col_untinted = col | ~IM_COL32_A_MASK; + + while (s < text_end) + { + if (word_wrap_enabled) + { + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); + if (word_wrap_eol == s) + word_wrap_eol++; + } + + if (s >= word_wrap_eol) + { + x = pos.x; + y += line_height; + word_wrap_eol = NULL; + + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; + } + + if (c < 32) + { + if (c == '\n') + { + x = pos.x; + y += line_height; + if (y > clip_rect.w) + break; + continue; + } + if (c == '\r') + continue; + } + + const ImFontGlyph* glyph = FindGlyph((ImWchar)c); + if (glyph == NULL) + continue; + + float char_width = glyph->AdvanceX * scale; + if (glyph->Visible) + { + 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) + { + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + 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; + } + } + + ImU32 glyph_col = glyph->Colored ? col_untinted : col; + + { + idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); + idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); + 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; + vtx_write += 4; + vtx_current_idx += 4; + idx_write += 6; + } + } + } + x += char_width; + } + + draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); + 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_current_idx; +} + +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) +{ + 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, false, thickness); +} + +void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) +{ + if (mouse_cursor == ImGuiMouseCursor_None) + return; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + + ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; + ImVec2 offset, size, uv[4]; + if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + { + pos -= offset; + const 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(); + } +} + +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; + } +} + +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); +} + +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; + 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); + draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); + } + else + { + draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); + draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); + } + 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); + draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); + } + else + { + draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); + draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); + } + } + draw_list->PathFillConvex(col); +} + +void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, 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, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight); +} + +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) +{ + if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) + { + ImU32 col_bg1 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); + ImU32 col_bg2 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_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; + int rounding_corners_flags_cell = 0; + if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } + rounding_corners_flags_cell &= rounding_corners_flags; + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); + } + } + } + else + { + draw_list->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); + } +} + +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) +{ + 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) { + 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 stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } else { + 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 ) +{ + if (stb__in4(0) != 0x57bC0000) return 0; + if (stb__in4(4) != 0) return 0; + 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); + return 0; + } + } + IM_ASSERT(stb__dout <= output + olen); + if (stb__dout > output + olen) + return 0; + } +} + +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 + +``` + +`SpyCustom/imgui/imgui_impl_dx9.cpp`: + +```cpp +#include "imgui.h" +#include "imgui_impl_dx9.h" + +#include +#define DIRECTINPUT_VERSION 0x0800 +#include + +static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; +static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; +static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; +static LPDIRECT3DTEXTURE9 g_FontTexture = NULL; +static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000; + +struct CUSTOMVERTEX +{ + float pos[3]; + D3DCOLOR col; + float uv[2]; +}; +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) + +static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) +{ + 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; + g_pd3dDevice->SetViewport(&vp); + + g_pd3dDevice->SetPixelShader(NULL); + g_pd3dDevice->SetVertexShader(NULL); + g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + { + 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 + } } }; + g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); + g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); + g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); + } +} + +void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) +{ + if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) + return; + + if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) + { + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } + g_VertexBufferSize = draw_data->TotalVtxCount + 5000; + if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) + return; + } + if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) + { + if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } + g_IndexBufferSize = draw_data->TotalIdxCount + 10000; + if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &g_pIB, NULL) < 0) + return; + } + + IDirect3DStateBlock9* d3d9_state_block = NULL; + if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) + return; + + D3DMATRIX last_world, last_view, last_projection; + g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); + g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); + g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); + + CUSTOMVERTEX* vtx_dst; + ImDrawIdx* idx_dst; + if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) + return; + if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0) + return; + 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 = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000) >> 16) | ((vtx_src->col & 0xFF) << 16); + 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; + } + g_pVB->Unlock(); + g_pIB->Unlock(); + g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX)); + g_pd3dDevice->SetIndices(g_pIB); + g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); + + ImGui_ImplDX9_SetupRenderState(draw_data); + + 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 != NULL) + { + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplDX9_SetupRenderState(draw_data); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + const RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) }; + const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->TextureId; + g_pd3dDevice->SetTexture(0, texture); + g_pd3dDevice->SetScissorRect(&r); + g_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; + } + + g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world); + g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view); + g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection); + + d3d9_state_block->Apply(); + d3d9_state_block->Release(); +} + +bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) +{ + ImGuiIO& io = ImGui::GetIO(); + io.BackendRendererName = "imgui_impl_dx9"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; + + g_pd3dDevice = device; + g_pd3dDevice->AddRef(); + return true; +} + +void ImGui_ImplDX9_Shutdown() +{ + ImGui_ImplDX9_InvalidateDeviceObjects(); + if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } +} + +static bool ImGui_ImplDX9_CreateFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + unsigned char* pixels; + int width, height, bytes_per_pixel; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); + + g_FontTexture = NULL; + if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0) + return false; + D3DLOCKED_RECT tex_locked_rect; + if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) + return false; + for (int y = 0; y < height; y++) + memcpy((unsigned char*)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel)); + g_FontTexture->UnlockRect(0); + + io.Fonts->SetTexID((ImTextureID)g_FontTexture); + + return true; +} + +bool ImGui_ImplDX9_CreateDeviceObjects() +{ + if (!g_pd3dDevice) + return false; + if (!ImGui_ImplDX9_CreateFontsTexture()) + return false; + return true; +} + +void ImGui_ImplDX9_InvalidateDeviceObjects() +{ + if (!g_pd3dDevice) + return; + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } + if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } + if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } +} + +void ImGui_ImplDX9_NewFrame() +{ + if (!g_FontTexture) + ImGui_ImplDX9_CreateDeviceObjects(); +} + +``` + +`SpyCustom/imgui/imgui_impl_dx9.h`: + +```h +#pragma once +#include "imgui.h" + +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); + +IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects(); + +``` + +`SpyCustom/imgui/imgui_impl_win32.cpp`: + +```cpp +#include "imgui.h" +#include "imgui_impl_win32.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +#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 + +static HWND g_hWnd = NULL; +static INT64 g_Time = 0; +static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; +static bool g_HasGamepad = false; +static bool g_WantUpdateHasGamepad = true; + +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +static HMODULE g_XInputDLL = NULL; +static PFN_XInputGetCapabilities g_XInputGetCapabilities = NULL; +static PFN_XInputGetState g_XInputGetState = NULL; +#endif + +bool ImGui_ImplWin32_Init(void* hwnd) +{ + if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond)) + return false; + if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time)) + return false; + + g_hWnd = (HWND)hwnd; + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; + io.BackendPlatformName = "imgui_impl_win32"; + io.ImeWindowHandle = hwnd; + + io.KeyMap[ImGuiKey_Tab] = VK_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; + io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR; + io.KeyMap[ImGuiKey_PageDown] = VK_NEXT; + io.KeyMap[ImGuiKey_Home] = VK_HOME; + io.KeyMap[ImGuiKey_End] = VK_END; + io.KeyMap[ImGuiKey_Insert] = VK_INSERT; + io.KeyMap[ImGuiKey_Delete] = VK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = VK_BACK; + io.KeyMap[ImGuiKey_Space] = VK_SPACE; + io.KeyMap[ImGuiKey_Enter] = VK_RETURN; + io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; + io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN; + io.KeyMap[ImGuiKey_A] = 'A'; + io.KeyMap[ImGuiKey_C] = 'C'; + io.KeyMap[ImGuiKey_V] = 'V'; + io.KeyMap[ImGuiKey_X] = 'X'; + io.KeyMap[ImGuiKey_Y] = 'Y'; + io.KeyMap[ImGuiKey_Z] = 'Z'; + +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + const char* xinput_dll_names[] = + { + "xinput1_4.dll", + "xinput1_3.dll", + "xinput9_1_0.dll", + "xinput1_2.dll", + "xinput1_1.dll" + }; + for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++) + if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n])) + { + g_XInputDLL = dll; + g_XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities"); + g_XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState"); + break; + } +#endif + + return true; +} + +void ImGui_ImplWin32_Shutdown() +{ +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + if (g_XInputDLL) + ::FreeLibrary(g_XInputDLL); + g_XInputDLL = NULL; + g_XInputGetCapabilities = NULL; + g_XInputGetState = NULL; +#endif + + g_hWnd = NULL; + g_Time = 0; + g_TicksPerSecond = 0; + g_LastMouseCursor = ImGuiMouseCursor_COUNT; + g_HasGamepad = false; + g_WantUpdateHasGamepad = true; +} + +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) + { + ::SetCursor(NULL); + } + else + { + 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(NULL, win32_cursor)); + } + return true; +} + +static void ImGui_ImplWin32_UpdateMousePos() +{ + ImGuiIO& io = ImGui::GetIO(); + + if (io.WantSetMousePos) + { + POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; + if (::ClientToScreen(g_hWnd, &pos)) + ::SetCursorPos(pos.x, pos.y); + } + + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + POINT pos; + if (HWND active_window = ::GetForegroundWindow()) + if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd)) + if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos)) + io.MousePos = ImVec2((float)pos.x, (float)pos.y); +} + +static void ImGui_ImplWin32_UpdateGamepads() +{ +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + if (g_WantUpdateHasGamepad) + { + XINPUT_CAPABILITIES caps; + g_HasGamepad = g_XInputGetCapabilities ? (g_XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false; + g_WantUpdateHasGamepad = false; + } + + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + XINPUT_STATE xinput_state; + if (g_HasGamepad && g_XInputGetState && g_XInputGetState(0, &xinput_state) == ERROR_SUCCESS) + { + const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + + #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } + #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); + MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); + MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); + MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); + MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); + MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); + MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); + MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); + MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); + MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); + MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); + MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); + MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); + #undef MAP_BUTTON + #undef MAP_ANALOG + } +#endif +} + +void ImGui_ImplWin32_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + RECT rect = { 0, 0, 0, 0 }; + ::GetClientRect(g_hWnd, &rect); + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + + INT64 current_time = 0; + ::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time); + io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; + g_Time = current_time; + + io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0; + io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0; + io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; + ImGui_ImplWin32_UpdateMousePos(); + + ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (g_LastMouseCursor != mouse_cursor) + { + g_LastMouseCursor = mouse_cursor; + ImGui_ImplWin32_UpdateMouseCursor(); + } + + ImGui_ImplWin32_UpdateGamepads(); +} + +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef DBT_DEVNODES_CHANGED +#define DBT_DEVNODES_CHANGED 0x0007 +#endif + +#if 0 +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui::GetCurrentContext() == NULL) + return 0; + + ImGuiIO& io = ImGui::GetIO(); + switch (msg) + { + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: + { + 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 (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) + ::SetCapture(hwnd); + io.MouseDown[button] = true; + return 0; + } + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + 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; } + io.MouseDown[button] = false; + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) + ::ReleaseCapture(); + return 0; + } + case WM_MOUSEWHEEL: + io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (wParam < 256) + io.KeysDown[wParam] = 1; + return 0; + case WM_KEYUP: + case WM_SYSKEYUP: + if (wParam < 256) + io.KeysDown[wParam] = 0; + return 0; + case WM_CHAR: + if (wParam > 0 && wParam < 0x10000) + io.AddInputCharacterUTF16((unsigned short)wParam); + return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + return 1; + return 0; + case WM_DEVICECHANGE: + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + g_WantUpdateHasGamepad = true; + return 0; + } + return 0; +} + + +#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS) +static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + return ::VerifyVersionInfoW(&osvi, mask, cond); +} +#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) +#endif + +#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); +typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); +typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); + +void ImGui_ImplWin32_EnableDpiAwareness() +{ + { + static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); + 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"); + 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") +#endif + +float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) +{ + UINT xdpi = 96, ydpi = 96; + static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater(); + if (bIsWindows8Point1OrGreater) + { + static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); + if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor")) + GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + } +#ifndef NOGDI + else + { + const HDC dc = ::GetDC(NULL); + xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); + ydpi = ::GetDeviceCaps(dc, LOGPIXELSY); + ::ReleaseDC(NULL, dc); + } +#endif + IM_ASSERT(xdpi == ydpi); + return xdpi / 96.0f; +} + +float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) +{ + HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST); + return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); +} + + +``` + +`SpyCustom/imgui/imgui_impl_win32.h`: + +```h +#pragma once +#include "imgui.h" + +IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); +IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); + +#if 0 +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); + +``` + +`SpyCustom/imgui/imgui_internal.h`: + +```h +#pragma once +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_VERSION +#error Must include imgui.h before imgui_internal.h +#endif + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4251) +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#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" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS +#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#endif + + + +#ifndef IMGUI_ENABLE_FREETYPE +#define IMGUI_ENABLE_STB_TRUETYPE +#endif + +struct ImBitVector; +struct ImRect; +struct ImDrawDataBuilder; +struct ImDrawListSharedData; +struct ImGuiColorMod; +struct ImGuiContext; +struct ImGuiContextHook; +struct ImGuiDataTypeInfo; +struct ImGuiGroupData; +struct ImGuiInputTextState; +struct ImGuiLastItemDataBackup; +struct ImGuiMenuColumns; +struct ImGuiNavMoveResult; +struct ImGuiMetricsConfig; +struct ImGuiNextWindowData; +struct ImGuiNextItemData; +struct ImGuiOldColumnData; +struct ImGuiOldColumns; +struct ImGuiPopupData; +struct ImGuiSettingsHandler; +struct ImGuiStackSizes; +struct ImGuiStyleMod; +struct ImGuiTabBar; +struct ImGuiTabItem; +struct ImGuiTable; +struct ImGuiTableColumn; +struct ImGuiTableSettings; +struct ImGuiTableColumnsSettings; +struct ImGuiWindow; +struct ImGuiWindowTempData; +struct ImGuiWindowSettings; + +typedef int ImGuiLayoutType; +typedef int ImGuiItemFlags; +typedef int ImGuiItemStatusFlags; +typedef int ImGuiOldColumnFlags; +typedef int ImGuiNavHighlightFlags; +typedef int ImGuiNavDirSourceFlags; +typedef int ImGuiNavMoveFlags; +typedef int ImGuiNextItemDataFlags; +typedef int ImGuiNextWindowDataFlags; +typedef int ImGuiSeparatorFlags; +typedef int ImGuiTextFlags; +typedef int ImGuiTooltipFlags; + +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); + +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; +#endif + +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" + +} + +#ifndef IMGUI_DEBUG_LOG +#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) +#endif + +#define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) +#define IMGUI_DEBUG_LOG_NAV(...) ((void)0) + +#if (__cplusplus >= 201100) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201100) +#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") +#else +#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] +#endif + +#ifdef IMGUI_DEBUG_PARANOID +#define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) +#else +#define IM_ASSERT_PARANOID(_EXPR) +#endif + +#ifndef IM_ASSERT_USER_ERROR +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) +#endif + +#define IM_PI 3.14159265358979323846f +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" +#else +#define IM_NEWLINE "\n" +#endif +#define IM_TABSIZE (4) +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) +#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) +#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) + +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif + +#ifndef IM_DEBUG_BREAK +#if defined(__clang__) +#define IM_DEBUG_BREAK() __builtin_debugtrap() +#elif defined (_MSC_VER) +#define IM_DEBUG_BREAK() __debugbreak() +#else +#define IM_DEBUG_BREAK() IM_ASSERT(0) +#endif +#endif + +IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static inline ImGuiID ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } +#endif + +#define ImQsort qsort + +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); + +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; } + +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); +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); +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); +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 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 int ImParseFormatPrecision(const char* format, int default_value); +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } + +IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); +IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); + +#ifdef IMGUI_DEFINE_MATH_OPERATORS +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*=(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); } +#endif + +#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 +#endif +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); + +#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) +#define ImCeil(X) ceilf(X) +static inline float ImPow(float x, float y) { return powf(x, y); } +static inline double ImPow(double x, double y) { return pow(x, y); } +static inline float ImLog(float x) { return logf(x); } +static inline double ImLog(double x) { return log(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); } +static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); } +#endif +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; } +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 1.0f / ImSqrt(d); return fail_value; } +static inline float ImFloor(float f) { return (float)(int)(f); } +static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(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); } + +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); +IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol); +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; } +IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); + +struct ImVec1 +{ + float x; + ImVec1() { x = 0.0f; } + ImVec1(float _x) { x = _x; } +}; + +struct ImVec2ih +{ + short x, y; + ImVec2ih() { x = y = 0; } + ImVec2ih(short _x, short _y) { x = _x; y = _y; } + explicit ImVec2ih(const ImVec2& rhs) { x = (short)rhs.x; y = (short)rhs.y; } +}; + +struct IMGUI_API ImRect +{ + ImVec2 Min; + ImVec2 Max; + + ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} + ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + 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; } + ImVec2 GetTL() const { return Min; } + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } + ImVec2 GetBR() const { return Max; } + 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); } + void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } + 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); } +}; + +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) +{ + 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; + } +} + +template +struct IMGUI_API ImBitArray +{ + ImU32 Storage[(BITCOUNT + 31) >> 5]; + ImBitArray() { } + void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } + void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } + bool TestBit(int n) const { IM_ASSERT(n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + void SetBit(int n) { IM_ASSERT(n < BITCOUNT); ImBitArraySetBit(Storage, n); } + void ClearBit(int n) { IM_ASSERT(n < BITCOUNT); ImBitArrayClearBit(Storage, n); } + void SetBitRange(int n, int n2) { ImBitArraySetBitRange(Storage, n, n2); } +}; + +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 ImBitArrayTestBit(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); } +}; + +template +struct ImSpan +{ + T* Data; + T* DataEnd; + + 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; } + + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < DataEnd); const ptrdiff_t off = it - Data; return (int)off; } +}; + +template +struct ImSpanAllocator +{ + char* BasePtr; + int TotalSize; + int CurrSpan; + int Offsets[CHUNKS]; + + ImSpanAllocator() { memset(this, 0, sizeof(*this)); } + inline void ReserveBytes(int n, size_t sz) { IM_ASSERT(n == CurrSpan && n < CHUNKS); IM_UNUSED(n); Offsets[CurrSpan++] = TotalSize; TotalSize += (int)sz; } + inline int GetArenaSizeInBytes() { return TotalSize; } + inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; } + inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrSpan == CHUNKS); return (void*)(BasePtr + Offsets[n]); } + inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrSpan == CHUNKS); return (n + 1 < CHUNKS) ? BasePtr + Offsets[n + 1] : (void*)(BasePtr + TotalSize); } + template + inline void GetSpan(int n, ImSpan* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } +}; + +typedef int ImPoolIdx; +template +struct IMGUI_API ImPool +{ + ImVector Buf; + ImGuiStorage Map; + ImPoolIdx FreeIdx; + + ImPool() { FreeIdx = 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 = 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(); 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); } + void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } + int GetSize() const { return Buf.Size; } +}; + +template +struct IMGUI_API 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 = ((HDR_SZ + sz) + 3u) & ~3u; 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); } + +}; + +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 12 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp((int)((IM_PI * 2.0f) / ImAcos(((_RAD) - (_MAXERROR)) / (_RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) + +#ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER +#define IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER 1 +#endif + +struct IMGUI_API ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; + ImFont* Font; + float FontSize; + float CurveTessellationTol; + float CircleSegmentMaxError; + ImVec4 ClipRectFullscreen; + ImDrawListFlags InitialFlags; + + ImVec2 ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER]; + ImU8 CircleSegmentCounts[64]; + const ImVec4* TexUvLines; + + ImDrawListSharedData(); + void SetCircleSegmentMaxError(float max_error); +}; + +struct ImDrawDataBuilder +{ + ImVector Layers[2]; + + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + IMGUI_API void FlattenIntoSingleLayer(); +}; + +enum ImGuiItemFlags_ +{ + ImGuiItemFlags_None = 0, + ImGuiItemFlags_NoTabStop = 1 << 0, + ImGuiItemFlags_ButtonRepeat = 1 << 1, + ImGuiItemFlags_Disabled = 1 << 2, + ImGuiItemFlags_NoNav = 1 << 3, + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, + ImGuiItemFlags_MixedValue = 1 << 6, + ImGuiItemFlags_ReadOnly = 1 << 7, + ImGuiItemFlags_Default_ = 0 +}; + +enum ImGuiItemStatusFlags_ +{ + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_Edited = 1 << 2, + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, + ImGuiItemStatusFlags_Deactivated = 1 << 6 + +#ifdef IMGUI_ENABLE_TEST_ENGINE + , + ImGuiItemStatusFlags_Openable = 1 << 10, + ImGuiItemStatusFlags_Opened = 1 << 11, + ImGuiItemStatusFlags_Checkable = 1 << 12, + ImGuiItemStatusFlags_Checked = 1 << 13 +#endif +}; + +enum ImGuiButtonFlagsPrivate_ +{ + ImGuiButtonFlags_PressedOnClick = 1 << 4, + ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, + ImGuiButtonFlags_PressedOnRelease = 1 << 7, + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, + ImGuiButtonFlags_Repeat = 1 << 10, + ImGuiButtonFlags_FlattenChildren = 1 << 11, + ImGuiButtonFlags_AllowItemOverlap = 1 << 12, + ImGuiButtonFlags_DontClosePopups = 1 << 13, + ImGuiButtonFlags_Disabled = 1 << 14, + ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, + ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, + ImGuiButtonFlags_NoNavFocus = 1 << 18, + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease +}; + +enum ImGuiSliderFlagsPrivate_ +{ + ImGuiSliderFlags_Vertical = 1 << 20, + ImGuiSliderFlags_ReadOnly = 1 << 21 +}; + +enum ImGuiSelectableFlagsPrivate_ +{ + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnClick = 1 << 21, + ImGuiSelectableFlags_SelectOnRelease = 1 << 22, + ImGuiSelectableFlags_SpanAvailWidth = 1 << 23, + ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 24, + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26 +}; + +enum ImGuiTreeNodeFlagsPrivate_ +{ + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 +}; + +enum ImGuiSeparatorFlags_ +{ + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 +}; + +enum ImGuiTextFlags_ +{ + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 +}; + +enum ImGuiTooltipFlags_ +{ + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0 +}; + +enum ImGuiLayoutType_ +{ + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}; + +enum ImGuiLogType +{ + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard +}; + +enum ImGuiAxis +{ + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}; + +enum ImGuiPlotType +{ + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Nav, + ImGuiInputSource_NavKeyboard, + ImGuiInputSource_NavGamepad, + ImGuiInputSource_COUNT +}; + +enum ImGuiInputReadMode +{ + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}; + +enum ImGuiNavHighlightFlags_ +{ + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, + ImGuiNavHighlightFlags_NoRounding = 1 << 3 +}; + +enum ImGuiNavDirSourceFlags_ +{ + ImGuiNavDirSourceFlags_None = 0, + ImGuiNavDirSourceFlags_Keyboard = 1 << 0, + ImGuiNavDirSourceFlags_PadDPad = 1 << 1, + ImGuiNavDirSourceFlags_PadLStick = 1 << 2 +}; + +enum ImGuiNavMoveFlags_ +{ + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, + ImGuiNavMoveFlags_WrapY = 1 << 3, + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, + ImGuiNavMoveFlags_ScrollToEdge = 1 << 6 +}; + +enum ImGuiNavForward +{ + ImGuiNavForward_None, + ImGuiNavForward_ForwardQueued, + ImGuiNavForward_ForwardActive +}; + +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, + ImGuiNavLayer_Menu = 1, + ImGuiNavLayer_COUNT +}; + +enum ImGuiPopupPositionPolicy +{ + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox, + ImGuiPopupPositionPolicy_Tooltip +}; + +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; +}; + +struct ImGuiDataTypeInfo +{ + size_t Size; + const char* Name; + const char* PrintFmt; + const char* ScanFmt; +}; + +enum ImGuiDataTypePrivate_ +{ + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID +}; + +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; + +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; } +}; + +struct ImGuiGroupData +{ + ImGuiID WindowID; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool EmitItem; +}; + +struct IMGUI_API ImGuiMenuColumns +{ + float Spacing; + float Width, NextWidth; + float Pos[3], NextWidths[3]; + + ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } + void Update(int count, float spacing, bool clear); + float DeclColumns(float w0, float w1, float w2); + float CalcExtraSpace(float avail_w) const; +}; + +struct IMGUI_API ImGuiInputTextState +{ + ImGuiID ID; + int CurLenW, CurLenA; + ImVector TextW; + ImVector TextA; + ImVector InitialTextA; + bool TextAIsValid; + int BufCapacityA; + float ScrollX; + ImStb::STB_TexteditState Stb; + float CursorAnim; + bool CursorFollow; + bool SelectedAllMouseLock; + bool Edited; + ImGuiInputTextFlags UserFlags; + ImGuiInputTextCallback UserCallback; + void* UserCallbackData; + + 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); + + void CursorAnimReset() { CursorAnim = -0.30f; } + 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; } + void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } +}; + +struct ImGuiPopupData +{ + ImGuiID PopupId; + ImGuiWindow* Window; + ImGuiWindow* SourceWindow; + int OpenFrameCount; + ImGuiID OpenParentId; + ImVec2 OpenPopupPos; + ImVec2 OpenMousePos; + + ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; } +}; + +struct ImGuiNavMoveResult +{ + ImGuiWindow* Window; + ImGuiID ID; + ImGuiID FocusScopeId; + float DistBox; + float DistCenter; + float DistAxial; + ImRect RectRel; + + ImGuiNavMoveResult() { Clear(); } + void Clear() { Window = NULL; ID = FocusScopeId = 0; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } +}; + +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 +}; + +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; + ImVec2 MenuBarOffsetMinVal; + + 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; + float Width; + ImGuiID FocusScopeId; + ImGuiCond OpenCond; + bool OpenVal; + + ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } +}; + +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; +}; + +struct ImGuiPtrOrIndex +{ + void* Ptr; + int Index; + + ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } + ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } +}; + +enum ImGuiOldColumnFlags_ +{ + ImGuiOldColumnFlags_None = 0, + ImGuiOldColumnFlags_NoBorder = 1 << 0, + ImGuiOldColumnFlags_NoResize = 1 << 1, + ImGuiOldColumnFlags_NoPreserveWidths = 1 << 2, + ImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3, + ImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4 + +#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; + float OffsetNormBeforeResize; + ImGuiOldColumnFlags Flags; + 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; + float LineMinY, LineMaxY; + float HostCursorPosY; + float HostCursorMaxPosX; + ImRect HostInitialClipRect; + ImRect HostBackupClipRect; + ImRect HostBackupParentWorkRect; + ImVector Columns; + ImDrawListSplitter Splitter; + + ImGuiOldColumns() { memset(this, 0, sizeof(*this)); } +}; + +#ifdef IMGUI_HAS_MULTI_SELECT +#endif + +#ifdef IMGUI_HAS_DOCK +#endif + +#ifdef IMGUI_HAS_VIEWPORT +#endif + +struct ImGuiWindowSettings +{ + ImGuiID ID; + ImVec2ih Pos; + ImVec2ih Size; + bool Collapsed; + bool WantApply; + + ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } + char* GetName() { return (char*)(this + 1); } +}; + +struct ImGuiSettingsHandler +{ + const char* TypeName; + ImGuiID TypeHash; + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); + void* UserData; + + ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } +}; + +struct ImGuiMetricsConfig +{ + bool ShowWindowsRects; + bool ShowWindowsBeginOrder; + bool ShowTablesRects; + bool ShowDrawCmdMesh; + bool ShowDrawCmdBoundingBoxes; + int ShowWindowsRectsType; + int ShowTablesRectsType; + + ImGuiMetricsConfig() + { + ShowWindowsRects = false; + ShowWindowsBeginOrder = false; + ShowTablesRects = false; + ShowDrawCmdMesh = true; + ShowDrawCmdBoundingBoxes = true; + ShowWindowsRectsType = -1; + ShowTablesRectsType = -1; + } +}; + +struct IMGUI_API ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfBeginPopupStack; + + ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } + void SetToCurrentState(); + void CompareWithCurrentState(); +}; + +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; + ImGuiContextHookType Type; + ImGuiID Owner; + ImGuiContextHookCallback Callback; + void* UserData; + + ImGuiContextHook() { memset(this, 0, sizeof(*this)); } +}; + +struct ImGuiContext +{ + bool Initialized; + bool FontAtlasOwnedByContext; + ImGuiIO IO; + ImGuiStyle Style; + ImFont* Font; + float FontSize; + float FontBaseSize; + ImDrawListSharedData DrawListSharedData; + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountRendered; + bool WithinFrameScope; + bool WithinFrameScopeWithImplicitWindow; + bool WithinEndChild; + bool GcCompactAll; + bool TestEngineHookItems; + ImGuiID TestEngineHookIdInfo; + void* TestEngine; + + ImVector Windows; + ImVector WindowsFocusOrder; + ImVector WindowsTempSortBuffer; + ImVector CurrentWindowStack; + ImGuiStorage WindowsById; + int WindowsActiveCount; + ImGuiWindow* CurrentWindow; + ImGuiWindow* HoveredWindow; + ImGuiWindow* HoveredRootWindow; + ImGuiWindow* HoveredWindowUnderMovingWindow; + ImGuiWindow* MovingWindow; + ImGuiWindow* WheelingWindow; + ImVec2 WheelingWindowRefMousePos; + float WheelingWindowTimer; + + ImGuiID HoveredId; + ImGuiID HoveredIdPreviousFrame; + bool HoveredIdAllowOverlap; + bool HoveredIdUsingMouseWheel; + bool HoveredIdPreviousFrameUsingMouseWheel; + bool HoveredIdDisabled; + float HoveredIdTimer; + float HoveredIdNotActiveTimer; + ImGuiID ActiveId; + ImGuiID ActiveIdIsAlive; + float ActiveIdTimer; + bool ActiveIdIsJustActivated; + bool ActiveIdAllowOverlap; + bool ActiveIdNoClearOnFocusLoss; + bool ActiveIdHasBeenPressedBefore; + bool ActiveIdHasBeenEditedBefore; + bool ActiveIdHasBeenEditedThisFrame; + bool ActiveIdUsingMouseWheel; + ImU32 ActiveIdUsingNavDirMask; + ImU32 ActiveIdUsingNavInputMask; + ImU64 ActiveIdUsingKeyInputMask; + ImVec2 ActiveIdClickOffset; + ImGuiWindow* ActiveIdWindow; + ImGuiInputSource ActiveIdSource; + int ActiveIdMouseButton; + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; + float LastActiveIdTimer; + + ImGuiNextWindowData NextWindowData; + ImGuiNextItemData NextItemData; + + ImVector ColorStack; + ImVector StyleVarStack; + ImVector FontStack; + ImVector FocusScopeStack; + ImVectorItemFlagsStack; + ImVectorGroupStack; + ImVectorOpenPopupStack; + ImVectorBeginPopupStack; + + ImGuiWindow* NavWindow; + ImGuiID NavId; + ImGuiID NavFocusScopeId; + ImGuiID NavActivateId; + ImGuiID NavActivateDownId; + ImGuiID NavActivatePressedId; + ImGuiID NavInputId; + ImGuiID NavJustTabbedId; + ImGuiID NavJustMovedToId; + ImGuiID NavJustMovedToFocusScopeId; + ImGuiKeyModFlags NavJustMovedToKeyMods; + ImGuiID NavNextActivateId; + ImGuiInputSource NavInputSource; + ImRect NavScoringRect; + int NavScoringCount; + ImGuiNavLayer NavLayer; + int NavIdTabCounter; + bool NavIdIsAlive; + bool NavMousePosDirty; + bool NavDisableHighlight; + bool NavDisableMouseHover; + bool NavAnyRequest; + bool NavInitRequest; + bool NavInitRequestFromMove; + ImGuiID NavInitResultId; + ImRect NavInitResultRectRel; + bool NavMoveRequest; + ImGuiNavMoveFlags NavMoveRequestFlags; + ImGuiNavForward NavMoveRequestForward; + ImGuiKeyModFlags NavMoveRequestKeyMods; + ImGuiDir NavMoveDir, NavMoveDirLast; + ImGuiDir NavMoveClipDir; + ImGuiNavMoveResult NavMoveResultLocal; + ImGuiNavMoveResult NavMoveResultLocalVisibleSet; + ImGuiNavMoveResult NavMoveResultOther; + ImGuiWindow* NavWrapRequestWindow; + ImGuiNavMoveFlags NavWrapRequestFlags; + + ImGuiWindow* NavWindowingTarget; + ImGuiWindow* NavWindowingTargetAnim; + ImGuiWindow* NavWindowingListWindow; + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + + ImGuiWindow* FocusRequestCurrWindow; + ImGuiWindow* FocusRequestNextWindow; + int FocusRequestCurrCounterRegular; + int FocusRequestCurrCounterTabStop; + int FocusRequestNextCounterRegular; + int FocusRequestNextCounterTabStop; + bool FocusTabPressed; + + ImDrawData DrawData; + ImDrawDataBuilder DrawDataBuilder; + float DimBgRatio; + ImDrawList BackgroundDrawList; + ImDrawList ForegroundDrawList; + ImGuiMouseCursor MouseCursor; + + bool DragDropActive; + bool DragDropWithinSource; + bool DragDropWithinTarget; + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; + ImGuiID DragDropAcceptIdCurr; + ImGuiID DragDropAcceptIdPrev; + int DragDropAcceptFrameCount; + ImGuiID DragDropHoldJustPressedId; + ImVector DragDropPayloadBufHeap; + unsigned char DragDropPayloadBufLocal[16]; + + ImGuiTable* CurrentTable; + ImPool Tables; + ImVector CurrentTableStack; + ImVector TablesLastTimeActive; + ImVector DrawChannelsTempMergeBuffer; + + ImGuiTabBar* CurrentTabBar; + ImPool TabBars; + ImVector CurrentTabBarStack; + ImVector ShrinkWidthBuffer; + + ImVec2 LastValidMousePos; + ImGuiInputTextState InputTextState; + ImFont InputTextPasswordFont; + ImGuiID TempInputId; + ImGuiColorEditFlags ColorEditOptions; + float ColorEditLastHue; + float ColorEditLastSat; + float ColorEditLastColor[3]; + ImVec4 ColorPickerRef; + float SliderCurrentAccum; + bool SliderCurrentAccumDirty; + bool DragCurrentAccumDirty; + float DragCurrentAccum; + float DragSpeedDefaultRatio; + float ScrollbarClickDeltaToGrabCenter; + int TooltipOverrideCount; + float TooltipSlowDelay; + ImVector ClipboardHandlerData; + ImVector MenusIdSubmittedThisFrame; + + ImVec2 PlatformImePos; + ImVec2 PlatformImeLastPos; + char PlatformLocaleDecimalPoint; + + bool SettingsLoaded; + float SettingsDirtyTimer; + ImGuiTextBuffer SettingsIniData; + ImVector SettingsHandlers; + ImChunkStream SettingsWindows; + ImChunkStream SettingsTables; + ImVector Hooks; + ImGuiID HookIdNext; + + bool LogEnabled; + ImGuiLogType LogType; + ImFileHandle LogFile; + ImGuiTextBuffer LogBuffer; + const char* LogNextPrefix; + const char* LogNextSuffix; + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; + + bool DebugItemPickerActive; + ImGuiID DebugItemPickerBreakId; + ImGuiMetricsConfig DebugMetricsConfig; + + float FramerateSecPerFrame[120]; + int FramerateSecPerFrameIdx; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; + int WantCaptureKeyboardNextFrame; + int WantTextInputNextFrame; + char TempBuffer[1024 * 3 + 1]; + + ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData) + { + 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; + TestEngineHookIdInfo = 0; + TestEngine = NULL; + + WindowsActiveCount = 0; + CurrentWindow = NULL; + HoveredWindow = NULL; + HoveredRootWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; + MovingWindow = NULL; + WheelingWindow = NULL; + WheelingWindowTimer = 0.0f; + + HoveredId = HoveredIdPreviousFrame = 0; + HoveredIdAllowOverlap = false; + HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = 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; + ActiveIdUsingMouseWheel = false; + ActiveIdUsingNavDirMask = 0x00; + ActiveIdUsingNavInputMask = 0x00; + ActiveIdUsingKeyInputMask = 0x00; + ActiveIdClickOffset = ImVec2(-1, -1); + ActiveIdWindow = NULL; + ActiveIdSource = ImGuiInputSource_None; + ActiveIdMouseButton = 0; + ActiveIdPreviousFrame = 0; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEditedBefore = false; + ActiveIdPreviousFrameWindow = NULL; + LastActiveId = 0; + LastActiveIdTimer = 0.0f; + + NavWindow = NULL; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; + NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; + NavJustMovedToKeyMods = ImGuiKeyModFlags_None; + NavInputSource = ImGuiInputSource_None; + NavScoringRect = ImRect(); + NavScoringCount = 0; + NavLayer = ImGuiNavLayer_Main; + NavIdTabCounter = INT_MAX; + NavIdIsAlive = false; + NavMousePosDirty = false; + NavDisableHighlight = true; + NavDisableMouseHover = false; + NavAnyRequest = false; + NavInitRequest = false; + NavInitRequestFromMove = false; + NavInitResultId = 0; + NavMoveRequest = false; + NavMoveRequestFlags = ImGuiNavMoveFlags_None; + NavMoveRequestForward = ImGuiNavForward_None; + NavMoveRequestKeyMods = ImGuiKeyModFlags_None; + NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; + NavWrapRequestWindow = NULL; + NavWrapRequestFlags = ImGuiNavMoveFlags_None; + + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; + + FocusRequestCurrWindow = FocusRequestNextWindow = NULL; + FocusRequestCurrCounterRegular = FocusRequestCurrCounterTabStop = INT_MAX; + FocusRequestNextCounterRegular = FocusRequestNextCounterTabStop = INT_MAX; + FocusTabPressed = false; + + DimBgRatio = 0.0f; + BackgroundDrawList._OwnerName = "##Background"; + ForegroundDrawList._OwnerName = "##Foreground"; + MouseCursor = ImGuiMouseCursor_Arrow; + + 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)); + + CurrentTable = NULL; + CurrentTabBar = NULL; + + LastValidMousePos = ImVec2(0.0f, 0.0f); + TempInputId = 0; + ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; + ColorEditLastHue = ColorEditLastSat = 0.0f; + ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX; + SliderCurrentAccum = 0.0f; + SliderCurrentAccumDirty = false; + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; + DragSpeedDefaultRatio = 1.0f / 100.0f; + ScrollbarClickDeltaToGrabCenter = 0.0f; + TooltipOverrideCount = 0; + TooltipSlowDelay = 0.50f; + + PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + PlatformLocaleDecimalPoint = '.'; + + SettingsLoaded = false; + SettingsDirtyTimer = 0.0f; + HookIdNext = 0; + + LogEnabled = false; + LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; + LogFile = NULL; + LogLinePosY = FLT_MAX; + LogLineFirstItem = false; + LogDepthRef = 0; + LogDepthToExpand = LogDepthToExpandDefault = 2; + + DebugItemPickerActive = false; + DebugItemPickerBreakId = 0; + + memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); + FramerateSecPerFrameIdx = 0; + FramerateSecPerFrameAccum = 0.0f; + WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; + memset(TempBuffer, 0, sizeof(TempBuffer)); + } +}; + +struct IMGUI_API ImGuiWindowTempData +{ + ImVec2 CursorPos; + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; + ImVec2 CursorMaxPos; + ImVec2 IdealMaxPos; + ImVec2 CurrLineSize; + ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; + float PrevLineTextBaseOffset; + ImVec1 Indent; + ImVec1 ColumnsOffset; + ImVec1 GroupOffset; + + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; + ImRect LastItemDisplayRect; + + ImGuiNavLayer NavLayerCurrent; + int NavLayerActiveMask; + int NavLayerActiveMaskNext; + ImGuiID NavFocusScopeIdCurrent; + bool NavHideHighlightOneFrame; + bool NavHasScroll; + + bool MenuBarAppending; + ImVec2 MenuBarOffset; + ImGuiMenuColumns MenuColumns; + int TreeDepth; + ImU32 TreeJumpToParentOnPopMask; + ImVector ChildWindows; + ImGuiStorage* StateStorage; + ImGuiOldColumns* CurrentColumns; + int CurrentTableIdx; + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; + int FocusCounterRegular; + int FocusCounterTabStop; + + ImGuiItemFlags ItemFlags; + float ItemWidth; + float TextWrapPos; + ImVector ItemWidthStack; + ImVector TextWrapPosStack; + ImGuiStackSizes StackSizesOnBegin; +}; + +struct IMGUI_API ImGuiWindow +{ + char* Name; + ImGuiID ID; + ImGuiWindowFlags Flags; + ImVec2 Pos; + ImVec2 Size; + ImVec2 SizeFull; + ImVec2 ContentSize; + ImVec2 ContentSizeIdeal; + ImVec2 ContentSizeExplicit; + ImVec2 WindowPadding; + float WindowRounding; + float WindowBorderSize; + int NameBufLen; + ImGuiID MoveId; + ImGuiID ChildId; + ImVec2 Scroll; + ImVec2 ScrollMax; + ImVec2 ScrollTarget; + ImVec2 ScrollTargetCenterRatio; + ImVec2 ScrollTargetEdgeSnapDist; + ImVec2 ScrollbarSizes; + bool ScrollbarX, ScrollbarY; + bool Active; + bool WasActive; + bool WriteAccessed; + bool Collapsed; + bool WantCollapseToggle; + bool SkipItems; + bool Appearing; + bool Hidden; + bool IsFallbackWindow; + bool HasCloseButton; + signed char ResizeBorderHeld; + short BeginCount; + short BeginOrderWithinParent; + short BeginOrderWithinContext; + ImGuiID PopupId; + ImS8 AutoFitFramesX, AutoFitFramesY; + ImS8 AutoFitChildAxises; + bool AutoFitOnlyGrows; + ImGuiDir AutoPosLastDirection; + ImS8 HiddenFramesCanSkipItems; + ImS8 HiddenFramesCannotSkipItems; + ImS8 HiddenFramesForRenderOnly; + ImGuiCond SetWindowPosAllowFlags : 8; + ImGuiCond SetWindowSizeAllowFlags : 8; + ImGuiCond SetWindowCollapsedAllowFlags : 8; + ImVec2 SetWindowPosVal; + ImVec2 SetWindowPosPivot; + + ImVector IDStack; + ImGuiWindowTempData DC; + + ImRect OuterRectClipped; + ImRect InnerRect; + ImRect InnerClipRect; + ImRect WorkRect; + ImRect ParentWorkRect; + ImRect ClipRect; + ImRect ContentRegionRect; + ImVec2ih HitTestHoleSize; + ImVec2ih HitTestHoleOffset; + + int LastFrameActive; + float LastTimeActive; + float ItemWidthDefault; + ImGuiStorage StateStorage; + ImVector ColumnsStorage; + float FontWindowScale; + int SettingsOffset; + + ImDrawList* DrawList; + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; + ImGuiWindow* RootWindow; + ImGuiWindow* RootWindowForTitleBarHighlight; + ImGuiWindow* RootWindowForNav; + + ImGuiWindow* NavLastChildNavWindow; + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; + ImRect NavRectRel[ImGuiNavLayer_COUNT]; + + int MemoryDrawListIdxCapacity; + int MemoryDrawListVtxCapacity; + bool MemoryCompacted; + +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 GetIDNoKeepAlive(const char* str, const char* str_end = NULL); + ImGuiID GetIDNoKeepAlive(const void* ptr); + ImGuiID GetIDNoKeepAlive(int n); + ImGuiID GetIDFromRectangle(const ImRect& r_abs); + + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float TitleBarHeight() const { ImGuiContext& g = *GImGui; 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 = *GImGui; 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()); } +}; + +struct ImGuiLastItemDataBackup +{ + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; + ImRect LastItemDisplayRect; + + ImGuiLastItemDataBackup() { Backup(); } + void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } + void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } +}; + +enum ImGuiTabBarFlagsPrivate_ +{ + ImGuiTabBarFlags_DockNode = 1 << 20, + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 +}; + +enum ImGuiTabItemFlagsPrivate_ +{ + ImGuiTabItemFlags_NoCloseButton = 1 << 20, + ImGuiTabItemFlags_Button = 1 << 21 +}; + +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; + float Offset; + float Width; + float ContentWidth; + ImS16 NameOffset; + ImS16 BeginOrder; + ImS16 IndexDuringLayout; + bool WantClose; + + ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; NameOffset = BeginOrder = IndexDuringLayout = -1; } +}; + +struct ImGuiTabBar +{ + ImVector Tabs; + ImGuiTabBarFlags Flags; + ImGuiID ID; + ImGuiID SelectedTabId; + ImGuiID NextSelectedTabId; + ImGuiID VisibleTabId; + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float CurrTabsContentsHeight; + float PrevTabsContentsHeight; + float WidthAllTabs; + float WidthAllTabsIdeal; + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + float ScrollingRectMinX; + float ScrollingRectMaxX; + ImGuiID ReorderRequestTabId; + ImS8 ReorderRequestDir; + ImS8 BeginCount; + bool WantLayout; + bool VisibleTabWasSubmitted; + bool TabsAddedNew; + ImS16 TabsActiveCount; + ImS16 LastTabItemIdx; + float ItemSpacingY; + ImVec2 FramePadding; + ImVec2 BackupCursorPos; + ImGuiTextBuffer TabsNames; + + ImGuiTabBar(); + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + IM_ASSERT(tab->NameOffset != -1 && (int)tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } +}; + +#ifdef IMGUI_HAS_TABLE + +#define IM_COL32_DISABLE IM_COL32(0,0,0,1) +#define IMGUI_TABLE_MAX_COLUMNS 64 +#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) + +typedef ImS8 ImGuiTableColumnIdx; +typedef ImU8 ImGuiTableDrawChannelIdx; + +struct ImGuiTableColumn +{ + ImGuiTableColumnFlags Flags; + float WidthGiven; + float MinX; + float MaxX; + float WidthRequest; + float WidthAuto; + float StretchWeight; + float InitStretchWeightOrWidth; + ImRect ClipRect; + ImGuiID UserID; + float WorkMinX; + float WorkMaxX; + float ItemWidth; + float ContentMaxXFrozen; + float ContentMaxXUnfrozen; + float ContentMaxXHeadersUsed; + float ContentMaxXHeadersIdeal; + ImS16 NameOffset; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx IndexWithinEnabledSet; + ImGuiTableColumnIdx PrevEnabledColumn; + ImGuiTableColumnIdx NextEnabledColumn; + ImGuiTableColumnIdx SortOrder; + ImGuiTableDrawChannelIdx DrawChannelCurrent; + ImGuiTableDrawChannelIdx DrawChannelFrozen; + ImGuiTableDrawChannelIdx DrawChannelUnfrozen; + bool IsEnabled; + bool IsEnabledNextFrame; + bool IsVisibleX; + bool IsVisibleY; + bool IsRequestOutput; + bool IsSkipItems; + bool IsPreserveWidthAuto; + ImS8 NavLayerCurrent; + ImU8 AutoFitQueue; + ImU8 CannotSkipItemsQueue; + ImU8 SortDirection : 2; + ImU8 SortDirectionsAvailCount : 2; + ImU8 SortDirectionsAvailMask : 4; + ImU8 SortDirectionsAvailList; + + 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; + } +}; + +struct ImGuiTableCellData +{ + ImU32 BgColor; + ImGuiTableColumnIdx Column; +}; + +struct ImGuiTable +{ + ImGuiID ID; + ImGuiTableFlags Flags; + void* RawData; + ImSpan Columns; + ImSpan DisplayOrderToIndex; + ImSpan RowCellData; + ImU64 EnabledMaskByDisplayOrder; + ImU64 EnabledMaskByIndex; + ImU64 VisibleMaskByIndex; + ImU64 RequestOutputMaskByIndex; + ImGuiTableFlags SettingsLoadedFlags; + int SettingsOffset; + int LastFrameActive; + int ColumnsCount; + int CurrentRow; + int CurrentColumn; + ImS16 InstanceCurrent; + ImS16 InstanceInteracted; + float RowPosY1; + float RowPosY2; + float RowMinHeight; + float RowTextBaseline; + float RowIndentOffsetX; + ImGuiTableRowFlags RowFlags : 16; + ImGuiTableRowFlags LastRowFlags : 16; + int RowBgColorCounter; + ImU32 RowBgColor[2]; + ImU32 BorderColorStrong; + ImU32 BorderColorLight; + float BorderX1; + float BorderX2; + float HostIndentX; + float MinColumnWidth; + float OuterPaddingX; + float CellPaddingX; + float CellPaddingY; + float CellSpacingX1; + float CellSpacingX2; + float LastOuterHeight; + float LastFirstRowHeight; + float InnerWidth; + float ColumnsGivenWidth; + float ColumnsAutoFitWidth; + float ResizedColumnNextWidth; + float ResizeLockMinContentsX2; + float RefScale; + ImRect OuterRect; + ImRect InnerRect; + ImRect WorkRect; + ImRect InnerClipRect; + ImRect BgClipRect; + ImRect Bg0ClipRectForDrawCmd; + ImRect Bg2ClipRectForDrawCmd; + ImRect HostClipRect; + ImRect HostBackupWorkRect; + ImRect HostBackupParentWorkRect; + ImRect HostBackupInnerClipRect; + ImVec2 HostBackupPrevLineSize; + ImVec2 HostBackupCurrLineSize; + ImVec2 HostBackupCursorMaxPos; + ImVec2 UserOuterSize; + ImVec1 HostBackupColumnsOffset; + float HostBackupItemWidth; + int HostBackupItemWidthStackSize; + ImGuiWindow* OuterWindow; + ImGuiWindow* InnerWindow; + ImGuiTextBuffer ColumnsNames; + ImDrawListSplitter DrawSplitter; + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector SortSpecsMulti; + ImGuiTableSortSpecs SortSpecs; + ImGuiTableColumnIdx SortSpecsCount; + ImGuiTableColumnIdx ColumnsEnabledCount; + ImGuiTableColumnIdx ColumnsEnabledFixedCount; + ImGuiTableColumnIdx DeclColumnsCount; + ImGuiTableColumnIdx HoveredColumnBody; + ImGuiTableColumnIdx HoveredColumnBorder; + ImGuiTableColumnIdx AutoFitSingleColumn; + ImGuiTableColumnIdx ResizedColumn; + ImGuiTableColumnIdx LastResizedColumn; + ImGuiTableColumnIdx HeldHeaderColumn; + ImGuiTableColumnIdx ReorderColumn; + ImGuiTableColumnIdx ReorderColumnDir; + ImGuiTableColumnIdx LeftMostStretchedColumn; + ImGuiTableColumnIdx RightMostStretchedColumn; + ImGuiTableColumnIdx RightMostEnabledColumn; + ImGuiTableColumnIdx ContextPopupColumn; + ImGuiTableColumnIdx FreezeRowsRequest; + ImGuiTableColumnIdx FreezeRowsCount; + ImGuiTableColumnIdx FreezeColumnsRequest; + ImGuiTableColumnIdx FreezeColumnsCount; + ImGuiTableColumnIdx RowCellDataCurrent; + ImGuiTableDrawChannelIdx DummyDrawChannel; + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; + ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + bool IsLayoutLocked; + bool IsInsideRow; + bool IsInitializing; + bool IsSortSpecsDirty; + bool IsUsingHeaders; + bool IsContextPopupOpen; + bool IsSettingsRequestLoad; + bool IsSettingsDirty; + bool IsDefaultDisplayOrder; + bool IsResetAllRequest; + bool IsResetDisplayOrderRequest; + bool IsUnfrozenRows; + bool IsDefaultSizingPolicy; + bool MemoryCompacted; + bool HostSkipItems; + + IMGUI_API ImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; } + IMGUI_API ~ImGuiTable() { IM_FREE(RawData); } +}; + +struct ImGuiTableColumnSettings +{ + float WidthOrWeight; + ImGuiID UserID; + ImGuiTableColumnIdx Index; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx SortOrder; + ImU8 SortDirection : 2; + ImU8 IsEnabled : 1; + ImU8 IsStretch : 1; + + ImGuiTableColumnSettings() + { + WidthOrWeight = 0.0f; + UserID = 0; + Index = -1; + DisplayOrder = SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + IsEnabled = 1; + IsStretch = 0; + } +}; + +struct ImGuiTableSettings +{ + ImGuiID ID; + ImGuiTableFlags SaveFlags; + float RefScale; + ImGuiTableColumnIdx ColumnsCount; + ImGuiTableColumnIdx ColumnsCountMax; + bool WantApply; + + ImGuiTableSettings() { memset(this, 0, sizeof(*this)); } + ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } +}; + +#endif + +namespace ImGui +{ + 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); + IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below); + IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); + IMGUI_API ImRect GetWindowAllowedExtentRect(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 FocusWindow(ImGuiWindow* window); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); + IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); + + 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); ImGuiContext& g = *GImGui; return &g.ForegroundDrawList; } + + IMGUI_API void Initialize(ImGuiContext* context); + IMGUI_API void Shutdown(ImGuiContext* context); + + IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); + IMGUI_API void UpdateMouseMovingWindowNewFrame(); + IMGUI_API void UpdateMouseMovingWindowEndFrame(); + + 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); + + IMGUI_API void MarkIniSettingsDirty(); + IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); + IMGUI_API void ClearIniSettings(); + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); + IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + + IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); + 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); + IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect); + + inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } + inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; } + inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } + inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } + inline ImGuiItemFlags GetItemsFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.ItemFlags; } + 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); + IMGUI_API void PushOverrideID(ImGuiID id); + IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); + + IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); + IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); + IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); + IMGUI_API void SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); + IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); + IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); + 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 void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); + IMGUI_API bool IsItemToggledSelection(); + IMGUI_API ImVec2 GetContentRegionMaxAbs(); + IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); + + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); + IMGUI_API void LogToBuffer(int auto_open_depth = -1); + 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); + + 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 bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); + IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); + IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags); + IMGUI_API ImGuiWindow* GetTopMostPopupModal(); + 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); + + IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); + IMGUI_API bool NavMoveRequestButNoResultYet(); + IMGUI_API void NavMoveRequestCancel(); + IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); + IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); + IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); + IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); + IMGUI_API void ActivateItem(ImGuiID id); + IMGUI_API void SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id); + IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); + + IMGUI_API void PushFocusScope(ImGuiID id); + IMGUI_API void PopFocusScope(); + inline ImGuiID GetFocusedFocusScope() { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; } + inline ImGuiID GetFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.NavFocusScopeIdCurrent; } + + IMGUI_API void SetItemUsingMouseWheel(); + inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } + inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; } + inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; } + IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } + inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } + inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } + IMGUI_API ImGuiKeyModFlags GetMergedKeyModFlags(); + + IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); + IMGUI_API void ClearDragDrop(); + IMGUI_API bool IsDragDropPayloadBeingAccepted(); + + IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); + IMGUI_API void EndColumns(); + 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); + + IMGUI_API void TableOpenContextMenu(int column_n = -1); + IMGUI_API void TableSetColumnEnabled(int column_n, bool enabled); + 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(); + IMGUI_API float TableGetHeaderRowHeight(); + IMGUI_API void TablePushBackgroundChannel(); + IMGUI_API void TablePopBackgroundChannel(); + + 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 void TableMergeDrawChannels(ImGuiTable* table); + 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(const 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 TableGcCompactSettings(); + + 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 TableSettingsInstallHandler(ImGuiContext* context); + IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); + IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); + + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); + IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); + IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); + 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, bool tabActive = 1); + + IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true, ImU32 customcol = 0); + 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 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, ImColor customcolor); + + 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, ImU32 Color = 0); + 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, ImU32 Color = 0); + 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, int rounding_corners_flags = ~0); + IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); + + 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 RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); + 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, ImRect outer, ImRect inner, ImU32 col, float rounding); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); } + inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); } +#endif + + 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 CloseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); + IMGUI_API void Scrollbar(ImGuiAxis axis); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col); + IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); + IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); + IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); + + 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); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); + IMGUI_API void TreePushOverrideID(ImGuiID id); + + 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); + + 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 DataTypeApplyOpFromText(const char* buf, const char* initial_value_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); + + 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 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 (g.InputTextState.ID == id) ? &g.InputTextState : NULL; } + + 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); + + 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, ImVec2 frame_size); + + 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); + + IMGUI_API void GcCompactTransientMiscBuffers(); + IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); + IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); + + IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); } + inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } + + IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); + IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label); + IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); + 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 DebugNodeWindow(ImGuiWindow* window, const char* label); + IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings); + IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); + +} + + +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; + +IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); +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); + +#ifdef IMGUI_ENABLE_TEST_ENGINE +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id); +extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end); +extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) +#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA)); +#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2)); +#else +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) do { } while (0) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) do { } while (0) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) do { } while (0) +#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) do { } while (0) +#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) do { } while (0) +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#endif + +``` + +`SpyCustom/imgui/imgui_tables.cpp`: + +```cpp + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#if defined(_MSC_VER) && _MSC_VER <= 1500 +#include +#else +#include +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4127) +#pragma warning (disable: 4996) +#if defined(_MSC_VER) && _MSC_VER >= 1922 +#pragma warning (disable: 5054) +#endif +#endif + +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wenum-enum-conversion" +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +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; +static const float TABLE_BORDER_SIZE = 1.0f; +static const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f; +static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; + +inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window) +{ + if ((flags & ImGuiTableFlags_SizingMask_) == 0) + flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame; + + if ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableFlags_NoKeepColumnsVisible; + + if (flags & ImGuiTableFlags_Resizable) + flags |= ImGuiTableFlags_BordersInnerV; + + if (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) + flags &= ~(ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoHostExtendY); + + if (flags & ImGuiTableFlags_NoBordersInBodyUntilResize) + flags &= ~ImGuiTableFlags_NoBordersInBody; + + if ((flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable)) == 0) + flags |= ImGuiTableFlags_NoSavedSettings; + +#ifdef IMGUI_HAS_DOCK + ImGuiWindow* window_for_settings = outer_window->RootWindowDockStop; +#else + ImGuiWindow* window_for_settings = outer_window->RootWindow; +#endif + if (window_for_settings->Flags & ImGuiWindowFlags_NoSavedSettings) + flags |= ImGuiTableFlags_NoSavedSettings; + + return flags; +} + +ImGuiTable* ImGui::TableFindByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return g.Tables.GetByKey(id); +} + +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) + return false; + + IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!"); + if (flags & ImGuiTableFlags_ScrollX) + IM_ASSERT(inner_width >= 0.0f); + + 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, false)) + { + ItemSize(outer_rect); + return false; + } + + ImGuiTable* table = g.Tables.GetOrAddByKey(id); + const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; + const ImGuiID instance_id = id + instance_no; + const ImGuiTableFlags table_last_flags = table->Flags; + if (instance_no > 0) + IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); + + table->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0; + flags = TableFixFlags(flags, outer_window); + + table->ID = id; + table->Flags = flags; + table->InstanceCurrent = (ImS16)instance_no; + table->LastFrameActive = g.FrameCount; + table->OuterWindow = table->InnerWindow = outer_window; + table->ColumnsCount = columns_count; + table->IsLayoutLocked = false; + table->InnerWidth = inner_width; + table->UserOuterSize = outer_size; + + if (use_child_window) + { + ImVec2 override_content_size(FLT_MAX, FLT_MAX); + if ((flags & ImGuiTableFlags_ScrollX) && !(flags & ImGuiTableFlags_ScrollY)) + override_content_size.y = FLT_MIN; + + 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)); + + if ((table_last_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) + SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + + 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); + } + else + { + table->WorkRect = table->OuterRect = table->InnerRect = outer_rect; + } + + PushOverrideID(instance_id); + + ImGuiWindow* inner_window = table->InnerWindow; + table->HostIndentX = inner_window->DC.Indent.x; + table->HostClipRect = inner_window->ClipRect; + table->HostSkipItems = inner_window->SkipItems; + table->HostBackupWorkRect = inner_window->WorkRect; + table->HostBackupParentWorkRect = inner_window->ParentWorkRect; + table->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset; + table->HostBackupPrevLineSize = inner_window->DC.PrevLineSize; + table->HostBackupCurrLineSize = inner_window->DC.CurrLineSize; + table->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos; + table->HostBackupItemWidth = outer_window->DC.ItemWidth; + table->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; + inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + + 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); + 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; + table->RowTextBaseline = 0.0f; + table->FreezeRowsRequest = table->FreezeRowsCount = 0; + table->FreezeColumnsRequest = table->FreezeColumnsCount = 0; + table->IsUnfrozenRows = true; + table->DeclColumnsCount = 0; + + table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong); + table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight); + + const int table_idx = g.Tables.GetIndex(table); + g.CurrentTableStack.push_back(ImGuiPtrOrIndex(table_idx)); + g.CurrentTable = table; + outer_window->DC.CurrentTableIdx = table_idx; + if (inner_window != outer_window) + inner_window->DC.CurrentTableIdx = table_idx; + + if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) + table->IsResetDisplayOrderRequest = true; + + if (table_idx >= g.TablesLastTimeActive.Size) + g.TablesLastTimeActive.resize(table_idx + 1, -1.0f); + g.TablesLastTimeActive[table_idx] = (float)g.Time; + table->MemoryCompacted = false; + + const int stored_size = table->Columns.size(); + if (stored_size != 0 && stored_size != columns_count) + { + IM_FREE(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) + { + 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]; + float width_auto = column->WidthAuto; + *column = ImGuiTableColumn(); + column->WidthAuto = width_auto; + column->IsPreserveWidthAuto = true; + column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n; + column->IsEnabled = column->IsEnabledNextFrame = true; + } + } + + if (table->IsSettingsRequestLoad) + TableLoadSettings(table); + + const float new_ref_scale_unit = g.FontSize; + if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) + { + const float scale_factor = new_ref_scale_unit / table->RefScale; + for (int n = 0; n < columns_count; n++) + table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; + } + table->RefScale = new_ref_scale_unit; + + inner_window->SkipItems = true; + + if (table->ColumnsNames.Buf.Size > 0) + table->ColumnsNames.Buf.resize(0); + + TableBeginApplyRequests(table); + + return true; +} + +void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) +{ + ImSpanAllocator<3> span_allocator; + span_allocator.ReserveBytes(0, columns_count * sizeof(ImGuiTableColumn)); + span_allocator.ReserveBytes(1, columns_count * sizeof(ImGuiTableColumnIdx)); + span_allocator.ReserveBytes(2, columns_count * sizeof(ImGuiTableCellData)); + 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); +} + +void ImGui::TableBeginApplyRequests(ImGuiTable* table) +{ + 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; + + if (table->AutoFitSingleColumn != -1) + { + TableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto); + table->AutoFitSingleColumn = -1; + } + } + + if (table->InstanceCurrent == 0) + { + if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1) + table->ReorderColumn = -1; + table->HeldHeaderColumn = -1; + if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0) + { + 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); + + 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; + } + } + + 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; + } +} + +static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) +{ + ImGuiTableColumnFlags flags = flags_in; + + 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_)); + } + + if ((table->Flags & ImGuiTableFlags_Resizable) == 0) + flags |= ImGuiTableColumnFlags_NoResize; + + if ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending)) + flags |= ImGuiTableColumnFlags_NoSort; + + if ((flags & ImGuiTableColumnFlags_IndentMask_) == 0) + flags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable; + + column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_); + + 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); + } +} + +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; + table->EnabledMaskByIndex = 0x00; + table->EnabledMaskByDisplayOrder = 0x00; + table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); + + int count_fixed = 0; + int count_stretch = 0; + int last_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]; + + if (table->DeclColumnsCount <= column_n) + { + TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); + column->NameOffset = -1; + column->UserID = 0; + column->InitStretchWeightOrWidth = -1.0f; + } + + if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) + column->IsEnabledNextFrame = true; + if (column->IsEnabled != column->IsEnabledNextFrame) + { + column->IsEnabled = column->IsEnabledNextFrame; + table->IsSettingsDirty = true; + if (!column->IsEnabled && column->SortOrder != -1) + table->IsSortSpecsDirty = true; + } + if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) + table->IsSortSpecsDirty = true; + + 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; + + if (!column->IsEnabled) + { + column->IndexWithinEnabledSet = -1; + continue; + } + + column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; + column->NextEnabledColumn = -1; + if (last_visible_column_idx != -1) + table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; + column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; + table->EnabledMaskByIndex |= (ImU64)1 << column_n; + table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder; + last_visible_column_idx = column_n; + IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); + + if (!column->IsPreserveWidthAuto) + column->WidthAuto = TableGetColumnWidthAuto(table, column); + + 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)last_visible_column_idx; + IM_ASSERT(table->RightMostEnabledColumn >= 0); + + if (has_auto_fit_request && table->OuterWindow != table->InnerWindow) + table->InnerWindow->SkipItems = false; + if (has_auto_fit_request) + table->IsSettingsDirty = true; + + float sum_width_requests = 0.0f; + float stretch_sum_weights = 0.0f; + table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column->Flags & ImGuiTableColumnFlags_WidthFixed) + { + float width_auto = column->WidthAuto; + if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable)) + width_auto = fixed_max_width_auto; + + if (column->AutoFitQueue != 0x00) + column->WidthRequest = width_auto; + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n))) + column->WidthRequest = width_auto; + + if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto) + column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); + sum_width_requests += column->WidthRequest; + } + else + { + 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; + + const ImRect work_rect = table->WorkRect; + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + const float width_avail = ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth(); + 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 (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + 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; + } + + if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumn != -1) + column->Flags |= ImGuiTableColumnFlags_NoDirectResize_; + + column->WidthGiven = ImFloor(ImMax(column->WidthRequest, table->MinColumnWidth)); + table->ColumnsGivenWidth += column->WidthGiven; + } + + 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 (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << 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; + } + + 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->LastOuterHeight)); + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0); + + 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; + table->VisibleMaskByIndex = 0x00; + table->RequestOutputMaskByIndex = 0x00; + 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 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); + + if (offset_x_frozen && table->FreezeColumnsCount == visible_n) + { + offset_x += work_rect.Min.x - table->OuterRect.Min.x; + offset_x_frozen = false; + } + + column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; + + if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0) + { + 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; + } + + 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; + + column->MinX = offset_x; + + 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; + + column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1; + column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; + 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->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + + column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x); + column->IsVisibleY = true; + const bool is_visible = column->IsVisibleX; + if (is_visible) + table->VisibleMaskByIndex |= ((ImU64)1 << column_n); + + column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; + if (column->IsRequestOutput) + table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n); + + column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; + if (column->IsSkipItems) + IM_ASSERT(!is_visible); + + 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; + + column->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX; + column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX; + + 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++; + } + + 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; + + 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->BorderX2 = table->InnerClipRect.Max.x; + + TableSetupDrawChannels(table); + + if (table->Flags & ImGuiTableFlags_Resizable) + TableUpdateBorders(table); + table->LastFirstRowHeight = 0.0f; + table->IsLayoutLocked = true; + table->IsUsingHeaders = false; + + if (table->IsContextPopupOpen && table->InstanceCurrent == table->InstanceInteracted) + { + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + if (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) + { + TableDrawContextMenu(table); + EndPopup(); + } + else + { + table->IsContextPopupOpen = false; + } + } + + if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) + TableSortSpecsBuild(table); + + 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); +} + +void ImGui::TableUpdateBorders(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->Flags & ImGuiTableFlags_Resizable); + + 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->LastOuterHeight); + const float hit_y2_head = hit_y1 + table->LastFirstRowHeight; + + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << 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; + + 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 (table->FreezeColumnsCount > 0) + if (column->MaxX < table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsCount - 1]].MaxX) + 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); + KeepAliveID(column_id); + + bool hovered = false, held = false; + bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick); + 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!"); + + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + const ImGuiTableFlags flags = table->Flags; + ImGuiWindow* inner_window = table->InnerWindow; + ImGuiWindow* outer_window = table->OuterWindow; + IM_ASSERT(inner_window == g.CurrentWindow); + IM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow); + + if (table->IsInsideRow) + TableEndRow(table); + + if (flags & ImGuiTableFlags_ContextMenuInBody) + if (table->HoveredColumnBody != -1 && !IsAnyItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + TableOpenContextMenu((int)table->HoveredColumnBody); + + inner_window->DC.PrevLineSize = table->HostBackupPrevLineSize; + inner_window->DC.CurrLineSize = table->HostBackupCurrLineSize; + inner_window->DC.CursorMaxPos = table->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); + table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y); + table->LastOuterHeight = table->OuterRect.GetHeight(); + + 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; + } + + if (!(flags & ImGuiTableFlags_NoClip)) + inner_window->DrawList->PopClipRect(); + inner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back(); + + if ((flags & ImGuiTableFlags_Borders) != 0) + TableDrawBorders(table); + +#if 0 + if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1) + { + ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel]; + dummy_channel->_CmdBuffer.resize(0); + dummy_channel->_IdxBuffer.resize(0); + } +#endif + + table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 0); + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + TableMergeDrawChannels(table); + table->DrawSplitter.Merge(inner_window->DrawList); + + 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; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (table->EnabledMaskByIndex & ((ImU64)1 << column_n)) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) + table->ColumnsAutoFitWidth += column->WidthRequest; + else + table->ColumnsAutoFitWidth += TableGetColumnWidthAuto(table, column); + } + + 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) + { + 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); + } + + 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; + } + + IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!"); + IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= table->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); + PopID(); + + const ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos; + inner_window->WorkRect = table->HostBackupWorkRect; + inner_window->ParentWorkRect = table->HostBackupParentWorkRect; + inner_window->SkipItems = table->HostSkipItems; + outer_window->DC.CursorPos = table->OuterRect.Min; + outer_window->DC.ItemWidth = table->HostBackupItemWidth; + outer_window->DC.ItemWidthStack.Size = table->HostBackupItemWidthStackSize; + outer_window->DC.ColumnsOffset = table->HostBackupColumnsOffset; + + if (inner_window != outer_window) + { + EndChild(); + } + else + { + ItemSize(table->OuterRect.GetSize()); + ItemAdd(table->OuterRect, 0); + } + + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + 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 (table->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 - table->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 (table->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 - table->UserOuterSize.y); + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y)); + } + else + { + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table->OuterRect.Max.y); + } + + if (table->IsSettingsDirty) + TableSaveSettings(table); + table->IsInitializing = false; + + IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table); + g.CurrentTableStack.pop_back(); + g.CurrentTable = g.CurrentTableStack.Size ? g.Tables.GetByIndex(g.CurrentTableStack.back().Index) : NULL; + outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; +} + +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++; + + 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."); + + 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; + + column->InitStretchWeightOrWidth = init_width_or_weight; + if (table->IsInitializing) + { + 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; + + if (init_width_or_weight > 0.0f) + column->AutoFitQueue = 0x00; + } + + if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) + column->IsEnabled = column->IsEnabledNextFrame = false; + if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) + { + column->SortOrder = 0; + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + } + } + + column->NameOffset = -1; + if (label != NULL && label[0] != 0) + { + column->NameOffset = (ImS16)table->ColumnsNames.size(); + table->ColumnsNames.append(label, label + strlen(label) + 1); + } +} + +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); + + table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)columns : 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); +} + +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 ""; + const ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->NameOffset == -1) + return ""; + return &table->ColumnsNames.Buf[column->NameOffset]; +} + +void ImGui::TableSetColumnEnabled(int column_n, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + if (!table) + return; + if (column_n < 0) + column_n = table->CurrentColumn; + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->IsEnabledNextFrame = enabled; +} + +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; +} + +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->CellSpacingX1; + if (column->NextEnabledColumn == -1) + x2 += table->CellSpacingX2; + return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); +} + +ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) +{ + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; + return id; +} + +int ImGui::TableGetHoveredColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return -1; + return (int)table->HoveredColumnBody; +} + +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; + + switch (target) + { + case ImGuiTableBgTarget_CellBg: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) + return; + if (column_n == -1) + column_n = table->CurrentColumn; + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + 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) + return; + IM_ASSERT(column_n == -1); + int bg_idx = (target == ImGuiTableBgTarget_RowBg1) ? 1 : 0; + table->RowBgColor[bg_idx] = color; + break; + } + default: + IM_ASSERT(0); + } +} + +int ImGui::TableGetRowIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentRow; +} + +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); + + table->RowPosY2 += table->CellPaddingY * 2.0f; + table->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height); + + table->InnerWindow->SkipItems = true; +} + +void ImGui::TableBeginRow(ImGuiTable* table) +{ + ImGuiWindow* window = table->InnerWindow; + IM_ASSERT(!table->IsInsideRow); + + table->CurrentRow++; + table->CurrentColumn = -1; + table->RowBgColor[0] = table->RowBgColor[1] = IM_COL32_DISABLE; + table->RowCellDataCurrent = -1; + table->IsInsideRow = true; + + 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; + window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.CursorMaxPos.y = next_y1; + + if (table->RowFlags & ImGuiTableRowFlags_Headers) + { + TableSetBgColor(ImGuiTableBgTarget_RowBg0, GetColorU32(ImGuiCol_TableHeaderBg)); + if (table->CurrentRow == 0) + table->IsUsingHeaders = true; + } +} + +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); + + if (g.LogEnabled) + LogRenderedText(NULL, "|"); + + window->DC.CursorPos.y = table->RowPosY2; + + 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) + table->LastFirstRowHeight = bg_y2 - bg_y1; + + const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y); + if (is_visible) + { + 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]; + + 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) + { + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4(); + table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0); + } + + 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); + } + + 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++) + { + 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); + 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); + } + } + + 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); + + 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); + } + + if (unfreeze_rows_request) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->NavLayerCurrent = (ImS8)((column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); + } + if (unfreeze_rows_actual) + { + IM_ASSERT(table->IsUnfrozenRows == false); + table->IsUnfrozenRows = true; + + float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); + 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; + } + + 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; +} + +int ImGui::TableGetColumnIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentColumn; +} + +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 (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; +} + +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); + } + + int column_n = table->CurrentColumn; + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; +} + + +void ImGui::TableBeginCell(ImGuiTable* table, int column_n) +{ + ImGuiTableColumn* column = &table->Columns[column_n]; + ImGuiWindow* window = table->InnerWindow; + table->CurrentColumn = column_n; + + float start_x = column->WorkMinX; + + if (column->Flags & ImGuiTableColumnFlags_IndentEnable) + start_x += table->RowIndentOffsetX; + 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; + window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; + window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; + + 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; + + if (!column->IsEnabled) + window->DC.CursorPos.y = ImMax(window->DC.CursorPos.y, table->RowPosY2); + + window->SkipItems = column->IsSkipItems; + if (column->IsSkipItems) + { + window->DC.LastItemId = 0; + window->DC.LastItemStatusFlags = 0; + } + + if (table->Flags & ImGuiTableFlags_NoClip) + { + table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + } + else + { + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); + } + + ImGuiContext& g = *GImGui; + if (g.LogEnabled && !column->IsSkipItems) + { + LogRenderedText(&window->DC.CursorPos, "|"); + g.LogLinePosY = FLT_MAX; + } +} + +void ImGui::TableEndCell(ImGuiTable* table) +{ + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + ImGuiWindow* window = table->InnerWindow; + + float* p_max_pos_x; + if (table->RowFlags & ImGuiTableRowFlags_Headers) + p_max_pos_x = &column->ContentMaxXHeadersUsed; + else + p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen; + *p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x); + table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); + column->ItemWidth = window->DC.ItemWidth; + + table->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset); +} + +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) + { + 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) + { + max_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - column->MinX; + max_width -= table->CellSpacingX2; + max_width -= table->CellPaddingX * 2.0f; + max_width -= table->OuterPaddingX; + } + return max_width; +} + +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); + + 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); +} + +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; + + 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; + + ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL; + + 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; + } + + if (column_1 == NULL) + column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL; + if (column_1 == NULL) + return; + + 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; +} + +void ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n) +{ + 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)) + continue; + column->CannotSkipItemsQueue = (1 << 0); + column->AutoFitQueue = (1 << 1); + } +} + +void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table) +{ + IM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1); + + 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); + + 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); + } +} + +void ImGui::TablePushBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + + 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]; + + SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect); + table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); +} + +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 || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +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; + } + + table->BgClipRect = table->InnerClipRect; + table->Bg0ClipRectForDrawCmd = table->OuterWindow->ClipRect; + table->Bg2ClipRectForDrawCmd = table->HostClipRect; + IM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y); +} + +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); + + struct MergeGroup + { + ImRect ClipRect; + int ChannelsCount; + ImBitArray ChannelsMask; + }; + int merge_group_mask = 0x00; + MergeGroup merge_groups[4]; + memset(merge_groups, 0, sizeof(merge_groups)); + + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + 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; + + ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; + if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0) + src_channel->_CmdBuffer.pop_back(); + if (src_channel->_CmdBuffer.Size != 1) + continue; + + if (!(column->Flags & ImGuiTableColumnFlags_NoClip)) + { + float content_max_x; + if (!has_freeze_v) + content_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); + else if (merge_group_sub_n == 0) + content_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed); + else + content_max_x = column->ContentMaxXUnfrozen; + 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 < IMGUI_TABLE_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); + merge_group->ChannelsMask.SetBit(channel_no); + merge_group->ChannelsCount++; + merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect); + merge_group_mask |= (1 << merge_group_n); + } + + column->DrawChannelCurrent = (ImGuiTableDrawChannelIdx)-1; + } + +#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 + + if (merge_group_mask != 0) + { + const int LEADING_DRAW_CHANNELS = 2; + g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); + ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; + ImBitArray remaining_mask; + remaining_mask.ClearAllBits(); + remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count); + remaining_mask.ClearBit(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->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; + + 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); +#if 0 + GetOverlayDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, ~0, 1.0f); + GetOverlayDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); + GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); +#endif + remaining_count -= merge_group->ChannelsCount; + for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++) + remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n]; + for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) + { + if (!merge_group->ChannelsMask.TestBit(n)) + continue; + merge_group->ChannelsMask.ClearBit(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)); + } + } + + if (merge_group_n == 1 && has_freeze_v) + memcpy(dst_tmp++, &splitter->_Channels[table->Bg2DrawChannelUnfrozen], sizeof(ImDrawChannel)); + } + + for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) + { + if (!remaining_mask.TestBit(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)); + } +} + +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); + + 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->LastFirstRowHeight) : draw_y1; + if (table->Flags & ImGuiTableFlags_BordersInnerV) + { + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << 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 != -1 && table->FreezeColumnsCount == order_n + 1); + if (column->MaxX > table->InnerClipRect.Max.x && !is_resized) + continue; + + 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) + continue; + + 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); + } + } + + if (table->Flags & ImGuiTableFlags_BordersOuter) + { + 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) + { + 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(); +} + +ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + + if (!(table->Flags & ImGuiTableFlags_Sortable)) + return NULL; + + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + if (table->IsSortSpecsDirty) + TableSortSpecsBuild(table); + + return &table->SortSpecs; +} + +static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n) +{ + IM_ASSERT(n < column->SortDirectionsAvailCount); + return (column->SortDirectionsAvailList >> (n << 1)) & 0x03; +} + +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; +} + +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; +} + +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); + + 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++) + { + 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; + + 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; + } + } + } + + 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) +{ + IM_ASSERT(table->IsSortSpecsDirty); + TableSortSpecsSanitize(table); + + table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; + 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; + table->SortSpecs.SpecsDirty = true; + table->IsSortSpecsDirty = false; +} + +float ImGui::TableGetHeaderRowHeight() +{ + float row_height = GetTextLineHeight(); + int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + if (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_IsEnabled) + row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y); + row_height += GetStyle().CellPadding.y * 2.0f; + return row_height; +} + +void ImGui::TableHeadersRow() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); + + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + const float row_y1 = GetCursorScreenPos().y; + const float row_height = TableGetHeaderRowHeight(); + TableNextRow(ImGuiTableRowFlags_Headers, row_height); + if (table->HostSkipItems) + return; + + const int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + if (!TableSetColumnIndex(column_n)) + continue; + + const char* name = TableGetColumnName(column_n); + PushID(table->InstanceCurrent * table->ColumnsCount + column_n); + TableHeader(name); + PopID(); + } + + 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); +} + +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]; + + if (label == NULL) + label = ""; + const char* label_end = FindRenderedTextEnd(label); + ImVec2 label_size = CalcTextSize(label, label_end, true); + ImVec2 label_pos = window->DC.CursorPos; + + ImRect cell_r = TableGetCellBgRect(table, column_n); + float label_height = ImMax(label_size.y, table->RowMinHeight - table->CellPaddingY * 2.0f); + + 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; + } + } + + 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); + + 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)); + if (!ItemAdd(bb, id)) + return; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); + if (held || hovered || selected) + { + const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + else + { + if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); + } + if (held) + table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; + window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; + + if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive) + { + table->ReorderColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + + 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; + } + + const float ellipsis_max = cell_r.Max.x - w_arrow - w_sort_text; + 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); + } + + if (pressed && table->ReorderColumn != column_n) + { + ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column); + TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift); + } + } + + 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.HoveredIdNotActiveTimer > g.TooltipSlowDelay) + SetTooltip("%.*s", (int)(label_end - label), label); + + if (IsMouseReleased(1) && IsItemHovered()) + TableOpenContextMenu(column_n); +} + +void ImGui::TableOpenContextMenu(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (column_n == -1 && table->CurrentColumn != -1) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) + 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); + } +} + +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; + + if (table->Flags & ImGuiTableFlags_Resizable) + { + if (column != NULL) + { + const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled; + if (MenuItem("Size column to fit###SizeOne", NULL, false, can_resize)) + TableSetColumnWidthAutoSingle(table, column_n); + } + + const char* size_all_desc; + if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame) + size_all_desc = "Size all columns to fit###SizeAll"; + else + size_all_desc = "Size all columns to default###SizeAll"; + if (MenuItem(size_all_desc, NULL)) + TableSetColumnWidthAutoAll(table); + want_separator = true; + } + + if (table->Flags & ImGuiTableFlags_Reorderable) + { + if (MenuItem("Reset order", NULL, false, !table->IsDefaultDisplayOrder)) + table->IsResetDisplayOrderRequest = true; + want_separator = true; + } + +#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 + + 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]; + const char* name = TableGetColumnName(table, other_column_n); + if (name == NULL || name[0] == 0) + name = ""; + + bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true; + if (other_column->IsEnabled && table->ColumnsEnabledCount <= 1) + menu_item_active = false; + if (MenuItem(name, NULL, other_column->IsEnabled, menu_item_active)) + other_column->IsEnabledNextFrame = !other_column->IsEnabled; + } + PopItemFlag(); + } +} + +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; +} + +ImGuiTableSettings* ImGui::TableSettingsFindByID(ImGuiID id) +{ + 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; +} + +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; + settings->ID = 0; + } + return NULL; +} + +void ImGui::TableResetSettings(ImGuiTable* table) +{ + table->IsInitializing = table->IsSettingsDirty = true; + table->IsResetAllRequest = false; + table->IsSettingsRequestLoad = false; + table->SettingsLoadedFlags = ImGuiTableFlags_None; +} + +void ImGui::TableSaveSettings(ImGuiTable* table) +{ + table->IsSettingsDirty = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + 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; + + 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->IsEnabled; + column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0; + if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0) + save_ref_scale = true; + + 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->IsEnabled != ((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; + + ImGuiTableSettings* settings; + if (table->SettingsOffset == -1) + { + settings = TableSettingsFindByID(table->ID); + if (settings == NULL) + return; + if (settings->ColumnsCount != table->ColumnsCount) + table->IsSettingsDirty = true; + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + else + { + settings = TableGetBoundSettings(table); + } + + table->SettingsLoadedFlags = settings->SaveFlags; + table->RefScale = settings->RefScale; + + 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->IsEnabled = column->IsEnabledNextFrame = column_settings->IsEnabled; + column->SortOrder = column_settings->SortOrder; + column->SortDirection = column_settings->SortDirection; + } + + 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; + + 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.GetSize(); i++) + g.Tables.GetByIndex(i)->SettingsOffset = -1; + g.SettingsTables.clear(); +} + +static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetSize(); i++) + { + ImGuiTable* table = g.Tables.GetByIndex(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); + return settings; + } + settings->ID = 0; + } + return ImGui::TableSettingsCreate(id, columns_count); +} + +static void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + 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) + continue; + + 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); + 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++) + { + 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::TableSettingsInstallHandler(ImGuiContext* context) +{ + ImGuiContext& g = *context; + 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; + g.SettingsHandlers.push_back(ini_handler); +} + +void ImGui::TableRemove(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + int table_idx = g.Tables.GetIndex(table); + g.Tables.Remove(table->ID, table); + g.TablesLastTimeActive[table_idx] = -1.0f; +} + +void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->MemoryCompacted == false); + table->DrawSplitter.ClearFreeMemory(); + table->SortSpecsMulti.clear(); + table->SortSpecs.Specs = NULL; + table->IsSortSpecsDirty = true; + 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::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); +} + + +#ifndef IMGUI_DISABLE_METRICS_WINDOW + +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) +{ + char buf[512]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + const bool is_active = (table->LastFrameActive >= ImGui::GetFrameCount() - 2); + ImFormatString(p, buf_end - p, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(table, "%s", buf); + 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; + 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); + 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); + 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 + +void ImGui::DebugNodeTable(ImGuiTable*) {} +void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {} + +#endif + + +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) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(column_index > 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); +} + +void ImGui::PushColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + 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; + + SetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); +} + +ImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) +{ + 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(); + + 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); + + 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; + + columns->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostInitialClipRect = window->ClipRect; + columns->HostBackupParentWorkRect = window->ParentWorkRect; + window->ParentWorkRect = window->WorkRect; + + 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; + + if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) + columns->Columns.resize(0); + + 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++) + { + 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); + } + + 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; +} + +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; + } + + if (++columns->Current == columns->Count) + columns->Current = 0; + + PopItemWidth(); + + 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) + { + window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; + } + else + { + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + 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; + + 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; + + bool is_being_resized = false; + if (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems) + { + 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)); + KeepAliveID(column_id); + if (IsClippedEx(column_hit_rect, column_id, false)) + 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; + } + + 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); + } + + 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); +} + +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); + 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 + +``` + +`SpyCustom/imgui/imgui_widgets.cpp`: + +```cpp +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#ifdef OLDSTYLE +const ImU32 colWhite = 0xFFC1C1C1; const ImU32 colBlack = 0xFF585858; const ImU32 colWhiteText = 0xFFD9D9D9; +#else +const ImU32 colWhite = 0xB2C1C1C1; const ImU32 colBlack = 0xB2585858; const ImU32 colWhiteText = 0xB2D9D9D9; +#endif + +#include +#if defined(_MSC_VER) && _MSC_VER <= 1500 +#include +#else +#include +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4127) +#pragma warning (disable: 4996) +#if defined(_MSC_VER) && _MSC_VER >= 1922 +#pragma warning (disable: 5054) +#endif +#endif + +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wenum-enum-conversion" +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f; +static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f; + +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; +static const ImS32 IM_S32_MAX = INT_MAX; +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = UINT_MAX; +#ifdef LLONG_MIN +static const ImS64 IM_S64_MIN = LLONG_MIN; +static const ImS64 IM_S64_MAX = LLONG_MAX; +#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; +#else +static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); +#endif + +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); + +void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(text != NULL); + const char* text_begin = text; + if (text_end == NULL) + text_end = text + strlen(text); + + 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) + { + const char* line = text; + float line_height = GetTextLineHeight(); + ImVec2 text_size(0, 0); + + 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; + } + } + + if (line < text_end) + { + ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); + while (line < text_end) + { + if (IsClippedEx(line_rect, 0, false)) + 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; + } + + 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); + } + else + { + 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; + + RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); + } +} + +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; + + ImGuiContext& g = *GImGui; + const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + TextEx(g.TempBuffer, 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); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); + else + 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]); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); + else + 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; + bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); + if (need_backup) + PushTextWrapPos(0.0f); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); + else + 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); +} + +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 ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2)); + const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y * 2) + label_size); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0)) + return; + + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f, 0.5f)); + 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); +} + +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 = g.TempBuffer; + const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), 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); + 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; + + 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); +} + +bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + if (flags & ImGuiButtonFlags_Disabled) + { + if (out_hovered) *out_hovered = false; + if (out_held) *out_held = false; + if (g.ActiveId == id) ClearActiveID(); + return false; + } + + if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) + flags |= ImGuiButtonFlags_MouseButtonDefault_; + + if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) + flags |= ImGuiButtonFlags_PressedOnDefault_; + + ImGuiWindow* backup_hovered_window = g.HoveredWindow; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window; + if (flatten_hovered_children) + g.HoveredWindow = window; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0 && window->DC.LastItemId != id) + IMGUI_TEST_ENGINE_ITEM_ADD(bb, id); +#endif + + bool pressed = false; + bool hovered = ItemHoverable(bb, id); + + if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + hovered = false; + + if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + hovered = true; + SetHoveredID(id); + if (CalcTypematicRepeatAmount(g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, g.HoveredIdTimer + 0.0001f, DRAGDROP_HOLD_TO_OPEN_TIMER, 0.00f)) + { + pressed = true; + g.DragDropHoldJustPressedId = id; + FocusWindow(window); + } + } + + if (flatten_hovered_children) + g.HoveredWindow = backup_hovered_window; + + if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + hovered = false; + + if (hovered) + { + if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) + { + int mouse_button_clicked = -1; + int mouse_button_released = -1; + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && g.IO.MouseClicked[0]) { mouse_button_clicked = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && g.IO.MouseClicked[1]) { mouse_button_clicked = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && g.IO.MouseClicked[2]) { mouse_button_clicked = 2; } + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && g.IO.MouseReleased[0]) { mouse_button_released = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && g.IO.MouseReleased[1]) { mouse_button_released = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && g.IO.MouseReleased[2]) { mouse_button_released = 2; } + + if (mouse_button_clicked != -1 && g.ActiveId != 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.MouseDoubleClicked[mouse_button_clicked])) + { + pressed = true; + if (flags & ImGuiButtonFlags_NoHoldingActiveId) + ClearActiveID(); + else + SetActiveID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + FocusWindow(window); + } + } + if ((flags & ImGuiButtonFlags_PressedOnRelease) && mouse_button_released != -1) + { + const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; + if (!has_repeated_at_least_once) + pressed = true; + ClearActiveID(); + } + + if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) + if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, true)) + pressed = true; + } + + if (pressed) + g.NavDisableHighlight = true; + } + + 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 = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + if (nav_activated_by_code || nav_activated_by_inputs) + pressed = true; + if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) + { + g.NavActivateId = id; + SetActiveID(id, window); + if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + } + } + + 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; + IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); + if (g.IO.MouseDown[mouse_button]) + { + 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) + { + bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDownWasDoubleClick[mouse_button]; + bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; + if (!is_double_click_release && !is_repeating_already) + pressed = true; + } + ClearActiveID(); + } + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + g.NavDisableHighlight = true; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + 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) + 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); + + + ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, id)) + return false; + + + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + + if (!held) { + RenderFrame(bb.Min - ImVec2(1, 1), bb.Max - ImVec2(0, 0), colWhite, true, style.FrameRounding); + RenderFrame(bb.Min + ImVec2(0, 0), bb.Max + ImVec2(1, 1), colBlack, true, style.FrameRounding); + } + else + { + RenderFrame(bb.Min - ImVec2(1, 1), bb.Max - ImVec2(0, 0), colBlack, true, style.FrameRounding); + RenderFrame(bb.Min + ImVec2(0, 0), bb.Max + ImVec2(1, 1), colWhite, true, style.FrameRounding); + } + + const ImU32 col = GetColorU32(ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + + if (g.LogEnabled) + LogSetNextTextDecoration("[", "]"); + + if (!held) { + RenderTextClipped(bb.Min + style.FramePadding - ImVec2(1,1), bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + } + else + { + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding + ImVec2(2.0f, 2.0f), label, NULL, &label_size, style.ButtonTextAlign, &bb); + } + + + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + + ImVec2 newpos = window->DC.CursorPos; + window->DC.CursorPos = newpos + ImVec2(0, 8.0f); + + return pressed; +} + +bool ImGui::Button(const char* label, const ImVec2& size_arg) +{ + return ButtonEx(label, size_arg, ImGuiButtonFlags_None); +} + +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; +} + +bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + 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); + + return pressed; +} + +bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + 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; + + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + ImU32 bg_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + 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); + + window->DrawList->AddLine(ImVec2(bb.Min.x - 1.0f, bb.Min.y), ImVec2(bb.Max.x - 1.0f, bb.Min.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(bb.Min.x - 1.0f, bb.Min.y), ImVec2(bb.Min.x - 1.0f, bb.Max.y), 0xFFA2A2A2, 1.0f); + + window->DrawList->AddLine(ImVec2(bb.Max.x - 1.0f, bb.Min.y), ImVec2(bb.Max.x - 1.0f, bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(bb.Min.x - 1.0f, bb.Max.y), ImVec2(bb.Max.x - 1.0f, bb.Max.y), colWhite, 1.0f); + return pressed; +} + +bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) +{ + float sz = GetFrameHeight(); + return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); +} + +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + bool is_clipped = !ItemAdd(bb, id); + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + if (is_clipped) + return pressed; + + 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, 12); + + 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); + + ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImVec2 center = bb.GetCenter(); + if (hovered || held) + window->DrawList->AddCircleFilled(center , g.FontSize * 0.5f + 1.0f, bg_col, 12); + RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); + + if (IsItemActive() && IsMouseDragging(0)) + StartMouseMovingWindow(window); + + return pressed; +} + +ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +{ + return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); +} + +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]; + 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, outer_rect.Max.y); + else + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x, inner_rect.Max.y); +} + +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiID id = GetWindowScrollbarID(window, axis); + KeepAliveID(id); + + ImRect bb = GetWindowScrollbarRect(window, axis); + ImDrawCornerFlags rounding_corners = 0; + if (axis == ImGuiAxis_X) + { + rounding_corners |= ImDrawCornerFlags_BotLeft; + if (!window->ScrollbarY) + rounding_corners |= ImDrawCornerFlags_BotRight; + } + else + { + if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) + rounding_corners |= ImDrawCornerFlags_TopRight; + if (!window->ScrollbarX) + rounding_corners |= ImDrawCornerFlags_BotRight; + } + float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; + float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; + ScrollbarEx(bb, id, axis, &window->Scroll[axis], size_avail, size_contents, rounding_corners); +} + +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawCornerFlags rounding_corners) +{ + 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; + + 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))); + + const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight(); + + IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); + const float win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), 1.0f); + const float grab_h_pixels = ImClamp(scrollbar_size_v * (size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); + const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + + bool held = false; + bool hovered = false; + ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + + float scroll_max = ImMax(1.0f, size_contents_v - size_avail_v); + float scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); + float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + if (held && allow_interaction && grab_h_norm < 1.0f) + { + float scrollbar_pos_v = bb.Min[axis]; + float mouse_pos_v = g.IO.MousePos[axis]; + + const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); + SetHoveredID(id); + + bool seek_absolute = false; + if (g.ActiveIdIsJustActivated) + { + 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; + } + + const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); + *p_scroll_v = IM_ROUND(scroll_v_norm * scroll_max); + + scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); + grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + const ImU32 grab_col = GetColorU32(ImGuiCol_ScrollbarGrabActive) ; + const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, rounding_corners); + 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); + + RenderFrame(grab_rect.Min - ImVec2(1, 1), grab_rect.Max - ImVec2(0, 0), colWhite, true, style.FrameRounding); + RenderFrame(grab_rect.Min + ImVec2(0, 0), grab_rect.Max + ImVec2(1, 1), colBlack, true, style.FrameRounding); + 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)); + } +} + +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); + ItemSize(bb); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + 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(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; + + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + + const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : g.Style.FramePadding; + return ImageButtonEx(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col); +} + +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; + 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)); + total_bb.Max.y += 10.0f; + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + { + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | 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); + } + + ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + RenderNavHighlight(total_bb, id); + + check_bb.Max.x -= 10.0f; + check_bb.Max.y -= 10.0f; + + RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + + window->DrawList->AddLine(ImVec2(check_bb.Min.x - 1.0f, check_bb.Min.y), ImVec2(check_bb.Max.x - 1.0f, check_bb.Min.y ), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(check_bb.Min.x - 1.0f, check_bb.Min.y), ImVec2(check_bb.Min.x - 1.0f, check_bb.Max.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(check_bb.Max.x - 1.0f, check_bb.Min.y), ImVec2(check_bb.Max.x - 1.0f, check_bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(check_bb.Min.x - 1.0f, check_bb.Max.y), ImVec2(check_bb.Max.x - 1.0f, check_bb.Max.y), colWhite, 1.0f); + + ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); + bool mixed_value = (window->DC.ItemFlags & ImGuiItemFlags_MixedValue) != 0; + if (mixed_value) + { + 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) - ImVec2(2.0f,1.0f), check_col, square_sz - pad * 2.0f - 7.0f); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + label_pos.y -= 5.0f; label_pos.x += 3.0f; + if (g.LogEnabled) + LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + if (label_size.x > 0.0f) { + if (*v) + RenderText(label_pos, label, 0, 1); + else + RenderText(label_pos, label, 0, 1, colWhiteText); + } + + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | 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) + { + ImGuiWindow* window = GetCurrentWindow(); + ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_MixedValue; + pressed = Checkbox(label, &all_on); + window->DC.ItemFlags = backup_item_flags; + } + 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); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); + if (active) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); + } + + if (style.FrameBorderSize > 0.0f) + { + window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, 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, window->DC.ItemFlags); + return pressed; +} + +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; +} + +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; + + 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); + + 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 + g.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; + } + + 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); +} + +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; + if (window->DC.CurrLineSize.y > 0.0f) + 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); +} + +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); + + float thickness_draw = 1.0f; + float thickness_layout = 0.0f; + if (flags & ImGuiSeparatorFlags_Vertical) + { + 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_draw, y2)); + ItemSize(ImVec2(thickness_layout, 0.0f)); + if (!ItemAdd(bb, 0)) + return; + + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogText(" |"); + } + else if (flags & ImGuiSeparatorFlags_Horizontal) + { + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + + if (g.GroupStack.Size > 0 && g.GroupStack.back().WindowID == window->ID) + x1 += window->DC.Indent.x; + + ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + if (columns) + PushColumnsBackground(); + + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); + ItemSize(ImVec2(0.0f, thickness_layout)); + const bool item_visible = ItemAdd(bb, 0); + if (item_visible) + { + window->DrawList->AddLine(ImVec2(bb.Min.x + 19.0f, bb.Min.y), ImVec2(bb.Max.x - 74.0f, bb.Min.y), colBlack); + 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; + + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + flags |= ImGuiSeparatorFlags_SpanAllColumns; + SeparatorEx(flags); +} + +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) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; + bool item_add = ItemAdd(bb, id); + window->DC.ItemFlags = item_flags_backup; + if (!item_add) + return false; + + 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, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); + + if (held || (g.HoveredId == id && 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; + + 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; + + 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); + } + } + + 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); +} + +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; + } + + 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; + } + if (width_excess > 0.0f) + for (int n = 0; n < count; n++) + if (items[n].Index < (int)(width_excess + 0.01f)) + items[n].Width += 1.0f; +} + +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; + bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0; + g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint; + + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); + + ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const float expected_w = CalcItemWidth(); + const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w; + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + ImRect total_bb(frame_bb.Min - ImVec2(0.0f,10.0f), frame_bb.Max + ImVec2(style.ItemInnerSpacing.x,-10.0f)); + total_bb.Max.y += 10.0f; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); + bool popup_open = IsPopupOpen(id, ImGuiPopupFlags_None); + + const ImU32 frame_col = GetColorU32(ImGuiCol_FrameBg); + + const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size); + RenderNavHighlight(frame_bb, id); + if (!(flags & ImGuiComboFlags_NoPreview)) + window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Left); + + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Min.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), colWhite, 1.0f); + + + if (!(flags & ImGuiComboFlags_NoArrowButton)) + { + ImU32 bg_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + window->DrawList->AddRectFilled(ImVec2(value_x2 + 1.0f, frame_bb.Min.y + 1.0f), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); + + if (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x) + RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + } + RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); + if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) + { + ImVec2 preview_pos = frame_bb.Min + style.FramePadding; + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(preview_pos, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f, 0.0f)); + } + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y - 20.0f), label); + + if ((pressed || g.NavActivateId == id) && !popup_open) + { + if (window->DC.NavLayerCurrent == 0) + window->NavLastIds[0] = id; + OpenPopupEx(id, ImGuiPopupFlags_None); + popup_open = true; + } + + if (!popup_open) + return false; + + if (has_window_size_constraint) + { + 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_)); + 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; + SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + } + + char name[16]; + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); + + if (ImGuiWindow* popup_window = FindWindowByName(name)) + if (popup_window->WasActive) + { + ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window); + if (flags & ImGuiComboFlags_PopupAlignLeft) + popup_window->AutoPosLastDirection = ImGuiDir_Left; + else + popup_window->AutoPosLastDirection = ImGuiDir_Down; + ImRect r_outer = GetWindowAllowedExtentRect(popup_window); + ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox); + SetNextWindowPos(pos); + } + + ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; + + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y)); + bool ret = Begin(name, NULL, window_flags); + PopStyleVar(); + if (!ret) + { + EndPopup(); + IM_ASSERT(0); + return false; + } + return true; +} + +void ImGui::EndCombo() +{ + EndPopup(); +} + +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; +} + +static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) +{ + 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; +} + +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; + + const char* preview_value = NULL; + if (*current_item >= 0 && *current_item < items_count) + items_getter(data, *current_item, &preview_value); + + 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; + + bool value_changed = false; + for (int i = 0; i < items_count; i++) + { + PushID((void*)(intptr_t)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)) + { + value_changed = true; + *current_item = i; + } + if (item_selected) { + SetItemDefaultFocus(); + } + PopID(); + } + + EndCombo(); + if (value_changed) { + MarkItemEdited(g.CurrentWindow->DC.LastItemId); + } + + return value_changed; +} + +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; +} + +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; + 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; +} + +static const ImGuiDataTypeInfo GDataTypeInfo[] = +{ + { sizeof(char), "S8", "%d", "%d" }, + { sizeof(unsigned char), "U8", "%u", "%u" }, + { sizeof(short), "S16", "%d", "%d" }, + { sizeof(unsigned short), "U16", "%u", "%u" }, + { sizeof(int), "S32", "%d", "%d" }, + { sizeof(unsigned int), "U32", "%u", "%u" }, +#ifdef _MSC_VER + { sizeof(ImS64), "S64", "%I64d","%I64d" }, + { sizeof(ImU64), "U64", "%I64u","%I64u" }, +#else + { sizeof(ImS64), "S64", "%lld", "%lld" }, + { sizeof(ImU64), "U64", "%llu", "%llu" }, +#endif + { sizeof(float), "float", "%f", "%f" }, + { sizeof(double), "double","%f", "%lf" }, +}; +IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); + +static const char* PatchFormatStringFloatToInt(const char* fmt) +{ + if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) + return "%d"; + const char* fmt_start = ImParseFormatFindStart(fmt); + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end > fmt_start && fmt_end[-1] == 'f') + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (fmt_start == fmt && fmt_end[0] == 0) + return "%d"; + ImGuiContext& g = *GImGui; + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); + return g.TempBuffer; +#else + IM_ASSERT(0 && "DragInt(): Invalid format string!"); +#endif + } + return fmt; +} + +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) +{ + 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); +} + +bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format) +{ + while (ImCharIsBlankA(*buf)) + buf++; + + char op = buf[0]; + if (op == '+' || op == '*' || op == '/') + { + buf++; + while (ImCharIsBlankA(*buf)) + buf++; + } + else + { + op = 0; + } + if (!buf[0]) + return false; + + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, type_info->Size); + + if (format == NULL) + format = type_info->ScanFmt; + + int arg1i = 0; + if (data_type == ImGuiDataType_S32) + { + int* v = (int*)p_data; + int arg0i = *v; + float arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0i) < 1) + return false; + if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } + else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } + else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } + else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } + } + else if (data_type == ImGuiDataType_Float) + { + format = "%f"; + float* v = (float*)p_data; + float arg0f = *v, arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } + else if (op == '*') { *v = arg0f * arg1f; } + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } + else { *v = arg1f; } + } + else if (data_type == ImGuiDataType_Double) + { + format = "%lf"; + double* v = (double*)p_data; + double arg0f = *v, arg1f = 0.0; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } + else if (op == '*') { *v = arg0f * arg1f; } + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } + else { *v = arg1f; } + } + else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + { + sscanf(buf, format, p_data); + } + else + { + int v32; + sscanf(buf, format, &v32); + 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) +{ + 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 +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; +} + +template +TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) +{ + const char* fmt_start = ImParseFormatFindStart(format); + if (fmt_start[0] != '%' || fmt_start[1] == '%') + return v; + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + const char* p = v_str; + while (*p == ' ') + p++; + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v = (TYPE)ImAtof(p); + else + ImAtoi(p, (SIGNEDTYPE*)&v); + return v; +} + +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_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_clamped = (v_min < v_max); + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && is_decimal; + + if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) + v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); + + 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_Nav) + { + int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis]; + v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); + } + adjust_delta *= v_speed; + + if (axis == ImGuiAxis_Y) + adjust_delta = -adjust_delta; + + if (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f)) + adjust_delta /= (float)(v_max - v_min); + + 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; + const float zero_deadzone_halfsize = 0.0f; + if (is_logarithmic) + { + const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + + 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; + } + + if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_cur = RoundScalarWithFormatT(format, data_type, v_cur); + + g.DragCurrentAccumDirty = false; + if (is_logarithmic) + { + 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); + } + + if (v_cur == (TYPE)-0) + v_cur = (TYPE)0; + + if (*v != v_cur && is_clamped) + { + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_decimal)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_decimal)) + v_cur = v_max; + } + + 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) +{ + 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) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (g.ActiveId != id) + return false; + if ((g.CurrentWindow->DC.ItemFlags & 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; +} + +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)); + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + + const bool hovered = ItemHoverable(frame_bb, id); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) + { + const bool focus_requested = temp_input_allowed && FocusableItemRegister(window, id); + const bool clicked = (hovered && g.IO.MouseClicked[0]); + const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); + if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id)) + { + temp_input_is_active = true; + FocusableItemUnregister(window); + } + } + 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.NavInputId = id; + temp_input_is_active = true; + FocusableItemUnregister(window); + } + } + + if (temp_input_is_active) + { + 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); + } + + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + + const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags); + if (value_changed) + MarkItemEdited(id); + + 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); + + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Min.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), colBlack, 1.0f); + + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + 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); +} + +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; +} + +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); +} + +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; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +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, float power) +{ + ImGuiSliderFlags drag_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + IM_ASSERT(p_min != NULL && p_max != NULL); + drag_flags |= ImGuiSliderFlags_Logarithmic; + } + return DragScalar(label, data_type, p_data, v_speed, p_min, p_max, format, drag_flags); +} + +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, float power) +{ + ImGuiSliderFlags drag_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + IM_ASSERT(p_min != NULL && p_max != NULL); + drag_flags |= ImGuiSliderFlags_Logarithmic; + } + return DragScalarN(label, data_type, p_data, components, v_speed, p_min, p_max, format, drag_flags); +} + +#endif + +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) + ImSwap(v_min, v_max); + + 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; + + 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; + else if (v_clamped >= v_max_fudged) + result = 1.0f; + else if ((v_min * v_max) < 0.0f) + { + float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); + 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; + 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)) + 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; + } + + return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min)); +} + +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) +{ + if (v_min == v_max) + return v_min; + const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + + TYPE result; + if (is_logarithmic) + { + if (t <= 0.0f) + result = v_min; + else if (t >= 1.0f) + result = v_max; + else + { + bool flipped = v_max < v_min; + + 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; + + if (flipped) + ImSwap(v_min_fudged, v_max_fudged); + + if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float t_with_flip = flipped ? (1.0f - t) : t; + + if ((v_min * v_max) < 0.0f) + { + float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); + 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; + 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)) + 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 + { + if (is_decimal) + { + result = ImLerp(v_min, v_max, t); + } + else + { + if (t < 1.0) + { + 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))); + } + else + { + result = v_max; + } + } + } + + return result; +} + +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_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && is_decimal; + + const float grab_padding = 2.0f; + const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; + float grab_sz = style.GrabMinSize; + SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + if (!is_decimal && v_range >= 0) + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); + 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; + float zero_deadzone_halfsize = 0.0f; + if (is_logarithmic) + { + const int decimal_precision = is_decimal ? 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); + } + + 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]; + clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + set_new_value = true; + } + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + if (g.ActiveIdIsJustActivated) + { + g.SliderCurrentAccum = 0.0f; + g.SliderCurrentAccumDirty = false; + } + + const ImVec2 input_delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f); + float input_delta = (axis == ImGuiAxis_X) ? input_delta2.x : -input_delta2.y; + if (input_delta != 0.0f) + { + const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + if (decimal_precision > 0) + { + input_delta /= 100.0f; + if (IsNavInputDown(ImGuiNavInput_TweakSlow)) + input_delta /= 10.0f; + } + else + { + if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow)) + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; + else + input_delta /= 100.0f; + } + if (IsNavInputDown(ImGuiNavInput_TweakFast)) + 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)) + { + set_new_value = false; + g.SliderCurrentAccum = 0.0f; + } + else + { + set_new_value = true; + float old_clicked_t = clicked_t; + clicked_t = ImSaturate(clicked_t + delta); + + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (!(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); + + if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); + + if (*v != v_new) + { + *v = v_new; + value_changed = true; + } + } + } + + if (slider_sz < 1.0f) + { + *out_grab_bb = ImRect(bb.Min, bb.Min); + } + else + { + 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; +} + +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) +{ + 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."); + + ImGuiContext& g = *GImGui; + if ((g.CurrentWindow->DC.ItemFlags & 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; +} + +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) +{ + InvisibleButton("##0", ImVec2(0, 0)); + + 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); + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + frame_bb.Max -= ImVec2(style.ItemInnerSpacing.x + 30.0f, 7.0f); + ImRect total_bb(frame_bb.Min + ImVec2(0,20.0f), frame_bb.Max + ImVec2(0, 30.0f)); + frame_bb.Min -= ImVec2(0, 7.0f); + + total_bb.Min += ImVec2(0, 10.0f); + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + + const bool hovered = ItemHoverable(frame_bb, id); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) + { + const bool focus_requested = temp_input_allowed && FocusableItemRegister(window, id); + const bool clicked = (hovered && g.IO.MouseClicked[0]); + if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id)) + { + temp_input_is_active = true; + FocusableItemUnregister(window); + } + } + } + + if (temp_input_is_active) + { + 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); + } + + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + + ImVec2 tempmin = frame_bb.Min + ImVec2(0, 9.0f); + ImVec2 tempmax = frame_bb.Max - ImVec2(0, 9.0f); + + RenderFrame(tempmin, tempmax, frame_col, true, g.Style.FrameRounding); + window->DrawList->AddLine(ImVec2(tempmin.x - 1.0f, tempmin.y - 1.0f), ImVec2(tempmax.x - 1.0f, tempmin.y - 1.0f), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(tempmin.x - 1.0f, tempmin.y - 1.0f), ImVec2(tempmin.x - 1.0f, tempmax.y ), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(tempmax.x - 1.0f, tempmin.y - 1.0f), ImVec2(tempmax.x - 1.0f, tempmax.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(tempmin.x - 1.0f, tempmax.y), ImVec2(tempmax.x - 1.0f, tempmax.y), colWhite, 1.0f); + + + + 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); + + + tempmin.x += 1.0f; tempmax.x -= 2.0f; + tempmin.x += (grab_bb.Max.x - grab_bb.Min.x)/2; + tempmax.x -= (grab_bb.Max.x - grab_bb.Min.x)/2; + + for (int i = 0; i < 11; i++) + window->DrawList->AddLine(ImVec2(tempmin.x + (i * (tempmax.x - tempmin.x) / 10) - 1.0f, tempmax.y + 4.0f), ImVec2(tempmin.x + (i * (tempmax.x - tempmin.x) / 10) - 1.0f, tempmax.y + 9.0f), 0xFFD9D9D9, 1.0f); + + + if (grab_bb.Max.x > grab_bb.Min.x) { + grab_bb.Min.x += 1.0f; grab_bb.Max.x -= 2.0f; + grab_bb.Min.y += 1.0f; grab_bb.Max.y -= 1.0f; + + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + window->DrawList->AddLine(ImVec2(grab_bb.Min.x - 1.0f, grab_bb.Min.y - 1.0f), ImVec2(grab_bb.Max.x - 1.0f, grab_bb.Min.y - 1.0f), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(grab_bb.Min.x - 1.0f, grab_bb.Min.y - 1.0f), ImVec2(grab_bb.Min.x - 1.0f, grab_bb.Max.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(grab_bb.Max.x - 1.0f, grab_bb.Min.y - 1.0f), ImVec2(grab_bb.Max.x - 1.0f, grab_bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(grab_bb.Min.x - 1.0f, grab_bb.Max.y), ImVec2(grab_bb.Max.x - 1.0f, grab_bb.Max.y), colWhite, 1.0f); + } + + 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 + ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0), frame_bb.Max + ImVec2(45.0f, 0), value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + { + RenderText(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y - 20.0f), label); + } + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return value_changed; +} + +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; + + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + + const bool hovered = ItemHoverable(frame_bb, id); + if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + } + + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + 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); + + 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); + + 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); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + slider_flags |= ImGuiSliderFlags_Logarithmic; + } + return SliderScalar(label, data_type, p_data, p_min, p_max, format, slider_flags); +} + +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + slider_flags |= ImGuiSliderFlags_Logarithmic; + } + return SliderScalarN(label, data_type, v, components, v_min, v_max, format, slider_flags); +} + +#endif + +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) +{ + 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; +} + +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) +{ + const char* fmt_start = ImParseFormatFindStart(fmt); + if (fmt_start[0] != '%') + return fmt; + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end[0] == 0) + return fmt_start; + ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); + return buf; +} + +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') + precision = -1; + if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) + precision = -1; + return (precision == INT_MAX) ? default_precision : precision; +} + +bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) +{ + 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); + if (init) + { + IM_ASSERT(g.ActiveId == id); + g.TempInputId = g.ActiveId; + } + return value_changed; +} + +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) +{ + ImGuiContext& g = *GImGui; + + char fmt_buf[32]; + char data_buf[32]; + format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); + ImStrTrimBlanks(data_buf); + + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; + flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); + bool value_changed = false; + if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) + { + size_t data_type_size = DataTypeGetInfo(data_type)->Size; + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); + if (p_clamp_min || p_clamp_max) + { + if (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); + } + + value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (value_changed) + MarkItemEdited(id); + } + return value_changed; +} + +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); + + bool value_changed = false; + if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= ImGuiInputTextFlags_CharsDecimal; + flags |= ImGuiInputTextFlags_AutoSelectAll; + flags |= ImGuiInputTextFlags_NoMarkEdited; + + if (p_step != NULL) + { + const float button_size = GetFrameHeight(); + + BeginGroup(); + PushID(label); + SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + + const ImVec2 backup_frame_padding = style.FramePadding; + style.FramePadding.x = style.FramePadding.y; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + if (flags & ImGuiInputTextFlags_ReadOnly) + button_flags |= ImGuiButtonFlags_Disabled; + 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; + } + + 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(); + } + else + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + } + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + 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) +{ + 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); +} + +bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); + 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)); + 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++) + 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(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +{ + ImGuiContext& g = *GImGui; + 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); + + if (line_width > 0 || text_size.y == 0.0f) + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +namespace ImStb +{ + +static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* 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 = *GImGui; 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, STB_TEXTEDIT_STRING* obj, int line_start_idx) +{ + const ImWchar* text = obj->TextW.Data; + const ImWchar* text_remaining = NULL; + const ImVec2 size = InputTextCalcTextSizeW(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 ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } +static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +#ifdef __APPLE__ +static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx]) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +#else +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +#endif +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL + +static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) +{ + ImWchar* dst = obj->TextW.Data + pos; + + obj->Edited = true; + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + const ImWchar* src = obj->TextW.Data + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; +} + +static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) +{ + const bool is_resizable = (obj->UserFlags & 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; + + 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; +} + +#define STB_TEXTEDIT_K_LEFT 0x200000 +#define STB_TEXTEDIT_K_RIGHT 0x200001 +#define STB_TEXTEDIT_K_UP 0x200002 +#define STB_TEXTEDIT_K_DOWN 0x200003 +#define STB_TEXTEDIT_K_LINESTART 0x200004 +#define STB_TEXTEDIT_K_LINEEND 0x200005 +#define STB_TEXTEDIT_K_TEXTSTART 0x200006 +#define STB_TEXTEDIT_K_TEXTEND 0x200007 +#define STB_TEXTEDIT_K_DELETE 0x200008 +#define STB_TEXTEDIT_K_BACKSPACE 0x200009 +#define STB_TEXTEDIT_K_UNDO 0x20000A +#define STB_TEXTEDIT_K_REDO 0x20000B +#define STB_TEXTEDIT_K_WORDLEFT 0x20000C +#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D +#define STB_TEXTEDIT_K_PGUP 0x20000E +#define STB_TEXTEDIT_K_PGDOWN 0x20000F +#define STB_TEXTEDIT_K_SHIFT 0x400000 + +#define STB_TEXTEDIT_IMPLEMENTATION +#include "imstb_textedit.h" + +static void stb_textedit_replace(STB_TEXTEDIT_STRING* 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); + if (text_len <= 0) + return; + if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len)) + { + state->cursor = text_len; + state->has_preferred_x = 0; + return; + } + IM_ASSERT(0); +} + +} + +void ImGuiInputTextState::OnKeyPressed(int key) +{ + stb_textedit_key(this, &Stb, key); + CursorFollow = true; + CursorAnimReset(); +} + +ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() +{ + memset(this, 0, sizeof(*this)); +} + +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) +{ + 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; + + ImGuiContext& g = *GImGui; + 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; +} + +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + unsigned int c = *p_char; + + if (c < 0x20) + { + bool pass = false; + pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); + pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); + if (!pass) + return false; + } + + if (c == 127) + return false; + + if (c >= 0xE000 && c <= 0xF8FF) + return false; + + if (c > IM_UNICODE_CODEPOINT_MAX) + return false; + + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) + { + ImGuiContext& g = *GImGui; + const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + + if (flags & ImGuiInputTextFlags_CharsDecimal) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + return false; + + if (flags & ImGuiInputTextFlags_CharsScientific) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + return false; + + if (flags & ImGuiInputTextFlags_CharsHexadecimal) + if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) + return false; + + if (flags & ImGuiInputTextFlags_CharsUppercase) + if (c >= 'a' && c <= 'z') + *p_char = (c += (unsigned int)('A' - 'a')); + + if (flags & ImGuiInputTextFlags_CharsNoBlank) + if (ImCharIsBlankW(c)) + return false; + } + + if (flags & ImGuiInputTextFlags_CallbackCharFilter) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + 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; +} + +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))); + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); + + 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); + + if (is_multiline) + 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); + 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); + ImRect total_bb(frame_bb.Min - ImVec2(0.0f, 10.0f), frame_bb.Max + ImVec2(style.ItemInnerSpacing.x, 0.0f)); + + + ImGuiWindow* draw_window = window; + ImVec2 inner_size = frame_size; + if (is_multiline) + { + if (!ItemAdd(total_bb, id, &frame_bb)) + { + ItemSize(total_bb, style.FramePadding.y); + EndGroup(); + return false; + } + + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove); + PopStyleVar(2); + PopStyleColor(); + if (!child_visible) + { + EndChild(); + EndGroup(); + return false; + } + draw_window = g.CurrentWindow; + draw_window->DC.NavLayerActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); + draw_window->DC.CursorPos += style.FramePadding; + inner_size.x -= draw_window->ScrollbarSizes.x; + } + else + { + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + } + const bool hovered = ItemHoverable(frame_bb, id); + if (hovered) + g.MouseCursor = ImGuiMouseCursor_TextInput; + + ImGuiInputTextState* state = GetInputTextState(id); + + const bool focus_requested = FocusableItemRegister(window, id); + const bool focus_requested_by_code = focus_requested && (g.FocusRequestCurrWindow == window && g.FocusRequestCurrCounterRegular == window->DC.FocusCounterRegular); + const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; + + const bool user_clicked = hovered && io.MouseClicked[0]; + const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); + 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 = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); + + float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; + + const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); + const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start); + const bool init_state = (init_make_active || user_scroll_active); + if ((init_state && g.ActiveId != id) || init_changed_specs) + { + state = &g.InputTextState; + state->CursorAnimReset(); + + const int buf_len = (int)strlen(buf); + state->InitialTextA.resize(buf_len + 1); + memcpy(state->InitialTextA.Data, buf, buf_len + 1); + + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); + state->TextA.resize(0); + state->TextAIsValid = false; + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); + + const bool recycle_state = (state->ID == id && !init_changed_specs); + if (recycle_state) + { + state->CursorClamp(); + } + else + { + state->ID = id; + state->ScrollX = 0.0f; + stb_textedit_initialize_state(&state->Stb, !is_multiline); + if (!is_multiline && focus_requested_by_code) + select_all = true; + } + if (flags & ImGuiInputTextFlags_AlwaysInsertMode) + state->Stb.insert_mode = 1; + if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) + select_all = true; + } + + if (g.ActiveId != id && init_make_active) + { + IM_ASSERT(state && state->ID == id); + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + + IM_ASSERT(ImGuiNavInput_COUNT < 32); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End); + if (is_multiline) + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab); + } + + if (g.ActiveId == id && state == NULL) + ClearActiveID(); + + if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) + clear_active_id = true; + + const bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); + bool render_selection = state && state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool value_changed = false; + bool enter_pressed = false; + + 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(); + } + + 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); + + 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); + } + + 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->UserFlags = flags; + state->UserCallback = callback; + state->UserCallbackData = callback_user_data; + + g.ActiveIdAllowOverlap = !io.MouseDown[0]; + g.WantTextInputNextFrame = 1; + + 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)); + + const bool is_osx = io.ConfigMacOSXBehaviors; + if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) + { + state->SelectAll(); + state->SelectedAllMouseLock = true; + } + else if (hovered && is_osx && io.MouseDoubleClicked[0]) + { + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + } + else if (io.MouseClicked[0] && !state->SelectedAllMouseLock) + { + if (hovered) + { + 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; + + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) + if (!io.InputQueueCharacters.contains('\t')) + { + unsigned int c = '\t'; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + + if (io.InputQueueCharacters.Size > 0) + { + if (!ignore_char_inputs && !is_readonly && !user_nav_input_start) + for (int n = 0; n < io.InputQueueCharacters.Size; n++) + { + unsigned int c = (unsigned int)io.InputQueueCharacters[n]; + if (c == '\t' && io.KeyShift) + continue; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + + io.InputQueueCharacters.resize(0); + } + } + + bool cancel_edit = false; + if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) + { + IM_ASSERT(state != NULL); + IM_ASSERT(io.KeyMods == GetMergedKeyModFlags() && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + + 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_osx = io.ConfigMacOSXBehaviors; + const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyModFlags_Super | ImGuiKeyModFlags_Shift)); + const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; + const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; + const bool is_ctrl_key_only = (io.KeyMods == ImGuiKeyModFlags_Ctrl); + const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift); + const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); + + const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; + const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable); + const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable; + + if (IsKeyPressedMap(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 (IsKeyPressedMap(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 (IsKeyPressedMap(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 (IsKeyPressedMap(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 (IsKeyPressedMap(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } + else if (IsKeyPressedMap(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } + else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } + else if (IsKeyPressedMap(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 (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter)) + { + bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; + if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + { + enter_pressed = clear_active_id = true; + } + else if (!is_readonly) + { + unsigned int c = '\n'; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + } + else if (IsKeyPressedMap(ImGuiKey_Escape)) + { + clear_active_id = cancel_edit = true; + } + else if (is_undo || is_redo) + { + state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); + state->ClearSelection(); + } + else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) + { + state->SelectAll(); + state->CursorFollow = true; + } + else if (is_cut || is_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()) + { + 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; ) + { + unsigned int c; + s += ImTextCharFromUtf8(&c, s, NULL); + if (c == 0) + break; + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + continue; + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; + } + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) + { + stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); + state->CursorFollow = true; + } + MemFree(clipboard_filtered); + } + } + + render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + } + + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + const char* apply_new_text = NULL; + int apply_new_text_length = 0; + if (cancel_edit) + { + if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0) + { + apply_new_text = state->InitialTextA.Data; + apply_new_text_length = state->InitialTextA.Size - 1; + 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); + } + } + + bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + if (apply_edit_back_to_user_buffer) + { + 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); + } + + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) + { + IM_ASSERT(callback != NULL); + + ImGuiInputTextFlags event_flag = 0; + ImGuiKey event_key = ImGuiKey_COUNT; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) + { + event_flag = ImGuiInputTextFlags_CallbackCompletion; + event_key = ImGuiKey_Tab; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_UpArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(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; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = event_flag; + callback_data.Flags = flags; + callback_data.UserData = callback_user_data; + + callback_data.EventKey = event_key; + callback_data.Buf = state->TextA.Data; + callback_data.BufTextLen = state->CurLenA; + callback_data.BufSize = state->BufCapacityA; + callback_data.BufDirty = false; + + 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); + + callback(&callback_data); + + IM_ASSERT(callback_data.Buf == state->TextA.Data); + 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(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); + if (callback_data.BufTextLen > backup_current_text_length && is_resizable) + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); + state->CurLenA = callback_data.BufTextLen; + state->CursorAnimReset(); + } + } + } + + if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) + { + apply_new_text = state->TextA.Data; + apply_new_text_length = state->CurLenA; + } + } + + if (apply_new_text) + { + IM_ASSERT(apply_new_text_length >= 0); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + 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); + } + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; + } + + state->UserFlags = 0; + state->UserCallback = NULL; + state->UserCallbackData = NULL; + } + + if (clear_active_id && g.ActiveId == id) + ClearActiveID(); + + if (!is_multiline) + { + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + + } + + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Min.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Min.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), ImVec2(frame_bb.Max.x - 1.0f, frame_bb.Max.y), colWhite, 1.0f); + + + 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); + ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; + ImVec2 text_size(0.0f, 0.0f); + + const int buf_display_max_length = 2 * 1024 * 1024; + const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; + const char* buf_display_end = NULL; + if (is_displaying_hint) + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + } + + if (render_cursor || render_selection) + { + IM_ASSERT(state != NULL); + if (!is_displaying_hint) + buf_display_end = buf_display + state->CurLenA; + + const ImWchar* text_begin = state->TextW.Data; + ImVec2 cursor_offset, select_start_offset; + + { + 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++; + } + + searches_remaining += is_multiline ? 1 : 0; + int line_count = 0; + 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; + + cursor_offset.x = InputTextCalcTextSizeW(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(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.y = searches_result_line_no[1] * g.FontSize; + } + + if (is_multiline) + text_size = ImVec2(inner_size.x, line_count * g.FontSize); + } + + if (render_cursor && state->CursorFollow) + { + 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; + } + + if (is_multiline) + { + 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 >= 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); + draw_window->Scroll.y = scroll_y; + } + + state->CursorFollow = false; + } + + 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); + float bg_offy_up = is_multiline ? 0.0f : -1.0f; + 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) + { + while (p < text_selected_end) + if (*p++ == '\n') + break; + } + else + { + ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); + if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); + 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; + } + } + + 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); + } + + 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 = 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)); + + if (!is_readonly) + g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + } + } + else + { + if (is_multiline) + text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); + 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) + { + Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); + EndChild(); + EndGroup(); + } + + 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.Min.x, frame_bb.Min.y + style.FramePadding.y - 20.0f), label); + if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) + MarkItemEdited(id); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) + return enter_pressed; + else + return value_changed; +} + + +bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); +} + + +bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) +{ + 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); + + window->DC.CursorPos.y += 5.0f; + + + const ImGuiColorEditFlags flags_untouched = flags; + if (flags & ImGuiColorEditFlags_NoInputs) + flags = (flags & (~ImGuiColorEditFlags__DisplayMask)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorEditOptionsPopup(col, flags); + + 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)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); + + const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; + const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; + const int components = alpha ? 4 : 3; + + 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)) + { + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + if (memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) + { + if (f[1] == 0) + f[0] = g.ColorEditLastHue; + if (f[2] == 0) + f[1] = g.ColorEditLastSat; + } + } + 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; + + 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) + { + 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" }, + { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, + { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } + }; + static const char* fmt_table_float[3][4] = + { + { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, + { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, + { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } + }; + 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); + + 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"); + } + } + else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + 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] = i[3] = 0; + if (alpha) + sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); + else + sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + + + + 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 - 5.0f); + + const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); + if (ColorButton("##ColorButton", col_v4, flags)) + { + if (!(flags & ImGuiColorEditFlags_NoPicker)) + { + g.ColorPickerRef = col_v4; + OpenPopup("picker"); + SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1, style.ItemSpacing.y)); + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + if (BeginPopup("picker")) + { + 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); + value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); + EndPopup(); + } + } + + if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) + { + const float text_offset_x = (flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x; + window->DC.CursorPos = ImVec2(pos.x + text_offset_x, pos.y + style.FramePadding.y); + TextEx(label, label_display_end); + } + + 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.ColorEditLastHue = f[0]; + g.ColorEditLastSat = f[1]; + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + memcpy(g.ColorEditLastColor, f, sizeof(float) * 3); + } + 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]; + } + + PopID(); + EndGroup(); + + + if ((window->DC.LastItemStatusFlags & 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); + 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; + } + + if (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]); + EndDragDropTarget(); + } + + if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) + window->DC.LastItemId = g.ActiveId; + + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + + window->DC.CursorPos.y += 10.0f; + 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; +} + +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)); +} + +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); + BeginGroup(); + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + flags |= ImGuiColorEditFlags_NoSmallPreview; + + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorPickerOptionsPopup(col, flags); + + if (!(flags & ImGuiColorEditFlags__PickerMask)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__PickerMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__PickerMask; + if (!(flags & ImGuiColorEditFlags__InputMask)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__InputMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__InputMask; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); + if (!(flags & ImGuiColorEditFlags_NoOptions)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); + + 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; + float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); + 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); + + float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); + ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); + ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); + ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); + + float H = col[0], S = col[1], V = col[2]; + float R = col[0], G = col[1], B = col[2]; + if (flags & ImGuiColorEditFlags_InputRGB) + { + ColorConvertRGBtoHSV(R, G, B, H, S, V); + if (memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) + { + if (S == 0) + H = g.ColorEditLastHue; + if (V == 0) + S = g.ColorEditLastSat; + } + } + 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) + { + 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)) + { + 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))) + { + 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"); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + 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)); + value_changed = value_changed_sv = true; + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + 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; + } + } + + 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(); + + 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(); + } + + if (value_changed_h || value_changed_sv) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10 * 1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]); + g.ColorEditLastHue = H; + g.ColorEditLastSat = S; + memcpy(g.ColorEditLastColor, col, sizeof(float) * 3); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + col[0] = H; + col[1] = S; + col[2] = V; + } + } + + 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)) + { + 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(); + } + + 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); + if (memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) + { + if (S == 0) + H = g.ColorEditLastHue; + if (V == 0) + S = g.ColorEditLastSat; + } + } + 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)); + + ImVec2 sv_cursor_pos; + + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + const float aeps = 0.5f / wheel_r_outer; + 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, false, wheel_thickness); + const int vert_end_idx = draw_list->VtxBuffer.Size; + + 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]); + } + + 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 = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); + 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); + + 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(6, 6); + draw_list->PrimVtx(tra, uv_white, hue_color32); + draw_list->PrimVtx(trb, uv_white, hue_color32); + draw_list->PrimVtx(trc, uv_white, col_white); + draw_list->PrimVtx(tra, uv_white, 0); + draw_list->PrimVtx(trb, uv_white, col_black); + draw_list->PrimVtx(trc, uv_white, 0); + 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) + { + 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); + 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); + + 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); + } + + float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12); + + 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) + MarkItemEdited(window->DC.LastItemId); + + PopID(); + + return value_changed; +} + + +bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(desc_id); + float default_size = GetFrameHeight(); + if (size.x == 0.0f) + size.x = default_size; + if (size.y == 0.0f) + size.y = default_size; + 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 = ImMin(g.Style.FrameRounding, grid_step * 0.5f); + ImRect bb_inner = bb; + float off = 0.0f; + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + off = -0.75f; + bb_inner.Expand(off); + } + + RenderFrame(bb_inner.Min - ImVec2(1, 1), bb_inner.Max - ImVec2(0, 0), colWhite, true, 0); + RenderFrame(bb_inner.Min + ImVec2(0, 0), bb_inner.Max + ImVec2(1, 1), colBlack, true, 0); + 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, ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft); + } + else + { + 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, ImDrawCornerFlags_All); + } + RenderNavHighlight(bb, id); + + + + 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(); + } + + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + + return pressed; +} + +void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + if ((flags & ImGuiColorEditFlags__DisplayMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DisplayMask; + if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DataTypeMask; + if ((flags & ImGuiColorEditFlags__PickerMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__PickerMask; + if ((flags & ImGuiColorEditFlags__InputMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__InputMask; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DataTypeMask)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); + g.ColorEditOptions = flags; +} + +void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + + BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); + 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)); + PushItemWidth(picker_size.x); + for (int picker_type = 0; picker_type < 2; picker_type++) + { + 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)) + 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(); +} + +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; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, 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; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) +{ + if (flags & ImGuiTreeNodeFlags_Leaf) + return true; + + 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; + storage->SetInt(id, is_open); + } + else + { + const int stored_value = storage->GetInt(id, -1); + if (stored_value == -1) + { + is_open = g.NextItemData.OpenVal; + storage->SetInt(id, is_open); + } + else + { + is_open = stored_value != 0; + } + } + } + else + { + is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; + } + + 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); + + 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) + { + 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); + const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); + const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); + 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); + + 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; + + const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; + bool is_open = TreeNodeBehaviorIsOpen(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); + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + window->DC.LastItemDisplayRect = frame_bb; + + if (!item_add) + { + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; + } + + ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + button_flags |= ImGuiButtonFlags_AllowItemOverlap; + if (!is_leaf) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + + 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; + + 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; + if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0]) + toggled = true; + } + else if (pressed && g.DragDropHoldJustPressedId == id) + { + IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); + if (!is_open) + toggled = true; + } + + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) + { + toggled = true; + NavMoveRequestCancel(); + } + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) + { + toggled = true; + NavMoveRequestCancel(); + } + + if (toggled) + { + is_open = !is_open; + window->DC.StateStorage->SetInt(id, is_open); + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen; + } + } + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + if (selected != was_selected) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin; + if (display_frame) + { + 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 ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); + else + text_pos.x -= text_offset_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 + { + 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 ? 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, window->DC.ItemFlags | (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 ? str_id : "#TreePush"); +} + +void ImGui::TreePush(const void* ptr_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); +} + +void ImGui::TreePushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Indent(); + window->DC.TreeDepth++; + window->IDStack.push_back(id); +} + +void ImGui::TreePop() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Unindent(); + + window->DC.TreeDepth--; + ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); + + 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); + NavMoveRequestCancel(); + } + window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; + + IM_ASSERT(window->IDStack.Size > 1); + PopID(); +} + +float ImGui::GetTreeNodeToLabelSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + (g.Style.FramePadding.x * 2.0f); +} + +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; +} + +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); +} + +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_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + bool is_open = TreeNodeBehavior(id, flags, label); + if (p_visible != NULL) + { + ImGuiContext& g = *GImGui; + ImGuiLastItemDataBackup last_item_backup; + float button_size = g.FontSize; + float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); + float button_y = window->DC.LastItemRect.Min.y; + ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); + if (CloseButton(close_button_id, ImVec2(button_x, button_y))) + *p_visible = false; + last_item_backup.Restore(); + } + + return is_open; +} + +bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg, bool ncolorhovered) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + 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); + + 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); + + const ImVec2 text_min = pos; + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + 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); + } + 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; + } + + bool item_add; + if (flags & ImGuiSelectableFlags_Disabled) + { + ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; + item_add = ItemAdd(bb, id); + window->DC.ItemFlags = backup_item_flags; + } + else + { + item_add = ItemAdd(bb, id); + } + + 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; + + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePushBackgroundChannel(); + + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_Disabled) { button_flags |= ImGuiButtonFlags_Disabled; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } + + if (flags & ImGuiSelectableFlags_Disabled) + selected = false; + + const bool was_selected = selected; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + + if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) + { + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + { + g.NavDisableHighlight = true; + SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent); + } + } + if (pressed) + MarkItemEdited(id); + + if (flags & ImGuiSelectableFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + if (selected != was_selected) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) + hovered = true; + + + if (ncolorhovered) + { + if (selected) + { + ImU32 col = GetColorU32(ImGuiCol_HeaderActive); + RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + } + else { + if (hovered || selected) + { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + } + + + if (span_all_columns && window->DC.CurrentColumns) + PopColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePopBackgroundChannel(); + + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + + if (ncolorhovered) + { + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); + } + else + { + if (selected || hovered) + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb, colBlack); + else RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); + } + + if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); + + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return pressed; +} + +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; +} + +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); + + 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); + + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y - 1.0f), ImVec2(frame_bb.Max.x , frame_bb.Min.y - 1.0f), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Min.y - 1.0f), ImVec2(frame_bb.Min.x - 1.0f, frame_bb.Max.y), colBlack, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Max.x , frame_bb.Min.y), ImVec2(frame_bb.Max.x , frame_bb.Max.y), colWhite, 1.0f); + window->DrawList->AddLine(ImVec2(frame_bb.Min.x , frame_bb.Max.y), ImVec2(frame_bb.Max.x , frame_bb.Max.y), colWhite, 1.0f); + + 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; + } + + BeginGroup(); + if (label_size.x > 0.0f) + { + ImVec2 label_pos = ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y - 20.0f); + RenderText(label_pos, label); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); + } + + BeginChildFrame(id, frame_bb.GetSize()); + return true; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) +{ + ImGuiContext& g = *GImGui; + float height_in_items_f = (height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f; + ImVec2 size; + size.x = 0.0f; + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; + return BeginListBox(label, size); +} +#endif + +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?"); + + EndChildFrame(); + EndGroup(); +} + +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; +} + +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; + + 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; + + bool value_changed = false; + ImGuiListClipper clipper; + clipper.Begin(items_count, GetTextLineHeightWithSpacing()); + 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.CurrentWindow->DC.LastItemId); + + return value_changed; +} + +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, ImVec2 frame_size) +{ + 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); + if (frame_size.x == 0.0f) + frame_size.x = CalcItemWidth(); + if (frame_size.y == 0.0f) + frame_size.y = label_size.y + (style.FramePadding.y * 2); + + 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); + + 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) + 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); + + 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) ); + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); + + 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) ); + + 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; + } + } + + 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 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); +} + +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); + } +} + +void ImGuiMenuColumns::Update(int count, float spacing, bool clear) +{ + IM_ASSERT(count == IM_ARRAYSIZE(Pos)); + IM_UNUSED(count); + Width = NextWidth = 0.0f; + Spacing = spacing; + if (clear) + memset(NextWidths, 0, sizeof(NextWidths)); + for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + { + if (i > 0 && NextWidths[i] > 0.0f) + Width += Spacing; + Pos[i] = IM_FLOOR(Width); + Width += NextWidths[i]; + NextWidths[i] = 0.0f; + } +} + +float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) +{ + NextWidth = 0.0f; + NextWidths[0] = ImMax(NextWidths[0], w0); + NextWidths[1] = ImMax(NextWidths[1], w1); + NextWidths[2] = ImMax(NextWidths[2], w2); + for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f); + return ImMax(Width, NextWidth); +} + +float ImGuiMenuColumns::CalcExtraSpace(float avail_w) const +{ + return ImMax(0.0f, avail_w - Width); +} + +bool ImGui::BeginMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + if (!(window->Flags & ImGuiWindowFlags_MenuBar)) + return false; + + IM_ASSERT(!window->DC.MenuBarAppending); + BeginGroup(); + PushID("##menubar"); + + 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); + + 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.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.MenuBarAppending = true; + AlignTextToFramePadding(); + return true; +} + +void ImGui::EndMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + { + 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.NavMoveRequestForward == ImGuiNavForward_None) + { + const ImGuiNavLayer layer = ImGuiNavLayer_Menu; + IM_ASSERT(window->DC.NavLayerActiveMaskNext & (1 << layer)); + FocusWindow(window); + SetNavIDWithRectRel(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + g.NavLayer = layer; + g.NavDisableHighlight = true; + g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; + NavMoveRequestCancel(); + } + } + + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + PopClipRect(); + PopID(); + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; + g.GroupStack.back().EmitItem = false; + EndGroup(); + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.MenuBarAppending = false; +} + +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + SetNextWindowPos(ImVec2(0.0f, 0.0f)); + SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); + PopStyleVar(2); + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + if (!is_open) + { + End(); + return false; + } + return true; +} + +void ImGui::EndMainMenuBar() +{ + EndMenuBar(); + + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) + FocusTopMostWindowUnderOne(g.NavWindow, NULL); + + End(); +} + +bool ImGui::BeginMenu(const char* label, 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); + + ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + if (window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) + flags |= ImGuiWindowFlags_ChildWindow; + + if (g.MenusIdSubmittedThisFrame.contains(id)) + { + if (menu_is_open) + menu_is_open = BeginPopupEx(id, flags); + else + g.NextWindowData.ClearFlags(); + return menu_is_open; + } + + g.MenusIdSubmittedThisFrame.push_back(id); + + ImVec2 label_size = CalcTextSize(label, NULL, true); + bool pressed; + bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back()); + ImGuiWindow* backed_nav_window = g.NavWindow; + if (menuset_is_open) + g.NavWindow = window; + + ImVec2 popup_pos, pos = window->DC.CursorPos; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + 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; + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + PopStyleVar(); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); + } + else + { + popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); + float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, 0.0f, IM_FLOOR(g.FontSize * 1.20f)); + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(min_w, 0.0f)); + ImU32 text_col = GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled); + RenderArrow(window->DrawList, pos + ImVec2(window->DC.MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), text_col, ImGuiDir_Right); + } + + const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); + if (menuset_is_open) + g.NavWindow = backed_nav_window; + + bool want_open = false; + bool want_close = false; + if (window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + bool moving_toward_other_child_menu = false; + + ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL; + if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar)) + { + ImRect next_window_rect = child_menu_window->Rect(); + ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; + ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); + ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); + moving_toward_other_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); + } + if (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_toward_other_child_menu) + want_close = true; + + if (!menu_is_open && hovered && pressed) + want_open = true; + else if (!menu_is_open && hovered && !moving_toward_other_child_menu) + want_open = true; + + if (g.NavActivateId == id) + { + want_close = menu_is_open; + want_open = !menu_is_open; + } + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) + { + want_open = true; + NavMoveRequestCancel(); + } + } + else + { + if (menu_is_open && pressed && menuset_is_open) + { + want_close = true; + want_open = menu_is_open = false; + } + else if (pressed || (hovered && menuset_is_open && !menu_is_open)) + { + want_open = true; + } + else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) + { + want_open = true; + NavMoveRequestCancel(); + } + } + + if (!enabled) + want_close = true; + if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) + { + OpenPopup(label); + return false; + } + + menu_is_open |= want_open; + if (want_open) + OpenPopup(label); + + if (menu_is_open) + { + SetNextWindowPos(popup_pos, ImGuiCond_Always); + menu_is_open = BeginPopupEx(id, flags); + } + else + { + g.NextWindowData.ClearFlags(); + } + + return menu_is_open; +} + +void ImGui::EndMenu() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + ClosePopupToLevel(g.BeginPopupStack.Size, true); + NavMoveRequestCancel(); + } + + EndPopup(); +} + +bool ImGui::MenuItem(const char* label, 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); + + ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled); + bool pressed; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + float w = label_size.x; + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); + PopStyleVar(); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); + } + else + { + float shortcut_w = shortcut ? CalcTextSize(shortcut, NULL).x : 0.0f; + float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, shortcut_w, IM_FLOOR(g.FontSize * 1.20f)); + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable(label, false, flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); + if (shortcut_w > 0.0f) + { + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + RenderText(pos + ImVec2(window->DC.MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); + PopStyleColor(); + } + if (selected) + RenderCheckMark(window->DrawList, pos + ImVec2(window->DC.MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); + } + + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) +{ + if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) + { + if (p_selected) + *p_selected = !*p_selected; + return true; + } + return false; +} + +struct ImGuiTabBarSection +{ + int TabCount; + float Width; + float Spacing; + + ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); } +}; + +namespace ImGui +{ + static void TabBarLayout(ImGuiTabBar* tab_bar); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); + static float TabBarCalcMaxTabWidth(); + static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, 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 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 = (a->Flags & ImGuiTabItemFlags_Leading) ? 0 : (a->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + const int b_section = (b->Flags & ImGuiTabItemFlags_Leading) ? 0 : (b->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + 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); + + g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); + g.CurrentTabBar = tab_bar; + + 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; + } + + if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) + if (tab_bar->Tabs.Size > 1) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); + tab_bar->TabsAddedNew = false; + + if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + + tab_bar->Flags = flags; + tab_bar->BarRect = tab_bar_bb; + tab_bar->WantLayout = true; + 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->BeginCount = 1; + + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); + + const ImU32 col = colWhite; + + const float y = tab_bar->BarRect.Max.y - 1.0f; + { + float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f) + 2.0f ; + float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f) - 2.0f ; + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + + float vosem = 380.0f; + window->DrawList->AddLine(ImVec2(separator_min_x, y + vosem), ImVec2(separator_max_x, y + vosem), colBlack, 1.0f); + + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_min_x, y + vosem), col, 1.0f); + window->DrawList->AddLine(ImVec2(separator_max_x, y), ImVec2(separator_max_x, y + vosem), colBlack, 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; + } + + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + 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; + + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + PopID(); + + g.CurrentTabBarStack.pop_back(); + g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); +} + +static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + tab_bar->WantLayout = false; + + int tab_dst_n = 0; + bool need_sort_by_section = false; + ImGuiTabBarSection sections[3]; + 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) + { + 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; + + int curr_tab_section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + if (tab_dst_n > 0) + { + ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1]; + int prev_tab_section_n = (prev_tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (prev_tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + 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); + + 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; + + ImGuiID scroll_track_selected_tab_id = 0; + if (tab_bar->NextSelectedTabId) + { + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; + tab_bar->NextSelectedTabId = 0; + scroll_track_selected_tab_id = tab_bar->SelectedTabId; + } + + if (tab_bar->ReorderRequestTabId != 0) + { + if (TabBarProcessReorder(tab_bar)) + if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId) + scroll_track_selected_tab_id = tab_bar->ReorderRequestTabId; + tab_bar->ReorderRequestTabId = 0; + } + + 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)) + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount }; + g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); + + 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_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_track_selected_tab_id = tab->ID; + + const char* tab_name = tab_bar->GetTabName(tab); + const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true; + tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x; + + int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + 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; + + int shrink_buffer_index = shrink_buffer_indexes[section_n]++; + g.ShrinkWidthBuffer[shrink_buffer_index].Index = tab_n; + g.ShrinkWidthBuffer[shrink_buffer_index].Width = tab->ContentWidth; + + IM_ASSERT(tab->ContentWidth > 0.0f); + tab->Width = tab->ContentWidth; + } + + 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; + + 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_track_selected_tab = TabBarScrollingButtons(tab_bar)) + { + scroll_track_selected_tab_id = scroll_track_selected_tab->ID; + if (!(scroll_track_selected_tab->Flags & ImGuiTabItemFlags_Button)) + tab_bar->SelectedTabId = scroll_track_selected_tab_id; + } + + 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); + else + width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); + + if (width_excess > 0.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); + + 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; + + int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + sections[section_n].Width -= (tab->Width - shrinked_width); + tab->Width = shrinked_width; + } + } + + 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_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; + } + + 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_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + + tab_bar->VisibleTabId = tab_bar->SelectedTabId; + tab_bar->VisibleTabWasSubmitted = false; + + if (scroll_track_selected_tab_id) + if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id)) + TabBarScrollToTab(tab_bar, scroll_track_selected_tab, sections); + 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) + { + 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; + + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + tab_bar->TabsNames.Buf.resize(0); + + 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); +} + +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) +{ + 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; +} + +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; } +} + +void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + IM_ASSERT(!(tab->Flags & ImGuiTabItemFlags_Button)); + if (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + tab->WantClose = true; + if (tab_bar->VisibleTabId == tab->ID) + { + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } + } + else + { + if (tab_bar->VisibleTabId != tab->ID) + tab_bar->NextSelectedTabId = tab->ID; + } +} + +static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +{ + scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth()); + return ImMax(scrolling, 0.0f); +} + +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections) +{ + if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) + return; + + ImGuiContext& g = *GImGui; + float margin = g.FontSize * 1.0f; + int order = tab_bar->GetTabOrder(tab); + + float scrollable_width = tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; + + 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)) + { + 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) + { + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - scrollable_width; + } +} + +void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir) +{ + IM_ASSERT(dir == -1 || dir == +1); + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + tab_bar->ReorderRequestTabId = tab->ID; + tab_bar->ReorderRequestDir = (ImS8)dir; +} + +bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) +{ + ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId); + if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder)) + return false; + + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; + if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) + return false; + + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + if (tab2->Flags & ImGuiTabItemFlags_NoReorder) + return false; + if ((tab1->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (tab2->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing))) + return false; + + ImGuiTabItem item_tmp = *tab1; + *tab1 = *tab2; + *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; + 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 = tab_bar->GetTabOrder(tab_item); + int target_order = selected_order + select_dir; + + while (tab_to_scroll_to == NULL) + { + tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; + + 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; + + 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 = tab_bar->GetTabName(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; +} + +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)); + + bool ret = TabItemEx(tab_bar, label, p_open, flags); + if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + PushOverrideID(tab->ID); + } + 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); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = TabBarCalcTabID(tab_bar, label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + if (p_open && !*p_open) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return false; + } + + IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button)); + IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); + + if (flags & ImGuiTabItemFlags_NoCloseButton) + p_open = NULL; + else if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; + + ImVec2 size = TabItemCalcSize(label, p_open != NULL); + 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->Width = size.x; + tab_bar->TabsAddedNew = true; + tab_is_new = true; + } + tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab); + 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 is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0; + tab->LastFrameVisible = g.FrameCount; + tab->Flags = flags; + + tab->NameOffset = (ImS16)tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); + + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; + if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; + + bool tab_contents_visible = (tab_bar->VisibleTabId == id); + if (tab_contents_visible) + tab_bar->VisibleTabWasSubmitted = true; + + 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; + + if (tab_appearing && (!tab_bar_appearing || tab_is_new)) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + if (is_tab_button) + return false; + return tab_contents_visible; + } + + if (tab_bar->SelectedTabId == id) + tab->LastFrameSelected = g.FrameCount; + + const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; + + const bool is_central_section = (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) == 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); + + 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; + } + + ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap); + if (g.DragDropActive) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (pressed && !is_tab_button) + tab_bar->NextSelectedTabId = id; + hovered |= (g.HoveredId == id); + + if (g.ActiveId != id) + SetItemAllowOverlap(); + + if (held && !tab_appearing && IsMouseDragging(0)) + { + if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) + { + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueReorder(tab_bar, tab, -1); + } + else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) + { + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueReorder(tab_bar, tab, +1); + } + } + } + +#if 0 + if (hovered && g.HoveredIdNotActiveTimer > TOOLTIP_DELAY && bb.GetWidth() < tab->ContentWidth) + { + 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 + + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32(ImGuiCol_Tab); + bb.Min.y -= 5.0f; + if ( tab_contents_visible && tab_bar_focused) bb.Min.y -= 3.0f; + bb.Max.x += 3.0f; bb.Max.y += 1.0f; + TabItemBackground(display_draw_list, bb, flags, tab_col); + + const float y2 = bb.Max.y - 1.0f; + if ((!tab_contents_visible && tab_bar_focused)) { + display_draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); + display_draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); + display_draw_list->PathStroke(colWhite, false, g.Style.TabBorderSize); + } + + RenderNavHighlight(bb, id); + + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; + bool just_closed; + bool text_clipped; + + bb.Min.y += 3.0f; + if ((!tab_contents_visible && tab_bar_focused)) + TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped, false); + else + TabItemLabelAndCloseButton(display_draw_list, bb, 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); + } + + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + + if (text_clipped && g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay && IsItemHovered()) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); + if (is_tab_button) + return pressed; + return tab_contents_visible; +} + +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); + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab->WantClose = true; + } +} + +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) +{ + 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) + size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); + else + size.x += g.Style.FramePadding.x + 1.0f; + + return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); +} + +void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +{ + 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), false, g.Style.TabBorderSize); + + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->PathLineTo(ImVec2(bb.Max.x, bb.Min.y + 2.0f)); + draw_list->PathStroke(colBlack, false, g.Style.TabBorderSize); + } +} + +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, bool tabActive) +{ + 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; + +#if 0 + const float backup_alpha = g.Style.Alpha; + if (!is_contents_visible) + g.Style.Alpha *= 0.7f; +#endif + + const char* TAB_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); + if (flags & ImGuiTabItemFlags_UnsavedDocument) + { + text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; + ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + IM_FLOOR(-g.FontSize * 0.25f)); + RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL); + } + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + if (out_text_clipped) + { + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x; + } + + bool close_button_pressed = false; + bool close_button_visible = false; + if (close_button_id != 0) + if (is_contents_visible || bb.GetWidth() >= 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; + if (close_button_visible) + { + ImGuiLastItemDataBackup last_item_backup; + const float close_button_sz = g.FontSize; + PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); + if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x * 2.0f - close_button_sz, bb.Min.y))) + close_button_pressed = true; + PopStyleVar(); + last_item_backup.Restore(); + + if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + close_button_pressed = true; + + text_pixel_clip_bb.Max.x -= close_button_sz; + } + + float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + + if (!tabActive) + 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, colWhiteText); + else + 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 + +``` + +`SpyCustom/imgui/imstb_rectpack.h`: + +```h +#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; + +#ifdef STBRP_LARGE_RECTS +typedef int stbrp_coord; +#else +typedef unsigned short stbrp_coord; +#endif + +STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); +struct stbrp_rect +{ + int id; + + stbrp_coord w, h; + + stbrp_coord x, y; + int was_packed; + +}; + + +STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); +STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); + +STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); +enum +{ + STBRP_HEURISTIC_Skyline_default=0, + STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, + STBRP_HEURISTIC_Skyline_BF_sortHeight +}; + + +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]; +}; + +#ifdef __cplusplus +} +#endif + +#endif + +#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) + context->align = 1; + else { + 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; +#ifndef STBRP_LARGE_RECTS + STBRP_ASSERT(width <= 0xffff && height <= 0xffff); +#endif + + 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); + + context->extra[0].x = 0; + context->extra[0].y = 0; + context->extra[0].next = &context->extra[1]; + context->extra[1].x = (stbrp_coord) width; +#ifdef STBRP_LARGE_RECTS + context->extra[1].y = (1<<30); +#else + context->extra[1].y = 65535; +#endif + context->extra[1].next = NULL; +} + +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 + while (node->next->x <= x0) + ++node; + #else + STBRP_ASSERT(node->next->x > x0); + #endif + + STBRP_ASSERT(node->x <= x0); + + min_y = 0; + waste_area = 0; + visited_width = 0; + while (node->x < x1) { + if (node->y > min_y) { + waste_area += visited_width * (node->y - min_y); + min_y = node->y; + if (node->x < x0) + visited_width += node->next->x - x0; + else + visited_width += node->next->x - node->x; + } else { + 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; + + width = (width + c->align - 1); + width -= width % c->align; + STBRP_ASSERT(width % c->align == 0); + + 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) { + if (y < best_y) { + best_y = y; + best = prev; + } + } else { + if (y + height <= c->height) { + 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 (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { + tail = c->active_head; + node = c->active_head; + prev = &c->active_head; + while (tail->x < width) + tail = tail->next; + while (tail) { + int xpos = tail->x - width; + int y,waste; + STBRP_ASSERT(xpos >= 0); + 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); + 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) +{ + stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); + stbrp_node *node, *cur; + + if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { + res.prev_link = NULL; + return res; + } + + node = context->free_head; + node->x = (stbrp_coord) res.x; + node->y = (stbrp_coord) (res.y + height); + + context->free_head = node->next; + + cur = *res.prev_link; + if (cur->x < res.x) { + stbrp_node *next = cur->next; + cur->next = node; + cur = next; + } else { + *res.prev_link = node; + } + + while (cur->next && cur->next->x <= res.x + width) { + stbrp_node *next = cur->next; + cur->next = context->free_head; + context->free_head = cur; + cur = next; + } + + 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); +} + +#ifdef STBRP_LARGE_RECTS +#define STBRP__MAXVAL 0xffffffff +#else +#define STBRP__MAXVAL 0xffff +#endif + +STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) +{ + int i, all_rects_packed = 1; + + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = i; + } + + 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; + } 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; + } + } + } + + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); + + 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 all_rects_packed; +} +#endif + + +``` + +`SpyCustom/imgui/imstb_textedit.h`: + +```h + +#ifndef INCLUDE_STB_TEXTEDIT_H +#define INCLUDE_STB_TEXTEDIT_H + +#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 +{ + STB_TEXTEDIT_POSITIONTYPE where; + STB_TEXTEDIT_POSITIONTYPE insert_length; + STB_TEXTEDIT_POSITIONTYPE delete_length; + int char_storage; +} StbUndoRecord; + +typedef struct +{ + 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 +{ + int cursor; + int select_start; + int select_end; + unsigned char insert_mode; + int row_count_per_page; + unsigned char cursor_at_end_of_line; + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char padding1, padding2, padding3; + float preferred_x; + StbUndoState undostate; +} STB_TexteditState; + + +typedef struct +{ + float x0,x1; + float baseline_y_delta; + float ymin,ymax; + int num_chars; +} StbTexteditRow; +#endif + + + +#ifdef STB_TEXTEDIT_IMPLEMENTATION + +#ifndef STB_TEXTEDIT_memmove +#include +#define STB_TEXTEDIT_memmove memmove +#endif + + +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; + + 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; + } + + if (i >= n) + return n; + + if (x < r.x0) + return i; + + if (x < r.x1) { + 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; + } + } + + 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; +} + +static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + 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; +} + +static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + int p = 0; + + 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; +} + +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; + float height; + int first_char, length; + int prev_first; +} StbFindState; + +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) { + if (single_line) { + 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; + } else { + find->y = 0; + find->x = 0; + find->height = 1; + while (i < z) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + prev_start = i; + i += r.num_chars; + } + find->first_char = i; + find->length = 0; + find->prev_first = prev_start; + } + return; + } + + find->y = 0; + + for(;;) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (n < i + r.num_chars) + break; + prev_start = i; + i += r.num_chars; + find->y += r.baseline_y_delta; + } + + find->first_char = first = i; + find->length = r.num_chars; + find->height = r.ymax - r.ymin; + find->prev_first = prev_start; + + 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) + +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 (state->select_start == state->select_end) + state->cursor = state->select_start; + } + if (state->cursor > n) state->cursor = n; +} + +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; +} + +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; + } +} + +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; + } +} + +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; + } +} + +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; + 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; + 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 + +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; +} + +static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_delete_selection(str,state); + state->has_preferred_x = 0; + return 1; + } + return 0; +} + +static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +{ + stb_textedit_clamp(str, state); + stb_textedit_delete_selection(str,state); + 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; + } + if (state->undostate.undo_point) + --state->undostate.undo_point; + return 0; +} + +#ifndef STB_TEXTEDIT_KEYTYPE +#define STB_TEXTEDIT_KEYTYPE int +#endif + +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; + + 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); + 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 (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 (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); + 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); + ++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) { + 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); + + 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; + + if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) + break; + + 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; + + 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) { + 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); + + 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; + + if (find.prev_first == find.first_char) + break; + + 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; + + 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; + } + } +} + +static void stb_textedit_flush_redo(StbUndoState *state) +{ + state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; +} + +static void stb_textedit_discard_undo(StbUndoState *state) +{ + if (state->undo_point > 0) { + if (state->undo_rec[0].char_storage >= 0) { + int n = state->undo_rec[0].insert_length, i; + 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; + } + --state->undo_point; + STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); + } +} + +static void stb_textedit_discard_redo(StbUndoState *state) +{ + int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; + + if (state->redo_point <= k) { + if (state->undo_rec[k].char_storage >= 0) { + int n = state->undo_rec[k].insert_length, i; + 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))); + for (i=state->redo_point; i < k; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage += n; + } + 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); + + ++state->redo_point; + } +} + +static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) +{ + stb_textedit_flush_redo(state); + + if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + stb_textedit_discard_undo(state); + + if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { + state->undo_point = 0; + state->undo_char_point = 0; + return NULL; + } + + 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; + + 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 (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { + r->insert_length = 0; + } else { + int i; + + while (s->undo_char_point + u.delete_length > s->redo_char_point) { + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + 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; + + for (i=0; i < u.delete_length; ++i) + s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); + } + + STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); + } + + if (u.insert_length) { + 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; + + u = &s->undo_rec[s->undo_point]; + r = s->undo_rec[s->redo_point]; + + u->delete_length = r.insert_length; + u->insert_length = r.delete_length; + u->where = r.where; + u->char_storage = -1; + + if (r.delete_length) { + 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; + + 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) { + 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); + } +} + +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; +} + +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 + + +``` + +`SpyCustom/imgui/imstb_truetype.h`: + +```h + +#if 0 +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" + +unsigned char ttf_buffer[1<<20]; +unsigned char temp_bitmap[512*512]; + +stbtt_bakedchar cdata[96]; +GLuint ftex; + +void my_stbtt_initfont(void) +{ + fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); + stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); + glGenTextures(1, &ftex); + glBindTexture(GL_TEXTURE_2D, ftex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +} + +void my_stbtt_print(float x, float y, char *text) +{ + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, ftex); + glBegin(GL_QUADS); + while (*text) { + if (*text >= 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +#if 0 +#include +#define STB_TRUETYPE_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 +#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; + char *text = "Heljo World!"; + + 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]); + 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 + + +#ifdef STB_TRUETYPE_IMPLEMENTATION + #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]; + + #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 + + #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 + +#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 + +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +typedef struct +{ + unsigned short x0,y0,x1,y1; + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +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); +typedef struct +{ + float x0,y0,s0,t0; + float x1,y1,s1,t1; +} stbtt_aligned_quad; + +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); +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); + +typedef struct +{ + unsigned short x0,y0,x1,y1; + 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); +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +#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); +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; + int *array_of_unicode_codepoints; + int num_chars; + stbtt_packedchar *chardata_for_range; + unsigned char h_oversample, v_oversample; +} 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); +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +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); + +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); +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; +}; + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; + int fontstart; + + int numGlyphs; + + int loca,head,glyf,hhea,hmtx,kern,gpos; + int index_map; + int indexToLocFormat; + + stbtt__buf cff; + stbtt__buf charstrings; + stbtt__buf gsubrs; + stbtt__buf subrs; + stbtt__buf fontdicts; + stbtt__buf fdselect; +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +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); + +#ifndef STBTT_vmove + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex + #define stbtt_vertex_type short + 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); +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); +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +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); +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); +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_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_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_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_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_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); + + +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +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); + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +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); + + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +#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 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +enum { + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { + 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 { + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { + 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 { + 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 { + 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 + +#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 + +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); +} + +#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) +{ + if (stbtt_tag4(font, '1',0,0,0)) return 1; + if (stbtt_tag(font, "typ1")) return 1; + if (stbtt_tag(font, "OTTO")) return 1; + if (stbtt_tag4(font, 0,1,0,0)) return 1; + if (stbtt_tag(font, "true")) return 1; + return 0; +} + +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 (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + if (stbtt_tag(font_collection, "ttcf")) { + 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 (stbtt__isfont(font_collection)) + return 1; + + if (stbtt_tag(font_collection, "ttcf")) { + 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); +} + +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"); + info->loca = stbtt__find_table(data, fontstart, "loca"); + info->head = stbtt__find_table(data, fontstart, "head"); + info->glyf = stbtt__find_table(data, fontstart, "glyf"); + info->hhea = stbtt__find_table(data, fontstart, "hhea"); + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); + info->kern = stbtt__find_table(data, fontstart, "kern"); + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + if (!info->loca) return 0; + } else { + 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); + + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); + + stbtt__cff_get_index(&b); + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); + 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); + + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + 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; + + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + 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: + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + 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) { + 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); + return 0; + } else if (format == 4) { + 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; + + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + 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; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + 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; + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); + 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 + return start_glyph; + } + } + return 0; + } + 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; + if (info->indexToLocFormat >= 2) return -1; + + 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; +} + +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; + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + off = m - n; + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + 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; + } + + 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; + } + + 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); + + start_off = !(flags & 1); + if (start_off) { + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; + } + } 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 (was_off) + 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 == -1) { + 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) { + if (flags & 1) { + 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 { + STBTT_assert(0); + } + if (flags & (1<<3)) { + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { + 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)) { + 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; + } + + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + 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])); + } + 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) 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 = flags & (1<<5); + } + } else if (numberOfContours < 0) { + STBTT_assert(0); + } else { + } + + *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) { + 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) stbtt__new_buf(NULL, 0); + 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) + + 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) { + case 0x13: + case 0x14: + if (in_header) + maskbits += (sp / 2); + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: + case 0x03: + case 0x12: + case 0x17: + maskbits += (sp / 2); + break; + + case 0x15: + 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: + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: + 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; + + case 0x07: + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: + 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: + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: + 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: + 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: + 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: + 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: + case 0x1B: + 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: + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + case 0x1D: + 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: + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + case 0x22: + 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: + 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]; + 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: + 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: + 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 || b0 > 254)) + return STBTT__CSERR("reserved operator"); + + 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) +{ + 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)); + } +} + +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; + + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) + return 0; + if (ttUSHORT(data+8) != 1) + 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)); + 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); + + 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; + + 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: { + STBTT_assert(0); + } break; + } + + 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; + + 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: { + STBTT_assert(0); + } break; + } + + return -1; +} + +#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; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; + if (ttUSHORT(data+2) != 0) return 0; + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i> 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; + } + } + } break; + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + + 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_assert(glyph1class < class1Count); + STBTT_assert(glyph2class < class2Count); + + STBTT_GPOS_TODO_assert(valueFormat1 == 4); + if (valueFormat1 != 4) return 0; + STBTT_GPOS_TODO_assert(valueFormat2 == 0); + if (valueFormat2 != 0) return 0; + + if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { + stbtt_uint8 *class1Records = table + 16; + stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); + stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } + } break; + + default: { + STBTT_assert(0); + break; + } + } + } + break; + } + + default: + break; + } + } + + 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); + + 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) + 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 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; + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + 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); +} + +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; + + 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)); + 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); + 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 +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + int x0=0, w=0; + + while (e) { + if (w == 0) { + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; + + if (j < len) + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; + + for (++i; i < j; ++i) + 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); + int s; + 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) { + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; + step = &((*step)->next); + } + } + + 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; + } + + 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) { + if (active == NULL) + active = z; + else if (z->x < active->x) { + z->next = active; + active = z; + } else { + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + 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 + +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); + } +} + +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) { + 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); + + 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) { + if ((int) x_top == (int) x_bottom) { + float height; + int x = (int) x_top; + height = sy1 - sy0; + STBTT_assert(x >= 0 && x < len); + scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; + scanline_fill[x] += e->direction * height; + } else { + int x,x1,x2; + float y_crossing, step, sign, area; + if (x_top > x_bottom) { + 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; + (void)dx; + } + + x1 = (int) x_top; + x2 = (int) x_bottom; + y_crossing = (x1+1 - x0) * dy + y_top; + + sign = e->direction; + area = sign * (y_crossing-sy0); + scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); + + step = sign * dy; + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; + area += step; + } + y_crossing += dy * (x2 - (x1+1)); + + STBTT_assert(STBTT_fabs(area) <= 1.01f); + + scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); + + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + int x; + for (x=0; x < len; ++x) { + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { + 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) { + 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) { + 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) { + 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) { + 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) { + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + 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, 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) { + 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])); + + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); + } + } + + 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) { + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); + z->next = active; + active = z; + } + } + ++e; + } + + 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; + } + } + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; + step = &((*step)->next); + } + + ++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) +{ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + if (c01 != c12) { + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + t = p[0]; + p[0] = p[m]; + p[m] = t; + + i=1; + j=n-1; + for(;;) { + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + 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 + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); + 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; + if (p[j].y == p[k].y) + continue; + 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; + } + } + + stbtt__sort_edges(e, n); + + 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; + points[n].x = x; + points[n].y = y; +} + +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) +{ + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { + 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) +{ + 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) + 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; + } +} + +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; + + 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; + } + + 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: + 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); + + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; + + 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); +} + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, + float pixel_height, + unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, + 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); + 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; + if (y + gh + 1 >= ph) + 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; +} + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +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 + +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); + + 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); + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + 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); + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + 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; + + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +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; + + 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) { + 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); + } + ++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); +} + +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, return_value = 1; + + 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; + + 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; + } else { + return_value = 0; + } + + ++k; + } + } + + 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; + stbrp_rect *rects; + + 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; +} + +#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 { + 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; + + orig[0] = x; + 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[1] = 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); +} + +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; + 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); + + 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_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) return NULL; + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + 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; + + 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); + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (verts[i].type == STBTT_vline) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + 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); + 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],px,py,t,it; + float a_inv = precompute[i]; + if (a_inv == 0.0) { + 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 (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; + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; + 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); + } + 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; + 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); +} + +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + 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; + 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); +} + +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) { + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + 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); + + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + 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 (matchlen == nlen) + return 1; + } + } + } + + } + } + 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; + + 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 (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 + + + +``` + +`SpyCustom/inventory_changer.h`: + +```h +#pragma once +#include "ProtoParse.h" +#include "ProtobuffMessages.h" +#include + +#include "Options.hpp" + +struct wskin +{ + int wId; + int paintkit; +}; + +#define START_MUSICKIT_INDEX 1500000 +#define START_ITEM_INDEX 2000000 + +static void clear_equip_state(CMsgClientWelcome::SubscribedType& object); +static void apply_medals(CMsgClientWelcome::SubscribedType& object); +static void apply_music_kits(CMsgClientWelcome::SubscribedType& object); + +static void add_item(CMsgClientWelcome::SubscribedType& object, int index, ItemDefinitionIndex itemIndex, int quality, int rarity, int paintKit, int seed, float wear, std::string name, std::string desc, sticker stickers[5], int stattrak, int flag); + +static int GetAvailableClassID(int definition_index); +static int GetSlotID(int definition_index); +static std::vector music_kits = { 3, 4, 5, 6, 7, 8 }; + + +template +inline std::string get_4bytes(T value) +{ + return std::string{ reinterpret_cast(reinterpret_cast(&value)), 4 }; +} + +template +inline CSOEconItemAttribute make_econ_item_attribute(int def_index, T value) +{ + CSOEconItemAttribute attribute; + attribute.def_index().set(def_index); + attribute.value_bytes().set(get_4bytes(value)); + return attribute; +} + +inline CSOEconItemEquipped make_equipped_state(int team, int slot) +{ + CSOEconItemEquipped equipped_state; + equipped_state.new_class().set(team); + equipped_state.new_slot().set(slot); + return equipped_state; +} + +static std::string inventory_changer(void* pubDest, uint32_t* pcubMsgSize) { + CMsgClientWelcome msg((void*)((DWORD)pubDest + 8), *pcubMsgSize - 8); + if (!msg.outofdate_subscribed_caches().has()) + return msg.serialize(); + + auto cache = msg.outofdate_subscribed_caches().get(); + + static auto fix_null_inventory = [&cache]() + { + auto objects = cache.objects().get_all(); + auto it = std::find_if(objects.begin(), objects.end(), [](decltype(objects.front()) o) + { + return o.type_id().has() && o.type_id().get() == 1; + }); + + if (it == objects.end()) + { + CMsgClientWelcome::SubscribedType null_object; + null_object.type_id().set(1); + cache.objects().add(null_object); + } + }; + + fix_null_inventory(); + + auto objects = cache.objects().get_all(); + for (size_t i = 0; i < objects.size(); i++) { + auto object = objects[i]; + + if (!object.type_id().has()) + continue; + + switch (object.type_id().get()) + { + case 1: + { + if (true) + object.object_data().clear(); + + int indexcount = 0; + + for (int i = 0; i < g_Options.weapons.value->weaponzcount; i++) + if (g_Options.weapons.value->arr[i].active) { + indexcount++; + add_item(object, indexcount, + (ItemDefinitionIndex)g_Options.weapons.value->arr[i].modeldefindex, + g_Options.weapons.value->arr[i].quality, + g_Options.weapons.value->arr[i].rarity, + g_Options.weapons.value->arr[i].skinid, + g_Options.weapons.value->arr[i].seed, + g_Options.weapons.value->arr[i].wear, + g_Options.weapons.value->arr[i].nametag, + g_Options.weapons.value->arr[i].desctag, + g_Options.weapons.value->arr[i].stickers, + g_Options.weapons.value->arr[i].stattrak, + i); + } + + cache.objects().set(object, i); + } + break; + } + } + msg.outofdate_subscribed_caches().set(cache); + + return msg.serialize(); +} + +static bool inventory_changer_presend(void* pubData, uint32_t& cubData) +{ + CMsgAdjustItemEquippedState msg((void*)((DWORD)pubData + 8), cubData - 8); + if (msg.item_id().has() && (msg.new_class().get() == 0 || msg.new_slot().get() == 54)) + { + auto ItemIndex = msg.item_id().get() - START_MUSICKIT_INDEX; + + if (ItemIndex > 38 || ItemIndex < 3) + return true; + + msg.new_slot().get() == 0xFFFF ? 0 : ItemIndex - 2; + + return false; + } + if (!msg.item_id().has() || !msg.new_class().get() || !msg.new_slot().get()) + return true; + + return false; +} + + +static void clear_equip_state(CMsgClientWelcome::SubscribedType& object) +{ + auto object_data = object.object_data().get_all(); + for (size_t j = 0; j < object_data.size(); j++) + { + auto item = object_data[j]; + + if (!item.equipped_state().has()) + continue; + + auto null_equipped_state = make_equipped_state(0, 0); + + auto equipped_state = item.equipped_state().get_all(); + for (size_t k = 0; k < equipped_state.size(); k++) + item.equipped_state().set(null_equipped_state, k); + + object.object_data().set(item, j); + } +} + + +static void add_item(CMsgClientWelcome::SubscribedType& object, int index, ItemDefinitionIndex itemIndex, int quality, int rarity, int paintKit, int seed, float wear, std::string name, std::string desc, sticker stickers[5], int stattrak, int flag) +{ + uint32_t steamid = iff.g_SteamUser->GetSteamID().GetAccountID(); + + CSOEconItem item; + item.id().set(START_ITEM_INDEX + itemIndex); + item.account_id().set(steamid); + if (flag == 5) + item.def_index().set(1314); + else item.def_index().set(itemIndex); + item.inventory().set(START_ITEM_INDEX + index); + item.origin().set(24); + item.quantity().set(1); + item.level().set(1); + item.style().set(0); + item.flags().set(0); + item.in_use().set(true); + item.original_id().set(0); + item.rarity().set(rarity); + item.quality().set(quality); + + if (name.size() > 0) + item.custom_name().set(name); + + if (desc.size() > 0) + item.custom_desc().set(desc); + + if (flag > 5) { + int avalTeam = GetAvailableClassID(itemIndex); + if (avalTeam == TEAM_SPECTATOR || avalTeam == TEAM_TERRORIST) { + item.equipped_state().add(make_equipped_state(TEAM_TERRORIST, GetSlotID(itemIndex))); + } + if (avalTeam == TEAM_SPECTATOR || avalTeam == TEAM_CT) { + item.equipped_state().add(make_equipped_state(TEAM_CT, GetSlotID(itemIndex))); + } + } + + item.attribute().add(make_econ_item_attribute(6, float(paintKit))); + item.attribute().add(make_econ_item_attribute(7, float(seed))); + item.attribute().add(make_econ_item_attribute(8, float(wear))); + + + for (int j = 0; j < 5; j++) + { + item.attribute().add(make_econ_item_attribute(113 + 4 * j, stickers[j].stickerid )); + item.attribute().add(make_econ_item_attribute(114 + 4 * j, stickers[j].wear)); + item.attribute().add(make_econ_item_attribute(115 + 4 * j, stickers[j].scale)); + item.attribute().add(make_econ_item_attribute(116 + 4 * j, stickers[j].rotation)); + } + + if (stattrak != -1) + { + item.attribute().add(make_econ_item_attribute(80, stattrak)); + item.attribute().add(make_econ_item_attribute(81, 0)); + } + + if (flag == 0) + { + item.equipped_state().add(make_equipped_state(TEAM_TERRORIST, 0)); + item.equipped_state().add(make_equipped_state(TEAM_CT, 0)); + } + + if (flag == 1) + { + item.equipped_state().add(make_equipped_state(TEAM_TERRORIST, 41)); + item.equipped_state().add(make_equipped_state(TEAM_CT, 41)); + } + + if (flag == 2) + item.equipped_state().set(make_equipped_state(2, 38)); + + if (flag == 3) + item.equipped_state().set(make_equipped_state(3, 38)); + + + if (flag == 4) + item.equipped_state().set(make_equipped_state(0, 55)); + + + if (flag == 5) + { + item.attribute().add(make_econ_item_attribute(166, itemIndex)); + item.inventory().set(START_MUSICKIT_INDEX + itemIndex); + item.id().set(START_MUSICKIT_INDEX + itemIndex); + item.equipped_state().set(make_equipped_state(0, 54)); + } + + object.object_data().add(item); +} + +static int GetAvailableClassID(int definition_index) +{ + switch (definition_index) + { + case WEAPON_KNIFE_BAYONET: + case WEAPON_KNIFE_FLIP: + case WEAPON_KNIFE_GUT: + case WEAPON_KNIFE_KARAMBIT: + case WEAPON_KNIFE_M9_BAYONET: + case WEAPON_KNIFE_TACTICAL: + case WEAPON_KNIFE_FALCHION: + case WEAPON_KNIFE_SURVIVAL_BOWIE: + case WEAPON_KNIFE_BUTTERFLY: + case WEAPON_KNIFE_PUSH: + case WEAPON_ELITE: + case WEAPON_P250: + case WEAPON_CZ75A: + case WEAPON_DEAGLE: + case WEAPON_REVOLVER: + case WEAPON_MP7: + case WEAPON_UMP45: + case WEAPON_P90: + case WEAPON_BIZON: + case WEAPON_SSG08: + case WEAPON_AWP: + case WEAPON_NOVA: + case WEAPON_XM1014: + case WEAPON_M249: + case WEAPON_NEGEV: + case GLOVE_STUDDED_BLOODHOUND: + case GLOVE_SPORTY: + case GLOVE_SLICK: + case GLOVE_LEATHER_WRAP: + case GLOVE_MOTORCYCLE: + case GLOVE_SPECIALIST: + return TEAM_SPECTATOR; + + case WEAPON_GLOCK: + case WEAPON_AK47: + case WEAPON_MAC10: + case WEAPON_G3SG1: + case WEAPON_TEC9: + case WEAPON_GALILAR: + case WEAPON_SG553: + case WEAPON_SAWEDOFF: + case WEAPON_C4: + return TEAM_TERRORIST; + + case WEAPON_AUG: + case WEAPON_FAMAS: + case WEAPON_MAG7: + case WEAPON_FIVESEVEN: + case WEAPON_USP_SILENCER: + case WEAPON_HKP2000: + case WEAPON_MP9: + case WEAPON_M4A1_SILENCER: + case WEAPON_M4A1: + case WEAPON_SCAR20: + return TEAM_CT; + + default: + return TEAM_UNASSIGNED; + } +} + +static int GetSlotID(int definition_index) +{ + switch (definition_index) + { + case WEAPON_KNIFE_BAYONET: + case WEAPON_KNIFE_FLIP: + case WEAPON_KNIFE_GUT: + case WEAPON_KNIFE_KARAMBIT: + case WEAPON_KNIFE_M9_BAYONET: + case WEAPON_KNIFE_TACTICAL: + case WEAPON_KNIFE_FALCHION: + case WEAPON_KNIFE_SURVIVAL_BOWIE: + case WEAPON_KNIFE_BUTTERFLY: + case WEAPON_KNIFE_PUSH: + return 0; + case WEAPON_C4: + return 1; + case WEAPON_USP_SILENCER: + case WEAPON_HKP2000: + case WEAPON_GLOCK: + return 2; + case WEAPON_ELITE: + return 3; + case WEAPON_P250: + return 4; + case WEAPON_TEC9: + case WEAPON_CZ75A: + case WEAPON_FIVESEVEN: + return 5; + case WEAPON_DEAGLE: + case WEAPON_REVOLVER: + return 6; + case WEAPON_MP9: + case WEAPON_MAC10: + return 8; + case WEAPON_MP7: + return 9; + case WEAPON_UMP45: + return 10; + case WEAPON_P90: + return 11; + case WEAPON_BIZON: + return 12; + case WEAPON_FAMAS: + case WEAPON_GALILAR: + return 14; + case WEAPON_M4A1_SILENCER: + case WEAPON_M4A1: + case WEAPON_AK47: + return 15; + case WEAPON_SSG08: + return 16; + case WEAPON_SG553: + case WEAPON_AUG: + return 17; + case WEAPON_AWP: + return 18; + case WEAPON_G3SG1: + case WEAPON_SCAR20: + return 19; + case WEAPON_NOVA: + return 20; + case WEAPON_XM1014: + return 21; + case WEAPON_SAWEDOFF: + case WEAPON_MAG7: + return 22; + case WEAPON_M249: + return 23; + case WEAPON_NEGEV: + return 24; + case GLOVE_STUDDED_BLOODHOUND: + case GLOVE_SPORTY: + case GLOVE_SLICK: + case GLOVE_LEATHER_WRAP: + case GLOVE_MOTORCYCLE: + case GLOVE_SPECIALIST: + return 41; + default: + return -1; + } +} +``` + +`SpyCustom/netvars.cpp`: + +```cpp +#include "netvars.hpp" + +#include +#include + +#include "interfaces.hpp" + +void NetvarSys::Initialize() +{ + + m_tables.clear(); + + ClientClass* clientClass = iff.g_pClient->GetAllClasses(); + if (!clientClass) + return; + + while (clientClass) + { + RecvTable* recvTable = clientClass->m_pRecvTable; + m_tables.push_back(recvTable); + + clientClass = clientClass->m_pNext; + } + +} + + +#undef GetProp + +int NetvarSys::GetOffset(const char* tableName, const char* propName) +{ + int offset = this->GetProp(tableName, propName); + if (!offset) + { + printfdbg("%s not found!\n", propName); + return 0; + } + printfdbg("%s: 0x%02X\n", propName, offset); + + return offset; +} + + +int NetvarSys::GetProp(const char* tableName, const char* propName, RecvProp** prop) +{ + RecvTable* recvTable = GetTable(tableName); + if (!recvTable) + return 0; + + int offset = this->GetProp(recvTable, propName, prop); + if (!offset) + return 0; + + return offset; +} + + +int NetvarSys::GetProp(RecvTable* recvTable, const char* propName, RecvProp** prop) +{ + int extraOffset = 0; + for (int i = 0; i < recvTable->m_nProps; ++i) + { + RecvProp* recvProp = &recvTable->m_pProps[i]; + RecvTable* child = recvProp->m_pDataTable; + + if (child && (child->m_nProps > 0)) + { + int tmp = this->GetProp(child, propName, prop); + if (tmp) + extraOffset += (recvProp->m_Offset + tmp); + } + + if (_stricmp(recvProp->m_pVarName, propName)) + continue; + + if (prop) + *prop = recvProp; + + return (recvProp->m_Offset + extraOffset); + } + + return extraOffset; +} + +RecvTable* NetvarSys::GetTable(const char* tableName) +{ + if (m_tables.empty()) + return 0; + + for (const auto& table : m_tables) + { + if (!table) + continue; + + if (_stricmp(table->m_pNetTableName, tableName) == 0) + return table; + } + + return 0; +} + + + + + + + + +``` + +`SpyCustom/netvars.hpp`: + +```hpp +#pragma once + +#include +#include +#include + +#include "sdk/dt_recv.h" +#include "Singleton.hpp" + +class NetvarSys + : public Singleton +{ +public: + void Initialize(); + + int GetOffset(const char* tableName, const char* propName); + + RecvTable* GetTable(const char* tableName); + std::vector m_tables; + +private: + int GetProp(const char* tableName, const char* propName, RecvProp** prop = 0); + int GetProp(RecvTable* recvTable, const char* propName, RecvProp** prop = 0); + +}; + + +#define NETVAR_OFFSET2(funcname, class_name, var_name, offset, ...) \ +auto funcname() -> std::add_lvalue_reference_t<__VA_ARGS__> \ +{ \ + static int netvar = NetvarSys::Get().GetOffset(class_name, var_name); \ + auto addr = std::uintptr_t(this) + offset + netvar; \ + return *reinterpret_cast>(addr); \ +} + +#define NETVAR2(funcname, class_name, var_name, ...) \ + NETVAR_OFFSET2(funcname, class_name, var_name, 0, __VA_ARGS__) + +``` + +`SpyCustom/pbwrap.hpp`: + +```hpp +#pragma once +#include +#include +#include +#include + +#define PBFIELD(number, type, name) \ + pbfield name() const { \ + return std::move(pbfield( fv_ )); \ + } + +#if defined(__GNUC__) +#include +#include + +#define __forceinline __attribute__((always_inline)) + +#define PBMSG_CTOR(class_name) \ + class_name() : pbmsg() {} \ + class_name(void* buf, size_t bytes) : pbmsg(buf, bytes) {} \ + class_name(const std::string& buf) : pbmsg(buf) {} + +#elif defined(_MSC_VER) +#define PBMSG_CTOR using pbmsg::pbmsg +#endif + +namespace pbwrap +{ + static constexpr int32_t k_invalid_id = -1; + + enum e_field_type + { + TYPE_DOUBLE = 1, + TYPE_FLOAT = 2, + TYPE_INT64 = 3, + TYPE_UINT64 = 4, + TYPE_INT32 = 5, + TYPE_FIXED64 = 6, + TYPE_FIXED32 = 7, + TYPE_BOOL = 8, + TYPE_STRING = 9, + TYPE_GROUP = 10, + TYPE_MESSAGE = 11, + TYPE_BYTES = 12, + TYPE_UINT32 = 13, + TYPE_ENUM = 14, + TYPE_SFIXED32 = 15, + TYPE_SFIXED64 = 16, + TYPE_SINT32 = 17, + TYPE_SINT64 = 18, + MAX_FIELD_TYPE = 18, + }; + + enum e_wire_type + { + WIRETYPE_VARINT = 0, + WIRETYPE_FIXED64 = 1, + WIRETYPE_LENGTH_DELIMITED = 2, + WIRETYPE_START_GROUP = 3, + WIRETYPE_END_GROUP = 4, + WIRETYPE_FIXED32 = 5, + }; + + static constexpr e_wire_type k_wire_type_for_field_type[MAX_FIELD_TYPE + 1] = { + static_cast(k_invalid_id), + WIRETYPE_FIXED64, + WIRETYPE_FIXED32, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + WIRETYPE_FIXED64, + WIRETYPE_FIXED32, + WIRETYPE_VARINT, + WIRETYPE_LENGTH_DELIMITED, + WIRETYPE_START_GROUP, + WIRETYPE_LENGTH_DELIMITED, + WIRETYPE_LENGTH_DELIMITED, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + WIRETYPE_FIXED32, + WIRETYPE_FIXED64, + WIRETYPE_VARINT, + WIRETYPE_VARINT, + }; + + namespace utils + { + static constexpr int k_tag_type_bits = 3; + static constexpr uint32_t k_tag_type_mask = (1 << k_tag_type_bits) - 1; + static constexpr int k_max_varint_bytes = 10; + static constexpr int k_max_varint32_bytes = 5; + + __forceinline auto make_tag(uint32_t field_number, uint32_t wire_type) -> uint32_t + { + return static_cast((field_number << k_tag_type_bits) | wire_type); + } + + static auto get_bytes_varint32(uint32_t value) -> std::string + { + uint8_t bytes[k_max_varint32_bytes]; + int size = 0; + while (value > 0x7F) + { + bytes[size++] = (static_cast(value) & 0x7F) | 0x80; + value >>= 7; + } + bytes[size++] = static_cast(value) & 0x7F; + return std::string{ reinterpret_cast(&bytes[0]), (size_t)size }; + } + + static auto get_bytes_varint64(uint64_t value) -> std::string + { + uint8_t bytes[k_max_varint_bytes]; + int size = 0; + while (value > 0x7F) + { + bytes[size++] = (static_cast(value) & 0x7F) | 0x80; + value >>= 7; + } + bytes[size++] = static_cast(value) & 0x7F; + return std::string{ reinterpret_cast(&bytes[0]), (size_t)size }; + } + + static auto read_varuint32(const void* data, size_t& bytes_read) -> uint32_t + { + auto ptr = reinterpret_cast(data); + auto value = 0u; + auto bytes = 0u; + + do + { + value |= static_cast(*ptr & 0x7f) << (7 * bytes); + bytes++; + } while (*(ptr++) & 0x80 && bytes <= 5); + + bytes_read = bytes; + return value; + } + + static auto read_varuint64(const void* data, size_t& bytes_read) -> uint64_t + { + auto ptr = reinterpret_cast(data); + auto value = 0ull; + auto bytes = 0u; + + do + { + value |= static_cast(*ptr & 0x7f) << (7 * bytes); + bytes++; + } while (*(ptr++) & 0x80 && bytes <= 10); + + bytes_read = bytes; + + return value; + } + + static auto read_field(const void* data, size_t& bytes_read) + -> std::tuple + { + uint32_t field = *reinterpret_cast(data); + uint32_t wire_type = field & k_tag_type_mask; + + if (field == 0xffff) + { + bytes_read = 0; + return std::make_tuple(k_invalid_id, k_invalid_id, "", ""); + } + + if (field & 0x80) + { + field = ((field & 0x7f) | ((field & 0xff00) >> 1)) >> k_tag_type_bits; + bytes_read = 2; + } + else + { + field = (field & 0xff) >> k_tag_type_bits; + bytes_read = 1; + } + + std::string value_bytes, full_bytes; + size_t length, size_delimited; + + switch (wire_type) + { + case WIRETYPE_VARINT: + read_varuint64((void*)((ptrdiff_t)data + bytes_read), length); + value_bytes = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytes_read)), length }; + full_bytes = std::string{ reinterpret_cast(data), bytes_read + length }; + bytes_read += length; + break; + case WIRETYPE_FIXED64: + value_bytes = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytes_read)), 8 }; + full_bytes = std::string{ reinterpret_cast(data), bytes_read + 8 }; + bytes_read += 8; + break; + case WIRETYPE_LENGTH_DELIMITED: + size_delimited = read_varuint32((void*)((ptrdiff_t)data + bytes_read), length); + value_bytes = std::string{ + reinterpret_cast((void*)((ptrdiff_t)data + bytes_read)), length + size_delimited + }; + full_bytes = std::string{ reinterpret_cast(data), bytes_read + length + size_delimited }; + bytes_read += length + size_delimited; + break; + case WIRETYPE_START_GROUP: + throw std::runtime_error("WIRETYPE_START_GROUP not implemented"); + break; + case WIRETYPE_END_GROUP: + throw std::runtime_error("WIRETYPE_END_GROUP not implemented"); + break; + case WIRETYPE_FIXED32: + value_bytes = std::string{ reinterpret_cast((void*)((ptrdiff_t)data + bytes_read)), 4 }; + full_bytes = std::string{ reinterpret_cast(data), bytes_read + 4 }; + bytes_read += 4; + break; + default: + throw std::runtime_error("Unknown wire type"); + break; + } + + return std::make_tuple(field, wire_type, std::move(value_bytes), std::move(full_bytes)); + } + + template + auto get_field_bytes(uint32_t field, uint32_t wire_type, T value) + -> std::pair + { + const auto tag = get_bytes_varint32(make_tag(field, wire_type)); + + std::string bytes{}; + switch (wire_type) + { + case WIRETYPE_VARINT: + bytes += get_bytes_varint64(static_cast(value)); + break; + case WIRETYPE_FIXED32: + bytes += std::string{ reinterpret_cast(&value), 4 }; + break; + case WIRETYPE_FIXED64: + bytes += std::string{ reinterpret_cast(&value), 8 }; + break; + } + + return { bytes, tag + bytes }; + } + + template <> + inline auto get_field_bytes(uint32_t field, uint32_t wire_type, std::string value) + -> std::pair + { + const auto tag = get_bytes_varint32(make_tag(field, wire_type)); + + std::string bytes{}; + bytes += get_bytes_varint32(value.size()); + bytes += value; + + return { bytes, tag + bytes }; + } + + template <> + inline auto get_field_bytes(uint32_t field, uint32_t wire_type, const char* value) + -> std::pair + { + const auto tag = get_bytes_varint32(make_tag(field, wire_type)); + + std::string bytes{}; + bytes += get_bytes_varint32(strlen(value)); + bytes += value; + + return { bytes, tag + bytes }; + } + } + + namespace types + { + struct Int32 + { + static constexpr e_field_type field_type = TYPE_INT32; + using type = int32_t; + + static __forceinline auto get(const std::string& value) -> int32_t + { + size_t bytes_read; + return utils::read_varuint32(value.data(), bytes_read); + } + }; + + struct Uint32 + { + static constexpr e_field_type field_type = TYPE_UINT32; + using type = uint32_t; + + static __forceinline auto get(const std::string& value) -> uint32_t + { + size_t bytes_read; + return utils::read_varuint32(value.data(), bytes_read); + } + }; + + struct Int64 + { + static constexpr e_field_type field_type = TYPE_INT64; + using type = int64_t; + + static __forceinline auto get(const std::string& value) -> int64_t + { + size_t bytes_read; + return utils::read_varuint64(value.data(), bytes_read); + } + }; + + struct Uint64 + { + static constexpr e_field_type field_type = TYPE_UINT64; + using type = uint64_t; + + static __forceinline auto get(const std::string& value) -> uint64_t + { + size_t bytes_read; + return utils::read_varuint64(value.data(), bytes_read); + } + }; + + struct Float + { + static constexpr e_field_type field_type = TYPE_FLOAT; + using type = float; + + static __forceinline auto get(const std::string& value) -> float + { + return *reinterpret_cast(value.data()); + } + }; + + struct Double + { + static constexpr e_field_type field_type = TYPE_DOUBLE; + using type = double; + + static __forceinline auto get(const std::string& value) -> double + { + return *reinterpret_cast(value.data()); + } + }; + + struct Fixed32 + { + static constexpr e_field_type field_type = TYPE_FIXED32; + using type = int32_t; + + static __forceinline auto get(const std::string& value) -> int32_t + { + return *reinterpret_cast(value.data()); + } + }; + + struct Fixed64 + { + static constexpr e_field_type field_type = TYPE_FIXED64; + using type = int64_t; + + static __forceinline auto get(const std::string& value) -> int64_t + { + return *reinterpret_cast(value.data()); + } + }; + + struct Bool + { + static constexpr e_field_type field_type = TYPE_BOOL; + using type = bool; + + static __forceinline auto get(const std::string& value) -> bool + { + size_t bytes_read; + return !!utils::read_varuint32(value.data(), bytes_read); + } + }; + + struct String + { + static constexpr e_field_type field_type = TYPE_STRING; + using type = std::string; + + static __forceinline auto get(const std::string& value) -> std::string + { + size_t bytes_read; + const auto length = utils::read_varuint32(value.data(), bytes_read); + auto result = std::string{ value.data() + bytes_read, length }; + return std::move(result); + } + }; + + struct Group : String + { + static constexpr e_field_type field_type = TYPE_GROUP; + }; + + struct Message : String + { + static constexpr e_field_type field_type = TYPE_MESSAGE; + }; + + struct Bytes : String + { + static constexpr e_field_type field_type = TYPE_BYTES; + }; + + struct Enum : Int32 + { + static constexpr e_field_type field_type = TYPE_ENUM; + }; + + struct Sfixed32 : Fixed32 + { + static constexpr e_field_type field_type = TYPE_SFIXED32; + }; + + struct Sfixed64 : Fixed64 + { + static constexpr e_field_type field_type = TYPE_SFIXED64; + }; + + struct Sint32 + { + static constexpr e_field_type field_type = TYPE_SINT32; + using type = int32_t; + }; + + struct Sint64 + { + static constexpr e_field_type field_type = TYPE_SINT64; + using type = int64_t; + }; + } + + namespace base + { + struct field_vector + { + using Entry = std::pair; + using Field = std::vector; + using Fields = std::vector; + + const std::shared_ptr fields; + const size_t max_size; + + explicit field_vector(const size_t max_size) : fields{ std::make_shared() }, max_size{ max_size + 1 } + { + fields->resize(this->max_size); + } + + auto clear(const uint32_t field) const -> void + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + auto& fld = fields->at(field); + + if (!fld.empty()) + fld.clear(); + } + + auto has(const uint32_t field, const size_t index = 0) const -> bool + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + auto& fld = fields->at(field); + + return fld.size() > index; + } + + auto count(const uint32_t field) const -> size_t + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + auto& fld = fields->at(field); + + return fld.size(); + } + + auto add(const uint32_t field, const Entry& entry) const -> void + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + fields->at(field).emplace_back(entry); + } + + auto set(const uint32_t field, const Entry& entry, const size_t index = 0) const -> void + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + auto& fld = fields->at(field); + + if (index == 0 && fld.empty()) + { + fld.emplace_back(entry); + } + else + { + if (index >= fld.size()) + throw std::runtime_error("field range error"); + + fld.at(index) = entry; + } + } + + auto get(const uint32_t field, const size_t index = 0) const -> std::string + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + const auto& fld = fields->at(field); + + if (index >= fld.size()) + throw std::runtime_error("field range error"); + + return fld.at(index).first; + } + + auto get_all(const uint32_t field) const -> std::vector + { + if (field >= max_size) + throw std::runtime_error("field range error"); + + const auto& fld = fields->at(field); + + std::vector ret; + + for (const auto& v : fld) + ret.emplace_back(v.first); + + return std::move(ret); + } + }; + + template + struct header + { + static constexpr uint32_t field = Field; + static constexpr e_field_type type = Type::field_type; + static constexpr e_wire_type wire_type = k_wire_type_for_field_type[type]; + }; + + struct msg + { + static constexpr e_field_type field_type = TYPE_STRING; + using type = std::string; + virtual ~msg() = default; + msg() = delete; + + explicit msg(const size_t max_size) : fv_{ field_vector(max_size) } + { + } + + auto serialize() const -> std::string + { + std::string result; + for (const auto& f0 : *fv_.fields) + for (const auto& f1 : f0) + result.append(f1.second); + + return std::move(result); + } + + auto parse(const uint8_t* buf, size_t bytes) -> void + { + if (buf == nullptr) + return; + + size_t pos = 0, bytes_read; + uint32_t field, wire_type; + std::string field_value_bytes, field_full_bytes; + + while (pos < bytes) + { + std::tie(field, wire_type, field_value_bytes, field_full_bytes) = utils::read_field(buf + pos, bytes_read); + + if (bytes_read == 0) + break; + + if (field >= fv_.max_size) + throw std::runtime_error("field range error"); + + fv_.fields->at(field).emplace_back(field_value_bytes, field_full_bytes); + pos += bytes_read; + } + } + + protected: + const field_vector fv_; + }; + + template + struct field + { + virtual ~field() = default; + + explicit field(const field_vector& fv) : fv_{ fv } + { + } + + auto clear() const -> void + { + fv_.clear(hdr.field); + } + + auto has(size_t index = 0) const -> bool + { + return fv_.has(hdr.field, index); + } + + auto count() const -> size_t + { + return fv_.count(hdr.field); + } + + protected: + static constexpr header hdr{}; + const field_vector fv_; + }; + } + + + template + struct pbfield; + + + template + struct pbfield::value>::type + > : base::field + { + virtual ~pbfield() = default; + + explicit pbfield(const base::field_vector& fv) : base::field{ fv } + { + } + + using type = typename Type::type; + + auto add(type&& value) const -> void + { + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, value); + fv_.add(hdr.field, pair); + } + + auto set(type&& value, size_t index = 0) const -> void + { + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, value); + fv_.set(hdr.field, pair, index); + } + + auto set(const type& value, size_t index = 0) const -> void + { + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, value); + fv_.set(hdr.field, pair, index); + } + + auto set(std::vector&& values) const -> void + { + fv_.clear(hdr.field); + + for (auto& v : values) + { + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, v); + fv_.add(hdr.field, pair); + } + } + + auto set(std::vector& values) const -> void + { + fv_.clear(hdr.field); + + for (auto& v : values) + { + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, v); + fv_.add(hdr.field, pair); + } + } + + auto get_all() const -> std::vector + { + const auto values = fv_.get_all(hdr.field); + + std::vector ret; + + for (const auto& v : values) + ret.emplace_back(Type::get(v)); + + return std::move(ret); + } + + auto get(size_t index = 0) const -> type + { + const auto value = fv_.get(hdr.field, index); + return Type::get(value); + } + + private: + using base::field::hdr; + using base::field::fv_; + }; + + template + struct pbfield::value>::type + > : base::field + { + virtual ~pbfield() = default; + + explicit pbfield(const base::field_vector& fv) : base::field{ fv } + { + } + + using type = typename Type::type; + + auto add(const Type& value) const -> void + { + const auto v = value.serialize(); + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, v); + fv_.add(hdr.field, pair); + } + + auto set(const Type& value, size_t index = 0) const -> void + { + const auto v = value.serialize(); + const auto pair = utils::get_field_bytes(hdr.field, hdr.wire_type, v); + fv_.set(hdr.field, pair, index); + } + + auto get_all() const -> std::vector + { + const auto values = fv_.get_all(hdr.field); + + std::vector ret; + + for (const auto& v : values) + { + const auto s = types::String::get(v); + ret.emplace_back(s); + } + + return std::move(ret); + } + + auto get(size_t index = 0) const -> Type + { + const auto value = fv_.get(hdr.field, index); + const auto s = types::String::get(value); + return std::move(Type(s)); + } + + private: + using base::field::hdr; + using base::field::fv_; + }; + + template + struct pbmsg : base::msg + { + virtual ~pbmsg() = default; + + explicit pbmsg() : msg(MsgSize) + { + } + + explicit pbmsg(void* buf, size_t bytes) : msg(MsgSize) + { + parse(reinterpret_cast(buf), bytes); + } + + explicit pbmsg(const std::string& buf) : msg(MsgSize) + { + parse(reinterpret_cast(buf.data()), buf.size()); + } + }; +} + +``` + +`SpyCustom/protobuffs.cpp`: + +```cpp +#include "Protobuffs.hpp" +#include "Interfaces.hpp" +#include "inventory_changer.h" + +extern Protobuffs ProtoFeatures; +#define CAST(cast, address, add) reinterpret_cast((uint32_t)address + (uint32_t)add) + +void Protobuffs::WritePacket(std::string packet, void* thisPtr, void* oldEBP, void* pubDest, uint32_t cubDest, uint32_t* pcubMsgSize) +{ + if ((uint32_t)packet.size() <= cubDest - 8) + { + memcpy((void*)((DWORD)pubDest + 8), (void*)packet.data(), packet.size()); + *pcubMsgSize = packet.size() + 8; + } + else if (iff.g_pMemAlloc) + { + auto memPtr = *CAST(void**, thisPtr, 0x18); + auto memPtrSize = *CAST(uint32_t*, thisPtr, 0x1C); + auto newSize = (memPtrSize - cubDest) + packet.size() + 8; + + auto memory = iff.g_pMemAlloc->Realloc(memPtr, newSize + 4); + + *CAST(void**, thisPtr, 0x18) = memory; + *CAST(uint32_t*, thisPtr, 0x1C) = newSize; + *CAST(void**, oldEBP, -0x14) = memory; + + memcpy(CAST(void*, memory, 0x1C), (void*)packet.data(), packet.size()); + + *pcubMsgSize = packet.size() + 8; + } +} + +static bool onceChanger = false; + +void Protobuffs::ReceiveMessage(void* thisPtr, void* oldEBP, uint32_t messageType, void* pubDest, uint32_t cubDest, uint32_t* pcubMsgSize) +{ + if (messageType == k_EMsgGCCStrike15_v2_MatchmakingGC2ClientHello) + { + printfdbg("Packet == k_EMsgGCCStrike15_v2_MatchmakingGC2ClientHello\n"); + + if (g_Options.profile_active) { + + MatchmakingGC2ClientHello msg((void*)((DWORD)pubDest + 8), *pcubMsgSize - 8); + MatchmakingGC2ClientHello::PlayerCommendationInfo commendations; + commendations.cmd_friendly().set(g_Options.comfriendly); + commendations.cmd_teaching().set(g_Options.comteacher); + commendations.cmd_leader().set(g_Options.comleader); + msg.commendation().set(commendations); + + msg.player_level().set(g_Options.level); + msg.player_cur_xp().set(g_Options.xp); + + if (g_Options.banduration != 0) { + msg.penalty_reason().set(g_Options.banreason); + msg.penalty_seconds().set(g_Options.banduration); + } + + msg.vac_banned().set(g_Options.vacban); + + MatchmakingGC2ClientHello::PlayerRankingInfo ranking; + ranking.account_id().set(iff.g_SteamUser->GetSteamID().GetAccountID()); + ranking.rank_type_id().set(6); + ranking.rank_id().set(g_Options.rankz.value->arr[0].rank); + ranking.wins().set(g_Options.rankz.value->arr[0].wins); + msg.ranking().set(ranking); + + auto packet = msg.serialize(); + WritePacket(packet, thisPtr, oldEBP, pubDest, cubDest, pcubMsgSize); + + printfdbg("send packet 0 6 rank %d wins %d\n", g_Options.rankz.value->arr[0].rank, g_Options.rankz.value->arr[0].wins); + + } + + + + } + else if (messageType == k_EMsgGCCStrike15_v2_ClientGCRankUpdate) + { + printfdbg("Packet == k_EMsgGCCStrike15_v2_ClientGCRankUpdate\n"); + + if (g_Options.profile_active) { + CMsgGCCStrike15_v2_ClientGCRankUpdate msg((void*)((DWORD)pubDest + 8), *pcubMsgSize - 8); + + auto ranking = msg.ranking().get(); + + int ranktype = ranking.rank_type_id().get(); + printfdbg("ranktype = %d\n", ranktype); + int rankcount = 0; + if (ranktype == 7) rankcount = 1; + if (ranktype == 10) rankcount = 2; + + ranking.rank_id().set(g_Options.rankz.value->arr[rankcount].rank); + ranking.wins().set(g_Options.rankz.value->arr[rankcount].wins); + + msg.ranking().set(ranking); + + auto packet = msg.serialize(); + WritePacket(packet, thisPtr, oldEBP, pubDest, cubDest, pcubMsgSize); + + } + + } + else if (messageType == k_EMsgGCClientWelcome) + { + printfdbg("Packet == k_EMsgGCClientWelcome\n"); + auto packet = inventory_changer(pubDest, pcubMsgSize); + WritePacket(packet, thisPtr, oldEBP, pubDest, cubDest, pcubMsgSize); + } + printfdbg(".GC Receive: %d\n", messageType); +} + +bool Protobuffs::PreSendMessage(uint32_t& unMsgType, void* pubData, uint32_t& cubData) +{ + uint32_t MessageType = unMsgType & 0x7FFFFFFF; + printfdbg(".GC Sent: %d\n", MessageType); + return true; +} + +bool Protobuffs::SendClientHello() +{ + CMsgClientHello msg; + msg.client_session_need().set(1); + auto packet = msg.serialize(); + + void* ptr = malloc(packet.size() + 8); + + if (!ptr) + return false; + + ((uint32_t*)ptr)[0] = k_EMsgGCClientHello | ((DWORD)1 << 31); + ((uint32_t*)ptr)[1] = 0; + + memcpy((void*)((DWORD)ptr + 8), (void*)packet.data(), packet.size()); + bool result = iff.g_SteamGameCoordinator->SendMessage(k_EMsgGCClientHello | ((DWORD)1 << 31), ptr, packet.size() + 8) == k_EGCResultOK; + free(ptr); + + return result; +} + +bool Protobuffs::SendMatchmakingClient2GCHello() +{ + ProtoWriter msg(0); + auto packet = msg.serialize(); + void* ptr = malloc(packet.size() + 8); + + if (!ptr) + return false; + + ((uint32_t*)ptr)[0] = k_EMsgGCCStrike15_v2_MatchmakingClient2GCHello | ((DWORD)1 << 31); + ((uint32_t*)ptr)[1] = 0; + + memcpy((void*)((DWORD)ptr + 8), (void*)packet.data(), packet.size()); + bool result = iff.g_SteamGameCoordinator->SendMessage(k_EMsgGCCStrike15_v2_MatchmakingClient2GCHello | ((DWORD)1 << 31), ptr, packet.size() + 8) == k_EGCResultOK; + free(ptr); + + return result; +} + +bool Protobuffs::SendClientGcRankUpdate() +{ + MatchmakingGC2ClientHello::PlayerRankingInfo rank_wingman; + rank_wingman.rank_type_id().set(7); + + CMsgGCCStrike15_v2_ClientGCRankUpdate msg; + msg.ranking().set(rank_wingman); + + auto packet = msg.serialize(); + + void* ptr = malloc(packet.size() + 8); + + if (!ptr) + return false; + + ((uint32_t*)ptr)[0] = k_EMsgGCCStrike15_v2_ClientGCRankUpdate | ((DWORD)1 << 31); + ((uint32_t*)ptr)[1] = 0; + + memcpy((void*)((DWORD)ptr + 8), (void*)packet.data(), packet.size()); + bool result = iff.g_SteamGameCoordinator->SendMessage(k_EMsgGCCStrike15_v2_ClientGCRankUpdate | ((DWORD)1 << 31), ptr, packet.size() + 8) == k_EGCResultOK; + free(ptr); + + return result; +} + +bool Protobuffs::EquipWeapon(int weaponid, int classid, int slotid) +{ + CMsgAdjustItemEquippedState msg; + msg.item_id().set(START_ITEM_INDEX + weaponid); + msg.new_class().set(classid); + msg.new_slot().set(slotid); + msg.swap().set(true); + auto packet = msg.serialize(); + + void* ptr = malloc(packet.size() + 8); + + if (!ptr) + return false; + + ((uint32_t*)ptr)[0] = k_EMsgGCAdjustItemEquippedState | ((DWORD)1 << 31); + ((uint32_t*)ptr)[1] = 0; + + memcpy((void*)((DWORD)ptr + 8), (void*)packet.data(), packet.size()); + bool result = iff.g_SteamGameCoordinator->SendMessage(k_EMsgGCAdjustItemEquippedState | ((DWORD)1 << 31), ptr, packet.size() + 8) == k_EGCResultOK; + free(ptr); + + return result; +} + + + + + +VMTHook* ProtoHook = nullptr; +Protobuffs ProtoFeatures; + + + +EGCResults __fastcall hkGCRetrieveMessage(void* ecx, void*, uint32_t* punMsgType, void* pubDest, uint32_t cubDest, uint32_t* pcubMsgSize) +{ + static auto oGCRetrieveMessage = ProtoHook->GetOriginal(2); + + auto status = oGCRetrieveMessage(ecx, punMsgType, pubDest, cubDest, pcubMsgSize); + + + if (status == k_EGCResultOK) + { + void* thisPtr = nullptr; + __asm mov thisPtr, ebx; + auto oldEBP = *reinterpret_cast((uint32_t)_AddressOfReturnAddress() - 4); + + uint32_t messageType = *punMsgType & 0x7FFFFFFF; + ProtoFeatures.ReceiveMessage(thisPtr, oldEBP, messageType, pubDest, cubDest, pcubMsgSize); + } + + + return status; +} + +EGCResults __fastcall hkGCSendMessage(void* ecx, void*, uint32_t unMsgType, const void* pubData, uint32_t cubData) +{ + static auto oGCSendMessage = ProtoHook->GetOriginal(0); + + bool sendMessage = ProtoFeatures.PreSendMessage(unMsgType, const_cast(pubData), cubData); + + if (!sendMessage) + return k_EGCResultOK; + + + return oGCSendMessage(ecx, unMsgType, const_cast(pubData), cubData); +} + +``` + +`SpyCustom/protobuffs.hpp`: + +```hpp +#pragma once +#include +#include + +#include "VMT.hpp" + +//#include "sdk/steam.h" +#include "sdk/steam_api.h" +#include "sdk/isteamgamecoordinator.h" +#include "intrin.h" + +extern VMTHook* ProtoHook; + +class Protobuffs +{ +public: + static void WritePacket(std::string packet, void* thisPtr, void* oldEBP, void* pubDest, uint32_t cubDest, uint32_t* pcubMsgSize); + void ReceiveMessage(void* thisPtr, void* oldEBP, uint32_t messageType, void* pubDest, uint32_t cubDest, uint32_t* pcubMsgSize); + bool PreSendMessage(uint32_t& unMsgType, void* pubData, uint32_t& cubData); + bool SendClientHello(); + bool SendMatchmakingClient2GCHello(); + bool SendClientGcRankUpdate(); + bool EquipWeapon(int weaponid, int classid, int slotid); +}; + + +extern Protobuffs ProtoFeatures; + +EGCResults __fastcall hkGCRetrieveMessage(void* ecx, void*, uint32_t* punMsgType, void* pubDest, uint32_t cubDest, uint32_t* pcubMsgSize); +EGCResults __fastcall hkGCSendMessage(void* ecx, void*, uint32_t unMsgType, const void* pubData, uint32_t cubData); + + + +``` + +`SpyCustom/proxies.hpp`: + +```hpp +#pragma once + + +RecvVarProxyFn fnSequenceProxyFn = NULL; + +void SetViewModelSequence(const CRecvProxyData* pDataConst, void* pStruct, void* pOut) { + + CRecvProxyData* pData = const_cast(pDataConst); + + C_BaseViewModel* pViewModel = (C_BaseViewModel*)pStruct; + + if (pViewModel) { + IClientEntity* pOwner = iff.g_pEntityList->GetClientEntityFromHandle(pViewModel->GetOwner()); + + if (pOwner && pOwner->GetIndex() == iff.g_pEngineClient->GetLocalPlayer()) { + + + + const model_t* pModel = iff.g_pMdlInfo->GetModel(pViewModel->GetModelIndex()); + const char* szModel = iff.g_pMdlInfo->GetModelName(pModel); + + int m_nSequence = pData->m_Value.m_Int; + + auto model = fnv2::hashRuntime(szModel); + + static int defknifethash = fnv2::hash("models/weapons/v_knife_default_t.mdl"); + static int defknifecthash = fnv2::hash("models/weapons/v_knife_default_ct.mdl"); + if (model == defknifethash || model == defknifecthash) model = fnv2::hash(g_Options.weapons.value->arr[0].model); + + for (int i = 2; i < g_Options.models.value->itemcount; i++) { + + if (model == g_Options.models.value->arr[i].vmodel_hash) + { + if (g_Options.models.value->arr[i].seq_active) + m_nSequence = g_Options.models.value->arr[i].seqs[m_nSequence].seq_repl; + break; + } + if (model == fnv2::hash(g_Options.models.value->arr[i].vmodel_orig)) + { + if (g_Options.models.value->arr[i].seq_active) + m_nSequence = g_Options.models.value->arr[i].seqs[m_nSequence].seq_repl; + + break; + } + } + + switch (model) { + case fnv2::hash("models/weapons/v_knife_butterfly.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_DRAW: + m_nSequence = random(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2); break; + case SEQUENCE_DEFAULT_LOOKAT01: + m_nSequence = random(SEQUENCE_BUTTERFLY_LOOKAT01, SEQUENCE_BUTTERFLY_LOOKAT03); break; + default: + m_nSequence++; + } + break; + } + + + case fnv2::hash("models/weapons/v_knife_falchion_advanced.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_IDLE2: + m_nSequence = SEQUENCE_FALCHION_IDLE1; break; + case SEQUENCE_DEFAULT_HEAVY_MISS1: + m_nSequence = random(SEQUENCE_FALCHION_HEAVY_MISS1, SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP); break; + case SEQUENCE_DEFAULT_LOOKAT01: + m_nSequence = random(SEQUENCE_FALCHION_LOOKAT01, SEQUENCE_FALCHION_LOOKAT02); break; + case SEQUENCE_DEFAULT_DRAW: + case SEQUENCE_DEFAULT_IDLE1: + m_nSequence = m_nSequence; break; + default: + m_nSequence--; + } + break; + } + + + case fnv2::hash("models/weapons/v_knife_push.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_IDLE2: + m_nSequence = SEQUENCE_DAGGERS_IDLE1; break; + case SEQUENCE_DEFAULT_LIGHT_MISS1: + case SEQUENCE_DEFAULT_LIGHT_MISS2: + m_nSequence = random(SEQUENCE_DAGGERS_LIGHT_MISS1, SEQUENCE_DAGGERS_LIGHT_MISS5); break; + case SEQUENCE_DEFAULT_HEAVY_MISS1: + m_nSequence = random(SEQUENCE_DAGGERS_HEAVY_MISS2, SEQUENCE_DAGGERS_HEAVY_MISS1); break; + case SEQUENCE_DEFAULT_HEAVY_HIT1: + case SEQUENCE_DEFAULT_HEAVY_BACKSTAB: + case SEQUENCE_DEFAULT_LOOKAT01: + m_nSequence = m_nSequence + 3; break; + case SEQUENCE_DEFAULT_DRAW: + case SEQUENCE_DEFAULT_IDLE1: + m_nSequence = m_nSequence; break; + default: + m_nSequence = m_nSequence + 2; + } + break; + } + + case fnv2::hash("models/weapons/v_knife_survival_bowie.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_DRAW: + case SEQUENCE_DEFAULT_IDLE1: + m_nSequence = m_nSequence; break; + case SEQUENCE_DEFAULT_IDLE2: + m_nSequence = SEQUENCE_BOWIE_IDLE1; break; + default: + m_nSequence = m_nSequence - 1; + } + break; + } + + case fnv2::hash("models/weapons/v_knife_ursus.mdl"): + case fnv2::hash("models/weapons/v_knife_skeleton.mdl"): + case fnv2::hash("models/weapons/v_knife_outdoor.mdl"): + case fnv2::hash("models/weapons/v_knife_cord.mdl"): + case fnv2::hash("models/weapons/v_knife_canis.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_DRAW: + m_nSequence = random(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2); break; + case SEQUENCE_DEFAULT_LOOKAT01: + m_nSequence = random(SEQUENCE_BUTTERFLY_LOOKAT01, 14); break; + default: + m_nSequence = m_nSequence + 1; + } + break; + } + + case fnv2::hash("models/weapons/v_knife_stiletto.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_LOOKAT01: + m_nSequence = random(12, 13); break; + } + break; + } + + case fnv2::hash("models/weapons/v_knife_widowmaker.mdl"): + { + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_LOOKAT01: + m_nSequence = random(14, 15); break; + } + break; + } + + case fnv2::hash("models/weapons/v_fists.mdl"): + case fnv2::hash("models/weapons/v_axe.mdl"): + case fnv2::hash("models/weapons/v_hammer.mdl"): + case fnv2::hash("models/weapons/v_spanner.mdl"): + { + static int lastpunch = 3; + switch (m_nSequence) + { + case SEQUENCE_DEFAULT_DRAW: + m_nSequence = 1; break; + case 1: + case 2: + case 12: + m_nSequence = 0; break; + default: + if (lastpunch == 3) lastpunch = 2; else lastpunch = 3; + m_nSequence = lastpunch; + } + + break; + } + + } + + //printfdbg("Sequence %s %d (%s)\n", (char*)pViewModel->GetSequenceActivity(m_nSequence), m_nSequence, szModel); + + pData->m_Value.m_Int = m_nSequence; + } + } + + fnSequenceProxyFn(pData, pStruct, pOut); +} + +``` + +`SpyCustom/resources.h`: + +```h +#pragma once + +#ifndef RESOURCES +#define RESOURCES +BYTE hitsound_cod[] = {0x52, 0x49, 0x46, 0x46, 0x56, 0x2E, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x10, 0xB1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x4C, 0x49, 0x53, 0x54, 0x6E, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x46, 0x4F, 0x49, 0x41, 0x52, 0x54, 0x0F, 0x00, 0x00, 0x00, 0x4D, 0x65, 0x74, 0x61, 0x6C, 0x6C, 0x69, 0x63, 0x44, 0x6F, 0x6F, 0x6D, 0x31, 0x36, 0x00, 0x00, 0x49, 0x43, 0x4D, 0x54, 0x1F, 0x00, 0x00, 0x00, 0x42, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x62, 0x79, 0x20, 0x66, 0x6C, 0x61, 0x73, 0x68, 0x6B, 0x69, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x49, 0x4E, 0x41, 0x4D, 0x0B, 0x00, 0x00, 0x00, 0x48, 0x69, 0x74, 0x20, 0x4D, 0x61, 0x72, 0x6B, 0x65, 0x72, 0x00, 0x00, 0x49, 0x53, 0x46, 0x54, 0x0E, 0x00, 0x00, 0x00, 0x4C, 0x61, 0x76, 0x66, 0x35, 0x39, 0x2E, 0x33, 0x31, 0x2E, 0x31, 0x30, 0x30, 0x00, 0x64, 0x61, 0x74, 0x61, 0xBC, 0x2D, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x02, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFB, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF9, 0xFF, 0xF5, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x04, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x06, 0x00, 0x04, 0x00, 0x01, 0x00, 0x06, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xFA, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xF8, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x05, 0x00, 0x09, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFA, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFD, 0xFF, 0x02, 0x00, 0x03, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xF8, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00, 0x06, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x04, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0xFC, 0xFF, 0xF4, 0xFF, 0xF9, 0xFF, 0xFA, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x09, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x09, 0x00, 0x08, 0x00, 0x05, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x04, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFD, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x05, 0x00, 0x04, 0x00, 0xFC, 0xFF, 0xFB, 0xFF, 0xF7, 0xFF, 0xF5, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0x09, 0x00, 0x08, 0x00, 0x11, 0x00, 0x0B, 0x00, 0x03, 0x00, 0x06, 0x00, 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFA, 0xFF, 0x0A, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x13, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xF4, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x14, 0x00, 0x15, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0xFC, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x0E, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x06, 0x00, 0x02, 0x00, 0xF7, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0x03, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0xFD, 0xFF, 0xFB, 0xFF, 0xF4, 0xFF, 0xF2, 0xFF, 0x02, 0x00, 0x05, 0x00, 0x13, 0x00, 0x14, 0x00, 0x09, 0x00, 0x06, 0x00, 0xEC, 0xFF, 0xED, 0xFF, 0xE5, 0xFF, 0xEB, 0xFF, 0x03, 0x00, 0x06, 0x00, 0x1D, 0x00, 0x1A, 0x00, 0x10, 0x00, 0x0D, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xEC, 0xFF, 0xEF, 0xFF, 0xE9, 0xFF, 0xED, 0xFF, 0x08, 0x00, 0x07, 0x00, 0x1A, 0x00, 0x18, 0x00, 0x04, 0x00, 0x07, 0x00, 0xF0, 0xFF, 0xF2, 0xFF, 0xF8, 0xFF, 0xF4, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xF3, 0xFF, 0xF2, 0xFF, 0xE9, 0xFF, 0xEB, 0xFF, 0x0C, 0x00, 0x0C, 0x00, 0x38, 0x00, 0x36, 0x00, 0x16, 0x00, 0x18, 0x00, 0xCB, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xC7, 0xFF, 0x0A, 0x00, 0x0B, 0x00, 0x18, 0x00, 0x1B, 0x00, 0xEE, 0xFF, 0xEB, 0xFF, 0xDF, 0xFF, 0xDC, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x2B, 0x00, 0x2D, 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x11, 0x00, 0x0E, 0x00, 0xBB, 0xFF, 0xB5, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0x06, 0x00, 0x09, 0x00, 0x4A, 0x00, 0x4C, 0x00, 0x25, 0x00, 0x26, 0x00, 0xEB, 0xFF, 0xE9, 0xFF, 0xF9, 0xFF, 0xF6, 0xFF, 0x45, 0x00, 0x47, 0x00, 0x59, 0x00, 0x57, 0x00, 0xE7, 0xFF, 0xE1, 0xFF, 0x8A, 0xFF, 0x8B, 0xFF, 0xDA, 0xFF, 0xDF, 0xFF, 0x4E, 0x00, 0x4F, 0x00, 0x46, 0x00, 0x44, 0x00, 0x02, 0x00, 0x01, 0x00, 0xF2, 0xFF, 0xF1, 0xFF, 0x2E, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x6D, 0x00, 0x1C, 0x00, 0x1B, 0x00, 0x79, 0xFF, 0x79, 0xFF, 0x79, 0xFF, 0x77, 0xFF, 0x0B, 0x00, 0x0A, 0x00, 0x58, 0x00, 0x5A, 0x00, 0x58, 0x00, 0x58, 0x00, 0x43, 0x00, 0x43, 0x00, 0xF1, 0xFF, 0xF3, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0x31, 0x00, 0x31, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x80, 0xFF, 0x7E, 0xFF, 0x46, 0xFF, 0x44, 0xFF, 0x25, 0x00, 0x27, 0x00, 0xC2, 0x00, 0xC1, 0x00, 0x6B, 0x00, 0x69, 0x00, 0xF0, 0xFF, 0xF3, 0xFF, 0xBC, 0xFF, 0xBF, 0xFF, 0xBC, 0xFF, 0xBA, 0xFF, 0x09, 0x00, 0x08, 0x00, 0x30, 0x00, 0x33, 0x00, 0xC6, 0xFF, 0xC5, 0xFF, 0x91, 0xFF, 0x8D, 0xFF, 0x26, 0x00, 0x24, 0x00, 0xA9, 0x00, 0xAC, 0x00, 0x60, 0x00, 0x63, 0x00, 0xD8, 0xFF, 0xD7, 0xFF, 0xB3, 0xFF, 0xB2, 0xFF, 0xD2, 0xFF, 0xD2, 0xFF, 0xF5, 0xFF, 0xF3, 0xFF, 0x17, 0x00, 0x16, 0x00, 0x06, 0x00, 0x05, 0x00, 0xC9, 0xFF, 0xC8, 0xFF, 0x35, 0x00, 0x39, 0x00, 0x36, 0x01, 0x38, 0x01, 0xED, 0x00, 0xEA, 0x00, 0x28, 0xFF, 0x28, 0xFF, 0x8B, 0xFE, 0x8C, 0xFE, 0xDC, 0xFF, 0xD8, 0xFF, 0xBC, 0x00, 0xBC, 0x00, 0x49, 0x00, 0x4E, 0x00, 0xE9, 0xFF, 0xEA, 0xFF, 0x2D, 0x00, 0x2A, 0x00, 0xD3, 0x00, 0xD3, 0x00, 0x76, 0x01, 0x75, 0x01, 0xB8, 0x00, 0xB5, 0x00, 0x7E, 0xFE, 0x81, 0xFE, 0x94, 0xFD, 0x98, 0xFD, 0x88, 0xFF, 0x87, 0xFF, 0xEC, 0x01, 0xEB, 0x01, 0xEB, 0x01, 0xEC, 0x01, 0xF2, 0xFF, 0xF1, 0xFF, 0x1A, 0xFF, 0x1A, 0xFF, 0xE7, 0x00, 0xE8, 0x00, 0x28, 0x02, 0x26, 0x02, 0xDF, 0xFF, 0xDE, 0xFF, 0x3F, 0xFD, 0x42, 0xFD, 0x69, 0xFE, 0x69, 0xFE, 0x74, 0x01, 0x72, 0x01, 0x5F, 0x02, 0x63, 0x02, 0xBF, 0x00, 0xC3, 0x00, 0x32, 0xFF, 0x30, 0xFF, 0x4E, 0x00, 0x4A, 0x00, 0x59, 0x02, 0x56, 0x02, 0xA5, 0x00, 0xA5, 0x00, 0xB0, 0xFC, 0xB5, 0xFC, 0xD4, 0xFC, 0xD7, 0xFC, 0xA1, 0x00, 0x9F, 0x00, 0xDA, 0x02, 0xDB, 0x02, 0xC8, 0x02, 0xC9, 0x02, 0x3B, 0x01, 0x38, 0x01, 0x7D, 0xFE, 0x7B, 0xFE, 0x68, 0xFE, 0x68, 0xFE, 0xA3, 0x01, 0xA5, 0x01, 0x5B, 0x01, 0x5E, 0x01, 0xE0, 0xFC, 0xDF, 0xFC, 0xF3, 0xFC, 0xF0, 0xFC, 0xA8, 0x02, 0xAA, 0x02, 0x1A, 0x05, 0x1C, 0x05, 0xB5, 0x01, 0xB4, 0x01, 0x5D, 0xFE, 0x5C, 0xFE, 0x06, 0xFE, 0x06, 0xFE, 0x10, 0xFF, 0x0F, 0xFF, 0x27, 0x00, 0x27, 0x00, 0x4B, 0x00, 0x4D, 0x00, 0x1C, 0xFF, 0x1C, 0xFF, 0x28, 0xFF, 0x27, 0xFF, 0x44, 0x02, 0x45, 0x02, 0x3D, 0x04, 0x3F, 0x04, 0xCC, 0x00, 0xCC, 0x00, 0x9F, 0xFC, 0x9D, 0xFC, 0xF9, 0xFD, 0xF7, 0xFD, 0xE3, 0x00, 0xE4, 0x00, 0x9C, 0xFF, 0x9F, 0xFF, 0x9C, 0xFD, 0x9C, 0xFD, 0x96, 0xFE, 0x93, 0xFE, 0x02, 0x01, 0x02, 0x01, 0x18, 0x05, 0x1B, 0x05, 0x37, 0x07, 0x37, 0x07, 0x68, 0xFF, 0x65, 0xFF, 0xE7, 0xF5, 0xE8, 0xF5, 0x63, 0xFA, 0x65, 0xFA, 0x2E, 0x03, 0x2D, 0x03, 0xDA, 0xFF, 0xD8, 0xFF, 0xC6, 0xFB, 0xC5, 0xFB, 0x78, 0x02, 0x79, 0x02, 0x18, 0x07, 0x1B, 0x07, 0x17, 0x04, 0x18, 0x04, 0xA4, 0x01, 0xA4, 0x01, 0x87, 0xFC, 0x88, 0xFC, 0x41, 0xF5, 0x40, 0xF5, 0xC8, 0xF9, 0xC5, 0xF9, 0x69, 0x04, 0x69, 0x04, 0xFA, 0x02, 0xFD, 0x02, 0xB4, 0xFD, 0xB4, 0xFD, 0x0D, 0x03, 0x0C, 0x03, 0x69, 0x08, 0x68, 0x08, 0x1B, 0x03, 0x1B, 0x03, 0x92, 0xFA, 0x94, 0xFA, 0xF0, 0xF6, 0xF0, 0xF6, 0xA5, 0xFA, 0xA5, 0xFA, 0xDB, 0x01, 0xDC, 0x01, 0xE6, 0x01, 0xE4, 0x01, 0x46, 0xFC, 0x44, 0xFC, 0x31, 0xFF, 0x33, 0xFF, 0xC9, 0x08, 0xCA, 0x08, 0x95, 0x0A, 0x93, 0x0A, 0xEC, 0x02, 0xED, 0x02, 0xB9, 0xF8, 0xBA, 0xF8, 0x3C, 0xF3, 0x3B, 0xF3, 0x4A, 0xF9, 0x4C, 0xF9, 0xCA, 0x02, 0xC9, 0x02, 0xE1, 0x01, 0xDC, 0x01, 0x68, 0xFF, 0x6A, 0xFF, 0x17, 0x07, 0x1B, 0x07, 0x2A, 0x0C, 0x28, 0x0C, 0x4F, 0x05, 0x4C, 0x05, 0xF8, 0xFB, 0xF8, 0xFB, 0xE4, 0xF4, 0xE3, 0xF4, 0xEC, 0xF2, 0xED, 0xF2, 0x6C, 0xFC, 0x6F, 0xFC, 0x2C, 0x06, 0x2A, 0x06, 0x53, 0x03, 0x50, 0x03, 0x0E, 0x02, 0x0E, 0x02, 0x05, 0x0B, 0x06, 0x0B, 0x22, 0x0B, 0x22, 0x0B, 0x91, 0xFC, 0x93, 0xFC, 0x45, 0xF2, 0x45, 0xF2, 0x61, 0xF4, 0x5E, 0xF4, 0x0A, 0xFC, 0x0B, 0xFC, 0x29, 0x03, 0x2C, 0x03, 0x1B, 0x04, 0x1A, 0x04, 0x16, 0x00, 0x14, 0x00, 0x03, 0x01, 0x04, 0x01, 0x39, 0x07, 0x3A, 0x07, 0xCD, 0x08, 0xCC, 0x08, 0x4D, 0x01, 0x4C, 0x01, 0x04, 0xF4, 0x04, 0xF4, 0xE6, 0xEC, 0xE7, 0xEC, 0xB9, 0xF7, 0xBC, 0xF7, 0x69, 0x07, 0x68, 0x07, 0x77, 0x06, 0x76, 0x06, 0xA6, 0xFF, 0xA6, 0xFF, 0x15, 0x06, 0x13, 0x06, 0xDA, 0x0C, 0xD8, 0x0C, 0x29, 0x04, 0x2C, 0x04, 0x2E, 0xF6, 0x30, 0xF6, 0xBE, 0xEF, 0xBC, 0xEF, 0xA7, 0xF4, 0xA7, 0xF4, 0x9A, 0x02, 0x9B, 0x02, 0x0B, 0x0A, 0x0C, 0x0A, 0xE4, 0x02, 0xE4, 0x02, 0x29, 0xFF, 0x27, 0xFF, 0xD9, 0x07, 0xD5, 0x07, 0x67, 0x0B, 0x66, 0x0B, 0xA6, 0x00, 0xA9, 0x00, 0x05, 0xF2, 0x08, 0xF2, 0x08, 0xED, 0x08, 0xED, 0x9B, 0xFA, 0x9B, 0xFA, 0x4B, 0x0E, 0x4C, 0x0E, 0xB9, 0x0C, 0xB7, 0x0C, 0x32, 0xFB, 0x30, 0xFB, 0xBE, 0xF9, 0xBF, 0xF9, 0xDB, 0x08, 0xDB, 0x08, 0x41, 0x0E, 0x41, 0x0E, 0x72, 0x01, 0x73, 0x01, 0x4D, 0xEF, 0x4D, 0xEF, 0x30, 0xED, 0x30, 0xED, 0x3D, 0x02, 0x40, 0x02, 0x9D, 0x0F, 0x9D, 0x0F, 0x85, 0xFF, 0x80, 0xFF, 0xB9, 0xF4, 0xB9, 0xF4, 0xBC, 0x06, 0xBF, 0x06, 0x5A, 0x11, 0x5B, 0x11, 0xA3, 0x01, 0xA4, 0x01, 0xD6, 0xF3, 0xD7, 0xF3, 0xB0, 0xF1, 0xAF, 0xF1, 0x69, 0xF3, 0x68, 0xF3, 0xC5, 0x01, 0xC3, 0x01, 0xDB, 0x10, 0xDE, 0x10, 0xD9, 0x04, 0xDD, 0x04, 0x64, 0xF4, 0x61, 0xF4, 0x96, 0x02, 0x94, 0x02, 0xEC, 0x10, 0xF1, 0x10, 0x57, 0xFC, 0x55, 0xFC, 0x2E, 0xE6, 0x29, 0xE6, 0x6D, 0xF0, 0x72, 0xF0, 0x91, 0x05, 0x93, 0x05, 0x47, 0x0C, 0x42, 0x0C, 0x99, 0x04, 0x99, 0x04, 0x06, 0xF6, 0x08, 0xF6, 0xFB, 0xF1, 0xFB, 0xF1, 0x54, 0x01, 0x56, 0x01, 0x40, 0x0A, 0x40, 0x0A, 0xA3, 0xFB, 0x9F, 0xFB, 0xD9, 0xEE, 0xD8, 0xEE, 0xAD, 0xF6, 0xAF, 0xF6, 0x86, 0x03, 0x86, 0x03, 0x94, 0x06, 0x95, 0x06, 0x9B, 0x01, 0x9D, 0x01, 0xB0, 0xFA, 0xAF, 0xFA, 0x27, 0xF8, 0x24, 0xF8, 0xA8, 0xFC, 0xA6, 0xFC, 0x08, 0x02, 0x0A, 0x02, 0xFE, 0xFD, 0xFF, 0xFD, 0xF2, 0xF1, 0xF1, 0xF1, 0xDD, 0xF1, 0xDE, 0xF1, 0x0F, 0x04, 0x11, 0x04, 0xFF, 0x0B, 0xFE, 0x0B, 0xE4, 0xFB, 0xE4, 0xFB, 0x16, 0xF2, 0x17, 0xF2, 0xAB, 0x00, 0xA7, 0x00, 0x55, 0x0F, 0x54, 0x0F, 0x34, 0x07, 0x37, 0x07, 0xDA, 0xF0, 0xD9, 0xF0, 0xBF, 0xE7, 0xBE, 0xE7, 0x65, 0xF9, 0x67, 0xF9, 0x10, 0x0F, 0x12, 0x0F, 0xA5, 0x0E, 0xA6, 0x0E, 0x10, 0x00, 0x10, 0x00, 0xA3, 0xF5, 0xA1, 0xF5, 0xCB, 0xF5, 0xCA, 0xF5, 0x57, 0x00, 0x56, 0x00, 0x08, 0x05, 0x06, 0x05, 0x56, 0xF6, 0x56, 0xF6, 0x1B, 0xED, 0x1B, 0xED, 0xF8, 0xFF, 0xF9, 0xFF, 0x15, 0x14, 0x17, 0x14, 0xB3, 0x0B, 0xB1, 0x0B, 0xC6, 0xF6, 0xC5, 0xF6, 0x90, 0xF5, 0x94, 0xF5, 0x28, 0x08, 0x29, 0x08, 0x89, 0x0D, 0x84, 0x0D, 0x1C, 0xF9, 0x1D, 0xF9, 0x7C, 0xED, 0x7D, 0xED, 0x06, 0x00, 0x04, 0x00, 0xDA, 0x14, 0xDB, 0x14, 0x21, 0x15, 0x23, 0x15, 0x5B, 0x08, 0x59, 0x08, 0x4C, 0xF8, 0x4D, 0xF8, 0xC3, 0xEF, 0xC5, 0xEF, 0x0D, 0xF6, 0x0B, 0xF6, 0x1A, 0xFE, 0x18, 0xFE, 0xC4, 0xFE, 0xC2, 0xFE, 0xCB, 0x00, 0xCE, 0x00, 0xD7, 0x05, 0xDF, 0x05, 0x13, 0x08, 0x12, 0x08, 0x00, 0x02, 0xF7, 0x01, 0xD1, 0xEE, 0xD0, 0xEE, 0xBA, 0xE2, 0xBE, 0xE2, 0x90, 0xF5, 0x8F, 0xF5, 0x58, 0x08, 0x57, 0x08, 0xBD, 0xF6, 0xBB, 0xF6, 0x46, 0xE1, 0x45, 0xE1, 0xE6, 0xEB, 0xE9, 0xEB, 0xBA, 0xFE, 0xBE, 0xFE, 0xB7, 0xFF, 0xB6, 0xFF, 0x12, 0xF8, 0x12, 0xF8, 0x34, 0xF6, 0x34, 0xF6, 0xEB, 0xF9, 0xE7, 0xF9, 0x95, 0xF6, 0x96, 0xF6, 0x1F, 0xEE, 0x21, 0xEE, 0x07, 0xF6, 0x05, 0xF6, 0xE2, 0x02, 0xE4, 0x02, 0x48, 0xF7, 0x4B, 0xF7, 0x6F, 0xE8, 0x6D, 0xE8, 0xD8, 0xEF, 0xD9, 0xEF, 0xCD, 0xF9, 0xD0, 0xF9, 0x2F, 0x00, 0x2C, 0x00, 0x9D, 0x04, 0x9B, 0x04, 0x6B, 0xF0, 0x6D, 0xF0, 0x18, 0xD8, 0x17, 0xD8, 0x03, 0xE6, 0x00, 0xE6, 0x87, 0x00, 0x87, 0x00, 0xDF, 0x09, 0xDD, 0x09, 0xCE, 0x10, 0xCC, 0x10, 0xA4, 0x0C, 0xA6, 0x0C, 0x7D, 0xF8, 0x80, 0xF8, 0x4C, 0xF4, 0x4C, 0xF4, 0x82, 0xFA, 0x82, 0xFA, 0xCE, 0xF4, 0xD0, 0xF4, 0xCF, 0xF7, 0xD1, 0xF7, 0xEE, 0x04, 0xF0, 0x04, 0x4F, 0xFE, 0x4C, 0xFE, 0xE3, 0xEA, 0xE0, 0xEA, 0x0C, 0xE9, 0x0E, 0xE9, 0x4F, 0xFD, 0x53, 0xFD, 0x7D, 0x08, 0x7A, 0x08, 0x47, 0xF3, 0x46, 0xF3, 0x7F, 0xE5, 0x81, 0xE5, 0xB8, 0xFC, 0xB7, 0xFC, 0xA8, 0x09, 0xA6, 0x09, 0xA9, 0xFE, 0xAA, 0xFE, 0x0D, 0xFC, 0x0D, 0xFC, 0xF4, 0xF0, 0xF4, 0xF0, 0x16, 0xE8, 0x15, 0xE8, 0x78, 0x02, 0x77, 0x02, 0x8B, 0xFF, 0x8C, 0xFF, 0x2A, 0xD4, 0x2C, 0xD4, 0x3E, 0xE1, 0x3B, 0xE1, 0x0C, 0xFE, 0x0A, 0xFE, 0xF0, 0xDD, 0xF2, 0xDD, 0x9C, 0xE1, 0x9B, 0xE1, 0x89, 0x1A, 0x89, 0x1A, 0xFC, 0x15, 0x03, 0x16, 0x2A, 0xFA, 0x2D, 0xFA, 0x04, 0x09, 0x02, 0x09, 0x58, 0xFD, 0x58, 0xFD, 0x22, 0xE4, 0x20, 0xE4, 0x4F, 0xFD, 0x4A, 0xFD, 0xFE, 0x09, 0xFE, 0x09, 0x35, 0xEF, 0x38, 0xEF, 0x8B, 0xEA, 0x8B, 0xEA, 0xAC, 0xF3, 0xAA, 0xF3, 0xF7, 0xF5, 0xF6, 0xF5, 0x63, 0x07, 0x62, 0x07, 0x00, 0x13, 0x03, 0x13, 0x53, 0x04, 0x58, 0x04, 0x72, 0xF5, 0x72, 0xF5, 0x73, 0xF6, 0x6E, 0xF6, 0x90, 0x08, 0x8C, 0x08, 0x4B, 0x1D, 0x4C, 0x1D, 0xC8, 0x1C, 0xCA, 0x1C, 0xB1, 0x0F, 0xAF, 0x0F, 0x80, 0xF8, 0x81, 0xF8, 0x86, 0xD3, 0x89, 0xD3, 0x4A, 0xD3, 0x49, 0xD3, 0x56, 0x01, 0x55, 0x01, 0x27, 0x0F, 0x29, 0x0F, 0x0E, 0xED, 0x0E, 0xED, 0xAE, 0xDD, 0xAC, 0xDD, 0xD6, 0x00, 0xD8, 0x00, 0x32, 0x35, 0x34, 0x35, 0x6A, 0x38, 0x67, 0x38, 0xEE, 0x04, 0xEC, 0x04, 0x39, 0xE1, 0x39, 0xE1, 0xE2, 0xD2, 0xE1, 0xD2, 0xFD, 0xC3, 0xFD, 0xC3, 0x11, 0xE0, 0x11, 0xE0, 0x43, 0x04, 0x40, 0x04, 0xD9, 0xF4, 0xD9, 0xF4, 0xF6, 0x04, 0xF9, 0x04, 0x6E, 0x38, 0x6F, 0x38, 0x21, 0x20, 0x1F, 0x20, 0x8F, 0xFC, 0x90, 0xFC, 0x63, 0x11, 0x60, 0x11, 0x11, 0xFA, 0x10, 0xFA, 0x9E, 0xD7, 0xA3, 0xD7, 0xCD, 0xFD, 0xCD, 0xFD, 0xBC, 0xFF, 0xB7, 0xFF, 0xE9, 0xDA, 0xE8, 0xDA, 0xD7, 0x0A, 0xD9, 0x0A, 0xBC, 0x38, 0xBD, 0x38, 0xB1, 0x0B, 0xB3, 0x0B, 0xBB, 0xE3, 0xBD, 0xE3, 0x80, 0xD1, 0x81, 0xD1, 0x51, 0xBA, 0x52, 0xBA, 0xB6, 0xD5, 0xB4, 0xD5, 0xCF, 0xFF, 0xCB, 0xFF, 0x0C, 0xFF, 0x0B, 0xFF, 0xA0, 0x0E, 0xA1, 0x0E, 0x85, 0x36, 0x85, 0x36, 0x50, 0x3E, 0x4E, 0x3E, 0x87, 0x18, 0x85, 0x18, 0xEF, 0xC6, 0xED, 0xC6, 0x9E, 0x9A, 0xA0, 0x9A, 0xCC, 0xE1, 0xD0, 0xE1, 0x4C, 0x1E, 0x4C, 0x1E, 0x3F, 0xFC, 0x3B, 0xFC, 0xF9, 0xFC, 0xF9, 0xFC, 0x65, 0x31, 0x68, 0x31, 0x9A, 0x36, 0x99, 0x36, 0x7B, 0x23, 0x7A, 0x23, 0x63, 0x07, 0x68, 0x07, 0x8D, 0xDB, 0x8F, 0xDB, 0xAB, 0xE4, 0xA7, 0xE4, 0x4B, 0xF5, 0x4A, 0xF5, 0x07, 0xC3, 0x0C, 0xC3, 0x28, 0xC6, 0x29, 0xC6, 0x32, 0x1E, 0x2E, 0x1E, 0xB2, 0x3B, 0xB1, 0x3B, 0xEF, 0x24, 0xEF, 0x24, 0x44, 0x11, 0x43, 0x11, 0x36, 0xD5, 0x33, 0xD5, 0x99, 0xBB, 0x98, 0xBB, 0xA6, 0x0C, 0xA5, 0x0C, 0x12, 0x32, 0x13, 0x32, 0xB1, 0xDB, 0xB3, 0xDB, 0xB6, 0x9B, 0xB6, 0x9B, 0xD1, 0xCE, 0xD2, 0xCE, 0x7D, 0x2F, 0x80, 0x2F, 0x16, 0x5C, 0x17, 0x5C, 0x03, 0x2D, 0x01, 0x2D, 0xAB, 0xC8, 0xAB, 0xC8, 0x58, 0x91, 0x58, 0x91, 0x51, 0xCA, 0x50, 0xCA, 0x2C, 0x1A, 0x2F, 0x1A, 0xCD, 0xFD, 0xD0, 0xFD, 0x44, 0xDA, 0x42, 0xDA, 0xBF, 0x28, 0xBE, 0x28, 0x02, 0x2F, 0x03, 0x2F, 0x22, 0x9D, 0x21, 0x9D, 0x00, 0x80, 0x00, 0x80, 0x34, 0xE8, 0x35, 0xE8, 0x91, 0xFD, 0x91, 0xFD, 0x3F, 0xF7, 0x3F, 0xF7, 0x09, 0x25, 0x08, 0x25, 0x25, 0xE0, 0x20, 0xE0, 0xE3, 0x82, 0xDF, 0x82, 0x12, 0xF4, 0x15, 0xF4, 0xD7, 0x5D, 0xDD, 0x5D, 0x57, 0xE7, 0x5C, 0xE7, 0x4C, 0x92, 0x4C, 0x92, 0xAB, 0xE9, 0xAB, 0xE9, 0x94, 0x1C, 0x99, 0x1C, 0x9B, 0x18, 0x9C, 0x18, 0x72, 0x43, 0x6D, 0x43, 0xD9, 0x2E, 0xD7, 0x2E, 0x51, 0xC0, 0x50, 0xC0, 0x27, 0x87, 0x26, 0x87, 0x61, 0x8C, 0x63, 0x8C, 0x86, 0xC2, 0x87, 0xC2, 0x73, 0x43, 0x72, 0x43, 0x1E, 0x78, 0x1E, 0x78, 0x1A, 0x1C, 0x18, 0x1C, 0x28, 0xF0, 0x23, 0xF0, 0x5E, 0x18, 0x5E, 0x18, 0x84, 0x22, 0x87, 0x22, 0xD6, 0x41, 0xD7, 0x41, 0x2E, 0x7A, 0x30, 0x7A, 0x7C, 0x6F, 0x7F, 0x6F, 0xE8, 0x5D, 0xE6, 0x5D, 0x80, 0x42, 0x7F, 0x42, 0x2F, 0xBA, 0x32, 0xBA, 0x00, 0x80, 0x00, 0x80, 0x98, 0x20, 0x97, 0x20, 0xFF, 0x7F, 0xFF, 0x7F, 0xD1, 0x2F, 0xD3, 0x2F, 0x22, 0xD7, 0x1B, 0xD7, 0x8F, 0x37, 0x89, 0x37, 0xFB, 0x7A, 0xFD, 0x7A, 0x96, 0x2B, 0x98, 0x2B, 0xA1, 0xFC, 0xA1, 0xFC, 0x1E, 0x47, 0x21, 0x47, 0x11, 0x7E, 0x13, 0x7E, 0xF2, 0x6A, 0xF1, 0x6A, 0xCB, 0x70, 0xCA, 0x70, 0xFF, 0x7F, 0xFF, 0x7F, 0x77, 0x5F, 0x75, 0x5F, 0xF6, 0x26, 0xF8, 0x26, 0xD4, 0x45, 0xD5, 0x45, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x53, 0x57, 0x51, 0x57, 0xB4, 0x3B, 0xB0, 0x3B, 0xE5, 0x4B, 0xE8, 0x4B, 0x3A, 0x70, 0x3D, 0x70, 0x47, 0x4B, 0x44, 0x4B, 0x76, 0xDC, 0x76, 0xDC, 0x8A, 0xD8, 0x8D, 0xD8, 0xBF, 0x52, 0xBF, 0x52, 0x1A, 0x6F, 0x1B, 0x6F, 0xDC, 0x08, 0xDD, 0x08, 0xD7, 0xC6, 0xD7, 0xC6, 0x63, 0xF5, 0x64, 0xF5, 0x54, 0x66, 0x55, 0x66, 0xA7, 0x71, 0xA6, 0x71, 0xDD, 0xC3, 0xDE, 0xC3, 0x00, 0x80, 0x00, 0x80, 0x6E, 0x09, 0x69, 0x09, 0xEA, 0x7B, 0xE9, 0x7B, 0xEB, 0x3F, 0xED, 0x3F, 0x68, 0x17, 0x67, 0x17, 0x3A, 0x32, 0x3B, 0x32, 0xE5, 0x36, 0xE9, 0x36, 0x02, 0x07, 0x02, 0x07, 0x7B, 0xD6, 0x79, 0xD6, 0xEB, 0x0B, 0xED, 0x0B, 0x2C, 0x4A, 0x2E, 0x4A, 0x31, 0xFA, 0x2F, 0xFA, 0x25, 0xD1, 0x23, 0xD1, 0x16, 0x3C, 0x15, 0x3C, 0x5D, 0x6E, 0x5B, 0x6E, 0x88, 0x56, 0x87, 0x56, 0x7E, 0x26, 0x80, 0x26, 0x93, 0x96, 0x92, 0x96, 0x00, 0x80, 0x00, 0x80, 0x24, 0x21, 0x28, 0x21, 0x5D, 0x42, 0x5F, 0x42, 0xEC, 0xD0, 0xE9, 0xD0, 0xA9, 0xF8, 0xAB, 0xF8, 0x22, 0x44, 0x26, 0x44, 0xBF, 0x3B, 0xBE, 0x3B, 0x38, 0x69, 0x36, 0x69, 0x73, 0x78, 0x74, 0x78, 0xB3, 0x3C, 0xB3, 0x3C, 0x20, 0x59, 0x1D, 0x59, 0x76, 0x48, 0x75, 0x48, 0x68, 0xA0, 0x69, 0xA0, 0xB7, 0x9F, 0xB8, 0x9F, 0x85, 0x58, 0x83, 0x58, 0xD5, 0x4C, 0xD2, 0x4C, 0x34, 0xC3, 0x34, 0xC3, 0x04, 0xE5, 0x05, 0xE5, 0x49, 0x08, 0x4A, 0x08, 0x9D, 0x92, 0x9D, 0x92, 0x00, 0x80, 0x00, 0x80, 0x6C, 0xDD, 0x6E, 0xDD, 0xBB, 0x1F, 0xBC, 0x1F, 0x4C, 0x25, 0x4C, 0x25, 0xBD, 0xE3, 0xBF, 0xE3, 0x00, 0x80, 0x00, 0x80, 0x36, 0xA2, 0x36, 0xA2, 0x07, 0x65, 0x05, 0x65, 0x5D, 0x75, 0x5A, 0x75, 0xB8, 0xE7, 0xB5, 0xE7, 0xF5, 0x99, 0xF3, 0x99, 0x7B, 0x82, 0x77, 0x82, 0x62, 0x8B, 0x5E, 0x8B, 0x46, 0xD7, 0x4A, 0xD7, 0x5D, 0x2D, 0x63, 0x2D, 0x14, 0x76, 0x13, 0x76, 0xFF, 0x7F, 0xFF, 0x7F, 0x8E, 0x16, 0x92, 0x16, 0x00, 0x80, 0x00, 0x80, 0xDD, 0x80, 0xDD, 0x80, 0xE2, 0x19, 0xE3, 0x19, 0x4F, 0x30, 0x4E, 0x30, 0xAB, 0xA8, 0xA9, 0xA8, 0x00, 0x80, 0x00, 0x80, 0x94, 0x94, 0x95, 0x94, 0xA9, 0x85, 0xA9, 0x85, 0x4C, 0x84, 0x4B, 0x84, 0xE4, 0xAF, 0xE3, 0xAF, 0x00, 0x80, 0x00, 0x80, 0x90, 0x83, 0x8F, 0x83, 0x9D, 0x44, 0x9B, 0x44, 0x96, 0x77, 0x96, 0x77, 0xC1, 0xDD, 0xC2, 0xDD, 0x20, 0xDF, 0x20, 0xDF, 0x2D, 0x6C, 0x2E, 0x6C, 0xBE, 0x7C, 0xBD, 0x7C, 0x6F, 0x27, 0x6D, 0x27, 0x1B, 0xE9, 0x1E, 0xE9, 0xDD, 0xEB, 0xE0, 0xEB, 0x01, 0x24, 0xFF, 0x23, 0xDC, 0x4C, 0xDA, 0x4C, 0xEC, 0x53, 0xED, 0x53, 0x4F, 0x61, 0x51, 0x61, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xE6, 0x70, 0xE6, 0x70, 0xB5, 0x5B, 0xB5, 0x5B, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x4D, 0xF1, 0x51, 0xF1, 0x6F, 0xDD, 0x6E, 0xDD, 0xDF, 0x05, 0xDA, 0x05, 0x1B, 0xC3, 0x1C, 0xC3, 0x4B, 0xCA, 0x50, 0xCA, 0xDF, 0x59, 0xE0, 0x59, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x64, 0xFA, 0x5F, 0xFA, 0x00, 0x80, 0x00, 0x80, 0x3F, 0xD0, 0x41, 0xD0, 0xD7, 0x2A, 0xD6, 0x2A, 0x63, 0xBD, 0x64, 0xBD, 0x00, 0x80, 0x00, 0x80, 0x2C, 0x9B, 0x2B, 0x9B, 0x85, 0xAA, 0x86, 0xAA, 0x3E, 0x89, 0x41, 0x89, 0xDF, 0xAC, 0xDE, 0xAC, 0x98, 0x0E, 0x97, 0x0E, 0x38, 0x03, 0x39, 0x03, 0x00, 0x80, 0x00, 0x80, 0x3F, 0x95, 0x3E, 0x95, 0xFE, 0x65, 0xFE, 0x65, 0xCD, 0x5B, 0xCD, 0x5B, 0x3E, 0x97, 0x3E, 0x97, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0xFA, 0xA9, 0xFA, 0xA9, 0x53, 0x4C, 0x56, 0x4C, 0xFF, 0x7F, 0xFF, 0x7F, 0x60, 0x3E, 0x5C, 0x3E, 0xEC, 0xC4, 0xEC, 0xC4, 0x30, 0x18, 0x35, 0x18, 0xDA, 0x57, 0xDC, 0x57, 0x97, 0xB7, 0x95, 0xB7, 0x00, 0x80, 0x00, 0x80, 0x48, 0xDA, 0x48, 0xDA, 0xB0, 0xF0, 0xAE, 0xF0, 0x00, 0x80, 0x00, 0x80, 0x86, 0xC5, 0x88, 0xC5, 0xCD, 0x59, 0xCD, 0x59, 0xD0, 0x6B, 0xD0, 0x6B, 0x6A, 0x7F, 0x6B, 0x7F, 0x6F, 0x5D, 0x6F, 0x5D, 0x8C, 0x0A, 0x89, 0x0A, 0x16, 0x6F, 0x12, 0x6F, 0xFF, 0x7F, 0xFF, 0x7F, 0xB5, 0x01, 0xB8, 0x01, 0xF5, 0x83, 0xF6, 0x83, 0xEB, 0xEC, 0xE9, 0xEC, 0xDA, 0x65, 0xDB, 0x65, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x7D, 0x2A, 0x7E, 0x2A, 0x93, 0x9B, 0x93, 0x9B, 0x00, 0x80, 0x00, 0x80, 0x9C, 0x82, 0x9C, 0x82, 0x1C, 0xA9, 0x1C, 0xA9, 0x1F, 0x8F, 0x1E, 0x8F, 0x19, 0x89, 0x1A, 0x89, 0x85, 0x97, 0x85, 0x97, 0xB5, 0x9A, 0xB3, 0x9A, 0x99, 0x05, 0x98, 0x05, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x1F, 0x78, 0x1D, 0x78, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xF5, 0x7E, 0xF6, 0x7E, 0xFF, 0x7F, 0xFF, 0x7F, 0xE1, 0x76, 0xE1, 0x76, 0x02, 0x57, 0xFF, 0x56, 0xFF, 0x7F, 0xFF, 0x7F, 0xF8, 0x54, 0xFB, 0x54, 0x00, 0x80, 0x00, 0x80, 0x4A, 0xAE, 0x49, 0xAE, 0x0F, 0xEC, 0x12, 0xEC, 0x00, 0x80, 0x00, 0x80, 0xCA, 0xBF, 0xC6, 0xBF, 0xCE, 0x75, 0xCD, 0x75, 0xB9, 0xD2, 0xB9, 0xD2, 0xF0, 0x8B, 0xF2, 0x8B, 0x2A, 0x42, 0x2A, 0x42, 0x11, 0x1A, 0x0D, 0x1A, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x58, 0x1B, 0x5C, 0x1B, 0xFF, 0x7F, 0xFF, 0x7F, 0xFC, 0x4C, 0xFB, 0x4C, 0xF1, 0x0D, 0xEE, 0x0D, 0x01, 0x6E, 0x00, 0x6E, 0x0F, 0x62, 0x11, 0x62, 0xE2, 0x92, 0xE2, 0x92, 0x00, 0x80, 0x00, 0x80, 0x02, 0xC4, 0x04, 0xC4, 0x88, 0x9C, 0x89, 0x9C, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x1B, 0x91, 0x1D, 0x91, 0x34, 0x94, 0x36, 0x94, 0xB5, 0x8F, 0xB5, 0x8F, 0xC1, 0x8D, 0xC1, 0x8D, 0x2A, 0xA1, 0x28, 0xA1, 0x7F, 0xBA, 0x7C, 0xBA, 0x2C, 0x8A, 0x2D, 0x8A, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x1A, 0x89, 0x1A, 0x89, 0xFE, 0x8C, 0xFE, 0x8C, 0x35, 0x83, 0x35, 0x83, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x44, 0x98, 0x44, 0x98, 0x67, 0xCE, 0x68, 0xCE, 0x8B, 0x26, 0x8B, 0x26, 0xFF, 0x7F, 0xFF, 0x7F, 0x7B, 0x6C, 0x7B, 0x6C, 0x5F, 0xF8, 0x5E, 0xF8, 0x62, 0x1C, 0x60, 0x1C, 0xFF, 0x7F, 0xFF, 0x7F, 0x25, 0x7B, 0x25, 0x7B, 0x40, 0x5A, 0x3F, 0x5A, 0x60, 0x7C, 0x61, 0x7C, 0x29, 0x77, 0x2D, 0x77, 0xCF, 0x7B, 0xD1, 0x7B, 0xFF, 0x7F, 0xFF, 0x7F, 0x13, 0x57, 0x13, 0x57, 0xB8, 0xAC, 0xBB, 0xAC, 0x00, 0x80, 0x00, 0x80, 0x25, 0xE1, 0x22, 0xE1, 0x83, 0x7D, 0x81, 0x7D, 0xFF, 0x7F, 0xFF, 0x7F, 0xC5, 0x4B, 0xC3, 0x4B, 0x36, 0xB3, 0x34, 0xB3, 0x00, 0x80, 0x00, 0x80, 0x79, 0xD7, 0x7A, 0xD7, 0x3C, 0x7B, 0x3C, 0x7B, 0x80, 0x73, 0x81, 0x73, 0x20, 0xB2, 0x21, 0xB2, 0x00, 0x80, 0x00, 0x80, 0x4B, 0x06, 0x4C, 0x06, 0xBA, 0x6B, 0xB9, 0x6B, 0x42, 0x65, 0x41, 0x65, 0x52, 0x72, 0x53, 0x72, 0xFE, 0x7D, 0xFD, 0x7D, 0xA7, 0x6E, 0xA6, 0x6E, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x90, 0x7D, 0x91, 0x7D, 0xF4, 0x7C, 0xF5, 0x7C, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xF3, 0x73, 0xF6, 0x73, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x6F, 0x77, 0x6E, 0x77, 0x6C, 0x77, 0x6C, 0x77, 0xE8, 0x7D, 0xE7, 0x7D, 0xC7, 0x78, 0xC7, 0x78, 0x58, 0x7E, 0x5B, 0x7E, 0xFF, 0x7F, 0xFF, 0x7F, 0xA4, 0x63, 0xA3, 0x63, 0x13, 0xE2, 0x12, 0xE2, 0x00, 0x80, 0x00, 0x80, 0x13, 0xB7, 0x12, 0xB7, 0x13, 0x7F, 0x11, 0x7F, 0xCE, 0x7A, 0xD0, 0x7A, 0xAD, 0xB2, 0xAF, 0xB2, 0x7A, 0x96, 0x7A, 0x96, 0x3B, 0x3C, 0x3A, 0x3C, 0xFF, 0x7F, 0xFF, 0x7F, 0x46, 0x71, 0x44, 0x71, 0xFF, 0x7F, 0xFF, 0x7F, 0x1E, 0x50, 0x1E, 0x50, 0xA0, 0xB7, 0xA4, 0xB7, 0x00, 0x80, 0x00, 0x80, 0xD4, 0x88, 0xD3, 0x88, 0x0E, 0x93, 0x0D, 0x93, 0x44, 0x89, 0x45, 0x89, 0x04, 0x83, 0x06, 0x83, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x9B, 0x84, 0x9B, 0x84, 0xEB, 0x88, 0xEC, 0x88, 0x57, 0x8B, 0x56, 0x8B, 0x6D, 0x87, 0x6C, 0x87, 0x9B, 0x84, 0x9A, 0x84, 0x8B, 0x82, 0x8A, 0x82, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0xDD, 0x84, 0xDB, 0x84, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x9A, 0x8D, 0x9B, 0x8D, 0xFE, 0x8B, 0xFA, 0x8B, 0x5A, 0x9A, 0x56, 0x9A, 0x52, 0xBD, 0x53, 0xBD, 0xB8, 0xBD, 0xBB, 0xBD, 0x25, 0xB1, 0x24, 0xB1, 0xA2, 0xBF, 0x9E, 0xBF, 0x8D, 0xC7, 0x8D, 0xC7, 0x0A, 0xC5, 0x0D, 0xC5, 0x14, 0xD9, 0x15, 0xD9, 0x6E, 0xF2, 0x70, 0xF2, 0x7E, 0xF6, 0x80, 0xF6, 0x65, 0xEC, 0x61, 0xEC, 0x68, 0xE6, 0x67, 0xE6, 0x35, 0xEF, 0x38, 0xEF, 0x04, 0xF8, 0x02, 0xF8, 0x72, 0xF7, 0x70, 0xF7, 0xD0, 0xFF, 0xD3, 0xFF, 0x34, 0x0C, 0x31, 0x0C, 0x86, 0x0E, 0x83, 0x0E, 0x02, 0x10, 0x05, 0x10, 0xF9, 0x03, 0xF8, 0x03, 0x6A, 0xED, 0x68, 0xED, 0x2F, 0xFC, 0x35, 0xFC, 0xC9, 0x1C, 0xCC, 0x1C, 0xE4, 0x18, 0xE2, 0x18, 0xB9, 0x11, 0xBA, 0x11, 0xAA, 0x1A, 0xA9, 0x1A, 0x1F, 0x0C, 0x1B, 0x0C, 0x7C, 0x04, 0x7D, 0x04, 0x0A, 0x1F, 0x0B, 0x1F, 0xC2, 0x20, 0xC0, 0x20, 0xAB, 0x19, 0xAD, 0x19, 0x6B, 0x4C, 0x6C, 0x4C, 0xA8, 0x7E, 0xA8, 0x7E, 0x5D, 0x7B, 0x5F, 0x7B, 0xB2, 0x7B, 0xB2, 0x7B, 0xFF, 0x7F, 0xFF, 0x7F, 0x85, 0x71, 0x86, 0x71, 0xA6, 0x73, 0xA5, 0x73, 0x76, 0x77, 0x73, 0x77, 0x22, 0x53, 0x22, 0x53, 0x1C, 0x52, 0x1D, 0x52, 0x28, 0x79, 0x2C, 0x79, 0xFB, 0x5A, 0x01, 0x5B, 0x17, 0x29, 0x16, 0x29, 0x77, 0x4C, 0x73, 0x4C, 0x34, 0x79, 0x33, 0x79, 0x33, 0x74, 0x32, 0x74, 0x7A, 0x7A, 0x79, 0x7A, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xB7, 0x6A, 0xB2, 0x6A, 0x75, 0x49, 0x77, 0x49, 0x76, 0x44, 0x7A, 0x44, 0xE2, 0x5C, 0xE2, 0x5C, 0xFB, 0x4B, 0xFC, 0x4B, 0x38, 0x30, 0x3B, 0x30, 0x55, 0x5D, 0x55, 0x5D, 0xFF, 0x7F, 0xFF, 0x7F, 0x5F, 0x65, 0x5D, 0x65, 0xEC, 0x45, 0xED, 0x45, 0x42, 0x56, 0x3F, 0x56, 0x63, 0x64, 0x61, 0x64, 0x7F, 0x63, 0x81, 0x63, 0x80, 0x62, 0x81, 0x62, 0x44, 0x65, 0x46, 0x65, 0xFF, 0x70, 0x02, 0x71, 0x76, 0x7A, 0x75, 0x7A, 0xD8, 0x72, 0xD6, 0x72, 0xD7, 0x5F, 0xDA, 0x5F, 0xD3, 0x4E, 0xD5, 0x4E, 0x0C, 0x4D, 0x0A, 0x4D, 0xE5, 0x58, 0xE3, 0x58, 0x76, 0x60, 0x72, 0x60, 0xBD, 0x60, 0xBE, 0x60, 0xC9, 0x62, 0xD0, 0x62, 0x2D, 0x64, 0x2D, 0x64, 0xE6, 0x5D, 0xE1, 0x5D, 0x0A, 0x5B, 0x08, 0x5B, 0x82, 0x6C, 0x81, 0x6C, 0xDE, 0x6E, 0xE1, 0x6E, 0xFB, 0x39, 0x00, 0x3A, 0x0C, 0x12, 0x09, 0x12, 0x91, 0x2A, 0x8E, 0x2A, 0xDD, 0x2A, 0xE3, 0x2A, 0x20, 0x03, 0x21, 0x03, 0x54, 0x1D, 0x4E, 0x1D, 0x15, 0x59, 0x16, 0x59, 0xEF, 0x44, 0xF0, 0x44, 0x8F, 0x02, 0x8D, 0x02, 0xD7, 0xE4, 0xD9, 0xE4, 0x46, 0xED, 0x46, 0xED, 0xFF, 0xF5, 0xFB, 0xF5, 0xC8, 0xDC, 0xC9, 0xDC, 0x4F, 0xBB, 0x52, 0xBB, 0x8A, 0xC9, 0x89, 0xC9, 0xAF, 0xE6, 0xAF, 0xE6, 0x3A, 0xE0, 0x3A, 0xE0, 0x61, 0xDE, 0x5E, 0xDE, 0x6B, 0x00, 0x6C, 0x00, 0x5A, 0x21, 0x5C, 0x21, 0x65, 0x21, 0x64, 0x21, 0xC6, 0x09, 0xC7, 0x09, 0xB6, 0xFD, 0xB8, 0xFD, 0x66, 0x02, 0x64, 0x02, 0xCC, 0xF7, 0xCA, 0xF7, 0xF6, 0xEB, 0xF6, 0xEB, 0x7F, 0xEA, 0x7F, 0xEA, 0x6A, 0xBC, 0x6B, 0xBC, 0x77, 0x8A, 0x75, 0x8A, 0x19, 0xCB, 0x16, 0xCB, 0x4E, 0x2F, 0x4F, 0x2F, 0x1A, 0x1C, 0x1F, 0x1C, 0x1F, 0xE8, 0x1E, 0xE8, 0x18, 0x13, 0x16, 0x13, 0x5A, 0x40, 0x5B, 0x40, 0x31, 0x23, 0x33, 0x23, 0xBC, 0x11, 0xBF, 0x11, 0x74, 0x30, 0x75, 0x30, 0xB1, 0x50, 0xAD, 0x50, 0x8C, 0x68, 0x87, 0x68, 0x7D, 0x69, 0x7C, 0x69, 0x9A, 0x46, 0x9B, 0x46, 0x8A, 0x31, 0x8B, 0x31, 0x03, 0x3C, 0x08, 0x3C, 0xEB, 0x3E, 0xEB, 0x3E, 0x8B, 0x3E, 0x88, 0x3E, 0xE8, 0x49, 0xE9, 0x49, 0x40, 0x4C, 0x44, 0x4C, 0xA4, 0x42, 0xA2, 0x42, 0xFD, 0x37, 0xFB, 0x37, 0x8E, 0x32, 0x8E, 0x32, 0x08, 0x32, 0x08, 0x32, 0x22, 0x14, 0x24, 0x14, 0x93, 0xDB, 0x95, 0xDB, 0x85, 0xD6, 0x83, 0xD6, 0x82, 0x0A, 0x80, 0x0A, 0x3D, 0x1C, 0x3E, 0x1C, 0x61, 0xF0, 0x62, 0xF0, 0xE4, 0xC7, 0xE3, 0xC7, 0x8C, 0xD4, 0x89, 0xD4, 0xD0, 0xEB, 0xCF, 0xEB, 0x46, 0xCA, 0x46, 0xCA, 0xDB, 0xA5, 0xDE, 0xA5, 0x4F, 0xC2, 0x52, 0xC2, 0x1C, 0xC8, 0x1C, 0xC8, 0xE8, 0x8F, 0xE7, 0x8F, 0xDE, 0x86, 0xDE, 0x86, 0x9C, 0xA9, 0x9D, 0xA9, 0x4B, 0x9D, 0x48, 0x9D, 0x43, 0x82, 0x3F, 0x82, 0x0D, 0x82, 0x0D, 0x82, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x70, 0x8A, 0x72, 0x8A, 0xCA, 0xA4, 0xCC, 0xA4, 0x3F, 0x9C, 0x3F, 0x9C, 0x80, 0x8C, 0x7E, 0x8C, 0x12, 0x89, 0x11, 0x89, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x5B, 0x83, 0x5E, 0x83, 0xBA, 0x92, 0xBB, 0x92, 0x85, 0xAD, 0x82, 0xAD, 0xAE, 0xC5, 0xAF, 0xC5, 0x40, 0xCF, 0x3F, 0xCF, 0xD9, 0xB9, 0xD6, 0xB9, 0x59, 0x92, 0x5B, 0x92, 0xC7, 0x97, 0xC9, 0x97, 0xE8, 0xD9, 0xE9, 0xD9, 0x49, 0x08, 0x4E, 0x08, 0x88, 0xF4, 0x87, 0xF4, 0x8E, 0xDF, 0x86, 0xDF, 0xD1, 0xF5, 0xD1, 0xF5, 0x20, 0x04, 0x26, 0x04, 0x6E, 0xF3, 0x6C, 0xF3, 0x06, 0xEE, 0x05, 0xEE, 0xF5, 0xF6, 0xF7, 0xF6, 0xF4, 0xF6, 0xF2, 0xF6, 0x44, 0xF8, 0x42, 0xF8, 0xAD, 0xFB, 0xB0, 0xFB, 0x3A, 0xF7, 0x3E, 0xF7, 0x12, 0xF8, 0x12, 0xF8, 0x2E, 0xFE, 0x2A, 0xFE, 0x78, 0xFE, 0x75, 0xFE, 0xCA, 0x00, 0xCC, 0x00, 0xA2, 0x01, 0xA4, 0x01, 0x3E, 0xF9, 0x3F, 0xF9, 0x06, 0xF8, 0x09, 0xF8, 0xD6, 0x00, 0xD5, 0x00, 0x67, 0x03, 0x64, 0x03, 0x2A, 0x02, 0x2A, 0x02, 0xC9, 0x05, 0xCA, 0x05, 0xF3, 0x09, 0xF1, 0x09, 0x8F, 0x08, 0x8F, 0x08, 0xFB, 0x02, 0xFB, 0x02, 0x03, 0x01, 0x01, 0x01, 0xE9, 0x00, 0xEA, 0x00, 0xA5, 0xFC, 0xA6, 0xFC, 0xC2, 0x00, 0xC1, 0x00, 0x38, 0x0D, 0x39, 0x0D, 0x47, 0x08, 0x49, 0x08, 0xA2, 0xF8, 0xA3, 0xF8, 0x04, 0xFA, 0x01, 0xFA, 0xC3, 0x00, 0xBF, 0x00, 0x10, 0xFB, 0x10, 0xFB, 0x40, 0xF7, 0x43, 0xF7, 0x9E, 0x00, 0x9F, 0x00, 0x93, 0x0E, 0x93, 0x0E, 0xB1, 0x12, 0xB1, 0x12, 0xD3, 0x05, 0xD2, 0x05, 0x0D, 0xF6, 0x0C, 0xF6, 0x1E, 0xF4, 0x1E, 0xF4, 0xAB, 0xFA, 0xAB, 0xFA, 0x02, 0x00, 0x03, 0x00, 0x1A, 0x02, 0x1B, 0x02, 0x34, 0xFE, 0x32, 0xFE, 0x02, 0xF8, 0x02, 0xF8, 0x52, 0xF8, 0x54, 0xF8, 0x9F, 0xFE, 0x9D, 0xFE, 0x34, 0x04, 0x35, 0x04, 0x1B, 0x05, 0x1E, 0x05, 0x6E, 0x01, 0x6E, 0x01, 0x1C, 0xFB, 0x19, 0xFB, 0xE2, 0xF3, 0xE0, 0xF3, 0xD2, 0xF2, 0xD3, 0xF2, 0x4E, 0xFE, 0x50, 0xFE, 0x06, 0x0B, 0x07, 0x0B, 0x01, 0x0B, 0x00, 0x0B, 0xBA, 0x04, 0xBC, 0x04, 0x6D, 0x02, 0x6E, 0x02, 0x62, 0x01, 0x5D, 0x01, 0x74, 0xFE, 0x72, 0xFE, 0x47, 0xFD, 0x4C, 0xFD, 0x1C, 0x01, 0x1D, 0x01, 0x88, 0x06, 0x84, 0x06, 0x44, 0x06, 0x45, 0x06, 0xB9, 0x00, 0xBB, 0x00, 0x36, 0xFD, 0x35, 0xFD, 0x4F, 0xFD, 0x50, 0xFD, 0x89, 0xFE, 0x8B, 0xFE, 0xA9, 0x00, 0xA5, 0x00, 0xB4, 0x02, 0xB0, 0x02, 0x39, 0x03, 0x3B, 0x03, 0xB3, 0x01, 0xB5, 0x01, 0x26, 0xFE, 0x26, 0xFE, 0xFE, 0xFB, 0xFD, 0xFB, 0x68, 0xFE, 0x65, 0xFE, 0xEF, 0x02, 0xEE, 0x02, 0x7C, 0x05, 0x7F, 0x05, 0x80, 0x03, 0x82, 0x03, 0xE6, 0xFD, 0xE5, 0xFD, 0x16, 0xFA, 0x14, 0xFA, 0x34, 0xFA, 0x32, 0xFA, 0x55, 0xFC, 0x55, 0xFC, 0xA8, 0x00, 0xA9, 0x00, 0x34, 0x04, 0x33, 0x04, 0x79, 0x02, 0x7B, 0x02, 0x0C, 0xFF, 0x0F, 0xFF, 0x39, 0xFE, 0x35, 0xFE, 0x20, 0xFF, 0x1C, 0xFF, 0xFA, 0xFF, 0xFE, 0xFF, 0x39, 0xFD, 0x38, 0xFD, 0x4D, 0xF9, 0x49, 0xF9, 0x82, 0xFC, 0x85, 0xFC, 0xFA, 0x00, 0xFC, 0x00, 0x6C, 0xFE, 0x6A, 0xFE, 0xD6, 0xFD, 0xD8, 0xFD, 0xEA, 0xFF, 0xEC, 0xFF, 0xD4, 0xFA, 0xD2, 0xFA, 0xAE, 0xF8, 0xAD, 0xF8, 0x55, 0x02, 0x54, 0x02, 0x90, 0x07, 0x8F, 0x07, 0x57, 0xFF, 0x56, 0xFF, 0xE4, 0xF5, 0xE4, 0xF5, 0xDC, 0xF6, 0xDC, 0xF6, 0x27, 0x01, 0x29, 0x01, 0x9C, 0x06, 0x9D, 0x06, 0xF1, 0xFF, 0xEF, 0xFF, 0x7D, 0xFB, 0x7C, 0xFB, 0xDD, 0xFF, 0xDE, 0xFF, 0xB3, 0x00, 0xB7, 0x00, 0x2B, 0xFD, 0x2D, 0xFD, 0x60, 0xFE, 0x5C, 0xFE, 0x26, 0x02, 0x26, 0x02, 0xD9, 0x02, 0xDD, 0x02, 0x0B, 0x01, 0x0C, 0x01, 0x7D, 0x01, 0x7F, 0x01, 0x20, 0x05, 0x22, 0x05, 0x70, 0x02, 0x6F, 0x02, 0x05, 0xF9, 0x04, 0xF9, 0xA5, 0xF8, 0xA6, 0xF8, 0x96, 0x00, 0x94, 0x00, 0xBC, 0x01, 0xBB, 0x01, 0xA7, 0xFE, 0xAB, 0xFE, 0xCE, 0xFD, 0xD0, 0xFD, 0xDD, 0xFA, 0xDD, 0xFA, 0x60, 0xF9, 0x60, 0xF9, 0x52, 0xFE, 0x4E, 0xFE, 0xD2, 0x01, 0xD0, 0x01, 0xA4, 0xFF, 0xA6, 0xFF, 0x03, 0xFE, 0x06, 0xFE, 0xBD, 0x00, 0xBC, 0x00, 0x29, 0x04, 0x28, 0x04, 0x12, 0x02, 0x11, 0x02, 0x3D, 0xFD, 0x3A, 0xFD, 0xE1, 0xFF, 0xDE, 0xFF, 0xA9, 0x06, 0xAB, 0x06, 0x48, 0x04, 0x4C, 0x04, 0x18, 0xFC, 0x17, 0xFC, 0x98, 0xFC, 0x96, 0xFC, 0xFD, 0x03, 0xFF, 0x03, 0xCE, 0x03, 0xCC, 0x03, 0xE4, 0xFC, 0xDF, 0xFC, 0x09, 0xFF, 0x0B, 0xFF, 0x98, 0x08, 0x9C, 0x08, 0xA5, 0x06, 0xA4, 0x06, 0x7F, 0xFB, 0x7F, 0xFB, 0x0C, 0xFB, 0x0C, 0xFB, 0xD1, 0x02, 0xCD, 0x02, 0xD4, 0x01, 0xD0, 0x01, 0x45, 0xFB, 0x45, 0xFB, 0x19, 0xFD, 0x1D, 0xFD, 0x3B, 0x04, 0x3E, 0x04, 0x68, 0x03, 0x67, 0x03, 0xE0, 0xFB, 0xDE, 0xFB, 0xCA, 0xFA, 0xCB, 0xFA, 0xBF, 0x00, 0xC0, 0x00, 0x06, 0x02, 0x04, 0x02, 0x66, 0xFD, 0x66, 0xFD, 0xC6, 0xFB, 0xC6, 0xFB, 0x5F, 0xFE, 0x5E, 0xFE, 0x21, 0xFF, 0x1D, 0xFF, 0xB7, 0xFC, 0xB5, 0xFC, 0x73, 0xFC, 0x76, 0xFC, 0x24, 0x00, 0x23, 0x00, 0xAE, 0x01, 0xAA, 0x01, 0xC4, 0xFF, 0xC7, 0xFF, 0x42, 0x00, 0x45, 0x00, 0x08, 0x01, 0x03, 0x01, 0x27, 0xFE, 0x26, 0xFE, 0xA7, 0xFE, 0xA8, 0xFE, 0x0E, 0x04, 0x0B, 0x04, 0x91, 0x04, 0x90, 0x04, 0x01, 0x00, 0x02, 0x00, 0x94, 0xFE, 0x93, 0xFE, 0x31, 0x00, 0x32, 0x00, 0x25, 0x00, 0x23, 0x00, 0x20, 0xFE, 0x1C, 0xFE, 0x59, 0xFD, 0x5D, 0xFD, 0x26, 0xFF, 0x2B, 0xFF, 0x9A, 0xFF, 0x97, 0xFF, 0xC2, 0xFD, 0xC4, 0xFD, 0x46, 0xFF, 0x49, 0xFF, 0x9E, 0x02, 0x9A, 0x02, 0x4B, 0x00, 0x4B, 0x00, 0x7C, 0xFB, 0x81, 0xFB, 0x64, 0xFC, 0x63, 0xFC, 0x53, 0x01, 0x51, 0x01, 0x22, 0x03, 0x25, 0x03, 0x10, 0x00, 0x13, 0x00, 0x96, 0xFD, 0x97, 0xFD, 0xB6, 0xFF, 0xB3, 0xFF, 0xB5, 0x01, 0xB2, 0x01, 0x24, 0x00, 0x26, 0x00, 0x98, 0xFF, 0x9A, 0xFF, 0xB2, 0x00, 0xB0, 0x00, 0x70, 0xFF, 0x70, 0xFF, 0x4D, 0xFE, 0x4F, 0xFE, 0x6C, 0x00, 0x70, 0x00, 0x33, 0x02, 0x34, 0x02, 0xF2, 0x00, 0xEE, 0x00, 0xFD, 0xFE, 0xFD, 0xFE, 0x3B, 0xFF, 0x3F, 0xFF, 0x57, 0x01, 0x56, 0x01, 0xD0, 0x01, 0xD0, 0x01, 0xB5, 0xFF, 0xB7, 0xFF, 0x55, 0xFE, 0x51, 0xFE, 0xA5, 0xFE, 0xA2, 0xFE, 0x03, 0xFF, 0x06, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xAA, 0x01, 0xA8, 0x01, 0x65, 0x02, 0x65, 0x02, 0x0F, 0x01, 0x11, 0x01, 0x1E, 0xFF, 0x23, 0xFF, 0xCF, 0xFE, 0xD1, 0xFE, 0x31, 0x00, 0x2D, 0x00, 0x04, 0x01, 0x05, 0x01, 0x5D, 0x00, 0x61, 0x00, 0x8A, 0xFF, 0x89, 0xFF, 0x99, 0xFF, 0x96, 0xFF, 0x28, 0x00, 0x29, 0x00, 0x13, 0x00, 0x15, 0x00, 0xA5, 0xFF, 0xA6, 0xFF, 0x43, 0x00, 0x42, 0x00, 0xE2, 0x00, 0xE3, 0x00, 0x13, 0x00, 0x18, 0x00, 0x81, 0xFF, 0x80, 0xFF, 0x18, 0x00, 0x15, 0x00, 0x5A, 0x00, 0x5D, 0x00, 0xF0, 0xFF, 0xEF, 0xFF, 0x6B, 0xFF, 0x69, 0xFF, 0x78, 0xFF, 0x7F, 0xFF, 0x94, 0x00, 0x94, 0x00, 0xE5, 0x00, 0xDC, 0x00, 0x3F, 0xFF, 0x3E, 0xFF, 0x43, 0xFE, 0x44, 0xFE, 0x1C, 0xFF, 0x18, 0xFF, 0xED, 0xFF, 0xE9, 0xFF, 0x54, 0x00, 0x54, 0x00, 0xC5, 0x00, 0xC9, 0x00, 0xB8, 0x00, 0xBD, 0x00, 0x25, 0x00, 0x22, 0x00, 0x79, 0xFF, 0x75, 0xFF, 0x3D, 0xFF, 0x3F, 0xFF, 0xB7, 0xFF, 0xB5, 0xFF, 0x08, 0x00, 0x01, 0x00, 0xF6, 0xFF, 0xF7, 0xFF, 0x42, 0x00, 0x45, 0x00, 0x49, 0x00, 0x46, 0x00, 0xA7, 0xFF, 0xA4, 0xFF, 0x7A, 0xFF, 0x7C, 0xFF, 0xA0, 0xFF, 0xA3, 0xFF, 0x57, 0xFF, 0x56, 0xFF, 0x34, 0xFF, 0x32, 0xFF, 0x71, 0xFF, 0x73, 0xFF, 0x8C, 0xFF, 0x8B, 0xFF, 0x70, 0xFF, 0x6E, 0xFF, 0x28, 0xFF, 0x2A, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0x43, 0xFF, 0x41, 0xFF, 0x6C, 0xFF, 0x70, 0xFF, 0x3B, 0xFF, 0x3B, 0xFF, 0x48, 0xFF, 0x46, 0xFF, 0x95, 0xFF, 0x98, 0xFF, 0x8F, 0xFF, 0x8F, 0xFF, 0x4E, 0xFF, 0x4B, 0xFF, 0x5D, 0xFF, 0x60, 0xFF, 0xCD, 0xFF, 0xCD, 0xFF, 0x1D, 0x00, 0x18, 0x00, 0x07, 0x00, 0x0A, 0x00, 0xDE, 0xFF, 0xE0, 0xFF, 0xD9, 0xFF, 0xD5, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0x33, 0x00, 0x36, 0x00, 0x89, 0x00, 0x88, 0x00, 0xC2, 0x00, 0xC2, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0x8B, 0x00, 0x8A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x87, 0x00, 0x85, 0x00, 0xB2, 0x00, 0xB2, 0x00, 0xA7, 0x00, 0xA9, 0x00, 0x76, 0x00, 0x76, 0x00, 0x55, 0x00, 0x54, 0x00, 0x64, 0x00, 0x66, 0x00, 0x67, 0x00, 0x6A, 0x00, 0x36, 0x00, 0x37, 0x00, 0x19, 0x00, 0x18, 0x00, 0x13, 0x00, 0x13, 0x00, 0xDE, 0xFF, 0xE0, 0xFF, 0xA6, 0xFF, 0xA6, 0xFF, 0x95, 0xFF, 0x94, 0xFF, 0x7E, 0xFF, 0x80, 0xFF, 0x4F, 0xFF, 0x51, 0xFF, 0x1A, 0xFF, 0x18, 0xFF, 0xFD, 0xFE, 0xFD, 0xFE, 0x09, 0xFF, 0x0B, 0xFF, 0xED, 0xFE, 0xF1, 0xFE, 0x97, 0xFE, 0x99, 0xFE, 0x71, 0xFE, 0x70, 0xFE, 0x82, 0xFE, 0x80, 0xFE, 0x83, 0xFE, 0x85, 0xFE, 0x82, 0xFE, 0x84, 0xFE, 0x8B, 0xFE, 0x8D, 0xFE, 0x85, 0xFE, 0x85, 0xFE, 0x6F, 0xFE, 0x6B, 0xFE, 0x54, 0xFE, 0x53, 0xFE, 0x54, 0xFE, 0x55, 0xFE, 0x75, 0xFE, 0x72, 0xFE, 0x8D, 0xFE, 0x8B, 0xFE, 0xA7, 0xFE, 0xA9, 0xFE, 0xD1, 0xFE, 0xCE, 0xFE, 0xD3, 0xFE, 0xD0, 0xFE, 0xBF, 0xFE, 0xC2, 0xFE, 0xD9, 0xFE, 0xDA, 0xFE, 0x02, 0xFF, 0xFF, 0xFE, 0x18, 0xFF, 0x18, 0xFF, 0x2C, 0xFF, 0x2C, 0xFF, 0x42, 0xFF, 0x3E, 0xFF, 0x5D, 0xFF, 0x5A, 0xFF, 0x7A, 0xFF, 0x7A, 0xFF, 0x86, 0xFF, 0x85, 0xFF, 0x8F, 0xFF, 0x91, 0xFF, 0xAB, 0xFF, 0xAE, 0xFF, 0xC2, 0xFF, 0xC2, 0xFF, 0xCE, 0xFF, 0xCB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, 0xEB, 0xFF, 0xEE, 0xFF, 0xF6, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF2, 0xFF, 0xF5, 0xFF, 0xF2, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01, 0x00, 0xF2, 0xFF, 0xEE, 0xFF, 0xE1, 0xFF, 0xE0, 0xFF, 0xD9, 0xFF, 0xDB, 0xFF, 0xDD, 0xFF, 0xDD, 0xFF, 0xD8, 0xFF, 0xDA, 0xFF, 0xCA, 0xFF, 0xCC, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xA3, 0xFF, 0xA1, 0xFF, 0x8F, 0xFF, 0x8F, 0xFF, 0x85, 0xFF, 0x84, 0xFF, 0x77, 0xFF, 0x77, 0xFF, 0x69, 0xFF, 0x67, 0xFF, 0x5A, 0xFF, 0x57, 0xFF, 0x48, 0xFF, 0x49, 0xFF, 0x3E, 0xFF, 0x41, 0xFF, 0x37, 0xFF, 0x37, 0xFF, 0x29, 0xFF, 0x2A, 0xFF, 0x2A, 0xFF, 0x27, 0xFF, 0x2D, 0xFF, 0x27, 0xFF, 0x24, 0xFF, 0x25, 0xFF, 0x24, 0xFF, 0x29, 0xFF, 0x2C, 0xFF, 0x2C, 0xFF, 0x2E, 0xFF, 0x2E, 0xFF, 0x3A, 0xFF, 0x3B, 0xFF, 0x48, 0xFF, 0x49, 0xFF, 0x4D, 0xFF, 0x51, 0xFF, 0x5E, 0xFF, 0x62, 0xFF, 0x73, 0xFF, 0x70, 0xFF, 0x7C, 0xFF, 0x79, 0xFF, 0x8F, 0xFF, 0x8E, 0xFF, 0xA9, 0xFF, 0xA7, 0xFF, 0xBE, 0xFF, 0xBE, 0xFF, 0xD9, 0xFF, 0xDA, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0x03, 0x00, 0x03, 0x00, 0x17, 0x00, 0x18, 0x00, 0x2B, 0x00, 0x2B, 0x00, 0x3C, 0x00, 0x3A, 0x00, 0x50, 0x00, 0x50, 0x00, 0x64, 0x00, 0x65, 0x00, 0x76, 0x00, 0x78, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x91, 0x00, 0x91, 0x00, 0x92, 0x00, 0x92, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0xA5, 0x00, 0xA7, 0x00, 0xA8, 0x00, 0xA7, 0x00, 0xAA, 0x00, 0xA7, 0x00, 0xA8, 0x00, 0xA7, 0x00, 0xA5, 0x00, 0xA7, 0x00, 0xA2, 0x00, 0xA6, 0x00, 0x9C, 0x00, 0x9E, 0x00, 0x96, 0x00, 0x96, 0x00, 0x8E, 0x00, 0x8E, 0x00, 0x82, 0x00, 0x81, 0x00, 0x77, 0x00, 0x74, 0x00, 0x6D, 0x00, 0x6F, 0x00, 0x61, 0x00, 0x63, 0x00, 0x56, 0x00, 0x52, 0x00, 0x47, 0x00, 0x47, 0x00, 0x38, 0x00, 0x3A, 0x00, 0x32, 0x00, 0x2D, 0x00, 0x28, 0x00, 0x26, 0x00, 0x12, 0x00, 0x19, 0x00, 0x07, 0x00, 0x08, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xE8, 0xFF, 0xE0, 0xFF, 0xDF, 0xFF, 0xD8, 0xFF, 0xDC, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xD6, 0xFF, 0xD3, 0xFF, 0xCF, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xCE, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xCE, 0xFF, 0xCC, 0xFF, 0xD0, 0xFF, 0xD0, 0xFF, 0xD2, 0xFF, 0xD5, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD8, 0xFF, 0xDA, 0xFF, 0xE1, 0xFF, 0xE0, 0xFF, 0xE5, 0xFF, 0xE5, 0xFF, 0xE7, 0xFF, 0xE9, 0xFF, 0xEC, 0xFF, 0xEA, 0xFF, 0xEE, 0xFF, 0xEA, 0xFF, 0xF1, 0xFF, 0xF0, 0xFF, 0xF6, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xF8, 0xFF, 0xF4, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x07, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x0F, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x13, 0x00, 0x12, 0x00, 0x14, 0x00, 0x11, 0x00, 0x13, 0x00, 0x13, 0x00, 0x10, 0x00, 0x12, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x08, 0x00, 0x07, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFB, 0xFF, 0xFB, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, 0xF8, 0xFF, 0xFD, 0xFF, 0xF9, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF5, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF5, 0xFF, 0xF9, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xF7, 0xFF, 0xF6, 0xFF, 0xF6, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0xFA, 0xFF, 0xFD, 0xFF, 0xFD, 0xFF, 0xF8, 0xFF, 0xFA, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFD, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFD, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; +BYTE hitsound_crit[] = {0x52, 0x49, 0x46, 0x46, 0xFA, 0x40, 0x01, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58, 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x80, 0x40, 0x01, 0x00, 0xCF, 0xFD, 0xD2, 0xFF, 0xD7, 0xFD, 0x9F, 0xFF, 0x50, 0xFE, 0x20, 0xFE, 0xB4, 0x00, 0x09, 0xFF, 0x81, 0x01, 0xC4, 0xFC, 0xF8, 0x00, 0x6F, 0x00, 0x29, 0x01, 0x22, 0x04, 0x00, 0xFF, 0xFF, 0x02, 0x12, 0xFE, 0xE6, 0x0D, 0xD6, 0x10, 0xDC, 0x0E, 0xB6, 0x03, 0x65, 0xE2, 0xAF, 0xE3, 0xE4, 0xCA, 0xE9, 0xFF, 0x66, 0x25, 0x72, 0x07, 0x55, 0x42, 0xBB, 0x24, 0x66, 0xFE, 0x80, 0xEC, 0xB8, 0xE0, 0x4E, 0xFE, 0x12, 0xE2, 0x69, 0x17, 0x62, 0x09, 0xE3, 0x05, 0x58, 0x19, 0xF3, 0xBD, 0xA0, 0x25, 0x9B, 0x2B, 0xD6, 0xC4, 0xA2, 0x08, 0xA0, 0x2E, 0xA4, 0xED, 0x79, 0xBA, 0x16, 0x18, 0x20, 0x12, 0x52, 0xFA, 0x07, 0x44, 0x33, 0xF0, 0x43, 0x0B, 0x1A, 0x2E, 0x25, 0xCD, 0x5E, 0xD6, 0x08, 0x06, 0x3C, 0x06, 0xC8, 0xD1, 0x72, 0xFC, 0x84, 0x26, 0xE4, 0xD7, 0xAC, 0xD1, 0xA9, 0x10, 0x02, 0x2B, 0x02, 0x02, 0x1B, 0xF2, 0xE1, 0x09, 0x8D, 0x05, 0x02, 0xE0, 0xD2, 0xE0, 0xB3, 0x31, 0x19, 0x23, 0xA9, 0xF9, 0x8F, 0xF7, 0x96, 0xCD, 0x46, 0xD7, 0x39, 0xCC, 0xA4, 0xD5, 0x27, 0x26, 0x15, 0x2F, 0xC3, 0x17, 0x9A, 0x12, 0x46, 0x21, 0x7A, 0x35, 0x1D, 0x3F, 0x9C, 0x3A, 0x7B, 0x08, 0xD8, 0xDF, 0xF2, 0xC5, 0xDF, 0xE2, 0x52, 0x32, 0xDF, 0x04, 0xF2, 0xF7, 0x16, 0x2D, 0xA7, 0xEA, 0x33, 0x07, 0xE3, 0x57, 0x7E, 0x36, 0xF7, 0x16, 0x4E, 0x02, 0xA6, 0xE8, 0x9D, 0xBC, 0xFA, 0xBA, 0xD1, 0xCC, 0xF6, 0xE9, 0xED, 0x37, 0xD6, 0x36, 0xE5, 0x2A, 0xC2, 0x10, 0x21, 0x02, 0x1F, 0x1A, 0xBF, 0xEB, 0xED, 0x05, 0x6E, 0xF5, 0x37, 0xD0, 0x08, 0x06, 0x12, 0xD8, 0x05, 0xD0, 0x23, 0xF3, 0x5D, 0x09, 0x59, 0x21, 0xEB, 0x06, 0xF4, 0x17, 0xC2, 0xE4, 0x12, 0xBB, 0x52, 0x01, 0x34, 0x1A, 0x51, 0x41, 0x47, 0x42, 0x56, 0xFB, 0xCE, 0xDA, 0x00, 0xBC, 0x9D, 0xC6, 0x05, 0x09, 0xDF, 0x26, 0x9A, 0x21, 0x3A, 0x13, 0x4E, 0x02, 0xBC, 0xF9, 0x17, 0xE8, 0x9C, 0xE2, 0x5C, 0x0E, 0x86, 0x35, 0xB1, 0x35, 0x23, 0x1B, 0x9D, 0xE7, 0xAE, 0xE2, 0xCF, 0xF0, 0xD1, 0xCB, 0x3F, 0xED, 0xDD, 0x22, 0xAB, 0xFD, 0x21, 0xF0, 0x3D, 0xF1, 0x59, 0x00, 0x67, 0x31, 0x91, 0x1F, 0x57, 0x13, 0xC5, 0x19, 0xCC, 0xFE, 0xAD, 0x1E, 0x8F, 0x20, 0xAD, 0xDE, 0xEF, 0xC0, 0x64, 0xA0, 0x20, 0xA6, 0x3F, 0xD4, 0x45, 0xEB, 0xA3, 0x27, 0xF6, 0x63, 0x91, 0x77, 0xA2, 0x42, 0x91, 0xDB, 0x33, 0xB9, 0x9F, 0xB9, 0x3D, 0xB5, 0x5A, 0xD5, 0xD9, 0x0A, 0xDD, 0x0B, 0x86, 0xEB, 0x63, 0xFD, 0x61, 0x18, 0x82, 0x1B, 0xCE, 0x1B, 0x5F, 0x20, 0x77, 0x07, 0x5D, 0xE4, 0x88, 0xD6, 0x06, 0xB0, 0x5D, 0xD8, 0xFA, 0x20, 0xA4, 0x0B, 0x35, 0x13, 0xC5, 0x17, 0x2A, 0xE4, 0x50, 0xBE, 0x40, 0xD8, 0x55, 0x30, 0xDA, 0x4A, 0x27, 0x49, 0x95, 0x5D, 0x25, 0x17, 0xA9, 0xC2, 0xCC, 0xC6, 0x06, 0xDF, 0xAE, 0xFE, 0x98, 0x1A, 0xCF, 0x0E, 0xF7, 0xF3, 0xE7, 0xD7, 0xCF, 0xD2, 0xC8, 0xE5, 0xB0, 0x04, 0x8E, 0x2D, 0x03, 0x21, 0x94, 0xE8, 0x7D, 0xF8, 0xDC, 0x28, 0x5B, 0xF9, 0xF4, 0xF7, 0xAB, 0x45, 0xC3, 0x13, 0xF6, 0xC7, 0x5B, 0xBD, 0x3F, 0xBB, 0x77, 0xE6, 0x78, 0x0F, 0x7F, 0x1E, 0x97, 0x13, 0xEB, 0xF4, 0x91, 0x02, 0xC8, 0x05, 0x3C, 0xFF, 0x11, 0x30, 0x02, 0x2C, 0x67, 0xEC, 0x54, 0xE6, 0x47, 0xE6, 0xA4, 0xC8, 0x2E, 0xC6, 0xFD, 0xE3, 0x28, 0x03, 0x6F, 0x08, 0x89, 0x10, 0xED, 0x36, 0x94, 0x47, 0x01, 0x2A, 0x0E, 0x18, 0xE5, 0x02, 0xC1, 0xD1, 0x9B, 0xC1, 0x49, 0xD7, 0xC6, 0xF0, 0xEC, 0xF5, 0x43, 0x12, 0x2E, 0x30, 0x4D, 0x09, 0x4C, 0xF8, 0x73, 0xF1, 0xCB, 0xF5, 0x00, 0x26, 0x88, 0x20, 0xA2, 0x1B, 0xF7, 0x10, 0x79, 0xD8, 0xBC, 0xCF, 0xB4, 0xE1, 0x5A, 0xF0, 0xFC, 0x09, 0x79, 0x17, 0x62, 0x04, 0x82, 0xE8, 0xA9, 0xF3, 0x3A, 0x01, 0x0E, 0xF3, 0x07, 0x1E, 0xFB, 0x40, 0x58, 0xF7, 0xC6, 0xDE, 0xCF, 0xEE, 0xD2, 0xCA, 0x5F, 0xCC, 0x38, 0xE4, 0x34, 0x04, 0xDD, 0x06, 0x01, 0xDB, 0x74, 0x03, 0xF8, 0x3A, 0xD5, 0x1D, 0x96, 0x29, 0x6E, 0x41, 0x4C, 0xFD, 0xFE, 0xD0, 0xDD, 0xDB, 0x85, 0xEB, 0x85, 0xF6, 0x45, 0xF7, 0x8D, 0x11, 0x82, 0x02, 0x1B, 0xF5, 0xD7, 0x0D, 0x38, 0xE8, 0x29, 0xDA, 0x26, 0x0B, 0xE2, 0x3C, 0xE7, 0x23, 0x79, 0xEA, 0xC5, 0x09, 0xF4, 0x04, 0x80, 0xF0, 0xC2, 0x2D, 0x8F, 0x2C, 0x00, 0xF0, 0xD5, 0xE4, 0x93, 0xE4, 0xC4, 0xCC, 0x4E, 0xC9, 0x27, 0xE6, 0x02, 0x05, 0x0E, 0x0E, 0x04, 0x39, 0x48, 0x5B, 0x2A, 0x19, 0xD8, 0xF0, 0xD0, 0xF4, 0x76, 0xD2, 0x9B, 0xCE, 0xD9, 0xF1, 0x4C, 0xFE, 0xC9, 0xD8, 0xB3, 0xCE, 0xE5, 0x01, 0xDE, 0x1A, 0x2A, 0x15, 0x28, 0x26, 0xA8, 0x34, 0x89, 0x06, 0xE5, 0xDB, 0xFA, 0xDF, 0x10, 0xCB, 0x67, 0xC8, 0x25, 0x0F, 0x1F, 0x1B, 0x69, 0xE9, 0xD3, 0x03, 0xC8, 0x08, 0xEF, 0xF3, 0xCF, 0x24, 0x77, 0x43, 0x93, 0x3D, 0x8E, 0x20, 0xB8, 0x0F, 0xEC, 0xED, 0x78, 0xAF, 0x04, 0xC4, 0x8E, 0xD3, 0x7E, 0xE3, 0x27, 0x1D, 0x1F, 0x23, 0x66, 0x34, 0x3D, 0x3E, 0x3B, 0x36, 0x31, 0x41, 0xF0, 0x22, 0xD6, 0x01, 0xD3, 0xE6, 0x90, 0xDD, 0xA3, 0x00, 0x32, 0x12, 0x7D, 0x1E, 0x6A, 0x1A, 0x24, 0x02, 0x8D, 0xFE, 0x88, 0xE0, 0xFC, 0xCD, 0xCF, 0xEB, 0x80, 0x07, 0x13, 0x16, 0x4C, 0x09, 0x71, 0xFB, 0x94, 0x0A, 0x26, 0x2B, 0x79, 0x2A, 0x74, 0x0E, 0xE6, 0x0E, 0xAD, 0xEF, 0x6A, 0xD0, 0xA5, 0xD6, 0x8A, 0xE3, 0x69, 0x03, 0x5C, 0x0C, 0x91, 0x22, 0xCF, 0x17, 0x3E, 0xF5, 0xC4, 0x1C, 0xA5, 0x0B, 0x47, 0x07, 0xA7, 0x57, 0xBE, 0x52, 0x61, 0xFF, 0x4F, 0xBE, 0x15, 0xAF, 0x80, 0xBA, 0xE9, 0xD7, 0xDC, 0xF3, 0x45, 0xF3, 0x45, 0xF8, 0x41, 0x1C, 0x88, 0x58, 0x88, 0x56, 0xC8, 0x3F, 0x75, 0x30, 0xCB, 0xE8, 0xF7, 0xB8, 0xC4, 0xE1, 0x16, 0xE8, 0x53, 0xD2, 0xE8, 0xFC, 0x32, 0x15, 0x42, 0x01, 0x54, 0x19, 0xF5, 0x19, 0x2F, 0x00, 0xD0, 0x0E, 0x86, 0x16, 0xD5, 0x1D, 0x8A, 0x0C, 0x1E, 0xDB, 0x21, 0xCE, 0x75, 0xB7, 0xDE, 0xBB, 0x22, 0x0B, 0xC7, 0x32, 0xC9, 0x3C, 0xC0, 0x40, 0x04, 0x1B, 0xE8, 0xED, 0xA0, 0xCD, 0x13, 0xE0, 0xEE, 0xF9, 0x4F, 0xFA, 0xE8, 0x09, 0x32, 0xFA, 0x22, 0xF4, 0x42, 0x15, 0xC7, 0x0F, 0xD1, 0xE9, 0xDB, 0xC9, 0xC7, 0xB5, 0x6F, 0xBE, 0xFD, 0xEF, 0x0F, 0x23, 0x33, 0x49, 0x44, 0x45, 0x35, 0x1D, 0x10, 0x16, 0xAF, 0x00, 0x0A, 0xEE, 0xA0, 0xEE, 0x45, 0xD3, 0x77, 0xD9, 0x78, 0xF0, 0x53, 0xF5, 0x87, 0xF1, 0x82, 0xF3, 0xEE, 0x0C, 0x3A, 0x08, 0x47, 0xFC, 0x6C, 0xFF, 0xFB, 0xF1, 0xAF, 0xF5, 0xE8, 0x0D, 0xC9, 0x1B, 0xFA, 0x05, 0x4B, 0xF7, 0xF7, 0x11, 0xD8, 0xE9, 0xFC, 0xB6, 0xA8, 0xED, 0x7F, 0xF8, 0x99, 0xE1, 0x62, 0x17, 0xC8, 0x2F, 0xA4, 0x23, 0x89, 0x24, 0x7A, 0x1C, 0xC0, 0x02, 0x6B, 0xED, 0x5C, 0x00, 0xA6, 0x00, 0x9F, 0xDD, 0xFA, 0xE0, 0x78, 0xF7, 0x03, 0xE8, 0x8F, 0xE8, 0xE7, 0x0C, 0x60, 0x16, 0x39, 0x36, 0x33, 0x4F, 0x70, 0x2D, 0x58, 0x07, 0x03, 0xCE, 0xAD, 0xBD, 0x1D, 0xDB, 0xA5, 0xE1, 0x33, 0xF2, 0xF5, 0xF6, 0xB1, 0xEE, 0x51, 0xFD, 0xBE, 0x0C, 0x00, 0xFA, 0xCF, 0xEA, 0x35, 0x00, 0xA5, 0xFB, 0x9E, 0xF7, 0xD7, 0xFD, 0x6E, 0xDA, 0x19, 0xD4, 0xCA, 0xE9, 0x0F, 0xD3, 0x72, 0xC5, 0x0D, 0xCA, 0x3D, 0xBA, 0x3A, 0xC6, 0x16, 0xE7, 0x5F, 0x19, 0x62, 0x43, 0x10, 0x21, 0x74, 0x06, 0x66, 0xFD, 0x4D, 0xDE, 0xFA, 0xE1, 0xD2, 0xF8, 0xB8, 0xF2, 0x9A, 0xD9, 0x24, 0xE3, 0xEB, 0xE0, 0x19, 0xD8, 0x32, 0x11, 0x8E, 0x2C, 0x2A, 0x1E, 0x57, 0x0E, 0x46, 0xF4, 0x20, 0xF0, 0xE7, 0xFB, 0x25, 0x1A, 0xCE, 0x3A, 0x55, 0x45, 0x6F, 0x37, 0x0D, 0x2D, 0x30, 0x1F, 0xE2, 0xED, 0x88, 0xE9, 0x50, 0xF7, 0xAC, 0xE5, 0xA8, 0xE7, 0x93, 0xFC, 0x00, 0x1E, 0x70, 0x1D, 0x01, 0x26, 0x60, 0x42, 0xA3, 0x23, 0x4E, 0x18, 0x63, 0x11, 0x37, 0xE9, 0xE8, 0xDE, 0x23, 0xE5, 0xFF, 0xF3, 0x0F, 0xF4, 0xEE, 0xF7, 0xF8, 0x1C, 0xE2, 0x1C, 0x07, 0x14, 0xDB, 0x35, 0x8F, 0x37, 0x4D, 0x18, 0x27, 0x06, 0xDD, 0xD9, 0x48, 0xA5, 0x43, 0x9F, 0xAD, 0xC4, 0x37, 0xF2, 0x44, 0x02, 0x69, 0x13, 0x6C, 0x20, 0xE6, 0xFD, 0x53, 0xF0, 0x13, 0x10, 0xDF, 0x00, 0x06, 0xD8, 0xD9, 0xE7, 0xCD, 0xE2, 0x5C, 0xB3, 0xA1, 0xBF, 0xD9, 0xDF, 0x9A, 0xE2, 0x87, 0xF3, 0x43, 0x03, 0xD7, 0xF9, 0x41, 0xF2, 0xA9, 0xEF, 0xAD, 0xF0, 0xDB, 0xF9, 0x2B, 0xE3, 0x37, 0xCA, 0xB4, 0xCD, 0xED, 0xB3, 0x47, 0xB1, 0x2D, 0xF1, 0x58, 0x07, 0xC7, 0xFD, 0x8C, 0xF7, 0x39, 0xD7, 0x48, 0xB9, 0x1F, 0xC1, 0x34, 0xE7, 0x59, 0xFF, 0x94, 0xFA, 0x96, 0x00, 0x54, 0x06, 0xC8, 0xFD, 0xF5, 0x01, 0x97, 0x09, 0x68, 0xF9, 0x9E, 0xE6, 0x6B, 0xEF, 0xDE, 0xEC, 0x64, 0xEA, 0xAD, 0x13, 0x83, 0x2D, 0x4A, 0x1F, 0xE6, 0x0D, 0xD9, 0x0E, 0x31, 0x19, 0x5D, 0x1A, 0x88, 0x27, 0x38, 0x34, 0xE4, 0x2E, 0x32, 0x2D, 0x0D, 0x29, 0x76, 0x15, 0xC7, 0x02, 0x17, 0x06, 0x61, 0x1F, 0x07, 0x3C, 0x95, 0x4A, 0x2E, 0x71, 0xC7, 0x7E, 0x4C, 0x60, 0x8F, 0x22, 0xBF, 0xFD, 0xBB, 0xC9, 0x2D, 0xB0, 0xDD, 0xB8, 0xE9, 0xC9, 0x67, 0xE1, 0x76, 0x10, 0x5E, 0x2D, 0xB8, 0x1F, 0x63, 0x1C, 0x4A, 0x1D, 0x63, 0x23, 0x7B, 0x4D, 0x77, 0x45, 0x92, 0x15, 0x45, 0xFD, 0xDE, 0xE6, 0xB3, 0xB4, 0x21, 0xA3, 0xDF, 0xCE, 0x63, 0xF2, 0x33, 0x10, 0x2A, 0x39, 0xE3, 0x51, 0x55, 0x60, 0x4F, 0x49, 0x3D, 0x23, 0x34, 0x08, 0xAE, 0xF9, 0xD8, 0xF8, 0x74, 0xFA, 0xC1, 0x1D, 0x9E, 0x1B, 0x33, 0x0A, 0x9E, 0x19, 0x11, 0xD8, 0xEB, 0xC4, 0x14, 0xDF, 0x73, 0xB6, 0x94, 0xF5, 0xD3, 0x33, 0xA1, 0x05, 0x6A, 0x04, 0xEC, 0x12, 0x6F, 0x05, 0x8A, 0x0D, 0xEA, 0x00, 0x38, 0xEF, 0x57, 0xF3, 0x40, 0x04, 0x8E, 0xFC, 0x70, 0xE2, 0x71, 0xF7, 0x46, 0x3D, 0x1A, 0x23, 0x1D, 0xD8, 0x03, 0xFA, 0x4A, 0x27, 0x33, 0x1F, 0xCB, 0x10, 0xC8, 0x1F, 0x2D, 0x20, 0x5C, 0xDD, 0x5E, 0xD1, 0xA0, 0xEA, 0xA4, 0xEA, 0xE2, 0x22, 0x81, 0x4B, 0x62, 0x16, 0xB1, 0xD7, 0x36, 0xF1, 0x70, 0x21, 0x2D, 0x0C, 0x92, 0x05, 0x02, 0x0C, 0xCA, 0xE1, 0x93, 0xC8, 0x7E, 0xD6, 0x1C, 0xDC, 0x1B, 0xE1, 0x7C, 0x08, 0x34, 0x13, 0x80, 0xD6, 0xB9, 0xA0, 0xC6, 0xC1, 0x0D, 0xF2, 0x24, 0xED, 0x51, 0x0F, 0x9F, 0x18, 0x72, 0xE8, 0x24, 0xC7, 0x0A, 0xC8, 0x7E, 0xB2, 0x43, 0x9F, 0x9F, 0xCF, 0x1D, 0xE1, 0xB5, 0xBD, 0xE8, 0xC3, 0x82, 0xE0, 0x9E, 0xD2, 0x6C, 0xAE, 0x51, 0xDE, 0x92, 0x30, 0x36, 0x0C, 0x91, 0xAA, 0xBD, 0x85, 0xAA, 0xA3, 0x7B, 0xCC, 0x2E, 0xC2, 0x84, 0xA7, 0x0D, 0xA9, 0x66, 0xD9, 0x58, 0xFC, 0xB1, 0xF2, 0x7A, 0xE4, 0xEF, 0xE6, 0x11, 0xE6, 0x97, 0xE7, 0x8F, 0x04, 0xC8, 0xFB, 0xBA, 0xCF, 0xD5, 0xD0, 0x15, 0xEE, 0x62, 0xF0, 0x66, 0xC6, 0x7F, 0xA8, 0x6A, 0xC1, 0xC3, 0xF4, 0x48, 0x12, 0x11, 0x12, 0x23, 0x1D, 0xFD, 0x30, 0x81, 0x3D, 0x1E, 0x1E, 0xA9, 0xCC, 0x51, 0xA3, 0xAC, 0xCC, 0x99, 0x08, 0x79, 0x05, 0xBC, 0x02, 0xF3, 0x22, 0xAA, 0x16, 0xFD, 0x12, 0x74, 0x12, 0x25, 0xE3, 0x09, 0xE8, 0x7E, 0x29, 0xD3, 0x37, 0x1F, 0x0C, 0x9B, 0x0F, 0xB5, 0x45, 0xA8, 0x53, 0x95, 0x39, 0xBC, 0x21, 0xD8, 0x03, 0x6F, 0xE0, 0x1C, 0xD8, 0x26, 0xDD, 0x03, 0xE1, 0xEB, 0x01, 0x0C, 0x3E, 0x66, 0x56, 0x6F, 0x3B, 0x39, 0x33, 0xC6, 0x27, 0xB1, 0xEE, 0x1D, 0xCE, 0x25, 0xCC, 0xB4, 0xC7, 0xAC, 0xC3, 0x78, 0xD2, 0x96, 0xEB, 0xF0, 0xF7, 0xBD, 0x16, 0xE5, 0x31, 0x0C, 0x2A, 0xE2, 0x18, 0x76, 0xFF, 0xD8, 0xD5, 0xD9, 0xA2, 0x8E, 0x96, 0xF5, 0xB4, 0xA2, 0xB3, 0xD7, 0xC6, 0x38, 0xF4, 0xC8, 0xFA, 0xCC, 0xF4, 0x4F, 0xF4, 0x4A, 0xF8, 0x85, 0xF2, 0x9D, 0xDB, 0xDD, 0xDC, 0xF8, 0xCF, 0x7B, 0xAA, 0x15, 0xC5, 0xCD, 0xEC, 0x3C, 0xD4, 0x7D, 0xC7, 0xC2, 0xD4, 0xE6, 0xC5, 0xCF, 0xCB, 0x5A, 0xF9, 0x3F, 0x16, 0x18, 0x22, 0x9C, 0x2E, 0x50, 0x2E, 0x67, 0x1B, 0x33, 0x1A, 0xB4, 0x31, 0xAA, 0x33, 0xF8, 0x2C, 0x5D, 0x3F, 0x01, 0x48, 0x0A, 0x35, 0x0E, 0x1C, 0xF9, 0x32, 0x50, 0x1C, 0xA9, 0x00, 0x0A, 0x25, 0xC4, 0x1A, 0x8F, 0xF9, 0xA4, 0x17, 0x34, 0x35, 0x01, 0x44, 0xDE, 0x5C, 0x6F, 0x6A, 0x1A, 0x6B, 0xEB, 0x40, 0x2F, 0x0B, 0xFF, 0x00, 0x66, 0xF4, 0x86, 0x00, 0x38, 0x31, 0xC0, 0x3A, 0xCE, 0x45, 0x67, 0x5B, 0x6A, 0x5C, 0x6F, 0x5F, 0x06, 0x73, 0xC5, 0x6B, 0xF2, 0x48, 0x70, 0x0A, 0xF0, 0xE8, 0x74, 0xF2, 0xED, 0xF1, 0x44, 0x0D, 0xFF, 0x3B, 0xB7, 0x21, 0x5E, 0x06, 0x6D, 0x20, 0x37, 0x2F, 0x62, 0x32, 0x5D, 0x1E, 0xF3, 0xDF, 0xE5, 0xB4, 0x88, 0xB9, 0x27, 0xD7, 0xED, 0x0D, 0x43, 0x2B, 0x97, 0x13, 0xA9, 0xFF, 0xE5, 0xF7, 0x54, 0xF5, 0x9D, 0xF6, 0xD3, 0xF3, 0xC7, 0xFD, 0x01, 0x12, 0x46, 0x15, 0x67, 0x02, 0x41, 0x00, 0xA7, 0x0C, 0x91, 0x04, 0x29, 0xE1, 0x63, 0xBB, 0xE3, 0xBF, 0x7F, 0xD7, 0x98, 0xF1, 0x42, 0x07, 0x64, 0x13, 0x79, 0x3B, 0x1E, 0x41, 0x6C, 0x1F, 0x72, 0x10, 0x09, 0x0E, 0x0F, 0x1C, 0x05, 0x28, 0x22, 0x35, 0xAD, 0x47, 0x64, 0x3A, 0x57, 0x1E, 0xF1, 0x08, 0xC5, 0x1B, 0x1A, 0x4B, 0xDB, 0x4D, 0xFF, 0x35, 0xEE, 0x21, 0xA1, 0x0B, 0x2C, 0x15, 0x6D, 0x37, 0x5E, 0x42, 0x1A, 0x32, 0x6D, 0x16, 0xA8, 0x13, 0x60, 0x25, 0x48, 0x2D, 0x1D, 0x43, 0x23, 0x4A, 0xD5, 0x3E, 0xCE, 0x44, 0xFE, 0x33, 0x59, 0x24, 0x2E, 0x37, 0x87, 0x47, 0x43, 0x50, 0xA2, 0x4A, 0x8D, 0x30, 0xB6, 0x0F, 0x2F, 0xED, 0x32, 0xF1, 0x32, 0x1B, 0x88, 0x13, 0x1D, 0x01, 0xD7, 0x20, 0xEA, 0x26, 0x59, 0x26, 0xCB, 0x37, 0x7E, 0x30, 0xF2, 0x19, 0x40, 0xF7, 0x3C, 0xF8, 0xD2, 0x0B, 0x41, 0xF2, 0xF5, 0xD7, 0x85, 0xC7, 0xED, 0xD1, 0x5C, 0xFB, 0x37, 0x0C, 0x2F, 0x04, 0x1C, 0xFA, 0xAF, 0x15, 0x54, 0x34, 0xB7, 0x23, 0xAC, 0x0E, 0xB6, 0xEC, 0x6E, 0xD2, 0xF2, 0xD8, 0xCE, 0xCA, 0x15, 0xAD, 0x37, 0x9D, 0x4F, 0xA0, 0xB0, 0xC9, 0x2C, 0x0F, 0xDA, 0x1C, 0xE3, 0x0A, 0x78, 0xF0, 0x97, 0xD2, 0x36, 0xBA, 0x6B, 0xA9, 0x9E, 0xA0, 0x21, 0xB4, 0xA3, 0xC7, 0xB8, 0xE9, 0xAA, 0x04, 0x4C, 0xFD, 0x9C, 0x0D, 0x43, 0x1B, 0xC8, 0x07, 0x69, 0x02, 0x57, 0xFF, 0x6C, 0xF3, 0x35, 0xF8, 0x6F, 0x04, 0x8D, 0x07, 0x5A, 0x06, 0xFE, 0x01, 0x2E, 0xF8, 0x35, 0xEB, 0x17, 0xE8, 0x80, 0x07, 0x4A, 0x2E, 0x81, 0x33, 0x87, 0x28, 0x65, 0x14, 0xB2, 0xF5, 0xA6, 0xE2, 0xEC, 0xF2, 0x54, 0x17, 0x03, 0x24, 0x9A, 0x26, 0x33, 0x23, 0xD7, 0x0F, 0x07, 0x0A, 0xAD, 0x06, 0x6B, 0xFF, 0xCE, 0xF9, 0x93, 0x04, 0x0F, 0x2C, 0xA4, 0x38, 0x6F, 0x34, 0x29, 0x3F, 0x33, 0x3E, 0xD0, 0x3D, 0x3D, 0x3E, 0x95, 0x29, 0x33, 0xFB, 0xB5, 0xD6, 0x14, 0xDF, 0x91, 0xF3, 0xA9, 0xFC, 0xE0, 0x05, 0x21, 0x14, 0x3C, 0x17, 0xC1, 0x26, 0x84, 0x55, 0xF9, 0x60, 0xE4, 0x59, 0x7E, 0x57, 0xE5, 0x0D, 0x14, 0xB6, 0xC2, 0xAE, 0x3D, 0xC2, 0xE3, 0xC5, 0x26, 0xCE, 0xE9, 0xE9, 0x00, 0x10, 0x29, 0x18, 0xFC, 0x19, 0xDE, 0x28, 0x9B, 0x16, 0x69, 0x04, 0x02, 0xFB, 0x3F, 0xD8, 0xA6, 0xBC, 0xE5, 0xC1, 0xBC, 0xDF, 0x5F, 0xED, 0x89, 0xF9, 0x0E, 0x16, 0xB0, 0x0F, 0x1D, 0xFE, 0x5B, 0x00, 0x95, 0x06, 0x77, 0x0B, 0x33, 0x0B, 0x20, 0xFD, 0x00, 0xE1, 0x20, 0xDB, 0x87, 0xE1, 0xC2, 0xE4, 0xDE, 0xFE, 0x9F, 0x11, 0x72, 0x03, 0xC6, 0xE7, 0x0C, 0xD9, 0xD9, 0xE0, 0x68, 0xF4, 0x05, 0x0D, 0x3B, 0x1E, 0x94, 0x21, 0x1B, 0x1D, 0x59, 0x21, 0x32, 0x2E, 0x90, 0x2D, 0x8A, 0x1B, 0x3C, 0x00, 0xCF, 0xEF, 0xED, 0xF7, 0x01, 0x10, 0x86, 0x24, 0x90, 0x20, 0xE0, 0x06, 0xC6, 0xE9, 0xF9, 0xDC, 0x4C, 0xF5, 0xBF, 0x24, 0x08, 0x41, 0xD1, 0x54, 0x39, 0x5A, 0xAC, 0x3B, 0x56, 0x28, 0xFC, 0x14, 0xD3, 0xE5, 0xAD, 0xDB, 0x76, 0xF6, 0x92, 0x1E, 0x72, 0x48, 0x96, 0x65, 0xD9, 0x69, 0x20, 0x4D, 0xB9, 0x39, 0xB2, 0x1D, 0x43, 0x10, 0x04, 0x15, 0xF6, 0x1D, 0x47, 0x37, 0x8A, 0x39, 0xF3, 0x2F, 0x25, 0x38, 0x25, 0x2A, 0xFC, 0x1E, 0x35, 0x36, 0xDD, 0x47, 0xDC, 0x3B, 0xB3, 0x34, 0xCD, 0x3F, 0x94, 0x42, 0xB0, 0x45, 0x97, 0x40, 0xBE, 0x27, 0xC9, 0x1E, 0x2A, 0x2A, 0x82, 0x2F, 0x4F, 0x28, 0xEC, 0x22, 0x56, 0x2C, 0xED, 0x2E, 0x05, 0x15, 0xBD, 0x13, 0xF5, 0x34, 0x20, 0x2C, 0xD8, 0x1F, 0x28, 0x3C, 0x8A, 0x46, 0x90, 0x41, 0x67, 0x34, 0x2D, 0x13, 0x5F, 0xFE, 0x01, 0x09, 0x2B, 0x28, 0x13, 0x38, 0x40, 0x37, 0x47, 0x44, 0x38, 0x41, 0x11, 0x19, 0xD5, 0xFE, 0x54, 0x06, 0x99, 0x0E, 0x32, 0x03, 0x0E, 0xDC, 0xEC, 0xBA, 0xF1, 0xC0, 0x78, 0xD2, 0x89, 0xF1, 0x8C, 0x18, 0xC7, 0x25, 0x8F, 0x2E, 0x26, 0x35, 0xDA, 0x26, 0x1C, 0x1B, 0x8E, 0x28, 0x6A, 0x34, 0xDA, 0x27, 0x66, 0x25, 0x9B, 0x1F, 0x51, 0x05, 0x11, 0xFB, 0xF4, 0xEE, 0x35, 0xEC, 0x6C, 0x02, 0xEF, 0x0B, 0x39, 0x15, 0xBA, 0x13, 0x80, 0x11, 0x34, 0x39, 0x3E, 0x57, 0x84, 0x57, 0x13, 0x4A, 0x0F, 0x23, 0x62, 0xF6, 0x8C, 0xDE, 0x62, 0xE4, 0x6D, 0xE8, 0x99, 0xE6, 0x78, 0xF9, 0xF4, 0x01, 0x3E, 0x05, 0xFD, 0x1F, 0x68, 0x37, 0x28, 0x3D, 0x42, 0x3A, 0x16, 0x2E, 0x38, 0x18, 0x7D, 0x09, 0x2F, 0x02, 0x03, 0xFF, 0xE5, 0xFC, 0x76, 0xE7, 0x20, 0xDF, 0xFD, 0xF0, 0x66, 0x07, 0xC8, 0x2A, 0xB7, 0x43, 0x3B, 0x4C, 0xFB, 0x45, 0x40, 0x2A, 0xC7, 0x07, 0xF2, 0xDD, 0x9C, 0xD1, 0xFD, 0xE5, 0xB8, 0xF6, 0xC8, 0x0B, 0x3F, 0x1B, 0x4B, 0x1E, 0x8A, 0x21, 0x7D, 0x32, 0x05, 0x38, 0xAD, 0x25, 0xD4, 0x23, 0x35, 0x10, 0xC0, 0xF2, 0x58, 0xF9, 0x6D, 0xFC, 0x18, 0xFF, 0x66, 0x0A, 0x5B, 0x0F, 0x37, 0x0D, 0x93, 0x08, 0x91, 0x1C, 0x11, 0x3A, 0xF7, 0x38, 0x18, 0x20, 0xA7, 0x07, 0xFC, 0xE9, 0xBE, 0xDA, 0x92, 0xEE, 0x36, 0xFE, 0xB2, 0x11, 0xE5, 0x2D, 0x51, 0x24, 0xC7, 0x02, 0x34, 0xF4, 0xAA, 0xEA, 0xB1, 0xD6, 0x92, 0xD4, 0x77, 0xD4, 0x54, 0xD7, 0xAB, 0xE7, 0x2E, 0xF0, 0x23, 0x09, 0xE5, 0x1B, 0xAB, 0x26, 0xA3, 0x26, 0xDA, 0xFF, 0x4F, 0xE7, 0x52, 0xCC, 0x83, 0xB3, 0x1A, 0xB1, 0xBA, 0xB8, 0x38, 0xE0, 0x99, 0xF5, 0x13, 0x10, 0xB6, 0x28, 0x9B, 0x21, 0x6E, 0x42, 0x2A, 0x44, 0x9E, 0x1C, 0xF4, 0x0C, 0x67, 0xF2, 0xE0, 0xD7, 0x81, 0xCB, 0x69, 0xD2, 0x4B, 0xD8, 0xE1, 0xD4, 0x9C, 0xF4, 0x9E, 0x1D, 0xB0, 0x2A, 0xD0, 0x33, 0x97, 0x51, 0xCC, 0x5F, 0xBB, 0x2A, 0x34, 0xF3, 0x34, 0xE4, 0xC2, 0xEC, 0x31, 0xFC, 0xE9, 0xF8, 0x8E, 0xF7, 0x61, 0x14, 0x81, 0x27, 0x6A, 0x25, 0x18, 0x25, 0x14, 0x25, 0xF1, 0x14, 0x9D, 0xE8, 0x3C, 0xCF, 0x8C, 0xDE, 0xB5, 0xE3, 0x0C, 0xD6, 0x47, 0xDC, 0x4C, 0xF5, 0x1D, 0xEA, 0x75, 0xCA, 0x40, 0xCA, 0xED, 0xCE, 0x5F, 0xC5, 0x87, 0xC2, 0x20, 0xCB, 0x3A, 0xCC, 0x9D, 0xD3, 0x4C, 0xE8, 0x10, 0xEF, 0x22, 0xF6, 0x7A, 0xF4, 0xEE, 0xDA, 0xA6, 0xC7, 0xE9, 0xC7, 0xFE, 0xD2, 0x74, 0xD7, 0xA1, 0xD4, 0xCA, 0xD3, 0x4C, 0xD7, 0x02, 0xD9, 0x91, 0xE1, 0xDC, 0xFB, 0x6F, 0x14, 0x43, 0x27, 0x73, 0x1D, 0x63, 0xF3, 0x16, 0xD5, 0x03, 0xC7, 0xE0, 0xC1, 0xF4, 0xC1, 0x4E, 0xD0, 0x17, 0xE6, 0xC7, 0xEB, 0xE9, 0xEB, 0xA1, 0xF5, 0x1A, 0x13, 0x35, 0x24, 0x65, 0x1F, 0xB2, 0x1B, 0x0F, 0x0B, 0xDD, 0xF9, 0xFD, 0xE9, 0x0F, 0xE4, 0x7D, 0xF0, 0xD8, 0xED, 0x3A, 0xE5, 0xE7, 0xDC, 0x4D, 0xDA, 0x96, 0xF5, 0xD6, 0x1B, 0x3F, 0x2A, 0x26, 0x1D, 0x1B, 0x14, 0x5A, 0x0F, 0xE6, 0xF6, 0x80, 0xDC, 0x77, 0xD5, 0x0C, 0xDE, 0x0F, 0xF7, 0xA4, 0x0F, 0xC0, 0x03, 0x59, 0xEC, 0x36, 0xF7, 0x54, 0x18, 0x09, 0x2E, 0x61, 0x29, 0xCB, 0x19, 0x45, 0x0D, 0x2B, 0x01, 0x88, 0xF2, 0x83, 0xE4, 0x45, 0xE8, 0xCF, 0x05, 0x7B, 0x20, 0x2D, 0x1E, 0x57, 0x16, 0x73, 0x19, 0xC4, 0x22, 0xAB, 0x31, 0x71, 0x3B, 0x93, 0x46, 0x21, 0x42, 0xAB, 0x2D, 0x5A, 0x40, 0x51, 0x5A, 0x36, 0x42, 0xD6, 0x0E, 0x3D, 0xE3, 0x3C, 0xDD, 0x5C, 0xF2, 0x76, 0xFB, 0x87, 0x08, 0xCF, 0x33, 0x8B, 0x5C, 0x40, 0x5D, 0x85, 0x3F, 0x58, 0x18, 0x81, 0x06, 0xFC, 0x15, 0xCE, 0x0B, 0xBD, 0xE6, 0x57, 0xE4, 0xDC, 0xF5, 0xE5, 0x05, 0x37, 0x0E, 0xB3, 0xFB, 0xAA, 0xDE, 0x69, 0xD1, 0x05, 0xD8, 0x4A, 0xE1, 0xD1, 0xF1, 0x3A, 0x07, 0xFD, 0x01, 0xE6, 0xEC, 0xEB, 0xE4, 0x43, 0xF9, 0x08, 0x0A, 0x5E, 0xF9, 0xAF, 0xE3, 0xD5, 0xCA, 0x2C, 0xB5, 0x46, 0xCD, 0xAE, 0xF7, 0xD1, 0x1B, 0x6C, 0x2D, 0xD4, 0x36, 0x72, 0x37, 0x9F, 0x2A, 0x28, 0x1D, 0xBE, 0xFE, 0x26, 0xD6, 0x3C, 0xCB, 0xF4, 0xE3, 0xDC, 0xF1, 0x37, 0xDF, 0xCC, 0xD1, 0x59, 0xDB, 0x7F, 0xFE, 0xC9, 0x2B, 0x84, 0x4A, 0xCA, 0x53, 0x74, 0x38, 0x21, 0x11, 0xA3, 0xFE, 0x36, 0xFA, 0xD9, 0xEF, 0x30, 0xD3, 0x92, 0xC0, 0x21, 0xCF, 0x16, 0x02, 0x58, 0x37, 0x97, 0x3C, 0xCB, 0x37, 0x5F, 0x37, 0x8D, 0x1E, 0x04, 0x11, 0x06, 0x0D, 0x11, 0xF5, 0x22, 0xE6, 0xBA, 0xF5, 0xE8, 0x05, 0xA7, 0xF5, 0x00, 0xDA, 0x3C, 0xDC, 0x41, 0xFA, 0x73, 0x10, 0x1C, 0x10, 0x65, 0x0E, 0xBB, 0x14, 0x6E, 0x16, 0x93, 0x09, 0x88, 0xEA, 0x38, 0xBE, 0x23, 0x94, 0xEA, 0x86, 0xD1, 0x9A, 0x22, 0xE6, 0x0A, 0x4F, 0xFF, 0x7F, 0x20, 0x53, 0xF8, 0x08, 0x86, 0xB9, 0x8E, 0x89, 0x5E, 0x88, 0x39, 0x9F, 0x44, 0xCF, 0xCB, 0xFD, 0x39, 0x09, 0xD2, 0xF9, 0x5A, 0xD7, 0x71, 0xA8, 0x95, 0x95, 0x8F, 0xBC, 0x64, 0xFB, 0x91, 0xFF, 0x42, 0xBF, 0x47, 0x8A, 0x88, 0x8D, 0x30, 0xBF, 0x50, 0xDE, 0x4C, 0xDD, 0x3D, 0xE4, 0x8C, 0x14, 0x81, 0x49, 0x68, 0x41, 0xEC, 0xFF, 0x79, 0xB6, 0x49, 0x88, 0x52, 0x83, 0x8F, 0x8F, 0x44, 0x8A, 0xA2, 0x86, 0xEF, 0xA9, 0x13, 0xF0, 0x11, 0x06, 0xBB, 0xC7, 0x02, 0x99, 0x04, 0x9D, 0xA0, 0xD5, 0x8E, 0x07, 0x50, 0xEC, 0xF8, 0x9F, 0xBD, 0x88, 0x7D, 0x99, 0xBE, 0x9E, 0x53, 0xAF, 0x12, 0xE3, 0x8A, 0x0B, 0xD4, 0x02, 0xE8, 0xCE, 0x9E, 0xA3, 0x82, 0x9A, 0x09, 0x97, 0xC2, 0x8C, 0xD2, 0x91, 0x37, 0x91, 0x50, 0x93, 0x73, 0x99, 0xC9, 0xA1, 0xD9, 0xB0, 0x1E, 0xC9, 0x97, 0xC7, 0x70, 0xBB, 0x9E, 0xCD, 0xFC, 0xEE, 0xBE, 0xF9, 0x2F, 0xE4, 0xD6, 0xC0, 0xEC, 0xBF, 0x7C, 0xF2, 0x6B, 0x29, 0x10, 0x4B, 0x08, 0x55, 0x0E, 0x38, 0x6D, 0xFA, 0x4E, 0xC6, 0x4C, 0xC9, 0xCA, 0x04, 0x4E, 0x50, 0x1D, 0x72, 0x8E, 0x47, 0xA5, 0x06, 0x38, 0xDE, 0x80, 0xCB, 0xC2, 0xC4, 0x3C, 0xDA, 0x42, 0x24, 0xAB, 0x6B, 0x91, 0x4A, 0x85, 0x07, 0x05, 0xA7, 0xBB, 0xB5, 0xCC, 0x29, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x0D, 0x63, 0x22, 0x20, 0x23, 0xED, 0xE5, 0xEB, 0xC5, 0x0F, 0x86, 0x32, 0xC6, 0x3F, 0xB3, 0x4D, 0x10, 0x4A, 0xA2, 0x16, 0x99, 0xC9, 0xC5, 0xA4, 0x2D, 0xB8, 0x61, 0xC3, 0x8E, 0xAC, 0xD6, 0x96, 0xC3, 0xA2, 0x58, 0xB3, 0x2E, 0x99, 0x71, 0x94, 0xFD, 0xAE, 0xE4, 0xE0, 0x75, 0xF0, 0x6E, 0xC8, 0x10, 0xB7, 0xD9, 0xEB, 0xF5, 0x35, 0x0E, 0x3A, 0x0F, 0xEE, 0x38, 0xB8, 0x3D, 0xD9, 0x3E, 0x1D, 0xCD, 0x35, 0xFB, 0x25, 0x23, 0x16, 0x1D, 0x21, 0x6F, 0x42, 0x51, 0x4C, 0x08, 0x44, 0xA3, 0x47, 0x13, 0x54, 0x14, 0x62, 0xDD, 0x65, 0xD3, 0x62, 0x0E, 0x5E, 0x02, 0x4E, 0xA1, 0x32, 0x22, 0x1F, 0x90, 0x1E, 0xE2, 0x29, 0x4C, 0x3A, 0x21, 0x41, 0x97, 0x43, 0xC1, 0x4B, 0x8C, 0x52, 0x54, 0x5E, 0x99, 0x66, 0xA6, 0x62, 0x02, 0x62, 0x7B, 0x5A, 0xF4, 0x47, 0xE0, 0x37, 0xC4, 0x34, 0x85, 0x39, 0xC9, 0x46, 0x2F, 0x5C, 0xE8, 0x67, 0x3A, 0x5F, 0x6B, 0x46, 0xB0, 0x3A, 0x0E, 0x43, 0xA0, 0x52, 0xA7, 0x5A, 0xB3, 0x5A, 0xBC, 0x65, 0x06, 0x6C, 0x3A, 0x71, 0xAA, 0x69, 0x04, 0x5C, 0xD9, 0x5A, 0x0E, 0x5A, 0x0E, 0x54, 0x53, 0x45, 0x14, 0x3B, 0x1E, 0x45, 0xF4, 0x55, 0xEA, 0x6B, 0x42, 0x72, 0xD9, 0x7A, 0xEE, 0x7E, 0x3B, 0x79, 0xDF, 0x66, 0xAD, 0x5E, 0x15, 0x5C, 0xA4, 0x4A, 0x88, 0x3B, 0x93, 0x3A, 0x16, 0x39, 0x8A, 0x50, 0xBB, 0x73, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x40, 0x6A, 0x31, 0x5E, 0x10, 0x5C, 0xE0, 0x46, 0xDC, 0x32, 0xE0, 0x37, 0x16, 0x48, 0x6A, 0x58, 0x6A, 0x70, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xC7, 0x6A, 0xE3, 0x42, 0x9A, 0x3D, 0x41, 0x51, 0xC6, 0x5D, 0x73, 0x5D, 0x45, 0x5B, 0x86, 0x59, 0x39, 0x5D, 0xC7, 0x6F, 0xE2, 0x78, 0xE2, 0x75, 0x5B, 0x74, 0x8A, 0x78, 0x7E, 0x62, 0x1C, 0x58, 0x12, 0x5F, 0x7A, 0x6E, 0x4F, 0x75, 0x4A, 0x66, 0xBC, 0x54, 0xC6, 0x51, 0x12, 0x5A, 0x21, 0x66, 0x41, 0x6C, 0x3F, 0x6C, 0xC1, 0x72, 0xBB, 0x6F, 0x43, 0x5C, 0xAD, 0x4C, 0xA2, 0x54, 0x7A, 0x67, 0x49, 0x7B, 0xFF, 0x7F, 0xAB, 0x79, 0xC1, 0x76, 0x04, 0x75, 0xD8, 0x63, 0x27, 0x52, 0x84, 0x4B, 0x5F, 0x41, 0x84, 0x3D, 0x42, 0x57, 0x54, 0x72, 0xA3, 0x7A, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xD2, 0x77, 0x19, 0x61, 0x05, 0x42, 0xF5, 0x35, 0xB1, 0x3E, 0xC0, 0x48, 0xBB, 0x51, 0xA4, 0x5D, 0xCE, 0x70, 0x4C, 0x79, 0xFF, 0x7F, 0xFF, 0x7F, 0xFE, 0x7F, 0x02, 0x6E, 0xEF, 0x64, 0xAD, 0x56, 0x50, 0x43, 0x1E, 0x30, 0x88, 0x30, 0x84, 0x35, 0x1D, 0x25, 0x6F, 0x05, 0x1E, 0xEB, 0xB7, 0xE4, 0x1F, 0xF6, 0x2A, 0x06, 0x87, 0xF8, 0x41, 0xE0, 0x22, 0xCB, 0xD1, 0xAE, 0xD3, 0x98, 0x71, 0x8B, 0x21, 0x8B, 0xE9, 0x9C, 0x54, 0xBB, 0xCB, 0xCF, 0x34, 0xDB, 0x65, 0xD9, 0x00, 0xCD, 0xCE, 0xBE, 0xF8, 0xB3, 0x8F, 0xB1, 0x0D, 0xBF, 0x52, 0xD7, 0x10, 0xE4, 0x02, 0xDF, 0x8D, 0xD0, 0x4E, 0xBF, 0x63, 0xB0, 0xF9, 0x9F, 0xC6, 0x94, 0x2F, 0x97, 0xE8, 0xA1, 0x1C, 0xBF, 0xA8, 0xE1, 0x61, 0xEF, 0xEF, 0xEC, 0x49, 0xE2, 0xE7, 0xC7, 0xAA, 0xAB, 0xCB, 0xA5, 0xE7, 0xAA, 0x84, 0xB0, 0x07, 0xC3, 0xB5, 0xD4, 0x46, 0xD3, 0x4B, 0xC4, 0x73, 0xB2, 0xB6, 0xAB, 0xCA, 0xB6, 0x9C, 0xC4, 0xF8, 0xC5, 0x99, 0xC8, 0xFE, 0xCF, 0x69, 0xCB, 0xB4, 0xC1, 0xFD, 0xB5, 0x66, 0xA7, 0x26, 0x9C, 0x56, 0x8E, 0x22, 0x8A, 0x15, 0x8C, 0xB3, 0xA8, 0x60, 0xD2, 0xE3, 0xEC, 0xE9, 0xEE, 0x3A, 0xE2, 0x75, 0xCD, 0xFD, 0xB5, 0x13, 0xA6, 0xAC, 0xA0, 0x70, 0x96, 0x9A, 0x89, 0xA8, 0x8D, 0x8E, 0x94, 0xE1, 0x96, 0xB3, 0xAA, 0x66, 0xC5, 0x00, 0xD4, 0xC0, 0xD4, 0xF1, 0xC6, 0xBA, 0xB5, 0x30, 0xB0, 0x23, 0xAD, 0x31, 0xA9, 0xD3, 0xA4, 0xC9, 0x9A, 0xB1, 0x91, 0x3D, 0x91, 0x2B, 0x99, 0xEC, 0xA1, 0xFB, 0xAA, 0x44, 0xB9, 0xD7, 0xCA, 0x72, 0xDD, 0x38, 0xDE, 0x44, 0xC4, 0xE5, 0xB0, 0x4A, 0xB0, 0x79, 0xAE, 0xFA, 0xA9, 0x58, 0xA6, 0xE0, 0x9E, 0xCC, 0x96, 0x45, 0x9A, 0xFC, 0x9C, 0x84, 0xAD, 0xFE, 0xBE, 0x06, 0xCE, 0x59, 0xD9, 0x7F, 0xE0, 0x07, 0xDE, 0x2E, 0xD9, 0x37, 0xCA, 0x56, 0xAB, 0x80, 0x95, 0xC2, 0x8D, 0x02, 0x8C, 0x46, 0x9C, 0x88, 0xBB, 0x01, 0xD3, 0xAA, 0xE5, 0x59, 0xEE, 0x03, 0xDE, 0x5D, 0xC6, 0xCE, 0xA7, 0x11, 0x94, 0x89, 0xA5, 0x51, 0xB8, 0x06, 0xC0, 0x3E, 0xCB, 0xE2, 0xD8, 0x05, 0xE9, 0xAE, 0xEE, 0x4A, 0xDF, 0x2B, 0xC0, 0xEC, 0xA7, 0x50, 0x9E, 0xB4, 0x98, 0xB4, 0xA5, 0x35, 0xC6, 0xC9, 0xE1, 0xC3, 0xF0, 0x4E, 0xF5, 0xD7, 0xEA, 0xD2, 0xCF, 0x6C, 0xB3, 0x01, 0xA4, 0x4F, 0x9D, 0xAE, 0x9D, 0x37, 0xA9, 0x98, 0xB6, 0xAD, 0xC7, 0xCF, 0xE4, 0x33, 0xFF, 0xAE, 0x07, 0x8C, 0xFC, 0xB8, 0xEB, 0x3F, 0xDB, 0x46, 0xBF, 0xEE, 0x9C, 0xE0, 0x8D, 0x29, 0x8B, 0xBD, 0x9B, 0x86, 0xA3, 0x8B, 0xA8, 0x7C, 0xB8, 0xF2, 0xD1, 0x3F, 0xE5, 0x72, 0xEF, 0x66, 0xF1, 0x83, 0xE9, 0xAE, 0xDE, 0xE5, 0xC4, 0x3D, 0x9E, 0xC0, 0x85, 0x58, 0x88, 0xB5, 0x8E, 0x92, 0x9E, 0x30, 0xB4, 0xE0, 0xCA, 0x70, 0xDC, 0x92, 0xE4, 0x54, 0xDB, 0x2C, 0xCE, 0xE0, 0xBE, 0x18, 0xA0, 0x04, 0x87, 0x75, 0x8C, 0x35, 0x99, 0xB6, 0x9A, 0x6B, 0x9C, 0x68, 0xAA, 0x2E, 0xBC, 0x1F, 0xC7, 0xCB, 0xBE, 0x5C, 0xA6, 0xBA, 0x92, 0xD6, 0x91, 0x50, 0x95, 0x40, 0x92, 0x8D, 0x90, 0x42, 0xA3, 0xD1, 0xAF, 0xE4, 0xA9, 0x14, 0xAB, 0x57, 0xB8, 0x27, 0xBD, 0x51, 0xB2, 0xB6, 0x9C, 0xA8, 0x85, 0x00, 0x80, 0x00, 0x80, 0x0C, 0x80, 0xD8, 0x8A, 0xB3, 0xB6, 0xFB, 0xD1, 0xBA, 0xD7, 0xEF, 0xCD, 0xD5, 0xAD, 0x2D, 0x98, 0x5C, 0x8A, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x5A, 0x88, 0xEA, 0x9D, 0x80, 0xCD, 0x33, 0xE0, 0xAF, 0xE6, 0xDD, 0xE5, 0x1B, 0xD0, 0x3A, 0xAE, 0x09, 0x93, 0xBC, 0x8A, 0x0A, 0x89, 0xC0, 0x85, 0xAF, 0x84, 0xFE, 0x89, 0x21, 0x8F, 0xD0, 0xB3, 0xA5, 0xE0, 0xFD, 0xE7, 0x39, 0xE4, 0xA1, 0xE5, 0x7A, 0xDA, 0xD7, 0xB4, 0xCD, 0x8B, 0x2C, 0x8B, 0xC2, 0x8D, 0x19, 0x85, 0x5F, 0x82, 0x58, 0x89, 0xC5, 0xA5, 0xF0, 0xCF, 0x73, 0xDF, 0x6D, 0xD4, 0x42, 0xC4, 0x92, 0xB4, 0xFE, 0xA2, 0xD6, 0x91, 0xF2, 0x8B, 0x1D, 0x96, 0x34, 0xB1, 0xC2, 0xC3, 0x10, 0xB9, 0x5F, 0xB1, 0xDD, 0xB4, 0xFD, 0xB3, 0xC2, 0xB4, 0x54, 0xB6, 0xF0, 0xB3, 0x47, 0xA8, 0xDF, 0x98, 0x65, 0x96, 0x20, 0xA8, 0xDC, 0xB8, 0x8E, 0xBA, 0x23, 0xC2, 0xA8, 0xB5, 0x1C, 0x93, 0x4B, 0x8A, 0x9D, 0x8B, 0xD4, 0x9B, 0xCB, 0xAE, 0x64, 0xAF, 0x68, 0xB7, 0xDF, 0xBC, 0x6E, 0xB7, 0x10, 0xB9, 0xE4, 0xBB, 0x19, 0xAE, 0x80, 0x9C, 0xF2, 0xA2, 0x3B, 0xA4, 0xF0, 0x93, 0xBF, 0x8F, 0x96, 0x8F, 0x7D, 0x97, 0x79, 0xA0, 0x40, 0x96, 0xF5, 0x90, 0x62, 0xA1, 0x88, 0xB0, 0x23, 0xB7, 0xD7, 0xBA, 0xA9, 0xAB, 0xF0, 0xA2, 0x90, 0x97, 0x29, 0x83, 0xF8, 0x85, 0x81, 0x8C, 0x77, 0x8E, 0xB7, 0x87, 0x00, 0x80, 0x43, 0x8B, 0xEE, 0xA8, 0x67, 0xBE, 0x50, 0xB5, 0xC0, 0xA6, 0x15, 0xA7, 0xB5, 0xA2, 0x7B, 0x9A, 0x27, 0x8C, 0xDA, 0x82, 0x5F, 0x82, 0xED, 0x80, 0x22, 0x84, 0x72, 0x85, 0x45, 0x8A, 0xDC, 0x96, 0x03, 0x9F, 0x33, 0xA5, 0xE2, 0xB4, 0xC7, 0xB3, 0x93, 0xAA, 0x8E, 0xA0, 0xE9, 0x95, 0xAA, 0x91, 0x77, 0x91, 0xF8, 0x89, 0x1C, 0x81, 0x00, 0x80, 0x4E, 0x9A, 0xA9, 0xCC, 0xD7, 0xE3, 0xEA, 0xD9, 0x16, 0xD4, 0xB0, 0xF0, 0xC1, 0x1E, 0x92, 0x3E, 0x25, 0x38, 0x13, 0x0A, 0xF8, 0xD6, 0x38, 0xBF, 0x6E, 0xD3, 0x1F, 0x0E, 0xCE, 0x3F, 0x95, 0x47, 0x57, 0x42, 0xCC, 0x4A, 0x68, 0x55, 0x1E, 0x59, 0x88, 0x57, 0xF0, 0x53, 0x79, 0x48, 0x51, 0x2C, 0x85, 0x1D, 0xD2, 0x38, 0xA3, 0x63, 0xFD, 0x7B, 0xC5, 0x78, 0xFD, 0x60, 0x1B, 0x48, 0xED, 0x39, 0xC0, 0x37, 0xF0, 0x3C, 0xE4, 0x45, 0xD6, 0x4E, 0xD8, 0x52, 0x14, 0x5B, 0xBE, 0x6D, 0x80, 0x7D, 0x82, 0x70, 0xEC, 0x5F, 0x0E, 0x4B, 0x85, 0x30, 0x80, 0x18, 0x7D, 0x15, 0xF0, 0x2A, 0x45, 0x4A, 0x8C, 0x66, 0xCB, 0x79, 0x39, 0x7D, 0x64, 0x77, 0x58, 0x6F, 0xD4, 0x72, 0xCD, 0x69, 0x3E, 0x5A, 0x7F, 0x38, 0xC0, 0x20, 0xA1, 0x06, 0x1E, 0xFC, 0x26, 0x14, 0x95, 0x3D, 0xDD, 0x60, 0x63, 0x79, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x69, 0x7E, 0xBF, 0x5A, 0xE9, 0x25, 0xF5, 0x0B, 0xE3, 0x14, 0x6F, 0x27, 0xA4, 0x32, 0x1D, 0x3B, 0x70, 0x48, 0xF3, 0x68, 0x44, 0x7E, 0x01, 0x7C, 0xA8, 0x73, 0x19, 0x62, 0x57, 0x4A, 0xB5, 0x34, 0x62, 0x27, 0x9D, 0x27, 0xB5, 0x31, 0xFA, 0x3C, 0x1E, 0x4E, 0x1A, 0x62, 0x06, 0x6F, 0x73, 0x75, 0xE1, 0x78, 0x8F, 0x76, 0x29, 0x69, 0xB0, 0x58, 0xAE, 0x4A, 0xF5, 0x3A, 0x13, 0x34, 0xE9, 0x3F, 0xEA, 0x50, 0x4A, 0x5D, 0x2F, 0x6A, 0x1B, 0x6B, 0x5A, 0x65, 0xB4, 0x5D, 0xFC, 0x52, 0x3B, 0x43, 0x48, 0x34, 0xDF, 0x32, 0x55, 0x4B, 0xD8, 0x65, 0xDD, 0x74, 0xEF, 0x7C, 0x04, 0x79, 0x2E, 0x66, 0x26, 0x51, 0x51, 0x44, 0x1B, 0x40, 0xF1, 0x42, 0xA3, 0x3B, 0x93, 0x25, 0x94, 0x1D, 0xD6, 0x34, 0xBC, 0x5F, 0x42, 0x7C, 0xFF, 0x7F, 0x0C, 0x74, 0xC7, 0x63, 0xF1, 0x56, 0xAC, 0x4A, 0x1A, 0x39, 0xC9, 0x24, 0xAA, 0x1E, 0x5B, 0x25, 0x6A, 0x2D, 0xD8, 0x37, 0x5C, 0x4E, 0x1F, 0x66, 0x61, 0x70, 0x10, 0x78, 0x08, 0x69, 0x67, 0x56, 0x62, 0x44, 0xEE, 0x38, 0x5A, 0x37, 0xE7, 0x2F, 0xCF, 0x2C, 0xE8, 0x2A, 0xD9, 0x27, 0xDB, 0x2E, 0x58, 0x35, 0xA8, 0x44, 0xA1, 0x59, 0x4A, 0x62, 0x66, 0x60, 0x42, 0x4E, 0x93, 0x30, 0x53, 0x1B, 0x96, 0x15, 0xE8, 0x14, 0xF2, 0x1A, 0x7A, 0x32, 0x4D, 0x4A, 0xA5, 0x51, 0x61, 0x51, 0xE6, 0x4C, 0x41, 0x46, 0x63, 0x47, 0xD7, 0x43, 0x57, 0x3E, 0xD1, 0x3F, 0x11, 0x36, 0xF0, 0x2D, 0x53, 0x27, 0xEE, 0x1E, 0x24, 0x28, 0x2B, 0x2A, 0xE9, 0x26, 0x51, 0x2E, 0x1D, 0x2E, 0xD6, 0x25, 0x4C, 0x1F, 0xE3, 0x2D, 0x25, 0x4A, 0x3F, 0x57, 0xFF, 0x4E, 0xBD, 0x31, 0xA8, 0x21, 0xD3, 0x31, 0xA6, 0x3B, 0xB6, 0x34, 0x49, 0x2C, 0x72, 0x20, 0xD2, 0x14, 0x71, 0x10, 0x44, 0x15, 0xA9, 0x24, 0x07, 0x3E, 0xDE, 0x55, 0x67, 0x56, 0xCA, 0x42, 0xC9, 0x2E, 0xEF, 0x2D, 0xDE, 0x44, 0x93, 0x4A, 0xB7, 0x2F, 0x54, 0x0F, 0xAA, 0x00, 0xFC, 0x19, 0x0D, 0x39, 0x72, 0x32, 0x6C, 0x2D, 0xDE, 0x42, 0x56, 0x51, 0xC3, 0x55, 0x55, 0x53, 0x6D, 0x3F, 0x25, 0x40, 0xA6, 0x5B, 0x78, 0x60, 0xF6, 0x46, 0xCF, 0x1E, 0xA6, 0x0A, 0x95, 0x25, 0xA9, 0x46, 0xAA, 0x55, 0x99, 0x5A, 0xB3, 0x5A, 0xD2, 0x63, 0x25, 0x72, 0x00, 0x6A, 0xBB, 0x5F, 0xFD, 0x58, 0xB3, 0x3C, 0x8F, 0x1B, 0x7A, 0xFF, 0x69, 0xF5, 0xC3, 0x19, 0x42, 0x5C, 0xFF, 0x7F, 0xFF, 0x7F, 0x13, 0x73, 0xA7, 0x70, 0xF9, 0x68, 0x1C, 0x65, 0x29, 0x6A, 0x39, 0x6B, 0xB7, 0x66, 0x7A, 0x62, 0x4B, 0x5B, 0xEC, 0x50, 0x2E, 0x46, 0x3F, 0x49, 0xB9, 0x5A, 0xD5, 0x65, 0x4C, 0x72, 0xFF, 0x7F, 0xFF, 0x7F, 0xAA, 0x7F, 0x5B, 0x67, 0x08, 0x4E, 0xEC, 0x3F, 0xE0, 0x3B, 0x73, 0x4B, 0x59, 0x5B, 0xE9, 0x63, 0x1C, 0x6E, 0x92, 0x76, 0x03, 0x65, 0x7E, 0x55, 0x40, 0x4B, 0xFE, 0x43, 0x3A, 0x45, 0x21, 0x4F, 0x8F, 0x56, 0x89, 0x68, 0xFA, 0x72, 0x72, 0x73, 0x81, 0x6D, 0x81, 0x65, 0xF5, 0x53, 0x1D, 0x49, 0x1B, 0x44, 0xF0, 0x3E, 0x19, 0x40, 0xF7, 0x50, 0xDF, 0x62, 0x48, 0x72, 0xFF, 0x7F, 0x79, 0x77, 0xFC, 0x69, 0x41, 0x63, 0x95, 0x68, 0x37, 0x6D, 0x60, 0x53, 0x20, 0x25, 0x63, 0xFE, 0x36, 0xED, 0xEA, 0xF2, 0xE8, 0x03, 0x7A, 0x28, 0x01, 0x60, 0x91, 0x7A, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xC9, 0x77, 0x1A, 0x45, 0x3E, 0x24, 0xC7, 0x25, 0x34, 0x35, 0x89, 0x48, 0xAB, 0x4C, 0xA4, 0x3B, 0x6A, 0x38, 0xA6, 0x4F, 0x36, 0x63, 0x21, 0x65, 0x45, 0x6D, 0x40, 0x6F, 0xA2, 0x6B, 0x85, 0x56, 0xF4, 0x41, 0x2E, 0x2A, 0xE7, 0x19, 0x51, 0x22, 0x37, 0x3B, 0xE4, 0x5D, 0x87, 0x68, 0x4D, 0x69, 0x94, 0x6C, 0x5C, 0x77, 0xF6, 0x7D, 0x08, 0x76, 0x64, 0x68, 0x34, 0x4F, 0xA8, 0x2F, 0xAC, 0x1B, 0x2A, 0x20, 0x6E, 0x27, 0xCF, 0x32, 0x8A, 0x42, 0xE7, 0x4C, 0xAD, 0x56, 0x7C, 0x64, 0xD8, 0x75, 0x7B, 0x70, 0xEE, 0x6A, 0xDE, 0x71, 0x53, 0x7C, 0x55, 0x71, 0x87, 0x69, 0xB5, 0x5D, 0xDD, 0x4B, 0x91, 0x36, 0x80, 0x24, 0x0D, 0x26, 0xF6, 0x32, 0xE0, 0x34, 0x6B, 0x3C, 0x1A, 0x40, 0x5E, 0x47, 0x94, 0x6A, 0xF2, 0x7B, 0x7F, 0x70, 0x9B, 0x59, 0xAA, 0x56, 0x1F, 0x52, 0x54, 0x35, 0xB5, 0x18, 0xB5, 0xFE, 0x64, 0xEC, 0x9F, 0xE1, 0x68, 0xD3, 0x4F, 0xE2, 0xA2, 0x03, 0x00, 0x03, 0xAE, 0xE9, 0xEA, 0xE1, 0x93, 0xE4, 0xD8, 0xE8, 0xC5, 0x0B, 0x10, 0x33, 0x86, 0x32, 0x2E, 0x1D, 0x14, 0x07, 0xE6, 0xE5, 0x1A, 0xC0, 0x91, 0xB2, 0xDA, 0xCA, 0xEB, 0xF4, 0xDD, 0xFE, 0x50, 0xE4, 0x8E, 0xCF, 0xEC, 0xCA, 0xB6, 0xD5, 0xDA, 0xDA, 0xF0, 0xCF, 0xB6, 0xD3, 0x7A, 0xE0, 0x59, 0xE4, 0x8B, 0xE8, 0x0E, 0xF7, 0x5A, 0x00, 0x81, 0xEF, 0x3F, 0xD8, 0xC2, 0xD5, 0x64, 0xEA, 0x4F, 0xF7, 0xB9, 0xDF, 0xB3, 0xBB, 0x30, 0xAE, 0xF9, 0xB7, 0xB7, 0xC6, 0x8A, 0xDB, 0x6D, 0xF4, 0xF5, 0x06, 0x14, 0x1B, 0xFB, 0x21, 0xC7, 0x12, 0xFC, 0xF7, 0x58, 0xD8, 0x81, 0xD3, 0xFA, 0xEA, 0xA6, 0xFB, 0xB9, 0xF2, 0xAF, 0xD1, 0xFC, 0xB4, 0xC9, 0xAC, 0xB3, 0xAF, 0xDA, 0xAF, 0xBB, 0xA7, 0x22, 0xAE, 0x08, 0xC6, 0xA1, 0xD2, 0xD0, 0xC9, 0x29, 0xBD, 0x48, 0xC5, 0xEC, 0xD3, 0x14, 0xD2, 0x9E, 0xCB, 0xA3, 0xC0, 0xDF, 0xAD, 0xC1, 0xA4, 0xE3, 0xAC, 0x0F, 0xB3, 0x54, 0xAC, 0x4B, 0xAB, 0x10, 0xAE, 0x13, 0xAA, 0xCE, 0x9D, 0x6E, 0x8D, 0x56, 0x8D, 0x7F, 0x8D, 0x18, 0x8B, 0xC2, 0x90, 0x18, 0xA4, 0x91, 0xB4, 0x5D, 0xBC, 0x79, 0xBE, 0x84, 0xBB, 0x67, 0xA9, 0x47, 0x97, 0xF5, 0x97, 0x89, 0xA0, 0x9E, 0x9E, 0x07, 0x9B, 0xEB, 0xA3, 0x20, 0xB7, 0x1C, 0xCF, 0x83, 0xD7, 0x8A, 0xC9, 0x30, 0xA8, 0xF3, 0x8B, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x7E, 0x85, 0xAF, 0x95, 0xAE, 0xAE, 0x73, 0xCB, 0xD8, 0xD3, 0xCD, 0xD1, 0xDE, 0xD0, 0xA8, 0xC2, 0x50, 0xB2, 0x80, 0xA3, 0xF0, 0x8D, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x4F, 0x83, 0xB5, 0x9F, 0xBB, 0xB6, 0x42, 0xBF, 0x5B, 0xCD, 0x20, 0xDD, 0x9F, 0xD1, 0x16, 0xAB, 0xB9, 0x8F, 0xE8, 0x82, 0x65, 0x8B, 0x68, 0x91, 0xFB, 0x9B, 0xF5, 0xAD, 0xF7, 0xC2, 0x81, 0xCA, 0x6A, 0xC3, 0xAC, 0xB2, 0xD9, 0x9D, 0xEC, 0x8F, 0xE8, 0x94, 0x72, 0x9D, 0x15, 0x94, 0x1E, 0x90, 0x8C, 0x99, 0x81, 0xA1, 0x34, 0xA7, 0xC1, 0xA7, 0x62, 0x9B, 0x26, 0x84, 0x00, 0x80, 0x45, 0x83, 0xB8, 0x81, 0x00, 0x80, 0x4E, 0x81, 0xB7, 0x80, 0x00, 0x9E, 0x63, 0xC6, 0xA2, 0xDF, 0x32, 0xE3, 0x16, 0xDC, 0x84, 0xD3, 0xE5, 0xBA, 0x05, 0x8F, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0xF0, 0x93, 0x1B, 0xA1, 0xFC, 0xA7, 0x2B, 0xA8, 0xE4, 0xA2, 0x09, 0x9D, 0x03, 0x9E, 0x81, 0x9B, 0xB3, 0x8F, 0x00, 0x80, 0x00, 0x80, 0x21, 0x83, 0xD6, 0x91, 0x72, 0xA2, 0xDD, 0xC4, 0x96, 0xD0, 0x72, 0xCB, 0x96, 0xC1, 0x3C, 0xB2, 0xF7, 0xA1, 0x8B, 0x96, 0xFE, 0x81, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0xF9, 0x9C, 0xC3, 0xB2, 0x4D, 0xC3, 0x82, 0xD4, 0xA1, 0xD4, 0x8F, 0xC0, 0x29, 0xA9, 0x2A, 0x9B, 0x12, 0x97, 0x03, 0x90, 0xAC, 0x83, 0x00, 0x80, 0x59, 0x87, 0x6F, 0x8F, 0x78, 0x98, 0x98, 0xA1, 0x71, 0xA4, 0xD6, 0x99, 0xBC, 0x8E, 0xED, 0x99, 0x8B, 0x9F, 0x05, 0x96, 0xCE, 0x9D, 0x52, 0x9E, 0xBF, 0x94, 0xF3, 0x8E, 0x74, 0x96, 0xEF, 0x97, 0x3C, 0x92, 0xD8, 0x82, 0x00, 0x80, 0x00, 0x80, 0x85, 0x8E, 0x2E, 0x9D, 0x3E, 0xB2, 0x5D, 0xCA, 0x59, 0xD4, 0x04, 0xC5, 0x3B, 0xAD, 0x92, 0x9A, 0xBC, 0x8E, 0x37, 0x91, 0x26, 0x9B, 0xB0, 0x9F, 0x0C, 0x9C, 0x08, 0x94, 0x8D, 0x8D, 0xEC, 0x8C, 0x75, 0x93, 0x78, 0xA8, 0x8B, 0xC2, 0x4B, 0xC8, 0x8E, 0xB8, 0x5A, 0x99, 0xC9, 0x8A, 0x75, 0x88, 0x3F, 0x99, 0xA3, 0xAD, 0xE2, 0xB2, 0x78, 0xAB, 0xB2, 0xAA, 0xEE, 0xAE, 0xE5, 0xB9, 0x9B, 0xC6, 0x85, 0xD4, 0x42, 0xDA, 0x3C, 0xC7, 0xA5, 0xB3, 0xA2, 0xA8, 0xEF, 0x9D, 0x5C, 0x9D, 0xE2, 0x91, 0xF1, 0x83, 0x3E, 0x84, 0xDD, 0x8E, 0x8F, 0x9E, 0x26, 0xB1, 0x82, 0xB9, 0x8B, 0xB0, 0x1A, 0xB6, 0x53, 0xC3, 0x46, 0xC0, 0x6E, 0xBB, 0xBC, 0xB8, 0x15, 0xB9, 0x24, 0xBE, 0x60, 0xB2, 0xCB, 0xA7, 0x65, 0xAB, 0x8D, 0x97, 0xD1, 0x8C, 0x28, 0xA6, 0x25, 0xC4, 0x62, 0xD1, 0xF4, 0xCD, 0xCA, 0xC6, 0x41, 0xBE, 0x6E, 0xA9, 0x96, 0x9E, 0x37, 0x9D, 0xFA, 0x9E, 0xEA, 0xA1, 0x01, 0x9C, 0xAE, 0x99, 0x28, 0xA3, 0xE8, 0xAA, 0x24, 0xAC, 0xC1, 0xAC, 0x3A, 0xAC, 0x95, 0xA5, 0x8E, 0xA1, 0xA0, 0x90, 0xB7, 0xA0, 0x98, 0xCA, 0x6F, 0xE3, 0x63, 0xE0, 0x8B, 0xD9, 0xF6, 0xCF, 0xD8, 0xC4, 0x19, 0xB8, 0xE2, 0xA1, 0x3A, 0x90, 0xCC, 0x92, 0xF4, 0xAB, 0x9A, 0xCD, 0xBD, 0xE1, 0xEB, 0xD7, 0x65, 0xB5, 0x7B, 0x9A, 0x4A, 0x97, 0x81, 0x97, 0x76, 0x91, 0x0F, 0x81, 0x00, 0x80, 0xC1, 0x88, 0x86, 0xA6, 0xCC, 0xC2, 0x05, 0xDA, 0x12, 0xE9, 0xB1, 0xEE, 0x63, 0xF8, 0x80, 0xFF, 0x37, 0x01, 0x1B, 0x04, 0x22, 0xFF, 0x22, 0xEF, 0x06, 0xDB, 0x64, 0xDD, 0xBE, 0xF6, 0x01, 0x05, 0x0B, 0xFB, 0x78, 0xEA, 0x9D, 0xF3, 0x84, 0x0E, 0x40, 0x25, 0x9C, 0x2E, 0xE4, 0x22, 0x49, 0x13, 0xDC, 0xFC, 0x26, 0xCF, 0x8E, 0x9C, 0x3B, 0x99, 0x27, 0xD4, 0xF5, 0x11, 0x11, 0x33, 0xE6, 0x3C, 0x3E, 0x38, 0xFF, 0x37, 0xB3, 0x4A, 0xBE, 0x74, 0xFF, 0x7F, 0x2A, 0x70, 0x61, 0x4A, 0x70, 0x22, 0x94, 0x10, 0xD5, 0x14, 0xF2, 0x2E, 0xD1, 0x45, 0x11, 0x47, 0x50, 0x38, 0x2F, 0x38, 0xE9, 0x51, 0xD0, 0x63, 0xDD, 0x60, 0x02, 0x64, 0x76, 0x6E, 0x3D, 0x72, 0x30, 0x5F, 0x23, 0x3F, 0xFF, 0x38, 0x7E, 0x5C, 0x57, 0x7C, 0x68, 0x7D, 0xD7, 0x74, 0xA3, 0x61, 0xFE, 0x42, 0x67, 0x32, 0xE1, 0x2F, 0x0B, 0x2F, 0xF3, 0x41, 0x9C, 0x64, 0xA2, 0x6D, 0x81, 0x74, 0xC7, 0x74, 0xDE, 0x57, 0x46, 0x35, 0x73, 0x26, 0x75, 0x32, 0xCA, 0x46, 0x40, 0x4E, 0xEA, 0x4E, 0x06, 0x59, 0xA8, 0x69, 0x30, 0x6F, 0x95, 0x7A, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xB3, 0x7D, 0x53, 0x71, 0x14, 0x63, 0xE1, 0x59, 0x10, 0x58, 0x30, 0x57, 0xBB, 0x59, 0xD6, 0x67, 0xC7, 0x7B, 0xCB, 0x7F, 0xFF, 0x7F, 0x04, 0x7D, 0x1E, 0x63, 0x0D, 0x5C, 0x6A, 0x5D, 0x81, 0x52, 0x8F, 0x53, 0xAD, 0x41, 0x31, 0x34, 0xC7, 0x27, 0x5B, 0x1B, 0x82, 0x33, 0x04, 0x59, 0xA4, 0x74, 0x82, 0x70, 0x35, 0x63, 0xC5, 0x51, 0x56, 0x4C, 0x67, 0x4F, 0x69, 0x54, 0x5C, 0x5E, 0xDE, 0x63, 0xCA, 0x5F, 0xE4, 0x5B, 0x4F, 0x63, 0xB0, 0x65, 0x2F, 0x60, 0x4B, 0x5B, 0x4E, 0x58, 0x4F, 0x51, 0xF6, 0x4F, 0x23, 0x4B, 0xCD, 0x4B, 0xAE, 0x57, 0xC8, 0x68, 0x9D, 0x6F, 0x5D, 0x74, 0xA9, 0x6B, 0xCD, 0x55, 0x4C, 0x5C, 0x4B, 0x63, 0xB4, 0x50, 0x46, 0x43, 0xA8, 0x3C, 0x6D, 0x44, 0xA6, 0x56, 0xDA, 0x5A, 0xF2, 0x56, 0x35, 0x5D, 0xA4, 0x6D, 0xAC, 0x77, 0x89, 0x76, 0xD1, 0x62, 0xA7, 0x50, 0xA2, 0x4B, 0xD9, 0x44, 0xAA, 0x4F, 0x05, 0x6C, 0xE0, 0x7A, 0xC0, 0x7C, 0x36, 0x6F, 0xF4, 0x65, 0x2F, 0x5C, 0x6A, 0x50, 0x95, 0x35, 0xDD, 0x1D, 0x7C, 0x24, 0xE2, 0x38, 0x31, 0x46, 0xE8, 0x3C, 0x7E, 0x3C, 0xF5, 0x51, 0x11, 0x5F, 0x70, 0x68, 0x4D, 0x68, 0x2A, 0x6C, 0x7C, 0x6C, 0x85, 0x57, 0xCE, 0x47, 0xAD, 0x44, 0xAD, 0x4D, 0x44, 0x50, 0x59, 0x4F, 0xA4, 0x56, 0x1D, 0x63, 0x40, 0x6E, 0x99, 0x77, 0x3D, 0x7F, 0x87, 0x76, 0x77, 0x61, 0xF1, 0x57, 0xAB, 0x41, 0xF2, 0x3E, 0x92, 0x4B, 0x98, 0x37, 0x8B, 0x2C, 0x13, 0x25, 0x58, 0x15, 0xF7, 0x19, 0x7F, 0x31, 0xCC, 0x54, 0x4F, 0x73, 0x70, 0x7C, 0xAF, 0x7C, 0x4C, 0x74, 0x51, 0x6E, 0xCA, 0x71, 0x1E, 0x7A, 0x47, 0x68, 0xFC, 0x56, 0x6D, 0x30, 0xE5, 0x18, 0xAC, 0x1B, 0x6A, 0x21, 0xF2, 0x27, 0x24, 0x3D, 0x14, 0x4D, 0xF2, 0x50, 0xC1, 0x47, 0x20, 0x3E, 0x80, 0x3D, 0x86, 0x40, 0x2D, 0x4B, 0xCB, 0x50, 0x76, 0x4E, 0xC2, 0x55, 0x5E, 0x60, 0x57, 0x63, 0xE4, 0x6A, 0xF0, 0x75, 0x35, 0x73, 0x39, 0x61, 0x7A, 0x49, 0xE9, 0x3E, 0x49, 0x49, 0x3C, 0x5D, 0x8F, 0x67, 0xD4, 0x6F, 0x7F, 0x77, 0xE6, 0x79, 0x35, 0x7A, 0x38, 0x7F, 0xE1, 0x76, 0x74, 0x65, 0x9F, 0x45, 0xAF, 0x21, 0x03, 0x10, 0x6B, 0x1A, 0x82, 0x39, 0x5C, 0x56, 0x81, 0x5B, 0x88, 0x46, 0x90, 0x38, 0x1E, 0x42, 0x57, 0x4A, 0x34, 0x4F, 0xF7, 0x49, 0xE4, 0x2C, 0xD3, 0x0F, 0xCE, 0x08, 0x6C, 0x18, 0xBC, 0x33, 0x04, 0x4C, 0x01, 0x5A, 0x4E, 0x64, 0x64, 0x6D, 0x7D, 0x7D, 0xFF, 0x7F, 0x7C, 0x7E, 0xAE, 0x62, 0xD3, 0x42, 0xE7, 0x3A, 0x4C, 0x40, 0x56, 0x45, 0x9E, 0x51, 0x7C, 0x64, 0x75, 0x6D, 0x91, 0x61, 0x78, 0x4F, 0xEA, 0x54, 0x73, 0x65, 0x0D, 0x63, 0xB5, 0x51, 0x13, 0x2F, 0x2B, 0x2B, 0x38, 0x38, 0xEC, 0x3C, 0xB5, 0x3A, 0xA3, 0x38, 0x62, 0x39, 0x40, 0x54, 0x77, 0x77, 0xD4, 0x6F, 0x06, 0x5E, 0x6A, 0x49, 0xFA, 0x28, 0xE9, 0x15, 0xC0, 0x2A, 0x35, 0x4D, 0xAE, 0x64, 0x8F, 0x7B, 0x79, 0x7F, 0x86, 0x7F, 0x41, 0x5D, 0x6C, 0x49, 0x7B, 0x3D, 0x11, 0x24, 0x09, 0x07, 0xCC, 0xEF, 0xC1, 0xF3, 0xF3, 0x20, 0xD3, 0x54, 0xE5, 0x6A, 0x0C, 0x6A, 0xE5, 0x5B, 0xEC, 0x47, 0x9C, 0x2A, 0x12, 0x16, 0x17, 0x17, 0x2D, 0x33, 0xAB, 0x53, 0x95, 0x56, 0xA4, 0x58, 0xBC, 0x4A, 0xE7, 0x50, 0xD0, 0x7A, 0xFF, 0x7F, 0xD4, 0x78, 0x8A, 0x5A, 0xFC, 0x2F, 0x63, 0x1F, 0x9E, 0x3E, 0x40, 0x3B, 0x31, 0x28, 0xE2, 0xFF, 0xCA, 0xDE, 0x9F, 0xE8, 0x38, 0x16, 0x89, 0x38, 0x38, 0x43, 0xB6, 0x2D, 0xC9, 0x0E, 0xAD, 0xF7, 0x55, 0xEC, 0x20, 0x01, 0xB0, 0x13, 0xEA, 0x0D, 0xDE, 0x03, 0xB2, 0xE8, 0xB3, 0xD0, 0x28, 0xED, 0x0A, 0x1F, 0x29, 0x3E, 0x70, 0x5B, 0x02, 0x6E, 0x98, 0x65, 0x64, 0x54, 0x8B, 0x2A, 0x72, 0x07, 0x18, 0xFE, 0x15, 0x07, 0x70, 0x15, 0x7B, 0x21, 0xCB, 0x32, 0x58, 0x3B, 0xC0, 0x28, 0x0F, 0xF8, 0x7F, 0xBD, 0x4E, 0xA7, 0xE5, 0xB9, 0x8D, 0xD5, 0xFE, 0xDF, 0x53, 0xD0, 0x14, 0xC9, 0x86, 0xD6, 0x8F, 0xC2, 0x42, 0x95, 0xE4, 0x8B, 0x95, 0x92, 0xA3, 0xA9, 0x53, 0xB7, 0x6C, 0xBE, 0xCE, 0xE6, 0xE8, 0x19, 0x68, 0x24, 0x70, 0x11, 0x1D, 0xFB, 0x13, 0xF1, 0xA3, 0xE7, 0x2D, 0xDE, 0x9B, 0xEF, 0x60, 0x0E, 0x60, 0x15, 0x45, 0xF5, 0xE7, 0xC1, 0xDE, 0x9F, 0x52, 0xA3, 0x2D, 0xCD, 0x57, 0xF2, 0x18, 0xEC, 0xBC, 0xDA, 0x02, 0xE4, 0x33, 0xEF, 0xFD, 0xE7, 0xF3, 0xDF, 0x2F, 0xDE, 0x86, 0xD8, 0x6F, 0xCA, 0x3A, 0xBA, 0x7F, 0xB5, 0x7E, 0xC8, 0x24, 0xDE, 0xF4, 0xDE, 0x3E, 0xE6, 0x4D, 0x07, 0xAC, 0x29, 0x6D, 0x28, 0xF6, 0xFF, 0xEC, 0xDC, 0x40, 0xDB, 0xB4, 0xE9, 0xC6, 0xDF, 0x32, 0xB5, 0x5D, 0x99, 0xCC, 0x96, 0x6A, 0x92, 0x28, 0x97, 0x24, 0xA2, 0x0A, 0xB2, 0x3F, 0xC0, 0x92, 0xCC, 0x2D, 0xD7, 0x61, 0xE8, 0xAD, 0xF7, 0xB9, 0xF4, 0x30, 0xF2, 0xAA, 0xFD, 0x61, 0x08, 0xA2, 0x02, 0xF5, 0xF6, 0x46, 0xFB, 0x7E, 0x03, 0xB8, 0xF9, 0x53, 0xE8, 0xBC, 0xE3, 0xD0, 0xED, 0xE8, 0xFF, 0xFA, 0x0C, 0xF7, 0x0A, 0xFB, 0xFC, 0x83, 0xE4, 0x91, 0xD2, 0x05, 0xCF, 0x88, 0xC2, 0xC8, 0xB0, 0x20, 0xB3, 0x14, 0xD2, 0x7A, 0x01, 0xB5, 0x18, 0x52, 0xF8, 0x25, 0xC8, 0x27, 0xBC, 0x01, 0xBE, 0x47, 0xB8, 0x7A, 0xBB, 0xDF, 0xC1, 0xC7, 0xBF, 0x75, 0xB4, 0xFB, 0xB8, 0xCD, 0xE8, 0xB8, 0x15, 0x20, 0x0F, 0xA0, 0xEA, 0xC4, 0xC7, 0xA3, 0xB2, 0x24, 0xAA, 0x94, 0xB1, 0x6B, 0xCA, 0xA4, 0xE4, 0xA1, 0xF4, 0x59, 0xEE, 0x39, 0xD4, 0x35, 0xBB, 0xE4, 0xB3, 0x8C, 0xC5, 0xAC, 0xDF, 0x03, 0xF5, 0x18, 0xFA, 0xB2, 0xEB, 0x36, 0xE1, 0x87, 0xDC, 0x34, 0xE3, 0xF4, 0xF2, 0x65, 0xED, 0x40, 0xD5, 0x73, 0xBB, 0xA8, 0xA9, 0xB0, 0x9F, 0x2B, 0x9B, 0x62, 0xA2, 0xAF, 0xAC, 0xDC, 0xAE, 0x49, 0xAF, 0xBD, 0xBF, 0xE5, 0xD5, 0x26, 0xE4, 0xE1, 0xEE, 0xC3, 0xE1, 0xB7, 0xC2, 0xC4, 0xA6, 0x3C, 0x91, 0x71, 0x8E, 0x6D, 0x97, 0x13, 0xA0, 0x74, 0xA3, 0x41, 0xA8, 0x4A, 0xB7, 0xD0, 0xD0, 0xB0, 0xDC, 0xD6, 0xD7, 0x52, 0xC9, 0x70, 0xB2, 0x56, 0x93, 0x99, 0x84, 0x83, 0x94, 0xE4, 0xB3, 0xAF, 0xD4, 0xDD, 0xEA, 0x75, 0xED, 0xB3, 0xDD, 0x96, 0xC6, 0x45, 0xBA, 0x7C, 0xB0, 0xEF, 0x95, 0x58, 0x8A, 0x64, 0x82, 0x00, 0x80, 0x00, 0x80, 0x6B, 0x83, 0xBE, 0x91, 0xDD, 0xA5, 0xF3, 0xA6, 0xAD, 0xA4, 0x3C, 0xB0, 0x88, 0xBF, 0xFC, 0xC0, 0xB3, 0xAF, 0x57, 0x92, 0x74, 0x8C, 0x00, 0x8F, 0xEE, 0x8C, 0xF6, 0x9C, 0xA4, 0xB9, 0xE8, 0xC6, 0x07, 0xD0, 0xB1, 0xD1, 0xBA, 0xC4, 0x48, 0xB4, 0x87, 0xA0, 0xE3, 0x8F, 0x48, 0x8C, 0xB4, 0x98, 0x6D, 0xA8, 0x22, 0xB0, 0x61, 0xB3, 0x36, 0xBB, 0x50, 0xBE, 0x1A, 0xBE, 0x94, 0xB0, 0xBE, 0x9B, 0x63, 0x91, 0xA9, 0x8B, 0xE4, 0x8F, 0x0C, 0x95, 0x96, 0x93, 0xA2, 0x95, 0x26, 0xAC, 0xF4, 0xCA, 0xFF, 0xDE, 0xE3, 0xDC, 0x6B, 0xD7, 0x38, 0xD1, 0x83, 0xB7, 0x16, 0x8F, 0x13, 0x87, 0x34, 0x97, 0x54, 0x94, 0x73, 0x86, 0xE4, 0x82, 0xBB, 0x8F, 0x42, 0xA9, 0xAE, 0xB9, 0x10, 0xC5, 0x2C, 0xCE, 0xA4, 0xC8, 0xD1, 0xBA, 0x66, 0xAF, 0x82, 0xAD, 0x53, 0xB5, 0x3F, 0xBB, 0x4F, 0xBB, 0x57, 0xB9, 0x21, 0xB7, 0x19, 0xB4, 0xDE, 0xB8, 0x12, 0xCE, 0xDE, 0xE0, 0x13, 0xD9, 0x71, 0xB8, 0x10, 0x9B, 0xD5, 0x9E, 0x8E, 0xB3, 0xDF, 0xB2, 0xCA, 0xAD, 0x73, 0xC4, 0x40, 0xDA, 0xC3, 0xCB, 0x05, 0xA4, 0xE7, 0x8C, 0x9E, 0x96, 0x21, 0xB7, 0x10, 0xC6, 0x8C, 0xB4, 0x35, 0xA1, 0x4C, 0x9D, 0x91, 0x98, 0x6C, 0x96, 0x94, 0x8C, 0x52, 0x8F, 0xBC, 0x8E, 0x77, 0x83, 0xD2, 0x83, 0x97, 0x8A, 0xF3, 0x96, 0xFB, 0x9C, 0xCF, 0xAB, 0xA8, 0xC4, 0xD1, 0xDC, 0xE2, 0xDF, 0x49, 0xD8, 0x5E, 0xDC, 0x9D, 0xE8, 0x14, 0xE5, 0xA5, 0xD4, 0x85, 0xCF, 0xD6, 0xD6, 0x8D, 0xD6, 0x56, 0xBE, 0x77, 0xA4, 0xFD, 0xA0, 0x05, 0xA6, 0x4F, 0xA9, 0x89, 0xA4, 0xF1, 0x95, 0xC6, 0x8E, 0xB3, 0x90, 0xA8, 0x92, 0x16, 0x9F, 0x10, 0xA6, 0xB5, 0xA4, 0x44, 0xA2, 0x2F, 0xA3, 0x41, 0xAB, 0x60, 0xAA, 0xCF, 0x97, 0xE4, 0x8B, 0xBA, 0x8D, 0x27, 0x9D, 0xF2, 0xB6, 0xB1, 0xD9, 0x6F, 0xE7, 0x11, 0xE1, 0x22, 0xCC, 0x71, 0xA5, 0x91, 0x99, 0xE9, 0x95, 0x69, 0x8F, 0x02, 0x89, 0x9A, 0x8C, 0x42, 0xAB, 0x2D, 0xC9, 0x94, 0xD9, 0xBA, 0xEE, 0x2B, 0xFE, 0x2B, 0x09, 0x14, 0x13, 0xF5, 0x05, 0x7C, 0xDC, 0x67, 0xAE, 0xE9, 0xA6, 0x4F, 0xCC, 0x22, 0xE9, 0x81, 0xE3, 0x82, 0xD1, 0x9F, 0xCB, 0x4A, 0xD2, 0xBF, 0xCF, 0x05, 0xC2, 0x95, 0xAE, 0x70, 0xA6, 0x43, 0xB5, 0x28, 0xCC, 0x97, 0xE1, 0x5B, 0xEC, 0x76, 0xE7, 0x7A, 0xD8, 0xC9, 0xC9, 0xA8, 0xD4, 0x12, 0xEA, 0x97, 0xEB, 0x7F, 0xD8, 0x39, 0xC3, 0xC7, 0xC6, 0x95, 0xD3, 0x88, 0xD5, 0xD2, 0xCD, 0xA4, 0xBB, 0x41, 0xB2, 0xF4, 0xB6, 0x62, 0xBC, 0x80, 0xC1, 0xE3, 0xC7, 0xD9, 0xD2, 0xD2, 0xEF, 0x37, 0x16, 0x77, 0x20, 0x9F, 0x18, 0x68, 0x18, 0x45, 0x0C, 0x37, 0xF6, 0xF7, 0xEA, 0x11, 0xE7, 0xCB, 0xE2, 0x29, 0xDD, 0x6C, 0xE5, 0xFE, 0x07, 0x22, 0x34, 0x74, 0x47, 0xA9, 0x58, 0xB3, 0x61, 0x51, 0x5F, 0x5D, 0x51, 0x70, 0x51, 0x44, 0x59, 0x35, 0x62, 0xA3, 0x6D, 0xD3, 0x6D, 0xF8, 0x64, 0x67, 0x45, 0x06, 0x0B, 0xB0, 0xDE, 0x37, 0xD4, 0x99, 0xEC, 0xBC, 0x06, 0xAC, 0xFC, 0xF9, 0xEE, 0x42, 0xFF, 0xEF, 0x17, 0xC1, 0x1B, 0x46, 0xFA, 0x4D, 0xB1, 0xBB, 0x86, 0x21, 0x9A, 0x67, 0xDC, 0x19, 0x18, 0xEC, 0x39, 0xE9, 0x44, 0x5E, 0x52, 0xBA, 0x5C, 0x87, 0x53, 0xAA, 0x3D, 0xFB, 0x1A, 0x25, 0xFD, 0x4D, 0xE5, 0x6C, 0xD6, 0xE7, 0xD5, 0x25, 0xE1, 0x93, 0xE7, 0x39, 0xDF, 0x57, 0xD9, 0xAE, 0xE4, 0x50, 0xF1, 0xD7, 0xE6, 0x45, 0xD2, 0xDF, 0xCB, 0x58, 0xCE, 0x81, 0xC7, 0x3E, 0xB0, 0x9A, 0xA9, 0x98, 0xCD, 0xD0, 0xF4, 0x53, 0xFA, 0x82, 0xE6, 0x4D, 0xD6, 0xD0, 0xDE, 0xB3, 0xF0, 0xFE, 0xFA, 0x45, 0x05, 0x81, 0x12, 0x9B, 0x1D, 0x18, 0x27, 0xA7, 0x2F, 0xD9, 0x33, 0xD6, 0x41, 0x96, 0x5F, 0x9E, 0x71, 0xE8, 0x6B, 0xD8, 0x58, 0xA5, 0x42, 0xFC, 0x19, 0xA8, 0xE8, 0x26, 0xDA, 0x45, 0xF5, 0x0C, 0x22, 0x0D, 0x42, 0x59, 0x46, 0x08, 0x4A, 0x2F, 0x55, 0xAC, 0x4E, 0x6C, 0x36, 0xCA, 0x31, 0x83, 0x34, 0xB3, 0x13, 0x0D, 0xEE, 0x3B, 0xE3, 0x47, 0xFC, 0xC3, 0x2C, 0x70, 0x45, 0x61, 0x51, 0xDB, 0x68, 0xA8, 0x79, 0x48, 0x7C, 0x2C, 0x7D, 0xAF, 0x7C, 0x80, 0x71, 0x96, 0x62, 0xDE, 0x54, 0x9B, 0x50, 0x27, 0x4D, 0x0C, 0x48, 0x6A, 0x34, 0x7E, 0x29, 0x4F, 0x18, 0x86, 0x0A, 0xC3, 0x12, 0x40, 0x34, 0x66, 0x53, 0xEC, 0x5F, 0x93, 0x5B, 0x8B, 0x4A, 0x65, 0x3A, 0xB8, 0x32, 0x34, 0x2C, 0xC6, 0x2A, 0x29, 0x2B, 0xB7, 0x1E, 0x10, 0x04, 0x86, 0xE3, 0xFF, 0xD0, 0x8E, 0xE0, 0xCD, 0x01, 0x19, 0x10, 0x25, 0x0B, 0xB9, 0x03, 0xFE, 0xF8, 0x34, 0x00, 0x5F, 0x1C, 0xB7, 0x2F, 0xBB, 0x3F, 0x54, 0x43, 0xD4, 0x32, 0xC2, 0x30, 0x53, 0x49, 0x33, 0x6A, 0x15, 0x6E, 0x33, 0x50, 0x3F, 0x31, 0x07, 0x1D, 0x5F, 0x1C, 0x38, 0x2B, 0x5E, 0x3C, 0xBA, 0x40, 0x96, 0x26, 0x0C, 0x08, 0x50, 0x03, 0xD7, 0x11, 0x22, 0x1F, 0x65, 0x1B, 0xCB, 0x0A, 0x02, 0xF5, 0x01, 0xDA, 0x4F, 0xC4, 0x21, 0xD0, 0xB0, 0xFF, 0x10, 0x31, 0x6B, 0x52, 0x4E, 0x62, 0xE7, 0x63, 0x90, 0x57, 0x61, 0x34, 0x45, 0x05, 0xFC, 0xE8, 0xC7, 0xED, 0x57, 0xFF, 0x6E, 0x07, 0x62, 0x07, 0xCD, 0x08, 0xE6, 0x0C, 0x5C, 0x0C, 0xB2, 0x0C, 0x37, 0x11, 0xAE, 0x11, 0xDC, 0x0F, 0xA4, 0x12, 0x11, 0x22, 0x41, 0x38, 0x3B, 0x4A, 0xBB, 0x51, 0x78, 0x45, 0x0F, 0x36, 0x58, 0x34, 0x25, 0x3E, 0xF7, 0x4D, 0x4E, 0x52, 0xE3, 0x41, 0xC1, 0x16, 0xCC, 0xE5, 0x53, 0xE3, 0xD1, 0x09, 0xEF, 0x32, 0x1F, 0x4B, 0x0D, 0x44, 0x79, 0x37, 0x46, 0x3F, 0x32, 0x46, 0x55, 0x45, 0xA3, 0x43, 0x48, 0x3D, 0x46, 0x32, 0x67, 0x1E, 0x5A, 0x07, 0x6D, 0xFD, 0x28, 0x09, 0xD1, 0x23, 0x80, 0x3A, 0xFF, 0x49, 0x24, 0x4E, 0x3F, 0x44, 0x03, 0x39, 0x30, 0x28, 0x49, 0x19, 0x81, 0x17, 0x63, 0x11, 0x50, 0x09, 0x4D, 0x0F, 0xA7, 0x19, 0xF5, 0x16, 0x9F, 0x0C, 0x94, 0x05, 0xB1, 0xFD, 0xD2, 0xFE, 0x5C, 0x13, 0x22, 0x2F, 0x30, 0x44, 0xF4, 0x48, 0xC7, 0x41, 0x11, 0x30, 0xAB, 0x0A, 0x51, 0xE4, 0x48, 0xD2, 0xB3, 0xCF, 0xD0, 0xD7, 0x9B, 0xE2, 0x68, 0xDB, 0xC4, 0xC4, 0x86, 0xC3, 0x42, 0xE2, 0x5E, 0x0F, 0x23, 0x3A, 0x7E, 0x44, 0xBF, 0x2B, 0x8A, 0x0B, 0xCF, 0xFF, 0x30, 0x17, 0x68, 0x2E, 0x67, 0x22, 0x38, 0xFB, 0x00, 0xE0, 0x61, 0xF6, 0x66, 0x23, 0xCD, 0x33, 0x92, 0x1E, 0xAF, 0x06, 0x6F, 0x07, 0x00, 0x0B, 0xD0, 0x05, 0xE8, 0x02, 0x03, 0xFE, 0x31, 0xEF, 0x77, 0xDC, 0x7D, 0xD3, 0x2C, 0xD5, 0x5F, 0xD9, 0x18, 0xDB, 0x80, 0xE4, 0x5E, 0xFB, 0x81, 0x13, 0x64, 0x28, 0x3B, 0x36, 0x55, 0x3F, 0x84, 0x45, 0x5A, 0x3F, 0x41, 0x27, 0xFE, 0x02, 0xFB, 0xF2, 0x25, 0xF7, 0x8F, 0xF0, 0x2D, 0xEE, 0x87, 0xFE, 0x18, 0x15, 0xA0, 0x22, 0x8D, 0x22, 0x5D, 0x26, 0x72, 0x33, 0xFA, 0x35, 0xB1, 0x19, 0xB9, 0xED, 0xAD, 0xDB, 0xE9, 0xE9, 0xDD, 0x05, 0x2D, 0x1F, 0xCE, 0x18, 0x67, 0xFE, 0x53, 0x06, 0xB1, 0x1F, 0x26, 0x19, 0x17, 0x01, 0x29, 0xEC, 0xA6, 0xDC, 0xCB, 0xD7, 0x5D, 0xE5, 0xC4, 0x0E, 0xC9, 0x3E, 0x07, 0x52, 0x42, 0x44, 0x6F, 0x31, 0x2D, 0x33, 0xA6, 0x37, 0x43, 0x27, 0x13, 0x0F, 0xA0, 0x01, 0x66, 0xFF, 0x2E, 0xFF, 0x1A, 0xFF, 0x56, 0x05, 0x9D, 0x16, 0x45, 0x2E, 0x80, 0x40, 0x74, 0x49, 0x30, 0x4D, 0x55, 0x4C, 0xE2, 0x34, 0xE6, 0xFF, 0xE2, 0xD2, 0xE4, 0xCA, 0xE4, 0xD7, 0xD5, 0xD8, 0xE0, 0xC7, 0x24, 0xC0, 0x10, 0xCD, 0xC4, 0xD2, 0xBE, 0xB8, 0x9D, 0xA0, 0xD4, 0xA5, 0xD3, 0xBD, 0x9B, 0xD5, 0xC4, 0xDD, 0xAE, 0xE9, 0xFF, 0x07, 0xCA, 0x0D, 0xD7, 0xF7, 0x69, 0xF3, 0x02, 0x17, 0x38, 0x47, 0x4C, 0x53, 0xE0, 0x3F, 0xE8, 0x39, 0xED, 0x4F, 0x9D, 0x5B, 0x3C, 0x42, 0x0E, 0x21, 0xEE, 0x13, 0xD9, 0x14, 0xE3, 0x12, 0x30, 0x0D, 0x6C, 0x0F, 0x04, 0x1B, 0xA4, 0x25, 0x1A, 0x29, 0x64, 0x29, 0xCE, 0x25, 0x15, 0x1E, 0x31, 0x0C, 0xE4, 0xE5, 0xC2, 0xBE, 0xFE, 0xB9, 0xE2, 0xDC, 0x3B, 0xFA, 0x02, 0xEF, 0xB6, 0xD8, 0xE8, 0xDC, 0xB7, 0xF3, 0xD5, 0xFD, 0x1A, 0xF9, 0xE9, 0xFA, 0xFD, 0x0A, 0xF6, 0x1D, 0x60, 0x26, 0xC0, 0x29, 0x34, 0x22, 0x5F, 0x05, 0xC2, 0xE7, 0x45, 0xDA, 0x9C, 0xDB, 0x1B, 0xE0, 0x25, 0xDC, 0xAB, 0xD6, 0xCC, 0xDD, 0x58, 0xEF, 0xDA, 0xF8, 0xC7, 0xF3, 0x9F, 0xE8, 0xD6, 0xDA, 0x3A, 0xCA, 0x4D, 0xC7, 0x81, 0xE1, 0xDD, 0xFE, 0xD5, 0x09, 0x65, 0x0A, 0xE7, 0x01, 0x58, 0xFD, 0xA8, 0x09, 0x96, 0x18, 0x7F, 0x1F, 0x90, 0x12, 0x7C, 0xE1, 0x0C, 0xA5, 0xC8, 0x8F, 0x6F, 0x9E, 0xAC, 0xC2, 0xD8, 0xD5, 0xA9, 0xD9, 0x6B, 0xDF, 0x38, 0xDA, 0x58, 0xC9, 0x14, 0xC5, 0x41, 0xD3, 0x9C, 0xE4, 0xDC, 0xDF, 0xE7, 0xC4, 0xF6, 0xB8, 0x9E, 0xC1, 0xDD, 0xC9, 0x2B, 0xD4, 0xED, 0xD3, 0x59, 0xBB, 0xAD, 0x9C, 0x61, 0x8C, 0xAD, 0x90, 0x7B, 0xAA, 0x10, 0xC1, 0x08, 0xCA, 0x58, 0xCE, 0x1E, 0xDF, 0xA5, 0xE3, 0xE9, 0xCD, 0xEA, 0xC0, 0xF8, 0xC6, 0xF1, 0xD3, 0xBB, 0xDA, 0x50, 0xE4, 0x7E, 0xFC, 0x4C, 0x0A, 0x42, 0x0B, 0x2E, 0x12, 0x80, 0x22, 0xB4, 0x25, 0xA0, 0x06, 0x8E, 0xE7, 0x0A, 0xDE, 0xF5, 0xD5, 0x4D, 0xC9, 0x47, 0xC8, 0xF0, 0xE2, 0xBC, 0x03, 0xD3, 0x0D, 0xA8, 0xFD, 0x47, 0xDF, 0xF4, 0xC9, 0x30, 0xBF, 0x53, 0xB5, 0x05, 0xB6, 0x40, 0xCA, 0xAD, 0xEB, 0x41, 0x0B, 0xD4, 0x20, 0x55, 0x34, 0xB2, 0x41, 0xC4, 0x29, 0x1A, 0xE7, 0x7F, 0xA8, 0x0B, 0x9B, 0x8C, 0xAE, 0x32, 0xB6, 0x7B, 0xAF, 0x93, 0xAE, 0x42, 0xB9, 0x2E, 0xC1, 0x95, 0xBC, 0x37, 0xC2, 0x87, 0xE9, 0x48, 0x2F, 0x9C, 0x62, 0xC4, 0x4F, 0x8B, 0x0E, 0x66, 0xD9, 0xEC, 0xC5, 0x66, 0xBE, 0x93, 0xAC, 0x15, 0x94, 0x10, 0x86, 0xE7, 0x95, 0x72, 0xC2, 0x18, 0xF9, 0x0F, 0x16, 0xC0, 0x0F, 0x4A, 0xEC, 0x3E, 0xBF, 0xD7, 0xA8, 0x39, 0xBC, 0x47, 0xDB, 0x28, 0xD4, 0xA8, 0xB5, 0x30, 0xAF, 0xB4, 0xCB, 0x11, 0xF5, 0xF6, 0x04, 0x07, 0xFD, 0x93, 0xFD, 0xFD, 0x0B, 0x64, 0x09, 0x9D, 0xDE, 0x94, 0xBA, 0xCB, 0xBE, 0x24, 0xD0, 0xC5, 0xE1, 0x3B, 0xEB, 0xA5, 0xE2, 0xE6, 0xD1, 0x8D, 0xC2, 0xE0, 0xBA, 0x07, 0xCF, 0xBF, 0xFC, 0x52, 0x20, 0x89, 0x32, 0x67, 0x3D, 0xF2, 0x3F, 0x6D, 0x32, 0xD6, 0x08, 0x65, 0xCC, 0x9A, 0x9D, 0xAC, 0x95, 0x5C, 0xA4, 0xD2, 0xAA, 0x3B, 0xA0, 0x99, 0x93, 0x8C, 0xA2, 0x98, 0xC3, 0x1A, 0xD8, 0xD6, 0xE1, 0xE2, 0xF3, 0x3E, 0x12, 0x43, 0x28, 0xAE, 0x24, 0xF5, 0xF6, 0xC4, 0xAF, 0x88, 0x89, 0xC5, 0x94, 0x34, 0xC2, 0x44, 0xF2, 0xC3, 0xFD, 0x31, 0xF2, 0xE6, 0xEB, 0x9E, 0xE2, 0xFE, 0xC9, 0x85, 0xAD, 0xC1, 0xA0, 0x5C, 0xAC, 0x55, 0xBE, 0xDA, 0xBC, 0x13, 0xC0, 0x54, 0xE3, 0x7D, 0x06, 0xA8, 0x0A, 0xE7, 0xFD, 0x25, 0xFE, 0xB5, 0x06, 0x0A, 0xFD, 0x22, 0xEA, 0x71, 0xE4, 0xFA, 0xF1, 0x8C, 0x02, 0xCA, 0xFC, 0xC3, 0xEF, 0x7D, 0xFB, 0x05, 0x24, 0x69, 0x46, 0x23, 0x35, 0x09, 0x08, 0xA9, 0xF7, 0x61, 0x0F, 0xF8, 0x39, 0x16, 0x4D, 0x6D, 0x3A, 0x06, 0x26, 0xBB, 0x19, 0xA1, 0xFF, 0xD4, 0xE0, 0x22, 0xD8, 0x21, 0xE0, 0xB2, 0xD8, 0xD1, 0xBB, 0xE8, 0xAB, 0xA3, 0xBE, 0x8B, 0xE8, 0xE4, 0x13, 0x01, 0x38, 0xAD, 0x57, 0xF6, 0x5B, 0x07, 0x33, 0xAE, 0xFC, 0x5F, 0xE1, 0x2D, 0xEC, 0x8A, 0xFF, 0xA2, 0xFD, 0x84, 0xFE, 0x15, 0x18, 0x72, 0x34, 0x24, 0x43, 0x93, 0x3D, 0x1A, 0x2A, 0x68, 0x21, 0x0C, 0x26, 0x9D, 0x32, 0x12, 0x3F, 0x21, 0x33, 0xA1, 0x0F, 0x63, 0xF1, 0xD3, 0xE6, 0xCF, 0xE1, 0x04, 0xDD, 0xE6, 0xE8, 0xD8, 0x03, 0x00, 0x1D, 0x79, 0x31, 0x08, 0x40, 0xE6, 0x3A, 0xBE, 0x24, 0x66, 0x10, 0xC8, 0x06, 0xEE, 0x03, 0x4C, 0xFC, 0xEF, 0xF5, 0xE9, 0xF6, 0xBB, 0xEA, 0xA9, 0xC6, 0x68, 0xA7, 0x18, 0xA8, 0x70, 0xBA, 0x88, 0xCF, 0xF0, 0xE2, 0x6D, 0xF6, 0xBA, 0x04, 0xA6, 0xF9, 0xC3, 0xE8, 0xFA, 0xED, 0x03, 0x11, 0x42, 0x2F, 0x10, 0x10, 0x06, 0xD2, 0xD3, 0xAD, 0xFD, 0xBE, 0x22, 0xF1, 0xB4, 0x04, 0x5E, 0xFF, 0x6C, 0x00, 0x37, 0x16, 0x17, 0x4A, 0xEA, 0x7E, 0xFF, 0x7F, 0xD5, 0x76, 0xAE, 0x3F, 0xA7, 0x05, 0x4B, 0xEA, 0xCF, 0xDD, 0x60, 0xD9, 0xBB, 0xED, 0x7C, 0x0C, 0xCF, 0x23, 0xA6, 0x2E, 0x2E, 0x3A, 0x77, 0x4F, 0xA5, 0x3C, 0xAE, 0xFE, 0x08, 0xD6, 0xEC, 0xDD, 0x71, 0xF5, 0xFA, 0xF8, 0x80, 0xFE, 0xE3, 0x11, 0x85, 0x23, 0x9C, 0x34, 0x7B, 0x42, 0x93, 0x51, 0x27, 0x5A, 0xCD, 0x47, 0x36, 0x2C, 0x4E, 0x22, 0xD2, 0x25, 0x50, 0x20, 0xC2, 0x06, 0xC7, 0xF1, 0x90, 0xFA, 0x14, 0x11, 0x89, 0x24, 0x80, 0x3D, 0x76, 0x5D, 0xC0, 0x6D, 0x37, 0x5A, 0x41, 0x35, 0x84, 0x21, 0x86, 0x22, 0x1C, 0x25, 0x78, 0x1F, 0xED, 0x0E, 0x5E, 0xFA, 0xD8, 0xE7, 0x81, 0xD6, 0x35, 0xE0, 0x10, 0x06, 0x77, 0x21, 0x60, 0x2A, 0x73, 0x29, 0xBB, 0x2C, 0x62, 0x37, 0xCB, 0x35, 0xC1, 0x30, 0x9F, 0x35, 0x39, 0x2A, 0x6E, 0x09, 0xEF, 0xF8, 0xCA, 0xFE, 0x49, 0x0D, 0x96, 0x19, 0x44, 0x0B, 0xE5, 0xEE, 0xCF, 0xE1, 0xD4, 0xEC, 0x84, 0x06, 0x72, 0x09, 0x62, 0xEF, 0x45, 0xE1, 0xED, 0xF6, 0xDF, 0x12, 0xDF, 0x11, 0xDA, 0x04, 0xA1, 0x02, 0x22, 0x0C, 0xB8, 0x1C, 0x08, 0x2B, 0x60, 0x38, 0x16, 0x46, 0x3A, 0x51, 0xF6, 0x42, 0x02, 0x1F, 0x56, 0x0E, 0x46, 0x21, 0x16, 0x3A, 0xED, 0x3E, 0x85, 0x23, 0xA9, 0x01, 0xB2, 0xFD, 0xFE, 0x09, 0x3D, 0x13, 0xE0, 0x08, 0x33, 0xE9, 0x54, 0xE4, 0xDB, 0x0B, 0x98, 0x40, 0x7B, 0x65, 0x0E, 0x6A, 0xB9, 0x57, 0x9B, 0x40, 0xB6, 0x24, 0x91, 0xFF, 0x95, 0xEB, 0x4F, 0xEF, 0x1E, 0xE3, 0x26, 0xCC, 0x91, 0xC0, 0xB6, 0xCA, 0xE1, 0xF6, 0x68, 0x1B, 0x1E, 0x17, 0xFC, 0xF9, 0x18, 0xE4, 0x85, 0xF8, 0x1B, 0x28, 0xF5, 0x4C, 0xA1, 0x49, 0xF6, 0x17, 0x33, 0xE9, 0x4D, 0xE1, 0x15, 0xF0, 0x20, 0xF3, 0x2D, 0xE5, 0xDA, 0xE0, 0x41, 0xEC, 0x35, 0xF9, 0xBB, 0xFD, 0x1B, 0x07, 0x61, 0x13, 0x4D, 0x02, 0xFF, 0xE2, 0x50, 0xE3, 0x2C, 0x0B, 0x0E, 0x28, 0x01, 0x08, 0x5C, 0xCA, 0x16, 0xAD, 0x3B, 0xB2, 0x7D, 0xAF, 0x94, 0xAB, 0x5B, 0xC9, 0x84, 0xF6, 0x64, 0x09, 0x18, 0xF2, 0xAF, 0xDE, 0xD7, 0x05, 0x5B, 0x4D, 0x0F, 0x6D, 0xE6, 0x47, 0x8C, 0x0A, 0xA3, 0xDB, 0x0B, 0xBC, 0x1B, 0xA6, 0x72, 0x97, 0x4F, 0x9D, 0x96, 0xA6, 0x49, 0xA7, 0xB9, 0xB9, 0x00, 0xCC, 0xC4, 0xC1, 0xAD, 0xA6, 0x46, 0x99, 0xCA, 0xA3, 0x17, 0xC3, 0x75, 0xD5, 0xDE, 0xC9, 0x48, 0xA7, 0x8C, 0x95, 0x89, 0xA0, 0xCB, 0xBA, 0xA8, 0xE2, 0x96, 0xFC, 0x56, 0xF7, 0x40, 0xEC, 0x8A, 0xEF, 0xB7, 0x03, 0x77, 0x0D, 0xE0, 0xF8, 0x90, 0xE5, 0x92, 0xF1, 0x47, 0x19, 0xB5, 0x44, 0x41, 0x5C, 0x12, 0x5A, 0x22, 0x43, 0xC7, 0x1E, 0xD7, 0x02, 0x0B, 0x09, 0x0B, 0x1D, 0xB4, 0x18, 0x2A, 0xF9, 0xD9, 0xCC, 0x8C, 0xA8, 0x16, 0x9B, 0x64, 0xA2, 0x53, 0xAF, 0xD4, 0xB6, 0x91, 0xC2, 0xD7, 0xCC, 0xAC, 0xCC, 0x6A, 0xD5, 0xBC, 0xEB, 0x5F, 0xFF, 0x05, 0xF8, 0xC6, 0xD1, 0x2F, 0xBD, 0x82, 0xCE, 0xA4, 0xDE, 0xA4, 0xD6, 0x31, 0xC9, 0x07, 0xD7, 0xCA, 0xF9, 0x06, 0x0A, 0x49, 0xFD, 0x27, 0xEE, 0x00, 0xF1, 0x51, 0xF3, 0x1D, 0xE1, 0xB5, 0xCB, 0xB4, 0xD5, 0x77, 0x00, 0x6C, 0x1C, 0xA0, 0x0B, 0xAD, 0xE4, 0x30, 0xD7, 0xAB, 0xF7, 0xEE, 0x21, 0xBC, 0x24, 0xF9, 0xED, 0xC8, 0xA8, 0x3B, 0x9B, 0x54, 0xD0, 0xD3, 0x13, 0xE2, 0x31, 0x3C, 0x2A, 0xAA, 0x1D, 0x9A, 0x24, 0x43, 0x38, 0xDD, 0x3C, 0x6C, 0x22, 0x9C, 0xE6, 0x62, 0xA4, 0x33, 0x82, 0xF3, 0x95, 0x19, 0xD8, 0x42, 0x20, 0xEA, 0x3A, 0xDF, 0x21, 0xDA, 0xF8, 0x70, 0xE6, 0x4D, 0xD9, 0x5C, 0xBF, 0xF9, 0xA2, 0x18, 0x91, 0x16, 0x91, 0xC4, 0x8C, 0x2C, 0x88, 0x14, 0x8F, 0x89, 0x9B, 0x3B, 0xB5, 0x33, 0xD6, 0x08, 0x0B, 0x18, 0x39, 0x7D, 0x30, 0x91, 0xEF, 0x80, 0x9E, 0xF0, 0x84, 0x74, 0x94, 0x58, 0xB0, 0x77, 0xB6, 0xA0, 0xB4, 0x5C, 0xD1, 0xD0, 0xF9, 0x76, 0x03, 0x4C, 0xF9, 0x0C, 0xF3, 0xDE, 0xF6, 0x12, 0xF9, 0x79, 0xE8, 0x10, 0xE0, 0x9A, 0xFB, 0x65, 0x22, 0x84, 0x33, 0x82, 0x26, 0x57, 0x11, 0x2B, 0x05, 0xFA, 0xF6, 0xA8, 0xE8, 0xB4, 0xDF, 0x10, 0xDE, 0x47, 0xE6, 0x53, 0xE9, 0xFB, 0xEA, 0x95, 0xF7, 0x41, 0x05, 0xF5, 0x07, 0xDD, 0xFB, 0xCD, 0xF0, 0x6F, 0xED, 0x7C, 0xEB, 0xAF, 0xEB, 0xC4, 0xE8, 0xB4, 0xF8, 0x6F, 0x23, 0x4F, 0x3E, 0x88, 0x48, 0x9C, 0x5D, 0x8A, 0x6B, 0xED, 0x57, 0x75, 0x2D, 0xFC, 0xFF, 0xB9, 0xDB, 0xD8, 0xD0, 0xE0, 0xD3, 0x11, 0xD1, 0x29, 0xD5, 0x70, 0xF1, 0x96, 0x27, 0x14, 0x52, 0x5C, 0x4F, 0xD5, 0x3D, 0x80, 0x38, 0x95, 0x3B, 0x83, 0x3C, 0x5F, 0x2B, 0x7E, 0x0F, 0x85, 0xFF, 0x85, 0x05, 0xBF, 0x15, 0xED, 0x1A, 0x28, 0x19, 0x4A, 0x1B, 0x13, 0x12, 0x9C, 0xFF, 0x52, 0x04, 0x11, 0x16, 0x9D, 0x16, 0xA6, 0x12, 0xF1, 0x17, 0x81, 0x21, 0xB6, 0x24, 0x17, 0x1B, 0xDA, 0x0C, 0x39, 0x02, 0xDD, 0xF7, 0x27, 0xDE, 0xD3, 0xBC, 0x6B, 0xB6, 0x45, 0xD9, 0xFC, 0x0D, 0xCF, 0x2B, 0xA7, 0x2D, 0xE3, 0x29, 0xED, 0x25, 0xBF, 0x1D, 0x2F, 0x1E, 0x28, 0x3A, 0x77, 0x5A, 0x86, 0x5D, 0x67, 0x5D, 0xDF, 0x5E, 0x2D, 0x5D, 0x8F, 0x42, 0x1D, 0x1F, 0x30, 0x15, 0x75, 0x2A, 0x0D, 0x3E, 0x90, 0x2B, 0x34, 0x06, 0x8E, 0xEE, 0xB9, 0xEA, 0xEC, 0xEE, 0x20, 0xEA, 0xE9, 0xE7, 0x94, 0xF3, 0x12, 0x04, 0x9B, 0x18, 0x02, 0x39, 0xB3, 0x59, 0x71, 0x60, 0x6D, 0x4F, 0x0D, 0x42, 0x29, 0x49, 0x8F, 0x54, 0x47, 0x58, 0x8A, 0x64, 0xD2, 0x6E, 0x2D, 0x65, 0x14, 0x48, 0xAC, 0x2A, 0x0F, 0x1B, 0x7E, 0x1E, 0x3D, 0x27, 0x80, 0x2D, 0xF9, 0x3E, 0xD2, 0x53, 0xBB, 0x61, 0xB6, 0x71, 0xC5, 0x7A, 0x7A, 0x78, 0x41, 0x74, 0x6A, 0x66, 0x04, 0x43, 0x86, 0x1A, 0x6A, 0x05, 0x21, 0x02, 0xCB, 0x02, 0x6D, 0xF7, 0xB4, 0xE6, 0x2B, 0xDF, 0x56, 0xDD, 0x31, 0xDA, 0x26, 0xD2, 0x5B, 0xCC, 0x97, 0xCE, 0x19, 0xD3, 0xD5, 0xD0, 0xF2, 0xD8, 0xEB, 0xFF, 0xF1, 0x32, 0xC6, 0x5F, 0x62, 0x70, 0x0F, 0x7B, 0x74, 0x7C, 0x6B, 0x6E, 0x46, 0x5D, 0xDF, 0x51, 0x3F, 0x55, 0x24, 0x60, 0xF5, 0x54, 0x05, 0x40, 0xC2, 0x31, 0xDD, 0x1F, 0x26, 0x0B, 0x04, 0xFF, 0x26, 0xFB, 0x49, 0xF9, 0x60, 0x04, 0xDD, 0x19, 0xE7, 0x26, 0x84, 0x22, 0x0B, 0x18, 0x1C, 0x1B, 0x70, 0x1F, 0xB0, 0x0C, 0xC9, 0xE5, 0x0C, 0xCA, 0xF9, 0xC6, 0x17, 0xCB, 0xFC, 0xCC, 0x37, 0xC7, 0xEB, 0xC4, 0x75, 0xD7, 0x35, 0xFA, 0x83, 0x13, 0x41, 0x06, 0x51, 0xE6, 0x9F, 0xD7, 0x0F, 0xDB, 0xDC, 0xE1, 0x4F, 0xE0, 0x5E, 0xE3, 0x0B, 0xFE, 0xC6, 0x22, 0xF1, 0x31, 0xE4, 0x24, 0xD9, 0x14, 0x65, 0x22, 0xFA, 0x46, 0x42, 0x50, 0xAD, 0x3B, 0xBB, 0x2D, 0xF0, 0x2A, 0x84, 0x2A, 0xAB, 0x21, 0xB9, 0x12, 0xCB, 0x0E, 0x4D, 0x15, 0x8A, 0x18, 0xD0, 0x15, 0x8A, 0x18, 0xDB, 0x26, 0x4A, 0x3A, 0x3D, 0x40, 0x1E, 0x2C, 0xD7, 0x0C, 0x99, 0xFB, 0xF8, 0x06, 0x4C, 0x19, 0x5E, 0x0A, 0xD2, 0xE9, 0x54, 0xE3, 0x4D, 0xE8, 0xD7, 0xDA, 0x13, 0xCA, 0x85, 0xCD, 0xB5, 0xE6, 0x2D, 0xFB, 0x20, 0xFA, 0x41, 0xFD, 0xDC, 0x0B, 0x82, 0x0D, 0xA1, 0xFF, 0x71, 0xF4, 0x0B, 0xEC, 0x3C, 0xDD, 0x83, 0xDE, 0xCF, 0xF7, 0x0C, 0x0F, 0x4D, 0x1D, 0x89, 0x1B, 0xFC, 0x08, 0xF4, 0xF9, 0xB6, 0xF0, 0x0C, 0xEB, 0x19, 0xEE, 0x9D, 0xF8, 0xFB, 0xFE, 0xC9, 0xFA, 0x92, 0xFA, 0x87, 0x05, 0xB3, 0x12, 0xDA, 0x12, 0x85, 0x0A, 0x78, 0x18, 0xCC, 0x38, 0xE5, 0x4E, 0x83, 0x50, 0x83, 0x3F, 0x4B, 0x26, 0x9B, 0x11, 0xCC, 0x0A, 0x56, 0x0E, 0x06, 0x14, 0xE2, 0x17, 0x8C, 0x18, 0x93, 0x19, 0x1F, 0x1A, 0xA1, 0x1D, 0xE8, 0x1B, 0xCE, 0x06, 0x11, 0xEA, 0x92, 0xD4, 0xAD, 0xDF, 0x3A, 0x13, 0x24, 0x40, 0x2F, 0x46, 0x42, 0x2D, 0x46, 0x0A, 0x96, 0xF2, 0x44, 0xE4, 0x5B, 0xD9, 0xF7, 0xDE, 0x0E, 0xF5, 0x53, 0x05, 0xD5, 0xFC, 0xF0, 0xE3, 0x26, 0xDE, 0x3E, 0xF5, 0x0E, 0x14, 0x00, 0x2C, 0xA9, 0x2F, 0x9E, 0x21, 0x36, 0x16, 0x00, 0x14, 0x4E, 0x16, 0x6A, 0x11, 0x25, 0xF5, 0xB4, 0xCF, 0xB2, 0xC6, 0xDB, 0xD9, 0x6C, 0xEB, 0xF0, 0xF1, 0xBD, 0x00, 0x6A, 0x23, 0x69, 0x37, 0xB7, 0x1D, 0x8A, 0xE6, 0x5D, 0xBF, 0xEE, 0xCA, 0x27, 0xEB, 0x84, 0xF1, 0x53, 0xE1, 0xFA, 0xD2, 0x5F, 0xD4, 0x59, 0xE0, 0x4C, 0xEC, 0x44, 0xF6, 0xE7, 0xFF, 0x7D, 0x07, 0x1B, 0x0B, 0xF9, 0x0F, 0xDE, 0x1D, 0x4C, 0x38, 0x1B, 0x4C, 0xDA, 0x46, 0xC8, 0x2E, 0x14, 0x06, 0xF6, 0xE3, 0x0D, 0xE3, 0xFE, 0xEB, 0x3E, 0xEA, 0x07, 0xE5, 0xA4, 0xE5, 0x26, 0xF5, 0xB8, 0x14, 0x6D, 0x38, 0x26, 0x4F, 0x3F, 0x4C, 0x77, 0x30, 0x6A, 0x0F, 0xE8, 0xF7, 0x89, 0xE6, 0x08, 0xD8, 0x91, 0xD6, 0x32, 0xEF, 0xCC, 0x0C, 0x7A, 0x16, 0x64, 0x10, 0xCF, 0x00, 0xB0, 0xF6, 0x40, 0xF2, 0x8B, 0xE9, 0x3C, 0xE9, 0x8D, 0xEF, 0xBF, 0xEF, 0xDA, 0xE7, 0x8A, 0xDD, 0x4F, 0xD3, 0x38, 0xCB, 0x7A, 0xDC, 0xCE, 0x08, 0xD3, 0x26, 0x13, 0x1F, 0xF2, 0x0A, 0x57, 0xF9, 0xAE, 0xDA, 0xC5, 0xC0, 0x9A, 0xC5, 0xAF, 0xEA, 0xE7, 0x1B, 0x93, 0x2E, 0x39, 0x20, 0x6E, 0x08, 0xDA, 0xF4, 0xF5, 0xF2, 0x91, 0xF0, 0xC2, 0xDF, 0x0B, 0xD3, 0xA0, 0xD7, 0x8D, 0xF1, 0xC6, 0x11, 0x81, 0x20, 0x4E, 0x1B, 0xCD, 0x07, 0x76, 0xEF, 0x29, 0xE4, 0xA8, 0xEA, 0x4E, 0xF3, 0x80, 0xEE, 0x74, 0xE0, 0x15, 0xDC, 0x18, 0xF1, 0x40, 0x17, 0xDA, 0x2B, 0x13, 0x1F, 0x76, 0xFD, 0x66, 0xD5, 0x56, 0xBA, 0x2F, 0xB0, 0x62, 0xA9, 0x75, 0xA4, 0xC8, 0xA3, 0x5A, 0xA8, 0x4E, 0xB6, 0x4A, 0xD1, 0x7D, 0xFD, 0xF2, 0x31, 0x6A, 0x52, 0x3F, 0x50, 0xBF, 0x3A, 0xB6, 0x24, 0x26, 0x13, 0xD4, 0x02, 0x33, 0xFB, 0x60, 0x07, 0x72, 0x13, 0xE5, 0x05, 0x73, 0xED, 0x8D, 0xE8, 0x57, 0xF7, 0xCD, 0x02, 0x19, 0x07, 0x96, 0x0F, 0x17, 0x1B, 0x0A, 0x1D, 0x57, 0x06, 0xD9, 0xE5, 0x39, 0xDE, 0x34, 0xF0, 0xCE, 0x07, 0x1B, 0x10, 0x55, 0xFF, 0x7F, 0xE6, 0x5B, 0xDA, 0xCE, 0xDF, 0xE2, 0xE5, 0x9F, 0xDF, 0x5C, 0xD4, 0xB3, 0xD0, 0xF9, 0xE0, 0xEF, 0xFD, 0x73, 0x16, 0x38, 0x25, 0x5A, 0x2A, 0x94, 0x24, 0x12, 0x16, 0x01, 0x06, 0xDB, 0xF0, 0x3B, 0xDB, 0x46, 0xCC, 0x37, 0xC7, 0xCC, 0xDA, 0x90, 0xF3, 0x41, 0xFC, 0xEB, 0x03, 0xF3, 0x12, 0x30, 0x27, 0xBE, 0x33, 0xD6, 0x2F, 0x33, 0x23, 0x6B, 0x17, 0xC6, 0x10, 0xDC, 0x0E, 0xA4, 0x14, 0x84, 0x1E, 0x6C, 0x22, 0x63, 0x15, 0x0B, 0xF8, 0x57, 0xDD, 0x91, 0xD9, 0xD0, 0xF1, 0x76, 0x08, 0x30, 0x07, 0xA6, 0xFF, 0x1C, 0x04, 0xE9, 0x12, 0xA8, 0x26, 0xDF, 0x42, 0xD2, 0x5C, 0x52, 0x67, 0xA1, 0x5F, 0x11, 0x45, 0x06, 0x1E, 0x5D, 0xEB, 0x5E, 0xC1, 0x6D, 0xB8, 0xE0, 0xC8, 0x88, 0xE1, 0x39, 0xF9, 0x6E, 0x0C, 0x9A, 0x06, 0x1D, 0xE4, 0xBD, 0xB7, 0xEC, 0x9F, 0x48, 0xAE, 0x74, 0xB6, 0xBA, 0xBF, 0xAF, 0xCD, 0x8B, 0xDE, 0x9C, 0xF6, 0x5F, 0x08, 0x8D, 0x04, 0x55, 0xFD, 0x9E, 0x0D, 0x16, 0x2F, 0xDF, 0x43, 0x9B, 0x53, 0xD8, 0x5A, 0x37, 0x49, 0x21, 0x32, 0x83, 0x21, 0x81, 0x14, 0x07, 0xFE, 0x3B, 0xDF, 0x80, 0xD1, 0xF6, 0xD2, 0x71, 0xCD, 0x0D, 0xC8, 0x80, 0xE3, 0xB9, 0x14, 0xDD, 0x27, 0x7A, 0x0C, 0xA1, 0xE1, 0xF8, 0xD1, 0xB2, 0xE0, 0x19, 0xE6, 0x37, 0xDD, 0x13, 0xEB, 0x37, 0x07, 0x9F, 0x0E, 0x97, 0x08, 0x75, 0x09, 0x10, 0x0C, 0x18, 0xF8, 0x42, 0xDA, 0x11, 0xE2, 0xC7, 0x10, 0x3F, 0x3C, 0x03, 0x46, 0x22, 0x39, 0x54, 0x2D, 0xFB, 0x26, 0xC4, 0x2B, 0x2F, 0x3E, 0xF0, 0x4C, 0xB2, 0x3B, 0xE4, 0x0F, 0x3C, 0xF7, 0x37, 0x08, 0x61, 0x2A, 0x78, 0x36, 0x35, 0x2F, 0x92, 0x31, 0x1A, 0x35, 0xC1, 0x2A, 0xC8, 0x20, 0x41, 0x21, 0x92, 0x1B, 0x58, 0x01, 0xD2, 0xDB, 0x3D, 0xBE, 0x67, 0xB7, 0xE1, 0xC0, 0xBC, 0xCC, 0x07, 0xDF, 0x67, 0xF6, 0x67, 0x00, 0xB7, 0xFE, 0xF3, 0x07, 0x6E, 0x1C, 0x46, 0x28, 0xE1, 0x29, 0x7D, 0x33, 0x26, 0x46, 0x60, 0x48, 0x70, 0x2E, 0x56, 0x16, 0x59, 0x1C, 0xDD, 0x2D, 0x79, 0x2E, 0x30, 0x19, 0xD2, 0xFB, 0x6C, 0xE1, 0x49, 0xC6, 0x52, 0xB9, 0x77, 0xC7, 0x0D, 0xDC, 0xC5, 0xE7, 0xE6, 0xF4, 0x39, 0x0B, 0x04, 0x13, 0x79, 0xF3, 0x41, 0xC3, 0x59, 0xB5, 0x6E, 0xD3, 0xC4, 0xF3, 0xE9, 0xFD, 0x1B, 0x01, 0xC2, 0x10, 0x13, 0x1F, 0xAC, 0x14, 0xD3, 0xFA, 0x6A, 0xE0, 0x81, 0xCD, 0xA5, 0xC0, 0x97, 0xB5, 0xE0, 0xB6, 0xF3, 0xC2, 0xD9, 0xD3, 0x06, 0xE6, 0xEC, 0xEF, 0x87, 0xFB, 0xB1, 0x16, 0x5D, 0x3C, 0xFC, 0x5E, 0xAE, 0x6D, 0x02, 0x68, 0x59, 0x63, 0x55, 0x6C, 0xF9, 0x74, 0xFE, 0x5E, 0xC7, 0x27, 0x16, 0xF5, 0xF5, 0xDC, 0xB5, 0xD4, 0x68, 0xD1, 0x41, 0xD0, 0x32, 0xD4, 0x0B, 0xEB, 0x62, 0x10, 0x55, 0x20, 0x2B, 0x0B, 0x36, 0xEA, 0xAE, 0xE0, 0x37, 0xF2, 0x61, 0x03, 0x85, 0xFF, 0x96, 0xE6, 0xA9, 0xCC, 0x99, 0xC1, 0x48, 0xCA, 0xD8, 0xDF, 0x73, 0xEF, 0xEA, 0xF5, 0xC4, 0xF8, 0x38, 0x00, 0x5A, 0x04, 0x78, 0xF8, 0x0D, 0xEB, 0x39, 0xE6, 0xCB, 0xEE, 0x44, 0xF3, 0x50, 0xE2, 0x50, 0xD5, 0x55, 0xD8, 0xBD, 0xE3, 0x23, 0xED, 0xA7, 0xF5, 0xDB, 0x08, 0x33, 0x17, 0xDF, 0x0E, 0x0C, 0xF1, 0xCF, 0xD4, 0x16, 0xD0, 0x25, 0xD6, 0xB6, 0xDB, 0x4D, 0xE6, 0x2D, 0xF5, 0x96, 0x02, 0xFB, 0x06, 0xB8, 0x01, 0xD3, 0x00, 0x46, 0x06, 0x74, 0x08, 0xA0, 0x01, 0x6A, 0xF2, 0x09, 0xF2, 0xA0, 0x0E, 0x2C, 0x3F, 0x31, 0x72, 0xFF, 0x7F, 0xFF, 0x7F, 0x72, 0x71, 0x15, 0x4F, 0x6F, 0x4A, 0x45, 0x57, 0x9D, 0x55, 0x34, 0x39, 0xFA, 0x1B, 0x8B, 0x1B, 0x54, 0x36, 0xE0, 0x4B, 0x1A, 0x3A, 0xF6, 0x12, 0x5A, 0xFF, 0x7A, 0x02, 0xF4, 0x01, 0x87, 0xFA, 0x53, 0xFE, 0xE3, 0x02, 0xF9, 0xF3, 0x83, 0xDB, 0x4F, 0xDD, 0x07, 0x09, 0xC2, 0x42, 0x19, 0x62, 0xB1, 0x55, 0xAF, 0x34, 0x2B, 0x14, 0x9D, 0xF3, 0xF1, 0xDD, 0x02, 0xDD, 0xBC, 0xE2, 0x1C, 0xDF, 0x01, 0xDD, 0x9B, 0xE9, 0xE8, 0xFA, 0xDE, 0x01, 0x52, 0x00, 0x5C, 0x08, 0xC2, 0x1E, 0x87, 0x32, 0xD5, 0x2F, 0x3B, 0x18, 0x2F, 0x03, 0xD4, 0xF5, 0xC9, 0xE5, 0x18, 0xDB, 0xD8, 0xDB, 0x85, 0xE1, 0xFA, 0xEF, 0xC1, 0xFD, 0x42, 0xF8, 0xA5, 0xEC, 0x62, 0xEF, 0x44, 0xFF, 0xF2, 0x0B, 0x7B, 0x0F, 0x83, 0x11, 0x66, 0x12, 0xD4, 0x12, 0xD7, 0x0B, 0xA9, 0xF6, 0xD7, 0xE5, 0xBD, 0xEC, 0x5B, 0xFF, 0x4C, 0x01, 0xD2, 0xF1, 0x20, 0xE2, 0x55, 0xDF, 0x63, 0xF1, 0xBE, 0x0B, 0x1D, 0x1F, 0xDD, 0x21, 0xDF, 0x12, 0xF4, 0x01, 0xC7, 0xEB, 0x91, 0xCA, 0x78, 0xB2, 0xB0, 0xAB, 0x47, 0xBA, 0xA1, 0xE5, 0x7B, 0x1A, 0xAC, 0x3B, 0x24, 0x3E, 0x15, 0x31, 0xA5, 0x21, 0x9E, 0x06, 0x93, 0xE5, 0xC6, 0xD8, 0x35, 0xED, 0x08, 0x0F, 0xCD, 0x1C, 0xB5, 0x05, 0xB6, 0xD6, 0x47, 0xB5, 0x47, 0xB0, 0x4A, 0xBA, 0x9D, 0xC8, 0x72, 0xD8, 0x19, 0xED, 0x26, 0xFF, 0x61, 0x09, 0x19, 0x0D, 0xB1, 0x06, 0xFB, 0xFC, 0x5D, 0xF8, 0x73, 0xFF, 0xBB, 0x0B, 0x47, 0x06, 0xDF, 0xEE, 0x73, 0xD7, 0x7F, 0xCE, 0x32, 0xDD, 0x52, 0xF8, 0x65, 0x0C, 0xE5, 0x14, 0xCB, 0x12, 0xD9, 0x0F, 0x7D, 0x17, 0x6E, 0x23, 0x4C, 0x27, 0x26, 0x14, 0x74, 0xEF, 0xE6, 0xD9, 0x57, 0xE1, 0xBC, 0xF7, 0xD3, 0x0D, 0x18, 0x1F, 0xF1, 0x24, 0x85, 0x1E, 0xA1, 0x10, 0x53, 0xF8, 0x44, 0xE3, 0x2C, 0xE3, 0xF6, 0xFB, 0x65, 0x23, 0xF9, 0x37, 0x70, 0x25, 0x19, 0xFE, 0xF8, 0xE7, 0x7D, 0xF5, 0x16, 0x11, 0xC2, 0x1A, 0x31, 0x08, 0xCA, 0xF0, 0x98, 0xEE, 0xA1, 0xFF, 0xC3, 0x0F, 0x5A, 0x06, 0x02, 0xE8, 0x9E, 0xD7, 0xF2, 0xE1, 0x89, 0xF2, 0x88, 0xF7, 0x95, 0xF9, 0x0A, 0x09, 0x56, 0x26, 0xB8, 0x40, 0xD7, 0x41, 0x55, 0x22, 0xE0, 0xEF, 0x86, 0xC8, 0x95, 0xC0, 0x76, 0xCD, 0x8A, 0xE2, 0x02, 0xFB, 0x07, 0x10, 0xDB, 0x26, 0xF6, 0x45, 0xE8, 0x5E, 0x7A, 0x5C, 0x51, 0x38, 0xE0, 0x0D, 0x1D, 0xFB, 0x6E, 0xF0, 0x89, 0xE2, 0xD5, 0xDE, 0x7A, 0xF4, 0x0B, 0x23, 0xC6, 0x35, 0xE9, 0x0F, 0xBF, 0xD1, 0x0F, 0xA5, 0x2C, 0xAC, 0x84, 0xCE, 0x2F, 0xD6, 0xDE, 0xB8, 0x33, 0xA3, 0xDA, 0xC2, 0x6E, 0xF8, 0xCB, 0x0D, 0x99, 0xF7, 0x51, 0xD6, 0xE7, 0xD0, 0x3E, 0xE1, 0x41, 0xFD, 0x4D, 0x26, 0xDC, 0x47, 0x24, 0x4C, 0x6D, 0x3A, 0xB8, 0x26, 0x25, 0x14, 0x8F, 0xFA, 0x70, 0xE2, 0xD4, 0xE9, 0xB5, 0x0E, 0x7B, 0x2B, 0x63, 0x28, 0x5E, 0x09, 0x0D, 0xEF, 0x5D, 0xEF, 0xB9, 0xFF, 0x60, 0x05, 0xCC, 0xF3, 0x1B, 0xE2, 0x08, 0xE0, 0x1B, 0xE7, 0xDB, 0xEC, 0xF6, 0xED, 0xAD, 0xF4, 0x09, 0x02, 0x69, 0x03, 0xF3, 0xEE, 0xE5, 0xDE, 0xF2, 0xE5, 0x9F, 0xF1, 0x9C, 0xF4, 0xE0, 0xF6, 0xD3, 0x00, 0x99, 0x07, 0xD3, 0x02, 0x49, 0xF8, 0x21, 0xEA, 0x1D, 0xDC, 0x4E, 0xD3, 0x19, 0xDB, 0x13, 0xF4, 0x90, 0x05, 0xED, 0x01, 0x4A, 0xE8, 0x38, 0xC8, 0x4E, 0xBD, 0x51, 0xC2, 0xDA, 0xCE, 0xF8, 0xE7, 0x48, 0x02, 0xD2, 0x13, 0x92, 0x16, 0xF2, 0x0E, 0x13, 0x0D, 0x72, 0x11, 0xCF, 0x17, 0x25, 0x1B, 0x21, 0x1A, 0xCC, 0x1B, 0x44, 0x1E, 0x5F, 0x16, 0xD8, 0x00, 0x50, 0xF7, 0x93, 0x0C, 0x81, 0x29, 0x92, 0x38, 0x6E, 0x41, 0x03, 0x49, 0xB5, 0x3F, 0xED, 0x24, 0xF8, 0x0D, 0x7A, 0x07, 0xF9, 0x0F, 0x40, 0x1B, 0xD3, 0x1E, 0x08, 0x1F, 0xA5, 0x1D, 0x42, 0x10, 0x2F, 0xF5, 0xD1, 0xD5, 0x81, 0xC1, 0xC4, 0xBC, 0x0E, 0xC2, 0x23, 0xDA, 0xF4, 0xFA, 0xB7, 0x14, 0xE3, 0x1D, 0x19, 0x0B, 0xA4, 0xF4, 0xD5, 0xED, 0xA3, 0xE9, 0xBA, 0xC2, 0xEB, 0x93, 0x20, 0xAA, 0x1B, 0xCC, 0xE3, 0xD7, 0xDD, 0xF9, 0x6F, 0x0D, 0xF3, 0x12, 0x6D, 0x15, 0x61, 0x03, 0xEE, 0xED, 0x1C, 0xD2, 0xB2, 0xC2, 0xAE, 0xCF, 0x67, 0xE2, 0x8A, 0xFF, 0x7C, 0x22, 0xEC, 0x2C, 0x60, 0x1A, 0x5C, 0x00, 0x2E, 0xEC, 0xC0, 0xE0, 0x27, 0xE1, 0xE8, 0xEF, 0x1F, 0x0F, 0xE3, 0x32, 0xB1, 0x4D, 0xCC, 0x56, 0x23, 0x4B, 0x89, 0x3B, 0x65, 0x28, 0xB7, 0x0A, 0x54, 0xF0, 0xB3, 0xE5, 0x6F, 0xF3, 0x77, 0x0C, 0xA4, 0x21, 0x6E, 0x2D, 0x0C, 0x23, 0x1E, 0x12, 0x07, 0xFC, 0x8E, 0xD6, 0x3D, 0xBA, 0x57, 0xAA, 0xB6, 0xA5, 0x16, 0xB6, 0x8D, 0xD7, 0x87, 0xFF, 0xD1, 0x1B, 0x37, 0x28, 0x53, 0x22, 0xC7, 0x06, 0x7E, 0xE0, 0xF8, 0xC5, 0xE7, 0xC4, 0xF9, 0xBC, 0x71, 0xA3, 0xEA, 0x9D, 0x34, 0xB9, 0xAF, 0xE3, 0xB7, 0x01, 0xCE, 0x06, 0x4E, 0xF8, 0x26, 0xE2, 0x45, 0xD8, 0x89, 0xDD, 0xDB, 0xDC, 0xD3, 0xC9, 0x27, 0xB9, 0xB9, 0xBB, 0x2F, 0xC7, 0x46, 0xCF, 0xD4, 0xCE, 0xA1, 0xD2, 0xE4, 0xE0, 0xC7, 0xEB, 0xC2, 0xF2, 0xD2, 0xFB, 0x48, 0x08, 0x16, 0x15, 0x81, 0x23, 0xD2, 0x36, 0x26, 0x3C, 0x31, 0x2B, 0x30, 0x14, 0xF3, 0xFD, 0xAB, 0xEA, 0xCD, 0xD7, 0xD8, 0xBE, 0xC3, 0xA9, 0x07, 0xAB, 0x1E, 0xC5, 0xF9, 0xE8, 0x2F, 0x0C, 0x71, 0x2B, 0xC6, 0x3C, 0x09, 0x39, 0x4E, 0x24, 0x51, 0x04, 0x4C, 0xE1, 0x26, 0xCB, 0xC9, 0xCD, 0x69, 0xE3, 0xEE, 0xF9, 0xBE, 0x09, 0x02, 0x16, 0x89, 0x1B, 0x72, 0x17, 0xE5, 0x0F, 0xE6, 0x0B, 0x1D, 0x05, 0xEE, 0xF6, 0xFA, 0xEB, 0xB2, 0xE5, 0xF4, 0xE5, 0x03, 0xF3, 0x74, 0x04, 0xB6, 0x10, 0x5C, 0x0E, 0x4B, 0xF9, 0x99, 0xDF, 0x58, 0xD6, 0x2A, 0xE8, 0x12, 0x0D, 0xE3, 0x27, 0x96, 0x16, 0x3C, 0xED, 0xF1, 0xE0, 0xE0, 0xEF, 0xE3, 0xFE, 0x65, 0x09, 0x53, 0x0B, 0x79, 0x00, 0x5A, 0xEB, 0xF7, 0xD5, 0xFA, 0xD2, 0xC2, 0xE6, 0x40, 0xFE, 0xA9, 0x0C, 0x72, 0x19, 0x37, 0x22, 0xC6, 0x1C, 0x7B, 0x18, 0x3B, 0x22, 0x54, 0x2F, 0x09, 0x31, 0xAD, 0x19, 0x6A, 0xF4, 0x2A, 0xDF, 0xAF, 0xE0, 0xAD, 0xEA, 0x90, 0xF4, 0xE6, 0x05, 0xD8, 0x18, 0xE6, 0x15, 0xE4, 0x07, 0x61, 0x05, 0x5B, 0x00, 0xC1, 0xF5, 0x05, 0xF5, 0xE1, 0xF8, 0xB6, 0xFD, 0x1B, 0x08, 0xDC, 0x18, 0xDB, 0x25, 0x7D, 0x21, 0x93, 0x14, 0xD2, 0x0B, 0xB6, 0x0B, 0x5E, 0x10, 0x94, 0x0D, 0x86, 0xFF, 0x6C, 0xE7, 0x96, 0xD3, 0x0D, 0xD7, 0xCA, 0xEC, 0x88, 0xFD, 0xF7, 0xFA, 0x95, 0xED, 0x7E, 0xEB, 0xAF, 0xFD, 0x9D, 0x02, 0x2E, 0xE6, 0xF4, 0xCD, 0xF9, 0xD4, 0xDC, 0xEE, 0x79, 0x01, 0xF4, 0x07, 0x55, 0x10, 0x09, 0x13, 0x61, 0x01, 0x90, 0xDF, 0xDC, 0xC5, 0x72, 0xC0, 0xFA, 0xC0, 0xD6, 0xC5, 0x20, 0xD2, 0x56, 0xDB, 0x69, 0xE0, 0xF1, 0xE8, 0x94, 0xF7, 0xEC, 0x0B, 0xEC, 0x1D, 0xDA, 0x22, 0xDC, 0x19, 0x88, 0x09, 0xFE, 0x01, 0xE2, 0x06, 0xBC, 0x06, 0x0C, 0x03, 0xA1, 0x04, 0x13, 0x07, 0xEC, 0x0E, 0x19, 0x1A, 0x41, 0x20, 0xAB, 0x25, 0x91, 0x21, 0x36, 0x0F, 0xD2, 0xF8, 0xD7, 0xE3, 0x3D, 0xDA, 0xF1, 0xD7, 0x40, 0xD6, 0x08, 0xD7, 0x8B, 0xD6, 0x8E, 0xDE, 0x65, 0xEB, 0xB5, 0xF1, 0xB4, 0xF8, 0xE2, 0xFD, 0xC4, 0xFD, 0x2D, 0xFA, 0x39, 0xF4, 0x78, 0xED, 0x27, 0xE5, 0xBF, 0xDD, 0x47, 0xDB, 0x4D, 0xDD, 0x9D, 0xDE, 0x97, 0xE2, 0xD1, 0xE3, 0x85, 0xD7, 0x24, 0xD0, 0x6A, 0xD9, 0xA6, 0xE5, 0x29, 0xE9, 0x06, 0xE7, 0x74, 0xE9, 0x87, 0xED, 0x95, 0xEE, 0xC8, 0xE9, 0xA5, 0xE0, 0xAE, 0xE4, 0xE7, 0xF7, 0x39, 0x0D, 0x18, 0x27, 0x19, 0x41, 0x3D, 0x49, 0x01, 0x3E, 0x95, 0x29, 0x90, 0x13, 0x86, 0x03, 0xB3, 0xFD, 0x26, 0xFB, 0xD9, 0xFA, 0x5E, 0x06, 0xDE, 0x17, 0xCC, 0x28, 0x6C, 0x32, 0x7E, 0x31, 0x55, 0x34, 0x95, 0x30, 0x5D, 0x1D, 0x27, 0x06, 0xF1, 0xEF, 0x1A, 0xE9, 0x07, 0xF1, 0xF0, 0xFA, 0xA0, 0x01, 0x80, 0xFF, 0xA9, 0xF0, 0x26, 0xD5, 0x86, 0xC6, 0x7B, 0xD2, 0x4D, 0xE6, 0xB3, 0xFA, 0x58, 0x0F, 0x62, 0x1D, 0xC2, 0x17, 0xF9, 0x01, 0x9E, 0xEB, 0x06, 0xDA, 0xA4, 0xDC, 0x80, 0xF5, 0x8A, 0x09, 0x13, 0x03, 0x0B, 0xF0, 0xC6, 0xF1, 0xC1, 0xFE, 0x8A, 0x00, 0xBE, 0x06, 0xB6, 0x16, 0x9C, 0x1D, 0xB9, 0x14, 0x52, 0x03, 0x92, 0xF7, 0xAE, 0x03, 0x45, 0x25, 0xCE, 0x3B, 0x3C, 0x33, 0xC1, 0x16, 0x10, 0xF5, 0x63, 0xDC, 0x18, 0xD5, 0x3A, 0xD9, 0x0C, 0xE3, 0x26, 0xEE, 0x2F, 0xFA, 0x69, 0x06, 0x9A, 0x0F, 0xD9, 0x1A, 0x2B, 0x22, 0xD9, 0x15, 0x42, 0xF5, 0x5B, 0xDC, 0x50, 0xE9, 0x44, 0x09, 0xD3, 0x20, 0x5C, 0x33, 0x49, 0x3E, 0x7F, 0x3B, 0x1A, 0x31, 0xCA, 0x26, 0x10, 0x22, 0xF2, 0x23, 0x87, 0x21, 0x58, 0x10, 0x23, 0xFA, 0xE3, 0xEA, 0xC8, 0xE2, 0x00, 0xE2, 0x51, 0xE6, 0x5E, 0xEC, 0x86, 0xF6, 0x02, 0x09, 0x2F, 0x27, 0xB3, 0x45, 0x5F, 0x54, 0x19, 0x57, 0xCA, 0x51, 0xD4, 0x45, 0xAE, 0x37, 0x0E, 0x22, 0xB5, 0x07, 0x29, 0xF5, 0x8C, 0xF8, 0x66, 0x0F, 0x34, 0x21, 0xA4, 0x26, 0xF4, 0x24, 0x1C, 0x1C, 0x04, 0x0F, 0xBC, 0x05, 0x94, 0x02, 0x9A, 0x02, 0xE4, 0x0B, 0xE4, 0x14, 0x7B, 0x0E, 0x41, 0xFC, 0xF3, 0xE7, 0xC6, 0xE4, 0x6E, 0xF3, 0x46, 0x03, 0x13, 0x0C, 0x72, 0x07, 0xAE, 0xFD, 0x3A, 0xF9, 0x5E, 0xF7, 0xFB, 0xF4, 0x92, 0xFB, 0x2A, 0x13, 0x5C, 0x2A, 0x0C, 0x35, 0xCD, 0x30, 0x52, 0x1D, 0xA5, 0x06, 0x4E, 0xE9, 0x80, 0xC8, 0x42, 0xBB, 0x6D, 0xC9, 0x5C, 0xEC, 0x2C, 0x0C, 0x36, 0x15, 0x63, 0x12, 0xF5, 0x12, 0x7E, 0x16, 0x4B, 0x11, 0x69, 0x00, 0x8C, 0xF1, 0x76, 0xF1, 0xF3, 0xFA, 0x15, 0xFE, 0x31, 0xFD, 0x71, 0x02, 0x44, 0x0C, 0x6A, 0x14, 0xA9, 0x13, 0x4A, 0x10, 0x23, 0x0F, 0x04, 0x07, 0xB0, 0x00, 0xC2, 0x06, 0x79, 0x08, 0xFF, 0xF8, 0xDE, 0xEC, 0xEA, 0xFA, 0x80, 0x13, 0xDF, 0x1E, 0x60, 0x1F, 0x41, 0x16, 0x9A, 0xFF, 0x41, 0xED, 0x74, 0xEC, 0x99, 0xED, 0xBA, 0xEC, 0x56, 0xF9, 0x6B, 0x0C, 0xA7, 0x11, 0x29, 0x07, 0xCF, 0xF5, 0x5A, 0xE4, 0x06, 0xD0, 0x58, 0xBC, 0xE7, 0xBD, 0x42, 0xD2, 0x35, 0xE6, 0x34, 0xF3, 0xE1, 0xF3, 0x64, 0xEC, 0x47, 0xEA, 0x74, 0xF1, 0xA2, 0xF6, 0x7D, 0xF3, 0x5F, 0xEC, 0xD1, 0xDB, 0xCE, 0xC9, 0xCA, 0xC1, 0xCE, 0xBD, 0xD1, 0xC2, 0xE7, 0xD3, 0x2A, 0xEA, 0x6B, 0xF6, 0xE8, 0xEE, 0xD1, 0xE3, 0xB4, 0xE0, 0x14, 0xED, 0x2D, 0x08, 0x3C, 0x1C, 0x0A, 0x1C, 0x9D, 0x08, 0x16, 0xF9, 0xE2, 0x00, 0x78, 0x12, 0x51, 0x1D, 0x1D, 0x13, 0xE3, 0xFA, 0x09, 0xF2, 0x01, 0xFB, 0x88, 0x08, 0xEB, 0x15, 0x25, 0x1E, 0xF8, 0x1A, 0xC5, 0x11, 0x01, 0x12, 0x95, 0x18, 0x1C, 0x19, 0x9C, 0x15, 0x28, 0x14, 0x8C, 0x16, 0x0A, 0x16, 0xF2, 0x0B, 0xB5, 0xF9, 0x8A, 0xE7, 0x8A, 0xE2, 0x97, 0xEF, 0xD6, 0x06, 0x26, 0x1A, 0xA5, 0x23, 0xDB, 0x21, 0xD7, 0x15, 0x6F, 0x0B, 0x1C, 0x06, 0xA1, 0x07, 0x6D, 0x04, 0x93, 0xEB, 0x6D, 0xD5, 0x72, 0xD4, 0x89, 0xE1, 0x4A, 0xF6, 0x31, 0x08, 0x94, 0x10, 0x49, 0x07, 0xCF, 0xF2, 0x8D, 0xE5, 0xD5, 0xE3, 0x0A, 0xEF, 0x03, 0xFC, 0xF3, 0xFC, 0xD7, 0xF9, 0xD5, 0xF6, 0xDB, 0xF1, 0x1D, 0xF3, 0x18, 0xF6, 0xC5, 0xF3, 0x87, 0xF2, 0x49, 0xED, 0x85, 0xE1, 0xAA, 0xD8, 0xB0, 0xD9, 0xD4, 0xE0, 0xA9, 0xE9, 0x09, 0xFB, 0x9D, 0x07, 0x35, 0x02, 0x87, 0xF5, 0x04, 0xEF, 0x12, 0xF7, 0x95, 0xFC, 0xEF, 0xF5, 0x58, 0xF0, 0xB2, 0xF0, 0x02, 0xF4, 0xAC, 0xF0, 0x17, 0xF0, 0x79, 0xFE, 0x30, 0x12, 0x20, 0x25, 0x93, 0x29, 0x5B, 0x13, 0x63, 0xF4, 0xFD, 0xE5, 0xB4, 0xEB, 0x83, 0xF9, 0x38, 0x02, 0x86, 0xFE, 0xE8, 0xF2, 0xEA, 0xEB, 0xFC, 0xF1, 0xBB, 0xFA, 0xA6, 0xFE, 0x6A, 0x03, 0x6C, 0x05, 0x97, 0x03, 0x35, 0x00, 0xCA, 0xFE, 0xA6, 0x02, 0x39, 0x00, 0x46, 0xF7, 0x7F, 0xF7, 0x76, 0xFE, 0xFA, 0x00, 0xC8, 0xFE, 0x13, 0xFA, 0x29, 0xF3, 0x97, 0xE4, 0xE5, 0xD4, 0x0D, 0xD6, 0x07, 0xE3, 0xD9, 0xF5, 0x5F, 0x0A, 0xEF, 0x19, 0xBC, 0x2D, 0x99, 0x40, 0x34, 0x40, 0x49, 0x25, 0x30, 0x03, 0x7E, 0xF3, 0xE9, 0xF6, 0x2C, 0x0C, 0x3E, 0x22, 0x9C, 0x22, 0x28, 0x15, 0xB8, 0x0B, 0x9A, 0x14, 0x61, 0x2F, 0xEF, 0x46, 0x76, 0x44, 0xAF, 0x2F, 0xBC, 0x22, 0x86, 0x1F, 0x53, 0x12, 0xA9, 0xF1, 0x44, 0xCE, 0xC9, 0xB8, 0x15, 0xBD, 0xEC, 0xD6, 0xF6, 0xE8, 0xA9, 0xE8, 0x97, 0xDE, 0x0C, 0xDE, 0x4D, 0xEA, 0x18, 0xF0, 0x1C, 0xF1, 0x3F, 0xED, 0x71, 0xE2, 0xD6, 0xD6, 0x4C, 0xD1, 0x39, 0xD9, 0xB3, 0xE1, 0x5F, 0xE7, 0x75, 0xF0, 0xA5, 0xF2, 0x7A, 0xEC, 0x20, 0xE4, 0xD7, 0xDE, 0xC2, 0xDF, 0xC7, 0xDB, 0x95, 0xCD, 0x6E, 0xC7, 0x45, 0xD5, 0x24, 0xF3, 0xA5, 0x14, 0xB2, 0x26, 0x50, 0x28, 0x8A, 0x21, 0x10, 0x13, 0x1D, 0xFC, 0x5F, 0xDB, 0x7F, 0xBB, 0x64, 0xA8, 0x4D, 0x9E, 0x35, 0xA5, 0xB4, 0xB2, 0x4B, 0xD5, 0x16, 0xF7, 0x07, 0x02, 0x68, 0xEE, 0xAE, 0xDD, 0x6B, 0xE1, 0xC9, 0xEF, 0xAE, 0xFC, 0x0F, 0xFC, 0xA4, 0xFD, 0x58, 0x0C, 0xCA, 0x1C, 0x4F, 0x27, 0xEF, 0x2C, 0x5B, 0x33, 0x7C, 0x2F, 0xB5, 0x1F, 0x26, 0x13, 0x23, 0x08, 0x32, 0xFD, 0x1A, 0xFA, 0xF7, 0xFE, 0xCF, 0x09, 0x77, 0x20, 0x6C, 0x39, 0xCD, 0x3F, 0xB8, 0x31, 0x9A, 0x1E, 0xD0, 0x16, 0x40, 0x14, 0x1D, 0x0B, 0x5E, 0x03, 0x70, 0x08, 0x58, 0x19, 0x59, 0x24, 0xB1, 0x1F, 0x31, 0x19, 0x73, 0x1C, 0x9B, 0x20, 0xA8, 0x1B, 0x37, 0x12, 0x88, 0x0A, 0xC7, 0x08, 0xD6, 0x07, 0x50, 0xFD, 0x8F, 0xEA, 0x03, 0xDC, 0xB1, 0xE2, 0x71, 0xFB, 0x9B, 0x0C, 0xFD, 0x07, 0x22, 0xF8, 0x72, 0xEA, 0x69, 0xDE, 0x5F, 0xD2, 0xA8, 0xC6, 0x20, 0xBE, 0xE1, 0xBF, 0x7F, 0xC9, 0x80, 0xD0, 0x67, 0xD5, 0x34, 0xDE, 0x7E, 0xE4, 0x40, 0xE3, 0x05, 0xDA, 0x43, 0xC9, 0xDB, 0xB5, 0x71, 0xA5, 0xE4, 0xA5, 0xD6, 0xBB, 0xFD, 0xDF, 0xA3, 0x05, 0xE9, 0x13, 0xB8, 0x08, 0x0F, 0x00, 0x0D, 0x0C, 0xC8, 0x1B, 0xDE, 0x1A, 0x20, 0x0D, 0x31, 0xF8, 0x77, 0xEB, 0xDD, 0xF3, 0x51, 0x0C, 0xD7, 0x28, 0x3E, 0x36, 0xE3, 0x3A, 0xD2, 0x46, 0x28, 0x53, 0x72, 0x58, 0x4B, 0x53, 0xFC, 0x3F, 0x21, 0x1E, 0x48, 0x00, 0xFE, 0xFA, 0xBC, 0x09, 0x9A, 0x1F, 0x11, 0x2B, 0x94, 0x22, 0xF2, 0x0E, 0x24, 0xFE, 0x36, 0xFC, 0x6B, 0x0C, 0xCD, 0x28, 0x02, 0x3B, 0xD7, 0x37, 0x49, 0x30, 0x4B, 0x28, 0x45, 0x1C, 0x8C, 0x0E, 0xBD, 0x00, 0xB8, 0xF6, 0xAB, 0xEA, 0xB2, 0xDA, 0xF3, 0xD0, 0xF1, 0xD0, 0xB6, 0xD7, 0xC5, 0xE1, 0x53, 0xEB, 0x23, 0xF4, 0x82, 0xFF, 0x1A, 0x07, 0x9D, 0x01, 0x05, 0xF2, 0x77, 0xDE, 0x73, 0xC6, 0x56, 0xAD, 0xBC, 0xA7, 0x5C, 0xB9, 0xC6, 0xCD, 0x71, 0xE4, 0xC5, 0x00, 0xAD, 0x15, 0x48, 0x1B, 0x92, 0x18, 0x3A, 0x16, 0x86, 0x13, 0x32, 0x0B, 0xA7, 0xF8, 0x78, 0xE7, 0xC3, 0xE6, 0x2A, 0xF6, 0xE8, 0x0C, 0x46, 0x18, 0x5B, 0x18, 0xB1, 0x18, 0x1F, 0x11, 0xC4, 0x00, 0x5C, 0xF1, 0x7C, 0xEC, 0x0F, 0xF4, 0x5B, 0xFE, 0xAF, 0x07, 0x02, 0x0F, 0x15, 0x13, 0xA7, 0x15, 0xEF, 0x16, 0x8E, 0x15, 0xED, 0x0D, 0x0E, 0x03, 0x5F, 0x03, 0xA5, 0x15, 0x6E, 0x2E, 0x76, 0x3E, 0x52, 0x3E, 0x7E, 0x32, 0x55, 0x20, 0xFE, 0x08, 0xCF, 0xF5, 0x53, 0xE7, 0xD1, 0xD6, 0x47, 0xCD, 0x09, 0xD7, 0xEB, 0xF5, 0x0F, 0x19, 0x72, 0x29, 0x64, 0x1F, 0x5F, 0x0E, 0x67, 0x17, 0x24, 0x2F, 0xAF, 0x37, 0xBD, 0x33, 0x30, 0x22, 0xD6, 0x05, 0x49, 0xEE, 0xC9, 0xDE, 0x25, 0xDB, 0x38, 0xE0, 0xDC, 0xE6, 0x2C, 0xF4, 0xFC, 0x06, 0x52, 0x17, 0xC9, 0x22, 0x75, 0x29, 0x18, 0x28, 0xFC, 0x1D, 0xC7, 0x0C, 0xA3, 0xF1, 0x84, 0xD6, 0x95, 0xCE, 0xFD, 0xD7, 0x5D, 0xDE, 0xB9, 0xD9, 0x6E, 0xD7, 0x17, 0xDE, 0x2B, 0xE5, 0xDB, 0xE6, 0xAC, 0xE9, 0x84, 0xF5, 0x15, 0xFE, 0x10, 0xF7, 0x47, 0xEA, 0x40, 0xE3, 0x5A, 0xE6, 0x0F, 0xF4, 0x63, 0x06, 0xBC, 0x13, 0x1B, 0x15, 0x26, 0x0B, 0x5A, 0x01, 0x9E, 0xFD, 0xF5, 0xF7, 0xCC, 0xEF, 0x65, 0xE9, 0x67, 0xE5, 0xB7, 0xE5, 0x8D, 0xEF, 0x11, 0x06, 0x29, 0x19, 0x8A, 0x1F, 0x91, 0x25, 0xFD, 0x29, 0x51, 0x21, 0xB9, 0x0F, 0xE6, 0x03, 0x4A, 0xFF, 0x0B, 0xFF, 0xE3, 0x07, 0xDD, 0x1A, 0x60, 0x36, 0xB4, 0x49, 0x3D, 0x47, 0xD1, 0x38, 0x08, 0x29, 0x2B, 0x20, 0xDA, 0x18, 0xE0, 0x0B, 0xB7, 0x08, 0x1D, 0x17, 0xBB, 0x2A, 0x93, 0x3C, 0x5D, 0x51, 0x62, 0x63, 0x29, 0x65, 0xF7, 0x55, 0xC8, 0x41, 0x64, 0x31, 0x81, 0x1B, 0x1F, 0x00, 0xE4, 0xEE, 0x09, 0xED, 0x6F, 0xF8, 0xFE, 0x06, 0x81, 0x10, 0xDE, 0x17, 0x95, 0x24, 0x59, 0x3B, 0x02, 0x51, 0x1F, 0x5B, 0x52, 0x59, 0x1F, 0x4C, 0x0A, 0x3C, 0xDD, 0x2E, 0x04, 0x1D, 0xD6, 0x05, 0xF3, 0xEF, 0x1E, 0xE0, 0xCC, 0xE1, 0x6D, 0xEE, 0xEE, 0xF6, 0x5C, 0x05, 0xDA, 0x17, 0x6F, 0x1E, 0xD4, 0x15, 0xD4, 0x03, 0xB9, 0xF4, 0x3A, 0xEF, 0xAD, 0xF3, 0xB4, 0xF9, 0x2C, 0xFA, 0x14, 0xF9, 0x52, 0xF4, 0x1D, 0xED, 0x5A, 0xE9, 0x7E, 0xEA, 0x83, 0xEB, 0xD9, 0xE7, 0x50, 0xED, 0xE3, 0xFE, 0x96, 0x10, 0x1C, 0x25, 0xE9, 0x39, 0xB7, 0x43, 0x16, 0x42, 0xF6, 0x36, 0x15, 0x20, 0x8A, 0x04, 0xE3, 0xF4, 0x34, 0xF8, 0x45, 0x08, 0x71, 0x19, 0x04, 0x21, 0x4A, 0x1C, 0x0A, 0x12, 0x69, 0x0A, 0x59, 0x06, 0x2D, 0x02, 0xF9, 0xFC, 0x12, 0xF6, 0xD0, 0xE8, 0xA8, 0xD7, 0xEC, 0xCF, 0x81, 0xD7, 0x10, 0xE3, 0xE4, 0xED, 0x49, 0x03, 0xA4, 0x1A, 0x1E, 0x1C, 0x7E, 0x06, 0x9B, 0xF1, 0x21, 0xF3, 0xE4, 0xFF, 0x50, 0x05, 0x98, 0x06, 0xE4, 0x04, 0x51, 0xFC, 0xBD, 0xED, 0x6C, 0xDE, 0x32, 0xDB, 0x4D, 0xEA, 0x1A, 0xFC, 0x53, 0x02, 0xF3, 0x02, 0x3C, 0xFF, 0x4A, 0xF6, 0xE6, 0xF0, 0x5F, 0xF0, 0x5F, 0xF6, 0x63, 0x02, 0x9A, 0x0B, 0xF3, 0x0D, 0x94, 0x01, 0x4A, 0xE7, 0x5D, 0xD4, 0x75, 0xD7, 0xE1, 0xEE, 0xD9, 0x0F, 0x71, 0x2D, 0x6E, 0x3A, 0x5A, 0x30, 0x3A, 0x1A, 0x1A, 0x02, 0x23, 0xF0, 0xCB, 0xF0, 0xF9, 0xFE, 0x42, 0x0B, 0xE7, 0x0C, 0xC1, 0x07, 0xD9, 0x05, 0x34, 0x03, 0x21, 0xFF, 0x6F, 0x02, 0x9E, 0x06, 0x7B, 0x06, 0x3D, 0x0B, 0x93, 0x14, 0xE7, 0x16, 0x86, 0x11, 0xC2, 0x11, 0xDB, 0x1B, 0x73, 0x21, 0x46, 0x19, 0xE9, 0x09, 0x2A, 0xFE, 0x7B, 0xFC, 0x19, 0x01, 0x57, 0x04, 0x5E, 0x02, 0x90, 0xFA, 0xE5, 0xF0, 0x7E, 0xEA, 0x04, 0xEB, 0x7B, 0xF4, 0x13, 0x04, 0x40, 0x13, 0x81, 0x19, 0xDF, 0x0F, 0xBA, 0xFD, 0x98, 0xF4, 0x82, 0xF6, 0xC2, 0xFA, 0xC0, 0x01, 0x91, 0x0F, 0xFD, 0x20, 0x79, 0x27, 0xC0, 0x1A, 0x46, 0x08, 0xF7, 0xFC, 0xCC, 0xF7, 0x2C, 0xF5, 0x4F, 0xF6, 0x17, 0x00, 0x45, 0x0E, 0x21, 0x14, 0x8C, 0x0D, 0xC4, 0x03, 0x9B, 0x05, 0xD3, 0x0E, 0x39, 0x0E, 0x37, 0x09, 0x67, 0x09, 0xD5, 0x08, 0xE6, 0x02, 0x0B, 0xFF, 0xD0, 0x07, 0x7F, 0x11, 0xA7, 0x0F, 0x71, 0x10, 0xEF, 0x1A, 0x9E, 0x22, 0x77, 0x1F, 0x82, 0x19, 0xC6, 0x19, 0x9C, 0x1A, 0x14, 0x14, 0x1C, 0x03, 0x34, 0xEA, 0xB7, 0xD4, 0x60, 0xCA, 0x6C, 0xCC, 0xA1, 0xDC, 0x42, 0xF8, 0x74, 0x14, 0x9B, 0x29, 0x37, 0x37, 0x87, 0x38, 0x69, 0x30, 0x80, 0x2A, 0xE0, 0x24, 0x32, 0x1C, 0xE7, 0x0D, 0xD5, 0xF9, 0xD5, 0xEF, 0x5C, 0xF3, 0x40, 0xFA, 0x0C, 0xFF, 0xCA, 0xFD, 0xC2, 0xFB, 0x1E, 0x00, 0xAF, 0x08, 0x6E, 0x0B, 0x97, 0x01, 0xDB, 0xF4, 0xB7, 0xF3, 0x16, 0x00, 0xC4, 0x10, 0x22, 0x18, 0x46, 0x0D, 0xEC, 0xFE, 0x22, 0x00, 0x5E, 0x0D, 0xD6, 0x1B, 0x2B, 0x22, 0x83, 0x20, 0x2D, 0x19, 0x1F, 0x0B, 0x15, 0xFF, 0x71, 0xFA, 0xDA, 0xFF, 0x03, 0x0E, 0x5D, 0x1D, 0x33, 0x26, 0x71, 0x1C, 0x60, 0x05, 0xC4, 0xF4, 0x11, 0xF0, 0xD8, 0xEC, 0x3D, 0xED, 0x47, 0x02, 0x73, 0x22, 0xF2, 0x3C, 0xC6, 0x50, 0x56, 0x5D, 0x5B, 0x62, 0xA2, 0x59, 0xB7, 0x43, 0xBA, 0x29, 0x58, 0x14, 0xB0, 0x09, 0x55, 0x02, 0x56, 0xFD, 0xDF, 0xFF, 0xDD, 0x03, 0xCA, 0x03, 0x20, 0x00, 0x30, 0xFD, 0xA6, 0xFA, 0x51, 0xF5, 0x18, 0xF0, 0x2F, 0xEB, 0xD7, 0xE2, 0xD1, 0xDA, 0x53, 0xDA, 0xC2, 0xE0, 0xF7, 0xEF, 0x85, 0x08, 0x44, 0x1D, 0xA9, 0x25, 0x6F, 0x1F, 0x6F, 0x0D, 0xCE, 0xFF, 0xE9, 0xFA, 0x94, 0xF1, 0x5D, 0xDB, 0x82, 0xBE, 0x91, 0xAD, 0x5B, 0xB3, 0xDB, 0xCC, 0x7B, 0xEE, 0x71, 0x06, 0xDB, 0x0D, 0xB1, 0x0A, 0xE1, 0x04, 0x43, 0x00, 0x24, 0xFC, 0x06, 0xF8, 0x1A, 0xEF, 0x4C, 0xE3, 0xC2, 0xE4, 0x8E, 0xF4, 0xD2, 0xFF, 0x8F, 0xFF, 0x86, 0xFC, 0x6C, 0xFF, 0x3A, 0x09, 0x23, 0x0E, 0x75, 0x07, 0xB3, 0xF7, 0xDE, 0xE1, 0x09, 0xD7, 0x82, 0xE3, 0xE9, 0xFF, 0xC2, 0x18, 0x2E, 0x19, 0xAE, 0x03, 0x4C, 0xE7, 0xED, 0xD2, 0xE9, 0xCD, 0xB4, 0xD2, 0x52, 0xDE, 0xC3, 0xE9, 0x30, 0xF2, 0x1A, 0xF8, 0xEF, 0xF6, 0x2C, 0xF4, 0xD3, 0xF3, 0x51, 0xF6, 0xAA, 0xF8, 0x3D, 0xFA, 0x28, 0xFC, 0x7D, 0xED, 0x95, 0xCB, 0xDA, 0xA8, 0xC1, 0x98, 0xD3, 0xA8, 0x87, 0xC9, 0x54, 0xE4, 0xBF, 0xF4, 0x63, 0xFE, 0x44, 0x04, 0x27, 0x05, 0x4C, 0xFF, 0xEC, 0xF7, 0xD2, 0xFC, 0x4D, 0x0C, 0x60, 0x17, 0x7D, 0x18, 0x32, 0x12, 0x29, 0x0B, 0xA6, 0x01, 0x60, 0xF5, 0x2B, 0xED, 0xC4, 0xEC, 0xAF, 0xFB, 0x29, 0x11, 0xD9, 0x17, 0xE1, 0x0E, 0x9A, 0x04, 0xEF, 0x03, 0x50, 0x08, 0x19, 0x08, 0xD8, 0x06, 0x05, 0x0A, 0x49, 0x0E, 0xFB, 0x11, 0x7C, 0x15, 0x53, 0x17, 0xB0, 0x17, 0x85, 0x18, 0xAC, 0x1A, 0x0C, 0x1D, 0xB0, 0x22, 0xF4, 0x26, 0xB4, 0x1D, 0x0D, 0x0B, 0xD7, 0xFC, 0x3E, 0xFB, 0x3C, 0xF9, 0xDB, 0xE8, 0x9D, 0xE0, 0x27, 0xF1, 0xD2, 0x01, 0x99, 0xFE, 0x16, 0xF6, 0x72, 0xF6, 0x98, 0xFA, 0x5C, 0xF7, 0x49, 0xE5, 0x72, 0xD1, 0xB8, 0xCF, 0xD9, 0xE3, 0x32, 0x02, 0x49, 0x19, 0x5D, 0x1F, 0xF9, 0x11, 0x5D, 0xFB, 0x82, 0xEC, 0xCB, 0xEA, 0x11, 0xF0, 0x41, 0xF8, 0x0C, 0x01, 0x1F, 0x02, 0xDB, 0x01, 0x51, 0x0B, 0x26, 0x20, 0x85, 0x37, 0x4D, 0x3A, 0x5C, 0x27, 0x22, 0x0A, 0x14, 0xF0, 0xA7, 0xE9, 0xAF, 0xEB, 0x99, 0xEB, 0x36, 0xF1, 0x5B, 0x02, 0x4F, 0x18, 0x90, 0x2A, 0x95, 0x3A, 0xF4, 0x46, 0x54, 0x4E, 0x3F, 0x4C, 0xB7, 0x44, 0x4F, 0x40, 0xC9, 0x37, 0x8D, 0x2E, 0x30, 0x29, 0x24, 0x21, 0x82, 0x1A, 0xD1, 0x1F, 0xE2, 0x2B, 0x1A, 0x35, 0x2B, 0x43, 0xF8, 0x51, 0x51, 0x53, 0x93, 0x4C, 0x54, 0x4B, 0x2C, 0x4C, 0xE9, 0x42, 0xFD, 0x34, 0x3C, 0x25, 0x99, 0x14, 0x26, 0x08, 0x74, 0xFF, 0x6B, 0x00, 0x46, 0x05, 0xD7, 0xFF, 0x1B, 0xED, 0xFA, 0xDB, 0xDA, 0xD8, 0xEF, 0xDA, 0x55, 0xE2, 0xCF, 0xEB, 0x44, 0xF4, 0xF2, 0xFE, 0xBA, 0x00, 0x6F, 0xFD, 0xEB, 0xFA, 0xB9, 0xF9, 0x70, 0x01, 0x92, 0x04, 0x81, 0xF3, 0x0E, 0xDC, 0xA3, 0xD2, 0x79, 0xDA, 0x79, 0xEC, 0x07, 0xF9, 0x52, 0xF6, 0x01, 0xEE, 0x72, 0xE6, 0xD7, 0xE1, 0x86, 0xE6, 0xA4, 0xF2, 0xDE, 0xFA, 0x04, 0xFE, 0xE2, 0x04, 0x65, 0x0F, 0x2A, 0x19, 0xCF, 0x1D, 0x89, 0x1D, 0x87, 0x15, 0x07, 0x02, 0x64, 0xF3, 0xC4, 0xED, 0x26, 0xE3, 0x8A, 0xD5, 0x99, 0xCF, 0x05, 0xD8, 0x07, 0xEE, 0x51, 0x06, 0x84, 0x10, 0x64, 0x07, 0xC2, 0xF7, 0xB0, 0xF3, 0xD6, 0x02, 0x44, 0x18, 0x1E, 0x1F, 0x0F, 0x13, 0xAB, 0xFF, 0x8D, 0xEF, 0xC9, 0xEB, 0x07, 0xF3, 0xBF, 0xFB, 0x22, 0x0C, 0x0E, 0x21, 0x11, 0x2B, 0xD3, 0x27, 0x13, 0x15, 0x57, 0xF6, 0x17, 0xD5, 0x94, 0xBD, 0x3F, 0xBB, 0xEB, 0xC0, 0x61, 0xBB, 0x3C, 0xA6, 0x2C, 0x91, 0x4D, 0x96, 0xBE, 0xB3, 0xF0, 0xD5, 0xB0, 0xF0, 0x34, 0xFE, 0x45, 0x00, 0xD1, 0xF8, 0xC1, 0xEB, 0x0B, 0xE2, 0x0E, 0xE3, 0xC0, 0xEE, 0x39, 0xFA, 0x0E, 0xFB, 0x93, 0xF8, 0xC9, 0xFA, 0x5F, 0xF5, 0x66, 0xE8, 0x80, 0xDE, 0x05, 0xD8, 0x46, 0xDB, 0x2F, 0xE2, 0x51, 0xE1, 0x2F, 0xD7, 0x17, 0xCA, 0x40, 0xCA, 0x00, 0xD7, 0x1E, 0xE6, 0x71, 0xE5, 0x24, 0xDC, 0x4F, 0xE8, 0xFD, 0xF5, 0xF6, 0x05, 0x95, 0x1E, 0x53, 0x22, 0xF5, 0x1E, 0x8B, 0x10, 0xBD, 0xF3, 0x2B, 0xEB, 0x7D, 0xEA, 0xF1, 0xE3, 0x44, 0xDD, 0xFC, 0xD2, 0x67, 0xCA, 0xB4, 0xC7, 0x44, 0xD6, 0x44, 0xF2, 0xE3, 0xF8, 0x45, 0xE2, 0xB1, 0xC6, 0x58, 0xC5, 0xB7, 0xDE, 0x9E, 0xD7, 0x8E, 0xB2, 0xDE, 0xB1, 0x91, 0xC4, 0x4E, 0xD6, 0x73, 0xF5, 0xE1, 0x04, 0x4C, 0xFF, 0xC9, 0xF0, 0x19, 0xD8, 0x79, 0xC7, 0xC3, 0xC0, 0xF0, 0xC3, 0x38, 0xD7, 0x15, 0xED, 0x02, 0xFF, 0x09, 0x01, 0xC1, 0xEC, 0x6A, 0xD7, 0xD4, 0xCF, 0x39, 0xD6, 0xC1, 0xD6, 0x47, 0xC4, 0x3D, 0xBA, 0x5B, 0xCB, 0x21, 0xE5, 0xC6, 0xF6, 0xC2, 0x07, 0x26, 0x1E, 0x3F, 0x2E, 0x18, 0x2C, 0x3E, 0x1B, 0x17, 0x09, 0x6B, 0xFF, 0x63, 0x03, 0x37, 0x16, 0x1D, 0x32, 0xE6, 0x33, 0x15, 0x0A, 0xDD, 0xE5, 0x74, 0xE4, 0xB2, 0x00, 0x69, 0x25, 0x74, 0x2F, 0xAA, 0x29, 0xA7, 0x20, 0x9B, 0x12, 0x36, 0x09, 0xFA, 0xFE, 0x87, 0xF2, 0x7B, 0xE4, 0x7D, 0xD9, 0x50, 0xD7, 0x91, 0xD7, 0xFC, 0xDF, 0xDC, 0xEF, 0x61, 0xFA, 0x67, 0x00, 0x25, 0x04, 0x9C, 0xFC, 0xEA, 0xEE, 0x68, 0xE8, 0x6E, 0xE5, 0xD1, 0xE9, 0xE2, 0xF8, 0x62, 0x07, 0x4E, 0x0C, 0xF9, 0x00, 0x7B, 0xEA, 0x77, 0xD4, 0x5D, 0xC6, 0x45, 0xC4, 0x25, 0xC8, 0x38, 0xCA, 0x87, 0xD2, 0xC3, 0xE2, 0x64, 0xE5, 0x9F, 0xD7, 0xF3, 0xC9, 0x56, 0xC3, 0x28, 0xC0, 0xFB, 0xB4, 0xA2, 0xA8, 0x08, 0xB0, 0xB0, 0xCD, 0x08, 0xEF, 0x0C, 0xFD, 0xEF, 0xF6, 0x73, 0xEF, 0xEE, 0xED, 0x24, 0xF0, 0x44, 0xF3, 0xCA, 0xED, 0x76, 0xE6, 0x01, 0xEE, 0x21, 0x02, 0xDF, 0x16, 0x58, 0x1E, 0xB1, 0x17, 0x9F, 0x0C, 0x5E, 0x02, 0xD9, 0xF9, 0x9E, 0xEF, 0xE9, 0xEC, 0x09, 0xF9, 0x3F, 0x0A, 0xEA, 0x10, 0x7E, 0x00, 0xA1, 0xE4, 0xB9, 0xD5, 0x11, 0xDB, 0xA0, 0xE4, 0xAD, 0xE4, 0xEF, 0xE1, 0xE0, 0xE8, 0xB7, 0xFD, 0xE9, 0x12, 0xDC, 0x1C, 0xE1, 0x18, 0x4B, 0x0C, 0x32, 0x06, 0x96, 0x00, 0x3C, 0xFA, 0xA5, 0x03, 0x42, 0x11, 0x59, 0x0A, 0xCB, 0xF1, 0x45, 0xE2, 0xA2, 0xEB, 0x3F, 0x01, 0xFB, 0x0C, 0xB9, 0x0E, 0xA1, 0x10, 0x57, 0x0A, 0x75, 0xF4, 0x21, 0xD2, 0x43, 0xB2, 0xE4, 0xAE, 0x68, 0xC4, 0x90, 0xD2, 0x19, 0xD0, 0xBC, 0xCA, 0x91, 0xCB, 0x14, 0xD1, 0x6B, 0xCF, 0xD4, 0xC8, 0x38, 0xC8, 0x94, 0xD0, 0xDA, 0xEC, 0x62, 0x0E, 0x9F, 0x13, 0x8F, 0xFC, 0xAF, 0xE3, 0xF8, 0xDF, 0xC2, 0xE9, 0x1F, 0xF0, 0xC6, 0xF6, 0x7E, 0x08, 0x3E, 0x1C, 0x5C, 0x18, 0xC4, 0x07, 0x4B, 0x05, 0xEF, 0x08, 0x83, 0x06, 0x57, 0xFE, 0x78, 0xFB, 0x92, 0x0B, 0xE6, 0x1F, 0x35, 0x23, 0xE0, 0x17, 0xDB, 0x01, 0xDE, 0xED, 0x47, 0xEE, 0x27, 0xFC, 0x2C, 0x0E, 0x98, 0x20, 0x36, 0x2B, 0x51, 0x25, 0xD8, 0x0A, 0x8F, 0xED, 0x56, 0xDD, 0xD1, 0xD8, 0xF6, 0xDA, 0x9F, 0xDC, 0x39, 0xE1, 0x0B, 0xEC, 0x8F, 0xF5, 0x60, 0xF5, 0xF4, 0xEC, 0x00, 0xED, 0xDA, 0xFD, 0x66, 0x16, 0x75, 0x2B, 0x9C, 0x34, 0x99, 0x2C, 0xD4, 0x1A, 0xC1, 0x0F, 0xA3, 0x0A, 0xC8, 0x01, 0xDA, 0xF9, 0xB7, 0xFB, 0xDF, 0x01, 0x54, 0xFE, 0x2F, 0xF5, 0x15, 0xF6, 0x70, 0x04, 0x63, 0x13, 0x64, 0x11, 0x80, 0x05, 0x2C, 0x05, 0xCD, 0x0D, 0x06, 0x12, 0x80, 0x13, 0xFA, 0x15, 0x68, 0x17, 0x8C, 0x15, 0xBB, 0x0D, 0x6F, 0x07, 0x3F, 0x07, 0xC3, 0x05, 0xC2, 0x05, 0x05, 0x09, 0x04, 0x0F, 0x77, 0x17, 0xA6, 0x16, 0x22, 0x0C, 0xCF, 0xFD, 0xBD, 0xEC, 0x84, 0xE2, 0x35, 0xE5, 0xAC, 0xF0, 0xDB, 0xFD, 0x92, 0x09, 0x11, 0x14, 0x46, 0x19, 0x0E, 0x17, 0xF4, 0x17, 0x5F, 0x25, 0x13, 0x2F, 0xAB, 0x1F, 0xF6, 0xFE, 0x3C, 0xE6, 0x23, 0xE3, 0xCB, 0xF0, 0x7E, 0x00, 0x42, 0x04, 0x23, 0xFE, 0xFA, 0xF8, 0xFF, 0xFA, 0x05, 0x04, 0xA8, 0x08, 0x0B, 0x04, 0x12, 0xFA, 0x59, 0xEC, 0x97, 0xE0, 0xA3, 0xDD, 0x12, 0xE4, 0xC9, 0xE9, 0x66, 0xEF, 0x0F, 0xF9, 0xC0, 0xFB, 0x09, 0xFD, 0x06, 0x01, 0x30, 0xFE, 0xEF, 0xF9, 0x49, 0xFA, 0xAA, 0x01, 0x93, 0x0F, 0x05, 0x17, 0xA1, 0x11, 0xAD, 0x0E, 0x9D, 0x11, 0x04, 0x07, 0xA3, 0xED, 0xEC, 0xD5, 0xF7, 0xD1, 0x28, 0xDC, 0x6E, 0xDB, 0xDD, 0xDC, 0xDC, 0xEE, 0xFF, 0x01, 0xD8, 0x0C, 0xEF, 0x0F, 0xA7, 0x13, 0x14, 0x13, 0xC7, 0x05, 0x0A, 0xF1, 0x3E, 0xE0, 0x57, 0xE5, 0x85, 0xF1, 0xC0, 0xEF, 0xFB, 0xEB, 0xB3, 0xEA, 0x52, 0xEC, 0x1D, 0xF5, 0x3A, 0x07, 0x14, 0x20, 0x6C, 0x2E, 0x1D, 0x23, 0xDF, 0x01, 0xA6, 0xE9, 0x56, 0xEF, 0xBD, 0xFF, 0x53, 0x0D, 0xF9, 0x1A, 0xCB, 0x22, 0xBC, 0x1D, 0x20, 0x0F, 0xE7, 0x02, 0xBD, 0x02, 0x2D, 0x0A, 0x41, 0x0C, 0x3B, 0x04, 0x76, 0xF7, 0x72, 0xEB, 0x4D, 0xE1, 0xC6, 0xDE, 0xD5, 0xEC, 0xE0, 0x07, 0xCA, 0x1C, 0x36, 0x17, 0x34, 0xFB, 0x3A, 0xE0, 0x75, 0xD5, 0x8B, 0xD8, 0xA6, 0xDD, 0x12, 0xE8, 0xE5, 0x00, 0xF0, 0x1C, 0xC2, 0x2B, 0xD9, 0x27, 0xE8, 0x16, 0xF1, 0x07, 0x22, 0x03, 0x38, 0xFE, 0xC1, 0xEF, 0x6A, 0xDA, 0xBB, 0xCD, 0x46, 0xDB, 0xA7, 0xF8, 0xC3, 0x0E, 0x0D, 0x11, 0x97, 0x03, 0x25, 0xF9, 0xC5, 0xF3, 0xCC, 0xE9, 0x40, 0xDE, 0x90, 0xD9, 0xE1, 0xD8, 0xBC, 0xDA, 0x89, 0xE8, 0x0F, 0xF9, 0x17, 0x01, 0x9C, 0x08, 0xAC, 0x17, 0xE5, 0x2C, 0x09, 0x39, 0x7F, 0x32, 0x6B, 0x1E, 0x06, 0x08, 0x39, 0xF8, 0x27, 0xEE, 0x65, 0xEF, 0x32, 0x03, 0xE9, 0x22, 0x50, 0x3E, 0xD8, 0x46, 0x06, 0x3C, 0xD8, 0x25, 0x64, 0x0E, 0xB7, 0xFE, 0xD5, 0xF1, 0xF4, 0xDF, 0xA0, 0xD3, 0xF8, 0xD7, 0x22, 0xE6, 0x9D, 0xEC, 0x8A, 0xE7, 0xF5, 0xE6, 0x85, 0xF0, 0xA6, 0xFF, 0x69, 0x04, 0x9A, 0xF1, 0xBB, 0xDC, 0x3C, 0xD7, 0xD7, 0xE0, 0x2C, 0xF4, 0x2F, 0x09, 0x4B, 0x18, 0x70, 0x14, 0x69, 0x06, 0xDA, 0xF9, 0x94, 0xF0, 0xD0, 0xEB, 0x90, 0xDB, 0x48, 0xC4, 0x90, 0xB7, 0x00, 0xBD, 0x03, 0xDA, 0x43, 0xFE, 0x5C, 0x15, 0xB4, 0x1C, 0x9E, 0x23, 0x97, 0x31, 0xA0, 0x36, 0xE1, 0x2E, 0x6F, 0x29, 0xE0, 0x2C, 0x4D, 0x29, 0x53, 0x17, 0x8E, 0x06, 0x60, 0x00, 0x00, 0x09, 0xFD, 0x1D, 0xFE, 0x2F, 0x7B, 0x33, 0xCC, 0x28, 0x87, 0x18, 0xAB, 0x0C, 0xFB, 0x05, 0x02, 0xFD, 0x5D, 0xF4, 0xB7, 0xF2, 0x85, 0xF5, 0xA8, 0xFD, 0x81, 0x0F, 0xD9, 0x24, 0xBD, 0x2F, 0xAA, 0x29, 0xC1, 0x1A, 0x9A, 0x10, 0xB6, 0x0C, 0x2C, 0x0B, 0xF6, 0x0A, 0x4B, 0x08, 0x4C, 0x08, 0x99, 0x09, 0x47, 0xFD, 0x50, 0xE7, 0xEA, 0xDA, 0x80, 0xE2, 0x86, 0xF2, 0xD6, 0xF8, 0xED, 0xF3, 0xEE, 0xEA, 0x2C, 0xE3, 0xCD, 0xDB, 0x3A, 0xD6, 0x44, 0xD9, 0x4F, 0xE3, 0xE0, 0xEB, 0xEB, 0xED, 0x8F, 0xED, 0x67, 0xEC, 0x68, 0xE7, 0xEE, 0xE2, 0xC5, 0xE1, 0xD7, 0xE5, 0xCE, 0xEF, 0x77, 0xF8, 0xB9, 0xFC, 0xC3, 0x02, 0x49, 0x12, 0x97, 0x21, 0x49, 0x20, 0xB8, 0x13, 0x79, 0x08, 0x75, 0x06, 0x3E, 0x0C, 0x9A, 0x11, 0x32, 0x16, 0xA2, 0x19, 0x41, 0x1C, 0xAE, 0x1A, 0xA4, 0x12, 0xE3, 0x0E, 0xB1, 0x0F, 0x9A, 0x14, 0xA2, 0x1F, 0xDC, 0x2A, 0xB7, 0x37, 0xA8, 0x3B, 0xA7, 0x2F, 0x9E, 0x24, 0x5B, 0x21, 0x38, 0x28, 0xA0, 0x38, 0xAE, 0x47, 0x97, 0x52, 0x68, 0x55, 0x96, 0x4F, 0x21, 0x47, 0x58, 0x38, 0x10, 0x2A, 0xA5, 0x29, 0x6E, 0x31, 0x5C, 0x36, 0x77, 0x35, 0xE2, 0x30, 0x8F, 0x2A, 0x5F, 0x22, 0xA8, 0x18, 0x94, 0x13, 0x02, 0x1A, 0xB7, 0x26, 0x79, 0x2D, 0xE6, 0x28, 0x82, 0x1E, 0xEA, 0x13, 0x15, 0x10, 0x4C, 0x19, 0x9B, 0x26, 0xAA, 0x2C, 0x14, 0x1F, 0x11, 0xFE, 0xEC, 0xE7, 0xC7, 0xEF, 0x1F, 0x08, 0x0A, 0x19, 0xEC, 0x1B, 0xB6, 0x1B, 0x2C, 0x1F, 0x33, 0x22, 0x3D, 0x1F, 0x1D, 0x20, 0x72, 0x29, 0x0D, 0x2F, 0x51, 0x28, 0x8C, 0x18, 0x58, 0x12, 0xF5, 0x1E, 0x4C, 0x36, 0x66, 0x47, 0x07, 0x43, 0xBB, 0x33, 0x74, 0x2A, 0xD0, 0x2A, 0x77, 0x26, 0xAB, 0x0C, 0xAE, 0xF0, 0xD3, 0xF0, 0x10, 0x0D, 0xEE, 0x2F, 0x76, 0x45, 0xD4, 0x49, 0x9B, 0x4B, 0x9C, 0x52, 0x36, 0x53, 0x42, 0x46, 0x9B, 0x33, 0x11, 0x2C, 0x83, 0x32, 0xE8, 0x38, 0x47, 0x38, 0x57, 0x32, 0xA6, 0x2D, 0xE7, 0x28, 0xCC, 0x22, 0xA1, 0x25, 0xCA, 0x33, 0x8A, 0x43, 0x0B, 0x47, 0xB7, 0x3C, 0xD1, 0x2F, 0xB2, 0x29, 0xB0, 0x28, 0x9C, 0x21, 0x73, 0x14, 0xA5, 0x05, 0x0A, 0xFA, 0x9F, 0xF9, 0x6E, 0x04, 0x63, 0x19, 0xE0, 0x2E, 0x4F, 0x38, 0x58, 0x34, 0x46, 0x26, 0xF4, 0x1D, 0xBD, 0x26, 0x56, 0x35, 0xC9, 0x40, 0x49, 0x46, 0xCC, 0x3C, 0x69, 0x23, 0x09, 0x07, 0x5E, 0xF0, 0x97, 0xDD, 0xAB, 0xCC, 0x0A, 0xC3, 0x3E, 0xCB, 0x36, 0xE4, 0xE1, 0xFD, 0xEC, 0x0C, 0x2C, 0x0D, 0xC2, 0x02, 0xAD, 0xF7, 0x43, 0xEE, 0x8E, 0xEA, 0x6F, 0xF0, 0x83, 0xF7, 0x25, 0xEF, 0x98, 0xDC, 0x80, 0xE0, 0xF2, 0xFE, 0xE4, 0x1B, 0x06, 0x23, 0x3F, 0x19, 0x9E, 0x0B, 0x01, 0xFD, 0xE8, 0xF7, 0x03, 0xF9, 0x6B, 0xF7, 0xE4, 0xF7, 0xD4, 0xF7, 0xB8, 0x01, 0x31, 0x16, 0xC5, 0x23, 0xFA, 0x21, 0xE7, 0x0E, 0x12, 0xFE, 0x4C, 0xFE, 0x33, 0x06, 0xDE, 0x09, 0xC3, 0x0B, 0xB1, 0x16, 0xFA, 0x20, 0x58, 0x1E, 0xF7, 0x11, 0x65, 0x05, 0x5E, 0xFE, 0x6C, 0xF9, 0x9C, 0xF2, 0xF5, 0xE8, 0x7C, 0xE6, 0x27, 0xF2, 0xDF, 0x03, 0xF5, 0x12, 0x07, 0x20, 0x48, 0x2D, 0xC6, 0x31, 0x0D, 0x2C, 0x64, 0x1B, 0xA6, 0x03, 0xBE, 0xF8, 0x8E, 0xF8, 0xEC, 0xFA, 0x9C, 0xFC, 0x8C, 0xF8, 0xF2, 0xF6, 0x38, 0xFA, 0x07, 0x00, 0x82, 0x04, 0x3D, 0x05, 0xA3, 0x07, 0xD7, 0x09, 0xF3, 0x0B, 0xE7, 0x0B, 0x24, 0x02, 0xE3, 0xF4, 0x59, 0xEE, 0xE8, 0xED, 0x6D, 0xEA, 0x2A, 0xE0, 0x5B, 0xD9, 0xD7, 0xDD, 0xC0, 0xE7, 0xEB, 0xF0, 0x80, 0xF9, 0xEA, 0x03, 0x95, 0x0D, 0xB6, 0x0B, 0x83, 0x00, 0x2E, 0xF9, 0x25, 0xF6, 0xD6, 0xEF, 0x10, 0xE4, 0x92, 0xDB, 0x26, 0xDF, 0x1D, 0xEC, 0x16, 0xF7, 0xB1, 0xFA, 0x92, 0xFF, 0xAC, 0x05, 0xAA, 0x08, 0xF3, 0x07, 0xDC, 0xFA, 0xEE, 0xE2, 0x8D, 0xC7, 0x1A, 0xB1, 0x9E, 0xA7, 0x50, 0xA5, 0xEA, 0xAD, 0x06, 0xBF, 0x9C, 0xC6, 0x50, 0xC7, 0x3A, 0xCA, 0xE9, 0xCE, 0x4D, 0xD2, 0x00, 0xD2, 0xF4, 0xCB, 0x6B, 0xBF, 0x8E, 0xB2, 0x2F, 0xA9, 0x32, 0xA8, 0x64, 0xB5, 0xE3, 0xCC, 0x8F, 0xE1, 0xF3, 0xE4, 0xCA, 0xDF, 0xF0, 0xE3, 0xF5, 0xF1, 0x66, 0xFF, 0x9E, 0xFE, 0xD0, 0xEE, 0xB3, 0xD6, 0x65, 0xBE, 0x9F, 0xB5, 0x12, 0xBF, 0xFA, 0xCC, 0x7F, 0xD3, 0x1A, 0xD2, 0x76, 0xD3, 0xCE, 0xDD, 0x8E, 0xE8, 0xB2, 0xEC, 0x81, 0xEB, 0x68, 0xE4, 0x8E, 0xDB, 0xDF, 0xD6, 0x32, 0xD5, 0x6C, 0xD5, 0x75, 0xD6, 0xEE, 0xD5, 0xA2, 0xCF, 0x69, 0xC2, 0x54, 0xB7, 0x85, 0xB6, 0xE0, 0xBB, 0xE3, 0xBF, 0xE8, 0xC6, 0x58, 0xD5, 0x57, 0xDF, 0x95, 0xE2, 0x76, 0xEC, 0x20, 0xFB, 0x75, 0x00, 0x95, 0xF3, 0xB7, 0xE1, 0x8C, 0xDE, 0x1D, 0xE0, 0xF5, 0xDF, 0xB0, 0xE4, 0x5A, 0xEC, 0x42, 0xF5, 0x8D, 0xF4, 0x14, 0xEB, 0x6A, 0xE6, 0x54, 0xE6, 0x5F, 0xE8, 0xCA, 0xE6, 0xC6, 0xE4, 0x92, 0xEC, 0x1F, 0xFA, 0xD0, 0x02, 0x5F, 0x03, 0x27, 0x05, 0xDD, 0x07, 0x24, 0x06, 0x5A, 0x04, 0xB9, 0x03, 0x3B, 0x05, 0x0B, 0x06, 0x21, 0x02, 0x0D, 0xF6, 0x08, 0xE2, 0xD5, 0xD2, 0xF6, 0xCE, 0xFC, 0xD1, 0x7A, 0xD5, 0x5C, 0xD8, 0x50, 0xDF, 0x1D, 0xEF, 0xEF, 0x05, 0x7F, 0x13, 0xF9, 0x14, 0xDD, 0x15, 0x76, 0x14, 0x1E, 0x0A, 0x32, 0xF7, 0x84, 0xE9, 0xFB, 0xEB, 0x4F, 0xF5, 0x6E, 0xF4, 0x24, 0xEC, 0x72, 0xF3, 0x93, 0x06, 0xBA, 0x11, 0xAA, 0x12, 0xDE, 0x08, 0xC8, 0xF5, 0x96, 0xE0, 0x50, 0xD3, 0x74, 0xD1, 0x25, 0xD5, 0x1C, 0xDE, 0x52, 0xE5, 0x47, 0xE1, 0xEA, 0xD8, 0xAD, 0xD4, 0xC9, 0xD7, 0x2C, 0xDF, 0x1A, 0xE2, 0xDD, 0xE0, 0x9F, 0xE0, 0xE4, 0xE2, 0x45, 0xE9, 0xCE, 0xF2, 0x25, 0xF9, 0x20, 0xF6, 0x47, 0xF0, 0xD6, 0xEF, 0xBF, 0xED, 0xC2, 0xE7, 0xD8, 0xE4, 0xE2, 0xE5, 0x37, 0xE5, 0xF2, 0xDF, 0xE9, 0xDB, 0x98, 0xD9, 0xEE, 0xD9, 0x3D, 0xE9, 0x9E, 0x08, 0xEB, 0x21, 0xF5, 0x25, 0x9F, 0x23, 0xB0, 0x28, 0x76, 0x30, 0x48, 0x30, 0xD6, 0x23, 0x5A, 0x11, 0x13, 0xFF, 0x8C, 0xFB, 0xFC, 0x09, 0x5B, 0x1B, 0x0A, 0x28, 0x6A, 0x27, 0x05, 0x20, 0x17, 0x1C, 0xF9, 0x17, 0x08, 0x19, 0x5E, 0x1C, 0xA3, 0x19, 0x2C, 0x14, 0x9D, 0x12, 0x62, 0x16, 0xF7, 0x1A, 0xEC, 0x1C, 0xD2, 0x1B, 0x24, 0x1F, 0x11, 0x27, 0x5A, 0x2D, 0x64, 0x2F, 0xAA, 0x2B, 0xC5, 0x29, 0x9C, 0x28, 0xD6, 0x27, 0x25, 0x2C, 0x87, 0x2F, 0x21, 0x32, 0x8D, 0x34, 0xA9, 0x38, 0x66, 0x3C, 0x07, 0x39, 0xBE, 0x33, 0x46, 0x2D, 0xE0, 0x25, 0xC4, 0x1E, 0xE8, 0x13, 0xF5, 0x07, 0x4E, 0xFF, 0x35, 0xFA, 0xA1, 0xFB, 0x92, 0x07, 0x5C, 0x13, 0x93, 0x12, 0xB0, 0x0A, 0x63, 0x05, 0x28, 0x04, 0xD3, 0x06, 0x71, 0x10, 0xA5, 0x1C, 0x5F, 0x23, 0x02, 0x21, 0xDA, 0x1A, 0xA7, 0x16, 0x3B, 0x10, 0x32, 0x09, 0x1A, 0xFF, 0x72, 0xF4, 0xA9, 0xF6, 0x1B, 0x01, 0xBE, 0x08, 0xD5, 0x05, 0x49, 0xFF, 0x9E, 0x02, 0xBD, 0x0A, 0x1F, 0x10, 0x33, 0x11, 0x8F, 0x12, 0xC9, 0x15, 0x00, 0x19, 0x52, 0x1F, 0x99, 0x26, 0xBA, 0x2A, 0xD8, 0x2A, 0x81, 0x26, 0x88, 0x1B, 0x52, 0x11, 0x3A, 0x11, 0x55, 0x1A, 0x8A, 0x2A, 0x08, 0x37, 0xAB, 0x3E, 0x9E, 0x49, 0x2F, 0x53, 0x69, 0x58, 0x1C, 0x59, 0xBC, 0x54, 0x37, 0x49, 0x60, 0x3B, 0x7B, 0x32, 0xB1, 0x2A, 0x4D, 0x29, 0x69, 0x34, 0xF3, 0x42, 0xF9, 0x47, 0x0D, 0x40, 0x9E, 0x33, 0x14, 0x2A, 0x0F, 0x24, 0x56, 0x1F, 0x19, 0x1B, 0xD7, 0x14, 0x1F, 0x11, 0xD8, 0x17, 0xBB, 0x25, 0xD5, 0x35, 0x21, 0x42, 0x13, 0x4B, 0x0B, 0x51, 0x05, 0x4A, 0xE2, 0x36, 0xEF, 0x21, 0xB7, 0x0D, 0xCC, 0xF8, 0xDF, 0xEB, 0x3F, 0xEA, 0x5C, 0xF1, 0x02, 0x04, 0x9D, 0x17, 0x21, 0x26, 0x8C, 0x31, 0xBC, 0x35, 0x32, 0x33, 0x24, 0x2E, 0x48, 0x2C, 0x69, 0x28, 0xAF, 0x1C, 0xB8, 0x0F, 0xA3, 0x06, 0x9F, 0x02, 0xAA, 0x00, 0x84, 0xFF, 0x08, 0x02, 0xCC, 0x0A, 0x0F, 0x14, 0x0D, 0x12, 0xB5, 0x05, 0x71, 0xFC, 0x17, 0x03, 0x19, 0x19, 0x83, 0x32, 0x07, 0x40, 0x4F, 0x3E, 0x3C, 0x39, 0xF3, 0x32, 0x99, 0x27, 0xE8, 0x12, 0x8D, 0xF8, 0xC2, 0xE3, 0x07, 0xD7, 0x43, 0xD9, 0x35, 0xE8, 0x19, 0xFD, 0xC7, 0x17, 0xCA, 0x2C, 0x0B, 0x3B, 0x90, 0x47, 0x22, 0x4F, 0x5D, 0x51, 0xF5, 0x4F, 0xB6, 0x4C, 0x6F, 0x43, 0x75, 0x37, 0x5C, 0x2F, 0x39, 0x29, 0xC0, 0x2A, 0x9F, 0x30, 0x1D, 0x2F, 0xDC, 0x28, 0x41, 0x24, 0xC3, 0x25, 0x3B, 0x2A, 0x94, 0x2D, 0x1F, 0x30, 0x4D, 0x2B, 0xA3, 0x21, 0xA4, 0x1B, 0xAF, 0x1C, 0x62, 0x24, 0x40, 0x2B, 0x19, 0x30, 0x91, 0x33, 0x1E, 0x39, 0x58, 0x41, 0x7F, 0x41, 0x11, 0x39, 0xD6, 0x26, 0xE8, 0x12, 0xD0, 0x0C, 0x68, 0x0C, 0x3F, 0x08, 0x57, 0xFE, 0x2F, 0xF5, 0x48, 0xF4, 0x2F, 0xF8, 0x9D, 0x00, 0xE6, 0x0B, 0xA1, 0x18, 0x1C, 0x27, 0x7F, 0x35, 0x67, 0x40, 0xEE, 0x42, 0x30, 0x3E, 0x1D, 0x35, 0x75, 0x2E, 0x32, 0x30, 0x9E, 0x34, 0xC1, 0x30, 0x81, 0x1E, 0x97, 0x02, 0xCC, 0xEA, 0x94, 0xE5, 0x26, 0xF0, 0x2C, 0x01, 0x34, 0x13, 0x1F, 0x1D, 0xAD, 0x20, 0x6B, 0x1F, 0x57, 0x1A, 0x89, 0x17, 0xDE, 0x12, 0x35, 0x0E, 0x3F, 0x09, 0xF1, 0xFB, 0xC8, 0xEE, 0x0C, 0xEC, 0xC4, 0xF1, 0x27, 0xFA, 0x72, 0x01, 0x8C, 0x0A, 0x24, 0x16, 0xBA, 0x1D, 0x90, 0x1E, 0x65, 0x18, 0xC4, 0x0C, 0xE8, 0x00, 0xF4, 0xF8, 0xA0, 0xF9, 0x73, 0x00, 0x62, 0x06, 0xCA, 0x0B, 0x8B, 0x12, 0x73, 0x1B, 0x89, 0x24, 0x55, 0x2A, 0xE4, 0x2E, 0xB1, 0x34, 0xDE, 0x37, 0x7B, 0x35, 0x18, 0x30, 0xC1, 0x2C, 0xB0, 0x2F, 0x4C, 0x34, 0x6C, 0x33, 0x85, 0x2B, 0xF6, 0x1F, 0x7D, 0x19, 0xE4, 0x1A, 0xB8, 0x1E, 0x7E, 0x23, 0x96, 0x29, 0xC5, 0x2F, 0xD6, 0x36, 0x1E, 0x34, 0x2E, 0x20, 0xB5, 0x0D, 0x14, 0x08, 0x18, 0x0E, 0x28, 0x17, 0x3E, 0x16, 0xF0, 0x11, 0x4C, 0x12, 0x18, 0x1C, 0xF1, 0x28, 0x56, 0x27, 0x80, 0x1C, 0x7F, 0x10, 0xD6, 0x01, 0xEB, 0xF0, 0x57, 0xE4, 0x7F, 0xE5, 0xCF, 0xF2, 0x32, 0x04, 0x98, 0x0E, 0x25, 0x12, 0xD4, 0x18, 0xFF, 0x22, 0xD0, 0x27, 0xAD, 0x1E, 0x74, 0x0D, 0xB2, 0x00, 0x93, 0x00, 0xE3, 0x08, 0x73, 0x0E, 0x84, 0x10, 0x38, 0x11, 0x5D, 0x11, 0xA5, 0x0A, 0x48, 0xF9, 0x41, 0xE4, 0x1B, 0xD6, 0x82, 0xD7, 0x58, 0xDB, 0xDB, 0xDA, 0xA0, 0xDF, 0x86, 0xE7, 0x3E, 0xF1, 0x7D, 0xF7, 0x28, 0xF7, 0x27, 0xFB, 0x4C, 0x05, 0xD6, 0x0A, 0x1C, 0x04, 0xE6, 0xF5, 0x3F, 0xED, 0x9C, 0xF2, 0xBD, 0x04, 0x08, 0x1C, 0x20, 0x2B, 0xB3, 0x27, 0x35, 0x15, 0x02, 0x04, 0xA4, 0xFF, 0xF1, 0x00, 0x53, 0x05, 0x68, 0x0C, 0x0F, 0x11, 0xE9, 0x13, 0x10, 0x0F, 0x41, 0x07, 0xDA, 0x08, 0x6A, 0x10, 0x97, 0x18, 0x6E, 0x21, 0x77, 0x28, 0x45, 0x26, 0x5C, 0x1E, 0x56, 0x16, 0x10, 0x0A, 0xBC, 0xFC, 0xB5, 0xF6, 0x0B, 0xF8, 0x5C, 0xF9, 0x8F, 0xFC, 0xE5, 0x00, 0xA4, 0x03, 0xD7, 0x0A, 0xC7, 0x0F, 0x25, 0x0E, 0x25, 0x07, 0xB1, 0xFE, 0x5C, 0xFD, 0x38, 0xFD, 0x41, 0xF9, 0x0B, 0xF1, 0xEA, 0xE7, 0x97, 0xDF, 0xA2, 0xD5, 0x3F, 0xD1, 0xE5, 0xCF, 0x45, 0xCA, 0x43, 0xC1, 0x6F, 0xBD, 0x20, 0xC8, 0xE2, 0xDA, 0xD3, 0xE9, 0x9C, 0xEB, 0x79, 0xE4, 0xE9, 0xDE, 0x78, 0xDC, 0x77, 0xE0, 0x8D, 0xEB, 0xB1, 0xF9, 0xF4, 0x02, 0x5C, 0x02, 0x00, 0xF9, 0x9A, 0xE8, 0x80, 0xD8, 0xB4, 0xCE, 0xD5, 0xCD, 0x35, 0xD4, 0xC3, 0xDB, 0xCB, 0xDE, 0x0E, 0xDB, 0x97, 0xD7, 0x4C, 0xDC, 0x53, 0xEA, 0xE8, 0xF4, 0x2C, 0xEF, 0x52, 0xE1, 0x7F, 0xD7, 0xFD, 0xD3, 0xAA, 0xD4, 0x81, 0xDA, 0xCD, 0xE1, 0x9F, 0xE1, 0x5E, 0xDD, 0x4E, 0xDC, 0xC8, 0xDE, 0xE6, 0xDF, 0x6F, 0xDC, 0xCE, 0xDA, 0xEC, 0xE4, 0x81, 0xFA, 0xFF, 0x0E, 0x15, 0x1C, 0x16, 0x23, 0xDB, 0x23, 0x44, 0x21, 0xD1, 0x1B, 0xAB, 0x0D, 0x60, 0xF4, 0x07, 0xD9, 0x3E, 0xCA, 0x40, 0xCB, 0x75, 0xD3, 0x37, 0xE0, 0x5F, 0xF0, 0xD8, 0xFC, 0x48, 0x01, 0x8E, 0xFB, 0xC0, 0xF0, 0x97, 0xEA, 0x04, 0xEC, 0xDB, 0xED, 0xBB, 0xE4, 0x25, 0xD3, 0xCF, 0xC4, 0x5D, 0xBE, 0x0F, 0xBB, 0x79, 0xBD, 0xDC, 0xCD, 0xD6, 0xDD, 0x70, 0xE0, 0x48, 0xDD, 0x0E, 0xDD, 0x2D, 0xE0, 0x3A, 0xDB, 0x76, 0xCA, 0xA1, 0xB7, 0x36, 0xAD, 0xAA, 0xAF, 0xC3, 0xB6, 0xC6, 0xB9, 0x9A, 0xB8, 0xC3, 0xB9, 0xE8, 0xC4, 0x43, 0xD5, 0xC0, 0xDD, 0x4E, 0xDD, 0xD6, 0xD9, 0xC1, 0xD6, 0xC7, 0xD5, 0x5C, 0xD1, 0x83, 0xC8, 0x0C, 0xC0, 0xF2, 0xBB, 0x9E, 0xB9, 0xFE, 0xAD, 0xB3, 0x9B, 0xF9, 0x8E, 0x7E, 0x91, 0x6A, 0xA1, 0x33, 0xB7, 0x85, 0xBF, 0x8F, 0xAA, 0x91, 0xA7, 0x37, 0xC0, 0x0E, 0xCA, 0x1B, 0xD5, 0xF5, 0xDE, 0x55, 0xDE, 0x0A, 0xE4, 0x31, 0xE6, 0x1E, 0xE6, 0xA6, 0xE6, 0x81, 0xE5, 0xA0, 0xE5, 0xC9, 0xE6, 0x5F, 0xE9, 0xDB, 0xE3, 0x10, 0xDB, 0xD1, 0xD0, 0xCE, 0xBC, 0x7F, 0xAD, 0x06, 0xAD, 0x1B, 0xBB, 0x1D, 0xD4, 0x75, 0xE6, 0xFF, 0xE5, 0xFE, 0xD9, 0xE3, 0xCA, 0xEF, 0xBE, 0x3E, 0xBD, 0x38, 0xC3, 0x17, 0xCD, 0xBB, 0xD8, 0x41, 0xE7, 0xA0, 0xF4, 0xE7, 0xF3, 0x4E, 0xEA, 0x2B, 0xDD, 0xBC, 0xC9, 0x6D, 0xB8, 0x72, 0xAD, 0x55, 0xAC, 0x3F, 0xB9, 0xD3, 0xC5, 0x13, 0xC5, 0x02, 0xC4, 0x43, 0xCB, 0xE8, 0xCE, 0x26, 0xCA, 0xC9, 0xC1, 0x55, 0xBC, 0x9A, 0xBE, 0x33, 0xC1, 0xD9, 0xBB, 0x1D, 0xB5, 0x94, 0xB2, 0xDA, 0xB1, 0x0F, 0xAF, 0x1C, 0xA4, 0x6C, 0xA0, 0xBE, 0x9F, 0x1A, 0x9C, 0x14, 0x9D, 0xC9, 0x9F, 0xCD, 0xA6, 0x3E, 0xB0, 0xBB, 0xB5, 0x33, 0xBE, 0x85, 0xC1, 0xA7, 0xBC, 0xA1, 0xB9, 0x41, 0xBA, 0x51, 0xBE, 0xE4, 0xBF, 0x51, 0xBC, 0x0E, 0xB9, 0x8E, 0xBB, 0x11, 0xC0, 0xE5, 0xBE, 0xB8, 0xBA, 0x6D, 0xB4, 0xFC, 0xAD, 0xF1, 0xAF, 0x05, 0xBD, 0xC6, 0xCA, 0x09, 0xCF, 0x3B, 0xD4, 0xB0, 0xE1, 0x58, 0xEF, 0x71, 0xF4, 0x80, 0xEC, 0xB9, 0xDB, 0xB8, 0xC8, 0x18, 0xBD, 0xE9, 0xBE, 0xB7, 0xCA, 0xE3, 0xD7, 0x2E, 0xD7, 0x9B, 0xC8, 0x2B, 0xBB, 0x8A, 0xB7, 0x1A, 0xBE, 0xED, 0xC4, 0xCD, 0xC6, 0x4F, 0xCC, 0x36, 0xDB, 0xEF, 0xEE, 0xDE, 0xFC, 0xE6, 0xFC, 0xD2, 0xF3, 0xBC, 0xED, 0x35, 0xED, 0xB8, 0xEC, 0x21, 0xE5, 0xE1, 0xD4, 0xAE, 0xC4, 0x61, 0xBA, 0xFE, 0xB7, 0xAD, 0xBE, 0xF0, 0xCA, 0xBF, 0xD6, 0x4C, 0xDD, 0x42, 0xE0, 0xE6, 0xDF, 0x3C, 0xDB, 0xE1, 0xD2, 0xD5, 0xC3, 0x1F, 0xB4, 0x96, 0xAD, 0x87, 0xAF, 0x35, 0xB4, 0x7E, 0xB8, 0x68, 0xBE, 0x9D, 0xC5, 0x3F, 0xCD, 0x5E, 0xD4, 0x57, 0xD6, 0xFD, 0xD2, 0xB6, 0xC9, 0x85, 0xBD, 0xD7, 0xB8, 0xC0, 0xBC, 0xC4, 0xC4, 0xA6, 0xCD, 0x89, 0xD5, 0xA9, 0xDE, 0x35, 0xE7, 0x1F, 0xEE, 0x4F, 0xF3, 0xC3, 0xEE, 0x10, 0xE2, 0x8C, 0xD6, 0xB2, 0xCD, 0x3B, 0xC9, 0x0F, 0xCA, 0xB3, 0xCF, 0xFC, 0xD9, 0xD0, 0xE3, 0x00, 0xE8, 0x07, 0xE6, 0xFD, 0xE2, 0xDE, 0xE2, 0xD7, 0xE3, 0x2F, 0xE4, 0x36, 0xE3, 0x91, 0xE1, 0xDC, 0xE2, 0x39, 0xE8, 0x5C, 0xEC, 0x85, 0xEC, 0xD2, 0xEB, 0xAE, 0xEA, 0x77, 0xE9, 0x4E, 0xEA, 0x2C, 0xEC, 0xC1, 0xED, 0xF1, 0xF2, 0xE4, 0xFC, 0x60, 0x03, 0x45, 0x01, 0xA4, 0xFA, 0xD6, 0xFA, 0xA5, 0x05, 0x48, 0x0D, 0xD1, 0x09, 0x6A, 0xFE, 0x79, 0xEF, 0x1F, 0xE0, 0x82, 0xD0, 0xCB, 0xC7, 0x61, 0xCC, 0x3F, 0xD9, 0xE6, 0xE7, 0xD1, 0xF5, 0xD3, 0x03, 0xF3, 0x0F, 0xD9, 0x14, 0x5C, 0x11, 0x8B, 0x0A, 0x5D, 0x05, 0x4D, 0x00, 0x20, 0xFB, 0x03, 0xF9, 0xA6, 0xF9, 0x7B, 0xFD, 0xC7, 0x05, 0x9F, 0x0F, 0x42, 0x17, 0xD1, 0x1A, 0xB7, 0x16, 0x04, 0x09, 0x7E, 0xF7, 0x4C, 0xE8, 0xCF, 0xDF, 0x73, 0xDF, 0xF1, 0xE0, 0x6E, 0xE3, 0xF5, 0xE9, 0x47, 0xF3, 0x2C, 0xFF, 0x54, 0x07, 0xD0, 0x08, 0x6D, 0x09, 0x8D, 0x08, 0xEC, 0x03, 0xA2, 0xFB, 0x54, 0xF4, 0xA3, 0xF5, 0x57, 0xFC, 0x0E, 0x00, 0x21, 0xFF, 0x20, 0xFB, 0x78, 0xF5, 0xA4, 0xF2, 0xEC, 0xF3, 0xDC, 0xF4, 0x7C, 0xF6, 0x47, 0xFD, 0xC5, 0x0C, 0x38, 0x22, 0xDA, 0x2F, 0x4B, 0x2D, 0x9D, 0x1E, 0x0E, 0x0E, 0x34, 0x07, 0x78, 0x09, 0xC9, 0x0A, 0x80, 0x08, 0xBD, 0x05, 0xA5, 0x06, 0xE6, 0x0D, 0x6A, 0x15, 0x62, 0x15, 0x65, 0x0E, 0x7C, 0x08, 0x71, 0x0D, 0x4B, 0x1A, 0xC6, 0x20, 0x66, 0x1D, 0xA6, 0x14, 0x1D, 0x09, 0x28, 0x00, 0xEB, 0xF9, 0x18, 0xF3, 0x3B, 0xEB, 0x3F, 0xE2, 0xBD, 0xDF, 0x68, 0xE7, 0xD3, 0xF4, 0x09, 0x04, 0x0D, 0x0E, 0x59, 0x13, 0x6C, 0x15, 0x6D, 0x11, 0xCA, 0x0D, 0x86, 0x10, 0x53, 0x16, 0x00, 0x19, 0x47, 0x19, 0x4F, 0x1A, 0x2D, 0x1A, 0x4A, 0x1C, 0x12, 0x24, 0x6F, 0x2E, 0xDD, 0x38, 0x96, 0x40, 0x46, 0x42, 0xF4, 0x3C, 0x9A, 0x32, 0x0A, 0x27, 0xF7, 0x1F, 0xC0, 0x1D, 0x78, 0x19, 0xEF, 0x12, 0xFF, 0x0D, 0x60, 0x0D, 0xD1, 0x14, 0x5A, 0x1E, 0x8E, 0x24, 0x10, 0x2D, 0x07, 0x38, 0x3C, 0x40, 0x67, 0x3F, 0xCB, 0x30, 0x01, 0x1C, 0xE1, 0x0F, 0xC5, 0x13, 0x03, 0x1F, 0xBC, 0x25, 0xAF, 0x24, 0x07, 0x1F, 0xD3, 0x1D, 0x14, 0x23, 0x33, 0x2A, 0x1F, 0x2D, 0xAE, 0x25, 0x89, 0x19, 0xD3, 0x0C, 0xD0, 0xFE, 0xDD, 0xF4, 0x4D, 0xF4, 0xC9, 0xFE, 0x21, 0x0E, 0x92, 0x19, 0x3D, 0x1C, 0x1D, 0x19, 0x6B, 0x18, 0x5B, 0x1A, 0xC9, 0x1A, 0x60, 0x17, 0x64, 0x12, 0xBB, 0x0D, 0x85, 0x06, 0x3A, 0x01, 0x54, 0x03, 0xBD, 0x0A, 0xF7, 0x10, 0xB1, 0x0E, 0xD9, 0x05, 0x64, 0xFF, 0x95, 0x00, 0x09, 0x09, 0x71, 0x15, 0x3F, 0x22, 0x2F, 0x2C, 0xB3, 0x30, 0xF5, 0x31, 0x5E, 0x33, 0xCD, 0x31, 0xB3, 0x2B, 0xC1, 0x24, 0x69, 0x1E, 0x79, 0x15, 0xD6, 0x0B, 0xAC, 0x0D, 0x6D, 0x19, 0xFF, 0x21, 0xC5, 0x28, 0xB8, 0x33, 0x47, 0x41, 0x6B, 0x4B, 0x4E, 0x4C, 0x9E, 0x44, 0x79, 0x3B, 0xEC, 0x36, 0x78, 0x35, 0xCE, 0x33, 0x0F, 0x32, 0x60, 0x32, 0xD3, 0x37, 0x28, 0x41, 0xB2, 0x49, 0x3A, 0x50, 0xD6, 0x53, 0xE4, 0x51, 0xE5, 0x4B, 0x0B, 0x46, 0xD6, 0x41, 0x21, 0x3C, 0x18, 0x31, 0x3C, 0x22, 0x4A, 0x16, 0x6F, 0x15, 0x3B, 0x1E, 0xAD, 0x29, 0xD0, 0x35, 0x83, 0x3B, 0x3B, 0x39, 0xB8, 0x37, 0xC0, 0x37, 0x9A, 0x3A, 0x6F, 0x41, 0xB4, 0x46, 0xA9, 0x47, 0x3E, 0x42, 0xD5, 0x37, 0x5A, 0x2D, 0x62, 0x24, 0x6D, 0x1D, 0xE6, 0x16, 0xE2, 0x0D, 0x7D, 0x02, 0xA5, 0xF8, 0x7D, 0xF3, 0x4C, 0xF5, 0x9F, 0x01, 0x50, 0x13, 0x5E, 0x20, 0x25, 0x26, 0xFB, 0x25, 0x16, 0x22, 0xD9, 0x1D, 0x38, 0x1D, 0xC0, 0x1F, 0xBD, 0x1E, 0x69, 0x15, 0xF9, 0x07, 0xF8, 0x00, 0xF3, 0x04, 0x0B, 0x0E, 0x09, 0x15, 0x06, 0x19, 0xDC, 0x1B, 0x3E, 0x1D, 0x6E, 0x1F, 0x69, 0x24, 0x0F, 0x27, 0xC4, 0x22, 0x81, 0x1C, 0xBD, 0x19, 0xFA, 0x1A, 0x85, 0x20, 0x0E, 0x28, 0x29, 0x31, 0xCD, 0x3A, 0x46, 0x42, 0x3F, 0x49, 0xA9, 0x4D, 0x83, 0x4C, 0xF8, 0x44, 0x31, 0x3A, 0x77, 0x30, 0x36, 0x28, 0xFF, 0x23, 0x59, 0x20, 0x86, 0x1D, 0x1C, 0x20, 0xC0, 0x23, 0xE2, 0x27, 0xF7, 0x2D, 0x31, 0x37, 0x89, 0x3F, 0x8C, 0x42, 0x15, 0x43, 0x4C, 0x40, 0x98, 0x3F, 0xAF, 0x42, 0x30, 0x44, 0xFF, 0x44, 0x2F, 0x43, 0x8D, 0x3F, 0xEB, 0x3C, 0x30, 0x3D, 0x7F, 0x3F, 0x71, 0x3F, 0xF8, 0x3A, 0xC3, 0x30, 0xA8, 0x27, 0xC3, 0x25, 0x39, 0x2B, 0xF4, 0x32, 0x9A, 0x2E, 0x53, 0x1E, 0x44, 0x0F, 0x74, 0x08, 0xF1, 0x0A, 0x78, 0x14, 0x93, 0x1F, 0xDC, 0x23, 0x0F, 0x20, 0x08, 0x1C, 0x3B, 0x1D, 0xBE, 0x1F, 0x37, 0x1F, 0x6A, 0x1D, 0xC2, 0x1B, 0xE5, 0x19, 0x79, 0x17, 0x54, 0x19, 0x3A, 0x1F, 0xE2, 0x1F, 0x6E, 0x1D, 0x8A, 0x21, 0xFF, 0x2B, 0x18, 0x35, 0x42, 0x39, 0x40, 0x37, 0x72, 0x31, 0x7A, 0x2C, 0x08, 0x25, 0x02, 0x1C, 0xB9, 0x16, 0xED, 0x18, 0xF1, 0x1E, 0xCF, 0x1E, 0xD9, 0x1E, 0x94, 0x23, 0x89, 0x27, 0x6B, 0x2A, 0x46, 0x2B, 0x56, 0x2D, 0xAC, 0x31, 0x54, 0x33, 0xEB, 0x2E, 0x5C, 0x25, 0xED, 0x1C, 0xB7, 0x17, 0xBC, 0x15, 0x38, 0x17, 0x32, 0x19, 0x99, 0x1C, 0x58, 0x24, 0xCC, 0x2D, 0x1D, 0x35, 0x4B, 0x38, 0xAA, 0x35, 0xEE, 0x2F, 0xD4, 0x2A, 0x13, 0x27, 0xA2, 0x22, 0xDA, 0x1B, 0xDA, 0x15, 0x1F, 0x14, 0x7C, 0x19, 0x88, 0x22, 0xB5, 0x28, 0x04, 0x29, 0x27, 0x20, 0xCE, 0x12, 0xE7, 0x07, 0xF4, 0x02, 0xA9, 0x04, 0xA1, 0x0A, 0x54, 0x16, 0x26, 0x1F, 0x82, 0x1E, 0xF0, 0x1B, 0x91, 0x16, 0x1E, 0x10, 0x16, 0x0D, 0xCA, 0x06, 0xB0, 0xFE, 0xB9, 0xFC, 0xCC, 0x01, 0xA8, 0x0C, 0xFF, 0x15, 0x02, 0x17, 0x01, 0x14, 0x25, 0x13, 0x66, 0x17, 0x15, 0x1C, 0x03, 0x18, 0x66, 0x09, 0x11, 0xFA, 0x8E, 0xF4, 0x6F, 0xF8, 0xE2, 0x04, 0x50, 0x13, 0x35, 0x1A, 0x93, 0x1B, 0xEF, 0x17, 0xAD, 0x14, 0x6C, 0x18, 0x95, 0x1F, 0xB3, 0x24, 0xB8, 0x22, 0x3E, 0x1C, 0x5D, 0x14, 0xB6, 0x0F, 0x52, 0x14, 0x7A, 0x1A, 0x40, 0x1C, 0xE6, 0x1B, 0x12, 0x1B, 0x1D, 0x1B, 0x4B, 0x1C, 0x5F, 0x1E, 0xAD, 0x23, 0x3F, 0x2B, 0xEB, 0x28, 0x64, 0x1B, 0x90, 0x0F, 0xD6, 0x0A, 0xD2, 0x0D, 0x40, 0x14, 0x8C, 0x1B, 0x2E, 0x27, 0x00, 0x33, 0x89, 0x39, 0xD1, 0x3A, 0xFF, 0x38, 0x21, 0x37, 0x9E, 0x33, 0xA5, 0x2B, 0xA4, 0x21, 0xE9, 0x18, 0x6D, 0x13, 0x13, 0x10, 0x4B, 0x0D, 0xFF, 0x0D, 0x1D, 0x13, 0x6A, 0x1B, 0xAB, 0x24, 0xAC, 0x28, 0xBA, 0x24, 0xB0, 0x1B, 0xC9, 0x11, 0x0B, 0x0A, 0xFD, 0x02, 0x92, 0xFA, 0xA5, 0xF3, 0xFB, 0xF1, 0xC7, 0xF7, 0xFD, 0x02, 0xAB, 0x0C, 0xDD, 0x11, 0x75, 0x13, 0xF4, 0x13, 0x3C, 0x13, 0x34, 0x0F, 0x17, 0x0B, 0xED, 0x05, 0x73, 0x00, 0x3D, 0xFD, 0x06, 0xF8, 0x97, 0xF0, 0xC0, 0xE7, 0x77, 0xE4, 0x8D, 0xEC, 0x13, 0xF9, 0xCC, 0x04, 0x41, 0x09, 0xF6, 0x07, 0x0F, 0x09, 0x68, 0x09, 0x1B, 0x05, 0x08, 0xFE, 0xA0, 0xFD, 0x19, 0x08, 0xF5, 0x13, 0xA4, 0x1A, 0xDA, 0x1A, 0xFD, 0x17, 0x1A, 0x16, 0xD2, 0x12, 0x93, 0x0C, 0xB3, 0x04, 0x05, 0xFF, 0xC0, 0xFD, 0x31, 0xFB, 0xEF, 0xF3, 0x7A, 0xEA, 0xFD, 0xE0, 0x61, 0xDC, 0x31, 0xDD, 0x7B, 0xDC, 0x8C, 0xD8, 0x46, 0xD5, 0x81, 0xD5, 0xA9, 0xD9, 0xC0, 0xE0, 0x6C, 0xE9, 0xEE, 0xF1, 0xB8, 0xF8, 0x2A, 0xFE, 0x3F, 0x03, 0xF3, 0x06, 0x87, 0x08, 0xBC, 0x05, 0x04, 0xFD, 0x7F, 0xF3, 0xE6, 0xEE, 0x1B, 0xF1, 0xEC, 0xF8, 0x44, 0x04, 0x45, 0x10, 0xC1, 0x1A, 0x43, 0x24, 0xCB, 0x29, 0x02, 0x26, 0x4A, 0x18, 0xAA, 0x08, 0x10, 0x00, 0x1F, 0xFC, 0x0E, 0xF8, 0x7B, 0xF5, 0x4D, 0xF7, 0x1C, 0xFC, 0x7F, 0x00, 0x91, 0x04, 0xC2, 0x0A, 0x26, 0x10, 0x65, 0x0E, 0x93, 0x07, 0x03, 0xFE, 0x29, 0xF5, 0xC1, 0xF4, 0xAA, 0xF5, 0xF4, 0xEE, 0x48, 0xE4, 0x43, 0xDF, 0x51, 0xE5, 0xBB, 0xEE, 0x7A, 0xF5, 0xEF, 0xF5, 0x2F, 0xEE, 0xCB, 0xE5, 0x41, 0xE4, 0x2E, 0xEB, 0x79, 0xF3, 0x38, 0xF6, 0xFA, 0xF2, 0xB1, 0xEC, 0x41, 0xE7, 0x8A, 0xE2, 0xEA, 0xE1, 0x15, 0xE7, 0xE6, 0xED, 0x7B, 0xF3, 0x06, 0xF4, 0x3D, 0xF0, 0x8E, 0xEC, 0x17, 0xEC, 0x87, 0xEB, 0xD6, 0xE4, 0xCF, 0xD9, 0xB0, 0xCD, 0x53, 0xC4, 0x88, 0xC0, 0xA4, 0xC1, 0x1B, 0xC6, 0x83, 0xC9, 0xFB, 0xCC, 0x73, 0xD3, 0x73, 0xD7, 0xFA, 0xD4, 0xD9, 0xD2, 0xD5, 0xD5, 0x7E, 0xDA, 0x48, 0xE3, 0x95, 0xEB, 0x16, 0xE9, 0xE6, 0xE1, 0x14, 0xDD, 0x78, 0xDB, 0xEE, 0xDA, 0x01, 0xD7, 0xB3, 0xD1, 0x9D, 0xCF, 0x0F, 0xD2, 0xB3, 0xD3, 0xC3, 0xD1, 0x15, 0xD3, 0xEE, 0xD9, 0x20, 0xE1, 0x7B, 0xE6, 0xD4, 0xEE, 0x7E, 0xF9, 0x5F, 0xFD, 0x9F, 0xF6, 0x8C, 0xE7, 0x31, 0xDA, 0x78, 0xD7, 0xDC, 0xDB, 0x86, 0xE2, 0x74, 0xE8, 0xE8, 0xEA, 0xD7, 0xE9, 0x3B, 0xE5, 0x5A, 0xDF, 0x88, 0xDD, 0x36, 0xE0, 0xAF, 0xE2, 0xD2, 0xE0, 0x4B, 0xDA, 0xE4, 0xD3, 0xCA, 0xD0, 0x5D, 0xD1, 0x60, 0xD8, 0xA9, 0xE7, 0x19, 0xF9, 0xF3, 0xFF, 0xBD, 0xF9, 0x19, 0xED, 0xC6, 0xDF, 0xC9, 0xD6, 0xB7, 0xCF, 0xF0, 0xC8, 0x20, 0xC5, 0xFD, 0xC4, 0xC3, 0xC9, 0xCE, 0xD1, 0xAD, 0xDB, 0x7D, 0xE6, 0x50, 0xEE, 0x65, 0xF2, 0xD9, 0xF7, 0xB9, 0xFF, 0x61, 0x00, 0x99, 0xF5, 0xD3, 0xE7, 0xFE, 0xE2, 0xF7, 0xEB, 0xA0, 0xFA, 0x28, 0x03, 0x03, 0x00, 0x7C, 0xF4, 0xF9, 0xE4, 0xAA, 0xD5, 0xF4, 0xCC, 0xC3, 0xCB, 0xF7, 0xCE, 0x65, 0xD2, 0x18, 0xD6, 0xA8, 0xDE, 0x68, 0xEB, 0x21, 0xF2, 0x61, 0xEA, 0xCB, 0xDC, 0x9F, 0xD1, 0xD2, 0xC7, 0xC8, 0xBF, 0x18, 0xBC, 0x68, 0xC1, 0xA7, 0xCC, 0xFC, 0xD7, 0x80, 0xE0, 0x69, 0xE6, 0xA8, 0xEF, 0x09, 0xFA, 0x5A, 0xFD, 0xD5, 0xF6, 0x20, 0xED, 0x19, 0xE4, 0xE0, 0xD7, 0x7D, 0xCA, 0xC0, 0xC1, 0xB2, 0xC8, 0x25, 0xDC, 0xFA, 0xEC, 0x35, 0xF9, 0x50, 0xFB, 0x3E, 0xF3, 0xA7, 0xE6, 0xF7, 0xD5, 0x61, 0xC7, 0x4F, 0xBE, 0x4C, 0xBC, 0x74, 0xBE, 0xCC, 0xC3, 0x43, 0xD1, 0xD7, 0xE0, 0xD7, 0xEA, 0x25, 0xEC, 0x17, 0xE7, 0x80, 0xE2, 0xA6, 0xDF, 0xD2, 0xDA, 0xD4, 0xD0, 0x6F, 0xC5, 0xC6, 0xBE, 0x9E, 0xBF, 0x43, 0xC6, 0x28, 0xD0, 0x8B, 0xDD, 0x08, 0xEA, 0xBE, 0xF0, 0x69, 0xF3, 0x90, 0xF3, 0xA0, 0xEF, 0x13, 0xEB, 0x5B, 0xE8, 0x73, 0xE3, 0xF9, 0xDE, 0x49, 0xDE, 0x47, 0xE3, 0xE0, 0xEA, 0xB0, 0xE8, 0x68, 0xDF, 0xE6, 0xD8, 0x5C, 0xD7, 0xAC, 0xDA, 0x30, 0xDA, 0x18, 0xCF, 0xCB, 0xC0, 0x60, 0xBB, 0xD8, 0xBE, 0x70, 0xC2, 0x36, 0xC2, 0x4C, 0xC2, 0x49, 0xCD, 0xFD, 0xDE, 0x33, 0xE5, 0x6D, 0xD9, 0xCF, 0xC3, 0xDC, 0xB6, 0x15, 0xBA, 0xDD, 0xC2, 0x94, 0xCB, 0x72, 0xD1, 0xFE, 0xD3, 0x25, 0xDA, 0xA0, 0xE4, 0x21, 0xED, 0x73, 0xED, 0xCC, 0xE3, 0x82, 0xD4, 0x3F, 0xC6, 0x2B, 0xC1, 0xF7, 0xC7, 0xB7, 0xD2, 0x07, 0xD9, 0xBA, 0xDA, 0xB9, 0xDD, 0xCC, 0xE3, 0x8B, 0xEB, 0xB2, 0xF4, 0x81, 0xF8, 0x47, 0xF0, 0x31, 0xDD, 0x64, 0xC9, 0x35, 0xC4, 0xDF, 0xC7, 0x2B, 0xC8, 0xDD, 0xCA, 0x69, 0xCC, 0x84, 0xC8, 0x0B, 0xC7, 0x50, 0xCB, 0xC3, 0xD8, 0xF3, 0xEA, 0x61, 0xF5, 0x12, 0xF4, 0xE9, 0xEF, 0x9D, 0xF4, 0x78, 0xFE, 0x2C, 0x05, 0xAC, 0x05, 0x75, 0x02, 0xE0, 0x00, 0xF3, 0xFB, 0x8F, 0xF4, 0xA2, 0xF3, 0x26, 0xF9, 0x2F, 0x00, 0x1A, 0x05, 0x9D, 0x04, 0x88, 0xF7, 0x9F, 0xE1, 0xA3, 0xD0, 0xE7, 0xCC, 0x36, 0xDB, 0xB8, 0xF2, 0x5E, 0x02, 0xB0, 0x01, 0x68, 0xFA, 0x98, 0xFE, 0xEB, 0x09, 0xAA, 0x0D, 0xC9, 0x05, 0xAD, 0xF7, 0x08, 0xEA, 0x0A, 0xDB, 0x76, 0xCF, 0xE5, 0xCD, 0xFD, 0xD2, 0x04, 0xDC, 0x82, 0xE0, 0xAF, 0xDC, 0x8F, 0xDB, 0xC9, 0xDF, 0xF9, 0xE5, 0x2E, 0xED, 0xB7, 0xEC, 0x76, 0xE2, 0x87, 0xD7, 0x67, 0xCD, 0x78, 0xC5, 0x0A, 0xC5, 0x39, 0xC9, 0xA1, 0xCE, 0xE3, 0xD7, 0xC4, 0xE4, 0xC7, 0xEF, 0x65, 0xF3, 0x28, 0xF0, 0x13, 0xEB, 0xF1, 0xE6, 0x5C, 0xE4, 0x40, 0xE0, 0xDF, 0xD8, 0x9C, 0xD3, 0xF8, 0xD1, 0xDE, 0xCF, 0x1F, 0xCA, 0x4A, 0xC2, 0x08, 0xBF, 0x3E, 0xC2, 0xF9, 0xC8, 0x55, 0xD2, 0x00, 0xDF, 0x04, 0xED, 0x60, 0xF6, 0x97, 0xF9, 0x54, 0xFB, 0xCB, 0xFD, 0x14, 0xFE, 0xBE, 0xF6, 0x6B, 0xE9, 0xC3, 0xE3, 0xD5, 0xEC, 0x83, 0xF9, 0xB4, 0xF8, 0x3F, 0xE4, 0xAD, 0xCC, 0xF8, 0xC6, 0x38, 0xD6, 0x07, 0xEF, 0x02, 0x01, 0xE5, 0x06, 0x4D, 0x05, 0x4D, 0x01, 0xF5, 0x00, 0x22, 0x05, 0xEF, 0x0C, 0xE7, 0x15, 0x5B, 0x1B, 0x80, 0x1A, 0x11, 0x11, 0x7B, 0x03, 0x2D, 0xFA, 0xB9, 0xF8, 0xD2, 0xF7, 0x11, 0xF1, 0xE3, 0xED, 0xAD, 0xF5, 0x5C, 0x05, 0x0F, 0x12, 0x0D, 0x15, 0x0F, 0x16, 0xB3, 0x15, 0x39, 0x10, 0xB1, 0x05, 0x06, 0xF8, 0x8B, 0xEF, 0xB9, 0xEC, 0x16, 0xEF, 0xD6, 0xF8, 0xC4, 0x03, 0xF0, 0x0D, 0xF6, 0x17, 0x88, 0x21, 0xC7, 0x27, 0xEA, 0x21, 0xD1, 0x11, 0x7D, 0x03, 0x31, 0xFE, 0x1D, 0xFE, 0x4C, 0xFA, 0x2D, 0xF2, 0x00, 0xEC, 0x22, 0xEC, 0x0B, 0xF1, 0x0A, 0xF8, 0x6D, 0x01, 0x53, 0x0B, 0x50, 0x10, 0xA1, 0x0A, 0x76, 0xFE, 0x31, 0xF7, 0xE7, 0xF6, 0xE4, 0xF6, 0xDB, 0xEF, 0x78, 0xE3, 0x19, 0xDB, 0x3C, 0xDB, 0x06, 0xE5, 0x19, 0xF7, 0x87, 0x09, 0x50, 0x13, 0x8C, 0x12, 0x99, 0x0D, 0x31, 0x0A, 0x83, 0x07, 0x36, 0x03, 0x62, 0xFF, 0xE0, 0xFF, 0x57, 0x02, 0xD7, 0x01, 0xE2, 0xFE, 0x3E, 0xFD, 0xF4, 0x02, 0x1E, 0x0E, 0x01, 0x13, 0xD8, 0x13, 0x0B, 0x17, 0x4C, 0x14, 0x84, 0x06, 0x5B, 0xF4, 0xC6, 0xE7, 0x65, 0xE2, 0x02, 0xDF, 0xAA, 0xDE, 0xE0, 0xE3, 0xC1, 0xEE, 0x17, 0xFF, 0xE7, 0x0F, 0x56, 0x1C, 0xEC, 0x28, 0xE3, 0x37, 0x41, 0x44, 0x63, 0x4D, 0xEE, 0x4E, 0xA5, 0x46, 0x51, 0x3B, 0x14, 0x2D, 0x30, 0x1D, 0xE6, 0x11, 0x6D, 0x0D, 0x0C, 0x0E, 0x48, 0x10, 0xC5, 0x12, 0xA8, 0x13, 0x99, 0x11, 0x80, 0x0D, 0x85, 0x0A, 0x4A, 0x0D, 0x64, 0x15, 0x37, 0x1F, 0x49, 0x25, 0x56, 0x24, 0xAF, 0x20, 0x74, 0x20, 0x9C, 0x24, 0x4D, 0x26, 0x68, 0x21, 0x03, 0x19, 0xCC, 0x11, 0x58, 0x0F, 0x51, 0x10, 0x69, 0x13, 0x97, 0x19, 0x8D, 0x1F, 0x41, 0x20, 0x9A, 0x1E, 0x2E, 0x20, 0x8C, 0x24, 0x74, 0x2A, 0xB3, 0x2D, 0x74, 0x2B, 0x3E, 0x27, 0xE4, 0x20, 0xC7, 0x18, 0x6A, 0x12, 0x3D, 0x12, 0x44, 0x19, 0x26, 0x1D, 0xC2, 0x17, 0x41, 0x10, 0xC4, 0x0C, 0xAD, 0x0C, 0xA9, 0x0F, 0x16, 0x14, 0xCD, 0x15, 0x27, 0x16, 0xC0, 0x14, 0xB2, 0x14, 0x69, 0x1F, 0x3C, 0x2C, 0xD2, 0x2F, 0x85, 0x2F, 0x11, 0x33, 0xAA, 0x3A, 0xC8, 0x39, 0x23, 0x2B, 0xFA, 0x19, 0x9C, 0x0F, 0x1E, 0x10, 0xC3, 0x14, 0x3B, 0x16, 0x93, 0x18, 0xA6, 0x1E, 0xB1, 0x28, 0x48, 0x33, 0xB2, 0x3A, 0xC8, 0x3F, 0xCC, 0x3E, 0x87, 0x32, 0x66, 0x1D, 0xED, 0x0B, 0x3C, 0x0A, 0x8A, 0x18, 0xB6, 0x2C, 0xF9, 0x37, 0xF3, 0x36, 0x40, 0x34, 0x8E, 0x36, 0x17, 0x3B, 0xED, 0x3B, 0xA2, 0x37, 0xB9, 0x33, 0x44, 0x34, 0xC8, 0x33, 0x39, 0x2F, 0xCC, 0x2C, 0x69, 0x2C, 0x78, 0x28, 0x98, 0x1F, 0xF2, 0x15, 0xB3, 0x12, 0xCA, 0x13, 0xB9, 0x0F, 0x7B, 0x05, 0x4E, 0xFE, 0x05, 0x03, 0xB6, 0x11, 0x84, 0x1F, 0x2B, 0x25, 0x45, 0x21, 0x29, 0x16, 0xB1, 0x0A, 0x1C, 0x00, 0x51, 0xF6, 0x46, 0xF3, 0xCC, 0xF6, 0xE8, 0xFE, 0xB6, 0x0A, 0xC3, 0x12, 0xFA, 0x13, 0xFA, 0x15, 0xDA, 0x1E, 0xEB, 0x2C, 0x39, 0x3B, 0x75, 0x3F, 0xED, 0x32, 0xC4, 0x1C, 0x85, 0x06, 0xF1, 0xF9, 0x2D, 0xFC, 0xD7, 0x09, 0xF3, 0x1B, 0xC0, 0x28, 0x99, 0x32, 0xBD, 0x3E, 0x3A, 0x44, 0xB4, 0x3E, 0x38, 0x33, 0x45, 0x26, 0x69, 0x19, 0x34, 0x0C, 0x39, 0xFF, 0x6B, 0xF5, 0x12, 0xF6, 0x8D, 0x05, 0x71, 0x19, 0x55, 0x20, 0x33, 0x1A, 0xF2, 0x14, 0x6C, 0x18, 0x35, 0x28, 0xD0, 0x3C, 0x05, 0x49, 0x32, 0x4B, 0xBD, 0x43, 0x15, 0x38, 0xF5, 0x33, 0x5A, 0x39, 0x4F, 0x40, 0x92, 0x3D, 0x18, 0x2E, 0x72, 0x1D, 0xBC, 0x1A, 0x66, 0x27, 0x71, 0x34, 0xD3, 0x36, 0xBC, 0x30, 0x19, 0x28, 0x67, 0x1F, 0x3B, 0x17, 0x95, 0x13, 0x80, 0x17, 0x70, 0x20, 0xB6, 0x2A, 0x63, 0x36, 0x98, 0x43, 0x9D, 0x4A, 0xAB, 0x43, 0xCB, 0x33, 0xEC, 0x27, 0x0C, 0x24, 0x21, 0x21, 0x6F, 0x1B, 0x12, 0x16, 0xD4, 0x15, 0x7A, 0x1B, 0xBA, 0x1D, 0xA8, 0x13, 0xAC, 0x04, 0x70, 0xFE, 0xE8, 0x02, 0x37, 0x0C, 0x6C, 0x14, 0x65, 0x18, 0xFD, 0x18, 0x3B, 0x18, 0x73, 0x18, 0xE6, 0x17, 0xFE, 0x14, 0xBB, 0x13, 0xE6, 0x14, 0xB3, 0x15, 0xE1, 0x13, 0x49, 0x12, 0xC0, 0x16, 0xF1, 0x1F, 0xE4, 0x29, 0x4F, 0x33, 0xA9, 0x3A, 0x00, 0x3D, 0xF9, 0x3A, 0x2F, 0x3B, 0xD7, 0x40, 0xCC, 0x45, 0x1A, 0x3D, 0x8A, 0x24, 0xFD, 0x0C, 0x02, 0x06, 0xBB, 0x0F, 0x68, 0x1C, 0x3C, 0x21, 0x8D, 0x20, 0x0C, 0x20, 0x3E, 0x20, 0x02, 0x1B, 0x39, 0x0F, 0x5F, 0x01, 0x45, 0xF4, 0x74, 0xEB, 0x5F, 0xE7, 0x09, 0xE9, 0x12, 0xF3, 0xCB, 0x04, 0x66, 0x1A, 0x99, 0x29, 0x3A, 0x2B, 0x08, 0x24, 0x7B, 0x1D, 0x1B, 0x1C, 0x21, 0x1D, 0x83, 0x1E, 0x30, 0x22, 0x64, 0x28, 0x43, 0x2A, 0xF0, 0x1F, 0xA9, 0x0D, 0x9A, 0x02, 0x15, 0x0A, 0xC8, 0x1F, 0x96, 0x35, 0xE0, 0x40, 0x7A, 0x40, 0x02, 0x38, 0xFD, 0x29, 0x42, 0x1F, 0x4A, 0x20, 0x4A, 0x27, 0x34, 0x2A, 0x97, 0x24, 0x60, 0x1A, 0xD4, 0x13, 0x75, 0x12, 0x2F, 0x13, 0x12, 0x14, 0x67, 0x16, 0x60, 0x1D, 0xDC, 0x23, 0x4B, 0x1F, 0x0A, 0x11, 0x5B, 0x05, 0x3A, 0x03, 0x16, 0x08, 0x17, 0x0C, 0x07, 0x0B, 0x72, 0x0B, 0xA3, 0x11, 0x30, 0x19, 0xC6, 0x1B, 0xA8, 0x13, 0xCF, 0x05, 0xE2, 0xFE, 0x29, 0x07, 0xB3, 0x1D, 0xA5, 0x34, 0x3F, 0x3F, 0x34, 0x3A, 0xC3, 0x2B, 0xA7, 0x21, 0x86, 0x20, 0xDC, 0x23, 0xD6, 0x25, 0x36, 0x24, 0x4C, 0x21, 0x01, 0x1B, 0x59, 0x10, 0xC3, 0x06, 0x03, 0x06, 0x6E, 0x0E, 0xFE, 0x12, 0x3E, 0x0C, 0x06, 0x03, 0x6C, 0x00, 0x0E, 0x01, 0x64, 0xFF, 0x8A, 0xFE, 0xDB, 0x00, 0x16, 0x00, 0xFB, 0xF2, 0x12, 0xE0, 0xB6, 0xD9, 0xA2, 0xE1, 0xD2, 0xEC, 0xBD, 0xF2, 0x29, 0xF2, 0xB2, 0xF4, 0xB9, 0x00, 0xD7, 0x0F, 0xD0, 0x1A, 0x22, 0x22, 0x0A, 0x28, 0x51, 0x28, 0xE7, 0x1E, 0x13, 0x13, 0x45, 0x0F, 0x1A, 0x13, 0xCD, 0x18, 0xF1, 0x1F, 0x27, 0x27, 0xA7, 0x27, 0x09, 0x21, 0x93, 0x1A, 0xC9, 0x1B, 0xA2, 0x27, 0x4E, 0x37, 0xF5, 0x3F, 0xEF, 0x3A, 0x6B, 0x2C, 0x4E, 0x21, 0x28, 0x1E, 0x6F, 0x1D, 0x74, 0x1A, 0x7E, 0x13, 0xA1, 0x09, 0x46, 0x01, 0x12, 0xFD, 0xAD, 0xFA, 0xBD, 0xF8, 0x26, 0xF9, 0x2C, 0xFF, 0x74, 0x09, 0x2D, 0x10, 0x1B, 0x10, 0x2A, 0x0F, 0x22, 0x16, 0xC2, 0x22, 0xA8, 0x28, 0xB8, 0x25, 0x5A, 0x21, 0x92, 0x1F, 0x5C, 0x1E, 0xD5, 0x1A, 0xF5, 0x13, 0x2D, 0x06, 0x9A, 0xF2, 0x40, 0xE5, 0xF0, 0xE6, 0x4D, 0xF0, 0x8A, 0xF3, 0x44, 0xF0, 0xD3, 0xF2, 0x78, 0xFF, 0xCC, 0x0B, 0x61, 0x0F, 0xE4, 0x0E, 0x9F, 0x12, 0xE2, 0x19, 0xF5, 0x1D, 0x46, 0x1B, 0x86, 0x13, 0xE5, 0x0A, 0xBC, 0x02, 0x9F, 0xFB, 0xF7, 0xF4, 0xA5, 0xEB, 0x80, 0xE3, 0x8E, 0xE2, 0x8C, 0xE9, 0x76, 0xF3, 0xBE, 0xF6, 0xE7, 0xF2, 0x15, 0xEF, 0x6B, 0xEC, 0x20, 0xE5, 0x0C, 0xD8, 0xC8, 0xD1, 0xC2, 0xDC, 0xDC, 0xF3, 0xC0, 0x0B, 0xAC, 0x1B, 0x9A, 0x20, 0xC2, 0x17, 0x59, 0xFF, 0xDD, 0xE3, 0xE9, 0xD5, 0x8B, 0xD9, 0xB7, 0xE9, 0x8B, 0xF8, 0x5D, 0xFA, 0x00, 0xF4, 0xC3, 0xF0, 0x55, 0xF8, 0xBE, 0x06, 0x0C, 0x10, 0xC8, 0x11, 0x87, 0x11, 0x2F, 0x13, 0x51, 0x14, 0xF1, 0x0F, 0xB0, 0x08, 0xE6, 0x03, 0xF4, 0xFF, 0x21, 0xFA, 0xBE, 0xF3, 0xEE, 0xED, 0x74, 0xE9, 0xF4, 0xE6, 0x3B, 0xE9, 0x57, 0xF4, 0x17, 0x02, 0x74, 0x0A, 0xB1, 0x11, 0x5C, 0x1A, 0x74, 0x18, 0xAE, 0x05, 0x56, 0xF6, 0x41, 0xFD, 0x8F, 0x0C, 0xA6, 0x0D, 0x50, 0x02, 0xD5, 0xFB, 0xB1, 0x00, 0x2C, 0x08, 0x37, 0x09, 0x9C, 0x05, 0x2E, 0x02, 0xE8, 0xFF, 0xCD, 0x00, 0x5C, 0x05, 0x3F, 0x0D, 0x9A, 0x18, 0xF7, 0x23, 0xC1, 0x2A, 0x52, 0x28, 0x4C, 0x1E, 0x67, 0x13, 0xCA, 0x08, 0xD8, 0xFE, 0xA8, 0xF5, 0x32, 0xEE, 0x32, 0xEF, 0x1B, 0xF9, 0xEF, 0x04, 0x21, 0x0D, 0xCB, 0x0C, 0x9A, 0x05, 0x01, 0xFF, 0x73, 0xF9, 0xD1, 0xEF, 0x5F, 0xE4, 0x41, 0xE2, 0xA9, 0xF0, 0xC2, 0x07, 0x6B, 0x14, 0x0D, 0x0F, 0x7F, 0x01, 0x47, 0xF3, 0xA5, 0xE9, 0xE1, 0xE5, 0xCA, 0xE1, 0xC6, 0xDF, 0xA6, 0xE2, 0xD8, 0xE5, 0x28, 0xE7, 0xA3, 0xE5, 0xEF, 0xE3, 0x1F, 0xE5, 0x11, 0xE6, 0x18, 0xE0, 0x7E, 0xD1, 0xC3, 0xC3, 0x2E, 0xC1, 0x27, 0xCA, 0x95, 0xD3, 0xA0, 0xD4, 0x95, 0xD2, 0x20, 0xD1, 0xDA, 0xCE, 0xAB, 0xCB, 0x8C, 0xC9, 0xF7, 0xCA, 0xBB, 0xC9, 0xD9, 0xC4, 0x85, 0xC5, 0x23, 0xCF, 0x12, 0xDE, 0xDB, 0xE8, 0xE1, 0xE9, 0xEB, 0xE3, 0x67, 0xDE, 0xF4, 0xDF, 0x30, 0xE3, 0x02, 0xE3, 0xDE, 0xE0, 0xE3, 0xDE, 0x66, 0xDF, 0x11, 0xDD, 0x1C, 0xD4, 0xB5, 0xCA, 0xDE, 0xCA, 0x76, 0xD7, 0x5D, 0xE5, 0x1A, 0xED, 0x5C, 0xF0, 0x9F, 0xF0, 0x80, 0xF1, 0x95, 0xF5, 0xC3, 0xF9, 0x8C, 0xF9, 0x15, 0xF6, 0x45, 0xF4, 0x64, 0xF6, 0x81, 0xFB, 0x42, 0x01, 0x52, 0x05, 0xEE, 0x05, 0x99, 0x02, 0xF8, 0xFD, 0x5D, 0x01, 0x7B, 0x0D, 0x76, 0x11, 0x38, 0x05, 0x8E, 0xF2, 0x98, 0xE8, 0xDA, 0xEA, 0x74, 0xEE, 0xD3, 0xF0, 0x07, 0xF5, 0x36, 0xFA, 0x07, 0xFE, 0x5B, 0xFB, 0x2B, 0xF4, 0x57, 0xEF, 0x3E, 0xEC, 0xDF, 0xE6, 0xFE, 0xE1, 0xB4, 0xE0, 0xFE, 0xDE, 0xBA, 0xDB, 0x18, 0xDB, 0x1E, 0xE2, 0xE6, 0xEB, 0x1C, 0xEE, 0x39, 0xED, 0xF9, 0xEF, 0x5C, 0xF6, 0xC8, 0xFC, 0xAB, 0xFE, 0x3F, 0x01, 0x5F, 0x05, 0x1C, 0x04, 0x86, 0xFF, 0xEB, 0xFD, 0x9E, 0xFD, 0xD2, 0xF2, 0x38, 0xDC, 0xC0, 0xC7, 0x56, 0xBB, 0x82, 0xB5, 0x1D, 0xB7, 0xB3, 0xC2, 0x77, 0xD5, 0xFF, 0xE0, 0xE0, 0xDC, 0x70, 0xD3, 0xEF, 0xCF, 0x28, 0xD2, 0x73, 0xD5, 0x15, 0xD7, 0xCD, 0xD5, 0x41, 0xD2, 0x39, 0xD1, 0x81, 0xD6, 0x54, 0xDE, 0x50, 0xE2, 0xFE, 0xE2, 0x6A, 0xE5, 0x40, 0xEB, 0x37, 0xF3, 0x0C, 0xF9, 0x45, 0xF9, 0xF9, 0xF6, 0x74, 0xF4, 0xB5, 0xF2, 0xD6, 0xF4, 0xA3, 0xF8, 0x6F, 0xF5, 0xDA, 0xE6, 0xB9, 0xD8, 0xEB, 0xD6, 0xEE, 0xD9, 0xFE, 0xD8, 0xB2, 0xD4, 0x11, 0xD2, 0xF8, 0xD4, 0xC8, 0xD8, 0x99, 0xDC, 0x77, 0xE4, 0xF5, 0xEC, 0xAF, 0xF1, 0x2D, 0xF1, 0x88, 0xEE, 0xD1, 0xEF, 0xA8, 0xF4, 0xCA, 0xF8, 0xD4, 0xF9, 0xE6, 0xF8, 0x85, 0xF9, 0xDA, 0xFC, 0x56, 0xFD, 0x8F, 0xF6, 0x2C, 0xF1, 0x55, 0xF3, 0x70, 0xF7, 0x6E, 0xFA, 0xBF, 0xFA, 0x31, 0xF7, 0xB7, 0xF3, 0x24, 0xF5, 0x6C, 0xFA, 0xB6, 0xFE, 0x3A, 0x02, 0x4E, 0x05, 0xCA, 0x04, 0x17, 0x00, 0x9A, 0xF9, 0x76, 0xF3, 0x59, 0xEC, 0x5C, 0xE6, 0xCE, 0xE7, 0xDF, 0xEF, 0x0B, 0xF6, 0x47, 0xF2, 0xF5, 0xE8, 0x25, 0xE6, 0x13, 0xE9, 0x91, 0xE9, 0x7B, 0xE9, 0xDF, 0xEE, 0xEC, 0xF5, 0xEF, 0xF2, 0xD6, 0xE3, 0xF3, 0xD6, 0x97, 0xD8, 0x01, 0xE4, 0x33, 0xEA, 0xE9, 0xE2, 0xD0, 0xD6, 0x4B, 0xD3, 0x5A, 0xDA, 0x5F, 0xE3, 0x8A, 0xE7, 0x76, 0xEB, 0x00, 0xF5, 0x7B, 0x00, 0xEB, 0x07, 0xE4, 0x0A, 0x45, 0x0C, 0xEC, 0x0C, 0xB7, 0x0A, 0x57, 0x04, 0xB7, 0xFD, 0xFC, 0xF8, 0xDD, 0xF1, 0x94, 0xE7, 0x0E, 0xDF, 0xF7, 0xDD, 0x6A, 0xE5, 0xE3, 0xEF, 0xA7, 0xF7, 0x55, 0xFB, 0x81, 0xFF, 0xFE, 0x04, 0xEB, 0x03, 0x00, 0xF9, 0x33, 0xE9, 0xC0, 0xDC, 0x2A, 0xD9, 0x98, 0xDB, 0x15, 0xDE, 0x4D, 0xE0, 0xD1, 0xE8, 0x36, 0xF8, 0xDD, 0x02, 0x2A, 0x00, 0x73, 0xF4, 0x34, 0xEA, 0x33, 0xE3, 0x7B, 0xD6, 0xD1, 0xC4, 0xE6, 0xBB, 0x3C, 0xC0, 0xD8, 0xC9, 0x72, 0xD3, 0xD1, 0xDC, 0xAE, 0xE6, 0xED, 0xF0, 0x41, 0xF6, 0x15, 0xF4, 0xDC, 0xF1, 0x53, 0xF5, 0xC8, 0xF9, 0x66, 0xF7, 0x36, 0xF1, 0x88, 0xF1, 0x76, 0xF9, 0x53, 0x01, 0xDB, 0x03, 0x4A, 0x04, 0x44, 0x06, 0x37, 0x07, 0x00, 0x05, 0x20, 0x00, 0x50, 0xFB, 0x41, 0xF6, 0xC8, 0xEE, 0x9A, 0xE7, 0x36, 0xE2, 0x44, 0xE0, 0x7E, 0xE3, 0x8F, 0xE8, 0xD4, 0xEB, 0xBD, 0xEE, 0x3F, 0xF6, 0x63, 0xFF, 0x7E, 0xFF, 0xC5, 0xF3, 0xAC, 0xE8, 0xD7, 0xE8, 0x11, 0xEC, 0xC1, 0xE8, 0xA3, 0xE0, 0xDA, 0xDE, 0xB5, 0xEC, 0x2F, 0xFE, 0x1E, 0x04, 0x0A, 0x03, 0x4F, 0x06, 0xA1, 0x0B, 0xDF, 0x05, 0x3C, 0xF5, 0x0B, 0xE8, 0x83, 0xE7, 0x28, 0xEE, 0xBC, 0xF1, 0x94, 0xF2, 0xE9, 0xF3, 0x5F, 0xF2, 0xA7, 0xEB, 0xAE, 0xE5, 0x9A, 0xE6, 0xB8, 0xEA, 0x25, 0xE9, 0xA9, 0xDC, 0x0B, 0xC9, 0x48, 0xB7, 0x29, 0xB1, 0xD2, 0xB9, 0x44, 0xC7, 0xA2, 0xD2, 0xEB, 0xDD, 0x26, 0xE9, 0xCF, 0xEF, 0xC0, 0xED, 0x03, 0xE8, 0xB6, 0xE6, 0x90, 0xE9, 0x10, 0xE8, 0x5A, 0xDD, 0xBA, 0xD2, 0xBD, 0xD1, 0x12, 0xD8, 0x69, 0xDF, 0x34, 0xE7, 0xAA, 0xF2, 0xBF, 0xFE, 0x32, 0x05, 0xF5, 0x05, 0xCA, 0x08, 0x4E, 0x10, 0x10, 0x14, 0x5E, 0x13, 0xF6, 0x14, 0xB8, 0x16, 0xE9, 0x10, 0x11, 0x02, 0xCD, 0xF3, 0x73, 0xEE, 0x00, 0xF0, 0xEA, 0xF3, 0x83, 0xF8, 0x1E, 0xFE, 0x1E, 0x01, 0x03, 0xFE, 0x77, 0xFC, 0x07, 0x04, 0x75, 0x0F, 0xB9, 0x13, 0xC1, 0x0D, 0x87, 0x07, 0x26, 0x09, 0xAF, 0x0E, 0x85, 0x10, 0x23, 0x0D, 0x1D, 0x08, 0x06, 0xFF, 0x60, 0xF0, 0x15, 0xE3, 0x9C, 0xDA, 0x0D, 0xD8, 0x1A, 0xDC, 0x95, 0xE8, 0xF8, 0x00, 0x31, 0x1A, 0xE0, 0x1F, 0x8F, 0x0B, 0x67, 0xEE, 0x14, 0xE0, 0x77, 0xE1, 0x01, 0xE3, 0xDB, 0xDE, 0x1E, 0xE2, 0xFD, 0xF6, 0x61, 0x0F, 0xFC, 0x19, 0xD0, 0x12, 0xD3, 0x02, 0x7F, 0xF7, 0xDE, 0xEF, 0x7F, 0xE7, 0x27, 0xE3, 0x1B, 0xEA, 0x04, 0xFD, 0x1D, 0x0C, 0x3E, 0x08, 0x57, 0xF8, 0xD2, 0xEE, 0xF3, 0xF4, 0x43, 0x02, 0x9A, 0x07, 0x01, 0x02, 0x16, 0xFB, 0xC7, 0xF7, 0x13, 0xF4, 0xB5, 0xEF, 0xD2, 0xF3, 0xA8, 0x05, 0x57, 0x19, 0xF7, 0x1E, 0xDA, 0x15, 0x12, 0x0A, 0xA5, 0x03, 0x0A, 0x00, 0x02, 0xFD, 0x6B, 0xFA, 0x1F, 0xF5, 0xD5, 0xEC, 0xBA, 0xE9, 0x05, 0xF6, 0xF2, 0x0E, 0x79, 0x21, 0xBD, 0x1E, 0x28, 0x0D, 0x2F, 0xFC, 0x2D, 0xF3, 0xB3, 0xF0, 0xDB, 0xF1, 0xF2, 0xF7, 0x1F, 0xFF, 0xDE, 0xFE, 0xF6, 0xF9, 0x66, 0xF6, 0xE3, 0xF2, 0xF9, 0xED, 0x79, 0xEB, 0xA0, 0xEF, 0xEB, 0xF3, 0xBD, 0xF0, 0xFE, 0xEA, 0xE4, 0xE7, 0xDB, 0xE3, 0xE7, 0xDB, 0xEE, 0xD6, 0xA1, 0xDC, 0xCF, 0xE6, 0xA4, 0xE6, 0x4A, 0xD7, 0xE0, 0xC7, 0xF9, 0xC6, 0x8C, 0xD0, 0xC4, 0xDD, 0xF3, 0xED, 0x41, 0x01, 0x43, 0x11, 0xE9, 0x10, 0xEC, 0xFF, 0x9A, 0xEC, 0xF5, 0xDF, 0x4A, 0xD7, 0x78, 0xD0, 0x9D, 0xD1, 0x8A, 0xDB, 0xCF, 0xE5, 0x53, 0xEA, 0x0C, 0xE9, 0x5E, 0xE5, 0x44, 0xE2, 0xC5, 0xE1, 0xD9, 0xE3, 0x8E, 0xE6, 0x14, 0xEA, 0x53, 0xF3, 0xFE, 0x08, 0xAB, 0x25, 0x93, 0x35, 0xE6, 0x2A, 0x50, 0x10, 0xA4, 0xFF, 0x81, 0x02, 0xCA, 0x0C, 0x22, 0x11, 0xAD, 0x0C, 0x95, 0x07, 0x6B, 0x0B, 0x77, 0x16, 0xF9, 0x1C, 0x44, 0x17, 0xEB, 0x09, 0x7B, 0xFF, 0x87, 0xF9, 0xAA, 0xEF, 0x15, 0xE5, 0x40, 0xE9, 0x80, 0x00, 0x3A, 0x1C, 0xCB, 0x29, 0xA3, 0x28, 0xA8, 0x24, 0xAF, 0x22, 0xE7, 0x24, 0x25, 0x2B, 0x81, 0x2F, 0xC2, 0x2D, 0x73, 0x26, 0xE8, 0x20, 0x88, 0x21, 0xA2, 0x20, 0x5B, 0x17, 0x55, 0x0B, 0x03, 0x07, 0xBE, 0x08, 0x2E, 0x07, 0x9B, 0x00, 0x88, 0xF8, 0x01, 0xF4, 0xAF, 0xF4, 0x64, 0xF6, 0x57, 0xF7, 0x2E, 0xF8, 0x08, 0xF6, 0xA0, 0xED, 0x46, 0xE3, 0x0D, 0xE0, 0x07, 0xE6, 0x31, 0xED, 0xE1, 0xEF, 0xD4, 0xF0, 0xFC, 0xF0, 0x12, 0xF2, 0xA1, 0xF5, 0x55, 0xF5, 0x04, 0xF0, 0x5E, 0xEB, 0x29, 0xEB, 0xBB, 0xEF, 0xC5, 0xF3, 0x74, 0xF2, 0x52, 0xEE, 0xAD, 0xED, 0x59, 0xF1, 0xE4, 0xF5, 0x69, 0xFD, 0x68, 0x09, 0x34, 0x11, 0x88, 0x0C, 0x58, 0xFF, 0xF9, 0xF2, 0x03, 0xED, 0x41, 0xEC, 0x75, 0xEB, 0xFB, 0xE8, 0x1A, 0xE6, 0xD3, 0xE2, 0x20, 0xDE, 0x50, 0xD7, 0xB9, 0xCE, 0xCA, 0xC7, 0x28, 0xCA, 0xC2, 0xD7, 0x9E, 0xE5, 0x24, 0xE9, 0x71, 0xE7, 0xC7, 0xEB, 0x65, 0xF4, 0xDC, 0xF4, 0xB1, 0xE8, 0xC8, 0xE0, 0xF2, 0xEE, 0xDB, 0x0B, 0x9C, 0x24, 0x24, 0x2E, 0x17, 0x2B, 0x20, 0x25, 0x22, 0x1E, 0xB3, 0x11, 0xD3, 0xFE, 0xD6, 0xEC, 0x49, 0xE3, 0x3B, 0xE1, 0xA9, 0xE3, 0xCE, 0xE7, 0xF2, 0xEF, 0x1C, 0x05, 0xCE, 0x24, 0x44, 0x3C, 0x20, 0x3B, 0x4E, 0x23, 0x3F, 0x08, 0x5B, 0xFA, 0xF5, 0xF9, 0xC7, 0x00, 0xDF, 0x07, 0x4D, 0x0A, 0x18, 0x0A, 0x30, 0x0C, 0xC3, 0x10, 0x30, 0x11, 0xA7, 0x0A, 0x18, 0x05, 0x96, 0x0A, 0x74, 0x1A, 0x29, 0x24, 0x28, 0x1D, 0x83, 0x10, 0x0C, 0x0A, 0x5E, 0x07, 0x6E, 0x02, 0xCC, 0xFE, 0x45, 0x05, 0xFC, 0x12, 0x2A, 0x18, 0x07, 0x0E, 0x53, 0x02, 0xCA, 0x04, 0x4E, 0x13, 0x7E, 0x1C, 0x44, 0x18, 0x55, 0x13, 0xFE, 0x16, 0x49, 0x1E, 0xA5, 0x22, 0xD4, 0x1F, 0xD1, 0x15, 0xA1, 0x09, 0xBA, 0xFE, 0xDF, 0xF4, 0xC1, 0xEC, 0x5F, 0xE9, 0x42, 0xEC, 0x4D, 0xF3, 0xE3, 0xF9, 0xAF, 0xFC, 0xA9, 0xFD, 0xB0, 0x01, 0xF1, 0x08, 0xD4, 0x0E, 0x5A, 0x10, 0x05, 0x0F, 0x61, 0x0C, 0x8F, 0x05, 0x85, 0xFD, 0x6E, 0x00, 0xA6, 0x0E, 0x3F, 0x16, 0x4B, 0x0B, 0x58, 0xF8, 0xBB, 0xEE, 0xC9, 0xF0, 0x76, 0xF2, 0x1E, 0xED, 0xEF, 0xEB, 0x70, 0xF7, 0xB9, 0x04, 0x4D, 0x0B, 0x85, 0x10, 0x1D, 0x16, 0xCD, 0x14, 0xD1, 0x06, 0x9E, 0xF2, 0x08, 0xEA, 0x5A, 0xF2, 0x47, 0xFA, 0x4D, 0xF6, 0x19, 0xEE, 0x32, 0xEB, 0xB5, 0xED, 0xF1, 0xEF, 0x1E, 0xF1, 0xB5, 0xF5, 0x7D, 0xFC, 0xA4, 0x00, 0x57, 0x03, 0x34, 0x08, 0x30, 0x0D, 0x0E, 0x0D, 0x66, 0x07, 0x6E, 0xFE, 0xD5, 0xEE, 0xDE, 0xD8, 0x18, 0xCA, 0x83, 0xD0, 0xD5, 0xEA, 0x32, 0x04, 0xF8, 0x08, 0x52, 0xFF, 0x92, 0xF8, 0x9C, 0xF9, 0x13, 0xFD, 0x74, 0x00, 0x5C, 0x07, 0xF4, 0x10, 0xC4, 0x14, 0xB6, 0x0C, 0xEE, 0xFB, 0x13, 0xEB, 0x62, 0xE2, 0x99, 0xE4, 0x23, 0xED, 0x56, 0xF6, 0x24, 0xFB, 0x7B, 0xFA, 0xB4, 0xFB, 0x76, 0x03, 0xF5, 0x0D, 0x0E, 0x18, 0x6F, 0x22, 0x91, 0x2A, 0x23, 0x2B, 0x90, 0x22, 0x04, 0x12, 0x9E, 0xFF, 0x13, 0xF6, 0x95, 0xF9, 0x2C, 0x06, 0x56, 0x16, 0x9A, 0x22, 0xC5, 0x26, 0x0F, 0x28, 0x38, 0x29, 0x7B, 0x28, 0x5E, 0x27, 0x46, 0x26, 0x88, 0x24, 0x51, 0x21, 0x43, 0x1B, 0x98, 0x0F, 0x4B, 0xFC, 0x35, 0xEB, 0xB6, 0xE6, 0x44, 0xEF, 0x05, 0x02, 0xAE, 0x11, 0x38, 0x11, 0x9A, 0x05, 0xE9, 0xFA, 0xFC, 0xFA, 0x77, 0x08, 0x2F, 0x1B, 0xDF, 0x27, 0xF4, 0x25, 0xD8, 0x14, 0xAF, 0xFD, 0x37, 0xED, 0xAC, 0xED, 0xF2, 0xF9, 0x31, 0x02, 0x16, 0x06, 0x06, 0x10, 0xF8, 0x22, 0x62, 0x3B, 0xC8, 0x4A, 0x9A, 0x42, 0x02, 0x2C, 0xF0, 0x1A, 0xEC, 0x15, 0x50, 0x13, 0x39, 0x08, 0x4A, 0xFA, 0x38, 0xF4, 0xD2, 0xF7, 0xB4, 0x04, 0xAE, 0x14, 0x6D, 0x1D, 0xEF, 0x1C, 0xEE, 0x17, 0xA8, 0x12, 0x1F, 0x0E, 0xF6, 0x09, 0xD7, 0x06, 0xA2, 0x05, 0xA9, 0x03, 0x75, 0xFB, 0xA9, 0xEE, 0xCE, 0xE7, 0xE6, 0xEC, 0x5D, 0xF7, 0x29, 0xFE, 0x41, 0x01, 0xFC, 0x04, 0x09, 0x09, 0xF5, 0x0A, 0xA6, 0x0C, 0x54, 0x12, 0x85, 0x1B, 0xA8, 0x20, 0x7A, 0x19, 0x56, 0x06, 0xA4, 0xF3, 0x5C, 0xEF, 0x35, 0xF8, 0xD5, 0x01, 0x4A, 0x05, 0x15, 0x03, 0x7E, 0xFE, 0xE7, 0xF9, 0xD5, 0xF8, 0x62, 0x02, 0x0B, 0x19, 0xBC, 0x31, 0xE3, 0x39, 0x0B, 0x2D, 0x44, 0x1A, 0x64, 0x13, 0xBC, 0x1B, 0x65, 0x23, 0x11, 0x20, 0x74, 0x18, 0x49, 0x11, 0xBE, 0x0C, 0x47, 0x0C, 0xB0, 0x0E, 0x53, 0x14, 0xFE, 0x17, 0xB7, 0x14, 0x1A, 0x10, 0xC0, 0x0E, 0xA5, 0x0D, 0xD6, 0x08, 0x8B, 0x01, 0x89, 0xFC, 0x33, 0xFA, 0x5B, 0xF8, 0xE1, 0xFA, 0x45, 0x03, 0xB8, 0x0A, 0x68, 0x0F, 0xF4, 0x13, 0xBD, 0x17, 0xBC, 0x1A, 0xFA, 0x1B, 0x48, 0x19, 0x40, 0x14, 0x2A, 0x11, 0xA4, 0x11, 0x68, 0x13, 0x58, 0x15, 0x69, 0x18, 0x4A, 0x1C, 0xB8, 0x1E, 0xAC, 0x1C, 0x58, 0x14, 0x38, 0x06, 0xEF, 0xF5, 0x28, 0xEB, 0xDA, 0xEA, 0x98, 0xF0, 0x3B, 0xF7, 0xCE, 0xFF, 0xE2, 0x0C, 0x9D, 0x1C, 0x4E, 0x27, 0x63, 0x29, 0xB6, 0x27, 0x1D, 0x28, 0xE1, 0x2B, 0x83, 0x2F, 0x1B, 0x30, 0x8C, 0x2B, 0xFE, 0x21, 0x55, 0x18, 0xA5, 0x11, 0x55, 0x0D, 0xFA, 0x06, 0xF7, 0xFB, 0x1E, 0xF3, 0x27, 0xF3, 0x28, 0xFB, 0x49, 0x06, 0x43, 0x0F, 0xF4, 0x14, 0x84, 0x18, 0xB1, 0x16, 0xE3, 0x0D, 0xCC, 0x02, 0xB2, 0xF9, 0xE8, 0xF8, 0xBB, 0x06, 0x9D, 0x1F, 0xC6, 0x35, 0x23, 0x3A, 0xE3, 0x2F, 0xAA, 0x29, 0xDA, 0x2E, 0x89, 0x37, 0xAB, 0x38, 0x1E, 0x31, 0xE4, 0x2B, 0x2F, 0x2B, 0xE8, 0x24, 0xCD, 0x16, 0xC0, 0x08, 0xF3, 0x00, 0x05, 0xFE, 0xE0, 0xFB, 0x21, 0xFB, 0x08, 0xFF, 0x19, 0x09, 0x1C, 0x15, 0xA0, 0x1D, 0x8B, 0x24, 0xB5, 0x2B, 0x8D, 0x30, 0x89, 0x30, 0xAC, 0x29, 0xB2, 0x1D, 0x6B, 0x12, 0xE7, 0x0B, 0x44, 0x0A, 0xF3, 0x0B, 0x5A, 0x10, 0xBC, 0x16, 0xAD, 0x1A, 0xD1, 0x19, 0x15, 0x17, 0x94, 0x11, 0x96, 0x06, 0x5A, 0xF8, 0x6B, 0xEC, 0x2D, 0xE7, 0x0D, 0xE7, 0x09, 0xE8, 0xDD, 0xE9, 0x6D, 0xF0, 0x13, 0xFC, 0x1A, 0x06, 0xB9, 0x0A, 0x83, 0x0A, 0x4C, 0x06, 0x2D, 0x01, 0x1F, 0xFF, 0xA8, 0xFF, 0xAF, 0xFE, 0x03, 0xFE, 0xD3, 0x04, 0x71, 0x15, 0xBB, 0x27, 0x78, 0x2E, 0x91, 0x26, 0x99, 0x17, 0x70, 0x08, 0x60, 0x00, 0x84, 0x06, 0x9B, 0x17, 0xDE, 0x26, 0x7E, 0x29, 0x6E, 0x1E, 0x3B, 0x0D, 0x20, 0xFD, 0x07, 0xF2, 0xD1, 0xED, 0x52, 0xEF, 0x78, 0xF4, 0x94, 0xFB, 0x91, 0x04, 0x48, 0x0F, 0x95, 0x17, 0xDF, 0x18, 0xA0, 0x14, 0x29, 0x11, 0x6B, 0x12, 0xC6, 0x16, 0x93, 0x18, 0x7B, 0x15, 0x4A, 0x11, 0xC0, 0x0B, 0x0E, 0x00, 0x1C, 0xEE, 0x3C, 0xDC, 0xB9, 0xD3, 0xF9, 0xDA, 0x8B, 0xEC, 0xB4, 0xF9, 0xE4, 0xFA, 0x6B, 0xF3, 0x92, 0xEC, 0xF2, 0xED, 0x23, 0xF4, 0xD0, 0xF9, 0x57, 0x00, 0xEB, 0x0A, 0x29, 0x17, 0xF8, 0x1C, 0xDA, 0x1B, 0xC7, 0x1C, 0xED, 0x22, 0x40, 0x27, 0xB4, 0x21, 0x85, 0x12, 0x3E, 0x02, 0x0B, 0xF9, 0xB6, 0xF8, 0x01, 0xFD, 0x78, 0xFD, 0x54, 0xF8, 0x55, 0xF6, 0xA7, 0xFC, 0x4A, 0x08, 0xC1, 0x12, 0x54, 0x17, 0xC1, 0x17, 0x3B, 0x18, 0x8A, 0x1A, 0x61, 0x1C, 0xE1, 0x1A, 0x8B, 0x17, 0xA0, 0x15, 0x50, 0x16, 0xD0, 0x19, 0xF4, 0x1E, 0xE0, 0x21, 0x79, 0x20, 0x2A, 0x1C, 0x95, 0x17, 0x0D, 0x15, 0xE4, 0x12, 0x13, 0x0F, 0x54, 0x0B, 0xBF, 0x08, 0x19, 0x06, 0xD8, 0x00, 0x26, 0xF6, 0x83, 0xE6, 0x34, 0xD9, 0x5C, 0xD8, 0x79, 0xE4, 0x15, 0xF2, 0xD6, 0xFA, 0xA8, 0x04, 0x62, 0x14, 0xA1, 0x24, 0x93, 0x2A, 0xA6, 0x24, 0xD5, 0x1F, 0x57, 0x25, 0x0A, 0x30, 0x6C, 0x37, 0xD3, 0x38, 0x64, 0x36, 0xA3, 0x31, 0x2A, 0x29, 0x78, 0x1C, 0xC9, 0x0E, 0x6F, 0x05, 0x31, 0x06, 0x66, 0x11, 0x1C, 0x1E, 0x32, 0x25, 0x3D, 0x27, 0xF5, 0x25, 0x8E, 0x23, 0xC2, 0x22, 0xDB, 0x23, 0xDF, 0x23, 0xBF, 0x1F, 0xCA, 0x17, 0x72, 0x0E, 0x7C, 0x07, 0xA8, 0x06, 0x4F, 0x0B, 0xF0, 0x10, 0x72, 0x13, 0xA2, 0x11, 0x56, 0x0B, 0x40, 0x01, 0x20, 0xF8, 0xC4, 0xF5, 0x64, 0xF9, 0xFF, 0xFB, 0xFC, 0xF8, 0x86, 0xF2, 0xCF, 0xEE, 0x04, 0xF1, 0x69, 0xF7, 0x9D, 0x00, 0xF7, 0x0B, 0x0D, 0x18, 0x8A, 0x1F, 0xA9, 0x1E, 0x19, 0x1C, 0x44, 0x19, 0x8A, 0x0E, 0x0C, 0xFC, 0x24, 0xE8, 0x82, 0xDA, 0xCD, 0xD8, 0x0A, 0xE0, 0xB2, 0xEB, 0x67, 0xFA, 0x0D, 0x05, 0x38, 0x03, 0xA3, 0xF9, 0x27, 0xF3, 0x24, 0xF2, 0x8E, 0xF0, 0x32, 0xEA, 0x0D, 0xE2, 0x0E, 0xDD, 0x81, 0xDE, 0x9E, 0xE7, 0xDE, 0xF7, 0x54, 0x09, 0x22, 0x11, 0xD3, 0x0C, 0x4B, 0x03, 0xED, 0xFA, 0x57, 0xF6, 0xF1, 0xF4, 0x71, 0xF6, 0x50, 0xFB, 0xC2, 0x01, 0x79, 0x06, 0xC9, 0x08, 0x9C, 0x07, 0xC1, 0x01, 0x22, 0xFB, 0xBA, 0xF7, 0x5B, 0xF9, 0xEF, 0xFE, 0xEC, 0x04, 0x48, 0x09, 0x0F, 0x0A, 0xF8, 0x06, 0x42, 0x02, 0x37, 0xFF, 0x80, 0xFD, 0x19, 0xFA, 0x7F, 0xF8, 0x1F, 0xFC, 0x53, 0x02, 0x50, 0x06, 0xAC, 0x06, 0xD7, 0x07, 0x8A, 0x0C, 0x6E, 0x14, 0x65, 0x1A, 0xD9, 0x16, 0x66, 0x0B, 0xB7, 0x01, 0x36, 0x03, 0x93, 0x0D, 0x85, 0x13, 0xAE, 0x0D, 0x70, 0x01, 0x84, 0xFB, 0x31, 0x02, 0xF7, 0x0E, 0xDE, 0x17, 0x73, 0x18, 0x38, 0x13, 0xDA, 0x0C, 0x74, 0x08, 0xCB, 0x06, 0xF9, 0x05, 0x35, 0x04, 0x59, 0x02, 0xC9, 0x02, 0x3C, 0x06, 0xAB, 0x09, 0x0C, 0x0A, 0x97, 0x08, 0xE2, 0x07, 0x06, 0x08, 0x9D, 0x08, 0xC1, 0x0C, 0x01, 0x16, 0x62, 0x1E, 0x2A, 0x20, 0x6D, 0x1B, 0x27, 0x15, 0xB8, 0x11, 0x98, 0x0D, 0xAE, 0x04, 0x61, 0xFA, 0x6E, 0xF6, 0xA4, 0xFB, 0x02, 0x03, 0x28, 0x05, 0xA2, 0x01, 0x5E, 0xFF, 0xE7, 0x05, 0xE3, 0x12, 0x43, 0x1B, 0x50, 0x16, 0x9E, 0x0A, 0x4C, 0x06, 0x73, 0x0A, 0x8D, 0x0E, 0x8C, 0x0D, 0xB8, 0x07, 0x14, 0xFF, 0x06, 0xF7, 0xEF, 0xF4, 0xE8, 0xFA, 0x06, 0x05, 0x6A, 0x0B, 0xA7, 0x0A, 0x2F, 0x08, 0xD8, 0x06, 0x92, 0x03, 0xC4, 0xFE, 0xFE, 0xFC, 0x38, 0xFF, 0xDD, 0xFF, 0x57, 0xFC, 0x62, 0xFB, 0x96, 0x01, 0x36, 0x0A, 0x54, 0x10, 0xE2, 0x11, 0xB2, 0x0E, 0x6A, 0x0A, 0x9A, 0x06, 0x2C, 0x02, 0xC4, 0xFF, 0x6E, 0x03, 0xFA, 0x0B, 0x8F, 0x11, 0x9C, 0x0E, 0x7D, 0x04, 0xCF, 0xF7, 0x79, 0xEF, 0x81, 0xEF, 0x54, 0xF4, 0x8D, 0xF9, 0x09, 0xFF, 0x5C, 0x04, 0xB8, 0x08, 0x41, 0x0D, 0xA7, 0x0F, 0x45, 0x0C, 0x11, 0x03, 0x9E, 0xF7, 0xAE, 0xEF, 0x98, 0xEA, 0x92, 0xE3, 0x1D, 0xDC, 0x27, 0xD9, 0xBC, 0xDC, 0x39, 0xE4, 0x3F, 0xEB, 0x01, 0xF0, 0x14, 0xF4, 0x9D, 0xF6, 0x76, 0xF2, 0x04, 0xE9, 0xF2, 0xE1, 0x2D, 0xE2, 0xCC, 0xE9, 0x03, 0xF2, 0x1D, 0xF4, 0xFC, 0xF1, 0xFE, 0xF0, 0x57, 0xF4, 0x9E, 0xFA, 0x50, 0xFF, 0x73, 0xFF, 0x25, 0xFC, 0x3D, 0xFA, 0x84, 0xFB, 0xB4, 0xFC, 0xC3, 0xFC, 0x01, 0xFD, 0xBE, 0xFD, 0xCC, 0xFF, 0xFF, 0x03, 0x87, 0x08, 0x5E, 0x0A, 0x63, 0x09, 0x28, 0x08, 0x28, 0x08, 0x72, 0x07, 0xBA, 0x04, 0x27, 0x03, 0x26, 0x04, 0x57, 0x05, 0x7B, 0x03, 0xA1, 0xFC, 0x52, 0xF5, 0x43, 0xF5, 0xA9, 0xFF, 0x23, 0x10, 0x56, 0x1D, 0xF8, 0x22, 0x2F, 0x24, 0xB3, 0x24, 0x1B, 0x25, 0x20, 0x24, 0x6A, 0x21, 0x37, 0x1D, 0x5E, 0x16, 0xA9, 0x0A, 0xD9, 0xFB, 0x4E, 0xF0, 0x8D, 0xEA, 0x9A, 0xE8, 0xD4, 0xE9, 0xF3, 0xED, 0xD5, 0xF3, 0xCE, 0xF8, 0xE0, 0xF9, 0x71, 0xF8, 0x3B, 0xF8, 0x4C, 0xF9, 0x65, 0xF8, 0x97, 0xF3, 0x74, 0xED, 0xAD, 0xEB, 0x3C, 0xF0, 0x7E, 0xF4, 0xD9, 0xF3, 0x69, 0xF3, 0xC9, 0xF6, 0x72, 0xFB, 0x13, 0xFE, 0xCA, 0xFB, 0xD3, 0xF4, 0x18, 0xEE, 0x08, 0xEB, 0x4C, 0xEA, 0xD2, 0xE8, 0x0D, 0xE4, 0xA4, 0xDE, 0x80, 0xDE, 0x86, 0xE3, 0x14, 0xEA, 0xFF, 0xF0, 0x52, 0xF8, 0x21, 0xFD, 0xDF, 0xFB, 0x29, 0xF8, 0xB2, 0xF5, 0xB7, 0xF0, 0xE0, 0xE8, 0x11, 0xE6, 0xE4, 0xEB, 0x0A, 0xF2, 0xE7, 0xEE, 0x8B, 0xE4, 0x45, 0xDF, 0x7B, 0xE7, 0xB0, 0xF6, 0xDE, 0xFF, 0x55, 0xFD, 0x37, 0xF2, 0xB5, 0xE5, 0xED, 0xDD, 0xBE, 0xDC, 0xD6, 0xDF, 0x6B, 0xE3, 0x98, 0xE6, 0x0F, 0xEA, 0xE7, 0xEC, 0xB4, 0xEE, 0xF4, 0xEF, 0x41, 0xF2, 0x2D, 0xF6, 0x75, 0xF8, 0xCD, 0xF7, 0xFE, 0xF6, 0x82, 0xF8, 0xAC, 0xFB, 0xAC, 0xFF, 0x9E, 0x08, 0xB4, 0x16, 0xCA, 0x1F, 0xCD, 0x1B, 0x43, 0x0E, 0x7E, 0x01, 0x8E, 0xFB, 0xBE, 0xFA, 0x63, 0xFC, 0x5E, 0xFF, 0xA0, 0x00, 0x66, 0xFE, 0x4B, 0xFC, 0x92, 0xFE, 0x51, 0x05, 0x99, 0x0B, 0xD1, 0x0A, 0x62, 0xFF, 0x58, 0xEA, 0x40, 0xD5, 0x56, 0xCD, 0x66, 0xD5, 0x92, 0xE4, 0xD5, 0xEF, 0x13, 0xF4, 0xEF, 0xF8, 0xDE, 0x02, 0xFA, 0x0A, 0x98, 0x0A, 0x86, 0x04, 0x82, 0xFF, 0xE3, 0xFB, 0xE0, 0xF4, 0x14, 0xEA, 0x8A, 0xE1, 0xF3, 0xDF, 0x6E, 0xE3, 0x56, 0xED, 0x91, 0x01, 0xAF, 0x17, 0xA6, 0x21, 0x58, 0x1C, 0xFB, 0x11, 0x01, 0x0D, 0xB0, 0x0A, 0xD1, 0x03, 0x27, 0xF9, 0x74, 0xF1, 0x59, 0xF0, 0x2C, 0xEF, 0x65, 0xE7, 0x26, 0xDF, 0x30, 0xDE, 0xD2, 0xE0, 0x92, 0xDE, 0x08, 0xD6, 0xB0, 0xCD, 0x3F, 0xCB, 0x6D, 0xCE, 0x24, 0xD4, 0xA9, 0xDA, 0x29, 0xE3, 0x12, 0xEF, 0x0A, 0xFB, 0xBA, 0x01, 0xD4, 0x03, 0xDF, 0x02, 0xD7, 0xFC, 0xF5, 0xF5, 0xAC, 0xF4, 0x39, 0xF8, 0x81, 0xFC, 0xB6, 0xFE, 0xDF, 0xFF, 0x56, 0x00, 0xE7, 0xFE, 0x8F, 0xFC, 0xFC, 0xF9, 0xE0, 0xF8, 0xB0, 0xF9, 0xC6, 0xF9, 0xB7, 0xF8, 0xF6, 0xF6, 0x97, 0xF5, 0xD2, 0xF6, 0xCD, 0xFA, 0x36, 0x00, 0x48, 0x04, 0x46, 0x04, 0x12, 0x01, 0xBE, 0xFC, 0x19, 0xF7, 0x1B, 0xF2, 0x6A, 0xF3, 0x08, 0xFB, 0x4C, 0x02, 0xD3, 0x04, 0x5D, 0x03, 0xB2, 0x02, 0x40, 0x04, 0x9B, 0x03, 0x8C, 0x01, 0xC2, 0x03, 0x8C, 0x09, 0x6B, 0x09, 0x17, 0xFD, 0x2A, 0xEE, 0xC2, 0xEB, 0xB5, 0xF6, 0x99, 0x01, 0x23, 0x03, 0x73, 0xFD, 0x70, 0xF5, 0x75, 0xF1, 0xD5, 0xF3, 0xBA, 0xF8, 0xDF, 0xFE, 0xC2, 0x03, 0xF3, 0x03, 0x39, 0x01, 0x01, 0xFF, 0x54, 0xFD, 0xD5, 0xF9, 0xCF, 0xF4, 0x47, 0xF0, 0xEF, 0xED, 0x41, 0xEF, 0x3A, 0xF4, 0x2B, 0xFC, 0xF1, 0x04, 0x08, 0x0B, 0xCF, 0x0B, 0x83, 0x06, 0xB3, 0xFD, 0x71, 0xF5, 0x37, 0xEF, 0x09, 0xEA, 0xFE, 0xE5, 0x65, 0xE6, 0x7B, 0xED, 0xDA, 0xF7, 0xCB, 0x01, 0x40, 0x0A, 0x8A, 0x10, 0xAD, 0x14, 0x7D, 0x14, 0xF9, 0x0E, 0xAA, 0x08, 0x1C, 0x06, 0x75, 0x06, 0xFF, 0x03, 0xBE, 0xFD, 0xFC, 0xF8, 0x53, 0xF8, 0xBD, 0xF8, 0xE6, 0xF5, 0x90, 0xF2, 0x07, 0xF3, 0xC3, 0xF5, 0x40, 0xF8, 0x02, 0xF9, 0x11, 0xF9, 0xD5, 0xF9, 0x55, 0xFA, 0x7F, 0xFA, 0x15, 0xFC, 0x5B, 0xFF, 0x17, 0x00, 0xAC, 0xFA, 0x9D, 0xF0, 0x14, 0xE6, 0x82, 0xDE, 0x18, 0xDB, 0x07, 0xDB, 0xC8, 0xDC, 0xD6, 0xE0, 0x71, 0xE7, 0x27, 0xEF, 0x37, 0xF8, 0x23, 0x02, 0x65, 0x09, 0x52, 0x08, 0x55, 0xFC, 0x3A, 0xEB, 0x21, 0xDE, 0xCC, 0xD8, 0x64, 0xD8, 0x22, 0xDB, 0xB4, 0xE0, 0xD4, 0xE6, 0xEF, 0xEB, 0x84, 0xEE, 0x54, 0xEE, 0x8A, 0xEC, 0xE1, 0xE9, 0xD6, 0xE8, 0xAD, 0xEB, 0x11, 0xF1, 0x03, 0xF6, 0x06, 0xFA, 0xBC, 0xFD, 0x7E, 0xFF, 0xC0, 0xFD, 0x3B, 0xF9, 0x94, 0xF5, 0xDA, 0xF5, 0x14, 0xF7, 0xD9, 0xF4, 0xB3, 0xF0, 0x4A, 0xEE, 0x44, 0xED, 0x8B, 0xEC, 0xA2, 0xED, 0xA0, 0xF1, 0x02, 0xF7, 0x98, 0xFC, 0xD0, 0x03, 0x11, 0x0D, 0xDA, 0x14, 0xCB, 0x17, 0x37, 0x17, 0xD7, 0x15, 0x7D, 0x14, 0x5A, 0x13, 0x81, 0x12, 0xF0, 0x11, 0x24, 0x0F, 0x8A, 0x09, 0x00, 0x06, 0xB6, 0x05, 0x6E, 0x05, 0xBC, 0x02, 0x29, 0xFE, 0xE9, 0xFA, 0x62, 0xF9, 0x18, 0xF8, 0x14, 0xF7, 0xCC, 0xF6, 0xE6, 0xF5, 0x16, 0xF2, 0xB5, 0xED, 0x7D, 0xED, 0x39, 0xF3, 0x1E, 0xFD, 0x57, 0x07, 0x98, 0x0D, 0xD1, 0x0A, 0x9C, 0x00, 0x12, 0xF9, 0x29, 0xFB, 0xBD, 0x03, 0xAC, 0x0A, 0x3D, 0x0E, 0xA9, 0x12, 0x49, 0x18, 0x91, 0x1A, 0xF4, 0x15, 0x1E, 0x0C, 0x97, 0x01, 0x52, 0xFA, 0x4D, 0xF7, 0x87, 0xF5, 0x89, 0xF4, 0xD2, 0xF6, 0x47, 0xFB, 0xA5, 0xFF, 0xEC, 0x01, 0x29, 0xFF, 0x74, 0xF9, 0x17, 0xF6, 0x7D, 0xF6, 0x3C, 0xF9, 0x29, 0xFC, 0x11, 0xFF, 0xA6, 0x02, 0x16, 0x05, 0x13, 0x04, 0xAA, 0xFF, 0x5C, 0xFD, 0xC7, 0x00, 0x3A, 0x03, 0xBA, 0xFD, 0x0A, 0xF1, 0x56, 0xE6, 0x9D, 0xE7, 0xA1, 0xF1, 0x73, 0xF9, 0x1D, 0xFA, 0xE7, 0xF5, 0x35, 0xF2, 0x2B, 0xF2, 0x2C, 0xF4, 0xE4, 0xF4, 0x71, 0xF2, 0x1B, 0xED, 0x32, 0xE7, 0xF9, 0xE3, 0x2C, 0xE5, 0xEE, 0xE7, 0x33, 0xE5, 0x9E, 0xDA, 0x99, 0xD0, 0xED, 0xD0, 0x74, 0xDA, 0x70, 0xE3, 0xDF, 0xE4, 0x39, 0xE1, 0x31, 0xE0, 0xC8, 0xE4, 0xDA, 0xEB, 0xB7, 0xF0, 0x6F, 0xF0, 0x1B, 0xEB, 0x6B, 0xE2, 0xEB, 0xD9, 0x8C, 0xD5, 0xF8, 0xD5, 0xFB, 0xD9, 0x64, 0xE0, 0x19, 0xE8, 0xDD, 0xEF, 0x2B, 0xF6, 0xF9, 0xF8, 0x9C, 0xF7, 0x44, 0xF6, 0xED, 0xF9, 0xCC, 0x02, 0x71, 0x0B, 0x07, 0x0C, 0xB4, 0x02, 0xF2, 0xF6, 0x15, 0xF2, 0xD7, 0xF4, 0x27, 0xF8, 0x6F, 0xF7, 0x14, 0xF5, 0xE9, 0xF5, 0x97, 0xF9, 0xC5, 0xFD, 0xDF, 0x02, 0xA2, 0x07, 0xC7, 0x09, 0xBC, 0x08, 0x1D, 0x07, 0x17, 0x08, 0xB9, 0x09, 0x60, 0x0A, 0x15, 0x0C, 0xC4, 0x0F, 0x1C, 0x14, 0x37, 0x16, 0xEE, 0x13, 0x93, 0x0E, 0x88, 0x09, 0xB1, 0x06, 0xE7, 0x05, 0x98, 0x07, 0x10, 0x0F, 0x3C, 0x1D, 0xF8, 0x29, 0xF4, 0x2A, 0x26, 0x1E, 0x74, 0x0A, 0x01, 0xFA, 0xB4, 0xF4, 0x08, 0xFB, 0x1D, 0x04, 0xFF, 0x08, 0x9E, 0x0A, 0x03, 0x0B, 0x28, 0x0B, 0x7C, 0x0B, 0x11, 0x0C, 0x51, 0x0B, 0xE9, 0x07, 0x76, 0x04, 0xDD, 0x02, 0x5E, 0x03, 0x53, 0x06, 0xB5, 0x0B, 0xF6, 0x12, 0x89, 0x18, 0x39, 0x19, 0x81, 0x16, 0x75, 0x13, 0xE0, 0x11, 0x91, 0x11, 0xA8, 0x10, 0xB5, 0x0B, 0x3C, 0x00, 0x47, 0xF1, 0x36, 0xE7, 0x8B, 0xE8, 0xD3, 0xF0, 0x77, 0xF4, 0xBA, 0xF0, 0x24, 0xEE, 0xDD, 0xF1, 0x38, 0xF6, 0x93, 0xF3, 0x65, 0xEA, 0xC7, 0xE0, 0x6E, 0xDB, 0x0B, 0xDB, 0xDC, 0xDD, 0xCA, 0xE3, 0x92, 0xEC, 0x3C, 0xF3, 0xAB, 0xF3, 0xD2, 0xEF, 0x01, 0xEC, 0x6F, 0xEB, 0x98, 0xED, 0x73, 0xEF, 0xC7, 0xF0, 0xBA, 0xF4, 0xE3, 0xFC, 0x54, 0x02, 0xCB, 0xFA, 0x39, 0xE9, 0xAE, 0xDC, 0x2B, 0xDE, 0xE8, 0xE6, 0x38, 0xEB, 0xA5, 0xEA, 0x92, 0xEC, 0x4B, 0xF1, 0xBB, 0xEF, 0x13, 0xE5, 0x2A, 0xDB, 0x25, 0xDB, 0x81, 0xE2, 0xD3, 0xE5, 0xC7, 0xE1, 0xD2, 0xDD, 0xBF, 0xDC, 0x0E, 0xDD, 0xE8, 0xDE, 0xE8, 0xE3, 0x7A, 0xEC, 0x8F, 0xF3, 0xAE, 0xF4, 0x6F, 0xF4, 0x4E, 0xF9, 0x71, 0x01, 0xBD, 0x06, 0x2F, 0x05, 0x6A, 0xFD, 0x84, 0xF4, 0x05, 0xEE, 0x69, 0xEB, 0xA5, 0xEC, 0x72, 0xEF, 0x25, 0xF3, 0x96, 0xF8, 0x5D, 0xFF, 0x54, 0x04, 0xC9, 0x04, 0x07, 0x02, 0xF3, 0xFE, 0xFF, 0xFC, 0x11, 0xFC, 0xDF, 0xFB, 0x0E, 0xFC, 0x3B, 0xFC, 0x5E, 0xFB, 0x7F, 0xF9, 0xB7, 0xF9, 0x6E, 0xFD, 0x13, 0x02, 0xF5, 0x03, 0xC8, 0x02, 0x08, 0x01, 0x5B, 0xFF, 0x4D, 0xFD, 0x5B, 0xFA, 0x56, 0xF7, 0x35, 0xF3, 0x46, 0xEC, 0x90, 0xE5, 0x64, 0xE1, 0xA4, 0xE1, 0xCE, 0xE5, 0xE4, 0xE8, 0x53, 0xE9, 0xD2, 0xE9, 0xC7, 0xEF, 0xF6, 0xFB, 0xD9, 0x06, 0x4D, 0x0B, 0x32, 0x0A, 0xBD, 0x07, 0x14, 0x07, 0xB8, 0x06, 0x2D, 0x05, 0x5E, 0x03, 0x0E, 0x01, 0x03, 0xFE, 0x60, 0xFB, 0xCA, 0xFA, 0x41, 0xFE, 0x33, 0x05, 0xDD, 0x0D, 0xF6, 0x16, 0xB6, 0x1D, 0x2F, 0x20, 0x9C, 0x1D, 0xD6, 0x16, 0x34, 0x0E, 0x00, 0x07, 0xFA, 0x03, 0xEE, 0x03, 0xB1, 0x04, 0xCA, 0x03, 0x52, 0x02, 0x85, 0x05, 0x39, 0x0D, 0x95, 0x16, 0x94, 0x1F, 0x79, 0x26, 0xEA, 0x29, 0x6A, 0x27, 0x57, 0x20, 0x01, 0x1A, 0x15, 0x17, 0xAB, 0x14, 0x02, 0x0F, 0x55, 0x08, 0x98, 0x05, 0x7C, 0x07, 0x87, 0x0A, 0xE3, 0x0C, 0xFC, 0x0D, 0x93, 0x0B, 0x14, 0x05, 0xDF, 0xFB, 0x4E, 0xF3, 0x4B, 0xEF, 0xBC, 0xED, 0x83, 0xEA, 0xA4, 0xE6, 0x19, 0xE4, 0xE0, 0xE2, 0xA1, 0xE2, 0x32, 0xE2, 0x11, 0xE2, 0xAB, 0xE3, 0x11, 0xE6, 0xB9, 0xE7, 0xE5, 0xE8, 0x8B, 0xEC, 0xEC, 0xF3, 0xFC, 0xF9, 0xDC, 0xF8, 0x9C, 0xF1, 0x3B, 0xEA, 0x95, 0xE7, 0x7B, 0xEA, 0x42, 0xEE, 0x16, 0xF0, 0xC3, 0xF1, 0xE3, 0xF2, 0x73, 0xF2, 0x7A, 0xEF, 0xF9, 0xEA, 0x76, 0xE7, 0x84, 0xE3, 0x87, 0xE0, 0x10, 0xE2, 0x34, 0xE7, 0xD1, 0xEC, 0xEE, 0xEF, 0xAF, 0xF1, 0x46, 0xF5, 0x3B, 0xFA, 0xFB, 0xFD, 0x5B, 0xFF, 0x06, 0x00, 0x7B, 0x01, 0x7D, 0x01, 0x53, 0xFD, 0x30, 0xF8, 0x3C, 0xF7, 0x53, 0xF9, 0x32, 0xFA, 0x12, 0xF8, 0xBE, 0xF3, 0x60, 0xEF, 0x65, 0xEC, 0xCC, 0xEB, 0xAF, 0xEF, 0x05, 0xF7, 0xCB, 0xFC, 0x6D, 0xFE, 0x4C, 0xFD, 0x4D, 0xFD, 0x83, 0x00, 0x3A, 0x03, 0x8C, 0x02, 0x7D, 0xFF, 0xDE, 0xFB, 0x18, 0xF9, 0x6F, 0xF6, 0x0A, 0xF2, 0xF3, 0xEB, 0x77, 0xE8, 0x63, 0xEC, 0x6A, 0xF7, 0x1D, 0x06, 0xBE, 0x12, 0x16, 0x18, 0x3E, 0x16, 0xB2, 0x11, 0x54, 0x10, 0x99, 0x13, 0x52, 0x16, 0x4B, 0x14, 0xD3, 0x10, 0xF6, 0x12, 0xD1, 0x1B, 0xE2, 0x22, 0xDF, 0x1F, 0x9F, 0x12, 0x44, 0xFE, 0x63, 0xEA, 0xDC, 0xE0, 0x96, 0xE4, 0x43, 0xF2, 0xEF, 0xFF, 0x38, 0x06, 0xA6, 0x08, 0x3B, 0x09, 0xB0, 0x05, 0xBD, 0xFE, 0x4B, 0xF9, 0xB0, 0xF8, 0x02, 0xF9, 0x2F, 0xF6, 0xF5, 0xF2, 0xEA, 0xF5, 0x84, 0xFF, 0x01, 0x07, 0x08, 0x06, 0x2E, 0x01, 0x5F, 0x01, 0xB6, 0x06, 0xE0, 0x0A, 0x55, 0x0C, 0xC1, 0x0D, 0xDE, 0x10, 0xB4, 0x13, 0x1A, 0x13, 0x71, 0x0F, 0xB2, 0x0A, 0x3B, 0x06, 0x22, 0x05, 0x4E, 0x08, 0xDE, 0x0B, 0x66, 0x0D, 0xB3, 0x0B, 0xB1, 0x07, 0x54, 0x04, 0x4A, 0x00, 0x8A, 0xFB, 0x2E, 0xFA, 0x8B, 0xFD, 0x33, 0x03, 0x06, 0x0A, 0x55, 0x14, 0x26, 0x21, 0xD1, 0x29, 0xDA, 0x28, 0x4C, 0x1F, 0xF3, 0x11, 0x1A, 0x05, 0x60, 0xFD, 0xE7, 0xFC, 0xFD, 0x00, 0xF4, 0x04, 0x59, 0x07, 0xAF, 0x0B, 0x01, 0x13, 0x35, 0x18, 0x6A, 0x15, 0x36, 0x0D, 0xDE, 0x08, 0xBE, 0x0A, 0x36, 0x0C, 0xAB, 0x07, 0x8F, 0x01, 0x5D, 0x01, 0xD8, 0x04, 0x0B, 0x06, 0xBE, 0x03, 0xA3, 0xFF, 0x19, 0xFA, 0x14, 0xF3, 0xF6, 0xED, 0x6A, 0xED, 0xA3, 0xF0, 0xA3, 0xF5, 0x05, 0xF9, 0x0B, 0xFA, 0x06, 0xFC, 0xA4, 0xFF, 0x8E, 0x04, 0x27, 0x0B, 0x46, 0x10, 0xF8, 0x0F, 0x27, 0x0B, 0x0B, 0x08, 0x88, 0x09, 0xA9, 0x0A, 0x9E, 0x07, 0x20, 0x03, 0xE1, 0x01, 0x38, 0x01, 0x93, 0xF9, 0x7E, 0xEC, 0x49, 0xE4, 0xBF, 0xE7, 0x34, 0xF2, 0xE7, 0xFB, 0x13, 0x05, 0x07, 0x0D, 0x7A, 0x0D, 0x6C, 0x04, 0x67, 0xF9, 0x53, 0xF7, 0xDC, 0xFD, 0x52, 0x00, 0x56, 0xF9, 0x6A, 0xF0, 0xE0, 0xE9, 0x17, 0xE3, 0xED, 0xDC, 0xEC, 0xDD, 0x33, 0xE9, 0x47, 0xF6, 0x2A, 0xFC, 0x5D, 0x00, 0xD4, 0x0A, 0x24, 0x17, 0x05, 0x1D, 0xD4, 0x1A, 0xD0, 0x15, 0xAD, 0x11, 0x3E, 0x0A, 0x9B, 0xFE, 0xB1, 0xF8, 0x80, 0x01, 0xDE, 0x13, 0x80, 0x20, 0x07, 0x22, 0x3C, 0x22, 0x78, 0x29, 0xE2, 0x33, 0x44, 0x35, 0x4A, 0x28, 0x03, 0x16, 0xEA, 0x06, 0x77, 0xFD, 0x44, 0xFC, 0x52, 0x00, 0x83, 0x04, 0xC0, 0x09, 0xC6, 0x0F, 0x40, 0x13, 0x6F, 0x12, 0x31, 0x0E, 0xB5, 0x0A, 0x4E, 0x0B, 0xFA, 0x0D, 0x09, 0x11, 0xD3, 0x15, 0xB7, 0x18, 0x86, 0x13, 0xA4, 0x08, 0xBE, 0xFF, 0x54, 0xFB, 0x04, 0xF8, 0x97, 0xF3, 0xBF, 0xF0, 0xDB, 0xF1, 0x40, 0xF2, 0x2E, 0xEC, 0x19, 0xE4, 0xC5, 0xE3, 0x66, 0xED, 0x93, 0xF8, 0x06, 0xFC, 0xFD, 0xF9, 0x5C, 0xFB, 0x57, 0x01, 0x9E, 0x05, 0x4D, 0x05, 0x1A, 0x05, 0xAE, 0x0A, 0xE5, 0x14, 0x55, 0x1C, 0xE8, 0x1B, 0xBF, 0x16, 0x70, 0x12, 0x58, 0x10, 0x6C, 0x0F, 0xAF, 0x0E, 0xCD, 0x0D, 0xFD, 0x0D, 0xE5, 0x0F, 0xF7, 0x10, 0xD8, 0x0D, 0x6A, 0x07, 0xFB, 0x01, 0x2B, 0x03, 0xF4, 0x0D, 0x00, 0x1B, 0x6D, 0x1F, 0x53, 0x17, 0xA6, 0x08, 0x90, 0xFF, 0xAA, 0xFE, 0x1B, 0xFE, 0x30, 0xFB, 0xE1, 0xF8, 0xAB, 0xF8, 0xA0, 0xFB, 0x55, 0x04, 0xD8, 0x11, 0x4B, 0x1E, 0x7B, 0x25, 0x4B, 0x27, 0xA3, 0x25, 0xFD, 0x22, 0xC5, 0x1F, 0xC0, 0x18, 0x3C, 0x0E, 0x7A, 0x07, 0xC1, 0x07, 0x64, 0x09, 0xE9, 0x06, 0xB0, 0x00, 0x93, 0xF9, 0x1A, 0xF6, 0xF1, 0xFA, 0x9C, 0x06, 0xB1, 0x0F, 0xDD, 0x0B, 0xE2, 0xFC, 0x5C, 0xF0, 0x06, 0xF1, 0xF3, 0xFC, 0x67, 0x07, 0x0F, 0x07, 0x65, 0xFF, 0x30, 0xF9, 0x10, 0xFA, 0x0C, 0x02, 0xF7, 0x0B, 0xFC, 0x12, 0xD1, 0x16, 0x49, 0x19, 0x6B, 0x1B, 0xE4, 0x1B, 0xB2, 0x19, 0x52, 0x16, 0x26, 0x12, 0x7D, 0x0B, 0x3A, 0x01, 0x1D, 0xF7, 0xB8, 0xF3, 0x1E, 0xF9, 0x89, 0x03, 0x45, 0x0C, 0x64, 0x0F, 0x84, 0x0E, 0x73, 0x0D, 0x32, 0x0E, 0xB0, 0x0F, 0x4F, 0x10, 0x42, 0x0F, 0x4E, 0x0C, 0xC1, 0x05, 0x40, 0xFA, 0x56, 0xEE, 0xC0, 0xE8, 0x2F, 0xEA, 0xD1, 0xED, 0x31, 0xF1, 0x57, 0xF5, 0x69, 0xFA, 0x00, 0xFE, 0x68, 0xFE, 0x4E, 0x00, 0xEC, 0x08, 0xD5, 0x15, 0xD9, 0x1E, 0x66, 0x1E, 0xCF, 0x17, 0x42, 0x10, 0x4A, 0x09, 0x73, 0x02, 0xCC, 0xFC, 0x12, 0xFC, 0xA2, 0x00, 0xEA, 0x06, 0x3E, 0x0C, 0x24, 0x10, 0xAB, 0x11, 0xF6, 0x0F, 0x57, 0x0D, 0x87, 0x0B, 0x17, 0x09, 0x52, 0x04, 0x13, 0x00, 0x07, 0x00, 0x79, 0x02, 0xC5, 0x06, 0x30, 0x0D, 0xD5, 0x12, 0xA1, 0x14, 0x5F, 0x13, 0x23, 0x14, 0x38, 0x1A, 0x78, 0x24, 0x60, 0x2E, 0x20, 0x34, 0x85, 0x35, 0x86, 0x32, 0x8F, 0x2B, 0x0D, 0x22, 0x58, 0x18, 0xBB, 0x10, 0xAA, 0x0A, 0x2A, 0x05, 0x2B, 0x00, 0x30, 0xFC, 0xE2, 0xF8, 0x4E, 0xF4, 0xEF, 0xEF, 0x20, 0xF1, 0x42, 0xF9, 0xDD, 0x03, 0x93, 0x0B, 0xD3, 0x0D, 0x79, 0x0C, 0xA7, 0x0A, 0xD6, 0x09, 0xF6, 0x09, 0xED, 0x09, 0x12, 0x09, 0x7D, 0x07, 0x3D, 0x05, 0xA2, 0x01, 0x49, 0xFE, 0x22, 0xFE, 0x39, 0xFF, 0xD8, 0xFE, 0x40, 0xFE, 0x55, 0x01, 0x1B, 0x09, 0xF0, 0x0F, 0xD2, 0x12, 0x7A, 0x15, 0x27, 0x1A, 0xF3, 0x1D, 0x74, 0x1C, 0xCC, 0x15, 0x1E, 0x10, 0x80, 0x0F, 0xB8, 0x10, 0xBF, 0x0F, 0xE7, 0x0A, 0xF1, 0x03, 0x6A, 0x01, 0x69, 0x07, 0x3A, 0x13, 0x1F, 0x1D, 0xB0, 0x1E, 0xBF, 0x18, 0x16, 0x11, 0x46, 0x0C, 0x1B, 0x0B, 0x2D, 0x0D, 0x33, 0x11, 0x83, 0x14, 0x1E, 0x14, 0x98, 0x0E, 0x79, 0x06, 0xD5, 0xFE, 0xEB, 0xF8, 0x2F, 0xF6, 0xE1, 0xF7, 0x49, 0xFB, 0xFE, 0xFA, 0x64, 0xF5, 0xCA, 0xEE, 0x9B, 0xED, 0xE3, 0xF1, 0x11, 0xF5, 0x9D, 0xF3, 0xFF, 0xEF, 0xAF, 0xEE, 0x1F, 0xF0, 0xFF, 0xF0, 0xA0, 0xEE, 0xAE, 0xEA, 0xDF, 0xEA, 0x3F, 0xF1, 0x6A, 0xFA, 0xB7, 0x01, 0x00, 0x05, 0xB4, 0x04, 0xF7, 0x02, 0xE8, 0x03, 0xD3, 0x07, 0x0E, 0x0B, 0x7C, 0x0A, 0xFA, 0x06, 0xDD, 0x04, 0xD6, 0x02, 0x6A, 0xFC, 0xE7, 0xF2, 0x3B, 0xED, 0xA2, 0xEE, 0x06, 0xF0, 0x05, 0xEB, 0x78, 0xE4, 0xC2, 0xE5, 0x53, 0xEE, 0xED, 0xF2, 0xCC, 0xEC, 0x80, 0xE2, 0x9E, 0xDD, 0xDD, 0xDC, 0x5B, 0xDE, 0xCB, 0xE6, 0x7B, 0xF5, 0x8D, 0x03, 0x6C, 0x0B, 0xE6, 0x0F, 0x7B, 0x17, 0x26, 0x1F, 0xEA, 0x1F, 0x36, 0x19, 0x02, 0x0F, 0xE3, 0x05, 0xFE, 0x01, 0x11, 0x03, 0xE3, 0x03, 0x9E, 0xFF, 0x2E, 0xF5, 0x0A, 0xEB, 0xA7, 0xEA, 0x51, 0xF4, 0x92, 0xFF, 0x2F, 0x06, 0x72, 0x09, 0x62, 0x0B, 0x37, 0x0A, 0x04, 0x06, 0x4A, 0x03, 0x01, 0x06, 0x7C, 0x0B, 0xC5, 0x0C, 0x0C, 0x07, 0x43, 0x00, 0x02, 0x00, 0x17, 0x04, 0x26, 0x05, 0xDD, 0x01, 0xB4, 0xFE, 0x47, 0xFF, 0xFD, 0x01, 0x86, 0x05, 0xCF, 0x0B, 0xAA, 0x13, 0x52, 0x19, 0x6E, 0x1B, 0x4E, 0x1D, 0x88, 0x23, 0x39, 0x2C, 0xDB, 0x2E, 0x3D, 0x26, 0xA3, 0x18, 0xE3, 0x0F, 0x6C, 0x0D, 0x01, 0x0D, 0x0C, 0x0B, 0x2B, 0x07, 0x33, 0x04, 0xD1, 0x03, 0x4D, 0x04, 0x37, 0x03, 0x94, 0x01, 0xCD, 0x02, 0x59, 0x07, 0x65, 0x0C, 0x6C, 0x0F, 0xEB, 0x0F, 0x58, 0x0E, 0xDE, 0x0A, 0xA6, 0x05, 0xC1, 0xFF, 0xA4, 0xFA, 0x4B, 0xF7, 0x09, 0xF5, 0xE3, 0xF2, 0x8A, 0xF3, 0x70, 0xF9, 0x63, 0x02, 0xF4, 0x09, 0x5B, 0x0D, 0x29, 0x0F, 0xD8, 0x13, 0x11, 0x1C, 0xDD, 0x23, 0xFD, 0x26, 0xBF, 0x25, 0x14, 0x22, 0xEE, 0x1C, 0x82, 0x16, 0x58, 0x10, 0x4F, 0x0F, 0xB6, 0x13, 0x3D, 0x15, 0x47, 0x0E, 0x1B, 0x04, 0x75, 0x00, 0xFC, 0x05, 0x78, 0x0B, 0x56, 0x08, 0x1F, 0x01, 0x85, 0xFC, 0xCB, 0xF8, 0x53, 0xF0, 0xE6, 0xE2, 0x93, 0xD9, 0x24, 0xDA, 0xFB, 0xDE, 0x70, 0xE0, 0xC8, 0xDD, 0x75, 0xDB, 0x27, 0xDD, 0x27, 0xE4, 0xA6, 0xEE, 0xF7, 0xF7, 0xB0, 0xFC, 0xAC, 0xFE, 0x3F, 0x02, 0x7E, 0x06, 0x37, 0x06, 0x2F, 0x00, 0x1C, 0xFA, 0x1C, 0xF9, 0xDD, 0xFB, 0x52, 0xFF, 0xD9, 0x02, 0x24, 0x07, 0x96, 0x0B, 0x9A, 0x0D, 0x55, 0x0A, 0xFB, 0x01, 0x67, 0xF8, 0x83, 0xF1, 0x9B, 0xF0, 0x86, 0xF5, 0xB0, 0xFC, 0x87, 0x03, 0x85, 0x08, 0x23, 0x0C, 0x55, 0x0E, 0xC4, 0x0D, 0x26, 0x0C, 0x89, 0x0C, 0x68, 0x0F, 0x2A, 0x12, 0x79, 0x12, 0x2E, 0x10, 0x36, 0x0D, 0xC7, 0x0B, 0x09, 0x0C, 0x8E, 0x0C, 0x99, 0x0A, 0xC6, 0x05, 0x54, 0x01, 0xBC, 0xFF, 0x13, 0x01, 0x16, 0x04, 0x2B, 0x07, 0x03, 0x07, 0xE2, 0x01, 0x4F, 0xFA, 0x9A, 0xF2, 0xC4, 0xEC, 0x57, 0xEA, 0x89, 0xEB, 0x4D, 0xF0, 0xD1, 0xF7, 0x05, 0x00, 0x4C, 0x05, 0x46, 0x05, 0xD2, 0x01, 0x77, 0xFE, 0x33, 0xFD, 0x1B, 0xFE, 0xE3, 0x00, 0x56, 0x06, 0x06, 0x0C, 0x2D, 0x0C, 0x7F, 0x06, 0xAE, 0xFF, 0x2C, 0xFB, 0x34, 0xF8, 0xB4, 0xF4, 0x8B, 0xF3, 0x59, 0xF7, 0x4C, 0xFD, 0x1B, 0x01, 0x2C, 0x02, 0x81, 0x02, 0xB2, 0x00, 0xF5, 0xFB, 0xA9, 0xF7, 0x91, 0xF8, 0xB9, 0xFF, 0x4A, 0x06, 0xF3, 0x06, 0x16, 0x05, 0xFF, 0x06, 0xAE, 0x0D, 0xC1, 0x13, 0x9B, 0x14, 0x0E, 0x10, 0x4A, 0x09, 0x26, 0x05, 0xF6, 0x08, 0x35, 0x15, 0xB7, 0x21, 0xDB, 0x26, 0x5A, 0x25, 0xF5, 0x22, 0xA2, 0x21, 0x2F, 0x1E, 0xB4, 0x17, 0x8F, 0x10, 0xAF, 0x0A, 0xEE, 0x04, 0x8D, 0xFF, 0x14, 0xFE, 0x02, 0x00, 0x4A, 0x01, 0x1F, 0xFE, 0x3E, 0xF6, 0x2C, 0xEE, 0xFD, 0xE8, 0x12, 0xE7, 0x6C, 0xE8, 0xBC, 0xED, 0xF8, 0xF6, 0xA6, 0xFF, 0x2A, 0x03, 0xE3, 0x00, 0xD8, 0xFA, 0xD0, 0xF5, 0xCE, 0xF5, 0xBB, 0xFB, 0x06, 0x05, 0x0D, 0x0B, 0x1E, 0x0A, 0xDC, 0x05, 0xBC, 0x03, 0xE5, 0x04, 0x27, 0x06, 0xAF, 0x04, 0xD3, 0x00, 0xAF, 0xFC, 0xB2, 0xFA, 0x4C, 0xFD, 0xFA, 0x02, 0xD6, 0x05, 0xDA, 0x03, 0x13, 0xFF, 0xA5, 0xF8, 0x45, 0xF0, 0xCA, 0xE6, 0x16, 0xE2, 0x3B, 0xE7, 0xD8, 0xF2, 0xEA, 0xFC, 0x7F, 0x00, 0xC8, 0xFF, 0x55, 0x00, 0x80, 0x03, 0x7D, 0x05, 0x88, 0x03, 0x02, 0xFF, 0xD0, 0xFA, 0xD4, 0xF8, 0x85, 0xF8, 0xEB, 0xF7, 0xB1, 0xF5, 0xD8, 0xF3, 0x9D, 0xF6, 0x8B, 0xFD, 0xBA, 0x03, 0xE4, 0x05, 0x78, 0x04, 0x73, 0x02, 0x42, 0x00, 0xF6, 0xFA, 0x1D, 0xF3, 0xC9, 0xEB, 0x4F, 0xE6, 0x41, 0xE4, 0x9F, 0xE6, 0x2D, 0xEC, 0x31, 0xF3, 0x5A, 0xFA, 0x04, 0x00, 0xD9, 0x02, 0xB0, 0x03, 0x88, 0x04, 0x32, 0x07, 0x54, 0x0C, 0xC1, 0x11, 0x9B, 0x14, 0x87, 0x13, 0x2F, 0x0D, 0xB4, 0x00, 0x45, 0xF2, 0x4E, 0xE9, 0x49, 0xE9, 0x62, 0xEF, 0x7D, 0xF5, 0x9F, 0xF8, 0x50, 0xFA, 0x06, 0xFD, 0xFB, 0x01, 0x21, 0x08, 0x6D, 0x0D, 0x1E, 0x0F, 0x5F, 0x09, 0x26, 0xFC, 0x0E, 0xEF, 0x87, 0xEB, 0x53, 0xF4, 0xF8, 0x03, 0xA8, 0x11, 0x53, 0x18, 0xA5, 0x19, 0xB4, 0x1A, 0xDE, 0x1C, 0xBB, 0x1C, 0x29, 0x18, 0x26, 0x10, 0xF8, 0x06, 0x1D, 0xFD, 0x6B, 0xF2, 0xE6, 0xE9, 0x44, 0xE6, 0x39, 0xE6, 0xDD, 0xE5, 0xA3, 0xE4, 0x62, 0xE6, 0x90, 0xED, 0xFF, 0xF8, 0xB0, 0x04, 0x7B, 0x0E, 0x83, 0x15, 0xF3, 0x17, 0x87, 0x16, 0x95, 0x13, 0xA8, 0x0F, 0x3C, 0x08, 0x63, 0xFD, 0x10, 0xF5, 0xEB, 0xF3, 0x20, 0xF8, 0x83, 0xFC, 0x5E, 0x00, 0xBB, 0x06, 0xED, 0x10, 0x47, 0x1B, 0x9E, 0x1E, 0xFB, 0x1B, 0xE1, 0x19, 0xDA, 0x18, 0x61, 0x17, 0x40, 0x15, 0xC2, 0x10, 0xAF, 0x08, 0x9D, 0xFF, 0xF2, 0xF8, 0xB7, 0xF5, 0xD6, 0xF4, 0x7A, 0xF5, 0x30, 0xF9, 0x7B, 0x00, 0x4C, 0x08, 0xC8, 0x0B, 0x11, 0x09, 0x9E, 0x02, 0x8B, 0xFA, 0x65, 0xF2, 0x42, 0xED, 0x43, 0xEE, 0x40, 0xF4, 0x18, 0xFA, 0x9C, 0xFC, 0x13, 0xFC, 0xA6, 0xFA, 0xC1, 0xFA, 0x7C, 0xFD, 0x52, 0x02, 0x19, 0x08, 0x73, 0x0B, 0xA2, 0x07, 0x93, 0xFE, 0xAB, 0xF6, 0xD6, 0xF2, 0xCC, 0xF2, 0xE0, 0xF4, 0x17, 0xF8, 0xB1, 0xFB, 0x9A, 0xFC, 0x1A, 0xF7, 0x17, 0xEC, 0xFF, 0xE0, 0x40, 0xDB, 0xD4, 0xDC, 0x1B, 0xE1, 0x48, 0xE3, 0x0D, 0xE5, 0x1E, 0xE9, 0xF1, 0xEF, 0x40, 0xF9, 0x37, 0x05, 0xA9, 0x12, 0x39, 0x1D, 0x71, 0x21, 0xAA, 0x20, 0xD4, 0x1E, 0x0B, 0x1D, 0x56, 0x19, 0x53, 0x13, 0xE2, 0x0C, 0x0D, 0x07, 0x57, 0x00, 0x5C, 0xF7, 0x4B, 0xED, 0x30, 0xE5, 0x57, 0xE2, 0xE7, 0xE6, 0x24, 0xF1, 0x11, 0xFB, 0x6A, 0xFF, 0x02, 0xFE, 0x13, 0xFB, 0x12, 0xFA, 0x25, 0xFA, 0x52, 0xF8, 0x1B, 0xF3, 0xEF, 0xEC, 0xE3, 0xE9, 0x2F, 0xEA, 0x58, 0xEB, 0xD0, 0xEC, 0x13, 0xEF, 0xDF, 0xF2, 0xC2, 0xF8, 0xFA, 0xFD, 0x66, 0xFF, 0x45, 0xFD, 0xC2, 0xFA, 0x43, 0xFB, 0xB3, 0xFD, 0x3F, 0xFF, 0x86, 0xFF, 0xAC, 0xFE, 0xA7, 0xFB, 0x0A, 0xF6, 0x68, 0xF0, 0xB0, 0xED, 0x1E, 0xEF, 0x17, 0xF4, 0xAC, 0xF9, 0x81, 0xFD, 0xE7, 0xFE, 0x6D, 0xFE, 0x2E, 0xFD, 0x49, 0xFB, 0xF7, 0xF8, 0x2F, 0xF7, 0x92, 0xF7, 0xE0, 0xF9, 0xAA, 0xFB, 0x32, 0xFC, 0x93, 0xFC, 0x21, 0xFE, 0x1A, 0x00, 0x7C, 0x01, 0x03, 0x05, 0x0B, 0x0D, 0x27, 0x17, 0xC4, 0x1C, 0xF5, 0x19, 0x26, 0x13, 0xD9, 0x0D, 0xA6, 0x0A, 0xA9, 0x06, 0x82, 0xFF, 0x87, 0xF7, 0x5F, 0xF3, 0x44, 0xF5, 0x2E, 0xFC, 0x6D, 0x05, 0xAB, 0x0C, 0x62, 0x0D, 0x8C, 0x08, 0xE6, 0x01, 0x0F, 0xFC, 0x3E, 0xF9, 0xC4, 0xF9, 0xDB, 0xFB, 0xBF, 0xFC, 0xB9, 0xFB, 0x1C, 0xFB, 0x33, 0xFC, 0xCA, 0xFE, 0x9E, 0x02, 0xD7, 0x06, 0xFA, 0x08, 0x2E, 0x08, 0x4F, 0x06, 0x50, 0x03, 0x6F, 0xFD, 0xDE, 0xF3, 0xDA, 0xE9, 0xE6, 0xE4, 0x7E, 0xE6, 0xDF, 0xEC, 0x18, 0xF5, 0x94, 0xFD, 0x3B, 0x06, 0x50, 0x0C, 0x96, 0x0C, 0x08, 0x07, 0xB8, 0xFF, 0xF3, 0xFA, 0xFC, 0xF8, 0xB3, 0xF8, 0x08, 0xF9, 0xD6, 0xF9, 0x8F, 0xFB, 0x23, 0xFE, 0x4E, 0x03, 0xAE, 0x0B, 0xA2, 0x13, 0x24, 0x18, 0x76, 0x19, 0xB8, 0x18, 0xDA, 0x15, 0xE9, 0x0E, 0xBC, 0x04, 0xFE, 0xFB, 0xCC, 0xF6, 0xE7, 0xF4, 0x83, 0xF4, 0xA8, 0xF2, 0xE6, 0xEF, 0x6A, 0xEE, 0x12, 0xEF, 0xD6, 0xF1, 0x60, 0xF7, 0x9C, 0x00, 0x11, 0x0A, 0x84, 0x0E, 0xC4, 0x0B, 0x83, 0x02, 0x8A, 0xF6, 0x71, 0xED, 0x41, 0xE9, 0xFE, 0xE7, 0xDC, 0xE8, 0x92, 0xEB, 0xC2, 0xEF, 0x6B, 0xF5, 0x8C, 0xFB, 0x89, 0x01, 0x1C, 0x05, 0x8D, 0x04, 0xCC, 0x00, 0xE4, 0xFA, 0xDB, 0xF5, 0xED, 0xF3, 0x34, 0xF4, 0x60, 0xF4, 0xCE, 0xF3, 0xD2, 0xF5, 0x2B, 0xFC, 0x43, 0x04, 0x9F, 0x08, 0xBF, 0x07, 0xD5, 0x05, 0xC1, 0x03, 0x8D, 0x00, 0xF0, 0xFC, 0x4E, 0xFB, 0xF7, 0xFD, 0x21, 0x02, 0x6E, 0x04, 0xF5, 0x04, 0xDB, 0x04, 0xEA, 0x04, 0x5A, 0x04, 0xC6, 0x02, 0xC2, 0x00, 0x48, 0xFD, 0x45, 0xF8, 0x11, 0xF5, 0xC1, 0xF5, 0x60, 0xF9, 0x12, 0xFD, 0x30, 0xFD, 0x95, 0xF9, 0xDB, 0xF4, 0x05, 0xF1, 0x73, 0xEF, 0x65, 0xEF, 0x07, 0xEE, 0x5F, 0xE9, 0x8D, 0xE3, 0x55, 0xE2, 0x16, 0xEA, 0xE0, 0xF8, 0xA8, 0x06, 0x44, 0x0D, 0xAB, 0x0D, 0x59, 0x0A, 0xDD, 0x03, 0x4F, 0xFC, 0xE5, 0xF5, 0x90, 0xF1, 0x89, 0xF0, 0x46, 0xF3, 0x3D, 0xF8, 0x94, 0xFB, 0xC9, 0xFA, 0x39, 0xF7, 0xE3, 0xF3, 0x96, 0xF2, 0xE8, 0xF1, 0x1E, 0xF1, 0xCA, 0xF2, 0xA7, 0xF8, 0x0A, 0x00, 0x66, 0x02, 0xBC, 0xFD, 0xBB, 0xF7, 0x52, 0xF5, 0x52, 0xF7, 0x23, 0xFC, 0x80, 0x01, 0x00, 0x06, 0xF5, 0x07, 0xCF, 0x06, 0xA8, 0x04, 0x27, 0x03, 0xD8, 0x01, 0x6E, 0xFF, 0x32, 0xFC, 0x4F, 0xFA, 0x7D, 0xFA, 0x59, 0xFC, 0xA7, 0xFE, 0xC1, 0xFE, 0x98, 0xFB, 0xF6, 0xF6, 0x75, 0xF4, 0x45, 0xF6, 0xD8, 0xF9, 0xE2, 0xFA, 0x64, 0xF7, 0xBE, 0xF0, 0x19, 0xEC, 0x4D, 0xED, 0xFC, 0xF2, 0xA9, 0xFA, 0x75, 0x01, 0x80, 0x06, 0x38, 0x0C, 0xA4, 0x11, 0xA6, 0x13, 0x26, 0x12, 0xDB, 0x0E, 0x5B, 0x0B, 0x09, 0x09, 0xCE, 0x08, 0x79, 0x09, 0xF0, 0x08, 0x4F, 0x05, 0x15, 0xFE, 0xFF, 0xF4, 0x81, 0xEC, 0xF9, 0xE7, 0x15, 0xE8, 0x68, 0xEB, 0xE2, 0xF1, 0x05, 0xFA, 0x6F, 0x01, 0x5E, 0x07, 0x04, 0x0C, 0x47, 0x0E, 0x31, 0x0D, 0xF0, 0x09, 0x7E, 0x06, 0xBC, 0x05, 0x64, 0x07, 0xF0, 0x07, 0x3B, 0x05, 0x7C, 0xFF, 0xA0, 0xFA, 0x92, 0xF9, 0xDE, 0xFB, 0x83, 0x01, 0x80, 0x07, 0x4C, 0x08, 0xD0, 0x03, 0x36, 0xFF, 0x7D, 0xFD, 0x3C, 0xFE, 0x55, 0x00, 0x74, 0x02, 0xF7, 0x04, 0x46, 0x09, 0x35, 0x0F, 0x1F, 0x15, 0xC4, 0x18, 0xE1, 0x17, 0x6C, 0x12, 0xA9, 0x0A, 0xDD, 0x02, 0x0C, 0xFC, 0xF8, 0xF4, 0xBB, 0xEC, 0x00, 0xE5, 0xA9, 0xDD, 0x06, 0xD6, 0x91, 0xD1, 0xBB, 0xD3, 0xF4, 0xDB, 0xB9, 0xE5, 0xEA, 0xEA, 0x76, 0xEB, 0xB7, 0xEB, 0x74, 0xED, 0x5E, 0xF1, 0x74, 0xF7, 0xE3, 0xFF, 0x13, 0x09, 0xA0, 0x0D, 0x9A, 0x0B, 0xB9, 0x05, 0xEC, 0x00, 0x84, 0x00, 0x15, 0x01, 0x61, 0xFE, 0xF3, 0xF8, 0x4C, 0xF4, 0x96, 0xF2, 0x93, 0xF3, 0x1A, 0xF6, 0xEC, 0xF7, 0xE2, 0xF7, 0xA8, 0xF5, 0x50, 0xF1, 0xFF, 0xEB, 0x56, 0xE7, 0x4B, 0xE6, 0x92, 0xEA, 0x8B, 0xF2, 0x37, 0xFA, 0xB5, 0xFD, 0xA3, 0xFC, 0x1B, 0xF8, 0x08, 0xF2, 0x08, 0xEE, 0xE1, 0xEF, 0xC1, 0xF6, 0x05, 0xFC, 0x73, 0xFB, 0xC0, 0xF7, 0x61, 0xF7, 0xF9, 0xFB, 0xF1, 0xFE, 0xFD, 0xFB, 0x4B, 0xF6, 0xE4, 0xF3, 0xAA, 0xF7, 0xC1, 0xFE, 0xB0, 0x04, 0xDD, 0x07, 0x1A, 0x09, 0x13, 0x08, 0x41, 0x04, 0x00, 0x00, 0x0E, 0xFE, 0x67, 0xFD, 0x5A, 0xF9, 0x25, 0xF2, 0xD0, 0xEE, 0xBB, 0xF2, 0x63, 0xFA, 0x88, 0x00, 0x2E, 0x03, 0xB8, 0x03, 0x50, 0x03, 0x85, 0x01, 0x61, 0xFE, 0xD5, 0xFC, 0x61, 0x00, 0xA5, 0x08, 0xC5, 0x10, 0xF3, 0x12, 0xDE, 0x0E, 0x3A, 0x0A, 0x8B, 0x0A, 0xBF, 0x0F, 0xDC, 0x13, 0x89, 0x11, 0x32, 0x0B, 0x5C, 0x08, 0xBC, 0x0C, 0x86, 0x13, 0xB5, 0x14, 0xCD, 0x0E, 0x17, 0x06, 0x32, 0xFD, 0x98, 0xF4, 0x7B, 0xED, 0xA6, 0xEA, 0xEC, 0xEC, 0x7A, 0xF0, 0x50, 0xF2, 0x70, 0xF3, 0xD3, 0xF4, 0x73, 0xF5, 0x6F, 0xF4, 0x3A, 0xF4, 0xE5, 0xF8, 0xB8, 0x02, 0xF1, 0x0C, 0x4C, 0x11, 0x37, 0x0F, 0x6F, 0x0C, 0x88, 0x0C, 0x43, 0x0E, 0x84, 0x0E, 0x32, 0x0B, 0x16, 0x06, 0x8D, 0x02, 0xC2, 0x00, 0x1C, 0xFE, 0x81, 0xFA, 0xE8, 0xF7, 0x96, 0xF5, 0x40, 0xF2, 0x18, 0xEF, 0xD4, 0xED, 0xD6, 0xEE, 0x1E, 0xF1, 0x5C, 0xF4, 0x4B, 0xF9, 0x6B, 0xFF, 0x44, 0x04, 0x28, 0x05, 0x1B, 0x03, 0x8D, 0x02, 0xCF, 0x04, 0xF7, 0x07, 0x82, 0x0A, 0xFF, 0x0B, 0x10, 0x0C, 0x67, 0x09, 0x87, 0x05, 0xA9, 0x03, 0xFE, 0x04, 0x54, 0x0B, 0x27, 0x14, 0x0E, 0x18, 0xCC, 0x14, 0x11, 0x0D, 0x50, 0x04, 0x60, 0xFD, 0xD1, 0xF8, 0xEC, 0xF6, 0xC9, 0xF7, 0x48, 0xF9, 0x51, 0xF9, 0x44, 0xF7, 0xBA, 0xF4, 0x56, 0xF4, 0xE1, 0xF5, 0x96, 0xF7, 0x24, 0xF8, 0x35, 0xF8, 0x29, 0xFA, 0xAD, 0xFD, 0x7E, 0x01, 0x9B, 0x04, 0x0B, 0x05, 0xC7, 0x01, 0x2D, 0xFB, 0x16, 0xF4, 0xB0, 0xF0, 0x57, 0xF1, 0x56, 0xF3, 0xC5, 0xF5, 0xC3, 0xF8, 0x7F, 0xFB, 0x71, 0xFC, 0xA9, 0xFA, 0x58, 0xF8, 0x6E, 0xF6, 0x0C, 0xF4, 0x12, 0xF2, 0x15, 0xF1, 0xF2, 0xF2, 0x3B, 0xF8, 0xFA, 0xFD, 0x06, 0x01, 0xF8, 0xFE, 0xAF, 0xF9, 0x28, 0xF6, 0x81, 0xF7, 0x93, 0xFC, 0x56, 0x00, 0x79, 0xFE, 0x77, 0xF6, 0x5A, 0xEC, 0x19, 0xE6, 0x38, 0xE7, 0xA6, 0xED, 0xFF, 0xF4, 0x30, 0xFD, 0x4C, 0x07, 0xB4, 0x10, 0x59, 0x14, 0xBE, 0x10, 0x9C, 0x0A, 0x0B, 0x06, 0x39, 0x03, 0x81, 0x00, 0xEC, 0xFB, 0x1A, 0xF6, 0x0B, 0xF2, 0x36, 0xF0, 0x95, 0xEE, 0x6A, 0xEC, 0x1D, 0xEB, 0x5D, 0xEB, 0xCA, 0xEA, 0x55, 0xE9, 0x25, 0xEB, 0x6A, 0xF2, 0x03, 0xFC, 0x45, 0x01, 0x66, 0x01, 0x65, 0x01, 0xEA, 0x02, 0xC0, 0x04, 0x55, 0x06, 0x71, 0x09, 0x4E, 0x0E, 0x36, 0x11, 0xF2, 0x0D, 0x61, 0x03, 0x03, 0xF8, 0x30, 0xF4, 0x86, 0xF8, 0x91, 0xFD, 0xFD, 0xFC, 0xC7, 0xF8, 0x13, 0xF6, 0x3A, 0xF7, 0x3C, 0xF9, 0x9A, 0xF7, 0xFF, 0xF1, 0xD4, 0xEB, 0xF1, 0xE9, 0x47, 0xEE, 0xA9, 0xF7, 0xB9, 0x01, 0x2E, 0x07, 0x63, 0x07, 0x4F, 0x04, 0x0B, 0x02, 0xD6, 0x03, 0xF2, 0x07, 0x6C, 0x0A, 0x24, 0x08, 0xD8, 0x03, 0x75, 0x03, 0xFD, 0x07, 0x21, 0x0E, 0xE7, 0x11, 0x3E, 0x12, 0x90, 0x11, 0x77, 0x12, 0x30, 0x15, 0xD4, 0x17, 0x23, 0x19, 0xFE, 0x17, 0x2F, 0x13, 0x5B, 0x0B, 0xE8, 0x02, 0x53, 0xFC, 0x87, 0xF7, 0x6E, 0xF4, 0x94, 0xF4, 0x5A, 0xF6, 0x06, 0xF7, 0x9A, 0xF6, 0xDA, 0xF6, 0x58, 0xF8, 0x47, 0xF8, 0x06, 0xF6, 0x1B, 0xF5, 0x77, 0xF7, 0x40, 0xFB, 0x9D, 0xFD, 0x4B, 0xFE, 0x88, 0xFF, 0x95, 0x03, 0xCD, 0x09, 0xC5, 0x0E, 0x27, 0x10, 0xB7, 0x0D, 0x40, 0x09, 0x40, 0x05, 0x5A, 0x03, 0xD7, 0x03, 0x63, 0x04, 0x4E, 0x02, 0xE8, 0xFD, 0x00, 0xF9, 0x18, 0xF5, 0xFE, 0xF3, 0xAD, 0xF6, 0xDD, 0xFC, 0xC4, 0x04, 0x58, 0x0A, 0x8C, 0x0B, 0x05, 0x09, 0x09, 0x04, 0x47, 0xFE, 0x57, 0xF8, 0xAB, 0xF2, 0xAD, 0xED, 0xB6, 0xE9, 0x30, 0xE8, 0xCC, 0xE9, 0x19, 0xED, 0xD8, 0xEF, 0x2E, 0xF1, 0x1E, 0xF1, 0x8B, 0xEF, 0xD1, 0xED, 0xF9, 0xEE, 0x08, 0xF4, 0x8A, 0xF9, 0xD2, 0xFA, 0x48, 0xF6, 0x71, 0xEF, 0x25, 0xEB, 0xEE, 0xEA, 0xF2, 0xED, 0x75, 0xF3, 0xFE, 0xFA, 0x07, 0x02, 0xAC, 0x06, 0x03, 0x08, 0x5C, 0x03, 0x04, 0xFA, 0xBD, 0xF1, 0x9D, 0xEE, 0xA7, 0xF0, 0xEE, 0xF4, 0x56, 0xF8, 0x3D, 0xF9, 0xDF, 0xF8, 0x67, 0xF8, 0xBF, 0xF8, 0x69, 0xFB, 0x2F, 0xFF, 0x14, 0x01, 0x77, 0xFE, 0x0D, 0xF8, 0x40, 0xF1, 0xFA, 0xEC, 0x9A, 0xED, 0xBE, 0xF2, 0xEB, 0xF8, 0x86, 0xFC, 0xBE, 0xFD, 0x62, 0xFF, 0xDA, 0x01, 0xB0, 0x03, 0xB0, 0x03, 0x90, 0x03, 0x79, 0x06, 0xD4, 0x0B, 0xC6, 0x0F, 0xFD, 0x0F, 0xD5, 0x0C, 0x20, 0x07, 0xBB, 0x00, 0xD6, 0xFA, 0xC1, 0xF5, 0x3E, 0xF3, 0x5C, 0xF3, 0xDB, 0xF4, 0x9A, 0xF6, 0x55, 0xF8, 0xAB, 0xFB, 0xCB, 0x00, 0xB6, 0x05, 0x30, 0x08, 0x33, 0x07, 0x7D, 0x03, 0x45, 0xFE, 0x59, 0xF8, 0x5E, 0xF2, 0x1A, 0xED, 0x5F, 0xE9, 0x43, 0xE8, 0xC9, 0xE9, 0x28, 0xEC, 0xC9, 0xEE, 0x41, 0xF2, 0x2E, 0xF6, 0x07, 0xFA, 0x53, 0xFD, 0xD2, 0xFE, 0x88, 0xFE, 0x10, 0xFD, 0x6C, 0xF9, 0xA3, 0xF3, 0x3E, 0xEE, 0x15, 0xEC, 0x52, 0xED, 0x6B, 0xEF, 0xF5, 0xF0, 0xAA, 0xF2, 0xA1, 0xF5, 0xF1, 0xF9, 0xF0, 0xFE, 0x48, 0x03, 0x33, 0x05, 0x9D, 0x04, 0xC8, 0x02, 0x8E, 0x00, 0x2B, 0xFE, 0xA3, 0xFB, 0x8E, 0xF9, 0x01, 0xF9, 0x50, 0xFA, 0x19, 0xFC, 0x00, 0xFD, 0x86, 0xFD, 0xAF, 0xFE, 0x3C, 0x00, 0x5A, 0x00, 0x8D, 0xFD, 0x9E, 0xF8, 0xD1, 0xF3, 0x1A, 0xF0, 0x88, 0xED, 0x52, 0xED, 0x1C, 0xF0, 0x98, 0xF5, 0x58, 0xFD, 0x68, 0x05, 0xA9, 0x0A, 0xAC, 0x0B, 0xCC, 0x0A, 0xBB, 0x0B, 0x74, 0x0F, 0x94, 0x12, 0xC8, 0x10, 0x96, 0x0B, 0x2C, 0x07, 0xA3, 0x03, 0x2A, 0x00, 0xE1, 0xFE, 0x7F, 0x01, 0x50, 0x05, 0x9B, 0x05, 0xCB, 0x01, 0x58, 0xFE, 0x59, 0xFF, 0x80, 0x04, 0xA5, 0x0A, 0x7D, 0x0F, 0x9D, 0x12, 0x97, 0x12, 0xF6, 0x0D, 0xCB, 0x07, 0xF3, 0x04, 0x99, 0x07, 0xD5, 0x0F, 0x4F, 0x1A, 0xAB, 0x1F, 0x9E, 0x1B, 0x7A, 0x11, 0xCC, 0x08, 0xDC, 0x06, 0x4E, 0x09, 0x09, 0x0B, 0x54, 0x09, 0x28, 0x03, 0xE1, 0xFA, 0xFB, 0xF4, 0xE6, 0xF5, 0xF1, 0xFD, 0x0F, 0x05, 0xB6, 0x04, 0xBD, 0x01, 0xB0, 0x03, 0x7E, 0x0A, 0x60, 0x13, 0xC0, 0x1C, 0x7F, 0x23, 0x5D, 0x24, 0xFC, 0x1E, 0xF4, 0x18, 0xC6, 0x17, 0xD3, 0x17, 0xB6, 0x12, 0x60, 0x07, 0xEB, 0xF9, 0x2B, 0xEF, 0x4B, 0xE9, 0x41, 0xE8, 0x34, 0xEB, 0xD7, 0xEF, 0xA4, 0xF3, 0x51, 0xF8, 0x77, 0xFE, 0xF7, 0x00, 0xE4, 0xFE, 0x23, 0xFC, 0xFB, 0xF9, 0xC8, 0xF8, 0x07, 0xF9, 0xF3, 0xF9, 0xD9, 0xFB, 0x81, 0xFE, 0x20, 0x00, 0x89, 0x00, 0x9D, 0xFF, 0xDA, 0xFD, 0x72, 0xFD, 0x41, 0xFF, 0x4A, 0x02, 0x08, 0x04, 0x45, 0x03, 0x6D, 0x01, 0x57, 0x00, 0x11, 0x01, 0x16, 0x02, 0x28, 0x01, 0xBC, 0xFE, 0x73, 0xFC, 0xE8, 0xF9, 0x7E, 0xF6, 0xD9, 0xF4, 0x86, 0xF7, 0xB2, 0xFD, 0xD8, 0x03, 0xF7, 0x06, 0x55, 0x07, 0x79, 0x07, 0x0E, 0x09, 0x57, 0x0B, 0x8E, 0x0C, 0x70, 0x0A, 0x32, 0x04, 0xC4, 0xFC, 0xFA, 0xF7, 0xF4, 0xF7, 0x05, 0xFB, 0x24, 0xFD, 0x0F, 0xFC, 0x17, 0xF8, 0x80, 0xF2, 0x37, 0xEC, 0x60, 0xE7, 0x22, 0xE6, 0x6C, 0xE8, 0x3E, 0xED, 0x0A, 0xF3, 0x63, 0xF9, 0x10, 0x00, 0x7B, 0x04, 0x85, 0x04, 0x0A, 0x02, 0x8B, 0x01, 0xB4, 0x04, 0xD2, 0x08, 0xB6, 0x0A, 0x68, 0x0A, 0xFA, 0x09, 0x26, 0x0A, 0x63, 0x0B, 0x5A, 0x0F, 0x04, 0x17, 0x4A, 0x20, 0xC0, 0x25, 0x65, 0x22, 0x51, 0x18, 0xAA, 0x0F, 0x97, 0x0B, 0x52, 0x08, 0x3B, 0x02, 0x4D, 0xF9, 0x98, 0xF2, 0x26, 0xF3, 0xA0, 0xFA, 0x4A, 0x04, 0xE3, 0x09, 0x37, 0x09, 0xD3, 0x04, 0xD9, 0xFF, 0x2B, 0xFC, 0x89, 0xFA, 0x59, 0xFB, 0x65, 0xFD, 0x9E, 0xFF, 0x81, 0x01, 0xCC, 0x01, 0x22, 0x01, 0x4B, 0x01, 0xE2, 0x04, 0x63, 0x0B, 0x0E, 0x10, 0x37, 0x11, 0x4F, 0x11, 0x36, 0x13, 0x6E, 0x15, 0x29, 0x13, 0x20, 0x0B, 0xFC, 0xFF, 0x7C, 0xF6, 0x4C, 0xF2, 0x58, 0xF4, 0x10, 0xFA, 0xCD, 0xFC, 0xC4, 0xF8, 0xC8, 0xF1, 0xB2, 0xEF, 0xD6, 0xF5, 0xD1, 0xFE, 0x18, 0x04, 0xBD, 0x04, 0x03, 0x04, 0xF2, 0x03, 0xC3, 0x02, 0xF1, 0xFE, 0x48, 0xFB, 0x86, 0xFB, 0x9E, 0x00, 0xF0, 0x08, 0x66, 0x10, 0x63, 0x14, 0xE6, 0x15, 0xCC, 0x16, 0x5D, 0x18, 0x7E, 0x1A, 0x10, 0x1C, 0x68, 0x1B, 0x16, 0x18, 0x62, 0x13, 0x86, 0x0E, 0x46, 0x0A, 0xF4, 0x06, 0xDF, 0x06, 0x17, 0x0C, 0x11, 0x15, 0x2F, 0x1E, 0xAD, 0x23, 0x6B, 0x25, 0xBE, 0x25, 0xFF, 0x25, 0x22, 0x27, 0x3D, 0x29, 0xDA, 0x2A, 0x3B, 0x29, 0x4B, 0x22, 0x03, 0x16, 0x69, 0x08, 0x63, 0xFF, 0x40, 0xFC, 0x70, 0xFC, 0xC1, 0xFC, 0x9A, 0xFC, 0x67, 0xFD, 0x71, 0xFF, 0xEA, 0x02, 0xF8, 0x07, 0x08, 0x0E, 0xC1, 0x13, 0xE3, 0x18, 0x15, 0x1D, 0xFB, 0x1D, 0xE3, 0x1A, 0x83, 0x14, 0x93, 0x0D, 0x35, 0x0A, 0x66, 0x09, 0x25, 0x07, 0xA0, 0x02, 0x46, 0xFF, 0xD6, 0xFF, 0xE9, 0x01, 0xF8, 0x01, 0x07, 0xFF, 0x42, 0xFA, 0x51, 0xF5, 0x2B, 0xF2, 0x40, 0xF2, 0xE5, 0xF3, 0x73, 0xF4, 0xF4, 0xF2, 0xD7, 0xF0, 0xDF, 0xF0, 0xD5, 0xF3, 0x3E, 0xF8, 0xB8, 0xFB, 0x12, 0xFC, 0x80, 0xF8, 0xA5, 0xF1, 0x83, 0xE8, 0xD0, 0xDE, 0x4E, 0xD7, 0x88, 0xD4, 0x00, 0xD8, 0xD9, 0xDF, 0xA5, 0xE7, 0xDB, 0xEC, 0x9F, 0xEF, 0xE2, 0xF2, 0xBA, 0xF8, 0x33, 0xFF, 0xB0, 0x03, 0xB6, 0x04, 0xF7, 0x02, 0x79, 0xFF, 0x13, 0xFA, 0x01, 0xF4, 0xAD, 0xEF, 0x6C, 0xEF, 0x17, 0xF3, 0x50, 0xF7, 0x98, 0xF8, 0x74, 0xF6, 0xAE, 0xF3, 0x3D, 0xF3, 0x5B, 0xF6, 0x20, 0xFB, 0xB1, 0xFE, 0x95, 0xFF, 0x8C, 0xFB, 0x55, 0xF2, 0xFF, 0xE7, 0xDF, 0xE0, 0x6C, 0xDE, 0x02, 0xE0, 0xF8, 0xE3, 0xC6, 0xE7, 0x96, 0xEA, 0x94, 0xED, 0x1D, 0xF2, 0x68, 0xF7, 0xCC, 0xFB, 0x1E, 0xFF, 0xC8, 0x01, 0xAC, 0x05, 0xBE, 0x0A, 0x66, 0x0D, 0x07, 0x0A, 0x8A, 0x01, 0xD9, 0xFA, 0x6C, 0xFA, 0x64, 0xFE, 0x4C, 0x01, 0x84, 0x00, 0x10, 0x00, 0x1F, 0x03, 0x1D, 0x0A, 0x69, 0x11, 0x4E, 0x14, 0x9D, 0x12, 0x48, 0x0E, 0x63, 0x0B, 0x70, 0x0C, 0x74, 0x10, 0xA6, 0x14, 0x7C, 0x16, 0x83, 0x16, 0xC2, 0x13, 0x2B, 0x0D, 0xEB, 0x04, 0xCA, 0xFD, 0xC7, 0xF9, 0x4D, 0xFA, 0xD1, 0xFF, 0x79, 0x06, 0x65, 0x0B, 0x94, 0x0F, 0xC8, 0x11, 0x84, 0x0F, 0xDC, 0x08, 0x9D, 0x02, 0xD8, 0x01, 0x2B, 0x06, 0x37, 0x0A, 0x34, 0x09, 0x78, 0x04, 0xE9, 0x01, 0x42, 0x07, 0xBA, 0x13, 0x2C, 0x20, 0x38, 0x25, 0x53, 0x20, 0xCA, 0x16, 0xFD, 0x0F, 0xF2, 0x0E, 0x37, 0x12, 0x52, 0x17, 0xA0, 0x1C, 0x62, 0x20, 0xF9, 0x21, 0x51, 0x21, 0xA4, 0x1E, 0x97, 0x18, 0x7C, 0x0D, 0x2D, 0x01, 0x23, 0xF8, 0xCA, 0xF2, 0x4D, 0xF0, 0x30, 0xF1, 0x9D, 0xF5, 0x15, 0xFB, 0xAC, 0xFF, 0xB6, 0x02, 0xA7, 0x05, 0x53, 0x0A, 0xCF, 0x0F, 0xC4, 0x14, 0x3F, 0x17, 0xE6, 0x15, 0x72, 0x11, 0x2E, 0x0B, 0x20, 0x05, 0xF1, 0x01, 0xD0, 0x02, 0xD7, 0x05, 0x6F, 0x08, 0xDD, 0x09, 0x36, 0x0B, 0x6A, 0x0D, 0xBE, 0x0E, 0x1C, 0x0D, 0xA4, 0x09, 0x4B, 0x07, 0x35, 0x07, 0x85, 0x07, 0xC4, 0x05, 0x28, 0x02, 0x33, 0xFF, 0x94, 0xFD, 0x4C, 0xFB, 0x82, 0xF6, 0x0B, 0xF0, 0xC5, 0xEA, 0xBB, 0xE8, 0x2C, 0xEA, 0x6F, 0xED, 0xE3, 0xF0, 0xC9, 0xF3, 0x6A, 0xF6, 0xA0, 0xF9, 0x24, 0xFC, 0xCC, 0xFC, 0x81, 0xFC, 0x7F, 0xFC, 0xDB, 0xFC, 0xF7, 0xFB, 0x24, 0xFA, 0xFF, 0xF9, 0x64, 0xFC, 0xEC, 0xFE, 0x04, 0xFE, 0x66, 0xF9, 0x2A, 0xF3, 0xE2, 0xED, 0xCD, 0xEB, 0x4F, 0xEC, 0x50, 0xEE, 0xFF, 0xF0, 0x80, 0xF3, 0xE8, 0xF5, 0x66, 0xF7, 0xD1, 0xF7, 0x79, 0xF7, 0xF9, 0xF5, 0xA4, 0xF4, 0xFB, 0xF4, 0x83, 0xF7, 0x79, 0xFB, 0xA3, 0xFF, 0x7C, 0x03, 0x90, 0x06, 0x5A, 0x09, 0x86, 0x0B, 0xDC, 0x0C, 0xFD, 0x0D, 0xDF, 0x0E, 0xAD, 0x0F, 0x63, 0x0F, 0x62, 0x0E, 0xEE, 0x0C, 0x36, 0x09, 0x3A, 0x04, 0xF4, 0xFE, 0x85, 0xFA, 0xE3, 0xF7, 0x2A, 0xF5, 0xE6, 0xF1, 0xEF, 0xED, 0xCA, 0xEA, 0x9C, 0xEA, 0x57, 0xEB, 0x5E, 0xEB, 0xCC, 0xEB, 0x46, 0xEE, 0x65, 0xF3, 0x73, 0xFA, 0xA4, 0x01, 0xAB, 0x05, 0x41, 0x04, 0x05, 0xFF, 0xBD, 0xFA, 0x01, 0xFA, 0x10, 0xFB, 0x96, 0xFB, 0xFC, 0xFA, 0xAE, 0xFB, 0x35, 0x00, 0xBA, 0x08, 0x21, 0x14, 0xA9, 0x1E, 0x0A, 0x24, 0x95, 0x22, 0x82, 0x1A, 0xAB, 0x0E, 0x3C, 0x04, 0xD2, 0xFE, 0x15, 0xFE, 0xB9, 0xFF, 0x11, 0x02, 0x25, 0x05, 0xB7, 0x09, 0x7B, 0x0E, 0xE5, 0x0F, 0xA9, 0x0B, 0x75, 0x04, 0x87, 0xFF, 0xC4, 0xFE, 0x51, 0x00, 0x6C, 0x02, 0x37, 0x05, 0x75, 0x09, 0x30, 0x0F, 0x7A, 0x15, 0xD3, 0x1A, 0xB7, 0x1E, 0xA3, 0x21, 0x2D, 0x24, 0xD2, 0x26, 0x3F, 0x28, 0xF1, 0x25, 0xDF, 0x1F, 0xE7, 0x18, 0x46, 0x14, 0xEA, 0x12, 0xDC, 0x12, 0x33, 0x12, 0xFA, 0x0F, 0xC6, 0x0B, 0xF0, 0x06, 0x56, 0x03, 0x64, 0x01, 0x7C, 0x00, 0xA9, 0x00, 0x03, 0x03, 0x08, 0x08, 0x0D, 0x0E, 0xD6, 0x11, 0xCB, 0x11, 0x8C, 0x0E, 0x63, 0x09, 0x38, 0x04, 0x87, 0x00, 0xBB, 0xFF, 0xA2, 0x02, 0x6C, 0x08, 0x3A, 0x0F, 0x2B, 0x14, 0x3F, 0x16, 0x30, 0x17, 0xB8, 0x18, 0x94, 0x1A, 0xCF, 0x1A, 0xB1, 0x18, 0xEA, 0x13, 0x7D, 0x0B, 0xDE, 0x00, 0x63, 0xF8, 0xCF, 0xF4, 0xDA, 0xF5, 0xA6, 0xF9, 0x79, 0xFD, 0xDE, 0x00, 0x30, 0x04, 0x69, 0x06, 0xC4, 0x06, 0x38, 0x04, 0xF7, 0xFF, 0xD7, 0xFB, 0x56, 0xF7, 0x88, 0xF2, 0x7C, 0xEE, 0x29, 0xED, 0xE1, 0xEF, 0x85, 0xF5, 0x84, 0xFB, 0xCC, 0xFE, 0x9A, 0xFD, 0xA1, 0xF8, 0xE0, 0xF2, 0xF8, 0xEF, 0x15, 0xF1, 0xC4, 0xF3, 0x8D, 0xF5, 0xD0, 0xF6, 0xE8, 0xF8, 0x3E, 0xFC, 0x55, 0xFF, 0x46, 0x01, 0x34, 0x02, 0xE0, 0x01, 0x68, 0x00, 0x48, 0xFE, 0xDE, 0xFC, 0x6E, 0xFB, 0x45, 0xF8, 0x1A, 0xF4, 0x53, 0xF0, 0x17, 0xEF, 0x13, 0xF1, 0xE6, 0xF4, 0x09, 0xF8, 0xD7, 0xF8, 0x38, 0xF8, 0xE1, 0xF6, 0x13, 0xF7, 0x1A, 0xFA, 0x8E, 0xFE, 0xAE, 0x02, 0xCF, 0x03, 0xCD, 0x02, 0xBC, 0x01, 0x29, 0x01, 0x1D, 0x01, 0x1E, 0x01, 0x8B, 0x02, 0xD7, 0x03, 0xCD, 0x02, 0x05, 0x01, 0xF8, 0xFF, 0xBD, 0x00, 0x8C, 0x02, 0xA7, 0x03, 0xCE, 0x02, 0x7E, 0xFF, 0xAC, 0xFB, 0xF9, 0xF8, 0xDF, 0xF7, 0x41, 0xF8, 0xE3, 0xF9, 0xD5, 0xFC, 0x28, 0x00, 0x24, 0x02, 0x2F, 0x01, 0x18, 0xFE, 0x3F, 0xFC, 0x73, 0xFE, 0x77, 0x04, 0xB2, 0x0A, 0x56, 0x0D, 0x47, 0x0A, 0x5C, 0x02, 0x76, 0xF9, 0xCA, 0xF3, 0xDD, 0xF2, 0xD9, 0xF4, 0x32, 0xF8, 0x45, 0xFD, 0x98, 0x03, 0x68, 0x09, 0xF8, 0x0C, 0x39, 0x0D, 0x72, 0x0A, 0xB0, 0x05, 0x4F, 0x00, 0x57, 0xFC, 0x17, 0xFB, 0x89, 0xFC, 0xE9, 0xFF, 0x07, 0x04, 0xB7, 0x07, 0x58, 0x0A, 0xBB, 0x0C, 0x74, 0x0F, 0x25, 0x12, 0x70, 0x14, 0xDD, 0x15, 0xC7, 0x16, 0xDB, 0x17, 0x10, 0x19, 0xF6, 0x19, 0xB4, 0x19, 0xB8, 0x17, 0xB3, 0x13, 0xBE, 0x0E, 0x29, 0x0B, 0xE4, 0x09, 0x77, 0x0A, 0xDA, 0x0B, 0x80, 0x0D, 0x9E, 0x0F, 0xF6, 0x11, 0x02, 0x13, 0xEE, 0x11, 0x1E, 0x10, 0xC7, 0x0E, 0x5E, 0x0E, 0xF6, 0x0D, 0xE1, 0x0B, 0x9D, 0x07, 0x29, 0x01, 0x0F, 0xFA, 0x44, 0xF5, 0xE3, 0xF5, 0x39, 0xFC, 0xAE, 0x04, 0x40, 0x0C, 0x8F, 0x11, 0x5A, 0x14, 0x6A, 0x14, 0x55, 0x11, 0x7B, 0x0C, 0xCA, 0x07, 0xB9, 0x04, 0xA5, 0x02, 0x6C, 0xFF, 0xAE, 0xF9, 0xDE, 0xF1, 0x8B, 0xEA, 0xFB, 0xE5, 0x03, 0xE6, 0xE9, 0xE9, 0xB7, 0xEF, 0x96, 0xF7, 0x03, 0x00, 0x79, 0x06, 0x98, 0x08, 0xF7, 0x05, 0x87, 0x01, 0x2E, 0xFD, 0x61, 0xFA, 0x43, 0xFA, 0x26, 0xFD, 0xAD, 0x02, 0xAF, 0x08, 0xD8, 0x0C, 0x4F, 0x0C, 0xD8, 0x06, 0x5D, 0x00, 0xBB, 0xFC, 0xEA, 0xFC, 0xDE, 0xFD, 0xA1, 0xFC, 0xDE, 0xF8, 0x4B, 0xF4, 0x2D, 0xF2, 0xA4, 0xF4, 0xD3, 0xFA, 0xB2, 0x01, 0x03, 0x07, 0x33, 0x0A, 0x77, 0x0B, 0x26, 0x0B, 0x76, 0x09, 0x37, 0x07, 0x27, 0x05, 0x91, 0x03, 0x7D, 0x02, 0x40, 0x01, 0x41, 0xFF, 0xB2, 0xFC, 0x80, 0xFA, 0xCE, 0xF8, 0x08, 0xF7, 0x3A, 0xF5, 0x38, 0xF4, 0xBC, 0xF4, 0x70, 0xF6, 0x8D, 0xF8, 0xA3, 0xF9, 0x4E, 0xF8, 0x19, 0xF5, 0xBA, 0xF1, 0xC9, 0xEF, 0x13, 0xEF, 0x21, 0xEE, 0xDC, 0xEC, 0xD1, 0xEB, 0x80, 0xEC, 0x92, 0xF0, 0xEF, 0xF6, 0x0D, 0xFD, 0xE7, 0xFF, 0xDC, 0xFD, 0xB6, 0xF8, 0xFB, 0xF3, 0xDE, 0xF1, 0x2F, 0xF0, 0x72, 0xEC, 0x3C, 0xE8, 0xE1, 0xE5, 0x7B, 0xE5, 0x09, 0xE5, 0x91, 0xE4, 0xC7, 0xE5, 0x1F, 0xE9, 0x4B, 0xEE, 0x3C, 0xF4, 0x0B, 0xFA, 0x93, 0xFD, 0x60, 0xFD, 0x9E, 0xFB, 0xCC, 0xFA, 0x85, 0xFC, 0xDF, 0xFF, 0xE5, 0x01, 0x06, 0x01, 0xC3, 0xFE, 0x0D, 0xFF, 0x8F, 0x03, 0x9E, 0x09, 0xE4, 0x0D, 0x60, 0x0F, 0x5B, 0x0E, 0x57, 0x0B, 0x30, 0x07, 0xDC, 0x02, 0xB8, 0xFF, 0xB0, 0xFD, 0xEF, 0xFB, 0x1F, 0xFA, 0x92, 0xF8, 0x1E, 0xF9, 0xB1, 0xFC, 0xC2, 0x02, 0xD3, 0x09, 0x76, 0x10, 0x90, 0x16, 0x66, 0x1B, 0x50, 0x1D, 0xA6, 0x1A, 0x70, 0x13, 0xF7, 0x09, 0xEF, 0x01, 0x92, 0xFD, 0x2B, 0xFC, 0x69, 0xFD, 0x8C, 0x00, 0x96, 0x04, 0x91, 0x08, 0x38, 0x0B, 0x1F, 0x0C, 0x57, 0x0A, 0xA8, 0x06, 0x6D, 0x02, 0xF9, 0xFD, 0xF6, 0xF9, 0xAC, 0xF5, 0x47, 0xF1, 0xD1, 0xEE, 0x29, 0xF0, 0xD2, 0xF4, 0x36, 0xFA, 0xD7, 0xFE, 0xC6, 0x02, 0x48, 0x07, 0xB8, 0x0B, 0xAA, 0x0E, 0x08, 0x10, 0xD2, 0x0E, 0xF0, 0x0B, 0x0B, 0x09, 0xD9, 0x06, 0xA3, 0x06, 0xBE, 0x06, 0xF6, 0x04, 0x93, 0x02, 0x4D, 0x01, 0x7F, 0x02, 0x98, 0x05, 0x9E, 0x07, 0x42, 0x07, 0xBC, 0x03, 0x95, 0xFD, 0x07, 0xF8, 0x52, 0xF5, 0x8C, 0xF5, 0xED, 0xF6, 0xD0, 0xF8, 0x33, 0xFB, 0xA0, 0xFD, 0x69, 0x00, 0x2A, 0x02, 0xFE, 0x01, 0xED, 0xFE, 0x97, 0xF9, 0x7C, 0xF5, 0xDF, 0xF2, 0x46, 0xF1, 0xC3, 0xEF, 0x8F, 0xEE, 0xF3, 0xEF, 0x79, 0xF3, 0xE6, 0xF8, 0xBE, 0xFE, 0x36, 0x02, 0xCF, 0x01, 0x6E, 0xFD, 0x45, 0xF8, 0xC1, 0xF5, 0x8D, 0xF7, 0xE0, 0xFB, 0xF3, 0xFE, 0xBB, 0xFE, 0x79, 0xFB, 0x67, 0xF8, 0x96, 0xF6, 0xAE, 0xF5, 0x92, 0xF6, 0x52, 0xF8, 0xAB, 0xF9, 0xC4, 0xF9, 0xCD, 0xF8, 0xF6, 0xF7, 0xCE, 0xF7, 0x31, 0xF7, 0x8E, 0xF4, 0x3F, 0xF1, 0x9E, 0xEE, 0xF5, 0xEC, 0xB6, 0xEB, 0x98, 0xE9, 0xCB, 0xE7, 0x8E, 0xE7, 0xC9, 0xE8, 0x92, 0xEB, 0x52, 0xEF, 0x6F, 0xF3, 0x96, 0xF7, 0xAF, 0xFB, 0x91, 0x00, 0x1F, 0x07, 0xD2, 0x0E, 0x46, 0x15, 0x9C, 0x17, 0xE4, 0x14, 0xCB, 0x0E, 0x70, 0x08, 0x86, 0x03, 0xEE, 0xFE, 0x64, 0xFA, 0x87, 0xF7, 0x99, 0xF7, 0x87, 0xFA, 0x0D, 0xFF, 0x6A, 0x03, 0xD7, 0x05, 0xB7, 0x05, 0x6D, 0x03, 0x5B, 0x00, 0x8A, 0xFE, 0x26, 0xFE, 0x78, 0xFE, 0x95, 0xFE, 0x40, 0xFE, 0x76, 0xFE, 0x07, 0xFF, 0xC2, 0x00, 0x6C, 0x04, 0x7A, 0x08, 0x91, 0x0A, 0xC8, 0x08, 0x24, 0x04, 0x7A, 0xFE, 0x49, 0xF9, 0xB4, 0xF5, 0x0A, 0xF3, 0x3D, 0xF1, 0x7D, 0xF0, 0x74, 0xF1, 0x3A, 0xF5, 0x5F, 0xFA, 0xDE, 0xFE, 0xD4, 0x01, 0xC9, 0x03, 0x39, 0x06, 0xD7, 0x09, 0xAB, 0x0D, 0x4E, 0x10, 0x28, 0x11, 0x50, 0x0F, 0xA7, 0x0A, 0xF9, 0x02, 0xDD, 0xF8, 0xAB, 0xEF, 0x10, 0xEA, 0xB5, 0xE9, 0x81, 0xEE, 0x46, 0xF6, 0x70, 0xFE, 0x59, 0x04, 0xD0, 0x07, 0xD8, 0x09, 0xFC, 0x0A, 0xFC, 0x0A, 0x0F, 0x09, 0x0B, 0x06, 0x42, 0x03, 0x82, 0x01, 0x45, 0x00, 0xA7, 0xFE, 0x60, 0xFD, 0x2D, 0xFD, 0x7A, 0xFE, 0xC6, 0xFF, 0xEA, 0xFE, 0xE3, 0xFC, 0xE5, 0xFA, 0xF2, 0xF8, 0xCE, 0xF7, 0x11, 0xF7, 0x8C, 0xF5, 0x13, 0xF3, 0xC9, 0xEF, 0x54, 0xED, 0x1C, 0xED, 0xD2, 0xEE, 0xC7, 0xF1, 0x67, 0xF4, 0xB1, 0xF6, 0xF7, 0xF8, 0x15, 0xFB, 0x9F, 0xFD, 0x46, 0xFF, 0x9C, 0xFE, 0x9C, 0xFB, 0xE7, 0xF8, 0x3A, 0xF9, 0xA9, 0xFB, 0x9D, 0xFE, 0x6A, 0x00, 0x5F, 0x00, 0x0F, 0xFF, 0xA8, 0xFD, 0xEF, 0xFD, 0x4F, 0x00, 0x14, 0x04, 0x6C, 0x07, 0x80, 0x09, 0x89, 0x09, 0x88, 0x06, 0xA3, 0x01, 0xE0, 0xFB, 0x8B, 0xF7, 0xDA, 0xF5, 0x20, 0xF6, 0x80, 0xF8, 0xE7, 0xFB, 0x53, 0xFF, 0x5E, 0x01, 0xD0, 0x01, 0x0B, 0x02, 0x9B, 0x02, 0xC0, 0x03, 0x58, 0x04, 0xD2, 0x03, 0x57, 0x02, 0x75, 0x00, 0x2A, 0x00, 0x1C, 0x02, 0x14, 0x05, 0x3E, 0x07, 0xC8, 0x08, 0x4D, 0x0B, 0xF1, 0x0F, 0xC8, 0x15, 0xF6, 0x19, 0x88, 0x1A, 0x9C, 0x15, 0x42, 0x0C, 0x85, 0x02, 0xCE, 0xFB, 0x99, 0xF9, 0xCF, 0xF9, 0xF6, 0xFA, 0x7C, 0xFC, 0xDC, 0xFC, 0xC2, 0xFB, 0xE6, 0xF9, 0x3D, 0xF9, 0x85, 0xFA, 0x64, 0xFC, 0x36, 0xFC, 0x81, 0xF8, 0x89, 0xF3, 0x10, 0xF0, 0x7F, 0xEF, 0x7F, 0xF1, 0x6D, 0xF5, 0x6F, 0xFA, 0x4F, 0xFE, 0x08, 0x00, 0x7B, 0xFF, 0x1F, 0xFE, 0x22, 0xFF, 0xAF, 0x03, 0x73, 0x09, 0x0D, 0x0C, 0x68, 0x0A, 0x32, 0x07, 0x30, 0x05, 0x5F, 0x05, 0xF2, 0x05, 0x77, 0x05, 0x29, 0x04, 0x9D, 0x01, 0xBF, 0xFD, 0x62, 0xFA, 0x13, 0xFA, 0x32, 0xFD, 0x68, 0x01, 0xB4, 0x04, 0xB6, 0x06, 0x10, 0x08, 0xB9, 0x08, 0x13, 0x07, 0x62, 0x02, 0xCA, 0xFB, 0x2A, 0xF5, 0x67, 0xEF, 0xC0, 0xEA, 0xA7, 0xE8, 0x51, 0xEB, 0xEF, 0xF3, 0x4D, 0xFF, 0x92, 0x07, 0x12, 0x0A, 0xC4, 0x07, 0xB6, 0x02, 0x3D, 0xFC, 0x9D, 0xF5, 0xA5, 0xF0, 0xFF, 0xEE, 0x4E, 0xF1, 0xA2, 0xF6, 0x53, 0xFD, 0xF3, 0x02, 0xC9, 0x05, 0x7E, 0x05, 0x81, 0x03, 0x47, 0x01, 0xE1, 0xFD, 0xAC, 0xF9, 0x10, 0xF6, 0xC2, 0xF3, 0x2C, 0xF3, 0xDD, 0xF2, 0x46, 0xF1, 0xDF, 0xED, 0x07, 0xEA, 0x19, 0xE8, 0x6C, 0xE9, 0xAD, 0xED, 0x5C, 0xF3, 0xC9, 0xF9, 0x41, 0xFF, 0x5D, 0x02, 0x47, 0x03, 0x9D, 0x02, 0xA2, 0x01, 0x18, 0xFF, 0xAD, 0xF9, 0x9F, 0xF2, 0xBD, 0xEC, 0x64, 0xEA, 0xBF, 0xEA, 0x0C, 0xED, 0x7D, 0xF1, 0x83, 0xF7, 0x38, 0xFD, 0x99, 0x00, 0xB7, 0x01, 0x1E, 0x01, 0xAE, 0xFF, 0x97, 0xFD, 0x31, 0xFB, 0xB4, 0xF9, 0xBB, 0xF8, 0xD5, 0xF7, 0x31, 0xF7, 0xDF, 0xF7, 0x87, 0xFB, 0x22, 0x02, 0x7E, 0x09, 0xC3, 0x0E, 0x9C, 0x11, 0x83, 0x13, 0x26, 0x16, 0x33, 0x19, 0x82, 0x1A, 0x7E, 0x19, 0xE0, 0x15, 0xF9, 0x10, 0x15, 0x0D, 0x73, 0x0A, 0x66, 0x07, 0x96, 0x02, 0xF7, 0xFD, 0x55, 0xFB, 0x60, 0xFA, 0xCB, 0xF9, 0xD1, 0xF7, 0xFA, 0xF4, 0x3D, 0xF2, 0x28, 0xF0, 0xD3, 0xEE, 0x5A, 0xED, 0x01, 0xED, 0x28, 0xEF, 0xBF, 0xF2, 0xF3, 0xF5, 0x11, 0xF8, 0x51, 0xFA, 0xB8, 0xFD, 0xE1, 0x01, 0x7F, 0x05, 0x92, 0x06, 0x49, 0x04, 0x11, 0x00, 0x0F, 0xFC, 0x8E, 0xF9, 0x9F, 0xF8, 0xC5, 0xF8, 0xD4, 0xF9, 0x02, 0xFB, 0x0C, 0xFB, 0x13, 0xFA, 0x37, 0xFA, 0x50, 0xFD, 0x5D, 0x02, 0x69, 0x06, 0xB6, 0x07, 0xAC, 0x06, 0x2A, 0x04, 0x9B, 0x01, 0x0C, 0x01, 0x62, 0x03, 0xC6, 0x07, 0x8F, 0x0B, 0x26, 0x0C, 0x00, 0x09, 0xE7, 0x03, 0xDE, 0xFF, 0x4C, 0xFE, 0xA9, 0xFE, 0x0D, 0xFF, 0x20, 0xFE, 0xD7, 0xFC, 0x7C, 0xFC, 0x41, 0xFF, 0x52, 0x05, 0xCC, 0x0A, 0x5C, 0x0D, 0xAB, 0x0C, 0x84, 0x09, 0x37, 0x05, 0xD6, 0xFF, 0x45, 0xFA, 0x90, 0xF5, 0x18, 0xF2, 0x1C, 0xF0, 0xC1, 0xEF, 0x48, 0xF1, 0x8A, 0xF3, 0xB7, 0xF5, 0x57, 0xF8, 0x75, 0xFB, 0x95, 0xFD, 0xBB, 0xFC, 0x2A, 0xF9, 0xD3, 0xF3, 0x40, 0xEE, 0x03, 0xEB, 0xB0, 0xEA, 0xF8, 0xEC, 0x5E, 0xF0, 0x96, 0xF3, 0xAA, 0xF5, 0xB0, 0xF5, 0xC5, 0xF5, 0x37, 0xF7, 0x58, 0xF9, 0x2D, 0xFB, 0xFD, 0xFA, 0x07, 0xF9, 0x9A, 0xF6, 0x1B, 0xF5, 0x4A, 0xF4, 0xF7, 0xF2, 0xB1, 0xF1, 0x44, 0xF0, 0xB9, 0xEF, 0xC4, 0xF0, 0xF6, 0xF1, 0x38, 0xF4, 0x54, 0xF7, 0xB6, 0xF9, 0xC8, 0xFA, 0x9E, 0xFA, 0x24, 0xFB, 0xD3, 0xFC, 0xB4, 0xFD, 0x83, 0xFC, 0xA7, 0xF9, 0x65, 0xF7, 0x99, 0xF7, 0xB5, 0xF8, 0xCB, 0xF9, 0x0A, 0xFD, 0xBB, 0x01, 0x22, 0x05, 0x39, 0x06, 0x21, 0x06, 0x97, 0x07, 0xE5, 0x09, 0x77, 0x0B, 0x42, 0x0D, 0x2B, 0x0F, 0x1E, 0x10, 0x64, 0x0E, 0x2E, 0x09, 0x6E, 0x02, 0xE2, 0xFC, 0xFB, 0xF8, 0xA0, 0xF5, 0x4F, 0xF3, 0x7F, 0xF2, 0x98, 0xF3, 0xC5, 0xF5, 0xD7, 0xF6, 0x17, 0xF7, 0x55, 0xF7, 0x19, 0xF8, 0xBE, 0xF9, 0x8F, 0xFB, 0xC1, 0xFD, 0xB3, 0x00, 0x73, 0x03, 0x50, 0x04, 0x40, 0x02, 0x78, 0xFD, 0x92, 0xF8, 0xE5, 0xF5, 0x9B, 0xF4, 0x01, 0xF4, 0x1A, 0xF3, 0xAA, 0xF1, 0xF6, 0xF0, 0x33, 0xF1, 0x5C, 0xF3, 0x50, 0xF7, 0xBA, 0xFB, 0xBF, 0xFF, 0x8D, 0x02, 0x9F, 0x03, 0xA1, 0x02, 0x82, 0x01, 0x6C, 0x01, 0x51, 0x01, 0xD8, 0xFF, 0xDF, 0xFB, 0x4C, 0xF8, 0xC4, 0xF8, 0x1F, 0xFD, 0x30, 0x02, 0xD4, 0x03, 0x5C, 0x00, 0x6C, 0xF9, 0x2C, 0xF3, 0xD4, 0xEF, 0x2A, 0xEF, 0xEF, 0xF0, 0xF9, 0xF3, 0x2B, 0xF8, 0xCD, 0xFC, 0x54, 0x00, 0x96, 0x02, 0xEC, 0x03, 0xA2, 0x05, 0xD0, 0x07, 0xAC, 0x09, 0x4D, 0x0A, 0x7B, 0x08, 0xDC, 0x04, 0x15, 0x00, 0x78, 0xFB, 0xFA, 0xF9, 0x7E, 0xFC, 0xE9, 0x00, 0x6C, 0x04, 0x4E, 0x06, 0x05, 0x08, 0xEC, 0x0A, 0xC2, 0x0E, 0xDF, 0x11, 0xAE, 0x12, 0x90, 0x10, 0xBD, 0x0B, 0x50, 0x04, 0xFA, 0xFA, 0x51, 0xF2, 0x18, 0xED, 0x51, 0xEC, 0x06, 0xEF, 0x47, 0xF3, 0xBE, 0xF7, 0x40, 0xFC, 0x17, 0x01, 0x09, 0x07, 0x0A, 0x0D, 0x75, 0x10, 0x60, 0x11, 0x70, 0x11, 0x68, 0x11, 0x3D, 0x11, 0xF4, 0x0F, 0x4B, 0x0D, 0xDB, 0x09, 0x9E, 0x06, 0xD5, 0x04, 0x8D, 0x04, 0x55, 0x05, 0x1E, 0x07, 0xC2, 0x09, 0xA8, 0x0C, 0x23, 0x0F, 0x42, 0x10, 0xF5, 0x0E, 0x25, 0x0B, 0xA8, 0x05, 0x3C, 0x01, 0x07, 0x00, 0x5A, 0x01, 0xAC, 0x03, 0x45, 0x05, 0x08, 0x06, 0x61, 0x06, 0x09, 0x06, 0x95, 0x04, 0x18, 0x01, 0x72, 0xFC, 0x42, 0xF8, 0x72, 0xF6, 0x8C, 0xF8, 0x0B, 0xFE, 0xDF, 0x05, 0xAB, 0x0C, 0xFC, 0x0E, 0xC4, 0x0B, 0x1C, 0x04, 0xCD, 0xFB, 0xBA, 0xF5, 0xA7, 0xF3, 0x53, 0xF4, 0x8B, 0xF4, 0xE0, 0xF3, 0xB8, 0xF2, 0x4B, 0xF2, 0x57, 0xF3, 0x98, 0xF4, 0xEC, 0xF4, 0xDA, 0xF3, 0x2D, 0xF1, 0x04, 0xED, 0x0E, 0xE9, 0x26, 0xE7, 0xDC, 0xE8, 0x03, 0xEE, 0x20, 0xF4, 0xF8, 0xF9, 0x6F, 0xFE, 0x68, 0x01, 0x34, 0x03, 0x82, 0x02, 0x36, 0xFF, 0xA0, 0xF9, 0xA1, 0xF3, 0x98, 0xF0, 0xB6, 0xF1, 0x0F, 0xF6, 0x0F, 0xFC, 0x18, 0x02, 0x3A, 0x07, 0xAD, 0x0B, 0x9E, 0x0E, 0xA3, 0x0E, 0xC1, 0x0B, 0x92, 0x07, 0x65, 0x04, 0x17, 0x03, 0xB2, 0x03, 0xFF, 0x04, 0x9F, 0x05, 0x30, 0x06, 0xB7, 0x06, 0xAF, 0x06, 0x83, 0x05, 0xED, 0x02, 0xB7, 0xFF, 0x6B, 0xFC, 0x81, 0xF9, 0xB0, 0xF7, 0x00, 0xF8, 0x81, 0xFA, 0xCC, 0xFD, 0x09, 0x01, 0x4D, 0x04, 0x17, 0x08, 0x07, 0x0C, 0x3F, 0x0F, 0x69, 0x11, 0x6E, 0x12, 0x64, 0x12, 0x7F, 0x11, 0x66, 0x0F, 0xF4, 0x0B, 0x9C, 0x08, 0x2F, 0x06, 0x73, 0x04, 0x5B, 0x03, 0x73, 0x02, 0x6E, 0x01, 0xD7, 0xFF, 0xD9, 0xFD, 0xC3, 0xFC, 0x77, 0xFD, 0x15, 0x00, 0xEF, 0x03, 0x4C, 0x07, 0x66, 0x08, 0xCB, 0x06, 0x5C, 0x03, 0xCE, 0xFF, 0x0A, 0xFD, 0xCE, 0xFA, 0xD7, 0xF9, 0x04, 0xFB, 0x25, 0xFE, 0x2C, 0x02, 0x52, 0x06, 0x46, 0x0A, 0xEE, 0x0D, 0x73, 0x11, 0xA4, 0x13, 0x68, 0x14, 0x94, 0x14, 0xAF, 0x13, 0xF8, 0x12, 0x80, 0x13, 0xD9, 0x14, 0x22, 0x16, 0xB6, 0x15, 0x3E, 0x13, 0x22, 0x10, 0x7C, 0x0E, 0x00, 0x0F, 0x89, 0x10, 0xF0, 0x10, 0xEB, 0x0E, 0xC2, 0x0B, 0xD3, 0x08, 0x63, 0x07, 0xB6, 0x08, 0x1F, 0x0C, 0x87, 0x0F, 0x07, 0x10, 0xBF, 0x0C, 0x95, 0x08, 0xDC, 0x05, 0x93, 0x04, 0xAF, 0x04, 0xA5, 0x05, 0x3A, 0x06, 0xA0, 0x05, 0xD0, 0x03, 0x42, 0x02, 0xEE, 0x01, 0xB6, 0x02, 0xAE, 0x03, 0xC0, 0x03, 0xE4, 0x02, 0x8F, 0x01, 0x3C, 0x01, 0x35, 0x02, 0xB7, 0x02, 0x6F, 0x01, 0xFA, 0xFD, 0x4E, 0xF9, 0xA7, 0xF4, 0x96, 0xF0, 0x72, 0xED, 0x17, 0xEC, 0xC6, 0xED, 0x26, 0xF2, 0x35, 0xF7, 0xD6, 0xFA, 0xDF, 0xFC, 0x57, 0xFE, 0xD1, 0xFF, 0x39, 0x01, 0x1B, 0x01, 0x93, 0xFF, 0xC5, 0xFD, 0xF9, 0xFB, 0x22, 0xFA, 0xE2, 0xF7, 0xB0, 0xF5, 0xD4, 0xF3, 0x0C, 0xF3, 0x62, 0xF4, 0x5B, 0xF7, 0x06, 0xFB, 0x3B, 0xFE, 0xCC, 0x00, 0x1C, 0x03, 0xB4, 0x05, 0x6E, 0x09, 0xA7, 0x0D, 0xDE, 0x10, 0x54, 0x12, 0x84, 0x12, 0x28, 0x12, 0x2B, 0x11, 0xA7, 0x0E, 0xED, 0x09, 0x23, 0x04, 0x48, 0xFF, 0x80, 0xFC, 0x18, 0xFB, 0x8C, 0xFA, 0x76, 0xFB, 0xBE, 0xFD, 0xDE, 0x00, 0xA6, 0x03, 0x7B, 0x05, 0x8C, 0x06, 0x72, 0x06, 0xAA, 0x04, 0x73, 0x01, 0xF6, 0xFE, 0xD4, 0xFE, 0xDC, 0x00, 0xCB, 0x03, 0x41, 0x06, 0x50, 0x08, 0xB2, 0x09, 0x5E, 0x0A, 0x5C, 0x0A, 0xCD, 0x08, 0x91, 0x05, 0x33, 0x01, 0x57, 0xFD, 0x0F, 0xFB, 0x28, 0xFA, 0xFC, 0xFA, 0xDA, 0xFD, 0x2B, 0x02, 0x57, 0x06, 0x4E, 0x09, 0xA9, 0x0A, 0x8D, 0x0A, 0x2F, 0x09, 0xE1, 0x05, 0x41, 0x01, 0xEC, 0xFC, 0x8F, 0xFA, 0x29, 0xFB, 0xFA, 0xFD, 0x5B, 0x02, 0xAA, 0x07, 0x35, 0x0C, 0x33, 0x0E, 0x91, 0x0D, 0xAC, 0x0B, 0x6A, 0x0A, 0x66, 0x0B, 0xBF, 0x0D, 0xDF, 0x0F, 0x0C, 0x11, 0xB2, 0x10, 0x47, 0x0F, 0xA6, 0x0C, 0x16, 0x08, 0x49, 0x02, 0xC9, 0xFC, 0x03, 0xFA, 0xFE, 0xFA, 0x80, 0xFE, 0xDA, 0x03, 0xB7, 0x09, 0xFB, 0x0E, 0x53, 0x14, 0x32, 0x19, 0x58, 0x1C, 0xCA, 0x1C, 0xB5, 0x1A, 0x92, 0x18, 0xE7, 0x17, 0xC5, 0x17, 0xD3, 0x16, 0x49, 0x15, 0x61, 0x14, 0xEB, 0x14, 0x7D, 0x16, 0xEF, 0x17, 0x01, 0x19, 0xD2, 0x18, 0xA6, 0x16, 0x90, 0x12, 0x3E, 0x0C, 0x5E, 0x05, 0x32, 0xFF, 0x98, 0xF9, 0xF9, 0xF4, 0x0A, 0xF1, 0x12, 0xEF, 0x11, 0xF1, 0x58, 0xF6, 0x0D, 0xFC, 0xD9, 0xFF, 0xBC, 0x01, 0x31, 0x03, 0x29, 0x05, 0x8A, 0x06, 0x8B, 0x06, 0xA0, 0x05, 0x2F, 0x04, 0x44, 0x03, 0x0F, 0x03, 0x5C, 0x03, 0x17, 0x04, 0xC7, 0x03, 0xEC, 0x01, 0xB4, 0xFF, 0x2B, 0xFE, 0xC4, 0xFD, 0xEE, 0xFD, 0xFB, 0xFD, 0x15, 0xFF, 0xBC, 0x01, 0x62, 0x04, 0xDD, 0x06, 0xF7, 0x08, 0xEC, 0x09, 0x97, 0x0A, 0x17, 0x0B, 0xF8, 0x0B, 0x80, 0x0E, 0xDE, 0x11, 0x62, 0x15, 0x39, 0x18, 0xA2, 0x19, 0x2A, 0x1A, 0x18, 0x19, 0x28, 0x16, 0xC1, 0x11, 0x02, 0x0C, 0x93, 0x06, 0x9B, 0x02, 0x9F, 0x00, 0xFB, 0xFF, 0x40, 0xFF, 0xEC, 0xFE, 0xA9, 0xFF, 0x42, 0x02, 0xE4, 0x05, 0x88, 0x08, 0x45, 0x09, 0x86, 0x06, 0x4C, 0x01, 0x1F, 0xFC, 0xF7, 0xF7, 0x6E, 0xF5, 0x0D, 0xF4, 0x4D, 0xF3, 0xFB, 0xF2, 0x4D, 0xF3, 0x76, 0xF4, 0x86, 0xF6, 0x4A, 0xF9, 0x2A, 0xFB, 0x3C, 0xFB, 0xA1, 0xF9, 0xF0, 0xF7, 0x74, 0xF7, 0xBD, 0xF6, 0xD6, 0xF4, 0x8F, 0xF1, 0x45, 0xEE, 0x7E, 0xED, 0xA8, 0xEF, 0x65, 0xF3, 0xC9, 0xF6, 0x73, 0xF9, 0x4F, 0xFB, 0x75, 0xFB, 0x85, 0xF9, 0x27, 0xF6, 0x7F, 0xF3, 0xEB, 0xF2, 0x80, 0xF4, 0x78, 0xF7, 0x6F, 0xFA, 0x34, 0xFD, 0x19, 0x00, 0x51, 0x03, 0xC7, 0x06, 0x6E, 0x0A, 0x2C, 0x0E, 0xC1, 0x11, 0x0D, 0x14, 0x05, 0x14, 0xC8, 0x12, 0x44, 0x10, 0x75, 0x0C, 0xEA, 0x08, 0x5E, 0x06, 0x85, 0x05, 0x7F, 0x05, 0xB9, 0x05, 0xE7, 0x06, 0x65, 0x08, 0xCF, 0x09, 0x3A, 0x0B, 0x2B, 0x0D, 0x1F, 0x10, 0x12, 0x13, 0x5E, 0x14, 0xCF, 0x13, 0xE9, 0x11, 0xA5, 0x0E, 0x33, 0x0B, 0xA3, 0x08, 0xD8, 0x06, 0x79, 0x05, 0x99, 0x03, 0x7D, 0x01, 0x0A, 0x00, 0xD3, 0xFF, 0x29, 0x01, 0x24, 0x03, 0x75, 0x04, 0xD8, 0x03, 0xF9, 0xFF, 0x00, 0xF9, 0x32, 0xF1, 0x11, 0xEB, 0x46, 0xE8, 0xFF, 0xE8, 0x72, 0xEC, 0x3F, 0xF2, 0xC3, 0xF9, 0x95, 0x01, 0x0F, 0x08, 0x5D, 0x0C, 0x0A, 0x0E, 0xE7, 0x0C, 0x0C, 0x0A, 0xE8, 0x05, 0x51, 0x01, 0x49, 0xFD, 0x21, 0xF9, 0xC4, 0xF4, 0xA4, 0xF0, 0xF2, 0xED, 0xE4, 0xED, 0xBA, 0xF0, 0xC5, 0xF5, 0xEC, 0xFA, 0x06, 0xFF, 0x25, 0x02, 0x63, 0x05, 0xBB, 0x09, 0x08, 0x0E, 0x00, 0x11, 0xF7, 0x11, 0xA5, 0x11, 0x06, 0x11, 0xD2, 0x10, 0xE8, 0x11, 0xD0, 0x13, 0x5D, 0x16, 0x1D, 0x19, 0xD7, 0x1A, 0x41, 0x1B, 0xBC, 0x1A, 0x36, 0x1A, 0x77, 0x19, 0xDF, 0x16, 0xF2, 0x10, 0x79, 0x07, 0x51, 0xFD, 0x52, 0xF6, 0xAF, 0xF4, 0xEE, 0xF7, 0x7E, 0xFD, 0x7E, 0x03, 0xFD, 0x08, 0xFD, 0x0C, 0x19, 0x0F, 0xAD, 0x0E, 0x68, 0x0B, 0x36, 0x06, 0x9A, 0xFF, 0x98, 0xF8, 0xAA, 0xF2, 0x3A, 0xEF, 0x4B, 0xEF, 0x50, 0xF1, 0xBF, 0xF3, 0x08, 0xF6, 0xAB, 0xF7, 0x46, 0xF8, 0xAA, 0xF6, 0x81, 0xF3, 0x80, 0xF0, 0xDE, 0xEE, 0xDF, 0xEE, 0x9A, 0xEE, 0x58, 0xED, 0x2F, 0xEB, 0x21, 0xE8, 0xF4, 0xE4, 0x64, 0xE2, 0x49, 0xE2, 0xEF, 0xE5, 0x79, 0xED, 0xDC, 0xF6, 0xDD, 0xFE, 0x5A, 0x04, 0x00, 0x07, 0xD3, 0x07, 0x26, 0x08, 0x08, 0x09, 0xE2, 0x0A, 0x0F, 0x0C, 0xBF, 0x0B, 0xC0, 0x09, 0x1B, 0x07, 0x38, 0x05, 0xCD, 0x03, 0xEC, 0x02, 0xDF, 0x01, 0xB0, 0x00, 0xAE, 0xFF, 0x66, 0xFF, 0x70, 0x01, 0xBB, 0x04, 0xB1, 0x07, 0xB8, 0x08, 0xE1, 0x06, 0x46, 0x03, 0x83, 0xFE, 0x35, 0xFA, 0x81, 0xF7, 0x2F, 0xF6, 0x2D, 0xF5, 0x05, 0xF3, 0x47, 0xF0, 0x11, 0xEE, 0xA3, 0xED, 0x36, 0xEF, 0x85, 0xF1, 0x72, 0xF3, 0x32, 0xF5, 0xC2, 0xF7, 0xF2, 0xF9, 0xF7, 0xFA, 0x6C, 0xFA, 0x46, 0xF8, 0xD2, 0xF6, 0x59, 0xF6, 0x43, 0xF6, 0x66, 0xF6, 0x6F, 0xF6, 0x71, 0xF6, 0x57, 0xF5, 0x13, 0xF3, 0xA0, 0xF0, 0x16, 0xEF, 0x0D, 0xEF, 0xD6, 0xEF, 0x07, 0xF1, 0x97, 0xF2, 0xAB, 0xF4, 0x0F, 0xF7, 0x69, 0xF9, 0xAC, 0xFB, 0xD5, 0xFD, 0x01, 0x00, 0x4E, 0x02, 0x16, 0x05, 0xB4, 0x07, 0x05, 0x09, 0x4C, 0x08, 0x2E, 0x06, 0x9E, 0x04, 0x1D, 0x04, 0x42, 0x05, 0x7A, 0x07, 0x4F, 0x09, 0x59, 0x0A, 0x08, 0x09, 0xF1, 0x05, 0x4E, 0x02, 0x8D, 0xFE, 0xF6, 0xFB, 0x65, 0xFA, 0x58, 0xFA, 0x1C, 0xFC, 0x6C, 0xFE, 0x6B, 0x00, 0xCD, 0x01, 0xA0, 0x02, 0xD1, 0x02, 0x25, 0x03, 0xCE, 0x04, 0xA1, 0x08, 0xBB, 0x0D, 0x48, 0x11, 0x19, 0x12, 0xDF, 0x0F, 0x97, 0x0B, 0xF0, 0x07, 0x3A, 0x06, 0x74, 0x06, 0x48, 0x07, 0x26, 0x07, 0xCD, 0x04, 0x92, 0x00, 0x4D, 0xFC, 0xE0, 0xF8, 0x6D, 0xF7, 0x28, 0xF7, 0x69, 0xF6, 0x6F, 0xF5, 0x26, 0xF4, 0xD5, 0xF3, 0x7A, 0xF4, 0xD8, 0xF3, 0x4E, 0xF2, 0x79, 0xF1, 0xB5, 0xF2, 0x97, 0xF5, 0x07, 0xF8, 0x8F, 0xF9, 0xC4, 0xFA, 0xD5, 0xFA, 0xE9, 0xF8, 0xA2, 0xF6, 0xBE, 0xF5, 0xC0, 0xF6, 0xF5, 0xF8, 0x5B, 0xFB, 0x3C, 0xFE, 0xA3, 0x00, 0xC4, 0x01, 0x33, 0x01, 0x22, 0xFF, 0x60, 0xFD, 0x53, 0xFC, 0x18, 0xFC, 0x1D, 0xFC, 0xAC, 0xFB, 0xA1, 0xFB, 0x6C, 0xFC, 0x57, 0xFF, 0x40, 0x04, 0x31, 0x09, 0xD8, 0x0B, 0xB2, 0x0A, 0x4C, 0x07, 0x23, 0x03, 0x19, 0xFF, 0x87, 0xFC, 0xA7, 0xFC, 0x9E, 0xFF, 0x62, 0x03, 0xEE, 0x05, 0xA0, 0x06, 0x03, 0x07, 0x99, 0x07, 0xEC, 0x06, 0x4A, 0x04, 0xDC, 0xFF, 0xF2, 0xFB, 0x8E, 0xF9, 0x11, 0xF8, 0x8A, 0xF7, 0xCC, 0xF7, 0x92, 0xF9, 0x3A, 0xFC, 0xB8, 0xFD, 0x4C, 0xFC, 0x8A, 0xF7, 0x61, 0xF1, 0x46, 0xEC, 0xAF, 0xE9, 0xA6, 0xE8, 0xCD, 0xE8, 0x54, 0xEA, 0x23, 0xEC, 0x86, 0xED, 0x35, 0xED, 0x89, 0xEB, 0xB2, 0xEA, 0x1C, 0xEC, 0xF7, 0xEF, 0x42, 0xF4, 0x95, 0xF6, 0xB5, 0xF6, 0x15, 0xF6, 0x43, 0xF5, 0x93, 0xF4, 0xD8, 0xF3, 0x37, 0xF2, 0x55, 0xF0, 0x83, 0xEE, 0x2F, 0xEE, 0x79, 0xF1, 0xF3, 0xF7, 0x64, 0xFF, 0x1E, 0x05, 0x60, 0x08, 0x36, 0x0A, 0x71, 0x0B, 0x5A, 0x0B, 0xCB, 0x09, 0xD7, 0x07, 0xFD, 0x05, 0xCE, 0x05, 0x09, 0x07, 0x21, 0x08, 0x92, 0x08, 0x54, 0x07, 0x95, 0x04, 0x8A, 0x01, 0x07, 0x00, 0x09, 0x01, 0xAE, 0x03, 0xC9, 0x05, 0x39, 0x05, 0x78, 0x02, 0x8B, 0xFE, 0x03, 0xFB, 0x55, 0xF9, 0x2C, 0xF9, 0x0E, 0xFA, 0xAE, 0xFA, 0xEB, 0xFA, 0xBC, 0xFB, 0x4A, 0xFD, 0xEB, 0xFE, 0x09, 0xFF, 0x16, 0xFD, 0x20, 0xFA, 0x49, 0xF8, 0x88, 0xF8, 0xCF, 0xFA, 0x9A, 0xFD, 0x0C, 0xFE, 0xAC, 0xFC, 0x5E, 0xFA, 0xEA, 0xF6, 0x47, 0xF3, 0x8D, 0xF0, 0x84, 0xF0, 0x3B, 0xF3, 0x21, 0xF7, 0xA3, 0xFA, 0x7C, 0xFC, 0x1A, 0xFD, 0xDB, 0xFD, 0x2B, 0xFF, 0xFD, 0xFF, 0x0E, 0xFF, 0xE9, 0xFB, 0x38, 0xF8, 0x2D, 0xF6, 0x4A, 0xF6, 0xC2, 0xF8, 0xFC, 0xFC, 0xB8, 0x01, 0xEA, 0x05, 0x7D, 0x08, 0x32, 0x09, 0x25, 0x08, 0x7B, 0x05, 0xE8, 0x00, 0xBD, 0xFA, 0x5C, 0xF4, 0xFE, 0xEF, 0xD3, 0xEF, 0xD7, 0xF3, 0x2C, 0xFB, 0xCD, 0x03, 0xDA, 0x0A, 0x30, 0x0F, 0x6B, 0x10, 0x94, 0x0E, 0x42, 0x0A, 0xAB, 0x04, 0xA7, 0xFE, 0xA5, 0xF8, 0x8F, 0xF3, 0x36, 0xF0, 0xD3, 0xEF, 0xAF, 0xF2, 0xE8, 0xF8, 0x7C, 0x01, 0x57, 0x08, 0x90, 0x0B, 0x58, 0x0B, 0xC2, 0x08, 0x84, 0x06, 0x93, 0x05, 0x39, 0x05, 0x22, 0x04, 0x45, 0x01, 0xCC, 0xFD, 0x9D, 0xFB, 0xE7, 0xFA, 0x99, 0xFB, 0x8D, 0xFD, 0xD1, 0xFE, 0x99, 0xFE, 0x49, 0xFD, 0x9C, 0xFB, 0x26, 0xFB, 0x86, 0xFB, 0x00, 0xFC, 0xB5, 0xFB, 0x89, 0xF9, 0xA0, 0xF6, 0x3F, 0xF4, 0x31, 0xF4, 0x97, 0xF7, 0x6D, 0xFC, 0x2B, 0x00, 0x6F, 0x01, 0x8E, 0x00, 0x83, 0xFE, 0xFB, 0xFB, 0x8F, 0xF9, 0xD8, 0xF7, 0xFC, 0xF6, 0x6A, 0xF6, 0x8C, 0xF5, 0x31, 0xF3, 0xFA, 0xEF, 0xBB, 0xED, 0x89, 0xEC, 0x47, 0xEC, 0x2E, 0xEC, 0x0D, 0xEC, 0x4D, 0xEC, 0x2C, 0xED, 0x29, 0xEF, 0x57, 0xF1, 0xA4, 0xF3, 0x7A, 0xF6, 0x61, 0xF9, 0x29, 0xFC, 0xCF, 0xFE, 0x2D, 0x02, 0xE4, 0x04, 0xB4, 0x04, 0xD0, 0x01, 0x86, 0xFE, 0xD3, 0xFD, 0x07, 0xFF, 0x49, 0x00, 0xB2, 0x00, 0x91, 0xFF, 0xEE, 0xFD, 0xC1, 0xFC, 0x25, 0xFD, 0x42, 0xFF, 0x35, 0x01, 0x58, 0x01, 0xDF, 0xFE, 0x91, 0xFA, 0xF0, 0xF5, 0x91, 0xF2, 0xF1, 0xF0, 0xEE, 0xF0, 0xC5, 0xF2, 0x2F, 0xF5, 0x62, 0xF7, 0x82, 0xF8, 0x0E, 0xF7, 0x70, 0xF4, 0x75, 0xF2, 0x0C, 0xF2, 0x76, 0xF3, 0xFC, 0xF4, 0xF3, 0xF5, 0x08, 0xF7, 0xF9, 0xF7, 0x6A, 0xF8, 0x58, 0xF8, 0x78, 0xF8, 0x6F, 0xF9, 0x3D, 0xFA, 0xF4, 0xF9, 0xC5, 0xF8, 0xA0, 0xF7, 0x72, 0xF7, 0x87, 0xF8, 0x9B, 0xFB, 0xDF, 0x00, 0x77, 0x06, 0x84, 0x0A, 0x4C, 0x0C, 0x28, 0x0C, 0xA2, 0x0B, 0xD8, 0x0B, 0x9E, 0x0C, 0x2B, 0x0D, 0x71, 0x0C, 0xF5, 0x09, 0xD6, 0x05, 0xD4, 0x00, 0x3F, 0xFC, 0xA7, 0xF9, 0xB5, 0xFA, 0x7E, 0xFE, 0x23, 0x03, 0xDA, 0x07, 0x74, 0x0B, 0xFE, 0x0D, 0x26, 0x0F, 0xBB, 0x0E, 0x31, 0x0E, 0x5B, 0x0D, 0x75, 0x0B, 0x36, 0x08, 0xCD, 0x04, 0xB5, 0x03, 0x38, 0x05, 0x27, 0x08, 0xC5, 0x0A, 0x5B, 0x0B, 0x59, 0x09, 0xBE, 0x05, 0x8B, 0x02, 0xE6, 0x00, 0x74, 0x01, 0xC4, 0x03, 0xA7, 0x06, 0x1C, 0x09, 0xFF, 0x09, 0x2C, 0x09, 0xD4, 0x06, 0x82, 0x03, 0x0D, 0x00, 0xE0, 0xFC, 0x69, 0xFA, 0x2B, 0xF9, 0xE9, 0xF9, 0x3D, 0xFC, 0x27, 0xFF, 0x10, 0x02, 0x0B, 0x04, 0xF8, 0x04, 0x29, 0x04, 0x40, 0x01, 0xAF, 0xFD, 0xE7, 0xF9, 0x6B, 0xF6, 0xBA, 0xF3, 0xB7, 0xF1, 0x53, 0xF1, 0x59, 0xF3, 0x8A, 0xF7, 0x8A, 0xFC, 0xD1, 0x00, 0x19, 0x03, 0x7D, 0x03, 0x21, 0x03, 0x7D, 0x01, 0xE9, 0xFD, 0xBF, 0xF8, 0xDD, 0xF3, 0xA7, 0xF1, 0x95, 0xF2, 0xFC, 0xF5, 0x85, 0xF9, 0xCB, 0xFA, 0xA3, 0xF9, 0x70, 0xF7, 0x28, 0xF6, 0x30, 0xF6, 0x80, 0xF6, 0xA8, 0xF5, 0x9F, 0xF3, 0x12, 0xF2, 0x38, 0xF2, 0x11, 0xF5, 0xC0, 0xF9, 0x17, 0xFD, 0x94, 0xFC, 0x73, 0xF8, 0x49, 0xF3, 0x2D, 0xF0, 0xAC, 0xF0, 0x03, 0xF4, 0x5C, 0xF9, 0x7D, 0xFE, 0x42, 0x01, 0x33, 0x02, 0xEC, 0x01, 0xBC, 0x01, 0xE4, 0x01, 0x7F, 0x01, 0x36, 0x00, 0xA3, 0xFD, 0xFA, 0xFA, 0x53, 0xF9, 0x3C, 0xF9, 0xC8, 0xFA, 0x85, 0xFD, 0x03, 0x01, 0xB5, 0x03, 0x1D, 0x06, 0x88, 0x08, 0x9C, 0x09, 0xBC, 0x08, 0x23, 0x05, 0xAB, 0x00, 0x23, 0xFD, 0xC6, 0xFA, 0xB7, 0xF9, 0x71, 0xF8, 0xB3, 0xF6, 0xDC, 0xF4, 0x25, 0xF3, 0x31, 0xF2, 0xBA, 0xF1, 0x33, 0xF2, 0x99, 0xF3, 0x63, 0xF4, 0x5C, 0xF3, 0x60, 0xF1, 0x3B, 0xF0, 0x36, 0xF0, 0x44, 0xF1, 0x0F, 0xF3, 0x6C, 0xF5, 0x50, 0xF9, 0x7A, 0xFE, 0x7A, 0x03, 0x50, 0x07, 0x4D, 0x09, 0x3E, 0x09, 0x3E, 0x07, 0x05, 0x04, 0x50, 0x01, 0xEB, 0xFF, 0x28, 0xFF, 0x7F, 0xFE, 0xC9, 0xFD, 0xB2, 0xFD, 0x48, 0xFF, 0x6B, 0x02, 0x89, 0x06, 0xA5, 0x0A, 0x6D, 0x0D, 0xCD, 0x0E, 0xCC, 0x0E, 0x85, 0x0D, 0xB6, 0x0B, 0xAA, 0x09, 0xF3, 0x07, 0x1F, 0x07, 0x9D, 0x06, 0x89, 0x05, 0xDE, 0x03, 0x16, 0x02, 0xCC, 0x00, 0x17, 0x01, 0xD2, 0x02, 0xB5, 0x05, 0x6A, 0x09, 0x96, 0x0C, 0xB4, 0x0E, 0x16, 0x0F, 0x82, 0x0D, 0xBE, 0x0A, 0xC2, 0x07, 0x18, 0x06, 0x9F, 0x05, 0xC6, 0x05, 0x5D, 0x06, 0x1E, 0x07, 0xFD, 0x07, 0xC5, 0x08, 0x5D, 0x09, 0x81, 0x09, 0xB9, 0x09, 0xAE, 0x09, 0x1F, 0x08, 0x19, 0x05, 0xEB, 0x00, 0x4C, 0xFD, 0x94, 0xFB, 0x1A, 0xFB, 0x67, 0xFB, 0x27, 0xFC, 0x30, 0xFD, 0x1A, 0xFE, 0x96, 0xFE, 0x4F, 0xFE, 0xE3, 0xFD, 0x21, 0xFE, 0x5B, 0xFE, 0xBD, 0xFE, 0x69, 0xFF, 0xEF, 0xFF, 0x72, 0x00, 0xF0, 0x00, 0x54, 0x01, 0x2B, 0x02, 0xB1, 0x03, 0x99, 0x04, 0xEB, 0x04, 0x33, 0x05, 0x7A, 0x05, 0xF3, 0x05, 0x39, 0x05, 0xAF, 0x03, 0x0E, 0x02, 0xF4, 0xFF, 0x47, 0xFE, 0x56, 0xFD, 0xE8, 0xFC, 0xAB, 0xFC, 0x36, 0xFD, 0xFF, 0xFE, 0x83, 0x01, 0x4C, 0x04, 0x8E, 0x06, 0x2E, 0x08, 0xFB, 0x07, 0xD8, 0x05, 0x66, 0x02, 0x1D, 0xFE, 0x01, 0xFB, 0xAF, 0xF8, 0x3A, 0xF7, 0x82, 0xF6, 0x3B, 0xF5, 0xF1, 0xF4, 0x2B, 0xF6, 0xC5, 0xF8, 0xC4, 0xFB, 0x0C, 0xFE, 0x3E, 0x00, 0xC2, 0x01, 0x0F, 0x02, 0x46, 0x00, 0x20, 0xFD, 0x59, 0xFA, 0xC5, 0xF7, 0x11, 0xF6, 0x24, 0xF5, 0x08, 0xF4, 0x9F, 0xF2, 0x68, 0xF1, 0x7E, 0xF1, 0xBC, 0xF3, 0xF0, 0xF7, 0x65, 0xFC, 0x71, 0xFF, 0xC5, 0xFF, 0x3C, 0xFE, 0x91, 0xFC, 0x0F, 0xFB, 0xB3, 0xFA, 0x6A, 0xFA, 0xE2, 0xF8, 0x42, 0xF6, 0x02, 0xF3, 0x41, 0xF1, 0x71, 0xF1, 0x77, 0xF3, 0x1C, 0xF7, 0xEE, 0xFA, 0x32, 0xFE, 0xB7, 0xFF, 0x52, 0xFE, 0xEA, 0xF9, 0x0C, 0xF4, 0x81, 0xEE, 0x84, 0xEA, 0xCE, 0xE8, 0x93, 0xE8, 0xCD, 0xEA, 0x8F, 0xEF, 0xD3, 0xF4, 0xBC, 0xF9, 0xE3, 0xFC, 0x12, 0xFE, 0x25, 0xFD, 0x19, 0xFA, 0x82, 0xF6, 0xC9, 0xF3, 0xE2, 0xF3, 0x4B, 0xF7, 0x24, 0xFD, 0xC6, 0x03, 0xD2, 0x08, 0x0B, 0x0C, 0xEC, 0x0D, 0xD0, 0x0E, 0x86, 0x0F, 0xBB, 0x0F, 0xE7, 0x0D, 0x5B, 0x0A, 0x73, 0x07, 0x37, 0x07, 0xCA, 0x0A, 0x38, 0x10, 0x42, 0x14, 0x37, 0x15, 0x6A, 0x13, 0x29, 0x11, 0x64, 0x0F, 0x49, 0x0E, 0x23, 0x0D, 0x7B, 0x0A, 0xA1, 0x06, 0xF2, 0x01, 0xAA, 0xFD, 0x6C, 0xFB, 0x95, 0xFB, 0x24, 0xFD, 0x94, 0xFE, 0xDB, 0xFF, 0x0F, 0x01, 0x62, 0x02, 0x6C, 0x03, 0x4F, 0x03, 0xC1, 0x02, 0xFA, 0x01, 0x3E, 0x01, 0x21, 0x01, 0xE2, 0x01, 0x27, 0x04, 0x26, 0x08, 0x91, 0x0D, 0xA8, 0x13, 0xCF, 0x18, 0x36, 0x1B, 0xD3, 0x1A, 0xD9, 0x18, 0x29, 0x16, 0xC5, 0x13, 0xF0, 0x11, 0x37, 0x10, 0x77, 0x0E, 0x20, 0x0D, 0xCB, 0x0C, 0x81, 0x0D, 0x57, 0x0E, 0xE4, 0x0D, 0x44, 0x0C, 0xEB, 0x0A, 0x03, 0x0B, 0x4E, 0x0C, 0xA2, 0x0D, 0xB4, 0x0D, 0x68, 0x0C, 0x19, 0x0B, 0x36, 0x0A, 0x3F, 0x0A, 0x54, 0x0B, 0xA7, 0x0C, 0xA6, 0x0D, 0x81, 0x0D, 0x4E, 0x0D, 0x97, 0x0D, 0x15, 0x0E, 0x9E, 0x0E, 0x1F, 0x0E, 0xAA, 0x0D, 0x0E, 0x0D, 0xB7, 0x0B, 0x9A, 0x0A, 0xF9, 0x09, 0x6E, 0x0A, 0x1A, 0x0B, 0x26, 0x0B, 0xF1, 0x09, 0x72, 0x07, 0xFE, 0x04, 0x47, 0x02, 0x96, 0xFF, 0xC0, 0xFD, 0x61, 0xFD, 0x1B, 0xFE, 0x15, 0xFE, 0x93, 0xFC, 0x3C, 0xFA, 0x2D, 0xF9, 0x7E, 0xFA, 0x3A, 0xFD, 0xB0, 0xFF, 0x76, 0x00, 0xDE, 0xFF, 0xF7, 0xFD, 0x8E, 0xFB, 0xB7, 0xF9, 0x48, 0xF8, 0x36, 0xF7, 0xD7, 0xF5, 0xAA, 0xF3, 0x70, 0xF1, 0x7F, 0xF0, 0x45, 0xF1, 0xFD, 0xF2, 0x3A, 0xF4, 0x46, 0xF4, 0x73, 0xF3, 0xA9, 0xF1, 0xAD, 0xEF, 0x34, 0xEE, 0x9D, 0xED, 0x56, 0xEE, 0x29, 0xF0, 0xC8, 0xF2, 0x22, 0xF5, 0x0B, 0xF7, 0xC4, 0xF8, 0xF1, 0xFA, 0x3F, 0xFD, 0xBF, 0xFD, 0x79, 0xFC, 0x89, 0xF9, 0xD4, 0xF6, 0xAF, 0xF5, 0x5A, 0xF5, 0xC2, 0xF6, 0xF5, 0xF8, 0x55, 0xFB, 0x3D, 0xFD, 0xC0, 0xFE, 0x25, 0x01, 0xFD, 0x02, 0xC8, 0x03, 0xEC, 0x02, 0x84, 0x01, 0x38, 0x01, 0xC2, 0x01, 0x24, 0x03, 0xC7, 0x03, 0x56, 0x04, 0x96, 0x04, 0x85, 0x03, 0xF5, 0x01, 0xF2, 0xFE, 0xCA, 0xFB, 0x77, 0xF9, 0xF6, 0xF8, 0xB6, 0xFB, 0x38, 0x00, 0xF0, 0x04, 0xEE, 0x07, 0x09, 0x09, 0xC9, 0x08, 0xF9, 0x06, 0x64, 0x04, 0x9A, 0x01, 0x85, 0xFF, 0xA1, 0xFD, 0x3F, 0xFB, 0xF6, 0xF8, 0xE5, 0xF7, 0x13, 0xF9, 0x4A, 0xFC, 0x13, 0x00, 0xB6, 0x01, 0x33, 0x00, 0xB7, 0xFB, 0xC9, 0xF5, 0x2E, 0xF1, 0x23, 0xEF, 0x82, 0xF0, 0xAD, 0xF3, 0xF5, 0xF6, 0xAA, 0xFA, 0xF5, 0xFE, 0x5F, 0x04, 0xA2, 0x09, 0x29, 0x0D, 0xB1, 0x0E, 0xCB, 0x0E, 0x29, 0x0E, 0x34, 0x0D, 0xAD, 0x0C, 0x42, 0x0C, 0x33, 0x0C, 0x75, 0x0C, 0x80, 0x0C, 0xB7, 0x0C, 0xC2, 0x0C, 0xD4, 0x0C, 0x5F, 0x0C, 0x7E, 0x0A, 0xB7, 0x07, 0x24, 0x05, 0x19, 0x04, 0x49, 0x05, 0x45, 0x09, 0x0F, 0x0F, 0x78, 0x14, 0x7E, 0x17, 0x34, 0x17, 0x4E, 0x15, 0xD6, 0x13, 0x9F, 0x13, 0x11, 0x14, 0x5C, 0x14, 0xB7, 0x14, 0x15, 0x15, 0xE1, 0x14, 0x7D, 0x13, 0xDB, 0x10, 0xC3, 0x0D, 0xDD, 0x0B, 0x74, 0x0B, 0xB0, 0x0B, 0x72, 0x0C, 0x55, 0x0D, 0x07, 0x0F, 0x5F, 0x11, 0x5E, 0x13, 0x25, 0x15, 0xDE, 0x15, 0x09, 0x15, 0x9E, 0x12, 0x38, 0x0F, 0x4A, 0x0C, 0x8D, 0x0A, 0x3E, 0x0A, 0x8C, 0x0A, 0x88, 0x0A, 0x7E, 0x09, 0xEF, 0x06, 0x78, 0x03, 0x8B, 0xFF, 0xF0, 0xFB, 0x35, 0xFA, 0xB4, 0xFA, 0x9D, 0xFC, 0x67, 0xFF, 0x00, 0x02, 0x91, 0x03, 0x00, 0x04, 0xD8, 0x02, 0x6F, 0x00, 0x42, 0xFD, 0xDF, 0xF9, 0x7D, 0xF7, 0xA5, 0xF6, 0x63, 0xF7, 0x57, 0xFA, 0xFD, 0xFE, 0x4E, 0x03, 0x0D, 0x06, 0xED, 0x05, 0x8E, 0x03, 0x64, 0x00, 0xED, 0xFB, 0x16, 0xF8, 0x91, 0xF6, 0xD9, 0xF7, 0x51, 0xFB, 0xDB, 0xFD, 0xE5, 0xFE, 0x83, 0xFE, 0x29, 0xFD, 0x62, 0xFB, 0xD4, 0xF8, 0xFC, 0xF6, 0xBF, 0xF6, 0x73, 0xF8, 0x69, 0xFA, 0xF6, 0xFA, 0xE6, 0xFA, 0xFC, 0xF9, 0x0B, 0xF9, 0x27, 0xF8, 0xE5, 0xF6, 0x9F, 0xF6, 0xC7, 0xF7, 0x5E, 0xFA, 0x7B, 0xFD, 0x63, 0x00, 0x9B, 0x02, 0x61, 0x03, 0xA3, 0x02, 0x32, 0x00, 0xB9, 0xFC, 0x0E, 0xF9, 0x76, 0xF6, 0x88, 0xF5, 0x47, 0xF5, 0x3E, 0xF5, 0xEE, 0xF4, 0x25, 0xF5, 0xBE, 0xF6, 0x63, 0xF8, 0x92, 0xF8, 0xAA, 0xF6, 0xBA, 0xF3, 0x5C, 0xF1, 0xEC, 0xEF, 0xFB, 0xEE, 0xBD, 0xEE, 0x24, 0xEF, 0xEC, 0xEF, 0x66, 0xF1, 0x73, 0xF3, 0x6A, 0xF6, 0xC9, 0xF9, 0x75, 0xFC, 0x4C, 0xFE, 0xEF, 0xFE, 0x72, 0xFE, 0x08, 0xFD, 0x1A, 0xFB, 0xF1, 0xF8, 0xD2, 0xF6, 0xBF, 0xF5, 0x7D, 0xF5, 0x81, 0xF6, 0xE7, 0xF8, 0x79, 0xFB, 0x69, 0xFE, 0xC1, 0x00, 0x7F, 0x01, 0x0B, 0x01, 0xCA, 0xFF, 0xBA, 0xFE, 0x98, 0xFE, 0xA6, 0xFE, 0xEC, 0xFD, 0x8C, 0xFC, 0x87, 0xFA, 0xCE, 0xF8, 0xBF, 0xF7, 0xD2, 0xF6, 0xE1, 0xF7, 0x5E, 0xFB, 0x31, 0x01, 0x21, 0x08, 0xD2, 0x0C, 0x38, 0x0F, 0x2C, 0x0F, 0x2F, 0x0D, 0x86, 0x0A, 0xAC, 0x06, 0x79, 0x02, 0x5C, 0xFE, 0x78, 0xFB, 0x50, 0xFB, 0xA1, 0xFE, 0xEB, 0x04, 0x27, 0x0B, 0xDD, 0x0F, 0xCB, 0x11, 0xB7, 0x10, 0x31, 0x0E, 0x7B, 0x0A, 0xA5, 0x06, 0x38, 0x03, 0xAD, 0x00, 0x63, 0xFF, 0xA5, 0xFF, 0x5C, 0x02, 0xA9, 0x06, 0xEE, 0x0B, 0xB7, 0x10, 0x9B, 0x13, 0x3E, 0x14, 0x21, 0x12, 0x9D, 0x0F, 0x31, 0x0E, 0x16, 0x0E, 0xE4, 0x0E, 0x1D, 0x0E, 0x0C, 0x0B, 0xF3, 0x06, 0x81, 0x03, 0x7C, 0x01, 0x0B, 0x01, 0x83, 0x02, 0xE2, 0x05, 0x6F, 0x0A, 0x83, 0x0E, 0x72, 0x11, 0xCA, 0x12, 0xF1, 0x12, 0xB4, 0x12, 0x6E, 0x11, 0xCF, 0x0F, 0x9F, 0x0D, 0xFA, 0x0A, 0x5E, 0x09, 0x68, 0x08, 0x9A, 0x08, 0xAC, 0x09, 0x0E, 0x0A, 0xE3, 0x09, 0x71, 0x09, 0x43, 0x09, 0x79, 0x0A, 0xC8, 0x0C, 0xFB, 0x0E, 0xEF, 0x10, 0xD0, 0x11, 0xAB, 0x10, 0x4D, 0x0E, 0x14, 0x0B, 0xA9, 0x07, 0x69, 0x04, 0x76, 0x01, 0x93, 0xFF, 0xDA, 0xFD, 0xDE, 0xFB, 0x9C, 0xFA, 0xE0, 0xFA, 0x1C, 0xFD, 0x5E, 0x00, 0xFF, 0x02, 0xB9, 0x03, 0x83, 0x02, 0x67, 0x00, 0x22, 0xFE, 0x5E, 0xFC, 0x60, 0xFB, 0x9E, 0xFB, 0x36, 0xFD, 0xFE, 0xFE, 0xEF, 0xFF, 0x6A, 0xFF, 0xB8, 0xFD, 0x71, 0xFB, 0x82, 0xF8, 0xAF, 0xF4, 0x45, 0xF0, 0x92, 0xEC, 0x26, 0xEA, 0x54, 0xE9, 0x2A, 0xEA, 0x50, 0xEB, 0x0B, 0xEC, 0x9B, 0xEC, 0xFD, 0xED, 0xDF, 0xEF, 0x6A, 0xF1, 0xFD, 0xF2, 0xC2, 0xF3, 0xF2, 0xF3, 0xF5, 0xF3, 0xB7, 0xF3, 0x2D, 0xF4, 0x14, 0xF5, 0xF0, 0xF5, 0xFB, 0xF5, 0x98, 0xF5, 0xA1, 0xF5, 0xB8, 0xF5, 0x05, 0xF6, 0x7A, 0xF5, 0x7C, 0xF4, 0x04, 0xF4, 0xA6, 0xF3, 0xE4, 0xF3, 0x00, 0xF4, 0xE1, 0xF3, 0xA0, 0xF3, 0xFA, 0xF2, 0xA2, 0xF2, 0xE6, 0xF2, 0x6E, 0xF4, 0x99, 0xF6, 0x23, 0xF9, 0xE9, 0xFB, 0xBE, 0xFD, 0xFD, 0xFE, 0x13, 0xFF, 0xE2, 0xFD, 0x8B, 0xFB, 0x9F, 0xF7, 0x12, 0xF3, 0xDF, 0xEE, 0xE8, 0xEC, 0x37, 0xEE, 0x48, 0xF2, 0x79, 0xF8, 0x77, 0xFF, 0x15, 0x06, 0xE4, 0x0A, 0x03, 0x0D, 0x6B, 0x0C, 0x9B, 0x09, 0xB1, 0x05, 0x0A, 0x01, 0xA7, 0xFC, 0xC3, 0xF9, 0x6D, 0xF8, 0x32, 0xF9, 0x7A, 0xFC, 0x2C, 0x01, 0x47, 0x06, 0xB5, 0x0A, 0xB6, 0x0C, 0x34, 0x0C, 0xCF, 0x09, 0x5C, 0x06, 0xD8, 0x03, 0xFB, 0x02, 0xC2, 0x02, 0xE3, 0x01, 0x05, 0x00, 0xF1, 0xFD, 0x6F, 0xFC, 0x01, 0xFC, 0xF4, 0xFC, 0x65, 0xFF, 0xEC, 0x02, 0xAA, 0x06, 0x95, 0x09, 0x39, 0x0B, 0xEB, 0x0B, 0x02, 0x0C, 0xB8, 0x0B, 0x46, 0x0B, 0x0A, 0x0B, 0xE9, 0x0A, 0x31, 0x0A, 0xCC, 0x08, 0x15, 0x07, 0x1F, 0x06, 0xC7, 0x06, 0x2F, 0x08, 0x9B, 0x09, 0x7B, 0x0A, 0x12, 0x0A, 0xDD, 0x08, 0x3A, 0x07, 0xC1, 0x05, 0x6E, 0x05, 0xBF, 0x05, 0xE2, 0x05, 0xC6, 0x05, 0xE6, 0x05, 0x90, 0x07, 0x10, 0x0B, 0x70, 0x0E, 0x32, 0x10, 0xA4, 0x10, 0x43, 0x10, 0x61, 0x10, 0x3D, 0x11, 0xC5, 0x11, 0x45, 0x12, 0xE3, 0x11, 0x2C, 0x10, 0xB9, 0x0D, 0x7C, 0x0A, 0xC3, 0x07, 0x0E, 0x06, 0x78, 0x05, 0x04, 0x06, 0xB9, 0x06, 0x06, 0x08, 0x41, 0x0A, 0x9D, 0x0C, 0x99, 0x0D, 0x3D, 0x0C, 0xE0, 0x08, 0xF7, 0x03, 0x14, 0xFF, 0xDA, 0xFB, 0x28, 0xFB, 0xA1, 0xFC, 0x43, 0xFF, 0xA5, 0x02, 0x89, 0x05, 0x1B, 0x07, 0xEC, 0x06, 0xBA, 0x04, 0x59, 0x01, 0x97, 0xFD, 0x56, 0xFA, 0xE5, 0xF7, 0x01, 0xF6, 0x9F, 0xF4, 0x87, 0xF3, 0x67, 0xF2, 0x25, 0xF1, 0x05, 0xF1, 0x99, 0xF2, 0xB3, 0xF4, 0x0D, 0xF6, 0x64, 0xF5, 0x55, 0xF3, 0x4B, 0xF1, 0xE6, 0xEF, 0x90, 0xEF, 0x6C, 0xEF, 0x78, 0xEF, 0xAD, 0xF0, 0x6C, 0xF2, 0x9E, 0xF3, 0x7C, 0xF3, 0x53, 0xF2, 0x7F, 0xF1, 0x88, 0xF1, 0x0F, 0xF2, 0x11, 0xF2, 0x3E, 0xF1, 0x96, 0xF0, 0xD7, 0xF0, 0x3C, 0xF2, 0xD9, 0xF3, 0x85, 0xF4, 0x71, 0xF4, 0x02, 0xF4, 0x0C, 0xF4, 0x14, 0xF5, 0x5D, 0xF6, 0x3F, 0xF7, 0x2F, 0xF7, 0xEE, 0xF6, 0xAD, 0xF7, 0x91, 0xF8, 0x3A, 0xF9, 0x93, 0xF9, 0x4E, 0xF9, 0xA6, 0xF9, 0x27, 0xFB, 0x70, 0xFD, 0xF6, 0xFF, 0x78, 0x01, 0x9F, 0x01, 0xC3, 0x01, 0x50, 0x02, 0x2C, 0x02, 0xD8, 0x00, 0x54, 0xFE, 0xEE, 0xFB, 0x0E, 0xFB, 0xF7, 0xFA, 0xB6, 0xFB, 0x03, 0xFD, 0x31, 0xFE, 0xA5, 0xFF, 0x7A, 0x00, 0xDB, 0x00, 0x85, 0x01, 0x2E, 0x02, 0xAF, 0x02, 0x0C, 0x03, 0xB7, 0x03, 0x83, 0x04, 0x38, 0x05, 0xB0, 0x05, 0xFB, 0x05, 0x24, 0x06, 0x4E, 0x05, 0xFA, 0x03, 0xA8, 0x02, 0x43, 0x01, 0xA3, 0x00, 0xEA, 0x00, 0xDB, 0x01, 0x89, 0x03, 0x35, 0x05, 0x5D, 0x06, 0xC3, 0x07, 0x43, 0x09, 0x9B, 0x0A, 0x4D, 0x0B, 0x47, 0x0A, 0x30, 0x08, 0x0C, 0x05, 0xE9, 0x01, 0x2E, 0x00, 0x17, 0xFF, 0x1F, 0xFF, 0x23, 0x00, 0x05, 0x02, 0x67, 0x05, 0x16, 0x0A, 0x57, 0x0F, 0xF6, 0x13, 0xD0, 0x17, 0xF6, 0x19, 0xDF, 0x1A, 0x89, 0x1B, 0xE5, 0x1A, 0xA2, 0x18, 0xFC, 0x13, 0x47, 0x0F, 0x70, 0x0D, 0x25, 0x0E, 0xBB, 0x10, 0xF2, 0x12, 0x2C, 0x14, 0x2B, 0x14, 0x97, 0x12, 0x4A, 0x10, 0xEF, 0x0C, 0x91, 0x09, 0xE6, 0x06, 0xBC, 0x05, 0xD7, 0x05, 0x16, 0x05, 0xBB, 0x03, 0xFF, 0x01, 0x9D, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xA0, 0xFE, 0xBE, 0xFE, 0xDC, 0xFF, 0x12, 0x01, 0x2E, 0x01, 0x4C, 0x00, 0xAD, 0xFE, 0x0F, 0xFD, 0xBA, 0xFB, 0x12, 0xFB, 0x4B, 0xFB, 0xBB, 0xFB, 0x4D, 0xFC, 0x05, 0xFD, 0x13, 0xFE, 0x1D, 0xFF, 0x3F, 0xFF, 0xAF, 0xFE, 0xBF, 0xFD, 0xC5, 0xFB, 0x7A, 0xF8, 0x9E, 0xF4, 0xA8, 0xF1, 0x17, 0xF1, 0xC5, 0xF2, 0xFC, 0xF4, 0x5B, 0xF6, 0xC6, 0xF6, 0x7B, 0xF6, 0x9D, 0xF5, 0x79, 0xF4, 0x60, 0xF3, 0x34, 0xF3, 0x36, 0xF4, 0x0E, 0xF6, 0x1F, 0xF8, 0xCC, 0xF8, 0xD1, 0xF7, 0xE0, 0xF5, 0x17, 0xF4, 0x26, 0xF4, 0xBA, 0xF5, 0x2C, 0xF8, 0xFA, 0xFA, 0x31, 0xFD, 0xBB, 0xFE, 0x0C, 0xFF, 0x71, 0xFD, 0x43, 0xFA, 0x15, 0xF6, 0xF3, 0xF1, 0x99, 0xEF, 0x7D, 0xEF, 0x4F, 0xF1, 0xB8, 0xF4, 0xC2, 0xF7, 0x76, 0xF9, 0x15, 0xFA, 0xAC, 0xF9, 0xA5, 0xF9, 0x8F, 0xFA, 0xFD, 0xFB, 0xE1, 0xFD, 0xAA, 0xFE, 0x82, 0xFD, 0x94, 0xFB, 0xBD, 0xF9, 0x5B, 0xF8, 0xB3, 0xF7, 0xA3, 0xF7, 0x86, 0xF7, 0xD9, 0xF6, 0x07, 0xF6, 0xB5, 0xF5, 0x3E, 0xF6, 0x92, 0xF7, 0x0E, 0xF9, 0x13, 0xFA, 0x65, 0xFA, 0xED, 0xF9, 0x6F, 0xF8, 0xF3, 0xF5, 0x1E, 0xF3, 0x77, 0xF0, 0xDD, 0xEE, 0x09, 0xEF, 0x80, 0xF0, 0x8C, 0xF2, 0x4E, 0xF4, 0xB4, 0xF5, 0x8B, 0xF7, 0xF5, 0xF9, 0x9B, 0xFC, 0x1C, 0xFF, 0x24, 0x01, 0x59, 0x02, 0xE0, 0x02, 0x1F, 0x03, 0xD6, 0x02, 0x95, 0x02, 0xC2, 0x02, 0x08, 0x03, 0x03, 0x04, 0x8C, 0x05, 0x61, 0x07, 0xB7, 0x08, 0x74, 0x08, 0xF0, 0x07, 0x23, 0x08, 0xD2, 0x08, 0xE9, 0x09, 0x16, 0x0B, 0xF5, 0x0B, 0xE7, 0x0B, 0xB9, 0x0A, 0x48, 0x08, 0x3D, 0x05, 0xDE, 0x02, 0xF8, 0x01, 0x79, 0x03, 0x54, 0x06, 0x8C, 0x09, 0xB2, 0x0C, 0xBD, 0x0E, 0xA5, 0x10, 0x45, 0x12, 0x3B, 0x13, 0xE1, 0x13, 0x6A, 0x13, 0x3A, 0x12, 0x0E, 0x10, 0x82, 0x0D, 0x49, 0x0C, 0x48, 0x0C, 0xEF, 0x0C, 0x9D, 0x0C, 0x0A, 0x0B, 0xE4, 0x09, 0xCE, 0x09, 0xC9, 0x0A, 0xE8, 0x0B, 0xE2, 0x0C, 0xE0, 0x0D, 0x65, 0x0E, 0x68, 0x0E, 0xC8, 0x0D, 0xE9, 0x0C, 0x6F, 0x0C, 0xFA, 0x0B, 0x64, 0x0B, 0xBD, 0x0A, 0xD7, 0x09, 0xDC, 0x08, 0xD2, 0x07, 0x2D, 0x06, 0xE4, 0x03, 0x75, 0x01, 0x9D, 0xFF, 0x54, 0xFF, 0x69, 0x00, 0x33, 0x02, 0x8D, 0x04, 0xA6, 0x06, 0xC8, 0x07, 0x83, 0x07, 0x61, 0x06, 0xE6, 0x05, 0x54, 0x06, 0xFC, 0x06, 0xAE, 0x06, 0xC9, 0x04, 0x13, 0x02, 0x84, 0xFF, 0x72, 0xFE, 0x2E, 0xFF, 0x59, 0x00, 0xD7, 0x00, 0x41, 0x00, 0xA8, 0xFF, 0x3D, 0x00, 0xF2, 0x01, 0x3F, 0x04, 0x30, 0x06, 0x47, 0x07, 0x27, 0x07, 0x16, 0x05, 0x75, 0x01, 0x0A, 0xFD, 0xAD, 0xF8, 0xA8, 0xF5, 0x3E, 0xF4, 0x3E, 0xF4, 0x8C, 0xF5, 0xD6, 0xF6, 0x6C, 0xF7, 0x5C, 0xF7, 0x0D, 0xF6, 0x55, 0xF4, 0x13, 0xF3, 0x0D, 0xF2, 0x72, 0xF1, 0x97, 0xF0, 0x81, 0xEF, 0x77, 0xEF, 0x81, 0xF0, 0x45, 0xF2, 0x0D, 0xF4, 0x34, 0xF5, 0xC0, 0xF5, 0xFD, 0xF5, 0x94, 0xF6, 0x10, 0xF7, 0x31, 0xF7, 0x42, 0xF7, 0x35, 0xF7, 0x9A, 0xF7, 0x7D, 0xF8, 0x70, 0xF9, 0xE1, 0xF9, 0xF0, 0xF9, 0x5B, 0xFA, 0x76, 0xFA, 0x1C, 0xFA, 0x84, 0xF9, 0xBF, 0xF8, 0xFD, 0xF7, 0x21, 0xF7, 0x24, 0xF6, 0x10, 0xF4, 0x7F, 0xF1, 0x47, 0xEF, 0xFF, 0xEC, 0x93, 0xEB, 0x9A, 0xEA, 0xEB, 0xE9, 0x1F, 0xEA, 0x68, 0xEA, 0x2D, 0xEB, 0xD4, 0xEC, 0x40, 0xEF, 0x5C, 0xF2, 0x29, 0xF5, 0xA3, 0xF6, 0x33, 0xF6, 0xFD, 0xF3, 0x25, 0xF1, 0x82, 0xEF, 0x13, 0xF0, 0x98, 0xF2, 0x3B, 0xF6, 0xB5, 0xF9, 0xFD, 0xFB, 0x19, 0xFD, 0xCE, 0xFD, 0x6E, 0xFE, 0x82, 0xFF, 0xCB, 0x00, 0x85, 0x01, 0xA8, 0x01, 0xA8, 0x00, 0x03, 0xFF, 0x08, 0xFD, 0x26, 0xFB, 0x97, 0xFA, 0xE9, 0xFA, 0x47, 0xFC, 0x65, 0xFE, 0x58, 0x00, 0x0C, 0x02, 0x92, 0x03, 0x9C, 0x05, 0x70, 0x07, 0x9F, 0x08, 0x65, 0x08, 0x81, 0x06, 0xBC, 0x04, 0xDA, 0x02, 0xBB, 0x01, 0xC7, 0x01, 0x91, 0x02, 0x47, 0x05, 0x6D, 0x08, 0xFB, 0x0A, 0x7D, 0x0C, 0x4A, 0x0C, 0x67, 0x0B, 0x85, 0x0A, 0x15, 0x0A, 0x4D, 0x09, 0xCD, 0x07, 0x89, 0x06, 0x25, 0x06, 0xD2, 0x06, 0xFD, 0x07, 0x80, 0x09, 0x8E, 0x0A, 0xA8, 0x0A, 0x0E, 0x0A, 0x8F, 0x08, 0x13, 0x07, 0xE5, 0x05, 0x73, 0x05, 0x0A, 0x06, 0x97, 0x06, 0x81, 0x06, 0xAA, 0x05, 0xD4, 0x04, 0x56, 0x04, 0x70, 0x04, 0x8C, 0x05, 0x1A, 0x07, 0xFC, 0x08, 0x22, 0x0A, 0xEF, 0x09, 0xDD, 0x08, 0x5F, 0x07, 0x6B, 0x06, 0x5A, 0x05, 0x18, 0x04, 0xED, 0x02, 0x91, 0x01, 0x38, 0x01, 0x32, 0x02, 0x0C, 0x04, 0x12, 0x06, 0xDD, 0x07, 0x9C, 0x09, 0xEE, 0x0A, 0x9D, 0x0C, 0x33, 0x0E, 0x93, 0x0E, 0xC8, 0x0D, 0x84, 0x0B, 0x73, 0x08, 0x6D, 0x05, 0x27, 0x03, 0xEE, 0x01, 0x85, 0x01, 0xC6, 0x01, 0x31, 0x02, 0x8A, 0x02, 0x84, 0x02, 0xFA, 0x02, 0x46, 0x04, 0xCE, 0x05, 0x58, 0x07, 0xDA, 0x06, 0x5E, 0x04, 0x00, 0x01, 0x3C, 0xFD, 0x1A, 0xFB, 0xA2, 0xFA, 0x8A, 0xFB, 0x25, 0xFD, 0xEE, 0xFD, 0x47, 0xFE, 0x54, 0xFE, 0x2A, 0xFE, 0x12, 0xFE, 0x29, 0xFE, 0xCB, 0xFD, 0x3A, 0xFC, 0xB1, 0xF9, 0x85, 0xF6, 0x6A, 0xF4, 0xFF, 0xF3, 0xCE, 0xF4, 0x25, 0xF6, 0xDD, 0xF5, 0x09, 0xF4, 0xD5, 0xF1, 0xFF, 0xEF, 0x50, 0xEF, 0x89, 0xEF, 0x50, 0xF0, 0xD9, 0xF0, 0xB9, 0xF0, 0xE9, 0xEF, 0xA5, 0xEE, 0x96, 0xED, 0xA8, 0xEC, 0x05, 0xEC, 0x5C, 0xEB, 0x7E, 0xEA, 0xF3, 0xE9, 0x3B, 0xE9, 0xF2, 0xE8, 0xB8, 0xE9, 0x39, 0xEA, 0x99, 0xEA, 0x30, 0xEB, 0x38, 0xEB, 0x2F, 0xEB, 0x3B, 0xEB, 0xA7, 0xEB, 0x67, 0xED, 0xCC, 0xEF, 0xF9, 0xF1, 0x8B, 0xF3, 0x7A, 0xF4, 0xBA, 0xF5, 0x13, 0xF8, 0xE7, 0xFA, 0xFA, 0xFC, 0xDE, 0xFD, 0xB6, 0xFD, 0xDB, 0xFD, 0x8B, 0xFE, 0x32, 0xFF, 0x64, 0x00, 0x6C, 0x01, 0x5C, 0x02, 0x59, 0x03, 0x8E, 0x03, 0xCE, 0x03, 0x7A, 0x04, 0x8C, 0x05, 0xA7, 0x06, 0x7A, 0x07, 0xF6, 0x07, 0xB3, 0x07, 0x43, 0x07, 0x5D, 0x06, 0xF0, 0x04, 0xCA, 0x02, 0xBE, 0xFF, 0x21, 0xFD, 0x48, 0xFB, 0xEC, 0xFA, 0x53, 0xFC, 0x6C, 0xFE, 0x5B, 0x00, 0x38, 0x01, 0x4E, 0x01, 0x7B, 0x00, 0x2C, 0xFE, 0x11, 0xFB, 0x55, 0xF8, 0x9D, 0xF6, 0xE0, 0xF5, 0x17, 0xF6, 0xF7, 0xF6, 0xA5, 0xF8, 0x38, 0xFB, 0xB2, 0xFD, 0x2B, 0xFF, 0x6E, 0xFF, 0x02, 0xFF, 0x7B, 0xFE, 0x74, 0xFE, 0xB9, 0xFE, 0x5C, 0xFF, 0x82, 0x00, 0x63, 0x01, 0x82, 0x02, 0xD7, 0x03, 0x67, 0x05, 0x7B, 0x07, 0xC3, 0x08, 0x7A, 0x08, 0x3A, 0x06, 0xB4, 0x02, 0x04, 0xFF, 0x5B, 0xFC, 0x3F, 0xFB, 0x27, 0xFB, 0x5C, 0xFD, 0x3F, 0x01, 0xDB, 0x05, 0x3D, 0x0A, 0x37, 0x0C, 0xC8, 0x0C, 0x7D, 0x0C, 0x7D, 0x0C, 0x4C, 0x0E, 0xF8, 0x10, 0x28, 0x14, 0x97, 0x16, 0x6F, 0x17, 0x2F, 0x17, 0x8E, 0x16, 0x2A, 0x16, 0x69, 0x15, 0x96, 0x13, 0x7D, 0x10, 0x6C, 0x0D, 0x19, 0x0B, 0x7B, 0x09, 0xFC, 0x08, 0x80, 0x09, 0xD0, 0x0B, 0x06, 0x0F, 0xCD, 0x11, 0xC7, 0x13, 0x0B, 0x14, 0x8F, 0x12, 0x75, 0x0F, 0xC1, 0x0B, 0x80, 0x08, 0x24, 0x06, 0x13, 0x05, 0xCC, 0x04, 0xF3, 0x04, 0xC6, 0x04, 0x97, 0x04, 0x1A, 0x05, 0xC3, 0x05, 0x55, 0x06, 0x6C, 0x06, 0x48, 0x06, 0x53, 0x06, 0x30, 0x06, 0x30, 0x05, 0x80, 0x03, 0x97, 0x01, 0x61, 0xFF, 0xA7, 0xFD, 0xDD, 0xFC, 0x78, 0xFD, 0xD3, 0xFE, 0x70, 0xFF, 0x61, 0xFF, 0xEE, 0xFD, 0xA8, 0xFB, 0xAE, 0xF9, 0x7C, 0xF7, 0xC0, 0xF5, 0xB6, 0xF4, 0x27, 0xF4, 0x97, 0xF4, 0xCB, 0xF5, 0xDD, 0xF6, 0xDB, 0xF7, 0x42, 0xF8, 0x4A, 0xF7, 0x19, 0xF6, 0x82, 0xF5, 0x79, 0xF6, 0x40, 0xF9, 0xDB, 0xFC, 0x31, 0x01, 0xF6, 0x04, 0x1E, 0x07, 0x9E, 0x07, 0x47, 0x06, 0x3E, 0x03, 0x04, 0xFF, 0x34, 0xFB, 0x2A, 0xF9, 0xAE, 0xF9, 0x10, 0xFC, 0x10, 0xFF, 0x51, 0x02, 0xA9, 0x04, 0x8F, 0x05, 0x18, 0x05, 0x87, 0x03, 0xBD, 0x01, 0x12, 0x00, 0x55, 0xFE, 0x2B, 0xFC, 0xC2, 0xF9, 0x90, 0xF7, 0x6D, 0xF6, 0xC6, 0xF6, 0x64, 0xF8, 0xCB, 0xFA, 0xAF, 0xFC, 0x68, 0xFD, 0x81, 0xFC, 0x10, 0xFA, 0xFC, 0xF6, 0xF5, 0xF3, 0x3A, 0xF2, 0xBF, 0xF1, 0xA4, 0xF1, 0x9F, 0xF1, 0x45, 0xF1, 0xE8, 0xF0, 0x7D, 0xF1, 0xD5, 0xF2, 0x41, 0xF4, 0xF8, 0xF5, 0x11, 0xF7, 0x2E, 0xF7, 0x60, 0xF6, 0xF0, 0xF3, 0x32, 0xF1, 0xD4, 0xEE, 0x55, 0xED, 0x09, 0xED, 0xED, 0xEC, 0xC1, 0xED, 0x67, 0xEF, 0x8E, 0xF1, 0xD2, 0xF3, 0x03, 0xF5, 0xB6, 0xF5, 0x73, 0xF6, 0x16, 0xF8, 0xB0, 0xFA, 0x27, 0xFD, 0xF1, 0xFE, 0x5B, 0xFF, 0xAA, 0xFE, 0xBE, 0xFD, 0x2E, 0xFD, 0x6A, 0xFD, 0xB4, 0xFE, 0x1E, 0x01, 0x56, 0x04, 0xE1, 0x07, 0x13, 0x0B, 0x81, 0x0D, 0xBF, 0x0E, 0xAF, 0x0E, 0x58, 0x0D, 0xA6, 0x0A, 0x87, 0x07, 0x55, 0x05, 0xE5, 0x04, 0xED, 0x05, 0x1F, 0x08, 0x0C, 0x0B, 0xCD, 0x0D, 0x02, 0x10, 0xFD, 0x10, 0xEF, 0x10, 0x4A, 0x10, 0x28, 0x0F, 0xCB, 0x0D, 0xD3, 0x0B, 0xDC, 0x09, 0x2A, 0x08, 0xA1, 0x06, 0xC3, 0x05, 0x42, 0x05, 0x5D, 0x05, 0x8D, 0x06, 0xAF, 0x08, 0x32, 0x0B, 0x37, 0x0D, 0x04, 0x0E, 0x64, 0x0D, 0x29, 0x0C, 0xDD, 0x0A, 0xEB, 0x09, 0x79, 0x09, 0xDD, 0x08, 0x29, 0x08, 0xD7, 0x07, 0x60, 0x08, 0xED, 0x09, 0x6A, 0x0B, 0xFB, 0x0B, 0xB9, 0x0B, 0x1D, 0x0B, 0xD4, 0x0A, 0xB9, 0x0A, 0x1B, 0x0A, 0x34, 0x09, 0xBE, 0x07, 0xA7, 0x05, 0xDC, 0x03, 0xF7, 0x01, 0x11, 0x00, 0x08, 0xFF, 0xCD, 0xFE, 0x8C, 0xFF, 0x50, 0x01, 0x60, 0x03, 0x85, 0x05, 0x99, 0x07, 0x7D, 0x09, 0x34, 0x0B, 0xB0, 0x0B, 0x2D, 0x0A, 0x45, 0x07, 0x67, 0x03, 0x91, 0xFF, 0x3A, 0xFD, 0xDF, 0xFC, 0x1D, 0xFE, 0xC4, 0x00, 0xE0, 0x04, 0x0B, 0x0A, 0x3D, 0x0F, 0xB2, 0x12, 0x63, 0x13, 0x59, 0x11, 0x1C, 0x0D, 0x3F, 0x08, 0x35, 0x04, 0x7C, 0x01, 0x3A, 0x00, 0xD7, 0xFF, 0xA3, 0xFF, 0x38, 0x00, 0xB1, 0x01, 0x8D, 0x03, 0x6B, 0x05, 0xFD, 0x05, 0x39, 0x05, 0xF6, 0x03, 0x85, 0x02, 0x57, 0x01, 0x4A, 0x00, 0x50, 0xFF, 0x16, 0xFE, 0x64, 0xFC, 0xC5, 0xFA, 0x8E, 0xF9, 0x98, 0xF8, 0xE1, 0xF7, 0x2A, 0xF8, 0xF8, 0xF9, 0xE9, 0xFD, 0x14, 0x03, 0x8C, 0x07, 0xF0, 0x0A, 0x2D, 0x0C, 0xD8, 0x0A, 0x61, 0x07, 0x92, 0x02, 0x27, 0xFE, 0x68, 0xFA, 0x21, 0xF7, 0x33, 0xF4, 0x34, 0xF2, 0xAC, 0xF1, 0x40, 0xF2, 0x6B, 0xF3, 0x08, 0xF4, 0xE0, 0xF4, 0x15, 0xF6, 0xE7, 0xF6, 0x08, 0xF8, 0x80, 0xF8, 0x30, 0xF8, 0xBF, 0xF7, 0xD8, 0xF6, 0x98, 0xF5, 0x84, 0xF4, 0x2C, 0xF4, 0x80, 0xF4, 0xEF, 0xF4, 0x4E, 0xF4, 0x0B, 0xF3, 0x19, 0xF2, 0x6F, 0xF1, 0xBE, 0xF1, 0x77, 0xF2, 0x54, 0xF3, 0xED, 0xF4, 0xBB, 0xF6, 0x43, 0xF8, 0x89, 0xF9, 0xB9, 0xFA, 0xE4, 0xFB, 0x35, 0xFD, 0xD2, 0xFD, 0x91, 0xFD, 0x01, 0xFD, 0x3B, 0xFC, 0x58, 0xFC, 0x20, 0xFD, 0x05, 0xFE, 0xDD, 0xFE, 0x98, 0xFF, 0x51, 0x00, 0xDF, 0x00, 0x3E, 0x02, 0x1E, 0x04, 0x9C, 0x06, 0x4A, 0x09, 0xE7, 0x0A, 0x5F, 0x0C, 0x0C, 0x0D, 0x34, 0x0D, 0xBA, 0x0C, 0xD6, 0x0A, 0xE7, 0x08, 0x96, 0x06, 0x29, 0x05, 0x95, 0x05, 0x17, 0x07, 0x18, 0x09, 0x34, 0x0A, 0x29, 0x0A, 0x80, 0x08, 0xAD, 0x05, 0xA0, 0x02, 0xFF, 0xFF, 0xCD, 0xFE, 0x07, 0xFE, 0x81, 0xFD, 0x40, 0xFD, 0x2F, 0xFD, 0xE4, 0xFD, 0x21, 0xFF, 0xE7, 0x00, 0x70, 0x02, 0xE9, 0x02, 0x28, 0x02, 0xCA, 0x00, 0x10, 0x00, 0x6E, 0x00, 0xE8, 0x01, 0xBD, 0x03, 0x2A, 0x05, 0xB7, 0x05, 0xA9, 0x05, 0xDD, 0x05, 0xCC, 0x06, 0x7D, 0x08, 0xF8, 0x09, 0xD7, 0x0A, 0x1E, 0x0B, 0xE7, 0x0A, 0xE8, 0x0A, 0xC6, 0x0B, 0x66, 0x0D, 0x5D, 0x0E, 0x52, 0x0E, 0xC2, 0x0C, 0xE5, 0x09, 0x65, 0x07, 0x5D, 0x05, 0x93, 0x04, 0xDD, 0x04, 0x4D, 0x05, 0xDA, 0x05, 0xE8, 0x05, 0x2D, 0x06, 0xBD, 0x06, 0x46, 0x07, 0xBB, 0x07, 0xDD, 0x07, 0x1A, 0x08, 0x39, 0x08, 0x34, 0x08, 0xE5, 0x07, 0xBE, 0x07, 0x13, 0x08, 0x9C, 0x08, 0x2B, 0x0A, 0x43, 0x0C, 0x5F, 0x0E, 0xF2, 0x0F, 0x51, 0x10, 0x7B, 0x10, 0x24, 0x10, 0xE2, 0x0E, 0x51, 0x0C, 0x6B, 0x08, 0x4F, 0x04, 0x4D, 0x00, 0x6F, 0xFD, 0x4B, 0xFC, 0x91, 0xFC, 0xC2, 0xFD, 0xFB, 0xFE, 0x6C, 0x00, 0x53, 0x02, 0x21, 0x04, 0x92, 0x05, 0xD8, 0x06, 0x44, 0x07, 0xC0, 0x06, 0xE8, 0x05, 0x5F, 0x04, 0x6A, 0x03, 0x81, 0x03, 0xF9, 0x02, 0xDD, 0x01, 0x3C, 0x00, 0x8F, 0xFE, 0x88, 0xFD, 0x21, 0xFC, 0x20, 0xFA, 0xEA, 0xF7, 0xC5, 0xF5, 0x53, 0xF4, 0x43, 0xF3, 0x45, 0xF2, 0x55, 0xF2, 0x8F, 0xF3, 0x45, 0xF5, 0x99, 0xF6, 0x11, 0xF6, 0x33, 0xF4, 0xF8, 0xF1, 0xD8, 0xEF, 0x23, 0xEF, 0x77, 0xEF, 0x8C, 0xF0, 0x65, 0xF2, 0xE9, 0xF3, 0x76, 0xF5, 0xDC, 0xF6, 0x57, 0xF7, 0xA0, 0xF6, 0x76, 0xF4, 0xE5, 0xF1, 0x37, 0xF0, 0x17, 0xF0, 0x48, 0xF1, 0x17, 0xF3, 0x3C, 0xF5, 0x35, 0xF7, 0xEC, 0xF8, 0x7C, 0xFA, 0x8C, 0xFB, 0x0B, 0xFC, 0x51, 0xFC, 0x2E, 0xFC, 0xFD, 0xFA, 0x11, 0xF9, 0x2E, 0xF7, 0xFD, 0xF5, 0xCF, 0xF5, 0xE9, 0xF6, 0x71, 0xF9, 0xBB, 0xFC, 0x47, 0x00, 0x5B, 0x03, 0xA9, 0x05, 0x8A, 0x07, 0x5E, 0x08, 0xD8, 0x07, 0xEC, 0x05, 0x79, 0x03, 0x1D, 0x02, 0x49, 0x02, 0xE5, 0x03, 0x22, 0x06, 0x75, 0x08, 0x47, 0x0A, 0xB9, 0x0A, 0x0E, 0x0A, 0xD5, 0x08, 0x9C, 0x07, 0x95, 0x06, 0x9A, 0x05, 0x79, 0x04, 0x39, 0x03, 0x65, 0x02, 0x81, 0x01, 0x99, 0x00, 0x3E, 0x00, 0x92, 0x00, 0xE8, 0x01, 0x75, 0x03, 0x90, 0x04, 0x1F, 0x05, 0xFF, 0x04, 0x55, 0x04, 0x36, 0x03, 0x15, 0x02, 0xAE, 0x00, 0xCE, 0xFE, 0xAF, 0xFC, 0x6D, 0xFA, 0x18, 0xF9, 0x34, 0xF9, 0x79, 0xFA, 0xF9, 0xFB, 0x8A, 0xFC, 0x7A, 0xFC, 0x8C, 0xFC, 0xAF, 0xFD, 0x75, 0x00, 0x46, 0x04, 0x73, 0x08, 0xD9, 0x0B, 0x95, 0x0D, 0x05, 0x0E, 0x7E, 0x0D, 0x60, 0x0C, 0x98, 0x0B, 0x96, 0x0B, 0xDB, 0x0C, 0xB9, 0x0F, 0xD2, 0x12, 0xE6, 0x14, 0x37, 0x15, 0xAD, 0x13, 0xDA, 0x11, 0x88, 0x10, 0x0F, 0x10, 0xB6, 0x10, 0xDF, 0x11, 0x19, 0x13, 0x5E, 0x13, 0x17, 0x12, 0x07, 0x10, 0xAE, 0x0D, 0xB1, 0x0B, 0x75, 0x0A, 0x7D, 0x09, 0xA1, 0x08, 0x44, 0x08, 0x28, 0x08, 0x12, 0x08, 0x45, 0x08, 0x77, 0x08, 0x1F, 0x08, 0x10, 0x07, 0x57, 0x05, 0xD1, 0x02, 0xD2, 0xFF, 0xBA, 0xFD, 0x44, 0xFD, 0x31, 0xFE, 0x91, 0xFF, 0x61, 0x00, 0xDE, 0x00, 0x00, 0x01, 0x9A, 0x00, 0xBB, 0xFF, 0xDE, 0xFD, 0xD0, 0xFA, 0x23, 0xF7, 0xF5, 0xF3, 0x2C, 0xF2, 0x92, 0xF2, 0x5F, 0xF5, 0x95, 0xF9, 0x23, 0xFE, 0x1F, 0x02, 0x15, 0x05, 0x3C, 0x06, 0xD9, 0x04, 0xDD, 0x01, 0x91, 0xFE, 0x1C, 0xFC, 0xD9, 0xFA, 0x83, 0xFA, 0xFE, 0xFA, 0x01, 0xFC, 0x98, 0xFD, 0x70, 0xFF, 0x0A, 0x01, 0xFC, 0x01, 0xDB, 0x01, 0xC2, 0x00, 0xBB, 0xFE, 0x67, 0xFC, 0x6B, 0xFA, 0x12, 0xF9, 0xC6, 0xF8, 0x42, 0xF9, 0x62, 0xFA, 0x9E, 0xFB, 0xD3, 0xFC, 0xC0, 0xFD, 0xDE, 0xFD, 0x29, 0xFE, 0x8B, 0xFE, 0x70, 0xFE, 0xEA, 0xFD, 0xDE, 0xFC, 0x11, 0xFC, 0xF3, 0xFB, 0xC0, 0xFC, 0x5E, 0xFE, 0xFF, 0xFF, 0x16, 0x01, 0x30, 0x01, 0x79, 0x00, 0xAB, 0xFF, 0x8A, 0xFF, 0x11, 0x00, 0xA9, 0x00, 0x43, 0x01, 0xF0, 0x01, 0xBF, 0x02, 0x63, 0x03, 0x9A, 0x03, 0x40, 0x03, 0x06, 0x02, 0xD6, 0xFF, 0xC0, 0xFC, 0x77, 0xF9, 0xD9, 0xF6, 0xCE, 0xF5, 0x5F, 0xF6, 0x07, 0xF8, 0xB4, 0xFA, 0x5D, 0xFD, 0x54, 0xFF, 0x4B, 0x00, 0xE9, 0xFF, 0xA8, 0xFE, 0xAB, 0xFC, 0x14, 0xFA, 0xD2, 0xF6, 0x12, 0xF3, 0xA6, 0xEF, 0x01, 0xED, 0xDA, 0xEB, 0x8E, 0xEC, 0x01, 0xEF, 0x3C, 0xF2, 0x09, 0xF5, 0xEB, 0xF6, 0xC2, 0xF7, 0x49, 0xF8, 0x6A, 0xF8, 0xF1, 0xF7, 0x91, 0xF7, 0xE1, 0xF6, 0x13, 0xF6, 0xDD, 0xF5, 0xF5, 0xF5, 0x56, 0xF6, 0x38, 0xF7, 0xB7, 0xF8, 0xEE, 0xFA, 0x6E, 0xFD, 0x94, 0xFF, 0xAE, 0x00, 0xBB, 0x00, 0x3D, 0x00, 0x9C, 0xFF, 0x0F, 0x00, 0xE9, 0x01, 0x97, 0x04, 0x6D, 0x07, 0xA7, 0x08, 0x2E, 0x08, 0xB5, 0x06, 0xFF, 0x04, 0x1F, 0x04, 0x9D, 0x03, 0x27, 0x03, 0x30, 0x02, 0x20, 0x01, 0xFA, 0x00, 0x7C, 0x01, 0x08, 0x03, 0x1B, 0x05, 0x7E, 0x07, 0xE9, 0x09, 0x98, 0x0B, 0x33, 0x0D, 0x1D, 0x0E, 0x83, 0x0E, 0xB7, 0x0E, 0xC6, 0x0D, 0x5D, 0x0C, 0xDD, 0x0A, 0x27, 0x09, 0xAA, 0x07, 0xA9, 0x06, 0x1D, 0x06, 0x31, 0x06, 0x32, 0x06, 0x39, 0x05, 0x30, 0x04, 0xF9, 0x02, 0xF1, 0x01, 0x35, 0x02, 0xC0, 0x02, 0x7A, 0x03, 0x16, 0x04, 0x78, 0x03, 0xEE, 0x01, 0x6C, 0xFF, 0x59, 0xFC, 0xD9, 0xF9, 0x3B, 0xF8, 0x40, 0xF8, 0x11, 0xFA, 0xDF, 0xFC, 0x6C, 0x00, 0xAB, 0x03, 0x4E, 0x06, 0x7E, 0x08, 0x1E, 0x09, 0x46, 0x08, 0xBC, 0x05, 0xAA, 0x01, 0xAB, 0xFD, 0x56, 0xFA, 0x3A, 0xF8, 0x77, 0xF7, 0xE8, 0xF7, 0x06, 0xF9, 0x8D, 0xFA, 0x77, 0xFC, 0x1F, 0xFE, 0xF7, 0xFF, 0x84, 0x01, 0x4D, 0x02, 0xB2, 0x02, 0x7C, 0x02, 0x83, 0x02, 0xAE, 0x02, 0x94, 0x02, 0x1F, 0x02, 0x1C, 0x01, 0xCF, 0xFF, 0x7B, 0xFE, 0x9D, 0xFE, 0x5F, 0x00, 0xE4, 0x02, 0x98, 0x05, 0x1D, 0x07, 0x9D, 0x07, 0x31, 0x07, 0x78, 0x05, 0x35, 0x03, 0xA4, 0x00, 0x94, 0xFE, 0x2E, 0xFD, 0x5F, 0xFB, 0xB0, 0xF9, 0x8A, 0xF8, 0xDB, 0xF7, 0x18, 0xF8, 0x82, 0xF8, 0x0B, 0xF9, 0x3F, 0xFA, 0x94, 0xFB, 0x56, 0xFC, 0xD5, 0xFB, 0x75, 0xFA, 0x28, 0xF9, 0x7A, 0xF8, 0x77, 0xF8, 0x59, 0xF9, 0xB2, 0xFB, 0x2D, 0xFE, 0xF4, 0xFF, 0xD9, 0x00, 0xB8, 0x00, 0x52, 0x00, 0x7E, 0xFF, 0x8C, 0xFE, 0x2A, 0xFD, 0x0D, 0xFB, 0xFA, 0xF8, 0x0F, 0xF7, 0x8D, 0xF5, 0xF5, 0xF3, 0xD6, 0xF2, 0xBD, 0xF2, 0x04, 0xF3, 0x27, 0xF4, 0x77, 0xF5, 0xB1, 0xF6, 0x5F, 0xF8, 0x07, 0xFA, 0xDC, 0xFA, 0x24, 0xFA, 0x78, 0xF8, 0x26, 0xF6, 0x8D, 0xF3, 0xA5, 0xF1, 0x1D, 0xF1, 0x08, 0xF2, 0xE0, 0xF3, 0x64, 0xF6, 0x7F, 0xF8, 0xF1, 0xF9, 0x4B, 0xFB, 0x37, 0xFC, 0x0E, 0xFD, 0xAD, 0xFD, 0xCC, 0xFD, 0xA6, 0xFD, 0xD8, 0xFC, 0x31, 0xFB, 0x65, 0xF9, 0xEE, 0xF7, 0x01, 0xF7, 0x3A, 0xF7, 0x9A, 0xF8, 0xB6, 0xFA, 0xA5, 0xFC, 0xC1, 0xFD, 0x3B, 0xFE, 0x52, 0xFE, 0x93, 0xFE, 0x8D, 0xFE, 0xBF, 0xFD, 0x1B, 0xFC, 0x2B, 0xFA, 0x4E, 0xF9, 0xAE, 0xF9, 0x86, 0xFB, 0x36, 0xFE, 0x22, 0x01, 0x24, 0x04, 0x06, 0x06, 0xD7, 0x06, 0x2E, 0x06, 0x56, 0x04, 0x67, 0x02, 0x40, 0x00, 0x84, 0xFE, 0xA0, 0xFD, 0xC6, 0xFD, 0x91, 0xFE, 0x54, 0xFF, 0x3D, 0xFF, 0x61, 0xFE, 0x08, 0xFE, 0x2E, 0xFD, 0x2A, 0xFC, 0xAE, 0xFB, 0x52, 0xFB, 0x22, 0xFC, 0x67, 0xFD, 0xF0, 0xFE, 0xF8, 0x00, 0xA9, 0x02, 0xDF, 0x03, 0xFD, 0x03, 0x10, 0x03, 0xA0, 0x01, 0x27, 0x00, 0xE2, 0xFE, 0x18, 0xFE, 0xA3, 0xFD, 0xD3, 0xFC, 0x14, 0xFC, 0x2D, 0xFB, 0xE4, 0xFA, 0x46, 0xFC, 0x6E, 0xFE, 0xFD, 0x00, 0x79, 0x02, 0xAE, 0x01, 0xF0, 0xFE, 0xD1, 0xFA, 0x87, 0xF7, 0x95, 0xF6, 0xAF, 0xF7, 0x5F, 0xFA, 0x94, 0xFD, 0x13, 0x00, 0x17, 0x02, 0x65, 0x03, 0x88, 0x03, 0x49, 0x03, 0x1D, 0x02, 0x23, 0x00, 0xBE, 0xFD, 0x99, 0xFA, 0x9B, 0xF8, 0xB0, 0xF8, 0x76, 0xFA, 0x9F, 0xFD, 0xE6, 0x00, 0xBD, 0x03, 0xC1, 0x05, 0xE2, 0x06, 0x6F, 0x07, 0x9A, 0x07, 0x8B, 0x07, 0xF0, 0x06, 0x19, 0x06, 0x21, 0x05, 0x2A, 0x04, 0xAC, 0x03, 0xBD, 0x03, 0x54, 0x04, 0x9E, 0x04, 0x6E, 0x04, 0xAB, 0x03, 0x41, 0x02, 0x56, 0x01, 0x12, 0x01, 0xDA, 0x01, 0x6F, 0x03, 0x24, 0x04, 0x96, 0x03, 0x86, 0x01, 0x71, 0xFE, 0x7F, 0xFB, 0xF9, 0xF8, 0xF1, 0xF6, 0x56, 0xF5, 0x8F, 0xF4, 0xDB, 0xF4, 0xE6, 0xF5, 0x36, 0xF7, 0xAA, 0xF8, 0x67, 0xFA, 0xD5, 0xFB, 0xD7, 0xFC, 0x68, 0xFD, 0x8A, 0xFD, 0xAB, 0xFD, 0xB2, 0xFD, 0xFC, 0xFD, 0xA3, 0xFE, 0x55, 0xFF, 0xE1, 0xFF, 0x41, 0x00, 0x81, 0x00, 0x3D, 0x00, 0x8F, 0xFF, 0x3D, 0xFE, 0x00, 0xFC, 0xCE, 0xF8, 0x09, 0xF5, 0x2C, 0xF2, 0x9C, 0xF0, 0x9B, 0xF0, 0xF0, 0xF1, 0x5A, 0xF3, 0xC8, 0xF4, 0x60, 0xF6, 0x87, 0xF8, 0x27, 0xFB, 0xFF, 0xFC, 0x9F, 0xFD, 0xCC, 0xFD, 0x83, 0xFE, 0x81, 0xFF, 0x60, 0x00, 0x29, 0x01, 0x46, 0x01, 0x6F, 0x00, 0x9F, 0xFE, 0x37, 0xFC, 0x48, 0xFA, 0xFD, 0xF8, 0x47, 0xF8, 0x7B, 0xF8, 0x02, 0xF9, 0xA4, 0xF9, 0x8D, 0xFA, 0x02, 0xFB, 0x17, 0xFB, 0x21, 0xFB, 0x15, 0xFB, 0xD8, 0xFA, 0x1E, 0xFA, 0x25, 0xF9, 0x6F, 0xF8, 0xC0, 0xF8, 0x71, 0xFA, 0xC7, 0xFC, 0x26, 0xFF, 0xB6, 0x00, 0x2A, 0x00, 0x21, 0xFE, 0x75, 0xFC, 0x8A, 0xFB, 0xBB, 0xFB, 0xCD, 0xFC, 0xD8, 0xFD, 0xED, 0xFE, 0xBA, 0xFF, 0xFA, 0x00, 0xEA, 0x02, 0x5D, 0x04, 0x56, 0x05, 0x30, 0x05, 0xC4, 0x03, 0x25, 0x02, 0xED, 0x00, 0x84, 0x00, 0xEB, 0x00, 0x57, 0x01, 0x65, 0x01, 0x56, 0x01, 0x6B, 0x00, 0xA1, 0xFF, 0xD1, 0xFF, 0x05, 0x00, 0x82, 0x00, 0x1D, 0x00, 0xB5, 0xFE, 0x6F, 0xFD, 0x56, 0xFC, 0x5D, 0xFC, 0xF1, 0xFC, 0xA7, 0xFD, 0xBD, 0xFE, 0xF9, 0xFF, 0x34, 0x01, 0x7B, 0x01, 0x43, 0x01, 0xF4, 0x00, 0xA6, 0x00, 0xD7, 0x00, 0x5A, 0x01, 0x2A, 0x02, 0x9E, 0x02, 0xAA, 0x02, 0x35, 0x02, 0x3B, 0x01, 0x59, 0x00, 0x55, 0xFF, 0x45, 0xFF, 0x09, 0x00, 0x87, 0x00, 0xAB, 0x00, 0xE7, 0xFF, 0xFB, 0xFE, 0x07, 0xFF, 0x4E, 0x00, 0x50, 0x02, 0x28, 0x04, 0x73, 0x05, 0x91, 0x05, 0xB4, 0x04, 0x7C, 0x03, 0xB7, 0x02, 0x19, 0x03, 0x89, 0x03, 0x9D, 0x03, 0xDD, 0x03, 0x95, 0x04, 0x2A, 0x06, 0x78, 0x07, 0xA3, 0x07, 0xEE, 0x06, 0xCE, 0x04, 0xBA, 0x01, 0xCB, 0xFE, 0x7B, 0xFC, 0x6D, 0xFB, 0x94, 0xFB, 0x8E, 0xFC, 0x23, 0xFE, 0x00, 0x00, 0xC1, 0x01, 0x24, 0x03, 0x3D, 0x04, 0xF6, 0x04, 0xAF, 0x05, 0x58, 0x06, 0x2A, 0x06, 0x2F, 0x05, 0x98, 0x03, 0x20, 0x02, 0x0A, 0x01, 0xD8, 0xFF, 0x92, 0xFE, 0xED, 0xFC, 0x65, 0xFB, 0xC6, 0xFA, 0x14, 0xFB, 0x11, 0xFC, 0x95, 0xFD, 0xCE, 0xFF, 0x04, 0x02, 0xA3, 0x03, 0x8F, 0x04, 0x5E, 0x04, 0xF4, 0x02, 0x05, 0x00, 0xEE, 0xFB, 0xF4, 0xF7, 0x41, 0xF5, 0x72, 0xF4, 0x7F, 0xF5, 0xB8, 0xF7, 0x07, 0xFA, 0xE0, 0xFB, 0x43, 0xFD, 0x17, 0xFF, 0xA5, 0x01, 0x46, 0x04, 0x46, 0x06, 0xF9, 0x05, 0x29, 0x03, 0xA3, 0xFE, 0x5D, 0xF9, 0xA2, 0xF5, 0x2F, 0xF4, 0x52, 0xF4, 0x19, 0xF5, 0x96, 0xF5, 0xE8, 0xF5, 0xE2, 0xF6, 0xC7, 0xF8, 0xD2, 0xFA, 0x6B, 0xFC, 0xD9, 0xFC, 0xB1, 0xFC, 0x30, 0xFD, 0x4B, 0xFE, 0x7D, 0x00, 0xBA, 0x02, 0xA7, 0x03, 0x78, 0x03, 0x5E, 0x02, 0x5B, 0x01, 0xD0, 0x00, 0x50, 0x00, 0x63, 0xFF, 0x64, 0xFE, 0x84, 0xFD, 0xA2, 0xFC, 0x51, 0xFD, 0xDD, 0xFE, 0x60, 0x00, 0xC6, 0x01, 0xAD, 0x01, 0xC6, 0x01, 0xB2, 0x02, 0x87, 0x03, 0x76, 0x04, 0x95, 0x04, 0x76, 0x04, 0xCC, 0x04, 0xDB, 0x04, 0x79, 0x04, 0x0A, 0x04, 0xAB, 0x03, 0x47, 0x03, 0xEE, 0x02, 0x09, 0x02, 0x2C, 0x01, 0xFA, 0x00, 0x5A, 0x01, 0xBF, 0x02, 0x1A, 0x04, 0x36, 0x05, 0x68, 0x06, 0xA2, 0x06, 0x2C, 0x06, 0xDC, 0x04, 0x02, 0x02, 0x6C, 0xFE, 0x20, 0xFB, 0xA0, 0xF8, 0x39, 0xF7, 0x25, 0xF7, 0x0C, 0xF8, 0x8E, 0xF9, 0xBA, 0xFB, 0x37, 0xFE, 0x9E, 0x00, 0x63, 0x02, 0x88, 0x02, 0x24, 0x01, 0xEC, 0xFE, 0x8C, 0xFC, 0xFD, 0xFA, 0x2F, 0xFA, 0xCD, 0xF9, 0x68, 0xF9, 0x95, 0xF8, 0x72, 0xF8, 0x41, 0xF9, 0x14, 0xFA, 0xD5, 0xFA, 0x68, 0xFB, 0x97, 0xFB, 0xA8, 0xFB, 0x58, 0xFB, 0x71, 0xFA, 0x03, 0xFA, 0x79, 0xFA, 0xFB, 0xFB, 0x05, 0xFE, 0x26, 0xFF, 0xA8, 0xFF, 0x9B, 0xFF, 0x54, 0xFF, 0x86, 0xFF, 0x98, 0xFF, 0xF7, 0xFF, 0xB4, 0x00, 0x77, 0x01, 0x12, 0x02, 0x0A, 0x02, 0xD2, 0x01, 0x9F, 0x01, 0xA0, 0x01, 0x38, 0x01, 0x69, 0x00, 0x66, 0x00, 0x1F, 0x01, 0x18, 0x03, 0x9D, 0x05, 0x48, 0x07, 0xF5, 0x07, 0x2D, 0x07, 0xE6, 0x05, 0xA0, 0x04, 0xE3, 0x02, 0x3D, 0x01, 0x8D, 0xFF, 0xF0, 0xFD, 0xE4, 0xFC, 0xAC, 0xFC, 0x1D, 0xFD, 0xBA, 0xFD, 0x76, 0xFE, 0x69, 0xFF, 0xDF, 0x00, 0x6E, 0x02, 0xA0, 0x03, 0x37, 0x04, 0x62, 0x03, 0x88, 0x01, 0x35, 0xFF, 0x94, 0xFC, 0x1F, 0xFA, 0x2E, 0xF8, 0x79, 0xF7, 0x06, 0xF8, 0xA9, 0xF9, 0x20, 0xFC, 0xE4, 0xFE, 0x9D, 0x01, 0xC7, 0x03, 0x4A, 0x05, 0x1D, 0x06, 0x5B, 0x06, 0x1D, 0x06, 0x56, 0x05, 0x5D, 0x04, 0xFC, 0x02, 0x1F, 0x01, 0x46, 0xFF, 0xFD, 0xFD, 0x8B, 0xFD, 0xEE, 0xFD, 0xCD, 0xFE, 0x2A, 0xFF, 0x20, 0xFF, 0xD0, 0xFE, 0x46, 0xFE, 0x50, 0xFE, 0x76, 0xFE, 0xCF, 0xFE, 0x35, 0xFF, 0xF5, 0xFE, 0x7C, 0xFE, 0x32, 0xFE, 0x0D, 0xFF, 0xF9, 0x00, 0x3D, 0x03, 0x0E, 0x05, 0xBA, 0x05, 0xC6, 0x05, 0x86, 0x05, 0xAE, 0x05, 0xBF, 0x05, 0x73, 0x05, 0x7B, 0x05, 0x04, 0x05, 0x88, 0x04, 0xCD, 0x03, 0xAA, 0x02, 0x31, 0x02, 0x07, 0x02, 0xBA, 0x02, 0x21, 0x04, 0xF3, 0x05, 0x72, 0x08, 0xF3, 0x0A, 0x26, 0x0D, 0x9E, 0x0E, 0x9B, 0x0F, 0xE3, 0x0F, 0x9D, 0x0F, 0x26, 0x0F, 0x04, 0x0E, 0x00, 0x0D, 0xC8, 0x0B, 0xA7, 0x0A, 0x2F, 0x0A, 0xC0, 0x09, 0x4C, 0x0A, 0x37, 0x0B, 0xD6, 0x0B, 0x1D, 0x0C, 0x80, 0x0B, 0x80, 0x0A, 0x95, 0x08, 0x11, 0x06, 0xBB, 0x03, 0x99, 0x01, 0x69, 0x00, 0xCC, 0xFF, 0xAE, 0xFF, 0x10, 0x00, 0x55, 0x00, 0xA2, 0x00, 0x30, 0x01, 0x7F, 0x02, 0x3F, 0x04, 0x81, 0x05, 0xE9, 0x05, 0x30, 0x05, 0x6F, 0x03, 0x51, 0x01, 0xB7, 0xFF, 0x5D, 0xFE, 0x4E, 0xFD, 0xA7, 0xFC, 0x64, 0xFB, 0xDA, 0xF9, 0x12, 0xF8, 0x5A, 0xF6, 0x08, 0xF6, 0xEE, 0xF6, 0xB0, 0xF8, 0x82, 0xFA, 0x7C, 0xFB, 0x6D, 0xFB, 0x5D, 0xFA, 0xEC, 0xF8, 0xF8, 0xF6, 0xFF, 0xF4, 0x9B, 0xF3, 0xB7, 0xF2, 0xA2, 0xF2, 0x68, 0xF3, 0x1E, 0xF5, 0x2C, 0xF7, 0x11, 0xF9, 0xC5, 0xFA, 0x4A, 0xFC, 0x6A, 0xFD, 0x0E, 0xFE, 0xE0, 0xFE, 0x05, 0x00, 0x3E, 0x02, 0x3A, 0x05, 0x99, 0x07, 0x43, 0x09, 0x73, 0x09, 0xD3, 0x08, 0xE4, 0x07, 0xC9, 0x06, 0x26, 0x06, 0x31, 0x05, 0x8C, 0x04, 0x40, 0x04, 0x69, 0x04, 0x7E, 0x05, 0x68, 0x06, 0x25, 0x07, 0x35, 0x07, 0xD3, 0x06, 0xE8, 0x05, 0xD9, 0x03, 0xCD, 0x01, 0x15, 0x00, 0x58, 0xFF, 0x91, 0xFF, 0x34, 0x00, 0x71, 0x00, 0x22, 0xFF, 0x3B, 0xFD, 0x1B, 0xFB, 0xA9, 0xF9, 0x6E, 0xF9, 0x9C, 0xF9, 0x13, 0xFA, 0xE3, 0xF9, 0xDF, 0xF8, 0xD7, 0xF7, 0x8C, 0xF7, 0x33, 0xF8, 0x45, 0xF9, 0x5B, 0xFA, 0xDA, 0xFA, 0xF2, 0xFA, 0x91, 0xFA, 0xDA, 0xF9, 0x50, 0xF9, 0xC9, 0xF8, 0xA8, 0xF8, 0x3A, 0xF9, 0x2A, 0xFA, 0x15, 0xFB, 0xF1, 0xFB, 0x0B, 0xFC, 0x48, 0xFB, 0x56, 0xFA, 0x39, 0xF9, 0x04, 0xF9, 0x6E, 0xF9, 0x00, 0xFA, 0x0B, 0xFB, 0x14, 0xFC, 0x0B, 0xFE, 0xA3, 0x00, 0x56, 0x03, 0xD2, 0x05, 0x30, 0x07, 0xF9, 0x07, 0x03, 0x08, 0xD4, 0x07, 0x4B, 0x07, 0xC7, 0x05, 0xF7, 0x03, 0x08, 0x02, 0x58, 0x01, 0xDD, 0x01, 0x9D, 0x02, 0x6F, 0x03, 0x84, 0x03, 0x20, 0x03, 0x1D, 0x02, 0x25, 0x01, 0x4D, 0x01, 0x15, 0x02, 0x99, 0x03, 0x18, 0x05, 0xDC, 0x05, 0x14, 0x06, 0xFE, 0x05, 0x8C, 0x06, 0x09, 0x08, 0xEB, 0x09, 0x2C, 0x0B, 0x69, 0x0B, 0xD4, 0x0A, 0xC8, 0x09, 0x61, 0x09, 0x84, 0x09, 0x3F, 0x0A, 0x77, 0x0B, 0xC0, 0x0B, 0x7D, 0x0B, 0xDC, 0x0A, 0x17, 0x0A, 0xF2, 0x09, 0xC3, 0x09, 0x0B, 0x0A, 0xB7, 0x0A, 0x17, 0x0B, 0x2C, 0x0B, 0x79, 0x0A, 0xF9, 0x09, 0xF5, 0x09, 0x1D, 0x0A, 0x91, 0x0A, 0x5B, 0x0A, 0x8D, 0x09, 0xAC, 0x08, 0xB5, 0x07, 0x68, 0x06, 0xEB, 0x04, 0x50, 0x03, 0x49, 0x01, 0xEC, 0xFF, 0x42, 0xFF, 0x39, 0xFF, 0x44, 0x00, 0x4C, 0x01, 0x1A, 0x02, 0xE2, 0x02, 0x20, 0x03, 0xC7, 0x02, 0x10, 0x02, 0xCF, 0x00, 0x44, 0xFF, 0x54, 0xFE, 0x40, 0xFE, 0x2C, 0xFF, 0xDD, 0x00, 0x9C, 0x02, 0x90, 0x03, 0xB1, 0x03, 0xD3, 0x03, 0xAE, 0x03, 0x00, 0x03, 0x97, 0x01, 0xFB, 0xFF, 0x48, 0xFF, 0x64, 0xFF, 0xE9, 0xFF, 0x1D, 0x00, 0x04, 0x00, 0x97, 0xFF, 0x31, 0xFF, 0x6F, 0xFF, 0x44, 0xFF, 0x28, 0xFF, 0x31, 0xFF, 0x11, 0xFF, 0xEC, 0xFE, 0x01, 0xFE, 0x17, 0xFD, 0x3F, 0xFC, 0x8D, 0xFB, 0x59, 0xFB, 0xB2, 0xFB, 0x72, 0xFD, 0xFB, 0xFF, 0x3C, 0x03, 0x64, 0x06, 0xAC, 0x08, 0x7D, 0x0A, 0x0D, 0x0B, 0xE9, 0x0A, 0x44, 0x0A, 0xD4, 0x08, 0xE6, 0x06, 0x81, 0x04, 0x6C, 0x02, 0x84, 0x01, 0x73, 0x02, 0x68, 0x04, 0xD4, 0x06, 0x50, 0x09, 0x48, 0x0A, 0xE6, 0x09, 0x77, 0x08, 0x4A, 0x06, 0x14, 0x04, 0x0D, 0x02, 0x9A, 0x00, 0xBB, 0xFF, 0xA2, 0xFF, 0xA5, 0xFF, 0x02, 0xFF, 0xCC, 0xFD, 0x92, 0xFB, 0xEF, 0xF8, 0xF0, 0xF6, 0x1B, 0xF6, 0x82, 0xF6, 0x71, 0xF7, 0x7C, 0xF8, 0x77, 0xF9, 0x08, 0xFA, 0x13, 0xFA, 0xB2, 0xF9, 0x2F, 0xF9, 0x3C, 0xF9, 0xB3, 0xF9, 0x8F, 0xF9, 0x8D, 0xF8, 0xC7, 0xF6, 0x0C, 0xF5, 0x57, 0xF4, 0xBC, 0xF4, 0x27, 0xF6, 0x54, 0xF8, 0x74, 0xFA, 0xE4, 0xFB, 0xE3, 0xFC, 0x0B, 0xFE, 0x18, 0xFF, 0x05, 0xFF, 0xF0, 0xFD, 0xEF, 0xFC, 0x58, 0xFC, 0x94, 0xFC, 0xF5, 0xFD, 0x61, 0x00, 0x69, 0x03, 0xDE, 0x05, 0x21, 0x07, 0x08, 0x07, 0x00, 0x06, 0xE7, 0x04, 0xD4, 0x03, 0x62, 0x03, 0x21, 0x04, 0xBF, 0x05, 0xD4, 0x07, 0xAF, 0x09, 0xFA, 0x0A, 0xB7, 0x0B, 0xC2, 0x0B, 0xBF, 0x0A, 0x09, 0x09, 0xE0, 0x07, 0x20, 0x07, 0x4D, 0x06, 0x71, 0x05, 0x83, 0x04, 0xB8, 0x04, 0x59, 0x06, 0xFC, 0x07, 0x05, 0x09, 0x3D, 0x09, 0x11, 0x09, 0x49, 0x09, 0xF8, 0x09, 0xBB, 0x0A, 0x33, 0x0B, 0xA3, 0x0B, 0xFB, 0x0B, 0xD3, 0x0B, 0xEC, 0x0A, 0x7E, 0x09, 0x9F, 0x08, 0xB2, 0x08, 0x82, 0x09, 0x67, 0x0A, 0x7A, 0x0A, 0x2A, 0x0A, 0x91, 0x09, 0x80, 0x08, 0xA1, 0x07, 0xAB, 0x06, 0x7F, 0x05, 0xB0, 0x04, 0x1B, 0x04, 0xA3, 0x03, 0x53, 0x03, 0xE9, 0x02, 0x33, 0x02, 0xB3, 0x00, 0x62, 0xFE, 0xE7, 0xFB, 0xEB, 0xF9, 0x0C, 0xF9, 0x48, 0xF9, 0x2E, 0xFA, 0xEB, 0xFB, 0xB9, 0xFE, 0xF1, 0x01, 0xB0, 0x04, 0x63, 0x06, 0xB6, 0x06, 0x5B, 0x06, 0xEF, 0x05, 0x37, 0x05, 0xBF, 0x04, 0x1B, 0x05, 0xE7, 0x05, 0x6D, 0x06, 0x62, 0x06, 0xD8, 0x05, 0xCA, 0x04, 0x34, 0x03, 0xE8, 0x00, 0x93, 0xFE, 0x86, 0xFD, 0xA4, 0xFD, 0x6C, 0xFE, 0x37, 0xFF, 0x9F, 0xFF, 0x4C, 0x00, 0x10, 0x01, 0xEC, 0x01, 0xD7, 0x02, 0xF4, 0x02, 0xB2, 0x02, 0x30, 0x02, 0xDD, 0x01, 0x0A, 0x02, 0xA7, 0x01, 0x86, 0x00, 0xA4, 0xFE, 0xA6, 0xFC, 0x68, 0xFB, 0x07, 0xFB, 0xA6, 0xFB, 0x4C, 0xFC, 0x00, 0xFD, 0xC1, 0xFD, 0x89, 0xFE, 0xEB, 0xFF, 0xD0, 0x00, 0x2C, 0x01, 0x71, 0x00, 0xCA, 0xFD, 0xCE, 0xFA, 0x64, 0xF8, 0x5C, 0xF7, 0x0F, 0xF8, 0x92, 0xF9, 0x9C, 0xFB, 0x26, 0xFE, 0x62, 0x00, 0xB7, 0x01, 0x68, 0x02, 0x2C, 0x02, 0x91, 0x01, 0xD7, 0x00, 0xF5, 0xFF, 0xF1, 0xFF, 0x05, 0x00, 0xE7, 0xFF, 0x6A, 0xFF, 0xF6, 0xFD, 0xC3, 0xFC, 0xE6, 0xFB, 0x7A, 0xFB, 0xC2, 0xFB, 0x14, 0xFC, 0x05, 0xFC, 0x1D, 0xFB, 0x83, 0xF9, 0xBB, 0xF7, 0xBA, 0xF6, 0xE3, 0xF6, 0x29, 0xF8, 0x08, 0xFA, 0x10, 0xFB, 0x70, 0xFB, 0x47, 0xFB, 0xC9, 0xFA, 0x92, 0xFA, 0x33, 0xFA, 0x61, 0xF9, 0x0B, 0xF8, 0xD6, 0xF6, 0x2F, 0xF6, 0x37, 0xF6, 0x02, 0xF7, 0xC3, 0xF7, 0x86, 0xF8, 0x0C, 0xF9, 0x3A, 0xF9, 0xC6, 0xF9, 0x4C, 0xFA, 0x1F, 0xFA, 0x0D, 0xF9, 0xC9, 0xF7, 0x26, 0xF7, 0xBD, 0xF7, 0x45, 0xF9, 0xE7, 0xFA, 0xA7, 0xFC, 0x0C, 0xFE, 0x15, 0xFF, 0xD9, 0xFF, 0x2C, 0x00, 0x68, 0x00, 0x56, 0x00, 0x88, 0x00, 0xE9, 0x00, 0x67, 0x01, 0x5D, 0x02, 0xF3, 0x02, 0xF8, 0x02, 0xB5, 0x01, 0xAA, 0xFF, 0x79, 0xFE, 0xCC, 0xFD, 0x81, 0xFD, 0x65, 0xFD, 0xD1, 0xFD, 0x67, 0xFF, 0x3E, 0x01, 0x87, 0x02, 0xE7, 0x02, 0x0C, 0x03, 0x64, 0x03, 0x85, 0x03, 0x7E, 0x03, 0x25, 0x03, 0x62, 0x02, 0xCA, 0x00, 0x02, 0xFE, 0xB2, 0xFA, 0x05, 0xF8, 0x9F, 0xF6, 0x0D, 0xF6, 0xE4, 0xF5, 0xA6, 0xF5, 0x47, 0xF5, 0xAA, 0xF5, 0x67, 0xF6, 0x46, 0xF7, 0x57, 0xF8, 0xC9, 0xF8, 0x2B, 0xF9, 0x69, 0xF9, 0xC3, 0xF8, 0xA9, 0xF7, 0x32, 0xF6, 0xF2, 0xF4, 0x2C, 0xF4, 0xE2, 0xF3, 0x9E, 0xF4, 0xC7, 0xF5, 0xD9, 0xF6, 0x0F, 0xF7, 0x46, 0xF6, 0x4C, 0xF5, 0x6C, 0xF4, 0xA9, 0xF4, 0x45, 0xF6, 0x18, 0xF9, 0x35, 0xFC, 0xEC, 0xFD, 0x9D, 0xFE, 0xA3, 0xFE, 0xB4, 0xFE, 0x4F, 0xFF, 0xFB, 0xFF, 0x4C, 0x01, 0x12, 0x03, 0x25, 0x05, 0xEA, 0x06, 0xE7, 0x07, 0xB4, 0x08, 0xCD, 0x08, 0xBF, 0x08, 0xCA, 0x08, 0x92, 0x08, 0x2D, 0x08, 0xE7, 0x06, 0x46, 0x05, 0xDD, 0x03, 0xE7, 0x02, 0xDB, 0x02, 0xB6, 0x03, 0x45, 0x05, 0x96, 0x06, 0x2E, 0x07, 0x0C, 0x07, 0x21, 0x06, 0x6F, 0x04, 0x69, 0x02, 0xB9, 0x00, 0x64, 0xFF, 0xF5, 0xFE, 0x43, 0xFF, 0x63, 0xFF, 0x67, 0xFF, 0x64, 0xFF, 0xB9, 0xFF, 0x7A, 0x00, 0x72, 0x01, 0x78, 0x02, 0x04, 0x03, 0xB9, 0x02, 0x94, 0x01, 0xDF, 0xFF, 0xD2, 0xFD, 0xE5, 0xFB, 0x68, 0xFA, 0xAC, 0xF9, 0xF0, 0xF9, 0x9A, 0xFA, 0x9E, 0xFB, 0xA7, 0xFC, 0x93, 0xFD, 0x72, 0xFE, 0x76, 0xFE, 0x61, 0xFE, 0x7C, 0xFE, 0xF9, 0xFD, 0xE9, 0xFC, 0x8B, 0xFB, 0x8B, 0xFA, 0x93, 0xFA, 0xB2, 0xFB, 0x28, 0xFD, 0x8B, 0xFE, 0x96, 0xFF, 0xAF, 0xFF, 0x74, 0xFF, 0xC5, 0xFE, 0x6E, 0xFD, 0x3B, 0xFC, 0x67, 0xFB, 0x3A, 0xFB, 0x5F, 0xFB, 0xB0, 0xFB, 0x53, 0xFC, 0x19, 0xFD, 0x26, 0xFE, 0xD4, 0xFE, 0x20, 0xFF, 0x68, 0xFF, 0x76, 0xFF, 0xAB, 0xFF, 0xD2, 0xFF, 0xAB, 0xFF, 0x52, 0xFF, 0xB4, 0xFE, 0x34, 0xFE, 0x10, 0xFE, 0x4C, 0xFE, 0x7E, 0xFE, 0x73, 0xFE, 0x40, 0xFE, 0xBC, 0xFD, 0x1A, 0xFD, 0x40, 0xFC, 0x47, 0xFB, 0x72, 0xFA, 0x9F, 0xF9, 0x37, 0xF9, 0x4D, 0xF9, 0xBA, 0xF9, 0x1D, 0xFA, 0xD2, 0xF9, 0x09, 0xF9, 0x27, 0xF8, 0xC0, 0xF7, 0xF6, 0xF7, 0xC8, 0xF8, 0x36, 0xFA, 0xBD, 0xFB, 0x16, 0xFD, 0xE5, 0xFD, 0x54, 0xFE, 0xAB, 0xFE, 0x4A, 0xFE, 0x08, 0xFD, 0xFC, 0xFA, 0x70, 0xF8, 0xFF, 0xF5, 0x41, 0xF4, 0xDD, 0xF3, 0x0E, 0xF5, 0x5E, 0xF7, 0x01, 0xFA, 0x3E, 0xFC, 0xC7, 0xFD, 0x35, 0xFF, 0x63, 0x00, 0xEB, 0x00, 0x3D, 0x01, 0xDD, 0x00, 0xF7, 0xFF, 0xC8, 0xFE, 0x6A, 0xFD, 0xAE, 0xFC, 0x5C, 0xFC, 0x94, 0xFC, 0x4A, 0xFD, 0x5E, 0xFE, 0xE8, 0xFF, 0x17, 0x01, 0xD5, 0x01, 0x36, 0x02, 0x7A, 0x02, 0xA5, 0x02, 0x3B, 0x02, 0xAC, 0x01, 0x49, 0x01, 0x50, 0x01, 0xC5, 0x01, 0x4A, 0x02, 0x85, 0x02, 0x8F, 0x02, 0xF2, 0x02, 0x85, 0x03, 0xCA, 0x03, 0x36, 0x03, 0x29, 0x02, 0xF3, 0x00, 0x98, 0xFF, 0x2A, 0xFF, 0xBD, 0xFF, 0x1E, 0x01, 0x05, 0x03, 0xAA, 0x04, 0x3E, 0x06, 0x80, 0x07, 0x49, 0x08, 0x79, 0x08, 0x97, 0x08, 0x6A, 0x09, 0x68, 0x0A, 0x20, 0x0B, 0x19, 0x0B, 0x57, 0x0A, 0x8A, 0x09, 0xE9, 0x08, 0x79, 0x08, 0xDC, 0x07, 0xD3, 0x06, 0x9D, 0x05, 0x18, 0x05, 0x44, 0x05, 0xDA, 0x05, 0xBF, 0x06, 0x24, 0x07, 0x23, 0x07, 0xA7, 0x06, 0xE6, 0x05, 0xE1, 0x05, 0x05, 0x06, 0xED, 0x05, 0x74, 0x05, 0xAC, 0x04, 0x15, 0x04, 0x74, 0x03, 0x94, 0x02, 0xAA, 0x01, 0xF1, 0x00, 0x66, 0x00, 0x67, 0x00, 0xD3, 0x00, 0x18, 0x01, 0x34, 0x01, 0x84, 0x00, 0x6F, 0xFF, 0xBE, 0xFE, 0x27, 0xFE, 0x35, 0xFE, 0xDC, 0xFE, 0xDB, 0xFF, 0x49, 0x01, 0x62, 0x02, 0x2D, 0x03, 0xEB, 0x03, 0x40, 0x04, 0x11, 0x04, 0x68, 0x03, 0x5F, 0x02, 0x62, 0x01, 0x88, 0x00, 0xA1, 0xFF, 0xF8, 0xFE, 0x9A, 0xFE, 0x1A, 0xFE, 0xAC, 0xFD, 0x83, 0xFD, 0xB9, 0xFD, 0xBF, 0xFE, 0x40, 0x00, 0xF0, 0x01, 0x9B, 0x03, 0xB7, 0x04, 0x5B, 0x05, 0x58, 0x05, 0x90, 0x04, 0x90, 0x03, 0x25, 0x02, 0x45, 0x00, 0x6F, 0xFE, 0xB9, 0xFC, 0xE2, 0xFB, 0xA5, 0xFC, 0x9E, 0xFE, 0x73, 0x01, 0x30, 0x04, 0xBA, 0x05, 0x6C, 0x06, 0x47, 0x06, 0x65, 0x05, 0x52, 0x04, 0x03, 0x03, 0x0D, 0x02, 0x8F, 0x01, 0x8E, 0x01, 0x0D, 0x02, 0x95, 0x02, 0x93, 0x03, 0xE1, 0x04, 0x26, 0x06, 0x4D, 0x07, 0x30, 0x08, 0xD7, 0x08, 0x75, 0x08, 0x84, 0x06, 0xCC, 0x02, 0x1D, 0xFE, 0xB8, 0xF9, 0x54, 0xF6, 0xEB, 0xF4, 0xDB, 0xF4, 0xEF, 0xF5, 0x65, 0xF8, 0xE4, 0xFA, 0xAE, 0xFC, 0x1C, 0xFD, 0x45, 0xFC, 0xEB, 0xFA, 0x55, 0xF9, 0xC6, 0xF7, 0x95, 0xF6, 0x2C, 0xF6, 0x09, 0xF6, 0x43, 0xF6, 0xF6, 0xF6, 0x22, 0xF8, 0x67, 0xFA, 0xF4, 0xFC, 0xD8, 0xFF, 0x4F, 0x02, 0x01, 0x03, 0xA3, 0x02, 0x45, 0x01, 0x1F, 0x00, 0x17, 0x00, 0xB1, 0x00, 0x3D, 0x02, 0x42, 0x04, 0x66, 0x06, 0x8C, 0x08, 0x79, 0x0A, 0xED, 0x0B, 0xEC, 0x0C, 0x33, 0x0E, 0xCA, 0x0F, 0x82, 0x11, 0xE2, 0x12, 0x4F, 0x13, 0xB6, 0x12, 0x45, 0x11, 0x68, 0x0F, 0x47, 0x0D, 0x49, 0x0B, 0xD7, 0x09, 0x75, 0x09, 0x0E, 0x0A, 0xD8, 0x0A, 0xB6, 0x0B, 0x31, 0x0C, 0xC6, 0x0B, 0x64, 0x0A, 0x76, 0x08, 0x9A, 0x06, 0xD6, 0x04, 0x48, 0x03, 0xC3, 0x01, 0xA2, 0x00, 0xE1, 0xFF, 0x08, 0xFF, 0xA4, 0xFE, 0x83, 0xFE, 0xD0, 0xFE, 0x89, 0xFF, 0x37, 0x00, 0xE7, 0x00, 0x07, 0x01, 0xC4, 0x00, 0xAA, 0xFF, 0x9F, 0xFD, 0xC6, 0xFB, 0x79, 0xFA, 0x2E, 0xFA, 0x60, 0xFA, 0xD7, 0xFA, 0xCA, 0xFB, 0x0B, 0xFD, 0xFD, 0xFE, 0x10, 0x01, 0xAA, 0x02, 0x0B, 0x04, 0x40, 0x05, 0x2C, 0x06, 0xA0, 0x06, 0xA7, 0x06, 0x39, 0x06, 0x80, 0x05, 0x87, 0x04, 0x5B, 0x03, 0x74, 0x02, 0xD1, 0x01, 0xAB, 0x01, 0x2D, 0x02, 0x0A, 0x03, 0x87, 0x04, 0x44, 0x06, 0x6F, 0x07, 0x07, 0x08, 0x98, 0x07, 0x11, 0x06, 0xE3, 0x03, 0xFB, 0x00, 0xB0, 0xFE, 0xBE, 0xFD, 0xB9, 0xFD, 0xC2, 0xFE, 0x7E, 0x00, 0xCB, 0x02, 0x4D, 0x05, 0xAD, 0x07, 0xC7, 0x09, 0xC7, 0x0A, 0xB9, 0x0A, 0x7E, 0x09, 0x5E, 0x07, 0x54, 0x05, 0xA7, 0x03, 0xD6, 0x02, 0xB3, 0x02, 0x43, 0x03, 0xA4, 0x04, 0x02, 0x06, 0xB5, 0x06, 0x87, 0x06, 0x00, 0x06, 0x45, 0x05, 0x4B, 0x04, 0x56, 0x03, 0x39, 0x02, 0x2D, 0x01, 0x1C, 0x00, 0x18, 0xFF, 0x46, 0xFE, 0x8A, 0xFD, 0x25, 0xFD, 0x77, 0xFC, 0x91, 0xFB, 0x1F, 0xFB, 0xF4, 0xFA, 0xBC, 0xFB, 0x54, 0xFD, 0xDD, 0xFE, 0x3B, 0x00, 0xC9, 0x00, 0x7A, 0x00, 0x7F, 0xFF, 0x75, 0xFD, 0xEC, 0xFA, 0x7D, 0xF8, 0xD5, 0xF6, 0x81, 0xF6, 0x24, 0xF7, 0x49, 0xF8, 0x72, 0xF9, 0x36, 0xFA, 0x6F, 0xFA, 0x55, 0xFA, 0xDB, 0xF9, 0x13, 0xF9, 0xE6, 0xF8, 0x1A, 0xF9, 0x5D, 0xF9, 0x02, 0xFA, 0xE2, 0xFA, 0x17, 0xFC, 0x93, 0xFD, 0x33, 0xFF, 0x91, 0x00, 0x5D, 0x01, 0x8F, 0x01, 0xC5, 0x00, 0x61, 0xFF, 0x90, 0xFD, 0x5B, 0xFB, 0x8F, 0xF9, 0x77, 0xF8, 0x29, 0xF8, 0x54, 0xF8, 0x87, 0xF8, 0x0C, 0xF9, 0x04, 0xFA, 0x42, 0xFB, 0xA0, 0xFC, 0x80, 0xFD, 0xA0, 0xFD, 0x81, 0xFD, 0x23, 0xFD, 0xCF, 0xFC, 0x05, 0xFD, 0x6A, 0xFD, 0xAE, 0xFD, 0x7F, 0xFD, 0x3D, 0xFD, 0xF8, 0xFD, 0x9D, 0xFF, 0x3F, 0x01, 0x67, 0x02, 0xFC, 0x02, 0xF9, 0x02, 0xC4, 0x02, 0xC4, 0x02, 0x75, 0x03, 0xEA, 0x04, 0x4A, 0x06, 0x26, 0x07, 0xFD, 0x06, 0x58, 0x05, 0xEA, 0x02, 0xE4, 0x00, 0xF1, 0xFF, 0x35, 0x00, 0xD4, 0x01, 0x05, 0x04, 0xEF, 0x05, 0x4A, 0x07, 0xDF, 0x07, 0x33, 0x08, 0x34, 0x08, 0x7E, 0x07, 0x2A, 0x06, 0x4B, 0x04, 0x4E, 0x02, 0xA5, 0x00, 0x75, 0xFF, 0x88, 0xFE, 0x21, 0xFE, 0x75, 0xFE, 0x4A, 0xFF, 0x58, 0x00, 0xA8, 0x00, 0x17, 0x00, 0x47, 0xFE, 0x3B, 0xFB, 0x34, 0xF8, 0x3A, 0xF5, 0x4B, 0xF3, 0xCB, 0xF2, 0x64, 0xF2, 0x44, 0xF2, 0x97, 0xF2, 0x41, 0xF3, 0x40, 0xF4, 0xFF, 0xF4, 0xF4, 0xF4, 0x96, 0xF4, 0x88, 0xF4, 0xE4, 0xF4, 0x16, 0xF6, 0xD3, 0xF7, 0xBE, 0xF9, 0xDA, 0xFB, 0x8E, 0xFD, 0xE8, 0xFE, 0xDD, 0xFF, 0x76, 0x00, 0x27, 0x01, 0x70, 0x01, 0x01, 0x01, 0xD6, 0xFF, 0x76, 0xFE, 0xC4, 0xFD, 0xD6, 0xFD, 0x6D, 0xFE, 0xF0, 0xFE, 0x3E, 0xFF, 0x18, 0x00, 0xAB, 0x01, 0xB8, 0x03, 0x0F, 0x06, 0x63, 0x08, 0x4E, 0x0A, 0x38, 0x0B, 0xEB, 0x0A, 0x8C, 0x09, 0x8F, 0x07, 0xA3, 0x05, 0x4C, 0x04, 0x9D, 0x03, 0x1A, 0x03, 0x9F, 0x02, 0x07, 0x02, 0x62, 0x01, 0x53, 0x01, 0x86, 0x01, 0x21, 0x02, 0x28, 0x03, 0xC0, 0x03, 0xCB, 0x03, 0x04, 0x03, 0xEB, 0x01, 0x16, 0x01, 0x67, 0x00, 0xCC, 0xFF, 0x69, 0xFE, 0x4C, 0xFC, 0x03, 0xFA, 0x29, 0xF8, 0x70, 0xF7, 0xD6, 0xF7, 0x15, 0xF9, 0x41, 0xFA, 0xC0, 0xFA, 0x0B, 0xFA, 0x8D, 0xF8, 0x5D, 0xF7, 0x5E, 0xF6, 0x18, 0xF6, 0x52, 0xF6, 0xE8, 0xF6, 0xC0, 0xF7, 0x18, 0xF8, 0x96, 0xF8, 0xAD, 0xF8, 0x42, 0xF8, 0xA7, 0xF7, 0x59, 0xF6, 0x4A, 0xF5, 0x99, 0xF4, 0x9A, 0xF4, 0x52, 0xF5, 0x12, 0xF6, 0x07, 0xF7, 0xD0, 0xF7, 0x80, 0xF8, 0xF6, 0xF8, 0xEB, 0xF8, 0xAE, 0xF8, 0x27, 0xF8, 0xBA, 0xF7, 0x6D, 0xF7, 0x89, 0xF7, 0x8C, 0xF8, 0x65, 0xFA, 0x9B, 0xFC, 0x52, 0xFE, 0xB2, 0xFF, 0xF8, 0x00, 0x39, 0x02, 0x88, 0x03, 0xA8, 0x04, 0xC2, 0x05, 0x5B, 0x06, 0x3C, 0x06, 0x75, 0x05, 0x03, 0x04, 0xA7, 0x02, 0xAB, 0x01, 0x4F, 0x01, 0xF3, 0x01, 0x75, 0x03, 0xA9, 0x05, 0x38, 0x07, 0xF6, 0x06, 0xA6, 0x05, 0xA1, 0x03, 0x3A, 0x01, 0x48, 0xFF, 0x8D, 0xFD, 0x3F, 0xFC, 0xA1, 0xFB, 0x2D, 0xFB, 0xFF, 0xFA, 0xEF, 0xFA, 0xE7, 0xFA, 0x11, 0xFB, 0xC3, 0xFA, 0xEB, 0xF9, 0x5B, 0xF9, 0x15, 0xF9, 0x36, 0xF9, 0x2C, 0xFA, 0x65, 0xFB, 0x83, 0xFC, 0x1A, 0xFD, 0x99, 0xFC, 0x74, 0xFB, 0x1D, 0xFA, 0xC6, 0xF8, 0xB9, 0xF7, 0x24, 0xF7, 0xB3, 0xF6, 0x37, 0xF6, 0x5B, 0xF6, 0x12, 0xF7, 0xB5, 0xF7, 0xB4, 0xF7, 0xC4, 0xF6, 0xA0, 0xF5, 0xF2, 0xF4, 0xA1, 0xF4, 0xCF, 0xF4, 0xA1, 0xF5, 0xE3, 0xF6, 0x7A, 0xF8, 0xDD, 0xF9, 0xE1, 0xFA, 0xB8, 0xFB, 0x62, 0xFC, 0x54, 0xFD, 0xF6, 0xFD, 0x99, 0xFD, 0x76, 0xFC, 0xE3, 0xFA, 0x98, 0xF9, 0xF4, 0xF8, 0xF3, 0xF8, 0x15, 0xF9, 0x7B, 0xF9, 0x66, 0xFA, 0x4E, 0xFB, 0x47, 0xFC, 0x0A, 0xFD, 0x9D, 0xFD, 0xE1, 0xFD, 0xC6, 0xFD, 0xB7, 0xFD, 0x4A, 0xFD, 0xED, 0xFC, 0xB3, 0xFC, 0xD2, 0xFC, 0xC8, 0xFD, 0x0D, 0xFF, 0xB1, 0x00, 0xB5, 0x01, 0xFE, 0x01, 0x67, 0x01, 0xBC, 0xFF, 0x6A, 0xFE, 0x68, 0xFD, 0x41, 0xFD, 0xB8, 0xFD, 0xC3, 0xFD, 0xB1, 0xFD, 0x4C, 0xFD, 0xE4, 0xFC, 0x56, 0xFC, 0xFA, 0xFB, 0x1A, 0xFC, 0x78, 0xFC, 0x7C, 0xFD, 0x4B, 0xFE, 0xEE, 0xFE, 0x13, 0xFF, 0x4E, 0xFE, 0x24, 0xFD, 0x4A, 0xFB, 0xC0, 0xF9, 0x11, 0xF9, 0x2F, 0xF9, 0x40, 0xFA, 0xFF, 0xFB, 0xCA, 0xFE, 0x3E, 0x02, 0x56, 0x05, 0xF9, 0x06, 0x10, 0x07, 0x70, 0x06, 0xAF, 0x05, 0x6C, 0x05, 0x1A, 0x05, 0x25, 0x04, 0x89, 0x02, 0xA0, 0x00, 0x3F, 0xFF, 0x6B, 0xFE, 0xC0, 0xFD, 0x4B, 0xFD, 0x33, 0xFD, 0xF4, 0xFC, 0x86, 0xFC, 0x1E, 0xFC, 0xF8, 0xFB, 0xBC, 0xFC, 0xCB, 0xFD, 0xEE, 0xFE, 0x10, 0x00, 0xE8, 0x00, 0xEE, 0x01, 0xDE, 0x02, 0xC2, 0x03, 0xAB, 0x04, 0x53, 0x05, 0xDB, 0x05, 0x5E, 0x06, 0xB9, 0x06, 0xB3, 0x06, 0x75, 0x06, 0x55, 0x05, 0xD3, 0x03, 0xBD, 0x02, 0xE2, 0x01, 0xF2, 0x01, 0xFC, 0x01, 0x16, 0x02, 0x27, 0x03, 0x21, 0x04, 0x3C, 0x05, 0x54, 0x06, 0x17, 0x07, 0xCA, 0x07, 0x25, 0x08, 0x1E, 0x08, 0xDC, 0x07, 0x5B, 0x07, 0x7A, 0x06, 0xD1, 0x05, 0x7E, 0x05, 0x84, 0x05, 0x68, 0x06, 0x6C, 0x07, 0x6F, 0x08, 0x4E, 0x09, 0x73, 0x09, 0x6D, 0x09, 0x5D, 0x09, 0x44, 0x09, 0x34, 0x09, 0xC7, 0x08, 0xD9, 0x07, 0xAB, 0x06, 0xB9, 0x05, 0x5F, 0x05, 0x57, 0x05, 0x85, 0x05, 0x2E, 0x06, 0xEA, 0x06, 0xBD, 0x07, 0x97, 0x08, 0xDD, 0x08, 0xA2, 0x08, 0xA3, 0x07, 0xF9, 0x05, 0x09, 0x04, 0x09, 0x02, 0x97, 0x00, 0xCC, 0xFF, 0xC4, 0xFF, 0x1C, 0x00, 0x86, 0x00, 0xC8, 0x00, 0x48, 0x00, 0x9B, 0xFF, 0xD4, 0xFE, 0x13, 0xFE, 0xA5, 0xFD, 0x02, 0xFD, 0xA7, 0xFC, 0xBB, 0xFC, 0xFA, 0xFC, 0x15, 0xFD, 0x5C, 0xFC, 0xC4, 0xFA, 0x09, 0xF9, 0x2E, 0xF8, 0x20, 0xF8, 0x3A, 0xF8, 0x37, 0xF8, 0x69, 0xF8, 0x3B, 0xF9, 0xE8, 0xF9, 0x17, 0xFA, 0xF8, 0xF9, 0x8F, 0xF9, 0x43, 0xF9, 0x09, 0xF9, 0x84, 0xF8, 0xDE, 0xF7, 0x47, 0xF7, 0xCA, 0xF6, 0xEA, 0xF6, 0xBB, 0xF7, 0x4D, 0xF9, 0xBE, 0xFB, 0x69, 0xFE, 0x00, 0x01, 0xBA, 0x02, 0x4B, 0x03, 0x6C, 0x03, 0x11, 0x03, 0x70, 0x02, 0xD2, 0x01, 0x8A, 0x01, 0xD1, 0x01, 0x8C, 0x02, 0x9F, 0x03, 0x90, 0x04, 0x90, 0x05, 0x33, 0x06, 0x15, 0x06, 0x30, 0x05, 0x4C, 0x03, 0x46, 0x01, 0x75, 0xFF, 0x90, 0xFE, 0xD2, 0xFE, 0x9F, 0xFF, 0x38, 0x01, 0xA6, 0x02, 0xF3, 0x03, 0x05, 0x05, 0x1E, 0x05, 0xF6, 0x04, 0x3E, 0x04, 0x2B, 0x03, 0x25, 0x02, 0x08, 0x01, 0x5B, 0x00, 0x1E, 0x00, 0xE7, 0xFF, 0x27, 0xFF, 0x02, 0xFE, 0x6E, 0xFC, 0xB3, 0xFA, 0xA8, 0xF9, 0xF0, 0xF8, 0x95, 0xF8, 0xA8, 0xF8, 0xBD, 0xF8, 0xD5, 0xF8, 0x75, 0xF9, 0xD9, 0xFA, 0x93, 0xFC, 0x42, 0xFE, 0x2B, 0xFF, 0x62, 0xFF, 0x14, 0xFF, 0xE5, 0xFD, 0xC4, 0xFC, 0x33, 0xFC, 0x61, 0xFC, 0x69, 0xFD, 0x7D, 0xFE, 0x5E, 0xFF, 0x86, 0x00, 0xE3, 0x01, 0x09, 0x03, 0x6A, 0x04, 0x48, 0x05, 0x0D, 0x05, 0x5C, 0x04, 0x46, 0x03, 0xBA, 0x02, 0xD0, 0x02, 0x09, 0x03, 0xE9, 0x03, 0x05, 0x05, 0x33, 0x06, 0x8F, 0x07, 0x78, 0x08, 0xD2, 0x08, 0xDD, 0x08, 0xFE, 0x07, 0x09, 0x06, 0xED, 0x03, 0x87, 0x02, 0x07, 0x03, 0x20, 0x05, 0x91, 0x07, 0x2E, 0x0A, 0x80, 0x0C, 0x28, 0x0E, 0xF7, 0x0E, 0xA8, 0x0E, 0x79, 0x0D, 0xD0, 0x0B, 0xCF, 0x09, 0x52, 0x07, 0x40, 0x05, 0x39, 0x04, 0x60, 0x04, 0xC3, 0x05, 0x21, 0x07, 0x1A, 0x08, 0xAF, 0x08, 0x09, 0x08, 0x7E, 0x06, 0x93, 0x04, 0xAF, 0x02, 0xC1, 0x01, 0xA1, 0x01, 0xD8, 0x01, 0x42, 0x02, 0x81, 0x02, 0x94, 0x02, 0x80, 0x02, 0x98, 0x02, 0xD6, 0x02, 0x85, 0x02, 0x01, 0x02, 0xC5, 0x01, 0xC9, 0x01, 0x0A, 0x02, 0x6E, 0x02, 0xD3, 0x02, 0x0E, 0x03, 0x10, 0x03, 0x49, 0x02, 0xE1, 0x00, 0x4B, 0xFF, 0x82, 0xFD, 0x71, 0xFC, 0x78, 0xFC, 0x95, 0xFD, 0x40, 0xFF, 0x3E, 0x00, 0x95, 0x00, 0x95, 0x00, 0xEE, 0x00, 0xB6, 0x01, 0x93, 0x02, 0x51, 0x03, 0x2D, 0x03, 0x8C, 0x02, 0x49, 0x01, 0x16, 0xFF, 0xB3, 0xFC, 0x38, 0xFA, 0xAB, 0xF8, 0x80, 0xF8, 0xFA, 0xF8, 0xFE, 0xF9, 0x37, 0xFB, 0x35, 0xFC, 0xE5, 0xFC, 0x49, 0xFD, 0xB9, 0xFD, 0x9E, 0xFE, 0xAF, 0xFF, 0x26, 0x00, 0xA1, 0xFF, 0x50, 0xFE, 0xBD, 0xFC, 0x5C, 0xFB, 0xC1, 0xFA, 0xD6, 0xFA, 0x2E, 0xFB, 0xCE, 0xFB, 0x62, 0xFC, 0xA9, 0xFC, 0x5F, 0xFC, 0x13, 0xFB, 0xD2, 0xF8, 0x8C, 0xF6, 0x2C, 0xF5, 0x7F, 0xF4, 0x9E, 0xF4, 0x39, 0xF5, 0x4B, 0xF6, 0xE9, 0xF7, 0xBF, 0xF8, 0x0D, 0xF9, 0xFF, 0xF8, 0x78, 0xF8, 0x1E, 0xF8, 0x55, 0xF7, 0x41, 0xF6, 0x84, 0xF5, 0xC8, 0xF5, 0xB0, 0xF6, 0x19, 0xF7, 0x32, 0xF7, 0xE8, 0xF6, 0x56, 0xF7, 0x54, 0xF8, 0x10, 0xF9, 0x56, 0xFA, 0x4F, 0xFB, 0x30, 0xFC, 0xEE, 0xFC, 0xF5, 0xFC, 0x2D, 0xFD, 0x6A, 0xFD, 0xF1, 0xFD, 0x35, 0xFE, 0x78, 0xFD, 0x43, 0xFC, 0xAC, 0xFA, 0x52, 0xF9, 0x94, 0xF8, 0xE9, 0xF8, 0x56, 0xFA, 0x7E, 0xFC, 0xC0, 0xFE, 0xD2, 0xFF, 0x0A, 0x00, 0x1B, 0xFF, 0x6C, 0xFD, 0x3C, 0xFC, 0x4F, 0xFB, 0x41, 0xFB, 0xA2, 0xFB, 0xAF, 0xFB, 0x8C, 0xFB, 0x03, 0xFB, 0x69, 0xFA, 0x05, 0xFA, 0xF7, 0xF9, 0xF0, 0xF9, 0x04, 0xFA, 0x36, 0xFA, 0x60, 0xFA, 0x9F, 0xFA, 0x3F, 0xFA, 0x9F, 0xF9, 0x45, 0xF9, 0xE4, 0xF8, 0x03, 0xF9, 0x50, 0xFA, 0xA9, 0xFC, 0x51, 0xFF, 0xDD, 0x01, 0xDE, 0x03, 0x75, 0x05, 0xC6, 0x06, 0xD4, 0x06, 0x97, 0x05, 0xB0, 0x03, 0xFD, 0x01, 0x4C, 0x01, 0x22, 0x01, 0x26, 0x01, 0x8A, 0x01, 0xBD, 0x02, 0xBF, 0x04, 0xD8, 0x06, 0x5D, 0x08, 0x0E, 0x09, 0xD6, 0x08, 0x09, 0x08, 0x38, 0x07, 0x75, 0x06, 0xDC, 0x05, 0x3D, 0x05, 0x8E, 0x04, 0xFB, 0x03, 0x6E, 0x03, 0x35, 0x03, 0x1D, 0x03, 0x6E, 0x03, 0x29, 0x04, 0x80, 0x04, 0x7D, 0x04, 0xC4, 0x03, 0xD0, 0x02, 0xF4, 0x01, 0xF9, 0x00, 0x95, 0x00, 0x71, 0x00, 0x77, 0x00, 0xB8, 0x00, 0x06, 0x01, 0x9F, 0x01, 0x2D, 0x02, 0x89, 0x02, 0x9A, 0x02, 0x7A, 0x02, 0xEC, 0x01, 0xB5, 0x00, 0xDD, 0xFF, 0xD7, 0xFF, 0x47, 0x00, 0x86, 0x00, 0x2A, 0x00, 0xA5, 0xFF, 0x5A, 0xFF, 0x41, 0xFF, 0x05, 0xFF, 0x0D, 0xFF, 0xC8, 0xFF, 0xCE, 0x00, 0xB6, 0x01, 0x0F, 0x02, 0x42, 0x02, 0xC0, 0x02, 0xB4, 0x02, 0xE4, 0x01, 0xA8, 0x00, 0x99, 0xFF, 0x69, 0xFF, 0xB7, 0xFF, 0x7A, 0x00, 0x09, 0x02, 0x06, 0x04, 0xDF, 0x05, 0x0E, 0x07, 0x8F, 0x07, 0x32, 0x07, 0x21, 0x06, 0xDC, 0x04, 0x88, 0x03, 0x7B, 0x02, 0x5E, 0x01, 0x09, 0x00, 0x02, 0xFF, 0x20, 0xFF, 0xED, 0x00, 0x11, 0x03, 0x79, 0x04, 0x0D, 0x05, 0x96, 0x04, 0x7A, 0x03, 0xF6, 0x01, 0x32, 0x00, 0xD0, 0xFE, 0x11, 0xFE, 0x62, 0xFD, 0x77, 0xFC, 0xA5, 0xFB, 0x98, 0xFA, 0x68, 0xF9, 0xD6, 0xF8, 0xB6, 0xF8, 0xB1, 0xF8, 0xC6, 0xF8, 0xAB, 0xF8, 0x8D, 0xF8, 0x88, 0xF8, 0x50, 0xF8, 0x4B, 0xF8, 0x60, 0xF8, 0x27, 0xF8, 0x39, 0xF7, 0x9E, 0xF5, 0x2C, 0xF4, 0xE8, 0xF2, 0x69, 0xF2, 0x18, 0xF3, 0x40, 0xF4, 0x90, 0xF5, 0x56, 0xF6, 0x63, 0xF6, 0xBA, 0xF5, 0x4E, 0xF4, 0xC7, 0xF2, 0x2A, 0xF1, 0x96, 0xEF, 0xC2, 0xEE, 0x0B, 0xEF, 0x14, 0xF0, 0xB7, 0xF1, 0xB0, 0xF3, 0x6D, 0xF5, 0xF8, 0xF6, 0x58, 0xF8, 0xEA, 0xF9, 0x8C, 0xFB, 0x8D, 0xFC, 0x9F, 0xFC, 0x1A, 0xFC, 0xAC, 0xFB, 0x5F, 0xFB, 0x7B, 0xFB, 0x1D, 0xFC, 0x10, 0xFD, 0x5D, 0xFE, 0x75, 0xFF, 0x88, 0x00, 0xBA, 0x01, 0xF6, 0x02, 0xEA, 0x03, 0x01, 0x04, 0x8A, 0x03, 0x02, 0x03, 0x2A, 0x03, 0xA3, 0x03, 0x0C, 0x04, 0x5F, 0x04, 0x1C, 0x04, 0x17, 0x04, 0x97, 0x04, 0xC2, 0x05, 0x76, 0x07, 0xBE, 0x08, 0x2C, 0x09, 0xA7, 0x08, 0xFF, 0x07, 0x29, 0x07, 0x26, 0x06, 0x07, 0x05, 0x56, 0x03, 0x76, 0x01, 0xF3, 0xFE, 0x6E, 0xFC, 0xFC, 0xFA, 0xC6, 0xFA, 0x9E, 0xFB, 0x48, 0xFC, 0xF3, 0xFC, 0x2A, 0xFE, 0xA8, 0xFF, 0x3E, 0x01, 0x9B, 0x02, 0x2D, 0x03, 0xA9, 0x02, 0x88, 0x01, 0x07, 0x00, 0xA4, 0xFE, 0xAE, 0xFD, 0x35, 0xFD, 0xFD, 0xFC, 0xC4, 0xFC, 0x31, 0xFD, 0xAB, 0xFD, 0x6C, 0xFE, 0xD3, 0xFF, 0x0F, 0x01, 0x50, 0x02, 0x12, 0x03, 0xA1, 0x03, 0xC5, 0x03, 0x5A, 0x03, 0x26, 0x03, 0xF5, 0x02, 0x76, 0x03, 0x17, 0x04, 0xAF, 0x04, 0xDB, 0x05, 0x07, 0x07, 0x24, 0x08, 0xA3, 0x08, 0xF1, 0x08, 0x08, 0x09, 0x77, 0x08, 0xB9, 0x07, 0xF1, 0x06, 0xFF, 0x06, 0x87, 0x07, 0x80, 0x08, 0x04, 0x0A, 0x37, 0x0B, 0x95, 0x0C, 0x9F, 0x0D, 0x1E, 0x0E, 0x89, 0x0E, 0xE9, 0x0E, 0x56, 0x0F, 0x21, 0x0F, 0x41, 0x0E, 0x5B, 0x0D, 0x96, 0x0C, 0xBC, 0x0B, 0x02, 0x0B, 0x7B, 0x0A, 0xCC, 0x09, 0x2B, 0x09, 0x40, 0x08, 0x48, 0x07, 0xEE, 0x06, 0xE2, 0x06, 0xE7, 0x06, 0xAB, 0x06, 0x99, 0x05, 0x12, 0x04, 0xAB, 0x02, 0x34, 0x01, 0x3F, 0x00, 0x0A, 0x00, 0xEB, 0xFF, 0xEB, 0xFF, 0x01, 0x00, 0x66, 0x00, 0x5A, 0x01, 0x79, 0x02, 0x2B, 0x03, 0xF7, 0x02, 0x06, 0x02, 0x9B, 0x00, 0x43, 0xFF, 0xF8, 0xFD, 0xBE, 0xFC, 0x22, 0xFC, 0xE3, 0xFB, 0x28, 0xFC, 0xF0, 0xFC, 0xA4, 0xFD, 0xF8, 0xFD, 0x0B, 0xFE, 0x36, 0xFE, 0x89, 0xFE, 0xEA, 0xFE, 0x1C, 0xFF, 0x20, 0xFF, 0xDD, 0xFE, 0x83, 0xFE, 0x63, 0xFE, 0x50, 0xFE, 0x3E, 0xFE, 0xB6, 0xFD, 0x0C, 0xFD, 0xA3, 0xFC, 0x43, 0xFC, 0x53, 0xFC, 0xD2, 0xFC, 0xF5, 0xFD, 0x12, 0xFF, 0x91, 0xFF, 0xC5, 0xFF, 0x77, 0xFF, 0x37, 0xFF, 0xCA, 0xFE, 0xEE, 0xFD, 0x0B, 0xFD, 0x2A, 0xFC, 0x87, 0xFB, 0x03, 0xFB, 0xF3, 0xFA, 0x87, 0xFB, 0xE9, 0xFC, 0x00, 0xFF, 0x31, 0x01, 0x54, 0x03, 0xB8, 0x04, 0x79, 0x05, 0x63, 0x05, 0x24, 0x04, 0x6D, 0x02, 0x6A, 0x00, 0xCC, 0xFE, 0xBA, 0xFD, 0x85, 0xFD, 0x7B, 0xFE, 0x1C, 0x00, 0x1E, 0x02, 0x76, 0x03, 0xE8, 0x03, 0x30, 0x03, 0x29, 0x01, 0xAF, 0xFE, 0x74, 0xFC, 0x5A, 0xFB, 0xE3, 0xFA, 0xED, 0xFA, 0x75, 0xFB, 0x0F, 0xFC, 0x5C, 0xFD, 0xDC, 0xFE, 0x8D, 0x00, 0x4F, 0x02, 0x27, 0x03, 0x04, 0x03, 0xE1, 0x01, 0x7B, 0x00, 0x12, 0xFF, 0xCC, 0xFD, 0x4E, 0xFD, 0x40, 0xFD, 0x7D, 0xFD, 0xB9, 0xFD, 0xAD, 0xFD, 0x44, 0xFD, 0xB3, 0xFC, 0x55, 0xFC, 0x23, 0xFC, 0x75, 0xFC, 0x11, 0xFD, 0x79, 0xFD, 0x9E, 0xFD, 0x30, 0xFD, 0xB9, 0xFC, 0x99, 0xFC, 0x78, 0xFC, 0x44, 0xFC, 0x7F, 0xFB, 0x2D, 0xFA, 0x12, 0xF9, 0x0F, 0xF8, 0xA9, 0xF7, 0x67, 0xF8, 0xA4, 0xF9, 0x20, 0xFB, 0x23, 0xFC, 0x85, 0xFC, 0x7A, 0xFC, 0xAA, 0xFB, 0xAB, 0xFA, 0xCB, 0xF9, 0x87, 0xF9, 0x1A, 0xFA, 0x1E, 0xFB, 0xA6, 0xFC, 0x8B, 0xFE, 0x97, 0x00, 0x31, 0x02, 0x34, 0x03, 0xCF, 0x03, 0xF8, 0x03, 0x16, 0x04, 0x00, 0x04, 0xF9, 0x03, 0x40, 0x04, 0xE9, 0x04, 0x30, 0x06, 0xED, 0x07, 0x37, 0x0A, 0x47, 0x0C, 0xF6, 0x0D, 0x84, 0x0F, 0x45, 0x10, 0x78, 0x10, 0xD5, 0x0F, 0x7B, 0x0E, 0x38, 0x0D, 0x2D, 0x0C, 0xE3, 0x0B, 0x63, 0x0C, 0x33, 0x0D, 0x20, 0x0E, 0x1A, 0x0F, 0x8A, 0x0F, 0x3D, 0x0F, 0x9D, 0x0E, 0xCE, 0x0D, 0x9B, 0x0D, 0x97, 0x0E, 0x81, 0x10, 0x91, 0x12, 0x0E, 0x14, 0xD9, 0x14, 0x77, 0x14, 0x0B, 0x13, 0xC4, 0x10, 0xD1, 0x0D, 0x38, 0x0B, 0x58, 0x09, 0x44, 0x08, 0xCE, 0x07, 0x9B, 0x07, 0xC7, 0x07, 0x57, 0x08, 0xB8, 0x08, 0xC7, 0x08, 0x78, 0x08, 0xAF, 0x07, 0xD3, 0x06, 0x39, 0x05, 0x66, 0x03, 0x07, 0x02, 0x82, 0x00, 0xEC, 0xFF, 0x98, 0xFF, 0xE9, 0xFE, 0x8A, 0xFE, 0xC6, 0xFD, 0x64, 0xFD, 0x7C, 0xFD, 0x28, 0xFD, 0xCA, 0xFC, 0xBE, 0xFC, 0x31, 0xFD, 0x0D, 0xFE, 0xD3, 0xFE, 0x64, 0xFF, 0xC8, 0x00, 0x88, 0x02, 0x24, 0x04, 0x0F, 0x06, 0x52, 0x07, 0x05, 0x08, 0xFF, 0x07, 0xF1, 0x06, 0x9B, 0x05, 0x60, 0x04, 0xAC, 0x03, 0x25, 0x03, 0x1E, 0x03, 0x71, 0x03, 0x8A, 0x03, 0xD1, 0x03, 0x1B, 0x04, 0xD5, 0x04, 0xE9, 0x05, 0x03, 0x07, 0x0E, 0x08, 0x79, 0x08, 0x40, 0x08, 0x5D, 0x07, 0x79, 0x06, 0x0E, 0x06, 0xE1, 0x05, 0x9B, 0x05, 0x2E, 0x05, 0xF3, 0x04, 0xA1, 0x04, 0x68, 0x04, 0x40, 0x04, 0x69, 0x04, 0x17, 0x05, 0xCB, 0x05, 0xB1, 0x06, 0x2A, 0x07, 0x23, 0x07, 0xEB, 0x06, 0xDA, 0x05, 0x9F, 0x03, 0xF4, 0x00, 0xEC, 0xFE, 0x71, 0xFD, 0x2D, 0xFD, 0xAB, 0xFD, 0x53, 0xFE, 0x02, 0x00, 0x05, 0x01, 0xF0, 0x00, 0x15, 0x00, 0x44, 0xFE, 0x60, 0xFC, 0x73, 0xFA, 0xF9, 0xF8, 0x01, 0xF8, 0xCE, 0xF7, 0x3E, 0xF8, 0xAE, 0xF8, 0x8B, 0xF9, 0x61, 0xFA, 0x3B, 0xFB, 0xC4, 0xFB, 0xE0, 0xFB, 0xB1, 0xFB, 0xA4, 0xFA, 0x78, 0xF9, 0xE4, 0xF7, 0xF1, 0xF5, 0x66, 0xF4, 0x79, 0xF3, 0x6A, 0xF3, 0x18, 0xF4, 0xC0, 0xF5, 0xC7, 0xF7, 0x14, 0xFA, 0x52, 0xFC, 0x99, 0xFD, 0xAA, 0xFE, 0xFC, 0xFE, 0x82, 0xFE, 0x1E, 0xFE, 0xC3, 0xFD, 0xF6, 0xFD, 0xC9, 0xFE, 0xC9, 0xFF, 0x50, 0x00, 0x8D, 0x00, 0x0B, 0x01, 0x86, 0x01, 0x05, 0x02, 0x79, 0x02, 0xF8, 0x02, 0x92, 0x03, 0xE8, 0x03, 0xCF, 0x03, 0x24, 0x03, 0x3B, 0x02, 0xBD, 0x01, 0xA1, 0x01, 0xC5, 0x01, 0x57, 0x02, 0x0E, 0x03, 0xDE, 0x03, 0xBA, 0x04, 0x94, 0x05, 0xF2, 0x06, 0xA0, 0x08, 0x6C, 0x0A, 0xFA, 0x0B, 0x85, 0x0C, 0xF2, 0x0B, 0x2D, 0x0A, 0x16, 0x08, 0xA4, 0x06, 0x98, 0x05, 0xE4, 0x04, 0x33, 0x04, 0x70, 0x03, 0x10, 0x03, 0xEF, 0x02, 0x07, 0x03, 0x86, 0x03, 0x18, 0x04, 0xDB, 0x04, 0x8A, 0x05, 0xD4, 0x05, 0x0B, 0x06, 0x24, 0x06, 0x84, 0x06, 0xE0, 0x06, 0xC5, 0x06, 0xDF, 0x06, 0xDC, 0x06, 0xCF, 0x06, 0xF4, 0x06, 0xEB, 0x06, 0xEA, 0x06, 0x18, 0x07, 0x85, 0x07, 0x1F, 0x08, 0xC5, 0x08, 0x09, 0x09, 0x2B, 0x09, 0xA9, 0x09, 0x01, 0x0A, 0x31, 0x0A, 0xF8, 0x09, 0x76, 0x09, 0x49, 0x09, 0x4E, 0x09, 0xAD, 0x09, 0x04, 0x0A, 0x33, 0x0A, 0x07, 0x0A, 0x0E, 0x09, 0xFE, 0x07, 0xB3, 0x06, 0x49, 0x05, 0x3A, 0x04, 0xF7, 0x02, 0xFD, 0x01, 0x87, 0x01, 0x3B, 0x01, 0x82, 0x01, 0xC4, 0x01, 0xB7, 0x01, 0xD2, 0x01, 0xB4, 0x01, 0x67, 0x01, 0xDE, 0x00, 0xED, 0xFF, 0xF0, 0xFE, 0xE8, 0xFD, 0xBE, 0xFC, 0x6D, 0xFB, 0x71, 0xFA, 0xCC, 0xF9, 0x6D, 0xF9, 0xEA, 0xF9, 0xD4, 0xFA, 0x28, 0xFC, 0xF0, 0xFD, 0xAC, 0xFF, 0x1F, 0x01, 0x00, 0x02, 0xB8, 0x02, 0x35, 0x03, 0x8E, 0x03, 0xF3, 0x03, 0xCD, 0x03, 0x76, 0x03, 0xAB, 0x02, 0x86, 0x01, 0x0C, 0x01, 0x49, 0x01, 0x0A, 0x02, 0x6B, 0x02, 0xFF, 0x01, 0x19, 0x01, 0xEB, 0xFF, 0xF7, 0xFE, 0x22, 0xFE, 0xA6, 0xFD, 0x6C, 0xFD, 0x38, 0xFD, 0x5D, 0xFD, 0x72, 0xFD, 0xEE, 0xFD, 0xFC, 0xFE, 0x1A, 0x00, 0x4D, 0x01, 0xC1, 0x01, 0x67, 0x01, 0x7C, 0x00, 0xCD, 0xFE, 0xDC, 0xFC, 0xC0, 0xFA, 0xD6, 0xF8, 0x3F, 0xF7, 0xF0, 0xF5, 0x36, 0xF5, 0x06, 0xF5, 0xA7, 0xF5, 0xE4, 0xF6, 0xC9, 0xF8, 0x04, 0xFB, 0xC9, 0xFC, 0xD1, 0xFD, 0x85, 0xFD, 0x7D, 0xFC, 0xD6, 0xFA, 0x64, 0xF8, 0x5A, 0xF6, 0xF0, 0xF4, 0xAF, 0xF4, 0x6E, 0xF5, 0x97, 0xF6, 0x26, 0xF8, 0x5B, 0xF9, 0x6C, 0xFA, 0x84, 0xFB, 0x48, 0xFC, 0x74, 0xFC, 0x08, 0xFC, 0x54, 0xFB, 0x77, 0xFA, 0x48, 0xFA, 0x8E, 0xFA, 0xCA, 0xFA, 0x08, 0xFB, 0xA9, 0xFA, 0xDD, 0xF9, 0x8E, 0xF8, 0xFB, 0xF6, 0x2D, 0xF6, 0x3B, 0xF6, 0x30, 0xF7, 0x05, 0xF9, 0x0A, 0xFB, 0xC4, 0xFC, 0x50, 0xFE, 0x85, 0xFF, 0x01, 0x00, 0x68, 0xFF, 0x99, 0xFD, 0x73, 0xFB, 0xB1, 0xF9, 0xDD, 0xF8, 0x30, 0xF9, 0x2F, 0xFA, 0x9A, 0xFB, 0x78, 0xFD, 0x46, 0xFF, 0x89, 0x00, 0x56, 0x01, 0x8F, 0x01, 0xA5, 0x01, 0xD3, 0x01, 0xBB, 0x01, 0xC8, 0x01, 0xC6, 0x01, 0x15, 0x02, 0xD6, 0x02, 0x23, 0x03, 0x54, 0x03, 0x42, 0x03, 0x19, 0x03, 0xE8, 0x02, 0x83, 0x02, 0x96, 0x02, 0xF0, 0x02, 0x89, 0x03, 0xFD, 0x03, 0x17, 0x04, 0x59, 0x04, 0x9A, 0x04, 0x40, 0x05, 0x35, 0x06, 0xDA, 0x06, 0x27, 0x07, 0x60, 0x07, 0x94, 0x07, 0x04, 0x07, 0x85, 0x05, 0x4C, 0x03, 0xEE, 0x00, 0x31, 0xFF, 0xDF, 0xFD, 0x3C, 0xFD, 0x6D, 0xFD, 0xE8, 0xFD, 0xC0, 0xFE, 0xC3, 0xFF, 0x9D, 0x00, 0x83, 0x01, 0x47, 0x02, 0x97, 0x02, 0x3F, 0x02, 0x21, 0x01, 0xB6, 0xFF, 0xB7, 0xFE, 0x32, 0xFE, 0xB8, 0xFD, 0x3C, 0xFD, 0x65, 0xFC, 0x5B, 0xFB, 0xC7, 0xFA, 0xA1, 0xFA, 0x39, 0xFB, 0x77, 0xFC, 0xF5, 0xFD, 0xC7, 0xFF, 0x76, 0x01, 0x15, 0x03, 0x2B, 0x04, 0xF4, 0x03, 0xF7, 0x02, 0x93, 0x01, 0x2C, 0x00, 0x14, 0xFF, 0xCA, 0xFD, 0x56, 0xFC, 0x92, 0xFB, 0xCD, 0xFB, 0x80, 0xFC, 0x79, 0xFD, 0x58, 0xFE, 0xFF, 0xFE, 0xCA, 0xFF, 0x8E, 0x00, 0x04, 0x01, 0x2E, 0x01, 0xBD, 0x00, 0x9F, 0xFF, 0x9C, 0xFE, 0xBA, 0xFD, 0x1E, 0xFD, 0xFF, 0xFC, 0x87, 0xFC, 0xEE, 0xFB, 0x72, 0xFB, 0xE8, 0xFA, 0xDA, 0xFA, 0x5D, 0xFB, 0x16, 0xFC, 0x02, 0xFD, 0x0F, 0xFE, 0xCC, 0xFE, 0xB8, 0xFF, 0xC2, 0x00, 0x66, 0x01, 0x32, 0x02, 0x86, 0x02, 0x38, 0x02, 0xAD, 0x01, 0xE1, 0x00, 0x59, 0x00, 0x91, 0xFF, 0x22, 0xFE, 0xFE, 0xFB, 0x87, 0xF9, 0x2E, 0xF7, 0x3E, 0xF5, 0x53, 0xF4, 0x05, 0xF4, 0xB6, 0xF4, 0x03, 0xF6, 0x39, 0xF7, 0xC3, 0xF8, 0xDB, 0xF9, 0xCC, 0xFA, 0x19, 0xFC, 0x50, 0xFD, 0x39, 0xFE, 0x51, 0xFE, 0xC5, 0xFD, 0xA4, 0xFC, 0x2E, 0xFB, 0x78, 0xF9, 0x9E, 0xF7, 0x84, 0xF6, 0x64, 0xF6, 0x57, 0xF7, 0x96, 0xF8, 0x78, 0xF9, 0x07, 0xFA, 0xFC, 0xF9, 0xB8, 0xF9, 0x3E, 0xF9, 0x6E, 0xF8, 0x7B, 0xF7, 0xB4, 0xF6, 0x25, 0xF6, 0x57, 0xF5, 0xA2, 0xF4, 0xF6, 0xF3, 0x88, 0xF3, 0xE6, 0xF3, 0xB4, 0xF4, 0x02, 0xF6, 0xB4, 0xF7, 0x55, 0xF9, 0x8E, 0xFA, 0xD8, 0xFA, 0x67, 0xFA, 0x0B, 0xFA, 0x43, 0xFA, 0x99, 0xFA, 0xA3, 0xFA, 0x7B, 0xFA, 0x4A, 0xFA, 0x0D, 0xFA, 0xC0, 0xF9, 0x5F, 0xF9, 0xD3, 0xF8, 0x6D, 0xF8, 0xEC, 0xF7, 0x49, 0xF7, 0x30, 0xF7, 0x70, 0xF7, 0x20, 0xF8, 0x0F, 0xF9, 0xB2, 0xF9, 0x10, 0xFA, 0xE8, 0xF9, 0x8A, 0xF9, 0x4F, 0xF9, 0x33, 0xF9, 0x64, 0xF9, 0xF7, 0xF9, 0xC2, 0xFA, 0x7A, 0xFB, 0x5F, 0xFC, 0x5E, 0xFD, 0x7E, 0xFE, 0xDE, 0xFF, 0x86, 0x00, 0x99, 0x00, 0x76, 0x00, 0x4A, 0x00, 0x18, 0x01, 0x5F, 0x02, 0x9F, 0x03, 0xE0, 0x04, 0x86, 0x05, 0xF5, 0x05, 0x7D, 0x06, 0xB2, 0x06, 0x6C, 0x06, 0xE9, 0x05, 0x4D, 0x05, 0x8A, 0x04, 0xF5, 0x03, 0xA3, 0x03, 0x9D, 0x03, 0xEF, 0x03, 0x6E, 0x04, 0x4E, 0x05, 0x8D, 0x06, 0xFA, 0x07, 0x40, 0x09, 0xC1, 0x09, 0xFD, 0x08, 0x29, 0x07, 0xC8, 0x04, 0xB6, 0x01, 0x20, 0xFF, 0xB4, 0xFD, 0x14, 0xFD, 0xFC, 0xFD, 0x8B, 0xFF, 0x74, 0x01, 0xA5, 0x03, 0xF5, 0x04, 0xF7, 0x05, 0xB4, 0x05, 0xCC, 0x03, 0xC2, 0x01, 0x9B, 0xFF, 0x29, 0xFE, 0x89, 0xFD, 0xF7, 0xFC, 0x95, 0xFC, 0x03, 0xFC, 0x32, 0xFB, 0x8D, 0xFA, 0x3D, 0xFA, 0x1C, 0xFA, 0x4C, 0xFA, 0xA4, 0xFA, 0x0C, 0xFB, 0xC8, 0xFB, 0x8B, 0xFC, 0x3B, 0xFD, 0x8F, 0xFD, 0x88, 0xFD, 0x47, 0xFD, 0xDC, 0xFC, 0x20, 0xFD, 0x92, 0xFD, 0xC2, 0xFD, 0xCD, 0xFD, 0x98, 0xFD, 0xD1, 0xFD, 0x2D, 0xFE, 0xAC, 0xFE, 0x5C, 0xFF, 0x90, 0xFF, 0xA5, 0xFF, 0xAA, 0xFF, 0xAD, 0xFF, 0xEE, 0xFF, 0x38, 0x00, 0xA0, 0x00, 0x1C, 0x01, 0x7D, 0x01, 0xB7, 0x01, 0xAD, 0x01, 0x53, 0x01, 0x2F, 0x01, 0x1D, 0x01, 0xFA, 0x00, 0x58, 0x01, 0xA6, 0x01, 0xD7, 0x01, 0x4F, 0x02, 0x98, 0x02, 0xB0, 0x02, 0x61, 0x02, 0x7E, 0x01, 0x93, 0x00, 0x50, 0x00, 0xEE, 0x00, 0xB8, 0x01, 0x1D, 0x02, 0x1C, 0x02, 0x6A, 0x01, 0x02, 0x00, 0x64, 0xFE, 0x98, 0xFC, 0xF2, 0xFA, 0xDA, 0xF9, 0xFB, 0xF8, 0x59, 0xF8, 0x3B, 0xF8, 0xF3, 0xF8, 0x0D, 0xFA, 0xE3, 0xFA, 0x32, 0xFB, 0xBD, 0xFA, 0x44, 0xFA, 0xF8, 0xF9, 0xAA, 0xF9, 0x72, 0xF9, 0x47, 0xF9, 0x90, 0xF9, 0xF3, 0xF9, 0x94, 0xFA, 0x68, 0xFB, 0xF7, 0xFB, 0x7A, 0xFC, 0xED, 0xFC, 0x8C, 0xFD, 0xFD, 0xFD, 0x1D, 0xFE, 0x19, 0xFE, 0xBE, 0xFD, 0x2B, 0xFD, 0x4C, 0xFC, 0xB7, 0xFB, 0xC6, 0xFB, 0xBC, 0xFC, 0x5E, 0xFE, 0x89, 0xFF, 0xF4, 0xFF, 0x81, 0xFF, 0xC6, 0xFE, 0xED, 0xFD, 0x61, 0xFD, 0x66, 0xFD, 0x06, 0xFD, 0xB7, 0xFC, 0xE9, 0xFB, 0xC5, 0xFA, 0x55, 0xFA, 0xDB, 0xF9, 0xB7, 0xF9, 0xE6, 0xF9, 0x1F, 0xFA, 0x9A, 0xFA, 0x37, 0xFB, 0xDF, 0xFB, 0xAA, 0xFC, 0xA7, 0xFD, 0x31, 0xFE, 0x6F, 0xFE, 0x29, 0xFE, 0x73, 0xFD, 0xA9, 0xFC, 0xA2, 0xFB, 0x19, 0xFB, 0x9E, 0xFA, 0x80, 0xFA, 0xF3, 0xFA, 0x8F, 0xFB, 0x0F, 0xFD, 0xBC, 0xFE, 0xBA, 0x00, 0x3C, 0x02, 0xC3, 0x02, 0x5B, 0x03, 0xFF, 0x02, 0xDF, 0x01, 0x47, 0x00, 0x6F, 0xFE, 0xD4, 0xFC, 0x6B, 0xFB, 0xC0, 0xFA, 0x88, 0xFA, 0xCC, 0xFA, 0x4E, 0xFB, 0x08, 0xFC, 0x09, 0xFD, 0xBF, 0xFD, 0x71, 0xFE, 0xEB, 0xFE, 0x7B, 0xFF, 0xD6, 0xFF, 0x86, 0xFF, 0x12, 0xFF, 0x62, 0xFE, 0x27, 0xFE, 0x83, 0xFE, 0x6E, 0xFF, 0x6D, 0x00, 0x0B, 0x01, 0x92, 0x01, 0x94, 0x01, 0xE5, 0x01, 0x7D, 0x02, 0x55, 0x03, 0x63, 0x04, 0x56, 0x04, 0xB8, 0x03, 0x20, 0x02, 0x1E, 0x00, 0xEA, 0xFE, 0xF0, 0xFD, 0xB8, 0xFD, 0xFA, 0xFD, 0x5E, 0xFE, 0xDB, 0xFE, 0x1E, 0xFF, 0x49, 0xFF, 0xF6, 0xFE, 0x6F, 0xFE, 0xC2, 0xFD, 0x0D, 0xFD, 0xB2, 0xFC, 0x86, 0xFC, 0xA8, 0xFC, 0xFF, 0xFC, 0x78, 0xFD, 0x4A, 0xFE, 0xA2, 0xFF, 0x4C, 0x01, 0xBE, 0x02, 0xE9, 0x03, 0x9B, 0x04, 0xD2, 0x04, 0xD7, 0x04, 0x31, 0x04, 0x3C, 0x03, 0x56, 0x02, 0xDA, 0x00, 0x73, 0xFF, 0x7A, 0xFE, 0xDB, 0xFD, 0xF1, 0xFD, 0x58, 0xFE, 0x35, 0xFF, 0x61, 0x00, 0xDA, 0x01, 0x82, 0x03, 0x27, 0x04, 0xBD, 0x03, 0x26, 0x02, 0x3A, 0x00, 0xF0, 0xFE, 0xB0, 0xFD, 0xF9, 0xFC, 0xA9, 0xFC, 0xAA, 0xFC, 0x23, 0xFD, 0x17, 0xFE, 0xB8, 0xFF, 0x44, 0x01, 0x99, 0x02, 0x7D, 0x03, 0xF3, 0x03, 0x3E, 0x04, 0x63, 0x04, 0xD0, 0x04, 0xE6, 0x04, 0xD8, 0x04, 0xBC, 0x04, 0x29, 0x04, 0xE1, 0x03, 0xD6, 0x03, 0x10, 0x04, 0xBC, 0x04, 0x4F, 0x05, 0x67, 0x05, 0xFC, 0x04, 0x02, 0x04, 0xF9, 0x02, 0x7F, 0x02, 0x03, 0x02, 0x9A, 0x01, 0x89, 0x01, 0x8F, 0x01, 0xBC, 0x01, 0xA3, 0x01, 0x81, 0x01, 0x66, 0x01, 0xF7, 0x00, 0x5D, 0x00, 0xDC, 0xFF, 0xC5, 0xFF, 0x9D, 0xFF, 0x3C, 0xFF, 0xCF, 0xFE, 0x6E, 0xFE, 0x30, 0xFE, 0x26, 0xFE, 0x4A, 0xFE, 0x39, 0xFE, 0x92, 0xFE, 0x02, 0xFF, 0x45, 0xFF, 0xCE, 0xFF, 0x11, 0x00, 0x40, 0x00, 0x19, 0x00, 0xE8, 0xFF, 0xF7, 0xFF, 0xA5, 0xFF, 0x49, 0xFF, 0x89, 0xFE, 0x98, 0xFD, 0x7A, 0xFC, 0x57, 0xFB, 0x0A, 0xFB, 0x5E, 0xFB, 0x8B, 0xFC, 0x24, 0xFE, 0x02, 0x00, 0xDB, 0x01, 0x02, 0x03, 0x9E, 0x03, 0x6A, 0x03, 0x3B, 0x03, 0xF9, 0x02, 0x0A, 0x02, 0xF8, 0x00, 0xEA, 0xFF, 0x84, 0xFF, 0x73, 0xFF, 0xE1, 0xFF, 0xDB, 0x00, 0xC1, 0x01, 0xBB, 0x02, 0xC9, 0x02, 0xDC, 0x01, 0x63, 0x00, 0xC7, 0xFE, 0x12, 0xFE, 0xF7, 0xFD, 0x46, 0xFE, 0xB5, 0xFE, 0x29, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0xB7, 0xFF, 0xE7, 0xFF, 0xD6, 0xFF, 0x68, 0xFF, 0xB1, 0xFE, 0x06, 0xFE, 0x70, 0xFD, 0x41, 0xFD, 0x6E, 0xFD, 0xA6, 0xFD, 0xFE, 0xFD, 0xB7, 0xFE, 0xCA, 0xFF, 0xD7, 0x00, 0x2F, 0x01, 0xBF, 0x00, 0x47, 0x00, 0xCD, 0xFF, 0x76, 0xFF, 0x75, 0xFF, 0x8E, 0xFF, 0xA1, 0xFF, 0x7D, 0xFF, 0x7D, 0xFF, 0x62, 0xFF, 0x25, 0xFF, 0xEE, 0xFE, 0x87, 0xFE, 0x8D, 0xFE, 0xFA, 0xFE, 0x2B, 0x00, 0xC5, 0x01, 0xDA, 0x02, 0xD0, 0x03, 0x57, 0x04, 0x92, 0x04, 0x64, 0x04, 0xFC, 0x03, 0x16, 0x04, 0xE7, 0x03, 0x97, 0x03, 0x29, 0x03, 0x9B, 0x02, 0x6C, 0x02, 0x97, 0x02, 0x15, 0x03, 0x76, 0x03, 0xC3, 0x03, 0xB2, 0x03, 0xA4, 0x03, 0xFC, 0x03, 0x2A, 0x04, 0x8D, 0x04, 0xBC, 0x04, 0xDF, 0x04, 0x20, 0x05, 0x4A, 0x05, 0xE1, 0x05, 0xEF, 0x05, 0x5A, 0x05, 0x71, 0x04, 0x3F, 0x03, 0x74, 0x02, 0x04, 0x02, 0xEE, 0x01, 0xFC, 0x01, 0xDE, 0x01, 0x79, 0x01, 0xF5, 0x00, 0x8D, 0x00, 0x3E, 0x00, 0xFC, 0xFF, 0x7E, 0xFF, 0x19, 0xFF, 0xF5, 0xFE, 0x91, 0xFF, 0x16, 0x01, 0xB9, 0x02, 0xA9, 0x04, 0xFD, 0x05, 0x93, 0x06, 0xA8, 0x06, 0xBE, 0x05, 0x89, 0x04, 0xC0, 0x02, 0xD1, 0x00, 0x23, 0xFF, 0xA2, 0xFD, 0xCD, 0xFC, 0x60, 0xFC, 0x7C, 0xFC, 0xB4, 0xFC, 0x18, 0xFD, 0xA0, 0xFD, 0xDF, 0xFD, 0x70, 0xFE, 0x03, 0xFF, 0xAC, 0xFF, 0xD1, 0xFF, 0x62, 0xFF, 0x35, 0xFF, 0xF7, 0xFE, 0x61, 0xFF, 0x16, 0x00, 0xA2, 0x00, 0xEF, 0x00, 0xEA, 0x00, 0xBF, 0x00, 0xB9, 0xFF, 0x0D, 0xFF, 0xB4, 0xFE, 0x77, 0xFE, 0x16, 0xFF, 0x5A, 0xFF, 0xDE, 0xFF, 0xA6, 0x00, 0x28, 0x01, 0x88, 0x01, 0x66, 0x01, 0x6D, 0x01, 0xB3, 0x01, 0x5F, 0x02, 0x32, 0x03, 0xDC, 0x03, 0x80, 0x04, 0xD9, 0x04, 0x8D, 0x05, 0xDB, 0x05, 0xC1, 0x05, 0x9F, 0x05, 0xB3, 0x04, 0xD7, 0x03, 0xF6, 0x02, 0x1A, 0x02, 0xBA, 0x01, 0x87, 0x01, 0x22, 0x02, 0x41, 0x03, 0x4A, 0x04, 0xCD, 0x04, 0x8C, 0x04, 0xE3, 0x03, 0xCA, 0x02, 0xA2, 0x01, 0x9C, 0x00, 0xF0, 0xFF, 0xA7, 0xFF, 0x6E, 0xFF, 0xB5, 0xFF, 0x20, 0x00, 0xA7, 0x00, 0xC8, 0x01, 0xA5, 0x02, 0xCC, 0x02, 0x52, 0x02, 0x25, 0x01, 0x5B, 0xFF, 0x43, 0xFD, 0x8F, 0xFB, 0x76, 0xFA, 0xE4, 0xF9, 0xB2, 0xF9, 0xD3, 0xF9, 0x62, 0xFA, 0x24, 0xFB, 0x24, 0xFC, 0x11, 0xFD, 0xA5, 0xFD, 0xE6, 0xFD, 0x88, 0xFD, 0xAB, 0xFC, 0x50, 0xFB, 0xE9, 0xF9, 0xE5, 0xF8, 0xA6, 0xF8, 0xEE, 0xF9, 0xCB, 0xFB, 0x6F, 0xFD, 0xB6, 0xFE, 0x24, 0xFF, 0x21, 0xFF, 0xFB, 0xFE, 0xB4, 0xFE, 0x65, 0xFE, 0xD8, 0xFD, 0xDF, 0xFC, 0xFF, 0xFB, 0x58, 0xFB, 0xD6, 0xFA, 0x16, 0xFB, 0x96, 0xFB, 0x23, 0xFC, 0x02, 0xFD, 0xD5, 0xFD, 0xA0, 0xFE, 0xFF, 0xFE, 0x58, 0xFF, 0x13, 0x00, 0xBD, 0x00, 0x5C, 0x01, 0xB3, 0x01, 0x75, 0x01, 0xE3, 0x00, 0x2C, 0x00, 0x5A, 0xFF, 0xE1, 0xFE, 0xB6, 0xFE, 0xB6, 0xFE, 0xF7, 0xFE, 0xD1, 0xFE, 0x8F, 0xFE, 0x5D, 0xFE, 0x54, 0xFE, 0xCE, 0xFE, 0x51, 0xFF, 0x3C, 0x00, 0xBD, 0x00, 0x6F, 0x00, 0x26, 0x00, 0xBB, 0xFF, 0xBC, 0xFF, 0x00, 0x00, 0x81, 0x00, 0x84, 0x01, 0xC2, 0x02, 0xF6, 0x03, 0x95, 0x04, 0x45, 0x05, 0xD6, 0x05, 0xF0, 0x05, 0x81, 0x05, 0x2F, 0x04, 0xF4, 0x02, 0x7D, 0x01, 0x3D, 0x00, 0xB9, 0xFF, 0x0A, 0xFF, 0x93, 0xFE, 0x60, 0xFE, 0x5E, 0xFE, 0x4D, 0xFE, 0x36, 0xFE, 0x53, 0xFE, 0x59, 0xFE, 0xC5, 0xFE, 0x1F, 0xFF, 0x3C, 0xFF, 0x62, 0xFF, 0x41, 0xFF, 0x4B, 0xFF, 0x24, 0xFF, 0x82, 0xFE, 0x27, 0xFE, 0x46, 0xFE, 0xCD, 0xFE, 0x9F, 0xFF, 0xFC, 0xFF, 0xD6, 0xFF, 0xDD, 0xFF, 0xB5, 0xFF, 0x99, 0xFF, 0xCB, 0xFF, 0xE7, 0xFF, 0x28, 0x00, 0x35, 0x00, 0xD3, 0xFF, 0x4D, 0xFF, 0xC5, 0xFE, 0x8D, 0xFE, 0xDC, 0xFE, 0x8B, 0xFF, 0x47, 0x00, 0xC4, 0x00, 0xBB, 0x00, 0x9C, 0x00, 0x63, 0x00, 0x03, 0x00, 0xF9, 0xFF, 0x2E, 0x00, 0xCC, 0x00, 0x92, 0x01, 0x6A, 0x02, 0x65, 0x03, 0x16, 0x04, 0xC9, 0x04, 0x25, 0x05, 0x03, 0x05, 0xB3, 0x04, 0x8A, 0x04, 0xC6, 0x04, 0xEA, 0x04, 0x13, 0x05, 0x23, 0x05, 0xB2, 0x04, 0xCE, 0x03, 0xC3, 0x02, 0xFC, 0x01, 0xA9, 0x01, 0xFA, 0x01, 0x91, 0x02, 0x99, 0x03, 0xC8, 0x04, 0x64, 0x05, 0xE4, 0x05, 0xF4, 0x05, 0xAD, 0x05, 0x1F, 0x05, 0xEE, 0x03, 0x9A, 0x02, 0x5F, 0x01, 0x63, 0x00, 0x82, 0xFF, 0xF6, 0xFE, 0x8A, 0xFE, 0x47, 0xFE, 0xB7, 0xFE, 0x28, 0xFF, 0xF0, 0xFF, 0xEC, 0x00, 0x9C, 0x01, 0x0B, 0x02, 0xE2, 0x01, 0xC5, 0x01, 0xA1, 0x01, 0xA1, 0x01, 0xA6, 0x01, 0x75, 0x01, 0xB3, 0x01, 0xCA, 0x01, 0x11, 0x02, 0x7F, 0x02, 0x07, 0x03, 0xD6, 0x03, 0xD1, 0x03, 0x96, 0x03, 0x31, 0x03, 0x67, 0x02, 0x9E, 0x01, 0x49, 0x00, 0xAC, 0xFE, 0x81, 0xFD, 0x33, 0xFD, 0x83, 0xFD, 0x56, 0xFE, 0x3E, 0xFF, 0x9D, 0xFF, 0xE5, 0xFF, 0xA2, 0xFF, 0x2B, 0xFF, 0xE2, 0xFE, 0x28, 0xFE, 0x7F, 0xFD, 0xCF, 0xFC, 0xEE, 0xFB, 0x36, 0xFB, 0xF9, 0xFA, 0x3F, 0xFB, 0xCA, 0xFB, 0xCE, 0xFC, 0x96, 0xFD, 0x04, 0xFE, 0x70, 0xFE, 0x5F, 0xFE, 0x56, 0xFE, 0x85, 0xFE, 0xC8, 0xFE, 0x99, 0xFF, 0x87, 0x00, 0x2D, 0x01, 0xB0, 0x01, 0xB6, 0x01, 0x46, 0x01, 0xC2, 0x00, 0x94, 0x00, 0x29, 0x01, 0x44, 0x02, 0xCB, 0x03, 0x99, 0x05, 0x0C, 0x07, 0x1D, 0x08, 0xCC, 0x08, 0x07, 0x09, 0xE5, 0x08, 0x5A, 0x08, 0xAE, 0x07, 0xE7, 0x06, 0xC6, 0x05, 0xF4, 0x04, 0x08, 0x05, 0xDF, 0x05, 0x51, 0x07, 0x7D, 0x08, 0x22, 0x09, 0x5A, 0x09, 0xB1, 0x08, 0xC2, 0x07, 0x82, 0x06, 0xF4, 0x04, 0xC5, 0x03, 0xDA, 0x02, 0x5D, 0x02, 0x30, 0x02, 0x5A, 0x02, 0xB4, 0x02, 0xC0, 0x02, 0xE6, 0x02, 0x0F, 0x03, 0x37, 0x03, 0x07, 0x03, 0x14, 0x02, 0x9F, 0x00, 0xF5, 0xFE, 0xE0, 0xFD, 0x68, 0xFD, 0x5E, 0xFD, 0xCC, 0xFD, 0x37, 0xFE, 0xAA, 0xFE, 0x20, 0xFF, 0xC0, 0xFF, 0x7E, 0x00, 0xF9, 0x00, 0x1D, 0x01, 0x98, 0x00, 0xA4, 0xFF, 0x9F, 0xFE, 0x92, 0xFD, 0x0E, 0xFD, 0x2C, 0xFD, 0x36, 0xFD, 0x45, 0xFD, 0x69, 0xFD, 0x80, 0xFD, 0xFA, 0xFD, 0x91, 0xFE, 0x3F, 0xFF, 0xE8, 0xFF, 0xD1, 0xFF, 0x4E, 0xFF, 0x65, 0xFE, 0x7A, 0xFD, 0x59, 0xFD, 0xBF, 0xFD, 0x4D, 0xFE, 0xE5, 0xFE, 0xA9, 0xFF, 0x6B, 0x00, 0x30, 0x01, 0x03, 0x02, 0x7B, 0x02, 0xF9, 0x02, 0x65, 0x03, 0x53, 0x03, 0x17, 0x03, 0xD1, 0x02, 0xD9, 0x02, 0x68, 0x03, 0x38, 0x04, 0x49, 0x05, 0x19, 0x06, 0x3F, 0x06, 0x30, 0x06, 0xC2, 0x05, 0x1B, 0x05, 0x7D, 0x04, 0xBE, 0x03, 0x66, 0x03, 0x7E, 0x03, 0x72, 0x03, 0xEB, 0x02, 0x2E, 0x02, 0xA3, 0x01, 0xB6, 0x01, 0xD4, 0x02, 0x14, 0x04, 0x49, 0x05, 0x82, 0x06, 0x23, 0x07, 0x86, 0x07, 0x52, 0x07, 0x21, 0x07, 0x55, 0x07, 0x4F, 0x07, 0x65, 0x07, 0x15, 0x07, 0xA2, 0x06, 0x45, 0x06, 0xD2, 0x05, 0x76, 0x05, 0x82, 0x04, 0x6D, 0x03, 0x8D, 0x02, 0xF9, 0x01, 0x8D, 0x01, 0xE1, 0x00, 0x52, 0x00, 0x94, 0xFF, 0x15, 0xFF, 0x15, 0xFF, 0x0A, 0xFF, 0x00, 0xFF, 0xA8, 0xFE, 0x2D, 0xFE, 0xB5, 0xFD, 0x5F, 0xFD, 0x4F, 0xFD, 0x74, 0xFD, 0xC9, 0xFD, 0x1C, 0xFE, 0x63, 0xFE, 0xA2, 0xFE, 0xFF, 0xFE, 0x2D, 0xFF, 0x04, 0xFF, 0x12, 0xFF, 0x4A, 0xFF, 0x38, 0xFF, 0xA5, 0xFE, 0x3B, 0xFE, 0x30, 0xFE, 0x81, 0xFE, 0x03, 0xFF, 0x36, 0xFF, 0xDD, 0xFF, 0x9F, 0x00, 0x28, 0x01, 0xA2, 0x01, 0xA1, 0x01, 0xEE, 0x01, 0x6A, 0x02, 0x2D, 0x03, 0xEC, 0x03, 0xFD, 0x03, 0xF0, 0x03, 0x35, 0x03, 0x21, 0x02, 0xFA, 0x00, 0xBF, 0xFF, 0x40, 0xFF, 0x18, 0xFF, 0x92, 0xFF, 0x6E, 0x00, 0x17, 0x01, 0x22, 0x02, 0x64, 0x03, 0x9E, 0x04, 0x67, 0x05, 0x98, 0x05, 0x4E, 0x05, 0xA3, 0x04, 0x1E, 0x04, 0xC5, 0x03, 0xA6, 0x03, 0xD2, 0x03, 0xF9, 0x03, 0xB7, 0x03, 0x29, 0x03, 0x82, 0x02, 0xB0, 0x01, 0x1B, 0x01, 0xC0, 0x00, 0x6C, 0x00, 0x7D, 0x00, 0x91, 0x00, 0x99, 0x00, 0x0D, 0x01, 0xD9, 0x01, 0xEB, 0x02, 0xD7, 0x03, 0x3B, 0x04, 0x22, 0x04, 0x67, 0x03, 0x81, 0x02, 0x86, 0x01, 0x79, 0x00, 0xFA, 0xFF, 0xAB, 0xFF, 0x75, 0xFF, 0x14, 0xFF, 0x90, 0xFE, 0x70, 0xFE, 0x55, 0xFE, 0xD0, 0xFE, 0xC4, 0xFF, 0x7D, 0x00, 0x20, 0x01, 0x28, 0x01, 0x9B, 0x00, 0xCC, 0xFF, 0xD7, 0xFE, 0x0B, 0xFE, 0x7C, 0xFD, 0x11, 0xFD, 0x72, 0xFC, 0xE5, 0xFB, 0xC7, 0xFB, 0x48, 0xFC, 0x27, 0xFD, 0xF7, 0xFD, 0x86, 0xFE, 0x6B, 0xFE, 0xFC, 0xFD, 0x74, 0xFD, 0x1A, 0xFD, 0x31, 0xFD, 0x2D, 0xFD, 0x00, 0xFD, 0xA8, 0xFC, 0x33, 0xFC, 0xC8, 0xFB, 0x74, 0xFB, 0x5A, 0xFB, 0x2C, 0xFB, 0x13, 0xFB, 0xCF, 0xFA, 0x74, 0xFA, 0x9E, 0xFA, 0x0E, 0xFB, 0xAC, 0xFB, 0x3B, 0xFC, 0xA4, 0xFC, 0xE7, 0xFC, 0xF5, 0xFC, 0x34, 0xFD, 0x92, 0xFD, 0x12, 0xFE, 0xB8, 0xFE, 0x3A, 0xFF, 0x88, 0xFF, 0x99, 0xFF, 0x57, 0xFF, 0x95, 0xFE, 0xC2, 0xFD, 0x32, 0xFD, 0x30, 0xFD, 0xF0, 0xFD, 0xD5, 0xFE, 0xB3, 0xFF, 0x3F, 0x00, 0x20, 0x00, 0xC8, 0xFF, 0x31, 0xFF, 0x61, 0xFE, 0x74, 0xFD, 0x42, 0xFC, 0x49, 0xFB, 0xF5, 0xFA, 0xE9, 0xFA, 0x16, 0xFB, 0x50, 0xFB, 0x2F, 0xFB, 0xCB, 0xFA, 0x1D, 0xFA, 0x1E, 0xF9, 0x65, 0xF8, 0x89, 0xF8, 0x4F, 0xF9, 0x17, 0xFA, 0x0B, 0xFB, 0x1F, 0xFC, 0xF6, 0xFC, 0x98, 0xFD, 0xE7, 0xFD, 0x01, 0xFE, 0xDF, 0xFD, 0x9C, 0xFD, 0x7E, 0xFD, 0x26, 0xFD, 0x3A, 0xFD, 0xF6, 0xFD, 0xBD, 0xFE, 0x6C, 0xFF, 0x23, 0xFF, 0x4B, 0xFE, 0x8A, 0xFD, 0xE5, 0xFC, 0x23, 0xFD, 0x79, 0xFD, 0xAA, 0xFD, 0x97, 0xFD, 0x17, 0xFD, 0x22, 0xFD, 0x0E, 0xFD, 0x3B, 0xFD, 0xE8, 0xFD, 0x71, 0xFE, 0x5D, 0xFF, 0x42, 0x00, 0x1B, 0x01, 0xC2, 0x01, 0x22, 0x02, 0x52, 0x02, 0xE0, 0x01, 0x7D, 0x01, 0xD1, 0x00, 0x03, 0x00, 0x23, 0xFF, 0xE9, 0xFD, 0x5D, 0xFD, 0xF1, 0xFC, 0x12, 0xFD, 0xEB, 0xFD, 0x83, 0xFE, 0x5B, 0xFF, 0xB6, 0xFF, 0x57, 0xFF, 0x62, 0xFE, 0x07, 0xFD, 0xFA, 0xFB, 0x45, 0xFB, 0x45, 0xFB, 0xC3, 0xFB, 0x64, 0xFC, 0x00, 0xFD, 0x7A, 0xFD, 0xB8, 0xFD, 0x91, 0xFD, 0x97, 0xFD, 0xC3, 0xFD, 0xF4, 0xFD, 0xE4, 0xFD, 0x49, 0xFD, 0x72, 0xFC, 0x8B, 0xFB, 0x0F, 0xFB, 0x12, 0xFB, 0xC0, 0xFB, 0xCB, 0xFC, 0xB2, 0xFD, 0x94, 0xFE, 0x02, 0xFF, 0x3B, 0xFF, 0x63, 0xFF, 0xA6, 0xFF, 0x52, 0x00, 0xAD, 0x00, 0xA5, 0x00, 0x4D, 0x00, 0xE3, 0xFF, 0x9A, 0xFF, 0x36, 0xFF, 0xCF, 0xFE, 0x53, 0xFE, 0x13, 0xFE, 0xDF, 0xFD, 0xAB, 0xFD, 0xF1, 0xFD, 0x90, 0xFE, 0x8F, 0xFF, 0xB4, 0x00, 0x6B, 0x01, 0x73, 0x01, 0x52, 0x01, 0x50, 0x01, 0x25, 0x01, 0x1B, 0x01, 0xE3, 0x00, 0x44, 0x00, 0x00, 0x00, 0x30, 0x00, 0x83, 0x00, 0x24, 0x01, 0x70, 0x01, 0xF0, 0x00, 0xA5, 0x00, 0x52, 0x00, 0x09, 0x00, 0x44, 0x00, 0x85, 0x00, 0x0B, 0x01, 0x7F, 0x01, 0x34, 0x02, 0x30, 0x03, 0xB1, 0x03, 0x12, 0x04, 0xCA, 0x03, 0x12, 0x03, 0x39, 0x02, 0x6C, 0x01, 0x33, 0x01, 0x1E, 0x01, 0x5A, 0x01, 0x48, 0x01, 0xEC, 0x00, 0x9A, 0x00, 0xEC, 0xFF, 0xD4, 0xFF, 0xD3, 0xFF, 0x77, 0xFF, 0x3A, 0xFF, 0x26, 0xFF, 0x6D, 0xFF, 0x9F, 0xFF, 0xD8, 0xFF, 0xD6, 0xFF, 0x85, 0xFF, 0x02, 0xFF, 0xF7, 0xFD, 0xF3, 0xFC, 0xC5, 0xFB, 0x8D, 0xFA, 0xBC, 0xF9, 0x3F, 0xF9, 0x42, 0xF9, 0x96, 0xF9, 0x68, 0xFA, 0x50, 0xFB, 0x14, 0xFC, 0x30, 0xFD, 0x1C, 0xFE, 0xFA, 0xFE, 0x9E, 0xFF, 0x4F, 0xFF, 0x4F, 0xFE, 0x41, 0xFD, 0x73, 0xFC, 0x8B, 0xFB, 0xBA, 0xFA, 0x61, 0xFA, 0x4A, 0xFA, 0x6A, 0xFA, 0xA9, 0xFA, 0x2B, 0xFB, 0x0D, 0xFC, 0x09, 0xFD, 0xF6, 0xFD, 0x8F, 0xFE, 0xBC, 0xFE, 0xA3, 0xFE, 0x39, 0xFE, 0xAA, 0xFD, 0x53, 0xFD, 0x58, 0xFD, 0x7F, 0xFD, 0x89, 0xFD, 0xB9, 0xFD, 0xBC, 0xFD, 0x5B, 0xFD, 0x93, 0xFC, 0x58, 0xFB, 0xA9, 0xFA, 0x36, 0xFA, 0x52, 0xF9, 0xCD, 0xF8, 0xD2, 0xF8, 0x64, 0xF9, 0x2C, 0xFA, 0xC7, 0xFA, 0x2E, 0xFB, 0x26, 0xFB, 0x3D, 0xFB, 0x33, 0xFB, 0x17, 0xFB, 0x98, 0xFB, 0x3F, 0xFC, 0x07, 0xFD, 0x94, 0xFD, 0x83, 0xFD, 0x55, 0xFD, 0xF5, 0xFC, 0x60, 0xFC, 0xA6, 0xFB, 0x02, 0xFB, 0x8C, 0xFA, 0x94, 0xFA, 0x2E, 0xFB, 0xED, 0xFB, 0x25, 0xFD, 0x66, 0xFE, 0x69, 0xFF, 0x8A, 0x00, 0x36, 0x01, 0x45, 0x01, 0xC5, 0x00, 0xF8, 0xFF, 0x5D, 0xFF, 0x14, 0xFF, 0x0A, 0xFF, 0xF0, 0xFE, 0xDA, 0xFE, 0xAF, 0xFE, 0x53, 0xFE, 0x01, 0xFE, 0xD5, 0xFD, 0xF2, 0xFD, 0x18, 0xFE, 0xF3, 0xFD, 0x98, 0xFD, 0x59, 0xFD, 0x35, 0xFD, 0x51, 0xFD, 0xA6, 0xFD, 0x11, 0xFE, 0xF9, 0xFE, 0xF8, 0xFF, 0x2A, 0x01, 0x52, 0x02, 0x9E, 0x02, 0x81, 0x02, 0x74, 0x01, 0xFB, 0xFF, 0xDB, 0xFE, 0xB9, 0xFD, 0x48, 0xFD, 0x0E, 0xFD, 0xD8, 0xFC, 0xE7, 0xFC, 0x20, 0xFD, 0x80, 0xFD, 0x38, 0xFD, 0xA1, 0xFC, 0xFE, 0xFB, 0x70, 0xFB, 0x5F, 0xFB, 0x61, 0xFB, 0x89, 0xFB, 0xFF, 0xFB, 0xBB, 0xFC, 0x10, 0xFD, 0x31, 0xFD, 0x97, 0xFD, 0xD7, 0xFD, 0x69, 0xFE, 0xE0, 0xFE, 0x50, 0xFF, 0x12, 0x00, 0xC5, 0x00, 0x76, 0x01, 0x4D, 0x01, 0xFF, 0x00, 0x27, 0x01, 0x84, 0x01, 0x4D, 0x02, 0x9F, 0x02, 0xA5, 0x02, 0x85, 0x02, 0xA3, 0x02, 0x58, 0x03, 0xEE, 0x03, 0xA2, 0x04, 0xF4, 0x04, 0xCB, 0x04, 0x65, 0x04, 0x98, 0x03, 0xD6, 0x02, 0xCA, 0x01, 0xBB, 0x00, 0x2E, 0x00, 0x15, 0x00, 0x6F, 0x00, 0x02, 0x01, 0xC5, 0x01, 0x96, 0x02, 0x70, 0x03, 0x29, 0x04, 0x72, 0x04, 0x84, 0x04, 0x71, 0x04, 0x48, 0x04, 0x02, 0x04, 0xAB, 0x03, 0x85, 0x03, 0x8C, 0x03, 0x66, 0x03, 0xF7, 0x02, 0x5A, 0x02, 0x09, 0x02, 0x38, 0x02, 0x90, 0x02, 0x82, 0x03, 0x82, 0x04, 0x0A, 0x05, 0x5F, 0x05, 0x2E, 0x05, 0x02, 0x05, 0xA6, 0x04, 0xFA, 0x03, 0x33, 0x03, 0x01, 0x02, 0xFD, 0x00, 0xDC, 0xFF, 0xFB, 0xFE, 0x96, 0xFE, 0x31, 0xFE, 0x3C, 0xFE, 0xD0, 0xFD, 0xCF, 0xFC, 0xB5, 0xFB, 0xA1, 0xFA, 0xC2, 0xF9, 0xA5, 0xF8, 0xA0, 0xF7, 0x8C, 0xF6, 0xCF, 0xF5, 0x0F, 0xF6, 0x13, 0xF7, 0x97, 0xF8, 0x8B, 0xF9, 0x81, 0xFA, 0xC7, 0xFB, 0xF7, 0xFC, 0x99, 0xFE, 0xC8, 0xFF, 0x4A, 0x00, 0x05, 0x00, 0x8E, 0xFE, 0xCC, 0xFC, 0x8F, 0xFB, 0xE5, 0xFA, 0xB0, 0xFA, 0xF5, 0xFA, 0x07, 0xFB, 0xFA, 0xFA, 0x3B, 0xFB, 0x5D, 0xFB, 0xDF, 0xFB, 0x94, 0xFC, 0x20, 0xFD, 0xBF, 0xFD, 0xDD, 0xFD, 0xA4, 0xFD, 0xBC, 0xFD, 0x10, 0xFE, 0x5E, 0xFE, 0xB2, 0xFE, 0xE0, 0xFE, 0xDC, 0xFE, 0xD1, 0xFE, 0xF5, 0xFE, 0xD2, 0xFF, 0x07, 0x01, 0x5A, 0x02, 0xEC, 0x03, 0x4F, 0x05, 0x82, 0x06, 0x2F, 0x07, 0x0A, 0x07, 0x63, 0x06, 0x5B, 0x05, 0xF6, 0x03, 0x92, 0x02, 0x84, 0x01, 0xC3, 0x00, 0xB2, 0x00, 0x24, 0x01, 0xDD, 0x01, 0xF8, 0x02, 0xB8, 0x03, 0x21, 0x04, 0x18, 0x04, 0x97, 0x03, 0x5E, 0x03, 0x5E, 0x03, 0xC8, 0x03, 0x31, 0x04, 0x57, 0x04, 0x20, 0x04, 0x45, 0x03, 0x98, 0x02, 0x2F, 0x02, 0xB9, 0x01, 0x5D, 0x01, 0x1F, 0x01, 0xCF, 0x00, 0x81, 0x00, 0xA6, 0x00, 0x6A, 0x00, 0xED, 0xFF, 0x7A, 0xFF, 0x78, 0xFE, 0xCC, 0xFD, 0x35, 0xFD, 0x91, 0xFC, 0x47, 0xFC, 0xD9, 0xFB, 0xB3, 0xFB, 0x64, 0xFB, 0xC1, 0xFA, 0x47, 0xFA, 0xFA, 0xF9, 0x51, 0xFA, 0xF4, 0xFA, 0x88, 0xFB, 0xC8, 0xFB, 0xC9, 0xFB, 0x1C, 0xFC, 0x6C, 0xFC, 0xDE, 0xFC, 0x5E, 0xFD, 0x88, 0xFD, 0x93, 0xFD, 0x5B, 0xFD, 0x3A, 0xFD, 0x98, 0xFD, 0x0F, 0xFE, 0x92, 0xFE, 0x1E, 0xFF, 0x5C, 0xFF, 0x90, 0xFF, 0xA7, 0xFF, 0xBE, 0xFF, 0x69, 0x00, 0x3B, 0x01, 0x76, 0x02, 0xC4, 0x03, 0x7C, 0x04, 0x22, 0x05, 0x56, 0x05, 0x74, 0x05, 0xEB, 0x05, 0x94, 0x06, 0x42, 0x07, 0x5D, 0x07, 0x27, 0x07, 0xE2, 0x06, 0xE4, 0x06, 0x43, 0x07, 0xC4, 0x07, 0x9F, 0x08, 0x9F, 0x09, 0xE7, 0x0A, 0x22, 0x0C, 0x14, 0x0D, 0xB5, 0x0D, 0xDA, 0x0D, 0xB6, 0x0D, 0xB3, 0x0C, 0x7C, 0x0B, 0x2E, 0x0A, 0x7F, 0x08, 0xAA, 0x07, 0x39, 0x07, 0x34, 0x07, 0xCB, 0x07, 0x5E, 0x08, 0x07, 0x09, 0x46, 0x09, 0x1A, 0x09, 0x6F, 0x08, 0x82, 0x07, 0xEA, 0x06, 0x8B, 0x06, 0x3B, 0x06, 0x91, 0x05, 0xED, 0x04, 0x8B, 0x04, 0x4D, 0x04, 0x51, 0x04, 0x2A, 0x04, 0xDA, 0x03, 0xA1, 0x03, 0x11, 0x03, 0xBF, 0x01, 0x58, 0x00, 0x43, 0xFF, 0x7E, 0xFE, 0x46, 0xFE, 0xF0, 0xFD, 0xBF, 0xFD, 0xE8, 0xFD, 0x45, 0xFE, 0xF8, 0xFE, 0x4C, 0xFF, 0xB6, 0xFF, 0x2E, 0x00, 0x76, 0x00, 0x04, 0x01, 0x63, 0x01, 0xC9, 0x01, 0x01, 0x02, 0xD5, 0x01, 0x76, 0x01, 0xBF, 0x00, 0x0F, 0x00, 0x99, 0xFF, 0xB5, 0xFF, 0x70, 0x00, 0xB2, 0x01, 0x41, 0x03, 0x79, 0x04, 0x64, 0x05, 0xCF, 0x05, 0xE1, 0x05, 0xA7, 0x05, 0xEA, 0x04, 0x67, 0x04, 0x0A, 0x04, 0xD7, 0x03, 0xDE, 0x03, 0x58, 0x03, 0xD2, 0x02, 0xBA, 0x02, 0xE4, 0x02, 0xA3, 0x03, 0x91, 0x04, 0xBF, 0x05, 0x18, 0x07, 0xA0, 0x07, 0x6C, 0x07, 0xB6, 0x06, 0xC2, 0x05, 0x0B, 0x05, 0x97, 0x04, 0x9D, 0x04, 0xCC, 0x04, 0xF8, 0x04, 0x45, 0x05, 0xAF, 0x05, 0x4F, 0x06, 0xAC, 0x06, 0xB1, 0x06, 0x37, 0x06, 0x69, 0x05, 0xB2, 0x04, 0xA2, 0x03, 0xDA, 0x02, 0xB5, 0x02, 0xDB, 0x02, 0x6B, 0x03, 0x17, 0x04, 0xBA, 0x04, 0x3B, 0x05, 0x40, 0x05, 0x9D, 0x04, 0xBD, 0x03, 0xED, 0x02, 0x40, 0x02, 0x22, 0x02, 0xF7, 0x01, 0x87, 0x01, 0x0B, 0x01, 0x5E, 0x00, 0x02, 0x00, 0xE5, 0xFF, 0x0D, 0x00, 0x9F, 0x00, 0x40, 0x01, 0xD0, 0x01, 0x34, 0x02, 0x67, 0x02, 0x6E, 0x02, 0x50, 0x02, 0xEA, 0x01, 0x6A, 0x01, 0x0D, 0x01, 0x7C, 0x00, 0x1D, 0x00, 0x3D, 0x00, 0x87, 0x00, 0xF7, 0x00, 0x80, 0x01, 0xC5, 0x01, 0xB6, 0x01, 0xB7, 0x01, 0x8C, 0x01, 0x43, 0x01, 0xD3, 0x00, 0x16, 0x00, 0x9C, 0xFF, 0x32, 0xFF, 0xE2, 0xFE, 0xAC, 0xFE, 0x65, 0xFE, 0x6F, 0xFE, 0x6C, 0xFE, 0xA1, 0xFE, 0xEA, 0xFE, 0xF4, 0xFE, 0x34, 0xFF, 0x4F, 0xFF, 0x7F, 0xFF, 0xEB, 0xFF, 0x42, 0x00, 0x6F, 0x00, 0x51, 0x00, 0x44, 0x00, 0x18, 0x00, 0x12, 0x00, 0x54, 0x00, 0x75, 0x00, 0xA9, 0x00, 0x84, 0x00, 0x42, 0x00, 0x49, 0x00, 0x4E, 0x00, 0xC1, 0x00, 0x55, 0x01, 0x96, 0x01, 0x9C, 0x01, 0x7D, 0x01, 0x40, 0x01, 0xCD, 0x00, 0x5F, 0x00, 0xF3, 0xFF, 0x06, 0x00, 0xE1, 0x00, 0x08, 0x02, 0x77, 0x03, 0x90, 0x04, 0x79, 0x05, 0x6E, 0x06, 0xDE, 0x06, 0x1B, 0x07, 0x06, 0x07, 0xE2, 0x06, 0x12, 0x07, 0xE5, 0x06, 0x63, 0x06, 0x06, 0x06, 0x27, 0x06, 0xAE, 0x06, 0xA1, 0x07, 0x8C, 0x08, 0xA2, 0x08, 0x68, 0x08, 0x9F, 0x07, 0x6A, 0x06, 0x6C, 0x05, 0x61, 0x04, 0xF4, 0x03, 0xDC, 0x03, 0xB1, 0x03, 0xC4, 0x03, 0xF7, 0x03, 0x7C, 0x04, 0xFE, 0x04, 0x78, 0x05, 0xD6, 0x05, 0x25, 0x06, 0x8A, 0x06, 0x66, 0x06, 0x33, 0x06, 0x97, 0x05, 0x4E, 0x04, 0x37, 0x03, 0x15, 0x02, 0x57, 0x01, 0xD1, 0x00, 0xE7, 0xFF, 0xFD, 0xFE, 0x2E, 0xFE, 0xFD, 0xFD, 0xA5, 0xFE, 0xD9, 0xFF, 0x56, 0x01, 0x63, 0x02, 0xEE, 0x02, 0x17, 0x03, 0x85, 0x02, 0x4C, 0x01, 0x44, 0x00, 0x7F, 0xFF, 0x72, 0xFE, 0x51, 0xFD, 0xBF, 0xFB, 0xDE, 0xF9, 0xFA, 0xF8, 0x07, 0xF9, 0xD5, 0xF9, 0x5A, 0xFB, 0xDA, 0xFC, 0x2D, 0xFE, 0x10, 0xFF, 0x51, 0xFF, 0xFB, 0xFE, 0x4E, 0xFE, 0xD8, 0xFD, 0x5E, 0xFD, 0x50, 0xFD, 0xE4, 0xFD, 0x81, 0xFE, 0x65, 0xFF, 0x7C, 0x00, 0xDB, 0x01, 0xDB, 0x02, 0x11, 0x03, 0x43, 0x03, 0x2B, 0x03, 0x2E, 0x03, 0x66, 0x03, 0x66, 0x03, 0x7D, 0x03, 0x7D, 0x03, 0xEB, 0x03, 0xC2, 0x04, 0x57, 0x05, 0x73, 0x05, 0xE4, 0x04, 0x18, 0x04, 0x26, 0x03, 0x41, 0x02, 0x8A, 0x01, 0x33, 0x01, 0x7C, 0x01, 0xD2, 0x01, 0x2D, 0x02, 0x06, 0x02, 0x2B, 0x01, 0x48, 0x00, 0x4B, 0xFF, 0x9F, 0xFE, 0x46, 0xFE, 0x37, 0xFE, 0xCB, 0xFE, 0x27, 0xFF, 0x45, 0xFF, 0x4E, 0xFF, 0x3E, 0xFF, 0xE1, 0xFF, 0xA8, 0x00, 0xE7, 0x00, 0xC3, 0x00, 0x32, 0x00, 0x89, 0xFF, 0xC1, 0xFE, 0x12, 0xFE, 0xAD, 0xFD, 0x3A, 0xFD, 0xB2, 0xFC, 0xBB, 0xFB, 0xD6, 0xFA, 0x78, 0xFA, 0x60, 0xFA, 0x99, 0xFA, 0x61, 0xFA, 0xF5, 0xF9, 0x7C, 0xF9, 0xB5, 0xF8, 0x08, 0xF8, 0x17, 0xF7, 0xBC, 0xF6, 0x04, 0xF7, 0x38, 0xF7, 0x8B, 0xF7, 0x81, 0xF7, 0x9D, 0xF7, 0xBB, 0xF7, 0x81, 0xF7, 0x7D, 0xF7, 0x4D, 0xF7, 0x82, 0xF7, 0x2F, 0xF8, 0xEA, 0xF8, 0xE9, 0xF9, 0xE5, 0xFA, 0xD2, 0xFB, 0x83, 0xFC, 0xD8, 0xFC, 0x1F, 0xFD, 0x75, 0xFD, 0xE0, 0xFD, 0x67, 0xFE, 0xDD, 0xFE, 0x0A, 0xFF, 0x14, 0xFF, 0xB4, 0xFE, 0x2B, 0xFE, 0xDD, 0xFD, 0x8D, 0xFD, 0x7E, 0xFD, 0x94, 0xFD, 0xC0, 0xFD, 0x40, 0xFE, 0xE0, 0xFE, 0x73, 0xFF, 0xFE, 0xFF, 0x22, 0x00, 0xDE, 0xFF, 0x04, 0x00, 0x0C, 0x00, 0xFA, 0xFF, 0x5B, 0x00, 0xD9, 0x00, 0xF4, 0x01, 0xFE, 0x02, 0xA9, 0x03, 0x21, 0x04, 0xA6, 0x03, 0xE8, 0x02, 0xF4, 0x01, 0xE9, 0x00, 0x6D, 0x00, 0x39, 0x00, 0x38, 0x00, 0x09, 0x00, 0x15, 0x00, 0x64, 0x00, 0xC7, 0x00, 0x7F, 0x01, 0xE1, 0x01, 0x4A, 0x02, 0x90, 0x02, 0x5F, 0x02, 0x55, 0x02, 0x47, 0x02, 0x51, 0x02, 0x3E, 0x02, 0xE3, 0x01, 0x59, 0x01, 0x9A, 0x00, 0x18, 0x00, 0xD4, 0xFF, 0xE1, 0xFF, 0x1F, 0x00, 0x43, 0x00, 0x48, 0x00, 0x24, 0x00, 0xEF, 0xFF, 0x97, 0xFF, 0x64, 0xFF, 0x6B, 0xFF, 0x87, 0xFF, 0x89, 0xFF, 0x10, 0xFF, 0x80, 0xFE, 0xA3, 0xFD, 0x93, 0xFC, 0xAC, 0xFB, 0xD6, 0xFA, 0xC3, 0xFA, 0xFF, 0xFA, 0x62, 0xFB, 0x21, 0xFC, 0xB8, 0xFC, 0x91, 0xFD, 0x68, 0xFE, 0x23, 0xFF, 0x94, 0xFF, 0x6B, 0xFF, 0x3D, 0xFF, 0xDE, 0xFE, 0x94, 0xFE, 0x64, 0xFE, 0x4C, 0xFE, 0xCF, 0xFE, 0xA0, 0xFF, 0x9D, 0x00, 0x63, 0x01, 0xDB, 0x01, 0xCF, 0x01, 0x0F, 0x01, 0x2D, 0x00, 0x36, 0xFF, 0x85, 0xFE, 0xDC, 0xFD, 0x1C, 0xFD, 0xB3, 0xFC, 0xA5, 0xFC, 0x4E, 0xFD, 0xFE, 0xFD, 0x9B, 0xFE, 0x47, 0xFF, 0x6B, 0xFF, 0x44, 0xFF, 0xA3, 0xFE, 0xEE, 0xFD, 0x7B, 0xFD, 0x0E, 0xFD, 0xA8, 0xFC, 0x35, 0xFC, 0x19, 0xFC, 0x40, 0xFC, 0xAA, 0xFC, 0x5E, 0xFD, 0xD0, 0xFD, 0xE1, 0xFD, 0xC5, 0xFD, 0x83, 0xFD, 0x0B, 0xFD, 0x06, 0xFD, 0x7F, 0xFD, 0x39, 0xFE, 0x17, 0xFF, 0x69, 0xFF, 0x7A, 0xFF, 0x54, 0xFF, 0xF6, 0xFE, 0xB9, 0xFE, 0x51, 0xFE, 0x93, 0xFD, 0x5F, 0xFC, 0x30, 0xFB, 0x52, 0xFA, 0x00, 0xFA, 0x4C, 0xFA, 0xC7, 0xFA, 0x8C, 0xFB, 0x36, 0xFC, 0xE6, 0xFC, 0xAD, 0xFD, 0xEB, 0xFD, 0xCC, 0xFD, 0x65, 0xFD, 0x37, 0xFD, 0x53, 0xFD, 0x96, 0xFD, 0xE7, 0xFD, 0xCC, 0xFD, 0xE2, 0xFD, 0xF9, 0xFD, 0x89, 0xFD, 0xD1, 0xFC, 0xEA, 0xFB, 0x10, 0xFB, 0xC0, 0xFA, 0xE6, 0xFA, 0xD7, 0xFA, 0x07, 0xFB, 0x2C, 0xFB, 0x0F, 0xFB, 0x55, 0xFB, 0x22, 0xFB, 0x01, 0xFB, 0x60, 0xFB, 0xD1, 0xFB, 0x9F, 0xFC, 0xF7, 0xFC, 0x0E, 0xFD, 0x0F, 0xFD, 0xB7, 0xFC, 0xB7, 0xFC, 0xCF, 0xFC, 0xD5, 0xFC, 0x0B, 0xFD, 0x98, 0xFD, 0x2C, 0xFE, 0x55, 0xFE, 0x44, 0xFE, 0xE9, 0xFD, 0x76, 0xFD, 0x11, 0xFD, 0x78, 0xFC, 0xDA, 0xFB, 0x78, 0xFB, 0x68, 0xFB, 0xAF, 0xFB, 0xFD, 0xFB, 0x2B, 0xFC, 0x52, 0xFC, 0x55, 0xFC, 0x83, 0xFC, 0xF1, 0xFC, 0x3C, 0xFD, 0x53, 0xFD, 0x6D, 0xFD, 0x11, 0xFE, 0xCF, 0xFE, 0x3A, 0xFF, 0x78, 0xFF, 0x65, 0xFF, 0x54, 0xFF, 0x18, 0xFF, 0x99, 0xFE, 0x50, 0xFE, 0x53, 0xFE, 0x02, 0xFF, 0x15, 0x00, 0x41, 0x01, 0x56, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xB0, 0x02, 0x5E, 0x02, 0xA2, 0x01, 0xA2, 0x00, 0x69, 0xFF, 0x77, 0xFE, 0x20, 0xFE, 0x0B, 0xFE, 0x9F, 0xFE, 0xAC, 0xFF, 0x26, 0x01, 0xC1, 0x02, 0xAD, 0x03, 0x1E, 0x04, 0xBC, 0x03, 0x4E, 0x03, 0xFD, 0x02, 0x1F, 0x02, 0xB1, 0x01, 0x21, 0x01, 0x60, 0x00, 0xE0, 0xFF, 0x43, 0xFF, 0x35, 0xFF, 0x60, 0xFF, 0x91, 0xFF, 0xA8, 0xFF, 0x8F, 0xFF, 0x1D, 0x00, 0x23, 0x01, 0x4C, 0x02, 0x36, 0x03, 0xA7, 0x03, 0xE8, 0x03, 0xD3, 0x03, 0x8B, 0x03, 0x1C, 0x03, 0xBA, 0x02, 0x6E, 0x02, 0x10, 0x02, 0xE5, 0x01, 0x96, 0x01, 0x30, 0x01, 0x00, 0x01, 0xD6, 0x00, 0xA3, 0x00, 0x63, 0x00, 0x3E, 0x00, 0x31, 0x00, 0x6E, 0x00, 0x1C, 0x01, 0xBE, 0x01, 0x6F, 0x02, 0x3A, 0x03, 0xE3, 0x03, 0x60, 0x04, 0x61, 0x04, 0x08, 0x04, 0x85, 0x03, 0xF8, 0x02, 0x8B, 0x02, 0xC7, 0x01, 0xCC, 0x00, 0xB7, 0xFF, 0x7D, 0xFE, 0x9D, 0xFD, 0x0C, 0xFD, 0x08, 0xFD, 0x74, 0xFD, 0x17, 0xFE, 0x2F, 0xFF, 0x21, 0x00, 0x51, 0x01, 0x72, 0x02, 0x1D, 0x03, 0xF5, 0x03, 0x29, 0x04, 0xCD, 0x03, 0xF8, 0x02, 0xE3, 0x01, 0x47, 0x01, 0x5E, 0x00, 0xF6, 0xFF, 0xBB, 0xFF, 0x1F, 0xFF, 0x2C, 0xFF, 0xF7, 0xFE, 0xE8, 0xFE, 0x42, 0xFF, 0x64, 0xFF, 0xF5, 0xFF, 0x5C, 0x00, 0x85, 0x00, 0x78, 0x00, 0xC2, 0xFF, 0xF0, 0xFE, 0x18, 0xFE, 0x67, 0xFD, 0xF4, 0xFC, 0xB6, 0xFC, 0xB3, 0xFC, 0x96, 0xFC, 0x65, 0xFC, 0xF4, 0xFB, 0x65, 0xFB, 0x31, 0xFB, 0x1A, 0xFB, 0xF2, 0xFA, 0xB6, 0xFA, 0x6E, 0xFA, 0x6D, 0xFA, 0xEA, 0xFA, 0xEF, 0xFB, 0x44, 0xFD, 0xBE, 0xFE, 0x08, 0x00, 0xAE, 0x00, 0xAA, 0x00, 0xF2, 0xFF, 0xED, 0xFE, 0x0A, 0xFE, 0x68, 0xFD, 0x5F, 0xFD, 0x90, 0xFD, 0xF8, 0xFD, 0xBA, 0xFE, 0x86, 0xFF, 0xCA, 0x00, 0x02, 0x02, 0xCE, 0x02, 0x57, 0x03, 0x42, 0x03, 0x05, 0x03, 0x8B, 0x02, 0xD3, 0x01, 0x3F, 0x01, 0xBE, 0x00, 0x9C, 0x00, 0x8A, 0x00, 0x80, 0x00, 0xD3, 0x00, 0x4E, 0x01, 0xE2, 0x01, 0x41, 0x02, 0x3C, 0x02, 0x12, 0x02, 0xAC, 0x01, 0x03, 0x01, 0x72, 0x00, 0x43, 0x00, 0xA5, 0x00, 0x48, 0x01, 0x91, 0x01, 0x7E, 0x01, 0x15, 0x01, 0x97, 0x00, 0x7E, 0x00, 0xD8, 0x00, 0xA9, 0x01, 0x6C, 0x02, 0x16, 0x03, 0xBE, 0x03, 0xFE, 0x03, 0x18, 0x04, 0xE0, 0x03, 0x00, 0x03, 0xC0, 0x01, 0x1D, 0x00, 0x63, 0xFE, 0x1C, 0xFD, 0x5D, 0xFC, 0x42, 0xFC, 0xF1, 0xFC, 0x0A, 0xFE, 0x05, 0xFF, 0x91, 0xFF, 0xA6, 0xFF, 0xC2, 0xFF, 0xE9, 0xFF, 0xC1, 0xFF, 0x8A, 0xFF, 0x65, 0xFF, 0x2A, 0xFF, 0x20, 0xFF, 0x04, 0xFF, 0xE6, 0xFE, 0x94, 0xFF, 0x67, 0x00, 0x09, 0x01, 0xD1, 0x01, 0x24, 0x02, 0x4C, 0x02, 0x30, 0x02, 0x99, 0x01, 0x3F, 0x01, 0xF1, 0x00, 0xB0, 0x00, 0x5F, 0x00, 0x20, 0x00, 0x7D, 0x00, 0xED, 0x00, 0x2B, 0x01, 0x0A, 0x01, 0xAE, 0x00, 0x5D, 0x00, 0xE7, 0xFF, 0xC4, 0xFF, 0xA5, 0xFF, 0x87, 0xFF, 0x91, 0xFF, 0xF4, 0xFE, 0x30, 0xFE, 0xA1, 0xFD, 0x74, 0xFD, 0x29, 0xFE, 0x43, 0xFF, 0xA7, 0x00, 0x2A, 0x02, 0x68, 0x03, 0x2B, 0x04, 0x5E, 0x04, 0x3A, 0x04, 0x9E, 0x03, 0xBA, 0x02, 0x9E, 0x01, 0x41, 0x00, 0xE2, 0xFE, 0x8D, 0xFD, 0xB1, 0xFC, 0x67, 0xFC, 0xBB, 0xFC, 0x82, 0xFD, 0x67, 0xFE, 0x94, 0xFF, 0x9A, 0x00, 0x6B, 0x01, 0x0F, 0x02, 0x9B, 0x02, 0xF8, 0x02, 0x88, 0x02, 0xD8, 0x01, 0x31, 0x01, 0x6E, 0x00, 0x2A, 0x00, 0x6E, 0x00, 0x20, 0x01, 0x0E, 0x02, 0x99, 0x02, 0x01, 0x03, 0x7E, 0x03, 0x8C, 0x03, 0x66, 0x03, 0x08, 0x03, 0x4F, 0x02, 0xF0, 0x01, 0xB3, 0x01, 0x8B, 0x01, 0x68, 0x01, 0xF5, 0x00, 0xB7, 0x00, 0xA3, 0x00, 0x56, 0x00, 0x94, 0xFF, 0xE2, 0xFE, 0xC0, 0xFE, 0xE3, 0xFE, 0x4C, 0xFF, 0x08, 0xFF, 0x0B, 0xFE, 0x1E, 0xFD, 0x89, 0xFC, 0xA0, 0xFC, 0xEF, 0xFC, 0xC0, 0xFD, 0xDF, 0xFE, 0x92, 0xFF, 0x31, 0x00, 0xC6, 0x00, 0x59, 0x01, 0x16, 0x02, 0x05, 0x03, 0x8F, 0x03, 0x7E, 0x03, 0x05, 0x03, 0xD8, 0x01, 0x7B, 0x00, 0xF8, 0xFE, 0xA1, 0xFD, 0xB0, 0xFC, 0xC5, 0xFB, 0x90, 0xFB, 0xE4, 0xFB, 0xA1, 0xFC, 0x8A, 0xFD, 0x2C, 0xFE, 0x95, 0xFE, 0x88, 0xFE, 0x55, 0xFE, 0xA5, 0xFD, 0x82, 0xFC, 0x31, 0xFB, 0xD3, 0xF9, 0x0B, 0xF9, 0x4A, 0xF8, 0xCB, 0xF7, 0xBB, 0xF7, 0xE6, 0xF7, 0x85, 0xF8, 0x07, 0xF9, 0xC3, 0xF9, 0x5B, 0xFA, 0xB6, 0xFA, 0x15, 0xFB, 0xD9, 0xFA, 0xAD, 0xFA, 0x9E, 0xFA, 0xAB, 0xFA, 0xDA, 0xFA, 0xFC, 0xFA, 0x72, 0xFB, 0xC0, 0xFB, 0x1B, 0xFC, 0x95, 0xFC, 0x17, 0xFD, 0xC2, 0xFD, 0xF1, 0xFD, 0xB3, 0xFD, 0x0B, 0xFD, 0xD1, 0xFC, 0x25, 0xFD, 0x6C, 0xFD, 0x44, 0xFE, 0xEE, 0xFE, 0x80, 0xFF, 0x2D, 0x00, 0x30, 0x00, 0x2B, 0x00, 0xD4, 0xFF, 0x64, 0xFF, 0x82, 0xFF, 0x8B, 0xFF, 0xB4, 0xFF, 0x2E, 0x00, 0x97, 0x00, 0x8A, 0x00, 0x72, 0x00, 0x6A, 0x00, 0x3B, 0x00, 0x20, 0x00, 0xAF, 0xFF, 0x7C, 0xFF, 0x88, 0xFF, 0x91, 0xFF, 0x0D, 0x00, 0x22, 0x00, 0x3B, 0x00, 0x65, 0x00, 0x09, 0x00, 0xAF, 0xFF, 0xFD, 0xFE, 0x61, 0xFE, 0xC6, 0xFD, 0xDF, 0xFC, 0x67, 0xFC, 0x33, 0xFC, 0x5B, 0xFC, 0x8F, 0xFC, 0xB6, 0xFC, 0xF7, 0xFC, 0x30, 0xFD, 0xB9, 0xFD, 0xDB, 0xFD, 0x4B, 0xFD, 0x55, 0xFC, 0x11, 0xFB, 0xD6, 0xF9, 0xAE, 0xF8, 0xB0, 0xF7, 0x0D, 0xF7, 0xFD, 0xF6, 0x34, 0xF7, 0xA3, 0xF7, 0x64, 0xF8, 0x2E, 0xF9, 0x07, 0xFA, 0xCC, 0xFA, 0xA0, 0xFB, 0x27, 0xFC, 0x3D, 0xFC, 0x3B, 0xFC, 0x07, 0xFC, 0x14, 0xFC, 0xFC, 0xFB, 0xF1, 0xFB, 0x2B, 0xFC, 0x25, 0xFC, 0x5B, 0xFC, 0x40, 0xFC, 0xCE, 0xFB, 0x88, 0xFB, 0x95, 0xFB, 0x2D, 0xFC, 0xCF, 0xFC, 0x61, 0xFD, 0x8F, 0xFD, 0x82, 0xFD, 0x58, 0xFD, 0x32, 0xFD, 0x7E, 0xFD, 0x9D, 0xFD, 0x0B, 0xFE, 0x4E, 0xFE, 0x69, 0xFE, 0x42, 0xFF, 0xE9, 0xFF, 0xCC, 0x00, 0x94, 0x01, 0xFB, 0x01, 0x5F, 0x02, 0x2E, 0x02, 0x04, 0x02, 0xDF, 0x01, 0x17, 0x02, 0xBA, 0x02, 0x20, 0x03, 0x6B, 0x03, 0x5B, 0x03, 0x6E, 0x03, 0x7D, 0x03, 0x5E, 0x03, 0x57, 0x03, 0x04, 0x03, 0xCC, 0x02, 0x92, 0x02, 0x5C, 0x02, 0x64, 0x02, 0x89, 0x02, 0xC5, 0x02, 0xD1, 0x02, 0xE8, 0x02, 0xC6, 0x02, 0x7D, 0x02, 0x4C, 0x02, 0xFD, 0x01, 0xCD, 0x01, 0xAA, 0x01, 0xA1, 0x01, 0x4A, 0x01, 0xC9, 0x00, 0x6D, 0x00, 0xD7, 0xFF, 0x87, 0xFF, 0x32, 0xFF, 0xE4, 0xFE, 0x17, 0xFF, 0x7B, 0xFF, 0x26, 0x00, 0x98, 0x00, 0xEF, 0x00, 0x48, 0x01, 0x10, 0x01, 0x85, 0x00, 0xA7, 0xFF, 0x8C, 0xFE, 0x6D, 0xFD, 0x63, 0xFC, 0x8A, 0xFB, 0x04, 0xFB, 0x28, 0xFB, 0x9B, 0xFB, 0xDD, 0xFB, 0xEA, 0xFB, 0xE6, 0xFB, 0x1E, 0xFC, 0x84, 0xFC, 0xB2, 0xFC, 0x90, 0xFC, 0x36, 0xFC, 0xBC, 0xFB, 0xB8, 0xFB, 0x17, 0xFC, 0x79, 0xFC, 0x4B, 0xFD, 0x44, 0xFE, 0x1C, 0xFF, 0xE2, 0xFF, 0x8C, 0x00, 0x22, 0x01, 0x1E, 0x01, 0xAC, 0x00, 0xF1, 0xFF, 0x16, 0xFF, 0xB2, 0xFE, 0x75, 0xFE, 0x54, 0xFE, 0x07, 0xFE, 0x85, 0xFD, 0x84, 0xFD, 0xB3, 0xFD, 0x1C, 0xFE, 0xC5, 0xFE, 0x5D, 0xFF, 0xC1, 0xFF, 0x82, 0xFF, 0xEB, 0xFE, 0x16, 0xFE, 0x2A, 0xFD, 0x63, 0xFC, 0xA5, 0xFB, 0x71, 0xFB, 0xAA, 0xFB, 0x3F, 0xFC, 0x3A, 0xFD, 0xD3, 0xFD, 0x1C, 0xFE, 0x22, 0xFE, 0xFA, 0xFD, 0xDC, 0xFD, 0xAC, 0xFD, 0xD2, 0xFD, 0x55, 0xFE, 0x18, 0xFF, 0x03, 0x00, 0xBE, 0x00, 0x19, 0x01, 0x10, 0x01, 0xD0, 0x00, 0x17, 0x00, 0x2D, 0xFF, 0x62, 0xFE, 0xA1, 0xFD, 0x5E, 0xFD, 0x77, 0xFD, 0xE8, 0xFD, 0x9B, 0xFE, 0xFE, 0xFE, 0x27, 0xFF, 0xFD, 0xFE, 0xD9, 0xFE, 0xD0, 0xFE, 0xAA, 0xFE, 0xC9, 0xFE, 0xC8, 0xFE, 0xC6, 0xFE, 0x0C, 0xFF, 0x22, 0xFF, 0x03, 0xFF, 0xC1, 0xFE, 0x4E, 0xFE, 0xC8, 0xFD, 0x4B, 0xFD, 0x01, 0xFD, 0x2C, 0xFD, 0x8B, 0xFD, 0xCF, 0xFD, 0x01, 0xFE, 0x15, 0xFE, 0x85, 0xFE, 0x34, 0xFF, 0x98, 0xFF, 0xC8, 0xFF, 0x91, 0xFF, 0x3A, 0xFF, 0x0F, 0xFF, 0x03, 0xFF, 0x01, 0xFF, 0x31, 0xFF, 0xF6, 0xFF, 0x7E, 0x00, 0xC6, 0x00, 0x12, 0x01, 0xEE, 0x00, 0xFD, 0x00, 0x34, 0x01, 0x6F, 0x01, 0x02, 0x02, 0x62, 0x02, 0xC1, 0x02, 0x29, 0x03, 0x06, 0x03, 0xB3, 0x02, 0x48, 0x02, 0xE2, 0x01, 0xF8, 0x01, 0xEB, 0x01, 0x96, 0x01, 0x8C, 0x01, 0x7E, 0x01, 0x71, 0x01, 0xD7, 0x01, 0x7F, 0x02, 0x47, 0x03, 0xFB, 0x03, 0x3E, 0x04, 0x47, 0x04, 0x4C, 0x04, 0x16, 0x04, 0x9C, 0x03, 0xE8, 0x02, 0xE8, 0x01, 0x1E, 0x01, 0xBC, 0x00, 0x6A, 0x00, 0x2D, 0x00, 0x16, 0x00, 0x60, 0x00, 0x53, 0x01, 0x5F, 0x02, 0x4B, 0x03, 0x2E, 0x04, 0x92, 0x04, 0x34, 0x04, 0x37, 0x03, 0xFD, 0x01, 0xFC, 0x00, 0x57, 0x00, 0xFE, 0xFF, 0xE9, 0xFF, 0x4B, 0x00, 0x04, 0x01, 0xF6, 0x01, 0xF6, 0x02, 0x83, 0x03, 0xB3, 0x03, 0x96, 0x03, 0x4A, 0x03, 0xD1, 0x02, 0x16, 0x02, 0xA8, 0x01, 0x89, 0x01, 0x8C, 0x01, 0xA5, 0x01, 0xF1, 0x01, 0xA0, 0x02, 0x3B, 0x03, 0xC3, 0x03, 0x92, 0x04, 0xBE, 0x05, 0x26, 0x07, 0x52, 0x08, 0x38, 0x09, 0xD1, 0x09, 0x12, 0x0A, 0x15, 0x0A, 0xA7, 0x09, 0xF4, 0x08, 0x51, 0x08, 0xDB, 0x07, 0x9D, 0x07, 0xA7, 0x07, 0xDE, 0x07, 0x2E, 0x08, 0x79, 0x08, 0x79, 0x08, 0x2C, 0x08, 0xC0, 0x07, 0x53, 0x07, 0xAE, 0x06, 0x0F, 0x06, 0xB8, 0x05, 0x8F, 0x05, 0xE0, 0x05, 0x24, 0x06, 0x15, 0x06, 0x15, 0x06, 0xDA, 0x05, 0x6A, 0x05, 0xB7, 0x04, 0xD2, 0x03, 0xE3, 0x02, 0xA7, 0x01, 0x43, 0x00, 0x05, 0xFF, 0x4E, 0xFE, 0x3E, 0xFE, 0x71, 0xFE, 0xA9, 0xFE, 0xDC, 0xFE, 0x07, 0xFF, 0xFD, 0xFE, 0xC6, 0xFE, 0x86, 0xFE, 0x28, 0xFE, 0xB4, 0xFD, 0x64, 0xFD, 0x38, 0xFD, 0x3B, 0xFD, 0x7C, 0xFD, 0xC3, 0xFD, 0x2F, 0xFE, 0xE5, 0xFE, 0xA9, 0xFF, 0x6E, 0x00, 0x11, 0x01, 0x51, 0x01, 0x50, 0x01, 0x4C, 0x01, 0x21, 0x01, 0x0C, 0x01, 0x13, 0x01, 0x01, 0x01, 0xDC, 0x00, 0x2A, 0x00, 0xA3, 0xFF, 0xAA, 0xFF, 0xF5, 0xFF, 0x09, 0x01, 0x37, 0x02, 0x1F, 0x03, 0xB3, 0x03, 0x9B, 0x03, 0x90, 0x03, 0xB8, 0x03, 0xF3, 0x03, 0x12, 0x04, 0xA1, 0x03, 0xCB, 0x02, 0xDD, 0x01, 0x06, 0x01, 0xC6, 0x00, 0x54, 0x01, 0x22, 0x02, 0x3A, 0x03, 0x3F, 0x04, 0xD3, 0x04, 0x67, 0x05, 0xA7, 0x05, 0xD7, 0x05, 0xC0, 0x05, 0x3F, 0x05, 0xF0, 0x04, 0x4B, 0x04, 0xDA, 0x03, 0xDA, 0x03, 0xAB, 0x03, 0x8A, 0x03, 0x06, 0x03, 0x5B, 0x02, 0x1A, 0x02, 0xE3, 0x01, 0xB2, 0x01, 0x7F, 0x01, 0x37, 0x01, 0xF4, 0x00, 0xAB, 0x00, 0xA9, 0x00, 0xE5, 0x00, 0xE0, 0x00, 0xB4, 0x00, 0x50, 0x00, 0xC6, 0xFF, 0x4C, 0xFF, 0x9A, 0xFE, 0x04, 0xFE, 0xA8, 0xFD, 0xB3, 0xFD, 0x01, 0xFE, 0xF8, 0xFD, 0x2B, 0xFE, 0x75, 0xFE, 0xBA, 0xFE, 0xEF, 0xFE, 0xA5, 0xFE, 0x77, 0xFE, 0x31, 0xFE, 0x9F, 0xFD, 0x10, 0xFD, 0x86, 0xFC, 0x40, 0xFC, 0x37, 0xFC, 0x7B, 0xFC, 0xC1, 0xFC, 0xCA, 0xFC, 0xAF, 0xFC, 0x60, 0xFC, 0x1E, 0xFC, 0xCE, 0xFB, 0x8A, 0xFB, 0x94, 0xFB, 0x20, 0xFC, 0x08, 0xFD, 0x99, 0xFD, 0x40, 0xFE, 0xDA, 0xFE, 0xD9, 0xFE, 0x15, 0xFF, 0x61, 0xFF, 0x9C, 0xFF, 0x1B, 0x00, 0x13, 0x00, 0xEA, 0xFF, 0x49, 0x00, 0xCF, 0x00, 0x84, 0x01, 0x3A, 0x02, 0xDC, 0x02, 0xA2, 0x03, 0x4D, 0x04, 0xBF, 0x04, 0x0E, 0x05, 0x1B, 0x05, 0xE7, 0x04, 0xB0, 0x04, 0x4D, 0x04, 0xD0, 0x03, 0xAC, 0x03, 0xD8, 0x03, 0x64, 0x04, 0xC4, 0x04, 0xA2, 0x04, 0x96, 0x04, 0x98, 0x04, 0xB9, 0x04, 0xE7, 0x04, 0x06, 0x05, 0x43, 0x05, 0x83, 0x05, 0x93, 0x05, 0x51, 0x05, 0x15, 0x05, 0xC8, 0x04, 0x36, 0x04, 0xA1, 0x03, 0xC6, 0x02, 0x19, 0x02, 0xD1, 0x01, 0xB0, 0x01, 0xF0, 0x01, 0x3E, 0x02, 0x7E, 0x02, 0xD3, 0x02, 0x0F, 0x03, 0x44, 0x03, 0x53, 0x03, 0x29, 0x03, 0x90, 0x02, 0x96, 0x01, 0xEE, 0x00, 0x5C, 0x00, 0xF3, 0xFF, 0x1A, 0x00, 0x3C, 0x00, 0x67, 0x00, 0x89, 0x00, 0x8E, 0x00, 0xC6, 0x00, 0xB7, 0x00, 0x93, 0x00, 0x86, 0x00, 0xA3, 0x00, 0xF8, 0x00, 0x4C, 0x01, 0xF0, 0x01, 0x72, 0x02, 0x13, 0x03, 0xE7, 0x03, 0x6A, 0x04, 0xB9, 0x04, 0x7B, 0x04, 0x57, 0x04, 0x36, 0x04, 0xE9, 0x03, 0xD6, 0x03, 0x4F, 0x03, 0xC9, 0x02, 0xEE, 0x01, 0xF6, 0x00, 0xAC, 0x00, 0x93, 0x00, 0x45, 0x01, 0xFF, 0x01, 0xA3, 0x02, 0x7A, 0x03, 0x8E, 0x03, 0x9B, 0x03, 0x75, 0x03, 0x12, 0x03, 0xBB, 0x02, 0x17, 0x02, 0x80, 0x01, 0xA7, 0x00, 0xC1, 0xFF, 0xEA, 0xFE, 0x4E, 0xFE, 0x28, 0xFE, 0xD0, 0xFD, 0xAB, 0xFD, 0xC0, 0xFD, 0xCC, 0xFD, 0xEE, 0xFD, 0xE1, 0xFD, 0xDC, 0xFD, 0xBA, 0xFD, 0xA8, 0xFD, 0x92, 0xFD, 0x42, 0xFD, 0x37, 0xFD, 0x2A, 0xFD, 0x56, 0xFD, 0xB5, 0xFD, 0xE1, 0xFD, 0x77, 0xFE, 0x02, 0xFF, 0x69, 0xFF, 0xDB, 0xFF, 0x00, 0x00, 0x43, 0x00, 0x34, 0x00, 0xCB, 0xFF, 0xBB, 0xFF, 0x94, 0xFF, 0x6F, 0xFF, 0x63, 0xFF, 0x2F, 0xFF, 0x69, 0xFF, 0xF0, 0xFF, 0x0B, 0x00, 0x1A, 0x00, 0x30, 0x00, 0x45, 0x00, 0x9F, 0x00, 0xB0, 0x00, 0xAF, 0x00, 0xBE, 0x00, 0x83, 0x00, 0x4E, 0x00, 0xDE, 0xFF, 0x70, 0xFF, 0xFE, 0xFE, 0x79, 0xFE, 0x68, 0xFE, 0x7D, 0xFE, 0xDA, 0xFE, 0x47, 0xFF, 0xF0, 0xFF, 0x0F, 0x01, 0xD8, 0x01, 0xCF, 0x02, 0x54, 0x03, 0x30, 0x03, 0x00, 0x03, 0x46, 0x02, 0xA6, 0x01, 0x0F, 0x01, 0xA7, 0x00, 0xCD, 0x00, 0xFF, 0x00, 0x59, 0x01, 0x9F, 0x01, 0x03, 0x02, 0x73, 0x02, 0x84, 0x02, 0x6B, 0x02, 0xFB, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xD7, 0x01, 0x01, 0x02, 0xDB, 0x01, 0xB0, 0x01, 0x85, 0x01, 0x8C, 0x01, 0xCA, 0x01, 0xFE, 0x01, 0x45, 0x02, 0x71, 0x02, 0x6D, 0x02, 0x36, 0x02, 0x04, 0x02, 0xE4, 0x01, 0xB2, 0x01, 0x82, 0x01, 0x20, 0x01, 0xBB, 0x00, 0x40, 0x00, 0x88, 0xFF, 0xF5, 0xFE, 0xB4, 0xFE, 0xCC, 0xFE, 0xC3, 0xFE, 0x4E, 0xFE, 0x86, 0xFD, 0xD6, 0xFC, 0x8F, 0xFC, 0x61, 0xFC, 0x58, 0xFC, 0x4A, 0xFC, 0x05, 0xFC, 0x95, 0xFB, 0xE4, 0xFA, 0x4E, 0xFA, 0xEE, 0xF9, 0xEA, 0xF9, 0x58, 0xFA, 0x0A, 0xFB, 0xDF, 0xFB, 0xA3, 0xFC, 0x61, 0xFD, 0x05, 0xFE, 0x73, 0xFE, 0xA9, 0xFE, 0xED, 0xFE, 0x44, 0xFF, 0x3F, 0xFF, 0x6D, 0xFF, 0xB5, 0xFF, 0xB9, 0xFF, 0xD2, 0xFF, 0xB2, 0xFF, 0x99, 0xFF, 0x8B, 0xFF, 0x80, 0xFF, 0xB1, 0xFF, 0xC1, 0xFF, 0xCF, 0xFF, 0xB8, 0xFF, 0x8A, 0xFF, 0x7E, 0xFF, 0x8B, 0xFF, 0xA1, 0xFF, 0x9C, 0xFF, 0x0A, 0x00, 0xB1, 0x00, 0x82, 0x01, 0x67, 0x02, 0xCC, 0x02, 0x32, 0x03, 0x22, 0x03, 0xBB, 0x02, 0x78, 0x02, 0xE9, 0x01, 0x84, 0x01, 0x41, 0x01, 0x39, 0x01, 0x60, 0x01, 0x9F, 0x01, 0x22, 0x02, 0xA9, 0x02, 0x57, 0x03, 0x7E, 0x03, 0x43, 0x03, 0xE0, 0x02, 0x0D, 0x02, 0xB7, 0x01, 0x51, 0x01, 0x35, 0x01, 0xDC, 0x01, 0x2C, 0x02, 0x87, 0x02, 0x62, 0x02, 0x9F, 0x01, 0x4C, 0x01, 0x0F, 0x01, 0xB7, 0x00, 0x4D, 0x00, 0xC9, 0xFF, 0x7C, 0xFF, 0xAC, 0xFF, 0x1B, 0x00, 0x74, 0x00, 0x05, 0x01, 0x9C, 0x01, 0xFD, 0x01, 0x20, 0x02, 0xDA, 0x01, 0x7E, 0x01, 0xFE, 0x00, 0xA6, 0x00, 0x1B, 0x01, 0x9E, 0x01, 0xBF, 0x01, 0xE3, 0x01, 0x03, 0x02, 0x8D, 0x02, 0x64, 0x03, 0x07, 0x04, 0x7F, 0x04, 0x7E, 0x04, 0x36, 0x04, 0xB8, 0x03, 0x32, 0x03, 0xDC, 0x02, 0x89, 0x02, 0xB9, 0x02, 0x07, 0x03, 0x1E, 0x03, 0x23, 0x03, 0xDD, 0x02, 0x9B, 0x02, 0x50, 0x02, 0x19, 0x02, 0x01, 0x02, 0xF9, 0x01, 0x29, 0x02, 0x32, 0x02, 0x79, 0x02, 0xC0, 0x02, 0xDC, 0x02, 0xFD, 0x02, 0xC2, 0x02, 0x72, 0x02, 0x5E, 0x01, 0xCE, 0xFF, 0x8E, 0xFE, 0x37, 0xFD, 0x5D, 0xFC, 0x1B, 0xFC, 0x59, 0xFC, 0x13, 0xFD, 0x20, 0xFE, 0x56, 0xFF, 0x00, 0x00, 0x66, 0x00, 0x5F, 0x00, 0xEE, 0xFF, 0x86, 0xFF, 0xF2, 0xFE, 0xC7, 0xFE, 0x8B, 0xFE, 0x53, 0xFE, 0x77, 0xFE, 0x19, 0xFE, 0x34, 0xFE, 0xA1, 0xFE, 0xE8, 0xFE, 0x9E, 0xFF, 0xF4, 0xFF, 0x25, 0x00, 0x6B, 0x00, 0x75, 0x00, 0xA5, 0x00, 0xAE, 0x00, 0xAC, 0x00, 0xD7, 0x00, 0xE1, 0x00, 0xB3, 0x00, 0x78, 0x00, 0x52, 0x00, 0x3A, 0x00, 0x61, 0x00, 0x68, 0x00, 0x55, 0x00, 0x7A, 0x00, 0x46, 0x00, 0x0E, 0x00, 0xE0, 0xFF, 0x7B, 0xFF, 0x74, 0xFF, 0x3F, 0xFF, 0xD9, 0xFE, 0x87, 0xFE, 0xE7, 0xFD, 0x7C, 0xFD, 0x15, 0xFD, 0xCB, 0xFC, 0x05, 0xFD, 0x51, 0xFD, 0xE0, 0xFD, 0x5A, 0xFE, 0xB3, 0xFE, 0x49, 0xFF, 0xBD, 0xFF, 0x1B, 0x00, 0x1D, 0x00, 0xDE, 0xFF, 0x71, 0xFF, 0xB7, 0xFE, 0x53, 0xFE, 0x0F, 0xFE, 0x10, 0xFE, 0x63, 0xFE, 0x84, 0xFE, 0xC8, 0xFE, 0xBC, 0xFE, 0x63, 0xFE, 0xD9, 0xFD, 0xFD, 0xFC, 0x9D, 0xFC, 0x83, 0xFC, 0xA1, 0xFC, 0xF3, 0xFC, 0xF4, 0xFC, 0xF8, 0xFC, 0x03, 0xFD, 0x16, 0xFD, 0x71, 0xFD, 0x3C, 0xFE, 0x5D, 0xFF, 0x3F, 0x00, 0xB0, 0x00, 0xAF, 0x00, 0x7E, 0x00, 0x30, 0x00, 0x8F, 0xFF, 0x0A, 0xFF, 0x8F, 0xFE, 0x70, 0xFE, 0xF0, 0xFE, 0x57, 0xFF, 0xEB, 0xFF, 0x6E, 0x00, 0xB1, 0x00, 0x21, 0x01, 0x63, 0x01, 0x72, 0x01, 0x58, 0x01, 0x09, 0x01, 0xA8, 0x00, 0x21, 0x00, 0xA5, 0xFF, 0x42, 0xFF, 0x26, 0xFF, 0x6D, 0xFF, 0x19, 0x00, 0x03, 0x01, 0xED, 0x01, 0xC1, 0x02, 0x37, 0x03, 0x56, 0x03, 0x06, 0x03, 0x9A, 0x02, 0x69, 0x02, 0x01, 0x02, 0xDF, 0x01, 0xE2, 0x01, 0xE5, 0x01, 0x24, 0x02, 0xF7, 0x01, 0xC1, 0x01, 0xC8, 0x01, 0xCB, 0x01, 0xDE, 0x01, 0xCB, 0x01, 0xA2, 0x01, 0x5E, 0x01, 0x37, 0x01, 0x15, 0x01, 0xC6, 0x00, 0x8B, 0x00, 0x50, 0x00, 0x4F, 0x00, 0x87, 0x00, 0x8F, 0x00, 0x89, 0x00, 0xC5, 0x00, 0x24, 0x01, 0x5D, 0x01, 0xAD, 0x01, 0xB8, 0x01, 0x4A, 0x01, 0xA9, 0x00, 0xF5, 0xFF, 0x71, 0xFF, 0x1B, 0xFF, 0xC2, 0xFE, 0x26, 0xFE, 0x69, 0xFD, 0xCA, 0xFC, 0x7F, 0xFC, 0xF8, 0xFC, 0xEB, 0xFD, 0x03, 0xFF, 0xF9, 0xFF, 0x4F, 0x00, 0x18, 0x00, 0xB0, 0xFF, 0x8A, 0xFF, 0x5E, 0xFF, 0xE5, 0xFE, 0x81, 0xFE, 0x66, 0xFE, 0xC0, 0xFE, 0x73, 0xFF, 0x54, 0x00, 0x21, 0x01, 0xC0, 0x01, 0x2A, 0x02, 0xEC, 0x01, 0x73, 0x01, 0x39, 0x01, 0x06, 0x01, 0xCF, 0x00, 0x67, 0x00, 0xCE, 0xFF, 0x62, 0xFF, 0x1B, 0xFF, 0x04, 0xFF, 0x58, 0xFF, 0xC0, 0xFF, 0x33, 0x00, 0x8B, 0x00, 0xB5, 0x00, 0x4B, 0x01, 0xF8, 0x01, 0x60, 0x02, 0x85, 0x02, 0x46, 0x02, 0xB3, 0x01, 0x19, 0x01, 0xC0, 0x00, 0x58, 0x00, 0x61, 0x00, 0xBD, 0x00, 0xCC, 0x00, 0x33, 0x01, 0x7A, 0x01, 0x97, 0x01, 0xD5, 0x01, 0xAF, 0x01, 0xB8, 0x01, 0xC2, 0x01, 0xCC, 0x01, 0xC5, 0x01, 0x42, 0x01, 0xC4, 0x00, 0x33, 0x00, 0xC0, 0xFF, 0x7E, 0xFF, 0x4F, 0xFF, 0x4B, 0xFF, 0x43, 0xFF, 0xA0, 0xFF, 0xFA, 0xFF, 0x0A, 0x00, 0xFE, 0xFF, 0x66, 0xFF, 0xD3, 0xFE, 0x7A, 0xFE, 0x04, 0xFE, 0x80, 0xFD, 0x23, 0xFD, 0x43, 0xFD, 0xD6, 0xFD, 0xB0, 0xFE, 0x3E, 0xFF, 0x77, 0xFF, 0x95, 0xFF, 0xB0, 0xFF, 0xFF, 0xFF, 0x1E, 0x00, 0x1C, 0x00, 0x01, 0x00, 0xD8, 0xFF, 0xBF, 0xFF, 0x50, 0xFF, 0x32, 0xFF, 0x72, 0xFF, 0xE5, 0xFF, 0xBE, 0x00, 0x90, 0x01, 0x7E, 0x02, 0xFE, 0x02, 0x10, 0x03, 0xF0, 0x02, 0x4A, 0x02, 0xAC, 0x01, 0x00, 0x01, 0x66, 0x00, 0xC6, 0xFF, 0x06, 0xFF, 0xA0, 0xFE, 0x40, 0xFE, 0x2B, 0xFE, 0x5B, 0xFE, 0x95, 0xFE, 0xE2, 0xFE, 0xFF, 0xFE, 0x2B, 0xFF, 0x18, 0xFF, 0xB2, 0xFE, 0x07, 0xFE, 0x46, 0xFD, 0xC5, 0xFC, 0x4E, 0xFC, 0x25, 0xFC, 0x1F, 0xFC, 0x3D, 0xFC, 0x3D, 0xFC, 0xF5, 0xFB, 0x03, 0xFC, 0xC6, 0xFB, 0x98, 0xFB, 0x81, 0xFB, 0xFE, 0xFA, 0xD2, 0xFA, 0xB4, 0xFA, 0x8B, 0xFA, 0x66, 0xFA, 0x2C, 0xFA, 0xF8, 0xF9, 0xFC, 0xF9, 0x91, 0xFA, 0x19, 0xFB, 0xA9, 0xFB, 0x55, 0xFC, 0xDF, 0xFC, 0x54, 0xFD, 0x43, 0xFD, 0xD3, 0xFC, 0xF6, 0xFB, 0xDB, 0xFA, 0xC5, 0xF9, 0xE0, 0xF8, 0xBC, 0xF8, 0xEC, 0xF8, 0x9D, 0xF9, 0xAD, 0xFA, 0x9B, 0xFB, 0xED, 0xFC, 0x0F, 0xFE, 0x0C, 0xFF, 0xFD, 0xFF, 0x31, 0x00, 0x1C, 0x00, 0xCA, 0xFF, 0x3E, 0xFF, 0xDB, 0xFE, 0x79, 0xFE, 0x49, 0xFE, 0x72, 0xFE, 0xD2, 0xFE, 0x54, 0xFF, 0xEF, 0xFF, 0x78, 0x00, 0xF3, 0x00, 0xAA, 0x01, 0x4E, 0x02, 0xD0, 0x02, 0x3E, 0x03, 0x44, 0x03, 0x57, 0x03, 0x26, 0x03, 0xA1, 0x02, 0x8B, 0x02, 0x59, 0x02, 0xF2, 0x01, 0x85, 0x01, 0x3D, 0x01, 0x77, 0x01, 0xBE, 0x01, 0xE5, 0x01, 0xDC, 0x01, 0x8D, 0x01, 0xE1, 0x00, 0x48, 0x00, 0xD5, 0xFF, 0x4A, 0xFF, 0x63, 0xFF, 0x7F, 0xFF, 0x99, 0xFF, 0x01, 0x00, 0xD3, 0xFF, 0x01, 0x00, 0x44, 0x00, 0x7A, 0x00, 0x03, 0x01, 0x8A, 0x00, 0x94, 0xFF, 0x46, 0xFE, 0x9E, 0xFC, 0x3E, 0xFB, 0xFF, 0xF9, 0x74, 0xF9, 0xA5, 0xF9, 0x6D, 0xFA, 0x87, 0xFB, 0x70, 0xFC, 0x49, 0xFD, 0xB1, 0xFD, 0x93, 0xFD, 0xF8, 0xFC, 0xF5, 0xFB, 0x25, 0xFB, 0x96, 0xFA, 0x52, 0xFA, 0x89, 0xFA, 0x2F, 0xFB, 0x1F, 0xFC, 0xD8, 0xFC, 0x21, 0xFD, 0x49, 0xFD, 0x3B, 0xFD, 0x30, 0xFD, 0x3B, 0xFD, 0x27, 0xFD, 0x4E, 0xFD, 0x9B, 0xFD, 0x06, 0xFE, 0x69, 0xFE, 0x62, 0xFE, 0x3E, 0xFE, 0xE4, 0xFD, 0x6A, 0xFD, 0x1F, 0xFD, 0xCD, 0xFC, 0x65, 0xFC, 0x4A, 0xFC, 0xC1, 0xFC, 0x85, 0xFD, 0x7A, 0xFE, 0x0D, 0xFF, 0x4B, 0xFF, 0x84, 0xFF, 0x08, 0xFF, 0x57, 0xFE, 0x8B, 0xFD, 0xD0, 0xFC, 0xAE, 0xFC, 0x87, 0xFC, 0xA2, 0xFC, 0xE2, 0xFC, 0x57, 0xFD, 0x68, 0xFE, 0x42, 0xFF, 0x0B, 0x00, 0xCA, 0x00, 0x00, 0x01, 0xAA, 0x00, 0xFE, 0xFF, 0x7B, 0xFF, 0xF7, 0xFE, 0x5A, 0xFE, 0xDE, 0xFD, 0x7A, 0xFD, 0x44, 0xFD, 0x19, 0xFD, 0xFD, 0xFC, 0x07, 0xFD, 0x05, 0xFD, 0x21, 0xFD, 0x7A, 0xFD, 0xC2, 0xFD, 0xCB, 0xFD, 0x62, 0xFD, 0xAF, 0xFC, 0x2B, 0xFC, 0xF4, 0xFB, 0xF3, 0xFB, 0x10, 0xFC, 0x2D, 0xFC, 0x37, 0xFC, 0x3E, 0xFC, 0x2E, 0xFC, 0xF0, 0xFB, 0x9C, 0xFB, 0xDF, 0xFA, 0xD9, 0xF9, 0x2D, 0xF9, 0xDB, 0xF8, 0xCE, 0xF8, 0x11, 0xF9, 0x42, 0xF9, 0x5E, 0xF9, 0x9E, 0xF9, 0x8E, 0xF9, 0x73, 0xF9, 0xEB, 0xF9, 0x62, 0xFA, 0xC2, 0xFA, 0x0F, 0xFB, 0x39, 0xFB, 0x7D, 0xFB, 0xAF, 0xFB, 0xCA, 0xFB, 0xD6, 0xFB, 0xC4, 0xFB, 0x7D, 0xFB, 0x0A, 0xFB, 0x94, 0xFA, 0x6F, 0xFA, 0xDD, 0xFA, 0x5C, 0xFB, 0xE9, 0xFB, 0x63, 0xFC, 0x70, 0xFC, 0x7C, 0xFC, 0x73, 0xFC, 0x6F, 0xFC, 0x78, 0xFC, 0x5E, 0xFC, 0x70, 0xFC, 0x54, 0xFC, 0x0F, 0xFC, 0x41, 0xFC, 0xB9, 0xFC, 0x1F, 0xFD, 0x7D, 0xFD, 0xD2, 0xFD, 0x30, 0xFE, 0x9D, 0xFE, 0xD1, 0xFE, 0xE9, 0xFE, 0xDA, 0xFE, 0xB6, 0xFE, 0xC4, 0xFE, 0xB1, 0xFE, 0x9D, 0xFE, 0x57, 0xFE, 0x0E, 0xFE, 0x44, 0xFE, 0x53, 0xFE, 0x56, 0xFE, 0x4D, 0xFE, 0x17, 0xFE, 0xFB, 0xFD, 0xBD, 0xFD, 0x98, 0xFD, 0xAD, 0xFD, 0xC1, 0xFD, 0xDD, 0xFD, 0xC4, 0xFD, 0x71, 0xFD, 0xFC, 0xFC, 0x86, 0xFC, 0x51, 0xFC, 0x57, 0xFC, 0x5F, 0xFC, 0x92, 0xFC, 0xF5, 0xFC, 0x5D, 0xFD, 0x9E, 0xFD, 0xC4, 0xFD, 0xF5, 0xFD, 0xD9, 0xFD, 0x4E, 0xFD, 0x6C, 0xFC, 0x52, 0xFB, 0x4E, 0xFA, 0x5A, 0xF9, 0xC9, 0xF8, 0xDB, 0xF8, 0x68, 0xF9, 0x5D, 0xFA, 0x96, 0xFB, 0xCC, 0xFC, 0xA6, 0xFD, 0x4B, 0xFE, 0x8F, 0xFE, 0xB4, 0xFE, 0x1D, 0xFF, 0x22, 0xFF, 0x3B, 0xFF, 0x49, 0xFF, 0x03, 0xFF, 0xCB, 0xFE, 0x37, 0xFE, 0x0C, 0xFE, 0x49, 0xFE, 0x67, 0xFE, 0xE8, 0xFE, 0x61, 0xFF, 0xDE, 0xFF, 0x6D, 0x00, 0x06, 0x01, 0x7D, 0x01, 0x9E, 0x01, 0xB4, 0x01, 0x5F, 0x01, 0xDB, 0x00, 0x35, 0x00, 0x64, 0xFF, 0x19, 0xFF, 0xFB, 0xFE, 0x1E, 0xFF, 0x74, 0xFF, 0xB7, 0xFF, 0xC4, 0xFF, 0x4E, 0xFF, 0xEB, 0xFE, 0x70, 0xFE, 0x0C, 0xFE, 0xD5, 0xFD, 0x38, 0xFD, 0xEC, 0xFC, 0x8C, 0xFC, 0x0D, 0xFC, 0x19, 0xFC, 0x35, 0xFC, 0xD8, 0xFC, 0xED, 0xFD, 0x0E, 0xFF, 0x4D, 0x00, 0xF8, 0x00, 0x15, 0x01, 0xDD, 0x00, 0x51, 0x00, 0x8F, 0xFF, 0xAF, 0xFE, 0xED, 0xFD, 0x1F, 0xFD, 0xD4, 0xFC, 0x44, 0xFD, 0x9F, 0xFD, 0x28, 0xFE, 0xDC, 0xFE, 0x87, 0xFF, 0x2B, 0x00, 0x58, 0x00, 0x3E, 0x00, 0x16, 0x00, 0xE1, 0xFF, 0xBD, 0xFF, 0x97, 0xFF, 0x77, 0xFF, 0x9B, 0xFF, 0x1A, 0x00, 0x90, 0x00, 0xA8, 0x00, 0x9D, 0x00, 0x6A, 0x00, 0x28, 0x00, 0x1D, 0x00, 0x52, 0x00, 0xC4, 0x00, 0x3F, 0x01, 0x70, 0x01, 0x5A, 0x01, 0x1F, 0x01, 0xF8, 0x00, 0xF3, 0x00, 0x25, 0x01, 0x90, 0x01, 0xA6, 0x01, 0x8D, 0x01, 0x4A, 0x01, 0xA0, 0x00, 0x73, 0x00, 0x7E, 0x00, 0x63, 0x00, 0x85, 0x00, 0x76, 0x00, 0x88, 0x00, 0x67, 0x00, 0xC6, 0xFF, 0x4D, 0xFF, 0xCD, 0xFE, 0x9F, 0xFE, 0xB6, 0xFE, 0xBB, 0xFE, 0xF2, 0xFE, 0x2F, 0xFF, 0x6D, 0xFF, 0x8E, 0xFF, 0x7A, 0xFF, 0x64, 0xFF, 0x78, 0xFF, 0x73, 0xFF, 0x4E, 0xFF, 0x71, 0xFF, 0x8A, 0xFF, 0xE9, 0xFF, 0x52, 0x00, 0x5D, 0x00, 0x91, 0x00, 0x40, 0x00, 0xEC, 0xFF, 0x5A, 0x00, 0xCC, 0x00, 0xFF, 0x00, 0xC0, 0x00, 0x79, 0x00, 0x74, 0x00, 0x91, 0x00, 0x04, 0x01, 0x79, 0x01, 0x0B, 0x02, 0x6F, 0x02, 0x69, 0x02, 0x6B, 0x02, 0x23, 0x02, 0xC2, 0x01, 0x5F, 0x01, 0x98, 0x00, 0xDB, 0xFF, 0x09, 0xFF, 0x32, 0xFE, 0xB0, 0xFD, 0x4F, 0xFD, 0x6F, 0xFD, 0xED, 0xFD, 0x5E, 0xFE, 0xFF, 0xFE, 0x9A, 0xFF, 0x0A, 0x00, 0x56, 0x00, 0x2F, 0x00, 0xB8, 0xFF, 0x1B, 0xFF, 0x5C, 0xFE, 0xF8, 0xFD, 0xD1, 0xFD, 0x7C, 0xFD, 0x83, 0xFD, 0xBB, 0xFD, 0xF4, 0xFD, 0x92, 0xFE, 0x1D, 0xFF, 0xCB, 0xFF, 0x60, 0x00, 0xA9, 0x00, 0x2C, 0x01, 0x0E, 0x01, 0xBA, 0x00, 0x9D, 0x00, 0x21, 0x00, 0x16, 0x00, 0x2A, 0x00, 0x35, 0x00, 0xCC, 0x00, 0x44, 0x01, 0xAC, 0x01, 0x22, 0x02, 0x78, 0x02, 0xB8, 0x02, 0xBA, 0x02, 0x8C, 0x02, 0x53, 0x02, 0x18, 0x02, 0xF2, 0x01, 0x1C, 0x02, 0x96, 0x02, 0xE5, 0x02, 0xFB, 0x02, 0x10, 0x03, 0x0E, 0x03, 0x2A, 0x03, 0x5F, 0x03, 0x87, 0x03, 0x03, 0x04, 0xA4, 0x04, 0x1D, 0x05, 0x3D, 0x05, 0x0C, 0x05, 0xD9, 0x04, 0x87, 0x04, 0x4C, 0x04, 0x1B, 0x04, 0x83, 0x03, 0xF7, 0x02, 0x9A, 0x02, 0x54, 0x02, 0x77, 0x02, 0xCA, 0x02, 0x1F, 0x03, 0x75, 0x03, 0x79, 0x03, 0x4D, 0x03, 0x05, 0x03, 0x66, 0x02, 0xE5, 0x01, 0x82, 0x01, 0x56, 0x01, 0x78, 0x01, 0x88, 0x01, 0xEF, 0x01, 0xA9, 0x02, 0x43, 0x03, 0x8A, 0x03, 0x5F, 0x03, 0xFB, 0x02, 0x69, 0x02, 0xBD, 0x01, 0x2F, 0x01, 0xE4, 0x00, 0xBF, 0x00, 0xD2, 0x00, 0x49, 0x01, 0xAE, 0x01, 0x06, 0x02, 0x6A, 0x02, 0xCE, 0x02, 0x47, 0x03, 0x5E, 0x03, 0x18, 0x03, 0x7C, 0x02, 0xD7, 0x01, 0xA1, 0x01, 0x94, 0x01, 0xA7, 0x01, 0xCE, 0x01, 0xF0, 0x01, 0x0E, 0x02, 0x40, 0x02, 0x80, 0x02, 0xF7, 0x02, 0xC5, 0x03, 0x32, 0x04, 0x6C, 0x04, 0x82, 0x04, 0x39, 0x04, 0x04, 0x04, 0x89, 0x03, 0xC7, 0x02, 0x02, 0x02, 0x3F, 0x01, 0xB1, 0x00, 0x24, 0x00, 0xC2, 0xFF, 0xCF, 0xFF, 0x25, 0x00, 0xAE, 0x00, 0x64, 0x01, 0x24, 0x02, 0xFF, 0x02, 0xE1, 0x03, 0x63, 0x04, 0x75, 0x04, 0x03, 0x04, 0x4D, 0x03, 0x7E, 0x02, 0x97, 0x01, 0x0F, 0x01, 0xCA, 0x00, 0xF0, 0x00, 0xB3, 0x01, 0xAC, 0x02, 0xBA, 0x03, 0xBE, 0x04, 0x98, 0x05, 0xF5, 0x05, 0xC8, 0x05, 0x11, 0x05, 0xFD, 0x03, 0x19, 0x03, 0x30, 0x02, 0x78, 0x01, 0x13, 0x01, 0xC1, 0x00, 0x11, 0x01, 0xD2, 0x01, 0x7C, 0x02, 0x0F, 0x03, 0x70, 0x03, 0x86, 0x03, 0x81, 0x03, 0x38, 0x03, 0xA3, 0x02, 0x5E, 0x02, 0x0B, 0x02, 0x83, 0x01, 0x6E, 0x01, 0x99, 0x01, 0x33, 0x02, 0x0B, 0x03, 0x9F, 0x03, 0x5D, 0x04, 0xFF, 0x04, 0x11, 0x05, 0xAD, 0x04, 0x02, 0x04, 0x92, 0x03, 0x37, 0x03, 0xC8, 0x02, 0x5B, 0x02, 0xC3, 0x01, 0x33, 0x01, 0xBD, 0x00, 0x70, 0x00, 0x5A, 0x00, 0x2D, 0x00, 0x0E, 0x00, 0x27, 0x00, 0x7C, 0x00, 0xFA, 0x00, 0x6F, 0x01, 0xCC, 0x01, 0xF5, 0x01, 0xF8, 0x01, 0xEA, 0x01, 0x12, 0x02, 0x9C, 0x02, 0x54, 0x03, 0x17, 0x04, 0xAB, 0x04, 0x4F, 0x05, 0x11, 0x06, 0x91, 0x06, 0x1A, 0x07, 0x9C, 0x07, 0xEE, 0x07, 0x23, 0x08, 0xFD, 0x07, 0xBE, 0x07, 0x51, 0x07, 0x93, 0x06, 0x31, 0x06, 0x14, 0x06, 0x2D, 0x06, 0xA5, 0x06, 0x0B, 0x07, 0x8C, 0x07, 0x1D, 0x08, 0x6F, 0x08, 0x9F, 0x08, 0x65, 0x08, 0xF2, 0x07, 0x7D, 0x07, 0xDB, 0x06, 0x70, 0x06, 0x40, 0x06, 0x07, 0x06, 0xFA, 0x05, 0x34, 0x06, 0x75, 0x06, 0xC5, 0x06, 0x25, 0x07, 0x8B, 0x07, 0xE9, 0x07, 0xC3, 0x07, 0x35, 0x07, 0x59, 0x06, 0x22, 0x05, 0x14, 0x04, 0x6D, 0x03, 0x78, 0x03, 0xE6, 0x03, 0x85, 0x04, 0x5E, 0x05, 0xD7, 0x05, 0x09, 0x06, 0xD6, 0x05, 0x3F, 0x05, 0xA7, 0x04, 0xC9, 0x03, 0xEC, 0x02, 0x2C, 0x02, 0x5C, 0x01, 0xCA, 0x00, 0x63, 0x00, 0x27, 0x00, 0x33, 0x00, 0x49, 0x00, 0x83, 0x00, 0xF6, 0x00, 0x3E, 0x01, 0x74, 0x01, 0x80, 0x01, 0x38, 0x01, 0xDC, 0x00, 0x2F, 0x00, 0x49, 0xFF, 0x45, 0xFE, 0x5D, 0xFD, 0xB6, 0xFC, 0x21, 0xFC, 0xDC, 0xFB, 0xBC, 0xFB, 0xDC, 0xFB, 0x4A, 0xFC, 0xE1, 0xFC, 0xB0, 0xFD, 0x87, 0xFE, 0x79, 0xFF, 0x1E, 0x00, 0xA2, 0x00, 0x3C, 0x01, 0x45, 0x01, 0x0C, 0x01, 0x83, 0x00, 0xD6, 0xFF, 0x60, 0xFF, 0xE5, 0xFE, 0xC5, 0xFE, 0xCC, 0xFE, 0xE2, 0xFE, 0x59, 0xFF, 0xF2, 0xFF, 0xB0, 0x00, 0xB3, 0x01, 0x96, 0x02, 0x47, 0x03, 0xDF, 0x03, 0x06, 0x04, 0xED, 0x03, 0xBC, 0x03, 0x81, 0x03, 0x3F, 0x03, 0xAA, 0x02, 0x23, 0x02, 0xAB, 0x01, 0x62, 0x01, 0x7F, 0x01, 0xA5, 0x01, 0xE9, 0x01, 0x10, 0x02, 0x19, 0x02, 0x26, 0x02, 0x6B, 0x02, 0x2C, 0x03, 0xDF, 0x03, 0xC2, 0x04, 0x8A, 0x05, 0xF5, 0x05, 0x3F, 0x06, 0x31, 0x06, 0x41, 0x06, 0xE9, 0x05, 0x2A, 0x05, 0x79, 0x04, 0x8E, 0x03, 0xE5, 0x02, 0x36, 0x02, 0x90, 0x01, 0x0F, 0x01, 0x86, 0x00, 0x6F, 0x00, 0x19, 0x00, 0xAF, 0xFF, 0xA0, 0xFF, 0x84, 0xFF, 0x9B, 0xFF, 0xA8, 0xFF, 0xC3, 0xFF, 0x05, 0x00, 0x1A, 0x00, 0xF8, 0xFF, 0x72, 0xFF, 0xCF, 0xFE, 0x15, 0xFE, 0x4F, 0xFD, 0xE4, 0xFC, 0x90, 0xFC, 0x3E, 0xFC, 0xE7, 0xFB, 0x80, 0xFB, 0x38, 0xFB, 0xF4, 0xFA, 0xC9, 0xFA, 0xDD, 0xFA, 0x27, 0xFB, 0xA2, 0xFB, 0x10, 0xFC, 0x6E, 0xFC, 0xBF, 0xFC, 0xF5, 0xFC, 0x0F, 0xFD, 0x14, 0xFD, 0x28, 0xFD, 0x2C, 0xFD, 0x44, 0xFD, 0x87, 0xFD, 0xB8, 0xFD, 0x20, 0xFE, 0x95, 0xFE, 0x1D, 0xFF, 0x0B, 0x00, 0xF5, 0x00, 0xC3, 0x01, 0x2B, 0x02, 0x26, 0x02, 0x51, 0x02, 0x54, 0x02, 0x4B, 0x02, 0xB7, 0x02, 0x62, 0x03, 0x2C, 0x04, 0xFF, 0x04, 0xC6, 0x05, 0x7D, 0x06, 0x6A, 0x07, 0x0E, 0x08, 0x0E, 0x08, 0xCB, 0x07, 0xF7, 0x06, 0x10, 0x06, 0x3B, 0x05, 0xCB, 0x04, 0x83, 0x05, 0x44, 0x06, 0x20, 0x07, 0x0E, 0x08, 0x4E, 0x08, 0x4B, 0x08, 0x9F, 0x07, 0x9C, 0x06, 0x99, 0x05, 0x68, 0x04, 0x7D, 0x03, 0xA2, 0x02, 0xF3, 0x01, 0x90, 0x01, 0xB2, 0x01, 0x31, 0x02, 0x66, 0x02, 0x99, 0x02, 0x73, 0x02, 0x11, 0x02, 0xA0, 0x01, 0xCF, 0x00, 0x5E, 0x00, 0x15, 0x00, 0xCE, 0xFF, 0xB1, 0xFF, 0x6B, 0xFF, 0xA2, 0xFF, 0x3A, 0x00, 0xD9, 0x00, 0x53, 0x01, 0x37, 0x01, 0xDA, 0x00, 0x4F, 0x00, 0xDA, 0xFF, 0xD6, 0xFF, 0xBA, 0xFF, 0xC5, 0xFF, 0xFF, 0xFF, 0x2B, 0x00, 0x64, 0x00, 0x6D, 0x00, 0x74, 0x00, 0xA6, 0x00, 0x06, 0x01, 0x88, 0x01, 0x11, 0x02, 0xB4, 0x02, 0x2D, 0x03, 0xBE, 0x03, 0x43, 0x04, 0x6E, 0x04, 0xBC, 0x04, 0x97, 0x04, 0x15, 0x04, 0x8D, 0x03, 0xC3, 0x02, 0x81, 0x02, 0x6F, 0x02, 0x77, 0x02, 0x00, 0x03, 0xA2, 0x03, 0x81, 0x04, 0x5D, 0x05, 0x1C, 0x06, 0xB2, 0x06, 0xBA, 0x06, 0x34, 0x06, 0x37, 0x05, 0x25, 0x04, 0xEC, 0x02, 0xD1, 0x01, 0x38, 0x01, 0xE2, 0x00, 0x26, 0x01, 0x9F, 0x01, 0x29, 0x02, 0xA7, 0x02, 0x88, 0x02, 0xA9, 0x02, 0x8E, 0x02, 0xF5, 0x01, 0xA0, 0x01, 0xF7, 0x00, 0x7F, 0x00, 0x3B, 0x00, 0xBC, 0xFF, 0xAC, 0xFF, 0xC5, 0xFF, 0xF2, 0xFF, 0x37, 0x00, 0x46, 0x00, 0x41, 0x00, 0x07, 0x00, 0xA1, 0xFF, 0x18, 0xFF, 0x7C, 0xFE, 0xCC, 0xFD, 0x26, 0xFD, 0xAA, 0xFC, 0x24, 0xFC, 0xBC, 0xFB, 0x9E, 0xFB, 0xE6, 0xFB, 0x9F, 0xFC, 0x98, 0xFD, 0x97, 0xFE, 0x7E, 0xFF, 0x62, 0x00, 0xC8, 0x00, 0x9C, 0x00, 0x1E, 0x00, 0x71, 0xFF, 0xBE, 0xFE, 0xF7, 0xFD, 0x91, 0xFD, 0x92, 0xFD, 0x7E, 0xFD, 0x52, 0xFD, 0x32, 0xFD, 0x8F, 0xFD, 0x6F, 0xFE, 0x8D, 0xFF, 0xB7, 0x00, 0xB6, 0x01, 0x78, 0x02, 0xF4, 0x02, 0x6E, 0x03, 0xBE, 0x03, 0xE9, 0x03, 0x03, 0x04, 0xD7, 0x03, 0x7B, 0x03, 0xE3, 0x02, 0x87, 0x02, 0x76, 0x02, 0x79, 0x02, 0xB2, 0x02, 0xC8, 0x02, 0xDE, 0x02, 0xCB, 0x02, 0x7E, 0x02, 0x30, 0x02, 0xFD, 0x01, 0x1C, 0x02, 0x47, 0x02, 0x84, 0x02, 0xA2, 0x02, 0x7E, 0x02, 0x1F, 0x02, 0xAF, 0x01, 0x80, 0x01, 0x27, 0x01, 0xE7, 0x00, 0xD2, 0x00, 0x6B, 0x00, 0x14, 0x00, 0xC8, 0xFF, 0x4C, 0xFF, 0xB4, 0xFE, 0x1C, 0xFE, 0x92, 0xFD, 0x06, 0xFD, 0x7B, 0xFC, 0x3B, 0xFC, 0x63, 0xFC, 0x95, 0xFC, 0xB7, 0xFC, 0x95, 0xFC, 0x1E, 0xFC, 0x67, 0xFB, 0x82, 0xFA, 0xA7, 0xF9, 0xB3, 0xF8, 0x29, 0xF8, 0xE4, 0xF7, 0xCE, 0xF7, 0x8E, 0xF8, 0x21, 0xF9, 0x89, 0xF9, 0x11, 0xFA, 0x34, 0xFA, 0x5D, 0xFA, 0x6A, 0xFA, 0x47, 0xFA, 0x40, 0xFA, 0x49, 0xFA, 0x6D, 0xFA, 0xED, 0xFA, 0xB7, 0xFB, 0x5E, 0xFC, 0xE5, 0xFC, 0x33, 0xFD, 0x9E, 0xFD, 0x0C, 0xFE, 0x07, 0xFE, 0x0A, 0xFE, 0xEE, 0xFD, 0xBD, 0xFD, 0xBF, 0xFD, 0xCC, 0xFD, 0xE5, 0xFD, 0x07, 0xFE, 0x28, 0xFE, 0x0E, 0xFE, 0x38, 0xFE, 0xB7, 0xFE, 0x03, 0xFF, 0x62, 0xFF, 0xB1, 0xFF, 0x01, 0x00, 0x79, 0x00, 0xCD, 0x00, 0x10, 0x01, 0x3A, 0x01, 0x3C, 0x01, 0x36, 0x01, 0x13, 0x01, 0xD2, 0x00, 0xA6, 0x00, 0x8D, 0x00, 0x48, 0x00, 0xEC, 0xFF, 0xF2, 0xFF, 0x75, 0x00, 0x4E, 0x01, 0x6B, 0x02, 0x4D, 0x03, 0x07, 0x04, 0x72, 0x04, 0x47, 0x04, 0x13, 0x04, 0x7F, 0x03, 0x97, 0x02, 0xA9, 0x01, 0xCA, 0x00, 0x88, 0x00, 0xAF, 0x00, 0x33, 0x01, 0xA4, 0x01, 0xBD, 0x01, 0xCC, 0x01, 0xA4, 0x01, 0x4B, 0x01, 0x8D, 0x00, 0xCA, 0xFF, 0x18, 0xFF, 0x7B, 0xFE, 0x24, 0xFE, 0x63, 0xFD, 0xD7, 0xFC, 0xA9, 0xFC, 0xA2, 0xFC, 0xEF, 0xFC, 0xFC, 0xFC, 0x27, 0xFD, 0x64, 0xFD, 0x8D, 0xFD, 0x9B, 0xFD, 0x19, 0xFD, 0x63, 0xFC, 0x99, 0xFB, 0x1B, 0xFB, 0xE2, 0xFA, 0xC1, 0xFA, 0xF7, 0xFA, 0x18, 0xFB, 0x50, 0xFB, 0xB3, 0xFB, 0x07, 0xFC, 0x61, 0xFC, 0xC0, 0xFC, 0x16, 0xFD, 0x2C, 0xFD, 0x15, 0xFD, 0xAF, 0xFC, 0x3E, 0xFC, 0xFA, 0xFB, 0x85, 0xFB, 0x47, 0xFB, 0xFD, 0xFA, 0x7F, 0xFA, 0x5E, 0xFA, 0x4B, 0xFA, 0x59, 0xFA, 0x8A, 0xFA, 0x8F, 0xFA, 0xD0, 0xFA, 0x54, 0xFB, 0xF8, 0xFB, 0xEE, 0xFC, 0xEC, 0xFD, 0xCA, 0xFE, 0x93, 0xFF, 0xF4, 0xFF, 0xE9, 0xFF, 0x9F, 0xFF, 0x36, 0xFF, 0x00, 0xFF, 0xF2, 0xFE, 0x01, 0xFF, 0x22, 0xFF, 0xFA, 0xFE, 0xC8, 0xFE, 0xC6, 0xFE, 0xC8, 0xFE, 0xBF, 0xFE, 0x90, 0xFE, 0x6F, 0xFE, 0x79, 0xFE, 0x8A, 0xFE, 0x9C, 0xFE, 0xC8, 0xFE, 0x28, 0xFF, 0x88, 0xFF, 0xF6, 0xFF, 0x43, 0x00, 0x19, 0x00, 0xF0, 0xFF, 0x9A, 0xFF, 0x01, 0xFF, 0x69, 0xFE, 0xC9, 0xFD, 0x69, 0xFD, 0x4A, 0xFD, 0x78, 0xFD, 0xF7, 0xFD, 0x5E, 0xFE, 0xC8, 0xFE, 0x61, 0xFF, 0xFD, 0xFF, 0x6C, 0x00, 0xC7, 0x00, 0xF7, 0x00, 0xC7, 0x00, 0x8C, 0x00, 0x2D, 0x00, 0xC5, 0xFF, 0x7C, 0xFF, 0x35, 0xFF, 0x23, 0xFF, 0xFC, 0xFE, 0xE1, 0xFE, 0xE9, 0xFE, 0xCC, 0xFE, 0xF9, 0xFE, 0x2A, 0xFF, 0x3B, 0xFF, 0x60, 0xFF, 0x1C, 0xFF, 0xD5, 0xFE, 0x71, 0xFE, 0xBA, 0xFD, 0x68, 0xFD, 0x48, 0xFD, 0x75, 0xFD, 0x0A, 0xFE, 0xAE, 0xFE, 0x76, 0xFF, 0x1A, 0x00, 0x6A, 0x00, 0x2D, 0x00, 0x81, 0xFF, 0x96, 0xFE, 0x67, 0xFD, 0x86, 0xFC, 0xCD, 0xFB, 0x4A, 0xFB, 0x3C, 0xFB, 0x51, 0xFB, 0xC2, 0xFB, 0x51, 0xFC, 0xBD, 0xFC, 0xFF, 0xFC, 0xF8, 0xFC, 0xE8, 0xFC, 0xC2, 0xFC, 0x8F, 0xFC, 0x5D, 0xFC, 0x3D, 0xFC, 0x48, 0xFC, 0x6C, 0xFC, 0xA6, 0xFC, 0xBD, 0xFC, 0x10, 0xFD, 0x6A, 0xFD, 0x55, 0xFD, 0x8E, 0xFD, 0xC8, 0xFD, 0xCC, 0xFD, 0xF3, 0xFD, 0xEC, 0xFD, 0x13, 0xFE, 0x38, 0xFE, 0x1E, 0xFE, 0xDA, 0xFD, 0x26, 0xFD, 0x84, 0xFC, 0xFF, 0xFB, 0xE3, 0xFB, 0x48, 0xFC, 0x62, 0xFC, 0x9D, 0xFC, 0xEA, 0xFC, 0x59, 0xFD, 0x28, 0xFE, 0xCA, 0xFE, 0x6F, 0xFF, 0xCD, 0xFF, 0xBC, 0xFF, 0x5A, 0xFF, 0xB7, 0xFE, 0x70, 0xFE, 0x44, 0xFE, 0x64, 0xFE, 0xC0, 0xFE, 0x1F, 0xFF, 0xD2, 0xFF, 0x43, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x5C, 0x00, 0x63, 0x00, 0x19, 0x00, 0xDB, 0xFF, 0x40, 0xFF, 0xED, 0xFE, 0x52, 0xFF, 0xB7, 0xFF, 0x1B, 0x00, 0x3A, 0x00, 0x83, 0x00, 0xBB, 0x00, 0x89, 0x00, 0x7A, 0x00, 0x44, 0x00, 0x1E, 0x00, 0xF7, 0xFF, 0xAA, 0xFF, 0xA1, 0xFF, 0xC3, 0xFF, 0xF3, 0xFF, 0x1D, 0x00, 0x2C, 0x00, 0xCE, 0xFF, 0x54, 0xFF, 0x13, 0xFF, 0xDA, 0xFE, 0xF4, 0xFE, 0x2F, 0xFF, 0x53, 0xFF, 0x5A, 0xFF, 0x67, 0xFF, 0x72, 0xFF, 0x33, 0xFF, 0xE5, 0xFE, 0x5E, 0xFE, 0xBA, 0xFD, 0x27, 0xFD, 0x70, 0xFC, 0xDC, 0xFB, 0x71, 0xFB, 0x35, 0xFB, 0x09, 0xFB, 0xFF, 0xFA, 0x74, 0xFB, 0x08, 0xFC, 0x67, 0xFC, 0x73, 0xFC, 0x01, 0xFC, 0x91, 0xFB, 0x7C, 0xFB, 0x73, 0xFB, 0xA6, 0xFB, 0xD1, 0xFB, 0xB2, 0xFB, 0xEB, 0xFB, 0x35, 0xFC, 0x68, 0xFC, 0xE0, 0xFC, 0x6E, 0xFD, 0xB0, 0xFD, 0xC1, 0xFD, 0xE4, 0xFD, 0xB3, 0xFD, 0xA0, 0xFD, 0xC0, 0xFD, 0x65, 0xFD, 0x41, 0xFD, 0x71, 0xFD, 0xEB, 0xFD, 0xA2, 0xFE, 0x2B, 0xFF, 0xA9, 0xFF, 0xDA, 0xFF, 0xBE, 0xFF, 0x91, 0xFF, 0x91, 0xFF, 0xA3, 0xFF, 0x89, 0xFF, 0x62, 0xFF, 0xF9, 0xFE, 0x9C, 0xFE, 0x95, 0xFE, 0xCB, 0xFE, 0x61, 0xFF, 0xEE, 0xFF, 0x41, 0x00, 0x75, 0x00, 0x5B, 0x00, 0xF0, 0xFF, 0x61, 0xFF, 0xC4, 0xFE, 0x4C, 0xFE, 0xD6, 0xFD, 0x25, 0xFD, 0xBA, 0xFC, 0x6D, 0xFC, 0x2D, 0xFC, 0x78, 0xFC, 0xDE, 0xFC, 0x75, 0xFD, 0x7C, 0xFE, 0x62, 0xFF, 0xE6, 0xFF, 0x30, 0x00, 0x30, 0x00, 0x10, 0x00, 0xFB, 0xFF, 0x95, 0xFF, 0x32, 0xFF, 0xDA, 0xFE, 0x88, 0xFE, 0xA5, 0xFE, 0xD3, 0xFE, 0x19, 0xFF, 0x51, 0xFF, 0x48, 0xFF, 0x42, 0xFF, 0x00, 0xFF, 0xAA, 0xFE, 0x86, 0xFE, 0x7C, 0xFE, 0x3F, 0xFE, 0xF7, 0xFD, 0xBE, 0xFD, 0x3E, 0xFD, 0xF5, 0xFC, 0xB2, 0xFC, 0x71, 0xFC, 0x70, 0xFC, 0x80, 0xFC, 0x10, 0xFD, 0xD6, 0xFD, 0xBE, 0xFE, 0xA3, 0xFF, 0x0A, 0x00, 0x30, 0x00, 0x1E, 0x00, 0xF9, 0xFF, 0xA0, 0xFF, 0x28, 0xFF, 0xCC, 0xFE, 0x61, 0xFE, 0x11, 0xFE, 0xD0, 0xFD, 0xEE, 0xFD, 0x0D, 0xFE, 0xEF, 0xFD, 0x20, 0xFE, 0x5F, 0xFE, 0xA6, 0xFE, 0xB6, 0xFE, 0x95, 0xFE, 0x8F, 0xFE, 0x90, 0xFE, 0xB2, 0xFE, 0x7E, 0xFE, 0x51, 0xFE, 0x44, 0xFE, 0x3E, 0xFE, 0x79, 0xFE, 0x7C, 0xFE, 0xA3, 0xFE, 0xA5, 0xFE, 0x5F, 0xFE, 0x3D, 0xFE, 0x9D, 0xFD, 0xF9, 0xFC, 0x7A, 0xFC, 0xE8, 0xFB, 0x9A, 0xFB, 0x80, 0xFB, 0x97, 0xFB, 0xA2, 0xFB, 0xF1, 0xFB, 0x54, 0xFC, 0x91, 0xFC, 0xE2, 0xFC, 0xD0, 0xFC, 0xC7, 0xFC, 0xD0, 0xFC, 0x90, 0xFC, 0x1D, 0xFC, 0x74, 0xFB, 0xF0, 0xFA, 0x9A, 0xFA, 0xA5, 0xFA, 0xE2, 0xFA, 0x20, 0xFB, 0xA9, 0xFB, 0x0A, 0xFC, 0x71, 0xFC, 0xA1, 0xFC, 0x9F, 0xFC, 0x04, 0xFD, 0x4D, 0xFD, 0xA9, 0xFD, 0xFF, 0xFD, 0xEB, 0xFD, 0x0A, 0xFE, 0x1C, 0xFE, 0xED, 0xFD, 0xEE, 0xFD, 0x00, 0xFE, 0x12, 0xFE, 0x1B, 0xFE, 0xF3, 0xFD, 0xE8, 0xFD, 0x22, 0xFE, 0x7C, 0xFE, 0xF6, 0xFE, 0x52, 0xFF, 0x91, 0xFF, 0xB3, 0xFF, 0xA3, 0xFF, 0x88, 0xFF, 0x4B, 0xFF, 0x15, 0xFF, 0xF6, 0xFE, 0x09, 0xFF, 0x94, 0xFF, 0x18, 0x00, 0x6D, 0x00, 0xD5, 0x00, 0x5D, 0x01, 0x06, 0x02, 0x8E, 0x02, 0xC9, 0x02, 0xE6, 0x02, 0xDE, 0x02, 0x9E, 0x02, 0x3B, 0x02, 0x9F, 0x01, 0x34, 0x01, 0x79, 0x01, 0x1F, 0x02, 0xFF, 0x02, 0xDB, 0x03, 0x3C, 0x04, 0x89, 0x04, 0xC4, 0x04, 0x84, 0x04, 0x68, 0x04, 0x68, 0x04, 0x25, 0x04, 0x0C, 0x04, 0x74, 0x03, 0xB5, 0x02, 0x51, 0x02, 0xAE, 0x01, 0x5F, 0x01, 0x1F, 0x01, 0xD6, 0x00, 0xDB, 0x00, 0x8C, 0x00, 0x2F, 0x00, 0xDF, 0xFF, 0x98, 0xFF, 0x5C, 0xFF, 0x1F, 0xFF, 0x18, 0xFF, 0x23, 0xFF, 0x71, 0xFF, 0x7A, 0xFF, 0x50, 0xFF, 0x5B, 0xFF, 0x4B, 0xFF, 0x5E, 0xFF, 0x0F, 0xFF, 0x48, 0xFE, 0x5B, 0xFD, 0x51, 0xFC, 0xB7, 0xFB, 0x57, 0xFB, 0x54, 0xFB, 0xA3, 0xFB, 0x07, 0xFC, 0x96, 0xFC, 0xF5, 0xFC, 0x7A, 0xFD, 0x1F, 0xFE, 0xB4, 0xFE, 0x46, 0xFF, 0x95, 0xFF, 0xC2, 0xFF, 0xC6, 0xFF, 0xE7, 0xFF, 0x2F, 0x00, 0x55, 0x00, 0x62, 0x00, 0xF7, 0xFF, 0x5C, 0xFF, 0x09, 0xFF, 0x0A, 0xFF, 0x92, 0xFF, 0x74, 0x00, 0x75, 0x01, 0x66, 0x02, 0x0A, 0x03, 0x97, 0x03, 0x2D, 0x04, 0x7E, 0x04, 0x9F, 0x04, 0x8B, 0x04, 0xFD, 0x03, 0x64, 0x03, 0x0B, 0x03, 0xE8, 0x02, 0xFD, 0x02, 0x48, 0x03, 0xC5, 0x03, 0x56, 0x04, 0xEB, 0x04, 0x5C, 0x05, 0x83, 0x05, 0x87, 0x05, 0xC5, 0x05, 0x16, 0x06, 0x10, 0x06, 0xF4, 0x05, 0xAF, 0x05, 0x5E, 0x05, 0x6B, 0x05, 0x62, 0x05, 0x4D, 0x05, 0x25, 0x05, 0x8D, 0x04, 0x00, 0x04, 0x58, 0x03, 0x8F, 0x02, 0x06, 0x02, 0xA2, 0x01, 0x77, 0x01, 0x68, 0x01, 0x60, 0x01, 0x8D, 0x01, 0xF7, 0x01, 0x8E, 0x02, 0x3D, 0x03, 0xA7, 0x03, 0x6B, 0x03, 0x0D, 0x03, 0xC2, 0x02, 0x6F, 0x02, 0x49, 0x02, 0xE9, 0x01, 0x52, 0x01, 0x95, 0x00, 0x90, 0xFF, 0xBC, 0xFE, 0x46, 0xFE, 0x18, 0xFE, 0x47, 0xFE, 0xCF, 0xFE, 0x56, 0xFF, 0xCF, 0xFF, 0x2A, 0x00, 0x38, 0x00, 0x59, 0x00, 0x2D, 0x00, 0xCC, 0xFF, 0x7D, 0xFF, 0xE1, 0xFE, 0x70, 0xFE, 0x11, 0xFE, 0xDB, 0xFD, 0x0A, 0xFE, 0x3E, 0xFE, 0xB5, 0xFE, 0x4C, 0xFF, 0xE2, 0xFF, 0x57, 0x00, 0xBC, 0x00, 0x2E, 0x01, 0x0E, 0x01, 0xEA, 0x00, 0xB1, 0x00, 0x6D, 0x00, 0xA3, 0x00, 0xA2, 0x00, 0xBB, 0x00, 0xDF, 0x00, 0xDA, 0x00, 0x4D, 0x01, 0xFC, 0x01, 0xAC, 0x02, 0xF5, 0x02, 0xDA, 0x02, 0xCD, 0x02, 0xD5, 0x02, 0x0A, 0x03, 0x07, 0x03, 0xE4, 0x02, 0xD4, 0x02, 0x81, 0x02, 0x2A, 0x02, 0xBE, 0x01, 0x51, 0x01, 0x5C, 0x01, 0x87, 0x01, 0xA8, 0x01, 0xF9, 0x01, 0x40, 0x02, 0x98, 0x02, 0x20, 0x03, 0x74, 0x03, 0x94, 0x03, 0x65, 0x03, 0xEA, 0x02, 0x84, 0x02, 0x17, 0x02, 0xB0, 0x01, 0x8A, 0x01, 0x76, 0x01, 0x87, 0x01, 0xE4, 0x01, 0x1B, 0x02, 0x45, 0x02, 0x84, 0x02, 0x9F, 0x02, 0xB8, 0x02, 0xA8, 0x02, 0x46, 0x02, 0xF6, 0x01, 0xBC, 0x01, 0x9F, 0x01, 0xE1, 0x01, 0x24, 0x02, 0x61, 0x02, 0xA5, 0x02, 0x7C, 0x02, 0x1D, 0x02, 0xA7, 0x01, 0x2B, 0x01, 0x11, 0x01, 0x0A, 0x01, 0xEF, 0x00, 0xEA, 0x00, 0xC5, 0x00, 0x91, 0x00, 0xB3, 0x00, 0x17, 0x01, 0x85, 0x01, 0x20, 0x02, 0x8E, 0x02, 0xB1, 0x02, 0x00, 0x03, 0x45, 0x03, 0x52, 0x03, 0x41, 0x03, 0x29, 0x03, 0x3B, 0x03, 0x47, 0x03, 0x1E, 0x03, 0xF6, 0x02, 0xC5, 0x02, 0x70, 0x02, 0x4A, 0x02, 0x59, 0x02, 0x9E, 0x02, 0x1B, 0x03, 0xB5, 0x03, 0xA3, 0x04, 0x59, 0x05, 0x89, 0x05, 0x8E, 0x05, 0x2D, 0x05, 0xA7, 0x04, 0x26, 0x04, 0x99, 0x03, 0x73, 0x03, 0x86, 0x03, 0x9E, 0x03, 0xDC, 0x03, 0x56, 0x04, 0x17, 0x05, 0x97, 0x05, 0x9D, 0x05, 0x54, 0x05, 0xAF, 0x04, 0x2B, 0x04, 0xCE, 0x03, 0x32, 0x03, 0xA8, 0x02, 0x19, 0x02, 0x72, 0x01, 0x08, 0x01, 0xB4, 0x00, 0x5C, 0x00, 0x1C, 0x00, 0xEA, 0xFF, 0xBC, 0xFF, 0x65, 0xFF, 0xBA, 0xFE, 0x11, 0xFE, 0x9B, 0xFD, 0x40, 0xFD, 0x35, 0xFD, 0x5D, 0xFD, 0xD7, 0xFD, 0x08, 0xFF, 0x5D, 0x00, 0x93, 0x01, 0x86, 0x02, 0xC7, 0x02, 0xA1, 0x02, 0x50, 0x02, 0xCD, 0x01, 0x34, 0x01, 0x80, 0x00, 0xEB, 0xFF, 0xBF, 0xFF, 0xB4, 0xFF, 0xC6, 0xFF, 0x01, 0x00, 0x0D, 0x00, 0x32, 0x00, 0x52, 0x00, 0x09, 0x00, 0xC8, 0xFF, 0xC5, 0xFF, 0x0B, 0x00, 0xA0, 0x00, 0x32, 0x01, 0xDE, 0x01, 0xB9, 0x02, 0x90, 0x03, 0x52, 0x04, 0xAD, 0x04, 0xAA, 0x04, 0x8A, 0x04, 0x12, 0x04, 0xCA, 0x03, 0xE9, 0x03, 0x27, 0x04, 0xAA, 0x04, 0x06, 0x05, 0x45, 0x05, 0x89, 0x05, 0xB0, 0x05, 0xDF, 0x05, 0xBE, 0x05, 0x90, 0x05, 0xB0, 0x05, 0xE2, 0x05, 0x1D, 0x06, 0x60, 0x06, 0xB8, 0x06, 0x25, 0x07, 0xAC, 0x07, 0xDD, 0x07, 0x8F, 0x07, 0xFE, 0x06, 0x16, 0x06, 0x23, 0x05, 0x29, 0x04, 0x35, 0x03, 0x8E, 0x02, 0x12, 0x02, 0xE7, 0x01, 0xEB, 0x01, 0xED, 0x01, 0xE9, 0x01, 0xCB, 0x01, 0xBA, 0x01, 0x9E, 0x01, 0x40, 0x01, 0xB3, 0x00, 0x0E, 0x00, 0x45, 0xFF, 0x56, 0xFE, 0x5D, 0xFD, 0xCB, 0xFC, 0x89, 0xFC, 0x5A, 0xFC, 0x7A, 0xFC, 0xB8, 0xFC, 0x0B, 0xFD, 0x55, 0xFD, 0x62, 0xFD, 0x6E, 0xFD, 0x58, 0xFD, 0x4F, 0xFD, 0x3C, 0xFD, 0x04, 0xFD, 0xDC, 0xFC, 0x98, 0xFC, 0x66, 0xFC, 0x2F, 0xFC, 0x21, 0xFC, 0x4B, 0xFC, 0x56, 0xFC, 0x66, 0xFC, 0x5C, 0xFC, 0x80, 0xFC, 0xA2, 0xFC, 0x9E, 0xFC, 0xEF, 0xFC, 0x40, 0xFD, 0x8D, 0xFD, 0xC1, 0xFD, 0xB2, 0xFD, 0x98, 0xFD, 0x6D, 0xFD, 0x5C, 0xFD, 0x79, 0xFD, 0xB3, 0xFD, 0x11, 0xFE, 0x62, 0xFE, 0x81, 0xFE, 0x8F, 0xFE, 0xA8, 0xFE, 0xE2, 0xFE, 0x34, 0xFF, 0x69, 0xFF, 0xC1, 0xFF, 0x16, 0x00, 0x64, 0x00, 0xFE, 0x00, 0x60, 0x01, 0x74, 0x01, 0x8B, 0x01, 0xA8, 0x01, 0xD2, 0x01, 0x22, 0x02, 0x75, 0x02, 0x81, 0x02, 0x70, 0x02, 0xFB, 0x01, 0x82, 0x01, 0x69, 0x01, 0x7E, 0x01, 0x33, 0x02, 0xE2, 0x02, 0x2E, 0x03, 0x28, 0x03, 0xAA, 0x02, 0x5E, 0x02, 0x07, 0x02, 0x9E, 0x01, 0x52, 0x01, 0xEC, 0x00, 0x83, 0x00, 0x0B, 0x00, 0xB4, 0xFF, 0x7E, 0xFF, 0x8C, 0xFF, 0xAF, 0xFF, 0xB6, 0xFF, 0xEE, 0xFF, 0x24, 0x00, 0x7D, 0x00, 0xE1, 0x00, 0x45, 0x01, 0xE2, 0x01, 0x4B, 0x02, 0x6A, 0x02, 0x1A, 0x02, 0x2D, 0x01, 0xFC, 0xFF, 0xD9, 0xFE, 0xCC, 0xFD, 0x05, 0xFD, 0xDE, 0xFC, 0x38, 0xFD, 0x9A, 0xFD, 0x08, 0xFE, 0xB5, 0xFE, 0x3F, 0xFF, 0x95, 0xFF, 0x9B, 0xFF, 0x23, 0xFF, 0xBF, 0xFE, 0x33, 0xFE, 0x96, 0xFD, 0x35, 0xFD, 0xEB, 0xFC, 0x02, 0xFD, 0x44, 0xFD, 0xF3, 0xFD, 0x9A, 0xFE, 0xF2, 0xFE, 0x4C, 0xFF, 0x4D, 0xFF, 0x7A, 0xFF, 0x94, 0xFF, 0xB2, 0xFF, 0x1A, 0x00, 0x32, 0x00, 0x93, 0x00, 0xB3, 0x00, 0xB0, 0x00, 0x14, 0x01, 0x50, 0x01, 0xDB, 0x01, 0x68, 0x02, 0xD6, 0x02, 0x2E, 0x03, 0x14, 0x03, 0xE6, 0x02, 0xE0, 0x02, 0xEE, 0x02, 0x84, 0x02, 0xEB, 0x01, 0x35, 0x01, 0x7B, 0x00, 0x53, 0x00, 0xF3, 0xFF, 0x9F, 0xFF, 0x8A, 0xFF, 0x91, 0xFF, 0x1D, 0x00, 0x62, 0x00, 0x6E, 0x00, 0x7D, 0x00, 0x94, 0x00, 0xCC, 0x00, 0x8D, 0x00, 0x15, 0x00, 0x7A, 0xFF, 0xBF, 0xFE, 0x05, 0xFE, 0x1F, 0xFD, 0x77, 0xFC, 0x23, 0xFC, 0x38, 0xFC, 0x8C, 0xFC, 0x18, 0xFD, 0xFE, 0xFD, 0xBD, 0xFE, 0x43, 0xFF, 0x66, 0xFF, 0x2D, 0xFF, 0xC1, 0xFE, 0xFD, 0xFD, 0x4A, 0xFD, 0x7A, 0xFC, 0xB0, 0xFB, 0x54, 0xFB, 0x32, 0xFB, 0xBA, 0xFB, 0xAB, 0xFC, 0x9E, 0xFD, 0xA6, 0xFE, 0x60, 0xFF, 0xFA, 0xFF, 0x81, 0x00, 0xE1, 0x00, 0x02, 0x01, 0xA8, 0x00, 0x4A, 0x00, 0xEC, 0xFF, 0x68, 0xFF, 0xF2, 0xFE, 0x80, 0xFE, 0x4A, 0xFE, 0x4A, 0xFE, 0xA3, 0xFE, 0x27, 0xFF, 0x8C, 0xFF, 0x2F, 0x00, 0xBC, 0x00, 0x3B, 0x01, 0xCA, 0x01, 0xEF, 0x01, 0x04, 0x02, 0x17, 0x02, 0xFF, 0x01, 0xF6, 0x01, 0xCC, 0x01, 0xA7, 0x01, 0xDA, 0x01, 0x1E, 0x02, 0x34, 0x02, 0x66, 0x02, 0x92, 0x02, 0xB3, 0x02, 0x12, 0x03, 0xE6, 0x02, 0x37, 0x02, 0x8D, 0x01, 0xC7, 0x00, 0x6A, 0x00, 0x41, 0x00, 0x36, 0x00, 0xA1, 0x00, 0x1C, 0x01, 0xC0, 0x01, 0x3F, 0x02, 0x4B, 0x02, 0x24, 0x02, 0xA0, 0x01, 0x15, 0x01, 0x91, 0x00, 0xE2, 0xFF, 0x47, 0xFF, 0xAA, 0xFE, 0x32, 0xFE, 0x3D, 0xFE, 0xAA, 0xFE, 0x0A, 0xFF, 0x44, 0xFF, 0x49, 0xFF, 0xF8, 0xFE, 0xA1, 0xFE, 0x66, 0xFE, 0x1A, 0xFE, 0xF5, 0xFD, 0x07, 0xFE, 0x02, 0xFE, 0x04, 0xFE, 0x05, 0xFE, 0xBE, 0xFD, 0x91, 0xFD, 0x71, 0xFD, 0x41, 0xFD, 0x33, 0xFD, 0x14, 0xFD, 0x37, 0xFD, 0x74, 0xFD, 0x67, 0xFD, 0x63, 0xFD, 0x53, 0xFD, 0x60, 0xFD, 0x92, 0xFD, 0xAC, 0xFD, 0xE4, 0xFD, 0x3C, 0xFE, 0x88, 0xFE, 0xD3, 0xFE, 0x5A, 0xFF, 0x07, 0x00, 0xC1, 0x00, 0x58, 0x01, 0x3E, 0x01, 0xC9, 0x00, 0x50, 0x00, 0xDF, 0xFF, 0xB7, 0xFF, 0xAB, 0xFF, 0x9F, 0xFF, 0xA2, 0xFF, 0xCB, 0xFF, 0x01, 0x00, 0x3C, 0x00, 0xC1, 0x00, 0x37, 0x01, 0x71, 0x01, 0x7C, 0x01, 0x4A, 0x01, 0x36, 0x01, 0x38, 0x01, 0x6D, 0x01, 0xB7, 0x01, 0xBB, 0x01, 0xD0, 0x01, 0xD3, 0x01, 0xC4, 0x01, 0xF7, 0x01, 0x0A, 0x02, 0xD2, 0x01, 0x54, 0x01, 0x78, 0x00, 0xC0, 0xFF, 0x93, 0xFF, 0xA1, 0xFF, 0x95, 0xFF, 0x5D, 0xFF, 0x36, 0xFF, 0x27, 0xFF, 0x04, 0xFF, 0x0C, 0xFF, 0x20, 0xFF, 0x1B, 0xFF, 0x28, 0xFF, 0x1E, 0xFF, 0x20, 0xFF, 0x22, 0xFF, 0x05, 0xFF, 0xCF, 0xFE, 0x88, 0xFE, 0x54, 0xFE, 0xDB, 0xFD, 0x33, 0xFD, 0xDC, 0xFC, 0xB8, 0xFC, 0xB1, 0xFC, 0xC1, 0xFC, 0xDF, 0xFC, 0x2B, 0xFD, 0xCA, 0xFD, 0x4B, 0xFE, 0x95, 0xFE, 0xEA, 0xFE, 0x18, 0xFF, 0x68, 0xFF, 0x66, 0xFF, 0xEA, 0xFE, 0x9D, 0xFE, 0x22, 0xFE, 0xDD, 0xFD, 0xF6, 0xFD, 0xE3, 0xFD, 0x3A, 0xFE, 0xBD, 0xFE, 0x18, 0xFF, 0x92, 0xFF, 0xC8, 0xFF, 0xD4, 0xFF, 0xBC, 0xFF, 0x38, 0xFF, 0xD9, 0xFE, 0x9E, 0xFE, 0x2A, 0xFE, 0x0E, 0xFE, 0x4A, 0xFE, 0xA0, 0xFE, 0x4C, 0xFF, 0xF9, 0xFF, 0x63, 0x00, 0xC1, 0x00, 0xD1, 0x00, 0x8A, 0x00, 0x4A, 0x00, 0x13, 0x00, 0xFA, 0xFF, 0xEE, 0xFF, 0xC2, 0xFF, 0xA1, 0xFF, 0x6A, 0xFF, 0x71, 0xFF, 0x91, 0xFF, 0x94, 0xFF, 0xD7, 0xFF, 0xDF, 0xFF, 0xE1, 0xFF, 0x1E, 0x00, 0x44, 0x00, 0x61, 0x00, 0x64, 0x00, 0x7B, 0x00, 0x73, 0x00, 0x3B, 0x00, 0xD5, 0xFF, 0x49, 0xFF, 0xCF, 0xFE, 0x5B, 0xFE, 0x52, 0xFE, 0x51, 0xFE, 0x64, 0xFE, 0xD2, 0xFE, 0x00, 0xFF, 0x68, 0xFF, 0xD0, 0xFF, 0x1C, 0x00, 0x61, 0x00, 0x34, 0x00, 0xEF, 0xFF, 0x75, 0xFF, 0xFB, 0xFE, 0x6B, 0xFE, 0xE7, 0xFD, 0xE0, 0xFD, 0xDC, 0xFD, 0x4A, 0xFE, 0xF4, 0xFE, 0x82, 0xFF, 0x27, 0x00, 0x91, 0x00, 0xC8, 0x00, 0x77, 0x00, 0xE9, 0xFF, 0x60, 0xFF, 0xC4, 0xFE, 0x40, 0xFE, 0xD7, 0xFD, 0xF1, 0xFD, 0x3D, 0xFE, 0xBA, 0xFE, 0x71, 0xFF, 0xED, 0xFF, 0x58, 0x00, 0x95, 0x00, 0xB7, 0x00, 0xA9, 0x00, 0x7E, 0x00, 0x92, 0x00, 0xBE, 0x00, 0xFD, 0x00, 0x39, 0x01, 0x75, 0x01, 0x7B, 0x01, 0x6A, 0x01, 0x64, 0x01, 0x73, 0x01, 0xC1, 0x01, 0xBD, 0x01, 0xB9, 0x01, 0xB0, 0x01, 0x6E, 0x01, 0x47, 0x01, 0x03, 0x01, 0x21, 0x01, 0x3F, 0x01, 0x2D, 0x01, 0x41, 0x01, 0x02, 0x01, 0xFD, 0x00, 0x1E, 0x01, 0x3E, 0x01, 0x63, 0x01, 0x6A, 0x01, 0xA6, 0x01, 0xCD, 0x01, 0xF0, 0x01, 0xE1, 0x01, 0x8D, 0x01, 0x31, 0x01, 0x92, 0x00, 0x56, 0x00, 0x70, 0x00, 0x96, 0x00, 0xB6, 0x00, 0xA6, 0x00, 0xF7, 0x00, 0x79, 0x01, 0xFE, 0x01, 0x7F, 0x02, 0xCE, 0x02, 0xE4, 0x02, 0xB1, 0x02, 0x61, 0x02, 0xC3, 0x01, 0x40, 0x01, 0xFF, 0x00, 0x7A, 0x00, 0xF1, 0xFF, 0x60, 0xFF, 0x0E, 0xFF, 0x1F, 0xFF, 0x30, 0xFF, 0x8E, 0xFF, 0xFC, 0xFF, 0x42, 0x00, 0x69, 0x00, 0x06, 0x00, 0x6A, 0xFF, 0xD1, 0xFE, 0x47, 0xFE, 0xDA, 0xFD, 0x89, 0xFD, 0xA6, 0xFD, 0xC5, 0xFD, 0xBE, 0xFD, 0xC9, 0xFD, 0xC4, 0xFD, 0xF6, 0xFD, 0x10, 0xFE, 0x03, 0xFE, 0x09, 0xFE, 0x0C, 0xFE, 0x46, 0xFE, 0x64, 0xFE, 0x72, 0xFE, 0x92, 0xFE, 0x99, 0xFE, 0xAE, 0xFE, 0x85, 0xFE, 0x4F, 0xFE, 0x33, 0xFE, 0x46, 0xFE, 0xBA, 0xFE, 0x18, 0xFF, 0x65, 0xFF, 0xB7, 0xFF, 0xF2, 0xFF, 0x6C, 0x00, 0xD5, 0x00, 0xDB, 0x00, 0xE4, 0x00, 0x02, 0x01, 0x16, 0x01, 0x56, 0x01, 0x69, 0x01, 0x4A, 0x01, 0x3F, 0x01, 0xF7, 0x00, 0x82, 0x00, 0xEA, 0xFF, 0x41, 0xFF, 0xA2, 0xFE, 0x0E, 0xFE, 0x99, 0xFD, 0x3E, 0xFD, 0x72, 0xFD, 0xE9, 0xFD, 0x5B, 0xFE, 0xF3, 0xFE, 0x5D, 0xFF, 0xD2, 0xFF, 0x1B, 0x00, 0xFB, 0xFF, 0x80, 0xFF, 0xD3, 0xFE, 0x4D, 0xFE, 0xA3, 0xFD, 0x25, 0xFD, 0xE0, 0xFC, 0x76, 0xFC, 0x39, 0xFC, 0x3E, 0xFC, 0x7D, 0xFC, 0xC9, 0xFC, 0x20, 0xFD, 0x3A, 0xFD, 0x41, 0xFD, 0xA5, 0xFD, 0xD8, 0xFD, 0x1E, 0xFE, 0x68, 0xFE, 0x64, 0xFE, 0x69, 0xFE, 0x0E, 0xFE, 0xA4, 0xFD, 0x5B, 0xFD, 0x02, 0xFD, 0xD9, 0xFC, 0xD0, 0xFC, 0x12, 0xFD, 0x86, 0xFD, 0xE4, 0xFD, 0x60, 0xFE, 0x31, 0xFF, 0xFD, 0xFF, 0x85, 0x00, 0xCC, 0x00, 0x89, 0x00, 0x30, 0x00, 0x00, 0x00, 0xB7, 0xFF, 0xA3, 0xFF, 0xAC, 0xFF, 0xDF, 0xFF, 0x5A, 0x00, 0xC9, 0x00, 0x1C, 0x01, 0x6A, 0x01, 0xBB, 0x01, 0xE2, 0x01, 0xD2, 0x01, 0xA8, 0x01, 0x88, 0x01, 0x6F, 0x01, 0x3F, 0x01, 0x31, 0x01, 0x37, 0x01, 0x19, 0x01, 0x0D, 0x01, 0xF2, 0x00, 0xB3, 0x00, 0x8E, 0x00, 0x62, 0x00, 0x5C, 0x00, 0x9D, 0x00, 0xCB, 0x00, 0xE2, 0x00, 0xD8, 0x00, 0x85, 0x00, 0x1E, 0x00, 0xE4, 0xFF, 0xE5, 0xFF, 0x20, 0x00, 0xBC, 0x00, 0x52, 0x01, 0xAF, 0x01, 0xFC, 0x01, 0xE8, 0x01, 0xAF, 0x01, 0x6E, 0x01, 0xF5, 0x00, 0x82, 0x00, 0xB3, 0xFF, 0x91, 0xFE, 0xC9, 0xFD, 0x3D, 0xFD, 0xF1, 0xFC, 0x45, 0xFD, 0xD5, 0xFD, 0x6C, 0xFE, 0x03, 0xFF, 0x41, 0xFF, 0x5F, 0xFF, 0x57, 0xFF, 0x46, 0xFF, 0x7A, 0xFF, 0x85, 0xFF, 0x4B, 0xFF, 0x03, 0xFF, 0xD3, 0xFE, 0xB9, 0xFE, 0xCB, 0xFE, 0x15, 0xFF, 0x4F, 0xFF, 0x85, 0xFF, 0xAC, 0xFF, 0xDE, 0xFF, 0xEA, 0xFF, 0xB5, 0xFF, 0x94, 0xFF, 0x33, 0xFF, 0xA9, 0xFE, 0x08, 0xFE, 0x73, 0xFD, 0x40, 0xFD, 0x26, 0xFD, 0x5E, 0xFD, 0x90, 0xFD, 0xB9, 0xFD, 0x4D, 0xFE, 0xE6, 0xFE, 0x73, 0xFF, 0xCF, 0xFF, 0x08, 0x00, 0x23, 0x00, 0xF9, 0xFF, 0x9D, 0xFF, 0x22, 0xFF, 0x1E, 0xFF, 0x5F, 0xFF, 0xAF, 0xFF, 0x2F, 0x00, 0x91, 0x00, 0xF8, 0x00, 0x2F, 0x01, 0x6E, 0x01, 0xB5, 0x01, 0xBF, 0x01, 0xDE, 0x01, 0x82, 0x01, 0xE4, 0x00, 0x88, 0x00, 0x3D, 0x00, 0x2D, 0x00, 0x27, 0x00, 0x4D, 0x00, 0xB4, 0x00, 0x1D, 0x01, 0x7D, 0x01, 0x85, 0x01, 0x81, 0x01, 0x69, 0x01, 0x3A, 0x01, 0x3F, 0x01, 0x2E, 0x01, 0x2B, 0x01, 0x28, 0x01, 0xE8, 0x00, 0xA7, 0x00, 0x74, 0x00, 0x5F, 0x00, 0x74, 0x00, 0xC8, 0x00, 0x45, 0x01, 0xC3, 0x01, 0x3E, 0x02, 0xC8, 0x02, 0x78, 0x03, 0xE9, 0x03, 0xD0, 0x03, 0x39, 0x03, 0x7D, 0x02, 0x92, 0x01, 0x55, 0x00, 0x6D, 0xFF, 0xA5, 0xFE, 0x0D, 0xFE, 0xFC, 0xFD, 0xE5, 0xFD, 0x0C, 0xFE, 0x69, 0xFE, 0xE9, 0xFE, 0x59, 0xFF, 0x8C, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0xC1, 0xFF, 0x50, 0xFF, 0x6C, 0xFE, 0xD4, 0xFD, 0x67, 0xFD, 0x3A, 0xFD, 0x09, 0xFD, 0xED, 0xFC, 0x1F, 0xFD, 0x46, 0xFD, 0xDC, 0xFD, 0x5E, 0xFE, 0xDA, 0xFE, 0x47, 0xFF, 0x17, 0xFF, 0xFA, 0xFE, 0x8B, 0xFE, 0x49, 0xFE, 0x80, 0xFE, 0xA7, 0xFE, 0x1B, 0xFF, 0x78, 0xFF, 0xD3, 0xFF, 0x03, 0x00, 0xF4, 0xFF, 0xB3, 0xFF, 0x35, 0xFF, 0xFD, 0xFE, 0x9F, 0xFE, 0x8A, 0xFE, 0xC1, 0xFE, 0xD0, 0xFE, 0x1D, 0xFF, 0x0F, 0xFF, 0x22, 0xFF, 0x5F, 0xFF, 0x6B, 0xFF, 0xC2, 0xFF, 0xF8, 0xFF, 0x39, 0x00, 0x58, 0x00, 0x30, 0x00, 0xEF, 0xFF, 0x51, 0xFF, 0xD3, 0xFE, 0x64, 0xFE, 0x12, 0xFE, 0xDD, 0xFD, 0x84, 0xFD, 0x50, 0xFD, 0x10, 0xFD, 0x22, 0xFD, 0x87, 0xFD, 0xDA, 0xFD, 0x53, 0xFE, 0x99, 0xFE, 0xA7, 0xFE, 0x9D, 0xFE, 0x56, 0xFE, 0x03, 0xFE, 0xBB, 0xFD, 0xB1, 0xFD, 0xD1, 0xFD, 0xF3, 0xFD, 0x25, 0xFE, 0x10, 0xFE, 0xE2, 0xFD, 0xEC, 0xFD, 0x0D, 0xFE, 0x43, 0xFE, 0x63, 0xFE, 0x84, 0xFE, 0xB6, 0xFE, 0xDA, 0xFE, 0xF5, 0xFE, 0xD5, 0xFE, 0x83, 0xFE, 0x1F, 0xFE, 0xB6, 0xFD, 0x65, 0xFD, 0x1C, 0xFD, 0xF3, 0xFC, 0xF4, 0xFC, 0x60, 0xFD, 0x21, 0xFE, 0xD4, 0xFE, 0x8E, 0xFF, 0xFC, 0xFF, 0x2A, 0x00, 0x57, 0x00, 0x0F, 0x00, 0x8D, 0xFF, 0x27, 0xFF, 0xEB, 0xFE, 0x14, 0xFF, 0x62, 0xFF, 0xCE, 0xFF, 0x56, 0x00, 0xC7, 0x00, 0x27, 0x01, 0x52, 0x01, 0x55, 0x01, 0x40, 0x01, 0x09, 0x01, 0xC9, 0x00, 0x58, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x7B, 0x00, 0xDA, 0x00, 0x3B, 0x01, 0xA1, 0x01, 0xD1, 0x01, 0xE5, 0x01, 0xA7, 0x01, 0x60, 0x01, 0x0D, 0x01, 0xA5, 0x00, 0x73, 0x00, 0x52, 0x00, 0x8F, 0x00, 0xF9, 0x00, 0x63, 0x01, 0xFA, 0x01, 0x60, 0x02, 0xA9, 0x02, 0xC2, 0x02, 0xAB, 0x02, 0x80, 0x02, 0x31, 0x02, 0xE8, 0x01, 0xA2, 0x01, 0x5B, 0x01, 0x03, 0x01, 0xB2, 0x00, 0x76, 0x00, 0x34, 0x00, 0x1F, 0x00, 0x2F, 0x00, 0x79, 0x00, 0xD5, 0x00, 0x39, 0x01, 0xD5, 0x01, 0x27, 0x02, 0x4E, 0x02, 0x6A, 0x02, 0x31, 0x02, 0xD5, 0x01, 0x7A, 0x01, 0x40, 0x01, 0x22, 0x01, 0xF1, 0x00, 0xE7, 0x00, 0xFB, 0x00, 0x23, 0x01, 0x7F, 0x01, 0xB7, 0x01, 0xCC, 0x01, 0x23, 0x02, 0x48, 0x02, 0x35, 0x02, 0x2F, 0x02, 0xFE, 0x01, 0xF2, 0x01, 0x29, 0x02, 0x0F, 0x02, 0xC7, 0x01, 0x97, 0x01, 0x63, 0x01, 0xAC, 0x01, 0x48, 0x02, 0x97, 0x02, 0xDB, 0x02, 0xC8, 0x02, 0x7A, 0x02, 0x40, 0x02, 0xBD, 0x01, 0x35, 0x01, 0x92, 0x00, 0x08, 0x00, 0xD2, 0xFF, 0x9E, 0xFF, 0xCB, 0xFF, 0x28, 0x00, 0xAE, 0x00, 0x4A, 0x01, 0x9A, 0x01, 0xD8, 0x01, 0xB1, 0x01, 0x41, 0x01, 0xCB, 0x00, 0x32, 0x00, 0xC2, 0xFF, 0x65, 0xFF, 0x41, 0xFF, 0x67, 0xFF, 0xA0, 0xFF, 0xE3, 0xFF, 0x12, 0x00, 0x2F, 0x00, 0x38, 0x00, 0x32, 0x00, 0xEF, 0xFF, 0xA5, 0xFF, 0x8D, 0xFF, 0x43, 0xFF, 0x12, 0xFF, 0x18, 0xFF, 0x32, 0xFF, 0x87, 0xFF, 0xD7, 0xFF, 0xE8, 0xFF, 0xD3, 0xFF, 0xF8, 0xFF, 0x24, 0x00, 0x51, 0x00, 0xB3, 0x00, 0xF3, 0x00, 0x32, 0x01, 0x44, 0x01, 0xEF, 0x00, 0x69, 0x00, 0xAE, 0xFF, 0x0D, 0xFF, 0x61, 0xFE, 0x98, 0xFD, 0x11, 0xFD, 0xDF, 0xFC, 0x05, 0xFD, 0x5E, 0xFD, 0xF0, 0xFD, 0x95, 0xFE, 0x25, 0xFF, 0xAE, 0xFF, 0x09, 0x00, 0x38, 0x00, 0x39, 0x00, 0x14, 0x00, 0xCB, 0xFF, 0x6F, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x84, 0xFF, 0xE0, 0xFF, 0x37, 0x00, 0x9A, 0x00, 0xCE, 0x00, 0xF4, 0x00, 0x02, 0x01, 0xED, 0x00, 0xD1, 0x00, 0xC1, 0x00, 0xAE, 0x00, 0x8F, 0x00, 0x88, 0x00, 0xA6, 0x00, 0xC3, 0x00, 0xD1, 0x00, 0x14, 0x01, 0x8C, 0x01, 0xD7, 0x01, 0x41, 0x02, 0xEB, 0x02, 0x72, 0x03, 0xD3, 0x03, 0xEE, 0x03, 0xC6, 0x03, 0xAE, 0x03, 0x83, 0x03, 0x21, 0x03, 0xE5, 0x02, 0xB8, 0x02, 0xA4, 0x02, 0xD1, 0x02, 0x0D, 0x03, 0x77, 0x03, 0xC7, 0x03, 0xE0, 0x03, 0xFD, 0x03, 0xDB, 0x03, 0xA2, 0x03, 0x4B, 0x03, 0x8D, 0x02, 0xCF, 0x01, 0x4D, 0x01, 0x0D, 0x01, 0x2C, 0x01, 0x60, 0x01, 0x9C, 0x01, 0xFD, 0x01, 0x46, 0x02, 0x88, 0x02, 0xB3, 0x02, 0xC4, 0x02, 0xED, 0x02, 0xD0, 0x02, 0x8F, 0x02, 0x6D, 0x02, 0x19, 0x02, 0xAE, 0x01, 0x4F, 0x01, 0x2B, 0x01, 0x32, 0x01, 0x0E, 0x01, 0xB6, 0x00, 0x57, 0x00, 0x29, 0x00, 0x00, 0x00, 0xF4, 0xFF, 0x0A, 0x00, 0xF8, 0xFF, 0xF5, 0xFF, 0xCB, 0xFF, 0x7F, 0xFF, 0x7D, 0xFF, 0x86, 0xFF, 0xA2, 0xFF, 0xA2, 0xFF, 0x36, 0xFF, 0xD2, 0xFE, 0x88, 0xFE, 0x67, 0xFE, 0x90, 0xFE, 0xE1, 0xFE, 0x69, 0xFF, 0xDB, 0xFF, 0xFA, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x0A, 0x00, 0x2D, 0x00, 0x41, 0x00, 0x2A, 0x00, 0x28, 0x00, 0x1A, 0x00, 0x29, 0x00, 0xB6, 0x00, 0x3E, 0x01, 0x68, 0x01, 0x4D, 0x01, 0x0A, 0x01, 0xB3, 0x00, 0x4A, 0x00, 0xEC, 0xFF, 0x86, 0xFF, 0x54, 0xFF, 0x86, 0xFF, 0xD0, 0xFF, 0x43, 0x00, 0xA7, 0x00, 0xA8, 0x00, 0x7F, 0x00, 0x37, 0x00, 0xCE, 0xFF, 0xBE, 0xFF, 0xF0, 0xFF, 0x09, 0x00, 0x4E, 0x00, 0x59, 0x00, 0x36, 0x00, 0x4E, 0x00, 0x40, 0x00, 0x5B, 0x00, 0x7D, 0x00, 0x51, 0x00, 0x21, 0x00, 0xA8, 0xFF, 0x14, 0xFF, 0xE7, 0xFE, 0xFE, 0xFE, 0xF8, 0xFE, 0xFE, 0xFE, 0x29, 0xFF, 0x40, 0xFF, 0x71, 0xFF, 0x86, 0xFF, 0x81, 0xFF, 0xB5, 0xFF, 0xE2, 0xFF, 0x06, 0x00, 0x17, 0x00, 0x04, 0x00, 0xF5, 0xFF, 0xF9, 0xFF, 0x07, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x31, 0x00, 0x5D, 0x00, 0x6D, 0x00, 0x8F, 0x00, 0xB4, 0x00, 0xED, 0x00, 0x18, 0x01, 0x52, 0x01, 0xCA, 0x01, 0x10, 0x02, 0x3B, 0x02, 0x57, 0x02, 0x35, 0x02, 0x29, 0x02, 0x23, 0x02, 0x1B, 0x02, 0x29, 0x02, 0x02, 0x02, 0xC7, 0x01, 0xAF, 0x01, 0xAB, 0x01, 0xD9, 0x01, 0x1E, 0x02, 0x63, 0x02, 0xA6, 0x02, 0x9F, 0x02, 0x49, 0x02, 0xAD, 0x01, 0xCF, 0x00, 0x16, 0x00, 0xA1, 0xFF, 0x50, 0xFF, 0x50, 0xFF, 0x80, 0xFF, 0xBF, 0xFF, 0xFB, 0xFF, 0xF2, 0xFF, 0xD6, 0xFF, 0xB4, 0xFF, 0x68, 0xFF, 0x47, 0xFF, 0x27, 0xFF, 0xF0, 0xFE, 0xCE, 0xFE, 0x8D, 0xFE, 0x7D, 0xFE, 0x9D, 0xFE, 0x9B, 0xFE, 0xBD, 0xFE, 0xCA, 0xFE, 0x9D, 0xFE, 0x79, 0xFE, 0x28, 0xFE, 0xCB, 0xFD, 0x84, 0xFD, 0x7F, 0xFD, 0xBF, 0xFD, 0xD6, 0xFD, 0x09, 0xFE, 0x33, 0xFE, 0x07, 0xFE, 0xD8, 0xFD, 0xAA, 0xFD, 0x99, 0xFD, 0xB0, 0xFD, 0xD8, 0xFD, 0xF3, 0xFD, 0x32, 0xFE, 0x9A, 0xFE, 0xAD, 0xFE, 0xC3, 0xFE, 0xCB, 0xFE, 0xD8, 0xFE, 0x28, 0xFF, 0x3D, 0xFF, 0x5D, 0xFF, 0x91, 0xFF, 0xBA, 0xFF, 0xF2, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xDF, 0xFF, 0xC3, 0xFF, 0xB8, 0xFF, 0xAF, 0xFF, 0xA8, 0xFF, 0x88, 0xFF, 0x86, 0xFF, 0x80, 0xFF, 0x9B, 0xFF, 0xDE, 0xFF, 0x29, 0x00, 0x94, 0x00, 0xD2, 0x00, 0x1D, 0x01, 0x58, 0x01, 0x7B, 0x01, 0xAD, 0x01, 0x93, 0x01, 0x51, 0x01, 0xB5, 0x00, 0x1A, 0x00, 0xA3, 0xFF, 0xF8, 0xFE, 0xA8, 0xFE, 0x88, 0xFE, 0x89, 0xFE, 0xE3, 0xFE, 0x78, 0xFF, 0x4B, 0x00, 0x0B, 0x01, 0x8D, 0x01, 0xCE, 0x01, 0xB4, 0x01, 0x3D, 0x01, 0xA4, 0x00, 0x15, 0x00, 0xAD, 0xFF, 0x50, 0xFF, 0x0C, 0xFF, 0x0B, 0xFF, 0x02, 0xFF, 0x42, 0xFF, 0xB9, 0xFF, 0x23, 0x00, 0xBB, 0x00, 0x08, 0x01, 0x65, 0x01, 0xDC, 0x01, 0x08, 0x02, 0x3A, 0x02, 0x37, 0x02, 0xF0, 0x01, 0x83, 0x01, 0x25, 0x01, 0xC4, 0x00, 0x80, 0x00, 0x9A, 0x00, 0xAB, 0x00, 0xD1, 0x00, 0xD9, 0x00, 0xCA, 0x00, 0xC8, 0x00, 0x89, 0x00, 0x64, 0x00, 0x27, 0x00, 0xFB, 0xFF, 0xDE, 0xFF, 0xB6, 0xFF, 0xD7, 0xFF, 0xF5, 0xFF, 0x2C, 0x00, 0x66, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x19, 0x00, 0x0A, 0x00, 0xDC, 0xFF, 0xCE, 0xFF, 0xB4, 0xFF, 0x5B, 0xFF, 0x32, 0xFF, 0xF1, 0xFE, 0xE2, 0xFE, 0xC6, 0xFE, 0x77, 0xFE, 0x71, 0xFE, 0x61, 0xFE, 0x4C, 0xFE, 0x30, 0xFE, 0x24, 0xFE, 0x42, 0xFE, 0x57, 0xFE, 0x96, 0xFE, 0xFF, 0xFE, 0x80, 0xFF, 0xF7, 0xFF, 0x2E, 0x00, 0x3C, 0x00, 0x27, 0x00, 0x04, 0x00, 0x02, 0x00, 0x14, 0x00, 0x59, 0x00, 0xAD, 0x00, 0x0A, 0x01, 0xB8, 0x01, 0x4C, 0x02, 0x92, 0x02, 0xA2, 0x02, 0x89, 0x02, 0x6E, 0x02, 0x11, 0x02, 0xA5, 0x01, 0x21, 0x01, 0xBC, 0x00, 0xCF, 0x00, 0xDB, 0x00, 0x0E, 0x01, 0x39, 0x01, 0x63, 0x01, 0xDD, 0x01, 0x2B, 0x02, 0x5B, 0x02, 0x7C, 0x02, 0xA4, 0x02, 0x9B, 0x02, 0x43, 0x02, 0xF3, 0x01, 0x80, 0x01, 0x43, 0x01, 0x53, 0x01, 0x6C, 0x01, 0x74, 0x01, 0x33, 0x01, 0x01, 0x01, 0xE1, 0x00, 0xA3, 0x00, 0xAD, 0x00, 0xA8, 0x00, 0x3A, 0x00, 0xD9, 0xFF, 0x80, 0xFF, 0x17, 0xFF, 0xEA, 0xFE, 0xBF, 0xFE, 0xC7, 0xFE, 0x0A, 0xFF, 0x47, 0xFF, 0x84, 0xFF, 0xA0, 0xFF, 0xD8, 0xFF, 0x1A, 0x00, 0x70, 0x00, 0xB8, 0x00, 0xA9, 0x00, 0xA3, 0x00, 0xB0, 0x00, 0xDE, 0x00, 0xDE, 0x00, 0xA1, 0x00, 0x4C, 0x00, 0xB1, 0xFF, 0x6C, 0xFF, 0x60, 0xFF, 0x70, 0xFF, 0x9C, 0xFF, 0xB2, 0xFF, 0xDB, 0xFF, 0xE3, 0xFF, 0x11, 0x00, 0x46, 0x00, 0x62, 0x00, 0x7F, 0x00, 0x5A, 0x00, 0x43, 0x00, 0xFB, 0xFF, 0xC6, 0xFF, 0xBB, 0xFF, 0x7F, 0xFF, 0x7C, 0xFF, 0x48, 0xFF, 0x07, 0xFF, 0xCB, 0xFE, 0x54, 0xFE, 0x0A, 0xFE, 0xD9, 0xFD, 0xB8, 0xFD, 0x8D, 0xFD, 0x6F, 0xFD, 0x75, 0xFD, 0xA2, 0xFD, 0x02, 0xFE, 0x1A, 0xFE, 0xF3, 0xFD, 0x80, 0xFD, 0xE7, 0xFC, 0x77, 0xFC, 0xDF, 0xFB, 0x71, 0xFB, 0x4B, 0xFB, 0x41, 0xFB, 0x64, 0xFB, 0x90, 0xFB, 0x06, 0xFC, 0x91, 0xFC, 0x03, 0xFD, 0x7B, 0xFD, 0xDB, 0xFD, 0x36, 0xFE, 0x92, 0xFE, 0xCC, 0xFE, 0xD1, 0xFE, 0x06, 0xFF, 0x8B, 0xFF, 0xF1, 0xFF, 0x49, 0x00, 0x89, 0x00, 0x81, 0x00, 0x51, 0x00, 0x09, 0x00, 0xD1, 0xFF, 0x9F, 0xFF, 0x78, 0xFF, 0x92, 0xFF, 0x0B, 0x00, 0xD2, 0x00, 0x45, 0x01, 0x70, 0x01, 0x6C, 0x01, 0x29, 0x01, 0x1A, 0x01, 0x20, 0x01, 0x8A, 0x01, 0x4C, 0x02, 0xD5, 0x02, 0x5B, 0x03, 0x8B, 0x03, 0x87, 0x03, 0x95, 0x03, 0x86, 0x03, 0x65, 0x03, 0x2F, 0x03, 0xE8, 0x02, 0x67, 0x02, 0x0D, 0x02, 0xE0, 0x01, 0xA8, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0x40, 0x02, 0xB8, 0x02, 0x1D, 0x03, 0x6C, 0x03, 0xA3, 0x03, 0xC0, 0x03, 0x6F, 0x03, 0x1F, 0x03, 0xE8, 0x02, 0x80, 0x02, 0x4E, 0x02, 0x19, 0x02, 0xF1, 0x01, 0xB7, 0x01, 0x35, 0x01, 0xC1, 0x00, 0x43, 0x00, 0x0A, 0x00, 0x13, 0x00, 0x0B, 0x00, 0x2A, 0x00, 0x6F, 0x00, 0xAF, 0x00, 0x07, 0x01, 0x5A, 0x01, 0x55, 0x01, 0x2E, 0x01, 0xB3, 0x00, 0xEB, 0xFF, 0x6F, 0xFF, 0x38, 0xFF, 0x40, 0xFF, 0x33, 0xFF, 0x13, 0xFF, 0x2A, 0xFF, 0x75, 0xFF, 0xFB, 0xFF, 0x69, 0x00, 0xDD, 0x00, 0x2C, 0x01, 0x23, 0x01, 0xC1, 0x00, 0x1F, 0x00, 0xC6, 0xFF, 0x9B, 0xFF, 0xCD, 0xFF, 0x25, 0x00, 0x33, 0x00, 0x6B, 0x00, 0x5C, 0x00, 0x12, 0x00, 0xC8, 0xFF, 0x42, 0xFF, 0xC2, 0xFE, 0x2D, 0xFE, 0x7D, 0xFD, 0xE7, 0xFC, 0x8B, 0xFC, 0x55, 0xFC, 0x6C, 0xFC, 0xC0, 0xFC, 0xEE, 0xFC, 0x40, 0xFD, 0x7F, 0xFD, 0xA4, 0xFD, 0xB1, 0xFD, 0x84, 0xFD, 0x96, 0xFD, 0x8D, 0xFD, 0x71, 0xFD, 0x7A, 0xFD, 0x79, 0xFD, 0x9A, 0xFD, 0x9D, 0xFD, 0x9A, 0xFD, 0x88, 0xFD, 0x55, 0xFD, 0x4A, 0xFD, 0x5E, 0xFD, 0x99, 0xFD, 0xCC, 0xFD, 0xF5, 0xFD, 0x20, 0xFE, 0x3A, 0xFE, 0x74, 0xFE, 0xB3, 0xFE, 0xFE, 0xFE, 0x4F, 0xFF, 0xA6, 0xFF, 0xF8, 0xFF, 0x41, 0x00, 0x94, 0x00, 0xC2, 0x00, 0x00, 0x01, 0x5A, 0x01, 0x9F, 0x01, 0xE6, 0x01, 0x24, 0x02, 0x39, 0x02, 0x2E, 0x02, 0x2A, 0x02, 0x02, 0x02, 0xC4, 0x01, 0x85, 0x01, 0x54, 0x01, 0x8F, 0x01, 0xEC, 0x01, 0xA9, 0x02, 0x8A, 0x03, 0x2D, 0x04, 0xD5, 0x04, 0xE5, 0x04, 0xA9, 0x04, 0x63, 0x04, 0xCA, 0x03, 0x58, 0x03, 0xDD, 0x02, 0x96, 0x02, 0x86, 0x02, 0x6F, 0x02, 0x96, 0x02, 0xBC, 0x02, 0xFE, 0x02, 0x30, 0x03, 0x44, 0x03, 0x62, 0x03, 0x4D, 0x03, 0x29, 0x03, 0xB6, 0x02, 0x0C, 0x02, 0x89, 0x01, 0x04, 0x01, 0xB2, 0x00, 0x90, 0x00, 0x7E, 0x00, 0x6A, 0x00, 0x5B, 0x00, 0x60, 0x00, 0x6B, 0x00, 0x90, 0x00, 0x76, 0x00, 0x47, 0x00, 0x4C, 0x00, 0x28, 0x00, 0xFD, 0xFF, 0xB8, 0xFF, 0x54, 0xFF, 0x20, 0xFF, 0xE0, 0xFE, 0xC9, 0xFE, 0xD1, 0xFE, 0xD3, 0xFE, 0xFE, 0xFE, 0x14, 0xFF, 0x3E, 0xFF, 0x7E, 0xFF, 0x9A, 0xFF, 0x95, 0xFF, 0x07, 0xFF, 0x4E, 0xFE, 0xD7, 0xFD, 0x91, 0xFD, 0xD0, 0xFD, 0x0B, 0xFE, 0x06, 0xFE, 0x29, 0xFE, 0x42, 0xFE, 0x63, 0xFE, 0x99, 0xFE, 0xCF, 0xFE, 0xFD, 0xFE, 0xF7, 0xFE, 0xC3, 0xFE, 0x60, 0xFE, 0xEC, 0xFD, 0x7B, 0xFD, 0x35, 0xFD, 0xE4, 0xFC, 0x7E, 0xFC, 0x4A, 0xFC, 0xF4, 0xFB, 0xF1, 0xFB, 0x3F, 0xFC, 0x77, 0xFC, 0x04, 0xFD, 0x3A, 0xFD, 0x31, 0xFD, 0x50, 0xFD, 0x4E, 0xFD, 0x72, 0xFD, 0x7F, 0xFD, 0x85, 0xFD, 0xA4, 0xFD, 0xA8, 0xFD, 0x9A, 0xFD, 0x62, 0xFD, 0x29, 0xFD, 0xE9, 0xFC, 0xE6, 0xFC, 0x18, 0xFD, 0x52, 0xFD, 0xA4, 0xFD, 0xB5, 0xFD, 0xDB, 0xFD, 0x06, 0xFE, 0xF7, 0xFD, 0x13, 0xFE, 0x41, 0xFE, 0xB5, 0xFE, 0x34, 0xFF, 0x78, 0xFF, 0x91, 0xFF, 0x67, 0xFF, 0x58, 0xFF, 0x6A, 0xFF, 0x5B, 0xFF, 0x4C, 0xFF, 0x4F, 0xFF, 0x47, 0xFF, 0x39, 0xFF, 0x2D, 0xFF, 0xF7, 0xFE, 0xCD, 0xFE, 0xC6, 0xFE, 0xE3, 0xFE, 0x01, 0xFF, 0xCE, 0xFE, 0xDD, 0xFE, 0x18, 0xFF, 0x28, 0xFF, 0x65, 0xFF, 0xA8, 0xFF, 0xD1, 0xFF, 0xD3, 0xFF, 0xBE, 0xFF, 0xBE, 0xFF, 0xAF, 0xFF, 0x9A, 0xFF, 0x7D, 0xFF, 0x50, 0xFF, 0x2A, 0xFF, 0xF0, 0xFE, 0xAF, 0xFE, 0x94, 0xFE, 0x79, 0xFE, 0x97, 0xFE, 0xF0, 0xFE, 0xFD, 0xFE, 0xF3, 0xFE, 0xC6, 0xFE, 0x6C, 0xFE, 0x13, 0xFE, 0x85, 0xFD, 0x50, 0xFD, 0x5A, 0xFD, 0x76, 0xFD, 0xFA, 0xFD, 0x5A, 0xFE, 0x97, 0xFE, 0xE7, 0xFE, 0x1F, 0xFF, 0x1F, 0xFF, 0xD4, 0xFE, 0x92, 0xFE, 0x56, 0xFE, 0x17, 0xFE, 0xE3, 0xFD, 0xE1, 0xFD, 0x53, 0xFE, 0xEB, 0xFE, 0x76, 0xFF, 0xAC, 0xFF, 0xA3, 0xFF, 0xB2, 0xFF, 0xB6, 0xFF, 0x02, 0x00, 0x43, 0x00, 0x42, 0x00, 0x7B, 0x00, 0x5C, 0x00, 0x17, 0x00, 0xDA, 0xFF, 0x7C, 0xFF, 0x93, 0xFF, 0xB5, 0xFF, 0xEE, 0xFF, 0x6E, 0x00, 0xAD, 0x00, 0xEA, 0x00, 0x1B, 0x01, 0x27, 0x01, 0x28, 0x01, 0xC4, 0x00, 0x11, 0x00, 0x6E, 0xFF, 0xCB, 0xFE, 0x2C, 0xFE, 0xEE, 0xFD, 0xDC, 0xFD, 0xF7, 0xFD, 0x77, 0xFE, 0xDE, 0xFE, 0x38, 0xFF, 0x75, 0xFF, 0x6B, 0xFF, 0x33, 0xFF, 0xB4, 0xFE, 0x63, 0xFE, 0x38, 0xFE, 0x19, 0xFE, 0x2F, 0xFE, 0x22, 0xFE, 0x0D, 0xFE, 0xFD, 0xFD, 0xEC, 0xFD, 0xEB, 0xFD, 0xE3, 0xFD, 0xDC, 0xFD, 0xD4, 0xFD, 0xCD, 0xFD, 0xB6, 0xFD, 0xC0, 0xFD, 0xF4, 0xFD, 0xFF, 0xFD, 0xF8, 0xFD, 0xDE, 0xFD, 0xE1, 0xFD, 0x37, 0xFE, 0x93, 0xFE, 0x0B, 0xFF, 0x75, 0xFF, 0x83, 0xFF, 0xAD, 0xFF, 0xED, 0xFF, 0xFD, 0xFF, 0x2D, 0x00, 0x4C, 0x00, 0x5C, 0x00, 0x55, 0x00, 0xD0, 0xFF, 0x50, 0xFF, 0xE4, 0xFE, 0xA6, 0xFE, 0xE2, 0xFE, 0x15, 0xFF, 0x65, 0xFF, 0xC9, 0xFF, 0x0C, 0x00, 0x58, 0x00, 0x7E, 0x00, 0xA8, 0x00, 0xDB, 0x00, 0xF4, 0x00, 0x03, 0x01, 0xE4, 0x00, 0xCE, 0x00, 0xF0, 0x00, 0x12, 0x01, 0x28, 0x01, 0x2A, 0x01, 0xFC, 0x00, 0xC5, 0x00, 0x8A, 0x00, 0x4E, 0x00, 0x1C, 0x00, 0xD3, 0xFF, 0x8D, 0xFF, 0x40, 0xFF, 0xF6, 0xFE, 0xD8, 0xFE, 0x03, 0xFF, 0x5C, 0xFF, 0xA1, 0xFF, 0xFD, 0xFF, 0x3D, 0x00, 0x73, 0x00, 0x98, 0x00, 0x60, 0x00, 0x3C, 0x00, 0x25, 0x00, 0xFA, 0xFF, 0xD0, 0xFF, 0xA1, 0xFF, 0x61, 0xFF, 0xD7, 0xFE, 0x61, 0xFE, 0x00, 0xFE, 0xEC, 0xFD, 0x2D, 0xFE, 0x4A, 0xFE, 0x82, 0xFE, 0x99, 0xFE, 0xC0, 0xFE, 0xFC, 0xFE, 0x0C, 0xFF, 0x53, 0xFF, 0x76, 0xFF, 0xB4, 0xFF, 0xEF, 0xFF, 0xC5, 0xFF, 0x70, 0xFF, 0xDB, 0xFE, 0x6B, 0xFE, 0x13, 0xFE, 0xDD, 0xFD, 0xDD, 0xFD, 0xC7, 0xFD, 0xEE, 0xFD, 0x1A, 0xFE, 0x78, 0xFE, 0x1E, 0xFF, 0x9D, 0xFF, 0x2D, 0x00, 0x71, 0x00, 0x5B, 0x00, 0x50, 0x00, 0x13, 0x00, 0xDA, 0xFF, 0xF3, 0xFF, 0x4F, 0x00, 0xC6, 0x00, 0x24, 0x01, 0x71, 0x01, 0x8D, 0x01, 0x76, 0x01, 0x53, 0x01, 0x03, 0x01, 0xCE, 0x00, 0xE9, 0x00, 0x35, 0x01, 0xB5, 0x01, 0x53, 0x02, 0xE9, 0x02, 0x41, 0x03, 0x68, 0x03, 0x62, 0x03, 0x32, 0x03, 0x38, 0x03, 0x34, 0x03, 0x38, 0x03, 0x70, 0x03, 0x84, 0x03, 0x9D, 0x03, 0xAD, 0x03, 0xCD, 0x03, 0xEC, 0x03, 0xEF, 0x03, 0xF8, 0x03, 0xBC, 0x03, 0x89, 0x03, 0x72, 0x03, 0x5E, 0x03, 0x76, 0x03, 0x5F, 0x03, 0x31, 0x03, 0xEF, 0x02, 0xA5, 0x02, 0x68, 0x02, 0x20, 0x02, 0xE7, 0x01, 0xA9, 0x01, 0x98, 0x01, 0x84, 0x01, 0x85, 0x01, 0xC9, 0x01, 0xAF, 0x01, 0x90, 0x01, 0x55, 0x01, 0xAE, 0x00, 0x41, 0x00, 0xD6, 0xFF, 0x83, 0xFF, 0x7E, 0xFF, 0x65, 0xFF, 0x55, 0xFF, 0x5B, 0xFF, 0x76, 0xFF, 0x95, 0xFF, 0x85, 0xFF, 0x2A, 0xFF, 0xC3, 0xFE, 0x44, 0xFE, 0xAF, 0xFD, 0x59, 0xFD, 0x01, 0xFD, 0xE0, 0xFC, 0xF1, 0xFC, 0xC0, 0xFC, 0xB2, 0xFC, 0xCA, 0xFC, 0x0A, 0xFD, 0x52, 0xFD, 0x56, 0xFD, 0x55, 0xFD, 0x42, 0xFD, 0x28, 0xFD, 0x12, 0xFD, 0x49, 0xFD, 0xB4, 0xFD, 0xF2, 0xFD, 0x1E, 0xFE, 0x13, 0xFE, 0x21, 0xFE, 0x30, 0xFE, 0x24, 0xFE, 0x35, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x11, 0xFE, 0x45, 0xFE, 0xBF, 0xFE, 0x35, 0xFF, 0x13, 0x00, 0x89, 0x00, 0xCE, 0x00, 0x13, 0x01, 0x0B, 0x01, 0x49, 0x01, 0x4F, 0x01, 0x69, 0x01, 0x92, 0x01, 0x97, 0x01, 0xE0, 0x01, 0x1E, 0x02, 0x7C, 0x02, 0xB1, 0x02, 0xBD, 0x02, 0x9A, 0x02, 0x42, 0x02, 0x11, 0x02, 0xC4, 0x01, 0xD9, 0x01, 0x09, 0x02, 0x41, 0x02, 0x99, 0x02, 0xBE, 0x02, 0x1B, 0x03, 0x0D, 0x03, 0x0C, 0x03, 0x4A, 0x03, 0x37, 0x03, 0x7B, 0x03, 0x77, 0x03, 0x4E, 0x03, 0x56, 0x03, 0x16, 0x03, 0xDD, 0x02, 0x77, 0x02, 0x23, 0x02, 0x10, 0x02, 0xF1, 0x01, 0xF0, 0x01, 0xFD, 0x01, 0x10, 0x02, 0x41, 0x02, 0x57, 0x02, 0x44, 0x02, 0x48, 0x02, 0x4D, 0x02, 0x7C, 0x02, 0xB3, 0x02, 0xBD, 0x02, 0xC5, 0x02, 0x6B, 0x02, 0xD1, 0x01, 0x7C, 0x01, 0x3D, 0x01, 0xE1, 0x00, 0xB5, 0x00, 0x62, 0x00, 0xF8, 0xFF, 0x22, 0x00, 0x4E, 0x00, 0xB5, 0x00, 0x35, 0x01, 0x51, 0x01, 0x93, 0x01, 0x55, 0x01, 0xF7, 0x00, 0x83, 0x00, 0xC1, 0xFF, 0x94, 0xFF, 0x61, 0xFF, 0x5D, 0xFF, 0x7A, 0xFF, 0x6C, 0xFF, 0x9D, 0xFF, 0x9E, 0xFF, 0xB5, 0xFF, 0xBA, 0xFF, 0xBD, 0xFF, 0xBF, 0xFF, 0x94, 0xFF, 0xC8, 0xFF, 0xD4, 0xFF, 0xEC, 0xFF, 0x2A, 0x00, 0x3B, 0x00, 0x94, 0x00, 0xE6, 0x00, 0x0F, 0x01, 0x11, 0x01, 0xE7, 0x00, 0xA0, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4D, 0x00, 0x60, 0x00, 0x6D, 0x00, 0x93, 0x00, 0xDE, 0x00, 0x00, 0x01, 0x2A, 0x01, 0x5C, 0x01, 0x93, 0x01, 0xD3, 0x01, 0xEC, 0x01, 0xD8, 0x01, 0xC5, 0x01, 0xA0, 0x01, 0x85, 0x01, 0xA4, 0x01, 0x91, 0x01, 0x98, 0x01, 0x8C, 0x01, 0x3E, 0x01, 0x2B, 0x01, 0xFE, 0x00, 0xFD, 0x00, 0x15, 0x01, 0x07, 0x01, 0x30, 0x01, 0x7D, 0x01, 0xD9, 0x01, 0x2E, 0x02, 0x86, 0x02, 0x8D, 0x02, 0x5F, 0x02, 0x29, 0x02, 0x8F, 0x01, 0x19, 0x01, 0x99, 0x00, 0x27, 0x00, 0x11, 0x00, 0xE7, 0xFF, 0xF3, 0xFF, 0xEA, 0xFF, 0xD1, 0xFF, 0xDF, 0xFF, 0xA2, 0xFF, 0x67, 0xFF, 0x15, 0xFF, 0xCF, 0xFE, 0xC4, 0xFE, 0xA7, 0xFE, 0xC5, 0xFE, 0x34, 0xFF, 0xAE, 0xFF, 0x1B, 0x00, 0x50, 0x00, 0x60, 0x00, 0x7E, 0x00, 0x8A, 0x00, 0x63, 0x00, 0x29, 0x00, 0xE9, 0xFF, 0xA5, 0xFF, 0x77, 0xFF, 0x53, 0xFF, 0x52, 0xFF, 0x7F, 0xFF, 0x99, 0xFF, 0xD8, 0xFF, 0x47, 0x00, 0xA1, 0x00, 0x17, 0x01, 0x80, 0x01, 0xD4, 0x01, 0x14, 0x02, 0x05, 0x02, 0xE7, 0x01, 0x9A, 0x01, 0x36, 0x01, 0xFD, 0x00, 0xAF, 0x00, 0x58, 0x00, 0x41, 0x00, 0x79, 0x00, 0xEB, 0x00, 0x76, 0x01, 0xCA, 0x01, 0xE4, 0x01, 0xF5, 0x01, 0xDA, 0x01, 0xB8, 0x01, 0xA0, 0x01, 0x76, 0x01, 0x1F, 0x01, 0x8D, 0x00, 0x01, 0x00, 0x80, 0xFF, 0x2E, 0xFF, 0x36, 0xFF, 0x71, 0xFF, 0xD2, 0xFF, 0x06, 0x00, 0x0F, 0x00, 0x11, 0x00, 0x00, 0x00, 0xC5, 0xFF, 0x54, 0xFF, 0xF0, 0xFE, 0x90, 0xFE, 0x3C, 0xFE, 0x4B, 0xFE, 0x71, 0xFE, 0xCC, 0xFE, 0x5F, 0xFF, 0xD9, 0xFF, 0x56, 0x00, 0xA2, 0x00, 0xDC, 0x00, 0x08, 0x01, 0xD1, 0x00, 0x9D, 0x00, 0x6C, 0x00, 0x52, 0x00, 0x60, 0x00, 0x7B, 0x00, 0x95, 0x00, 0x82, 0x00, 0x7D, 0x00, 0x49, 0x00, 0x43, 0x00, 0x79, 0x00, 0x72, 0x00, 0xC0, 0x00, 0xF1, 0x00, 0x04, 0x01, 0x25, 0x01, 0x0A, 0x01, 0x10, 0x01, 0xE6, 0x00, 0xCF, 0x00, 0xCA, 0x00, 0xA2, 0x00, 0x9F, 0x00, 0x53, 0x00, 0x29, 0x00, 0x15, 0x00, 0xF9, 0xFF, 0xD4, 0xFF, 0x6B, 0xFF, 0x4F, 0xFF, 0x4A, 0xFF, 0x62, 0xFF, 0x86, 0xFF, 0xA4, 0xFF, 0xFC, 0xFF, 0x2F, 0x00, 0x89, 0x00, 0xDA, 0x00, 0x1B, 0x01, 0x89, 0x01, 0xB7, 0x01, 0xC9, 0x01, 0x8B, 0x01, 0x4D, 0x01, 0x2F, 0x01, 0x0C, 0x01, 0x15, 0x01, 0xED, 0x00, 0xAE, 0x00, 0x55, 0x00, 0xFB, 0xFF, 0xEB, 0xFF, 0xFC, 0xFF, 0x6A, 0x00, 0xFD, 0x00, 0x63, 0x01, 0xB1, 0x01, 0xD1, 0x01, 0xCF, 0x01, 0xBE, 0x01, 0x74, 0x01, 0x0F, 0x01, 0xCA, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x28, 0x00, 0x14, 0x00, 0x3E, 0x00, 0x86, 0x00, 0x76, 0x00, 0x4E, 0x00, 0x31, 0x00, 0x06, 0x00, 0x1E, 0x00, 0x2E, 0x00, 0x20, 0x00, 0x48, 0x00, 0x5E, 0x00, 0x72, 0x00, 0x5A, 0x00, 0x17, 0x00, 0xE9, 0xFF, 0x73, 0xFF, 0xF9, 0xFE, 0x89, 0xFE, 0x38, 0xFE, 0x3D, 0xFE, 0x48, 0xFE, 0x73, 0xFE, 0x67, 0xFE, 0x39, 0xFE, 0x21, 0xFE, 0xDD, 0xFD, 0xA0, 0xFD, 0x75, 0xFD, 0x2F, 0xFD, 0xF2, 0xFC, 0xDA, 0xFC, 0xE7, 0xFC, 0x2B, 0xFD, 0x5D, 0xFD, 0x63, 0xFD, 0x65, 0xFD, 0x2A, 0xFD, 0xF3, 0xFC, 0xB2, 0xFC, 0x53, 0xFC, 0x2C, 0xFC, 0xEC, 0xFB, 0xAB, 0xFB, 0xA0, 0xFB, 0xBA, 0xFB, 0x13, 0xFC, 0xAA, 0xFC, 0x4F, 0xFD, 0xC2, 0xFD, 0x15, 0xFE, 0x23, 0xFE, 0x0C, 0xFE, 0xD7, 0xFD, 0x68, 0xFD, 0x06, 0xFD, 0xB1, 0xFC, 0xAE, 0xFC, 0xFB, 0xFC, 0x77, 0xFD, 0x21, 0xFE, 0xB8, 0xFE, 0x5F, 0xFF, 0xE7, 0xFF, 0x44, 0x00, 0x72, 0x00, 0x68, 0x00, 0x7C, 0x00, 0x7B, 0x00, 0x90, 0x00, 0xC1, 0x00, 0xE5, 0x00, 0x0F, 0x01, 0x2A, 0x01, 0x53, 0x01, 0x77, 0x01, 0x95, 0x01, 0xAF, 0x01, 0xCC, 0x01, 0x00, 0x02, 0x3B, 0x02, 0x90, 0x02, 0xB6, 0x02, 0xCA, 0x02, 0xBD, 0x02, 0x59, 0x02, 0x20, 0x02, 0x15, 0x02, 0x2B, 0x02, 0x73, 0x02, 0xC2, 0x02, 0x0D, 0x03, 0x43, 0x03, 0x5E, 0x03, 0x71, 0x03, 0x77, 0x03, 0x2F, 0x03, 0xB2, 0x02, 0x13, 0x02, 0x7D, 0x01, 0xEF, 0x00, 0x39, 0x00, 0xD1, 0xFF, 0xB9, 0xFF, 0xB6, 0xFF, 0xAE, 0xFF, 0xB7, 0xFF, 0x06, 0x00, 0x42, 0x00, 0x85, 0x00, 0xB3, 0x00, 0xA2, 0x00, 0x83, 0x00, 0x30, 0x00, 0xE2, 0xFF, 0x83, 0xFF, 0x54, 0xFF, 0x64, 0xFF, 0x68, 0xFF, 0xAD, 0xFF, 0xF6, 0xFF, 0x3E, 0x00, 0x79, 0x00, 0x60, 0x00, 0x3B, 0x00, 0x13, 0x00, 0x10, 0x00, 0x06, 0x00, 0xE8, 0xFF, 0xF5, 0xFF, 0xDB, 0xFF, 0xBD, 0xFF, 0xDD, 0xFF, 0x24, 0x00, 0x75, 0x00, 0xA2, 0x00, 0x7F, 0x00, 0x19, 0x00, 0xC4, 0xFF, 0xA7, 0xFF, 0x94, 0xFF, 0x7F, 0xFF, 0x63, 0xFF, 0x29, 0xFF, 0xD9, 0xFE, 0x90, 0xFE, 0x4C, 0xFE, 0x2A, 0xFE, 0x33, 0xFE, 0x32, 0xFE, 0x23, 0xFE, 0x24, 0xFE, 0x3D, 0xFE, 0x6C, 0xFE, 0x91, 0xFE, 0xA1, 0xFE, 0xA2, 0xFE, 0x5F, 0xFE, 0xF7, 0xFD, 0x74, 0xFD, 0xE9, 0xFC, 0xBA, 0xFC, 0xA5, 0xFC, 0x99, 0xFC, 0x92, 0xFC, 0x7B, 0xFC, 0x85, 0xFC, 0xA1, 0xFC, 0xD8, 0xFC, 0x0C, 0xFD, 0x31, 0xFD, 0x4B, 0xFD, 0x46, 0xFD, 0x31, 0xFD, 0xF8, 0xFC, 0x19, 0xFD, 0x74, 0xFD, 0xAE, 0xFD, 0xFC, 0xFD, 0xFC, 0xFD, 0x15, 0xFE, 0x52, 0xFE, 0x47, 0xFE, 0x6E, 0xFE, 0xA2, 0xFE, 0xE1, 0xFE, 0x32, 0xFF, 0x2F, 0xFF, 0x47, 0xFF, 0x87, 0xFF, 0xD2, 0xFF, 0x5A, 0x00, 0xC4, 0x00, 0x3A, 0x01, 0xB1, 0x01, 0xF0, 0x01, 0x33, 0x02, 0x2B, 0x02, 0x04, 0x02, 0xCE, 0x01, 0x46, 0x01, 0xE5, 0x00, 0x7B, 0x00, 0x07, 0x00, 0xBC, 0xFF, 0x76, 0xFF, 0x5A, 0xFF, 0x57, 0xFF, 0x77, 0xFF, 0x9A, 0xFF, 0xF4, 0xFF, 0x6D, 0x00, 0xB9, 0x00, 0x29, 0x01, 0x5E, 0x01, 0xA9, 0x01, 0xFD, 0x01, 0xD8, 0x01, 0xB0, 0x01, 0x2A, 0x01, 0x9B, 0x00, 0x3E, 0x00, 0xC6, 0xFF, 0x97, 0xFF, 0x71, 0xFF, 0x75, 0xFF, 0x9E, 0xFF, 0xCA, 0xFF, 0x05, 0x00, 0x1D, 0x00, 0x49, 0x00, 0x35, 0x00, 0xE8, 0xFF, 0xB3, 0xFF, 0x82, 0xFF, 0x8F, 0xFF, 0x8F, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x65, 0xFF, 0x84, 0xFF, 0xD2, 0xFF, 0x0B, 0x00, 0x26, 0x00, 0x24, 0x00, 0xEB, 0xFF, 0x9C, 0xFF, 0x5B, 0xFF, 0x25, 0xFF, 0xFE, 0xFE, 0xEB, 0xFE, 0xD4, 0xFE, 0xB3, 0xFE, 0xD0, 0xFE, 0x23, 0xFF, 0x6C, 0xFF, 0xB2, 0xFF, 0xE3, 0xFF, 0xF8, 0xFF, 0xCA, 0xFF, 0x68, 0xFF, 0x07, 0xFF, 0xAA, 0xFE, 0x9F, 0xFE, 0xA5, 0xFE, 0xA2, 0xFE, 0xC8, 0xFE, 0xF3, 0xFE, 0x42, 0xFF, 0x6F, 0xFF, 0x7A, 0xFF, 0x97, 0xFF, 0x92, 0xFF, 0x9D, 0xFF, 0xBE, 0xFF, 0x12, 0x00, 0x58, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x1F, 0x00, 0x96, 0xFF, 0x21, 0xFF, 0xC4, 0xFE, 0xAE, 0xFE, 0xBA, 0xFE, 0x1D, 0xFF, 0x90, 0xFF, 0xD3, 0xFF, 0x2F, 0x00, 0x58, 0x00, 0x71, 0x00, 0x81, 0x00, 0x66, 0x00, 0x72, 0x00, 0x6A, 0x00, 0x83, 0x00, 0xCF, 0x00, 0x1D, 0x01, 0x5F, 0x01, 0x81, 0x01, 0xAA, 0x01, 0xAB, 0x01, 0x82, 0x01, 0x3A, 0x01, 0xD4, 0x00, 0x72, 0x00, 0x05, 0x00, 0xAD, 0xFF, 0x83, 0xFF, 0xBF, 0xFF, 0x2B, 0x00, 0x73, 0x00, 0xBF, 0x00, 0xB0, 0x00, 0x9A, 0x00, 0xA5, 0x00, 0x98, 0x00, 0x0C, 0x01, 0x85, 0x01, 0xB6, 0x01, 0xD1, 0x01, 0xAB, 0x01, 0x94, 0x01, 0x84, 0x01, 0x56, 0x01, 0x2A, 0x01, 0x0B, 0x01, 0xCC, 0x00, 0x75, 0x00, 0x13, 0x00, 0xB3, 0xFF, 0x9E, 0xFF, 0x9A, 0xFF, 0xA9, 0xFF, 0xC0, 0xFF, 0xD5, 0xFF, 0x19, 0x00, 0x48, 0x00, 0x67, 0x00, 0x50, 0x00, 0x25, 0x00, 0x18, 0x00, 0xC1, 0xFF, 0x92, 0xFF, 0x82, 0xFF, 0x5D, 0xFF, 0x3D, 0xFF, 0xEE, 0xFE, 0xAF, 0xFE, 0x72, 0xFE, 0x53, 0xFE, 0x5A, 0xFE, 0x62, 0xFE, 0x94, 0xFE, 0xB0, 0xFE, 0xBF, 0xFE, 0xC9, 0xFE, 0xD8, 0xFE, 0x27, 0xFF, 0x6F, 0xFF, 0xAF, 0xFF, 0xD6, 0xFF, 0xCF, 0xFF, 0xBB, 0xFF, 0x78, 0xFF, 0x35, 0xFF, 0x12, 0xFF, 0xF8, 0xFE, 0xF8, 0xFE, 0x02, 0xFF, 0x10, 0xFF, 0x6D, 0xFF, 0xEA, 0xFF, 0x5F, 0x00, 0xD2, 0x00, 0xF4, 0x00, 0xEC, 0x00, 0xFE, 0x00, 0x0E, 0x01, 0x38, 0x01, 0x72, 0x01, 0x8D, 0x01, 0x79, 0x01, 0x3B, 0x01, 0x03, 0x01, 0xE9, 0x00, 0xC7, 0x00, 0xC0, 0x00, 0xD1, 0x00, 0xBC, 0x00, 0xAA, 0x00, 0xB1, 0x00, 0xE0, 0x00, 0x18, 0x01, 0x37, 0x01, 0x5A, 0x01, 0x55, 0x01, 0x3D, 0x01, 0x41, 0x01, 0x52, 0x01, 0x68, 0x01, 0x7E, 0x01, 0x9E, 0x01, 0xBF, 0x01, 0x0E, 0x02, 0x5A, 0x02, 0x7B, 0x02, 0x8C, 0x02, 0x40, 0x02, 0xCC, 0x01, 0x36, 0x01, 0xBB, 0x00, 0x9B, 0x00, 0x6D, 0x00, 0x8E, 0x00, 0xD4, 0x00, 0x12, 0x01, 0x70, 0x01, 0x9D, 0x01, 0xDE, 0x01, 0x09, 0x02, 0xE5, 0x01, 0xB0, 0x01, 0x4E, 0x01, 0xE0, 0x00, 0xAC, 0x00, 0x7F, 0x00, 0x3B, 0x00, 0x27, 0x00, 0x0B, 0x00, 0x02, 0x00, 0x4E, 0x00, 0x69, 0x00, 0x81, 0x00, 0xA1, 0x00, 0xB8, 0x00, 0xF0, 0x00, 0xF7, 0x00, 0x30, 0x01, 0x95, 0x01, 0xB8, 0x01, 0xC5, 0x01, 0x9F, 0x01, 0x29, 0x01, 0x86, 0x00, 0xD2, 0xFF, 0x40, 0xFF, 0xE9, 0xFE, 0xBC, 0xFE, 0xD8, 0xFE, 0x10, 0xFF, 0x1F, 0xFF, 0x35, 0xFF, 0x4E, 0xFF, 0x6E, 0xFF, 0x79, 0xFF, 0x45, 0xFF, 0x07, 0xFF, 0xA4, 0xFE, 0x70, 0xFE, 0x7C, 0xFE, 0x6D, 0xFE, 0x7D, 0xFE, 0x95, 0xFE, 0xBE, 0xFE, 0x21, 0xFF, 0x68, 0xFF, 0x6B, 0xFF, 0x42, 0xFF, 0xEF, 0xFE, 0x86, 0xFE, 0xFB, 0xFD, 0x41, 0xFD, 0xCA, 0xFC, 0x97, 0xFC, 0x75, 0xFC, 0xA2, 0xFC, 0xF1, 0xFC, 0x51, 0xFD, 0xC3, 0xFD, 0x04, 0xFE, 0x24, 0xFE, 0x35, 0xFE, 0x37, 0xFE, 0x0B, 0xFE, 0xA7, 0xFD, 0x5D, 0xFD, 0x2D, 0xFD, 0x0D, 0xFD, 0x1A, 0xFD, 0x45, 0xFD, 0xB7, 0xFD, 0x3E, 0xFE, 0x98, 0xFE, 0xEE, 0xFE, 0x35, 0xFF, 0x83, 0xFF, 0xE9, 0xFF, 0x05, 0x00, 0xD9, 0xFF, 0xC5, 0xFF, 0xA7, 0xFF, 0x5A, 0xFF, 0x21, 0xFF, 0xEC, 0xFE, 0xCA, 0xFE, 0xEA, 0xFE, 0x22, 0xFF, 0x69, 0xFF, 0x9A, 0xFF, 0xB4, 0xFF, 0xDC, 0xFF, 0x07, 0x00, 0x5B, 0x00, 0xA1, 0x00, 0x90, 0x00, 0x6C, 0x00, 0x23, 0x00, 0xEC, 0xFF, 0xE7, 0xFF, 0xE0, 0xFF, 0x0F, 0x00, 0x56, 0x00, 0xA6, 0x00, 0x09, 0x01, 0x36, 0x01, 0x6C, 0x01, 0x77, 0x01, 0x40, 0x01, 0x00, 0x01, 0x96, 0x00, 0x66, 0x00, 0x62, 0x00, 0x95, 0x00, 0xEC, 0x00, 0x03, 0x01, 0x33, 0x01, 0x27, 0x01, 0x13, 0x01, 0x30, 0x01, 0x16, 0x01, 0x6A, 0x01, 0xD5, 0x01, 0x2E, 0x02, 0x9B, 0x02, 0x96, 0x02, 0x60, 0x02, 0x09, 0x02, 0xDD, 0x01, 0xE7, 0x01, 0xBB, 0x01, 0x89, 0x01, 0x78, 0x01, 0xA4, 0x01, 0xCC, 0x01, 0x12, 0x02, 0x59, 0x02, 0x5F, 0x02, 0x6A, 0x02, 0x2B, 0x02, 0xDB, 0x01, 0x5F, 0x01, 0xBD, 0x00, 0x6E, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x42, 0x00, 0x6B, 0x00, 0xB4, 0x00, 0xCD, 0x00, 0xE9, 0x00, 0xCF, 0x00, 0x9B, 0x00, 0x3E, 0x00, 0xA1, 0xFF, 0x0A, 0xFF, 0x64, 0xFE, 0xEF, 0xFD, 0x9C, 0xFD, 0x84, 0xFD, 0xCA, 0xFD, 0x10, 0xFE, 0x63, 0xFE, 0xA8, 0xFE, 0xE5, 0xFE, 0x01, 0xFF, 0xFE, 0xFE, 0xE9, 0xFE, 0x90, 0xFE, 0x40, 0xFE, 0xF4, 0xFD, 0xCD, 0xFD, 0xD0, 0xFD, 0xA3, 0xFD, 0x92, 0xFD, 0x76, 0xFD, 0x5A, 0xFD, 0x42, 0xFD, 0x1D, 0xFD, 0x42, 0xFD, 0x9F, 0xFD, 0x1B, 0xFE, 0x8C, 0xFE, 0xE6, 0xFE, 0x23, 0xFF, 0x3E, 0xFF, 0x41, 0xFF, 0x10, 0xFF, 0xBD, 0xFE, 0x4C, 0xFE, 0xEA, 0xFD, 0xC0, 0xFD, 0xA3, 0xFD, 0xBA, 0xFD, 0xEF, 0xFD, 0x30, 0xFE, 0x89, 0xFE, 0xCF, 0xFE, 0x02, 0xFF, 0x38, 0xFF, 0x5B, 0xFF, 0x68, 0xFF, 0x81, 0xFF, 0x8A, 0xFF, 0xB2, 0xFF, 0x05, 0x00, 0x21, 0x00, 0x21, 0x00, 0x09, 0x00, 0xD2, 0xFF, 0xA2, 0xFF, 0x5D, 0xFF, 0x2B, 0xFF, 0x0B, 0xFF, 0xF2, 0xFE, 0xEC, 0xFE, 0x08, 0xFF, 0x37, 0xFF, 0x39, 0xFF, 0x33, 0xFF, 0x27, 0xFF, 0x13, 0xFF, 0x06, 0xFF, 0x1C, 0xFF, 0x51, 0xFF, 0x5B, 0xFF, 0x58, 0xFF, 0x00, 0xFF, 0x99, 0xFE, 0x99, 0xFE, 0x9E, 0xFE, 0xD2, 0xFE, 0xDE, 0xFE, 0xC7, 0xFE, 0xE5, 0xFE, 0xF1, 0xFE, 0x2D, 0xFF, 0x5E, 0xFF, 0x8B, 0xFF, 0xC0, 0xFF, 0xD2, 0xFF, 0xED, 0xFF, 0xD8, 0xFF, 0xF5, 0xFF, 0x12, 0x00, 0x29, 0x00, 0x84, 0x00, 0x75, 0x00, 0x86, 0x00, 0xC4, 0x00, 0xDC, 0x00, 0x30, 0x01, 0x61, 0x01, 0x95, 0x01, 0xD4, 0x01, 0xE4, 0x01, 0xF1, 0x01, 0xE6, 0x01, 0xF2, 0x01, 0x1D, 0x02, 0x19, 0x02, 0x02, 0x02, 0xDF, 0x01, 0x7F, 0x01, 0x29, 0x01, 0xE7, 0x00, 0xB3, 0x00, 0xC7, 0x00, 0xF7, 0x00, 0x47, 0x01, 0x76, 0x01, 0x5F, 0x01, 0x68, 0x01, 0x71, 0x01, 0x4F, 0x01, 0x14, 0x01, 0xC8, 0x00, 0x68, 0x00, 0x37, 0x00, 0x1F, 0x00, 0xBA, 0xFF, 0x8C, 0xFF, 0x74, 0xFF, 0x4B, 0xFF, 0x6E, 0xFF, 0x3D, 0xFF, 0xEF, 0xFE, 0xC8, 0xFE, 0xA1, 0xFE, 0xC5, 0xFE, 0xF4, 0xFE, 0xF1, 0xFE, 0xE8, 0xFE, 0xE8, 0xFE, 0xBA, 0xFE, 0x95, 0xFE, 0x7E, 0xFE, 0x60, 0xFE, 0x66, 0xFE, 0x33, 0xFE, 0xFB, 0xFD, 0xFA, 0xFD, 0xE4, 0xFD, 0xF4, 0xFD, 0x09, 0xFE, 0x2E, 0xFE, 0x7D, 0xFE, 0xA1, 0xFE, 0xAD, 0xFE, 0xC1, 0xFE, 0xDA, 0xFE, 0x0B, 0xFF, 0x52, 0xFF, 0x95, 0xFF, 0xD1, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0xDC, 0xFF, 0x9B, 0xFF, 0x81, 0xFF, 0x85, 0xFF, 0x8B, 0xFF, 0xB4, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0x07, 0x00, 0x11, 0x00, 0x1E, 0x00, 0x49, 0x00, 0x76, 0x00, 0xA3, 0x00, 0xD1, 0x00, 0x0C, 0x01, 0x60, 0x01, 0x8D, 0x01, 0xCD, 0x01, 0xFB, 0x01, 0xCE, 0x01, 0x91, 0x01, 0x48, 0x01, 0x38, 0x01, 0x38, 0x01, 0x31, 0x01, 0x28, 0x01, 0xD0, 0x00, 0xB2, 0x00, 0xA7, 0x00, 0x9A, 0x00, 0xD5, 0x00, 0x07, 0x01, 0x19, 0x01, 0x07, 0x01, 0xD5, 0x00, 0x6B, 0x00, 0x20, 0x00, 0xF7, 0xFF, 0xBD, 0xFF, 0xC2, 0xFF, 0xCA, 0xFF, 0xFD, 0xFF, 0x40, 0x00, 0x84, 0x00, 0x04, 0x01, 0x28, 0x01, 0x53, 0x01, 0x78, 0x01, 0x4F, 0x01, 0x2D, 0x01, 0xCD, 0x00, 0x8F, 0x00, 0x73, 0x00, 0x6A, 0x00, 0x8A, 0x00, 0x99, 0x00, 0xCF, 0x00, 0xEA, 0x00, 0xE1, 0x00, 0xB7, 0x00, 0x6D, 0x00, 0x51, 0x00, 0x14, 0x00, 0xCE, 0xFF, 0x93, 0xFF, 0x48, 0xFF, 0x25, 0xFF, 0x22, 0xFF, 0x3D, 0xFF, 0x77, 0xFF, 0xD1, 0xFF, 0x0E, 0x00, 0x14, 0x00, 0xE1, 0xFF, 0x72, 0xFF, 0x13, 0xFF, 0x6F, 0xFE, 0xB2, 0xFD, 0x2C, 0xFD, 0xB7, 0xFC, 0x8B, 0xFC, 0x97, 0xFC, 0xF9, 0xFC, 0x92, 0xFD, 0x21, 0xFE, 0xA4, 0xFE, 0xE8, 0xFE, 0x27, 0xFF, 0x6C, 0xFF, 0xBE, 0xFF, 0xD9, 0xFF, 0x70, 0xFF, 0xF7, 0xFE, 0x4B, 0xFE, 0xB4, 0xFD, 0x65, 0xFD, 0x39, 0xFD, 0x5D, 0xFD, 0x87, 0xFD, 0xE8, 0xFD, 0x5C, 0xFE, 0xD8, 0xFE, 0x81, 0xFF, 0x15, 0x00, 0xAB, 0x00, 0xE2, 0x00, 0xF6, 0x00, 0xE9, 0x00, 0x97, 0x00, 0x9B, 0x00, 0x7F, 0x00, 0x9E, 0x00, 0xF4, 0x00, 0x07, 0x01, 0x3C, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x2D, 0x01, 0x05, 0x01, 0x25, 0x01, 0x66, 0x01, 0xCF, 0x01, 0xF4, 0x01, 0x06, 0x02, 0xFF, 0x01, 0xEE, 0x01, 0x00, 0x02, 0xBC, 0x01, 0x90, 0x01, 0x45, 0x01, 0x0D, 0x01, 0x41, 0x01, 0x65, 0x01, 0xC5, 0x01, 0x34, 0x02, 0xA3, 0x02, 0xD8, 0x02, 0xA8, 0x02, 0x56, 0x02, 0xC3, 0x01, 0x7D, 0x01, 0x40, 0x01, 0x10, 0x01, 0x33, 0x01, 0x3A, 0x01, 0x66, 0x01, 0x7B, 0x01, 0xA7, 0x01, 0xD7, 0x01, 0xA1, 0x01, 0x72, 0x01, 0x2B, 0x01, 0xE9, 0x00, 0xB4, 0x00, 0x53, 0x00, 0x0A, 0x00, 0xE3, 0xFF, 0xD6, 0xFF, 0xC1, 0xFF, 0xA5, 0xFF, 0x84, 0xFF, 0x73, 0xFF, 0x3A, 0xFF, 0xDA, 0xFE, 0xA7, 0xFE, 0x79, 0xFE, 0x8E, 0xFE, 0xBD, 0xFE, 0xBB, 0xFE, 0xAC, 0xFE, 0xA5, 0xFE, 0xD2, 0xFE, 0xDF, 0xFE, 0xE7, 0xFE, 0xEC, 0xFE, 0xD1, 0xFE, 0xC5, 0xFE, 0x71, 0xFE, 0x2A, 0xFE, 0xE2, 0xFD, 0x97, 0xFD, 0x95, 0xFD, 0x8A, 0xFD, 0xC5, 0xFD, 0x16, 0xFE, 0x4F, 0xFE, 0x86, 0xFE, 0xAA, 0xFE, 0xE5, 0xFE, 0x07, 0xFF, 0x4A, 0xFF, 0x72, 0xFF, 0x79, 0xFF, 0xCD, 0xFF, 0xC9, 0xFF, 0xA9, 0xFF, 0xA1, 0xFF, 0x69, 0xFF, 0x3F, 0xFF, 0x2C, 0xFF, 0x45, 0xFF, 0x74, 0xFF, 0xC0, 0xFF, 0x36, 0x00, 0xAF, 0x00, 0x1C, 0x01, 0x56, 0x01, 0x77, 0x01, 0x64, 0x01, 0x33, 0x01, 0xF7, 0x00, 0xA3, 0x00, 0x82, 0x00, 0x7C, 0x00, 0x93, 0x00, 0xC6, 0x00, 0xF0, 0x00, 0x29, 0x01, 0x61, 0x01, 0xA9, 0x01, 0xC1, 0x01, 0x7E, 0x01, 0x19, 0x01, 0x9F, 0x00, 0x62, 0x00, 0x39, 0x00, 0x0B, 0x00, 0x33, 0x00, 0x76, 0x00, 0xCC, 0x00, 0x19, 0x01, 0x4D, 0x01, 0xAD, 0x01, 0x07, 0x02, 0x2F, 0x02, 0x5A, 0x02, 0x63, 0x02, 0x48, 0x02, 0x1A, 0x02, 0xA6, 0x01, 0x0F, 0x01, 0x9C, 0x00, 0x2D, 0x00, 0xF2, 0xFF, 0xCC, 0xFF, 0xA5, 0xFF, 0x98, 0xFF, 0x87, 0xFF, 0xC7, 0xFF, 0x31, 0x00, 0x7D, 0x00, 0xD2, 0x00, 0xF5, 0x00, 0xFB, 0x00, 0xE0, 0x00, 0x91, 0x00, 0x32, 0x00, 0xE2, 0xFF, 0xDD, 0xFF, 0xFA, 0xFF, 0x11, 0x00, 0x3A, 0x00, 0x84, 0x00, 0xE2, 0x00, 0x4E, 0x01, 0xAC, 0x01, 0xC4, 0x01, 0xB0, 0x01, 0x9B, 0x01, 0x73, 0x01, 0x34, 0x01, 0xF6, 0x00, 0xC2, 0x00, 0xAD, 0x00, 0xDB, 0x00, 0x31, 0x01, 0xA5, 0x01, 0x1A, 0x02, 0x58, 0x02, 0x72, 0x02, 0x62, 0x02, 0x46, 0x02, 0x0F, 0x02, 0xA6, 0x01, 0x53, 0x01, 0x12, 0x01, 0xE1, 0x00, 0xFE, 0x00, 0x4B, 0x01, 0x9D, 0x01, 0x0D, 0x02, 0x6E, 0x02, 0xA3, 0x02, 0xD5, 0x02, 0xD9, 0x02, 0xF1, 0x02, 0x2B, 0x03, 0x31, 0x03, 0x3A, 0x03, 0x21, 0x03, 0xE9, 0x02, 0xBF, 0x02, 0x5A, 0x02, 0x04, 0x02, 0xBF, 0x01, 0x8F, 0x01, 0x9D, 0x01, 0x95, 0x01, 0xA3, 0x01, 0xBF, 0x01, 0xB3, 0x01, 0xA8, 0x01, 0x97, 0x01, 0xA2, 0x01, 0xC0, 0x01, 0xC4, 0x01, 0x8D, 0x01, 0x13, 0x01, 0xA1, 0x00, 0x41, 0x00, 0xFC, 0xFF, 0xCA, 0xFF, 0x83, 0xFF, 0x71, 0xFF, 0x8A, 0xFF, 0x92, 0xFF, 0x80, 0xFF, 0x60, 0xFF, 0x64, 0xFF, 0x75, 0xFF, 0x81, 0xFF, 0x63, 0xFF, 0x26, 0xFF, 0xDE, 0xFE, 0x83, 0xFE, 0x41, 0xFE, 0xFB, 0xFD, 0xC2, 0xFD, 0x96, 0xFD, 0x78, 0xFD, 0x7D, 0xFD, 0x6E, 0xFD, 0x78, 0xFD, 0x71, 0xFD, 0x72, 0xFD, 0xBA, 0xFD, 0xF0, 0xFD, 0x56, 0xFE, 0xB9, 0xFE, 0xF1, 0xFE, 0x2B, 0xFF, 0x37, 0xFF, 0x5C, 0xFF, 0x6E, 0xFF, 0x73, 0xFF, 0x8F, 0xFF, 0x94, 0xFF, 0x9A, 0xFF, 0x95, 0xFF, 0x9F, 0xFF, 0xC4, 0xFF, 0xE2, 0xFF, 0xF8, 0xFF, 0xE9, 0xFF, 0xC2, 0xFF, 0xE5, 0xFF, 0x42, 0x00, 0x79, 0x00, 0xB8, 0x00, 0xD1, 0x00, 0xBF, 0x00, 0xDB, 0x00, 0xF5, 0x00, 0xEA, 0x00, 0xC6, 0x00, 0xBE, 0x00, 0xBB, 0x00, 0xB8, 0x00, 0xF2, 0x00, 0x3A, 0x01, 0xA7, 0x01, 0x02, 0x02, 0x74, 0x02, 0x08, 0x03, 0x3E, 0x03, 0x84, 0x03, 0xAE, 0x03, 0xA2, 0x03, 0xA8, 0x03, 0x71, 0x03, 0x47, 0x03, 0x32, 0x03, 0x23, 0x03, 0xF7, 0x02, 0xA8, 0x02, 0x7E, 0x02, 0x62, 0x02, 0x80, 0x02, 0x9F, 0x02, 0x99, 0x02, 0xB2, 0x02, 0x90, 0x02, 0x21, 0x02, 0xAD, 0x01, 0x4A, 0x01, 0x16, 0x01, 0x22, 0x01, 0x36, 0x01, 0x40, 0x01, 0x46, 0x01, 0x57, 0x01, 0xA2, 0x01, 0xC8, 0x01, 0xB6, 0x01, 0xB7, 0x01, 0x80, 0x01, 0x2A, 0x01, 0xF5, 0x00, 0xC6, 0x00, 0xB0, 0x00, 0x9C, 0x00, 0x5F, 0x00, 0x1A, 0x00, 0xE2, 0xFF, 0xA8, 0xFF, 0x87, 0xFF, 0x80, 0xFF, 0xA0, 0xFF, 0xC7, 0xFF, 0xD5, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xE2, 0xFF, 0xDE, 0xFF, 0xC7, 0xFF, 0x8D, 0xFF, 0x50, 0xFF, 0x48, 0xFF, 0x64, 0xFF, 0xDC, 0xFF, 0x3F, 0x00, 0x68, 0x00, 0xB6, 0x00, 0xD1, 0x00, 0xF7, 0x00, 0xEA, 0x00, 0x81, 0x00, 0x32, 0x00, 0xD6, 0xFF, 0xAD, 0xFF, 0x84, 0xFF, 0x64, 0xFF, 0x8D, 0xFF, 0x98, 0xFF, 0xD9, 0xFF, 0x49, 0x00, 0x9A, 0x00, 0xEA, 0x00, 0x1C, 0x01, 0x31, 0x01, 0x0A, 0x01, 0xC3, 0x00, 0x91, 0x00, 0x55, 0x00, 0x19, 0x00, 0xF0, 0xFF, 0xCF, 0xFF, 0xB6, 0xFF, 0xD3, 0xFF, 0x24, 0x00, 0x7B, 0x00, 0xE5, 0x00, 0x3D, 0x01, 0x7C, 0x01, 0x97, 0x01, 0x83, 0x01, 0x70, 0x01, 0x51, 0x01, 0x32, 0x01, 0x23, 0x01, 0x07, 0x01, 0x3F, 0x01, 0x7B, 0x01, 0x64, 0x01, 0x5A, 0x01, 0x46, 0x01, 0x49, 0x01, 0x71, 0x01, 0x7E, 0x01, 0x97, 0x01, 0xA2, 0x01, 0xC5, 0x01, 0xF3, 0x01, 0x0E, 0x02, 0x3B, 0x02, 0x32, 0x02, 0xEE, 0x01, 0x83, 0x01, 0x0A, 0x01, 0xD7, 0x00, 0xC7, 0x00, 0xC9, 0x00, 0xDE, 0x00, 0xE3, 0x00, 0xBD, 0x00, 0x6B, 0x00, 0xF6, 0xFF, 0x4F, 0xFF, 0xCB, 0xFE, 0x7B, 0xFE, 0x44, 0xFE, 0x57, 0xFE, 0x7B, 0xFE, 0x8F, 0xFE, 0xB5, 0xFE, 0xDD, 0xFE, 0xEC, 0xFE, 0x04, 0xFF, 0x1D, 0xFF, 0xFA, 0xFE, 0xC9, 0xFE, 0x89, 0xFE, 0x39, 0xFE, 0x14, 0xFE, 0xF4, 0xFD, 0xEB, 0xFD, 0xD8, 0xFD, 0xC5, 0xFD, 0xEE, 0xFD, 0x08, 0xFE, 0x23, 0xFE, 0x65, 0xFE, 0xAF, 0xFE, 0xEF, 0xFE, 0x1E, 0xFF, 0x5C, 0xFF, 0x88, 0xFF, 0x92, 0xFF, 0x95, 0xFF, 0x79, 0xFF, 0x3D, 0xFF, 0x0B, 0xFF, 0xF7, 0xFE, 0xEF, 0xFE, 0x2E, 0xFF, 0x7B, 0xFF, 0x92, 0xFF, 0xB0, 0xFF, 0xA7, 0xFF, 0x99, 0xFF, 0xB5, 0xFF, 0xB8, 0xFF, 0xDE, 0xFF, 0x13, 0x00, 0x0B, 0x00, 0x09, 0x00, 0x18, 0x00, 0x0A, 0x00, 0x25, 0x00, 0x5D, 0x00, 0x8A, 0x00, 0xD4, 0x00, 0x23, 0x01, 0x6E, 0x01, 0xA7, 0x01, 0xBE, 0x01, 0x9F, 0x01, 0x43, 0x01, 0xEA, 0x00, 0x85, 0x00, 0x34, 0x00, 0x1A, 0x00, 0x12, 0x00, 0x36, 0x00, 0x65, 0x00, 0x9D, 0x00, 0xB7, 0x00, 0xA1, 0x00, 0x8D, 0x00, 0x58, 0x00, 0x35, 0x00, 0x1C, 0x00, 0x16, 0x00, 0x4C, 0x00, 0x8E, 0x00, 0xC2, 0x00, 0x02, 0x01, 0x64, 0x01, 0x7A, 0x01, 0x67, 0x01, 0x54, 0x01, 0x22, 0x01, 0x16, 0x01, 0xD0, 0x00, 0x79, 0x00, 0x3F, 0x00, 0xDF, 0xFF, 0xB7, 0xFF, 0x96, 0xFF, 0x69, 0xFF, 0x49, 0xFF, 0x3D, 0xFF, 0x3F, 0xFF, 0x51, 0xFF, 0x89, 0xFF, 0x7F, 0xFF, 0x6C, 0xFF, 0x41, 0xFF, 0xFE, 0xFE, 0xFC, 0xFE, 0xA7, 0xFE, 0x4C, 0xFE, 0x1A, 0xFE, 0xCA, 0xFD, 0xAA, 0xFD, 0x99, 0xFD, 0x91, 0xFD, 0x90, 0xFD, 0xA4, 0xFD, 0xD9, 0xFD, 0xDF, 0xFD, 0xBB, 0xFD, 0x8B, 0xFD, 0x87, 0xFD, 0xAE, 0xFD, 0xE7, 0xFD, 0x1D, 0xFE, 0x2E, 0xFE, 0x11, 0xFE, 0xD7, 0xFD, 0xC8, 0xFD, 0xED, 0xFD, 0x57, 0xFE, 0xE8, 0xFE, 0x53, 0xFF, 0x96, 0xFF, 0xAD, 0xFF, 0xA8, 0xFF, 0x85, 0xFF, 0x6B, 0xFF, 0x89, 0xFF, 0xA8, 0xFF, 0xAB, 0xFF, 0xA0, 0xFF, 0xB0, 0xFF, 0xCE, 0xFF, 0xF7, 0xFF, 0x36, 0x00, 0x5C, 0x00, 0x79, 0x00, 0x84, 0x00, 0x80, 0x00, 0x89, 0x00, 0x94, 0x00, 0xA4, 0x00, 0x72, 0x00, 0x25, 0x00, 0xD5, 0xFF, 0x66, 0xFF, 0x2D, 0xFF, 0x0E, 0xFF, 0x0B, 0xFF, 0x0C, 0xFF, 0xDD, 0xFE, 0xC8, 0xFE, 0xBC, 0xFE, 0x9E, 0xFE, 0x7C, 0xFE, 0x7C, 0xFE, 0xA3, 0xFE, 0x99, 0xFE, 0x49, 0xFE, 0xF0, 0xFD, 0x89, 0xFD, 0x22, 0xFD, 0xE6, 0xFC, 0xAB, 0xFC, 0x4B, 0xFC, 0x10, 0xFC, 0x1E, 0xFC, 0x51, 0xFC, 0xA7, 0xFC, 0x12, 0xFD, 0xA0, 0xFD, 0x1D, 0xFE, 0x5E, 0xFE, 0x88, 0xFE, 0x63, 0xFE, 0x2C, 0xFE, 0x18, 0xFE, 0x0A, 0xFE, 0x3D, 0xFE, 0x8A, 0xFE, 0xC7, 0xFE, 0xF5, 0xFE, 0x0F, 0xFF, 0x3C, 0xFF, 0x89, 0xFF, 0xDF, 0xFF, 0xF8, 0xFF, 0xDD, 0xFF, 0xA3, 0xFF, 0x70, 0xFF, 0x5E, 0xFF, 0x50, 0xFF, 0x6B, 0xFF, 0x8E, 0xFF, 0xBE, 0xFF, 0x01, 0x00, 0x30, 0x00, 0x5B, 0x00, 0x3F, 0x00, 0x24, 0x00, 0xFC, 0xFF, 0xAE, 0xFF, 0x9A, 0xFF, 0x90, 0xFF, 0xBE, 0xFF, 0x03, 0x00, 0x3C, 0x00, 0x92, 0x00, 0xAB, 0x00, 0xBB, 0x00, 0xB6, 0x00, 0x95, 0x00, 0x76, 0x00, 0x33, 0x00, 0xE2, 0xFF, 0x9B, 0xFF, 0x8D, 0xFF, 0x99, 0xFF, 0xB7, 0xFF, 0xC8, 0xFF, 0xAD, 0xFF, 0x9B, 0xFF, 0x78, 0xFF, 0x84, 0xFF, 0xA0, 0xFF, 0xB0, 0xFF, 0x01, 0x00, 0x28, 0x00, 0x38, 0x00, 0x4E, 0x00, 0x23, 0x00, 0x0C, 0x00, 0x15, 0x00, 0x10, 0x00, 0x2E, 0x00, 0x36, 0x00, 0x0D, 0x00, 0x18, 0x00, 0xEF, 0xFF, 0xD3, 0xFF, 0x06, 0x00, 0xFF, 0xFF, 0x37, 0x00, 0x5E, 0x00, 0x3D, 0x00, 0x3A, 0x00, 0xDA, 0xFF, 0x76, 0xFF, 0x30, 0xFF, 0xDD, 0xFE, 0xB3, 0xFE, 0x8B, 0xFE, 0x95, 0xFE, 0xDC, 0xFE, 0x44, 0xFF, 0xA5, 0xFF, 0xE2, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0xE5, 0xFF, 0x9D, 0xFF, 0x51, 0xFF, 0x4E, 0xFF, 0x5A, 0xFF, 0x55, 0xFF, 0x2B, 0xFF, 0xDA, 0xFE, 0xAC, 0xFE, 0xB3, 0xFE, 0xC1, 0xFE, 0xD4, 0xFE, 0xDB, 0xFE, 0xE6, 0xFE, 0x18, 0xFF, 0x3F, 0xFF, 0x5A, 0xFF, 0x60, 0xFF, 0x24, 0xFF, 0xB8, 0xFE, 0x38, 0xFE, 0xC8, 0xFD, 0x85, 0xFD, 0x82, 0xFD, 0xA6, 0xFD, 0xCB, 0xFD, 0xD1, 0xFD, 0xD9, 0xFD, 0xFE, 0xFD, 0x31, 0xFE, 0x79, 0xFE, 0xA0, 0xFE, 0xAD, 0xFE, 0x7F, 0xFE, 0x11, 0xFE, 0xC2, 0xFD, 0x79, 0xFD, 0x57, 0xFD, 0x40, 0xFD, 0x13, 0xFD, 0x03, 0xFD, 0xEF, 0xFC, 0x31, 0xFD, 0x7D, 0xFD, 0xB1, 0xFD, 0xF4, 0xFD, 0xD3, 0xFD, 0x8C, 0xFD, 0x55, 0xFD, 0x40, 0xFD, 0x40, 0xFD, 0x1A, 0xFD, 0x07, 0xFD, 0xF1, 0xFC, 0x00, 0xFD, 0x54, 0xFD, 0xAD, 0xFD, 0x10, 0xFE, 0x74, 0xFE, 0xBB, 0xFE, 0xEE, 0xFE, 0x42, 0xFF, 0x86, 0xFF, 0x8B, 0xFF, 0x8F, 0xFF, 0x99, 0xFF, 0x7F, 0xFF, 0x4C, 0xFF, 0x27, 0xFF, 0x02, 0xFF, 0x0D, 0xFF, 0x3C, 0xFF, 0x67, 0xFF, 0x9A, 0xFF, 0xA2, 0xFF, 0xB4, 0xFF, 0xC5, 0xFF, 0xD4, 0xFF, 0x05, 0x00, 0xFE, 0xFF, 0xE7, 0xFF, 0xC6, 0xFF, 0xBA, 0xFF, 0xCC, 0xFF, 0xC3, 0xFF, 0xDA, 0xFF, 0x01, 0x00, 0x4A, 0x00, 0x89, 0x00, 0xB0, 0x00, 0xB7, 0x00, 0x78, 0x00, 0x59, 0x00, 0x32, 0x00, 0xED, 0xFF, 0x89, 0xFF, 0x2A, 0xFF, 0x05, 0xFF, 0xCE, 0xFE, 0xEF, 0xFE, 0x32, 0xFF, 0x53, 0xFF, 0x9B, 0xFF, 0xAC, 0xFF, 0xB8, 0xFF, 0xB7, 0xFF, 0xA0, 0xFF, 0x89, 0xFF, 0x70, 0xFF, 0x6E, 0xFF, 0x26, 0xFF, 0xE3, 0xFE, 0xC5, 0xFE, 0xB8, 0xFE, 0xE6, 0xFE, 0x04, 0xFF, 0x4F, 0xFF, 0xAF, 0xFF, 0xED, 0xFF, 0x1E, 0x00, 0x2F, 0x00, 0x4B, 0x00, 0x51, 0x00, 0x32, 0x00, 0xF8, 0xFF, 0xBC, 0xFF, 0xA0, 0xFF, 0x80, 0xFF, 0x7A, 0xFF, 0x8A, 0xFF, 0x9E, 0xFF, 0xCD, 0xFF, 0xEA, 0xFF, 0xFC, 0xFF, 0x2B, 0x00, 0x3D, 0x00, 0x25, 0x00, 0x32, 0x00, 0x45, 0x00, 0x3B, 0x00, 0x21, 0x00, 0xD4, 0xFF, 0x84, 0xFF, 0x35, 0xFF, 0xFD, 0xFE, 0x19, 0xFF, 0x67, 0xFF, 0xDE, 0xFF, 0x47, 0x00, 0x81, 0x00, 0x8D, 0x00, 0x71, 0x00, 0x61, 0x00, 0x40, 0x00, 0xFF, 0xFF, 0x8D, 0xFF, 0x0D, 0xFF, 0xC4, 0xFE, 0x86, 0xFE, 0x76, 0xFE, 0x9A, 0xFE, 0xCF, 0xFE, 0x35, 0xFF, 0x90, 0xFF, 0xF2, 0xFF, 0x3D, 0x00, 0x39, 0x00, 0x4D, 0x00, 0x49, 0x00, 0x14, 0x00, 0x08, 0x00, 0xEE, 0xFF, 0xEE, 0xFF, 0x25, 0x00, 0x38, 0x00, 0x33, 0x00, 0x33, 0x00, 0x32, 0x00, 0x53, 0x00, 0xA9, 0x00, 0xE6, 0x00, 0x05, 0x01, 0x10, 0x01, 0xC6, 0x00, 0x83, 0x00, 0x8B, 0x00, 0xAA, 0x00, 0xE7, 0x00, 0x0C, 0x01, 0xF4, 0x00, 0x06, 0x01, 0x56, 0x01, 0xA8, 0x01, 0x07, 0x02, 0x4E, 0x02, 0x81, 0x02, 0x9C, 0x02, 0x48, 0x02, 0xBF, 0x01, 0x3F, 0x01, 0xF5, 0x00, 0x04, 0x01, 0x09, 0x01, 0x24, 0x01, 0x61, 0x01, 0x78, 0x01, 0xAF, 0x01, 0xF7, 0x01, 0x37, 0x02, 0x8B, 0x02, 0xC3, 0x02, 0xCF, 0x02, 0xB6, 0x02, 0x66, 0x02, 0x0C, 0x02, 0xBE, 0x01, 0x71, 0x01, 0x40, 0x01, 0x35, 0x01, 0x29, 0x01, 0x29, 0x01, 0x26, 0x01, 0x00, 0x01, 0xD6, 0x00, 0xB2, 0x00, 0xA1, 0x00, 0x97, 0x00, 0x6C, 0x00, 0x48, 0x00, 0x3F, 0x00, 0x30, 0x00, 0x25, 0x00, 0xFF, 0xFF, 0xB4, 0xFF, 0x93, 0xFF, 0x79, 0xFF, 0x3B, 0xFF, 0x12, 0xFF, 0xEC, 0xFE, 0xA8, 0xFE, 0x6F, 0xFE, 0x2D, 0xFE, 0x04, 0xFE, 0x29, 0xFE, 0x4A, 0xFE, 0x73, 0xFE, 0x99, 0xFE, 0x8C, 0xFE, 0xAD, 0xFE, 0xCC, 0xFE, 0xC7, 0xFE, 0xD9, 0xFE, 0xD8, 0xFE, 0xC8, 0xFE, 0xA8, 0xFE, 0x7E, 0xFE, 0x6E, 0xFE, 0x70, 0xFE, 0x85, 0xFE, 0xA9, 0xFE, 0xE0, 0xFE, 0x14, 0xFF, 0x5E, 0xFF, 0xD1, 0xFF, 0x39, 0x00, 0xAD, 0x00, 0x1D, 0x01, 0x66, 0x01, 0xA3, 0x01, 0xC9, 0x01, 0xC7, 0x01, 0x9C, 0x01, 0x74, 0x01, 0x73, 0x01, 0xA3, 0x01, 0x09, 0x02, 0x67, 0x02, 0xC9, 0x02, 0x21, 0x03, 0x33, 0x03, 0x42, 0x03, 0x41, 0x03, 0x32, 0x03, 0x35, 0x03, 0x08, 0x03, 0xE9, 0x02, 0xDC, 0x02, 0xAD, 0x02, 0xB6, 0x02, 0xD9, 0x02, 0xE9, 0x02, 0x0B, 0x03, 0xFD, 0x02, 0xE6, 0x02, 0xFC, 0x02, 0x26, 0x03, 0x3E, 0x03, 0x20, 0x03, 0xEC, 0x02, 0x9E, 0x02, 0x4D, 0x02, 0x1D, 0x02, 0xE8, 0x01, 0xC6, 0x01, 0x76, 0x01, 0x1B, 0x01, 0xEB, 0x00, 0x8A, 0x00, 0x84, 0x00, 0xC1, 0x00, 0xFD, 0x00, 0x5D, 0x01, 0x55, 0x01, 0x1B, 0x01, 0xD9, 0x00, 0x9B, 0x00, 0xA2, 0x00, 0x8F, 0x00, 0x53, 0x00, 0x0D, 0x00, 0xDA, 0xFF, 0xC8, 0xFF, 0xCB, 0xFF, 0xD9, 0xFF, 0xC7, 0xFF, 0xDE, 0xFF, 0xE2, 0xFF, 0xC6, 0xFF, 0xD1, 0xFF, 0xAC, 0xFF, 0xAB, 0xFF, 0xB3, 0xFF, 0xA7, 0xFF, 0xC6, 0xFF, 0xCD, 0xFF, 0xF8, 0xFF, 0x24, 0x00, 0x37, 0x00, 0x43, 0x00, 0x1A, 0x00, 0xFE, 0xFF, 0xDD, 0xFF, 0xE1, 0xFF, 0xEE, 0xFF, 0xCA, 0xFF, 0xCE, 0xFF, 0xB9, 0xFF, 0xB4, 0xFF, 0xD0, 0xFF, 0xEC, 0xFF, 0x40, 0x00, 0x8D, 0x00, 0xD1, 0x00, 0x02, 0x01, 0x1B, 0x01, 0x32, 0x01, 0x2B, 0x01, 0x26, 0x01, 0x06, 0x01, 0xBD, 0x00, 0x81, 0x00, 0x50, 0x00, 0x29, 0x00, 0x10, 0x00, 0x33, 0x00, 0x8F, 0x00, 0xE8, 0x00, 0x59, 0x01, 0xCD, 0x01, 0xEB, 0x01, 0xF0, 0x01, 0xEF, 0x01, 0xC0, 0x01, 0x9E, 0x01, 0x61, 0x01, 0x2D, 0x01, 0x1F, 0x01, 0xDB, 0x00, 0xC5, 0x00, 0xB3, 0x00, 0x72, 0x00, 0x4C, 0x00, 0x28, 0x00, 0x43, 0x00, 0x71, 0x00, 0x80, 0x00, 0x90, 0x00, 0xA6, 0x00, 0xE8, 0x00, 0x16, 0x01, 0x40, 0x01, 0x4F, 0x01, 0x3E, 0x01, 0x3A, 0x01, 0xFF, 0x00, 0xDC, 0x00, 0xCC, 0x00, 0xB0, 0x00, 0xA0, 0x00, 0x58, 0x00, 0x0D, 0x00, 0xB1, 0xFF, 0x4F, 0xFF, 0x03, 0xFF, 0xA2, 0xFE, 0x7F, 0xFE, 0x91, 0xFE, 0xC3, 0xFE, 0x1D, 0xFF, 0x64, 0xFF, 0xA3, 0xFF, 0xE4, 0xFF, 0x3C, 0x00, 0x5E, 0x00, 0x5A, 0x00, 0x5A, 0x00, 0x2E, 0x00, 0x03, 0x00, 0xD8, 0xFF, 0xBB, 0xFF, 0xB1, 0xFF, 0x9E, 0xFF, 0x9A, 0xFF, 0x7E, 0xFF, 0x98, 0xFF, 0xD8, 0xFF, 0x07, 0x00, 0x54, 0x00, 0x85, 0x00, 0xA0, 0x00, 0xA7, 0x00, 0x9F, 0x00, 0xA6, 0x00, 0xB8, 0x00, 0xCA, 0x00, 0x78, 0x00, 0xF2, 0xFF, 0x6E, 0xFF, 0xF5, 0xFE, 0xB1, 0xFE, 0x7B, 0xFE, 0x75, 0xFE, 0xA0, 0xFE, 0xF4, 0xFE, 0x8A, 0xFF, 0x18, 0x00, 0x92, 0x00, 0xC5, 0x00, 0xD8, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x1D, 0x01, 0x35, 0x01, 0x35, 0x01, 0x34, 0x01, 0x45, 0x01, 0x5F, 0x01, 0x6D, 0x01, 0x91, 0x01, 0xAE, 0x01, 0xC1, 0x01, 0xC1, 0x01, 0xBD, 0x01, 0xCD, 0x01, 0xDE, 0x01, 0x15, 0x02, 0xFA, 0x01, 0xAF, 0x01, 0x8F, 0x01, 0x46, 0x01, 0x2E, 0x01, 0x3D, 0x01, 0x31, 0x01, 0x1E, 0x01, 0x25, 0x01, 0x43, 0x01, 0x41, 0x01, 0x40, 0x01, 0x28, 0x01, 0x16, 0x01, 0x0C, 0x01, 0xF3, 0x00, 0xFA, 0x00, 0xC7, 0x00, 0x94, 0x00, 0x72, 0x00, 0x38, 0x00, 0x16, 0x00, 0xD5, 0xFF, 0xC5, 0xFF, 0xDB, 0xFF, 0xED, 0xFF, 0x25, 0x00, 0x47, 0x00, 0x7F, 0x00, 0x9D, 0x00, 0x63, 0x00, 0x07, 0x00, 0xAF, 0xFF, 0x66, 0xFF, 0x38, 0xFF, 0x47, 0xFF, 0x4F, 0xFF, 0x43, 0xFF, 0x30, 0xFF, 0x0E, 0xFF, 0x07, 0xFF, 0x0E, 0xFF, 0x22, 0xFF, 0x1D, 0xFF, 0x17, 0xFF, 0x26, 0xFF, 0x35, 0xFF, 0x6A, 0xFF, 0x8F, 0xFF, 0xA4, 0xFF, 0xB1, 0xFF, 0xB3, 0xFF, 0xA0, 0xFF, 0x84, 0xFF, 0x97, 0xFF, 0x7F, 0xFF, 0x3E, 0xFF, 0xEA, 0xFE, 0xA0, 0xFE, 0x9A, 0xFE, 0x84, 0xFE, 0x87, 0xFE, 0xA4, 0xFE, 0xC9, 0xFE, 0x1E, 0xFF, 0x70, 0xFF, 0xE2, 0xFF, 0x60, 0x00, 0xBF, 0x00, 0xF9, 0x00, 0x03, 0x01, 0x1E, 0x01, 0x41, 0x01, 0x2C, 0x01, 0xDD, 0x00, 0x87, 0x00, 0x35, 0x00, 0xEE, 0xFF, 0xCB, 0xFF, 0xC0, 0xFF, 0xF3, 0xFF, 0x6B, 0x00, 0xF0, 0x00, 0x51, 0x01, 0xA8, 0x01, 0xFC, 0x01, 0x2C, 0x02, 0x58, 0x02, 0x88, 0x02, 0x9D, 0x02, 0x88, 0x02, 0x4A, 0x02, 0xD4, 0x01, 0x4E, 0x01, 0xFB, 0x00, 0xA6, 0x00, 0x7E, 0x00, 0x97, 0x00, 0xBB, 0x00, 0xEF, 0x00, 0x17, 0x01, 0x40, 0x01, 0x3C, 0x01, 0x14, 0x01, 0xEE, 0x00, 0xCD, 0x00, 0xD9, 0x00, 0xC7, 0x00, 0xD4, 0x00, 0xF9, 0x00, 0x00, 0x01, 0x23, 0x01, 0x0B, 0x01, 0xFD, 0x00, 0xDB, 0x00, 0x65, 0x00, 0xFD, 0xFF, 0x7A, 0xFF, 0xF4, 0xFE, 0x86, 0xFE, 0x21, 0xFE, 0xBF, 0xFD, 0x7D, 0xFD, 0x98, 0xFD, 0xEB, 0xFD, 0x62, 0xFE, 0xC7, 0xFE, 0x15, 0xFF, 0x58, 0xFF, 0x70, 0xFF, 0x8C, 0xFF, 0x7E, 0xFF, 0x65, 0xFF, 0x4D, 0xFF, 0xF4, 0xFE, 0x9E, 0xFE, 0x7D, 0xFE, 0x73, 0xFE, 0x6C, 0xFE, 0x80, 0xFE, 0x91, 0xFE, 0x88, 0xFE, 0x72, 0xFE, 0x47, 0xFE, 0x18, 0xFE, 0x01, 0xFE, 0x46, 0xFE, 0xB0, 0xFE, 0xFD, 0xFE, 0x37, 0xFF, 0x43, 0xFF, 0x4F, 0xFF, 0x32, 0xFF, 0x00, 0xFF, 0xBD, 0xFE, 0x57, 0xFE, 0x46, 0xFE, 0x3E, 0xFE, 0x49, 0xFE, 0x89, 0xFE, 0xBC, 0xFE, 0xFC, 0xFE, 0x10, 0xFF, 0x2C, 0xFF, 0x54, 0xFF, 0x73, 0xFF, 0xC0, 0xFF, 0xEA, 0xFF, 0x14, 0x00, 0x4E, 0x00, 0x90, 0x00, 0xE7, 0x00, 0x0F, 0x01, 0x2B, 0x01, 0x40, 0x01, 0x4A, 0x01, 0x42, 0x01, 0xF4, 0x00, 0x99, 0x00, 0x44, 0x00, 0xF8, 0xFF, 0xD2, 0xFF, 0xCE, 0xFF, 0xE9, 0xFF, 0x3A, 0x00, 0xA9, 0x00, 0x07, 0x01, 0x79, 0x01, 0xF3, 0x01, 0x4B, 0x02, 0x81, 0x02, 0x80, 0x02, 0x50, 0x02, 0x07, 0x02, 0xA1, 0x01, 0x2F, 0x01, 0xB9, 0x00, 0x6F, 0x00, 0x5E, 0x00, 0x59, 0x00, 0x51, 0x00, 0x43, 0x00, 0x34, 0x00, 0x02, 0x00, 0xC6, 0xFF, 0xA3, 0xFF, 0x5F, 0xFF, 0x2C, 0xFF, 0x02, 0xFF, 0xBA, 0xFE, 0x91, 0xFE, 0x87, 0xFE, 0xCC, 0xFE, 0x12, 0xFF, 0x18, 0xFF, 0x24, 0xFF, 0x10, 0xFF, 0xFC, 0xFE, 0xCA, 0xFE, 0x67, 0xFE, 0x17, 0xFE, 0xA1, 0xFD, 0x2E, 0xFD, 0xB4, 0xFC, 0x44, 0xFC, 0x1B, 0xFC, 0x0B, 0xFC, 0x2D, 0xFC, 0x5A, 0xFC, 0x98, 0xFC, 0xF0, 0xFC, 0x44, 0xFD, 0x96, 0xFD, 0xB1, 0xFD, 0xC8, 0xFD, 0xC2, 0xFD, 0x9C, 0xFD, 0x94, 0xFD, 0x54, 0xFD, 0xDD, 0xFC, 0x89, 0xFC, 0x5F, 0xFC, 0x4E, 0xFC, 0x77, 0xFC, 0xD7, 0xFC, 0x41, 0xFD, 0xBA, 0xFD, 0x2A, 0xFE, 0xA4, 0xFE, 0x22, 0xFF, 0x6A, 0xFF, 0xA1, 0xFF, 0xD3, 0xFF, 0x01, 0x00, 0x33, 0x00, 0x52, 0x00, 0x6A, 0x00, 0x97, 0x00, 0xC8, 0x00, 0xD0, 0x00, 0xA3, 0x00, 0x5D, 0x00, 0x42, 0x00, 0x42, 0x00, 0x5A, 0x00, 0xB1, 0x00, 0xFC, 0x00, 0x59, 0x01, 0xA4, 0x01, 0x9E, 0x01, 0x99, 0x01, 0x67, 0x01, 0x3D, 0x01, 0x2B, 0x01, 0xF4, 0x00, 0xE1, 0x00, 0x05, 0x01, 0x51, 0x01, 0x83, 0x01, 0x92, 0x01, 0x8D, 0x01, 0x56, 0x01, 0x1C, 0x01, 0xDE, 0x00, 0x91, 0x00, 0x3C, 0x00, 0xEF, 0xFF, 0xB7, 0xFF, 0xAE, 0xFF, 0xF2, 0xFF, 0x33, 0x00, 0x89, 0x00, 0xD6, 0x00, 0xD4, 0x00, 0xC2, 0x00, 0x73, 0x00, 0x26, 0x00, 0xF7, 0xFF, 0xA5, 0xFF, 0x77, 0xFF, 0x42, 0xFF, 0xFC, 0xFE, 0xD7, 0xFE, 0xC6, 0xFE, 0xCC, 0xFE, 0xE8, 0xFE, 0x16, 0xFF, 0x46, 0xFF, 0x92, 0xFF, 0xE1, 0xFF, 0x0A, 0x00, 0x35, 0x00, 0x73, 0x00, 0xA6, 0x00, 0xC7, 0x00, 0xDB, 0x00, 0xD3, 0x00, 0xD1, 0x00, 0xCB, 0x00, 0x95, 0x00, 0x67, 0x00, 0x2A, 0x00, 0xF4, 0xFF, 0xE7, 0xFF, 0xB5, 0xFF, 0xA7, 0xFF, 0xCB, 0xFF, 0xE7, 0xFF, 0x16, 0x00, 0x40, 0x00, 0x72, 0x00, 0xC1, 0x00, 0x0F, 0x01, 0x5F, 0x01, 0x9A, 0x01, 0xB8, 0x01, 0xCD, 0x01, 0xBC, 0x01, 0xB5, 0x01, 0xBC, 0x01, 0x9D, 0x01, 0x80, 0x01, 0x30, 0x01, 0xDC, 0x00, 0xAF, 0x00, 0x64, 0x00, 0x42, 0x00, 0x53, 0x00, 0x8B, 0x00, 0xE6, 0x00, 0x48, 0x01, 0xCD, 0x01, 0x34, 0x02, 0x81, 0x02, 0xC5, 0x02, 0xCF, 0x02, 0xB3, 0x02, 0x7E, 0x02, 0x29, 0x02, 0xB3, 0x01, 0x4E, 0x01, 0x16, 0x01, 0x1F, 0x01, 0x6D, 0x01, 0xA9, 0x01, 0xE6, 0x01, 0x0A, 0x02, 0xF0, 0x01, 0xD2, 0x01, 0xB6, 0x01, 0xAF, 0x01, 0xB1, 0x01, 0xA8, 0x01, 0xB7, 0x01, 0xB3, 0x01, 0x8E, 0x01, 0x8D, 0x01, 0xB2, 0x01, 0xD7, 0x01, 0xF8, 0x01, 0x12, 0x02, 0x21, 0x02, 0x0F, 0x02, 0xDF, 0x01, 0xBA, 0x01, 0x9C, 0x01, 0xA6, 0x01, 0xB1, 0x01, 0x80, 0x01, 0x48, 0x01, 0x23, 0x01, 0x10, 0x01, 0x1F, 0x01, 0x3A, 0x01, 0x3B, 0x01, 0x44, 0x01, 0x48, 0x01, 0x3F, 0x01, 0x60, 0x01, 0x8B, 0x01, 0xB9, 0x01, 0xCA, 0x01, 0x9D, 0x01, 0x60, 0x01, 0xFE, 0x00, 0xCC, 0x00, 0xBF, 0x00, 0x98, 0x00, 0x96, 0x00, 0x93, 0x00, 0x86, 0x00, 0x90, 0x00, 0x9A, 0x00, 0xAC, 0x00, 0xCF, 0x00, 0xEA, 0x00, 0xD2, 0x00, 0xB5, 0x00, 0x8F, 0x00, 0x62, 0x00, 0x51, 0x00, 0x33, 0x00, 0x3B, 0x00, 0x66, 0x00, 0x8A, 0x00, 0xD8, 0x00, 0x23, 0x01, 0x54, 0x01, 0x93, 0x01, 0xB0, 0x01, 0xBB, 0x01, 0xD2, 0x01, 0xCA, 0x01, 0xCC, 0x01, 0xD3, 0x01, 0xC6, 0x01, 0xF0, 0x01, 0x31, 0x02, 0x5A, 0x02, 0x86, 0x02, 0x92, 0x02, 0x7E, 0x02, 0x81, 0x02, 0x70, 0x02, 0x5D, 0x02, 0x60, 0x02, 0x35, 0x02, 0x10, 0x02, 0xCD, 0x01, 0x62, 0x01, 0x69, 0x01, 0x82, 0x01, 0xB3, 0x01, 0x2F, 0x02, 0x69, 0x02, 0x95, 0x02, 0xA6, 0x02, 0x7B, 0x02, 0x4B, 0x02, 0x21, 0x02, 0x14, 0x02, 0x01, 0x02, 0xEE, 0x01, 0xB0, 0x01, 0x3B, 0x01, 0xF7, 0x00, 0xA8, 0x00, 0x7E, 0x00, 0x79, 0x00, 0x36, 0x00, 0x20, 0x00, 0x1C, 0x00, 0x14, 0x00, 0x3F, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0xE4, 0xFF, 0x78, 0xFF, 0x4F, 0xFF, 0x31, 0xFF, 0x00, 0xFF, 0x04, 0xFF, 0xED, 0xFE, 0xC9, 0xFE, 0xC6, 0xFE, 0xD8, 0xFE, 0xEA, 0xFE, 0xF9, 0xFE, 0xFA, 0xFE, 0xBB, 0xFE, 0x9C, 0xFE, 0x84, 0xFE, 0x70, 0xFE, 0xA7, 0xFE, 0xD3, 0xFE, 0xF4, 0xFE, 0xF5, 0xFE, 0xD7, 0xFE, 0x05, 0xFF, 0x2D, 0xFF, 0x21, 0xFF, 0x0A, 0xFF, 0x10, 0xFF, 0x28, 0xFF, 0x46, 0xFF, 0x53, 0xFF, 0x1C, 0xFF, 0xE3, 0xFE, 0xC4, 0xFE, 0xAB, 0xFE, 0xC9, 0xFE, 0x04, 0xFF, 0x58, 0xFF, 0xD6, 0xFF, 0x35, 0x00, 0x7E, 0x00, 0xD8, 0x00, 0x12, 0x01, 0x2D, 0x01, 0x30, 0x01, 0xF6, 0x00, 0xA1, 0x00, 0x4A, 0x00, 0x15, 0x00, 0x04, 0x00, 0x11, 0x00, 0x40, 0x00, 0x63, 0x00, 0x86, 0x00, 0xC3, 0x00, 0x35, 0x01, 0xB9, 0x01, 0x0D, 0x02, 0x64, 0x02, 0x86, 0x02, 0x71, 0x02, 0x44, 0x02, 0xDC, 0x01, 0x83, 0x01, 0x41, 0x01, 0x18, 0x01, 0x0B, 0x01, 0xEB, 0x00, 0xB8, 0x00, 0x99, 0x00, 0xB5, 0x00, 0xDB, 0x00, 0xF4, 0x00, 0x10, 0x01, 0x0D, 0x01, 0xFB, 0x00, 0xE3, 0x00, 0xDF, 0x00, 0xE6, 0x00, 0xE7, 0x00, 0xF2, 0x00, 0xFC, 0x00, 0xFA, 0x00, 0xD6, 0x00, 0x9C, 0x00, 0x6E, 0x00, 0x20, 0x00, 0xEB, 0xFF, 0xB1, 0xFF, 0x39, 0xFF, 0xEC, 0xFE, 0xBE, 0xFE, 0xA9, 0xFE, 0xAE, 0xFE, 0xA1, 0xFE, 0xA1, 0xFE, 0xA6, 0xFE, 0x9B, 0xFE, 0x77, 0xFE, 0x62, 0xFE, 0x83, 0xFE, 0x94, 0xFE, 0xA0, 0xFE, 0x6B, 0xFE, 0xFE, 0xFD, 0xC7, 0xFD, 0x8F, 0xFD, 0x88, 0xFD, 0x93, 0xFD, 0x92, 0xFD, 0xC2, 0xFD, 0xCE, 0xFD, 0xC5, 0xFD, 0xAE, 0xFD, 0xA2, 0xFD, 0xA2, 0xFD, 0x7B, 0xFD, 0x66, 0xFD, 0x55, 0xFD, 0x55, 0xFD, 0x52, 0xFD, 0x56, 0xFD, 0x7D, 0xFD, 0x9A, 0xFD, 0xD5, 0xFD, 0xF5, 0xFD, 0x08, 0xFE, 0x46, 0xFE, 0x7F, 0xFE, 0xC2, 0xFE, 0xF1, 0xFE, 0x14, 0xFF, 0x0A, 0xFF, 0xDC, 0xFE, 0x96, 0xFE, 0x33, 0xFE, 0x15, 0xFE, 0xF8, 0xFD, 0xF6, 0xFD, 0x24, 0xFE, 0x32, 0xFE, 0x61, 0xFE, 0x98, 0xFE, 0xDF, 0xFE, 0x27, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x39, 0xFF, 0x39, 0xFF, 0x25, 0xFF, 0x0F, 0xFF, 0xE4, 0xFE, 0xB3, 0xFE, 0x86, 0xFE, 0x3C, 0xFE, 0x15, 0xFE, 0xFE, 0xFD, 0x19, 0xFE, 0x56, 0xFE, 0x6F, 0xFE, 0x83, 0xFE, 0x92, 0xFE, 0xA6, 0xFE, 0xCB, 0xFE, 0xF8, 0xFE, 0x18, 0xFF, 0x41, 0xFF, 0x7A, 0xFF, 0x80, 0xFF, 0x83, 0xFF, 0x67, 0xFF, 0x48, 0xFF, 0x3F, 0xFF, 0x2B, 0xFF, 0x4E, 0xFF, 0x45, 0xFF, 0x22, 0xFF, 0xE2, 0xFE, 0x66, 0xFE, 0x16, 0xFE, 0xC4, 0xFD, 0xF0, 0xFD, 0x71, 0xFE, 0xE1, 0xFE, 0x92, 0xFF, 0xEB, 0xFF, 0x0D, 0x00, 0x20, 0x00, 0xFB, 0xFF, 0x0C, 0x00, 0x13, 0x00, 0xF3, 0xFF, 0xAA, 0xFF, 0x26, 0xFF, 0x9B, 0xFE, 0x11, 0xFE, 0xA6, 0xFD, 0x5B, 0xFD, 0x1E, 0xFD, 0x04, 0xFD, 0x19, 0xFD, 0x43, 0xFD, 0x93, 0xFD, 0x02, 0xFE, 0x47, 0xFE, 0x63, 0xFE, 0x3F, 0xFE, 0xFA, 0xFD, 0xDE, 0xFD, 0xCF, 0xFD, 0xCB, 0xFD, 0xB6, 0xFD, 0x96, 0xFD, 0x8C, 0xFD, 0x81, 0xFD, 0x84, 0xFD, 0x7D, 0xFD, 0x7F, 0xFD, 0xA1, 0xFD, 0xB2, 0xFD, 0xBC, 0xFD, 0xF3, 0xFD, 0x46, 0xFE, 0x7E, 0xFE, 0x99, 0xFE, 0xA8, 0xFE, 0xB9, 0xFE, 0xA6, 0xFE, 0x5A, 0xFE, 0x1D, 0xFE, 0xE7, 0xFD, 0xC2, 0xFD, 0xB7, 0xFD, 0x8D, 0xFD, 0x7E, 0xFD, 0x87, 0xFD, 0x7B, 0xFD, 0x4E, 0xFD, 0x16, 0xFD, 0x08, 0xFD, 0x0A, 0xFD, 0x4D, 0xFD, 0xB5, 0xFD, 0x0C, 0xFE, 0x65, 0xFE, 0x7F, 0xFE, 0xA0, 0xFE, 0xC7, 0xFE, 0xC9, 0xFE, 0xD9, 0xFE, 0xBF, 0xFE, 0x87, 0xFE, 0x5D, 0xFE, 0x2D, 0xFE, 0xF1, 0xFD, 0xBF, 0xFD, 0xB5, 0xFD, 0xBD, 0xFD, 0xE7, 0xFD, 0x05, 0xFE, 0x2D, 0xFE, 0x7A, 0xFE, 0xA2, 0xFE, 0xE1, 0xFE, 0x0C, 0xFF, 0x0F, 0xFF, 0x0C, 0xFF, 0xD2, 0xFE, 0xA9, 0xFE, 0x93, 0xFE, 0x7A, 0xFE, 0x6B, 0xFE, 0x32, 0xFE, 0xBC, 0xFD, 0x54, 0xFD, 0x29, 0xFD, 0x18, 0xFD, 0x36, 0xFD, 0x67, 0xFD, 0x8D, 0xFD, 0xBD, 0xFD, 0xBC, 0xFD, 0xCC, 0xFD, 0xF8, 0xFD, 0x26, 0xFE, 0x48, 0xFE, 0x4D, 0xFE, 0x5C, 0xFE, 0x46, 0xFE, 0x10, 0xFE, 0xFD, 0xFD, 0x04, 0xFE, 0x01, 0xFE, 0x0D, 0xFE, 0x08, 0xFE, 0xDA, 0xFD, 0xE5, 0xFD, 0xED, 0xFD, 0xE4, 0xFD, 0xFE, 0xFD, 0xDE, 0xFD, 0xCD, 0xFD, 0xCC, 0xFD, 0xB5, 0xFD, 0xD8, 0xFD, 0x1D, 0xFE, 0x60, 0xFE, 0x86, 0xFE, 0xA4, 0xFE, 0xAB, 0xFE, 0xAD, 0xFE, 0xB1, 0xFE, 0x80, 0xFE, 0x4C, 0xFE, 0x03, 0xFE, 0xEA, 0xFD, 0x19, 0xFE, 0x45, 0xFE, 0xA1, 0xFE, 0xFF, 0xFE, 0x41, 0xFF, 0x76, 0xFF, 0x95, 0xFF, 0x97, 0xFF, 0x7B, 0xFF, 0x5D, 0xFF, 0x49, 0xFF, 0x58, 0xFF, 0x6D, 0xFF, 0x88, 0xFF, 0xB1, 0xFF, 0xCA, 0xFF, 0xF1, 0xFF, 0xE2, 0xFF, 0xBB, 0xFF, 0xAE, 0xFF, 0x8E, 0xFF, 0x8F, 0xFF, 0x8E, 0xFF, 0x92, 0xFF, 0xBF, 0xFF, 0xDE, 0xFF, 0xF3, 0xFF, 0xF2, 0xFF, 0xEC, 0xFF, 0x0F, 0x00, 0x39, 0x00, 0x49, 0x00, 0x59, 0x00, 0x65, 0x00, 0x79, 0x00, 0xA0, 0x00, 0xB8, 0x00, 0xBD, 0x00, 0x8B, 0x00, 0x52, 0x00, 0x18, 0x00, 0xB6, 0xFF, 0x69, 0xFF, 0x1C, 0xFF, 0xD6, 0xFE, 0xB2, 0xFE, 0x92, 0xFE, 0x8F, 0xFE, 0xC5, 0xFE, 0x1D, 0xFF, 0x7E, 0xFF, 0xF0, 0xFF, 0x43, 0x00, 0x6D, 0x00, 0x7F, 0x00, 0x73, 0x00, 0x5F, 0x00, 0x21, 0x00, 0xCF, 0xFF, 0x57, 0xFF, 0xC7, 0xFE, 0x5D, 0xFE, 0x10, 0xFE, 0x15, 0xFE, 0x26, 0xFE, 0x1B, 0xFE, 0x1E, 0xFE, 0x02, 0xFE, 0xF6, 0xFD, 0x08, 0xFE, 0x2A, 0xFE, 0x68, 0xFE, 0x8B, 0xFE, 0x85, 0xFE, 0x7C, 0xFE, 0x87, 0xFE, 0x8D, 0xFE, 0xA8, 0xFE, 0xC6, 0xFE, 0xCA, 0xFE, 0xC8, 0xFE, 0x9F, 0xFE, 0x82, 0xFE, 0x57, 0xFE, 0x24, 0xFE, 0xF6, 0xFD, 0xA0, 0xFD, 0x67, 0xFD, 0x4A, 0xFD, 0x6A, 0xFD, 0xC6, 0xFD, 0x25, 0xFE, 0xA0, 0xFE, 0xF7, 0xFE, 0x3C, 0xFF, 0x72, 0xFF, 0x7C, 0xFF, 0x87, 0xFF, 0x84, 0xFF, 0x7E, 0xFF, 0x5D, 0xFF, 0x1C, 0xFF, 0xF0, 0xFE, 0xC5, 0xFE, 0x90, 0xFE, 0x7F, 0xFE, 0x90, 0xFE, 0xB8, 0xFE, 0x0F, 0xFF, 0x93, 0xFF, 0x10, 0x00, 0x77, 0x00, 0xC5, 0x00, 0x05, 0x01, 0x40, 0x01, 0x3A, 0x01, 0x0F, 0x01, 0x08, 0x01, 0xE3, 0x00, 0xBD, 0x00, 0xAE, 0x00, 0x84, 0x00, 0x77, 0x00, 0x6A, 0x00, 0x6D, 0x00, 0x83, 0x00, 0x7E, 0x00, 0x9E, 0x00, 0xD3, 0x00, 0x2B, 0x01, 0x80, 0x01, 0xA4, 0x01, 0xC4, 0x01, 0xA9, 0x01, 0x97, 0x01, 0xA4, 0x01, 0x97, 0x01, 0x8D, 0x01, 0x5C, 0x01, 0x41, 0x01, 0x38, 0x01, 0x11, 0x01, 0x09, 0x01, 0xEE, 0x00, 0xDA, 0x00, 0xE1, 0x00, 0xB6, 0x00, 0xA4, 0x00, 0x97, 0x00, 0x61, 0x00, 0x5A, 0x00, 0x6B, 0x00, 0x8D, 0x00, 0xE2, 0x00, 0x1F, 0x01, 0x3C, 0x01, 0x49, 0x01, 0xFE, 0x00, 0x8F, 0x00, 0x45, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xB1, 0xFF, 0x6E, 0xFF, 0x4E, 0xFF, 0x69, 0xFF, 0xBC, 0xFF, 0x0A, 0x00, 0x49, 0x00, 0x65, 0x00, 0x70, 0x00, 0x65, 0x00, 0x31, 0x00, 0x07, 0x00, 0xE2, 0xFF, 0xD3, 0xFF, 0xDF, 0xFF, 0xE3, 0xFF, 0xDC, 0xFF, 0xCF, 0xFF, 0xB5, 0xFF, 0xAA, 0xFF, 0xB1, 0xFF, 0xA5, 0xFF, 0xB5, 0xFF, 0xB7, 0xFF, 0x9F, 0xFF, 0xB1, 0xFF, 0x9B, 0xFF, 0x93, 0xFF, 0x93, 0xFF, 0x6F, 0xFF, 0xA3, 0xFF, 0xE5, 0xFF, 0x18, 0x00, 0x2A, 0x00, 0xEE, 0xFF, 0xCE, 0xFF, 0xB2, 0xFF, 0x74, 0xFF, 0x5D, 0xFF, 0x70, 0xFF, 0x73, 0xFF, 0x8F, 0xFF, 0xCD, 0xFF, 0xD6, 0xFF, 0xF5, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x27, 0x00, 0x0F, 0x00, 0x26, 0x00, 0x7C, 0x00, 0xAE, 0x00, 0xF5, 0x00, 0x15, 0x01, 0x47, 0x01, 0x91, 0x01, 0xA8, 0x01, 0xB8, 0x01, 0x88, 0x01, 0x3A, 0x01, 0xF0, 0x00, 0xA3, 0x00, 0x7B, 0x00, 0x52, 0x00, 0x57, 0x00, 0x78, 0x00, 0x88, 0x00, 0xA9, 0x00, 0xB5, 0x00, 0xE0, 0x00, 0x17, 0x01, 0x39, 0x01, 0x7B, 0x01, 0x92, 0x01, 0xB3, 0x01, 0xE9, 0x01, 0x00, 0x02, 0x47, 0x02, 0x74, 0x02, 0x72, 0x02, 0x80, 0x02, 0x73, 0x02, 0x66, 0x02, 0x63, 0x02, 0x3F, 0x02, 0x2A, 0x02, 0x20, 0x02, 0x1D, 0x02, 0x23, 0x02, 0x0C, 0x02, 0x03, 0x02, 0x06, 0x02, 0xF3, 0x01, 0xD6, 0x01, 0xAC, 0x01, 0x94, 0x01, 0x75, 0x01, 0x58, 0x01, 0x69, 0x01, 0x7B, 0x01, 0x96, 0x01, 0x93, 0x01, 0x5B, 0x01, 0x26, 0x01, 0xE8, 0x00, 0xD2, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xEA, 0x00, 0x0B, 0x01, 0x3F, 0x01, 0x8E, 0x01, 0xCE, 0x01, 0x0D, 0x02, 0x4F, 0x02, 0x3B, 0x02, 0x15, 0x02, 0xF1, 0x01, 0xA7, 0x01, 0x91, 0x01, 0x72, 0x01, 0x38, 0x01, 0x05, 0x01, 0xCF, 0x00, 0xBD, 0x00, 0xAD, 0x00, 0xC8, 0x00, 0xF8, 0x00, 0x1A, 0x01, 0x61, 0x01, 0xB8, 0x01, 0x20, 0x02, 0x52, 0x02, 0x55, 0x02, 0x63, 0x02, 0x64, 0x02, 0x8E, 0x02, 0xAB, 0x02, 0xC0, 0x02, 0xDD, 0x02, 0xC5, 0x02, 0x9F, 0x02, 0x83, 0x02, 0x5C, 0x02, 0x20, 0x02, 0xE3, 0x01, 0x9F, 0x01, 0x42, 0x01, 0xEE, 0x00, 0xB4, 0x00, 0xAF, 0x00, 0xE5, 0x00, 0x5A, 0x01, 0xE2, 0x01, 0x57, 0x02, 0xB6, 0x02, 0xDF, 0x02, 0xFC, 0x02, 0xFE, 0x02, 0xD9, 0x02, 0xB2, 0x02, 0x69, 0x02, 0x14, 0x02, 0x9E, 0x01, 0x0A, 0x01, 0xB0, 0x00, 0xAE, 0x00, 0xEA, 0x00, 0x4E, 0x01, 0xBD, 0x01, 0xFE, 0x01, 0x42, 0x02, 0x9D, 0x02, 0xFA, 0x02, 0x41, 0x03, 0x3A, 0x03, 0x1A, 0x03, 0xD4, 0x02, 0x75, 0x02, 0x42, 0x02, 0x14, 0x02, 0xF9, 0x01, 0xBB, 0x01, 0x46, 0x01, 0xEE, 0x00, 0xB4, 0x00, 0xB3, 0x00, 0xEE, 0x00, 0x26, 0x01, 0x49, 0x01, 0x65, 0x01, 0x7A, 0x01, 0xA8, 0x01, 0xEF, 0x01, 0x28, 0x02, 0x5A, 0x02, 0x65, 0x02, 0x5E, 0x02, 0x70, 0x02, 0x63, 0x02, 0x3A, 0x02, 0x21, 0x02, 0x0C, 0x02, 0xD1, 0x01, 0x85, 0x01, 0x47, 0x01, 0x0B, 0x01, 0xF4, 0x00, 0xE9, 0x00, 0xDD, 0x00, 0xF6, 0x00, 0x25, 0x01, 0x72, 0x01, 0xCA, 0x01, 0x1B, 0x02, 0x89, 0x02, 0x0A, 0x03, 0x5C, 0x03, 0x87, 0x03, 0x98, 0x03, 0x6C, 0x03, 0x33, 0x03, 0xCA, 0x02, 0x35, 0x02, 0xD4, 0x01, 0x94, 0x01, 0x7E, 0x01, 0x7D, 0x01, 0x72, 0x01, 0x97, 0x01, 0xDE, 0x01, 0x34, 0x02, 0x86, 0x02, 0xB5, 0x02, 0xC4, 0x02, 0xA5, 0x02, 0x68, 0x02, 0x39, 0x02, 0x23, 0x02, 0xF5, 0x01, 0xD6, 0x01, 0xCF, 0x01, 0xA5, 0x01, 0x9E, 0x01, 0x95, 0x01, 0x78, 0x01, 0x90, 0x01, 0xA0, 0x01, 0x8A, 0x01, 0x6A, 0x01, 0x58, 0x01, 0x53, 0x01, 0x70, 0x01, 0xA2, 0x01, 0xB8, 0x01, 0xD5, 0x01, 0xE0, 0x01, 0xEA, 0x01, 0x1C, 0x02, 0x3D, 0x02, 0x60, 0x02, 0x62, 0x02, 0x36, 0x02, 0xFF, 0x01, 0xB7, 0x01, 0x75, 0x01, 0x38, 0x01, 0x08, 0x01, 0xDC, 0x00, 0xEF, 0x00, 0x38, 0x01, 0x62, 0x01, 0xAF, 0x01, 0xEB, 0x01, 0x15, 0x02, 0x5A, 0x02, 0x7B, 0x02, 0x94, 0x02, 0x94, 0x02, 0x84, 0x02, 0x5A, 0x02, 0x28, 0x02, 0x0B, 0x02, 0xAC, 0x01, 0x55, 0x01, 0x24, 0x01, 0x07, 0x01, 0xF8, 0x00, 0xD1, 0x00, 0xE3, 0x00, 0x2E, 0x01, 0x83, 0x01, 0xC8, 0x01, 0xE3, 0x01, 0xEF, 0x01, 0xF2, 0x01, 0xEE, 0x01, 0xBE, 0x01, 0x99, 0x01, 0x9E, 0x01, 0x9D, 0x01, 0xD6, 0x01, 0xFA, 0x01, 0xFD, 0x01, 0x28, 0x02, 0x28, 0x02, 0x08, 0x02, 0xCF, 0x01, 0x7E, 0x01, 0x36, 0x01, 0xEB, 0x00, 0xA3, 0x00, 0x72, 0x00, 0x8D, 0x00, 0xD5, 0x00, 0x0E, 0x01, 0x4E, 0x01, 0x79, 0x01, 0xA0, 0x01, 0xCC, 0x01, 0xDD, 0x01, 0xD7, 0x01, 0xC0, 0x01, 0x88, 0x01, 0x19, 0x01, 0xAF, 0x00, 0x61, 0x00, 0x22, 0x00, 0x12, 0x00, 0xFA, 0xFF, 0xCF, 0xFF, 0xB1, 0xFF, 0x87, 0xFF, 0x6E, 0xFF, 0x71, 0xFF, 0xAB, 0xFF, 0x1B, 0x00, 0x5E, 0x00, 0x8B, 0x00, 0xAE, 0x00, 0xA2, 0x00, 0xAA, 0x00, 0x93, 0x00, 0x3D, 0x00, 0xEC, 0xFF, 0x95, 0xFF, 0x5C, 0xFF, 0x3F, 0xFF, 0x2A, 0xFF, 0x39, 0xFF, 0x42, 0xFF, 0x4B, 0xFF, 0x4C, 0xFF, 0x56, 0xFF, 0x94, 0xFF, 0xCD, 0xFF, 0x0B, 0x00, 0x40, 0x00, 0x53, 0x00, 0x5B, 0x00, 0x5A, 0x00, 0x76, 0x00, 0x7E, 0x00, 0x7B, 0x00, 0x74, 0x00, 0x59, 0x00, 0x55, 0x00, 0x42, 0x00, 0x3E, 0x00, 0x2E, 0x00, 0xFD, 0xFF, 0xDB, 0xFF, 0xAD, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xBB, 0xFF, 0xF2, 0xFF, 0x10, 0x00, 0x55, 0x00, 0x94, 0x00, 0xB5, 0x00, 0xCD, 0x00, 0xC6, 0x00, 0xAA, 0x00, 0x64, 0x00, 0x1B, 0x00, 0xDF, 0xFF, 0xB4, 0xFF, 0xAF, 0xFF, 0xAB, 0xFF, 0xA9, 0xFF, 0x7F, 0xFF, 0x6B, 0xFF, 0x9D, 0xFF, 0xCC, 0xFF, 0x02, 0x00, 0x26, 0x00, 0x52, 0x00, 0xA1, 0x00, 0xC6, 0x00, 0xCF, 0x00, 0xD9, 0x00, 0xD3, 0x00, 0xAC, 0x00, 0x65, 0x00, 0x21, 0x00, 0x0B, 0x00, 0x1B, 0x00, 0x26, 0x00, 0x1A, 0x00, 0xF5, 0xFF, 0xE2, 0xFF, 0xDD, 0xFF, 0xC3, 0xFF, 0xAB, 0xFF, 0x88, 0xFF, 0x5E, 0xFF, 0x43, 0xFF, 0x2E, 0xFF, 0x11, 0xFF, 0x10, 0xFF, 0x4D, 0xFF, 0xB5, 0xFF, 0x10, 0x00, 0x3A, 0x00, 0x61, 0x00, 0x76, 0x00, 0x54, 0x00, 0x3F, 0x00, 0x1D, 0x00, 0xEB, 0xFF, 0xD1, 0xFF, 0xB2, 0xFF, 0xAE, 0xFF, 0xD7, 0xFF, 0xFE, 0xFF, 0x31, 0x00, 0x80, 0x00, 0xC6, 0x00, 0x03, 0x01, 0x3F, 0x01, 0x4C, 0x01, 0x3D, 0x01, 0x27, 0x01, 0xF2, 0x00, 0xBA, 0x00, 0x97, 0x00, 0x71, 0x00, 0x70, 0x00, 0x6B, 0x00, 0x3F, 0x00, 0x2C, 0x00, 0x23, 0x00, 0x31, 0x00, 0x62, 0x00, 0x7A, 0x00, 0x81, 0x00, 0x86, 0x00, 0xA3, 0x00, 0xCE, 0x00, 0xE0, 0x00, 0xF5, 0x00, 0x12, 0x01, 0x23, 0x01, 0x1B, 0x01, 0xF7, 0x00, 0xAF, 0x00, 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4D, 0x00, 0x37, 0x00, 0x07, 0x00, 0xE6, 0xFF, 0xEE, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0x07, 0x00, 0x14, 0x00, 0x28, 0x00, 0x52, 0x00, 0x5D, 0x00, 0x59, 0x00, 0x49, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x0D, 0x00, 0xC5, 0xFF, 0xAA, 0xFF, 0x94, 0xFF, 0x9B, 0xFF, 0x82, 0xFF, 0x27, 0xFF, 0xFC, 0xFE, 0xF2, 0xFE, 0xED, 0xFE, 0x1C, 0xFF, 0x38, 0xFF, 0x29, 0xFF, 0x1E, 0xFF, 0xE0, 0xFE, 0xA4, 0xFE, 0x9D, 0xFE, 0x87, 0xFE, 0x80, 0xFE, 0xA2, 0xFE, 0x94, 0xFE, 0x72, 0xFE, 0x47, 0xFE, 0x1A, 0xFE, 0x13, 0xFE, 0x09, 0xFE, 0x09, 0xFE, 0xF8, 0xFD, 0xCF, 0xFD, 0xCC, 0xFD, 0xC3, 0xFD, 0xA0, 0xFD, 0x99, 0xFD, 0x93, 0xFD, 0x7A, 0xFD, 0x75, 0xFD, 0x78, 0xFD, 0x88, 0xFD, 0xC4, 0xFD, 0xF5, 0xFD, 0x31, 0xFE, 0x67, 0xFE, 0x79, 0xFE, 0x76, 0xFE, 0x48, 0xFE, 0x2B, 0xFE, 0x03, 0xFE, 0xC1, 0xFD, 0x9A, 0xFD, 0x82, 0xFD, 0x94, 0xFD, 0x96, 0xFD, 0x98, 0xFD, 0xC6, 0xFD, 0xEE, 0xFD, 0x3D, 0xFE, 0x8E, 0xFE, 0xE5, 0xFE, 0x5A, 0xFF, 0x9E, 0xFF, 0xC3, 0xFF, 0xCA, 0xFF, 0xB6, 0xFF, 0xA4, 0xFF, 0x7D, 0xFF, 0x4D, 0xFF, 0x1D, 0xFF, 0x0C, 0xFF, 0x3E, 0xFF, 0x96, 0xFF, 0x1E, 0x00, 0x9A, 0x00, 0xE8, 0x00, 0x13, 0x01, 0xF1, 0x00, 0xC9, 0x00, 0xB5, 0x00, 0x9E, 0x00, 0xAB, 0x00, 0xAA, 0x00, 0xA6, 0x00, 0xB2, 0x00, 0xAC, 0x00, 0xAD, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0xD2, 0x00, 0xF7, 0x00, 0x06, 0x01, 0x1A, 0x01, 0x41, 0x01, 0x8A, 0x01, 0xE9, 0x01, 0x3E, 0x02, 0x83, 0x02, 0x7D, 0x02, 0x47, 0x02, 0x40, 0x02, 0x3E, 0x02, 0x45, 0x02, 0x3F, 0x02, 0x07, 0x02, 0xDB, 0x01, 0x9A, 0x01, 0x5C, 0x01, 0x40, 0x01, 0x49, 0x01, 0x5D, 0x01, 0x3B, 0x01, 0x1C, 0x01, 0xF8, 0x00, 0xDA, 0x00, 0xEC, 0x00, 0xF1, 0x00, 0xED, 0x00, 0xDA, 0x00, 0xAA, 0x00, 0xA2, 0x00, 0xA9, 0x00, 0x8D, 0x00, 0x86, 0x00, 0x72, 0x00, 0x31, 0x00, 0xE6, 0xFF, 0xAB, 0xFF, 0xBA, 0xFF, 0xE0, 0xFF, 0xF6, 0xFF, 0x1A, 0x00, 0x40, 0x00, 0x56, 0x00, 0x55, 0x00, 0x4F, 0x00, 0x37, 0x00, 0x19, 0x00, 0xED, 0xFF, 0x9C, 0xFF, 0x5B, 0xFF, 0x0A, 0xFF, 0xDC, 0xFE, 0xD7, 0xFE, 0xDC, 0xFE, 0x24, 0xFF, 0x66, 0xFF, 0xA2, 0xFF, 0xC4, 0xFF, 0xC0, 0xFF, 0xC8, 0xFF, 0xCF, 0xFF, 0xFC, 0xFF, 0x11, 0x00, 0x06, 0x00, 0xF5, 0xFF, 0xB9, 0xFF, 0x82, 0xFF, 0x45, 0xFF, 0x14, 0xFF, 0xE7, 0xFE, 0xD4, 0xFE, 0xFD, 0xFE, 0x28, 0xFF, 0x6C, 0xFF, 0x82, 0xFF, 0x6E, 0xFF, 0x47, 0xFF, 0x13, 0xFF, 0x03, 0xFF, 0xC5, 0xFE, 0x93, 0xFE, 0x7C, 0xFE, 0x45, 0xFE, 0x4E, 0xFE, 0x83, 0xFE, 0xCE, 0xFE, 0x2B, 0xFF, 0x89, 0xFF, 0xBF, 0xFF, 0xC1, 0xFF, 0xD1, 0xFF, 0xE3, 0xFF, 0xF9, 0xFF, 0xFD, 0xFF, 0xF1, 0xFF, 0xE7, 0xFF, 0xBB, 0xFF, 0x96, 0xFF, 0x93, 0xFF, 0xB3, 0xFF, 0xD0, 0xFF, 0xD0, 0xFF, 0xDC, 0xFF, 0xE6, 0xFF, 0xEE, 0xFF, 0xF5, 0xFF, 0xE0, 0xFF, 0xCA, 0xFF, 0xC6, 0xFF, 0xBC, 0xFF, 0xB4, 0xFF, 0xCF, 0xFF, 0xF3, 0xFF, 0x1D, 0x00, 0x38, 0x00, 0x39, 0x00, 0x30, 0x00, 0x21, 0x00, 0x22, 0x00, 0x25, 0x00, 0x28, 0x00, 0x3C, 0x00, 0x3E, 0x00, 0x31, 0x00, 0x38, 0x00, 0x24, 0x00, 0x0D, 0x00, 0xF1, 0xFF, 0xCD, 0xFF, 0xD5, 0xFF, 0xC1, 0xFF, 0xB9, 0xFF, 0xD7, 0xFF, 0xD1, 0xFF, 0xFC, 0xFF, 0x22, 0x00, 0x2C, 0x00, 0x39, 0x00, 0x11, 0x00, 0xF7, 0xFF, 0xC7, 0xFF, 0x8A, 0xFF, 0x77, 0xFF, 0x63, 0xFF, 0x80, 0xFF, 0xAB, 0xFF, 0xD0, 0xFF, 0x05, 0x00, 0x36, 0x00, 0x64, 0x00, 0x83, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xBA, 0x00, 0x8E, 0x00, 0x50, 0x00, 0x0A, 0x00, 0xBC, 0xFF, 0xC7, 0xFF, 0xE0, 0xFF, 0x0D, 0x00, 0x6B, 0x00, 0x7A, 0x00, 0x84, 0x00, 0x8A, 0x00, 0x6A, 0x00, 0x71, 0x00, 0x56, 0x00, 0x3E, 0x00, 0x40, 0x00, 0x0B, 0x00, 0xEE, 0xFF, 0xF5, 0xFF, 0x03, 0x00, 0x34, 0x00, 0x59, 0x00, 0x64, 0x00, 0x6F, 0x00, 0x77, 0x00, 0x65, 0x00, 0x39, 0x00, 0x23, 0x00, 0x1D, 0x00, 0x28, 0x00, 0x3D, 0x00, 0x42, 0x00, 0x56, 0x00, 0x6B, 0x00, 0x84, 0x00, 0x91, 0x00, 0x86, 0x00, 0x9C, 0x00, 0xC1, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDD, 0x00, 0xEE, 0x00, 0xE3, 0x00, 0xDE, 0x00, 0xBF, 0x00, 0x75, 0x00, 0x3C, 0x00, 0x13, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x28, 0x00, 0x63, 0x00, 0xA8, 0x00, 0xE8, 0x00, 0x16, 0x01, 0x41, 0x01, 0x47, 0x01, 0x1B, 0x01, 0xDE, 0x00, 0x87, 0x00, 0x34, 0x00, 0xEE, 0xFF, 0xBF, 0xFF, 0xBB, 0xFF, 0x9D, 0xFF, 0x86, 0xFF, 0x8D, 0xFF, 0x64, 0xFF, 0x41, 0xFF, 0x37, 0xFF, 0x25, 0xFF, 0x23, 0xFF, 0xF9, 0xFE, 0xBF, 0xFE, 0x8B, 0xFE, 0x52, 0xFE, 0x4D, 0xFE, 0x43, 0xFE, 0x41, 0xFE, 0x53, 0xFE, 0x4D, 0xFE, 0x5D, 0xFE, 0x61, 0xFE, 0x6E, 0xFE, 0x88, 0xFE, 0x73, 0xFE, 0x53, 0xFE, 0x30, 0xFE, 0x08, 0xFE, 0xE0, 0xFD, 0xB3, 0xFD, 0x86, 0xFD, 0x7F, 0xFD, 0x8B, 0xFD, 0x91, 0xFD, 0xA3, 0xFD, 0xB0, 0xFD, 0xD9, 0xFD, 0xFA, 0xFD, 0xF3, 0xFD, 0x07, 0xFE, 0x0B, 0xFE, 0x1A, 0xFE, 0x3E, 0xFE, 0x34, 0xFE, 0x29, 0xFE, 0x33, 0xFE, 0x6D, 0xFE, 0xBC, 0xFE, 0xF5, 0xFE, 0x35, 0xFF, 0x60, 0xFF, 0x80, 0xFF, 0x9E, 0xFF, 0xAB, 0xFF, 0xAB, 0xFF, 0x8A, 0xFF, 0x4A, 0xFF, 0x0A, 0xFF, 0xD7, 0xFE, 0xDE, 0xFE, 0x06, 0xFF, 0x35, 0xFF, 0x81, 0xFF, 0x9C, 0xFF, 0x88, 0xFF, 0x86, 0xFF, 0x72, 0xFF, 0x82, 0xFF, 0x97, 0xFF, 0x95, 0xFF, 0xC9, 0xFF, 0xE9, 0xFF, 0xEC, 0xFF, 0xE1, 0xFF, 0xAC, 0xFF, 0x85, 0xFF, 0x58, 0xFF, 0x1D, 0xFF, 0x03, 0xFF, 0xFB, 0xFE, 0xF0, 0xFE, 0xED, 0xFE, 0x05, 0xFF, 0x1B, 0xFF, 0x24, 0xFF, 0x2B, 0xFF, 0x1D, 0xFF, 0xF5, 0xFE, 0xC2, 0xFE, 0x78, 0xFE, 0x2C, 0xFE, 0x1C, 0xFE, 0x2A, 0xFE, 0x45, 0xFE, 0x6C, 0xFE, 0x5E, 0xFE, 0x4B, 0xFE, 0x5C, 0xFE, 0x5D, 0xFE, 0x54, 0xFE, 0x59, 0xFE, 0x63, 0xFE, 0x6C, 0xFE, 0x73, 0xFE, 0x82, 0xFE, 0x8F, 0xFE, 0x8E, 0xFE, 0x80, 0xFE, 0x82, 0xFE, 0x82, 0xFE, 0x6E, 0xFE, 0x72, 0xFE, 0x8A, 0xFE, 0xA2, 0xFE, 0xC0, 0xFE, 0xB9, 0xFE, 0xA8, 0xFE, 0x93, 0xFE, 0x6D, 0xFE, 0x5F, 0xFE, 0x75, 0xFE, 0xAE, 0xFE, 0xE5, 0xFE, 0xEF, 0xFE, 0xF9, 0xFE, 0x0D, 0xFF, 0x26, 0xFF, 0x3D, 0xFF, 0x28, 0xFF, 0xF5, 0xFE, 0xB4, 0xFE, 0x86, 0xFE, 0x7E, 0xFE, 0x7B, 0xFE, 0x76, 0xFE, 0x6A, 0xFE, 0x62, 0xFE, 0x5D, 0xFE, 0x49, 0xFE, 0x35, 0xFE, 0x27, 0xFE, 0x2F, 0xFE, 0x58, 0xFE, 0x66, 0xFE, 0x6B, 0xFE, 0x64, 0xFE, 0x26, 0xFE, 0x0F, 0xFE, 0x19, 0xFE, 0x16, 0xFE, 0x27, 0xFE, 0xE7, 0xFD, 0x8C, 0xFD, 0x62, 0xFD, 0x3A, 0xFD, 0x70, 0xFD, 0xBE, 0xFD, 0xE0, 0xFD, 0x1F, 0xFE, 0x31, 0xFE, 0x31, 0xFE, 0x3C, 0xFE, 0x27, 0xFE, 0x23, 0xFE, 0x28, 0xFE, 0x36, 0xFE, 0x62, 0xFE, 0x7A, 0xFE, 0x8F, 0xFE, 0xC7, 0xFE, 0x0D, 0xFF, 0x3C, 0xFF, 0x55, 0xFF, 0x3F, 0xFF, 0xF1, 0xFE, 0xD6, 0xFE, 0xD9, 0xFE, 0xDC, 0xFE, 0xF2, 0xFE, 0xE7, 0xFE, 0xDB, 0xFE, 0xFA, 0xFE, 0x23, 0xFF, 0x48, 0xFF, 0x6D, 0xFF, 0x84, 0xFF, 0x99, 0xFF, 0xCE, 0xFF, 0xDC, 0xFF, 0xBC, 0xFF, 0xB5, 0xFF, 0x89, 0xFF, 0x64, 0xFF, 0x55, 0xFF, 0x26, 0xFF, 0x18, 0xFF, 0x07, 0xFF, 0xED, 0xFE, 0xED, 0xFE, 0xCB, 0xFE, 0xAC, 0xFE, 0xB4, 0xFE, 0xA4, 0xFE, 0x8E, 0xFE, 0x8F, 0xFE, 0x66, 0xFE, 0x44, 0xFE, 0x29, 0xFE, 0xDF, 0xFD, 0xBA, 0xFD, 0xA5, 0xFD, 0x88, 0xFD, 0x8A, 0xFD, 0x8B, 0xFD, 0x7B, 0xFD, 0x67, 0xFD, 0x59, 0xFD, 0x47, 0xFD, 0x1C, 0xFD, 0xDD, 0xFC, 0xB5, 0xFC, 0xAA, 0xFC, 0x99, 0xFC, 0xB0, 0xFC, 0xCE, 0xFC, 0xD3, 0xFC, 0xE5, 0xFC, 0xEB, 0xFC, 0xF5, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0x03, 0xFD, 0x07, 0xFD, 0x08, 0xFD, 0x03, 0xFD, 0x0F, 0xFD, 0x1F, 0xFD, 0x2D, 0xFD, 0x4F, 0xFD, 0x4E, 0xFD, 0x37, 0xFD, 0x2C, 0xFD, 0x1A, 0xFD, 0xFD, 0xFC, 0xE5, 0xFC, 0xDA, 0xFC, 0xEF, 0xFC, 0x10, 0xFD, 0x12, 0xFD, 0x0C, 0xFD, 0xF5, 0xFC, 0xFF, 0xFC, 0x45, 0xFD, 0x78, 0xFD, 0xCF, 0xFD, 0x12, 0xFE, 0x26, 0xFE, 0x63, 0xFE, 0x6E, 0xFE, 0x60, 0xFE, 0x64, 0xFE, 0x63, 0xFE, 0x6A, 0xFE, 0x6F, 0xFE, 0x89, 0xFE, 0xA5, 0xFE, 0xD2, 0xFE, 0xEB, 0xFE, 0xEA, 0xFE, 0x19, 0xFF, 0x3A, 0xFF, 0x51, 0xFF, 0x5E, 0xFF, 0x64, 0xFF, 0x85, 0xFF, 0x88, 0xFF, 0x99, 0xFF, 0x9A, 0xFF, 0x89, 0xFF, 0x83, 0xFF, 0x58, 0xFF, 0x2E, 0xFF, 0x12, 0xFF, 0x01, 0xFF, 0x04, 0xFF, 0x2C, 0xFF, 0x68, 0xFF, 0xA1, 0xFF, 0xFA, 0xFF, 0x30, 0x00, 0x40, 0x00, 0x33, 0x00, 0xE8, 0xFF, 0x97, 0xFF, 0x30, 0xFF, 0xD1, 0xFE, 0x7E, 0xFE, 0x30, 0xFE, 0x2C, 0xFE, 0x19, 0xFE, 0xFD, 0xFD, 0xE9, 0xFD, 0xB9, 0xFD, 0xA9, 0xFD, 0x9B, 0xFD, 0x9A, 0xFD, 0xA7, 0xFD, 0x9C, 0xFD, 0xA8, 0xFD, 0xC1, 0xFD, 0xC3, 0xFD, 0xC0, 0xFD, 0xBF, 0xFD, 0xA1, 0xFD, 0x5E, 0xFD, 0x3A, 0xFD, 0x16, 0xFD, 0xDF, 0xFC, 0xE9, 0xFC, 0x14, 0xFD, 0x26, 0xFD, 0x2A, 0xFD, 0x10, 0xFD, 0xF4, 0xFC, 0xEC, 0xFC, 0xFC, 0xFC, 0x43, 0xFD, 0x76, 0xFD, 0xA0, 0xFD, 0xD4, 0xFD, 0xE8, 0xFD, 0x2A, 0xFE, 0x7C, 0xFE, 0xAA, 0xFE, 0xEF, 0xFE, 0x16, 0xFF, 0x19, 0xFF, 0xFA, 0xFE, 0xCF, 0xFE, 0xBD, 0xFE, 0x90, 0xFE, 0x46, 0xFE, 0x16, 0xFE, 0x07, 0xFE, 0xF9, 0xFD, 0xF9, 0xFD, 0x0E, 0xFE, 0x41, 0xFE, 0xA2, 0xFE, 0xE8, 0xFE, 0x26, 0xFF, 0x42, 0xFF, 0x27, 0xFF, 0x0E, 0xFF, 0xBE, 0xFE, 0x72, 0xFE, 0x5A, 0xFE, 0x57, 0xFE, 0x88, 0xFE, 0xA9, 0xFE, 0xB8, 0xFE, 0xE1, 0xFE, 0xF8, 0xFE, 0x1E, 0xFF, 0x4F, 0xFF, 0x4E, 0xFF, 0x30, 0xFF, 0x08, 0xFF, 0xB7, 0xFE, 0x74, 0xFE, 0x3B, 0xFE, 0xFC, 0xFD, 0xFB, 0xFD, 0xE8, 0xFD, 0xE0, 0xFD, 0x0D, 0xFE, 0x31, 0xFE, 0x6F, 0xFE, 0x94, 0xFE, 0x8C, 0xFE, 0x9A, 0xFE, 0x79, 0xFE, 0x54, 0xFE, 0x51, 0xFE, 0x24, 0xFE, 0x00, 0xFE, 0xDE, 0xFD, 0x96, 0xFD, 0x63, 0xFD, 0x42, 0xFD, 0x29, 0xFD, 0x1C, 0xFD, 0x2F, 0xFD, 0x60, 0xFD, 0x8D, 0xFD, 0xD8, 0xFD, 0x14, 0xFE, 0x40, 0xFE, 0x65, 0xFE, 0x49, 0xFE, 0x27, 0xFE, 0x0B, 0xFE, 0xF8, 0xFD, 0xF0, 0xFD, 0xD0, 0xFD, 0xC6, 0xFD, 0xC5, 0xFD, 0xE5, 0xFD, 0x2D, 0xFE, 0x8B, 0xFE, 0x03, 0xFF, 0x62, 0xFF, 0x9E, 0xFF, 0xBB, 0xFF, 0xC1, 0xFF, 0xAB, 0xFF, 0x91, 0xFF, 0x83, 0xFF, 0x5F, 0xFF, 0x5D, 0xFF, 0x60, 0xFF, 0x66, 0xFF, 0x8F, 0xFF, 0x96, 0xFF, 0xA7, 0xFF, 0xC3, 0xFF, 0xC7, 0xFF, 0xD5, 0xFF, 0xE1, 0xFF, 0xF1, 0xFF, 0x03, 0x00, 0x2B, 0x00, 0x59, 0x00, 0x62, 0x00, 0x66, 0x00, 0x85, 0x00, 0xA8, 0x00, 0xBA, 0x00, 0xD5, 0x00, 0xFB, 0x00, 0x02, 0x01, 0xF6, 0x00, 0xE2, 0x00, 0xC1, 0x00, 0xAE, 0x00, 0xB0, 0x00, 0xB1, 0x00, 0xBB, 0x00, 0xCB, 0x00, 0xED, 0x00, 0x0D, 0x01, 0x1A, 0x01, 0x2D, 0x01, 0x40, 0x01, 0x78, 0x01, 0xB3, 0x01, 0xBA, 0x01, 0xC1, 0x01, 0xAF, 0x01, 0xA1, 0x01, 0x9C, 0x01, 0x90, 0x01, 0x99, 0x01, 0xA3, 0x01, 0xE3, 0x01, 0x21, 0x02, 0x38, 0x02, 0x58, 0x02, 0x5A, 0x02, 0x5C, 0x02, 0x5E, 0x02, 0x41, 0x02, 0x35, 0x02, 0x28, 0x02, 0x18, 0x02, 0xFD, 0x01, 0xC1, 0x01, 0xA3, 0x01, 0xAB, 0x01, 0xB9, 0x01, 0xD6, 0x01, 0xD6, 0x01, 0xC2, 0x01, 0xC4, 0x01, 0xB6, 0x01, 0x92, 0x01, 0x6B, 0x01, 0x51, 0x01, 0x1E, 0x01, 0xEE, 0x00, 0xF3, 0x00, 0xFD, 0x00, 0x21, 0x01, 0x45, 0x01, 0x52, 0x01, 0x5D, 0x01, 0x58, 0x01, 0x7D, 0x01, 0xAA, 0x01, 0xB3, 0x01, 0xC0, 0x01, 0xBE, 0x01, 0x9A, 0x01, 0x5A, 0x01, 0x16, 0x01, 0xEB, 0x00, 0xC5, 0x00, 0x89, 0x00, 0x63, 0x00, 0x5B, 0x00, 0x60, 0x00, 0x90, 0x00, 0xB2, 0x00, 0xCC, 0x00, 0xF8, 0x00, 0x11, 0x01, 0x2A, 0x01, 0x2E, 0x01, 0x24, 0x01, 0x37, 0x01, 0x63, 0x01, 0x77, 0x01, 0x60, 0x01, 0x4F, 0x01, 0x41, 0x01, 0x29, 0x01, 0xF3, 0x00, 0xCF, 0x00, 0xD1, 0x00, 0xCE, 0x00, 0xF9, 0x00, 0x24, 0x01, 0x4D, 0x01, 0x7A, 0x01, 0x9C, 0x01, 0xC5, 0x01, 0xBD, 0x01, 0xC0, 0x01, 0xBC, 0x01, 0xB0, 0x01, 0xE5, 0x01, 0xF0, 0x01, 0xEA, 0x01, 0xC1, 0x01, 0x60, 0x01, 0x39, 0x01, 0x20, 0x01, 0x20, 0x01, 0x38, 0x01, 0x44, 0x01, 0x4A, 0x01, 0x50, 0x01, 0x71, 0x01, 0xB1, 0x01, 0x0F, 0x02, 0x37, 0x02, 0x4E, 0x02, 0x80, 0x02, 0x71, 0x02, 0x66, 0x02, 0x65, 0x02, 0x47, 0x02, 0x45, 0x02, 0x43, 0x02, 0x2C, 0x02, 0x1B, 0x02, 0x19, 0x02, 0x09, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xED, 0x01, 0xE9, 0x01, 0xE9, 0x01, 0xD5, 0x01, 0xB9, 0x01, 0xCD, 0x01, 0xFB, 0x01, 0xFE, 0x01, 0xEB, 0x01, 0xDD, 0x01, 0xD2, 0x01, 0xD9, 0x01, 0xF2, 0x01, 0xF0, 0x01, 0xDA, 0x01, 0xE2, 0x01, 0xED, 0x01, 0xEC, 0x01, 0x06, 0x02, 0x2D, 0x02, 0x2A, 0x02, 0x1B, 0x02, 0x1A, 0x02, 0x21, 0x02, 0x50, 0x02, 0x58, 0x02, 0x44, 0x02, 0x47, 0x02, 0x3D, 0x02, 0x53, 0x02, 0x67, 0x02, 0x7E, 0x02, 0xA4, 0x02, 0x86, 0x02, 0x61, 0x02, 0x4C, 0x02, 0x40, 0x02, 0x45, 0x02, 0x40, 0x02, 0x2E, 0x02, 0xEE, 0x01, 0xDF, 0x01, 0x05, 0x02, 0x0F, 0x02, 0x40, 0x02, 0x78, 0x02, 0x9B, 0x02, 0xBE, 0x02, 0xBB, 0x02, 0xBA, 0x02, 0xC8, 0x02, 0xB5, 0x02, 0xA8, 0x02, 0xB4, 0x02, 0xC6, 0x02, 0xD5, 0x02, 0xD5, 0x02, 0xD3, 0x02, 0xB9, 0x02, 0x73, 0x02, 0x31, 0x02, 0x19, 0x02, 0x1A, 0x02, 0x24, 0x02, 0x44, 0x02, 0x4B, 0x02, 0x4D, 0x02, 0x6A, 0x02, 0x7E, 0x02, 0xA2, 0x02, 0xC9, 0x02, 0xE1, 0x02, 0x04, 0x03, 0x14, 0x03, 0x38, 0x03, 0x46, 0x03, 0x40, 0x03, 0x5E, 0x03, 0x5F, 0x03, 0x64, 0x03, 0x6B, 0x03, 0x5F, 0x03, 0x52, 0x03, 0x3C, 0x03, 0x2D, 0x03, 0x18, 0x03, 0x24, 0x03, 0x4A, 0x03, 0x82, 0x03, 0xAD, 0x03, 0xB0, 0x03, 0xD3, 0x03, 0xD1, 0x03, 0xE3, 0x03, 0x14, 0x04, 0xEC, 0x03, 0xD7, 0x03, 0x99, 0x03, 0x33, 0x03, 0xEF, 0x02, 0x7F, 0x02, 0x3C, 0x02, 0x1B, 0x02, 0xFB, 0x01, 0xF6, 0x01, 0x02, 0x02, 0x26, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x58, 0x02, 0x3D, 0x02, 0x31, 0x02, 0x1E, 0x02, 0xFB, 0x01, 0xD5, 0x01, 0x9E, 0x01, 0x5C, 0x01, 0x23, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x16, 0x01, 0x1C, 0x01, 0x1C, 0x01, 0x16, 0x01, 0x14, 0x01, 0x19, 0x01, 0x32, 0x01, 0x6D, 0x01, 0x9A, 0x01, 0xBE, 0x01, 0xD8, 0x01, 0xDF, 0x01, 0xDA, 0x01, 0xDE, 0x01, 0xF9, 0x01, 0xEF, 0x01, 0xCB, 0x01, 0x9D, 0x01, 0x63, 0x01, 0x54, 0x01, 0x4E, 0x01, 0x45, 0x01, 0x3E, 0x01, 0x2E, 0x01, 0x2A, 0x01, 0x2D, 0x01, 0x34, 0x01, 0x46, 0x01, 0x6B, 0x01, 0x81, 0x01, 0x91, 0x01, 0xA8, 0x01, 0xA1, 0x01, 0xAB, 0x01, 0xA0, 0x01, 0x7F, 0x01, 0x6A, 0x01, 0x38, 0x01, 0x3F, 0x01, 0x4F, 0x01, 0x31, 0x01, 0x36, 0x01, 0x37, 0x01, 0x40, 0x01, 0x5F, 0x01, 0x83, 0x01, 0xCF, 0x01, 0x15, 0x02, 0x3B, 0x02, 0x3B, 0x02, 0x1C, 0x02, 0x12, 0x02, 0x12, 0x02, 0x0A, 0x02, 0x09, 0x02, 0xF5, 0x01, 0xCF, 0x01, 0xB4, 0x01, 0xB1, 0x01, 0xB1, 0x01, 0xBB, 0x01, 0xDA, 0x01, 0x06, 0x02, 0x48, 0x02, 0x8B, 0x02, 0xB9, 0x02, 0xDB, 0x02, 0xE9, 0x02, 0xDF, 0x02, 0xD3, 0x02, 0xDF, 0x02, 0xF6, 0x02, 0x12, 0x03, 0x42, 0x03, 0x5D, 0x03, 0x5D, 0x03, 0x42, 0x03, 0x26, 0x03, 0x28, 0x03, 0x2E, 0x03, 0x3B, 0x03, 0x48, 0x03, 0x2B, 0x03, 0xF9, 0x02, 0xDD, 0x02, 0xC2, 0x02, 0xA6, 0x02, 0xA1, 0x02, 0x9F, 0x02, 0x99, 0x02, 0x77, 0x02, 0x4C, 0x02, 0x43, 0x02, 0x3F, 0x02, 0x52, 0x02, 0x65, 0x02, 0x47, 0x02, 0x1F, 0x02, 0xED, 0x01, 0xAC, 0x01, 0x87, 0x01, 0x86, 0x01, 0x9F, 0x01, 0xB9, 0x01, 0xD9, 0x01, 0xF4, 0x01, 0xEF, 0x01, 0xE7, 0x01, 0xCB, 0x01, 0x9F, 0x01, 0x83, 0x01, 0x58, 0x01, 0x2F, 0x01, 0x16, 0x01, 0x07, 0x01, 0x08, 0x01, 0x01, 0x01, 0xEF, 0x00, 0xC9, 0x00, 0xB3, 0x00, 0xB6, 0x00, 0xAD, 0x00, 0xA5, 0x00, 0x76, 0x00, 0x33, 0x00, 0xFD, 0xFF, 0xD4, 0xFF, 0xB8, 0xFF, 0x8D, 0xFF, 0x7B, 0xFF, 0x89, 0xFF, 0xA6, 0xFF, 0xDA, 0xFF, 0x1C, 0x00, 0x73, 0x00, 0xB7, 0x00, 0xE9, 0x00, 0xFB, 0x00, 0xDE, 0x00, 0xB1, 0x00, 0x84, 0x00, 0x5D, 0x00, 0x22, 0x00, 0xDD, 0xFF, 0x9B, 0xFF, 0x63, 0xFF, 0x58, 0xFF, 0x5F, 0xFF, 0x89, 0xFF, 0xD7, 0xFF, 0x0F, 0x00, 0x43, 0x00, 0x7A, 0x00, 0x92, 0x00, 0x93, 0x00, 0x9D, 0x00, 0x96, 0x00, 0x8E, 0x00, 0x75, 0x00, 0x44, 0x00, 0x20, 0x00, 0xEC, 0xFF, 0xC9, 0xFF, 0xBE, 0xFF, 0xB8, 0xFF, 0xB5, 0xFF, 0xB3, 0xFF, 0xC9, 0xFF, 0xBD, 0xFF, 0xCD, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x2B, 0x00, 0x49, 0x00, 0x54, 0x00, 0x66, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x47, 0x00, 0x18, 0x00, 0xF6, 0xFF, 0xDC, 0xFF, 0xCD, 0xFF, 0xAA, 0xFF, 0xA4, 0xFF, 0xAE, 0xFF, 0xCF, 0xFF, 0xED, 0xFF, 0xF1, 0xFF, 0xEC, 0xFF, 0xDD, 0xFF, 0x02, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x47, 0x00, 0x77, 0x00, 0xC9, 0x00, 0xE4, 0x00, 0xDF, 0x00, 0xC1, 0x00, 0x6A, 0x00, 0x47, 0x00, 0x24, 0x00, 0xFD, 0xFF, 0xE5, 0xFF, 0xAC, 0xFF, 0x83, 0xFF, 0x72, 0xFF, 0x82, 0xFF, 0xAD, 0xFF, 0xD5, 0xFF, 0xF8, 0xFF, 0x14, 0x00, 0x2A, 0x00, 0x1A, 0x00, 0xFE, 0xFF, 0xE0, 0xFF, 0xB1, 0xFF, 0x8C, 0xFF, 0x51, 0xFF, 0x19, 0xFF, 0xEF, 0xFE, 0xC3, 0xFE, 0xCD, 0xFE, 0xF7, 0xFE, 0x21, 0xFF, 0x3A, 0xFF, 0x5A, 0xFF, 0x93, 0xFF, 0xB1, 0xFF, 0xC4, 0xFF, 0xD3, 0xFF, 0xE6, 0xFF, 0x12, 0x00, 0x29, 0x00, 0x29, 0x00, 0x20, 0x00, 0x38, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x71, 0x00, 0x4D, 0x00, 0xFB, 0xFF, 0xC2, 0xFF, 0x8E, 0xFF, 0x79, 0xFF, 0x8A, 0xFF, 0xAF, 0xFF, 0xDE, 0xFF, 0xEE, 0xFF, 0xFC, 0xFF, 0x37, 0x00, 0x83, 0x00, 0xE3, 0x00, 0x4C, 0x01, 0x7F, 0x01, 0x7A, 0x01, 0x6E, 0x01, 0x65, 0x01, 0x59, 0x01, 0x4C, 0x01, 0x2F, 0x01, 0xF7, 0x00, 0xB9, 0x00, 0x80, 0x00, 0x6C, 0x00, 0x76, 0x00, 0x83, 0x00, 0xAC, 0x00, 0xE3, 0x00, 0x0C, 0x01, 0x38, 0x01, 0x59, 0x01, 0x58, 0x01, 0x25, 0x01, 0xC9, 0x00, 0x63, 0x00, 0x12, 0x00, 0xDA, 0xFF, 0xD1, 0xFF, 0xCE, 0xFF, 0xB1, 0xFF, 0xAB, 0xFF, 0xB6, 0xFF, 0xC7, 0xFF, 0xE3, 0xFF, 0xFB, 0xFF, 0x1C, 0x00, 0x26, 0x00, 0x22, 0x00, 0x24, 0x00, 0x1A, 0x00, 0xF5, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xC6, 0xFF, 0xA4, 0xFF, 0x95, 0xFF, 0x8A, 0xFF, 0x97, 0xFF, 0xBA, 0xFF, 0xBE, 0xFF, 0xC1, 0xFF, 0xCC, 0xFF, 0xC8, 0xFF, 0xC6, 0xFF, 0xA7, 0xFF, 0x7E, 0xFF, 0x71, 0xFF, 0x54, 0xFF, 0x6B, 0xFF, 0x99, 0xFF, 0xA7, 0xFF, 0xC4, 0xFF, 0xD1, 0xFF, 0xE2, 0xFF, 0xEB, 0xFF, 0xD6, 0xFF, 0xB8, 0xFF, 0xA5, 0xFF, 0xA1, 0xFF, 0x83, 0xFF, 0x74, 0xFF, 0x4B, 0xFF, 0x2B, 0xFF, 0x3C, 0xFF, 0x1A, 0xFF, 0x17, 0xFF, 0x1B, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0xE3, 0xFE, 0xED, 0xFE, 0x08, 0xFF, 0x17, 0xFF, 0x3B, 0xFF, 0x40, 0xFF, 0x4D, 0xFF, 0x6B, 0xFF, 0x8B, 0xFF, 0x96, 0xFF, 0xA9, 0xFF, 0xDC, 0xFF, 0xF4, 0xFF, 0x03, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x0F, 0x00, 0xEC, 0xFF, 0xC3, 0xFF, 0x96, 0xFF, 0x75, 0xFF, 0x76, 0xFF, 0x88, 0xFF, 0xAF, 0xFF, 0xCE, 0xFF, 0xEA, 0xFF, 0x14, 0x00, 0x32, 0x00, 0x45, 0x00, 0x68, 0x00, 0x83, 0x00, 0x95, 0x00, 0x92, 0x00, 0x75, 0x00, 0x70, 0x00, 0x60, 0x00, 0x33, 0x00, 0x1E, 0x00, 0x15, 0x00, 0x1E, 0x00, 0x40, 0x00, 0x4F, 0x00, 0x5C, 0x00, 0x77, 0x00, 0x9F, 0x00, 0xD9, 0x00, 0x20, 0x01, 0x6D, 0x01, 0x9F, 0x01, 0x9F, 0x01, 0x89, 0x01, 0x30, 0x01, 0xB2, 0x00, 0x5A, 0x00, 0x0F, 0x00, 0xDF, 0xFF, 0xC9, 0xFF, 0xCA, 0xFF, 0xE2, 0xFF, 0x01, 0x00, 0x1E, 0x00, 0x1D, 0x00, 0x12, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x33, 0x00, 0x42, 0x00, 0x3F, 0x00, 0x4B, 0x00, 0x55, 0x00, 0x4E, 0x00, 0x3C, 0x00, 0x19, 0x00, 0xEF, 0xFF, 0xC8, 0xFF, 0x7B, 0xFF, 0x29, 0xFF, 0x07, 0xFF, 0xFA, 0xFE, 0x12, 0xFF, 0x28, 0xFF, 0x1D, 0xFF, 0x27, 0xFF, 0x48, 0xFF, 0x6E, 0xFF, 0x9F, 0xFF, 0xAA, 0xFF, 0x77, 0xFF, 0x59, 0xFF, 0x29, 0xFF, 0xF1, 0xFE, 0xFB, 0xFE, 0xEA, 0xFE, 0xD8, 0xFE, 0xCF, 0xFE, 0xA2, 0xFE, 0x92, 0xFE, 0x8F, 0xFE, 0xAF, 0xFE, 0x01, 0xFF, 0x5B, 0xFF, 0xA9, 0xFF, 0xEB, 0xFF, 0x38, 0x00, 0x80, 0x00, 0xA0, 0x00, 0xA3, 0x00, 0x9B, 0x00, 0x7D, 0x00, 0x50, 0x00, 0x21, 0x00, 0xE9, 0xFF, 0xC6, 0xFF, 0xBF, 0xFF, 0xCA, 0xFF, 0xE3, 0xFF, 0xF2, 0xFF, 0x09, 0x00, 0x11, 0x00, 0x1D, 0x00, 0x21, 0x00, 0xED, 0xFF, 0xC9, 0xFF, 0x94, 0xFF, 0x65, 0xFF, 0x87, 0xFF, 0x9C, 0xFF, 0xB0, 0xFF, 0xEF, 0xFF, 0x13, 0x00, 0x3C, 0x00, 0x57, 0x00, 0x67, 0x00, 0x7E, 0x00, 0x75, 0x00, 0x62, 0x00, 0x3F, 0x00, 0xFD, 0xFF, 0xA9, 0xFF, 0x5C, 0xFF, 0x1C, 0xFF, 0xDF, 0xFE, 0xE2, 0xFE, 0x0A, 0xFF, 0x33, 0xFF, 0x80, 0xFF, 0xBF, 0xFF, 0xFA, 0xFF, 0x0D, 0x00, 0xF9, 0xFF, 0xF2, 0xFF, 0xC5, 0xFF, 0x95, 0xFF, 0x66, 0xFF, 0x1D, 0xFF, 0xED, 0xFE, 0xC2, 0xFE, 0x9A, 0xFE, 0x7A, 0xFE, 0x73, 0xFE, 0x99, 0xFE, 0xD2, 0xFE, 0x12, 0xFF, 0x58, 0xFF, 0x80, 0xFF, 0x70, 0xFF, 0x4D, 0xFF, 0x1C, 0xFF, 0xDA, 0xFE, 0xA6, 0xFE, 0x72, 0xFE, 0x32, 0xFE, 0x12, 0xFE, 0x0B, 0xFE, 0x18, 0xFE, 0x45, 0xFE, 0x57, 0xFE, 0x67, 0xFE, 0x6B, 0xFE, 0x3A, 0xFE, 0x2E, 0xFE, 0x1D, 0xFE, 0x04, 0xFE, 0x1C, 0xFE, 0x37, 0xFE, 0x60, 0xFE, 0x8F, 0xFE, 0xCE, 0xFE, 0x13, 0xFF, 0x46, 0xFF, 0x4C, 0xFF, 0x29, 0xFF, 0x31, 0xFF, 0x2F, 0xFF, 0x39, 0xFF, 0x5B, 0xFF, 0x46, 0xFF, 0x3F, 0xFF, 0x3C, 0xFF, 0x33, 0xFF, 0x37, 0xFF, 0x30, 0xFF, 0x43, 0xFF, 0x5D, 0xFF, 0x62, 0xFF, 0x62, 0xFF, 0x57, 0xFF, 0x54, 0xFF, 0x66, 0xFF, 0x83, 0xFF, 0x80, 0xFF, 0x6E, 0xFF, 0x50, 0xFF, 0x43, 0xFF, 0x5F, 0xFF, 0x5F, 0xFF, 0x5B, 0xFF, 0x5A, 0xFF, 0x40, 0xFF, 0x34, 0xFF, 0x3B, 0xFF, 0x39, 0xFF, 0x1E, 0xFF, 0x07, 0xFF, 0x01, 0xFF, 0xFD, 0xFE, 0xFB, 0xFE, 0xF1, 0xFE, 0xF4, 0xFE, 0xF9, 0xFE, 0xFC, 0xFE, 0x0B, 0xFF, 0x1E, 0xFF, 0x4B, 0xFF, 0x80, 0xFF, 0xAE, 0xFF, 0xD8, 0xFF, 0xE8, 0xFF, 0xD0, 0xFF, 0x93, 0xFF, 0x54, 0xFF, 0x12, 0xFF, 0xB2, 0xFE, 0x73, 0xFE, 0x57, 0xFE, 0x42, 0xFE, 0x62, 0xFE, 0x9B, 0xFE, 0xE5, 0xFE, 0x3F, 0xFF, 0x63, 0xFF, 0x63, 0xFF, 0x66, 0xFF, 0x60, 0xFF, 0x6C, 0xFF, 0x66, 0xFF, 0x41, 0xFF, 0x32, 0xFF, 0x1A, 0xFF, 0x04, 0xFF, 0xFE, 0xFE, 0xCB, 0xFE, 0x93, 0xFE, 0x55, 0xFE, 0x0D, 0xFE, 0xF5, 0xFD, 0xF8, 0xFD, 0x33, 0xFE, 0x9D, 0xFE, 0xEE, 0xFE, 0x33, 0xFF, 0x46, 0xFF, 0x12, 0xFF, 0xED, 0xFE, 0xCD, 0xFE, 0xB7, 0xFE, 0xCC, 0xFE, 0xC3, 0xFE, 0xAD, 0xFE, 0xA9, 0xFE, 0xAE, 0xFE, 0xD3, 0xFE, 0xE5, 0xFE, 0xCC, 0xFE, 0x92, 0xFE, 0x50, 0xFE, 0x3D, 0xFE, 0x37, 0xFE, 0x53, 0xFE, 0x94, 0xFE, 0xBA, 0xFE, 0xDC, 0xFE, 0xF5, 0xFE, 0xF6, 0xFE, 0xFF, 0xFE, 0x0A, 0xFF, 0xFC, 0xFE, 0xE3, 0xFE, 0xBE, 0xFE, 0x7C, 0xFE, 0x49, 0xFE, 0x23, 0xFE, 0x08, 0xFE, 0xF7, 0xFD, 0xD7, 0xFD, 0xE5, 0xFD, 0x1B, 0xFE, 0x57, 0xFE, 0xA8, 0xFE, 0xE0, 0xFE, 0xF2, 0xFE, 0x0A, 0xFF, 0x24, 0xFF, 0x25, 0xFF, 0x02, 0xFF, 0xC6, 0xFE, 0x8B, 0xFE, 0x54, 0xFE, 0x32, 0xFE, 0x3A, 0xFE, 0x48, 0xFE, 0x65, 0xFE, 0x6A, 0xFE, 0x6F, 0xFE, 0x9F, 0xFE, 0xD0, 0xFE, 0x0C, 0xFF, 0x3B, 0xFF, 0x5C, 0xFF, 0x6D, 0xFF, 0x64, 0xFF, 0x7E, 0xFF, 0x7B, 0xFF, 0x75, 0xFF, 0x80, 0xFF, 0x71, 0xFF, 0x61, 0xFF, 0x3F, 0xFF, 0x20, 0xFF, 0xFC, 0xFE, 0xF3, 0xFE, 0x24, 0xFF, 0x54, 0xFF, 0x85, 0xFF, 0xB7, 0xFF, 0xEB, 0xFF, 0x0B, 0x00, 0x32, 0x00, 0x61, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x4D, 0x00, 0x56, 0x00, 0x5C, 0x00, 0x60, 0x00, 0x5C, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3C, 0x00, 0x21, 0x00, 0xF6, 0xFF, 0xE2, 0xFF, 0xCF, 0xFF, 0xC8, 0xFF, 0xAF, 0xFF, 0x8A, 0xFF, 0x9B, 0xFF, 0xA7, 0xFF, 0xBA, 0xFF, 0xC8, 0xFF, 0xB3, 0xFF, 0xB8, 0xFF, 0xAB, 0xFF, 0x92, 0xFF, 0x8F, 0xFF, 0x78, 0xFF, 0x80, 0xFF, 0x99, 0xFF, 0x98, 0xFF, 0x98, 0xFF, 0x78, 0xFF, 0x63, 0xFF, 0x66, 0xFF, 0x50, 0xFF, 0x3C, 0xFF, 0x1A, 0xFF, 0xEC, 0xFE, 0xD1, 0xFE, 0xB3, 0xFE, 0x83, 0xFE, 0x5C, 0xFE, 0x58, 0xFE, 0x67, 0xFE, 0x7A, 0xFE, 0xA0, 0xFE, 0xC7, 0xFE, 0xD9, 0xFE, 0xE4, 0xFE, 0xEE, 0xFE, 0xD8, 0xFE, 0xB7, 0xFE, 0x80, 0xFE, 0x43, 0xFE, 0x0A, 0xFE, 0xC2, 0xFD, 0x8D, 0xFD, 0x67, 0xFD, 0x5B, 0xFD, 0x68, 0xFD, 0x99, 0xFD, 0xF0, 0xFD, 0x2A, 0xFE, 0x56, 0xFE, 0x60, 0xFE, 0x39, 0xFE, 0x24, 0xFE, 0x05, 0xFE, 0xD8, 0xFD, 0x99, 0xFD, 0x55, 0xFD, 0x26, 0xFD, 0x07, 0xFD, 0x01, 0xFD, 0xEF, 0xFC, 0x00, 0xFD, 0x25, 0xFD, 0x3C, 0xFD, 0x59, 0xFD, 0x5E, 0xFD, 0x87, 0xFD, 0xCC, 0xFD, 0x0F, 0xFE, 0x53, 0xFE, 0x62, 0xFE, 0x6F, 0xFE, 0x7F, 0xFE, 0x6C, 0xFE, 0x5E, 0xFE, 0x48, 0xFE, 0x21, 0xFE, 0x0B, 0xFE, 0xF2, 0xFD, 0xC8, 0xFD, 0xC8, 0xFD, 0xE2, 0xFD, 0x16, 0xFE, 0x66, 0xFE, 0x85, 0xFE, 0x7D, 0xFE, 0x74, 0xFE, 0x76, 0xFE, 0x8C, 0xFE, 0xA9, 0xFE, 0xAE, 0xFE, 0xA7, 0xFE, 0xA5, 0xFE, 0x98, 0xFE, 0xA9, 0xFE, 0xC1, 0xFE, 0xC5, 0xFE, 0xC7, 0xFE, 0xAE, 0xFE, 0x9C, 0xFE, 0x88, 0xFE, 0x79, 0xFE, 0x6F, 0xFE, 0x64, 0xFE, 0x80, 0xFE, 0x8F, 0xFE, 0xA7, 0xFE, 0xD0, 0xFE, 0xF8, 0xFE, 0x2D, 0xFF, 0x52, 0xFF, 0x70, 0xFF, 0x54, 0xFF, 0x2D, 0xFF, 0x19, 0xFF, 0xE7, 0xFE, 0xDD, 0xFE, 0xC7, 0xFE, 0x8D, 0xFE, 0x60, 0xFE, 0x5B, 0xFE, 0x6C, 0xFE, 0x61, 0xFE, 0x6E, 0xFE, 0x88, 0xFE, 0xAD, 0xFE, 0xDB, 0xFE, 0xED, 0xFE, 0x0D, 0xFF, 0x1A, 0xFF, 0x1E, 0xFF, 0x0E, 0xFF, 0xE0, 0xFE, 0xD1, 0xFE, 0xD8, 0xFE, 0xDD, 0xFE, 0xC0, 0xFE, 0x90, 0xFE, 0x64, 0xFE, 0x3E, 0xFE, 0x2B, 0xFE, 0x26, 0xFE, 0x32, 0xFE, 0x3C, 0xFE, 0x40, 0xFE, 0x48, 0xFE, 0x54, 0xFE, 0x7D, 0xFE, 0xAA, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xE6, 0xFE, 0xDD, 0xFE, 0xCC, 0xFE, 0xE6, 0xFE, 0xED, 0xFE, 0x00, 0xFF, 0x21, 0xFF, 0x03, 0xFF, 0xEB, 0xFE, 0xC5, 0xFE, 0xC1, 0xFE, 0xD5, 0xFE, 0xBE, 0xFE, 0xC1, 0xFE, 0xC1, 0xFE, 0xF0, 0xFE, 0x59, 0xFF, 0xB3, 0xFF, 0xFB, 0xFF, 0x08, 0x00, 0x0A, 0x00, 0x09, 0x00, 0xEF, 0xFF, 0xD2, 0xFF, 0xB7, 0xFF, 0x92, 0xFF, 0x69, 0xFF, 0x40, 0xFF, 0x0B, 0xFF, 0x0F, 0xFF, 0x3D, 0xFF, 0x69, 0xFF, 0xAE, 0xFF, 0xCE, 0xFF, 0xD8, 0xFF, 0xD7, 0xFF, 0xAE, 0xFF, 0x81, 0xFF, 0x50, 0xFF, 0x4A, 0xFF, 0x59, 0xFF, 0x57, 0xFF, 0x5E, 0xFF, 0x50, 0xFF, 0x3D, 0xFF, 0x2C, 0xFF, 0x28, 0xFF, 0x25, 0xFF, 0x06, 0xFF, 0xE4, 0xFE, 0xC3, 0xFE, 0xA9, 0xFE, 0x93, 0xFE, 0x81, 0xFE, 0x74, 0xFE, 0x69, 0xFE, 0x76, 0xFE, 0xA0, 0xFE, 0xD7, 0xFE, 0x0C, 0xFF, 0x41, 0xFF, 0x6A, 0xFF, 0x9F, 0xFF, 0xDC, 0xFF, 0xF8, 0xFF, 0x0B, 0x00, 0xEE, 0xFF, 0xA6, 0xFF, 0x61, 0xFF, 0x1B, 0xFF, 0xFD, 0xFE, 0xF1, 0xFE, 0xE3, 0xFE, 0xE2, 0xFE, 0xCC, 0xFE, 0xCC, 0xFE, 0xF0, 0xFE, 0x24, 0xFF, 0x7B, 0xFF, 0xD1, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0xED, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD9, 0xFF, 0xD8, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xC0, 0xFF, 0xA8, 0xFF, 0xAB, 0xFF, 0x95, 0xFF, 0x76, 0xFF, 0x57, 0xFF, 0x3F, 0xFF, 0x26, 0xFF, 0xFA, 0xFE, 0xFB, 0xFE, 0x07, 0xFF, 0x27, 0xFF, 0x66, 0xFF, 0x87, 0xFF, 0xA1, 0xFF, 0xA7, 0xFF, 0xAE, 0xFF, 0xD3, 0xFF, 0xE0, 0xFF, 0xD6, 0xFF, 0xB7, 0xFF, 0x8D, 0xFF, 0x5E, 0xFF, 0x27, 0xFF, 0xF8, 0xFE, 0xEA, 0xFE, 0xFE, 0xFE, 0x0A, 0xFF, 0x34, 0xFF, 0x74, 0xFF, 0xBA, 0xFF, 0x2D, 0x00, 0x77, 0x00, 0x94, 0x00, 0xAC, 0x00, 0x95, 0x00, 0x73, 0x00, 0x46, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x0A, 0x00, 0xF8, 0xFF, 0xF6, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0x0F, 0x00, 0x24, 0x00, 0x42, 0x00, 0x6A, 0x00, 0x91, 0x00, 0xC5, 0x00, 0xE8, 0x00, 0x07, 0x01, 0x3D, 0x01, 0x4E, 0x01, 0x4E, 0x01, 0x51, 0x01, 0x39, 0x01, 0x1F, 0x01, 0xF9, 0x00, 0xB9, 0x00, 0x87, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x70, 0x00, 0x7D, 0x00, 0x7A, 0x00, 0x77, 0x00, 0x83, 0x00, 0x8D, 0x00, 0x95, 0x00, 0x9A, 0x00, 0xAD, 0x00, 0xB2, 0x00, 0x8C, 0x00, 0x63, 0x00, 0x55, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x5D, 0x00, 0x3F, 0x00, 0x08, 0x00, 0xBB, 0xFF, 0x71, 0xFF, 0x57, 0xFF, 0x49, 0xFF, 0x4C, 0xFF, 0x72, 0xFF, 0x92, 0xFF, 0xC0, 0xFF, 0xEC, 0xFF, 0x18, 0x00, 0x49, 0x00, 0x5D, 0x00, 0x80, 0x00, 0x9B, 0x00, 0x95, 0x00, 0x94, 0x00, 0x80, 0x00, 0x63, 0x00, 0x4C, 0x00, 0x25, 0x00, 0xF4, 0xFF, 0xCD, 0xFF, 0xB4, 0xFF, 0xB4, 0xFF, 0xB7, 0xFF, 0xA8, 0xFF, 0xBB, 0xFF, 0xDB, 0xFF, 0xEE, 0xFF, 0x13, 0x00, 0x39, 0x00, 0x62, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x68, 0x00, 0x4E, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x40, 0x00, 0x42, 0x00, 0x47, 0x00, 0x45, 0x00, 0x2C, 0x00, 0x24, 0x00, 0x39, 0x00, 0x5F, 0x00, 0x6C, 0x00, 0x60, 0x00, 0x71, 0x00, 0x73, 0x00, 0x7F, 0x00, 0x9A, 0x00, 0xA4, 0x00, 0xE1, 0x00, 0xF2, 0x00, 0xCC, 0x00, 0xC0, 0x00, 0x94, 0x00, 0x79, 0x00, 0x6D, 0x00, 0x4E, 0x00, 0x57, 0x00, 0x4F, 0x00, 0x47, 0x00, 0x61, 0x00, 0x69, 0x00, 0x77, 0x00, 0x94, 0x00, 0xB6, 0x00, 0xF3, 0x00, 0x38, 0x01, 0x7B, 0x01, 0xA5, 0x01, 0xB8, 0x01, 0xCD, 0x01, 0xD1, 0x01, 0xC0, 0x01, 0xA5, 0x01, 0x7F, 0x01, 0x62, 0x01, 0x39, 0x01, 0x17, 0x01, 0x12, 0x01, 0x1C, 0x01, 0x4C, 0x01, 0x84, 0x01, 0xB2, 0x01, 0xD2, 0x01, 0xD0, 0x01, 0xBF, 0x01, 0xA9, 0x01, 0x97, 0x01, 0x94, 0x01, 0x87, 0x01, 0x76, 0x01, 0x73, 0x01, 0x78, 0x01, 0x97, 0x01, 0xE9, 0x01, 0x2B, 0x02, 0x5B, 0x02, 0x6F, 0x02, 0x35, 0x02, 0xF9, 0x01, 0xC6, 0x01, 0x8B, 0x01, 0x6E, 0x01, 0x60, 0x01, 0x67, 0x01, 0x76, 0x01, 0x77, 0x01, 0x86, 0x01, 0xA2, 0x01, 0xB8, 0x01, 0xE1, 0x01, 0x00, 0x02, 0xD8, 0x01, 0xA7, 0x01, 0x71, 0x01, 0x3B, 0x01, 0x2A, 0x01, 0xF9, 0x00, 0xBD, 0x00, 0x87, 0x00, 0x48, 0x00, 0x26, 0x00, 0x07, 0x00, 0xF2, 0xFF, 0xE3, 0xFF, 0xE8, 0xFF, 0x08, 0x00, 0x31, 0x00, 0x82, 0x00, 0xD6, 0x00, 0x17, 0x01, 0x4A, 0x01, 0x4B, 0x01, 0x2F, 0x01, 0x08, 0x01, 0xD6, 0x00, 0xAD, 0x00, 0x8B, 0x00, 0x6A, 0x00, 0x6F, 0x00, 0x78, 0x00, 0x6F, 0x00, 0x67, 0x00, 0x4B, 0x00, 0x55, 0x00, 0x6B, 0x00, 0x61, 0x00, 0x70, 0x00, 0x8F, 0x00, 0xCC, 0x00, 0x12, 0x01, 0x37, 0x01, 0x56, 0x01, 0x79, 0x01, 0x94, 0x01, 0xA6, 0x01, 0xB6, 0x01, 0xAF, 0x01, 0x9C, 0x01, 0x84, 0x01, 0x56, 0x01, 0x14, 0x01, 0xEC, 0x00, 0xE5, 0x00, 0xDA, 0x00, 0xED, 0x00, 0x0B, 0x01, 0x1E, 0x01, 0x5D, 0x01, 0x87, 0x01, 0xA8, 0x01, 0xC6, 0x01, 0xCD, 0x01, 0xF0, 0x01, 0xF9, 0x01, 0xF0, 0x01, 0xE6, 0x01, 0xB8, 0x01, 0x7C, 0x01, 0x42, 0x01, 0x11, 0x01, 0xEA, 0x00, 0xE0, 0x00, 0xE5, 0x00, 0xF5, 0x00, 0x2E, 0x01, 0x71, 0x01, 0xB8, 0x01, 0xFD, 0x01, 0x35, 0x02, 0x6C, 0x02, 0x99, 0x02, 0xBE, 0x02, 0xB4, 0x02, 0x86, 0x02, 0x5F, 0x02, 0x41, 0x02, 0x23, 0x02, 0xF8, 0x01, 0xD4, 0x01, 0xA6, 0x01, 0x82, 0x01, 0x81, 0x01, 0x7B, 0x01, 0x81, 0x01, 0x87, 0x01, 0x92, 0x01, 0xAC, 0x01, 0xC7, 0x01, 0x05, 0x02, 0x5A, 0x02, 0x9A, 0x02, 0xC0, 0x02, 0xCC, 0x02, 0xA5, 0x02, 0x65, 0x02, 0x27, 0x02, 0xD3, 0x01, 0x8D, 0x01, 0x5C, 0x01, 0x2E, 0x01, 0x23, 0x01, 0x00, 0x01, 0xD9, 0x00, 0xE4, 0x00, 0xF8, 0x00, 0x09, 0x01, 0x1C, 0x01, 0x23, 0x01, 0x25, 0x01, 0x46, 0x01, 0x50, 0x01, 0x42, 0x01, 0x51, 0x01, 0x37, 0x01, 0x20, 0x01, 0x07, 0x01, 0xC6, 0x00, 0x99, 0x00, 0x66, 0x00, 0x50, 0x00, 0x5A, 0x00, 0x67, 0x00, 0x98, 0x00, 0xBD, 0x00, 0xD0, 0x00, 0xED, 0x00, 0x08, 0x01, 0x11, 0x01, 0x12, 0x01, 0x15, 0x01, 0xFF, 0x00, 0x02, 0x01, 0x14, 0x01, 0x04, 0x01, 0xEB, 0x00, 0xD5, 0x00, 0xD3, 0x00, 0xE5, 0x00, 0xEF, 0x00, 0xEA, 0x00, 0xD2, 0x00, 0xBD, 0x00, 0xA6, 0x00, 0x95, 0x00, 0x83, 0x00, 0x75, 0x00, 0x87, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xCD, 0x00, 0x01, 0x01, 0x4F, 0x01, 0x90, 0x01, 0xAA, 0x01, 0xA6, 0x01, 0x93, 0x01, 0x68, 0x01, 0x38, 0x01, 0x0A, 0x01, 0xD9, 0x00, 0xB3, 0x00, 0x74, 0x00, 0x48, 0x00, 0x61, 0x00, 0xA2, 0x00, 0xEB, 0x00, 0x21, 0x01, 0x4E, 0x01, 0x6F, 0x01, 0x74, 0x01, 0x64, 0x01, 0x29, 0x01, 0xF6, 0x00, 0xE9, 0x00, 0xE5, 0x00, 0xD8, 0x00, 0xBC, 0x00, 0xA9, 0x00, 0x9D, 0x00, 0x84, 0x00, 0x85, 0x00, 0x83, 0x00, 0x7D, 0x00, 0x7C, 0x00, 0x81, 0x00, 0x8F, 0x00, 0x8D, 0x00, 0x99, 0x00, 0xA8, 0x00, 0xB3, 0x00, 0xCD, 0x00, 0xD6, 0x00, 0xDE, 0x00, 0xEE, 0x00, 0xFC, 0x00, 0x06, 0x01, 0x00, 0x01, 0xFD, 0x00, 0xEC, 0x00, 0xE5, 0x00, 0xD9, 0x00, 0xD0, 0x00, 0xE2, 0x00, 0xF1, 0x00, 0x05, 0x01, 0xEF, 0x00, 0xDA, 0x00, 0xC0, 0x00, 0x94, 0x00, 0xAB, 0x00, 0xC4, 0x00, 0x07, 0x01, 0x67, 0x01, 0x92, 0x01, 0xC0, 0x01, 0xB8, 0x01, 0xA6, 0x01, 0x8E, 0x01, 0x3C, 0x01, 0x02, 0x01, 0xD7, 0x00, 0xB8, 0x00, 0x99, 0x00, 0x8B, 0x00, 0x9A, 0x00, 0xAD, 0x00, 0xE8, 0x00, 0x33, 0x01, 0x55, 0x01, 0x56, 0x01, 0x59, 0x01, 0x58, 0x01, 0x4B, 0x01, 0x3B, 0x01, 0x14, 0x01, 0x01, 0x01, 0xF7, 0x00, 0xDD, 0x00, 0xD4, 0x00, 0xC7, 0x00, 0xC2, 0x00, 0xD9, 0x00, 0xFB, 0x00, 0x14, 0x01, 0x26, 0x01, 0x24, 0x01, 0x1C, 0x01, 0x21, 0x01, 0x10, 0x01, 0x0B, 0x01, 0x11, 0x01, 0x06, 0x01, 0x07, 0x01, 0xEF, 0x00, 0xE5, 0x00, 0x11, 0x01, 0x2F, 0x01, 0x50, 0x01, 0x5D, 0x01, 0x4D, 0x01, 0x4E, 0x01, 0x2A, 0x01, 0xFF, 0x00, 0xF8, 0x00, 0xCA, 0x00, 0xA3, 0x00, 0x91, 0x00, 0x54, 0x00, 0x48, 0x00, 0x6D, 0x00, 0x9F, 0x00, 0x03, 0x01, 0x4D, 0x01, 0x6F, 0x01, 0x7C, 0x01, 0x62, 0x01, 0x47, 0x01, 0x3E, 0x01, 0x2C, 0x01, 0x09, 0x01, 0xD5, 0x00, 0xA6, 0x00, 0x8E, 0x00, 0x91, 0x00, 0xA1, 0x00, 0xB9, 0x00, 0xE0, 0x00, 0xFC, 0x00, 0x16, 0x01, 0x33, 0x01, 0x45, 0x01, 0x5D, 0x01, 0x5B, 0x01, 0x32, 0x01, 0x08, 0x01, 0xD4, 0x00, 0xA0, 0x00, 0x7B, 0x00, 0x5C, 0x00, 0x2C, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0xD4, 0xFF, 0xBB, 0xFF, 0xBD, 0xFF, 0xB1, 0xFF, 0xC4, 0xFF, 0xCD, 0xFF, 0xBD, 0xFF, 0xBB, 0xFF, 0xB7, 0xFF, 0xB7, 0xFF, 0xA7, 0xFF, 0xA4, 0xFF, 0xB4, 0xFF, 0xCF, 0xFF, 0xEB, 0xFF, 0xDC, 0xFF, 0xBA, 0xFF, 0x9D, 0xFF, 0x71, 0xFF, 0x4D, 0xFF, 0x33, 0xFF, 0x0C, 0xFF, 0xE7, 0xFE, 0xCE, 0xFE, 0xDE, 0xFE, 0x2C, 0xFF, 0x8D, 0xFF, 0xDD, 0xFF, 0x26, 0x00, 0x51, 0x00, 0x61, 0x00, 0x7C, 0x00, 0x8C, 0x00, 0xA2, 0x00, 0xBE, 0x00, 0xA6, 0x00, 0x8F, 0x00, 0x67, 0x00, 0x3D, 0x00, 0x4F, 0x00, 0x42, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6A, 0x00, 0x95, 0x00, 0xA1, 0x00, 0xAD, 0x00, 0xD4, 0x00, 0xF0, 0x00, 0x13, 0x01, 0x27, 0x01, 0x4D, 0x01, 0x78, 0x01, 0xA0, 0x01, 0xBB, 0x01, 0xAA, 0x01, 0x9D, 0x01, 0x8C, 0x01, 0x6B, 0x01, 0x4A, 0x01, 0x40, 0x01, 0x3F, 0x01, 0x30, 0x01, 0x36, 0x01, 0x3A, 0x01, 0x3B, 0x01, 0x47, 0x01, 0x58, 0x01, 0x68, 0x01, 0x5A, 0x01, 0x53, 0x01, 0x55, 0x01, 0x55, 0x01, 0x57, 0x01, 0x61, 0x01, 0x5E, 0x01, 0x4F, 0x01, 0x38, 0x01, 0xFE, 0x00, 0xE1, 0x00, 0xC8, 0x00, 0x9E, 0x00, 0x98, 0x00, 0x71, 0x00, 0x64, 0x00, 0x6B, 0x00, 0x5C, 0x00, 0x77, 0x00, 0x83, 0x00, 0x7B, 0x00, 0x79, 0x00, 0x5A, 0x00, 0x36, 0x00, 0x21, 0x00, 0x0F, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0xEF, 0xFF, 0xE3, 0xFF, 0xD3, 0xFF, 0xC3, 0xFF, 0xAB, 0xFF, 0x86, 0xFF, 0x6B, 0xFF, 0x4A, 0xFF, 0x34, 0xFF, 0x1B, 0xFF, 0x00, 0xFF, 0xFF, 0xFE, 0x05, 0xFF, 0x22, 0xFF, 0x30, 0xFF, 0x43, 0xFF, 0x74, 0xFF, 0x7F, 0xFF, 0x7C, 0xFF, 0x6A, 0xFF, 0x57, 0xFF, 0x52, 0xFF, 0x59, 0xFF, 0x67, 0xFF, 0x6D, 0xFF, 0x6C, 0xFF, 0x4D, 0xFF, 0x2F, 0xFF, 0x1C, 0xFF, 0x08, 0xFF, 0xF7, 0xFE, 0xEB, 0xFE, 0xF4, 0xFE, 0xFF, 0xFE, 0x35, 0xFF, 0x7F, 0xFF, 0xB0, 0xFF, 0xDE, 0xFF, 0xEF, 0xFF, 0xF9, 0xFF, 0xD5, 0xFF, 0x88, 0xFF, 0x52, 0xFF, 0x14, 0xFF, 0xEC, 0xFE, 0xD9, 0xFE, 0xCB, 0xFE, 0xE2, 0xFE, 0x0A, 0xFF, 0x40, 0xFF, 0x85, 0xFF, 0xC8, 0xFF, 0xFD, 0xFF, 0x23, 0x00, 0x1D, 0x00, 0x07, 0x00, 0xF0, 0xFF, 0xE2, 0xFF, 0xF8, 0xFF, 0xFE, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0xF6, 0xFF, 0xE1, 0xFF, 0xC2, 0xFF, 0xAE, 0xFF, 0x8E, 0xFF, 0x6F, 0xFF, 0x52, 0xFF, 0x2B, 0xFF, 0x1C, 0xFF, 0x11, 0xFF, 0x22, 0xFF, 0x42, 0xFF, 0x5F, 0xFF, 0x7C, 0xFF, 0x8A, 0xFF, 0xA6, 0xFF, 0xCB, 0xFF, 0xEC, 0xFF, 0xFA, 0xFF, 0xEE, 0xFF, 0xE5, 0xFF, 0xD5, 0xFF, 0xB8, 0xFF, 0x7A, 0xFF, 0x4D, 0xFF, 0x1F, 0xFF, 0xE1, 0xFE, 0xD1, 0xFE, 0xCA, 0xFE, 0xD7, 0xFE, 0x01, 0xFF, 0x32, 0xFF, 0x80, 0xFF, 0xC2, 0xFF, 0xEF, 0xFF, 0x15, 0x00, 0x23, 0x00, 0x1F, 0x00, 0x02, 0x00, 0xBF, 0xFF, 0x63, 0xFF, 0x09, 0xFF, 0xB1, 0xFE, 0x85, 0xFE, 0x6A, 0xFE, 0x58, 0xFE, 0x71, 0xFE, 0x98, 0xFE, 0xC6, 0xFE, 0x0F, 0xFF, 0x56, 0xFF, 0x91, 0xFF, 0xC8, 0xFF, 0xC4, 0xFF, 0x95, 0xFF, 0x80, 0xFF, 0x4B, 0xFF, 0x25, 0xFF, 0x08, 0xFF, 0xC5, 0xFE, 0xB3, 0xFE, 0xA9, 0xFE, 0x9D, 0xFE, 0xA9, 0xFE, 0xB9, 0xFE, 0xE6, 0xFE, 0xF9, 0xFE, 0xFA, 0xFE, 0x0B, 0xFF, 0x13, 0xFF, 0x25, 0xFF, 0x3D, 0xFF, 0x57, 0xFF, 0x5E, 0xFF, 0x47, 0xFF, 0x2C, 0xFF, 0x1A, 0xFF, 0x16, 0xFF, 0x14, 0xFF, 0x1E, 0xFF, 0x17, 0xFF, 0xEF, 0xFE, 0xDE, 0xFE, 0xE2, 0xFE, 0xF3, 0xFE, 0x09, 0xFF, 0x0A, 0xFF, 0xFA, 0xFE, 0xF0, 0xFE, 0x02, 0xFF, 0x15, 0xFF, 0x21, 0xFF, 0x28, 0xFF, 0x18, 0xFF, 0x0B, 0xFF, 0xEF, 0xFE, 0xD5, 0xFE, 0xE8, 0xFE, 0xFF, 0xFE, 0xFA, 0xFE, 0xD3, 0xFE, 0xBD, 0xFE, 0xC3, 0xFE, 0xE1, 0xFE, 0x20, 0xFF, 0x50, 0xFF, 0x74, 0xFF, 0xA2, 0xFF, 0xBD, 0xFF, 0xC7, 0xFF, 0xCC, 0xFF, 0xD1, 0xFF, 0xD3, 0xFF, 0xBD, 0xFF, 0x99, 0xFF, 0x83, 0xFF, 0x7E, 0xFF, 0x7F, 0xFF, 0x8E, 0xFF, 0x97, 0xFF, 0x92, 0xFF, 0x8E, 0xFF, 0x87, 0xFF, 0x8B, 0xFF, 0x93, 0xFF, 0x91, 0xFF, 0x8F, 0xFF, 0x8C, 0xFF, 0x78, 0xFF, 0x6A, 0xFF, 0x6B, 0xFF, 0x66, 0xFF, 0x5E, 0xFF, 0x4D, 0xFF, 0x40, 0xFF, 0x43, 0xFF, 0x4C, 0xFF, 0x5D, 0xFF, 0x6B, 0xFF, 0x80, 0xFF, 0x74, 0xFF, 0x60, 0xFF, 0x59, 0xFF, 0x46, 0xFF, 0x46, 0xFF, 0x17, 0xFF, 0xEA, 0xFE, 0xD2, 0xFE, 0x9B, 0xFE, 0x9E, 0xFE, 0xBE, 0xFE, 0xE6, 0xFE, 0x28, 0xFF, 0x4D, 0xFF, 0x60, 0xFF, 0x5A, 0xFF, 0x48, 0xFF, 0x3C, 0xFF, 0x2B, 0xFF, 0x13, 0xFF, 0xFF, 0xFE, 0xEE, 0xFE, 0xC8, 0xFE, 0xC2, 0xFE, 0xE1, 0xFE, 0x0F, 0xFF, 0x3C, 0xFF, 0x3D, 0xFF, 0x3B, 0xFF, 0x3C, 0xFF, 0x3D, 0xFF, 0x44, 0xFF, 0x2F, 0xFF, 0x1A, 0xFF, 0x07, 0xFF, 0x04, 0xFF, 0x24, 0xFF, 0x4D, 0xFF, 0x87, 0xFF, 0xBD, 0xFF, 0xCF, 0xFF, 0xE9, 0xFF, 0xF0, 0xFF, 0xDA, 0xFF, 0xCD, 0xFF, 0xB7, 0xFF, 0xA0, 0xFF, 0x81, 0xFF, 0x56, 0xFF, 0x43, 0xFF, 0x3B, 0xFF, 0x37, 0xFF, 0x2E, 0xFF, 0x32, 0xFF, 0x41, 0xFF, 0x56, 0xFF, 0x83, 0xFF, 0xAE, 0xFF, 0xE6, 0xFF, 0x18, 0x00, 0x35, 0x00, 0x4F, 0x00, 0x60, 0x00, 0x63, 0x00, 0x56, 0x00, 0x46, 0x00, 0x25, 0x00, 0xF4, 0xFF, 0xDE, 0xFF, 0xBA, 0xFF, 0x95, 0xFF, 0x91, 0xFF, 0xAD, 0xFF, 0xEA, 0xFF, 0x23, 0x00, 0x54, 0x00, 0x79, 0x00, 0x8A, 0x00, 0x89, 0x00, 0x6E, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0B, 0x00, 0xE5, 0xFF, 0xDF, 0xFF, 0xDC, 0xFF, 0xD6, 0xFF, 0xE8, 0xFF, 0xDA, 0xFF, 0xD2, 0xFF, 0xB9, 0xFF, 0x91, 0xFF, 0xA0, 0xFF, 0xC1, 0xFF, 0xEB, 0xFF, 0x14, 0x00, 0x21, 0x00, 0x36, 0x00, 0x5E, 0x00, 0x75, 0x00, 0x79, 0x00, 0x8C, 0x00, 0x90, 0x00, 0x7D, 0x00, 0x56, 0x00, 0x10, 0x00, 0xE2, 0xFF, 0xC4, 0xFF, 0xBB, 0xFF, 0xC9, 0xFF, 0xD3, 0xFF, 0xEF, 0xFF, 0x11, 0x00, 0x37, 0x00, 0x5C, 0x00, 0x73, 0x00, 0x8D, 0x00, 0xA7, 0x00, 0xA4, 0x00, 0x90, 0x00, 0x84, 0x00, 0x73, 0x00, 0x70, 0x00, 0x6E, 0x00, 0x5A, 0x00, 0x4B, 0x00, 0x41, 0x00, 0x4E, 0x00, 0x71, 0x00, 0x90, 0x00, 0xBD, 0x00, 0xDA, 0x00, 0xD3, 0x00, 0xCE, 0x00, 0xBF, 0x00, 0x93, 0x00, 0x64, 0x00, 0x47, 0x00, 0x1C, 0x00, 0xF7, 0xFF, 0xF2, 0xFF, 0xE9, 0xFF, 0xFB, 0xFF, 0x0D, 0x00, 0x01, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x1B, 0x00, 0x3F, 0x00, 0x49, 0x00, 0x3F, 0x00, 0x29, 0x00, 0x1D, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x11, 0x00, 0x04, 0x00, 0xFE, 0xFF, 0xE9, 0xFF, 0xE6, 0xFF, 0xF7, 0xFF, 0x0D, 0x00, 0x3F, 0x00, 0x56, 0x00, 0x77, 0x00, 0x8C, 0x00, 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x6B, 0x00, 0x68, 0x00, 0x62, 0x00, 0x39, 0x00, 0x17, 0x00, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x1F, 0x00, 0x2C, 0x00, 0x5D, 0x00, 0x71, 0x00, 0x83, 0x00, 0x94, 0x00, 0x7E, 0x00, 0x77, 0x00, 0x63, 0x00, 0x56, 0x00, 0x71, 0x00, 0x89, 0x00, 0x99, 0x00, 0x99, 0x00, 0x8C, 0x00, 0x5C, 0x00, 0x33, 0x00, 0x24, 0x00, 0xFD, 0xFF, 0xDA, 0xFF, 0xBD, 0xFF, 0x97, 0xFF, 0x8D, 0xFF, 0x8D, 0xFF, 0x8C, 0xFF, 0x99, 0xFF, 0xA2, 0xFF, 0x92, 0xFF, 0x81, 0xFF, 0x77, 0xFF, 0x73, 0xFF, 0x6D, 0xFF, 0x4F, 0xFF, 0x2F, 0xFF, 0x1C, 0xFF, 0x03, 0xFF, 0xFD, 0xFE, 0x03, 0xFF, 0xFC, 0xFE, 0xF9, 0xFE, 0xF8, 0xFE, 0xED, 0xFE, 0xE1, 0xFE, 0xDE, 0xFE, 0xCD, 0xFE, 0xBF, 0xFE, 0xCD, 0xFE, 0xDD, 0xFE, 0xDF, 0xFE, 0xD4, 0xFE, 0xCF, 0xFE, 0xE8, 0xFE, 0xFB, 0xFE, 0x14, 0xFF, 0x27, 0xFF, 0x29, 0xFF, 0x2F, 0xFF, 0x44, 0xFF, 0x4A, 0xFF, 0x43, 0xFF, 0x4E, 0xFF, 0x52, 0xFF, 0x67, 0xFF, 0x8A, 0xFF, 0x90, 0xFF, 0xA3, 0xFF, 0xAA, 0xFF, 0xCB, 0xFF, 0xDC, 0xFF, 0xB9, 0xFF, 0xD5, 0xFF, 0xF8, 0xFF, 0x08, 0x00, 0x32, 0x00, 0x38, 0x00, 0x32, 0x00, 0x20, 0x00, 0x05, 0x00, 0xF9, 0xFF, 0xF7, 0xFF, 0xEA, 0xFF, 0xE6, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x2E, 0x00, 0x4B, 0x00, 0x65, 0x00, 0x8F, 0x00, 0x9C, 0x00, 0xA0, 0x00, 0x9F, 0x00, 0x86, 0x00, 0x6D, 0x00, 0x5F, 0x00, 0x43, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x33, 0x00, 0x53, 0x00, 0x7C, 0x00, 0x94, 0x00, 0xBA, 0x00, 0xD3, 0x00, 0xFC, 0x00, 0x04, 0x01, 0xF0, 0x00, 0xD6, 0x00, 0xA7, 0x00, 0xA9, 0x00, 0xA1, 0x00, 0x8F, 0x00, 0x8E, 0x00, 0x8C, 0x00, 0xA4, 0x00, 0xB6, 0x00, 0xCF, 0x00, 0xE5, 0x00, 0xDA, 0x00, 0xD0, 0x00, 0xBA, 0x00, 0x89, 0x00, 0x54, 0x00, 0x2E, 0x00, 0x15, 0x00, 0x08, 0x00, 0x12, 0x00, 0x23, 0x00, 0x25, 0x00, 0x2A, 0x00, 0x34, 0x00, 0x22, 0x00, 0x18, 0x00, 0x22, 0x00, 0x27, 0x00, 0x30, 0x00, 0x34, 0x00, 0x4A, 0x00, 0x51, 0x00, 0x48, 0x00, 0x42, 0x00, 0x1E, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xCE, 0xFF, 0xAB, 0xFF, 0x87, 0xFF, 0x78, 0xFF, 0x75, 0xFF, 0x6E, 0xFF, 0x6C, 0xFF, 0x67, 0xFF, 0x5B, 0xFF, 0x55, 0xFF, 0x3D, 0xFF, 0x3A, 0xFF, 0x3B, 0xFF, 0x34, 0xFF, 0x66, 0xFF, 0x93, 0xFF, 0xBD, 0xFF, 0xCE, 0xFF, 0xAD, 0xFF, 0x8F, 0xFF, 0x62, 0xFF, 0x39, 0xFF, 0x29, 0xFF, 0x17, 0xFF, 0x0B, 0xFF, 0x06, 0xFF, 0x0A, 0xFF, 0x11, 0xFF, 0x1F, 0xFF, 0x2C, 0xFF, 0x38, 0xFF, 0x49, 0xFF, 0x51, 0xFF, 0x58, 0xFF, 0x46, 0xFF, 0x20, 0xFF, 0x00, 0xFF, 0xD3, 0xFE, 0xA5, 0xFE, 0x82, 0xFE, 0x6B, 0xFE, 0x6A, 0xFE, 0x80, 0xFE, 0x9E, 0xFE, 0xB5, 0xFE, 0xD2, 0xFE, 0xE7, 0xFE, 0x07, 0xFF, 0x25, 0xFF, 0x24, 0xFF, 0x3B, 0xFF, 0x49, 0xFF, 0x42, 0xFF, 0x39, 0xFF, 0x26, 0xFF, 0x29, 0xFF, 0x28, 0xFF, 0x17, 0xFF, 0x01, 0xFF, 0xF7, 0xFE, 0xFD, 0xFE, 0x02, 0xFF, 0x1C, 0xFF, 0x3D, 0xFF, 0x60, 0xFF, 0x7B, 0xFF, 0x74, 0xFF, 0x74, 0xFF, 0x70, 0xFF, 0x69, 0xFF, 0x65, 0xFF, 0x54, 0xFF, 0x5E, 0xFF, 0x7E, 0xFF, 0x9B, 0xFF, 0xAF, 0xFF, 0xB6, 0xFF, 0xAB, 0xFF, 0x8D, 0xFF, 0x67, 0xFF, 0x43, 0xFF, 0x34, 0xFF, 0x18, 0xFF, 0x06, 0xFF, 0x10, 0xFF, 0x18, 0xFF, 0x34, 0xFF, 0x4B, 0xFF, 0x76, 0xFF, 0xAD, 0xFF, 0xBF, 0xFF, 0xCE, 0xFF, 0xC3, 0xFF, 0xAB, 0xFF, 0x9B, 0xFF, 0x9B, 0xFF, 0xAA, 0xFF, 0xA5, 0xFF, 0xA7, 0xFF, 0xAD, 0xFF, 0xA2, 0xFF, 0x98, 0xFF, 0x93, 0xFF, 0x98, 0xFF, 0xA0, 0xFF, 0xC7, 0xFF, 0xDB, 0xFF, 0xD8, 0xFF, 0xDC, 0xFF, 0xC0, 0xFF, 0xA8, 0xFF, 0x91, 0xFF, 0x6F, 0xFF, 0x5B, 0xFF, 0x47, 0xFF, 0x45, 0xFF, 0x3E, 0xFF, 0x34, 0xFF, 0x46, 0xFF, 0x64, 0xFF, 0x83, 0xFF, 0xA8, 0xFF, 0xC7, 0xFF, 0xD0, 0xFF, 0xCA, 0xFF, 0xB9, 0xFF, 0x9F, 0xFF, 0x8A, 0xFF, 0x7F, 0xFF, 0x6A, 0xFF, 0x55, 0xFF, 0x4C, 0xFF, 0x45, 0xFF, 0x4B, 0xFF, 0x6C, 0xFF, 0x89, 0xFF, 0xA7, 0xFF, 0xB8, 0xFF, 0x9F, 0xFF, 0x89, 0xFF, 0x71, 0xFF, 0x49, 0xFF, 0x37, 0xFF, 0x2C, 0xFF, 0x25, 0xFF, 0x29, 0xFF, 0x39, 0xFF, 0x67, 0xFF, 0x7F, 0xFF, 0x86, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9B, 0xFF, 0xB4, 0xFF, 0xC8, 0xFF, 0xD1, 0xFF, 0xD1, 0xFF, 0xC6, 0xFF, 0xB9, 0xFF, 0xC1, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, 0xC2, 0xFF, 0x9A, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x88, 0xFF, 0x9D, 0xFF, 0xA4, 0xFF, 0xA4, 0xFF, 0xA2, 0xFF, 0x85, 0xFF, 0x7B, 0xFF, 0x75, 0xFF, 0x6A, 0xFF, 0x6A, 0xFF, 0x55, 0xFF, 0x56, 0xFF, 0x68, 0xFF, 0x62, 0xFF, 0x6E, 0xFF, 0x79, 0xFF, 0x90, 0xFF, 0x9B, 0xFF, 0x8E, 0xFF, 0x87, 0xFF, 0x73, 0xFF, 0x59, 0xFF, 0x33, 0xFF, 0x04, 0xFF, 0xD9, 0xFE, 0xC9, 0xFE, 0xD0, 0xFE, 0xD4, 0xFE, 0xF2, 0xFE, 0x05, 0xFF, 0x0D, 0xFF, 0x30, 0xFF, 0x39, 0xFF, 0x38, 0xFF, 0x2F, 0xFF, 0x1D, 0xFF, 0x14, 0xFF, 0x06, 0xFF, 0xFD, 0xFE, 0xEE, 0xFE, 0xE4, 0xFE, 0xD8, 0xFE, 0xDF, 0xFE, 0x05, 0xFF, 0x18, 0xFF, 0x40, 0xFF, 0x76, 0xFF, 0x94, 0xFF, 0xAF, 0xFF, 0xD2, 0xFF, 0x02, 0x00, 0x20, 0x00, 0x21, 0x00, 0x0E, 0x00, 0xF1, 0xFF, 0xCD, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, 0xBE, 0xFF, 0xDD, 0xFF, 0xF5, 0xFF, 0x08, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x27, 0x00, 0x3B, 0x00, 0x3B, 0x00, 0x35, 0x00, 0x2C, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x42, 0x00, 0x5B, 0x00, 0x67, 0x00, 0x63, 0x00, 0x4C, 0x00, 0x3F, 0x00, 0x34, 0x00, 0x1E, 0x00, 0x16, 0x00, 0x0E, 0x00, 0xF3, 0xFF, 0xDE, 0xFF, 0xD0, 0xFF, 0xD6, 0xFF, 0xE9, 0xFF, 0xF4, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x2C, 0x00, 0x35, 0x00, 0x39, 0x00, 0x1C, 0x00, 0x06, 0x00, 0xFE, 0xFF, 0xE9, 0xFF, 0xD8, 0xFF, 0xD0, 0xFF, 0xCE, 0xFF, 0xCD, 0xFF, 0xD4, 0xFF, 0xE1, 0xFF, 0xED, 0xFF, 0x01, 0x00, 0x13, 0x00, 0x1A, 0x00, 0x1A, 0x00, 0x0D, 0x00, 0xF3, 0xFF, 0xF2, 0xFF, 0x0B, 0x00, 0x21, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x41, 0x00, 0x3E, 0x00, 0x30, 0x00, 0x2C, 0x00, 0x14, 0x00, 0xF9, 0xFF, 0xE0, 0xFF, 0xC7, 0xFF, 0xBD, 0xFF, 0xBC, 0xFF, 0xCE, 0xFF, 0xDC, 0xFF, 0xE1, 0xFF, 0xEE, 0xFF, 0x0F, 0x00, 0x2F, 0x00, 0x42, 0x00, 0x5F, 0x00, 0x56, 0x00, 0x47, 0x00, 0x3E, 0x00, 0x21, 0x00, 0x08, 0x00, 0xE2, 0xFF, 0xC9, 0xFF, 0xB2, 0xFF, 0xA6, 0xFF, 0xBB, 0xFF, 0xCC, 0xFF, 0xFD, 0xFF, 0x30, 0x00, 0x53, 0x00, 0x60, 0x00, 0x4E, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0xFC, 0xFF, 0xDA, 0xFF, 0xBD, 0xFF, 0xB0, 0xFF, 0x91, 0xFF, 0x76, 0xFF, 0x62, 0xFF, 0x5D, 0xFF, 0x71, 0xFF, 0x96, 0xFF, 0xC4, 0xFF, 0xE6, 0xFF, 0x09, 0x00, 0x21, 0x00, 0x23, 0x00, 0x29, 0x00, 0x37, 0x00, 0x46, 0x00, 0x3E, 0x00, 0x38, 0x00, 0x34, 0x00, 0x1E, 0x00, 0x13, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00, 0x1F, 0x00, 0x17, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x15, 0x00, 0x18, 0x00, 0x26, 0x00, 0x24, 0x00, 0x20, 0x00, 0x1B, 0x00, 0x02, 0x00, 0x05, 0x00, 0x19, 0x00, 0x30, 0x00, 0x6D, 0x00, 0x97, 0x00, 0xBE, 0x00, 0xCA, 0x00, 0x9C, 0x00, 0x8E, 0x00, 0x83, 0x00, 0x71, 0x00, 0x75, 0x00, 0x51, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x4D, 0x00, 0x73, 0x00, 0x93, 0x00, 0xBE, 0x00, 0xD3, 0x00, 0xE4, 0x00, 0xDE, 0x00, 0xB5, 0x00, 0x8F, 0x00, 0x56, 0x00, 0x28, 0x00, 0x0C, 0x00, 0xF6, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x17, 0x00, 0x28, 0x00, 0x55, 0x00, 0x7C, 0x00, 0xA0, 0x00, 0xBF, 0x00, 0xC2, 0x00, 0xC0, 0x00, 0xB4, 0x00, 0x91, 0x00, 0x8F, 0x00, 0x90, 0x00, 0x75, 0x00, 0x6F, 0x00, 0x68, 0x00, 0x59, 0x00, 0x56, 0x00, 0x56, 0x00, 0x63, 0x00, 0x66, 0x00, 0x67, 0x00, 0x6A, 0x00, 0x6E, 0x00, 0x7C, 0x00, 0x87, 0x00, 0x98, 0x00, 0x92, 0x00, 0x81, 0x00, 0x76, 0x00, 0x5E, 0x00, 0x58, 0x00, 0x5C, 0x00, 0x6D, 0x00, 0x88, 0x00, 0x9C, 0x00, 0xAB, 0x00, 0x9D, 0x00, 0x89, 0x00, 0x7E, 0x00, 0x61, 0x00, 0x2A, 0x00, 0xF8, 0xFF, 0xC0, 0xFF, 0x8D, 0xFF, 0x95, 0xFF, 0x9D, 0xFF, 0xA3, 0xFF, 0xD1, 0xFF, 0xF0, 0xFF, 0x05, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE5, 0xFF, 0xC7, 0xFF, 0xB3, 0xFF, 0x99, 0xFF, 0x9F, 0xFF, 0xBC, 0xFF, 0xCA, 0xFF, 0xCC, 0xFF, 0xC4, 0xFF, 0xC6, 0xFF, 0xC5, 0xFF, 0xC8, 0xFF, 0xD7, 0xFF, 0xE8, 0xFF, 0xF6, 0xFF, 0x13, 0x00, 0x33, 0x00, 0x30, 0x00, 0x42, 0x00, 0x63, 0x00, 0x72, 0x00, 0x8C, 0x00, 0x7B, 0x00, 0x77, 0x00, 0x8B, 0x00, 0x8A, 0x00, 0x91, 0x00, 0x9C, 0x00, 0xAF, 0x00, 0xAD, 0x00, 0xB1, 0x00, 0xC3, 0x00, 0xC0, 0x00, 0xBB, 0x00, 0xBD, 0x00, 0xCC, 0x00, 0xD5, 0x00, 0xE2, 0x00, 0x03, 0x01, 0x12, 0x01, 0x17, 0x01, 0x18, 0x01, 0x27, 0x01, 0x20, 0x01, 0x06, 0x01, 0xFF, 0x00, 0xEB, 0x00, 0xDF, 0x00, 0xD5, 0x00, 0xCC, 0x00, 0xE9, 0x00, 0x12, 0x01, 0x3C, 0x01, 0x61, 0x01, 0x76, 0x01, 0x87, 0x01, 0x8F, 0x01, 0x87, 0x01, 0x7C, 0x01, 0x6D, 0x01, 0x62, 0x01, 0x61, 0x01, 0x41, 0x01, 0x0F, 0x01, 0xEC, 0x00, 0xCE, 0x00, 0xC3, 0x00, 0xD4, 0x00, 0xE0, 0x00, 0xDA, 0x00, 0xE4, 0x00, 0xE4, 0x00, 0xF0, 0x00, 0x0B, 0x01, 0xF5, 0x00, 0xF3, 0x00, 0xE9, 0x00, 0xCD, 0x00, 0xD0, 0x00, 0xC0, 0x00, 0xC2, 0x00, 0xD5, 0x00, 0xD9, 0x00, 0xDE, 0x00, 0xC9, 0x00, 0xC2, 0x00, 0xCB, 0x00, 0xB9, 0x00, 0x99, 0x00, 0x76, 0x00, 0x53, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x55, 0x00, 0x7A, 0x00, 0x96, 0x00, 0x94, 0x00, 0xA0, 0x00, 0xA6, 0x00, 0xA6, 0x00, 0xAD, 0x00, 0xB3, 0x00, 0xB7, 0x00, 0xA8, 0x00, 0x95, 0x00, 0x8B, 0x00, 0x8B, 0x00, 0x84, 0x00, 0x77, 0x00, 0x68, 0x00, 0x6B, 0x00, 0x86, 0x00, 0x96, 0x00, 0xA6, 0x00, 0xB0, 0x00, 0xA5, 0x00, 0xAD, 0x00, 0xB5, 0x00, 0xAB, 0x00, 0xA8, 0x00, 0xA0, 0x00, 0xA2, 0x00, 0xB1, 0x00, 0xB0, 0x00, 0x9F, 0x00, 0x99, 0x00, 0x8C, 0x00, 0x8F, 0x00, 0x92, 0x00, 0x77, 0x00, 0x70, 0x00, 0x58, 0x00, 0x37, 0x00, 0x33, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x3D, 0x00, 0x4C, 0x00, 0x4B, 0x00, 0x57, 0x00, 0x66, 0x00, 0x90, 0x00, 0xB9, 0x00, 0xC6, 0x00, 0xE4, 0x00, 0xE0, 0x00, 0xD6, 0x00, 0xBC, 0x00, 0x86, 0x00, 0x6B, 0x00, 0x40, 0x00, 0x2E, 0x00, 0x35, 0x00, 0x2D, 0x00, 0x39, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x5B, 0x00, 0x69, 0x00, 0x75, 0x00, 0x7E, 0x00, 0x88, 0x00, 0x96, 0x00, 0x96, 0x00, 0x6B, 0x00, 0x56, 0x00, 0x50, 0x00, 0x4D, 0x00, 0x77, 0x00, 0x76, 0x00, 0x65, 0x00, 0x67, 0x00, 0x5D, 0x00, 0x69, 0x00, 0x5F, 0x00, 0x50, 0x00, 0x4E, 0x00, 0x4D, 0x00, 0x6B, 0x00, 0x88, 0x00, 0xAD, 0x00, 0xD3, 0x00, 0xE3, 0x00, 0xED, 0x00, 0xEF, 0x00, 0xE4, 0x00, 0xD4, 0x00, 0xB3, 0x00, 0x87, 0x00, 0x5F, 0x00, 0x2D, 0x00, 0x07, 0x00, 0xF0, 0xFF, 0xCD, 0xFF, 0xC5, 0xFF, 0xD7, 0xFF, 0xE9, 0xFF, 0x03, 0x00, 0x16, 0x00, 0x29, 0x00, 0x42, 0x00, 0x52, 0x00, 0x63, 0x00, 0x7E, 0x00, 0x84, 0x00, 0x8C, 0x00, 0x8E, 0x00, 0x69, 0x00, 0x50, 0x00, 0x2A, 0x00, 0xED, 0xFF, 0xC1, 0xFF, 0x92, 0xFF, 0x85, 0xFF, 0x9C, 0xFF, 0xBE, 0xFF, 0xDC, 0xFF, 0xF3, 0xFF, 0x06, 0x00, 0x19, 0x00, 0x28, 0x00, 0x28, 0x00, 0x2D, 0x00, 0x26, 0x00, 0x0D, 0x00, 0x09, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x17, 0x00, 0x1D, 0x00, 0x2E, 0x00, 0x39, 0x00, 0x3B, 0x00, 0x4F, 0x00, 0x66, 0x00, 0x65, 0x00, 0x64, 0x00, 0x5C, 0x00, 0x57, 0x00, 0x62, 0x00, 0x48, 0x00, 0x51, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x67, 0x00, 0x51, 0x00, 0x39, 0x00, 0x35, 0x00, 0x23, 0x00, 0x27, 0x00, 0x1C, 0x00, 0x08, 0x00, 0xFC, 0xFF, 0xED, 0xFF, 0xF0, 0xFF, 0xFD, 0xFF, 0x19, 0x00, 0x33, 0x00, 0x4F, 0x00, 0x61, 0x00, 0x5E, 0x00, 0x5F, 0x00, 0x66, 0x00, 0x7B, 0x00, 0x8D, 0x00, 0x8A, 0x00, 0x77, 0x00, 0x4E, 0x00, 0x22, 0x00, 0xF5, 0xFF, 0xBF, 0xFF, 0x94, 0xFF, 0x74, 0xFF, 0x69, 0xFF, 0x80, 0xFF, 0x8D, 0xFF, 0x9C, 0xFF, 0xBC, 0xFF, 0xD2, 0xFF, 0xEC, 0xFF, 0x12, 0x00, 0x20, 0x00, 0x1D, 0x00, 0x1C, 0x00, 0x13, 0x00, 0xF6, 0xFF, 0xD3, 0xFF, 0xB3, 0xFF, 0x98, 0xFF, 0x8F, 0xFF, 0x99, 0xFF, 0xAE, 0xFF, 0xC0, 0xFF, 0xC5, 0xFF, 0xCC, 0xFF, 0xD8, 0xFF, 0xE9, 0xFF, 0xF8, 0xFF, 0xFE, 0xFF, 0x0A, 0x00, 0x19, 0x00, 0x13, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xED, 0xFF, 0xDE, 0xFF, 0xB2, 0xFF, 0x8F, 0xFF, 0x74, 0xFF, 0x5B, 0xFF, 0x5E, 0xFF, 0x63, 0xFF, 0x6F, 0xFF, 0x7A, 0xFF, 0x79, 0xFF, 0x80, 0xFF, 0x80, 0xFF, 0x92, 0xFF, 0xAA, 0xFF, 0xB5, 0xFF, 0xD6, 0xFF, 0xEC, 0xFF, 0xE6, 0xFF, 0xDC, 0xFF, 0xC5, 0xFF, 0xAC, 0xFF, 0x9C, 0xFF, 0x90, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0x85, 0xFF, 0x82, 0xFF, 0x7C, 0xFF, 0x8C, 0xFF, 0xC0, 0xFF, 0xE9, 0xFF, 0x18, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x46, 0x00, 0x2A, 0x00, 0x0B, 0x00, 0xF8, 0xFF, 0xF2, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x32, 0x00, 0x67, 0x00, 0x73, 0x00, 0x83, 0x00, 0x91, 0x00, 0x97, 0x00, 0xA5, 0x00, 0x9E, 0x00, 0x99, 0x00, 0x90, 0x00, 0x81, 0x00, 0x8C, 0x00, 0x9B, 0x00, 0xAE, 0x00, 0xC6, 0x00, 0xD4, 0x00, 0xE1, 0x00, 0xE8, 0x00, 0xFD, 0x00, 0x16, 0x01, 0x26, 0x01, 0x1C, 0x01, 0xF0, 0x00, 0xD4, 0x00, 0xC1, 0x00, 0xA1, 0x00, 0x80, 0x00, 0x68, 0x00, 0x64, 0x00, 0x57, 0x00, 0x43, 0x00, 0x32, 0x00, 0x35, 0x00, 0x50, 0x00, 0x63, 0x00, 0x86, 0x00, 0xA2, 0x00, 0xB7, 0x00, 0xBF, 0x00, 0xA7, 0x00, 0x93, 0x00, 0x74, 0x00, 0x3C, 0x00, 0x0A, 0x00, 0xE9, 0xFF, 0xD6, 0xFF, 0xC6, 0xFF, 0xB7, 0xFF, 0xA5, 0xFF, 0x9C, 0xFF, 0x99, 0xFF, 0x8D, 0xFF, 0x88, 0xFF, 0x85, 0xFF, 0x84, 0xFF, 0x9B, 0xFF, 0xC1, 0xFF, 0xD9, 0xFF, 0xE8, 0xFF, 0xEB, 0xFF, 0xEA, 0xFF, 0xED, 0xFF, 0xE3, 0xFF, 0xCF, 0xFF, 0xBB, 0xFF, 0x99, 0xFF, 0x5D, 0xFF, 0x29, 0xFF, 0x08, 0xFF, 0xEA, 0xFE, 0x00, 0xFF, 0x2D, 0xFF, 0x49, 0xFF, 0x72, 0xFF, 0x97, 0xFF, 0xAD, 0xFF, 0xAC, 0xFF, 0xB5, 0xFF, 0xD1, 0xFF, 0xD3, 0xFF, 0xD5, 0xFF, 0xCF, 0xFF, 0xB5, 0xFF, 0x9B, 0xFF, 0x8D, 0xFF, 0x76, 0xFF, 0x6A, 0xFF, 0x73, 0xFF, 0x54, 0xFF, 0x41, 0xFF, 0x4A, 0xFF, 0x58, 0xFF, 0x8A, 0xFF, 0xBE, 0xFF, 0xDE, 0xFF, 0xE6, 0xFF, 0xFA, 0xFF, 0x09, 0x00, 0x0B, 0x00, 0x19, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x1A, 0x00, 0x08, 0x00, 0x03, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0xF5, 0xFF, 0xE6, 0xFF, 0xDF, 0xFF, 0xDC, 0xFF, 0xF6, 0xFF, 0x03, 0x00, 0x14, 0x00, 0x2C, 0x00, 0x32, 0x00, 0x3D, 0x00, 0x3A, 0x00, 0x42, 0x00, 0x3A, 0x00, 0x2F, 0x00, 0x35, 0x00, 0x24, 0x00, 0x2E, 0x00, 0x25, 0x00, 0x16, 0x00, 0x0F, 0x00, 0xEB, 0xFF, 0xD4, 0xFF, 0xB6, 0xFF, 0xB5, 0xFF, 0xCD, 0xFF, 0xDF, 0xFF, 0x04, 0x00, 0x20, 0x00, 0x4C, 0x00, 0x64, 0x00, 0x63, 0x00, 0x5E, 0x00, 0x44, 0x00, 0x33, 0x00, 0x17, 0x00, 0xF7, 0xFF, 0xD7, 0xFF, 0xAD, 0xFF, 0x93, 0xFF, 0x97, 0xFF, 0xA9, 0xFF, 0xBD, 0xFF, 0xE5, 0xFF, 0x01, 0x00, 0x0A, 0x00, 0x1D, 0x00, 0x18, 0x00, 0x1B, 0x00, 0x1D, 0x00, 0x10, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0xBF, 0xFF, 0xAD, 0xFF, 0xA1, 0xFF, 0xAC, 0xFF, 0xB4, 0xFF, 0xD0, 0xFF, 0xE8, 0xFF, 0xED, 0xFF, 0x02, 0x00, 0x08, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x09, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x21, 0x00, 0x26, 0x00, 0x25, 0x00, 0x2A, 0x00, 0x2D, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x33, 0x00, 0x25, 0x00, 0x1F, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x2E, 0x00, 0x48, 0x00, 0x62, 0x00, 0x71, 0x00, 0x7B, 0x00, 0x74, 0x00, 0x6E, 0x00, 0x5E, 0x00, 0x68, 0x00, 0x7A, 0x00, 0x7F, 0x00, 0x96, 0x00, 0x8B, 0x00, 0x79, 0x00, 0x5D, 0x00, 0x1E, 0x00, 0xFE, 0xFF, 0xD9, 0xFF, 0xC7, 0xFF, 0xCF, 0xFF, 0xC2, 0xFF, 0xCD, 0xFF, 0xDB, 0xFF, 0xE6, 0xFF, 0x09, 0x00, 0x1A, 0x00, 0x25, 0x00, 0x34, 0x00, 0x2E, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1F, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x00, 0x25, 0x00, 0x1C, 0x00, 0x1E, 0x00, 0x0D, 0x00, 0xF5, 0xFF, 0xD8, 0xFF, 0xAD, 0xFF, 0x97, 0xFF, 0x8C, 0xFF, 0x7A, 0xFF, 0x89, 0xFF, 0xBD, 0xFF, 0xF2, 0xFF, 0x22, 0x00, 0x4E, 0x00, 0x71, 0x00, 0x89, 0x00, 0x7C, 0x00, 0x70, 0x00, 0x49, 0x00, 0x01, 0x00, 0xE4, 0xFF, 0xC5, 0xFF, 0xA5, 0xFF, 0xAA, 0xFF, 0xB3, 0xFF, 0xCD, 0xFF, 0xD7, 0xFF, 0xDA, 0xFF, 0x0E, 0x00, 0x39, 0x00, 0x50, 0x00, 0x75, 0x00, 0x6D, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x53, 0x00, 0x61, 0x00, 0x71, 0x00, 0x6B, 0x00, 0x7B, 0x00, 0x6A, 0x00, 0x55, 0x00, 0x56, 0x00, 0x50, 0x00, 0x60, 0x00, 0x6C, 0x00, 0x72, 0x00, 0x7F, 0x00, 0x76, 0x00, 0x84, 0x00, 0xAB, 0x00, 0xC9, 0x00, 0xE0, 0x00, 0xEB, 0x00, 0xE4, 0x00, 0xC8, 0x00, 0x9C, 0x00, 0x7B, 0x00, 0x5D, 0x00, 0x52, 0x00, 0x63, 0x00, 0x5E, 0x00, 0x3A, 0x00, 0x20, 0x00, 0x1B, 0x00, 0x08, 0x00, 0xE5, 0xFF, 0xD9, 0xFF, 0xCF, 0xFF, 0xC9, 0xFF, 0xD6, 0xFF, 0xDA, 0xFF, 0xF1, 0xFF, 0x15, 0x00, 0x45, 0x00, 0x6D, 0x00, 0x85, 0x00, 0x8C, 0x00, 0x76, 0x00, 0x57, 0x00, 0x29, 0x00, 0xF4, 0xFF, 0xCC, 0xFF, 0xAE, 0xFF, 0xA2, 0xFF, 0x87, 0xFF, 0x85, 0xFF, 0x9C, 0xFF, 0xAD, 0xFF, 0xDA, 0xFF, 0x01, 0x00, 0x27, 0x00, 0x48, 0x00, 0x44, 0x00, 0x35, 0x00, 0x31, 0x00, 0x2B, 0x00, 0x1C, 0x00, 0x1A, 0x00, 0x11, 0x00, 0x00, 0x00, 0xF9, 0xFF, 0xEA, 0xFF, 0xF0, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x02, 0x00, 0x10, 0x00, 0x3D, 0x00, 0x64, 0x00, 0x71, 0x00, 0x8B, 0x00, 0xA2, 0x00, 0xA8, 0x00, 0xC0, 0x00, 0xB8, 0x00, 0x8E, 0x00, 0x71, 0x00, 0x48, 0x00, 0x1B, 0x00, 0x05, 0x00, 0xEB, 0xFF, 0xF3, 0xFF, 0x05, 0x00, 0xFF, 0xFF, 0x12, 0x00, 0x2D, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x9E, 0x00, 0xC8, 0x00, 0xD6, 0x00, 0xD8, 0x00, 0xC8, 0x00, 0x9E, 0x00, 0x70, 0x00, 0x4C, 0x00, 0x27, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0x09, 0x00, 0x1B, 0x00, 0x44, 0x00, 0x60, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x75, 0x00, 0x75, 0x00, 0x78, 0x00, 0x73, 0x00, 0x5A, 0x00, 0x32, 0x00, 0x19, 0x00, 0xFB, 0xFF, 0xF1, 0xFF, 0xF5, 0xFF, 0xF4, 0xFF, 0x06, 0x00, 0x1D, 0x00, 0x42, 0x00, 0x56, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x5A, 0x00, 0x53, 0x00, 0x3F, 0x00, 0x3B, 0x00, 0x40, 0x00, 0x41, 0x00, 0x4A, 0x00, 0x4D, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x62, 0x00, 0x6B, 0x00, 0x58, 0x00, 0x42, 0x00, 0x33, 0x00, 0x25, 0x00, 0x28, 0x00, 0x24, 0x00, 0x26, 0x00, 0x35, 0x00, 0x4A, 0x00, 0x6A, 0x00, 0x85, 0x00, 0x99, 0x00, 0xA9, 0x00, 0xA2, 0x00, 0x8D, 0x00, 0x76, 0x00, 0x56, 0x00, 0x41, 0x00, 0x2E, 0x00, 0x17, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x2E, 0x00, 0x39, 0x00, 0x43, 0x00, 0x59, 0x00, 0x54, 0x00, 0x46, 0x00, 0x26, 0x00, 0xFF, 0xFF, 0xE6, 0xFF, 0xD0, 0xFF, 0xD5, 0xFF, 0xD4, 0xFF, 0xE7, 0xFF, 0x00, 0x00, 0x06, 0x00, 0x29, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x3F, 0x00, 0x18, 0x00, 0xFC, 0xFF, 0xF3, 0xFF, 0xEB, 0xFF, 0xDF, 0xFF, 0xD2, 0xFF, 0xC6, 0xFF, 0xAE, 0xFF, 0xA9, 0xFF, 0xB0, 0xFF, 0xC3, 0xFF, 0xDF, 0xFF, 0xF2, 0xFF, 0x20, 0x00, 0x3C, 0x00, 0x48, 0x00, 0x67, 0x00, 0x65, 0x00, 0x4E, 0x00, 0x35, 0x00, 0xFE, 0xFF, 0xBA, 0xFF, 0x80, 0xFF, 0x55, 0xFF, 0x38, 0xFF, 0x34, 0xFF, 0x40, 0xFF, 0x57, 0xFF, 0x85, 0xFF, 0xBD, 0xFF, 0xE9, 0xFF, 0x01, 0x00, 0x0F, 0x00, 0x15, 0x00, 0x00, 0x00, 0xE2, 0xFF, 0xC9, 0xFF, 0xBB, 0xFF, 0xB2, 0xFF, 0x97, 0xFF, 0x82, 0xFF, 0x77, 0xFF, 0x61, 0xFF, 0x5C, 0xFF, 0x5B, 0xFF, 0x4D, 0xFF, 0x3E, 0xFF, 0x2A, 0xFF, 0x1F, 0xFF, 0x1E, 0xFF, 0x2C, 0xFF, 0x3F, 0xFF, 0x48, 0xFF, 0x50, 0xFF, 0x54, 0xFF, 0x59, 0xFF, 0x59, 0xFF, 0x5D, 0xFF, 0x5C, 0xFF, 0x4F, 0xFF, 0x3B, 0xFF, 0x1A, 0xFF, 0x05, 0xFF, 0xF6, 0xFE, 0xF5, 0xFE, 0xF7, 0xFE, 0xE1, 0xFE, 0xDD, 0xFE, 0xE0, 0xFE, 0xE6, 0xFE, 0x05, 0xFF, 0x24, 0xFF, 0x4A, 0xFF, 0x66, 0xFF, 0x78, 0xFF, 0x76, 0xFF, 0x63, 0xFF, 0x4B, 0xFF, 0x26, 0xFF, 0x02, 0xFF, 0xEA, 0xFE, 0xD8, 0xFE, 0xC9, 0xFE, 0xAB, 0xFE, 0xA4, 0xFE, 0xB7, 0xFE, 0xD7, 0xFE, 0x00, 0xFF, 0x23, 0xFF, 0x47, 0xFF, 0x6B, 0xFF, 0x89, 0xFF, 0x8F, 0xFF, 0x8A, 0xFF, 0x81, 0xFF, 0x6B, 0xFF, 0x6B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x78, 0xFF, 0x72, 0xFF, 0x66, 0xFF, 0x63, 0xFF, 0x5C, 0xFF, 0x46, 0xFF, 0x43, 0xFF, 0x50, 0xFF, 0x47, 0xFF, 0x49, 0xFF, 0x52, 0xFF, 0x58, 0xFF, 0x69, 0xFF, 0x7B, 0xFF, 0x8F, 0xFF, 0xA6, 0xFF, 0xB3, 0xFF, 0xC3, 0xFF, 0xD5, 0xFF, 0xE1, 0xFF, 0xE0, 0xFF, 0xC8, 0xFF, 0xB4, 0xFF, 0xA9, 0xFF, 0x94, 0xFF, 0x84, 0xFF, 0x78, 0xFF, 0x71, 0xFF, 0x70, 0xFF, 0x74, 0xFF, 0x88, 0xFF, 0xA4, 0xFF, 0xBC, 0xFF, 0xE2, 0xFF, 0xF7, 0xFF, 0xFD, 0xFF, 0xFC, 0xFF, 0xE7, 0xFF, 0xCE, 0xFF, 0xB2, 0xFF, 0xA3, 0xFF, 0x9A, 0xFF, 0x89, 0xFF, 0x94, 0xFF, 0x90, 0xFF, 0x83, 0xFF, 0x8C, 0xFF, 0x92, 0xFF, 0x97, 0xFF, 0x99, 0xFF, 0x9E, 0xFF, 0xA6, 0xFF, 0xAC, 0xFF, 0xB5, 0xFF, 0xB3, 0xFF, 0xBC, 0xFF, 0xCD, 0xFF, 0xCF, 0xFF, 0xD4, 0xFF, 0xCE, 0xFF, 0xC0, 0xFF, 0xBB, 0xFF, 0xB0, 0xFF, 0xB4, 0xFF, 0xC0, 0xFF, 0xB0, 0xFF, 0xA1, 0xFF, 0x96, 0xFF, 0x7A, 0xFF, 0x73, 0xFF, 0x77, 0xFF, 0x6F, 0xFF, 0x66, 0xFF, 0x70, 0xFF, 0x86, 0xFF, 0xA8, 0xFF, 0xD5, 0xFF, 0xEA, 0xFF, 0xF4, 0xFF, 0xF9, 0xFF, 0xE5, 0xFF, 0xD8, 0xFF, 0xBB, 0xFF, 0x9C, 0xFF, 0x8D, 0xFF, 0x6F, 0xFF, 0x54, 0xFF, 0x4D, 0xFF, 0x50, 0xFF, 0x5A, 0xFF, 0x71, 0xFF, 0x82, 0xFF, 0x8A, 0xFF, 0x98, 0xFF, 0x9A, 0xFF, 0x9B, 0xFF, 0x95, 0xFF, 0x80, 0xFF, 0x79, 0xFF, 0x73, 0xFF, 0x6B, 0xFF, 0x63, 0xFF, 0x61, 0xFF, 0x5B, 0xFF, 0x56, 0xFF, 0x56, 0xFF, 0x4E, 0xFF, 0x53, 0xFF, 0x4F, 0xFF, 0x4C, 0xFF, 0x5B, 0xFF, 0x46, 0xFF, 0x37, 0xFF, 0x32, 0xFF, 0x2B, 0xFF, 0x3D, 0xFF, 0x55, 0xFF, 0x6F, 0xFF, 0x7C, 0xFF, 0x86, 0xFF, 0x90, 0xFF, 0x9D, 0xFF, 0xA9, 0xFF, 0x9B, 0xFF, 0x89, 0xFF, 0x73, 0xFF, 0x4F, 0xFF, 0x31, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x25, 0xFF, 0x21, 0xFF, 0x1C, 0xFF, 0x3C, 0xFF, 0x65, 0xFF, 0x9F, 0xFF, 0xED, 0xFF, 0x02, 0x00, 0x13, 0x00, 0x19, 0x00, 0xFA, 0xFF, 0xE9, 0xFF, 0xD8, 0xFF, 0xC3, 0xFF, 0xB2, 0xFF, 0x98, 0xFF, 0x7D, 0xFF, 0x76, 0xFF, 0x7C, 0xFF, 0x78, 0xFF, 0x8A, 0xFF, 0x92, 0xFF, 0x8E, 0xFF, 0x9D, 0xFF, 0x8E, 0xFF, 0x99, 0xFF, 0xC6, 0xFF, 0xD4, 0xFF, 0xE9, 0xFF, 0xF9, 0xFF, 0xEB, 0xFF, 0xE9, 0xFF, 0xE2, 0xFF, 0xCF, 0xFF, 0xC9, 0xFF, 0xBD, 0xFF, 0xBC, 0xFF, 0xBC, 0xFF, 0xB3, 0xFF, 0xA1, 0xFF, 0x8C, 0xFF, 0x91, 0xFF, 0xA1, 0xFF, 0xAD, 0xFF, 0xB5, 0xFF, 0xB3, 0xFF, 0xBE, 0xFF, 0xCD, 0xFF, 0xE5, 0xFF, 0xFD, 0xFF, 0x09, 0x00, 0x23, 0x00, 0x3D, 0x00, 0x39, 0x00, 0x1E, 0x00, 0x09, 0x00, 0xEE, 0xFF, 0xD0, 0xFF, 0xBD, 0xFF, 0x97, 0xFF, 0x86, 0xFF, 0x76, 0xFF, 0x64, 0xFF, 0x7D, 0xFF, 0x98, 0xFF, 0xC4, 0xFF, 0x02, 0x00, 0x29, 0x00, 0x41, 0x00, 0x3D, 0x00, 0x23, 0x00, 0x0F, 0x00, 0xF5, 0xFF, 0xDD, 0xFF, 0xD0, 0xFF, 0xAE, 0xFF, 0x91, 0xFF, 0x93, 0xFF, 0x90, 0xFF, 0x95, 0xFF, 0xB0, 0xFF, 0xCC, 0xFF, 0xDD, 0xFF, 0xF1, 0xFF, 0x03, 0x00, 0x10, 0x00, 0x1E, 0x00, 0x19, 0x00, 0x11, 0x00, 0x02, 0x00, 0xEA, 0xFF, 0xDD, 0xFF, 0xC6, 0xFF, 0xB3, 0xFF, 0xA8, 0xFF, 0xA3, 0xFF, 0xAB, 0xFF, 0xB7, 0xFF, 0xC9, 0xFF, 0xD8, 0xFF, 0xE4, 0xFF, 0xDE, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xC2, 0xFF, 0xC7, 0xFF, 0xD6, 0xFF, 0xDB, 0xFF, 0xEA, 0xFF, 0xEF, 0xFF, 0xFA, 0xFF, 0xFE, 0xFF, 0xF6, 0xFF, 0xF5, 0xFF, 0xEA, 0xFF, 0xE6, 0xFF, 0xDF, 0xFF, 0xCD, 0xFF, 0xBF, 0xFF, 0xB4, 0xFF, 0xA8, 0xFF, 0x9A, 0xFF, 0x98, 0xFF, 0x9F, 0xFF, 0xAB, 0xFF, 0xBA, 0xFF, 0xBE, 0xFF, 0xC4, 0xFF, 0xCE, 0xFF, 0xDC, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE4, 0xFF, 0xD7, 0xFF, 0xC5, 0xFF, 0xB3, 0xFF, 0xA1, 0xFF, 0x86, 0xFF, 0x6C, 0xFF, 0x60, 0xFF, 0x4C, 0xFF, 0x4E, 0xFF, 0x59, 0xFF, 0x59, 0xFF, 0x61, 0xFF, 0x60, 0xFF, 0x63, 0xFF, 0x67, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x60, 0xFF, 0x61, 0xFF, 0x5F, 0xFF, 0x59, 0xFF, 0x5D, 0xFF, 0x6A, 0xFF, 0x82, 0xFF, 0x96, 0xFF, 0xA3, 0xFF, 0xA3, 0xFF, 0x8D, 0xFF, 0x72, 0xFF, 0x55, 0xFF, 0x36, 0xFF, 0x21, 0xFF, 0x23, 0xFF, 0x2B, 0xFF, 0x3D, 0xFF, 0x5E, 0xFF, 0x83, 0xFF, 0xB0, 0xFF, 0xD5, 0xFF, 0xF7, 0xFF, 0x10, 0x00, 0x0F, 0x00, 0x08, 0x00, 0xF6, 0xFF, 0xE5, 0xFF, 0xD9, 0xFF, 0xC5, 0xFF, 0xBA, 0xFF, 0xB9, 0xFF, 0xBF, 0xFF, 0xBC, 0xFF, 0xBC, 0xFF, 0xC1, 0xFF, 0xD1, 0xFF, 0xFB, 0xFF, 0x1F, 0x00, 0x4B, 0x00, 0x7A, 0x00, 0x97, 0x00, 0xA8, 0x00, 0x9A, 0x00, 0x7A, 0x00, 0x5E, 0x00, 0x41, 0x00, 0x2B, 0x00, 0x1B, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xF9, 0xFF, 0x03, 0x00, 0x10, 0x00, 0x27, 0x00, 0x3F, 0x00, 0x56, 0x00, 0x74, 0x00, 0x89, 0x00, 0x9A, 0x00, 0xA7, 0x00, 0xAF, 0x00, 0xB3, 0x00, 0xB8, 0x00, 0xB5, 0x00, 0x9E, 0x00, 0x96, 0x00, 0x8E, 0x00, 0x6F, 0x00, 0x57, 0x00, 0x40, 0x00, 0x32, 0x00, 0x21, 0x00, 0x16, 0x00, 0x1D, 0x00, 0x1F, 0x00, 0x3C, 0x00, 0x6E, 0x00, 0x92, 0x00, 0xB7, 0x00, 0xD1, 0x00, 0xDD, 0x00, 0xD5, 0x00, 0xB8, 0x00, 0x96, 0x00, 0x6D, 0x00, 0x48, 0x00, 0x31, 0x00, 0x0E, 0x00, 0xF3, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xFA, 0xFF, 0x0E, 0x00, 0x15, 0x00, 0x31, 0x00, 0x51, 0x00, 0x68, 0x00, 0x7C, 0x00, 0x88, 0x00, 0x9E, 0x00, 0xAD, 0x00, 0xB0, 0x00, 0xAB, 0x00, 0x98, 0x00, 0x80, 0x00, 0x6A, 0x00, 0x52, 0x00, 0x35, 0x00, 0x24, 0x00, 0x18, 0x00, 0x19, 0x00, 0x2C, 0x00, 0x3D, 0x00, 0x50, 0x00, 0x6A, 0x00, 0x7B, 0x00, 0x83, 0x00, 0x8F, 0x00, 0x90, 0x00, 0x93, 0x00, 0xA5, 0x00, 0xA8, 0x00, 0xB0, 0x00, 0xC2, 0x00, 0xD3, 0x00, 0xE0, 0x00, 0xD2, 0x00, 0xB2, 0x00, 0x85, 0x00, 0x4F, 0x00, 0x1A, 0x00, 0xEE, 0xFF, 0xCB, 0xFF, 0xBA, 0xFF, 0xC6, 0xFF, 0xE7, 0xFF, 0x1C, 0x00, 0x4B, 0x00, 0x70, 0x00, 0x92, 0x00, 0x8E, 0x00, 0x87, 0x00, 0x73, 0x00, 0x48, 0x00, 0x25, 0x00, 0xF8, 0xFF, 0xD7, 0xFF, 0xCF, 0xFF, 0xCB, 0xFF, 0xD4, 0xFF, 0xE5, 0xFF, 0xFB, 0xFF, 0x09, 0x00, 0x15, 0x00, 0x18, 0x00, 0x17, 0x00, 0x1A, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x15, 0x00, 0x13, 0x00, 0x11, 0x00, 0x0D, 0x00, 0x04, 0x00, 0xF3, 0xFF, 0xEF, 0xFF, 0xE6, 0xFF, 0xEA, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xF9, 0xFF, 0xFD, 0xFF, 0x15, 0x00, 0x2C, 0x00, 0x3E, 0x00, 0x5D, 0x00, 0x6D, 0x00, 0x7A, 0x00, 0x8D, 0x00, 0x99, 0x00, 0xA2, 0x00, 0x9F, 0x00, 0x8D, 0x00, 0x76, 0x00, 0x5D, 0x00, 0x3F, 0x00, 0x30, 0x00, 0x2D, 0x00, 0x29, 0x00, 0x31, 0x00, 0x32, 0x00, 0x39, 0x00, 0x56, 0x00, 0x70, 0x00, 0x90, 0x00, 0xA5, 0x00, 0xA5, 0x00, 0x9C, 0x00, 0x89, 0x00, 0x78, 0x00, 0x67, 0x00, 0x53, 0x00, 0x4E, 0x00, 0x47, 0x00, 0x41, 0x00, 0x42, 0x00, 0x40, 0x00, 0x3F, 0x00, 0x47, 0x00, 0x4A, 0x00, 0x37, 0x00, 0x27, 0x00, 0x1A, 0x00, 0x04, 0x00, 0x07, 0x00, 0x10, 0x00, 0x12, 0x00, 0x1B, 0x00, 0x13, 0x00, 0x11, 0x00, 0x1D, 0x00, 0x19, 0x00, 0x17, 0x00, 0x17, 0x00, 0x0D, 0x00, 0x09, 0x00, 0xFE, 0xFF, 0xEB, 0xFF, 0xEA, 0xFF, 0xE2, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, 0xD7, 0xFF, 0xDE, 0xFF, 0xF6, 0xFF, 0x0B, 0x00, 0x2C, 0x00, 0x53, 0x00, 0x63, 0x00, 0x6E, 0x00, 0x6D, 0x00, 0x63, 0x00, 0x56, 0x00, 0x42, 0x00, 0x2B, 0x00, 0x13, 0x00, 0x01, 0x00, 0xFC, 0xFF, 0x02, 0x00, 0x08, 0x00, 0x19, 0x00, 0x36, 0x00, 0x48, 0x00, 0x5B, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00, 0x5F, 0x00, 0x68, 0x00, 0x6B, 0x00, 0x61, 0x00, 0x5A, 0x00, 0x45, 0x00, 0x34, 0x00, 0x2F, 0x00, 0x2D, 0x00, 0x30, 0x00, 0x35, 0x00, 0x34, 0x00, 0x2B, 0x00, 0x2A, 0x00, 0x2E, 0x00, 0x3E, 0x00, 0x53, 0x00, 0x69, 0x00, 0x82, 0x00, 0x8C, 0x00, 0x9A, 0x00, 0x97, 0x00, 0x84, 0x00, 0x79, 0x00, 0x6A, 0x00, 0x67, 0x00, 0x65, 0x00, 0x68, 0x00, 0x64, 0x00, 0x50, 0x00, 0x46, 0x00, 0x38, 0x00, 0x39, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x5C, 0x00, 0x70, 0x00, 0x91, 0x00, 0xA6, 0x00, 0xB5, 0x00, 0xC9, 0x00, 0xD3, 0x00, 0xDB, 0x00, 0xC8, 0x00, 0xA6, 0x00, 0x79, 0x00, 0x4D, 0x00, 0x35, 0x00, 0x15, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x11, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x1D, 0x00, 0x25, 0x00, 0x3C, 0x00, 0x4A, 0x00, 0x51, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3B, 0x00, 0x35, 0x00, 0x23, 0x00, 0x19, 0x00, 0x20, 0x00, 0x11, 0x00, 0x12, 0x00, 0x11, 0x00, 0x09, 0x00, 0x19, 0x00, 0x1C, 0x00, 0x26, 0x00, 0x33, 0x00, 0x35, 0x00, 0x33, 0x00, 0x28, 0x00, 0x28, 0x00, 0x29, 0x00, 0x33, 0x00, 0x3C, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x27, 0x00, 0x15, 0x00, 0x09, 0x00, 0x02, 0x00, 0x06, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x22, 0x00, 0x30, 0x00, 0x47, 0x00, 0x63, 0x00, 0x78, 0x00, 0x90, 0x00, 0xA0, 0x00, 0xA3, 0x00, 0x9C, 0x00, 0x96, 0x00, 0x88, 0x00, 0x78, 0x00, 0x6E, 0x00, 0x55, 0x00, 0x45, 0x00, 0x39, 0x00, 0x32, 0x00, 0x41, 0x00, 0x49, 0x00, 0x5A, 0x00, 0x6B, 0x00, 0x75, 0x00, 0x81, 0x00, 0x79, 0x00, 0x6B, 0x00, 0x5E, 0x00, 0x50, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x5C, 0x00, 0x66, 0x00, 0x77, 0x00, 0x8A, 0x00, 0x94, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0x9A, 0x00, 0x96, 0x00, 0x94, 0x00, 0x7E, 0x00, 0x6D, 0x00, 0x5E, 0x00, 0x44, 0x00, 0x38, 0x00, 0x2D, 0x00, 0x26, 0x00, 0x27, 0x00, 0x24, 0x00, 0x1B, 0x00, 0x19, 0x00, 0x1C, 0x00, 0x18, 0x00, 0x1F, 0x00, 0x1D, 0x00, 0x16, 0x00, 0x13, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xD9, 0xFF, 0xC6, 0xFF, 0xBE, 0xFF, 0xB7, 0xFF, 0xC8, 0xFF, 0xD2, 0xFF, 0xEA, 0xFF, 0xFE, 0xFF, 0x09, 0x00, 0x16, 0x00, 0x0D, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0A, 0x00, 0x02, 0x00, 0xE6, 0xFF, 0xD7, 0xFF, 0xC8, 0xFF, 0xC2, 0xFF, 0xC5, 0xFF, 0xC9, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xDD, 0xFF, 0xD6, 0xFF, 0xD6, 0xFF, 0xE0, 0xFF, 0xDD, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0x14, 0x00, 0x30, 0x00, 0x3D, 0x00, 0x4E, 0x00, 0x50, 0x00, 0x4E, 0x00, 0x4A, 0x00, 0x42, 0x00, 0x40, 0x00, 0x30, 0x00, 0x22, 0x00, 0x0F, 0x00, 0xF7, 0xFF, 0xE9, 0xFF, 0xE6, 0xFF, 0x00, 0x00, 0x1E, 0x00, 0x41, 0x00, 0x56, 0x00, 0x65, 0x00, 0x77, 0x00, 0x72, 0x00, 0x68, 0x00, 0x4C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x1B, 0x00, 0x10, 0x00, 0xFE, 0xFF, 0xE7, 0xFF, 0xDD, 0xFF, 0xE1, 0xFF, 0xF0, 0xFF, 0x07, 0x00, 0x27, 0x00, 0x3D, 0x00, 0x56, 0x00, 0x71, 0x00, 0x7D, 0x00, 0x7D, 0x00, 0x70, 0x00, 0x5E, 0x00, 0x45, 0x00, 0x32, 0x00, 0x28, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x27, 0x00, 0x25, 0x00, 0x25, 0x00, 0x20, 0x00, 0x17, 0x00, 0x09, 0x00, 0x00, 0x00, 0xF5, 0xFF, 0xF2, 0xFF, 0xF1, 0xFF, 0xEC, 0xFF, 0xF2, 0xFF, 0x00, 0x00, 0x11, 0x00, 0x2B, 0x00, 0x46, 0x00, 0x57, 0x00, 0x5C, 0x00, 0x56, 0x00, 0x4A, 0x00, 0x3B, 0x00, 0x27, 0x00, 0x20, 0x00, 0x14, 0x00, 0xFD, 0xFF, 0xE5, 0xFF, 0xC8, 0xFF, 0xBD, 0xFF, 0xC2, 0xFF, 0xD0, 0xFF, 0xF1, 0xFF, 0x0E, 0x00, 0x26, 0x00, 0x3A, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x35, 0x00, 0x2D, 0x00, 0x27, 0x00, 0x13, 0x00, 0xFC, 0xFF, 0xEB, 0xFF, 0xE1, 0xFF, 0xE8, 0xFF, 0xF6, 0xFF, 0x0F, 0x00, 0x33, 0x00, 0x50, 0x00, 0x6C, 0x00, 0x77, 0x00, 0x71, 0x00, 0x62, 0x00, 0x4A, 0x00, 0x32, 0x00, 0x20, 0x00, 0x18, 0x00, 0x14, 0x00, 0x0F, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x27, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2C, 0x00, 0x2A, 0x00, 0x2A, 0x00, 0x2C, 0x00, 0x2E, 0x00, 0x2C, 0x00, 0x29, 0x00, 0x32, 0x00, 0x42, 0x00, 0x54, 0x00, 0x65, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x74, 0x00, 0x70, 0x00, 0x6D, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6C, 0x00, 0x63, 0x00, 0x4F, 0x00, 0x3A, 0x00, 0x24, 0x00, 0x22, 0x00, 0x2B, 0x00, 0x2D, 0x00, 0x37, 0x00, 0x45, 0x00, 0x58, 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x82, 0x00, 0x7C, 0x00, 0x69, 0x00, 0x5C, 0x00, 0x53, 0x00, 0x43, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x45, 0x00, 0x52, 0x00, 0x59, 0x00, 0x68, 0x00, 0x68, 0x00, 0x66, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x55, 0x00, 0x3A, 0x00, 0x19, 0x00, 0x04, 0x00, 0xF1, 0xFF, 0xE8, 0xFF, 0xE7, 0xFF, 0xF3, 0xFF, 0x0B, 0x00, 0x1C, 0x00, 0x27, 0x00, 0x22, 0x00, 0x13, 0x00, 0x01, 0x00, 0xF6, 0xFF, 0xE8, 0xFF, 0xDB, 0xFF, 0xDB, 0xFF, 0xC4, 0xFF, 0xAF, 0xFF, 0xAF, 0xFF, 0xB2, 0xFF, 0xC6, 0xFF, 0xE3, 0xFF, 0xFC, 0xFF, 0x08, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xE2, 0xFF, 0xD3, 0xFF, 0xCB, 0xFF, 0xBB, 0xFF, 0xA3, 0xFF, 0x95, 0xFF, 0x93, 0xFF, 0x8E, 0xFF, 0x94, 0xFF, 0xA7, 0xFF, 0xB0, 0xFF, 0xB8, 0xFF, 0xBA, 0xFF, 0xB1, 0xFF, 0xB3, 0xFF, 0xB7, 0xFF, 0xBF, 0xFF, 0xCA, 0xFF, 0xCD, 0xFF, 0xDB, 0xFF, 0xEC, 0xFF, 0xFD, 0xFF, 0x0D, 0x00, 0x02, 0x00, 0xF9, 0xFF, 0xF4, 0xFF, 0xEA, 0xFF, 0xF0, 0xFF, 0xEF, 0xFF, 0xE8, 0xFF, 0xE8, 0xFF, 0xEA, 0xFF, 0xEC, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x11, 0x00, 0x1C, 0x00, 0x2E, 0x00, 0x47, 0x00, 0x5C, 0x00, 0x6D, 0x00, 0x70, 0x00, 0x66, 0x00, 0x59, 0x00, 0x44, 0x00, 0x2C, 0x00, 0x19, 0x00, 0x0B, 0x00, 0x07, 0x00, 0x14, 0x00, 0x26, 0x00, 0x3F, 0x00, 0x65, 0x00, 0x84, 0x00, 0x9B, 0x00, 0xAD, 0x00, 0xB8, 0x00, 0xB5, 0x00, 0xAE, 0x00, 0xA1, 0x00, 0x84, 0x00, 0x61, 0x00, 0x36, 0x00, 0x0F, 0x00, 0xFB, 0xFF, 0xE6, 0xFF, 0xE2, 0xFF, 0xEC, 0xFF, 0xFD, 0xFF, 0x14, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x5F, 0x00, 0x74, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6E, 0x00, 0x6A, 0x00, 0x64, 0x00, 0x53, 0x00, 0x45, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x53, 0x00, 0x56, 0x00, 0x60, 0x00, 0x66, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x6C, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x75, 0x00, 0x7F, 0x00, 0x82, 0x00, 0x79, 0x00, 0x74, 0x00, 0x5B, 0x00, 0x4B, 0x00, 0x4D, 0x00, 0x48, 0x00, 0x54, 0x00, 0x59, 0x00, 0x53, 0x00, 0x5B, 0x00, 0x67, 0x00, 0x7B, 0x00, 0x8C, 0x00, 0x9D, 0x00, 0xA9, 0x00, 0xB2, 0x00, 0xAE, 0x00, 0x97, 0x00, 0x84, 0x00, 0x74, 0x00, 0x68, 0x00, 0x57, 0x00, 0x3F, 0x00, 0x2C, 0x00, 0x1E, 0x00, 0x20, 0x00, 0x24, 0x00, 0x25, 0x00, 0x2D, 0x00, 0x35, 0x00, 0x3A, 0x00, 0x33, 0x00, 0x2B, 0x00, 0x22, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x14, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xF5, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0x12, 0x00, 0x1C, 0x00, 0x21, 0x00, 0x1F, 0x00, 0x08, 0x00, 0xF6, 0xFF, 0xE6, 0xFF, 0xD5, 0xFF, 0xCC, 0xFF, 0xC3, 0xFF, 0xC3, 0xFF, 0xCD, 0xFF, 0xD8, 0xFF, 0xEB, 0xFF, 0x08, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x18, 0x00, 0xFF, 0xFF, 0xEA, 0xFF, 0xE4, 0xFF, 0xCF, 0xFF, 0xC4, 0xFF, 0xBA, 0xFF, 0xB6, 0xFF, 0xC1, 0xFF, 0xD4, 0xFF, 0xEB, 0xFF, 0xF5, 0xFF, 0x01, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xF5, 0xFF, 0xEF, 0xFF, 0xF9, 0xFF, 0x0A, 0x00, 0x19, 0x00, 0x24, 0x00, 0x2E, 0x00, 0x27, 0x00, 0x23, 0x00, 0x29, 0x00, 0x2D, 0x00, 0x41, 0x00, 0x43, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0F, 0x00, 0x01, 0x00, 0xF3, 0xFF, 0xE2, 0xFF, 0xDD, 0xFF, 0xD7, 0xFF, 0xD6, 0xFF, 0xEB, 0xFF, 0x04, 0x00, 0x1E, 0x00, 0x3F, 0x00, 0x43, 0x00, 0x3B, 0x00, 0x32, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0xF9, 0xFF, 0xEA, 0xFF, 0xE0, 0xFF, 0xDF, 0xFF, 0xED, 0xFF, 0xF4, 0xFF, 0x07, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x05, 0x00, 0xF4, 0xFF, 0xEC, 0xFF, 0xE2, 0xFF, 0xD9, 0xFF, 0xD2, 0xFF, 0xC6, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC7, 0xFF, 0xC1, 0xFF, 0xBF, 0xFF, 0xB6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA0, 0xFF, 0xA6, 0xFF, 0xAB, 0xFF, 0xA8, 0xFF, 0xAC, 0xFF, 0xA0, 0xFF, 0xA4, 0xFF, 0xAB, 0xFF, 0xAB, 0xFF, 0xB3, 0xFF, 0xB8, 0xFF, 0xC0, 0xFF, 0xC6, 0xFF, 0xCC, 0xFF, 0xCB, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF, 0xB0, 0xFF, 0xA1, 0xFF, 0x8A, 0xFF, 0x7A, 0xFF, 0x78, 0xFF, 0x7A, 0xFF, 0x7C, 0xFF, 0x82, 0xFF, 0x8E, 0xFF, 0x9F, 0xFF, 0xB5, 0xFF, 0xC3, 0xFF, 0xC8, 0xFF, 0xCC, 0xFF, 0xC4, 0xFF, 0xB9, 0xFF, 0xAC, 0xFF, 0xA4, 0xFF, 0x9E, 0xFF, 0x91, 0xFF, 0x90, 0xFF, 0x8E, 0xFF, 0x98, 0xFF, 0xA6, 0xFF, 0xA9, 0xFF, 0xAE, 0xFF, 0xB0, 0xFF, 0xAB, 0xFF, 0x9B, 0xFF, 0x93, 0xFF, 0x90, 0xFF, 0x86, 0xFF, 0x86, 0xFF, 0x7C, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x67, 0xFF, 0x62, 0xFF, 0x6E, 0xFF, 0x75, 0xFF, 0x83, 0xFF, 0x92, 0xFF, 0x9C, 0xFF, 0xAA, 0xFF, 0xAC, 0xFF, 0xA0, 0xFF, 0x8E, 0xFF, 0x70, 0xFF, 0x57, 0xFF, 0x44, 0xFF, 0x2F, 0xFF, 0x2D, 0xFF, 0x38, 0xFF, 0x48, 0xFF, 0x58, 0xFF, 0x64, 0xFF, 0x70, 0xFF, 0x7B, 0xFF, 0x83, 0xFF, 0x7D, 0xFF, 0x72, 0xFF, 0x62, 0xFF, 0x4A, 0xFF, 0x37, 0xFF, 0x2D, 0xFF, 0x28, 0xFF, 0x30, 0xFF, 0x37, 0xFF, 0x47, 0xFF, 0x67, 0xFF, 0x7B, 0xFF, 0x81, 0xFF, 0x85, 0xFF, 0x80, 0xFF, 0x80, 0xFF, 0x84, 0xFF, 0x7D, 0xFF, 0x73, 0xFF, 0x67, 0xFF, 0x5B, 0xFF, 0x58, 0xFF, 0x5A, 0xFF, 0x61, 0xFF, 0x6F, 0xFF, 0x7C, 0xFF, 0x88, 0xFF, 0x96, 0xFF, 0xA4, 0xFF, 0xB4, 0xFF, 0xC2, 0xFF, 0xC9, 0xFF, 0xCA, 0xFF, 0xBE, 0xFF, 0xAA, 0xFF, 0x97, 0xFF, 0x89, 0xFF, 0x81, 0xFF, 0x86, 0xFF, 0x8D, 0xFF, 0x91, 0xFF, 0xA0, 0xFF, 0xAE, 0xFF, 0xBD, 0xFF, 0xCD, 0xFF, 0xD7, 0xFF, 0xEB, 0xFF, 0xF7, 0xFF, 0xF2, 0xFF, 0xE9, 0xFF, 0xD1, 0xFF, 0xB7, 0xFF, 0xA9, 0xFF, 0x9B, 0xFF, 0x93, 0xFF, 0x96, 0xFF, 0x9D, 0xFF, 0xAF, 0xFF, 0xC1, 0xFF, 0xC5, 0xFF, 0xBC, 0xFF, 0xB1, 0xFF, 0xA7, 0xFF, 0x99, 0xFF, 0x90, 0xFF, 0x81, 0xFF, 0x78, 0xFF, 0x76, 0xFF, 0x79, 0xFF, 0x87, 0xFF, 0x8F, 0xFF, 0x95, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, 0x98, 0xFF, 0x91, 0xFF, 0x8F, 0xFF, 0x8F, 0xFF, 0x97, 0xFF, 0x9C, 0xFF, 0xA3, 0xFF, 0xAD, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xA6, 0xFF, 0xA3, 0xFF, 0x9E, 0xFF, 0x8F, 0xFF, 0x8D, 0xFF, 0x89, 0xFF, 0x8B, 0xFF, 0x8D, 0xFF, 0x8A, 0xFF, 0x8B, 0xFF, 0x86, 0xFF, 0x87, 0xFF, 0x85, 0xFF, 0x8B, 0xFF, 0xA3, 0xFF, 0xB4, 0xFF, 0xC8, 0xFF, 0xD0, 0xFF, 0xCB, 0xFF, 0xC9, 0xFF, 0xBC, 0xFF, 0xB1, 0xFF, 0xAA, 0xFF, 0xA1, 0xFF, 0x9A, 0xFF, 0x98, 0xFF, 0x96, 0xFF, 0x99, 0xFF, 0xA8, 0xFF, 0xB8, 0xFF, 0xD1, 0xFF, 0xE7, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0xEE, 0xFF, 0xE3, 0xFF, 0xCE, 0xFF, 0xBA, 0xFF, 0xAD, 0xFF, 0xA3, 0xFF, 0xA2, 0xFF, 0x9B, 0xFF, 0x94, 0xFF, 0x8F, 0xFF, 0x93, 0xFF, 0x9E, 0xFF, 0xA5, 0xFF, 0xA9, 0xFF, 0xAA, 0xFF, 0xAE, 0xFF, 0xAA, 0xFF, 0xA5, 0xFF, 0x9D, 0xFF, 0x9A, 0xFF, 0xA0, 0xFF, 0xA2, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, 0x98, 0xFF, 0x93, 0xFF, 0x9E, 0xFF, 0x9D, 0xFF, 0x9C, 0xFF, 0x93, 0xFF, 0x88, 0xFF, 0x7D, 0xFF, 0x72, 0xFF, 0x6C, 0xFF, 0x6A, 0xFF, 0x6E, 0xFF, 0x72, 0xFF, 0x78, 0xFF, 0x81, 0xFF, 0x8C, 0xFF, 0x93, 0xFF, 0x96, 0xFF, 0x95, 0xFF, 0x8D, 0xFF, 0x7E, 0xFF, 0x6E, 0xFF, 0x61, 0xFF, 0x5D, 0xFF, 0x5C, 0xFF, 0x5B, 0xFF, 0x61, 0xFF, 0x6D, 0xFF, 0x7C, 0xFF, 0x8C, 0xFF, 0x96, 0xFF, 0xAB, 0xFF, 0xBC, 0xFF, 0xC4, 0xFF, 0xC9, 0xFF, 0xBB, 0xFF, 0xA9, 0xFF, 0x95, 0xFF, 0x82, 0xFF, 0x73, 0xFF, 0x67, 0xFF, 0x67, 0xFF, 0x6B, 0xFF, 0x79, 0xFF, 0x8C, 0xFF, 0x9C, 0xFF, 0xAC, 0xFF, 0xB3, 0xFF, 0xBE, 0xFF, 0xC3, 0xFF, 0xBD, 0xFF, 0xB3, 0xFF, 0xA3, 0xFF, 0x98, 0xFF, 0x90, 0xFF, 0x8F, 0xFF, 0x94, 0xFF, 0x9F, 0xFF, 0xAE, 0xFF, 0xB6, 0xFF, 0xC4, 0xFF, 0xCC, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD1, 0xFF, 0xDB, 0xFF, 0xDB, 0xFF, 0xD4, 0xFF, 0xCA, 0xFF, 0xC2, 0xFF, 0xC8, 0xFF, 0xCC, 0xFF, 0xC9, 0xFF, 0xC9, 0xFF, 0xCE, 0xFF, 0xCD, 0xFF, 0xC9, 0xFF, 0xC9, 0xFF, 0xC4, 0xFF, 0xC6, 0xFF, 0xC3, 0xFF, 0xBC, 0xFF, 0xB7, 0xFF, 0xB3, 0xFF, 0xBC, 0xFF, 0xC3, 0xFF, 0xCA, 0xFF, 0xD9, 0xFF, 0xE4, 0xFF, 0xEC, 0xFF, 0xEE, 0xFF, 0xEE, 0xFF, 0xE0, 0xFF, 0xD2, 0xFF, 0xC7, 0xFF, 0xB6, 0xFF, 0xAC, 0xFF, 0xA4, 0xFF, 0xA6, 0xFF, 0xAE, 0xFF, 0xB2, 0xFF, 0xBA, 0xFF, 0xC7, 0xFF, 0xDD, 0xFF, 0xF3, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xF1, 0xFF, 0xE6, 0xFF, 0xD8, 0xFF, 0xCC, 0xFF, 0xB5, 0xFF, 0xA2, 0xFF, 0x9C, 0xFF, 0x96, 0xFF, 0x9C, 0xFF, 0xAB, 0xFF, 0xBF, 0xFF, 0xDB, 0xFF, 0xF5, 0xFF, 0x07, 0x00, 0x0B, 0x00, 0x0F, 0x00, 0x0C, 0x00, 0x03, 0x00, 0xFC, 0xFF, 0xED, 0xFF, 0xE2, 0xFF, 0xDA, 0xFF, 0xD4, 0xFF, 0xD0, 0xFF, 0xCD, 0xFF, 0xD0, 0xFF, 0xD3, 0xFF, 0xD9, 0xFF, 0xE0, 0xFF, 0xE8, 0xFF, 0xF4, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x1D, 0x00, 0x29, 0x00, 0x34, 0x00, 0x38, 0x00, 0x38, 0x00, 0x31, 0x00, 0x27, 0x00, 0x1B, 0x00, 0x0F, 0x00, 0x08, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x17, 0x00, 0x1B, 0x00, 0x1A, 0x00, 0x13, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x27, 0x00, 0x29, 0x00, 0x2D, 0x00, 0x27, 0x00, 0x17, 0x00, 0x03, 0x00, 0xED, 0xFF, 0xD9, 0xFF, 0xC8, 0xFF, 0xC0, 0xFF, 0xC6, 0xFF, 0xD8, 0xFF, 0xEE, 0xFF, 0x08, 0x00, 0x22, 0x00, 0x36, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x37, 0x00, 0x2D, 0x00, 0x25, 0x00, 0x11, 0x00, 0xFA, 0xFF, 0xEA, 0xFF, 0xD5, 0xFF, 0xD1, 0xFF, 0xD5, 0xFF, 0xDD, 0xFF, 0xF1, 0xFF, 0x02, 0x00, 0x15, 0x00, 0x25, 0x00, 0x30, 0x00, 0x36, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x2F, 0x00, 0x23, 0x00, 0x15, 0x00, 0x02, 0x00, 0xF3, 0xFF, 0xEC, 0xFF, 0xF4, 0xFF, 0xFA, 0xFF, 0x01, 0x00, 0x0D, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x25, 0x00, 0x27, 0x00, 0x29, 0x00, 0x21, 0x00, 0x1D, 0x00, 0x19, 0x00, 0x19, 0x00, 0x14, 0x00, 0x09, 0x00, 0x01, 0x00, 0xFA, 0xFF, 0xF5, 0xFF, 0xFB, 0xFF, 0x07, 0x00, 0x14, 0x00, 0x21, 0x00, 0x30, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x27, 0x00, 0x1C, 0x00, 0x12, 0x00, 0x0A, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x15, 0x00, 0x1E, 0x00, 0x21, 0x00, 0x22, 0x00, 0x1C, 0x00, 0x08, 0x00, 0xFA, 0xFF, 0xEE, 0xFF, 0xE4, 0xFF, 0xE3, 0xFF, 0xEB, 0xFF, 0xFB, 0xFF, 0x0E, 0x00, 0x24, 0x00, 0x31, 0x00, 0x3C, 0x00, 0x3F, 0x00, 0x32, 0x00, 0x2A, 0x00, 0x1E, 0x00, 0x15, 0x00, 0x15, 0x00, 0x13, 0x00, 0x1A, 0x00, 0x1F, 0x00, 0x23, 0x00, 0x2E, 0x00, 0x36, 0x00, 0x49, 0x00, 0x5F, 0x00, 0x71, 0x00, 0x78, 0x00, 0x71, 0x00, 0x6D, 0x00, 0x6D, 0x00, 0x66, 0x00, 0x5B, 0x00, 0x4E, 0x00, 0x35, 0x00, 0x21, 0x00, 0x19, 0x00, 0x16, 0x00, 0x23, 0x00, 0x3C, 0x00, 0x50, 0x00, 0x60, 0x00, 0x6F, 0x00, 0x78, 0x00, 0x82, 0x00, 0x83, 0x00, 0x7B, 0x00, 0x6F, 0x00, 0x5B, 0x00, 0x4B, 0x00, 0x45, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00, 0x61, 0x00, 0x67, 0x00, 0x69, 0x00, 0x64, 0x00, 0x63, 0x00, 0x62, 0x00, 0x55, 0x00, 0x44, 0x00, 0x39, 0x00, 0x31, 0x00, 0x37, 0x00, 0x3D, 0x00, 0x3F, 0x00, 0x43, 0x00, 0x4A, 0x00, 0x59, 0x00, 0x5E, 0x00, 0x5D, 0x00, 0x57, 0x00, 0x4C, 0x00, 0x40, 0x00, 0x31, 0x00, 0x20, 0x00, 0x16, 0x00, 0x15, 0x00, 0x13, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x2D, 0x00, 0x3F, 0x00, 0x4A, 0x00, 0x51, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3A, 0x00, 0x29, 0x00, 0x12, 0x00, 0xFD, 0xFF, 0xEA, 0xFF, 0xDC, 0xFF, 0xDB, 0xFF, 0xE8, 0xFF, 0x00, 0x00, 0x1A, 0x00, 0x2D, 0x00, 0x34, 0x00, 0x31, 0x00, 0x2E, 0x00, 0x28, 0x00, 0x1E, 0x00, 0x0B, 0x00, 0xF8, 0xFF, 0xEF, 0xFF, 0xEC, 0xFF, 0xF0, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0x02, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x25, 0x00, 0x27, 0x00, 0x26, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1C, 0x00, 0x13, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x17, 0x00, 0x17, 0x00, 0x15, 0x00, 0x1A, 0x00, 0x18, 0x00, 0x19, 0x00, 0x19, 0x00, 0x14, 0x00, 0x1D, 0x00, 0x27, 0x00, 0x2A, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00, 0x35, 0x00, 0x2F, 0x00, 0x27, 0x00, 0x22, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2A, 0x00, 0x29, 0x00, 0x29, 0x00, 0x24, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00, 0x1C, 0x00, 0x1A, 0x00, 0x1F, 0x00, 0x26, 0x00, 0x33, 0x00, 0x4A, 0x00, 0x59, 0x00, 0x5D, 0x00, 0x58, 0x00, 0x4D, 0x00, 0x43, 0x00, 0x3A, 0x00, 0x2E, 0x00, 0x20, 0x00, 0x1D, 0x00, 0x22, 0x00, 0x34, 0x00, 0x4C, 0x00, 0x5C, 0x00, 0x73, 0x00, 0x88, 0x00, 0x92, 0x00, 0x94, 0x00, 0x84, 0x00, 0x6E, 0x00, 0x56, 0x00, 0x40, 0x00, 0x31, 0x00, 0x30, 0x00, 0x3A, 0x00, 0x3F, 0x00, 0x4A, 0x00, 0x53, 0x00, 0x56, 0x00, 0x62, 0x00, 0x65, 0x00, 0x65, 0x00, 0x64, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5F, 0x00, 0x5C, 0x00, 0x5A, 0x00, 0x53, 0x00, 0x4D, 0x00, 0x4C, 0x00, 0x48, 0x00, 0x46, 0x00, 0x42, 0x00, 0x3C, 0x00, 0x3B, 0x00, 0x3D, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x53, 0x00, 0x55, 0x00, 0x4F, 0x00, 0x4A, 0x00, 0x45, 0x00, 0x3F, 0x00, 0x38, 0x00, 0x31, 0x00, 0x2E, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x35, 0x00, 0x3E, 0x00, 0x40, 0x00, 0x44, 0x00, 0x41, 0x00, 0x3F, 0x00, 0x40, 0x00, 0x3F, 0x00, 0x41, 0x00, 0x43, 0x00, 0x47, 0x00, 0x4F, 0x00, 0x5A, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x53, 0x00, 0x3F, 0x00, 0x31, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x23, 0x00, 0x3D, 0x00, 0x5D, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x5C, 0x00, 0x4D, 0x00, 0x36, 0x00, 0x25, 0x00, 0x1E, 0x00, 0x19, 0x00, 0x1C, 0x00, 0x29, 0x00, 0x35, 0x00, 0x45, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x5D, 0x00, 0x66, 0x00, 0x67, 0x00, 0x67, 0x00, 0x60, 0x00, 0x4D, 0x00, 0x3A, 0x00, 0x20, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x09, 0x00, 0x16, 0x00, 0x20, 0x00, 0x2C, 0x00, 0x35, 0x00, 0x37, 0x00, 0x3F, 0x00, 0x42, 0x00, 0x45, 0x00, 0x47, 0x00, 0x49, 0x00, 0x48, 0x00, 0x41, 0x00, 0x3C, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x16, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x13, 0x00, 0x13, 0x00, 0x15, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x2D, 0x00, 0x38, 0x00, 0x43, 0x00, 0x44, 0x00, 0x42, 0x00, 0x3A, 0x00, 0x33, 0x00, 0x2C, 0x00, 0x1A, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x09, 0x00, 0x15, 0x00, 0x1E, 0x00, 0x2A, 0x00, 0x38, 0x00, 0x3A, 0x00, 0x39, 0x00, 0x32, 0x00, 0x26, 0x00, 0x19, 0x00, 0x16, 0x00, 0x15, 0x00, 0x0C, 0x00, 0x05, 0x00, 0xF6, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xEF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x06, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x17, 0x00, 0x19, 0x00, 0x13, 0x00, 0x09, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x08, 0x00, 0x13, 0x00, 0x1D, 0x00, 0x29, 0x00, 0x2E, 0x00, 0x2A, 0x00, 0x27, 0x00, 0x1D, 0x00, 0x09, 0x00, 0xFD, 0xFF, 0xF0, 0xFF, 0xE5, 0xFF, 0xE6, 0xFF, 0xEB, 0xFF, 0x00, 0x00, 0x12, 0x00, 0x1A, 0x00, 0x1F, 0x00, 0x21, 0x00, 0x27, 0x00, 0x28, 0x00, 0x26, 0x00, 0x23, 0x00, 0x1C, 0x00, 0x19, 0x00, 0x1F, 0x00, 0x28, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x35, 0x00, 0x32, 0x00, 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3F, 0x00, 0x43, 0x00, 0x46, 0x00, 0x48, 0x00, 0x45, 0x00, 0x45, 0x00, 0x40, 0x00, 0x38, 0x00, 0x32, 0x00, 0x30, 0x00, 0x3B, 0x00, 0x43, 0x00, 0x53, 0x00, 0x60, 0x00, 0x63, 0x00, 0x67, 0x00, 0x66, 0x00, 0x60, 0x00, 0x55, 0x00, 0x45, 0x00, 0x33, 0x00, 0x23, 0x00, 0x19, 0x00, 0x16, 0x00, 0x1A, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1B, 0x00, 0x28, 0x00, 0x30, 0x00, 0x33, 0x00, 0x2E, 0x00, 0x21, 0x00, 0x0B, 0x00, 0xF3, 0xFF, 0xE3, 0xFF, 0xDD, 0xFF, 0xE0, 0xFF, 0xE7, 0xFF, 0xEF, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0x02, 0x00, 0x0B, 0x00, 0x13, 0x00, 0x13, 0x00, 0x0E, 0x00, 0x07, 0x00, 0xFD, 0xFF, 0xF8, 0xFF, 0xF3, 0xFF, 0xEE, 0xFF, 0xE9, 0xFF, 0xEC, 0xFF, 0xF2, 0xFF, 0xF2, 0xFF, 0xF6, 0xFF, 0xF9, 0xFF, 0xF6, 0xFF, 0xEE, 0xFF, 0xE3, 0xFF, 0xDC, 0xFF, 0xD8, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xF5, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x14, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0C, 0x00, 0x03, 0x00, 0xFC, 0xFF, 0xF3, 0xFF, 0xE8, 0xFF, 0xE0, 0xFF, 0xD6, 0xFF, 0xD4, 0xFF, 0xDA, 0xFF, 0xE5, 0xFF, 0xF5, 0xFF, 0x0B, 0x00, 0x25, 0x00, 0x32, 0x00, 0x34, 0x00, 0x2D, 0x00, 0x1E, 0x00, 0x0A, 0x00, 0xF2, 0xFF, 0xDB, 0xFF, 0xC4, 0xFF, 0xB9, 0xFF, 0xB8, 0xFF, 0xC0, 0xFF, 0xD4, 0xFF, 0xE9, 0xFF, 0x01, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x20, 0x00, 0x1E, 0x00, 0x17, 0x00, 0x0A, 0x00, 0xFE, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xFB, 0xFF, 0x06, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x21, 0x00, 0x22, 0x00, 0x25, 0x00, 0x26, 0x00, 0x22, 0x00, 0x1E, 0x00, 0x19, 0x00, 0x1D, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x2E, 0x00, 0x29, 0x00, 0x25, 0x00, 0x1F, 0x00, 0x1B, 0x00, 0x1B, 0x00, 0x1A, 0x00, 0x21, 0x00, 0x2A, 0x00, 0x2C, 0x00, 0x38, 0x00, 0x45, 0x00, 0x50, 0x00, 0x55, 0x00, 0x4E, 0x00, 0x43, 0x00, 0x33, 0x00, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xE6, 0xFF, 0xE5, 0xFF, 0xEC, 0xFF, 0xFA, 0xFF, 0x08, 0x00, 0x14, 0x00, 0x26, 0x00, 0x35, 0x00, 0x39, 0x00, 0x36, 0x00, 0x31, 0x00, 0x29, 0x00, 0x21, 0x00, 0x1D, 0x00, 0x0E, 0x00, 0x01, 0x00, 0xF7, 0xFF, 0xF0, 0xFF, 0xF5, 0xFF, 0xFC, 0xFF, 0x04, 0x00, 0x0F, 0x00, 0x1A, 0x00, 0x24, 0x00, 0x24, 0x00, 0x23, 0x00, 0x24, 0x00, 0x20, 0x00, 0x18, 0x00, 0x0F, 0x00, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x15, 0x00, 0x1C, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1F, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x14, 0x00, 0x24, 0x00, 0x31, 0x00, 0x3A, 0x00, 0x42, 0x00, 0x3D, 0x00, 0x34, 0x00, 0x2C, 0x00, 0x1A, 0x00, 0x0A, 0x00, 0x02, 0x00, 0xFA, 0xFF, 0xFD, 0xFF, 0x05, 0x00, 0x0E, 0x00, 0x1D, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00, 0x1B, 0x00, 0x19, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x14, 0x00, 0x17, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x19, 0x00, 0x13, 0x00, 0x12, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x09, 0x00, 0x07, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x07, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x07, 0x00, 0x11, 0x00, 0x23, 0x00, 0x31, 0x00, 0x3C, 0x00, 0x43, 0x00, 0x39, 0x00, 0x2E, 0x00, 0x21, 0x00, 0x11, 0x00, 0x03, 0x00, 0xF4, 0xFF, 0xE4, 0xFF, 0xD9, 0xFF, 0xD9, 0xFF, 0xE1, 0xFF, 0xF4, 0xFF, 0x0C, 0x00, 0x20, 0x00, 0x36, 0x00, 0x3F, 0x00, 0x40, 0x00, 0x3D, 0x00, 0x34, 0x00, 0x24, 0x00, 0x14, 0x00, 0x05, 0x00, 0xF9, 0xFF, 0xEC, 0xFF, 0xE5, 0xFF, 0xE2, 0xFF, 0xE5, 0xFF, 0xEA, 0xFF, 0xF0, 0xFF, 0xF4, 0xFF, 0xF3, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF2, 0xFF, 0xF7, 0xFF, 0xFA, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xF1, 0xFF, 0xE6, 0xFF, 0xDD, 0xFF, 0xD5, 0xFF, 0xD0, 0xFF, 0xD0, 0xFF, 0xCD, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xD1, 0xFF, 0xD9, 0xFF, 0xDC, 0xFF, 0xE0, 0xFF, 0xE9, 0xFF, 0xF4, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0x01, 0x00, 0xF7, 0xFF, 0xE5, 0xFF, 0xD3, 0xFF, 0xBD, 0xFF, 0xB0, 0xFF, 0xAC, 0xFF, 0xA8, 0xFF, 0xAA, 0xFF, 0xB1, 0xFF, 0xC1, 0xFF, 0xDB, 0xFF, 0xF6, 0xFF, 0x0B, 0x00, 0x13, 0x00, 0x08, 0x00, 0xF2, 0xFF, 0xE5, 0xFF, 0xE2, 0xFF, 0xDF, 0xFF, 0xD9, 0xFF, 0xD1, 0xFF, 0xCD, 0xFF, 0xCA, 0xFF, 0xD2, 0xFF, 0xE3, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x11, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x1E, 0x00, 0x1D, 0x00, 0x16, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0D, 0x00, 0x05, 0x00, 0xFE, 0xFF, 0xF7, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xED, 0xFF, 0xE9, 0xFF, 0xEC, 0xFF, 0xF0, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x0E, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x07, 0x00, 0xF9, 0xFF, 0xE6, 0xFF, 0xD6, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD8, 0xFF, 0xE9, 0xFF, 0xFB, 0xFF, 0x09, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x1B, 0x00, 0x12, 0x00, 0x08, 0x00, 0xFB, 0xFF, 0xF0, 0xFF, 0xEA, 0xFF, 0xE1, 0xFF, 0xD8, 0xFF, 0xD8, 0xFF, 0xE0, 0xFF, 0xE9, 0xFF, 0xF9, 0xFF, 0x09, 0x00, 0x16, 0x00, 0x1D, 0x00, 0x20, 0x00, 0x21, 0x00, 0x1B, 0x00, 0x11, 0x00, 0x05, 0x00, 0xFE, 0xFF, 0xFA, 0xFF, 0xF9, 0xFF, 0xF9, 0xFF, 0xF2, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x07, 0x00, 0x02, 0x00, 0xF6, 0xFF, 0xEA, 0xFF, 0xE0, 0xFF, 0xD1, 0xFF, 0xC6, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xC4, 0xFF, 0xC9, 0xFF, 0xD6, 0xFF, 0xE2, 0xFF, 0xEB, 0xFF, 0xF1, 0xFF, 0xF2, 0xFF, 0xEE, 0xFF, 0xE5, 0xFF, 0xE0, 0xFF, 0xD7, 0xFF, 0xCC, 0xFF, 0xBD, 0xFF, 0xB0, 0xFF, 0xAA, 0xFF, 0xA5, 0xFF, 0xAA, 0xFF, 0xB4, 0xFF, 0xBD, 0xFF, 0xC7, 0xFF, 0xCA, 0xFF, 0xCD, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF, 0xBD, 0xFF, 0xB4, 0xFF, 0xB2, 0xFF, 0xAD, 0xFF, 0xAA, 0xFF, 0xB1, 0xFF, 0xB9, 0xFF, 0xBF, 0xFF, 0xC1, 0xFF, 0xC5, 0xFF, 0xC4, 0xFF, 0xC2, 0xFF, 0xBD, 0xFF, 0xB2, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF, 0xB5, 0xFF, 0xBD, 0xFF, 0xC2, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xC6, 0xFF, 0xC7, 0xFF, 0xD1, 0xFF, 0xDB, 0xFF, 0xDE, 0xFF, 0xE0, 0xFF, 0xD7, 0xFF, 0xCD, 0xFF, 0xBF, 0xFF, 0xAE, 0xFF, 0xA4, 0xFF, 0x99, 0xFF, 0x90, 0xFF, 0x8D, 0xFF, 0x91, 0xFF, 0xA0, 0xFF, 0xB5, 0xFF, 0xCC, 0xFF, 0xDD, 0xFF, 0xEA, 0xFF, 0xF2, 0xFF, 0xEF, 0xFF, 0xEC, 0xFF, 0xE5, 0xFF, 0xDD, 0xFF, 0xD2, 0xFF, 0xC7, 0xFF, 0xBE, 0xFF, 0xB0, 0xFF, 0xA7, 0xFF, 0xA1, 0xFF, 0x9C, 0xFF, 0xA1, 0xFF, 0xA8, 0xFF, 0xB0, 0xFF, 0xB9, 0xFF, 0xC6, 0xFF, 0xD3, 0xFF, 0xDB, 0xFF, 0xDE, 0xFF, 0xDC, 0xFF, 0xD8, 0xFF, 0xD2, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xCE, 0xFF, 0xCC, 0xFF, 0xCB, 0xFF, 0xCA, 0xFF, 0xC7, 0xFF, 0xC0, 0xFF, 0xB8, 0xFF, 0xB1, 0xFF, 0xB0, 0xFF, 0xB2, 0xFF, 0xB6, 0xFF, 0xC2, 0xFF, 0xD2, 0xFF, 0xE1, 0xFF, 0xEB, 0xFF, 0xEF, 0xFF, 0xF2, 0xFF, 0xF1, 0xFF, 0xEC, 0xFF, 0xE9, 0xFF, 0xE0, 0xFF, 0xD4, 0xFF, 0xCA, 0xFF, 0xC0, 0xFF, 0xB8, 0xFF, 0xB2, 0xFF, 0xAE, 0xFF, 0xB1, 0xFF, 0xB5, 0xFF, 0xBE, 0xFF, 0xCC, 0xFF, 0xD7, 0xFF, 0xEA, 0xFF, 0xFA, 0xFF, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xD6, 0xFF, 0xC8, 0xFF, 0xC3, 0xFF, 0xBC, 0xFF, 0xB5, 0xFF, 0xB6, 0xFF, 0xBB, 0xFF, 0xC2, 0xFF, 0xCA, 0xFF, 0xD4, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xD6, 0xFF, 0xCE, 0xFF, 0xC2, 0xFF, 0xB8, 0xFF, 0xB4, 0xFF, 0xB9, 0xFF, 0xBD, 0xFF, 0xC2, 0xFF, 0xCF, 0xFF, 0xD9, 0xFF, 0xE2, 0xFF, 0xE6, 0xFF, 0xE6, 0xFF, 0xE1, 0xFF, 0xDA, 0xFF, 0xD6, 0xFF, 0xD0, 0xFF, 0xD2, 0xFF, 0xD7, 0xFF, 0xD6, 0xFF, 0xD7, 0xFF, 0xD3, 0xFF, 0xCF, 0xFF, 0xD3, 0xFF, 0xE8, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xF9, 0xFF, 0xEF, 0xFF, 0xDF, 0xFF, 0xC7, 0xFF, 0xBE, 0xFF, 0xC2, 0xFF, 0xD1, 0xFF, 0xD8, 0xFF, 0xD0, 0xFF, 0xCF, 0xFF, 0xCC, 0xFF, 0xD4, 0xFF, 0xEB, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0xFA, 0xFF, 0xF1, 0xFF, 0xE9, 0xFF, 0xDF, 0xFF, 0xD5, 0xFF, 0xCA, 0xFF, 0xC5, 0xFF, 0xC4, 0xFF, 0xC7, 0xFF, 0xD2, 0xFF, 0xDB, 0xFF, 0xE5, 0xFF, 0xEA, 0xFF, 0xEA, 0xFF, 0xE3, 0xFF, 0xD8, 0xFF, 0xD0, 0xFF, 0xC4, 0xFF, 0xB9, 0xFF, 0xB1, 0xFF, 0xAD, 0xFF, 0xB2, 0xFF, 0xBC, 0xFF, 0xCA, 0xFF, 0xD8, 0xFF, 0xE4, 0xFF, 0xEC, 0xFF, 0xEF, 0xFF, 0xE9, 0xFF, 0xDC, 0xFF, 0xD2, 0xFF, 0xC6, 0xFF, 0xBC, 0xFF, 0xB4, 0xFF, 0xAC, 0xFF, 0xB0, 0xFF, 0xB3, 0xFF, 0xB8, 0xFF, 0xC3, 0xFF, 0xC8, 0xFF, 0xCF, 0xFF, 0xD8, 0xFF, 0xDD, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xDF, 0xFF, 0xDE, 0xFF, 0xDA, 0xFF, 0xD0, 0xFF, 0xCA, 0xFF, 0xC5, 0xFF, 0xC1, 0xFF, 0xBD, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xC1, 0xFF, 0xCC, 0xFF, 0xD8, 0xFF, 0xE2, 0xFF, 0xE6, 0xFF, 0xE3, 0xFF, 0xE1, 0xFF, 0xDF, 0xFF, 0xDB, 0xFF, 0xD3, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, 0xD0, 0xFF, 0xD6, 0xFF, 0xE2, 0xFF, 0xEF, 0xFF, 0xFC, 0xFF, 0x05, 0x00, 0x08, 0x00, 0xFE, 0xFF, 0xF0, 0xFF, 0xE1, 0xFF, 0xD2, 0xFF, 0xC9, 0xFF, 0xC9, 0xFF, 0xCE, 0xFF, 0xD8, 0xFF, 0xEA, 0xFF, 0xFC, 0xFF, 0x07, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x1B, 0x00, 0x16, 0x00, 0x09, 0x00, 0xF7, 0xFF, 0xE9, 0xFF, 0xE0, 0xFF, 0xDD, 0xFF, 0xDC, 0xFF, 0xD9, 0xFF, 0xDC, 0xFF, 0xE5, 0xFF, 0xF1, 0xFF, 0xFE, 0xFF, 0x09, 0x00, 0x15, 0x00, 0x1D, 0x00, 0x1F, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x05, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0xF8, 0xFF, 0xFA, 0xFF, 0x03, 0x00, 0x0D, 0x00, 0x1A, 0x00, 0x23, 0x00, 0x29, 0x00, 0x30, 0x00, 0x36, 0x00, 0x39, 0x00, 0x35, 0x00, 0x2F, 0x00, 0x25, 0x00, 0x1A, 0x00, 0x14, 0x00, 0x11, 0x00, 0x11, 0x00, 0x13, 0x00, 0x1B, 0x00, 0x24, 0x00, 0x26, 0x00, 0x28, 0x00, 0x24, 0x00, 0x1D, 0x00, 0x18, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x14, 0x00, 0x20, 0x00, 0x2F, 0x00, 0x38, 0x00, 0x40, 0x00, 0x43, 0x00, 0x42, 0x00, 0x3C, 0x00, 0x2D, 0x00, 0x1D, 0x00, 0x0E, 0x00, 0x02, 0x00, 0xFA, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0x0B, 0x00, 0x14, 0x00, 0x21, 0x00, 0x2D, 0x00, 0x32, 0x00, 0x32, 0x00, 0x2E, 0x00, 0x27, 0x00, 0x1B, 0x00, 0x0A, 0x00, 0xFB, 0xFF, 0xF0, 0xFF, 0xEA, 0xFF, 0xE6, 0xFF, 0xE6, 0xFF, 0xE8, 0xFF, 0xEF, 0xFF, 0xF3, 0xFF, 0xFB, 0xFF, 0x0A, 0x00, 0x12, 0x00, 0x19, 0x00, 0x20, 0x00, 0x1F, 0x00, 0x20, 0x00, 0x1D, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0B, 0x00, 0x05, 0x00, 0x01, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x13, 0x00, 0x1B, 0x00, 0x1F, 0x00, 0x20, 0x00, 0x1C, 0x00, 0x11, 0x00, 0x05, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0D, 0x00, 0x19, 0x00, 0x21, 0x00, 0x23, 0x00, 0x1F, 0x00, 0x1A, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x19, 0x00, 0x14, 0x00, 0x1B, 0x00, 0x22, 0x00, 0x29, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1B, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1A, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2B, 0x00, 0x26, 0x00, 0x1F, 0x00, 0x1E, 0x00, 0x1B, 0x00, 0x16, 0x00, 0x11, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x11, 0x00, 0x17, 0x00, 0x20, 0x00, 0x2D, 0x00, 0x37, 0x00, 0x39, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1B, 0x00, 0x0E, 0x00, 0x03, 0x00, 0xFC, 0xFF, 0xF5, 0xFF, 0xF5, 0xFF, 0xFB, 0xFF, 0x02, 0x00, 0x0C, 0x00, 0x17, 0x00, 0x21, 0x00, 0x2A, 0x00, 0x2F, 0x00, 0x2C, 0x00, 0x24, 0x00, 0x1D, 0x00, 0x17, 0x00, 0x12, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x14, 0x00, 0x18, 0x00, 0x18, 0x00, 0x19, 0x00, 0x18, 0x00, 0x15, 0x00, 0x11, 0x00, 0x09, 0x00, 0xFF, 0xFF, 0xF9, 0xFF, 0xF4, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF6, 0xFF, 0xFC, 0xFF, 0x03, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x2A, 0x00, 0x32, 0x00, 0x32, 0x00, 0x2B, 0x00, 0x22, 0x00, 0x12, 0x00, 0xFE, 0xFF, 0xF0, 0xFF, 0xE3, 0xFF, 0xDA, 0xFF, 0xDD, 0xFF, 0xE6, 0xFF, 0xF6, 0xFF, 0x08, 0x00, 0x16, 0x00, 0x23, 0x00, 0x28, 0x00, 0x26, 0x00, 0x1F, 0x00, 0x12, 0x00, 0x06, 0x00, 0xFA, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x09, 0x00, 0xFF, 0xFF, 0xFA, 0xFF, 0xFD, 0xFF, 0x04, 0x00, 0x0C, 0x00, 0x16, 0x00, 0x18, 0x00, 0x15, 0x00, 0x16, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x02, 0x00, 0xFB, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0xFB, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0x01, 0x00, 0x0D, 0x00, 0x19, 0x00, 0x1F, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x21, 0x00, 0x13, 0x00, 0x05, 0x00, 0xF9, 0xFF, 0xEC, 0xFF, 0xE5, 0xFF, 0xE3, 0xFF, 0xE7, 0xFF, 0xEF, 0xFF, 0xF8, 0xFF, 0x02, 0x00, 0x09, 0x00, 0x14, 0x00, 0x19, 0x00, 0x16, 0x00, 0x0F, 0x00, 0x04, 0x00, 0xF7, 0xFF, 0xEA, 0xFF, 0xE0, 0xFF, 0xD9, 0xFF, 0xD9, 0xFF, 0xE1, 0xFF, 0xEA, 0xFF, 0xF3, 0xFF, 0xFB, 0xFF, 0x03, 0x00, 0x0B, 0x00, 0x11, 0x00, 0x15, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0B, 0x00, 0x02, 0x00, 0xFA, 0xFF, 0xF3, 0xFF, 0xF1, 0xFF, 0xF3, 0xFF, 0xF3, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0x05, 0x00, 0x0E, 0x00, 0x13, 0x00, 0x15, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xFB, 0xFF, 0xFA, 0xFF, 0xFE, 0xFF, 0x04, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x15, 0x00, 0x14, 0x00, 0x12, 0x00, 0x0C, 0x00, 0x06, 0x00, 0xFF, 0xFF, 0xF9, 0xFF, 0xF3, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x12, 0x00, 0x19, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x09, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xF5, 0xFF, 0xF1, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1B, 0x00, 0x1B, 0x00, 0x17, 0x00, 0x0E, 0x00, 0x07, 0x00, 0xFE, 0xFF, 0xF3, 0xFF, 0xEA, 0xFF, 0xE5, 0xFF, 0xE6, 0xFF, 0xEE, 0xFF, 0xF8, 0xFF, 0x04, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1C, 0x00, 0x16, 0x00, 0x0F, 0x00, 0x07, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x22, 0x00, 0x21, 0x00, 0x1E, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0F, 0x00, 0x15, 0x00, 0x1A, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x23, 0x00, 0x20, 0x00, 0x1F, 0x00, 0x1D, 0x00, 0x1A, 0x00, 0x19, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xF3, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0x01, 0x00, 0x0B, 0x00, 0x18, 0x00, 0x25, 0x00, 0x2C, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2B, 0x00, 0x23, 0x00, 0x13, 0x00, 0x04, 0x00, 0xFB, 0xFF, 0xF4, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF, 0x0A, 0x00, 0x13, 0x00, 0x1A, 0x00, 0x1C, 0x00, 0x1A, 0x00, 0x15, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x10, 0x00, 0x15, 0x00, 0x17, 0x00, 0x15, 0x00, 0x11, 0x00, 0x0A, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xF9, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0xFD, 0xFF, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x16, 0x00, 0x11, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xF2, 0xFF, 0xF0, 0xFF, 0xEE, 0xFF, 0xF1, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x12, 0x00, 0x19, 0x00, 0x1B, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x00, 0xFC, 0xFF, 0xF1, 0xFF, 0xE8, 0xFF, 0xE1, 0xFF, 0xDD, 0xFF, 0xE1, 0xFF, 0xEB, 0xFF, 0xF7, 0xFF, 0x05, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x16, 0x00, 0x0E, 0x00, 0x02, 0x00, 0xF6, 0xFF, 0xEC, 0xFF, 0xE6, 0xFF, 0xE6, 0xFF, 0xEA, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0x01, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1B, 0x00, 0x19, 0x00, 0x16, 0x00, 0x0F, 0x00, 0x07, 0x00, 0x02, 0x00, 0xF9, 0xFF, 0xF6, 0xFF, 0xF6, 0xFF, 0xF5, 0xFF, 0xFA, 0xFF, 0xFE, 0xFF, 0x05, 0x00, 0x0F, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, 0x12, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x13, 0x00, 0x15, 0x00, 0x15, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0x08, 0x00, 0x10, 0x00, 0x19, 0x00, 0x21, 0x00, 0x23, 0x00, 0x20, 0x00, 0x17, 0x00, 0x0F, 0x00, 0x03, 0x00, 0xF8, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xF2, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x16, 0x00, 0x1A, 0x00, 0x1D, 0x00, 0x1D, 0x00, 0x18, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xF3, 0xFF, 0xFB, 0xFF, 0x01, 0x00, 0x0C, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x16, 0x00, 0x10, 0x00, 0x06, 0x00, 0xFD, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xF3, 0xFF, 0xFB, 0xFF, 0x01, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x01, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xFA, 0xFF, 0xFC, 0xFF, 0x02, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x07, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xF2, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0x01, 0x00, 0x08, 0x00, 0x0F, 0x00, 0x11, 0x00, 0x13, 0x00, 0x11, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0xF9, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0xEE, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF3, 0xFF, 0xFC, 0xFF, 0x01, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x0F, 0x00, 0x12, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x00, 0x00, 0xF5, 0xFF, 0xED, 0xFF, 0xE6, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xEA, 0xFF, 0xF2, 0xFF, 0xFD, 0xFF, 0x07, 0x00, 0x10, 0x00, 0x15, 0x00, 0x17, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x04, 0x00, 0xFC, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF4, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xF9, 0xFF, 0xF6, 0xFF, 0xF4, 0xFF, 0xF8, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0x03, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x01, 0x00, 0xFA, 0xFF, 0xF4, 0xFF, 0xEB, 0xFF, 0xE9, 0xFF, 0xE8, 0xFF, 0xEB, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0x03, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xF6, 0xFF, 0xF0, 0xFF, 0xEA, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xEA, 0xFF, 0xEE, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x0A, 0x00, 0x13, 0x00, 0x14, 0x00, 0x16, 0x00, 0x14, 0x00, 0x0C, 0x00, 0x03, 0x00, 0xF8, 0xFF, 0xEF, 0xFF, 0xE6, 0xFF, 0xE3, 0xFF, 0xE5, 0xFF, 0xE9, 0xFF, 0xF2, 0xFF, 0xFD, 0xFF, 0x08, 0x00, 0x11, 0x00, 0x16, 0x00, 0x18, 0x00, 0x15, 0x00, 0x0E, 0x00, 0x05, 0x00, 0xFE, 0xFF, 0xF6, 0xFF, 0xEF, 0xFF, 0xED, 0xFF, 0xEC, 0xFF, 0xF1, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0x04, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x09, 0x00, 0x09, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0x01, 0x00, 0x09, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1C, 0x00, 0x1B, 0x00, 0x16, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xED, 0xFF, 0xE5, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xEB, 0xFF, 0xF8, 0xFF, 0x04, 0x00, 0x14, 0x00, 0x1D, 0x00, 0x24, 0x00, 0x25, 0x00, 0x1F, 0x00, 0x16, 0x00, 0x0A, 0x00, 0xFE, 0xFF, 0xF2, 0xFF, 0xE8, 0xFF, 0xE4, 0xFF, 0xE4, 0xFF, 0xE8, 0xFF, 0xEE, 0xFF, 0xF5, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x15, 0x00, 0x12, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0xF2, 0xFF, 0xF0, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF5, 0xFF, 0xFA, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x09, 0x00, 0x05, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xF5, 0xFF, 0xF4, 0xFF, 0xF6, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x02, 0x00, 0xFB, 0xFF, 0xF6, 0xFF, 0xEE, 0xFF, 0xEC, 0xFF, 0xEE, 0xFF, 0xF3, 0xFF, 0xFD, 0xFF, 0x05, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0C, 0x00, 0x02, 0x00, 0xF9, 0xFF, 0xEE, 0xFF, 0xE9, 0xFF, 0xE6, 0xFF, 0xE6, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x0B, 0x00, 0x12, 0x00, 0x16, 0x00, 0x17, 0x00, 0x13, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x00, 0x00, 0xF9, 0xFF, 0xF1, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xEF, 0xFF, 0xF1, 0xFF, 0xF7, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0C, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xF1, 0xFF, 0xEE, 0xFF, 0xEE, 0xFF, 0xF0, 0xFF, 0xF5, 0xFF, 0x00, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x14, 0x00, 0x12, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0xFA, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x04, 0x00, 0xFE, 0xFF, 0xFA, 0xFF, 0xF6, 0xFF, 0xF5, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0x02, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xF1, 0xFF, 0xEC, 0xFF, 0xEA, 0xFF, 0xED, 0xFF, 0xF2, 0xFF, 0xF9, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x14, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x05, 0x00, 0xFD, 0xFF, 0xF7, 0xFF, 0xF2, 0xFF, 0xED, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0x04, 0x00, 0x0B, 0x00, 0x12, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x04, 0x00, 0xFE, 0xFF, 0xF7, 0xFF, 0xF1, 0xFF, 0xEF, 0xFF, 0xED, 0xFF, 0xF2, 0xFF, 0xF6, 0xFF, 0xFD, 0xFF, 0x04, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFB, 0xFF, 0xF9, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0x04, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x04, 0x00, 0xFE, 0xFF, 0xF9, 0xFF, 0xF2, 0xFF, 0xEE, 0xFF, 0xEE, 0xFF, 0xEE, 0xFF, 0xF3, 0xFF, 0xFB, 0xFF, 0x04, 0x00, 0x0D, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1D, 0x00, 0x16, 0x00, 0x0A, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xE9, 0xFF, 0xE4, 0xFF, 0xE1, 0xFF, 0xE6, 0xFF, 0xEE, 0xFF, 0xFA, 0xFF, 0x07, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1B, 0x00, 0x10, 0x00, 0x07, 0x00, 0xFE, 0xFF, 0xF5, 0xFF, 0xF0, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF9, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x01, 0x00, 0xF7, 0xFF, 0xEF, 0xFF, 0xE6, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE9, 0xFF, 0xF4, 0xFF, 0x00, 0x00, 0x0B, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x1E, 0x00, 0x19, 0x00, 0x0F, 0x00, 0x02, 0x00, 0xF6, 0xFF, 0xEA, 0xFF, 0xE2, 0xFF, 0xDE, 0xFF, 0xE2, 0xFF, 0xE9, 0xFF, 0xF5, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x17, 0x00, 0x17, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x07, 0x00, 0xFE, 0xFF, 0xF7, 0xFF, 0xF2, 0xFF, 0xEE, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xF0, 0xFF, 0xF5, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x04, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF5, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFB, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0A, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xF4, 0xFF, 0xF0, 0xFF, 0xEE, 0xFF, 0xEE, 0xFF, 0xF6, 0xFF, 0xFD, 0xFF, 0x05, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1A, 0x00, 0x1A, 0x00, 0x16, 0x00, 0x0F, 0x00, 0x05, 0x00, 0xFE, 0xFF, 0xF6, 0xFF, 0xEE, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF, 0xEF, 0xFF, 0xF3, 0xFF, 0xFB, 0xFF, 0x02, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x13, 0x00, 0x14, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xF7, 0xFF, 0xF2, 0xFF, 0xF0, 0xFF, 0xED, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xF9, 0xFF, 0x01, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x05, 0x00, 0xFF, 0xFF, 0xFC, 0xFF, 0xF9, 0xFF, 0xF9, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xFB, 0xFF, 0xF9, 0xFF, 0xF9, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x05, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0xF2, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xF0, 0xFF, 0xEF, 0xFF, 0xEE, 0xFF, 0xEC, 0xFF, 0xF1, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1A, 0x00, 0x17, 0x00, 0x11, 0x00, 0x09, 0x00, 0x01, 0x00, 0xF6, 0xFF, 0xEE, 0xFF, 0xEB, 0xFF, 0xE8, 0xFF, 0xEB, 0xFF, 0xF1, 0xFF, 0xFB, 0xFF, 0x06, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x16, 0x00, 0x15, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x04, 0x00, 0xFD, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x03, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xFA, 0xFF, 0xFC, 0xFF, 0xFB, 0xFF, 0xFD, 0xFF, 0x02, 0x00, 0x06, 0x00, 0x0B, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xFB, 0xFF, 0xF8, 0xFF, 0xF4, 0xFF, 0xF3, 0xFF, 0xF3, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0x03, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x14, 0x00, 0x18, 0x00, 0x16, 0x00, 0x10, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0xF4, 0xFF, 0xE9, 0xFF, 0xE2, 0xFF, 0xE0, 0xFF, 0xE2, 0xFF, 0xEA, 0xFF, 0xF5, 0xFF, 0x03, 0x00, 0x0F, 0x00, 0x19, 0x00, 0x1F, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xF4, 0xFF, 0xEA, 0xFF, 0xE3, 0xFF, 0xE1, 0xFF, 0xE4, 0xFF, 0xEC, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xF4, 0xFF, 0xF1, 0xFF, 0xF2, 0xFF, 0xF4, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xF9, 0xFF, 0xF5, 0xFF, 0xF4, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0x04, 0x00, 0x0D, 0x00, 0x12, 0x00, 0x18, 0x00, 0x17, 0x00, 0x13, 0x00, 0x0C, 0x00, 0x02, 0x00, 0xF8, 0xFF, 0xED, 0xFF, 0xE8, 0xFF, 0xE5, 0xFF, 0xE7, 0xFF, 0xEF, 0xFF, 0xF7, 0xFF, 0x04, 0x00, 0x0F, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x20, 0x00, 0x1D, 0x00, 0x13, 0x00, 0x0A, 0x00, 0x02, 0x00, 0xF7, 0xFF, 0xEF, 0xFF, 0xEB, 0xFF, 0xE9, 0xFF, 0xEB, 0xFF, 0xF1, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x0E, 0x00, 0x13, 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0xF4, 0xFF, 0xF6, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x05, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x06, 0x00, 0x07, 0x00, 0x05, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0xFA, 0xFF, 0xF4, 0xFF, 0xF0, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0A, 0x00, 0x02, 0x00, 0xFD, 0xFF, 0xF6, 0xFF, 0xF2, 0xFF, 0xEE, 0xFF, 0xED, 0xFF, 0xEF, 0xFF, 0xF2, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x09, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0xF6, 0xFF, 0xF2, 0xFF, 0xED, 0xFF, 0xEC, 0xFF, 0xEE, 0xFF, 0xF3, 0xFF, 0xFC, 0xFF, 0x01, 0x00, 0x08, 0x00, 0x0F, 0x00, 0x11, 0x00, 0x12, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x04, 0x00, 0xFB, 0xFF, 0xF5, 0xFF, 0xEF, 0xFF, 0xED, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xFC, 0xFF, 0x02, 0x00, 0x07, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xF9, 0xFF, 0xF5, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0x05, 0x00, 0x0B, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x13, 0x00, 0x10, 0x00, 0x09, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xF9, 0xFF, 0xF4, 0xFF, 0xF2, 0xFF, 0xF2, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1A, 0x00, 0x16, 0x00, 0x11, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xEE, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE9, 0xFF, 0xEF, 0xFF, 0xF8, 0xFF, 0x04, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x19, 0x00, 0x17, 0x00, 0x11, 0x00, 0x0A, 0x00, 0x01, 0x00, 0xF8, 0xFF, 0xEF, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF2, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x05, 0x00, 0x01, 0x00, 0xFC, 0xFF, 0xF6, 0xFF, 0xF4, 0xFF, 0xF4, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF7, 0xFF, 0xF5, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xF3, 0xFF, 0xEE, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF, 0xEE, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0x08, 0x00, 0x12, 0x00, 0x16, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0xF5, 0xFF, 0xEA, 0xFF, 0xE5, 0xFF, 0xE3, 0xFF, 0xE6, 0xFF, 0xEE, 0xFF, 0xF8, 0xFF, 0x04, 0x00, 0x0F, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x18, 0x00, 0x0F, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xF6, 0xFF, 0xF1, 0xFF, 0xEE, 0xFF, 0xF0, 0xFF, 0xF2, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0B, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x07, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0x03, 0x00, 0x0A, 0x00, 0x0E, 0x00, 0x11, 0x00, 0x12, 0x00, 0x11, 0x00, 0x0C, 0x00, 0x06, 0x00, 0xFD, 0xFF, 0xF4, 0xFF, 0xEE, 0xFF, 0xE9, 0xFF, 0xEB, 0xFF, 0xEE, 0xFF, 0xF4, 0xFF, 0xFD, 0xFF, 0x06, 0x00, 0x0D, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x11, 0x00, 0x0A, 0x00, 0x02, 0x00, 0xFA, 0xFF, 0xF3, 0xFF, 0xEF, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF, 0xEF, 0xFF, 0xF4, 0xFF, 0xFA, 0xFF, 0x00, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xF5, 0xFF, 0xF0, 0xFF, 0xEF, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF6, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0xF4, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x05, 0x00, 0x05, 0x00, 0x01, 0x00, 0xFD, 0xFF, 0xF9, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0x03, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0A, 0x00, 0x04, 0x00, 0xFC, 0xFF, 0xF5, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xED, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xFD, 0xFF, 0x07, 0x00, 0x0E, 0x00, 0x12, 0x00, 0x13, 0x00, 0x13, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF7, 0xFF, 0xF4, 0xFF, 0xF4, 0xFF, 0xF3, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, 0x13, 0x00, 0x0C, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xF6, 0xFF, 0xF4, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0B, 0x00, 0x07, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xFA, 0xFF, 0xF9, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x08, 0x00, 0x05, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0xF3, 0xFF, 0xF2, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0D, 0x00, 0x05, 0x00, 0xFE, 0xFF, 0xF6, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xEC, 0xFF, 0xEE, 0xFF, 0xF0, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0x04, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x01, 0x00, 0xFB, 0xFF, 0xF5, 0xFF, 0xF0, 0xFF, 0xEB, 0xFF, 0xE7, 0xFF, 0xEA, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x14, 0x00, 0x15, 0x00, 0x13, 0x00, 0x0E, 0x00, 0x04, 0x00, 0xFB, 0xFF, 0xF4, 0xFF, 0xEB, 0xFF, 0xE8, 0xFF, 0xEA, 0xFF, 0xED, 0xFF, 0xF4, 0xFF, 0xFC, 0xFF, 0x02, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x12, 0x00, 0x11, 0x00, 0x0B, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xF9, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xFD, 0xFF, 0xFD, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xF1, 0xFF, 0xF0, 0xFF, 0xEE, 0xFF, 0xF0, 0xFF, 0xF6, 0xFF, 0xFE, 0xFF, 0x08, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x17, 0x00, 0x10, 0x00, 0x07, 0x00, 0xFA, 0xFF, 0xF2, 0xFF, 0xE8, 0xFF, 0xE3, 0xFF, 0xE7, 0xFF, 0xEB, 0xFF, 0xF3, 0xFF, 0xFE, 0xFF, 0x08, 0x00, 0x12, 0x00, 0x16, 0x00, 0x19, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0B, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0xF4, 0xFF, 0xF1, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF3, 0xFF, 0xF6, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF8, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF9, 0xFF, 0xFD, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x09, 0x00, 0x09, 0x00, 0x07, 0x00, 0x03, 0x00, 0xFC, 0xFF, 0xF6, 0xFF, 0xF3, 0xFF, 0xEC, 0xFF, 0xEE, 0xFF, 0xF3, 0xFF, 0xF7, 0xFF, 0x01, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x14, 0x00, 0x13, 0x00, 0x12, 0x00, 0x0A, 0x00, 0x03, 0x00, 0xF8, 0xFF, 0xF1, 0xFF, 0xED, 0xFF, 0xEA, 0xFF, 0xEC, 0xFF, 0xF2, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x07, 0x00, 0x0D, 0x00, 0x10, 0x00, 0x12, 0x00, 0x11, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF8, 0xFF, 0xF5, 0xFF, 0xF3, 0xFF, 0xF5, 0xFF, 0xF5, 0xFF, 0xF8, 0xFF, 0xFE, 0xFF, 0x02, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0F, 0x00, 0x12, 0x00, 0x10, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF9, 0xFF, 0xF8, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x14, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x03, 0x00, 0xFB, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xF1, 0xFF, 0xF6, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x0A, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xF4, 0xFF, 0xF1, 0xFF, 0xEF, 0xFF, 0xF1, 0xFF, 0xF4, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x08, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00, 0xFC, 0xFF, 0xF9, 0xFF, 0xF6, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF9, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFC, 0xFF, 0xF9, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xFE, 0xFF, 0x4C, 0x49, 0x53, 0x54, 0x4E, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x46, 0x4F, 0x49, 0x43, 0x52, 0x44, 0x0C, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30, 0x36, 0x2D, 0x31, 0x32, 0x2D, 0x31, 0x34, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x47, 0x10, 0x00, 0x00, 0x00, 0x4B, 0x65, 0x6C, 0x6C, 0x79, 0x20, 0x54, 0x68, 0x6F, 0x72, 0x6E, 0x74, 0x6F, 0x6E, 0x00, 0x00, 0x49, 0x53, 0x46, 0x54, 0x16, 0x00, 0x00, 0x00, 0x53, 0x6F, 0x6E, 0x79, 0x20, 0x53, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x46, 0x6F, 0x72, 0x67, 0x65, 0x20, 0x38, 0x2E, 0x30, 0x00, 0x00}; +#endif +``` + +`SpyCustom/sdk/AnalogCode.h`: + +```h +#ifndef ANALOGCODE_H +#define ANALOGCODE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#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, +}; + + +#endif +``` + +`SpyCustom/sdk/BuildGroup.h`: + +```h +#ifndef VGUI_BUILDGROUP_H +#define VGUI_BUILDGROUP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utlsymbol.h" +#include "vgui.h" +#include "Dar.h" +#include "Cursor.h" +#include "IScheme.h" +#include "Controls.h" +#include "PHandle.h" +#include "utlhandletable.h" + +class KeyValues; + +namespace vgui +{ + + class BuildGroup + { + DECLARE_HANDLES(BuildGroup, 20); + + public: + BuildGroup(Panel* parentPanel, Panel* contextPanel); + ~BuildGroup(); + + virtual void SetEnabled(bool state); + + virtual bool IsEnabled(); + + virtual Panel* GetCurrentPanel(); + + virtual void LoadControlSettings(const char* controlResourceName, const char* pathID = NULL, KeyValues* pPreloadedKeyValues = NULL, KeyValues* pConditions = NULL); + + void ReloadControlSettings(); + + void ChangeControlSettingsFile(const char* controlResourceName); + + virtual bool SaveControlSettings(); + + virtual void ApplySettings(KeyValues* resourceData); + + virtual void GetSettings(KeyValues* resourceData); + + virtual void RemoveSettings(); + + void GetNewFieldName(char* newFieldName, int newFieldNameSize, Panel* newPanel); + + Panel* FieldNameTaken(const char* fieldName); + + Panel* NewControl(KeyValues* controlKeys, int x = 0, int y = 0); + Panel* NewControl(const char* name, int x = 0, int y = 0); + + virtual void SetContextPanel(Panel* contextPanel); + + virtual Panel* GetContextPanel(); + + CUtlVector* GetPanelList(); + + virtual const char* GetResourceName(void) { return m_pResourceName; } + + void PanelAdded(Panel* panel); + void PanelRemoved(Panel* panel); + + virtual bool MousePressed(MouseCode code, Panel* panel); + virtual bool MouseReleased(MouseCode code, Panel* panel); + + virtual CUtlVector* GetControlGroup(); + + virtual void ToggleRulerDisplay(); + + virtual void SetRulerLabelsVisible(bool state); + + virtual bool HasRulersOn(); + + virtual void DrawRulers(); + + void RegisterControlSettingsFile(const char* controlResourceName, const char* pathID = NULL); + + int GetRegisteredControlSettingsFileCount(); + const char* GetRegisteredControlSettingsFileByIndex(int index); + + KeyValues* GetDialogVariables(); + + void ProcessConditionalKeys(KeyValues* pDat, KeyValues* pConditions); + + protected: + virtual bool CursorMoved(int x, int y, Panel* panel); + virtual bool MouseDoublePressed(MouseCode code, Panel* panel); + virtual bool KeyCodeTyped(KeyCode code, Panel* panel); + virtual bool KeyCodeReleased(KeyCode code, Panel* panel); + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual bool KeyTyped(wchar_t unichar, Panel* panel); + + virtual HCursor GetCursor(Panel* panel); + + private: + void ApplySnap(Panel* panel); + Panel* CreateBuildDialog(); + void ActivateBuildDialog(); + void DeleteAllControlsCreatedByControlSettingsFile(); + + bool _enabled; + int _snapX; + int _snapY; + HCursor _cursor_sizenwse; + HCursor _cursor_sizenesw; + HCursor _cursor_sizewe; + HCursor _cursor_sizens; + HCursor _cursor_sizeall; + bool _dragging; + MouseCode _dragMouseCode; + int _dragStartPanelPos[2]; + int _dragStartCursorPos[2]; + int _dragStartPanelSize[2]; + Panel* _currentPanel; + CUtlVector _panelDar; + char* m_pResourceName; + char* m_pResourcePathID; + PHandle m_hBuildDialog; + Panel* m_pBuildContext; + Panel* m_pParentPanel; + CUtlVector _controlGroup; + CUtlVector _groupDeltaX; + CUtlVector _groupDeltaY; + Label* _rulerNumber[4]; + bool _showRulers; + CUtlVector m_RegisteredControlSettingsFiles; + + friend class Panel; + }; + + + typedef CUtlHandle HBuildGroup; + + +} + +#endif +``` + +`SpyCustom/sdk/Button.h`: + +```h +#ifndef BUTTON_H +#define BUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "Dar.h" +#include "Color.h" +#include "Label.h" +#include "MouseCode.h" + +namespace vgui +{ + + class Button : public Label + { + DECLARE_CLASS_SIMPLE(Button, Label); + + public: + Button(Panel* parent, const char* panelName, const char* text, Panel* pActionSignalTarget = NULL, const char* pCmd = NULL); + Button(Panel* parent, const char* panelName, const wchar_t* text, Panel* pActionSignalTarget = NULL, const char* pCmd = NULL); + ~Button(); + private: + void Init(); + public: + virtual void SetArmed(bool state); + virtual bool IsArmed(void); + + virtual bool IsDepressed(); + virtual void ForceDepressed(bool state); + virtual void RecalculateDepressedState(void); + + virtual void SetSelected(bool state); + virtual bool IsSelected(void); + + virtual void SetBlink(bool state); + virtual bool IsBlinking(void); + + virtual void SetUseCaptureMouse(bool state); + virtual bool IsUseCaptureMouseEnabled(void); + + MESSAGE_FUNC(DoClick, "PressButton"); + MESSAGE_FUNC(OnHotkey, "Hotkey") + { + DoClick(); + } + + virtual void SetMouseClickEnabled(MouseCode code, bool state); + virtual bool IsMouseClickEnabled(MouseCode code); + enum ActivationType_t + { + ACTIVATE_ONPRESSEDANDRELEASED, + ACTIVATE_ONPRESSED, + ACTIVATE_ONRELEASED, + }; + virtual void SetButtonActivationType(ActivationType_t activationType); + + virtual void FireActionSignal(void); + virtual void PerformLayout(); + + virtual bool RequestInfo(KeyValues* data); + + virtual bool CanBeDefaultButton(void); + + MESSAGE_FUNC_INT(SetAsDefaultButton, "SetAsDefaultButton", state); + MESSAGE_FUNC_INT(SetAsCurrentDefaultButton, "SetAsCurrentDefaultButton", state); + + virtual void OnSetFocus(); + virtual void OnKillFocus(); + + virtual void SetButtonBorderEnabled(bool state); + + virtual void SetDefaultColor(Color fgColor, Color bgColor); + virtual void SetArmedColor(Color fgColor, Color bgColor); + virtual void SetSelectedColor(Color fgColor, Color bgColor); + virtual void SetDepressedColor(Color fgColor, Color bgColor); + virtual void SetBlinkColor(Color fgColor); + + virtual Color GetButtonFgColor(); + virtual Color GetButtonBgColor(); + + Color GetButtonDefaultFgColor() { return _defaultFgColor; } + Color GetButtonDefaultBgColor() { return _defaultBgColor; } + + Color GetButtonArmedFgColor() { return _armedFgColor; } + Color GetButtonArmedBgColor() { return _armedBgColor; } + + Color GetButtonSelectedFgColor() { return _selectedFgColor; } + Color GetButtonSelectedBgColor() { return _selectedBgColor; } + + Color GetButtonDepressedFgColor() { return _depressedFgColor; } + Color GetButtonDepressedBgColor() { return _depressedBgColor; } + + virtual void SetDefaultBorder(IBorder* border); + virtual void SetDepressedBorder(IBorder* border); + virtual void SetKeyFocusBorder(IBorder* border); + + virtual void SetCommand(const char* command); + virtual void SetCommand(KeyValues* message); + + void SetArmedSound(const char* sound); + void SetDepressedSound(const char* sound); + void SetReleasedSound(const char* sound); + + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + virtual void SizeToContents(); + + virtual KeyValues* GetCommand(); + + bool IsDrawingFocusBox(); + void DrawFocusBox(bool bEnable); + + bool ShouldPaint() { return _paint; } + void SetShouldPaint(bool paint) { _paint = paint; } + + virtual void ApplySettings(KeyValues* inResourceData); + virtual void NavigateTo(); + virtual void NavigateFrom(); + + protected: + virtual void DrawFocusBorder(int tx0, int ty0, int tx1, int ty1); + + virtual void Paint(void); + virtual IBorder* GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + virtual void ApplySchemeSettings(IScheme* pScheme); + MESSAGE_FUNC_INT(OnSetState, "SetState", state); + + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + virtual void OnKeyCodePressed(KeyCode code); + virtual void OnKeyCodeReleased(KeyCode code); + + virtual void GetSettings(KeyValues* outResourceData); + virtual const char* GetDescription(void); + + KeyValues* GetActionMessage(); + void PlayButtonReleasedSound(); + + protected: + enum ButtonFlags_t + { + ARMED = 0x0001, + DEPRESSED = 0x0002, + FORCE_DEPRESSED = 0x0004, + BUTTON_BORDER_ENABLED = 0x0008, + USE_CAPTURE_MOUSE = 0x0010, + BUTTON_KEY_DOWN = 0x0020, + DEFAULT_BUTTON = 0x0040, + SELECTED = 0x0080, + DRAW_FOCUS_BOX = 0x0100, + BLINK = 0x0200, + ALL_FLAGS = 0xFFFF, + }; + + CUtlFlags< unsigned short > _buttonFlags; + int _mouseClickMask; + KeyValues* _actionMessage; + ActivationType_t _activationType; + + IBorder* _defaultBorder; + IBorder* _depressedBorder; + IBorder* _keyFocusBorder; + + Color _defaultFgColor, _defaultBgColor; + Color _armedFgColor, _armedBgColor; + Color _selectedFgColor, _selectedBgColor; + Color _depressedFgColor, _depressedBgColor; + Color _keyboardFocusColor; + Color _blinkFgColor; + + bool _paint; + + unsigned short m_sArmedSoundName, m_sDepressedSoundName, m_sReleasedSoundName; + bool m_bSelectionStateSaved; + bool m_bStaySelectedOnClick; + }; + +} + +#endif +``` + +`SpyCustom/sdk/ButtonCode.h`: + +```h +#ifndef BUTTONCODE_H +#define BUTTONCODE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "InputEnums.h" +#include "mathlib.h" + +enum +{ + JOYSTICK_MAX_BUTTON_COUNT = 32, + JOYSTICK_POV_BUTTON_COUNT = 4, + JOYSTICK_AXIS_BUTTON_COUNT = MAX_JOYSTICK_AXES * 2, +}; + +#define JOYSTICK_BUTTON_INTERNAL( _joystick, _button ) ( JOYSTICK_FIRST_BUTTON + ((_joystick) * JOYSTICK_MAX_BUTTON_COUNT) + (_button) ) +#define JOYSTICK_POV_BUTTON_INTERNAL( _joystick, _button ) ( JOYSTICK_FIRST_POV_BUTTON + ((_joystick) * JOYSTICK_POV_BUTTON_COUNT) + (_button) ) +#define JOYSTICK_AXIS_BUTTON_INTERNAL( _joystick, _button ) ( JOYSTICK_FIRST_AXIS_BUTTON + ((_joystick) * JOYSTICK_AXIS_BUTTON_COUNT) + (_button) ) + +#define JOYSTICK_BUTTON( _joystick, _button ) ( (ButtonCode_t)JOYSTICK_BUTTON_INTERNAL( _joystick, _button ) ) +#define JOYSTICK_POV_BUTTON( _joystick, _button ) ( (ButtonCode_t)JOYSTICK_POV_BUTTON_INTERNAL( _joystick, _button ) ) +#define JOYSTICK_AXIS_BUTTON( _joystick, _button ) ( (ButtonCode_t)JOYSTICK_AXIS_BUTTON_INTERNAL( _joystick, _button ) ) + +enum ButtonCode_t +{ + BUTTON_CODE_INVALID = -1, + BUTTON_CODE_NONE = 0, + + KEY_FIRST = 0, + + KEY_NONE = KEY_FIRST, + KEY_0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_PAD_0, + KEY_PAD_1, + KEY_PAD_2, + KEY_PAD_3, + KEY_PAD_4, + KEY_PAD_5, + KEY_PAD_6, + KEY_PAD_7, + KEY_PAD_8, + KEY_PAD_9, + KEY_PAD_DIVIDE, + KEY_PAD_MULTIPLY, + KEY_PAD_MINUS, + KEY_PAD_PLUS, + KEY_PAD_ENTER, + KEY_PAD_DECIMAL, + KEY_LBRACKET, + KEY_RBRACKET, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_BACKQUOTE, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_BACKSLASH, + KEY_MINUS, + KEY_EQUAL, + KEY_ENTER, + KEY_SPACE, + KEY_BACKSPACE, + KEY_TAB, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_ESCAPE, + KEY_SCROLLLOCK, + KEY_INSERT, + KEY_DELETE, + KEY_HOME, + KEY_END, + KEY_PAGEUP, + KEY_PAGEDOWN, + KEY_BREAK, + KEY_LSHIFT, + KEY_RSHIFT, + KEY_LALT, + KEY_RALT, + KEY_LCONTROL, + KEY_RCONTROL, + KEY_LWIN, + KEY_RWIN, + KEY_APP, + KEY_UP, + KEY_LEFT, + KEY_DOWN, + KEY_RIGHT, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_CAPSLOCKTOGGLE, + KEY_NUMLOCKTOGGLE, + KEY_SCROLLLOCKTOGGLE, + + KEY_LAST = KEY_SCROLLLOCKTOGGLE, + KEY_COUNT = KEY_LAST - KEY_FIRST + 1, + + MOUSE_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, + +#if !defined ( _X360 ) + 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, +#endif + + 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, +}; + +inline bool IsAlpha(ButtonCode_t code) +{ + return (code >= KEY_A) && (code <= KEY_Z); +} + +inline bool IsAlphaNumeric(ButtonCode_t code) +{ + return (code >= KEY_0) && (code <= KEY_Z); +} + +inline bool IsSpace(ButtonCode_t code) +{ + return (code == KEY_ENTER) || (code == KEY_TAB) || (code == KEY_SPACE); +} + +inline bool IsKeypad(ButtonCode_t code) +{ + return (code >= MOUSE_FIRST) && (code <= KEY_PAD_DECIMAL); +} + +inline bool IsPunctuation(ButtonCode_t code) +{ + return (code >= KEY_0) && (code <= KEY_SPACE) && !IsAlphaNumeric(code) && !IsSpace(code) && !IsKeypad(code); +} + +inline bool IsKeyCode(ButtonCode_t code) +{ + return (code >= KEY_FIRST) && (code <= KEY_LAST); +} + +inline bool IsMouseCode(ButtonCode_t code) +{ + return (code >= MOUSE_FIRST) && (code <= MOUSE_LAST); +} + +inline bool IsNovintCode(ButtonCode_t code) +{ +#if !defined ( _X360 ) + return ((code >= NOVINT_FIRST) && (code <= NOVINT_LAST)); +#else + return false; +#endif +} + +inline bool IsNovintButtonCode(ButtonCode_t code) +{ +#if !defined ( _X360 ) + return IsNovintCode(code); +#else + return false; +#endif +} + +inline bool IsJoystickCode(ButtonCode_t code) +{ + return (((code >= JOYSTICK_FIRST) && (code <= JOYSTICK_LAST)) || IsNovintCode(code)); +} + +inline bool IsJoystickButtonCode(ButtonCode_t code) +{ + return (((code >= JOYSTICK_FIRST_BUTTON) && (code <= JOYSTICK_LAST_BUTTON)) || IsNovintButtonCode(code)); +} + +inline bool IsJoystickPOVCode(ButtonCode_t code) +{ + return (code >= JOYSTICK_FIRST_POV_BUTTON) && (code <= JOYSTICK_LAST_POV_BUTTON); +} + +inline bool IsJoystickAxisCode(ButtonCode_t code) +{ + return (code >= JOYSTICK_FIRST_AXIS_BUTTON) && (code <= JOYSTICK_LAST_AXIS_BUTTON); +} + +inline ButtonCode_t GetBaseButtonCode(ButtonCode_t code) +{ + if (IsJoystickButtonCode(code)) + { + int offset = (code - JOYSTICK_FIRST_BUTTON) % JOYSTICK_MAX_BUTTON_COUNT; + return (ButtonCode_t)(JOYSTICK_FIRST_BUTTON + offset); + } + + if (IsJoystickPOVCode(code)) + { + int offset = (code - JOYSTICK_FIRST_POV_BUTTON) % JOYSTICK_POV_BUTTON_COUNT; + return (ButtonCode_t)(JOYSTICK_FIRST_POV_BUTTON + offset); + } + + if (IsJoystickAxisCode(code)) + { + int offset = (code - JOYSTICK_FIRST_AXIS_BUTTON) % JOYSTICK_AXIS_BUTTON_COUNT; + return (ButtonCode_t)(JOYSTICK_FIRST_AXIS_BUTTON + offset); + } + + return code; +} + +inline int GetJoystickForCode(ButtonCode_t code) +{ + if (!IsJoystickCode(code)) + return 0; + + if (IsJoystickButtonCode(code)) + { + int offset = (code - JOYSTICK_FIRST_BUTTON) / JOYSTICK_MAX_BUTTON_COUNT; + return offset; + } + if (IsJoystickPOVCode(code)) + { + int offset = (code - JOYSTICK_FIRST_POV_BUTTON) / JOYSTICK_POV_BUTTON_COUNT; + return offset; + } + if (IsJoystickAxisCode(code)) + { + int offset = (code - JOYSTICK_FIRST_AXIS_BUTTON) / JOYSTICK_AXIS_BUTTON_COUNT; + return offset; + } + + return 0; +} + +inline ButtonCode_t ButtonCodeToJoystickButtonCode(ButtonCode_t code, int nDesiredJoystick) +{ + if (!IsJoystickCode(code) || nDesiredJoystick == 0) + return code; + + nDesiredJoystick = ::clamp(nDesiredJoystick, 0, MAX_JOYSTICKS - 1); + + code = GetBaseButtonCode(code); + + if (IsJoystickButtonCode(code)) + { + int nOffset = code - JOYSTICK_FIRST_BUTTON; + return JOYSTICK_BUTTON(nDesiredJoystick, nOffset); + } + + if (IsJoystickPOVCode(code)) + { + int nOffset = code - JOYSTICK_FIRST_POV_BUTTON; + return JOYSTICK_POV_BUTTON(nDesiredJoystick, nOffset); + } + + if (IsJoystickAxisCode(code)) + { + int nOffset = code - JOYSTICK_FIRST_AXIS_BUTTON; + return JOYSTICK_AXIS_BUTTON(nDesiredJoystick, nOffset); + } + + return code; +} + +#endif +``` + +`SpyCustom/sdk/CGameUI.h`: + +```h +#pragma once + +class ECommandMsgBoxSlot; +class KeyValues; +class IPanel; + +class CGameUI { +public: + virtual void Initialize(void* (*)(char const*, int*)) = 0; + virtual void PostInit(void) = 0; + virtual void Connect(void* (*)(char const*, int*)) = 0; + virtual void Start(void) = 0; + virtual void Shutdown(void) = 0; + virtual void RunFrame(void) = 0; + virtual void OnGameUIActivated(void) = 0; + virtual void OnGameUIHidden(void) = 0; + virtual void OLD_OnConnectToServer(char const*, int, int) = 0; + virtual void OnDisconnectFromServer_OLD(unsigned char, char const*) = 0; + virtual void OnLevelLoadingStarted(char const*, bool) = 0; + virtual void OnLevelLoadingFinished(bool, char const*, char const*) = 0; + virtual void StartLoadingScreenForCommand(char const*) = 0; + virtual void StartLoadingScreenForKeyValues(KeyValues*) = 0; + virtual void UpdateProgressBar(float, char const*, bool) = 0; + virtual void SetShowProgressText(bool) = 0; + virtual void UpdateSecondaryProgressBar(float, wchar_t const*) = 0; + virtual void SetProgressLevelName(char const*) = 0; + virtual void ShowMessageDialog(unsigned int, IPanel*) = 0; + virtual void ShowMessageDialog(char const*, char const*) = 0; + virtual void CreateCommandMsgBox(char const*, char const*, bool, bool, char const*, char const*, char const*, char const*, char const*) = 0; + //virtual void CreateCommandMsgBox(char const*, char const*, bool, bool, char const*, char const*, char const*, char const*) = 0; + virtual void CreateCommandMsgBoxInSlot(ECommandMsgBoxSlot, char const*, char const*, bool, bool, char const*, char const*, char const*, char const*) = 0; + virtual void SetLoadingBackgroundDialog(unsigned long long) = 0; + virtual void OnConnectToServer2(char const*, int, int, int) = 0; + virtual void SetProgressOnStart(void) = 0; + virtual void OnDisconnectFromServer(unsigned char) = 0; + virtual void NeedConnectionProblemWaitScreen(void) = 0; + virtual void ShowPasswordUI(char const*) = 0; + virtual void LoadingProgressWantsIsolatedRender(bool) = 0; + virtual bool IsPlayingFullScreenVideo(void) = 0; + virtual bool IsTransitionEffectEnabled(void) = 0; + virtual bool IsInLevel(void) = 0; + virtual void RestoreTopLevelMenu(void) = 0; + virtual void StartProgressBar(void) = 0; + virtual void ContinueProgressBar(float, bool) = 0; + virtual void StopProgressBar(bool, char const*, char const*) = 0; + virtual void SetProgressBarStatusText(char const*, bool) = 0; + virtual void SetSecondaryProgressBar(float) = 0; + virtual void SetSecondaryProgressBarText(wchar_t const*) = 0; + +}; +``` + +`SpyCustom/sdk/CheckButton.h`: + +```h +#ifndef CHECKBUTTON_H +#define CHECKBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "ToggleButton.h" +#include "TextImage.h" + +namespace vgui +{ + + class TextImage; + + class CheckImage : public TextImage + { + public: + CheckImage(CheckButton* CheckButton) : TextImage("g") + { + _CheckButton = CheckButton; + + SetSize(20, 13); + } + + virtual void Paint(); + + virtual void SetColor(Color color) + { + _borderColor1 = color; + _borderColor2 = color; + _checkColor = color; + } + + Color _borderColor1; + Color _borderColor2; + Color _checkColor; + + Color _bgColor; + + private: + CheckButton* _CheckButton; + }; + + class CheckButton : public ToggleButton + { + DECLARE_CLASS_SIMPLE(CheckButton, ToggleButton); + + public: + CheckButton(Panel* parent, const char* panelName, const char* text); + ~CheckButton(); + + virtual void SetSelected(bool state); + + virtual void SetCheckButtonCheckable(bool state); + virtual bool IsCheckButtonCheckable() const { return m_bCheckButtonCheckable; } + + Color GetDisabledFgColor() { return _disabledFgColor; } + Color GetDisabledBgColor() { return _disabledBgColor; } + + CheckImage* GetCheckImage() { return _checkBoxImage; } + + virtual void SetHighlightColor(Color fgColor); + + protected: + virtual void ApplySchemeSettings(IScheme* pScheme); + MESSAGE_FUNC_PTR(OnCheckButtonChecked, "CheckButtonChecked", panel); + virtual Color GetButtonFgColor(); + + virtual IBorder* GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + + private: + enum { CHECK_INSET = 6 }; + bool m_bCheckButtonCheckable; + CheckImage* _checkBoxImage; + Color _disabledFgColor; + Color _disabledBgColor; + Color _highlightFgColor; + }; + +} + +#endif +``` + +`SpyCustom/sdk/ClientNetMessage.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CLIENTNETMESSAGE_H +#define CLIENTNETMESSAGE_H +#ifdef _WIN32 +#pragma once +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif + +#include "inetmessage.h" +#include "protocol.h" +#include "checksum_crc.h" + +class bf_read; +class bf_write; + +#define DECLARE_CLIENTNETMESSAGE( msgtype ) \ + public: \ + int ReadFromBuffer( bf_read * buffer ); \ + int WriteToBuffer( bf_write * buffer ); \ + void Clear(); \ + const char *ToString(); \ + static int GetType() { return msgtype; }; \ + static const char *GetName() { return #msgtype; }; + +class CNetMessage : public INetMessage +{ +public: + CNetMessage() { m_bReliable = 0; m_bOwnData = false; }; + virtual ~CNetMessage() {}; + + void SetReliable( bool state = true) {m_bReliable = state;}; + bool IsReliable() { return m_bReliable; }; + bool IsConnectionless() { return false;}; + + virtual const char *ToString() { return "Unknown CNetMessage"; }; + +public: + + bool m_bReliable; // true if message should be send reliable + bool m_bOwnData; // true if message object uses dynamic allocated memory +}; + +class CLC_SendFile : public CNetMessage +{ + DECLARE_CLIENTNETMESSAGE(net_File); + + CLC_SendFile(CRC32_t fileCRC) + { + m_bReliable = true; + m_bOwnData = false; + m_FileCRC = fileCRC; + } + +public: + CRC32_t m_FileCRC; // CRC of file to send +}; + +class CLC_Move : public CNetMessage +{ + DECLARE_CLIENTNETMESSAGE( clc_Move ); + + CLC_Move( int numBackup, int numNew, int length, unsigned char * data) + { + m_bReliable = true; + m_bOwnData = false; + m_nNumBackupCommands = numBackup; + m_nNumNewCommands = numNew; + m_nLength = length; // in bits + m_Data = data; + } + +public: + int m_nNumBackupCommands; + int m_nNumNewCommands; + int m_nLength; + unsigned char *m_Data; +}; + + + +class CLC_StringCmd : public CNetMessage +{ + DECLARE_CLIENTNETMESSAGE(net_StringCmd); + + CLC_StringCmd(const char *command) + { + Assert( command ); + m_szClientCommand = (char*)command; + m_bReliable = true; + m_bOwnData = false; + }; + +public: + + char *m_szClientCommand; + +}; + +class CLC_Delta : public CNetMessage +{ + //DECLARE_CLIENTNETMESSAGE( clc_Delta ); + + CLC_Delta( int deltaSequeenceNr ); + +public: + int m_nSequenceNumber; +}; + +class CLC_VoiceData : public CNetMessage +{ + DECLARE_CLIENTNETMESSAGE(clc_VoiceData); + + CLC_VoiceData( unsigned char *data, int length ) + { + Assert( data ); + m_Data = data; + m_nLength = length; + m_bReliable = false; + m_bOwnData = false; + }; + +public: + + int m_nLength; + unsigned char *m_Data; +}; + + +#define MAX_OSPATH 260 + + +class NET_SetConVar : public CNetMessage +{ + DECLARE_CLIENTNETMESSAGE(net_SetConVar); + + int GetGroup() const { return INetChannelInfo::STRINGCMD; } + + NET_SetConVar() {} + NET_SetConVar(const char* name, const char* value) + { + cvar_t cvar; + strncpy(cvar.name, name, MAX_OSPATH); + strncpy(cvar.value, value, MAX_OSPATH); + m_ConVars.AddToTail(cvar); + } + +public: + + typedef struct cvar_s + { + char name[MAX_OSPATH]; + char value[MAX_OSPATH]; + } cvar_t; + + CUtlVector m_ConVars; +}; + + +#endif // CLIENTNETMESSAGE_H + +``` + +`SpyCustom/sdk/Color.h`: + +```h +#ifndef COLOR_H +#define COLOR_H + +#ifdef _WIN32 +#pragma once +#endif + +class Color +{ +public: + Color() + { + *((int*)this) = 0; + } + Color(int _r, int _g, int _b) + { + SetColor(_r, _g, _b, 0); + } + Color(int _r, int _g, int _b, int _a) + { + SetColor(_r, _g, _b, _a); + } + + void SetColor(int _r, int _g, int _b, int _a = 0) + { + _color[0] = (unsigned char)_r; + _color[1] = (unsigned char)_g; + _color[2] = (unsigned char)_b; + _color[3] = (unsigned char)_a; + } + + void GetColor(int& _r, int& _g, int& _b, int& _a) const + { + _r = _color[0]; + _g = _color[1]; + _b = _color[2]; + _a = _color[3]; + } + + void SetRawColor(int color32) + { + *((int*)this) = color32; + } + + int GetRawColor() const + { + return *((int*)this); + } + + inline int r() const { return _color[0]; } + inline int g() const { return _color[1]; } + inline int b() const { return _color[2]; } + inline int a() const { return _color[3]; } + + unsigned char& operator[](int index) + { + return _color[index]; + } + + const unsigned char& operator[](int index) const + { + return _color[index]; + } + + bool operator == (const Color& rhs) const + { + return (*((int*)this) == *((int*)&rhs)); + } + + bool operator != (const Color& rhs) const + { + return !(operator==(rhs)); + } + + Color& operator=(const Color& rhs) + { + SetRawColor(rhs.GetRawColor()); + return *this; + } + + unsigned char _color[4]; +}; + + +#endif +``` + +`SpyCustom/sdk/Controls.h`: + +```h +#ifndef CONTROLS_H +#define CONTROLS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "IPanel.h" +#include "IKeyValuesSystem.h" + +#include "interface.h" +#include "MouseCode.h" +#include "KeyCode.h" +#include "tier3.h" + + +namespace vgui +{ + + bool VGui_InitInterfacesList(const char* moduleName, CreateInterfaceFn* factoryList, int numFactories); + + const char* GetControlsModuleName(); + + class IPanel; + class IInput; + class ISchemeManager; + class ISurface; + class ISystem; + class IVGui; + + class AnalogBar; + class AnimatingImagePanel; + class AnimationController; + class BuildModeDialog; + class Button; + class CheckButton; + class CheckButtonList; + class CircularProgressBar; + template< class T >class CvarToggleCheckButton; + class ComboBox; + class DirectorySelectDialog; + class Divider; + class EditablePanel; + class FileOpenDialog; + class Frame; + class GraphPanel; + class HTML; + class ImagePanel; + class Label; + class ListPanel; + class ListViewPanel; + class Menu; + class MenuBar; + class MenuButton; + class MenuItem; + class MessageBox; + class Panel; + class PanelListPanel; + class ProgressBar; + class ProgressBox; + class PropertyDialog; + class PropertyPage; + class PropertySheet; + class QueryBox; + class RadioButton; + class RichText; + class ScalableImagePanel; + class ScrollBar; + class ScrollBarSlider; + class SectionedListPanel; + class Slider; + class Splitter; + class TextEntry; + class ToggleButton; + class BaseTooltip; + class TextTooltip; + class TreeView; + class CTreeViewListControl; + class URLLabel; + class WizardPanel; + class WizardSubPanel; + + class BuildGroup; + class FocusNavGroup; + class IBorder; + class IImage; + class Image; + class ImageList; + class TextImage; + +} + +#define VGUI_HOTKEYS_ENABLED +#define USING_BUILD_FACTORY( className ) \ + extern className *g_##className##LinkerHack; \ + className *g_##className##PullInModule = g_##className##LinkerHack; + +#define USING_BUILD_FACTORY_ALIAS( className, factoryName ) \ + extern className *g_##factoryName##LinkerHack; \ + className *g_##factoryName##PullInModule = g_##factoryName##LinkerHack; + +#endif +``` + +`SpyCustom/sdk/Cursor.h`: + +```h +#ifndef CURSOR_H +#define CURSOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" + +namespace vgui +{ + + enum CursorCode + { + dc_user, + dc_none, + dc_arrow, + dc_ibeam, + dc_hourglass, + dc_waitarrow, + dc_crosshair, + dc_up, + dc_sizenwse, + dc_sizenesw, + dc_sizewe, + dc_sizens, + dc_sizeall, + dc_no, + dc_hand, + dc_blank, + dc_last, + dc_alwaysvisible_push, + dc_alwaysvisible_pop, + }; + + typedef unsigned long HCursor; + +} + +#endif +``` + +`SpyCustom/sdk/Dar.h`: + +```h +#ifndef DAR_H +#define DAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "VGUI.h" +#include "utlvector.h" + +#include "memdbgon.h" + +namespace vgui +{ + + template class Dar : public CUtlVector< ELEMTYPE > + { + typedef CUtlVector< ELEMTYPE > BaseClass; + + public: + Dar() + { + } + Dar(int initialCapacity) : + BaseClass(0, initialCapacity) + { + } + + public: + void SetCount(int count) + { + this->EnsureCount(count); + } + int GetCount() + { + return this->Count(); + } + int AddElement(ELEMTYPE elem) + { + return this->AddToTail(elem); + } + void MoveElementToEnd(ELEMTYPE elem) + { + if (this->Count() == 0) + return; + + if (this->Element(this->Count() - 1) == elem) + return; + + int idx = this->GetOffset(elem); + if (idx == this->InvalidIndex()) + return; + + this->Remove(idx); + this->AddToTail(elem); + } + int FindElement(ELEMTYPE elem) + { + return this->GetOffset(elem); + } + bool HasElement(ELEMTYPE elem) + { + if (this->FindElement(elem) != this->InvalidIndex()) + { + return true; + } + return false; + } + int PutElement(ELEMTYPE elem) + { + int index = this->FindElement(elem); + if (index >= 0) + { + return index; + } + return this->AddElement(elem); + } + void InsertElementAt(ELEMTYPE elem, int index) + { + this->InsertBefore(index, elem); + } + void SetElementAt(ELEMTYPE elem, int index) + { + this->EnsureCount(index + 1); + this->Element(index) = elem; + } + void RemoveElementAt(int index) + { + this->Remove(index); + } + + void RemoveElementsBefore(int index) + { + if (index <= 0) + return; + this->RemoveMultiple(0, index - 1); + } + + void RemoveElement(ELEMTYPE elem) + { + this->FindAndRemove(elem); + } + + void* GetBaseData() + { + return this->Base(); + } + + void CopyFrom(Dar& dar) + { + this->CopyArray(dar.Base(), dar.Count()); + } + }; + +} + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/EditablePanel.h`: + +```h +#ifndef EDITABLEPANEL_H +#define EDITABLEPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "Panel.h" +#include "FocusNavGroup.h" + +namespace vgui +{ + + class EditablePanel : public Panel + { + DECLARE_CLASS_SIMPLE(EditablePanel, Panel); + + public: + EditablePanel(Panel* parent, const char* panelName); + EditablePanel(Panel* parent, const char* panelName, HScheme hScheme); + + virtual ~EditablePanel(); + + virtual void LoadControlSettings(const char* dialogResourceName, const char* pathID = NULL, KeyValues* pPreloadedKeyValues = NULL, KeyValues* pConditions = NULL); + virtual void ApplySettings(KeyValues* inResourceData); + + virtual void PerformLayout(); + + virtual void LoadUserConfig(const char* configName, int dialogID = 0); + virtual void SaveUserConfig(); + + virtual void LoadControlSettingsAndUserConfig(const char* dialogResourceName, int dialogID = 0); + + virtual void ActivateBuildMode(); + + virtual BuildGroup* GetBuildGroup(); + + virtual Panel* CreateControlByName(const char* controlName); + + virtual void SetControlString(const char* controlName, const char* string); + virtual void SetControlString(const char* controlName, const wchar_t* string); + virtual void SetControlInt(const char* controlName, int state); + virtual int GetControlInt(const char* controlName, int defaultState); + virtual const char* GetControlString(const char* controlName, const char* defaultString = ""); + virtual void GetControlString(const char* controlName, char* buf, int bufSize, const char* defaultString = ""); + virtual void SetControlEnabled(const char* controlName, bool enabled); + virtual void SetControlVisible(const char* controlName, bool visible); + + virtual void SetDialogVariable(const char* varName, const char* value); + virtual void SetDialogVariable(const char* varName, const wchar_t* value); + virtual void SetDialogVariable(const char* varName, int value); + virtual void SetDialogVariable(const char* varName, float value); + + virtual void RequestFocus(int direction = 0); + virtual bool RequestFocusNext(VPANEL panel); + virtual bool RequestFocusPrev(VPANEL panel); + virtual void OnSetFocus(); + virtual void OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel); + virtual VPANEL GetCurrentKeyFocus(); + virtual Panel* HasHotkey(wchar_t key); + + virtual void OnKeyCodePressed(KeyCode code); + + virtual bool RequestInfo(KeyValues* data); + virtual void RegisterControlSettingsFile(const char* dialogResourceName, const char* pathID = NULL); + + KeyValues* GetDialogVariables(); + + protected: + virtual void PaintBackground(); + + virtual FocusNavGroup& GetFocusNavGroup(); + + MESSAGE_FUNC_HANDLE(OnDefaultButtonSet, "DefaultButtonSet", button); + MESSAGE_FUNC_HANDLE(OnCurrentDefaultButtonSet, "CurrentDefaultButtonSet", button); + MESSAGE_FUNC(OnFindDefaultButton, "FindDefaultButton"); + + virtual void OnChildAdded(VPANEL child); + virtual void OnSizeChanged(int wide, int tall); + virtual void OnClose(); + + virtual void ApplyUserConfigSettings(KeyValues* userConfig); + + virtual void GetUserConfigSettings(KeyValues* userConfig); + + private: + void ForceSubPanelsToUpdateWithNewDialogVariables(); + + BuildGroup* _buildGroup; + FocusNavGroup m_NavGroup; + KeyValues* m_pDialogVariables; + + char* m_pszConfigName; + int m_iConfigID; + bool m_bShouldSkipAutoResize; + }; + +} + +#endif +``` + +`SpyCustom/sdk/FileOpenDialog.h`: + +```h +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Declaration of FileOpenDialog class, a generic open/save as file dialog +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FILEOPENDIALOG_H +#define FILEOPENDIALOG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "Frame.h" + +namespace vgui +{ + +class FileCompletionEdit; // local +class InputDialog; + +//----------------------------------------------------------------------------- +// Purpose: generic open/save as file dialog, by default deletes itself on close +//----------------------------------------------------------------------------- +enum FileOpenDialogType_t +{ + FOD_SAVE = 0, + FOD_OPEN, + FOD_SELECT_DIRECTORY, +}; + +struct FileData_t +{ + CUtlString m_FileAttributes; + CUtlString m_CreationTime; + int64 m_nCreationTime; + CUtlString m_LastAccessTime; + CUtlString m_LastWriteTime; + int64 m_nLastWriteTime; + int64 m_nFileSize; + CUtlString m_FileName; + CUtlString m_FullPath; + wchar_t m_FileType[ 80 ]; + + bool m_bDirectory; + + void PrepareKV( KeyValues *kv ); +}; + +class FileOpenDialog : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( FileOpenDialog, Frame ); + +public: + // NOTE: Backward compat constructor + FileOpenDialog( Panel *parent, const char *title, bool bOpenFile, KeyValues *pContextKeyValues = 0 ); + + // The context keyvalues are added to all messages sent by this dialog if they are specified + FileOpenDialog( Panel *parent, const char *title, FileOpenDialogType_t type, KeyValues *pContextKeyValues = 0 ); + ~FileOpenDialog(); + + // Set the directory the file search starts in + void SetStartDirectory(const char *dir); + + // Sets the start directory context (and resets the start directory in the process) + // NOTE: If you specify a startdir context, then if you've already opened + // a file with that same start dir context before, it will start in the + // same directory it ended up in. + void SetStartDirectoryContext( const char *pContext, const char *pDefaultDir ); + + // Add filters for the drop down combo box + // The filter info, if specified, gets sent back to the app in the FileSelected message + void AddFilter( const char *filter, const char *filterName, bool bActive, const char *pFilterInfo = NULL ); + + // Activate the dialog + // NOTE: The argument is there for backward compat + void DoModal( bool bUnused = false ); + + // Get the directory this is currently in + void GetCurrentDirectory( char *buf, int bufSize ); + + // Get the last selected file name + void GetSelectedFileName( char *buf, int bufSize ); + + /* + messages sent: + "FileSelected" + "fullpath" // specifies the fullpath of the file + "filterinfo" // Returns the filter info associated with the active filter + "FileSelectionCancelled" + */ + + static bool FileNameWildCardMatch( char const *pchFileName, char const *pchPattern ); + +protected: + virtual void OnCommand( const char *command ); + virtual void ApplySchemeSettings(IScheme *pScheme); + virtual void OnClose(); + virtual void OnKeyCodeTyped(KeyCode code); + + // handles the open button being pressed + // checks on what has changed and acts accordingly + MESSAGE_FUNC( OnOpen, "OnOpen" ); + MESSAGE_FUNC( OnSelectFolder, "SelectFolder" ); + MESSAGE_FUNC( OnFolderUp, "OnFolderUp" ); + MESSAGE_FUNC( OnNewFolder, "OnNewFolder" ); + MESSAGE_FUNC( OnOpenInExplorer, "OpenInExplorer" ); + + MESSAGE_FUNC( PopulateFileList, "PopulateFileList" ); + MESSAGE_FUNC( PopulateDriveList, "PopulateDriveList" ); + MESSAGE_FUNC( PopulateFileNameSearchHistory, "PopulateFileNameSearchHistory" ); + + // moves the directory structure up + virtual void MoveUpFolder(); + + // validates that the current path is valid + virtual void ValidatePath(); + + // handles an item in the list being selected + MESSAGE_FUNC( OnItemSelected, "ItemSelected" ); + MESSAGE_FUNC( OnListItemSelected, "ListItemSelected" ) + { + OnItemSelected(); + } + + // changes directories in response to selecting drives from the combo box + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv ); + + MESSAGE_FUNC( OnInputCanceled, "InputCanceled" ); + MESSAGE_FUNC_PARAMS( OnInputCompleted, "InputCompleted", data ); + MESSAGE_FUNC( OnMatchStringSelected, "OnMatchStringSelected" ); + +private: + // Necessary because we have 2 constructors + void Init( const char *title, KeyValues *pContextKeyValues ); + + // Does the specified extension match something in the filter list? + bool ExtensionMatchesFilter( const char *pExt ); + + // Choose the first non *.* filter in the filter list + void ChooseExtension( char *pExt, int nBufLen ); + + // Saves the file to the start dir context + void SaveFileToStartDirContext( const char *pFullPath ); + + // Posts a file selected message + void PostFileSelectedMessage( const char *pFileName ); + + // Creates a new folder + void NewFolder( char const *folderName ); + + void BuildFileList(); + void FilterFileList(); + + bool PassesFilter( FileData_t *fd ); + int CountSubstringMatches(); + + void AddSearchHistoryString( char const *str ); + + vgui::ComboBox *m_pFullPathEdit; + vgui::ListPanel *m_pFileList; + + vgui::ComboBox *m_pFileNameCombo; + + vgui::ComboBox *m_pFileTypeCombo; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + vgui::Button *m_pFolderUpButton; + vgui::Button *m_pNewFolderButton; + vgui::Button *m_pOpenInExplorerButton; + vgui::Label *m_pFileTypeLabel; + + KeyValues *m_pContextKeyValues; + + char m_szLastPath[1024]; + unsigned short m_nStartDirContext; + FileOpenDialogType_t m_DialogType; + bool m_bFileSelected : 1; + + VPANEL m_SaveModal; + vgui::DHANDLE< vgui::InputDialog > m_hInputDialog; + + CUtlVector< FileData_t > m_Files; + CUtlVector< FileData_t * > m_Filtered; + CUtlVector< CUtlString > m_SearchHistory; + + CUtlString m_CurrentSubstringFilter; +}; + +} // namespace vgui + +#endif // FILEOPENDIALOG_H +``` + +`SpyCustom/sdk/FocusNavGroup.h`: + +```h +#ifndef FOCUSNAVGROUP_H +#define FOCUSNAVGROUP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "PHandle.h" + +namespace vgui +{ + + class Panel; + + class FocusNavGroup + { + public: + FocusNavGroup(Panel* panel); + ~FocusNavGroup(); + virtual Panel* GetDefaultPanel(); + + virtual void SetDefaultButton(Panel* panel); + virtual VPANEL GetDefaultButton(); + virtual VPANEL GetCurrentDefaultButton(); + virtual Panel* FindPanelByHotkey(wchar_t key); + virtual bool RequestFocusPrev(VPANEL panel = NULL); + virtual bool RequestFocusNext(VPANEL panel = NULL); + + virtual Panel* GetCurrentFocus(); + virtual VPANEL SetCurrentFocus(VPANEL panel, VPANEL defaultPanel); + + virtual void SetFocusTopLevel(bool state); + + virtual void SetCurrentDefaultButton(VPANEL panel, bool sendCurrentDefaultButtonMessage = true); + private: + bool CanButtonBeDefault(VPANEL panel); + + VPanelHandle _defaultButton; + VPanelHandle _currentDefaultButton; + VPanelHandle _currentFocus; + + Panel* _mainPanel; + bool _topLevelFocus; + }; + +} + +#endif +``` + +`SpyCustom/sdk/Frame.h`: + +```h +#ifndef VGUI_FRAME_H +#define VGUI_FRAME_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui.h" +#include "Dar.h" +#include "Panel.h" +#include "EditablePanel.h" +#include "FocusNavGroup.h" + +namespace vgui +{ + + class FrameButton; + class FrameSystemButton; + + class Frame : public EditablePanel + { + DECLARE_CLASS_SIMPLE(Frame, EditablePanel); + + public: + Frame(Panel* parent, const char* panelName, bool showTaskbarIcon = true, bool bPopup = true); + virtual ~Frame(); + + virtual void SetTitle(const char* title, bool surfaceTitle); + virtual void SetTitle(const wchar_t* title, bool surfaceTitle); + + virtual void Activate(); + + virtual void ActivateMinimized(); + + MESSAGE_FUNC(Close, "Close"); + MESSAGE_FUNC(CloseModal, "CloseModal"); + + virtual void SetDeleteSelfOnClose(bool state); + + virtual void MoveToCenterOfScreen(); + + virtual void SetMoveable(bool state); + virtual bool IsMoveable(); + + virtual void SetSizeable(bool state); + virtual bool IsSizeable(); + virtual void SetMenuButtonVisible(bool state); + void SetMenuButtonResponsive(bool state); + + virtual void SetMinimizeButtonVisible(bool state); + virtual void SetMaximizeButtonVisible(bool state); + virtual void SetMinimizeToSysTrayButtonVisible(bool state); + + virtual void SetCloseButtonVisible(bool state); + + virtual bool IsMinimized(); + virtual void FlashWindow(); + virtual void FlashWindowStop(); + virtual void OnCommand(const char* command); + + virtual Menu* GetSysMenu(); + virtual void SetSysMenu(Menu* menu); + + void SetImages(const char* pEnabledImage, const char* pDisabledImage = NULL); + + virtual void SetTitleBarVisible(bool state); + + virtual void SetClipToParent(bool state); + virtual bool GetClipToParent() const; + + virtual void SetSmallCaption(bool state); + virtual bool IsSmallCaption() const; + + virtual int GetDraggerSize(); + virtual int GetCornerSize(); + virtual int GetBottomRightSize(); + virtual int GetCaptionHeight(); + + virtual void LoadControlSettings(const char* dialogResourceName, const char* pathID = NULL, KeyValues* pPreloadedKeyValues = NULL, KeyValues* pConditions = NULL); + + void SetChainKeysToParent(bool state); + bool CanChainKeysToParent() const; + + virtual void DoModal(); + + void PlaceUnderCursor(); + + void DisableFadeEffect(void); + + void SetFadeEffectDisableOverride(bool disabled); + + virtual void OnGripPanelMoved(int nNewX, int nNewY, int nNewW, int nNewH); + virtual void OnGripPanelMoveFinished() {} + + protected: + virtual void OnMousePressed(MouseCode code); + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + virtual void OnKeyCodeReleased(KeyCode code); + virtual void OnKeyFocusTicked(); + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual void PerformLayout(); + virtual void OnClose(); + virtual void OnFinishedClose(); + MESSAGE_FUNC(OnMinimize, "Minimize"); + virtual void OnMinimizeToSysTray(); + MESSAGE_FUNC(OnCloseFrameButtonPressed, "CloseFrameButtonPressed"); + virtual void OnChildAdded(VPANEL child); + virtual void ApplySettings(KeyValues* inResourceData); + virtual void GetSettings(KeyValues* outResourceData); + virtual const char* GetDescription(void); + + virtual bool GetDefaultScreenPosition(int& x, int& y, int& wide, int& tall); + + virtual void PaintBackground(); + + virtual void OnThink(); + + virtual void OnScreenSizeChanged(int iOldWide, int iOldTall); + + virtual void GetClientArea(int& x, int& y, int& wide, int& tall); + + virtual void ApplyUserConfigSettings(KeyValues* userConfig); + + virtual void GetUserConfigSettings(KeyValues* userConfig); + + virtual bool HasUserConfigSettings(); + + virtual void GetSizerClientArea(int& x, int& y, int& wide, int& tall); + + private: + MESSAGE_FUNC_CHARPTR(InternalSetTitle, "SetTitle", text); + MESSAGE_FUNC(InternalFlashWindow, "FlashWindow"); + MESSAGE_FUNC_PARAMS(OnDialogVariablesChanged, "DialogVariables", dialogVariables); + + void SetupResizeCursors(); + void LayoutProportional(FrameButton* bt); + void FinishClose(); + void OnFrameFocusChanged(bool bHasFocus); + + Color _titleBarBgColor; + Color _titleBarDisabledBgColor; + Color _titleBarFgColor; + Color _titleBarDisabledFgColor; + Color m_InFocusBgColor; + Color m_OutOfFocusBgColor; + TextImage* _title; + +#if !defined( _GAMECONSOLE ) + Panel* _topGrip; + Panel* _bottomGrip; + Panel* _leftGrip; + Panel* _rightGrip; + Panel* _topLeftGrip; + Panel* _topRightGrip; + Panel* _bottomLeftGrip; + Panel* _bottomRightGrip; + Panel* _captionGrip; + FrameButton* _minimizeButton; + FrameButton* _maximizeButton; + FrameButton* _minimizeToSysTrayButton; + FrameButton* _closeButton; + FrameSystemButton* _menuButton; + Menu* _sysMenu; +#endif + + float m_flTransitionEffectTime; + float m_flFocusTransitionEffectTime; + int m_iClientInsetX; + int m_iClientInsetY; + int m_iTitleTextInsetX; + int m_nGripperWidth; + VPANEL m_hPreviousModal; + HFont m_hCustomTitleFont; + + bool _sizeable : 1; + bool _moveable : 1; + bool m_bHasFocus : 1; + bool _flashWindow : 1; + bool _nextFlashState : 1; + bool _drawTitleBar : 1; + bool m_bPreviouslyVisible : 1; + bool m_bFadingOut : 1; + bool m_bDeleteSelfOnClose : 1; + bool m_bDisableFadeEffect : 1; + bool m_bClipToParent : 1; + bool m_bSmallCaption : 1; + bool m_bChainKeysToParent : 1; + bool m_bPrimed : 1; + bool m_iClientInsetXOverridden : 1; + + CPanelAnimationVarAliasType(int, m_iTitleTextInsetXOverride, "titletextinsetX", "0", "proportional_int"); + CPanelAnimationVarAliasType(int, m_iTitleTextInsetYOverride, "titletextinsetY", "0", "proportional_int"); + }; + +} + +#endif +``` + +`SpyCustom/sdk/GameEventListener.h`: + +```h +#ifndef GAME_EVENT_LISTENER_H +#define GAME_EVENT_LISTENER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igameevents.h" +extern IGameEventManager2* gameeventmanager; + +class CGameEventListener : public IGameEventListener2 +{ +public: + CGameEventListener() : m_bRegisteredForEvents(false) + { + } + + ~CGameEventListener() + { + StopListeningForAllEvents(); + } + + void ListenForGameEvent(const char* name) + { + m_bRegisteredForEvents = true; + +#ifdef CLIENT_DLL + bool bServerSide = false; +#else + bool bServerSide = true; +#endif + if (gameeventmanager) + gameeventmanager->AddListener(this, name, bServerSide); + } + + void ListenForAllGameEvents() + { + +#ifdef CLIENT_DLL + bool bServerSide = false; +#else + bool bServerSide = true; +#endif + + gameeventmanager->AddListenerGlobal(this, bServerSide); + } + + void StopListeningForAllEvents() + { + if (m_bRegisteredForEvents) + { + if (gameeventmanager) + gameeventmanager->RemoveListener(this); + m_bRegisteredForEvents = false; + } + } + + virtual void FireGameEvent(IGameEvent* event) = 0; + int m_nDebugID; + virtual int GetEventDebugID(void); + +private: + + bool m_bRegisteredForEvents; +}; + +#endif +``` + +`SpyCustom/sdk/GameEventManager.h`: + +```h +#if !defined ( GAMEEVENTMANAGER_H ) +#define GAMEEVENTMANAGER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "igameevents.h" +#include "utlvector.h" +#include "KeyValues.h" +#include "networkstringtabledefs.h" +#include "utlsymbol.h" + +#include "bitbuf.h" + +class SVC_GameEventList; +class CLC_ListenEvents; + +//#include "netmessages.h" + +class CGameEventCallback +{ +public: + void* m_pCallback; + int m_nListenerType; +}; + +class CGameEventDescriptor +{ +public: + CGameEventDescriptor() + { + name[0] = 0; + eventid = -1; + keys = NULL; + local = false; + reliable = true; + } + +public: + char name[MAX_EVENT_NAME_LENGTH]; + int eventid; + KeyValues* keys; + bool local; + bool reliable; + CUtlVector listeners; +}; + +class CGameEvent : public IGameEvent +{ +public: + + CGameEvent(CGameEventDescriptor* descriptor); + virtual ~CGameEvent(); + + const char* GetName() const; + bool IsEmpty(const char* keyName = NULL); + bool IsLocal() const; + bool IsReliable() const; + + bool GetBool(const char* keyName = NULL, bool defaultValue = false); + int GetInt(const char* keyName = NULL, int defaultValue = 0); + float GetFloat(const char* keyName = NULL, float defaultValue = 0.0f); + const char* GetString(const char* keyName = NULL, const char* defaultValue = ""); + + void SetBool(const char* keyName, bool value); + void SetInt(const char* keyName, int value); + void SetFloat(const char* keyName, float value); + void SetString(const char* keyName, const char* value); + + CGameEventDescriptor* m_pDescriptor; + KeyValues* m_pDataKeys; +}; + +class CGameEventManager : public IGameEventManager2 +{ + friend class CGameEventManagerOld; + +public: + + enum + { + SERVERSIDE = 0, + CLIENTSIDE, + CLIENTSTUB, + SERVERSIDE_OLD, + CLIENTSIDE_OLD, + }; + + enum + { + TYPE_LOCAL = 0, + TYPE_STRING, + TYPE_FLOAT, + TYPE_LONG, + TYPE_SHORT, + TYPE_BYTE, + TYPE_BOOL + }; + + CGameEventManager(); + virtual ~CGameEventManager(); + + int LoadEventsFromFile(const char* filename); + void Reset(); + + bool AddListener(IGameEventListener2* listener, const char* name, bool bServerSide); + bool FindListener(IGameEventListener2* listener, const char* name); + void RemoveListener(IGameEventListener2* listener); + + IGameEvent* CreateEvent(const char* name, bool bForce = false); + IGameEvent* DuplicateEvent(IGameEvent* event); + bool FireEvent(IGameEvent* event, bool bDontBroadcast = false); + bool FireEventClientSide(IGameEvent* event); + void FreeEvent(IGameEvent* event); + + bool SerializeEvent(IGameEvent* event, bf_write* buf); + IGameEvent* UnserializeEvent(bf_read* buf); + +public: + bool Init(); + void Shutdown(); + void ReloadEventDefinitions(); + bool AddListener(void* listener, CGameEventDescriptor* descriptor, int nListenerType); + + CGameEventDescriptor* GetEventDescriptor(const char* name); + CGameEventDescriptor* GetEventDescriptor(IGameEvent* event); + CGameEventDescriptor* GetEventDescriptor(int eventid); + + void WriteEventList(SVC_GameEventList* msg); + bool ParseEventList(SVC_GameEventList* msg); + + void WriteListenEventList(CLC_ListenEvents* msg); + bool HasClientListenersChanged(bool bReset = true); + void ConPrintEvent(IGameEvent* event); + + bool AddListenerAll(void* listener, int nListenerType); + void RemoveListenerOld(void* listener); + + +protected: + + IGameEvent* CreateEvent(CGameEventDescriptor* descriptor); + bool RegisterEvent(KeyValues* keys); + void UnregisterEvent(int index); + bool FireEventIntern(IGameEvent* event, bool bServerSide, bool bClientOnly); + CGameEventCallback* FindEventListener(void* listener); + + CUtlVector m_GameEvents; + CUtlVector m_Listeners; + CUtlSymbolTable m_EventFiles; + CUtlVector m_EventFileNames; + + bool m_bClientListenersChanged; +}; + +extern CGameEventManager& g_GameEventManager; + +#endif +``` + +`SpyCustom/sdk/IAppSystem.h`: + +```h +#ifndef IAPPSYSTEM_H +#define IAPPSYSTEM_H + +#ifdef COMPILER_MSVC +#pragma once +#endif + +#include "interface.h" + + + +struct AppSystemInfo_t +{ + const char* m_pModuleName; + const char* m_pInterfaceName; +}; + + +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + + INIT_LAST_VAL, +}; + +enum AppSystemTier_t +{ + APP_SYSTEM_TIER0 = 0, + APP_SYSTEM_TIER1, + APP_SYSTEM_TIER2, + APP_SYSTEM_TIER3, + + APP_SYSTEM_TIER_OTHER, +}; + + +abstract_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; + + virtual const AppSystemInfo_t* GetDependencies() { return NULL; } + + virtual AppSystemTier_t GetTier() { return APP_SYSTEM_TIER_OTHER; } + + virtual void Reconnect(CreateInterfaceFn factory, const char* pInterfaceName) {} + virtual bool IsSingleton() { return true; } +}; + + +template< class IInterface > +class CBaseAppSystem : public IInterface +{ +public: + virtual bool Connect(CreateInterfaceFn factory) { return true; } + virtual void Disconnect() {} + + virtual void* QueryInterface(const char* pInterfaceName) { return NULL; } + + virtual InitReturnVal_t Init() { return INIT_OK; } + virtual void Shutdown() {} + + virtual const AppSystemInfo_t* GetDependencies() { return NULL; } + virtual AppSystemTier_t GetTier() { return APP_SYSTEM_TIER_OTHER; } + + virtual void Reconnect(CreateInterfaceFn factory, const char* pInterfaceName); +}; + + +template< class IInterface > +class CTier0AppSystem : public CBaseAppSystem< IInterface > +{ +}; + + +#endif + + +``` + +`SpyCustom/sdk/IBorder.h`: + +```h +#ifndef IBORDER_H +#define IBORDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" + +class KeyValues; + +namespace vgui +{ + + class IScheme; + + class IBorder + { + public: + IBorder() {} + virtual ~IBorder() {} + + virtual void Paint(VPANEL panel) = 0; + virtual void Paint(int x0, int y0, int x1, int y1) = 0; + virtual void Paint(int x0, int y0, int x1, int y1, int breakSide, int breakStart, int breakStop) = 0; + virtual void SetInset(int left, int top, int right, int bottom) = 0; + virtual void GetInset(int& left, int& top, int& right, int& bottom) = 0; + virtual void ApplySchemeSettings(IScheme* pScheme, KeyValues* inResourceData) = 0; + virtual const char* GetName() = 0; + virtual void SetName(const char* name) = 0; + + enum backgroundtype_e + { + BACKGROUND_FILLED, + BACKGROUND_TEXTURED, + BACKGROUND_ROUNDEDCORNERS, + }; + virtual backgroundtype_e GetBackgroundType() = 0; + + enum sides_e + { + SIDE_LEFT = 0, + SIDE_TOP = 1, + SIDE_RIGHT = 2, + SIDE_BOTTOM = 3 + }; + + virtual bool PaintFirst(void) = 0; + }; + +} + + +#endif +``` + +`SpyCustom/sdk/IClientLeafSystem.h`: + +```h +#if !defined( ICLIENTLEAFSYSTEM_H ) +#define ICLIENTLEAFSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "platform.h" +#include "client_render_handle.h" +#include "ivmodelinfo.h" + + +#define CLIENTLEAFSYSTEM_INTERFACE_VERSION "ClientLeafSystem002" + + +enum RenderableModelType_t +{ + RENDERABLE_MODEL_UNKNOWN_TYPE = -1, + RENDERABLE_MODEL_ENTITY = 0, + RENDERABLE_MODEL_STUDIOMDL, + RENDERABLE_MODEL_STATIC_PROP, + RENDERABLE_MODEL_BRUSH, +}; + +enum RenderGroup_t +{ + RENDER_GROUP_OPAQUE = 0, + RENDER_GROUP_TRANSLUCENT, + RENDER_GROUP_TRANSLUCENT_IGNOREZ, + RENDER_GROUP_COUNT, +}; + + +abstract_class IClientLeafSystemEngine +{ +public: + virtual void CreateRenderableHandle(IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, UINT32 nSplitscreenEnabled = 0xFFFFFFFF) = 0; + virtual void RemoveRenderable(ClientRenderHandle_t handle) = 0; + virtual void AddRenderableToLeaves(ClientRenderHandle_t renderable, int nLeafCount, unsigned short* pLeaves) = 0; + virtual void SetTranslucencyType(ClientRenderHandle_t handle, RenderableTranslucencyType_t nType) = 0; + +}; + + +#endif + + + + + + + + +``` + +`SpyCustom/sdk/IClientPanel.h`: + +```h +#ifndef ICLIENTPANEL_H +#define ICLIENTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" + +#ifdef GetClassName +#undef GetClassName +#endif + +class KeyValues; + +namespace vgui +{ + + class Panel; + class SurfaceBase; + + enum EInterfaceID + { + ICLIENTPANEL_STANDARD_INTERFACE = 0, + }; + + class IClientPanel + { + public: + virtual VPANEL GetVPanel() = 0; + + virtual void Think() = 0; + virtual void PerformApplySchemeSettings() = 0; + virtual void PaintTraverse(bool forceRepaint, bool allowForce) = 0; + virtual void Repaint() = 0; + virtual VPANEL IsWithinTraverse(int x, int y, bool traversePopups) = 0; + virtual void GetInset(int& top, int& left, int& right, int& bottom) = 0; + virtual void GetClipRect(int& x0, int& y0, int& x1, int& y1) = 0; + virtual void OnChildAdded(VPANEL child) = 0; + virtual void OnSizeChanged(int newWide, int newTall) = 0; + + virtual void InternalFocusChanged(bool lost) = 0; + virtual bool RequestInfo(KeyValues* outputData) = 0; + virtual void RequestFocus(int direction) = 0; + virtual bool RequestFocusPrev(VPANEL existingPanel) = 0; + virtual bool RequestFocusNext(VPANEL existingPanel) = 0; + virtual void OnMessage(const KeyValues* params, VPANEL ifromPanel) = 0; + virtual VPANEL GetCurrentKeyFocus() = 0; + virtual int GetTabPosition() = 0; + + virtual const char* GetName() = 0; + virtual const char* GetClassName() = 0; + + virtual HScheme GetScheme() = 0; + virtual bool IsProportional() = 0; + virtual bool IsAutoDeleteSet() = 0; + virtual void DeletePanel() = 0; + + virtual void* QueryInterface(EInterfaceID id) = 0; + + virtual Panel* GetPanel() = 0; + + virtual const char* GetModuleName() = 0; + + virtual void OnTick() = 0; + }; + +} + + +#endif +``` + +`SpyCustom/sdk/ICollideable.h`: + +```h +#ifndef ENGINE_ICOLLIDEABLE_H +#define ENGINE_ICOLLIDEABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +enum SolidType_t; +class IHandleEntity; +struct Ray_t; +struct model_t; +class Vector; +class QAngle; +class CGameTrace; +typedef CGameTrace trace_t; +class IClientUnknown; + + +abstract_class ICollideable +{ +public: + virtual IHandleEntity * GetEntityHandle() = 0; + + virtual const Vector& OBBMinsPreScaled() const = 0; + virtual const Vector& OBBMaxsPreScaled() const = 0; + virtual const Vector& OBBMins() const = 0; + virtual const Vector& OBBMaxs() const = 0; + + virtual void WorldSpaceTriggerBounds(Vector* pVecWorldMins, Vector* pVecWorldMaxs) const = 0; + + virtual bool TestCollision(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr) = 0; + + virtual bool TestHitboxes(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr) = 0; + + virtual int GetCollisionModelIndex() = 0; + + virtual const model_t* GetCollisionModel() = 0; + + virtual const Vector& GetCollisionOrigin() const = 0; + virtual const QAngle& GetCollisionAngles() const = 0; + virtual const matrix3x4_t& CollisionToWorldTransform() const = 0; + + virtual SolidType_t GetSolid() const = 0; + virtual int GetSolidFlags() const = 0; + + virtual IClientUnknown* GetIClientUnknown() = 0; + + virtual int GetCollisionGroup() const = 0; + + virtual void WorldSpaceSurroundingBounds(Vector* pVecMins, Vector* pVecMaxs) = 0; + + virtual bool ShouldTouchTrigger(int triggerSolidFlags) const = 0; + + virtual const matrix3x4_t* GetRootParentToWorldTransform() const = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/IColorCorrection.h`: + +```h +#ifndef ICOLORCORRECTION_H +#define ICOLORCORRECTION_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "imageformat.h" + +typedef unsigned int ColorCorrectionHandle_t; +struct ShaderColorCorrectionInfo_t; + +#define COLORCORRECTION_INTERFACE_VERSION "COLORCORRECTION_VERSION_1" + +abstract_class IColorCorrectionSystem +{ +public: + virtual void Init() = 0; + virtual void Shutdown() = 0; + + virtual ColorCorrectionHandle_t AddLookup(const char* pName) = 0; + virtual bool RemoveLookup(ColorCorrectionHandle_t handle) = 0; + + virtual void SetLookupWeight(ColorCorrectionHandle_t handle, float flWeight) = 0; + virtual float GetLookupWeight(ColorCorrectionHandle_t handle) = 0; + virtual float GetLookupWeight(int i) = 0; + + virtual void LockLookup() = 0; + virtual void LockLookup(ColorCorrectionHandle_t handle) = 0; + + virtual void UnlockLookup() = 0; + virtual void UnlockLookup(ColorCorrectionHandle_t handle) = 0; + + virtual void SetLookup(RGBX5551_t inColor, color24 outColor) = 0; + virtual void SetLookup(ColorCorrectionHandle_t handle, RGBX5551_t inColor, color24 outColor) = 0; + + virtual color24 GetLookup(RGBX5551_t inColor) = 0; + virtual color24 GetLookup(ColorCorrectionHandle_t handle, RGBX5551_t inColor) = 0; + + virtual void LoadLookup(const char* pLookupName) = 0; + virtual void LoadLookup(ColorCorrectionHandle_t handle, const char* pLookupName) = 0; + + virtual void CopyLookup(const color24* pSrcColorCorrection) = 0; + virtual void CopyLookup(ColorCorrectionHandle_t handle, const color24* pSrcColorCorrection) = 0; + + virtual void ResetLookup(ColorCorrectionHandle_t handle) = 0; + virtual void ResetLookup() = 0; + + virtual void ReleaseTextures() = 0; + virtual void RestoreTextures() = 0; + + virtual void ResetLookupWeights() = 0; + + virtual int GetNumLookups() = 0; + + virtual color24 ConvertToColor24(RGBX5551_t inColor) = 0; + + virtual void SetResetable(ColorCorrectionHandle_t handle, bool bResetable) = 0; + + virtual void EnableColorCorrection(bool bEnable) = 0; + + virtual void GetCurrentColorCorrection(ShaderColorCorrectionInfo_t* pInfo) = 0; +}; + +#endif +``` + +`SpyCustom/sdk/IEffects.h`: + +```h +#ifndef IEFFECTS_H +#define IEFFECTS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "vector.h" +#include "interface.h" +#include "ipredictionsystem.h" + +enum ShakeCommand_t; +class Vector; +class CGameTrace; +typedef CGameTrace trace_t; + + +#define IEFFECTS_INTERFACE_VERSION "IEffects001" +abstract_class IEffects : public IPredictionSystem +{ +public: + virtual ~IEffects() {}; + virtual void Beam(const Vector & Start, const Vector & End, int nModelIndex, + int nHaloIndex, unsigned char frameStart, unsigned char frameRate, + float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength, + unsigned char noise, unsigned char red, unsigned char green, + unsigned char blue, unsigned char brightness, unsigned char speed) = 0; + + virtual void Smoke(const Vector& origin, int modelIndex, float scale, float framerate) = 0; + + virtual void Sparks(const Vector& position, int nMagnitude = 1, int nTrailLength = 1, const Vector* pvecDir = NULL) = 0; + + virtual void Dust(const Vector& pos, const Vector& dir, float size, float speed) = 0; + + virtual void MuzzleFlash(const Vector& vecOrigin, const Vector& vecAngles, float flScale, int iType) = 0; + + virtual void MetalSparks(const Vector& position, const Vector& direction) = 0; + + virtual void EnergySplash(const Vector& position, const Vector& direction, bool bExplosive = false) = 0; + + virtual void Ricochet(const Vector& position, const Vector& direction) = 0; + + virtual float Time() = 0; + virtual bool IsServer() = 0; + + virtual void SuppressEffectsSounds(bool bSuppress) = 0; +}; + + + +#endif +``` + +`SpyCustom/sdk/IEngineSound.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client-server neutral sound interface +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IENGINESOUND_H +#define IENGINESOUND_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "basetypes.h" +#include "interface.h" +#include "soundflags.h" +#include "irecipientfilter.h" +#include "utlvector.h" +#include "SndInfo.h" + +//----------------------------------------------------------------------------- +// forward declaration +//----------------------------------------------------------------------------- +class Vector; + +// Handy defines for EmitSound +#define SOUND_FROM_UI_PANEL -2 // Sound being played inside a UI panel on the client +#define SOUND_FROM_LOCAL_PLAYER -1 +#define SOUND_FROM_WORLD 0 + + + +// These are used to feed a soundlevel to the sound system and have it use +// goldsrc-type attenuation. We should use this as little as possible and +// phase it out as soon as possible. + +// Take a regular sndlevel and convert it to compatibility mode. +#define SNDLEVEL_TO_COMPATIBILITY_MODE( x ) ((soundlevel_t)(int)( (x) + 256 )) + +// Take a compatibility-mode sndlevel and get the REAL sndlevel out of it. +#define SNDLEVEL_FROM_COMPATIBILITY_MODE( x ) ((soundlevel_t)(int)( (x) - 256 )) + +// Tells if the given sndlevel is marked as compatibility mode. +#define SNDLEVEL_IS_COMPATIBILITY_MODE( x ) ( (x) >= soundlevel_t(256) ) + + + +//----------------------------------------------------------------------------- +// Client-server neutral effects interface +//----------------------------------------------------------------------------- +#define IENGINESOUND_CLIENT_INTERFACE_VERSION "IEngineSoundClient003" +#define IENGINESOUND_SERVER_INTERFACE_VERSION "IEngineSoundServer003" + +abstract_class IEngineSound +{ +public: + // Precache a particular sample + virtual bool PrecacheSound(const char* pSample, bool bPreload = false, bool bIsUISound = false) = 0; + virtual bool IsSoundPrecached(const char* pSample) = 0; + virtual void PrefetchSound(const char* pSample) = 0; + + // Just loads the file header and checks for duration (not hooked up for .mp3's yet) + // Is accessible to server and client though + virtual float GetSoundDuration(const char* pSample) = 0; + + // Pitch of 100 is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 + // down to 1 is a lower pitch. 150 to 70 is the realistic range. + // EmitSound with pitch != 100 should be used sparingly, as it's not quite as + // fast (the pitchshift mixer is not native coded). + + // NOTE: setting iEntIndex to -1 will cause the sound to be emitted from the local + // player (client-side only) + virtual void EmitSound(IRecipientFilter& filter, int iEntIndex, int iChannel, const char* pSample, + float flVolume, float flAttenuation, int iFlags = 0, int iPitch = PITCH_NORM, int iSpecialDSP = 0, + const Vector* pOrigin = NULL, const Vector* pDirection = NULL, CUtlVector< Vector >* pUtlVecOrigins = NULL, bool bUpdatePositions = true, float soundtime = 0.0f, int speakerentity = -1) = 0; + + virtual void EmitSound(IRecipientFilter& filter, int iEntIndex, int iChannel, const char* pSample, + float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM, int iSpecialDSP = 0, + const Vector* pOrigin = NULL, const Vector* pDirection = NULL, CUtlVector< Vector >* pUtlVecOrigins = NULL, bool bUpdatePositions = true, float soundtime = 0.0f, int speakerentity = -1) = 0; + + virtual void EmitSentenceByIndex(IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex, + float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM,int iSpecialDSP = 0, + const Vector* pOrigin = NULL, const Vector* pDirection = NULL, CUtlVector< Vector >* pUtlVecOrigins = NULL, bool bUpdatePositions = true, float soundtime = 0.0f, int speakerentity = -1) = 0; + + virtual void StopSound(int iEntIndex, int iChannel, const char* pSample) = 0; + + // stop all active sounds (client only) + virtual void StopAllSounds(bool bClearBuffers) = 0; + + // Set the room type for a player (client only) + virtual void SetRoomType(IRecipientFilter& filter, int roomType) = 0; + + // Set the dsp preset for a player (client only) + virtual void SetPlayerDSP(IRecipientFilter& filter, int dspType, bool fastReset) = 0; + + // emit an "ambient" sound that isn't spatialized + // only available on the client, assert on server + virtual void EmitAmbientSound(const char* pSample, float flVolume, int iPitch = PITCH_NORM, int flags = 0, float soundtime = 0.0f) = 0; + + + // virtual EntChannel_t CreateEntChannel() = 0; + + virtual float GetDistGainFromSoundLevel(soundlevel_t soundlevel, float dist) = 0; + + // Client .dll only functions + virtual int GetGuidForLastSoundEmitted() = 0; + virtual bool IsSoundStillPlaying(int guid) = 0; + virtual void StopSoundByGuid(int guid) = 0; + // Set's master volume (0.0->1.0) + virtual void SetVolumeByGuid(int guid, float fvol) = 0; + + // Retrieves list of all active sounds + virtual void GetActiveSounds(CUtlVector< SndInfo_t >& sndlist) = 0; + + virtual void PrecacheSentenceGroup(const char* pGroupName) = 0; + virtual void NotifyBeginMoviePlayback() = 0; + virtual void NotifyEndMoviePlayback() = 0; +}; + + +#endif // IENGINESOUND_H +``` + +`SpyCustom/sdk/IEngineVgui.h`: + +```h +#if !defined( IENGINEVGUI_H ) +#define IENGINEVGUI_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "VGUI.h" + +namespace vgui +{ + class Panel; +}; + +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), +}; + +abstract_class IEngineVGui +{ +public: + virtual ~IEngineVGui(void) { } + + virtual vgui::VPANEL GetPanel(VGuiPanel_t type) = 0; + + virtual bool IsGameUIVisible() = 0; +}; + +#define VENGINE_VGUI_VERSION "VEngineVGui001" + +#if defined(_STATIC_LINKED) && defined(CLIENT_DLL) +namespace Client +{ + extern IEngineVGui* enginevgui; +} +#else +extern IEngineVGui* g_pEnginevgui; +#endif + +#endif +``` + +`SpyCustom/sdk/IGameSystem.h`: + +```h +#ifndef IGAMESYSTEM_H +#define IGAMESYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + + +class IGameSystem +{ +public: + virtual char const* Name() = 0; + + virtual bool Init() = 0; + virtual void PostInit() = 0; + virtual void Shutdown() = 0; + + virtual void LevelInitPreEntity() = 0; + virtual void LevelInitPostEntity() = 0; + + virtual void LevelShutdownPreClearSteamAPIContext() {}; + virtual void LevelShutdownPreEntity() = 0; + virtual void LevelShutdownPostEntity() = 0; + virtual void OnSave() = 0; + + virtual void OnRestore() = 0; + + virtual void SafeRemoveIfDesired() = 0; + + virtual bool IsPerFrame() = 0; + + virtual ~IGameSystem(); + + static char const* MapName(); + + static void Add(IGameSystem* pSys); + static void Remove(IGameSystem* pSys); + static void RemoveAll(); + + static bool InitAllSystems(); + static void PostInitAllSystems(); + static void ShutdownAllSystems(); + static void LevelInitPreEntityAllSystems(char const* pMapName); + static void LevelInitPostEntityAllSystems(); + static void LevelShutdownPreClearSteamAPIContextAllSystems(); + static void LevelShutdownPreEntityAllSystems(); + static void LevelShutdownPostEntityAllSystems(); + + static void OnSaveAllSystems(); + static void OnRestoreAllSystems(); + + static void SafeRemoveIfDesiredAllSystems(); + +#ifdef CLIENT_DLL + static void PreRenderAllSystems(); + static void UpdateAllSystems(float frametime); + static void PostRenderAllSystems(); +#else + static void FrameUpdatePreEntityThinkAllSystems(); + static void FrameUpdatePostEntityThinkAllSystems(); + static void PreClientUpdateAllSystems(); + + static CBasePlayer* RunCommandPlayer(); + static CUserCmd* RunCommandUserCmd(); +#endif +}; + +class IGameSystemPerFrame : public IGameSystem +{ +public: + virtual ~IGameSystemPerFrame(); + +#ifdef CLIENT_DLL + virtual void PreRender() = 0; + + virtual void Update(float frametime) = 0; + + virtual void PostRender() = 0; +#else + virtual void FrameUpdatePreEntityThink() = 0; + virtual void FrameUpdatePostEntityThink() = 0; + virtual void PreClientUpdate() = 0; +#endif +}; + +class CBaseGameSystem : public IGameSystem +{ +public: + + virtual char const* Name() { return "unnamed"; } + + virtual bool Init() { return true; } + virtual void PostInit() {} + virtual void Shutdown() {} + + virtual void LevelInitPreEntity() {} + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreClearSteamAPIContext() {} + virtual void LevelShutdownPreEntity() {} + virtual void LevelShutdownPostEntity() {} + + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + + virtual bool IsPerFrame() { return false; } +private: + +#ifdef CLIENT_DLL + virtual void PreRender() {} + + virtual void Update(float frametime) {} + + virtual void PostRender() {} +#else + virtual void FrameUpdatePreEntityThink() {} + virtual void FrameUpdatePostEntityThink() {} + virtual void PreClientUpdate() {} +#endif +}; + +class CBaseGameSystemPerFrame : public IGameSystemPerFrame +{ +public: + virtual char const* Name() { return "unnamed"; } + + virtual bool Init() { return true; } + virtual void PostInit() {} + virtual void Shutdown() {} + + virtual void LevelInitPreEntity() {} + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreClearSteamAPIContext() {} + virtual void LevelShutdownPreEntity() {} + virtual void LevelShutdownPostEntity() {} + + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + + virtual bool IsPerFrame() { return true; } + +#ifdef CLIENT_DLL + virtual void PreRender() { } + + virtual void Update(float frametime) { } + + virtual void PostRender() { } +#else + virtual void FrameUpdatePreEntityThink() { } + virtual void FrameUpdatePostEntityThink() { } + virtual void PreClientUpdate() { } +#endif +}; + +class CAutoGameSystem : public CBaseGameSystem +{ +public: + CAutoGameSystem(char const* name = NULL); + CAutoGameSystem* m_pNext; + + virtual char const* Name() { return m_pszName ? m_pszName : "unnamed"; } + +private: + char const* m_pszName; +}; + +class CAutoGameSystemPerFrame : public CBaseGameSystemPerFrame +{ +public: + CAutoGameSystemPerFrame(char const* name = NULL); + CAutoGameSystemPerFrame* m_pNext; + + virtual char const* Name() { return m_pszName ? m_pszName : "unnamed"; } + +private: + char const* m_pszName; +}; + + +class IToolFrameworkServer +{ +public: + virtual void PreSetupVisibility() = 0; +}; + +#endif +``` + +`SpyCustom/sdk/IGameUI.h`: + +```h +#ifndef IGAMEUI_H +#define IGAMEUI_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "IPanel.h" + +#if !defined( _X360 ) +#include "xboxstubs.h" +#endif + +enum ESteamLoginFailure +{ + STEAMLOGINFAILURE_NONE, + STEAMLOGINFAILURE_BADTICKET, + STEAMLOGINFAILURE_NOSTEAMLOGIN, + STEAMLOGINFAILURE_VACBANNED, + STEAMLOGINFAILURE_LOGGED_IN_ELSEWHERE +}; + +enum ESystemNotify +{ + SYSTEMNOTIFY_STORAGEDEVICES_CHANGED, + SYSTEMNOTIFY_USER_SIGNEDIN, + SYSTEMNOTIFY_USER_SIGNEDOUT, + SYSTEMNOTIFY_XUIOPENING, + SYSTEMNOTIFY_XUICLOSED, + SYSTEMNOTIFY_INVITE_SHUTDOWN, +}; + +abstract_class IGameUI +{ +public: + virtual void Initialize(CreateInterfaceFn appFactory) = 0; + virtual void PostInit() = 0; + + virtual void Connect(CreateInterfaceFn gameFactory) = 0; + + virtual void Start() = 0; + virtual void Shutdown() = 0; + virtual void RunFrame() = 0; + + virtual void OnGameUIActivated() = 0; + virtual void OnGameUIHidden() = 0; + + virtual void OLD_OnConnectToServer(const char* game, int IP, int port) = 0; + + virtual void OnDisconnectFromServer_OLD(uint8 eSteamLoginFailure, const char* username) = 0; + virtual void OnLevelLoadingStarted(bool bShowProgressDialog) = 0; + virtual void OnLevelLoadingFinished(bool bError, const char* failureReason, const char* extendedReason) = 0; + + virtual bool UpdateProgressBar(float progress, const char* statusText) = 0; + virtual bool SetShowProgressText(bool show) = 0; + + virtual void ShowNewGameDialog(int chapter) = 0; + + virtual void SessionNotification(const int notification, const int param = 0) = 0; + virtual void SystemNotification(const int notification) = 0; + virtual void ShowMessageDialog(const uint nType, vgui::Panel* pOwner) = 0; + virtual void UpdatePlayerInfo(uint64 nPlayerId, const char* pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost) = 0; + virtual void SessionSearchResult(int searchIdx, void* pHostData, XSESSION_SEARCHRESULT* pResult, int ping) = 0; + virtual void OnCreditsFinished(void) = 0; + + virtual void SetLoadingBackgroundDialog(vgui::VPANEL panel) = 0; + + virtual void BonusMapUnlock(const char* pchFileName = NULL, const char* pchMapName = NULL) = 0; + virtual void BonusMapComplete(const char* pchFileName = NULL, const char* pchMapName = NULL) = 0; + virtual void BonusMapChallengeUpdate(const char* pchFileName, const char* pchMapName, const char* pchChallengeName, int iBest) = 0; + virtual void BonusMapChallengeNames(char* pchFileName, char* pchMapName, char* pchChallengeName) = 0; + virtual void BonusMapChallengeObjectives(int& iBronze, int& iSilver, int& iGold) = 0; + virtual void BonusMapDatabaseSave(void) = 0; + virtual int BonusMapNumAdvancedCompleted(void) = 0; + virtual void BonusMapNumMedals(int piNumMedals[3]) = 0; + + virtual void OnConnectToServer2(const char* game, int IP, int connectionPort, int queryPort) = 0; + + virtual bool ValidateStorageDevice(int* pStorageDeviceValidated) = 0; + + virtual void SetProgressOnStart() = 0; + virtual void OnDisconnectFromServer(uint8 eSteamLoginFailure) = 0; + + virtual void OnConfirmQuit(void) = 0; + + virtual bool IsMainMenuVisible(void) = 0; + + virtual void SetMainMenuOverride(vgui::VPANEL panel) = 0; + virtual void SendMainMenuCommand(const char* pszCommand) = 0; +}; + +#define GAMEUI_INTERFACE_VERSION "GameUI011" + +#endif +``` + +`SpyCustom/sdk/IHTML.h`: + +```h +#ifndef IHTML_H +#define IHTML_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "MouseCode.h" +#include "KeyCode.h" +#include "Cursor.h" +#include "IImage.h" + +namespace vgui +{ + + 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; + + enum MOUSE_STATE { UP, DOWN, MOVE, DBLCLICK }; + virtual void Obsolete_OnMouse(MouseCode code, MOUSE_STATE s, int x, int y) = 0; + virtual void Obsolete_OnChar(wchar_t unichar) = 0; + virtual void Obsolete_OnKeyDown(KeyCode code) = 0; + + virtual vgui::IImage* GetBitmap() = 0; + virtual void SetVisible(bool state) = 0; + + + virtual void SetSize(int wide, int tall) = 0; + + virtual void OnMouse(MouseCode code, MOUSE_STATE s, int x, int y, bool bPopupMenuMenu) = 0; + virtual void OnChar(wchar_t unichar, bool bPopupMenu) = 0; + virtual void OnKeyDown(KeyCode code, bool bPopupMenu) = 0; + + virtual void ScrollV(int nPixels) = 0; + virtual void ScrollH(int nPixels) = 0; + virtual void OnMouseWheeled(int delta, bool bPopupMenu) = 0; + + 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; + }; + + + enum EWebPageLoadError + { + eLoadErrorNone = 0, + eMimeTypeNotSupported, + eCacheMiss, + eBadURL, + eConnectionProblem, + eProxyConnectionProblem, + + eLoadErrorUnknown, + }; + + + 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(vgui::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; + }; + + +} + +#endif +``` + +`SpyCustom/sdk/IImage.h`: + +```h +#ifndef IIMAGE_H +#define IIMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" + +class Color; + +namespace vgui +{ + + 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 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; + }; + +} + + +#endif +``` + +`SpyCustom/sdk/IInput.h`: + +```h +#ifndef VGUI_IINPUT_H +#define VGUI_IINPUT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "interface.h" +#include "MouseCode.h" +#include "KeyCode.h" + +namespace vgui +{ + + class Cursor; + typedef unsigned long HCursor; + +#define VGUI_GCS_COMPREADSTR 0x0001 +#define VGUI_GCS_COMPREADATTR 0x0002 +#define VGUI_GCS_COMPREADCLAUSE 0x0004 +#define VGUI_GCS_COMPSTR 0x0008 +#define VGUI_GCS_COMPATTR 0x0010 +#define VGUI_GCS_COMPCLAUSE 0x0020 +#define VGUI_GCS_CURSORPOS 0x0080 +#define VGUI_GCS_DELTASTART 0x0100 +#define VGUI_GCS_RESULTREADSTR 0x0200 +#define VGUI_GCS_RESULTREADCLAUSE 0x0400 +#define VGUI_GCS_RESULTSTR 0x0800 +#define VGUI_GCS_RESULTCLAUSE 0x1000 +#define VGUI_CS_INSERTCHAR 0x2000 +#define VGUI_CS_NOMOVECARET 0x4000 + +#define MESSAGE_CURSOR_POS -1 +#define MESSAGE_CURRENT_KEYFOCUS -2 + + + class IInput : public IBaseInterface + { + public: + virtual void SetMouseFocus(VPANEL newMouseFocus) = 0; + virtual void SetMouseCapture(VPANEL panel) = 0; + + virtual void GetKeyCodeText(KeyCode code, OUT_Z_BYTECAP(buflen) char* buf, int buflen) = 0; + + virtual VPANEL GetFocus() = 0; + virtual VPANEL GetCalculatedFocus() = 0; + virtual VPANEL GetMouseOver() = 0; + + virtual void SetCursorPos(int x, int y) = 0; + virtual void GetCursorPos(int& x, int& y) = 0; + virtual bool WasMousePressed(MouseCode code) = 0; + virtual bool WasMouseDoublePressed(MouseCode code) = 0; + virtual bool IsMouseDown(MouseCode code) = 0; + + virtual void SetCursorOveride(HCursor cursor) = 0; + virtual HCursor GetCursorOveride() = 0; + + virtual bool WasMouseReleased(MouseCode code) = 0; + virtual bool WasKeyPressed(KeyCode code) = 0; + virtual bool IsKeyDown(KeyCode code) = 0; + virtual bool WasKeyTyped(KeyCode code) = 0; + virtual bool WasKeyReleased(KeyCode code) = 0; + + virtual VPANEL GetAppModalSurface() = 0; + virtual void SetAppModalSurface(VPANEL panel) = 0; + virtual void ReleaseAppModalSurface() = 0; + + virtual void GetCursorPosition(int& x, int& y) = 0; + + virtual void SetIMEWindow(void* hwnd) = 0; + virtual void* GetIMEWindow() = 0; + + virtual void OnChangeIME(bool forward) = 0; + virtual int GetCurrentIMEHandle() = 0; + virtual int GetEnglishIMEHandle() = 0; + + virtual void GetIMELanguageName(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* buf, int unicodeBufferSizeInBytes) = 0; + virtual void GetIMELanguageShortCode(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* buf, int unicodeBufferSizeInBytes) = 0; + + struct LanguageItem + { + wchar_t shortname[4]; + wchar_t menuname[128]; + int handleValue; + bool active; + }; + + struct ConversionModeItem + { + wchar_t menuname[128]; + int handleValue; + bool active; + }; + + struct SentenceModeItem + { + wchar_t menuname[128]; + int handleValue; + bool active; + }; + + virtual int GetIMELanguageList(LanguageItem* dest, int destcount) = 0; + virtual int GetIMEConversionModes(ConversionModeItem* dest, int destcount) = 0; + virtual int GetIMESentenceModes(SentenceModeItem* dest, int destcount) = 0; + + virtual void OnChangeIMEByHandle(int handleValue) = 0; + virtual void OnChangeIMEConversionModeByHandle(int handleValue) = 0; + virtual void OnChangeIMESentenceModeByHandle(int handleValue) = 0; + + virtual void OnInputLanguageChanged() = 0; + virtual void OnIMEStartComposition() = 0; + virtual void OnIMEComposition(int flags) = 0; + virtual void OnIMEEndComposition() = 0; + + virtual void OnIMEShowCandidates() = 0; + virtual void OnIMEChangeCandidates() = 0; + virtual void OnIMECloseCandidates() = 0; + virtual void OnIMERecomputeModes() = 0; + + virtual int GetCandidateListCount() = 0; + virtual void GetCandidate(int num, OUT_Z_BYTECAP(destSizeBytes) wchar_t* dest, int destSizeBytes) = 0; + virtual int GetCandidateListSelectedItem() = 0; + virtual int GetCandidateListPageSize() = 0; + virtual int GetCandidateListPageStart() = 0; + + virtual void SetCandidateWindowPos(int x, int y) = 0; + + virtual bool GetShouldInvertCompositionString() = 0; + virtual bool CandidateListStartsAtOne() = 0; + + virtual void SetCandidateListPageStart(int start) = 0; + + virtual void SetMouseCaptureEx(VPANEL panel, MouseCode captureStartMouseCode) = 0; + + virtual void RegisterKeyCodeUnhandledListener(VPANEL panel) = 0; + virtual void UnregisterKeyCodeUnhandledListener(VPANEL panel) = 0; + + virtual void OnKeyCodeUnhandled(int keyCode) = 0; + + virtual void SetModalSubTree(VPANEL subTree, VPANEL unhandledMouseClickListener, bool restrictMessagesToSubTree = true) = 0; + virtual void ReleaseModalSubTree() = 0; + virtual VPANEL GetModalSubTree() = 0; + + virtual void SetModalSubTreeReceiveMessages(bool state) = 0; + virtual bool ShouldModalSubTreeReceiveMessages() const = 0; + + virtual VPANEL GetMouseCapture() = 0; + }; + +#define VGUI_INPUT_INTERFACE_VERSION "VGUI_Input005" + +} + + +#endif +``` + +`SpyCustom/sdk/IKeyValuesSystem.h`: + +```h +#ifndef VSTDLIB_IKEYVALUESSYSTEM_H +#define VSTDLIB_IKEYVALUESSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vstdlib.h" + +typedef int HKeySymbol; +#define INVALID_KEY_SYMBOL (-1) + +class IKeyValuesSystem +{ +public: + virtual ~IKeyValuesSystem() = 0; + + virtual void RegisterSizeofKeyValues(int size) = 0; + + virtual void* AllocKeyValuesMemory(int size) = 0; + virtual void FreeKeyValuesMemory(void* pMem) = 0; + + virtual HKeySymbol GetSymbolForString(const char* name, bool bCreate = true) = 0; + virtual const char* GetStringForSymbol(HKeySymbol symbol) = 0; + + virtual void AddKeyValuesToMemoryLeakList(void* pMem, HKeySymbol name) = 0; + virtual void RemoveKeyValuesFromMemoryLeakList(void* pMem) = 0; + + virtual void SetKeyValuesExpressionSymbol(const char* name, bool bValue) = 0; + virtual bool GetKeyValuesExpressionSymbol(const char* name) = 0; + + virtual HKeySymbol GetSymbolForStringCaseSensitive(HKeySymbol& hCaseInsensitiveSymbol, const char* name, bool bCreate = true) = 0; +}; + +VSTDLIB_INTERFACE IKeyValuesSystem* KeyValuesSystem(); + +#endif + +``` + +`SpyCustom/sdk/ILocalize.h`: + +```h +#ifndef ILOCALIZE_H +#define ILOCALIZE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "IAppSystem.h" +#include "KeyValues.h" + +#if !defined(_WCHAR_T_DEFINED) && !defined(GNUC) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + + +typedef unsigned long StringIndex_t; +const unsigned long INVALID_LOCALIZE_STRING_INDEX = (StringIndex_t)-1; + +abstract_class ILocalize +{ +public: + virtual bool AddFile(const char* fileName, const char* pPathID = NULL, bool bIncludeFallbackSearchPaths = false) = 0; + + virtual void RemoveAll() = 0; + + virtual wchar_t* Find(char const* tokenName) = 0; + + virtual StringIndex_t FindIndex(const char* tokenName) = 0; + + virtual const char* GetNameByIndex(StringIndex_t index) = 0; + virtual wchar_t* GetValueByIndex(StringIndex_t index) = 0; + + virtual StringIndex_t GetFirstStringIndex() = 0; + virtual StringIndex_t GetNextStringIndex(StringIndex_t index) = 0; + + virtual void AddString(const char* tokenName, wchar_t* unicodeString, const char* fileName) = 0; + + virtual void SetValueByIndex(StringIndex_t index, wchar_t* newValue) = 0; + + virtual bool SaveToFile(const char* fileName) = 0; + + virtual int GetLocalizationFileCount() = 0; + virtual const char* GetLocalizationFileName(int index) = 0; + + virtual const char* GetFileNameByIndex(StringIndex_t index) = 0; + + virtual void ReloadLocalizationFiles() = 0; + + virtual const char* FindAsUTF8(const char* pchTokenName) = 0; + + virtual void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* unicodeOutput, int unicodeBufferSizeInBytes, const char* tokenName, KeyValues* localizationVariables) = 0; + virtual void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* unicodeOutput, int unicodeBufferSizeInBytes, StringIndex_t unlocalizedTextSymbol, KeyValues* localizationVariables) = 0; + + static int ConvertANSIToUnicode(const char* ansi, OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* unicode, int unicodeBufferSizeInBytes); + + static int ConvertUnicodeToANSI(const wchar_t* unicode, OUT_Z_BYTECAP(ansiBufferSize) char* ansi, int ansiBufferSize); + + template < typename T > + static void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T* unicodeOuput, int unicodeBufferSizeInBytes, const T* formatString, int numFormatParameters, ...) + { + va_list argList; + va_start(argList, numFormatParameters); + + ConstructStringVArgsInternal(unicodeOuput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList); + + va_end(argList); + } + + template < typename T > + static void ConstructStringVArgs(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T* unicodeOuput, int unicodeBufferSizeInBytes, const T* formatString, int numFormatParameters, va_list argList) + { + ConstructStringVArgsInternal(unicodeOuput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList); + } + + template < typename T > + static void ConstructString(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) T* unicodeOutput, int unicodeBufferSizeInBytes, const T* formatString, KeyValues* localizationVariables) + { + ConstructStringKeyValuesInternal(unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables); + } + +private: + static void ConstructStringVArgsInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) char* unicodeOutput, int unicodeBufferSizeInBytes, const char* formatString, int numFormatParameters, va_list argList); + static void ConstructStringVArgsInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t* formatString, int numFormatParameters, va_list argList); + + static void ConstructStringKeyValuesInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) char* unicodeOutput, int unicodeBufferSizeInBytes, const char* formatString, KeyValues* localizationVariables); + static void ConstructStringKeyValuesInternal(OUT_Z_BYTECAP(unicodeBufferSizeInBytes) wchar_t* unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t* formatString, KeyValues* localizationVariables); +}; + +#ifdef GC + +typedef char locchar_t; + +#define loc_snprintf Q_snprintf +#define loc_sprintf_safe V_sprintf_safe +#define loc_sncat Q_strncat +#define loc_scat_safe V_strcat_safe +#define loc_sncpy Q_strncpy +#define loc_scpy_safe V_strcpy_safe +#define loc_strlen Q_strlen +#define LOCCHAR( x ) x + +#else + +typedef wchar_t locchar_t; + +#define loc_snprintf V_snwprintf +#define loc_sprintf_safe V_swprintf_safe +#define loc_sncat V_wcsncat +#define loc_scat_safe V_wcscat_safe +#define loc_sncpy Q_wcsncpy +#define loc_scpy_safe V_wcscpy_safe +#define loc_strlen Q_wcslen +#define LOCCHAR(x) L ## x + +#endif + +template < typename T > +class TypedKeyValuesStringHelper +{ +public: + static const T* Read(KeyValues* pKeyValues, const char* pKeyName, const T* pDefaultValue); + static void Write(KeyValues* pKeyValues, const char* pKeyName, const T* pValue); +}; + +template < > +class TypedKeyValuesStringHelper +{ +public: + static const char* Read(KeyValues* pKeyValues, const char* pKeyName, const char* pDefaultValue) { return pKeyValues->GetString(pKeyName, pDefaultValue); } + static void Write(KeyValues* pKeyValues, const char* pKeyName, const char* pValue) { pKeyValues->SetString(pKeyName, pValue); } +}; + +template < > +class TypedKeyValuesStringHelper +{ +public: + static const wchar_t* Read(KeyValues* pKeyValues, const char* pKeyName, const wchar_t* pDefaultValue) { return pKeyValues->GetWString(pKeyName, pDefaultValue); } + static void Write(KeyValues* pKeyValues, const char* pKeyName, const wchar_t* pValue) { pKeyValues->SetWString(pKeyName, pValue); } +}; + +template < typename T > +class CLocalizedStringArg; + +template < typename T > +class CLocalizedStringArgStringImpl +{ +public: + enum { kIsValid = true }; + + CLocalizedStringArgStringImpl(const locchar_t* pStr) : m_pStr(pStr) { } + + const locchar_t* GetLocArg() const { Assert(m_pStr); return m_pStr; } + +private: + const locchar_t* m_pStr; +}; + +template < typename T > +class CLocalizedStringArg : public CLocalizedStringArgStringImpl +{ +public: + CLocalizedStringArg(const locchar_t* pStr) : CLocalizedStringArgStringImpl(pStr) { } +}; + +template < typename T > +class CLocalizedStringArgPrintfImpl +{ +public: + enum { kIsValid = true }; + + CLocalizedStringArgPrintfImpl(T value, const locchar_t* loc_Format) { loc_snprintf(m_cBuffer, kBufferSize, loc_Format, value); } + + const locchar_t* GetLocArg() const { return m_cBuffer; } + +private: + enum { kBufferSize = 128, }; + locchar_t m_cBuffer[kBufferSize]; +}; + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg(uint16 unValue) : CLocalizedStringArgPrintfImpl(unValue, LOCCHAR("%u")) { } +}; + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg(uint32 unValue) : CLocalizedStringArgPrintfImpl(unValue, LOCCHAR("%u")) { } +}; + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg(uint64 unValue) : CLocalizedStringArgPrintfImpl(unValue, LOCCHAR("%llu")) { } +}; + +template < > +class CLocalizedStringArg : public CLocalizedStringArgPrintfImpl +{ +public: + CLocalizedStringArg(float fValue) + : CLocalizedStringArgPrintfImpl(fValue, + fabsf(fValue) <= FLT_EPSILON || fabsf(fValue) >= 1.0f ? LOCCHAR("%.0f") : LOCCHAR("%.1f")) + { + } +}; + +class CConstructLocalizedString +{ +public: + template < typename T > + CConstructLocalizedString(const locchar_t* loc_Format, T arg0) + { + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + + m_loc_Buffer[0] = '\0'; + + if (loc_Format) + { + ::ILocalize::ConstructString(m_loc_Buffer, sizeof(m_loc_Buffer), loc_Format, 1, CLocalizedStringArg(arg0).GetLocArg()); + } + } + + template < typename T, typename U > + CConstructLocalizedString(const locchar_t* loc_Format, T arg0, U arg1) + { + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + + m_loc_Buffer[0] = '\0'; + + if (loc_Format) + { + ::ILocalize::ConstructString(m_loc_Buffer, sizeof(m_loc_Buffer), loc_Format, 2, CLocalizedStringArg(arg0).GetLocArg(), CLocalizedStringArg(arg1).GetLocArg()); + } + } + + template < typename T, typename U, typename V > + CConstructLocalizedString(const locchar_t* loc_Format, T arg0, U arg1, V arg2) + { + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + + m_loc_Buffer[0] = '\0'; + + if (loc_Format) + { + ::ILocalize::ConstructString(m_loc_Buffer, + sizeof(m_loc_Buffer), + loc_Format, + 3, + CLocalizedStringArg(arg0).GetLocArg(), + CLocalizedStringArg(arg1).GetLocArg(), + CLocalizedStringArg(arg2).GetLocArg()); + } + } + + template < typename T, typename U, typename V, typename W > + CConstructLocalizedString(const locchar_t* loc_Format, T arg0, U arg1, V arg2, W arg3) + { + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + + m_loc_Buffer[0] = '\0'; + + if (loc_Format) + { + ::ILocalize::ConstructString(m_loc_Buffer, + sizeof(m_loc_Buffer), + loc_Format, + 4, + CLocalizedStringArg(arg0).GetLocArg(), + CLocalizedStringArg(arg1).GetLocArg(), + CLocalizedStringArg(arg2).GetLocArg(), + CLocalizedStringArg(arg3).GetLocArg()); + } + } + + template < typename T, typename U, typename V, typename W, typename X, typename Y > + CConstructLocalizedString(const locchar_t* loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4, Y arg5) + { + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + + m_loc_Buffer[0] = '\0'; + + if (loc_Format) + { + ::ILocalize::ConstructString(m_loc_Buffer, + sizeof(m_loc_Buffer), + loc_Format, + 6, + CLocalizedStringArg(arg0).GetLocArg(), + CLocalizedStringArg(arg1).GetLocArg(), + CLocalizedStringArg(arg2).GetLocArg(), + CLocalizedStringArg(arg3).GetLocArg(), + CLocalizedStringArg(arg4).GetLocArg(), + CLocalizedStringArg(arg5).GetLocArg()); + } + } + + template < typename T, typename U, typename V, typename W, typename X, typename Y, typename Z > + CConstructLocalizedString(const locchar_t* loc_Format, T arg0, U arg1, V arg2, W arg3, X arg4, Y arg5, Z arg6) + { + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + COMPILE_TIME_ASSERT(CLocalizedStringArg::kIsValid); + + m_loc_Buffer[0] = '\0'; + + if (loc_Format) + { + ::ILocalize::ConstructString(m_loc_Buffer, + sizeof(m_loc_Buffer), + loc_Format, + 7, + CLocalizedStringArg(arg0).GetLocArg(), + CLocalizedStringArg(arg1).GetLocArg(), + CLocalizedStringArg(arg2).GetLocArg(), + CLocalizedStringArg(arg3).GetLocArg(), + CLocalizedStringArg(arg4).GetLocArg(), + CLocalizedStringArg(arg5).GetLocArg(), + CLocalizedStringArg(arg6).GetLocArg()); + } + } + + CConstructLocalizedString(const locchar_t* loc_Format, KeyValues* pKeyValues) + { + m_loc_Buffer[0] = '\0'; + + if (loc_Format && pKeyValues) + { + ::ILocalize::ConstructString(m_loc_Buffer, sizeof(m_loc_Buffer), loc_Format, pKeyValues); + } + } + + operator const locchar_t* () const + { + return m_loc_Buffer; + } + +private: + enum { kBufferSize = 512, }; + locchar_t m_loc_Buffer[kBufferSize]; +}; +namespace vgui +{ + class ILocalize : public ::ILocalize { }; +} + +#define VGUI_LOCALIZE_INTERFACE_VERSION "VGUI_Localize005" + + + +#endif +``` + +`SpyCustom/sdk/IMesh.h`: + +```h +#ifndef IMESH_H +#define IMESH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "imaterial.h" +#include +#include +#include "dbg.h" +#include "meshutils.h" + +#include "imaterialsystem.h" + +#ifdef OSX +#endif + +class IMaterial; +class CMeshBuilder; +class IMaterialVar; +typedef uint64 VertexFormat_t; +struct ShaderStencilState_t; + + +#ifdef _DEBUG +#endif + + +enum +{ + VERTEX_MAX_TEXTURE_COORDINATES = 8, + BONE_MATRIX_INDEX_INVALID = 255 +}; + +enum +{ + INDEX_BUFFER_SIZE = 32768, + DYNAMIC_VERTEX_BUFFER_MEMORY = (1024 + 512) * 1024, + DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL = 384 * 1024, +}; + +enum WriteCombineOrdering_t +{ + MB_FIELD_NONE = -1, + MB_FIELD_POSITION = 0, + MB_FIELD_BONE_WEIGHTS, + MB_FIELD_BONE_INDEX, + MB_FIELD_NORMAL, + MB_FIELD_COLOR, + MB_FIELD_SPECULAR, + MB_FIELD_TEXCOORD_FIRST, + MB_FIELD_TEXCOORD_LAST = MB_FIELD_TEXCOORD_FIRST + VERTEX_MAX_TEXTURE_COORDINATES - 1, + MB_FIELD_TANGENT_S, + MB_FIELD_TANGENT_T, + MB_FIELD_USERDATA, +}; + +#define MB_FIELD_TEXCOORD( nStage ) ( MB_FIELD_TEXCOORD_FIRST + ( nStage ) ) + +struct VertexDesc_t +{ + int m_VertexSize_Position; + int m_VertexSize_BoneWeight; + int m_VertexSize_BoneMatrixIndex; + int m_VertexSize_Normal; + int m_VertexSize_Color; + int m_VertexSize_Specular; + int m_VertexSize_TexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + int m_VertexSize_TangentS; + int m_VertexSize_TangentT; + int m_VertexSize_Wrinkle; + + int m_VertexSize_UserData; + + int m_ActualVertexSize; + VertexCompressionType_t m_CompressionType; + + int m_NumBoneWeights; + + float* m_pPosition; + + float* m_pBoneWeight; + +#ifndef NEW_SKINNING + unsigned char* m_pBoneMatrixIndex; +#else + float* m_pBoneMatrixIndex; +#endif + + float* m_pNormal; + + unsigned char* m_pColor; + unsigned char* m_pSpecular; + float* m_pTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + + float* m_pTangentS; + float* m_pTangentT; + + float* m_pWrinkle; + + float* m_pUserData; + + int m_nFirstVertex; + + unsigned int m_nOffset; + +#ifdef DEBUG_WRITE_COMBINE + int m_nLastWrittenField; + unsigned char* m_pLastWrittenAddress; +#endif +}; + +struct IndexDesc_t +{ + unsigned short* m_pIndices; + + unsigned int m_nOffset; + + unsigned int m_nFirstIndex; + + unsigned int m_nIndexSize; +}; + + +struct MeshDesc_t : public VertexDesc_t, public IndexDesc_t +{ +}; + + +struct ModelVertexDX8_t +{ + Vector m_vecPosition; + Vector m_vecNormal; + Vector2D m_vecTexCoord; + Vector4D m_vecUserData; +}; + +struct QuadTessVertex_t +{ + Vector4D m_vTangent; + Vector4D m_vUV01; + Vector4D m_vUV23; +}; + +struct MeshBoneRemap_t +{ + DECLARE_BYTESWAP_DATADESC(); + int m_nActualBoneIndex; + int m_nSrcBoneIndex; +}; + +struct MeshInstanceData_t +{ + int m_nIndexOffset; + int m_nIndexCount; + int m_nBoneCount; + MeshBoneRemap_t* m_pBoneRemap; + matrix3x4_t* m_pPoseToWorld; + const ITexture* m_pEnvCubemap; + MaterialLightingState_t* m_pLightingState; + MaterialPrimitiveType_t m_nPrimType; + const IVertexBuffer* m_pVertexBuffer; + int m_nVertexOffsetInBytes; + const IIndexBuffer* m_pIndexBuffer; + const IVertexBuffer* m_pColorBuffer; + int m_nColorVertexOffsetInBytes; + ShaderStencilState_t* m_pStencilState; + Vector4D m_DiffuseModulation; +}; + +struct MeshBuffersAllocationSettings_t +{ + uint32 m_uiIbUsageFlags; +}; + +inline float* OffsetFloatPointer(float* pBufferPointer, int nVertexCount, int vertexSize) +{ + return reinterpret_cast( + reinterpret_cast(pBufferPointer) + + nVertexCount * vertexSize); +} + +inline const float* OffsetFloatPointer(const float* pBufferPointer, int nVertexCount, int vertexSize) +{ + return reinterpret_cast( + reinterpret_cast(pBufferPointer) + + nVertexCount * vertexSize); +} + +inline void IncrementFloatPointer(float*& pBufferPointer, int vertexSize) +{ + pBufferPointer = reinterpret_cast(reinterpret_cast(pBufferPointer) + vertexSize); +} + + +class CPrimList +{ +public: + CPrimList(); + CPrimList(int nFirstIndex, int nIndexCount); + + int m_FirstIndex; + int m_NumIndices; +}; + +inline CPrimList::CPrimList() +{ +} + +inline CPrimList::CPrimList(int nFirstIndex, int nIndexCount) +{ + m_FirstIndex = nFirstIndex; + m_NumIndices = nIndexCount; +} + +abstract_class IVertexBuffer +{ +public: + virtual int VertexCount() const = 0; + virtual VertexFormat_t GetVertexFormat() const = 0; + + virtual bool IsDynamic() const = 0; + + virtual void BeginCastBuffer(VertexFormat_t format) = 0; + virtual void EndCastBuffer() = 0; + + virtual int GetRoomRemaining() const = 0; + + virtual bool Lock(int nVertexCount, bool bAppend, VertexDesc_t& desc) = 0; + virtual void Unlock(int nVertexCount, VertexDesc_t& desc) = 0; + + virtual void Spew(int nVertexCount, const VertexDesc_t& desc) = 0; + + virtual void ValidateData(int nVertexCount, const VertexDesc_t& desc) = 0; +}; + +abstract_class IIndexBuffer +{ +public: + virtual int IndexCount() const = 0; + virtual MaterialIndexFormat_t IndexFormat() const = 0; + + virtual bool IsDynamic() const = 0; + + virtual void BeginCastBuffer(MaterialIndexFormat_t format) = 0; + virtual void EndCastBuffer() = 0; + + virtual int GetRoomRemaining() const = 0; + + virtual bool Lock(int nMaxIndexCount, bool bAppend, IndexDesc_t& desc) = 0; + virtual void Unlock(int nWrittenIndexCount, IndexDesc_t& desc) = 0; + + virtual void ModifyBegin(bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc) = 0; + virtual void ModifyEnd(IndexDesc_t& desc) = 0; + + virtual void Spew(int nIndexCount, const IndexDesc_t& desc) = 0; + + virtual void ValidateData(int nIndexCount, const IndexDesc_t& desc) = 0; + + virtual IMesh* GetMesh() = 0; +}; + +abstract_class ICachedPerFrameMeshData +{ +public: + virtual void Free() = 0; +}; + +abstract_class IMesh : public IVertexBuffer, public IIndexBuffer +{ +public: + virtual void SetPrimitiveType(MaterialPrimitiveType_t type) = 0; + + virtual void Draw(int firstIndex = -1, int numIndices = 0) = 0; + + virtual void SetColorMesh(IMesh* pColorMesh, int nVertexOffset) = 0; + + virtual void Draw(CPrimList* pLists, int nLists) = 0; + + virtual void CopyToMeshBuilder( + int iStartVert, + int nVerts, + int iStartIndex, + int nIndices, + int indexOffset, + CMeshBuilder& builder) = 0; + + virtual void Spew(int numVerts, int numIndices, const MeshDesc_t& desc) = 0; + + virtual void ValidateData(int numVerts, int numIndices, const MeshDesc_t& desc) = 0; + + virtual void LockMesh(int numVerts, int numIndices, MeshDesc_t& desc, MeshBuffersAllocationSettings_t* pSettings) = 0; + virtual void ModifyBegin(int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc) = 0; + virtual void ModifyEnd(MeshDesc_t& desc) = 0; + virtual void UnlockMesh(int numVerts, int numIndices, MeshDesc_t& desc) = 0; + + virtual void ModifyBeginEx(bool bReadOnly, int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc) = 0; + + virtual void SetFlexMesh(IMesh* pMesh, int nVertexOffset) = 0; + + virtual void DisableFlexMesh() = 0; + + virtual void MarkAsDrawn() = 0; + + virtual void DrawModulated(const Vector4D& vecDiffuseModulation, int firstIndex = -1, int numIndices = 0) = 0; + + virtual unsigned int ComputeMemoryUsed() = 0; + + virtual void* AccessRawHardwareDataStream(uint8 nRawStreamIndex, uint32 numBytes, uint32 uiFlags, void* pvContext) = 0; + + virtual ICachedPerFrameMeshData* GetCachedPerFrameMeshData() = 0; + virtual void ReconstructFromCachedPerFrameMeshData(ICachedPerFrameMeshData* pData) = 0; +}; + + +#include "meshreader.h" + +#define INVALID_BUFFER_OFFSET 0xFFFFFFFFUL + +#define VTX_HAVEPOS 1 +#define VTX_HAVENORMAL 2 +#define VTX_HAVECOLOR 4 +#define VTX_HAVEALL ( VTX_HAVEPOS | VTX_HAVENORMAL | VTX_HAVECOLOR ) + + +class CVertexBuilder : private VertexDesc_t +{ +public: + CVertexBuilder(); + CVertexBuilder(IVertexBuffer* pVertexBuffer, VertexFormat_t fmt = 0); + ~CVertexBuilder(); + + bool Lock(int nMaxIndexCount, bool bAppend = false); + void Unlock(); + + void SpewData(); + + int GetRoomRemaining() const; + + void Bind(IMatRenderContext* pContext, int nStreamID, VertexFormat_t usage = 0); + + int Offset() const; + + void SetCompressionType(VertexCompressionType_t compressionType); + void ValidateCompressionType(); + + void Begin(IVertexBuffer* pVertexBuffer, int nVertexCount, int* nFirstVertex); + void Begin(IVertexBuffer* pVertexBuffer, int nVertexCount); + + void End(bool bSpewData = false); + + void BeginModify(IVertexBuffer* pVertexBuffer, int nFirstVertex = 0, int nVertexCount = -1); + void EndModify(bool bSpewData = false); + + int VertexCount() const; + + int TotalVertexCount() const; + + void Reset(); + + int VertexSize() { return m_ActualVertexSize; } + + int TextureCoordinateSize(int nTexCoordNumber) { return m_VertexSize_TexCoord[nTexCoordNumber]; } + + void* BaseVertexData(); + + void SelectVertex(int idx); + + void AdvanceVertex(void); + template void AdvanceVertexF(void); + void AdvanceVertices(int nVerts); + + int GetCurrentVertex() const; + int GetFirstVertex() const; + + const float* Position() const; + + const float* Normal() const; + + unsigned int Color() const; + + unsigned char* Specular() const; + + const float* TexCoord(int stage) const; + + const float* TangentS() const; + const float* TangentT() const; + + const float* BoneWeight() const; + float Wrinkle() const; + + int NumBoneWeights() const; +#ifndef NEW_SKINNING + unsigned char* BoneMatrix() const; +#else + float* BoneMatrix() const; +#endif + + void Position3f(float x, float y, float z); + void Position3fv(const float* v); + + void Normal3f(float nx, float ny, float nz); + void Normal3fv(const float* n); + void NormalDelta3fv(const float* n); + void NormalDelta3f(float nx, float ny, float nz); + template void CompressedNormal3f(float nx, float ny, float nz); + template void CompressedNormal3fv(const float* n); + + void Color3f(float r, float g, float b); + void Color3fv(const float* rgb); + void Color4f(float r, float g, float b, float a); + void Color4fv(const float* rgba); + + void Color3ub(unsigned char r, unsigned char g, unsigned char b); + void Color3ubv(unsigned char const* rgb); + void Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); + void Color4ubv(unsigned char const* rgba); + void Color4Packed(int packedColor); + int PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a); + + void Specular3f(float r, float g, float b); + void Specular3fv(const float* rgb); + void Specular4f(float r, float g, float b, float a); + void Specular4fv(const float* rgba); + + void Specular3ub(unsigned char r, unsigned char g, unsigned char b); + void Specular3ubv(unsigned char const* c); + void Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); + void Specular4ubv(unsigned char const* c); + + void TexCoord1f(int stage, float s); + void TexCoord2f(int stage, float s, float t); + void TexCoord2fv(int stage, const float* st); + void TexCoord3f(int stage, float s, float t, float u); + void TexCoord3fv(int stage, const float* stu); + void TexCoord4f(int stage, float s, float t, float u, float w); + void TexCoord4fv(int stage, const float* stuv); + + void TexCoordSubRect2f(int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT); + void TexCoordSubRect2fv(int stage, const float* st, const float* offset, const float* scale); + + void TangentS3f(float sx, float sy, float sz); + void TangentS3fv(const float* s); + + void TangentT3f(float tx, float ty, float tz); + void TangentT3fv(const float* t); + + void Wrinkle1f(float flWrinkle); + + void BoneWeight(int idx, float weight); + void BoneWeights2(float weight1, float weight2); + + template void CompressedBoneWeight3fv(const float* pWeights); + + void BoneMatrix(int idx, int matrixIndex); + void BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3); + + void UserData(const float* pData); + template void CompressedUserData(const float* pData); + + void FastVertex(const ModelVertexDX8_t& vertex); + void FastVertexSSE(const ModelVertexDX8_t& vertex); + void FastQuadVertexSSE(const QuadTessVertex_t& vertex); + + void FastAdvanceNVertices(int n); + +#if defined( _X360 ) + void VertexDX8ToX360(const ModelVertexDX8_t& vertex); +#endif + + void AttachBegin(IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t& desc); + void AttachEnd(); + void AttachBeginModify(IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t& desc); + void AttachEndModify(); + +private: + IVertexBuffer* m_pVertexBuffer; + + bool m_bModify; + + int m_nMaxVertexCount; + + int m_nVertexCount; + + mutable int m_nCurrentVertex; + + mutable float* m_pCurrPosition; + mutable float* m_pCurrNormal; + mutable unsigned char* m_pCurrColor; + mutable float* m_pCurrTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + + int m_nTotalVertexCount; + + unsigned int m_nBufferOffset; + unsigned int m_nBufferFirstVertex; + +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + bool m_bWrittenNormal : 1; + bool m_bWrittenUserData : 1; +#endif + + friend class CMeshBuilder; +}; + + +inline CVertexBuilder::CVertexBuilder() +{ + m_pVertexBuffer = NULL; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstVertex = 0; + m_nVertexCount = 0; + m_nCurrentVertex = 0; + m_nMaxVertexCount = 0; + m_nTotalVertexCount = 0; + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); + m_bModify = false; +#endif +} + +inline CVertexBuilder::CVertexBuilder(IVertexBuffer* pVertexBuffer, VertexFormat_t fmt) +{ + m_pVertexBuffer = pVertexBuffer; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstVertex = 0; + m_nVertexCount = 0; + m_nCurrentVertex = 0; + m_nMaxVertexCount = 0; + m_nTotalVertexCount = 0; + m_CompressionType = VERTEX_COMPRESSION_INVALID; + + if (m_pVertexBuffer->IsDynamic()) + { + m_pVertexBuffer->BeginCastBuffer(fmt); + } + else + { + Assert(m_pVertexBuffer->GetVertexFormat() == fmt); + } + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); + m_bModify = false; +#endif +} + +inline CVertexBuilder::~CVertexBuilder() +{ + if (m_pVertexBuffer && m_pVertexBuffer->IsDynamic()) + { + m_pVertexBuffer->EndCastBuffer(); + } +} + +inline bool CVertexBuilder::Lock(int nMaxVertexCount, bool bAppend) +{ + Assert(m_pVertexBuffer); + m_bModify = false; + m_nMaxVertexCount = nMaxVertexCount; + bool bFirstLock = (m_nBufferOffset == INVALID_BUFFER_OFFSET); + if (bFirstLock) + { + bAppend = false; + } + if (!bAppend) + { + m_nTotalVertexCount = 0; + } + + if (!m_pVertexBuffer->Lock(m_nMaxVertexCount, bAppend, *this)) + { + m_nMaxVertexCount = 0; + return false; + } + + Reset(); + + if (bFirstLock) + { + m_nBufferOffset = m_nOffset; + m_nBufferFirstVertex = m_nFirstVertex; + } + + return true; +} + +inline void CVertexBuilder::Unlock() +{ + Assert(!m_bModify && m_pVertexBuffer); + +#ifdef _DEBUG + m_pVertexBuffer->ValidateData(m_nVertexCount, *this); +#endif + + m_pVertexBuffer->Unlock(m_nVertexCount, *this); + m_nTotalVertexCount += m_nVertexCount; + + m_nMaxVertexCount = 0; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); + memset(static_cast(this), 0, sizeof(VertexDesc_t)); +#endif +} + +inline void CVertexBuilder::SpewData() +{ + m_pVertexBuffer->Spew(m_nVertexCount, *this); +} + + +inline void CVertexBuilder::Bind(IMatRenderContext* pContext, int nStreamID, VertexFormat_t usage) +{ + if (m_pVertexBuffer && (m_nBufferOffset != INVALID_BUFFER_OFFSET)) + { + pContext->BindVertexBuffer(nStreamID, m_pVertexBuffer, m_nBufferOffset, + m_nFirstVertex, m_nTotalVertexCount, usage ? usage : m_pVertexBuffer->GetVertexFormat()); + } + else + { + pContext->BindVertexBuffer(nStreamID, NULL, 0, 0, 0, 0); + } +} + + +inline int CVertexBuilder::Offset() const +{ + return m_nBufferOffset; +} + +inline int CVertexBuilder::GetFirstVertex() const +{ + return m_nBufferFirstVertex; +} + +inline void CVertexBuilder::SetCompressionType(VertexCompressionType_t compressionType) +{ + m_CompressionType = compressionType; +} + +inline void CVertexBuilder::ValidateCompressionType() +{ +#ifdef _DEBUG + VertexCompressionType_t vbCompressionType = CompressionType(m_pVertexBuffer->GetVertexFormat()); + if (vbCompressionType != VERTEX_COMPRESSION_NONE) + { + Assert(m_CompressionType == vbCompressionType); + if (m_CompressionType != vbCompressionType) + { + Warning("ERROR: CVertexBuilder::SetCompressionType() must be called to specify the same vertex compression type (%s) as the vertex buffer being modified." + "Junk vertices will be rendered, or there will be a crash in CVertexBuilder!\n", + vbCompressionType == VERTEX_COMPRESSION_ON ? "VERTEX_COMPRESSION_ON" : "VERTEX_COMPRESSION_NONE"); + } + Assert(!m_pVertexBuffer->IsDynamic()); + } +#endif +} + +inline void CVertexBuilder::Begin(IVertexBuffer* pVertexBuffer, int nVertexCount) +{ + Assert(pVertexBuffer && (!m_pVertexBuffer)); + + m_pVertexBuffer = pVertexBuffer; + m_bModify = false; + + m_nMaxVertexCount = nVertexCount; + m_nVertexCount = 0; + + ValidateCompressionType(); + + m_pVertexBuffer->Lock(m_nMaxVertexCount, false, *this); + + Reset(); +} + + +inline void CVertexBuilder::End(bool bSpewData) +{ + Assert(!m_bModify); + + if (bSpewData) + { + m_pVertexBuffer->Spew(m_nVertexCount, *this); + } + +#ifdef _DEBUG + m_pVertexBuffer->ValidateData(m_nVertexCount, *this); +#endif + + m_pVertexBuffer->Unlock(m_nVertexCount, *this); + + m_pVertexBuffer = 0; + m_nMaxVertexCount = 0; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); + memset(static_cast(this), 0, sizeof(VertexDesc_t)); +#endif +} + + +inline void CVertexBuilder::AttachBegin(IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t& desc) +{ + m_pVertexBuffer = pMesh; + memcpy(static_cast(this), static_cast(&desc), sizeof(VertexDesc_t)); + m_nMaxVertexCount = nMaxVertexCount; + m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; + m_nVertexCount = 0; + m_bModify = false; + + ValidateCompressionType(); + + if (m_nBufferOffset == INVALID_BUFFER_OFFSET) + { + m_nTotalVertexCount = 0; + m_nBufferOffset = static_cast(&desc)->m_nOffset; + m_nBufferFirstVertex = desc.m_nFirstVertex; + } +} + +inline void CVertexBuilder::AttachEnd() +{ + Assert(!m_bModify); + + m_nMaxVertexCount = 0; + m_pVertexBuffer = NULL; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); + memset(static_cast(this), 0, sizeof(VertexDesc_t)); +#endif +} + +inline void CVertexBuilder::AttachBeginModify(IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t& desc) +{ + Assert(pMesh && (!m_pVertexBuffer)); + + m_pVertexBuffer = pMesh; + memcpy(static_cast(this), static_cast(&desc), sizeof(VertexDesc_t)); + m_nMaxVertexCount = m_nVertexCount = nVertexCount; + m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; + m_bModify = true; + + ValidateCompressionType(); +} + +inline void CVertexBuilder::AttachEndModify() +{ + Assert(m_pVertexBuffer); + Assert(m_bModify); + + m_pVertexBuffer = 0; + m_nMaxVertexCount = 0; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset(m_pCurrTexCoord, 0, sizeof(m_pCurrTexCoord)); + memset(static_cast(this), 0, sizeof(VertexDesc_t)); +#endif +} + + +inline unsigned char* FindMinAddress(void* pAddress1, void* pAddress2, int nAddress2Size) +{ + if (nAddress2Size == 0) + return (unsigned char*)pAddress1; + if (!pAddress1) + return (unsigned char*)pAddress2; + return (pAddress1 < pAddress2) ? (unsigned char*)pAddress1 : (unsigned char*)pAddress2; +} + +inline void CVertexBuilder::Reset() +{ + m_nCurrentVertex = 0; + + m_pCurrPosition = m_pPosition; + m_pCurrNormal = m_pNormal; + for (size_t i = 0; i < NELEMS(m_pCurrTexCoord); i++) + { + m_pCurrTexCoord[i] = m_pTexCoord[i]; + } + m_pCurrColor = m_pColor; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif + +#ifdef DEBUG_WRITE_COMBINE + m_nLastWrittenField = MB_FIELD_NONE; + m_pLastWrittenAddress = NULL; + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pPosition, m_VertexSize_Position); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pBoneWeight, m_VertexSize_BoneWeight); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pBoneMatrixIndex, m_VertexSize_BoneMatrixIndex); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pNormal, m_VertexSize_Normal); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pColor, m_VertexSize_Color); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pSpecular, m_VertexSize_Specular); + for (int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i) + { + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pTexCoord[i], m_VertexSize_TexCoord[i]); + } + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pTangentS, m_VertexSize_TangentS); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pTangentT, m_VertexSize_TangentT); + m_pLastWrittenAddress = FindMinAddress(m_pLastWrittenAddress, m_pUserData, m_VertexSize_UserData); +#endif +} + + +inline int CVertexBuilder::VertexCount() const +{ + return m_nVertexCount; +} + + +inline int CVertexBuilder::TotalVertexCount() const +{ + return m_nTotalVertexCount; +} + + +inline void* CVertexBuilder::BaseVertexData() +{ + Assert(m_pPosition); + return m_pPosition; +} + + +inline void CVertexBuilder::SelectVertex(int nIndex) +{ + Assert((nIndex >= 0) && (nIndex < m_nMaxVertexCount)); + m_nCurrentVertex = nIndex; + + m_pCurrPosition = OffsetFloatPointer(m_pPosition, m_nCurrentVertex, m_VertexSize_Position); + m_pCurrNormal = OffsetFloatPointer(m_pNormal, m_nCurrentVertex, m_VertexSize_Normal); + + COMPILE_TIME_ASSERT(VERTEX_MAX_TEXTURE_COORDINATES == 8); + m_pCurrTexCoord[0] = OffsetFloatPointer(m_pTexCoord[0], m_nCurrentVertex, m_VertexSize_TexCoord[0]); + m_pCurrTexCoord[1] = OffsetFloatPointer(m_pTexCoord[1], m_nCurrentVertex, m_VertexSize_TexCoord[1]); + m_pCurrTexCoord[2] = OffsetFloatPointer(m_pTexCoord[2], m_nCurrentVertex, m_VertexSize_TexCoord[2]); + m_pCurrTexCoord[3] = OffsetFloatPointer(m_pTexCoord[3], m_nCurrentVertex, m_VertexSize_TexCoord[3]); + m_pCurrTexCoord[4] = OffsetFloatPointer(m_pTexCoord[4], m_nCurrentVertex, m_VertexSize_TexCoord[4]); + m_pCurrTexCoord[5] = OffsetFloatPointer(m_pTexCoord[5], m_nCurrentVertex, m_VertexSize_TexCoord[5]); + m_pCurrTexCoord[6] = OffsetFloatPointer(m_pTexCoord[6], m_nCurrentVertex, m_VertexSize_TexCoord[6]); + m_pCurrTexCoord[7] = OffsetFloatPointer(m_pTexCoord[7], m_nCurrentVertex, m_VertexSize_TexCoord[7]); + m_pCurrColor = m_pColor + m_nCurrentVertex * m_VertexSize_Color; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +template FORCEINLINE void CVertexBuilder::AdvanceVertexF() +{ + if (++m_nCurrentVertex > m_nVertexCount) + { + m_nVertexCount = m_nCurrentVertex; + } + + if (nFlags & VTX_HAVEPOS) + IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); + if (nFlags & VTX_HAVENORMAL) + IncrementFloatPointer(m_pCurrNormal, m_VertexSize_Normal); + if (nFlags & VTX_HAVECOLOR) + m_pCurrColor += m_VertexSize_Color; + + COMPILE_TIME_ASSERT(VERTEX_MAX_TEXTURE_COORDINATES == 8); + if (nNumTexCoords > 0) + IncrementFloatPointer(m_pCurrTexCoord[0], m_VertexSize_TexCoord[0]); + if (nNumTexCoords > 1) + IncrementFloatPointer(m_pCurrTexCoord[1], m_VertexSize_TexCoord[1]); + if (nNumTexCoords > 2) + IncrementFloatPointer(m_pCurrTexCoord[2], m_VertexSize_TexCoord[2]); + if (nNumTexCoords > 3) + IncrementFloatPointer(m_pCurrTexCoord[3], m_VertexSize_TexCoord[3]); + if (nNumTexCoords > 4) + IncrementFloatPointer(m_pCurrTexCoord[4], m_VertexSize_TexCoord[4]); + if (nNumTexCoords > 5) + IncrementFloatPointer(m_pCurrTexCoord[5], m_VertexSize_TexCoord[5]); + if (nNumTexCoords > 6) + IncrementFloatPointer(m_pCurrTexCoord[6], m_VertexSize_TexCoord[6]); + if (nNumTexCoords > 7) + IncrementFloatPointer(m_pCurrTexCoord[7], m_VertexSize_TexCoord[7]); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::AdvanceVertex() +{ + AdvanceVertexF(); +} + + +inline void CVertexBuilder::AdvanceVertices(int nVerts) +{ + m_nCurrentVertex += nVerts; + if (m_nCurrentVertex > m_nVertexCount) + { + m_nVertexCount = m_nCurrentVertex; + } + + IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position * nVerts); + IncrementFloatPointer(m_pCurrNormal, m_VertexSize_Normal * nVerts); + + COMPILE_TIME_ASSERT(VERTEX_MAX_TEXTURE_COORDINATES == 8); + IncrementFloatPointer(m_pCurrTexCoord[0], m_VertexSize_TexCoord[0] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[1], m_VertexSize_TexCoord[1] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[2], m_VertexSize_TexCoord[2] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[3], m_VertexSize_TexCoord[3] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[4], m_VertexSize_TexCoord[4] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[5], m_VertexSize_TexCoord[5] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[6], m_VertexSize_TexCoord[6] * nVerts); + IncrementFloatPointer(m_pCurrTexCoord[7], m_VertexSize_TexCoord[7] * nVerts); + m_pCurrColor += m_VertexSize_Color * nVerts; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +inline void CVertexBuilder::FastAdvanceNVertices(int n) +{ + m_nCurrentVertex += n; + m_nVertexCount = m_nCurrentVertex; +} + +inline void CVertexBuilder::FastVertex(const ModelVertexDX8_t& vertex) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void* pRead = &vertex; + void* pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movq mm0, [esi + 0] + movq mm1, [esi + 8] + movq mm2, [esi + 16] + movq mm3, [esi + 24] + movq mm4, [esi + 32] + movq mm5, [esi + 40] + + movntq[edi + 0], mm0 + movntq[edi + 8], mm1 + movntq[edi + 16], mm2 + movntq[edi + 24], mm3 + movntq[edi + 32], mm4 + movntq[edi + 40], mm5 + + emms + } +#elif defined(GNUC) + const void* pRead = &vertex; + void* pCurrPos = m_pCurrPosition; + __asm__ __volatile__( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "movntq %%mm6, 48(%1)\n" + "movntq %%mm7, 56(%1)\n" + "emms\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error("Implement CMeshBuilder::FastVertex(dx8)"); +#endif + + IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertexSSE(const ModelVertexDX8_t& vertex) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void* pRead = &vertex; + void* pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + + movntps[edi + 0], xmm0 + movntps[edi + 16], xmm1 + movntps[edi + 32], xmm2 + } +#elif defined(GNUC) + const void* pRead = &vertex; + void* pCurrPos = m_pCurrPosition; + __asm__ __volatile__( + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error("Implement CMeshBuilder::FastVertexSSE((dx8)"); +#endif + + IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +inline void CVertexBuilder::FastQuadVertexSSE(const QuadTessVertex_t& vertex) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void* pRead = &vertex; + void* pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + + movntps[edi + 0], xmm0 + movntps[edi + 16], xmm1 + movntps[edi + 32], xmm2 + } +#endif + + IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + + +inline int CVertexBuilder::GetCurrentVertex() const +{ + return m_nCurrentVertex; +} + + +#if defined( _X360 ) +inline void CVertexBuilder::VertexDX8ToX360(const ModelVertexDX8_t& vertex) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + + unsigned char* pDst = (unsigned char*)m_pCurrPosition; + + Assert(m_VertexSize_Position > 0); + Assert(GetVertexElementSize(VERTEX_ELEMENT_POSITION, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecPosition)); + memcpy(pDst, vertex.m_vecPosition.Base(), sizeof(vertex.m_vecPosition)); + pDst += sizeof(vertex.m_vecPosition); + + if (m_VertexSize_Normal) + { + Assert(GetVertexElementSize(VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecNormal)); + memcpy(pDst, vertex.m_vecNormal.Base(), sizeof(vertex.m_vecNormal)); + pDst += sizeof(vertex.m_vecNormal); + } + + if (m_VertexSize_TexCoord[0]) + { + Assert(GetVertexElementSize(VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecTexCoord)); + memcpy(pDst, vertex.m_vecTexCoord.Base(), sizeof(vertex.m_vecTexCoord)); + pDst += sizeof(vertex.m_vecTexCoord); + } + + if (m_VertexSize_UserData) + { + Assert(GetVertexElementSize(VERTEX_ELEMENT_USERDATA4, VERTEX_COMPRESSION_NONE) == sizeof(vertex.m_vecUserData)); + memcpy(pDst, vertex.m_vecUserData.Base(), sizeof(vertex.m_vecUserData)); + pDst += sizeof(vertex.m_vecUserData); + } + + Assert(pDst - (unsigned char*)m_pCurrPosition == m_VertexSize_Position); + + IncrementFloatPointer(m_pCurrPosition, m_VertexSize_Position); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} +#endif + + +inline const float* CVertexBuilder::Position() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return m_pCurrPosition; +} + +inline const float* CVertexBuilder::Normal() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return m_pCurrNormal; +} + +inline unsigned int CVertexBuilder::Color() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + unsigned int color; + if (IsPC() || !IsX360()) + { + color = (m_pCurrColor[3] << 24) | (m_pCurrColor[0] << 16) | (m_pCurrColor[1] << 8) | (m_pCurrColor[2]); + } + else + { + color = (m_pCurrColor[1] << 24) | (m_pCurrColor[2] << 16) | (m_pCurrColor[3] << 8) | (m_pCurrColor[0]); + } + return color; +} + +inline unsigned char* CVertexBuilder::Specular() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return m_pSpecular + m_nCurrentVertex * m_VertexSize_Specular; +} + +inline const float* CVertexBuilder::TexCoord(int stage) const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return m_pCurrTexCoord[stage]; +} + +inline const float* CVertexBuilder::TangentS() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return OffsetFloatPointer(m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS); +} + +inline const float* CVertexBuilder::TangentT() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return OffsetFloatPointer(m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT); +} + +inline float CVertexBuilder::Wrinkle() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return *OffsetFloatPointer(m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle); +} + +inline const float* CVertexBuilder::BoneWeight() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); +} + +inline int CVertexBuilder::NumBoneWeights() const +{ + return m_NumBoneWeights; +} + +#ifndef NEW_SKINNING +inline unsigned char* CVertexBuilder::BoneMatrix() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; +} +#else +inline float* CVertexBuilder::BoneMatrix() const +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_nCurrentVertex < m_nMaxVertexCount); + return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; +} +#endif + + +inline void CVertexBuilder::Position3f(float x, float y, float z) +{ + Assert(m_pPosition && m_pCurrPosition); + Assert(IsFinite(x) && IsFinite(y) && IsFinite(z)); + float* pDst = m_pCurrPosition; + *pDst++ = x; + *pDst++ = y; + *pDst = z; +} + +inline void CVertexBuilder::Position3fv(const float* v) +{ + Assert(v); + Assert(m_pPosition && m_pCurrPosition); + + float* pDst = m_pCurrPosition; + *pDst++ = *v++; + *pDst++ = *v++; + *pDst = *v; +} + + +inline void CVertexBuilder::Normal3f(float nx, float ny, float nz) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_pNormal); + Assert(IsFinite(nx) && IsFinite(ny) && IsFinite(nz)); + Assert(nx >= -1.05f && nx <= 1.05f); + Assert(ny >= -1.05f && ny <= 1.05f); + Assert(nz >= -1.05f && nz <= 1.05f); + + float* pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; +} + +inline void CVertexBuilder::Normal3fv(const float* n) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(n); + Assert(m_pNormal && m_pCurrNormal); + Assert(IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2])); + Assert(n[0] >= -1.05f && n[0] <= 1.05f); + Assert(n[1] >= -1.05f && n[1] <= 1.05f); + Assert(n[2] >= -1.05f && n[2] <= 1.05f); + + float* pDst = m_pCurrNormal; + *pDst++ = *n++; + *pDst++ = *n++; + *pDst = *n; +} + +inline void CVertexBuilder::NormalDelta3f(float nx, float ny, float nz) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(m_pNormal); + Assert(IsFinite(nx) && IsFinite(ny) && IsFinite(nz)); + + float* pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; +} + +inline void CVertexBuilder::NormalDelta3fv(const float* n) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(n); + Assert(m_pNormal && m_pCurrNormal); + Assert(IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2])); + + float* pDst = m_pCurrNormal; + *pDst++ = *n++; + *pDst++ = *n++; + *pDst = *n; +} + +template inline void CVertexBuilder::CompressedNormal3f(float nx, float ny, float nz) +{ + Assert(T == m_CompressionType); + Assert(m_pNormal && m_pCurrNormal); + Assert(IsFinite(nx) && IsFinite(ny) && IsFinite(nz)); + Assert(nx >= -1.05f && nx <= 1.05f); + Assert(ny >= -1.05f && ny <= 1.05f); + Assert(nz >= -1.05f && nz <= 1.05f); + if (T == VERTEX_COMPRESSION_ON) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + PackNormal_SHORT2(nx, ny, nz, (unsigned int*)m_pCurrNormal); + +#else +#ifdef _DEBUG + Assert(m_bWrittenUserData == false); + m_bWrittenNormal = true; +#endif + PackNormal_UBYTE4(nx, ny, nz, (unsigned int*)m_pCurrNormal); +#endif + } + else + { + float* pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; + } +} + +template inline void CVertexBuilder::CompressedNormal3fv(const float* n) +{ + Assert(n); + CompressedNormal3f(n[0], n[1], n[2]); +} + + +inline void CVertexBuilder::Color3f(float r, float g, float b) +{ + Assert(m_pColor && m_pCurrColor); + Assert(IsFinite(r) && IsFinite(g) && IsFinite(b)); + Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0)); + Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0)); + + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color3fv(const float* rgb) +{ + Assert(rgb); + Assert(m_pColor && m_pCurrColor); + Assert(IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2])); + Assert((rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0)); + Assert((rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0)); + + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4f(float r, float g, float b, float a) +{ + Assert(m_pColor && m_pCurrColor); + Assert(IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a)); + Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0)); + Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0)); + + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4fv(const float* rgba) +{ + Assert(rgba); + Assert(m_pColor && m_pCurrColor); + Assert(IsFinite(rgba[0]) && IsFinite(rgba[1]) && IsFinite(rgba[2]) && IsFinite(rgba[3])); + Assert((rgba[0] >= 0.0) && (rgba[1] >= 0.0) && (rgba[2] >= 0.0) && (rgba[3] >= 0.0)); + Assert((rgba[0] <= 1.0) && (rgba[1] <= 1.0) && (rgba[2] <= 1.0) && (rgba[3] <= 1.0)); + + int col = (FastFToC(rgba[2])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[0]) << 16) | (FastFToC(rgba[3]) << 24); + *(int*)m_pCurrColor = col; +} + + +inline void CVertexBuilder::Color3ub(unsigned char r, unsigned char g, unsigned char b) +{ + Assert(m_pColor && m_pCurrColor); +#ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | 0xFF000000; +#else + int col = b | (g << 8) | (r << 16) | 0xFF000000; +#endif + + * (int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color3ubv(unsigned char const* rgb) +{ + Assert(rgb); + Assert(m_pColor && m_pCurrColor); +#ifdef OPENGL_SWAP_COLORS + int col = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16) | 0xFF000000; +#else + int col = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16) | 0xFF000000; +#endif + + * (int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + Assert(m_pColor && m_pCurrColor); +#ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | (a << 24); +#else + int col = b | (g << 8) | (r << 16) | (a << 24); +#endif + + * (int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4ubv(unsigned char const* rgba) +{ + Assert(rgba); + Assert(m_pColor && m_pCurrColor); +#ifdef OPENGL_SWAP_COLORS + int col = rgba[0] | (rgba[1] << 8) | (rgba[2] << 16) | (rgba[3] << 24); +#else + int col = rgba[2] | (rgba[1] << 8) | (rgba[0] << 16) | (rgba[3] << 24); +#endif + * (int*)m_pCurrColor = col; +} + +FORCEINLINE void CVertexBuilder::Color4Packed(int packedColor) +{ + *(int*)m_pCurrColor = packedColor; +} + +FORCEINLINE int CVertexBuilder::PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return b | (g << 8) | (r << 16) | (a << 24); +} + + +inline void CVertexBuilder::Specular3f(float r, float g, float b) +{ + Assert(m_pSpecular); + Assert(IsFinite(r) && IsFinite(g) && IsFinite(b)); + Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0)); + Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0)); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3fv(const float* rgb) +{ + Assert(rgb); + Assert(m_pSpecular); + Assert(IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2])); + Assert((rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0)); + Assert((rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0)); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4f(float r, float g, float b, float a) +{ + Assert(m_pSpecular); + Assert(IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a)); + Assert((r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0)); + Assert((r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0f)); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4fv(const float* rgb) +{ + Assert(rgb); + Assert(m_pSpecular); + Assert(IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) && IsFinite(rgb[3])); + Assert((rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) && (rgb[3] >= 0.0)); + Assert((rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) && (rgb[3] <= 1.0)); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | (FastFToC(rgb[3]) << 24); + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3ub(unsigned char r, unsigned char g, unsigned char b) +{ + Assert(m_pSpecular); + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + +#ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | 0xFF000000; +#else + int col = b | (g << 8) | (r << 16) | 0xFF000000; +#endif + + * (int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3ubv(unsigned char const* c) +{ + Assert(m_pSpecular); + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + +#ifdef OPENGL_SWAP_COLORS + int col = c[0] | (c[1] << 8) | (c[2] << 16) | 0xFF000000; +#else + int col = c[2] | (c[1] << 8) | (c[0] << 16) | 0xFF000000; +#endif + + * (int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + Assert(m_pSpecular); + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + +#ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | (a << 24); +#else + int col = b | (g << 8) | (r << 16) | (a << 24); +#endif + + * (int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4ubv(unsigned char const* c) +{ + Assert(m_pSpecular); + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + +#ifdef OPENGL_SWAP_COLORS + int col = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); +#else + int col = c[2] | (c[1] << 8) | (c[0] << 16) | (c[3] << 24); +#endif + + * (int*)pSpecular = col; +} + + +inline void CVertexBuilder::TexCoord1f(int nStage, float s) +{ + Assert(m_pTexCoord[nStage] && m_pCurrTexCoord[nStage]); + Assert(IsFinite(s)); + + float* pDst = m_pCurrTexCoord[nStage]; + *pDst = s; +} + +inline void CVertexBuilder::TexCoord2f(int nStage, float s, float t) +{ + Assert(m_pTexCoord[nStage] && m_pCurrTexCoord[nStage]); + Assert(IsFinite(s) && IsFinite(t)); + + float* pDst = m_pCurrTexCoord[nStage]; + *pDst++ = s; + *pDst = t; +} + +inline void CVertexBuilder::TexCoord2fv(int nStage, const float* st) +{ + Assert(st); + Assert(m_pTexCoord[nStage] && m_pCurrTexCoord[nStage]); + Assert(IsFinite(st[0]) && IsFinite(st[1])); + + float* pDst = m_pCurrTexCoord[nStage]; + *pDst++ = *st++; + *pDst = *st; +} + +inline void CVertexBuilder::TexCoord3f(int stage, float s, float t, float u) +{ + Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); + Assert(IsFinite(s) && IsFinite(t) && IsFinite(u)); + float* pDst = m_pCurrTexCoord[stage]; + *pDst++ = s; + *pDst++ = t; + *pDst = u; +} + +inline void CVertexBuilder::TexCoord3fv(int stage, const float* stu) +{ + Assert(stu); + Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); + Assert(IsFinite(stu[0]) && IsFinite(stu[1]) && IsFinite(stu[2])); + + float* pDst = m_pCurrTexCoord[stage]; + *pDst++ = *stu++; + *pDst++ = *stu++; + *pDst = *stu; +} + +inline void CVertexBuilder::TexCoord4f(int stage, float s, float t, float u, float v) +{ + Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); + Assert(IsFinite(s) && IsFinite(t) && IsFinite(u)); + float* pDst = m_pCurrTexCoord[stage]; + *pDst++ = s; + *pDst++ = t; + *pDst++ = u; + *pDst = v; +} + +inline void CVertexBuilder::TexCoord4fv(int stage, const float* stuv) +{ + Assert(stuv); + Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); + Assert(IsFinite(stuv[0]) && IsFinite(stuv[1]) && IsFinite(stuv[2])); + + float* pDst = m_pCurrTexCoord[stage]; + *pDst++ = *stuv++; + *pDst++ = *stuv++; + *pDst++ = *stuv++; + *pDst = *stuv; +} + + +inline void CVertexBuilder::TexCoordSubRect2f(int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT) +{ + Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); + Assert(IsFinite(s) && IsFinite(t)); + + float* pDst = m_pCurrTexCoord[stage]; + *pDst++ = (s * scaleS) + offsetS; + *pDst = (t * scaleT) + offsetT; +} + +inline void CVertexBuilder::TexCoordSubRect2fv(int stage, const float* st, const float* offset, const float* scale) +{ + Assert(st); + Assert(m_pTexCoord[stage] && m_pCurrTexCoord[stage]); + Assert(IsFinite(st[0]) && IsFinite(st[1])); + + float* pDst = m_pCurrTexCoord[stage]; + *pDst++ = (*st++ * *scale++) + *offset++; + *pDst = (*st * *scale) + *offset; +} + + +inline void CVertexBuilder::TangentS3f(float sx, float sy, float sz) +{ + Assert(m_pTangentS); + Assert(IsFinite(sx) && IsFinite(sy) && IsFinite(sz)); + + float* pTangentS = OffsetFloatPointer(m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS); + *pTangentS++ = sx; + *pTangentS++ = sy; + *pTangentS = sz; +} + +inline void CVertexBuilder::TangentS3fv(const float* s) +{ + Assert(s); + Assert(m_pTangentS); + Assert(IsFinite(s[0]) && IsFinite(s[1]) && IsFinite(s[2])); + + float* pTangentS = OffsetFloatPointer(m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS); + *pTangentS++ = *s++; + *pTangentS++ = *s++; + *pTangentS = *s; +} + +inline void CVertexBuilder::TangentT3f(float tx, float ty, float tz) +{ + Assert(m_pTangentT); + Assert(IsFinite(tx) && IsFinite(ty) && IsFinite(tz)); + + float* pTangentT = OffsetFloatPointer(m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT); + *pTangentT++ = tx; + *pTangentT++ = ty; + *pTangentT = tz; +} + +inline void CVertexBuilder::TangentT3fv(const float* t) +{ + Assert(t); + Assert(m_pTangentT); + Assert(IsFinite(t[0]) && IsFinite(t[1]) && IsFinite(t[2])); + + float* pTangentT = OffsetFloatPointer(m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT); + *pTangentT++ = *t++; + *pTangentT++ = *t++; + *pTangentT = *t; +} + + +inline void CVertexBuilder::Wrinkle1f(float flWrinkle) +{ + Assert(m_pWrinkle); + Assert(IsFinite(flWrinkle)); + + float* pWrinkle = OffsetFloatPointer(m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle); + *pWrinkle = flWrinkle; +} + + +inline void CVertexBuilder::BoneWeight(int idx, float weight) +{ + Assert(m_pBoneWeight); + Assert(IsFinite(weight)); + Assert(idx >= 0); + Assert(m_NumBoneWeights == 2); + + if (idx < m_NumBoneWeights) + { + float* pBoneWeight = OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); + pBoneWeight[idx] = weight; + } +} + +inline void CVertexBuilder::BoneWeights2(float weight1, float weight2) +{ + Assert(m_pBoneWeight); + Assert(IsFinite(weight1) && IsFinite(weight2)); + AssertOnce(m_NumBoneWeights == 2); + + float* pBoneWeight = OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); + pBoneWeight[0] = weight1; + pBoneWeight[1] = weight2; +} + +inline void CVertexBuilder::BoneMatrix(int idx, int matrixIdx) +{ + Assert(m_pBoneMatrixIndex); + Assert(idx >= 0); + Assert(idx < 4); + + if (matrixIdx == BONE_MATRIX_INDEX_INVALID) + { + matrixIdx = 0; + } + Assert((matrixIdx >= 0) && (matrixIdx < 53)); + +#ifndef NEW_SKINNING + unsigned char* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + if (IsX360()) + { + idx = 3 - idx; + } + pBoneMatrix[idx] = (unsigned char)matrixIdx; +#else + float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + pBoneMatrix[idx] = matrixIdx; +#endif +} + +inline void CVertexBuilder::BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3) +{ + Assert(m_pBoneMatrixIndex); + + Assert(matrixIdx0 != BONE_MATRIX_INDEX_INVALID); + Assert(matrixIdx1 != BONE_MATRIX_INDEX_INVALID); + Assert(matrixIdx2 != BONE_MATRIX_INDEX_INVALID); + Assert(matrixIdx3 != BONE_MATRIX_INDEX_INVALID); + +#ifndef NEW_SKINNING + int nVal; + if (IsX360()) + { + nVal = matrixIdx3 | (matrixIdx2 << 8) | (matrixIdx1 << 16) | (matrixIdx0 << 24); + } + else + { + nVal = matrixIdx0 | (matrixIdx1 << 8) | (matrixIdx2 << 16) | (matrixIdx3 << 24); + } + int* pBoneMatrix = (int*)(&m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]); + *pBoneMatrix = nVal; +#else + float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + pBoneMatrix[0] = matrixIdx0; + pBoneMatrix[1] = matrixIdx1; + pBoneMatrix[2] = matrixIdx2; + pBoneMatrix[3] = matrixIdx3; +#endif +} + +template inline void CVertexBuilder::CompressedBoneWeight3fv(const float* pWeights) +{ + Assert(T == m_CompressionType); + Assert(m_pBoneWeight); + Assert(pWeights); + + float* pDestWeights = OffsetFloatPointer(m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight); + + if (T == VERTEX_COMPRESSION_ON) + { + Assert(m_NumBoneWeights <= 2); + + const int WEIGHT0_SHIFT = IsX360() ? 16 : 0; + const int WEIGHT1_SHIFT = IsX360() ? 0 : 16; + unsigned int* weights = (unsigned int*)pDestWeights; + + Assert(IsFinite(pWeights[0]) && (pWeights[0] >= 0.0f) && (pWeights[0] <= 1.0f)); + unsigned int weight0 = Float2Int(pWeights[0] * 32768.0f); + *weights = (0x0000FFFF & (weight0 - 1)) << WEIGHT0_SHIFT; + +#ifdef DEBUG + if (m_NumBoneWeights == 1) + { + Assert(IsFinite(pWeights[1]) && (pWeights[1] >= 0.0f) && (pWeights[1] <= 1.0f)); + unsigned int weight1 = Float2Int(pWeights[1] * 32768.0f); + Assert((weight0 + weight1) <= 32768); + } +#endif + + if (m_NumBoneWeights > 1) + { + Assert(m_NumBoneWeights == 2); + Assert(IsFinite(pWeights[1]) && (pWeights[1] >= 0.0f) && (pWeights[1] <= 1.0f)); + Assert(IsFinite(pWeights[2]) && (pWeights[2] >= 0.0f) && (pWeights[2] <= 1.0f)); + unsigned int weight1 = Float2Int(pWeights[1] * 32768.0f); + unsigned int weight2 = Float2Int(pWeights[2] * 32768.0f); + Assert((weight0 + weight1 + weight2) <= 32768); + unsigned int residual = 32768 - (weight0 + weight1 + weight2); + weight1 += residual; + *weights |= (0x0000FFFF & (weight1 - 1)) << WEIGHT1_SHIFT; + } + } + else + { + pDestWeights[0] = pWeights[0]; + pDestWeights[1] = pWeights[1]; + } +} + +inline void CVertexBuilder::UserData(const float* pData) +{ + Assert(m_CompressionType == VERTEX_COMPRESSION_NONE); + Assert(pData); + + int userDataSize = 4; + float* pUserData = OffsetFloatPointer(m_pUserData, m_nCurrentVertex, m_VertexSize_UserData); + memcpy(pUserData, pData, sizeof(float) * userDataSize); +} + +template inline void CVertexBuilder::CompressedUserData(const float* pData) +{ + Assert(T == m_CompressionType); + Assert(pData); + Assert(IsFinite(pData[0]) && IsFinite(pData[1]) && IsFinite(pData[2])); + Assert(pData[0] >= -1.05f && pData[0] <= 1.05f); + Assert(pData[1] >= -1.05f && pData[1] <= 1.05f); + Assert(pData[2] >= -1.05f && pData[2] <= 1.05f); + Assert(pData[3] == +1.0f || pData[3] == -1.0f); + if (T == VERTEX_COMPRESSION_ON) + { + float binormalSign = pData[3]; + +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + float* pUserData = OffsetFloatPointer(m_pUserData, m_nCurrentVertex, m_VertexSize_UserData); + PackNormal_SHORT2(pData, (unsigned int*)pUserData, binormalSign); +#else + unsigned int existingNormalData = *(unsigned int*)m_pCurrNormal; + Assert((existingNormalData & 0xFFFF0000) == 0); +#ifdef _DEBUG + Assert(m_bWrittenNormal == true); + m_bWrittenUserData = true; +#endif + bool bIsTangent = true; + unsigned int tangentData = 0; + PackNormal_UBYTE4(pData, &tangentData, bIsTangent, binormalSign); + *(unsigned int*)m_pCurrNormal = existingNormalData | tangentData; +#endif + } + else + { + int userDataSize = 4; + float* pUserData = OffsetFloatPointer(m_pUserData, m_nCurrentVertex, m_VertexSize_UserData); + memcpy(pUserData, pData, sizeof(float) * userDataSize); + } +} + + +class CIndexBuilder : private IndexDesc_t +{ +public: + CIndexBuilder(); + CIndexBuilder(IIndexBuffer* pIndexBuffer, MaterialIndexFormat_t fmt = MATERIAL_INDEX_FORMAT_UNKNOWN); + ~CIndexBuilder(); + + bool Lock(int nMaxIndexCount, int nIndexOffset, bool bAppend = false); + void Unlock(); + + void SpewData(); + + int GetRoomRemaining() const; + + void Bind(IMatRenderContext* pContext); + + int Offset() const; + + void Begin(IIndexBuffer* pIndexBuffer, int nMaxIndexCount, int nIndexOffset = 0); + void End(bool bSpewData = false); + + void BeginModify(IIndexBuffer* pIndexBuffer, int firstIndex = 0, int numIndices = 0, int nIndexOffset = 0); + void EndModify(bool bSpewData = false); + + int IndexCount() const; + + int TotalIndexCount() const; + + void Reset(); + + void SelectIndex(int nBufferIndex); + + void AdvanceIndex(); + void AdvanceIndices(int numIndices); + + int GetCurrentIndex(); + int GetFirstIndex() const; + + unsigned short const* Index() const; + + void Index(unsigned short nIndex); + + void FastIndex(unsigned short nIndex); + + void FastIndex2(unsigned short nIndex1, unsigned short nIndex2); + + void GenerateIndices(MaterialPrimitiveType_t primitiveType, int numIndices); + + void AttachBegin(IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t& desc); + void AttachEnd(); + void AttachBeginModify(IMesh* pMesh, int firstIndex, int numIndices, const MeshDesc_t& desc); + void AttachEndModify(); + + void FastTriangle(int startVert); + void FastQuad(int startVert); + void FastPolygon(int startVert, int numTriangles); + void FastPolygonList(int startVert, int* pVertexCount, int polygonCount); + void FastIndexList(const unsigned short* pIndexList, int startVert, int indexCount); + +private: + IIndexBuffer* m_pIndexBuffer; + + int m_nMaxIndexCount; + + int m_nIndexCount; + + int m_nIndexOffset; + + mutable int m_nCurrentIndex; + + int m_nTotalIndexCount; + + unsigned int m_nBufferOffset; + unsigned int m_nBufferFirstIndex; + + bool m_bModify; +}; + + +inline CIndexBuilder::CIndexBuilder() : m_pIndexBuffer(0), m_nMaxIndexCount(0), +m_nIndexCount(0), m_nCurrentIndex(0) +{ + m_nTotalIndexCount = 0; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstIndex = 0; +#ifdef _DEBUG + m_bModify = false; +#endif +} + +inline CIndexBuilder::CIndexBuilder(IIndexBuffer* pIndexBuffer, MaterialIndexFormat_t fmt) +{ + m_pIndexBuffer = pIndexBuffer; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstIndex = 0; + m_nIndexCount = 0; + m_nCurrentIndex = 0; + m_nMaxIndexCount = 0; + m_nTotalIndexCount = 0; + if (m_pIndexBuffer->IsDynamic()) + { + m_pIndexBuffer->BeginCastBuffer(fmt); + } + else + { + Assert(m_pIndexBuffer->IndexFormat() == fmt); + } +#ifdef _DEBUG + m_bModify = false; +#endif +} + +inline CIndexBuilder::~CIndexBuilder() +{ + if (m_pIndexBuffer && m_pIndexBuffer->IsDynamic()) + { + m_pIndexBuffer->EndCastBuffer(); + } +} + + +inline bool CIndexBuilder::Lock(int nMaxIndexCount, int nIndexOffset, bool bAppend) +{ + Assert(m_pIndexBuffer); + m_bModify = false; + m_nIndexOffset = nIndexOffset; + m_nMaxIndexCount = nMaxIndexCount; + m_nIndexCount = 0; + bool bFirstLock = (m_nBufferOffset == INVALID_BUFFER_OFFSET); + if (bFirstLock) + { + bAppend = false; + } + if (!bAppend) + { + m_nTotalIndexCount = 0; + } + Reset(); + + if (!m_pIndexBuffer->Lock(m_nMaxIndexCount, bAppend, *this)) + { + m_nMaxIndexCount = 0; + return false; + } + + if (bFirstLock) + { + m_nBufferOffset = m_nOffset; + m_nBufferFirstIndex = m_nFirstIndex; + } + + return true; +} + +inline void CIndexBuilder::Unlock() +{ + Assert(!m_bModify && m_pIndexBuffer); + + m_pIndexBuffer->Unlock(m_nIndexCount, *this); + m_nTotalIndexCount += m_nIndexCount; + + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); +#endif +} + +inline void CIndexBuilder::SpewData() +{ + m_pIndexBuffer->Spew(m_nIndexCount, *this); +} + + +inline void CIndexBuilder::Bind(IMatRenderContext* pContext) +{ + if (m_pIndexBuffer && (m_nBufferOffset != INVALID_BUFFER_OFFSET)) + { + pContext->BindIndexBuffer(m_pIndexBuffer, m_nBufferOffset); + } + else + { + pContext->BindIndexBuffer(NULL, 0); + } +} + + +inline int CIndexBuilder::Offset() const +{ + return m_nBufferOffset; +} + +inline int CIndexBuilder::GetFirstIndex() const +{ + return m_nBufferFirstIndex; +} + + +inline void CIndexBuilder::Begin(IIndexBuffer* pIndexBuffer, int nMaxIndexCount, int nIndexOffset) +{ + Assert(pIndexBuffer && (!m_pIndexBuffer)); + + m_pIndexBuffer = pIndexBuffer; + m_nIndexCount = 0; + m_nMaxIndexCount = nMaxIndexCount; + m_nIndexOffset = nIndexOffset; + + m_bModify = false; + + m_pIndexBuffer->Lock(m_nMaxIndexCount, false, *this); + + Reset(); +} + +inline void CIndexBuilder::End(bool bSpewData) +{ + Assert(!m_bModify); + + if (bSpewData) + { + m_pIndexBuffer->Spew(m_nIndexCount, *this); + } + + m_pIndexBuffer->Unlock(m_nIndexCount, *this); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); +#endif +} + + +inline void CIndexBuilder::BeginModify(IIndexBuffer* pIndexBuffer, int nFirstIndex, int nIndexCount, int nIndexOffset) +{ + m_pIndexBuffer = pIndexBuffer; + m_nIndexCount = nIndexCount; + m_nMaxIndexCount = nIndexCount; + m_nIndexOffset = nIndexOffset; + m_bModify = true; + + m_pIndexBuffer->ModifyBegin(false, nFirstIndex, nIndexCount, *this); + + Reset(); +} + +inline void CIndexBuilder::EndModify(bool bSpewData) +{ + Assert(m_pIndexBuffer); + Assert(m_bModify); + + if (bSpewData) + { + m_pIndexBuffer->Spew(m_nIndexCount, *this); + } + + m_pIndexBuffer->ModifyEnd(*this); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); +#endif +} + + +inline void CIndexBuilder::AttachBegin(IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t& desc) +{ + m_pIndexBuffer = pMesh; + m_nIndexCount = 0; + m_nMaxIndexCount = nMaxIndexCount; + + m_bModify = false; + + m_nIndexOffset = desc.m_nFirstVertex; + m_pIndices = desc.m_pIndices; + m_nIndexSize = desc.m_nIndexSize; + + Reset(); +} + +inline void CIndexBuilder::AttachEnd() +{ + Assert(m_pIndexBuffer); + Assert(!m_bModify); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); +#endif +} + +inline void CIndexBuilder::AttachBeginModify(IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t& desc) +{ + m_pIndexBuffer = pMesh; + m_nIndexCount = nIndexCount; + m_nMaxIndexCount = nIndexCount; + m_bModify = true; + + m_nIndexOffset = desc.m_nFirstVertex; + m_pIndices = desc.m_pIndices; + m_nIndexSize = desc.m_nIndexSize; + + Reset(); +} + +inline void CIndexBuilder::AttachEndModify() +{ + Assert(m_pIndexBuffer); + Assert(m_bModify); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + memset((IndexDesc_t*)this, 0, sizeof(IndexDesc_t)); +#endif +} + + +inline void CIndexBuilder::Reset() +{ + m_nCurrentIndex = 0; +} + + +inline int CIndexBuilder::IndexCount() const +{ + return m_nIndexCount; +} + + +inline int CIndexBuilder::TotalIndexCount() const +{ + return m_nTotalIndexCount; +} + + +inline void CIndexBuilder::AdvanceIndex() +{ + m_nCurrentIndex += m_nIndexSize; + if (m_nCurrentIndex > m_nIndexCount) + { + m_nIndexCount = m_nCurrentIndex; + } +} + +inline void CIndexBuilder::AdvanceIndices(int nIndices) +{ + m_nCurrentIndex += nIndices * m_nIndexSize; + if (m_nCurrentIndex > m_nIndexCount) + { + m_nIndexCount = m_nCurrentIndex; + } +} + + +inline int CIndexBuilder::GetCurrentIndex() +{ + return m_nCurrentIndex; +} + +inline unsigned short const* CIndexBuilder::Index() const +{ + Assert(m_nCurrentIndex < m_nMaxIndexCount); + return &m_pIndices[m_nCurrentIndex]; +} + +inline void CIndexBuilder::SelectIndex(int nIndex) +{ + Assert((nIndex >= 0) && (nIndex < m_nIndexCount)); + m_nCurrentIndex = nIndex * m_nIndexSize; +} + + +inline void CIndexBuilder::Index(unsigned short nIndex) +{ + Assert(m_pIndices); + Assert(m_nCurrentIndex < m_nMaxIndexCount); + m_pIndices[m_nCurrentIndex] = (unsigned short)(m_nIndexOffset + nIndex); +} + +inline void CIndexBuilder::FastIndex(unsigned short nIndex) +{ + Assert(m_pIndices); + Assert(m_nCurrentIndex < m_nMaxIndexCount); + m_pIndices[m_nCurrentIndex] = (unsigned short)(m_nIndexOffset + nIndex); + m_nCurrentIndex += m_nIndexSize; + m_nIndexCount = m_nCurrentIndex; +} + +FORCEINLINE void CIndexBuilder::FastTriangle(int startVert) +{ + startVert += m_nIndexOffset; + unsigned short* pIndices = &m_pIndices[m_nCurrentIndex]; + *pIndices++ = startVert++; + *pIndices++ = startVert++; + *pIndices++ = startVert; + AdvanceIndices(3); +} + +FORCEINLINE void CIndexBuilder::FastQuad(int startVert) +{ + startVert += m_nIndexOffset; + unsigned short* pIndices = &m_pIndices[m_nCurrentIndex]; + *pIndices++ = startVert++; + *pIndices++ = startVert++; + *pIndices++ = startVert; + + *pIndices++ = startVert - 2; + *pIndices++ = startVert++; + *pIndices++ = startVert; + AdvanceIndices(6); +} + +inline void CIndexBuilder::FastPolygon(int startVert, int triangleCount) +{ + unsigned short* pIndex = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + if (!IsX360()) + { + Assert(m_nIndexSize == 0 || m_nIndexSize == 1); + triangleCount *= m_nIndexSize; + } + for (int v = 0; v < triangleCount; ++v) + { + *pIndex++ = startVert; + *pIndex++ = startVert + v + 1; + *pIndex++ = startVert + v + 2; + } + AdvanceIndices(triangleCount * 3); +} + +inline void CIndexBuilder::FastPolygonList(int startVert, int* pVertexCount, int polygonCount) +{ + unsigned short* pIndex = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + int indexOut = 0; + + if (!IsX360()) + { + Assert(m_nIndexSize == 0 || m_nIndexSize == 1); + polygonCount *= m_nIndexSize; + } + + for (int i = 0; i < polygonCount; i++) + { + int vertexCount = pVertexCount[i]; + int triangleCount = vertexCount - 2; + for (int v = 0; v < triangleCount; ++v) + { + *pIndex++ = startVert; + *pIndex++ = startVert + v + 1; + *pIndex++ = startVert + v + 2; + } + startVert += vertexCount; + indexOut += triangleCount * 3; + } + AdvanceIndices(indexOut); +} + +inline void CIndexBuilder::FastIndexList(const unsigned short* pIndexList, int startVert, int indexCount) +{ + unsigned short* pIndexOut = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + if (!IsX360()) + { + Assert(m_nIndexSize == 0 || m_nIndexSize == 1); + indexCount *= m_nIndexSize; + } + for (int i = 0; i < indexCount; ++i) + { + pIndexOut[i] = startVert + pIndexList[i]; + } + AdvanceIndices(indexCount); +} + + +inline void CIndexBuilder::FastIndex2(unsigned short nIndex1, unsigned short nIndex2) +{ + Assert(m_pIndices); + Assert(m_nCurrentIndex < m_nMaxIndexCount - 1); +#ifndef _X360 + unsigned int nIndices = ((unsigned int)nIndex1 + m_nIndexOffset) | (((unsigned int)nIndex2 + m_nIndexOffset) << 16); +#else + unsigned int nIndices = ((unsigned int)nIndex2 + m_nIndexOffset) | (((unsigned int)nIndex1 + m_nIndexOffset) << 16); +#endif + + * (int*)(&m_pIndices[m_nCurrentIndex]) = nIndices; + m_nCurrentIndex += m_nIndexSize + m_nIndexSize; + m_nIndexCount = m_nCurrentIndex; +} + + +inline void CIndexBuilder::GenerateIndices(MaterialPrimitiveType_t primitiveType, int nIndexCount) +{ + if (m_nIndexSize == 0) + return; + + int nMaxIndices = m_nMaxIndexCount - m_nCurrentIndex; + nIndexCount = MIN(nMaxIndices, nIndexCount); + if (nIndexCount == 0) + return; + + unsigned short* pIndices = &m_pIndices[m_nCurrentIndex]; + + switch (primitiveType) + { + case MATERIAL_INSTANCED_QUADS: + Assert(0); + break; + case MATERIAL_QUADS: + GenerateQuadIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); + break; + case MATERIAL_POLYGON: + GeneratePolygonIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); + break; + case MATERIAL_LINE_STRIP: + GenerateLineStripIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); + break; + case MATERIAL_LINE_LOOP: + GenerateLineLoopIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); + break; + case MATERIAL_POINTS: + Assert(0); + break; + case MATERIAL_SUBD_QUADS_EXTRA: + case MATERIAL_SUBD_QUADS_REG: + default: + GenerateSequentialIndexBuffer(pIndices, nIndexCount, m_nIndexOffset); + break; + } + + AdvanceIndices(nIndexCount); +} + + +class CMeshBuilder : public MeshDesc_t +{ +public: + CMeshBuilder(); + ~CMeshBuilder() { Assert(!m_pMesh); } + + operator CIndexBuilder& () { return m_IndexBuilder; } + + void SetCompressionType(VertexCompressionType_t compressionType); + + void Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int numPrimitives); + + void Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex); + void Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount); + + void Begin(IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives); + void Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex); + void Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount); + + void End(bool bSpewData = false, bool bDraw = false); + + void BeginModify(IMesh* pMesh, int nFirstVertex = 0, int nVertexCount = -1, int nFirstIndex = 0, int nIndexCount = 0); + void EndModify(bool bSpewData = false); + + void DrawQuad(IMesh* pMesh, const float* v1, const float* v2, + const float* v3, const float* v4, unsigned char const* pColor, bool wireframe = false); + + int VertexCount() const; + int IndexCount() const; + + void Reset(); + + int VertexSize() { return m_ActualVertexSize; } + + int TextureCoordinateSize(int nTexCoordNumber) { return m_VertexSize_TexCoord[nTexCoordNumber]; } + + void* BaseVertexData(); + + void SelectVertex(int idx); + void SelectIndex(int idx); + + void SelectVertexFromIndex(int idx); + + void AdvanceVertex(); + template void AdvanceVertexF(); + void AdvanceVertices(int nVerts); + void AdvanceIndex(); + void AdvanceIndices(int nIndices); + + int GetCurrentVertex(); + int GetCurrentIndex(); + + const float* Position() const; + + const float* Normal() const; + + unsigned int Color() const; + + unsigned char* Specular() const; + + const float* TexCoord(int stage) const; + + const float* TangentS() const; + const float* TangentT() const; + + const float* BoneWeight() const; + float Wrinkle() const; + + int NumBoneWeights() const; +#ifndef NEW_SKINNING + unsigned char* BoneMatrix() const; +#else + float* BoneMatrix() const; +#endif + unsigned short const* Index() const; + + void Position3f(float x, float y, float z); + void Position3fv(const float* v); + + void Normal3f(float nx, float ny, float nz); + void Normal3fv(const float* n); + void NormalDelta3fv(const float* n); + void NormalDelta3f(float nx, float ny, float nz); + + template void CompressedNormal3f(float nx, float ny, float nz); + template void CompressedNormal3fv(const float* n); + + void Color3f(float r, float g, float b); + void Color3fv(const float* rgb); + void Color4f(float r, float g, float b, float a); + void Color4fv(const float* rgba); + + void Color3ub(unsigned char r, unsigned char g, unsigned char b); + void Color3ubv(unsigned char const* rgb); + void Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); + void Color4ubv(unsigned char const* rgba); + void Color4Packed(int packedColor); + int PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a); + + void Specular3f(float r, float g, float b); + void Specular3fv(const float* rgb); + void Specular4f(float r, float g, float b, float a); + void Specular4fv(const float* rgba); + + void Specular3ub(unsigned char r, unsigned char g, unsigned char b); + void Specular3ubv(unsigned char const* c); + void Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); + void Specular4ubv(unsigned char const* c); + + void TexCoord1f(int stage, float s); + void TexCoord2f(int stage, float s, float t); + void TexCoord2fv(int stage, const float* st); + void TexCoord3f(int stage, float s, float t, float u); + void TexCoord3fv(int stage, const float* stu); + void TexCoord4f(int stage, float s, float t, float u, float w); + void TexCoord4fv(int stage, const float* stuv); + + void TexCoordSubRect2f(int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT); + void TexCoordSubRect2fv(int stage, const float* st, const float* offset, const float* scale); + + void TangentS3f(float sx, float sy, float sz); + void TangentS3fv(const float* s); + + void TangentT3f(float tx, float ty, float tz); + void TangentT3fv(const float* t); + + void Wrinkle1f(float flWrinkle); + + void BoneWeight(int idx, float weight); + void BoneWeights2(float weight1, float weight2); + + template void CompressedBoneWeight3fv(const float* pWeights); + + void BoneMatrix(int idx, int matrixIndex); + void BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3); + + void UserData(const float* pData); + template void CompressedUserData(const float* pData); + + void Index(unsigned short index); + + void FastIndex2(unsigned short nIndex1, unsigned short nIndex2); + + void FastIndex(unsigned short index); + void FastQuad(int index); + + void FastVertex(const ModelVertexDX8_t& vertex); + void FastVertexSSE(const ModelVertexDX8_t& vertex); + void FastQuadVertexSSE(const QuadTessVertex_t& vertex); + + void FastAdvanceNVertices(int n); + +#if defined( _X360 ) + void VertexDX8ToX360(const ModelVertexDX8_t& vertex); +#endif + + FORCEINLINE void* GetVertexDataPtr(int nWhatSizeIThinkItIs) + { + if (m_VertexBuilder.m_VertexSize_Position != nWhatSizeIThinkItIs) + return NULL; + return m_VertexBuilder.m_pCurrPosition; + } + + +private: + void ComputeNumVertsAndIndices(int* pMaxVertices, int* pMaxIndices, + MaterialPrimitiveType_t type, int nPrimitiveCount); + int IndicesFromVertices(MaterialPrimitiveType_t type, int nVertexCount); + + IMesh* m_pMesh; + + MaterialPrimitiveType_t m_Type; + + bool m_bGenerateIndices; + + CIndexBuilder m_IndexBuilder; + CVertexBuilder m_VertexBuilder; +}; + + +inline void CMeshBuilder::Begin(IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives) +{ + Assert(0); +} + +inline void CMeshBuilder::Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex) +{ + Assert(0); +} + +inline void CMeshBuilder::Begin(IVertexBuffer* pVertexBuffer, IIndexBuffer* pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount) +{ + Assert(0); +} + + +inline CMeshBuilder::CMeshBuilder() : m_pMesh(0), m_bGenerateIndices(false) +{ +} + + +inline void CMeshBuilder::ComputeNumVertsAndIndices(int* pMaxVertices, int* pMaxIndices, + MaterialPrimitiveType_t type, int nPrimitiveCount) +{ + switch (type) + { + case MATERIAL_POINTS: + *pMaxVertices = *pMaxIndices = nPrimitiveCount; + break; + + case MATERIAL_LINES: + *pMaxVertices = *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_LINE_STRIP: + *pMaxVertices = nPrimitiveCount + 1; + *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_LINE_LOOP: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_TRIANGLES: + *pMaxVertices = *pMaxIndices = nPrimitiveCount * 3; + break; + + case MATERIAL_TRIANGLE_STRIP: + *pMaxVertices = *pMaxIndices = nPrimitiveCount + 2; + break; + + case MATERIAL_QUADS: + *pMaxVertices = nPrimitiveCount * 4; + *pMaxIndices = nPrimitiveCount * 6; + break; + + case MATERIAL_INSTANCED_QUADS: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = 0; + break; + + case MATERIAL_POLYGON: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = (nPrimitiveCount - 2) * 3; + break; + + default: + Assert(0); + } + + Assert(*pMaxVertices <= 32768); + Assert(*pMaxIndices <= 32768); +} + + +inline int CMeshBuilder::IndicesFromVertices(MaterialPrimitiveType_t type, int nVertexCount) +{ + switch (type) + { + case MATERIAL_QUADS: + Assert((nVertexCount & 0x3) == 0); + return (nVertexCount * 6) / 4; + + case MATERIAL_INSTANCED_QUADS: + return 0; + + case MATERIAL_POLYGON: + Assert(nVertexCount >= 3); + return (nVertexCount - 2) * 3; + + case MATERIAL_LINE_STRIP: + Assert(nVertexCount >= 2); + return (nVertexCount - 1) * 2; + + case MATERIAL_LINE_LOOP: + Assert(nVertexCount >= 3); + return nVertexCount * 2; + + default: + return nVertexCount; + } +} + +inline void CMeshBuilder::SetCompressionType(VertexCompressionType_t vertexCompressionType) +{ + m_CompressionType = vertexCompressionType; + m_VertexBuilder.SetCompressionType(vertexCompressionType); +} + +inline void CMeshBuilder::Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int numPrimitives) +{ + Assert(pMesh && (!m_pMesh)); + Assert(type != MATERIAL_HETEROGENOUS); + + m_pMesh = pMesh; + m_bGenerateIndices = true; + m_Type = type; + + int nMaxVertexCount, nMaxIndexCount; + ComputeNumVertsAndIndices(&nMaxVertexCount, &nMaxIndexCount, type, numPrimitives); + + switch (type) + { + case MATERIAL_INSTANCED_QUADS: + m_pMesh->SetPrimitiveType(MATERIAL_INSTANCED_QUADS); + break; + + case MATERIAL_QUADS: + case MATERIAL_POLYGON: + m_pMesh->SetPrimitiveType(MATERIAL_TRIANGLES); + break; + + case MATERIAL_LINE_STRIP: + case MATERIAL_LINE_LOOP: + m_pMesh->SetPrimitiveType(MATERIAL_LINES); + break; + + default: + m_pMesh->SetPrimitiveType(type); + } + + m_pMesh->LockMesh(nMaxVertexCount, nMaxIndexCount, *this, NULL); + + m_IndexBuilder.AttachBegin(pMesh, nMaxIndexCount, *this); + m_VertexBuilder.AttachBegin(pMesh, nMaxVertexCount, *this); + + Reset(); +} + +inline void CMeshBuilder::Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int* nFirstVertex) +{ + Begin(pMesh, type, nVertexCount, nIndexCount); + + *nFirstVertex = m_VertexBuilder.m_nFirstVertex * m_VertexBuilder.VertexSize(); +} + +inline void CMeshBuilder::Begin(IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount) +{ + Assert(pMesh && (!m_pMesh)); + + Assert((type != MATERIAL_QUADS) && (type != MATERIAL_INSTANCED_QUADS) && (type != MATERIAL_POLYGON) && + (type != MATERIAL_LINE_STRIP) && (type != MATERIAL_LINE_LOOP)); + + Assert(type != MATERIAL_POINTS); + + m_pMesh = pMesh; + m_bGenerateIndices = false; + m_Type = type; + + m_pMesh->SetPrimitiveType(type); + + m_pMesh->LockMesh(nVertexCount, nIndexCount, *this, NULL); + + m_IndexBuilder.AttachBegin(pMesh, nIndexCount, *this); + m_VertexBuilder.AttachBegin(pMesh, nVertexCount, *this); + + Reset(); +} + + +inline void CMeshBuilder::End(bool bSpewData, bool bDraw) +{ + if (m_bGenerateIndices) + { + int nIndexCount = IndicesFromVertices(m_Type, m_VertexBuilder.VertexCount()); + m_IndexBuilder.GenerateIndices(m_Type, nIndexCount); + } + + if (bSpewData) + { + m_pMesh->Spew(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); + } + +#ifdef _DEBUG + m_pMesh->ValidateData(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); +#endif + + m_pMesh->UnlockMesh(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); + + m_IndexBuilder.AttachEnd(); + m_VertexBuilder.AttachEnd(); + + if (bDraw) + { + m_pMesh->Draw(); + } + + m_pMesh = 0; + +#ifdef _DEBUG + memset((MeshDesc_t*)this, 0, sizeof(MeshDesc_t)); +#endif +} + + +inline void CMeshBuilder::BeginModify(IMesh* pMesh, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount) +{ + Assert(pMesh && (!m_pMesh)); + + if (nVertexCount < 0) + { + nVertexCount = pMesh->VertexCount(); + } + + m_pMesh = pMesh; + m_bGenerateIndices = false; + + pMesh->ModifyBeginEx(false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, *this); + + m_IndexBuilder.AttachBeginModify(pMesh, nFirstIndex, nIndexCount, *this); + m_VertexBuilder.AttachBeginModify(pMesh, nFirstVertex, nVertexCount, *this); + + Reset(); +} + +inline void CMeshBuilder::EndModify(bool bSpewData) +{ + Assert(m_pMesh); + + if (bSpewData) + { + m_pMesh->Spew(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); + } +#ifdef _DEBUG + m_pMesh->ValidateData(m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this); +#endif + + m_pMesh->ModifyEnd(*this); + m_pMesh = 0; + + m_IndexBuilder.AttachEndModify(); + m_VertexBuilder.AttachEndModify(); + +#ifdef _DEBUG + memset((MeshDesc_t*)this, 0, sizeof(MeshDesc_t)); +#endif +} + + +inline void CMeshBuilder::Reset() +{ + m_IndexBuilder.Reset(); + m_VertexBuilder.Reset(); +} + + +FORCEINLINE void CMeshBuilder::SelectVertex(int nIndex) +{ + m_VertexBuilder.SelectVertex(nIndex); +} + +inline void CMeshBuilder::SelectVertexFromIndex(int idx) +{ + int vertIdx = idx - m_nFirstVertex; + SelectVertex(vertIdx); +} + +FORCEINLINE void CMeshBuilder::SelectIndex(int idx) +{ + m_IndexBuilder.SelectIndex(idx); +} + + +template FORCEINLINE void CMeshBuilder::AdvanceVertexF() +{ + m_VertexBuilder.AdvanceVertexF(); +} +FORCEINLINE void CMeshBuilder::AdvanceVertex() +{ + m_VertexBuilder.AdvanceVertex(); +} + +FORCEINLINE void CMeshBuilder::AdvanceVertices(int nVertexCount) +{ + m_VertexBuilder.AdvanceVertices(nVertexCount); +} + +FORCEINLINE void CMeshBuilder::AdvanceIndex() +{ + m_IndexBuilder.AdvanceIndex(); +} + +FORCEINLINE void CMeshBuilder::AdvanceIndices(int nIndices) +{ + m_IndexBuilder.AdvanceIndices(nIndices); +} + +FORCEINLINE int CMeshBuilder::GetCurrentVertex() +{ + return m_VertexBuilder.GetCurrentVertex(); +} + +FORCEINLINE int CMeshBuilder::GetCurrentIndex() +{ + return m_IndexBuilder.GetCurrentIndex(); +} + + +inline void CMeshBuilder::DrawQuad(IMesh* pMesh, const float* v1, const float* v2, + const float* v3, const float* v4, unsigned char const* pColor, bool wireframe) +{ + if (!wireframe) + { + Begin(pMesh, MATERIAL_TRIANGLE_STRIP, 2); + + Position3fv(v1); + Color4ubv(pColor); + AdvanceVertexF(); + + Position3fv(v2); + Color4ubv(pColor); + AdvanceVertexF(); + + Position3fv(v4); + Color4ubv(pColor); + AdvanceVertexF(); + + Position3fv(v3); + Color4ubv(pColor); + AdvanceVertexF(); + } + else + { + Begin(pMesh, MATERIAL_LINE_LOOP, 4); + Position3fv(v1); + Color4ubv(pColor); + AdvanceVertexF(); + + Position3fv(v2); + Color4ubv(pColor); + AdvanceVertexF(); + + Position3fv(v3); + Color4ubv(pColor); + AdvanceVertexF(); + + Position3fv(v4); + Color4ubv(pColor); + AdvanceVertexF(); + } + + End(); + pMesh->Draw(); +} + + +FORCEINLINE int CMeshBuilder::VertexCount() const +{ + return m_VertexBuilder.VertexCount(); +} + +FORCEINLINE int CMeshBuilder::IndexCount() const +{ + return m_IndexBuilder.IndexCount(); +} + + +FORCEINLINE void* CMeshBuilder::BaseVertexData() +{ + return m_VertexBuilder.BaseVertexData(); +} + +FORCEINLINE const float* CMeshBuilder::Position() const +{ + return m_VertexBuilder.Position(); +} + +FORCEINLINE const float* CMeshBuilder::Normal() const +{ + return m_VertexBuilder.Normal(); +} + +FORCEINLINE unsigned int CMeshBuilder::Color() const +{ + return m_VertexBuilder.Color(); +} + +FORCEINLINE unsigned char* CMeshBuilder::Specular() const +{ + return m_VertexBuilder.Specular(); +} + +FORCEINLINE const float* CMeshBuilder::TexCoord(int nStage) const +{ + return m_VertexBuilder.TexCoord(nStage); +} + +FORCEINLINE const float* CMeshBuilder::TangentS() const +{ + return m_VertexBuilder.TangentS(); +} + +FORCEINLINE const float* CMeshBuilder::TangentT() const +{ + return m_VertexBuilder.TangentT(); +} + +FORCEINLINE float CMeshBuilder::Wrinkle() const +{ + return m_VertexBuilder.Wrinkle(); +} + +FORCEINLINE const float* CMeshBuilder::BoneWeight() const +{ + return m_VertexBuilder.BoneWeight(); +} + +FORCEINLINE int CMeshBuilder::NumBoneWeights() const +{ + return m_VertexBuilder.NumBoneWeights(); +} + +FORCEINLINE unsigned short const* CMeshBuilder::Index() const +{ + return m_IndexBuilder.Index(); +} + + +FORCEINLINE void CMeshBuilder::Index(unsigned short idx) +{ + m_IndexBuilder.Index(idx); +} + + +FORCEINLINE void CMeshBuilder::FastIndex(unsigned short idx) +{ + m_IndexBuilder.FastIndex(idx); +} + +FORCEINLINE void CMeshBuilder::FastIndex2(unsigned short nIndex1, unsigned short nIndex2) +{ + m_IndexBuilder.FastIndex2(nIndex1, nIndex2); +} + +FORCEINLINE void CMeshBuilder::FastQuad(int nIndex) +{ + m_IndexBuilder.FastQuad(nIndex); +} + +FORCEINLINE void CMeshBuilder::FastAdvanceNVertices(int nVertexCount) +{ + m_VertexBuilder.FastAdvanceNVertices(nVertexCount); +} + + +FORCEINLINE void CMeshBuilder::FastVertex(const ModelVertexDX8_t& vertex) +{ + m_VertexBuilder.FastVertex(vertex); +} + +FORCEINLINE void CMeshBuilder::FastVertexSSE(const ModelVertexDX8_t& vertex) +{ + m_VertexBuilder.FastVertexSSE(vertex); +} + +FORCEINLINE void CMeshBuilder::FastQuadVertexSSE(const QuadTessVertex_t& vertex) +{ + m_VertexBuilder.FastQuadVertexSSE(vertex); +} + + +#if defined( _X360 ) +inline void CMeshBuilder::VertexDX8ToX360(const ModelVertexDX8_t& vertex) +{ + m_VertexBuilder.VertexDX8ToX360(vertex); +} +#endif + +FORCEINLINE void CMeshBuilder::Position3f(float x, float y, float z) +{ + m_VertexBuilder.Position3f(x, y, z); +} + +FORCEINLINE void CMeshBuilder::Position3fv(const float* v) +{ + m_VertexBuilder.Position3fv(v); +} + +FORCEINLINE void CMeshBuilder::Normal3f(float nx, float ny, float nz) +{ + m_VertexBuilder.Normal3f(nx, ny, nz); +} + +FORCEINLINE void CMeshBuilder::Normal3fv(const float* n) +{ + m_VertexBuilder.Normal3fv(n); +} + +FORCEINLINE void CMeshBuilder::NormalDelta3f(float nx, float ny, float nz) +{ + m_VertexBuilder.NormalDelta3f(nx, ny, nz); +} + +FORCEINLINE void CMeshBuilder::NormalDelta3fv(const float* n) +{ + m_VertexBuilder.NormalDelta3fv(n); +} + +FORCEINLINE void CMeshBuilder::Color3f(float r, float g, float b) +{ + m_VertexBuilder.Color3f(r, g, b); +} + +FORCEINLINE void CMeshBuilder::Color3fv(const float* rgb) +{ + m_VertexBuilder.Color3fv(rgb); +} + +FORCEINLINE void CMeshBuilder::Color4f(float r, float g, float b, float a) +{ + m_VertexBuilder.Color4f(r, g, b, a); +} + +FORCEINLINE void CMeshBuilder::Color4fv(const float* rgba) +{ + m_VertexBuilder.Color4fv(rgba); +} + +FORCEINLINE void CMeshBuilder::Color3ub(unsigned char r, unsigned char g, unsigned char b) +{ + m_VertexBuilder.Color3ub(r, g, b); +} + +FORCEINLINE void CMeshBuilder::Color3ubv(unsigned char const* rgb) +{ + m_VertexBuilder.Color3ubv(rgb); +} + +FORCEINLINE void CMeshBuilder::Color4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + m_VertexBuilder.Color4ub(r, g, b, a); +} + +FORCEINLINE void CMeshBuilder::Color4ubv(unsigned char const* rgba) +{ + m_VertexBuilder.Color4ubv(rgba); +} + +FORCEINLINE void CMeshBuilder::Color4Packed(int packedColor) +{ + m_VertexBuilder.Color4Packed(packedColor); +} + +FORCEINLINE int CMeshBuilder::PackColor4(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return m_VertexBuilder.PackColor4(r, g, b, a); +} + +FORCEINLINE void CMeshBuilder::Specular3f(float r, float g, float b) +{ + m_VertexBuilder.Specular3f(r, g, b); +} + +FORCEINLINE void CMeshBuilder::Specular3fv(const float* rgb) +{ + m_VertexBuilder.Specular3fv(rgb); +} + +FORCEINLINE void CMeshBuilder::Specular4f(float r, float g, float b, float a) +{ + m_VertexBuilder.Specular4f(r, g, b, a); +} + +FORCEINLINE void CMeshBuilder::Specular4fv(const float* rgba) +{ + m_VertexBuilder.Specular4fv(rgba); +} + +FORCEINLINE void CMeshBuilder::Specular3ub(unsigned char r, unsigned char g, unsigned char b) +{ + m_VertexBuilder.Specular3ub(r, g, b); +} + +FORCEINLINE void CMeshBuilder::Specular3ubv(unsigned char const* c) +{ + m_VertexBuilder.Specular3ubv(c); +} + +FORCEINLINE void CMeshBuilder::Specular4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + m_VertexBuilder.Specular4ub(r, g, b, a); +} + +FORCEINLINE void CMeshBuilder::Specular4ubv(unsigned char const* c) +{ + m_VertexBuilder.Specular4ubv(c); +} + +FORCEINLINE void CMeshBuilder::TexCoord1f(int nStage, float s) +{ + m_VertexBuilder.TexCoord1f(nStage, s); +} + +FORCEINLINE void CMeshBuilder::TexCoord2f(int nStage, float s, float t) +{ + m_VertexBuilder.TexCoord2f(nStage, s, t); +} + +FORCEINLINE void CMeshBuilder::TexCoord2fv(int nStage, const float* st) +{ + m_VertexBuilder.TexCoord2fv(nStage, st); +} + +FORCEINLINE void CMeshBuilder::TexCoord3f(int nStage, float s, float t, float u) +{ + m_VertexBuilder.TexCoord3f(nStage, s, t, u); +} + +FORCEINLINE void CMeshBuilder::TexCoord3fv(int nStage, const float* stu) +{ + m_VertexBuilder.TexCoord3fv(nStage, stu); +} + +FORCEINLINE void CMeshBuilder::TexCoord4f(int nStage, float s, float t, float u, float v) +{ + m_VertexBuilder.TexCoord4f(nStage, s, t, u, v); +} + +FORCEINLINE void CMeshBuilder::TexCoord4fv(int nStage, const float* stuv) +{ + m_VertexBuilder.TexCoord4fv(nStage, stuv); +} + +FORCEINLINE void CMeshBuilder::TexCoordSubRect2f(int nStage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT) +{ + m_VertexBuilder.TexCoordSubRect2f(nStage, s, t, offsetS, offsetT, scaleS, scaleT); +} + +FORCEINLINE void CMeshBuilder::TexCoordSubRect2fv(int nStage, const float* st, const float* offset, const float* scale) +{ + m_VertexBuilder.TexCoordSubRect2fv(nStage, st, offset, scale); +} + +FORCEINLINE void CMeshBuilder::TangentS3f(float sx, float sy, float sz) +{ + m_VertexBuilder.TangentS3f(sx, sy, sz); +} + +FORCEINLINE void CMeshBuilder::TangentS3fv(const float* s) +{ + m_VertexBuilder.TangentS3fv(s); +} + +FORCEINLINE void CMeshBuilder::TangentT3f(float tx, float ty, float tz) +{ + m_VertexBuilder.TangentT3f(tx, ty, tz); +} + +FORCEINLINE void CMeshBuilder::TangentT3fv(const float* t) +{ + m_VertexBuilder.TangentT3fv(t); +} + +FORCEINLINE void CMeshBuilder::Wrinkle1f(float flWrinkle) +{ + m_VertexBuilder.Wrinkle1f(flWrinkle); +} + +FORCEINLINE void CMeshBuilder::BoneWeight(int nIndex, float flWeight) +{ + m_VertexBuilder.BoneWeight(nIndex, flWeight); +} + +FORCEINLINE void CMeshBuilder::BoneWeights2(float weight1, float weight2) +{ + m_VertexBuilder.BoneWeights2(weight1, weight2); +} + +template FORCEINLINE void CMeshBuilder::CompressedBoneWeight3fv(const float* pWeights) +{ + m_VertexBuilder.CompressedBoneWeight3fv(pWeights); +} + +FORCEINLINE void CMeshBuilder::BoneMatrix(int nIndex, int nMatrixIdx) +{ + m_VertexBuilder.BoneMatrix(nIndex, nMatrixIdx); +} + +FORCEINLINE void CMeshBuilder::BoneMatrices4(int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3) +{ + m_VertexBuilder.BoneMatrices4(matrixIdx0, matrixIdx1, matrixIdx2, matrixIdx3); +} + +FORCEINLINE void CMeshBuilder::UserData(const float* pData) +{ + m_VertexBuilder.UserData(pData); +} + +template FORCEINLINE void CMeshBuilder::CompressedUserData(const float* pData) +{ + m_VertexBuilder.CompressedUserData(pData); +} + +template FORCEINLINE void CMeshBuilder::CompressedNormal3f(float nx, float ny, float nz) +{ + m_VertexBuilder.CompressedNormal3f(nx, ny, nz); +} + +template FORCEINLINE void CMeshBuilder::CompressedNormal3fv(const float* n) +{ + m_VertexBuilder.CompressedNormal3fv(n); +} + +#endif +``` + +`SpyCustom/sdk/IPanel.h`: + +```h +#ifndef IPANEL_H +#define IPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui.h" +#include "interface.h" +#include "utlvector.h" + +#ifdef SendMessage +#undef SendMessage +#endif + +class KeyValues; +struct DmxElementUnpackStructure_t; +class CDmxElement; + +namespace vgui +{ + + class SurfacePlat; + class IClientPanel; + + class Panel; + + class IPanel : public IBaseInterface + { + public: + virtual void Init(VPANEL vguiPanel, IClientPanel* panel) = 0; + + virtual void SetPos(VPANEL vguiPanel, int x, int y) = 0; + virtual void GetPos(VPANEL vguiPanel, int& x, int& y) = 0; + virtual void SetSize(VPANEL vguiPanel, int wide, int tall) = 0; + virtual void GetSize(VPANEL vguiPanel, int& wide, int& tall) = 0; + virtual void SetMinimumSize(VPANEL vguiPanel, int wide, int tall) = 0; + virtual void GetMinimumSize(VPANEL vguiPanel, int& wide, int& tall) = 0; + virtual void SetZPos(VPANEL vguiPanel, int z) = 0; + virtual int GetZPos(VPANEL vguiPanel) = 0; + + virtual void GetAbsPos(VPANEL vguiPanel, int& x, int& y) = 0; + virtual void GetClipRect(VPANEL vguiPanel, int& x0, int& y0, int& x1, int& y1) = 0; + virtual void SetInset(VPANEL vguiPanel, int left, int top, int right, int bottom) = 0; + virtual void GetInset(VPANEL vguiPanel, int& left, int& top, int& right, int& bottom) = 0; + + virtual void SetVisible(VPANEL vguiPanel, bool state) = 0; + virtual bool IsVisible(VPANEL vguiPanel) = 0; + virtual void SetParent(VPANEL vguiPanel, VPANEL newParent) = 0; + virtual int GetChildCount(VPANEL vguiPanel) = 0; + virtual VPANEL GetChild(VPANEL vguiPanel, int index) = 0; + virtual CUtlVector< VPANEL >& GetChildren(VPANEL vguiPanel) = 0; + virtual VPANEL GetParent(VPANEL vguiPanel) = 0; + virtual void MoveToFront(VPANEL vguiPanel) = 0; + virtual void MoveToBack(VPANEL vguiPanel) = 0; + virtual bool HasParent(VPANEL vguiPanel, VPANEL potentialParent) = 0; + virtual bool IsPopup(VPANEL vguiPanel) = 0; + virtual void SetPopup(VPANEL vguiPanel, bool state) = 0; + virtual bool IsFullyVisible(VPANEL vguiPanel) = 0; + + virtual HScheme GetScheme(VPANEL vguiPanel) = 0; + virtual bool IsProportional(VPANEL vguiPanel) = 0; + virtual bool IsAutoDeleteSet(VPANEL vguiPanel) = 0; + virtual void DeletePanel(VPANEL vguiPanel) = 0; + + virtual void SetKeyBoardInputEnabled(VPANEL vguiPanel, bool state) = 0; + virtual void SetMouseInputEnabled(VPANEL vguiPanel, bool state) = 0; + virtual bool IsKeyBoardInputEnabled(VPANEL vguiPanel) = 0; + virtual bool IsMouseInputEnabled(VPANEL vguiPanel) = 0; + + virtual void Solve(VPANEL vguiPanel) = 0; + + virtual const char* GetName(VPANEL vguiPanel) = 0; + virtual const char* GetClassName(VPANEL vguiPanel) = 0; + + virtual void SendMessage(VPANEL vguiPanel, KeyValues* params, VPANEL ifromPanel) = 0; + + virtual void Think(VPANEL vguiPanel) = 0; + virtual void PerformApplySchemeSettings(VPANEL vguiPanel) = 0; + virtual void PaintTraverse(VPANEL vguiPanel, bool forceRepaint, bool allowForce = true) = 0; + virtual void Repaint(VPANEL vguiPanel) = 0; + virtual VPANEL IsWithinTraverse(VPANEL vguiPanel, int x, int y, bool traversePopups) = 0; + virtual void OnChildAdded(VPANEL vguiPanel, VPANEL child) = 0; + virtual void OnSizeChanged(VPANEL vguiPanel, int newWide, int newTall) = 0; + + virtual void InternalFocusChanged(VPANEL vguiPanel, bool lost) = 0; + virtual bool RequestInfo(VPANEL vguiPanel, KeyValues* outputData) = 0; + virtual void RequestFocus(VPANEL vguiPanel, int direction = 0) = 0; + virtual bool RequestFocusPrev(VPANEL vguiPanel, VPANEL existingPanel) = 0; + virtual bool RequestFocusNext(VPANEL vguiPanel, VPANEL existingPanel) = 0; + virtual VPANEL GetCurrentKeyFocus(VPANEL vguiPanel) = 0; + virtual int GetTabPosition(VPANEL vguiPanel) = 0; + + virtual SurfacePlat* Plat(VPANEL vguiPanel) = 0; + virtual void SetPlat(VPANEL vguiPanel, SurfacePlat* Plat) = 0; + + virtual Panel* GetPanel(VPANEL vguiPanel, const char* destinationModule) = 0; + + virtual bool IsEnabled(VPANEL vguiPanel) = 0; + virtual void SetEnabled(VPANEL vguiPanel, bool state) = 0; + + virtual bool IsTopmostPopup(VPANEL vguiPanel) = 0; + virtual void SetTopmostPopup(VPANEL vguiPanel, bool state) = 0; + + virtual void SetMessageContextId(VPANEL vguiPanel, int nContextId) = 0; + virtual int GetMessageContextId(VPANEL vguiPanel) = 0; + + virtual const DmxElementUnpackStructure_t* GetUnpackStructure(VPANEL vguiPanel) const = 0; + virtual void OnUnserialized(VPANEL vguiPanel, CDmxElement* pElement) = 0; + + virtual void SetSiblingPin(VPANEL vguiPanel, VPANEL newSibling, byte iMyCornerToPin = 0, byte iSiblingCornerToPinTo = 0) = 0; + }; + + +} + + +#endif +``` + +`SpyCustom/sdk/IScheme.h`: + +```h +#ifndef ISCHEME_H +#define ISCHEME_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "interface.h" + +class Color; +class KeyValues; + +namespace vgui +{ + + typedef unsigned long HScheme; + typedef unsigned long HTexture; + + class IBorder; + class IImage; + + class IScheme : public IBaseInterface + { + public: + virtual const char* GetResourceString(const char* stringName) = 0; + + virtual IBorder* GetBorder(const char* borderName) = 0; + + virtual HFont GetFont(const char* fontName, bool proportional = false) = 0; + + virtual char const* GetFontName(const HFont& font) = 0; + + virtual Color GetColor(const char* colorName, Color defaultColor) = 0; + + virtual int GetBorderCount() const = 0; + + virtual IBorder* GetBorderAtIndex(int iIndex) = 0; + + virtual int GetFontCount() const = 0; + + virtual HFont GetFontAtIndex(int iIndex) = 0; + + virtual const KeyValues* GetColorData() const = 0; + }; + + + + class ISchemeManager : public IBaseInterface + { + public: + virtual HScheme LoadSchemeFromFile(const char* fileName, const char* tag) = 0; + + virtual void ReloadSchemes() = 0; + + virtual void ReloadFonts() = 0; + + virtual HScheme GetDefaultScheme() = 0; + + virtual HScheme GetScheme(const char* tag) = 0; + + virtual IImage* GetImage(const char* imageName, bool hardwareFiltered) = 0; + virtual HTexture GetImageID(const char* imageName, bool hardwareFiltered) = 0; + + virtual IScheme* GetIScheme(HScheme scheme) = 0; + + virtual void Shutdown(bool full = true) = 0; + + virtual int GetProportionalScaledValue(int normalizedValue) = 0; + virtual int GetProportionalNormalizedValue(int scaledValue) = 0; + + virtual HScheme LoadSchemeFromFileEx(VPANEL sizingPanel, const char* fileName, const char* tag) = 0; + virtual int GetProportionalScaledValueEx(HScheme scheme, int normalizedValue) = 0; + virtual int GetProportionalNormalizedValueEx(HScheme scheme, int scaledValue) = 0; + + virtual bool DeleteImage(const char* pImageName) = 0; + }; + +#define VGUI_SCHEME_INTERFACE_VERSION "VGUI_Scheme010" + + +} + + +#endif +``` + +`SpyCustom/sdk/ISurface.h`: + +```h +#ifndef ISURFACE_H +#define ISURFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "IHTML.h" +#include "interface.h" +#include "imageformat.h" + +#include "IAppSystem.h" +#include "vector2d.h" +#include "ichromehtmlwrapper.h" + +#include "IVguiMatInfo.h" + +#ifdef CreateFont +#undef CreateFont +#endif + +#ifdef PlaySound +#undef PlaySound +#endif + +class Color; +class ITexture; + +namespace vgui +{ + + class IImage; + class Image; + class Point; + + typedef unsigned long HCursor; + typedef unsigned long HTexture; + typedef unsigned long HFont; + + + + struct Vertex_t + { + Vertex_t() {} + Vertex_t(const Vector2D& pos, const Vector2D& coord = Vector2D(0, 0)) + { + m_Position = pos; + m_TexCoord = coord; + } + void Init(const Vector2D& pos, const Vector2D& coord = Vector2D(0, 0)) + { + m_Position = pos; + m_TexCoord = coord; + } + + Vector2D m_Position; + Vector2D m_TexCoord; + }; + + + enum FontDrawType_t + { + FONT_DRAW_DEFAULT = 0, + + FONT_DRAW_NONADDITIVE, + FONT_DRAW_ADDITIVE, + + FONT_DRAW_TYPE_COUNT = 2, + }; + + + struct CharRenderInfo + { + int x, y; + Vertex_t* verts; + int textureId; + int abcA; + int abcB; + int abcC; + int fontTall; + HFont currentFont; + FontDrawType_t drawType; + wchar_t ch; + + bool valid; + bool shouldclip; + }; + + + struct IntRect + { + int x0; + int y0; + int x1; + int y1; + }; + + + + struct DrawTexturedRectParms_t + { + DrawTexturedRectParms_t() + { + s0 = t0 = 0; + s1 = t1 = 1.0f; + alpha_ul = alpha_ur = alpha_lr = alpha_ll = 255; + angle = 0; + } + + int x0; + int y0; + int x1; + int y1; + + float s0; + float t0; + float s1; + float t1; + + unsigned char alpha_ul; + unsigned char alpha_ur; + unsigned char alpha_lr; + unsigned char alpha_ll; + + float angle; + }; + + + 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 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 DrawSetApparentDepth(float depth) = 0; + virtual void DrawClearApparentDepth() = 0; + + virtual void DrawSetTextFont(HFont font) = 0; + virtual void DrawSetTextColor(int r, int g, int b, int a) = 0; + virtual void DrawSetTextColor(Color col) = 0; + virtual void DrawSetTextPos(int x, int y) = 0; + virtual void DrawGetTextPos(int& x, int& y) = 0; + virtual void DrawPrintText(const wchar_t* text, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT) = 0; + virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT) = 0; + + virtual void DrawFlushText() = 0; + virtual IHTML* CreateHTMLWindow(vgui::IHTMLEvents* events, VPANEL context) = 0; + virtual void PaintHTMLWindow(vgui::IHTML* htmlwin) = 0; + virtual void DeleteHTMLWindow(IHTML* htmlwin) = 0; + + enum ETextureFormat + { + eTextureFormat_RGBA, + eTextureFormat_BGRA, + eTextureFormat_BGRA_Opaque, + }; + + 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 bool DeleteTextureByID(int id) = 0; + + virtual void DrawGetTextureSize(int id, int& wide, int& tall) = 0; + virtual void DrawTexturedRect(int x0, int y0, int x1, int y1) = 0; + virtual bool IsTextureIDValid(int id) = 0; + + virtual int CreateNewTextureID(bool procedural = false) = 0; + + 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 bool IsCursorVisible() = 0; + virtual void ApplyChanges() = 0; + virtual bool IsWithin(int x, int y) = 0; + virtual bool HasFocus() = 0; + + enum SurfaceFeature_e + { + ANTIALIASED_FONTS = 1, + DROPSHADOW_FONTS = 2, + ESCAPE_KEY = 3, + OPENING_NEW_HTML_WINDOWS = 4, + FRAME_MINIMIZE_MAXIMIZE = 5, + OUTLINE_FONTS = 6, + DIRECT_HWND_RENDER = 7, + }; + virtual bool SupportsFeature(SurfaceFeature_e feature) = 0; + + 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; + + 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, + }; + + 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 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 void DrawWordBubble(int x0, int y0, int x1, int y1, int nBorderThickness, Color rgbaBackground, Color rgbaBorder, + bool bPointer = false, int nPointerX = 0, int nPointerY = 0, int nPointerBaseThickness = 16) = 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 vgui::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* GetFontName(HFont font) = 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 SetAbsPosForContext(int id, int x, int y) = 0; + virtual void GetAbsPosForContext(int id, int& x, int& y) = 0; + + virtual void ResetFontCaches() = 0; + + virtual bool IsScreenSizeOverrideActive(void) = 0; + virtual bool IsScreenPosOverrideActive(void) = 0; + + virtual void DestroyTextureID(int id) = 0; + + virtual int GetTextureNumFrames(int id) = 0; + virtual void DrawSetTextureFrame(int id, int nFrame, unsigned int* pFrameCache) = 0; + + virtual void GetClipRect(int& x0, int& y0, int& x1, int& y1) = 0; + virtual void SetClipRect(int x0, int y0, int x1, int y1) = 0; + + virtual void DrawTexturedRectEx(DrawTexturedRectParms_t* pDrawParms) = 0; + + virtual void GetKernedCharWidth(HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float& wide, float& abcA, float& abcC) = 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 void DrawSetTextureRGBALinear(int id, const unsigned char* rgba, int wide, int tall) = 0; + + virtual const char* GetWebkitHTMLUserAgentString() = 0; + + virtual void* Deprecated_AccessChromeHTMLController() = 0; + }; + +} + +#define VGUI_SURFACE_INTERFACE_VERSION "VGUI_Surface030" + +#endif +``` + +`SpyCustom/sdk/ISystem.h`: + +```h +#ifndef ISYSTEM_H +#define ISYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "VGUI.h" +#include "KeyCode.h" + +#ifdef PlaySound +#undef PlaySound +#endif + +class KeyValues; + +namespace vgui +{ + + class ISystem : public IBaseInterface + { + public: + virtual void Shutdown() = 0; + + virtual void RunFrame() = 0; + + virtual void ShellExecute(const char* command, const char* file) = 0; + + virtual double GetFrameTime() = 0; + + virtual double GetCurrentTime() = 0; + + virtual long GetTimeMillis() = 0; + + virtual int GetClipboardTextCount() = 0; + virtual void SetClipboardText(const char* text, int textLen) = 0; + virtual void SetClipboardText(const wchar_t* text, int textLen) = 0; + virtual int GetClipboardText(int offset, char* buf, int bufLen) = 0; + virtual int GetClipboardText(int offset, wchar_t* buf, int bufLen) = 0; + + virtual bool SetRegistryString(const char* key, const char* value) = 0; + virtual bool GetRegistryString(const char* key, char* value, int valueLen) = 0; + virtual bool SetRegistryInteger(const char* key, int value) = 0; + virtual bool GetRegistryInteger(const char* key, int& value) = 0; + + virtual KeyValues* GetUserConfigFileData(const char* dialogName, int dialogID) = 0; + virtual void SetUserConfigFile(const char* fileName, const char* pathName) = 0; + virtual void SaveUserConfigFile() = 0; + + virtual bool SetWatchForComputerUse(bool state) = 0; + virtual double GetTimeSinceLastUse() = 0; + + virtual int GetAvailableDrives(char* buf, int bufLen) = 0; + + virtual bool CommandLineParamExists(const char* paramName) = 0; + + virtual const char* GetFullCommandLine() = 0; + + virtual KeyCode KeyCode_VirtualKeyToVGUI(int keyCode) = 0; + + virtual bool GetCurrentTimeAndDate(int* year, int* month, int* dayOfWeek, int* day, int* hour, int* minute, int* second) = 0; + + virtual double GetFreeDiskSpace(const char* path) = 0; + + virtual bool CreateShortcut(const char* linkFileName, const char* targetPath, const char* arguments, const char* workingDirectory, const char* iconFile) = 0; + virtual bool GetShortcutTarget(const char* linkFileName, char* targetPath, char* arguments, int destBufferSizes) = 0; + virtual bool ModifyShortcutTarget(const char* linkFileName, const char* targetPath, const char* arguments, const char* workingDirectory) = 0; + + virtual bool GetCommandLineParamValue(const char* paramName, char* value, int valueBufferSize) = 0; + + virtual bool DeleteRegistryKey(const char* keyName) = 0; + + virtual const char* GetDesktopFolderPath() = 0; + + virtual void ShellExecuteEx(const char* command, const char* file, const char* pParams) = 0; + + virtual void SetClipboardImage(void* pWnd, int x1, int y1, int x2, int y2) = 0; + }; + +} + +#define VGUI_SYSTEM_INTERFACE_VERSION "VGUI_System010" + + +#endif +``` + +`SpyCustom/sdk/IVGUI.h`: + +```h +#ifndef IVGUI_H +#define IVGUI_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "VGUI.h" + +#include "IAppSystem.h" + +class KeyValues; + +namespace vgui +{ + + typedef unsigned long HPanel; + typedef int HContext; + + enum + { + DEFAULT_VGUI_CONTEXT = ((vgui::HContext)~0) + }; + + typedef unsigned long HPanel; + + class IVGui : public IAppSystem + { + public: + virtual void Start() = 0; + + virtual void Stop() = 0; + + virtual bool IsRunning() = 0; + + virtual void RunFrame() = 0; + + virtual void ShutdownMessage(unsigned int shutdownID) = 0; + + virtual VPANEL AllocPanel() = 0; + virtual void FreePanel(VPANEL panel) = 0; + + virtual void DPrintf(PRINTF_FORMAT_STRING const char* format, ...) = 0; + virtual void DPrintf2(PRINTF_FORMAT_STRING const char* format, ...) = 0; + virtual void SpewAllActivePanelNames() = 0; + + virtual HPanel PanelToHandle(VPANEL panel) = 0; + virtual VPANEL HandleToPanel(HPanel index) = 0; + virtual void MarkPanelForDeletion(VPANEL panel) = 0; + + virtual void AddTickSignal(VPANEL panel, int intervalMilliseconds = 0) = 0; + virtual void RemoveTickSignal(VPANEL panel) = 0; + + virtual void PostMessage(VPANEL target, KeyValues* params, VPANEL from, float delaySeconds = 0.0f) = 0; + + virtual HContext CreateContext() = 0; + virtual void DestroyContext(HContext context) = 0; + + virtual void AssociatePanelWithContext(HContext context, VPANEL pRoot) = 0; + + virtual void ActivateContext(HContext context) = 0; + + virtual void SetSleep(bool state) = 0; + + virtual bool GetShouldVGuiControlSleep() = 0; + + virtual void SetVRMode(bool bVRMode) = 0; + virtual bool GetVRMode() = 0; + + virtual void AddTickSignalToHead(VPANEL panel, int intervalMilliseconds = 0) = 0; + }; + +#define VGUI_IVGUI_INTERFACE_VERSION "VGUI_ivgui008" + +}; + + +#endif +``` + +`SpyCustom/sdk/IVguiMatInfo.h`: + +```h +#ifndef IVGUIMATINFO_H +#define IVGUIMATINFO_H + +#include "IVguiMatInfoVar.h" + +class IVguiMatInfo +{ +public: + virtual ~IVguiMatInfo() {} + + virtual IVguiMatInfoVar* FindVarFactory(const char* varName, bool* found) = 0; + + virtual int GetNumAnimationFrames() = 0; + +}; + +#endif +``` + +`SpyCustom/sdk/IVguiMatInfoVar.h`: + +```h +#ifndef IVGUIMATINFOVAR_H +#define IVGUIMATINFOVAR_H + + +class IVguiMatInfoVar +{ +public: + virtual ~IVguiMatInfoVar() {} + + virtual int GetIntValue(void) const = 0; + virtual void SetIntValue(int val) = 0; + +}; + +#endif +``` + +`SpyCustom/sdk/Image.h`: + +```h +#ifndef IMAGE_H +#define IMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "Color.h" +#include "IImage.h" + +namespace vgui +{ + + class Panel; + + class Image : public IImage + { + public: + Image(); + virtual ~Image(); + + virtual void SetPos(int x, int y); + virtual void GetPos(int& x, int& y); + virtual void GetSize(int& wide, int& tall); + virtual void GetContentSize(int& wide, int& tall); + virtual void SetColor(Color color); + virtual void SetBkColor(Color color) { DrawSetColor(color); } + virtual Color GetColor(); + virtual bool Evict(); + virtual int GetNumFrames(); + virtual void SetFrame(int nFrame); + virtual HTexture GetID(); + virtual void SetRotation(int iRotation) { return; }; + + protected: + virtual void SetSize(int wide, int tall); + virtual void DrawSetColor(Color color); + virtual void DrawSetColor(int r, int g, int b, int a); + virtual void DrawFilledRect(int x0, int y0, int x1, int y1); + virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1); + virtual void DrawLine(int x0, int y0, int x1, int y1); + virtual void DrawPolyLine(int* px, int* py, int numPoints); + virtual void DrawSetTextFont(HFont font); + virtual void DrawSetTextColor(Color color); + virtual void DrawSetTextColor(int r, int g, int b, int a); + virtual void DrawSetTextPos(int x, int y); + virtual void DrawPrintText(const wchar_t* str, int strlen); + virtual void DrawPrintText(int x, int y, const wchar_t* str, int strlen); + virtual void DrawPrintChar(wchar_t ch); + virtual void DrawPrintChar(int x, int y, wchar_t ch); + virtual void DrawSetTexture(int id); + virtual void DrawTexturedRect(int x0, int y0, int x1, int y1); + virtual void Paint() = 0; + + private: + int _pos[2]; + int _size[2]; + Color _color; + }; + +} + +#endif +``` + +`SpyCustom/sdk/InputEnums.h`: + +```h +#ifndef INPUTENUMS_H +#define INPUTENUMS_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAX_BUTTONSAMPLE 32768 + +#if !defined( _X360 ) +#define INVALID_USER_ID -1 +#else +#define INVALID_USER_ID XBX_INVALID_USER_ID +#endif + +enum +{ + MAX_JOYSTICKS = 1, + MOUSE_BUTTON_COUNT = 5, + MAX_NOVINT_DEVICES = 2, +}; + +#if defined( LINUX ) +enum JoystickAxis_t +{ + JOY_AXIS_X = 0, + JOY_AXIS_Y, + JOY_AXIS_Z, + JOY_AXIS_U, + JOY_AXIS_R, + JOY_AXIS_V, + MAX_JOYSTICK_AXES, +}; +#else +enum JoystickAxis_t +{ + JOY_AXIS_X = 0, + JOY_AXIS_Y, + JOY_AXIS_Z, + JOY_AXIS_R, + JOY_AXIS_U, + JOY_AXIS_V, + MAX_JOYSTICK_AXES, +}; +#endif + + + +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; + int m_nTick; + int m_nData; + int m_nData2; + int m_nData3; +}; + +#endif +``` + +`SpyCustom/sdk/KeyBindingMap.h`: + +```h +#ifndef KEYBINDINGMAP_H +#define KEYBINDINGMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +namespace vgui +{ + + class Panel; + + enum + { + MODIFIER_SHIFT = (1 << 0), + MODIFIER_CONTROL = (1 << 1), + MODIFIER_ALT = (1 << 2), + }; + + struct BoundKey_t + { + BoundKey_t(); + BoundKey_t(const BoundKey_t& src); + ~BoundKey_t(); + BoundKey_t& operator =(const BoundKey_t& src); + + bool isbuiltin; + char const* bindingname; + int keycode; + int modifiers; + }; + + struct KeyBindingMap_t + { + KeyBindingMap_t(); + KeyBindingMap_t(const KeyBindingMap_t& src); + ~KeyBindingMap_t(); + + char const* bindingname; + ALIGN16 MessageFunc_t func; + char const* helpstring; + char const* docstring; + bool passive; + }; + +#define DECLARE_KEYBINDINGMAP( className ) \ + static void KB_AddToMap \ + ( \ + char const *bindingname, \ + vgui::KeyCode defaultcode, \ + int default_modifiers, \ + vgui::MessageFunc_t function, \ + char const *helpstring, \ + char const *docstring, \ + bool passive \ + ) \ + { \ + vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + \ + vgui::KeyBindingMap_t entry; \ + entry.bindingname = bindingname; \ + \ + entry.func = function; \ + \ + entry.helpstring = helpstring; \ + entry.docstring = docstring; \ + \ + entry.passive = passive; \ + \ + map->entries.AddToTail( entry ); \ + \ + vgui::BoundKey_t kb; \ + kb.isbuiltin = true; \ + kb.bindingname = bindingname; \ + kb.keycode = defaultcode; \ + kb.modifiers = default_modifiers; \ + map->defaultkeys.AddToTail( kb ); \ + map->boundkeys.AddToTail( kb ); \ + } \ + \ + static void KB_ChainToMap( void ) \ + { \ + static bool chained = false; \ + if ( chained ) \ + return; \ + chained = true; \ + vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + map->pfnClassName = &GetPanelClassName; \ + if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] ) \ + { \ + map->baseMap = vgui::FindOrAddPanelKeyBindingMap( GetPanelBaseClassName() ); \ + } \ + } \ + \ + static void KB_AddBoundKey \ + ( \ + char const *bindingname, \ + int keycode, \ + int modifiers \ + ) \ + { \ + vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + vgui::BoundKey_t kb; \ + kb.isbuiltin = true; \ + kb.bindingname = bindingname; \ + kb.keycode = keycode; \ + kb.modifiers = modifiers; \ + map->defaultkeys.AddToTail( kb ); \ + map->boundkeys.AddToTail( kb ); \ + } \ + \ + class className##_RegisterKBMap; \ + friend class className##_RegisterKBMap; \ + class className##_RegisterKBMap \ + { \ + public: \ + className##_RegisterKBMap() \ + { \ + className::KB_ChainToMap(); \ + } \ + }; \ + className##_RegisterKBMap m_RegisterClassKB; \ + \ + virtual vgui::PanelKeyBindingMap *GetKBMap() \ + { \ + static vgui::PanelKeyBindingMap *s_pMap = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \ + return s_pMap; \ + } + +#define _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, passive ) \ + class PanelKBMapFunc_##name; \ + friend class PanelKBMapFunc_##name; \ + class PanelKBMapFunc_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + KB_AddToMap( #name, keycode, modifiers, (vgui::MessageFunc_t)&ThisClass::function, help, doc, passive ); \ + } \ + } \ + PanelKBMapFunc_##name() \ + { \ + PanelKBMapFunc_##name::InitVar(); \ + } \ + }; \ + PanelKBMapFunc_##name m_##name##_register; + +#define _KBBindKeyCommon( name, keycode, modifiers, _classname ) \ + class PanelKBBindFunc_##_classname; \ + friend class PanelKBBindFunc_##_classname; \ + class PanelKBBindFunc_##_classname \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + KB_AddBoundKey( #name, keycode, modifiers ); \ + } \ + } \ + PanelKBBindFunc_##_classname() \ + { \ + PanelKBBindFunc_##_classname::InitVar(); \ + } \ + }; \ + PanelKBBindFunc_##_classname m_##_classname##_bindkey_register; + +#define KEYBINDING_FUNC( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, false ); virtual void function() +#define KEYBINDING_FUNC_NODECLARE( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, false ); +#define KEYBINDING_FUNC_PASSIVE( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, true ); virtual void function() +#define KEYBINDING_FUNC_PASSIVE_NODECLARE( name, keycode, modifiers, function, help, doc ) _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, true ); + +#define KEYBINDING_ADDBINDING( name, keycode, modifiers ) _KBBindKeyCommon( name, keycode, modifiers, name ); +#define KEYBINDING_ADDBINDING_MULTIPLE( name, keycode, modifiers, _classname ) _KBBindKeyCommon( name, keycode, modifiers, _classname ); + + struct PanelKeyBindingMap + { + PanelKeyBindingMap() + { + baseMap = NULL; + pfnClassName = NULL; + processed = false; + } + + CUtlVector< KeyBindingMap_t > entries; + bool processed; + PanelKeyBindingMap* baseMap; + CUtlVector< BoundKey_t > defaultkeys; + CUtlVector< BoundKey_t > boundkeys; + char const* (*pfnClassName)(void); + }; + + PanelKeyBindingMap* FindPanelKeyBindingMap(char const* className); + PanelKeyBindingMap* FindOrAddPanelKeyBindingMap(char const* className); + +} + + +#endif +``` + +`SpyCustom/sdk/KeyCode.h`: + +```h +#ifndef KEYCODE_H +#define KEYCODE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "ButtonCode.h" + +namespace vgui +{ + typedef ButtonCode_t KeyCode; +} + +#endif +``` + +`SpyCustom/sdk/Label.h`: + +```h +#ifndef LABEL_H +#define LABEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "VGUI.h" +#include "Panel.h" +#include "PHandle.h" + +namespace vgui +{ + + class Label : public Panel + { + DECLARE_CLASS_SIMPLE(Label, Panel); + + public: + Label(Panel* parent, const char* panelName, const char* text); + Label(Panel* parent, const char* panelName, const wchar_t* wszText); + ~Label(); + + public: + virtual void SetText(const char* tokenName); + + virtual void SetText(const wchar_t* unicodeString, bool bClearUnlocalizedSymbol = false); + + virtual void GetText(OUT_Z_BYTECAP(bufferLen) char* textOut, int bufferLen); + virtual void GetText(OUT_Z_BYTECAP(bufLenInBytes) wchar_t* textOut, int bufLenInBytes); + + virtual void GetContentSize(int& wide, int& tall); + + enum Alignment + { + a_northwest = 0, + a_north, + a_northeast, + a_west, + a_center, + a_east, + a_southwest, + a_south, + a_southeast, + }; + + virtual void SetContentAlignment(Alignment alignment); + virtual void SetEnabled(bool state); + virtual void SetTextInset(int xInset, int yInset); + virtual void GetTextInset(int* xInset, int* yInset); + + virtual void SetFgColor(Color color); + virtual Color GetFgColor(); + + virtual void SetDisabledFgColor1(Color color); + virtual void SetDisabledFgColor2(Color color); + virtual Color GetDisabledFgColor1(); + virtual Color GetDisabledFgColor2(); + + enum EColorState + { + CS_NORMAL, + CS_DULL, + CS_BRIGHT, + }; + virtual void SetTextColorState(EColorState state); + + virtual void SetFont(HFont font); + virtual HFont GetFont(); + + virtual Panel* HasHotkey(wchar_t key); + virtual void SetHotkey(wchar_t key); + virtual wchar_t GetHotKey(); + + virtual void SetAssociatedControl(Panel* control); + + virtual int AddImage(IImage* image, int preOffset); + virtual void SetImageAtIndex(int index, IImage* image, int preOffset); + virtual void SetImagePreOffset(int index, int preOffset); + virtual IImage* GetImageAtIndex(int index); + virtual int GetImageCount(); + virtual void ClearImages(); + virtual void ResetToSimpleTextImage(); + virtual void SetImageBounds(int index, int x, int width); + + virtual TextImage* GetTextImage(); + + virtual int SetTextImageIndex(int newIndex); + + virtual bool RequestInfo(KeyValues* outputData); + virtual void SizeToContents(); + + enum Padding + { + Content = 8, + }; + + void SetWrap(bool bWrap); + void SetCenterWrap(bool bWrap); + + void SetAllCaps(bool bAllCaps); + + protected: + virtual void PerformLayout(); + virtual wchar_t CalculateHotkey(const char* text); + virtual wchar_t CalculateHotkey(const wchar_t* text); + virtual void ComputeAlignment(int& tx0, int& ty0, int& tx1, int& ty1); + virtual void Paint(); + MESSAGE_FUNC_PARAMS(OnSetText, "SetText", params); + virtual void DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen); + virtual void OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel); + MESSAGE_FUNC(OnHotkeyPressed, "Hotkey"); + virtual void OnMousePressed(MouseCode code); + virtual void OnSizeChanged(int wide, int tall); + + virtual void EnsureImageCapacity(int maxIndex); + + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual void GetSettings(KeyValues* outResourceData); + virtual void ApplySettings(KeyValues* inResourceData); + virtual const char* GetDescription(void); + + MESSAGE_FUNC_PARAMS(OnDialogVariablesChanged, "DialogVariables", dialogVariables); + + void HandleAutoSizing(void); + + private: + void Init(); + + Alignment _contentAlignment; + TextImage* _textImage; + struct TImageInfo + { + IImage* image; + short offset; + short xpos; + short width; + }; + CUtlVector _imageDar; + + int _textInset[2]; + Color _disabledFgColor1; + Color _disabledFgColor2; + Color _associateColor; + int _textImageIndex; + EColorState _textColorState; + + PHandle _associate; + char* _associateName; + + char* _fontOverrideName; + + wchar_t _hotkey; + + bool m_bWrap; + bool m_bCenterWrap; + bool m_bAllCaps; + bool m_bAutoWideToContents; + bool m_bAutoWideDirty; + bool m_bUseProportionalInsets; + + }; + +} + +#endif +``` + +`SpyCustom/sdk/ListPanel.h`: + +```h +#ifndef LISTPANEL_H +#define LISTPANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utllinkedlist.h" +#include "utlvector.h" +#include "utlrbtree.h" +#include "VGUI.h" +#include "Panel.h" + +class KeyValues; + +namespace vgui +{ + + class ScrollBar; + class TextImage; + class ImagePanel; + class Label; + class Button; + class IDraggerEvent; + class FastSortListPanelItem; + + class ListPanelItem + { + public: + ListPanelItem() : + kv(0), + userData(0), + m_pDragData(0), + m_bImage(false), + m_nImageIndex(-1), + m_nImageIndexSelected(-1), + m_pIcon(0) + { + } + + KeyValues* kv; + unsigned int userData; + KeyValues* m_pDragData; + bool m_bImage; + int m_nImageIndex; + int m_nImageIndexSelected; + IImage* m_pIcon; + }; + + typedef int __cdecl SortFunc( + ListPanel* pPanel, + const ListPanelItem& item1, + const ListPanelItem& item2); + + class ListPanel : public Panel + { + DECLARE_CLASS_SIMPLE(ListPanel, Panel); + + public: + ListPanel(Panel* parent, const char* panelName); + ~ListPanel(); + + enum ColumnFlags_e + { + COLUMN_FIXEDSIZE = 0x01, + COLUMN_RESIZEWITHWINDOW = 0x02, + COLUMN_IMAGE = 0x04, + COLUMN_HIDDEN = 0x08, + COLUMN_UNHIDABLE = 0x10, + }; + + virtual void AddColumnHeader(int index, const char* columnName, const char* columnText, int startingWidth, int minWidth, int maxWidth, int columnFlags = 0); + virtual void AddColumnHeader(int index, const char* columnName, const char* columnText, int width, int columnFlags = 0); + + virtual void RemoveColumn(int column); + virtual int FindColumn(const char* columnName); + virtual void SetColumnHeaderHeight(int height); + virtual void SetColumnHeaderText(int column, const char* text); + virtual void SetColumnHeaderText(int column, wchar_t* text); + virtual void SetColumnHeaderImage(int column, int imageListIndex); + virtual void SetColumnHeaderTooltip(int column, const char* tooltipText); + virtual void SetColumnTextAlignment(int column, int align); + + virtual int GetNumColumnHeaders() const; + virtual bool GetColumnHeaderText(int index, char* pOut, int maxLen); + + virtual void SetSortFunc(int column, SortFunc* func); + virtual void SetSortColumn(int column); + virtual void SortList(void); + virtual void SetColumnSortable(int column, bool sortable); + virtual void SetColumnVisible(int column, bool visible); + int GetSortColumn() const; + + virtual void SetAllowUserModificationOfColumns(bool allowed); + + virtual int AddItem(const KeyValues* data, unsigned int userData, bool bScrollToItem, bool bSortOnAdd); + void SetItemDragData(int itemID, const KeyValues* data); + virtual int GetItemCount(void); + virtual int GetItem(const char* itemName); + virtual KeyValues* GetItem(int itemID); + virtual int GetItemCurrentRow(int itemID); + virtual int GetItemIDFromRow(int currentRow); + virtual unsigned int GetItemUserData(int itemID); + virtual ListPanelItem* GetItemData(int itemID); + virtual void SetUserData(int itemID, unsigned int userData); + virtual int GetItemIDFromUserData(unsigned int userData); + virtual void ApplyItemChanges(int itemID); + virtual void RemoveItem(int itemID); + virtual void RereadAllItems(); + + virtual void RemoveAll(); + virtual void DeleteAllItems(); + + virtual void GetCellText(int itemID, int column, OUT_Z_BYTECAP(bufferSizeInBytes) wchar_t* buffer, int bufferSizeInBytes); + virtual IImage* GetCellImage(int itemID, int column); + + virtual int FirstItem() const; + virtual int NextItem(int iItem) const; + + virtual int InvalidItemID() const; + virtual bool IsValidItemID(int itemID); + + virtual void SetItemVisible(int itemID, bool state); + virtual void SetItemDisabled(int itemID, bool state); + bool IsItemVisible(int itemID); + + virtual void SetFont(HFont font); + + virtual void SetImageList(ImageList* imageList, bool deleteImageListWhenDone); + + virtual int GetSelectedItemsCount(); + + virtual int GetSelectedItem(int selectionIndex); + + virtual void ClearSelectedItems(); + + virtual bool IsItemSelected(int itemID); + + virtual void AddSelectedItem(int itemID); + + virtual void SetSingleSelectedItem(int itemID); + + virtual int GetSelectedColumn(); + + virtual void SetSelectIndividualCells(bool state); + + void SetMultiselectEnabled(bool bState); + bool IsMultiselectEnabled() const; + + virtual void SetSelectedCell(int row, int column); + + virtual bool GetCellAtPos(int x, int y, int& row, int& column); + virtual bool GetCellBounds(int row, int column, int& x, int& y, int& wide, int& tall); + + virtual void SetEmptyListText(const char* text); + virtual void SetEmptyListText(const wchar_t* text); + + void ResetScrollBar(); + + virtual void OnCreateDragData(KeyValues* msg); + + void SetIgnoreDoubleClick(bool state); + + virtual void EnterEditMode(int itemID, int column, vgui::Panel* editPanel); + + virtual void LeaveEditMode(); + + virtual bool IsInEditMode(); + + MESSAGE_FUNC_INT(ResizeColumnToContents, "ResizeColumnToContents", column); + +#ifdef _X360 + virtual void NavigateTo(); +#endif + int m_nUserConfigFileVersion; + + protected: + virtual Panel* GetCellRenderer(int row, int column); + + virtual void OnMouseWheeled(int delta); + virtual void OnSizeChanged(int wide, int tall); + virtual void PerformLayout(); + virtual void Paint(); + virtual void PaintBackground(); + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); +#ifdef _X360 + virtual void OnKeyCodePressed(KeyCode code); +#else + virtual void OnKeyCodePressed(KeyCode code); +#endif + MESSAGE_FUNC(OnSliderMoved, "ScrollBarSliderMoved"); + MESSAGE_FUNC_INT_INT(OnColumnResized, "ColumnResized", column, delta); + MESSAGE_FUNC_INT(OnSetSortColumn, "SetSortColumn", column); + MESSAGE_FUNC(OpenColumnChoiceMenu, "OpenColumnChoiceMenu"); + MESSAGE_FUNC_INT(OnToggleColumnVisible, "ToggleColumnVisible", col); + virtual float GetRowsPerPage(); + virtual int GetStartItem(); + + virtual void ApplyUserConfigSettings(KeyValues* userConfig); + virtual void GetUserConfigSettings(KeyValues* userConfig); + virtual bool HasUserConfigSettings(); + + public: + virtual void SetSortColumnEx(int iPrimarySortColumn, int iSecondarySortColumn, bool bSortAscending); + void GetSortColumnEx(int& iPrimarySortColumn, int& iSecondarySortColumn, bool& bSortAscending) const; + + private: + void CleanupItem(FastSortListPanelItem* data); + + void IndexItem(int itemID); + + void UpdateSelection(vgui::MouseCode code, int x, int y, int row, int column); + + void HandleMultiSelection(int itemID, int row, int column); + + void HandleAddSelection(int itemID, int row, int column); + + struct IndexItem_t + { + ListPanelItem* dataItem; + int duplicateIndex; + }; + typedef CUtlRBTree IndexRBTree_t; + + struct column_t + { + Button* m_pHeader; + int m_iMinWidth; + int m_iMaxWidth; + bool m_bResizesWithWindow; + Panel* m_pResizer; + SortFunc* m_pSortFunc; + bool m_bTypeIsText; + bool m_bHidden; + bool m_bUnhidable; + IndexRBTree_t m_SortedTree; + int m_nContentAlignment; + }; + + CUtlLinkedList m_ColumnsData; + + CUtlVector m_ColumnsHistory; + + CUtlVector m_CurrentColumns; + + int m_iColumnDraggerMoved; + int m_lastBarWidth; + + CUtlLinkedList m_DataItems; + CUtlVector m_VisibleItems; + + int m_iSortColumn; + int m_iSortColumnSecondary; + + void ResortColumnRBTree(int col); + static bool RBTreeLessFunc(vgui::ListPanel::IndexItem_t& item1, vgui::ListPanel::IndexItem_t& item2); + + TextImage* m_pTextImage; + ImagePanel* m_pImagePanel; + Label* m_pLabel; + ScrollBar* m_hbar; + ScrollBar* m_vbar; + + int m_iSelectedColumn; + + bool m_bNeedsSort : 1; + bool m_bSortAscending : 1; + bool m_bSortAscendingSecondary : 1; + bool m_bCanSelectIndividualCells : 1; + bool m_bShiftHeldDown : 1; + bool m_bMultiselectEnabled : 1; + bool m_bAllowUserAddDeleteColumns : 1; + bool m_bDeleteImageListWhenDone : 1; + bool m_bIgnoreDoubleClick : 1; + + int m_iHeaderHeight; + int m_iRowHeight; + + CUtlVector m_SelectedItems; + int m_LastItemSelected; + + int m_iTableStartX; + int m_iTableStartY; + + Color m_LabelFgColor; + Color m_DisabledColor; + Color m_SelectionFgColor; + Color m_DisabledSelectionFgColor; + + ImageList* m_pImageList; + TextImage* m_pEmptyListText; + + PHandle m_hEditModePanel; + int m_iEditModeItemID; + int m_iEditModeColumn; + + void ResetColumnHeaderCommands(); + }; + +} + +#endif +``` + +`SpyCustom/sdk/MaterialSystemUtil.h`: + +```h +#ifndef MATERIALSYSTEMUTIL_H +#define MATERIALSYSTEMUTIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "imageformat.h" +#include "imaterialsystem.h" + +class IMaterial; +class ITexture; +class KeyValues; + +class KeyValues; + + +class CMaterialReference +{ +public: + CMaterialReference(char const* pMaterialName = 0, const char* pTextureGroupName = 0, bool bComplain = true); + ~CMaterialReference(); + + void Init(const char* pMaterialName, const char* pTextureGroupName, bool bComplain = true); + void Init(const char* pMaterialName, KeyValues* pVMTKeyValues); + void Init(IMaterial* pMaterial); + void Init(CMaterialReference& ref); + void Init(const char* pMaterialName, const char* pTextureGroupName, KeyValues* pVMTKeyValues); + + void Shutdown(); + bool IsValid() { return m_pMaterial != 0; } + + operator IMaterial* () { return m_pMaterial; } + operator IMaterial* () const { return m_pMaterial; } + operator IMaterial const* () const { return m_pMaterial; } + IMaterial* operator->() { return m_pMaterial; } + +private: + IMaterial* m_pMaterial; +}; + +class CTextureReference +{ +public: + CTextureReference(); + CTextureReference(const CTextureReference& ref); + ~CTextureReference(); + + void Init(char const* pTexture, const char* pTextureGroupName, bool bComplain = true); + void InitProceduralTexture(const char* pTextureName, const char* pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags); + void InitRenderTarget(int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char* pStrOptionalName = NULL); +#if defined( _X360 ) + void InitRenderTargetTexture(int width, int height, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char* pStrOptionalName = NULL); + void InitRenderTargetSurface(int width, int height, ImageFormat fmt, bool bSameAsTexture); +#endif + void Init(ITexture* pTexture); + + void Shutdown(bool bDeleteIfUnReferenced = false); + bool IsValid() { return m_pTexture != 0; } + + operator ITexture* () { return m_pTexture; } + operator ITexture const* () const { return m_pTexture; } + ITexture* operator->() { return m_pTexture; } + + void operator=(CTextureReference& ref); + +private: + ITexture* m_pTexture; +}; + + +#endif +``` + +`SpyCustom/sdk/Menu.h`: + +```h +#ifndef MENU_H +#define MENU_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "Panel.h" +#include "Label.h" +#include "utllinkedlist.h" +#include "utlvector.h" + +namespace vgui +{ + + class MenuItem; + class ScrollBar; + class MenuSeparator; + + class Menu : public Panel + { + DECLARE_CLASS_SIMPLE(Menu, Panel); + friend class MenuItem; + public: + enum MenuDirection_e + { + LEFT, + RIGHT, + UP, + DOWN, + CURSOR, + ALIGN_WITH_PARENT, + }; + + Menu(Panel* parent, const char* panelName); + ~Menu(); + + static void PlaceContextMenu(Panel* parent, Menu* menu); + static void OnInternalMousePressed(Panel* other, MouseCode code); + + virtual void PositionRelativeToPanel(Panel* reference, MenuDirection_e direction, int nAdditionalYOffset = 0, bool showMenu = false); + + virtual int AddMenuItem(const char* itemName, const char* itemText, const char* command, Panel* target, const KeyValues* userData = NULL); + virtual int AddMenuItem(const char* itemName, const wchar_t* wszItemText, const char* command, Panel* target, const KeyValues* userData = NULL); + + virtual int AddMenuItem(const char* itemName, const char* itemText, KeyValues* message, Panel* target, const KeyValues* userData = NULL); + virtual int AddMenuItem(const char* itemName, const wchar_t* wszItemText, KeyValues* message, Panel* target, const KeyValues* userData = NULL); + + virtual int AddMenuItem(const char* itemText, const char* command, Panel* target, const KeyValues* userData = NULL); + virtual int AddMenuItem(const char* itemText, KeyValues* message, Panel* target, const KeyValues* userData = NULL); + virtual int AddMenuItem(const char* itemText, Panel* target, const KeyValues* userData = NULL); + + virtual int AddCheckableMenuItem(const char* itemName, const char* itemText, const char* command, Panel* target, const KeyValues* userData = NULL); + virtual int AddCheckableMenuItem(const char* itemName, const wchar_t* wszItemText, const char* command, Panel* target, const KeyValues* userData = NULL); + + virtual int AddCheckableMenuItem(const char* itemName, const char* itemText, KeyValues* message, Panel* target, const KeyValues* userData = NULL); + virtual int AddCheckableMenuItem(const char* itemName, const wchar_t* wszItemText, KeyValues* message, Panel* target, const KeyValues* userData = NULL); + + virtual int AddCheckableMenuItem(const char* itemText, const char* command, Panel* target, const KeyValues* userData = NULL); + virtual int AddCheckableMenuItem(const char* itemText, KeyValues* message, Panel* target, const KeyValues* userData = NULL); + virtual int AddCheckableMenuItem(const char* itemText, Panel* target, const KeyValues* userData = NULL); + + virtual int AddCascadingMenuItem(const char* itemName, const char* itemText, const char* command, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + virtual int AddCascadingMenuItem(const char* itemName, const wchar_t* wszItemText, const char* command, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + + virtual int AddCascadingMenuItem(const char* itemName, const char* itemText, KeyValues* message, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + virtual int AddCascadingMenuItem(const char* itemName, const wchar_t* wszItemText, KeyValues* message, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + + virtual int AddCascadingMenuItem(const char* itemText, const char* command, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + virtual int AddCascadingMenuItem(const char* itemText, KeyValues* message, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + virtual int AddCascadingMenuItem(const char* itemText, Panel* target, Menu* cascadeMenu, const KeyValues* userData = NULL); + + virtual int AddMenuItem(MenuItem* panel); + + virtual void AddSeparator(); + virtual void AddSeparatorAfterItem(int itemID); + + virtual void UpdateMenuItem(int itemID, const char* itemText, KeyValues* message, const KeyValues* userData = NULL); + virtual void UpdateMenuItem(int itemID, const wchar_t* wszItemText, KeyValues* message, const KeyValues* userData = NULL); + + virtual void MoveMenuItem(int itemID, int moveBeforeThisItemID); + + virtual bool IsValidMenuID(int itemID); + virtual int GetInvalidMenuID(); + + KeyValues* GetItemUserData(int itemID); + void GetItemText(int itemID, wchar_t* text, int bufLenInBytes); + void GetItemText(int itemID, char* text, int bufLenInBytes); + + virtual void SetItemEnabled(const char* itemName, bool state); + virtual void SetItemEnabled(int itemID, bool state); + virtual void SetItemVisible(const char* itemName, bool visible); + virtual void SetItemVisible(int itemID, bool visible); + + void DeleteItem(int itemID); + + void DeleteAllItems(); + + virtual void SetFixedWidth(int width); + + void SetContentAlignment(Label::Alignment alignment); + + virtual void SetMenuItemHeight(int itemHeight); + virtual int GetMenuItemHeight() const; + + virtual void SetNumberOfVisibleItems(int numItems); + + void EnableUseMenuManager(bool bUseMenuManager); + + virtual void PerformLayout(void); + + virtual void SetBorder(class IBorder* border); + virtual void ApplySchemeSettings(IScheme* pScheme); + + enum MenuTypeAheadMode + { + COMPAT_MODE = 0, + HOT_KEY_MODE, + TYPE_AHEAD_MODE, + }; + virtual void SetTypeAheadMode(MenuTypeAheadMode mode); + virtual int GetTypeAheadMode(); + + virtual void OnKeyTyped(wchar_t unichar); + virtual void OnKeyCodeTyped(KeyCode code); + + virtual void SetVisible(bool state); + + virtual void ActivateItem(int itemID); + virtual void SilentActivateItem(int itemID); + virtual void ActivateItemByRow(int row); + virtual int GetActiveItem(); + + virtual int GetItemCount(); + + virtual int GetMenuID(int index); + + int GetCurrentlyVisibleItemsCount(); + + MenuItem* GetMenuItem(int itemID); + void CloseOtherMenus(MenuItem* item); + virtual void OnKillFocus(); + + int GetMenuMode(); + enum MenuMode + { + MOUSE = 0, + KEYBOARD, + }; + + void SetCurrentlyHighlightedItem(int itemID); + int GetCurrentlyHighlightedItem(); + void ClearCurrentlyHighlightedItem(); + + void SetMenuItemChecked(int itemID, bool state); + bool IsChecked(int index); + + + void SetMinimumWidth(int width); + int GetMinimumWidth(); + + virtual void SetFgColor(Color newColor); + virtual void SetBgColor(Color newColor); + + virtual void SetFont(HFont font); + + void SetCurrentKeyBinding(int itemID, char const* hotkey); + + void ForceCalculateWidth(); + + void SetUseFallbackFont(bool bState, HFont hFallback); + + protected: + int AddMenuItemCharCommand(MenuItem* item, const char* command, Panel* target, const KeyValues* userData); + int AddMenuItemKeyValuesCommand(MenuItem* item, KeyValues* message, Panel* target, const KeyValues* userData); + + virtual void OnCommand(const char* command); + MESSAGE_FUNC_PTR(OnMenuItemSelected, "MenuItemSelected", panel); + virtual void AddScrollBar(); + virtual void RemoveScrollBar(); + MESSAGE_FUNC(OnSliderMoved, "ScrollBarSliderMoved"); + virtual void Paint(); + virtual void LayoutMenuBorder(); + virtual void MakeItemsVisibleInScrollRange(int maxVisibleItems, int nNumPixelsAvailable); + virtual void OnMouseWheeled(int delta); + virtual void OnHotKey(wchar_t unichar); + virtual void OnTypeAhead(wchar_t unichar); + + int CountVisibleItems(); + void ComputeWorkspaceSize(int& workWide, int& workTall); + int ComputeFullMenuHeightWithInsets(); + + void CalculateWidth(); + + void LayoutScrollBar(); + void PositionCascadingMenu(); + void SizeMenuItems(); + void OnCursorMoved(int x, int y); + void OnKeyCodePressed(KeyCode code); + void OnMenuClose(); + MESSAGE_FUNC(OnKeyModeSet, "KeyModeSet"); + + void SetCurrentlySelectedItem(MenuItem* item); + void SetCurrentlySelectedItem(int itemID); + MESSAGE_FUNC_INT(OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel); + MESSAGE_FUNC_INT(OnCursorExitedMenuItem, "CursorExitedMenuItem", VPanel); + + void MoveAlongMenuItemList(int direction, int loopCount); + + enum + { + DEFAULT_MENU_ITEM_HEIGHT = 22, + MENU_UP = -1, + MENU_DOWN = 1 + }; + +#ifdef DBGFLAG_VALIDATE + virtual void Validate(CValidator& validator, char* pchName); +#endif + + private: + MenuItem* GetParentMenuItem(); + + int m_iMenuItemHeight; + int m_iFixedWidth; + int m_iMinimumWidth; + int m_iNumVisibleLines; + ScrollBar* m_pScroller; + + CUtlLinkedList m_MenuItems; + + CUtlVector m_VisibleSortedItems; + CUtlVector m_SortedItems; + CUtlVector m_Separators; + CUtlVector m_SeparatorPanels; + + bool _sizedForScrollBar : 1; + bool m_bUseFallbackFont : 1; + bool _recalculateWidth : 1; + bool m_bUseMenuManager : 1; + + int _menuWide; + int m_iCurrentlySelectedItemID; + int m_iInputMode; + int m_iCheckImageWidth; + int m_iProportionalScrollBarSize; + Label::Alignment m_Alignment; + Color _borderDark; + int m_iActivatedItem; + HFont m_hItemFont; + HFont m_hFallbackItemFont; + +#define TYPEAHEAD_BUFSIZE 256 + MenuTypeAheadMode m_eTypeAheadMode; + wchar_t m_szTypeAheadBuf[TYPEAHEAD_BUFSIZE]; + int m_iNumTypeAheadChars; + double m_fLastTypeAheadTime; + }; + +} + +#endif +``` + +`SpyCustom/sdk/MenuItem.h`: + +```h +#ifndef MENUITEM_H +#define MENUITEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "Button.h" +#include "Menu.h" + +namespace vgui +{ + + class IBorder; + class TextImage; + class Menu; + class Image; + + class MenuItem : public Button + { + DECLARE_CLASS_SIMPLE(MenuItem, Button); + + public: + MenuItem(Menu* parent, const char* panelName, const char* text, Menu* cascadeMenu = NULL, bool checkable = false); + MenuItem(Menu* parent, const char* panelName, const wchar_t* wszText, Menu* cascadeMenu = NULL, bool checkable = false); + ~MenuItem(); + + virtual void Paint(); + + virtual void FireActionSignal(); + + virtual bool CanBeDefaultButton(void); + + void OnCursorEntered(); + void OnCursorExited(); + + void CloseCascadeMenu(); + + MESSAGE_FUNC(OnKillFocus, "MenuClose"); + + bool HasMenu(); + + void SetTextImageSize(int wide, int tall); + + void GetTextImageSize(int& wide, int& tall); + + void GetArrowImageSize(int& wide, int& tall); + + void GetCheckImageSize(int& wide, int& tall); + + Menu* GetMenu(); + + virtual void PerformLayout(); + + void OnCursorMoved(int x, int y); + + MESSAGE_FUNC(ArmItem, "ArmItem"); + MESSAGE_FUNC(DisarmItem, "DisarmItem"); + + bool IsItemArmed(); + + void OpenCascadeMenu(); + + bool IsCheckable(); + bool IsChecked(); + + void SetChecked(bool state); + + KeyValues* GetUserData(); + void SetUserData(const KeyValues* kv); + + int GetActiveItem() { if (m_pCascadeMenu) { return m_pCascadeMenu->GetActiveItem(); } else { return 0; } } + + Menu* GetParentMenu(); + + void SetCurrentKeyBinding(char const* keyName); + + virtual void GetContentSize(int& cw, int& ch); + + protected: + void OnKeyCodeReleased(KeyCode code); + void OnMenuClose(); + MESSAGE_FUNC(OnKeyModeSet, "KeyModeSet"); + + virtual void Init(void); + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual IBorder* GetBorder(bool depressed, bool armed, bool selected, bool keyfocus); + + private: + enum { CHECK_INSET = 6 }; + Menu* m_pCascadeMenu; + bool m_bCheckable; + bool m_bChecked; + TextImage* m_pCascadeArrow; + Image* m_pCheck; + TextImage* m_pBlankCheck; + + TextImage* m_pCurrentKeyBinding; + + KeyValues* m_pUserData; + + }; + +} + +#endif +``` + +`SpyCustom/sdk/MessageMap.h`: + +```h +#ifndef MESSAGEMAP_H +#define MESSAGEMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dmxelement.h" + +#pragma pointers_to_members( full_generality, virtual_inheritance ) + +namespace vgui +{ + + +#ifndef ARRAYSIZE +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) +#endif + + + enum DataType_t + { + DATATYPE_VOID, + DATATYPE_CONSTCHARPTR, + DATATYPE_INT, + DATATYPE_FLOAT, + DATATYPE_PTR, + DATATYPE_BOOL, + DATATYPE_KEYVALUES, + DATATYPE_CONSTWCHARPTR, + DATATYPE_UINT64, + DATATYPE_HANDLE, + }; + + class Panel; + typedef uintp VPANEL; + + typedef void (Panel::* MessageFunc_t)(void); + +#pragma warning(disable:4121) + struct MessageMapItem_t + { + const char* name; + ALIGN16 MessageFunc_t func; + + int numParams; + + DataType_t firstParamType; + const char* firstParamName; + + DataType_t secondParamType; + const char* secondParamName; + + int nameSymbol; + int firstParamSymbol; + int secondParamSymbol; + }; + +#define DECLARE_PANELMESSAGEMAP( className ) \ + static void AddToMap( char const *scriptname, vgui::MessageFunc_t function, int paramCount, int p1type, const char *p1name, int p2type, const char *p2name ) \ + { \ + vgui::PanelMessageMap *map = vgui::FindOrAddPanelMessageMap( GetPanelClassName() ); \ + \ + vgui::MessageMapItem_t entry; \ + entry.name = scriptname; \ + entry.func = function; \ + entry.numParams = paramCount; \ + entry.firstParamType = (vgui::DataType_t)p1type; \ + entry.firstParamName = p1name; \ + entry.secondParamType = (vgui::DataType_t)p2type; \ + entry.secondParamName = p2name; \ + entry.nameSymbol = 0; \ + entry.firstParamSymbol = 0; \ + entry.secondParamSymbol = 0; \ + \ + map->entries.AddToTail( entry ); \ + } \ + \ + static void ChainToMap( void ) \ + { \ + static bool chained = false; \ + if ( chained ) \ + return; \ + chained = true; \ + vgui::PanelMessageMap *map = vgui::FindOrAddPanelMessageMap( GetPanelClassName() ); \ + map->pfnClassName = &GetPanelClassName; \ + if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] ) \ + { \ + map->baseMap = vgui::FindOrAddPanelMessageMap( GetPanelBaseClassName() ); \ + } \ + } \ + \ + class className##_RegisterMap; \ + friend class className##_RegisterMap; \ + class className##_RegisterMap \ + { \ + public: \ + className##_RegisterMap() \ + { \ + className::ChainToMap(); \ + } \ + }; \ + className##_RegisterMap m_RegisterClass; \ + \ + virtual vgui::PanelMessageMap *GetMessageMap() \ + { \ + static vgui::PanelMessageMap *s_pMap = vgui::FindOrAddPanelMessageMap( GetPanelClassName() ); \ + return s_pMap; \ + } + +#define VGUI_USEKEYBINDINGMAPS 1 + +#if defined( VGUI_USEKEYBINDINGMAPS ) + +#define DECLARE_CLASS_SIMPLE( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + DECLARE_KEYBINDINGMAP( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return #baseClassName; } + +#define DECLARE_CLASS_SIMPLE_NOBASE( className ) \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + DECLARE_KEYBINDINGMAP( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return NULL; } + +#else + +#define DECLARE_CLASS_SIMPLE( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return #baseClassName; } + +#define DECLARE_CLASS_SIMPLE_NOBASE( className ) \ + typedef className ThisClass; \ +public: \ + DECLARE_PANELMESSAGEMAP( className ); \ + DECLARE_PANELANIMATION( className ); \ + static char const *GetPanelClassName() { return #className; } \ + static char const *GetPanelBaseClassName() { return NULL; } + +#endif + +#define _MessageFuncCommon( name, scriptname, paramCount, p1type, p1name, p2type, p2name ) \ + class PanelMessageFunc_##name; \ + friend class PanelMessageFunc_##name; \ + class PanelMessageFunc_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + AddToMap( scriptname, (vgui::MessageFunc_t)&ThisClass::name, paramCount, p1type, p1name, p2type, p2name ); \ + } \ + } \ + PanelMessageFunc_##name() \ + { \ + PanelMessageFunc_##name::InitVar(); \ + } \ + }; \ + PanelMessageFunc_##name m_##name##_register; \ + +#define MESSAGE_FUNC( name, scriptname ) _MessageFuncCommon( name, scriptname, 0, 0, 0, 0, 0 ); virtual void name( void ) + +#define MESSAGE_FUNC_INT( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 ); virtual void name( int p1 ) +#define MESSAGE_FUNC_UINT64( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_UINT64, #p1, 0, 0 ); virtual void name( uint64 p1 ) +#define MESSAGE_FUNC_PTR( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_PTR, #p1, 0, 0 ); virtual void name( vgui::Panel *p1 ) +#define MESSAGE_FUNC_HANDLE( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_HANDLE, #p1, 0, 0 ); virtual void name( vgui::VPANEL p1 ) +#define MESSAGE_FUNC_FLOAT( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_FLOAT, #p1, 0, 0 ); virtual void name( float p1 ) +#define MESSAGE_FUNC_CHARPTR( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_CONSTCHARPTR, #p1, 0, 0 ); virtual void name( const char *p1 ) +#define MESSAGE_FUNC_WCHARPTR( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_CONSTWCHARPTR, #p1, 0, 0 ); virtual void name( const wchar_t *p1 ) + +#define MESSAGE_FUNC_INT_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( int p1, int p2 ) +#define MESSAGE_FUNC_PTR_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( vgui::Panel *p1, int p2 ) +#define MESSAGE_FUNC_HANDLE_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_INT, #p2 ); virtual void name( vgui::VPANEL p1, int p2 ) +#define MESSAGE_FUNC_ENUM_ENUM( name, scriptname, t1, p1, t2, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_PTR, #p2 ); virtual void name( t1 p1, t2 p2 ) +#define MESSAGE_FUNC_INT_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( int p1, const char *p2 ) +#define MESSAGE_FUNC_PTR_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( vgui::Panel *p1, const char *p2 ) +#define MESSAGE_FUNC_HANDLE_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( vgui::VPANEL p1, const char *p2 ) +#define MESSAGE_FUNC_PTR_WCHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 ); virtual void name( vgui::Panel *p1, const wchar_t *p2 ) +#define MESSAGE_FUNC_HANDLE_WCHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 ); virtual void name( vgui::VPANEL p1, const wchar_t *p2 ) +#define MESSAGE_FUNC_CHARPTR_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_CONSTCHARPTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( const char *p1, const char *p2 ) + +#define MESSAGE_FUNC_PARAMS( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_KEYVALUES, NULL, 0, 0 ); virtual void name( KeyValues *p1 ) + +#define MESSAGE_FUNC_NV( name, scriptname ) _MessageFuncCommon( name, scriptname, 0, 0, 0, 0, 0 ); void name( void ) +#define MESSAGE_FUNC_NV_INT( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 ); void name( int p1 ) +#define MESSAGE_FUNC_NV_INT_INT( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 ); void name( int p1, int p2 ) + + + struct PanelMessageMap + { + PanelMessageMap() + { + baseMap = NULL; + pfnClassName = NULL; + processed = false; + } + + CUtlVector< MessageMapItem_t > entries; + bool processed; + PanelMessageMap* baseMap; + char const* (*pfnClassName)(void); + }; + + PanelMessageMap* FindPanelMessageMap(char const* className); + PanelMessageMap* FindOrAddPanelMessageMap(char const* className); + + + +#define MAP_MESSAGE( type, name, func ) { name, (vgui::MessageFunc_t)(&type::func), 0 } + +#define MAP_MESSAGE_PARAMS( type, name, func ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_KEYVALUES, NULL } + +#define MAP_MESSAGE_PTR( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_PTR, param1 } +#define MAP_MESSAGE_INT( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_INT, param1 } +#define MAP_MESSAGE_BOOL( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_BOOL, param1 } +#define MAP_MESSAGE_FLOAT( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_FLOAT, param1 } +#define MAP_MESSAGE_PTR( type, name, func, param1 ) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_PTR, param1 } +#define MAP_MESSAGE_CONSTCHARPTR( type, name, func, param1) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_CONSTCHARPTR, param1 } +#define MAP_MESSAGE_CONSTWCHARPTR( type, name, func, param1) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_CONSTWCHARPTR, param1 } + +#define MAP_MESSAGE_INT_INT( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_INT, param1, vgui::DATATYPE_INT, param2 } +#define MAP_MESSAGE_PTR_INT( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_INT, param2 } +#define MAP_MESSAGE_INT_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_INT, param1, vgui::DATATYPE_CONSTCHARPTR, param2 } +#define MAP_MESSAGE_PTR_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_CONSTCHARPTR, param2 } +#define MAP_MESSAGE_PTR_CONSTWCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_CONSTWCHARPTR, param2 } +#define MAP_MESSAGE_CONSTCHARPTR_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_CONSTCHARPTR, param1, vgui::DATATYPE_CONSTCHARPTR, param2 } + + + struct PanelMap_t + { + MessageMapItem_t* dataDesc; + int dataNumFields; + const char* dataClassName; + PanelMap_t* baseMap; + int processed; + }; + +#define DECLARE_PANELMAP() \ + static vgui::PanelMap_t m_PanelMap; \ + static vgui::MessageMapItem_t m_MessageMap[]; \ + virtual vgui::PanelMap_t *GetPanelMap( void ); + +#define IMPLEMENT_PANELMAP( derivedClass, baseClass ) \ + vgui::PanelMap_t derivedClass::m_PanelMap = { derivedClass::m_MessageMap, ARRAYSIZE(derivedClass::m_MessageMap), #derivedClass, &baseClass::m_PanelMap }; \ + vgui::PanelMap_t *derivedClass::GetPanelMap( void ) { return &m_PanelMap; } + + typedef vgui::Panel* (*PANELCREATEFUNC)(void); + + class CBuildFactoryHelper + { + public: + static CBuildFactoryHelper* m_sHelpers; + + public: + CBuildFactoryHelper(char const* className, PANELCREATEFUNC func); + + CBuildFactoryHelper* GetNext(void); + + char const* GetClassName() const; + + vgui::Panel* CreatePanel(); + + static vgui::Panel* InstancePanel(char const* className); + static void GetFactoryNames(CUtlVector< char const* >& list); + + static CDmxElement* CreatePanelDmxElement(vgui::Panel* pPanel); + static Panel* UnserializeDmxElementPanel(CDmxElement* pElement); + + static bool Serialize(CUtlBuffer& buf, vgui::Panel* pPanel); + static bool Unserialize(Panel** ppPanel, CUtlBuffer& buf, const char* pFileName = NULL); + + + private: + + static bool HasFactory(char const* className); + + CBuildFactoryHelper* m_pNext; + + int m_Type; + PANELCREATEFUNC m_CreateFunc; + char const* m_pClassName; + }; + +#define DECLARE_BUILD_FACTORY( className ) \ + static vgui::Panel *Create_##className( void ) \ + { \ + return new className( NULL, NULL ); \ + }; \ + static vgui::CBuildFactoryHelper g_##className##_Helper( #className, Create_##className );\ + className *g_##className##LinkerHack = NULL; + +#define DECLARE_BUILD_FACTORY_DEFAULT_TEXT( className, defaultText ) \ + static vgui::Panel *Create_##className( void ) \ + { \ + return new className( NULL, NULL, #defaultText ); \ + }; \ + static vgui::CBuildFactoryHelper g_##className##_Helper( #className, Create_##className );\ + className *g_##className##LinkerHack = NULL; + +#define DECLARE_BUILD_FACTORY_CUSTOM( className, createFunc ) \ + static vgui::CBuildFactoryHelper g_##className##_Helper( #className, createFunc );\ + className *g_##className##LinkerHack = NULL; + +#define DECLARE_BUILD_FACTORY_CUSTOM_ALIAS( className, factoryName, createFunc ) \ + static vgui::CBuildFactoryHelper g_##factoryName##_Helper( #factoryName, createFunc );\ + className *g_##factoryName##LinkerHack = NULL; + +} + + +#endif +``` + +`SpyCustom/sdk/MouseCode.h`: + +```h +#ifndef MOUSECODE_H +#define MOUSECODE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "ButtonCode.h" + +namespace vgui +{ + typedef ButtonCode_t MouseCode; +} + +#endif +``` + +`SpyCustom/sdk/PHandle.h`: + +```h +#ifndef PHANDLE_H +#define PHANDLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" + +namespace vgui +{ + + class Panel; + + class PHandle + { + public: + PHandle() : m_iPanelID(INVALID_PANEL) {} + + Panel* Get(); + Panel* Set(Panel* pPanel); + Panel* Set(HPanel hPanel); + + operator Panel* () { return Get(); } + Panel* operator ->() { return Get(); } + Panel* operator = (Panel* pPanel) { return Set(pPanel); } + + bool operator == (Panel* pPanel) { return (Get() == pPanel); } + operator bool() { return Get() != 0; } + + private: + HPanel m_iPanelID; + }; + + class VPanelHandle + { + public: + VPanelHandle() : m_iPanelID(INVALID_PANEL) {} + + VPANEL Get(); + VPANEL Set(VPANEL pPanel); + + operator VPANEL () { return Get(); } + VPANEL operator = (VPANEL pPanel) { return Set(pPanel); } + + bool operator == (VPANEL pPanel) { return (Get() == pPanel); } + operator bool() { return Get() != 0; } + + private: + HPanel m_iPanelID; + }; + + template< class PanelType > + class DHANDLE : public PHandle + { + public: + PanelType* Get() { return (PanelType*)PHandle::Get(); } + PanelType* Set(PanelType* pPanel) { return (PanelType*)PHandle::Set(pPanel); } + PanelType* Set(HPanel hPanel) { return (PanelType*)PHandle::Set(hPanel); } + + operator PanelType* () { return (PanelType*)PHandle::Get(); } + PanelType* operator ->() { return (PanelType*)PHandle::Get(); } + PanelType* operator = (PanelType* pPanel) { return (PanelType*)PHandle::Set(pPanel); } + bool operator == (Panel* pPanel) { return (PHandle::Get() == pPanel); } + operator bool() { return PHandle::Get() != NULL; } + }; + +}; + +#endif +``` + +`SpyCustom/sdk/Panel.h`: + +```h +#ifndef PANEL_H +#define PANEL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlflags.h" +#include "vgui.h" +#include "Dar.h" +#include "MessageMap.h" +#if defined( VGUI_USEKEYBINDINGMAPS ) +#include "KeyBindingMap.h" +#endif +#include "IClientPanel.h" +#include "IScheme.h" +#include "Controls.h" +#include "PHandle.h" +#include "PanelAnimationVar.h" +#include "color.h" +#include "keyvalues.h" +#include "ikeyvaluessystem.h" +#include "utlsymbol.h" +#include "BuildGroup.h" +#include "dmxelement.h" + +#ifdef PostMessage +#undef PostMessage +#endif + +#ifdef SetCursor +#undef SetCursor +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CUtlBuffer; +struct DmxElementUnpackStructure_t; + +namespace vgui +{ + +#if !defined( _GAMECONSOLE ) +#define VGUI_USEDRAGDROP 1 +#endif + +#if defined( VGUI_USEKEYBINDINGMAPS ) + struct PanelKeyBindingMap; +#endif + //----------------------------------------------------------------------------- + // Purpose: Helper functions to construct vgui panels + // + // SETUP_PANEL - will make a panel ready for use right now (i.e setup its colors, borders, fonts, etc) + // + template< class T > + inline T* SETUP_PANEL(T* panel) + { + panel->MakeReadyForUse(); + return panel; + } + + // + // CREATE_PANEL - creates a panel that is ready to use right now + // + // example of use = to set the FG Color of a panel inside of a constructor (i.e before ApplySchemeSettings() has been run on the child) + // +#define CREATE_PANEL(type, parent, name) (SETUP_PANEL(new type(parent, name))) + +//----------------------------------------------------------------------------- +// Purpose: Drag/drop support context info (could defined within Panel...) +//----------------------------------------------------------------------------- +#if defined( VGUI_USEDRAGDROP ) + struct DragDrop_t; + class Menu; +#endif + + + + class Panel; + + struct SizerAddArgs_t + { + SizerAddArgs_t() + { + m_flExpandFactor = 0.0f; + m_nPadding = 5; + m_bMinorExpand = true; + m_nMinX = -1; + m_nMinY = -1; + m_bIgnoreMemberMin = false; + } + + SizerAddArgs_t& Expand(float flExpandFactor) { m_flExpandFactor = flExpandFactor; return *this; } + SizerAddArgs_t& Padding(int nPadding) { m_nPadding = nPadding; return *this; } + SizerAddArgs_t& MinorExpand(bool bMinorExpand) { m_bMinorExpand = bMinorExpand; return *this; } + SizerAddArgs_t& MinSize(int nMinX, int nMinY) { m_nMinX = nMinX; m_nMinY = nMinY; return *this; } + SizerAddArgs_t& MinX(int nMinX) { m_nMinX = nMinX; return *this; } + SizerAddArgs_t& MinY(int nMinY) { m_nMinY = nMinY; return *this; } + + // IgnoreMemberMin --> MinX and MinY (when set) are the only criteria for minimum size; member-requested min size is ignored + SizerAddArgs_t& IgnoreMemberMin(bool bIgnoreMemberMin = true) { m_bIgnoreMemberMin = bIgnoreMemberMin; return *this; } + + SizerAddArgs_t& FixedSize(int nX, int nY) + { + IgnoreMemberMin(true); + MinSize(nX, nY); + Expand(0.f); + MinorExpand(false); + return *this; + } + + float m_flExpandFactor; + int m_nPadding; + bool m_bMinorExpand; + int m_nMinX; + int m_nMinY; + bool m_bIgnoreMemberMin; + }; + + + enum SizerLayoutDirection_t + { + ESLD_HORIZONTAL, // major axis = X + ESLD_VERTICAL // major axis = Y + }; + + enum SizerElementType_t + { + ESET_SIZER, + ESET_PANEL, + ESET_SPACER, + }; + + class CSizerBase + { + public: + CSizerBase(); + virtual ~CSizerBase(); + + int GetElementCount() { return m_Members.Count(); } + SizerElementType_t GetElementType(int i); + Panel* GetPanel(int i); + + void SetElementArgs(int nIndex, const SizerAddArgs_t& args) { m_Members[nIndex].Fill(args); } + + // The containing panel's layout should be invalidated if members are added to this sizer. + + // Inserts a panel/sizer/spacer at the specified index and shifts remaining elements down + void InsertPanel(int nIndex, Panel* pPanel, const SizerAddArgs_t& args); + void InsertSizer(int nIndex, CSizerBase* pSizer, const SizerAddArgs_t& args); + void InsertSpacer(int nIndex, const SizerAddArgs_t& args); + + void AddPanel(Panel* pPanel, const SizerAddArgs_t& args) { InsertPanel(GetElementCount(), pPanel, args); } + void AddSizer(CSizerBase* pSizer, const SizerAddArgs_t& args) { InsertSizer(GetElementCount(), pSizer, args); } + void AddSpacer(const SizerAddArgs_t& args) { InsertSpacer(GetElementCount(), args); } + + void RemoveElement(int i, bool bDelete); + void RemoveAllMembers(bool bDelete); + + void GetMinSize(int& OutX, int& OutY); + + // Called by Panel on PerformLayout() so that sizer client size computations are up-to-date + void RecursiveInvalidateCachedSize(); + + virtual void DoLayout(int BaseX, int BaseY, int SizeX, int SizeY) = 0; + virtual void CalculateSize() = 0; + + protected: + class CSizerMember + { + friend class CSizerBase; // allow CSizerBase to populate the private members directly + + public: + SizerElementType_t GetElementType() const; + Panel* GetPanel() const; + + void GetMemberMinSize(int& OutX, int& OutY); + void RecursiveInvalidateCachedSize(); + void Place(int BaseX, int BaseY, int SizeX, int SizeY); + + float GetExpandFactor() { return m_flExpandFactor; } + bool GetMinorExpand() { return m_bMinorExpand; } + + void DiscardOwnedSizer(); + + bool IsVisible(); + + void Fill(const SizerAddArgs_t& args); + + private: + void RecursiveRemove(bool bDelete); + + Panel* m_pPanel; + CSizerBase* m_pSizer; + + int m_nPadding; // if m_pPanel and m_pSizer are both NULL, this is the spacer min size + float m_flExpandFactor; + bool m_bMinorExpand; + bool m_bIgnoreMemberMin; + int m_nMinX; + int m_nMinY; + }; + + CUtlVector m_Members; + int m_nMinXSize; + int m_nMinYSize; + }; + + inline int SizerMajorAxis(SizerLayoutDirection_t Dir, int X, int Y) { return (Dir == ESLD_HORIZONTAL) ? X : Y; } + inline int SizerMinorAxis(SizerLayoutDirection_t Dir, int X, int Y) { return (Dir == ESLD_VERTICAL) ? X : Y; } + inline int SizerXAxis(SizerLayoutDirection_t Dir, int MajorAxis, int MinorAxis) { return (Dir == ESLD_HORIZONTAL) ? MajorAxis : MinorAxis; } + inline int SizerYAxis(SizerLayoutDirection_t Dir, int MajorAxis, int MinorAxis) { return (Dir == ESLD_VERTICAL) ? MajorAxis : MinorAxis; } + + class CBoxSizer : public CSizerBase + { + public: + CBoxSizer(SizerLayoutDirection_t LayoutDirection); + + virtual void CalculateSize(); + virtual void DoLayout(int BaseX, int BaseY, int SizeX, int SizeY); + + protected: + SizerLayoutDirection_t m_LayoutDirection; + }; + + + //----------------------------------------------------------------------------- + // Purpose: Macro to handle Colors that can be overridden in .res files + //----------------------------------------------------------------------------- + struct OverridableColorEntry + { + char const* name() { return m_pszScriptName; } + + char const* m_pszScriptName; + Color* m_pColor; + Color m_colFromScript; + UtlSymId_t m_sColorNameFromScript; + bool m_bOverridden; + }; + +#define REGISTER_COLOR_AS_OVERRIDABLE( name, scriptname ) \ + AddToOverridableColors( &name, scriptname ); + + + //----------------------------------------------------------------------------- + // Macros for unpacking vgui panels + //----------------------------------------------------------------------------- +#define DECLARE_VGUI_UNPACK() \ + DECLARE_DMXELEMENT_UNPACK() \ + private: \ + static DmxElementUnpackStructure_t *s_pUnpackParams; \ + public: \ + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const { return s_pUnpackParams; } + +#define DECLARE_VGUI_UNPACK_NAMESPACE( _namespace ) \ + template friend DmxElementUnpackStructure_t *DmxElementUnpackInit##_namespace(T *); \ + private: \ + static DmxElementUnpackStructure_t *s_pUnpackParams; \ + public: \ + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const { return s_pUnpackParams; } + +#define BEGIN_VGUI_UNPACK( _structName ) BEGIN_DMXELEMENT_UNPACK( _structName ) +#define END_VGUI_UNPACK( _structName ) \ + END_DMXELEMENT_UNPACK( _structName, s_pUnpackParams ) \ + DmxElementUnpackStructure_t *_structName::s_pUnpackParams = _structName##_UnpackInit::s_pUnpack; + +#define BEGIN_VGUI_UNPACK_NAMESPACE( _nameSpace, _structName ) BEGIN_DMXELEMENT_UNPACK_NAMESPACE( _nameSpace, _structName ) +#define END_VGUI_UNPACK_NAMESPACE( _nameSpace, _structName ) \ + END_DMXELEMENT_UNPACK_NAMESPACE( _nameSpace, _structName, s_pUnpackParams ) \ + DmxElementUnpackStructure_t *_structName::s_pUnpackParams = _namespace##_structName##_UnpackInit::s_pUnpack; + + +//----------------------------------------------------------------------------- +// Purpose: For hudanimations.txt scripting of vars +//----------------------------------------------------------------------------- + class IPanelAnimationPropertyConverter + { + public: + virtual void GetData(Panel* panel, KeyValues* kv, PanelAnimationMapEntry* entry) = 0; + virtual void SetData(Panel* panel, KeyValues* kv, PanelAnimationMapEntry* entry) = 0; + virtual void InitFromDefault(Panel* panel, PanelAnimationMapEntry* entry) = 0; + }; + +#if defined( VGUI_USEKEYBINDINGMAPS ) + enum KeyBindingContextHandle_t + { + INVALID_KEYBINDINGCONTEXT_HANDLE = 0xffffffff, + }; +#endif + + //============================================================================= + // HPE_BEGIN: + // [tj] bitwise defines for rounded corners + //============================================================================= +#define PANEL_ROUND_CORNER_TOP_LEFT (1 << 0) +#define PANEL_ROUND_CORNER_TOP_RIGHT (1 << 1) +#define PANEL_ROUND_CORNER_BOTTOM_LEFT (1 << 2) +#define PANEL_ROUND_CORNER_BOTTOM_RIGHT (1 << 3) +#define PANEL_ROUND_CORNER_ALL PANEL_ROUND_CORNER_TOP_LEFT | PANEL_ROUND_CORNER_TOP_RIGHT | PANEL_ROUND_CORNER_BOTTOM_LEFT | PANEL_ROUND_CORNER_BOTTOM_RIGHT +//============================================================================= +// HPE_END +//=============================================================================//----------------------------------------------------------------------------- +// Purpose: Base interface to all vgui windows +// All vgui controls that receive message and/or have a physical presence +// on screen are be derived from Panel. +// This is designed as an easy-access to the vgui-functionality; for more +// low-level access to vgui functions use the IPanel/IClientPanel interfaces directly +//----------------------------------------------------------------------------- + class Panel : public IClientPanel + { + DECLARE_CLASS_SIMPLE_NOBASE(Panel); + DECLARE_DMXELEMENT_UNPACK_NAMESPACE(vgui); + + public: + // For property mapping + static void InitPropertyConverters(void); + static void AddPropertyConverter(char const* typeName, IPanelAnimationPropertyConverter* converter); + + //----------------------------------------------------------------------------- + // CONSTRUCTORS + // these functions deal with the creation of the Panel + // the Panel automatically gets a handle to a vgui-internal panel, the ipanel(), upon construction + // vgui interfaces deal only with ipanel(), not Panel directly + Panel(); + Panel(Panel* parent); + Panel(Panel* parent, const char* panelName); + Panel(Panel* parent, const char* panelName, HScheme scheme); + + virtual ~Panel(); + + // returns pointer to Panel's vgui VPanel interface handle + virtual VPANEL GetVPanel() { return _vpanel; } + HPanel ToHandle() const; + + + //----------------------------------------------------------------------------- + // PANEL METHODS + // these functions all manipulate panels + // they cannot be derived from + void SetName(const char* panelName); // sets the name of the panel - used as an identifier + const char* GetName(); // returns the name of this panel... never NULL + const char* GetClassName(); // returns the class name of the panel (eg. Panel, Label, Button, etc.) + + void MakeReadyForUse(); // fully construct this panel so its ready for use right now (i.e fonts loaded, colors set, default label text set, ...) + + // panel position & size + // all units are in pixels + void SetPos(int x, int y); // sets position of panel, in local space (ie. relative to parent's position) + void GetPos(int& x, int& y); // gets local position of panel + void SetSize(int wide, int tall); // sets size of panel + void GetSize(int& wide, int& tall); // gets size of panel + void SetBounds(int x, int y, int wide, int tall); // combination of SetPos/SetSize + void GetBounds(int& x, int& y, int& wide, int& tall); // combination of GetPos/GetSize + int GetWide(); // returns width of panel + void SetWide(int wide); // sets width of panel + int GetTall(); // returns height of panel + void SetTall(int tall); // sets height of panel + void SetMinimumSize(int wide, int tall); // sets the minimum size the panel can go + void GetMinimumSize(int& wide, int& tall); // gets the minimum size + bool IsBuildModeEditable(); // editable in the buildModeDialog? + void SetBuildModeEditable(bool state); // set buildModeDialog editable + bool IsBuildModeDeletable(); // deletable in the buildModeDialog? + void SetBuildModeDeletable(bool state); // set buildModeDialog deletable + bool IsBuildModeActive(); // true if we're currently in edit mode + void SetZPos(int z); // sets Z ordering - lower numbers are always behind higher z's + int GetZPos(void); + void SetAlpha(int alpha); // sets alpha modifier for panel and all child panels [0..255] + int GetAlpha(); // returns the current alpha + + // panel visibility + // invisible panels and their children do not drawn, updated, or receive input messages + virtual void SetVisible(bool state); + virtual bool IsVisible(); + virtual bool IsFullyVisible(); // checks parent panels are IsVisible too + + // painting + virtual VPANEL IsWithinTraverse(int x, int y, bool traversePopups); // recursive; returns a pointer to the panel at those coordinates + MESSAGE_FUNC(Repaint, "Repaint"); // marks the panel as needing to be repainted + virtual void PostMessage(VPANEL target, KeyValues* message, float delaySeconds = 0.0f); + + bool IsWithin(int x, int y); //in screen space + void LocalToScreen(int& x, int& y); + void ScreenToLocal(int& x, int& y); + void ParentLocalToScreen(int& x, int& y); + void MakePopup(bool showTaskbarIcon = true, bool disabled = false); // turns the panel into a popup window (ie. can draw outside of it's parents space) + virtual void OnMove(); + + // panel hierarchy + virtual Panel* GetParent(); + virtual VPANEL GetVParent(); + virtual void SetParent(Panel* newParent); + virtual void SetParent(VPANEL newParent); + virtual bool HasParent(VPANEL potentialParent); + + int GetChildCount(); + Panel* GetChild(int index); + int FindChildIndexByName(const char* childName); + Panel* FindChildByName(const char* childName, bool recurseDown = false); + Panel* FindSiblingByName(const char* siblingName); + void CallParentFunction(KeyValues* message); + + virtual bool LookupElementBounds(const char* elementName, int& x, int& y, int& wide, int& tall) { return false; } + + virtual void SetAutoDelete(bool state); // if set to true, panel automatically frees itself when parent is deleted + virtual bool IsAutoDeleteSet(); + virtual void DeletePanel(); // simply does a { delete this; } + + // messaging + virtual void AddActionSignalTarget(Panel* messageTarget); + virtual void AddActionSignalTarget(VPANEL messageTarget); + virtual void RemoveActionSignalTarget(Panel* oldTarget); + virtual void PostActionSignal(KeyValues* message); // sends a message to the current actionSignalTarget(s) + virtual bool RequestInfoFromChild(const char* childName, KeyValues* outputData); + virtual void PostMessageToChild(const char* childName, KeyValues* messsage); + virtual void PostMessage(Panel* target, KeyValues* message, float delaySeconds = 0.0f); + virtual bool RequestInfo(KeyValues* outputData); // returns true if output is successfully written. You should always chain back to the base class if info request is not handled + virtual bool SetInfo(KeyValues* inputData); // sets a specified value in the control - inverse of the above + virtual void SetSilentMode(bool bSilent); //change the panel's silent mode; if silent, the panel will not post any action signals + + // install a mouse handler + virtual void InstallMouseHandler(Panel* pHandler); // mouse events will be send to handler panel instead of this panel + + // drawing state + virtual void SetEnabled(bool state); + virtual bool IsEnabled(); + virtual bool IsPopup(); // has a parent, but is in it's own space + virtual void GetClipRect(int& x0, int& y0, int& x1, int& y1); + virtual void MoveToFront(); + + // pin positions for auto-layout + enum PinCorner_e + { + PIN_TOPLEFT = 0, + PIN_TOPRIGHT, + PIN_BOTTOMLEFT, + PIN_BOTTOMRIGHT, + PIN_NO, + + // For sibling pinning + PIN_CENTER_TOP, + PIN_CENTER_RIGHT, + PIN_CENTER_BOTTOM, + PIN_CENTER_LEFT, + }; + + // specifies the auto-resize directions for the panel + enum AutoResize_e + { + AUTORESIZE_NO = 0, + AUTORESIZE_RIGHT, + AUTORESIZE_DOWN, + AUTORESIZE_DOWNANDRIGHT, + }; + + // Sets the pin corner for non-resizing panels + void SetPinCorner(PinCorner_e pinCorner, int nOffsetX, int nOffsetY); + + // Sets the pin corner + resize mode for resizing panels + void SetAutoResize(PinCorner_e pinCorner, AutoResize_e resizeDir, int nPinOffsetX, int nPinOffsetY, int nUnpinnedCornerOffsetX, int nUnpinnedCornerOffsetY); + + AutoResize_e GetAutoResize(); + PinCorner_e GetPinCorner(); + + // Gets the relative offset of the control from the pinned + non-pinned corner (for resizing) + void GetPinOffset(int& dx, int& dy); + void GetResizeOffset(int& dx, int& dy); + + void PinToSibling(const char* pszSibling, PinCorner_e pinOurCorner, PinCorner_e pinSibling); + void UpdateSiblingPin(void); + + // colors + virtual void SetBgColor(Color color); + virtual void SetFgColor(Color color); + virtual Color GetBgColor(); + virtual Color GetFgColor(); + + virtual void SetCursor(HCursor cursor); + virtual HCursor GetCursor(); + virtual void RequestFocus(int direction = 0); + virtual bool HasFocus(); + virtual void InvalidateLayout(bool layoutNow = false, bool reloadScheme = false); + virtual bool RequestFocusPrev(VPANEL panel = NULL); + virtual bool RequestFocusNext(VPANEL panel = NULL); + // tab positioning + virtual void SetTabPosition(int position); + virtual int GetTabPosition(); + // border + virtual void SetBorder(IBorder* border); + virtual IBorder* GetBorder(); + virtual void SetPaintBorderEnabled(bool state); + virtual void SetPaintBackgroundEnabled(bool state); + virtual void SetPaintEnabled(bool state); + virtual void SetPostChildPaintEnabled(bool state); + virtual void SetPaintBackgroundType(int type); // 0 for normal(opaque), 1 for single texture from Texture1, and 2 for rounded box w/ four corner textures + virtual void GetInset(int& left, int& top, int& right, int& bottom); + virtual void GetPaintSize(int& wide, int& tall); + virtual void SetBuildGroup(BuildGroup* buildGroup); + virtual bool IsBuildGroupEnabled(); + virtual bool IsCursorNone(); + virtual bool IsCursorOver(); // returns true if the cursor is currently over the panel + virtual void MarkForDeletion(); // object will free it's memory next tick + virtual bool IsLayoutInvalid(); // does this object require a perform layout? + virtual Panel* HasHotkey(wchar_t key); // returns the panel that has this hotkey + virtual bool IsOpaque(); + bool IsRightAligned(); // returns true if the settings are aligned to the right of the screen + bool IsBottomAligned(); // returns true if the settings are aligned to the bottom of the screen + bool IsPercentage(); // returns true if the settings are a percentage of screen size + + // scheme access functions + virtual HScheme GetScheme(); + virtual void SetScheme(const char* tag); + virtual void SetScheme(HScheme scheme); + virtual Color GetSchemeColor(const char* keyName, IScheme* pScheme); + virtual Color GetSchemeColor(const char* keyName, Color defaultColor, IScheme* pScheme); + + // called when scheme settings need to be applied; called the first time before the panel is painted + virtual void ApplySchemeSettings(IScheme* pScheme); + + // interface to build settings + // takes a group of settings and applies them to the control + virtual void ApplySettings(KeyValues* inResourceData); + virtual void OnUnserialized(CDmxElement* pElement); + + // records the settings into the resource data + virtual void GetSettings(KeyValues* outResourceData); + + // gets a description of the resource for use in the UI + // format: ... + // unknown types as just displayed as strings in the UI (for future UI expansion) + virtual const char* GetDescription(); + + // returns the name of the module that this instance of panel was compiled into + virtual const char* GetModuleName(); + + // user configuration settings + // this is used for any control details the user wants saved between sessions + // eg. dialog positions, last directory opened, list column width + virtual void ApplyUserConfigSettings(KeyValues* userConfig); + + // returns user config settings for this control + virtual void GetUserConfigSettings(KeyValues* userConfig); + + // optimization, return true if this control has any user config settings + virtual bool HasUserConfigSettings(); + + // message handlers + // override to get access to the message + // override to get access to the message + virtual void OnMessage(const KeyValues* params, VPANEL fromPanel); // called when panel receives message; must chain back + MESSAGE_FUNC_CHARPTR(OnCommand, "Command", command); // called when a panel receives a command + MESSAGE_FUNC(OnMouseCaptureLost, "MouseCaptureLost"); // called after the panel loses mouse capture + MESSAGE_FUNC(OnSetFocus, "SetFocus"); // called after the panel receives the keyboard focus + MESSAGE_FUNC(OnKillFocus, "KillFocus"); // called after the panel loses the keyboard focus + MESSAGE_FUNC(OnDelete, "Delete"); // called to delete the panel; Panel::OnDelete() does simply { delete this; } + virtual void OnThink(); // called every frame before painting, but only if panel is visible + virtual void OnChildAdded(VPANEL child); // called when a child has been added to this panel + virtual void OnSizeChanged(int newWide, int newTall); // called after the size of a panel has been changed + + // called every frame if ivgui()->AddTickSignal() is called + virtual void OnTick(); + + // input messages + MESSAGE_FUNC_INT_INT(OnCursorMoved, "OnCursorMoved", x, y); + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + virtual void OnMouseWheeled(int delta); + + // Trip pressing (e.g., select all text in a TextEntry) requires this to be enabled + virtual void SetTriplePressAllowed(bool state); + virtual bool IsTriplePressAllowed() const; + virtual void OnMouseTriplePressed(MouseCode code); + + static char const* KeyCodeToString(KeyCode code); + static wchar_t const* KeyCodeToDisplayString(KeyCode code); + static wchar_t const* KeyCodeModifiersToDisplayString(KeyCode code, int modifiers); // L"Ctrl+Alt+Shift+Backspace" + + static KeyCode StringToKeyCode(char const* str); +#if defined( VGUI_USEKEYBINDINGMAPS ) + static KeyBindingContextHandle_t CreateKeyBindingsContext(char const* filename, char const* pathID = 0); + virtual void SetKeyBindingsContext(KeyBindingContextHandle_t handle); + virtual KeyBindingContextHandle_t GetKeyBindingsContext() const; + virtual bool IsValidKeyBindingsContext() const; + + static int GetPanelsWithKeyBindingsCount(KeyBindingContextHandle_t handle); + static Panel* GetPanelWithKeyBindings(KeyBindingContextHandle_t handle, int index); + + static void RevertKeyBindings(KeyBindingContextHandle_t handle); + + static void ReloadKeyBindings(KeyBindingContextHandle_t handle); + static void SaveKeyBindings(KeyBindingContextHandle_t handle); + static void SaveKeyBindingsToFile(KeyBindingContextHandle_t handle, char const* filename, char const* pathID = 0); + static void LoadKeyBindings(KeyBindingContextHandle_t handle); + static void LoadKeyBindingsForOnePanel(KeyBindingContextHandle_t handle, Panel* panelOfInterest); + + // OnKeyCodeTyped hooks into here for action + virtual bool IsKeyRebound(KeyCode code, int modifiers); + // If a panel implements this and returns true, then the IsKeyRebound check will fail and OnKeyCodeTyped messages will pass through.. + // sort of like setting the SetAllowKeyBindingChainToParent flag to false for specific keys + virtual bool IsKeyOverridden(KeyCode code, int modifiers); + + virtual void AddKeyBinding(char const* bindingName, int keycode, int modifiers); + + KeyBindingMap_t* LookupBinding(char const* bindingName); + KeyBindingMap_t* LookupBindingByKeyCode(KeyCode code, int modifiers); + void LookupBoundKeys(char const* bindingName, CUtlVector< BoundKey_t* >& list); + BoundKey_t* LookupDefaultKey(char const* bindingName); + PanelKeyBindingMap* LookupMapForBinding(char const* bindingName); + + // Returns the number of keybindings + int GetKeyMappingCount(); + + void RevertKeyBindingsToDefault(); + void RemoveAllKeyBindings(); + void ReloadKeyBindings(); + virtual void EditKeyBindings(); + + // calls RevertKeyBindingsToDefault() and then LoadKeyBindingsForOnePanel( GetKeyBindingsContext(), this ); + void SaveKeyBindingsToBuffer(int level, CUtlBuffer& buf); + bool ParseKeyBindings(KeyValues* kv); + + virtual char const* GetKeyBindingsFile() const; + virtual char const* GetKeyBindingsFilePathID() const; + + // Set this to false to disallow IsKeyRebound chaining to GetParent() Panels... + void SetAllowKeyBindingChainToParent(bool state); + bool IsKeyBindingChainToParentAllowed() const; +#endif // VGUI_USEKEYBINDINGMAPS + + // base implementation forwards Key messages to the Panel's parent + // - override to 'swallow' the input + virtual void OnKeyCodePressed(KeyCode code); + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + virtual void OnKeyCodeReleased(KeyCode code); + virtual void OnKeyFocusTicked(); // every window gets key ticked events + + // forwards mouse messages to the panel's parent + MESSAGE_FUNC(OnMouseFocusTicked, "OnMouseFocusTicked"); + + // message handlers that don't go through the message pump + virtual void PaintBackground(); + virtual void Paint(); + virtual void PaintBorder(); + virtual void PaintBuildOverlay(); // the extra drawing for when in build mode + virtual void PostChildPaint(); + virtual void PerformLayout(); + + // this enables message mapping for this class - requires matching IMPLEMENT_PANELDESC() in the .cpp file + DECLARE_PANELMAP(); + + virtual VPANEL GetCurrentKeyFocus(); + + // returns a pointer to the tooltip object associated with the panel + // creates a new one if none yet exists + BaseTooltip* GetTooltip(); + void SetTooltip(BaseTooltip* pToolTip, const char* pszText); + + // proportional mode settings + virtual bool IsProportional() { return _flags.IsFlagSet(IS_PROPORTIONAL); } + virtual void SetProportional(bool state); + + // input interest + virtual void SetMouseInputEnabled(bool state); + virtual void SetKeyBoardInputEnabled(bool state); + virtual bool IsMouseInputEnabled(); + virtual bool IsKeyBoardInputEnabled(); + + // allows you to disable for this panel but not children + void DisableMouseInputForThisPanel(bool bDisable); + bool IsMouseInputDisabledForThisPanel() const; + + virtual void DrawTexturedBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha); + virtual void DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, bool hollow = false); + virtual void DrawBoxFade(int x, int y, int wide, int tall, Color color, float normalizedAlpha, unsigned int alpha0, unsigned int alpha1, bool bHorizontal, bool hollow = false); + virtual void DrawHollowBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha); + //============================================================================= + // HPE_BEGIN: + //============================================================================= + + // [menglish] Draws a hollow box similar to the already existing draw hollow box function, but takes the indents as params + virtual void DrawHollowBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int cornerWide, int cornerTall); + + // [tj] Simple getters and setters to decide which corners to draw rounded + unsigned char GetRoundedCorners() { return m_roundedCorners; } + void SetRoundedCorners(unsigned char cornerFlags) { m_roundedCorners = cornerFlags; } + bool ShouldDrawTopLeftCornerRounded() { return 0 != (m_roundedCorners & PANEL_ROUND_CORNER_TOP_LEFT); } + bool ShouldDrawTopRightCornerRounded() { return 0 != (m_roundedCorners & PANEL_ROUND_CORNER_TOP_RIGHT); } + bool ShouldDrawBottomLeftCornerRounded() { return 0 != (m_roundedCorners & PANEL_ROUND_CORNER_BOTTOM_LEFT); } + bool ShouldDrawBottomRightCornerRounded() { return 0 != (m_roundedCorners & PANEL_ROUND_CORNER_BOTTOM_RIGHT); } + + //============================================================================= + // HPE_END + //============================================================================= + + // Drag Drop Public interface + + virtual void SetDragEnabled(bool enabled); + virtual bool IsDragEnabled() const; + + virtual void SetShowDragHelper(bool enabled); + + // Called if drag drop is started but not dropped on top of droppable panel... + virtual void OnDragFailed(CUtlVector< KeyValues* >& msglist); + + // Use this to prevent chaining up from a parent which can mess with mouse functionality if you don't want to chain up from a child panel to the best + // draggable parent. + virtual void SetBlockDragChaining(bool block); + virtual bool IsBlockingDragChaining() const; + + virtual int GetDragStartTolerance() const; + virtual void SetDragSTartTolerance(int nTolerance); + + // If hover context time is non-zero, then after the drop cursor is hovering over the panel for that amount of time + // the Show hover context menu function will be invoked + virtual void SetDropEnabled(bool enabled, float m_flHoverContextTime = 0.0f); + virtual bool IsDropEnabled() const; + + // Called if m_flHoverContextTime was non-zero, allows droppee to preview the drop data and show an appropriate menu + // Return false if not using context menu + virtual bool GetDropContextMenu(Menu* menu, CUtlVector< KeyValues* >& msglist); + virtual void OnDropContextHoverShow(CUtlVector< KeyValues* >& msglist); + virtual void OnDropContextHoverHide(CUtlVector< KeyValues* >& msglist); + +#if defined( VGUI_USEDRAGDROP ) + virtual DragDrop_t* GetDragDropInfo(); +#endif + // For handling multiple selections... + virtual void OnGetAdditionalDragPanels(CUtlVector< Panel* >& dragabbles); + + virtual void OnCreateDragData(KeyValues* msg); + // Called to see if a drop enabled panel can accept the specified data blob + virtual bool IsDroppable(CUtlVector< KeyValues* >& msglist); + + // Mouse is on draggable panel and has started moving, but is not over a droppable panel yet + virtual void OnDraggablePanelPaint(); + // Mouse is now over a droppable panel + virtual void OnDroppablePanelPaint(CUtlVector< KeyValues* >& msglist, CUtlVector< Panel* >& dragPanels); + + virtual void OnPanelDropped(CUtlVector< KeyValues* >& msglist); + + // called on droptarget when draggable panel entered/exited droptarget + virtual void OnPanelEnteredDroppablePanel(CUtlVector< KeyValues* >& msglist); + virtual void OnPanelExitedDroppablePanel(CUtlVector< KeyValues* >& msglist); + + // Chains up to any parent marked DropEnabled + virtual Panel* GetDropTarget(CUtlVector< KeyValues* >& msglist); + // Chains up to first parent marked DragEnabled + virtual Panel* GetDragPanel(); + virtual bool IsBeingDragged(); + virtual HCursor GetDropCursor(CUtlVector< KeyValues* >& msglist); + virtual HCursor GetDragFailCursor(CUtlVector< KeyValues* >& msglist) { return dc_no; } + + Color GetDropFrameColor(); + Color GetDragFrameColor(); + + // Can override to require custom behavior to start the drag state + virtual bool CanStartDragging(int startx, int starty, int mx, int my); + + // Draws a filled rect of specified bounds, but omits the bounds of the skip panel from those bounds + virtual void FillRectSkippingPanel(const Color clr, int x, int y, int w, int h, Panel* skipPanel); + + virtual int GetPaintBackgroundType(); + virtual void GetCornerTextureSize(int& w, int& h); + + bool IsChildOfModalSubTree(); + bool IsChildOfSurfaceModalPanel(); + + bool ShouldHandleInputMessage(); + + virtual void SetSkipChildDuringPainting(Panel* child); + + // If this is set, then the drag drop won't occur until the mouse leaves the drag panels current rectangle + void SetStartDragWhenMouseExitsPanel(bool state); + bool IsStartDragWhenMouseExitsPanel() const; + + // Forces context ID for this panel and all children below it + void SetMessageContextId_R(int nContextID); + + void PostMessageToAllSiblings(KeyValues* msg, float delaySeconds = 0.0f); + template< class S > + void PostMessageToAllSiblingsOfType(KeyValues* msg, float delaySeconds = 0.0f); + + void SetConsoleStylePanel(bool bConsoleStyle); + bool IsConsoleStylePanel() const; + + // For 360: support directional navigation between UI controls via dpad + enum NAV_DIRECTION { ND_UP, ND_DOWN, ND_LEFT, ND_RIGHT, ND_BACK, ND_NONE }; + virtual Panel* NavigateUp(); + virtual Panel* NavigateDown(); + virtual Panel* NavigateLeft(); + virtual Panel* NavigateRight(); + virtual void NavigateTo(); + virtual void NavigateFrom(); + virtual void NavigateToChild(Panel* pNavigateTo); //mouse support + + Panel* SetNavUp(Panel* navUp); + Panel* SetNavDown(Panel* navDown); + Panel* SetNavLeft(Panel* navLeft); + Panel* SetNavRight(Panel* navRight); + NAV_DIRECTION GetLastNavDirection(); + MESSAGE_FUNC_CHARPTR(OnNavigateTo, "OnNavigateTo", panelName); + MESSAGE_FUNC_CHARPTR(OnNavigateFrom, "OnNavigateFrom", panelName); + + // Drag Drop protected/internal interface + protected: + + virtual void OnStartDragging(); + virtual void OnContinueDragging(); + virtual void OnFinishDragging(bool mousereleased, MouseCode code, bool aborted = false); + + virtual void DragDropStartDragging(); + + virtual void GetDragData(CUtlVector< KeyValues* >& list); + virtual void CreateDragData(); + + virtual void PaintTraverse(bool Repaint, bool allowForce = true); + + protected: + MESSAGE_FUNC_ENUM_ENUM(OnRequestFocus, "OnRequestFocus", VPANEL, subFocus, VPANEL, defaultPanel); + MESSAGE_FUNC_INT_INT(OnScreenSizeChanged, "OnScreenSizeChanged", oldwide, oldtall); + virtual void* QueryInterface(EInterfaceID id); + + void AddToOverridableColors(Color* pColor, char const* scriptname) + { + int iIdx = m_OverridableColorEntries.AddToTail(); + m_OverridableColorEntries[iIdx].m_pszScriptName = scriptname; + m_OverridableColorEntries[iIdx].m_pColor = pColor; + m_OverridableColorEntries[iIdx].m_bOverridden = false; + } + + void ApplyOverridableColors(IScheme* pScheme); + void SetOverridableColor(Color* pColor, const Color& newColor); + + protected: + void SetNavUp(const char* controlName); + void SetNavDown(const char* controlName); + void SetNavLeft(const char* controlName); + void SetNavRight(const char* controlName); + + public: + /* + Will recursively look for the next visible panel in the navigation chain, parameters are for internal use. + It will stop looking if first == nextpanel (to prevent infinite looping). + */ + Panel* GetNavUp(Panel* first = NULL); + Panel* GetNavDown(Panel* first = NULL); + Panel* GetNavLeft(Panel* first = NULL); + Panel* GetNavRight(Panel* first = NULL); + + // if set, Panel gets PerformLayout called after the camera and the renderer's m_matrixWorldToScreen has been setup, so panels can be correctly attached to entities in the world + inline void SetWorldPositionCurrentFrame(bool bWorldPositionCurrentFrame) { m_bWorldPositionCurrentFrame = bWorldPositionCurrentFrame; } + inline bool GetWorldPositionCurrentFrame() { return m_bWorldPositionCurrentFrame; } + + protected: + //this will return m_NavDown and will not look for the next visible panel + Panel* GetNavUpPanel(); + Panel* GetNavDownPanel(); + Panel* GetNavLeftPanel(); + Panel* GetNavRightPanel(); + + bool m_PassUnhandledInput; + NAV_DIRECTION m_LastNavDirection; + + void InternalInitDefaultValues(PanelAnimationMap* map); + + + private: + enum BuildModeFlags_t + { + BUILDMODE_EDITABLE = 0x01, + BUILDMODE_DELETABLE = 0x02, + BUILDMODE_SAVE_XPOS_RIGHTALIGNED = 0x04, + BUILDMODE_SAVE_XPOS_CENTERALIGNED = 0x08, + BUILDMODE_SAVE_YPOS_BOTTOMALIGNED = 0x10, + BUILDMODE_SAVE_YPOS_CENTERALIGNED = 0x20, + BUILDMODE_SAVE_WIDE_FULL = 0x40, + BUILDMODE_SAVE_TALL_FULL = 0x80, + BUILDMODE_SAVE_PROPORTIONAL_TO_PARENT = 0x100, + BUILDMODE_SAVE_PERCENTAGE = 0x200, + }; + + enum PanelFlags_t + { + MARKED_FOR_DELETION = 0x0001, + NEEDS_REPAINT = 0x0002, + PAINT_BORDER_ENABLED = 0x0004, + PAINT_BACKGROUND_ENABLED = 0x0008, + PAINT_ENABLED = 0x0010, + POST_CHILD_PAINT_ENABLED = 0x0020, + AUTODELETE_ENABLED = 0x0040, + NEEDS_LAYOUT = 0x0080, + NEEDS_SCHEME_UPDATE = 0x0100, + NEEDS_DEFAULT_SETTINGS_APPLIED = 0x0200, +#if defined( VGUI_USEKEYBINDINGMAPS ) + ALLOW_CHAIN_KEYBINDING_TO_PARENT = 0x0400, +#endif + IN_PERFORM_LAYOUT = 0x0800, + IS_PROPORTIONAL = 0x1000, + TRIPLE_PRESS_ALLOWED = 0x2000, + DRAG_REQUIRES_PANEL_EXIT = 0x4000, + IS_MOUSE_DISABLED_FOR_THIS_PANEL_ONLY = 0x8000, + ALL_FLAGS = 0xFFFF, + }; + + // used to get the Panel * for users with only IClientPanel + virtual Panel* GetPanel() { return this; } + + // private methods + void Think(); + void PerformApplySchemeSettings(); + + void InternalPerformLayout(); + void InternalSetCursor(); + + MESSAGE_FUNC_INT_INT(InternalCursorMoved, "CursorMoved", xpos, ypos); + MESSAGE_FUNC(InternalCursorEntered, "CursorEntered"); + MESSAGE_FUNC(InternalCursorExited, "CursorExited"); + + MESSAGE_FUNC_INT(InternalMousePressed, "MousePressed", code); + MESSAGE_FUNC_INT(InternalMouseDoublePressed, "MouseDoublePressed", code); + // Triple presses are synthesized + MESSAGE_FUNC_INT(InternalMouseTriplePressed, "MouseTriplePressed", code); + MESSAGE_FUNC_INT(InternalMouseReleased, "MouseReleased", code); + MESSAGE_FUNC_INT(InternalMouseWheeled, "MouseWheeled", delta); + MESSAGE_FUNC_INT(InternalKeyCodePressed, "KeyCodePressed", code); + MESSAGE_FUNC_INT(InternalKeyCodeTyped, "KeyCodeTyped", code); + MESSAGE_FUNC_INT(InternalKeyTyped, "KeyTyped", unichar); + MESSAGE_FUNC_INT(InternalKeyCodeReleased, "KeyCodeReleased", code); + + MESSAGE_FUNC(InternalKeyFocusTicked, "KeyFocusTicked"); + MESSAGE_FUNC(InternalMouseFocusTicked, "MouseFocusTicked"); + + MESSAGE_FUNC(InternalInvalidateLayout, "Invalidate"); + + MESSAGE_FUNC(InternalMove, "Move"); + virtual void InternalFocusChanged(bool lost); // called when the focus gets changed + + void Init(int x, int y, int wide, int tall); + void PreparePanelMap(PanelMap_t* panelMap); + + bool InternalRequestInfo(PanelAnimationMap* map, KeyValues* outputData); + bool InternalSetInfo(PanelAnimationMap* map, KeyValues* inputData); + + PanelAnimationMapEntry* FindPanelAnimationEntry(char const* scriptname, PanelAnimationMap* map); + + // Recursively invoke settings for PanelAnimationVars + void InternalApplySettings(PanelAnimationMap* map, KeyValues* inResourceData); + + // Purpose: Loads panel details related to autoresize from the resource info + void ApplyAutoResizeSettings(KeyValues* inResourceData); + + void FindDropTargetPanel_R(CUtlVector< VPANEL >& panelList, int x, int y, VPANEL check); + Panel* FindDropTargetPanel(); + + int GetProportionalScaledValue(int rootTall, int normalizedValue); + +#if defined( VGUI_USEDRAGDROP ) + DragDrop_t* m_pDragDrop; + Color m_clrDragFrame; + Color m_clrDropFrame; +#endif + + BaseTooltip* m_pTooltips; + bool m_bToolTipOverridden; + + PHandle m_SkipChild; + long m_lLastDoublePressTime; + HFont m_infoFont; // this is used exclusively by drag drop panels + +#if defined( VGUI_USEKEYBINDINGMAPS ) + KeyBindingContextHandle_t m_hKeyBindingsContext; +#endif + + // data + VPANEL _vpanel; // handle to a vgui panel + CUtlString _panelName; // string name of the panel - only unique within the current context + IBorder* _border; + + CUtlFlags< unsigned short > _flags; // see PanelFlags_t + Dar _actionSignalTargetDar; // the panel to direct notify messages to ("Command", "TextChanged", etc.) + + CUtlVector m_OverridableColorEntries; + + Color _fgColor; // foreground color + Color _bgColor; // background color + + HBuildGroup _buildGroup; + + short m_nPinDeltaX; // Relative position of the pinned corner to the edge + short m_nPinDeltaY; + short m_nResizeDeltaX; // Relative position of the non-pinned corner to the edge + short m_nResizeDeltaY; + + HCursor _cursor; + unsigned short _buildModeFlags; // flags that control how the build mode dialog handles this panel + + byte _pinCorner : 4; // the corner of the dialog this panel is pinned to + byte _autoResizeDirection : 4; // the directions in which the panel will auto-resize to + + GCC_DIAG_PUSH_OFF(overflow) + + DECLARE_DMXELEMENT_BITFIELD(_pinCorner, byte, Panel) + DECLARE_DMXELEMENT_BITFIELD(_autoResizeDirection, byte, Panel) + + GCC_DIAG_POP() + + unsigned char _tabPosition; // the panel's place in the tab ordering + HScheme m_iScheme; // handle to the scheme to use + + bool m_bIsDMXSerialized : 1; // Is this a DMX panel? + bool m_bUseSchemeColors : 1; // Should we use colors from the scheme? + bool m_bIsSilent : 1; // should this panel PostActionSignals? + bool m_bIsConsoleStylePanel : 1; + + DECLARE_DMXELEMENT_BITFIELD(m_bUseSchemeColors, bool, Panel) + DECLARE_DMXELEMENT_BITFIELD(m_bIsSilent, bool, Panel) + + // Sibling pinning + char* _pinToSibling; // string name of the sibling panel we're pinned to + byte _pinToSiblingCorner; // the corner of the sibling panel we're pinned to + byte _pinCornerToSibling; // the corner of our panel that we're pinning to our sibling + PHandle m_pinSibling; + + char* _tooltipText; // Tool tip text for panels that share tooltip panels with other panels + + PHandle m_hMouseEventHandler; + + bool m_bWorldPositionCurrentFrame; // if set, Panel gets PerformLayout called after the camera and the renderer's m_matrixWorldToScreen has been setup, so panels can be correctly attached to entities in the world + CUtlSymbol m_sBorderName; + + protected: + CUtlString m_sNavUpName; + PHandle m_NavUp; + + CUtlString m_sNavDownName; + PHandle m_NavDown; + + CUtlString m_sNavLeftName; + PHandle m_NavLeft; + + CUtlString m_sNavRightName; + PHandle m_NavRight; + protected: + static int s_NavLock; + + private: + + CPanelAnimationVar(float, m_flAlpha, "alpha", "255"); + + // 1 == Textured (TextureId1 only) + // 2 == Rounded Corner Box + CPanelAnimationVar(int, m_nPaintBackgroundType, "PaintBackgroundType", "0"); + CPanelAnimationVarAliasType(int, m_nBgTextureId1, "Texture1", "vgui/hud/800corner1", "textureid"); + CPanelAnimationVarAliasType(int, m_nBgTextureId2, "Texture2", "vgui/hud/800corner2", "textureid"); + CPanelAnimationVarAliasType(int, m_nBgTextureId3, "Texture3", "vgui/hud/800corner3", "textureid"); + CPanelAnimationVarAliasType(int, m_nBgTextureId4, "Texture4", "vgui/hud/800corner4", "textureid"); + + //============================================================================= + // HPE_BEGIN: + // [tj] A bitset of flags to determine which corners should be rounded + //============================================================================= + unsigned char m_roundedCorners; + //============================================================================= + // HPE_END + //============================================================================= + friend class BuildGroup; + friend class BuildModeDialog; + friend class PHandle; + + // obselete, remove soon + void OnOldMessage(KeyValues* params, VPANEL ifromPanel); + + public: + + virtual void GetSizerMinimumSize(int& wide, int& tall); + virtual void GetSizerClientArea(int& x, int& y, int& wide, int& tall); + CSizerBase* GetSizer(); + void SetSizer(CSizerBase* pSizer); + + protected: + + CSizerBase* m_pSizer; + }; + + inline void Panel::DisableMouseInputForThisPanel(bool bDisable) + { + _flags.SetFlag(IS_MOUSE_DISABLED_FOR_THIS_PANEL_ONLY, bDisable); + } + + inline bool Panel::IsMouseInputDisabledForThisPanel() const + { + return _flags.IsFlagSet(IS_MOUSE_DISABLED_FOR_THIS_PANEL_ONLY); + } + + template< class S > + inline void Panel::PostMessageToAllSiblingsOfType(KeyValues* msg, float delaySeconds /*= 0.0f*/) + { + Panel* parent = GetParent(); + if (parent) + { + int nChildCount = parent->GetChildCount(); + for (int i = 0; i < nChildCount; ++i) + { + Panel* sibling = parent->GetChild(i); + if (sibling == this) + continue; + if (dynamic_cast(sibling)) + { + PostMessage(sibling->GetVPanel(), msg->MakeCopy(), delaySeconds); + } + } + } + + msg->deleteThis(); + } + +} // namespace vgui + + +#endif // PANEL_H +``` + +`SpyCustom/sdk/PanelAnimationVar.h`: + +```h +#ifndef PANELANIMATIONVAR_H +#define PANELANIMATIONVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "Panel.h" + +#define DECLARE_PANELANIMATION( className ) \ + static void AddToAnimationMap( char const *scriptname, char const *type, char const *var, \ + char const *defaultvalue, bool array, PANELLOOKUPFUNC func ) \ + { \ + PanelAnimationMap *map = FindOrAddPanelAnimationMap( GetPanelClassName() ); \ + \ + PanelAnimationMapEntry entry; \ + entry.m_pszScriptName = scriptname; \ + entry.m_pszVariable = var; \ + entry.m_pszType = type; \ + entry.m_pszDefaultValue = defaultvalue; \ + entry.m_pfnLookup = func; \ + entry.m_bArray = array; \ + \ + map->entries.AddToTail( entry ); \ + } \ + \ + static void ChainToAnimationMap( void ) \ + { \ + static bool chained = false; \ + if ( chained ) \ + return; \ + chained = true; \ + PanelAnimationMap *map = FindOrAddPanelAnimationMap( GetPanelClassName() ); \ + map->pfnClassName = GetPanelClassName; \ + if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] ) \ + { \ + map->baseMap = FindOrAddPanelAnimationMap( GetPanelBaseClassName() ); \ + } \ + } \ + \ + class className##_Register; \ + friend class className##_Register; \ + class className##_Register \ + { \ + public: \ + className##_Register() \ + { \ + className::ChainToAnimationMap(); \ + } \ + }; \ + className##_Register m_RegisterAnimationClass; \ + \ + virtual PanelAnimationMap *GetAnimMap() \ + { \ + return FindOrAddPanelAnimationMap( GetPanelClassName() ); \ + } + +typedef void* (*PANELLOOKUPFUNC)(vgui::Panel* panel); + +#define CPanelAnimationVarAliasType( type, name, scriptname, defaultvalue, typealias ) \ + class PanelAnimationVar_##name; \ + friend class PanelAnimationVar_##name; \ + static void *GetVar_##name( vgui::Panel *panel ) \ + { \ + return &(( ThisClass *)panel)->name; \ + } \ + class PanelAnimationVar_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + AddToAnimationMap( scriptname, typealias, #name, defaultvalue, false, ThisClass::GetVar_##name ); \ + } \ + } \ + PanelAnimationVar_##name() \ + { \ + PanelAnimationVar_##name::InitVar(); \ + } \ + }; \ + PanelAnimationVar_##name m_##name##_register; \ + type name; + +#define CPanelAnimationVar( type, name, scriptname, defaultvalue ) \ + CPanelAnimationVarAliasType( type, name, scriptname, defaultvalue, #type ) + +#define CPanelAnimationStringVarAliasType( count, name, scriptname, defaultvalue, typealias ) \ + class PanelAnimationVar_##name; \ + friend class PanelAnimationVar_##name; \ + static void *GetVar_##name( vgui::Panel *panel ) \ + { \ + return &(( ThisClass *)panel)->name; \ + } \ + class PanelAnimationVar_##name \ + { \ + public: \ + static void InitVar() \ + { \ + static bool bAdded = false; \ + if ( !bAdded ) \ + { \ + bAdded = true; \ + AddToAnimationMap( scriptname, typealias, #name, defaultvalue, true, ThisClass::GetVar_##name ); \ + } \ + } \ + PanelAnimationVar_##name() \ + { \ + PanelAnimationVar_##name::InitVar(); \ + } \ + }; \ + PanelAnimationVar_##name m_##name##_register; \ + char name[ count ]; + +#define CPanelAnimationStringVar( count, name, scriptname, defaultvalue ) \ + CPanelAnimationStringVarAliasType( count, name, scriptname, defaultvalue, "string" ) + +struct PanelAnimationMapEntry +{ + char const* name() { return m_pszScriptName; } + char const* type() { return m_pszType; } + char const* defaultvalue() { return m_pszDefaultValue; } + bool isarray() { return m_bArray; } + + char const* m_pszScriptName; + char const* m_pszVariable; + char const* m_pszType; + char const* m_pszDefaultValue; + bool m_bArray; + + PANELLOOKUPFUNC m_pfnLookup; +}; + +struct PanelAnimationMap +{ + PanelAnimationMap() + { + baseMap = NULL; + pfnClassName = NULL; + } + + CUtlVector< PanelAnimationMapEntry > entries; + PanelAnimationMap* baseMap; + char const* (*pfnClassName)(void); +}; + +PanelAnimationMap* FindPanelAnimationMap(char const* className); +PanelAnimationMap* FindOrAddPanelAnimationMap(char const* className); +void PanelAnimationDumpVars(char const* className); + +#endif +``` + +`SpyCustom/sdk/ParticleSphereRenderer.h`: + +```h +#ifndef PARTICLESPHERERENDERER_H +#define PARTICLESPHERERENDERER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "particlemgr.h" +#include "particle_util.h" + + +class CParticleSphereRenderer +{ +public: + + CParticleSphereRenderer(); + + void Init(CParticleMgr* pParticleMgr, IMaterial* pMaterial); + + void StartRender(VMatrix& effectMatrix); + + void RenderParticle( + ParticleDraw* pDraw, + const Vector& vOriginalPos, + const Vector& vTransformedPos, + float flAlpha, + float flParticleSize, + float flAngle = 0.0f); + + void RenderParticle_AddColor( + ParticleDraw* pDraw, + const Vector& vOriginalPos, + const Vector& vTransformedPos, + float flAlpha, + float flParticleSize, + const Vector& vToAdd0to1 + ); + + + const Vector& GetBaseColor() const; + void SetBaseColor(const Vector& vColor); + + const CParticleLightInfo& GetAmbientLight() const; + void SetAmbientLight(const CParticleLightInfo& info); + + const CParticleLightInfo& GetDirectionalLight() const; + void SetDirectionalLight(const CParticleLightInfo& info); + + +private: + + void AddLightColor( + Vector const* pPos, + Vector const* pLightPos, + Vector const* pLightColor, + float flLightIntensity, + Vector* pOutColor); + + inline void ClampColor(Vector& vColor); + + +private: + + int m_iLastTickStartRenderCalled; + + CParticleMgr* m_pParticleMgr; + + Vector m_vBaseColor; + CParticleLightInfo m_AmbientLight; + CParticleLightInfo m_DirectionalLight; + bool m_bUsingPixelShaders; +}; + + +inline void CParticleSphereRenderer::AddLightColor( + Vector const* pPos, + Vector const* pLightPos, + Vector const* pLightColor, + float flLightIntensity, + Vector* pOutColor) +{ + if (flLightIntensity) + { + float fDist = pPos->DistToSqr(*pLightPos); + float fAmt; + if (fDist > 0.0001f) + fAmt = flLightIntensity / fDist; + else + fAmt = 1000.f; + + *pOutColor += *pLightColor * fAmt; + } +} + + +inline void CParticleSphereRenderer::ClampColor(Vector& vColor) +{ + float flMax = MAX(vColor.x, MAX(vColor.y, vColor.z)); + if (flMax > 1) + { + vColor *= 255.0f / flMax; + } + else + { + vColor *= 255.0; + } +} + + +inline const Vector& CParticleSphereRenderer::GetBaseColor() const +{ + return m_vBaseColor; +} + +inline void CParticleSphereRenderer::SetBaseColor(const Vector& vColor) +{ + m_vBaseColor = vColor; +} + +inline const CParticleLightInfo& CParticleSphereRenderer::GetAmbientLight() const +{ + return m_AmbientLight; +} + +inline void CParticleSphereRenderer::SetAmbientLight(const CParticleLightInfo& info) +{ + m_AmbientLight = info; +} + +inline const CParticleLightInfo& CParticleSphereRenderer::GetDirectionalLight() const +{ + return m_DirectionalLight; +} + +inline void CParticleSphereRenderer::SetDirectionalLight(const CParticleLightInfo& info) +{ + m_DirectionalLight = info; +} + +inline void CParticleSphereRenderer::RenderParticle( + ParticleDraw* pDraw, + const Vector& vOriginalPos, + const Vector& vTransformedPos, + float flAlpha, + float flParticleSize, + float flAngle) +{ +#ifdef _DEBUG + if (pDraw->GetMeshBuilder()) + { + Assert(m_iLastTickStartRenderCalled == gpGlobals->tickcount); + } +#endif + + Vector vColor = m_vBaseColor; + AddLightColor(&vOriginalPos, &m_AmbientLight.m_vPos, &m_AmbientLight.m_vColor, m_AmbientLight.m_flIntensity, &vColor); + + if (!m_bUsingPixelShaders) + { + AddLightColor(&vOriginalPos, &m_DirectionalLight.m_vPos, &m_DirectionalLight.m_vColor, m_DirectionalLight.m_flIntensity, &vColor); + } + + ClampColor(vColor); + + RenderParticle_Color255SizeNormalAngle( + pDraw, + vTransformedPos, + vColor, + flAlpha, + flParticleSize, + vec3_origin, + flAngle); +} + +inline void CParticleSphereRenderer::RenderParticle_AddColor( + ParticleDraw* pDraw, + const Vector& vOriginalPos, + const Vector& vTransformedPos, + float flAlpha, + float flParticleSize, + const Vector& vToAdd0to1 +) +{ +#ifdef _DEBUG + if (pDraw->GetMeshBuilder()) + { + Assert(m_iLastTickStartRenderCalled == gpGlobals->tickcount); + } +#endif + + Vector vColor = m_vBaseColor + vToAdd0to1; + AddLightColor(&vOriginalPos, &m_AmbientLight.m_vPos, &m_AmbientLight.m_vColor, m_AmbientLight.m_flIntensity, &vColor); + + if (!m_bUsingPixelShaders) + { + AddLightColor(&vOriginalPos, &m_DirectionalLight.m_vPos, &m_DirectionalLight.m_vColor, m_DirectionalLight.m_flIntensity, &vColor); + } + + ClampColor(vColor); + + RenderParticle_Color255Size( + pDraw, + vTransformedPos, + vColor, + flAlpha, + flParticleSize); +} + + +#endif +``` + +`SpyCustom/sdk/RichText.h`: + +```h +#ifndef RICHTEXT_H +#define RICHTEXT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "Panel.h" +#include "utlvector.h" + +namespace vgui +{ + + class ClickPanel; + + class RichText : public Panel + { + DECLARE_CLASS_SIMPLE(RichText, Panel); + + public: + RichText(Panel* parent, const char* panelName); + ~RichText(); + + virtual void SetText(const char* text); + virtual void SetText(const wchar_t* text); + void GetText(int offset, OUT_Z_BYTECAP(bufLenInBytes) wchar_t* buf, int bufLenInBytes); + void GetText(int offset, OUT_Z_BYTECAP(bufLenInBytes) char* pch, int bufLenInBytes); + + void SetFont(HFont font); + + void InsertChar(wchar_t ch); + void InsertString(const char* text); + void InsertString(const wchar_t* wszText); + + void SelectNone(); + void SelectAllText(); + void SelectNoText(); + MESSAGE_FUNC(CutSelected, "DoCutSelected"); + MESSAGE_FUNC(CopySelected, "DoCopySelected"); + + void SetPanelInteractive(bool bInteractive) { m_bInteractive = bInteractive; } + + void SetUnusedScrollbarInvisible(bool bInvis) { m_bUnusedScrollbarInvis = bInvis; } + + void GotoTextStart(); + void GotoTextEnd(); + + void SetVerticalScrollbar(bool state); + void SetMaximumCharCount(int maxChars); + + void InsertColorChange(Color col); + void InsertIndentChange(int pixelsIndent); + void InsertClickableTextStart(const char* pchClickAction = NULL); + void InsertClickableTextEnd(); + void InsertPossibleURLString(const char* text, Color URLTextColor, Color normalTextColor); + + void InsertFade(float flSustain, float flLength); + + void ResetAllFades(bool bHold, bool bOnlyExpired = false, float flNewSustain = -1.0f); + + void SetToFullHeight(); + int GetNumLines(); + + + virtual bool RequestInfo(KeyValues* outputData); + virtual void SetFgColor(Color color); + virtual void SetDrawOffsets(int ofsx, int ofsy); + bool IsScrollbarVisible(); + + void SetURLClickedHandler(Panel* pPanelToHandleClickMsg); + + void SetUnderlineFont(HFont font); + + bool IsAllTextAlphaZero() const; + bool HasText() const; + + void SetDrawTextOnly(); + + protected: + virtual void OnThink(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual void Paint(); + + virtual void ApplySettings(KeyValues* inResourceData); + virtual void GetSettings(KeyValues* outResourceData); + virtual const char* GetDescription(void); + MESSAGE_FUNC_WCHARPTR(OnSetText, "SetText", text); + MESSAGE_FUNC(OnSliderMoved, "ScrollBarSliderMoved"); + virtual void OnKillFocus(); + virtual void OnMouseWheeled(int delta); + virtual void OnKeyCodeTyped(KeyCode code); + + MESSAGE_FUNC_INT(OnClickPanel, "ClickPanel", index); + + virtual void OnCursorMoved(int x, int y); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + + virtual void OnMouseFocusTicked(); + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + + virtual void OnMouseCaptureLost(); + virtual void OnSizeChanged(int newWide, int newTall); + virtual void OnSetFocus(); + + int ParseTextStringForUrls(const char* text, int startPos, char* pchURLText, int cchURLText, char* pchURL, int cchURL, bool& clickable); + virtual void OnTextClicked(const wchar_t* text); + +#ifdef DBGFLAG_VALIDATE + virtual void Validate(CValidator& validator, char* pchName); +#endif + + protected: + ScrollBar* _vertScrollBar; + + private: + int GetLineHeight(); + HFont GetDefaultFont(); + + const wchar_t* ResolveLocalizedTextAndVariables(char const* pchLookup, OUT_Z_BYTECAP(outbufsizeinbytes) wchar_t* outbuf, size_t outbufsizeinbytes); + void CheckRecalcLineBreaks(); + + void GotoWordRight(); + void GotoWordLeft(); + + void TruncateTextStream(); + bool GetSelectedRange(int& cx0, int& cx1); + void CursorToPixelSpace(int cursorPos, int& cx, int& cy); + int PixelToCursorSpace(int cx, int cy); + void AddAnotherLine(int& cx, int& cy); + void RecalculateDefaultState(int startIndex); + + void LayoutVerticalScrollBarSlider(); + void OpenEditMenu(); + void FinishingURL(int x, int y); + int GetStartDrawIndex(int& lineBreakIndexIndex); + int GetCursorLine(); + int GetClickableTextIndexStart(int startIndex); + void CreateEditMenu(); + + MESSAGE_FUNC_INT(MoveScrollBar, "MoveScrollBar", delta); + MESSAGE_FUNC_INT(MoveScrollBarDirect, "MoveScrollBarDirect", delta); + + void InvalidateLineBreakStream(); + void RecalculateLineBreaks(); + + struct TFade + { + float flFadeStartTime; + float flFadeLength; + float flFadeSustain; + int iOriginalAlpha; + }; + + struct TFormatStream + { + Color color; + int pixelsIndent; + bool textClickable; + CUtlSymbol m_sClickableTextAction; + + TFade fade; + + int textStreamIndex; + }; + + bool m_bResetFades; + bool m_bInteractive; + bool m_bUnusedScrollbarInvis; + bool m_bAllTextAlphaIsZero; + + CUtlVector m_TextStream; + CUtlVector m_LineBreaks; + CUtlVector m_FormatStream; + + bool m_bRecalcLineBreaks; + + int _recalculateBreaksIndex; + bool _invalidateVerticalScrollbarSlider; + int _cursorPos; + bool _mouseSelection; + bool _mouseDragSelection; + int _select[2]; + int _pixelsIndent; + int _maxCharCount; + HFont _font; + HFont m_hFontUnderline; + Color _selectionColor; + Color _selectionTextColor; + bool _currentTextClickable; + CUtlVector _clickableTextPanels; + int _clickableTextIndex; + Color _defaultTextColor; + int _drawOffsetX; + int _drawOffsetY; + + Panel* m_pInterior; + PHandle m_hPanelToHandleClickingURLs; + + + Menu* m_pEditMenu; + + char* m_pszInitialText; + + bool _recalcSavedRenderState; + + struct TRenderState + { + int x, y; + + Color textColor; + int pixelsIndent; + bool textClickable; + + int formatStreamIndex; + }; + TRenderState m_CachedRenderState; + + bool UpdateRenderState(int textStreamPos, TRenderState& renderState); + void CalculateFade(TRenderState& renderState); + + void GenerateRenderStateForTextStreamIndex(int textStreamIndex, TRenderState& renderState); + int FindFormatStreamIndexForTextStreamPos(int textStreamIndex); + + int DrawString(int iFirst, int iLast, TRenderState& renderState, HFont font); + }; + +} + + +#endif +``` + +`SpyCustom/sdk/SndInfo.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef SNDINFO_H +#define SNDINFO_H +#ifdef _WIN32 +#pragma once +#endif + +class Vector; +#include "utlsymbol.h" + +//----------------------------------------------------------------------------- +// Purpose: Client side only +//----------------------------------------------------------------------------- +struct SndInfo_t +{ + // Sound Guid + int m_nGuid; + FileNameHandle_t m_filenameHandle; // filesystem filename handle - call IFilesystem to conver this to a string + int m_nSoundSource; + int m_nChannel; + // If a sound is being played through a speaker entity (e.g., on a monitor,), this is the + // entity upon which to show the lips moving, if the sound has sentence data + int m_nSpeakerEntity; + float m_flVolume; + float m_flLastSpatializedVolume; + // Radius of this sound effect (spatialization is different within the radius) + float m_flRadius; + int m_nPitch; + Vector* m_pOrigin; + Vector* m_pDirection; + + // if true, assume sound source can move and update according to entity + bool m_bUpdatePositions; + // true if playing linked sentence + bool m_bIsSentence; + // if true, bypass all dsp processing for this sound (ie: music) + bool m_bDryMix; + // true if sound is playing through in-game speaker entity. + bool m_bSpeaker; + // true if sound is playing with special DSP effect + bool m_bSpecialDSP; + // for snd_show, networked sounds get colored differently than local sounds + bool m_bFromServer; +}; + +#endif // SNDINFO_H +``` + +`SpyCustom/sdk/SteamCommon.h`: + +```h + +#ifndef INCLUDED_STEAM2_USERID_STRUCTS +#define INCLUDED_STEAM2_USERID_STRUCTS + +#if defined(_MSC_VER) && (_MSC_VER > 1000) +#pragma once +#endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined ( _WIN32 ) + +#ifdef STEAM_EXPORTS +#define STEAM_API __declspec(dllexport) +#else +#define STEAM_API __declspec(dllimport) +#endif + +#define STEAM_CALL __cdecl + +#else + +#define STEAM_API +#define STEAM_CALL + +#endif + + typedef void (STEAM_CALL* KeyValueIteratorCallback_t)(const char* Key, const char* Val, void* pvParam); + + +#define STEAM_USING_FILESYSTEM (0x00000001) +#define STEAM_USING_LOGGING (0x00000002) +#define STEAM_USING_USERID (0x00000004) +#define STEAM_USING_ACCOUNT (0x00000008) +#define STEAM_USING_ALL (0x0000000f) +#define STEAM_MAX_PATH (255) +#define STEAM_QUESTION_MAXLEN (255) +#define STEAM_SALT_SIZE (8) +#define STEAM_PROGRESS_PERCENT_SCALE (0x00001000) + +#define STEAM_CARD_NUMBER_SIZE (17) +#define STEAM_CARD_HOLDERNAME_SIZE (100) +#define STEAM_CARD_EXPYEAR_SIZE (4) +#define STEAM_CARD_EXPMONTH_SIZE (2) +#define STEAM_CARD_CVV2_SIZE (5) +#define STEAM_BILLING_ADDRESS1_SIZE (128) +#define STEAM_BILLING_ADDRESS2_SIZE (128) +#define STEAM_BILLING_CITY_SIZE (50) +#define STEAM_BILLING_ZIP_SIZE (16) +#define STEAM_BILLING_STATE_SIZE (32) +#define STEAM_BILLING_COUNTRY_SIZE (32) +#define STEAM_BILLING_PHONE_SIZE (20) +#define STEAM_BILLING_EMAIL_ADDRESS_SIZE (100) +#define STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE (20) +#define STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE (200) +#define STEAM_EXTERNAL_ACCOUNTNAME_SIZE (100) +#define STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE (80) +#define STEAM_BILLING_CONFIRMATION_CODE_SIZE (22) +#define STEAM_BILLING_CARD_APPROVAL_CODE_SIZE (100) +#define STEAM_BILLING_TRANS_DATE_SIZE (9) +#define STEAM_BILLING_TRANS_TIME_SIZE (9) + + + typedef unsigned int SteamHandle_t; + + typedef void* SteamUserIDTicketValidationHandle_t; + + typedef unsigned int SteamCallHandle_t; + +#if defined(_MSC_VER) + typedef unsigned __int64 SteamUnsigned64_t; +#else + typedef unsigned long long SteamUnsigned64_t; +#endif + + typedef enum + { + eSteamSeekMethodSet = 0, + eSteamSeekMethodCur = 1, + eSteamSeekMethodEnd = 2 + } ESteamSeekMethod; + + typedef enum + { + eSteamBufferMethodFBF = 0, + eSteamBufferMethodNBF = 1 + } ESteamBufferMethod; + + typedef enum + { + eSteamErrorNone = 0, + eSteamErrorUnknown = 1, + eSteamErrorLibraryNotInitialized = 2, + eSteamErrorLibraryAlreadyInitialized = 3, + eSteamErrorConfig = 4, + eSteamErrorContentServerConnect = 5, + eSteamErrorBadHandle = 6, + eSteamErrorHandlesExhausted = 7, + eSteamErrorBadArg = 8, + eSteamErrorNotFound = 9, + eSteamErrorRead = 10, + eSteamErrorEOF = 11, + eSteamErrorSeek = 12, + eSteamErrorCannotWriteNonUserConfigFile = 13, + eSteamErrorCacheOpen = 14, + eSteamErrorCacheRead = 15, + eSteamErrorCacheCorrupted = 16, + eSteamErrorCacheWrite = 17, + eSteamErrorCacheSession = 18, + eSteamErrorCacheInternal = 19, + eSteamErrorCacheBadApp = 20, + eSteamErrorCacheVersion = 21, + eSteamErrorCacheBadFingerPrint = 22, + + eSteamErrorNotFinishedProcessing = 23, + eSteamErrorNothingToDo = 24, + eSteamErrorCorruptEncryptedUserIDTicket = 25, + eSteamErrorSocketLibraryNotInitialized = 26, + eSteamErrorFailedToConnectToUserIDTicketValidationServer = 27, + eSteamErrorBadProtocolVersion = 28, + eSteamErrorReplayedUserIDTicketFromClient = 29, + eSteamErrorReceiveResultBufferTooSmall = 30, + eSteamErrorSendFailed = 31, + eSteamErrorReceiveFailed = 32, + eSteamErrorReplayedReplyFromUserIDTicketValidationServer = 33, + eSteamErrorBadSignatureFromUserIDTicketValidationServer = 34, + eSteamErrorValidationStalledSoAborted = 35, + eSteamErrorInvalidUserIDTicket = 36, + eSteamErrorClientLoginRateTooHigh = 37, + eSteamErrorClientWasNeverValidated = 38, + eSteamErrorInternalSendBufferTooSmall = 39, + eSteamErrorInternalReceiveBufferTooSmall = 40, + eSteamErrorUserTicketExpired = 41, + eSteamErrorCDKeyAlreadyInUseOnAnotherClient = 42, + + eSteamErrorNotLoggedIn = 101, + eSteamErrorAlreadyExists = 102, + eSteamErrorAlreadySubscribed = 103, + eSteamErrorNotSubscribed = 104, + eSteamErrorAccessDenied = 105, + eSteamErrorFailedToCreateCacheFile = 106, + eSteamErrorCallStalledSoAborted = 107, + eSteamErrorEngineNotRunning = 108, + eSteamErrorEngineConnectionLost = 109, + eSteamErrorLoginFailed = 110, + eSteamErrorAccountPending = 111, + eSteamErrorCacheWasMissingRetry = 112, + eSteamErrorLocalTimeIncorrect = 113, + eSteamErrorCacheNeedsDecryption = 114, + eSteamErrorAccountDisabled = 115, + eSteamErrorCacheNeedsRepair = 116, + eSteamErrorRebootRequired = 117, + + eSteamErrorNetwork = 200, + eSteamErrorOffline = 201 + + + } ESteamError; + + + typedef enum + { + eNoDetailedErrorAvailable, + eStandardCerrno, + eWin32LastError, + eWinSockLastError, + eDetailedPlatformErrorCount + } EDetailedPlatformErrorType; + + typedef enum + { + eSteamFindLocalOnly, + eSteamFindRemoteOnly, + eSteamFindAll + } ESteamFindFilter; + + + + typedef struct + { + ESteamError eSteamError; + EDetailedPlatformErrorType eDetailedErrorType; + int nDetailedErrorCode; + char szDesc[STEAM_MAX_PATH]; + } TSteamError; + + + + typedef struct + { + int bIsDir; + unsigned int uSizeOrCount; + int bIsLocal; + char cszName[STEAM_MAX_PATH]; + long lLastAccessTime; + long lLastModificationTime; + long lCreationTime; + } TSteamElemInfo; + + + typedef struct + { + unsigned int uNumSubscriptions; + unsigned int uMaxNameChars; + unsigned int uMaxApps; + + } TSteamSubscriptionStats; + + + typedef struct + { + unsigned int uNumApps; + unsigned int uMaxNameChars; + unsigned int uMaxInstallDirNameChars; + unsigned int uMaxVersionLabelChars; + unsigned int uMaxLaunchOptions; + unsigned int uMaxLaunchOptionDescChars; + unsigned int uMaxLaunchOptionCmdLineChars; + unsigned int uMaxNumIcons; + unsigned int uMaxIconSize; + unsigned int uMaxDependencies; + + } TSteamAppStats; + + typedef struct + { + char* szLabel; + unsigned int uMaxLabelChars; + unsigned int uVersionId; + int bIsNotAvailable; + } TSteamAppVersion; + + typedef struct + { + char* szDesc; + unsigned int uMaxDescChars; + char* szCmdLine; + unsigned int uMaxCmdLineChars; + unsigned int uIndex; + unsigned int uIconIndex; + int bNoDesktopShortcut; + int bNoStartMenuShortcut; + int bIsLongRunningUnattended; + + } TSteamAppLaunchOption; + + + typedef struct + { + char* szName; + unsigned int uMaxNameChars; + char* szLatestVersionLabel; + unsigned int uMaxLatestVersionLabelChars; + char* szCurrentVersionLabel; + unsigned int uMaxCurrentVersionLabelChars; + char* szInstallDirName; + unsigned int uMaxInstallDirNameChars; + unsigned int uId; + unsigned int uLatestVersionId; + unsigned int uCurrentVersionId; + unsigned int uMinCacheFileSizeMB; + unsigned int uMaxCacheFileSizeMB; + unsigned int uNumLaunchOptions; + unsigned int uNumIcons; + unsigned int uNumVersions; + unsigned int uNumDependencies; + + } TSteamApp; + + typedef enum + { + eNoCost = 0, + eBillOnceOnly = 1, + eBillMonthly = 2, + eProofOfPrepurchaseOnly = 3, + eGuestPass = 4, + eHardwarePromo = 5, + eNumBillingTypes, + } EBillingType; + + typedef struct + { + char* szName; + unsigned int uMaxNameChars; + unsigned int* puAppIds; + unsigned int uMaxAppIds; + unsigned int uId; + unsigned int uNumApps; + EBillingType eBillingType; + unsigned int uCostInCents; + unsigned int uNumDiscounts; + int bIsPreorder; + int bRequiresShippingAddress; + unsigned int uDomesticShippingCostInCents; + unsigned int uInternationalShippingCostInCents; + bool bIsCyberCafeSubscription; + unsigned int uGameCode; + char szGameCodeDesc[STEAM_MAX_PATH]; + bool bIsDisabled; + bool bRequiresCD; + unsigned int uTerritoryCode; + bool bIsSteam3Subscription; + + } TSteamSubscription; + + typedef struct + { + char szName[STEAM_MAX_PATH]; + unsigned int uDiscountInCents; + unsigned int uNumQualifiers; + + } TSteamSubscriptionDiscount; + + typedef struct + { + char szName[STEAM_MAX_PATH]; + unsigned int uRequiredSubscription; + int bIsDisqualifier; + + } TSteamDiscountQualifier; + + typedef struct TSteamProgress + { + int bValid; + unsigned int uPercentDone; + char szProgress[STEAM_MAX_PATH]; + } TSteamProgress; + + typedef enum + { + eSteamNotifyTicketsWillExpire, + eSteamNotifyAccountInfoChanged, + eSteamNotifyContentDescriptionChanged, + eSteamNotifyPleaseShutdown, + eSteamNotifyNewContentServer, + eSteamNotifySubscriptionStatusChanged, + eSteamNotifyContentServerConnectionLost, + eSteamNotifyCacheLoadingCompleted, + eSteamNotifyCacheNeedsDecryption, + eSteamNotifyCacheNeedsRepair + } ESteamNotificationCallbackEvent; + + + typedef void(*SteamNotificationCallback_t)(ESteamNotificationCallbackEvent eEvent, unsigned int nData); + + + typedef char SteamPersonalQuestion_t[STEAM_QUESTION_MAXLEN + 1]; + + typedef struct + { + unsigned char uchSalt[STEAM_SALT_SIZE]; + } SteamSalt_t; + + typedef enum + { + eVisa = 1, + eMaster = 2, + eAmericanExpress = 3, + eDiscover = 4, + eDinnersClub = 5, + eJCB = 6 + } ESteamPaymentCardType; + + typedef struct + { + ESteamPaymentCardType eCardType; + char szCardNumber[STEAM_CARD_NUMBER_SIZE + 1]; + char szCardHolderName[STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szCardExpYear[STEAM_CARD_EXPYEAR_SIZE + 1]; + char szCardExpMonth[STEAM_CARD_EXPMONTH_SIZE + 1]; + char szCardCVV2[STEAM_CARD_CVV2_SIZE + 1]; + char szBillingAddress1[STEAM_BILLING_ADDRESS1_SIZE + 1]; + char szBillingAddress2[STEAM_BILLING_ADDRESS2_SIZE + 1]; + char szBillingCity[STEAM_BILLING_CITY_SIZE + 1]; + char szBillingZip[STEAM_BILLING_ZIP_SIZE + 1]; + char szBillingState[STEAM_BILLING_STATE_SIZE + 1]; + char szBillingCountry[STEAM_BILLING_COUNTRY_SIZE + 1]; + char szBillingPhone[STEAM_BILLING_PHONE_SIZE + 1]; + char szBillingEmailAddress[STEAM_BILLING_EMAIL_ADDRESS_SIZE + 1]; + unsigned int uExpectedCostInCents; + unsigned int uExpectedTaxInCents; + char szShippingName[STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szShippingAddress1[STEAM_BILLING_ADDRESS1_SIZE + 1]; + char szShippingAddress2[STEAM_BILLING_ADDRESS2_SIZE + 1]; + char szShippingCity[STEAM_BILLING_CITY_SIZE + 1]; + char szShippingZip[STEAM_BILLING_ZIP_SIZE + 1]; + char szShippingState[STEAM_BILLING_STATE_SIZE + 1]; + char szShippingCountry[STEAM_BILLING_COUNTRY_SIZE + 1]; + char szShippingPhone[STEAM_BILLING_PHONE_SIZE + 1]; + unsigned int uExpectedShippingCostInCents; + + } TSteamPaymentCardInfo; + + typedef struct + { + char szTypeOfProofOfPurchase[STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1]; + + unsigned int uLengthOfBinaryProofOfPurchaseToken; + char cBinaryProofOfPurchaseToken[STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE + 1]; + } TSteamPrepurchaseInfo; + + typedef struct + { + char szAccountName[STEAM_EXTERNAL_ACCOUNTNAME_SIZE + 1]; + char szPassword[STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE + 1]; + } TSteamExternalBillingInfo; + + typedef enum + { + ePaymentCardInfo = 1, + ePrepurchasedInfo = 2, + eAccountBillingInfo = 3, + eExternalBillingInfo = 4, + ePaymentCardReceipt = 5, + ePrepurchaseReceipt = 6, + eEmptyReceipt = 7 + } ESteamSubscriptionBillingInfoType; + + typedef struct + { + ESteamSubscriptionBillingInfoType eBillingInfoType; + union { + TSteamPaymentCardInfo PaymentCardInfo; + TSteamPrepurchaseInfo PrepurchaseInfo; + TSteamExternalBillingInfo ExternalBillingInfo; + char bUseAccountBillingInfo; + }; + + } TSteamSubscriptionBillingInfo; + + typedef enum + { + eSteamSubscriptionOK = 0, + eSteamSubscriptionPending = 1, + eSteamSubscriptionPreorder = 2, + eSteamSubscriptionPrepurchaseTransferred = 3, + eSteamSubscriptionPrepurchaseInvalid = 4, + eSteamSubscriptionPrepurchaseRejected = 5, + eSteamSubscriptionPrepurchaseRevoked = 6, + eSteamSubscriptionPaymentCardDeclined = 7, + eSteamSubscriptionCancelledByUser = 8, + eSteamSubscriptionCancelledByVendor = 9, + eSteamSubscriptionPaymentCardUseLimit = 10, + eSteamSubscriptionPaymentCardAlert = 11, + eSteamSubscriptionFailed = 12, + eSteamSubscriptionPaymentCardAVSFailure = 13, + eSteamSubscriptionPaymentCardInsufficientFunds = 14, + eSteamSubscriptionRestrictedCountry = 15 + + } ESteamSubscriptionStatus; + + typedef struct + { + ESteamPaymentCardType eCardType; + char szCardLastFourDigits[4 + 1]; + char szCardHolderName[STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szBillingAddress1[STEAM_BILLING_ADDRESS1_SIZE + 1]; + char szBillingAddress2[STEAM_BILLING_ADDRESS2_SIZE + 1]; + char szBillingCity[STEAM_BILLING_CITY_SIZE + 1]; + char szBillingZip[STEAM_BILLING_ZIP_SIZE + 1]; + char szBillingState[STEAM_BILLING_STATE_SIZE + 1]; + char szBillingCountry[STEAM_BILLING_COUNTRY_SIZE + 1]; + + char szCardApprovalCode[STEAM_BILLING_CARD_APPROVAL_CODE_SIZE + 1]; + char szTransDate[STEAM_BILLING_TRANS_DATE_SIZE + 1]; + char szTransTime[STEAM_BILLING_TRANS_TIME_SIZE + 1]; + unsigned int uPriceWithoutTax; + unsigned int uTaxAmount; + unsigned int uShippingCost; + + } TSteamPaymentCardReceiptInfo; + + typedef struct + { + char szTypeOfProofOfPurchase[STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1]; + } TSteamPrepurchaseReceiptInfo; + + typedef struct + { + ESteamSubscriptionStatus eStatus; + ESteamSubscriptionStatus ePreviousStatus; + ESteamSubscriptionBillingInfoType eReceiptInfoType; + char szConfirmationCode[STEAM_BILLING_CONFIRMATION_CODE_SIZE + 1]; + union { + TSteamPaymentCardReceiptInfo PaymentCardReceiptInfo; + TSteamPrepurchaseReceiptInfo PrepurchaseReceiptInfo; + }; + + } TSteamSubscriptionReceipt; + + typedef enum + { + ePhysicalBytesReceivedThisSession = 1, + eAppReadyToLaunchStatus = 2, + eAppPreloadStatus = 3, + eAppEntireDepot = 4, + eCacheBytesPresent = 5 + } ESteamAppUpdateStatsQueryType; + + typedef struct + { + SteamUnsigned64_t uBytesTotal; + SteamUnsigned64_t uBytesPresent; + } TSteamUpdateStats; + + typedef enum + { + eSteamUserAdministrator = 0x00000001, + eSteamUserDeveloper = 0x00000002, + eSteamUserCyberCafe = 0x00000004 + } ESteamUserTypeFlags; + + typedef enum + { + eSteamAccountStatusDefault = 0x00000000, + eSteamAccountStatusEmailVerified = 0x00000001, + eSteamAccountDisabled = 0x00000004 + } ESteamAccountStatusBitFields; + + + typedef enum + { + eSteamBootstrapperError = -1, + eSteamBootstrapperDontCheckForUpdate = 0, + eSteamBootstrapperCheckForUpdateAndRerun = 7 + + } ESteamBootStrapperClientAppResult; + + typedef enum + { + eSteamOnline = 0, + eSteamOffline = 1, + eSteamNoAuthMode = 2, + eSteamBillingOffline = 3 + } eSteamOfflineStatus; + + typedef struct + { + int eOfflineNow; + int eOfflineNextSession; + } TSteamOfflineStatus; + + typedef struct + { + unsigned int uAppId; + int bIsSystemDefined; + char szMountPath[STEAM_MAX_PATH]; + } TSteamAppDependencyInfo; + + typedef enum + { + eSteamOpenFileRegular = 0x0, + eSteamOpenFileIgnoreLocal = 0x1, + eSteamOpenFileChecksumReads = 0x2 + } ESteamOpenFileFlags; + + typedef enum + { + eSteamValveCDKeyValidationServer = 0, + eSteamHalfLifeMasterServer = 1, + eSteamFriendsServer = 2, + eSteamCSERServer = 3, + eSteamHalfLife2MasterServer = 4, + eSteamRDKFMasterServer = 5, + eMaxServerTypes = 6 + } ESteamServerType; + + +#ifdef __cplusplus + + const SteamHandle_t STEAM_INVALID_HANDLE = 0; + const SteamCallHandle_t STEAM_INVALID_CALL_HANDLE = 0; + const SteamUserIDTicketValidationHandle_t STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE = 0; + const unsigned int STEAM_USE_LATEST_VERSION = 0xFFFFFFFF; + +#else + +#define STEAM_INVALID_HANDLE ((SteamHandle_t)(0)) +#define STEAM_INVALID_CALL_HANDLE ((SteamCallHandle_t)(0)) +#define STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE ((SteamUserIDTicketValidationHandle_t)(0)) +#define STEAM_USE_LATEST_VERSION (0xFFFFFFFFu); + +#endif + + + typedef unsigned short SteamInstanceID_t; + + +#if defined ( _WIN32 ) + typedef unsigned __int64 SteamLocalUserID_t; +#else + typedef unsigned long long SteamLocalUserID_t; +#endif + + typedef struct + { + unsigned int Low32bits; + unsigned int High32bits; + } TSteamSplitLocalUserID; + + typedef struct + { + SteamInstanceID_t m_SteamInstanceID; + + union + { + SteamLocalUserID_t As64bits; + TSteamSplitLocalUserID Split; + } m_SteamLocalUserID; + + } TSteamGlobalUserID; + + +#ifdef __cplusplus +} +#endif + + +#endif + +``` + +`SpyCustom/sdk/TextEntry.h`: + +```h +#ifndef TEXTENTRY_H +#define TEXTENTRY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "Color.h" +#include "Panel.h" +#include "Label.h" +#include "ListPanel.h" + +#include "utlvector.h" + +namespace vgui +{ + + class TextEntry : public Panel + { + DECLARE_CLASS_SIMPLE(TextEntry, Panel); + + public: + TextEntry(Panel* parent, const char* panelName); + virtual ~TextEntry(); + + virtual void SetText(const wchar_t* wszText); + virtual void SetText(const char* text); + virtual void GetText(OUT_Z_BYTECAP(bufLenInBytes) char* buf, int bufLenInBytes); + virtual void GetText(OUT_Z_BYTECAP(bufLenInBytes) wchar_t* buf, int bufLenInBytes); + virtual int GetTextLength() const; + virtual bool IsTextFullySelected() const; + + virtual void GotoLeft(); + virtual void GotoRight(); + virtual void GotoUp(); + virtual void GotoDown(); + virtual void GotoWordRight(); + virtual void GotoWordLeft(); + virtual void GotoFirstOfLine(); + virtual void GotoEndOfLine(); + virtual void GotoTextStart(); + virtual void GotoTextEnd(); + + virtual void InsertChar(wchar_t ch); + virtual void InsertString(const char* text); + virtual void InsertString(const wchar_t* wszText); + virtual void Backspace(); + virtual void Delete(); + virtual void SelectNone(); + virtual void OpenEditMenu(); + MESSAGE_FUNC(CutSelected, "DoCutSelected"); + MESSAGE_FUNC(CopySelected, "DoCopySelected"); + MESSAGE_FUNC(Paste, "DoPaste"); + + MESSAGE_FUNC_INT(LanguageChanged, "DoLanguageChanged", handle); + MESSAGE_FUNC_INT(ConversionModeChanged, "DoConversionModeChanged", handle); + MESSAGE_FUNC_INT(SentenceModeChanged, "DoSentenceModeChanged", handle); + + MESSAGE_FUNC_WCHARPTR(CompositionString, "DoCompositionString", string); + + MESSAGE_FUNC(ShowIMECandidates, "DoShowIMECandidates"); + MESSAGE_FUNC(HideIMECandidates, "DoHideIMECandidates"); + MESSAGE_FUNC(UpdateIMECandidates, "DoUpdateIMECandidates"); + + virtual void DeleteSelected(); + virtual void Undo(); + virtual void SaveUndoState(); + virtual void SetFont(HFont font); + virtual void SetTextHidden(bool bHideText); + virtual void SetEditable(bool state); + virtual bool IsEditable(); + virtual void SetEnabled(bool state); + virtual void MoveCursor(int line, int pixelsAcross); + + virtual void SetDisabledBgColor(Color col); + + virtual void SetMultiline(bool state); + virtual bool IsMultiline(); + + virtual void SetVerticalScrollbar(bool state); + + virtual void SetCatchEnterKey(bool state); + + virtual void SendNewLine(bool send); + + virtual void SetMaximumCharCount(int maxChars); + virtual int GetMaximumCharCount(); + virtual void SetAutoProgressOnHittingCharLimit(bool state); + + virtual void SetWrap(bool wrap); + + virtual void RecalculateLineBreaks(); + virtual void LayoutVerticalScrollBarSlider(); + + virtual bool RequestInfo(KeyValues* outputData); + + void SetToFullHeight(); + + void SetToFullWidth(); + + int GetNumLines(); + + void SelectAllText(bool bResetCursorPos); + void SelectNoText(); + void SelectAllOnFirstFocus(bool status); + void SetDrawWidth(int width); + int GetDrawWidth(); + void SetHorizontalScrolling(bool status); + + void SetAllowNonAsciiCharacters(bool state); + + void SetAllowNumericInputOnly(bool state); + + void SetDrawLanguageIDAtLeft(bool state); + + virtual bool GetDropContextMenu(Menu* menu, CUtlVector< KeyValues* >& data); + virtual bool IsDroppable(CUtlVector< KeyValues* >& data); + virtual void OnPanelDropped(CUtlVector< KeyValues* >& data); + virtual Panel* GetDragPanel(); + virtual void OnCreateDragData(KeyValues* msg); + + void SelectAllOnFocusAlways(bool status); + void SetSelectionTextColor(const Color& clr); + void SetSelectionBgColor(const Color& clr); + void SetSelectionUnfocusedBgColor(const Color& clr); + + void SetUseFallbackFont(bool bState, HFont hFallback); + + protected: + virtual void ResetCursorBlink(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme* pScheme); + virtual void PaintBackground(); + virtual int DrawChar(wchar_t ch, HFont font, int index, int x, int y); + virtual bool DrawCursor(int x, int y); + + virtual void SetCharAt(wchar_t ch, int index); + virtual void ApplySettings(KeyValues* inResourceData); + virtual void GetSettings(KeyValues* outResourceData); + virtual const char* GetDescription(void); + virtual void FireActionSignal(); + virtual bool GetSelectedRange(int& cx0, int& cx1); + virtual void CursorToPixelSpace(int cursorPos, int& cx, int& cy); + virtual int PixelToCursorSpace(int cx, int cy); + virtual void AddAnotherLine(int& cx, int& cy); + virtual int GetYStart(); + + virtual bool SelectCheck(bool fromMouse = false); + MESSAGE_FUNC_WCHARPTR(OnSetText, "SetText", text); + MESSAGE_FUNC(OnSliderMoved, "ScrollBarSliderMoved"); + virtual void OnKillFocus(); + virtual void OnMouseWheeled(int delta); + virtual void OnKeyCodePressed(KeyCode code); + virtual void OnKeyCodeTyped(KeyCode code); + virtual void OnKeyTyped(wchar_t unichar); + + virtual void OnCursorMoved(int x, int y); + virtual void OnMousePressed(MouseCode code); + virtual void OnMouseDoublePressed(MouseCode code); + virtual void OnMouseTriplePressed(MouseCode code); + virtual void OnMouseReleased(MouseCode code); + + virtual void OnKeyFocusTicked(); + virtual void OnMouseFocusTicked(); + virtual void OnCursorEntered(); + virtual void OnCursorExited(); + + virtual void OnMouseCaptureLost(); + virtual void OnSizeChanged(int newWide, int newTall); + + virtual int GetStartDrawIndex(int& lineBreakIndexIndex); + + public: + virtual float GetValueAsFloat(); + virtual int GetValueAsInt(); + + protected: + void ScrollRight(); + void ScrollLeft(); + bool IsCursorOffRightSideOfWindow(int cursorPos); + bool IsCursorOffLeftSideOfWindow(int cursorPos); + void ScrollLeftForResize(); + + void OnSetFocus(); + void OnChangeIME(bool forward); + + bool NeedsEllipses(HFont font, int* pIndex); + + private: + MESSAGE_FUNC_INT(OnSetState, "SetState", state); + int GetCurrentLineStart(); + int GetCurrentLineEnd(); + bool IsLineBreak(int index); + int GetCursorLine(); + void MoveScrollBar(int delta); + void CalcBreakIndex(); + void CreateEditMenu(); + + public: + Menu* GetEditMenu(); + + private: + void FlipToLastIME(); + + public: + virtual void GetTextRange(wchar_t* buf, int from, int numchars); + virtual void GetTextRange(char* buf, int from, int numchars); + + private: + + CUtlVector m_TextStream; + CUtlVector m_UndoTextStream; + CUtlVector m_LineBreaks; + + int _cursorPos; + bool _cursorIsAtEnd; + bool _putCursorAtEnd; + int _undoCursorPos; + bool _cursorBlink; + bool _hideText; + bool _editable; + bool _mouseSelection; + bool _mouseDragSelection; + int _mouseSelectCursorStart; + long _cursorNextBlinkTime; + int _cursorBlinkRate; + int _select[2]; + int _pixelsIndent; + int _charCount; + int _maxCharCount; + HFont _font; + HFont _smallfont; + bool _dataChanged; + bool _multiline; + bool _verticalScrollbar; + ScrollBar* _vertScrollBar; + Color _cursorColor; + Color _disabledFgColor; + Color _disabledBgColor; + Color _selectionColor; + Color _selectionTextColor; + Color _defaultSelectionBG2Color; + int _currentStartLine; + int _currentStartIndex; + bool _horizScrollingAllowed; + Color _focusEdgeColor; + bool _catchEnterKey; + bool _wrap; + bool _sendNewLines; + int _drawWidth; + + Menu* m_pEditMenu; + + int _recalculateBreaksIndex; + bool _selectAllOnFirstFocus : 1; + bool _selectAllOnFocusAlways : 1; + bool _firstFocusStatus; + bool m_bAllowNumericInputOnly; + bool m_bAllowNonAsciiCharacters; + bool m_bAutoProgressOnHittingCharLimit; + + enum + { + MAX_COMPOSITION_STRING = 256, + }; + + wchar_t m_szComposition[MAX_COMPOSITION_STRING]; + Menu* m_pIMECandidates; + int m_hPreviousIME; + bool m_bDrawLanguageIDAtLeft; + int m_nLangInset; + + bool m_bUseFallbackFont : 1; + HFont m_hFallbackFont; + }; + +} + +#endif +``` + +`SpyCustom/sdk/TextImage.h`: + +```h +#ifndef TEXTIMAGE_H +#define TEXTIMAGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "ILocalize.h" +#include "Image.h" + +#include "utlvector.h" +#include "UtlSortVector.h" + +class KeyValues; + +namespace vgui +{ + + struct label_colorchange_t + { + Color color; + int textStreamIndex; + }; + + class CColorChangeListLess + { + public: + bool Less(const label_colorchange_t& src1, const label_colorchange_t& src2, void* pCtx) + { + if (src1.textStreamIndex < src2.textStreamIndex) + return true; + + return false; + } + }; + + class TextImage : public Image + { + public: + TextImage(const char* text); + TextImage(const wchar_t* wszText); + ~TextImage(); + + public: + virtual void SetText(const char* text); + virtual void SetText(const wchar_t* text, bool bClearUnlocalizedSymbol = false); + virtual void GetText(char* buffer, int bufferSize); + virtual void GetText(wchar_t* buffer, int bufferLength); + virtual void GetUnlocalizedText(char* buffer, int bufferSize); + virtual StringIndex_t GetUnlocalizedTextSymbol(); + + virtual void SetFont(vgui::HFont font); + virtual vgui::HFont GetFont(); + + void SetDrawWidth(int width); + void GetDrawWidth(int& width); + + void ResizeImageToContent(); + void ResizeImageToContentMaxWidth(int nMaxWidth); + + virtual void SetSize(int wide, int tall); + + virtual void GetContentSize(int& wide, int& tall); + + virtual void Paint(); + + void SetWrap(bool bWrap); + void RecalculateNewLinePositions(); + + void SetUseFallbackFont(bool bState, HFont hFallback); + + void SetAllCaps(bool bAllCaps); + + void SetCenterWrap(bool bWrap); + void RecalculateCenterWrapIndents(); + + const wchar_t* GetUText(void) { return _utext; } + + void AddColorChange(Color col, int iTextStreamIndex); + void SetColorChangeStream(CUtlSortVector* pUtlVecStream); + void ClearColorChangeStream(void) { m_ColorChangeStream.Purge(); } + + const wchar_t* GetEllipsesPosition(void) const { return m_pwszEllipsesPosition; } + bool IsWrapping() const { return m_LineBreaks.Count() != 0; } + + protected: + void SizeText(wchar_t* tempText, int stringLength); + virtual void GetTextSize(int& wide, int& tall); + + private: + void RecalculateEllipsesPosition(); + + wchar_t* _utext; + short _textBufferLen; + short _textLen; + vgui::HFont _font; + vgui::HFont _fallbackFont; + int _drawWidth; + StringIndex_t _unlocalizedTextSymbol; + wchar_t* m_pwszEllipsesPosition; + + bool m_bRecalculateTruncation : 1; + bool m_bWrap : 1; + bool m_bUseFallbackFont : 1; + bool m_bRenderUsingFallbackFont : 1; + bool m_bAllCaps : 1; + CUtlVector m_LineBreaks; + + bool m_bWrapCenter; + CUtlVector m_LineXIndent; + + CUtlSortVector m_ColorChangeStream; + }; + +} + +#endif +``` + +`SpyCustom/sdk/ToggleButton.h`: + +```h +#ifndef TOGGLEBUTTON_H +#define TOGGLEBUTTON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "Button.h" + +namespace vgui +{ + + class ToggleButton : public Button + { + DECLARE_CLASS_SIMPLE(ToggleButton, Button); + + public: + ToggleButton(Panel* parent, const char* panelName, const char* text); + + virtual void DoClick(); + + protected: + virtual void OnMouseDoublePressed(MouseCode code); + + virtual Color GetButtonFgColor(); + virtual void ApplySchemeSettings(IScheme* pScheme); + + virtual bool CanBeDefaultButton(void); + virtual void OnKeyCodePressed(KeyCode code); + + private: + Color _selectedColor; + }; + +} + +#endif +``` + +`SpyCustom/sdk/Tooltip.h`: + +```h +#ifndef TOOLTIP_H +#define TOOLTIP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "VGUI.h" +#include "Controls.h" +#include "utlvector.h" + +namespace vgui +{ + + class BaseTooltip + { + public: + BaseTooltip(Panel* parent, const char* text = NULL); + + virtual void SetText(const char* text); + virtual const char* GetText(); + + virtual void ShowTooltip(Panel* currentPanel); + virtual void HideTooltip(); + + bool ShouldLayout(void); + virtual void PerformLayout() { return; } + virtual void PositionWindow(Panel* pTipPanel); + + void ResetDelay(); + void SetTooltipFormatToSingleLine(); + void SetTooltipFormatToMultiLine(); + void SetTooltipDelay(int tooltipDelayMilliseconds); + int GetTooltipDelay(); + void SetEnabled(bool bState); + + private: + Panel* m_pParent; + virtual void ApplySchemeSettings(IScheme* pScheme) {}; + protected: + CUtlVector m_Text; + int _delay; + int _tooltipDelay; + bool _makeVisible : 1; + bool _displayOnOneLine : 1; + bool _isDirty : 1; + bool _enabled : 1; + }; + + class TextTooltip : public BaseTooltip + { + public: + TextTooltip(Panel* parent, const char* text = NULL); + ~TextTooltip(); + + virtual void SetText(const char* text); + virtual void ShowTooltip(Panel* currentPanel); + virtual void HideTooltip(); + virtual void SizeTextWindow(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme* pScheme); + }; + +}; + +#endif +``` + +`SpyCustom/sdk/UtlSortVector.h`: + +```h +#ifndef UTLSORTVECTOR_H +#define UTLSORTVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + + +#ifndef _WIN32 +extern void* g_pUtlSortVectorQSortContext; +#endif + +template +class CUtlSortVectorDefaultLess +{ +public: + bool Less(const T& lhs, const T& rhs, void*) + { + return lhs < rhs; + } +}; + +template , class BaseVector = CUtlVector > +class CUtlSortVector : public BaseVector +{ + typedef BaseVector BaseClass; +public: + CUtlSortVector(int nGrowSize = 0, int initSize = 0); + CUtlSortVector(T* pMemory, int numElements); + + int Insert(const T& src); + + int InsertIfNotFound(const T& src); + + template< typename TKey > + int Find(const TKey& search) const; + template< typename TKey > + int FindLessOrEqual(const TKey& search) const; + template< typename TKey > + int FindLess(const TKey& search) const; + + void Remove(const T& search); + void Remove(int i); + + void SetLessContext(void* pCtx); + + int InsertNoSort(const T& src); + void RedoSort(bool bForceSort = false); + + int InsertAfter(int nElemIndex, const T& src); + + template< typename TKey > + int FindUnsorted(const TKey& src) const; + +protected: + CUtlSortVector(const CUtlSortVector&); + + int AddToHead(); + int AddToTail(); + int InsertBefore(int elem); + int InsertAfter(int elem); + int InsertBefore(int elem, const T& src); + int AddToHead(const T& src); + int AddToTail(const T& src); + int AddMultipleToHead(int num); + int AddMultipleToTail(int num, const T* pToCopy = NULL); + int InsertMultipleBefore(int elem, int num, const T* pToCopy = NULL); + int InsertMultipleAfter(int elem, int num); + int AddVectorToTail(CUtlVector const& src); + + struct QSortContext_t + { + void* m_pLessContext; + LessFunc* m_pLessFunc; + }; + +#ifdef _WIN32 + static int CompareHelper(void* context, const T* lhs, const T* rhs) + { + QSortContext_t* ctx = reinterpret_cast(context); + if (ctx->m_pLessFunc->Less(*lhs, *rhs, ctx->m_pLessContext)) + return -1; + if (ctx->m_pLessFunc->Less(*rhs, *lhs, ctx->m_pLessContext)) + return 1; + return 0; + } +#else + static int CompareHelper(const T* lhs, const T* rhs) + { + QSortContext_t* ctx = reinterpret_cast(g_pUtlSortVectorQSortContext); + if (ctx->m_pLessFunc->Less(*lhs, *rhs, ctx->m_pLessContext)) + return -1; + if (ctx->m_pLessFunc->Less(*rhs, *lhs, ctx->m_pLessContext)) + return 1; + return 0; + } +#endif + + void* m_pLessContext; + bool m_bNeedsSort; + +private: +private: + template< typename TKey > + int FindLessOrEqual(const TKey& search, bool* pFound) const; + + void QuickSort(LessFunc& less, int X, int I); +}; + + +template +CUtlSortVector::CUtlSortVector(int nGrowSize, int initSize) : + m_pLessContext(NULL), BaseVector(nGrowSize, initSize), m_bNeedsSort(false) +{ +} + +template +CUtlSortVector::CUtlSortVector(T* pMemory, int numElements) : + m_pLessContext(NULL), BaseVector(pMemory, numElements), m_bNeedsSort(false) +{ +} + +template +void CUtlSortVector::SetLessContext(void* pCtx) +{ + m_pLessContext = pCtx; +} + +template +int CUtlSortVector::Insert(const T& src) +{ + AssertFatal(!m_bNeedsSort); + + int pos = FindLessOrEqual(src) + 1; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct(&this->Element(pos), src); + return pos; +} + +template +int CUtlSortVector::InsertNoSort(const T& src) +{ + m_bNeedsSort = true; + int lastElement = BaseVector::m_Size; + this->GrowVector(); + this->ShiftElementsRight(lastElement); + CopyConstruct(&this->Element(lastElement), src); + return lastElement; +} + +template +int CUtlSortVector::InsertIfNotFound(const T& src) +{ + AssertFatal(!m_bNeedsSort); + bool bFound; + int pos = FindLessOrEqual(src, &bFound); + if (bFound) + return pos; + + ++pos; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct(&this->Element(pos), src); + return pos; +} + +template +int CUtlSortVector::InsertAfter(int nIndex, const T& src) +{ + int nInsertedIndex = this->BaseClass::InsertAfter(nIndex, src); + +#ifdef DEBUG + LessFunc less; + if (nInsertedIndex > 0) + { + Assert(less.Less(this->Element(nInsertedIndex - 1), src, m_pLessContext)); + } + if (nInsertedIndex < BaseClass::Count() - 1) + { + Assert(less.Less(src, this->Element(nInsertedIndex + 1), m_pLessContext)); + } +#endif + return nInsertedIndex; +} + +template +template < typename TKey > +int CUtlSortVector::Find(const TKey& src) const +{ + AssertFatal(!m_bNeedsSort); + + LessFunc less; + + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if (less.Less(this->Element(mid), src, m_pLessContext)) + { + start = mid + 1; + } + else if (less.Less(src, this->Element(mid), m_pLessContext)) + { + end = mid - 1; + } + else + { + return mid; + } + } + return -1; +} + + +template< class T, class LessFunc, class BaseVector > +template < typename TKey > +int CUtlSortVector::FindUnsorted(const TKey& src) const +{ + LessFunc less; + int nCount = this->Count(); + for (int i = 0; i < nCount; ++i) + { + if (less.Less(this->Element(i), src, m_pLessContext)) + continue; + if (less.Less(src, this->Element(i), m_pLessContext)) + continue; + return i; + } + return -1; +} + + +template +template < typename TKey > +int CUtlSortVector::FindLessOrEqual(const TKey& src, bool* pFound) const +{ + AssertFatal(!m_bNeedsSort); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if (less.Less(this->Element(mid), src, m_pLessContext)) + { + start = mid + 1; + } + else if (less.Less(src, this->Element(mid), m_pLessContext)) + { + end = mid - 1; + } + else + { + *pFound = true; + return mid; + } + } + + *pFound = false; + return end; +} + +template +template < typename TKey > +int CUtlSortVector::FindLessOrEqual(const TKey& src) const +{ + bool bFound; + return FindLessOrEqual(src, &bFound); +} + +template +template < typename TKey > +int CUtlSortVector::FindLess(const TKey& src) const +{ + AssertFatal(!m_bNeedsSort); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if (less.Less(this->Element(mid), src, m_pLessContext)) + { + start = mid + 1; + } + else + { + end = mid - 1; + } + } + return end; +} + + +template +void CUtlSortVector::Remove(const T& search) +{ + AssertFatal(!m_bNeedsSort); + + int pos = Find(search); + if (pos != -1) + { + BaseVector::Remove(pos); + } +} + +template +void CUtlSortVector::Remove(int i) +{ + BaseVector::Remove(i); +} + +#endif +``` + +`SpyCustom/sdk/UtlStringMap.h`: + +```h +#ifndef UTLSTRINGMAP_H +#define UTLSTRINGMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlsymbol.h" + +template +class CUtlStringMap +{ +public: + CUtlStringMap(bool caseInsensitive = true) : m_SymbolTable(0, 32, caseInsensitive) + { + } + + T& operator[](const char* pString) + { + CUtlSymbol symbol = m_SymbolTable.AddString(pString); + int index = (int)(UtlSymId_t)symbol; + if (m_Vector.Count() <= index) + { + m_Vector.EnsureCount(index + 1); + } + return m_Vector[index]; + } + + T& operator[](UtlSymId_t n) + { + Assert(n >= 0 && n <= m_Vector.Count()); + return m_Vector[n]; + } + + const T& operator[](UtlSymId_t n) const + { + Assert(n >= 0 && n <= m_Vector.Count()); + return m_Vector[n]; + } + + bool Defined(const char* pString) const + { + return m_SymbolTable.Find(pString) != UTL_INVAL_SYMBOL; + } + + UtlSymId_t Find(const char* pString) const + { + return m_SymbolTable.Find(pString); + } + + static UtlSymId_t InvalidIndex() + { + return UTL_INVAL_SYMBOL; + } + + int GetNumStrings(void) const + { + return m_SymbolTable.GetNumStrings(); + } + + const char* String(int n) const + { + return m_SymbolTable.String(n); + } + + void Clear() + { + m_Vector.RemoveAll(); + m_SymbolTable.RemoveAll(); + } + + void Purge() + { + m_Vector.Purge(); + m_SymbolTable.RemoveAll(); + } + + void PurgeAndDeleteElements() + { + m_Vector.PurgeAndDeleteElements(); + m_SymbolTable.RemoveAll(); + } + + + +private: + CUtlVector m_Vector; + CUtlSymbolTable m_SymbolTable; +}; + +#endif +``` + +`SpyCustom/sdk/VGUI.h`: + +```h +#ifndef VGUI_H +#define VGUI_H + +#ifdef _WIN32 +#pragma once +#endif + +#define null 0L + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#pragma warning( disable: 4800 ) +#pragma warning( disable: 4786 ) +#pragma warning( disable: 4355 ) +#pragma warning( disable: 4097 ) +#pragma warning( disable: 4514 ) +#pragma warning( disable: 4100 ) +#pragma warning( disable: 4127 ) + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifndef _WCHAR_T_DEFINED +#if !defined( __x86_64__ ) && !defined( __WCHAR_TYPE__ ) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif +#endif + +namespace vgui +{ + typedef unsigned int VPANEL; + + typedef unsigned long HScheme; + typedef unsigned long HTexture; + typedef unsigned long HCursor; + typedef unsigned long HPanel; + const HPanel INVALID_PANEL = 0xffffffff; + typedef unsigned long HFont; + const HFont INVALID_FONT = 0; +} + +#include "strtools.h" + +#if 0 +#define USE_GETKERNEDCHARWIDTH 1 +#else +#define USE_GETKERNEDCHARWIDTH 0 +#endif + + +#endif +``` + +`SpyCustom/sdk/animationlayer.h`: + +```h +#ifndef ANIMATIONLAYER_H +#define ANIMATIONLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "rangecheckedvar.h" +#include "lerp_functions.h" + +#include "shareddefs.h" +#include "cs_shareddefs.h" + +#ifdef CLIENT_DLL +class C_BaseAnimatingOverlay; +#endif + +class C_AnimationLayer +{ +public: + + ALLOW_DATATABLES_PRIVATE_ACCESS(); + + C_AnimationLayer(); + void Reset(); + +#ifdef CLIENT_DLL + void SetOwner(C_BaseAnimatingOverlay* pOverlay); + C_BaseAnimatingOverlay* GetOwner() const; +#endif + + void SetOrder(int order); + bool IsActive(void); + float GetFadeout(float flCurTime); + + void SetSequence(int nSequence); + void SetCycle(float flCycle); + void SetPrevCycle(float flCycle); + void SetPlaybackRate(float flPlaybackRate); + void SetWeight(float flWeight); + void SetWeightDeltaRate(float flDelta); + + int GetOrder() const; + int GetSequence() const; + float GetCycle() const; + float GetPrevCycle() const; + float GetPlaybackRate() const; + float GetWeight() const; + float GetWeightDeltaRate() const; + +#ifdef CLIENT_DLL + int GetInvalidatePhysicsBits() const; + void SetInvalidatePhysicsBits(int iBit) { m_nInvalidatePhysicsBits = iBit; } +#endif + +public: + float m_flLayerAnimtime; + float m_flLayerFadeOuttime; + + CStudioHdr* m_pDispatchedStudioHdr; + int m_nDispatchedSrc; + int m_nDispatchedDst; + +private: + int m_nOrder; + CRangeCheckedVar m_nSequence; + CRangeCheckedVar m_flPrevCycle; + CRangeCheckedVar m_flWeight; + CRangeCheckedVar m_flWeightDeltaRate; + + CRangeCheckedVar m_flPlaybackRate; + CRangeCheckedVar m_flCycle; + +#ifdef CLIENT_DLL + C_BaseAnimatingOverlay* m_pOwner; + int m_nInvalidatePhysicsBits; +#endif + + friend class C_BaseAnimatingOverlay; + friend C_AnimationLayer LoopingLerp(float flPercent, C_AnimationLayer& from, C_AnimationLayer& to); + friend C_AnimationLayer Lerp(float flPercent, const C_AnimationLayer& from, const C_AnimationLayer& to); + friend C_AnimationLayer LoopingLerp_Hermite(const C_AnimationLayer& current, float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to); + friend C_AnimationLayer Lerp_Hermite(const C_AnimationLayer& current, float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to); + friend void Lerp_Clamp(C_AnimationLayer& val); + friend int CheckForSequenceBoxChanges(const C_AnimationLayer& newLayer, const C_AnimationLayer& oldLayer); +}; + +#ifdef CLIENT_DLL +#define CAnimationLayer C_AnimationLayer +#endif + + +inline C_AnimationLayer::C_AnimationLayer() +{ +#ifdef CLIENT_DLL + m_pOwner = NULL; + m_nInvalidatePhysicsBits = 0; +#endif + m_pDispatchedStudioHdr = NULL; + m_nDispatchedSrc = 0; + m_nDispatchedDst = 0; + + Reset(); +} + +#ifdef GAME_DLL + +inline void C_AnimationLayer::SetSequence(int nSequence) +{ + m_nSequence = nSequence; +} + +inline void C_AnimationLayer::SetCycle(float flCycle) +{ + m_flCycle = flCycle; +} + +inline void C_AnimationLayer::SetWeight(float flWeight) +{ + m_flWeight = flWeight; +} + +#endif + +FORCEINLINE void C_AnimationLayer::SetPrevCycle(float flPrevCycle) +{ + m_flPrevCycle = flPrevCycle; +} + +FORCEINLINE void C_AnimationLayer::SetPlaybackRate(float flPlaybackRate) +{ + m_flPlaybackRate = flPlaybackRate; +} + +FORCEINLINE void C_AnimationLayer::SetWeightDeltaRate(float flDelta) +{ + m_flWeightDeltaRate = flDelta; +} + +FORCEINLINE int C_AnimationLayer::GetSequence() const +{ + return m_nSequence; +} + +FORCEINLINE float C_AnimationLayer::GetCycle() const +{ + return m_flCycle; +} + +FORCEINLINE float C_AnimationLayer::GetPrevCycle() const +{ + return m_flPrevCycle; +} + +FORCEINLINE float C_AnimationLayer::GetPlaybackRate() const +{ + return m_flPlaybackRate; +} + +FORCEINLINE float C_AnimationLayer::GetWeight() const +{ + return m_flWeight; +} + +FORCEINLINE float C_AnimationLayer::GetWeightDeltaRate() const +{ + return m_flWeightDeltaRate; +} + +FORCEINLINE int C_AnimationLayer::GetOrder() const +{ + return m_nOrder; +} + +inline float C_AnimationLayer::GetFadeout(float flCurTime) +{ + float s; + + if (m_flLayerFadeOuttime <= 0.0f) + { + s = 0; + } + else + { + s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime; + if (s > 0 && s <= 1.0) + { + s = 3 * s * s - 2 * s * s * s; + } + else if (s > 1.0f) + { + s = 1.0f; + } + } + return s; +} + +#ifdef CLIENT_DLL +FORCEINLINE int C_AnimationLayer::GetInvalidatePhysicsBits() const +{ + return m_nInvalidatePhysicsBits; +} +#endif + +inline C_AnimationLayer LoopingLerp(float flPercent, C_AnimationLayer& from, C_AnimationLayer& to) +{ +#ifdef CLIENT_DLL + Assert(from.GetOwner() == to.GetOwner()); +#endif + + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = LoopingLerp(flPercent, (float)from.m_flCycle, (float)to.m_flCycle); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp(flPercent, from.m_flWeight, to.m_flWeight); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; +#ifdef CLIENT_DLL + output.SetOwner(to.GetOwner()); +#endif + return output; +} + +inline C_AnimationLayer Lerp(float flPercent, const C_AnimationLayer& from, const C_AnimationLayer& to) +{ +#ifdef CLIENT_DLL + Assert(from.GetOwner() == to.GetOwner()); +#endif + + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = Lerp(flPercent, from.m_flCycle, to.m_flCycle); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp(flPercent, from.m_flWeight, to.m_flWeight); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; +#ifdef CLIENT_DLL + output.SetOwner(to.GetOwner()); +#endif + return output; +} + +inline int CheckForSequenceBoxChanges(const C_AnimationLayer& newLayer, const C_AnimationLayer& oldLayer) +{ + int nChangeFlags = 0; + + bool bOldIsZero = (oldLayer.GetWeight() == 0.0f); + bool bNewIsZero = (newLayer.GetWeight() == 0.0f); + + if ((newLayer.GetSequence() != oldLayer.GetSequence()) || + (bNewIsZero != bOldIsZero)) + { + nChangeFlags |= SEQUENCE_CHANGED | BOUNDS_CHANGED; + } + + if (newLayer.GetCycle() != oldLayer.GetCycle()) + { + nChangeFlags |= ANIMATION_CHANGED; + } + + if (newLayer.GetOrder() != oldLayer.GetOrder()) + { + nChangeFlags |= BOUNDS_CHANGED; + } + + return nChangeFlags; +} + +inline C_AnimationLayer LoopingLerp_Hermite(const C_AnimationLayer& current, float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to) +{ +#ifdef CLIENT_DLL + Assert(prev.GetOwner() == from.GetOwner()); + Assert(from.GetOwner() == to.GetOwner()); +#endif + + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = LoopingLerp_Hermite((float)current.m_flCycle, flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp(flPercent, from.m_flWeight, to.m_flWeight); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; + +#ifdef CLIENT_DLL + output.SetOwner(to.GetOwner()); + output.m_nInvalidatePhysicsBits = CheckForSequenceBoxChanges(output, current); +#endif + return output; +} + +inline C_AnimationLayer Lerp_Hermite(const C_AnimationLayer& current, float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to) +{ +#ifdef CLIENT_DLL + Assert(prev.GetOwner() == from.GetOwner()); + Assert(from.GetOwner() == to.GetOwner()); +#endif + + C_AnimationLayer output; + + output.m_nSequence = to.m_nSequence; + output.m_flCycle = Lerp_Hermite((float)current.m_flCycle, flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle); + output.m_flPrevCycle = to.m_flPrevCycle; + output.m_flWeight = Lerp(flPercent, from.m_flWeight, to.m_flWeight); + output.m_nOrder = to.m_nOrder; + + output.m_flLayerAnimtime = to.m_flLayerAnimtime; + output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; +#ifdef CLIENT_DLL + output.SetOwner(to.GetOwner()); + output.m_nInvalidatePhysicsBits = CheckForSequenceBoxChanges(output, current); +#endif + return output; +} + +inline void Lerp_Clamp(C_AnimationLayer& val) +{ + Lerp_Clamp(val.m_nSequence); + Lerp_Clamp(val.m_flCycle); + Lerp_Clamp(val.m_flPrevCycle); + Lerp_Clamp(val.m_flWeight); + Lerp_Clamp(val.m_nOrder); + Lerp_Clamp(val.m_flLayerAnimtime); + Lerp_Clamp(val.m_flLayerFadeOuttime); +} + +#endif +``` + +`SpyCustom/sdk/annotations.h`: + +```h +#ifndef ANALYSIS_ANNOTATIONS_H +#define ANALYSIS_ANNOTATIONS_H + +#if _MSC_VER >= 1600 +#pragma warning(error : 4789 ) + +#ifdef _PREFAST_ +#include + +#define ANALYZE_SUPPRESS(wnum) __pragma(warning(suppress: wnum)) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) __pragma(warning(supress: wnum1 wnum2)) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) __pragma(warning(suppress: wnum1 wnum2 wnum3)) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) __pragma(warning(suppress: wnum1 wnum2 wnum3 wnum4)) + +#define PRINTF_FORMAT_STRING _Printf_format_string_ +#define SCANF_FORMAT_STRING _Scanf_format_string_impl_ +#define IN_Z _In_z_ +#define IN_CAP(x) _In_count_(x) +#define IN_BYTECAP(x) _In_bytecount_(x) +#define OUT_Z_CAP(x) _Out_z_cap_(x) +#define OUT_CAP(x) _Out_cap_(x) +#define OUT_CAP_C(x) _Out_cap_c_(x) +#define OUT_BYTECAP(x) _Out_bytecap_(x) +#define OUT_Z_BYTECAP(x) _Out_z_bytecap_(x) +#define INOUT_BYTECAP(x) _Inout_bytecap_(x) +#define INOUT_Z_CAP(x) _Inout_z_cap_(x) +#define INOUT_Z_BYTECAP(x) _Inout_z_bytecap_(x) +#if _MSC_VER >= 1700 +#define IN_Z_ARRAY _Pre_z_ +#define OUT_Z_ARRAY _Post_z_ +#define INOUT_Z_ARRAY _Prepost_z_ +#else +#define IN_Z_ARRAY _Deref_pre_z_ +#define OUT_Z_ARRAY _Deref_post_z_ +#define INOUT_Z_ARRAY _Deref_prepost_z_ +#endif +#define MUST_CHECK_RETURN _Check_return_ +#endif +#endif + +#ifndef ANALYZE_SUPPRESS +#define ANALYZE_SUPPRESS(wnum) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) +#define PRINTF_FORMAT_STRING +#define SCANF_FORMAT_STRING +#define IN_Z +#define IN_CAP(x) +#define IN_BYTECAP(x) +#define OUT_Z_CAP(x) +#define OUT_CAP(x) +#define OUT_CAP_C(x) +#define OUT_BYTECAP(x) +#define OUT_Z_BYTECAP(x) +#define INOUT_BYTECAP(x) +#define INOUT_Z_CAP(x) +#define INOUT_Z_BYTECAP(x) +#define OUT_Z_ARRAY +#define INOUT_Z_ARRAY +#define MUST_CHECK_RETURN +#endif + +#endif +``` + +`SpyCustom/sdk/baseclientstate.h`: + +```h +#ifndef BASECLIENTSTATE_H +#define BASECLIENTSTATE_H +#ifdef _WIN32 +#pragma once +#endif + + + + + + + +class CBaseClientState +{ +public: + char _pad0[0x20C]; + int m_nDeltaTick; + bool m_bPaused; + char _pad1[0x3]; + int m_nViewEntity; + char _pad2[0x8]; + char m_szLevelName[260]; + char m_szLevelNameShort[40]; +}; + +class CClockDriftMgr +{ +public: + float m_ClockOffsets[16]; + uint32_t m_iCurClockOffset; + uint32_t m_nServerTick; + uint32_t m_nClientTick; +}; + +class CEventInfo +{ +public: + enum + { + EVENT_INDEX_BITS = 8, + EVENT_DATA_LEN_BITS = 11, + MAX_EVENT_DATA = 192, + }; + + inline CEventInfo() + { + classID = 0; + fire_delay = 0.0f; + flags = 0; + pSendTable = NULL; + pClientClass = NULL; + m_Packed = 0; + } + + short classID; + short pad; + float fire_delay; + const void* pSendTable; + const ClientClass* pClientClass; + int m_Packed; + int flags; + int filter[8]; + CEventInfo* next; +}; + +class CClientState +{ +public: + void ForceFullUpdate() + { + m_nDeltaTick = -1; + } + + char pad_0000[156]; + INetChannel* m_NetChannel; + int m_nChallengeNr; + char pad_00A4[100]; + int m_nSignonState; + int signon_pads[2]; + float m_flNextCmdTime; + int m_nServerCount; + int m_nCurrentSequence; + int musor_pads[2]; + CClockDriftMgr m_ClockDriftMgr; + int m_nDeltaTick; + bool m_bPaused; + char paused_align[3]; + int m_nViewEntity; + int m_nPlayerSlot; + int bruh; + char m_szLevelName[260]; + char m_szLevelNameShort[80]; + char m_szGroupName[80]; + char pad_032[92]; + int m_nMaxClients; + char pad_0314[18828]; + float m_nLastServerTickTime; + bool m_bInSimulation; + char pad_4C9D[3]; + int m_nOldTickCount; + float m_flTickReminder; + float m_flFrametime; + int m_nLastOutgoingCommand; + int m_nChokedCommands; + int m_nLastCommandAck; + int m_nPacketEndTickUpdate; + int m_nCommandAck; + int m_nSoundSequence; + char pad_4CCD[76]; + QAngle viewangles; + int pads[54]; + CEventInfo* m_pEvents; +}; + + + +#endif +#pragma once + +``` + +`SpyCustom/sdk/baseentity.h`: + +```h +#ifndef ENTITYLIST_H +#define ENTITYLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +class CBaseEntity; +class IEntityListener; + +class CBaseEntityClassList +{ +public: + CBaseEntityClassList(); + ~CBaseEntityClassList(); + virtual void LevelShutdownPostEntity() = 0; + + CBaseEntityClassList* m_pNextClassList; +}; + +template< class T > +class CEntityClassList : public CBaseEntityClassList +{ +public: + virtual void LevelShutdownPostEntity() { m_pClassList = NULL; } + + void Insert(T* pEntity) + { + pEntity->m_pNext = m_pClassList; + m_pClassList = pEntity; + } + + void Remove(T* pEntity) + { + T** pPrev = &m_pClassList; + T* pCur = *pPrev; + while (pCur) + { + if (pCur == pEntity) + { + *pPrev = pCur->m_pNext; + return; + } + pPrev = &pCur->m_pNext; + pCur = *pPrev; + } + } + + static T* m_pClassList; +}; + +abstract_class IEntityFindFilter +{ +public: + virtual bool ShouldFindEntity(CBaseEntity * pEntity) = 0; + virtual CBaseEntity* GetFilterResult(void) = 0; +}; + + +class CGlobalEntityList : public CBaseEntityList +{ +public: +private: + int m_iHighestEnt; + int m_iNumEnts; + int m_iNumEdicts; + + bool m_bClearingEntities; + CUtlVector m_entityListeners; + +public: + CBaseHandle AddNetworkableEntity(IHandleEntity* pEnt, int index, int iForcedSerialNum = -1); + CBaseHandle AddNonNetworkableEntity(IHandleEntity* pEnt); + + void UpdateName(IHandleEntity* pEnt, CBaseHandle hEnt); + void UpdateName(IHandleEntity* pEnt); + + IServerNetworkable* GetServerNetworkable(CBaseHandle hEnt) const; + CBaseNetworkable* GetBaseNetworkable(CBaseHandle hEnt) const; + CBaseEntity* GetBaseEntity(CBaseHandle hEnt) const; + edict_t* GetEdict(CBaseHandle hEnt) const; + + int NumberOfEntities(void); + int NumberOfEdicts(void); + + void AddToDeleteList(IServerNetworkable* ent); + void CleanupDeleteList(void); + int ResetDeleteList(void); + + void Clear(void); + + bool IsClearingEntities() { return m_bClearingEntities; } + + void AddListenerEntity(IEntityListener* pListener); + void RemoveListenerEntity(IEntityListener* pListener); + + void ReportEntityFlagsChanged(CBaseEntity* pEntity, unsigned int flagsOld, unsigned int flagsNow); + void AddPostClientMessageEntity(CBaseEntity* pEntity); + void PostClientMessagesSent(); + + void NotifyCreateEntity(CBaseEntity* pEnt); + void NotifySpawn(CBaseEntity* pEnt); + void NotifyRemoveEntity(CBaseEntity* pEnt); + CBaseEntity* NextEnt(CBaseEntity* pCurrentEnt); + CBaseEntity* FirstEnt() { return NextEnt(NULL); } + + template< class T > + T* NextEntByClass(T* start) + { + for (CBaseEntity* x = NextEnt(start); x; x = NextEnt(x)) + { + start = dynamic_cast(x); + if (start) + return start; + } + return NULL; + } + + bool IsEntityPtr(void* pTest); + CBaseEntity* FindEntityByClassname(CBaseEntity* pStartEntity, const char* szName); + CBaseEntity* FindEntityByName(CBaseEntity* pStartEntity, const char* szName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL, IEntityFindFilter* pFilter = NULL); + CBaseEntity* FindEntityByName(CBaseEntity* pStartEntity, string_t iszName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL, IEntityFindFilter* pFilter = NULL) + { + return FindEntityByName(pStartEntity, STRING(iszName), pSearchingEntity, pActivator, pCaller, pFilter); + } + CBaseEntity* FindEntityInSphere(CBaseEntity* pStartEntity, const Vector& vecCenter, float flRadius); + CBaseEntity* FindEntityByTarget(CBaseEntity* pStartEntity, const char* szName); + CBaseEntity* FindEntityByModel(CBaseEntity* pStartEntity, const char* szModelName); + CBaseEntity* FindEntityByOutputTarget(CBaseEntity* pStartEntity, string_t iTarget); + + CBaseEntity* FindEntityByNameNearest(const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityByNameWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityByClassnameNearest(const char* szName, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByClassnameNearest2D(const char* szName, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByClassnameWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByClassnameWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecMins, const Vector& vecMaxs); + + CBaseEntity* FindEntityGeneric(CBaseEntity* pStartEntity, const char* szName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityGenericWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityGenericNearest(const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + + CBaseEntity* FindEntityNearestFacing(const Vector& origin, const Vector& facing, float threshold); + CBaseEntity* FindEntityClassNearestFacing(const Vector& origin, const Vector& facing, float threshold, char* classname); + CBaseEntity* FindEntityByNetname(CBaseEntity* pStartEntity, const char* szModelName); + + CBaseEntity* FindEntityProcedural(const char* szName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + + CBaseEntity* FindEntityByClassnameFast(CBaseEntity* pStartEntity, string_t iszClassname); + CBaseEntity* FindEntityByClassnameNearestFast(string_t iszClassname, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByNameFast(CBaseEntity* pStartEntity, string_t iszName); + + CGlobalEntityList(); + +protected: + + virtual void OnAddEntity(IHandleEntity* pEnt, CBaseHandle handle); + virtual void OnRemoveEntity(IHandleEntity* pEnt, CBaseHandle handle); + +}; + +extern CGlobalEntityList gEntList; + + +inline CBaseHandle CGlobalEntityList::AddNetworkableEntity(IHandleEntity* pEnt, int index, int iForcedSerialNum) +{ + CBaseHandle h = CBaseEntityList::AddNetworkableEntity(pEnt, index, iForcedSerialNum); + UpdateName(pEnt, h); + return h; +} + +inline CBaseHandle CGlobalEntityList::AddNonNetworkableEntity(IHandleEntity* pEnt) +{ + CBaseHandle h = CBaseEntityList::AddNonNetworkableEntity(pEnt); + UpdateName(pEnt, h); + return h; +} + +inline edict_t* CGlobalEntityList::GetEdict(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetNetworkable()->GetEdict(); + else + return NULL; +} + +inline CBaseNetworkable* CGlobalEntityList::GetBaseNetworkable(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetNetworkable()->GetBaseNetworkable(); + else + return NULL; +} + +inline IServerNetworkable* CGlobalEntityList::GetServerNetworkable(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetNetworkable(); + else + return NULL; +} + +inline CBaseEntity* CGlobalEntityList::GetBaseEntity(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetBaseEntity(); + else + return NULL; +} + + +#if 0 + +template +inline bool FindEntityByName(const char* pszName, ENT_TYPE** ppResult) +{ + CBaseEntity* pBaseEntity = gEntList.FindEntityByName(NULL, pszName); + + if (pBaseEntity) + *ppResult = dynamic_cast(pBaseEntity); + else + *ppResult = NULL; + + return (*ppResult != NULL); +} + +template <> +inline bool FindEntityByName(const char* pszName, CBaseEntity** ppResult) +{ + *ppResult = gEntList.FindEntityByName(NULL, pszName); + return (*ppResult != NULL); +} + +template <> +inline bool FindEntityByName(const char* pszName, CAI_BaseNPC** ppResult) +{ + CBaseEntity* pBaseEntity = gEntList.FindEntityByName(NULL, pszName); + + if (pBaseEntity) + *ppResult = pBaseEntity->MyNPCPointer(); + else + *ppResult = NULL; + + return (*ppResult != NULL); +} +#endif +struct entitem_t +{ + EHANDLE hEnt; + struct entitem_t* pNext; + + static void* operator new(size_t stAllocateBlock); + static void* operator new(size_t stAllocateBlock, int nBlockUse, const char* pFileName, int nLine); + static void operator delete(void* pMem); + static void operator delete(void* pMem, int nBlockUse, const char* pFileName, int nLine) { operator delete(pMem); } +}; + +class CEntityList +{ +public: + CEntityList(); + ~CEntityList(); + + int m_iNumItems; + entitem_t* m_pItemList; + + void AddEntity(CBaseEntity*); + void DeleteEntity(CBaseEntity*); +}; + +enum notify_system_event_t +{ + NOTIFY_EVENT_TELEPORT = 0, + NOTIFY_EVENT_DESTROY, +}; + +struct notify_teleport_params_t +{ + Vector prevOrigin; + QAngle prevAngles; + bool physicsRotate; +}; + +struct notify_destroy_params_t +{ +}; + +struct notify_system_event_params_t +{ + union + { + const notify_teleport_params_t* pTeleport; + const notify_destroy_params_t* pDestroy; + }; + notify_system_event_params_t(const notify_teleport_params_t* pInTeleport) { pTeleport = pInTeleport; } + notify_system_event_params_t(const notify_destroy_params_t* pInDestroy) { pDestroy = pInDestroy; } +}; + + +abstract_class INotify +{ +public: + virtual void AddEntity(CBaseEntity * pNotify, CBaseEntity * pWatched) = 0; + + virtual void RemoveEntity(CBaseEntity* pNotify, CBaseEntity* pWatched) = 0; + + virtual void ReportNamedEvent(CBaseEntity* pEntity, const char* pEventName) = 0; + + virtual void ReportSystemEvent(CBaseEntity* pEntity, notify_system_event_t eventType, const notify_system_event_params_t& params) = 0; + + inline void ReportDestroyEvent(CBaseEntity* pEntity) + { + notify_destroy_params_t destroy; + ReportSystemEvent(pEntity, NOTIFY_EVENT_DESTROY, notify_system_event_params_t(&destroy)); + } + + inline void ReportTeleportEvent(CBaseEntity* pEntity, const Vector& prevOrigin, const QAngle& prevAngles, bool physicsRotate) + { + notify_teleport_params_t teleport; + teleport.prevOrigin = prevOrigin; + teleport.prevAngles = prevAngles; + teleport.physicsRotate = physicsRotate; + ReportSystemEvent(pEntity, NOTIFY_EVENT_TELEPORT, notify_system_event_params_t(&teleport)); + } + + virtual void ClearEntity(CBaseEntity* pNotify) = 0; +}; + +class IEntityListener +{ +public: + virtual void OnEntityCreated(CBaseEntity* pEntity) {}; + virtual void OnEntitySpawned(CBaseEntity* pEntity) {}; + virtual void OnEntityDeleted(CBaseEntity* pEntity) {}; +}; + +extern INotify* g_pNotify; + +void EntityTouch_Add(CBaseEntity* pEntity); +void EntityTouch_Remove(CBaseEntity* pEntity); +int AimTarget_ListCount(); +int AimTarget_ListCopy(CBaseEntity* pList[], int listMax); +CBaseEntity* AimTarget_ListElement(int iIndex); +void AimTarget_ForceRepopulateList(); + +void SimThink_EntityChanged(CBaseEntity* pEntity); +int SimThink_ListCount(); +int SimThink_ListCopy(CBaseEntity* pList[], int listMax); + +#endif +``` + +`SpyCustom/sdk/baseentity_shared.h`: + +```h +#ifndef BASEENTITY_SHARED_H +#define BASEENTITY_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +#define FCAP_MUST_SPAWN 0x00000001 +#define FCAP_ACROSS_TRANSITION 0x00000002 +#define FCAP_FORCE_TRANSITION 0x00000004 +#define FCAP_NOTIFY_ON_TRANSITION 0x00000008 + +#define FCAP_IMPULSE_USE 0x00000010 +#define FCAP_CONTINUOUS_USE 0x00000020 +#define FCAP_ONOFF_USE 0x00000040 +#define FCAP_DIRECTIONAL_USE 0x00000080 +#define FCAP_USE_ONGROUND 0x00000100 +#define FCAP_USE_IN_RADIUS 0x00000200 +#define FCAP_SAVE_NON_NETWORKABLE 0x00000400 + +#define FCAP_MASTER 0x10000000 +#define FCAP_WCEDIT_POSITION 0x40000000 +#define FCAP_DONT_SAVE 0x80000000 + + +#define NUM_PARENTATTACHMENT_BITS 6 + +#define VPHYSICS_MAX_OBJECT_LIST_COUNT 1024 + +enum InvalidatePhysicsBits_t +{ + POSITION_CHANGED = 0x1, + ANGLES_CHANGED = 0x2, + VELOCITY_CHANGED = 0x4, + ANIMATION_CHANGED = 0x8, +}; + + +#if defined( CLIENT_DLL ) +#include "c_baseentity.h" +#include "c_baseanimating.h" +#else +#include "baseentity.h" + +#ifdef HL2_EPISODIC +#include "info_darknessmode_lightsource.h" +#endif + +#endif + +#if !defined( NO_ENTITY_PREDICTION ) +inline bool CBaseEntity::IsPlayerSimulated(void) const +{ + return m_bIsPlayerSimulated; +} + +inline CBasePlayer* CBaseEntity::GetSimulatingPlayer(void) +{ + return m_hPlayerSimulationOwner; +} +#endif + +inline MoveType_t CBaseEntity::GetMoveType() const +{ + return (MoveType_t)(unsigned char)m_MoveType; +} + +inline MoveCollide_t CBaseEntity::GetMoveCollide() const +{ + return (MoveCollide_t)(unsigned char)m_MoveCollide; +} + +inline int CBaseEntity::GetCollisionGroup() const +{ + return m_CollisionGroup; +} + +inline int CBaseEntity::GetFlags(void) const +{ + return m_fFlags; +} + +inline bool CBaseEntity::IsAlive(void) +{ + return m_lifeState == LIFE_ALIVE; +} + +inline CBaseEntity* CBaseEntity::GetOwnerEntity() const +{ + return m_hOwnerEntity.Get(); +} + +inline CBaseEntity* CBaseEntity::GetEffectEntity() const +{ + return m_hEffectEntity.Get(); +} + +inline int CBaseEntity::GetPredictionRandomSeed(void) +{ + return m_nPredictionRandomSeed; +} + +inline CBasePlayer* CBaseEntity::GetPredictionPlayer(void) +{ + return m_pPredictionPlayer; +} + +inline void CBaseEntity::SetPredictionPlayer(CBasePlayer* player) +{ + m_pPredictionPlayer = player; +} + + +inline bool CBaseEntity::IsSimulatedEveryTick() const +{ + return m_bSimulatedEveryTick; +} + +inline bool CBaseEntity::IsAnimatedEveryTick() const +{ + return m_bAnimatedEveryTick; +} + +inline void CBaseEntity::SetSimulatedEveryTick(bool sim) +{ + if (m_bSimulatedEveryTick != sim) + { + m_bSimulatedEveryTick = sim; +#ifdef CLIENT_DLL + Interp_UpdateInterpolationAmounts(GetVarMapping()); +#endif + } +} + +inline void CBaseEntity::SetAnimatedEveryTick(bool anim) +{ + if (m_bAnimatedEveryTick != anim) + { + m_bAnimatedEveryTick = anim; +#ifdef CLIENT_DLL + Interp_UpdateInterpolationAmounts(GetVarMapping()); +#endif + } +} + +inline float CBaseEntity::GetAnimTime() const +{ + return m_flAnimTime; +} + +inline float CBaseEntity::GetSimulationTime() const +{ + return m_flSimulationTime; +} + +inline void CBaseEntity::SetAnimTime(float at) +{ + m_flAnimTime = at; +} + +inline void CBaseEntity::SetSimulationTime(float st) +{ + m_flSimulationTime = st; +} + +inline int CBaseEntity::GetEffects(void) const +{ + return m_fEffects; +} + +inline void CBaseEntity::RemoveEffects(int nEffects) +{ +#if !defined( CLIENT_DLL ) +#ifdef HL2_EPISODIC + if (nEffects & (EF_BRIGHTLIGHT | EF_DIMLIGHT)) + { + if (!IsPlayer()) + { + RemoveEntityFromDarknessCheck(this); + } + } +#endif +#endif + + m_fEffects &= ~nEffects; + if (nEffects & EF_NODRAW) + { +#ifndef CLIENT_DLL + NetworkProp()->MarkPVSInformationDirty(); + DispatchUpdateTransmitState(); +#else + UpdateVisibility(); +#endif + } +} + +inline void CBaseEntity::ClearEffects(void) +{ +#if !defined( CLIENT_DLL ) +#ifdef HL2_EPISODIC + if (m_fEffects & (EF_BRIGHTLIGHT | EF_DIMLIGHT)) + { + if (!IsPlayer()) + { + RemoveEntityFromDarknessCheck(this); + } + } +#endif +#endif + + m_fEffects = 0; +#ifndef CLIENT_DLL + DispatchUpdateTransmitState(); +#else + UpdateVisibility(); +#endif +} + +inline bool CBaseEntity::IsEffectActive(int nEffects) const +{ + return (m_fEffects & nEffects) != 0; +} + +#define BASEENTITY_MSG_REMOVE_DECALS 1 + +extern float k_flMaxEntityPosCoord; +extern float k_flMaxEntityEulerAngle; +extern float k_flMaxEntitySpeed; +extern float k_flMaxEntitySpinRate; + +inline bool IsEntityCoordinateReasonable(const vec_t c) +{ + float r = k_flMaxEntityPosCoord; + return c > -r && c < r; +} + +inline bool IsEntityPositionReasonable(const Vector& v) +{ + float r = k_flMaxEntityPosCoord; + return + v.x > -r && v.x < r&& + v.y > -r && v.y < r&& + v.z > -r && v.z < r; +} + +extern int CheckEntityVelocity(Vector& v); + +inline bool IsEntityQAngleReasonable(const QAngle& q) +{ + float r = k_flMaxEntityEulerAngle; + return + q.x > -r && q.x < r&& + q.y > -r && q.y < r&& + q.z > -r && q.z < r; +} + +inline bool IsEntityAngularVelocityReasonable(const Vector& q) +{ + float r = k_flMaxEntitySpinRate; + return + q.x > -r && q.x < r&& + q.y > -r && q.y < r&& + q.z > -r && q.z < r; +} + +inline bool IsEntityQAngleVelReasonable(const QAngle& q) +{ + float r = k_flMaxEntitySpinRate; + return + q.x > -r && q.x < r&& + q.y > -r && q.y < r&& + q.z > -r && q.z < r; +} + +extern bool CheckEmitReasonablePhysicsSpew(); + +#endif +``` + +`SpyCustom/sdk/basehandle.h`: + +```h +#ifndef BASEHANDLE_H +#define BASEHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "const.h" +#include "dbg.h" + + +class IHandleEntity; + + +class CBaseHandle +{ + friend class CBaseEntityList; + +public: + + CBaseHandle(); + CBaseHandle(const CBaseHandle& other); + CBaseHandle(unsigned long value); + CBaseHandle(int iEntry, int iSerialNumber); + + void Init(int iEntry, int iSerialNumber); + void Term(); + + 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) +{ + Assert(iEntry >= 0 && iEntry < NUM_ENT_ENTRIES); + Assert(iSerialNumber >= 0 && iSerialNumber < (1 << NUM_SERIAL_NUM_BITS)); + + m_Index = iEntry | (iSerialNumber << NUM_ENT_ENTRY_BITS); +} + +inline void CBaseHandle::Term() +{ + m_Index = INVALID_EHANDLE_INDEX; +} + +inline bool CBaseHandle::IsValid() const +{ + return m_Index != INVALID_EHANDLE_INDEX; +} + +inline int CBaseHandle::GetEntryIndex() const +{ + return m_Index & ENT_ENTRY_MASK; +} + +inline int CBaseHandle::GetSerialNumber() const +{ + return m_Index >> NUM_ENT_ENTRY_BITS; +} + +inline int CBaseHandle::ToInt() const +{ + return (int)m_Index; +} + +inline bool CBaseHandle::operator !=(const CBaseHandle& other) const +{ + return m_Index != other.m_Index; +} + +inline bool CBaseHandle::operator ==(const CBaseHandle& other) const +{ + return m_Index == other.m_Index; +} + +inline bool CBaseHandle::operator ==(const IHandleEntity* pEnt) const +{ + return Get() == pEnt; +} + +inline bool CBaseHandle::operator !=(const IHandleEntity* pEnt) const +{ + return Get() != pEnt; +} + +inline bool CBaseHandle::operator <(const CBaseHandle& other) const +{ + return m_Index < other.m_Index; +} + +inline bool CBaseHandle::operator <(const IHandleEntity* pEntity) const +{ + unsigned long otherIndex = (pEntity) ? pEntity->GetRefEHandle().m_Index : INVALID_EHANDLE_INDEX; + return m_Index < otherIndex; +} + +inline const CBaseHandle& CBaseHandle::operator=(const IHandleEntity* pEntity) +{ + return Set(pEntity); +} + +inline const CBaseHandle& CBaseHandle::Set(const IHandleEntity* pEntity) +{ + if (pEntity) + { + *this = pEntity->GetRefEHandle(); + } + else + { + m_Index = INVALID_EHANDLE_INDEX; + } + + return *this; +} + + +#endif +``` + +`SpyCustom/sdk/basetypes.h`: + +```h +#ifndef BASETYPES_H +#define BASETYPES_H + +#include "commonmacros.h" +#include "wchartypes.h" + +#ifdef _WIN32 +#pragma once +#endif + + + + +#define DLLExtTokenPaste(x) #x +#define DLLExtTokenPaste2(x) DLLExtTokenPaste(x) +#define DLL_EXT_STRING DLLExtTokenPaste2( _DLL_EXT ) + + + +#ifdef IN_XBOX_CODELINE +#define XBOX_CODELINE_ONLY() +#else +#define XBOX_CODELINE_ONLY() Error_Compiling_Code_Only_Valid_in_Xbox_Codeline +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +#ifdef POSIX +#include +#endif + +#define ExecuteNTimes( nTimes, x ) \ + { \ + static int __executeCount=0;\ + if ( __executeCount < nTimes )\ + { \ + x; \ + ++__executeCount; \ + } \ + } + + +#define ExecuteOnce( x ) ExecuteNTimes( 1, x ) + + +template +inline T AlignValue(T val, uintptr_t alignment) +{ + return (T)(((uintptr_t)val + alignment - 1) & ~(alignment - 1)); +} + + +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +#if !defined(M_PI) && !defined(HAVE_M_PI) +#define M_PI 3.14159265358979323846 +#endif + +#define COMPILETIME_MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#define COMPILETIME_MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#ifndef MIN +#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifndef MAX +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifdef __cplusplus + +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; +} + +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + + +#ifndef DONT_DEFINE_BOOL +typedef int BOOL; +#endif + +typedef int qboolean; +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned short word; +#ifdef _WIN32 +typedef wchar_t ucs2; +#else +typedef unsigned short ucs2; +#endif + +enum ThreeState_t +{ + TRS_FALSE, + TRS_TRUE, + TRS_NONE, +}; + +typedef float vec_t; + +#if defined(__GNUC__) +#define fpmin __builtin_fminf +#define fpmax __builtin_fmaxf +#elif !defined(_X360) +#define fpmin min +#define fpmax max +#endif + + + +inline unsigned long& FloatBits(vec_t& f) +{ + return *reinterpret_cast(&f); +} + +inline unsigned long const& FloatBits(vec_t const& f) +{ + return *reinterpret_cast(&f); +} + +inline vec_t BitsToFloat(unsigned long i) +{ + return *reinterpret_cast(&i); +} + +inline bool IsFinite(vec_t f) +{ + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +} + +inline unsigned long FloatAbsBits(vec_t f) +{ + return FloatBits(f) & 0x7FFFFFFF; +} + +#ifdef _MSC_VER +#ifndef _In_ +#define _In_ +#endif +extern "C" float fabsf(_In_ float); +#else +#include +#endif + +inline float FloatMakeNegative(vec_t f) +{ + return -fabsf(f); +} + +inline float FloatMakePositive(vec_t f) +{ + return fabsf(f); +} + +inline float FloatNegate(vec_t f) +{ + return -f; +} + + +#define FLOAT32_NAN_BITS (unsigned long)0x7FC00000 +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) + +#define VEC_T_NAN FLOAT32_NAN + + + +struct color24 +{ + byte r, g, b; +}; + +typedef struct color32_s +{ + bool operator!=(const struct color32_s& other) const; + + byte r, g, b, a; +} color32; + +inline bool color32::operator!=(const color32& other) const +{ + return r != other.r || g != other.g || b != other.b || a != other.a; +} + +struct colorVec +{ + unsigned r, g, b, a; +}; + + +#ifndef NOTE_UNUSED +#define NOTE_UNUSED(x) (void)(x) +#endif + +struct vrect_t +{ + int x, y, width, height; + vrect_t* pnext; +}; + + +struct Rect_t +{ + int x, y; + int width, height; +}; + + +struct interval_t +{ + float start; + float range; +}; + + +template< class HandleType > +class CBaseIntHandle +{ +public: + + inline bool operator==(const CBaseIntHandle& other) { return m_Handle == other.m_Handle; } + inline bool operator!=(const CBaseIntHandle& other) { return m_Handle != other.m_Handle; } + + inline HandleType GetHandleValue() { return m_Handle; } + inline void SetHandleValue(HandleType val) { m_Handle = val; } + + typedef HandleType HANDLE_TYPE; + +protected: + + HandleType m_Handle; +}; + +template< class DummyType > +class CIntHandle16 : public CBaseIntHandle< unsigned short > +{ +public: + inline CIntHandle16() {} + + static inline CIntHandle16 MakeHandle(HANDLE_TYPE val) + { + return CIntHandle16(val); + } + +protected: + inline CIntHandle16(HANDLE_TYPE val) + { + m_Handle = val; + } +}; + + +template< class DummyType > +class CIntHandle32 : public CBaseIntHandle< unsigned long > +{ +public: + inline CIntHandle32() {} + + static inline CIntHandle32 MakeHandle(HANDLE_TYPE val) + { + return CIntHandle32(val); + } + +protected: + inline CIntHandle32(HANDLE_TYPE val) + { + m_Handle = val; + } +}; + + +#define DECLARE_HANDLE_16BIT(name) typedef CIntHandle16< struct name##__handle * > name; +#define DECLARE_HANDLE_32BIT(name) typedef CIntHandle32< struct name##__handle * > name; + +#define DECLARE_POINTER_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#define FORWARD_DECLARE_HANDLE(name) typedef struct name##__ *name + +#if !defined(_STATIC_LINKED) && !defined(PUBLISH_DLL_SUBSYSTEM) +#define PUBLISH_DLL_SUBSYSTEM() +#endif + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define EXPAND_CONCAT(a,c) UID_CAT1(a,c) +#ifdef _MSC_VER +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__COUNTER__) +#else +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) +#endif + +#define DEFINE_ENUM_BITWISE_OPERATORS( Type ) \ + inline Type operator| ( Type a, Type b ) { return Type( int( a ) | int( b ) ); } \ + inline Type operator& ( Type a, Type b ) { return Type( int( a ) & int( b ) ); } \ + inline Type operator^ ( Type a, Type b ) { return Type( int( a ) ^ int( b ) ); } \ + inline Type operator<< ( Type a, int b ) { return Type( int( a ) << b ); } \ + inline Type operator>> ( Type a, int b ) { return Type( int( a ) >> b ); } \ + inline Type &operator|= ( Type &a, Type b ) { return a = a | b; } \ + inline Type &operator&= ( Type &a, Type b ) { return a = a & b; } \ + inline Type &operator^= ( Type &a, Type b ) { return a = a ^ b; } \ + inline Type &operator<<=( Type &a, int b ) { return a = a << b; } \ + inline Type &operator>>=( Type &a, int b ) { return a = a >> b; } \ + inline Type operator~( Type a ) { return Type( ~int( a ) ); } + +#define DEFINE_ENUM_INCREMENT_OPERATORS( Type ) \ + inline Type &operator++( Type &a ) { return a = Type( int( a ) + 1 ); } \ + inline Type &operator--( Type &a ) { return a = Type( int( a ) - 1 ); } \ + inline Type operator++( Type &a, int ) { Type t = a; ++a; return t; } \ + inline Type operator--( Type &a, int ) { Type t = a; --a; return t; } + + +#endif +``` + +`SpyCustom/sdk/baseviewport.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TEAMFORTRESSVIEWPORT_H +#define TEAMFORTRESSVIEWPORT_H + +// viewport interface for the rest of the dll +#include "iviewport.h" + +#include "vguitextwindow.h" +#include "commandmenu.h" + +#include "utlqueue.h" // a vector based queue template to manage our VGUI menu queue +#include "Frame.h" +#include "ISurface.h" +#include "igameevents.h" + +using namespace vgui; + +class IBaseFileSystem; +class IGameUIFuncs; +class IGameEventManager; + +//============================================================================== +class CBaseViewport : public vgui::EditablePanel, public IViewPort, public IGameEventListener2 +{ + DECLARE_CLASS_SIMPLE( CBaseViewport, vgui::EditablePanel ); + +public: + CBaseViewport(); + virtual ~CBaseViewport(); + + virtual IViewPortPanel* CreatePanelByName(const char *szPanelName); + virtual IViewPortPanel* FindPanelByName(const char *szPanelName); + virtual IViewPortPanel* GetActivePanel( void ); + virtual void RemoveAllPanels( void); + + virtual void ShowPanel( const char *pName, bool state ); + virtual void ShowPanel( IViewPortPanel* pPanel, bool state ); + virtual bool AddNewPanel( IViewPortPanel* pPanel, char const *pchDebugName ); + virtual void CreateDefaultPanels( void ); + virtual void UpdateAllPanels( void ); + virtual void PostMessageToPanel( const char *pName, KeyValues *pKeyValues ); + + virtual void Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 *pGameEventManager ); + virtual void SetParent(vgui::VPANEL parent); + + virtual void ReloadScheme(const char *fromFile); + virtual void ActivateClientUI(); + virtual void HideClientUI(); + virtual bool AllowedToPrintText( void ); + +#ifndef _XBOX + virtual int GetViewPortScheme() { return m_pBackGround->GetScheme(); } + virtual VPANEL GetViewPortPanel() { return m_pBackGround->GetVParent(); } +#endif + virtual AnimationController *GetAnimationController() { return m_pAnimController; } + + virtual void ShowBackGround(bool bShow) + { +#ifndef _XBOX + m_pBackGround->SetVisible( bShow ); +#endif + } + + virtual int GetDeathMessageStartHeight( void ); + + // virtual void ChatInputPosition( int *x, int *y ); + +public: // IGameEventListener: + virtual void FireGameEvent( IGameEvent * event); + + +protected: + + bool LoadHudAnimations( void ); + +#ifndef _XBOX + class CBackGroundPanel : public vgui::Frame + { + private: + typedef vgui::Frame BaseClass; + public: + CBackGroundPanel( vgui::Panel *parent) : Frame( parent, "ViewPortBackGround" ) + { + SetScheme("ClientScheme"); + + SetTitleBarVisible( false ); + SetMoveable(false); + SetSizeable(false); + SetProportional(true); + } + private: + + virtual void ApplySchemeSettings(IScheme *pScheme) + { + BaseClass::ApplySchemeSettings(pScheme); + SetBgColor(pScheme->GetColor("ViewportBG", Color( 0,0,0,0 ) )); + } + + virtual void PerformLayout() + { + int w,h; + GetHudSize(w, h); + + // fill the screen + SetBounds(0,0,w,h); + + BaseClass::PerformLayout(); + } + + virtual void OnMousePressed(MouseCode code) { }// don't respond to mouse clicks + virtual vgui::VPANEL IsWithinTraverse( int x, int y, bool traversePopups ) + { + return ( vgui::VPANEL )0; + } + + }; +#endif +protected: + + virtual void Paint(); + virtual void OnThink(); + virtual void OnScreenSizeChanged(int iOldWide, int iOldTall); + void PostMessageToPanel( IViewPortPanel* pPanel, KeyValues *pKeyValues ); + +protected: + IGameUIFuncs* m_GameuiFuncs; // for key binding details + IGameEventManager2* m_GameEventManager; +#ifndef _XBOX + CBackGroundPanel *m_pBackGround; +#endif + CUtlVector m_Panels; + + bool m_bHasParent; // Used to track if child windows have parents or not. + bool m_bInitialized; + IViewPortPanel *m_pActivePanel; + IViewPortPanel *m_pLastActivePanel; + vgui::HCursor m_hCursorNone; + vgui::AnimationController *m_pAnimController; + int m_OldSize[2]; +}; + + +#endif +``` + +`SpyCustom/sdk/beam_flags.h`: + +```h +#if !defined( BEAM_FLAGS_H ) +#define BEAM_FLAGS_H +#ifdef _WIN32 +#pragma once +#endif + +enum +{ + FBEAM_STARTENTITY = 0x00000001, + FBEAM_ENDENTITY = 0x00000002, + FBEAM_FADEIN = 0x00000004, + FBEAM_FADEOUT = 0x00000008, + FBEAM_SINENOISE = 0x00000010, + FBEAM_SOLID = 0x00000020, + FBEAM_SHADEIN = 0x00000040, + FBEAM_SHADEOUT = 0x00000080, + FBEAM_ONLYNOISEONCE = 0x00000100, + FBEAM_NOTILE = 0x00000200, + FBEAM_USE_HITBOXES = 0x00000400, + FBEAM_STARTVISIBLE = 0x00000800, + FBEAM_ENDVISIBLE = 0x00001000, + FBEAM_ISACTIVE = 0x00002000, + FBEAM_FOREVER = 0x00004000, + FBEAM_HALOBEAM = 0x00008000, + FBEAM_REVERSED = 0x00010000, + NUM_BEAM_FLAGS = 17 +}; + +#endif +``` + +`SpyCustom/sdk/bitbuf.h`: + +```h +#ifndef BITBUF_H +#define BITBUF_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib.h" +#include "vector.h" +#include "basetypes.h" + +#if _DEBUG +#define BITBUF_INLINE inline +#else +#define BITBUF_INLINE FORCEINLINE +#endif + +class Vector; +class QAngle; + +typedef enum +{ + BITBUFERROR_VALUE_OUT_OF_RANGE = 0, + BITBUFERROR_BUFFER_OVERRUN, + + 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 + + +void SetBitBufErrorHandler(BitBufErrorHandler fn); + + +inline int BitByte(int bits) +{ + return (bits + 7) >> 3; +} + +namespace bitbuf +{ + inline uint32 ZigZagEncode32(int32 n) + { + return(n << 1) ^ (n >> 31); + } + + inline int32 ZigZagDecode32(uint32 n) + { + return(n >> 1) ^ -static_cast(n & 1); + } + + inline uint64 ZigZagEncode64(int64 n) + { + return(n << 1) ^ (n >> 63); + } + + inline int64 ZigZagDecode64(uint64 n) + { + return(n >> 1) ^ -static_cast(n & 1); + } + + const int kMaxVarintBytes = 10; + const int kMaxVarint32Bytes = 5; +} + +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); + + +public: + + void SeekToBit(int bitPos); + + +public: + + 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 data); + void WriteVarInt64(uint64 data); + void WriteSignedVarInt32(int32 data); + void WriteSignedVarInt64(int64 data); + int ByteSizeVarInt32(uint32 data); + int ByteSizeVarInt64(uint64 data); + int ByteSizeSignedVarInt32(int32 data); + int ByteSizeSignedVarInt64(int64 data); + + bool WriteBitsFromBuffer(class bf_read* pIn, int nBits); + + void WriteBitAngle(float fAngle, int numbits); + void WriteBitCoord(const float f); + void WriteBitCoordMP(const float f, bool bIntegral, bool bLowPrecision); + void WriteBitFloat(float val); + void WriteBitVec3Coord(const Vector& fa); + void WriteBitNormal(float f); + void WriteBitVec3Normal(const Vector& fa); + void WriteBitAngles(const QAngle& fa); + + +public: + + void WriteChar(int val); + void WriteByte(int val); + void WriteShort(int val); + void WriteWord(int val); + void WriteLong(long val); + void WriteLongLong(int64 val); + void WriteFloat(float val); + bool WriteBytes(const void* pBuf, int nBytes); + + bool WriteString(const char* pStr); + + +public: + + 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* RESTRICT m_pData; + int m_nDataBytes; + int m_nDataBits; + + int m_iCurBit; + +private: + + bool m_bOverflow; + + bool m_bAssertOnOverflow; + const char* m_pDebugName; +}; + + +inline int bf_write::GetNumBytesWritten() const +{ + return BitByte(m_iCurBit); +} + +inline int bf_write::GetNumBitsWritten() const +{ + return m_iCurBit; +} + +inline int bf_write::GetMaxNumBits() +{ + return m_nDataBits; +} + +inline int bf_write::GetNumBitsLeft() +{ + return m_nDataBits - m_iCurBit; +} + +inline int bf_write::GetNumBytesLeft() +{ + return GetNumBitsLeft() >> 3; +} + +inline unsigned char* bf_write::GetData() +{ + return (unsigned char*)m_pData; +} + +inline const unsigned char* bf_write::GetData() const +{ + return (unsigned char*)m_pData; +} + +BITBUF_INLINE bool bf_write::CheckForOverflow(int nBits) +{ + if (m_iCurBit + nBits > m_nDataBits) + { + SetOverflowFlag(); + CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); + } + + return m_bOverflow; +} + +BITBUF_INLINE void bf_write::SetOverflowFlag() +{ +#ifdef DBGFLAG_ASSERT + if (m_bAssertOnOverflow) + { + Assert(false); + } +#endif + m_bOverflow = true; +} + +BITBUF_INLINE void bf_write::WriteOneBitNoCheck(int nValue) +{ +#if __i386__ + if (nValue) + m_pData[m_iCurBit >> 5] |= 1u << (m_iCurBit & 31); + else + m_pData[m_iCurBit >> 5] &= ~(1u << (m_iCurBit & 31)); +#else + extern unsigned long g_LittleBits[32]; + if (nValue) + m_pData[m_iCurBit >> 5] |= g_LittleBits[m_iCurBit & 31]; + else + m_pData[m_iCurBit >> 5] &= ~g_LittleBits[m_iCurBit & 31]; +#endif + + ++m_iCurBit; +} + +inline void bf_write::WriteOneBit(int nValue) +{ + if (m_iCurBit >= m_nDataBits) + { + SetOverflowFlag(); + CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); + return; + } + WriteOneBitNoCheck(nValue); +} + + +inline void bf_write::WriteOneBitAt(int iBit, int nValue) +{ + if (iBit >= m_nDataBits) + { + SetOverflowFlag(); + CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); + return; + } + +#if __i386__ + if (nValue) + m_pData[iBit >> 5] |= 1u << (iBit & 31); + else + m_pData[iBit >> 5] &= ~(1u << (iBit & 31)); +#else + extern unsigned long g_LittleBits[32]; + if (nValue) + m_pData[iBit >> 5] |= g_LittleBits[iBit & 31]; + else + m_pData[iBit >> 5] &= ~g_LittleBits[iBit & 31]; +#endif +} + +BITBUF_INLINE void bf_write::WriteUBitLong(unsigned int curData, int numbits, bool bCheckRange) RESTRICT +{ +#ifdef _DEBUG + if (bCheckRange && numbits < 32) + { + if (curData >= (unsigned long)(1 << numbits)) + { + CallErrorHandler(BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName()); + } + } + Assert(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; + + Assert((iDWord * 4 + sizeof(long)) <= (unsigned int)m_nDataBytes); + unsigned long* RESTRICT pOut = &m_pData[iDWord]; + + curData = (curData << iCurBitMasked) | (curData >> (32 - iCurBitMasked)); + + unsigned int temp = 1 << (numbits - 1); + unsigned int mask1 = (temp * 2 - 1) << iCurBitMasked; + unsigned int mask2 = (temp - 1) >> (31 - iCurBitMasked); + + int i = mask2 & 1; + unsigned long dword1 = LoadLittleDWord(pOut, 0); + unsigned long dword2 = LoadLittleDWord(pOut, i); + + dword1 ^= (mask1 & (curData ^ dword1)); + dword2 ^= (mask2 & (curData ^ dword2)); + + StoreLittleDWord(pOut, i, dword2); + StoreLittleDWord(pOut, 0, dword1); +} + +BITBUF_INLINE void bf_write::WriteUBitVar(unsigned int data) +{ + 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); + } +} + +BITBUF_INLINE void bf_write::WriteBitFloat(float val) +{ + long intVal; + + Assert(sizeof(long) == sizeof(float)); + Assert(sizeof(float) == 4); + + intVal = *((long*)&val); + WriteUBitLong(intVal, 32); +} + +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() + { + 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(const void* pData, int nBytes, int nBits = -1); + + + bf_read(const void* pData, int nBytes, int nBits = -1) + { + m_bAssertOnOverflow = true; + StartReading(pData, nBytes, 0, nBits); + } + + //bf_read(const char* pDebugName, const void* pData, int nBytes, int nBits = -1); + + + bf_read(const char* pDebugName, const void* pData, int nBytes, int nBits) + { + m_bAssertOnOverflow = true; + m_pDebugName = pDebugName; + StartReading(pData, nBytes, 0, nBits); + } + + 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); + + +public: + + int ReadOneBit(); + + +protected: + + unsigned int CheckReadUBitLong(int numbits); + int ReadOneBitNoCheck(); + bool CheckForOverflow(int nBits); + + +public: + + const unsigned char* GetBasePointer() { return m_pData; } + + BITBUF_INLINE int TotalBytesAvailable(void) const + { + return m_nDataBytes; + } + + inline bool 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 ReadVarInt32(); + uint64 ReadVarInt64(); + int32 ReadSignedVarInt32(); + int64 ReadSignedVarInt64(); + + unsigned int ReadBitLong(int numbits, bool bSigned); + + float ReadBitCoord(); + float ReadBitCoordMP(bool bIntegral, bool bLowPrecision); + float ReadBitFloat(); + float ReadBitNormal(); + void ReadBitVec3Coord(Vector& fa); + void ReadBitVec3Normal(Vector& fa); + void ReadBitAngles(QAngle& fa); + + unsigned int ReadBitCoordBits(); + unsigned int ReadBitCoordMPBits(bool bIntegral, bool bLowPrecision); + +public: + + BITBUF_INLINE int ReadChar() { return (char)ReadUBitLong(8); } + BITBUF_INLINE int ReadByte() { return ReadUBitLong(8); } + BITBUF_INLINE int ReadShort() { return (short)ReadUBitLong(16); } + BITBUF_INLINE int ReadWord() { return ReadUBitLong(16); } + BITBUF_INLINE long ReadLong() { return ReadUBitLong(32); } + int64 ReadLongLong(); + float ReadFloat(); + bool ReadBytes(void* pOut, int nBytes); + + 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; + +public: + int GetNumBytesLeft(); + int GetNumBytesRead(); + int GetNumBitsLeft(); + int GetNumBitsRead() const; + + inline bool IsOverflowed() const { return m_bOverflow; } + + inline bool Seek(int iBit); + inline bool SeekRelative(int iBitDelta); + + void SetOverflowFlag(); + +public: + + const unsigned char* RESTRICT m_pData; + int m_nDataBytes; + int m_nDataBits; + + int m_iCurBit; + + +private: + bool m_bOverflow; + + bool m_bAssertOnOverflow; + + const char* m_pDebugName; +}; + +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; + } +} + +inline bool bf_read::SeekRelative(int iBitDelta) +{ + return Seek(m_iCurBit + iBitDelta); +} + +inline bool bf_read::CheckForOverflow(int nBits) +{ + if (m_iCurBit + nBits > m_nDataBits) + { + SetOverflowFlag(); + CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); + } + + return m_bOverflow; +} + +inline int bf_read::ReadOneBitNoCheck() +{ +#if VALVE_LITTLE_ENDIAN + unsigned int value = ((unsigned long* RESTRICT)m_pData)[m_iCurBit >> 5] >> (m_iCurBit & 31); +#else + unsigned char value = m_pData[m_iCurBit >> 3] >> (m_iCurBit & 7); +#endif + ++m_iCurBit; + return value & 1; +} + +inline int bf_read::ReadOneBit() +{ + if (GetNumBitsLeft() <= 0) + { + SetOverflowFlag(); + CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); + return 0; + } + return ReadOneBitNoCheck(); +} + +inline float bf_read::ReadBitFloat() +{ + union { uint32 u; float f; } c = { ReadUBitLong(32) }; + return c.f; +} + +BITBUF_INLINE unsigned int bf_read::ReadUBitVar() +{ + unsigned int sixbits = ReadUBitLong(6); + unsigned int encoding = sixbits & 3; + if (encoding) + { + return ReadUBitVarInternal(encoding); + } + return sixbits >> 2; +} + +BITBUF_INLINE void bf_read::SetOverflowFlag() +{ + if (m_bAssertOnOverflow) + { + Assert(false); + } + + m_bOverflow = true; +} + +BITBUF_INLINE unsigned int bf_read::ReadUBitLong(int numbits) RESTRICT +{ + Assert(numbits > 0 && numbits <= 32); + + if (GetNumBitsLeft() < numbits) + { + m_iCurBit = m_nDataBits; + SetOverflowFlag(); + CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName()); + return 0; + } + + unsigned int iStartBit = m_iCurBit & 31u; + int iLastBit = m_iCurBit + numbits - 1; + unsigned int iWordOffset1 = m_iCurBit >> 5; + unsigned int iWordOffset2 = iLastBit >> 5; + m_iCurBit += numbits; + +#if __i386__ + unsigned int bitmask = (2 << (numbits - 1)) - 1; +#else + extern unsigned long g_ExtraMasks[33]; + unsigned int bitmask = g_ExtraMasks[numbits]; +#endif + + unsigned int dw1 = LoadLittleDWord((unsigned long* RESTRICT)m_pData, iWordOffset1) >> iStartBit; + unsigned int dw2 = LoadLittleDWord((unsigned long* RESTRICT)m_pData, iWordOffset2) << (32 - iStartBit); + + return (dw1 | dw2) & bitmask; +} + +BITBUF_INLINE int bf_read::CompareBits(bf_read* RESTRICT other, int numbits) RESTRICT +{ + return (ReadUBitLong(numbits) != other->ReadUBitLong(numbits)); +} + + + +inline bool bf_read::ReadString(char* pStr, int maxLen, bool bLine, int* pOutNumChars) +{ + Assert(maxLen != 0); + + bool bTooSmall = false; + int iChar = 0; + while (1) + { + char val = ReadChar(); + + //if (val == '\"') break; + + if (val == 0) + break; + else if (bLine && val == '\n') + break; + + if (iChar < (maxLen - 1)) + { + pStr[iChar] = val; + ++iChar; + } + else + { + bTooSmall = true; + } + } + + // Make sure it's null-terminated. + Assert(iChar < maxLen); + pStr[iChar] = 0; + + if (pOutNumChars) + *pOutNumChars = iChar; + + return !IsOverflowed() && !bTooSmall; +} + + +inline bool bf_read::ReadBits(void* pOutData, int nBits) +{ +#if defined( BB_PROFILING ) + VPROF("bf_write::ReadBits"); +#endif + + unsigned char* pOut = (unsigned char*)pOutData; + int nBitsLeft = nBits; + + + // Get output dword-aligned. + while (((unsigned long)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 the remaining bytes. + while (nBitsLeft >= 8) + { + *pOut = ReadUBitLong(8); + ++pOut; + nBitsLeft -= 8; + } + + // Read the remaining bits. + if (nBitsLeft) + { + *pOut = ReadUBitLong(nBitsLeft); + } + + return !IsOverflowed(); +} + +inline bool bf_read::ReadBytes(void* pOut, int nBytes) +{ + return ReadBits(pOut, nBytes << 3); +} + +inline void bf_read::StartReading(const void* pData, int nBytes, int iStartBit, int nBits) +{ + // Make sure we're dword aligned. + Assert(((unsigned long)pData & 3) == 0); + + m_pData = (unsigned char*)pData; + m_nDataBytes = nBytes; + + if (nBits == -1) + { + m_nDataBits = m_nDataBytes << 3; + } + else + { + Assert(nBits <= nBytes * 8); + m_nDataBits = nBits; + } + + m_iCurBit = iStartBit; + m_bOverflow = false; +} + +#endif +``` + +`SpyCustom/sdk/bittools.h`: + +```h +#ifndef BITTOOLS_H +#define BITTOOLS_H +#ifdef _WIN32 +#pragma once +#endif + +namespace bittools +{ + template + struct RecurseBit + { + enum { result = RecurseBit::result }; + }; + + template + struct RecurseBit<0, C> + { + enum { result = C }; + }; + + template + struct RecursePow2 + { + enum { result = RecursePow2::result }; + }; + + template + struct RecursePow2<0, C> + { + enum { result = C }; + }; + +} + +#define ROUND_TO_POWER_OF_2( n ) ( bittools::RecursePow2< (n) - 1 >::result ) +#define MINIMUM_BITS_NEEDED( n ) ( bittools::RecurseBit< (n) - 1 >::result ) + +#endif +``` + +`SpyCustom/sdk/bitvec.h`: + +```h +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "dbg.h" +#include "basetypes.h" + + +class CBitVecAccessor +{ +public: + CBitVecAccessor(uint32* pDWords, int iBit); + + void operator=(int val); + operator uint32(); + +private: + uint32* m_pDWords; + int m_iBit; +}; + + +#define LOG2_BITS_PER_INT 5 +#define BITS_PER_INT 32 + +#if _WIN32 && !defined(_X360) +#include +#pragma intrinsic(_BitScanForward) +#endif + +inline int FirstBitInWord(unsigned int elem, int offset) +{ +#if _WIN32 + if (!elem) + return -1; +#if defined( _X360 ) + unsigned int mask = elem - 1; + unsigned int comp = ~elem; + elem = mask & comp; + return (32 - _CountLeadingZeros(elem)) + offset; +#else + unsigned long out; + _BitScanForward(&out, elem); + return out + offset; +#endif + +#else + static unsigned firstBitLUT[256] = + { + 0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + }; + unsigned elemByte; + + elemByte = (elem & 0xFF); + if (elemByte) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if (elemByte) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if (elemByte) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if (elemByte) + return offset + firstBitLUT[elemByte]; + + return -1; +#endif +} + +inline unsigned GetEndMask(int numBits) +{ + static unsigned bitStringEndMasks[] = + { + 0xffffffff, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + }; + + return bitStringEndMasks[numBits % BITS_PER_INT]; +} + + +inline int GetBitForBitnum(int bitNum) +{ + static int bitsForBitnum[] = + { + (1 << 0), + (1 << 1), + (1 << 2), + (1 << 3), + (1 << 4), + (1 << 5), + (1 << 6), + (1 << 7), + (1 << 8), + (1 << 9), + (1 << 10), + (1 << 11), + (1 << 12), + (1 << 13), + (1 << 14), + (1 << 15), + (1 << 16), + (1 << 17), + (1 << 18), + (1 << 19), + (1 << 20), + (1 << 21), + (1 << 22), + (1 << 23), + (1 << 24), + (1 << 25), + (1 << 26), + (1 << 27), + (1 << 28), + (1 << 29), + (1 << 30), + (1 << 31), + }; + + return bitsForBitnum[(bitNum) & (BITS_PER_INT - 1)]; +} + +inline int GetBitForBitnumByte(int bitNum) +{ + static int bitsForBitnum[] = + { + (1 << 0), + (1 << 1), + (1 << 2), + (1 << 3), + (1 << 4), + (1 << 5), + (1 << 6), + (1 << 7), + }; + + return bitsForBitnum[bitNum & 7]; +} + +inline int CalcNumIntsForBits(int numBits) { return (numBits + (BITS_PER_INT - 1)) / BITS_PER_INT; } + +#ifdef _X360 +#define BitVec_Bit( bitNum ) GetBitForBitnum( bitNum ) +#define BitVec_BitInByte( bitNum ) GetBitForBitnumByte( bitNum ) +#else +#define BitVec_Bit( bitNum ) ( 1 << ( (bitNum) & (BITS_PER_INT-1) ) ) +#define BitVec_BitInByte( bitNum ) ( 1 << ( (bitNum) & 7 ) ) +#endif +#define BitVec_Int( bitNum ) ( (bitNum) >> LOG2_BITS_PER_INT ) + + +template +class CBitVecT : public BASE_OPS +{ +public: + CBitVecT(); + CBitVecT(int numBits); + + void Init(int val = 0); + + CBitVecAccessor operator[](int i); + + void And(const CBitVecT& andStr, CBitVecT* out) const; + void Or(const CBitVecT& orStr, CBitVecT* out) const; + void Xor(const CBitVecT& orStr, CBitVecT* out) const; + + void Not(CBitVecT* out) const; + + void CopyTo(CBitVecT* out) const; + void Copy(const CBitVecT& other, int nBits = -1); + bool Compare(const CBitVecT& other, int nBits = -1) const; + + bool IsAllClear(void) const; + bool IsAllSet(void) const; + + uint32 Get(uint32 bitNum) const; + bool IsBitSet(int bitNum) const; + void Set(int bitNum); + void Set(int bitNum, bool bNewVal); + void Clear(int bitNum); + + bool TestAndSet(int bitNum); + + void Set(uint32 offset, uint32 mask); + void Clear(uint32 offset, uint32 mask); + uint32 Get(uint32 offset, uint32 mask); + + void SetAll(void); + void ClearAll(void); + + uint32 GetDWord(int i) const; + void SetDWord(int i, uint32 val); + + CBitVecT& operator=(const CBitVecT& other) { other.CopyTo(this); return *this; } + bool operator==(const CBitVecT& other) { return Compare(other); } + bool operator!=(const CBitVecT& other) { return !operator==(other); } + + static void GetOffsetMaskForBit(uint32 bitNum, uint32* pOffset, uint32* pMask) { *pOffset = BitVec_Int(bitNum); *pMask = BitVec_Bit(bitNum); } +}; + +template +class CVarBitVecBase +{ +public: + bool IsFixedSize() const { return false; } + int GetNumBits(void) const { return m_numBits; } + void Resize(int numBits, bool bClearAll = false); + + int GetNumDWords() const { return m_numInts; } + uint32* Base() { return m_pInt; } + const uint32* Base() const { return m_pInt; } + + void Attach(uint32* pBits, int numBits); + bool Detach(uint32** ppBits, int* pNumBits); + + int FindNextSetBit(int iStartBit) const; + +protected: + CVarBitVecBase(); + CVarBitVecBase(int numBits); + CVarBitVecBase(const CVarBitVecBase& from); + CVarBitVecBase& operator=(const CVarBitVecBase& from); + ~CVarBitVecBase(void); + + void ValidateOperand(const CVarBitVecBase& operand) const { Assert(GetNumBits() == operand.GetNumBits()); } + + unsigned GetEndMask() const { return ::GetEndMask(GetNumBits()); } + +private: + + BITCOUNTTYPE m_numBits; + BITCOUNTTYPE m_numInts; + uint32 m_iBitStringStorage; + uint32* m_pInt; + + void AllocInts(int numInts); + void ReallocInts(int numInts); + void FreeInts(void); +}; + +template struct BitCountToEndMask_t { }; +template <> struct BitCountToEndMask_t< 0> { enum { MASK = 0xffffffff }; }; +template <> struct BitCountToEndMask_t< 1> { enum { MASK = 0x00000001 }; }; +template <> struct BitCountToEndMask_t< 2> { enum { MASK = 0x00000003 }; }; +template <> struct BitCountToEndMask_t< 3> { enum { MASK = 0x00000007 }; }; +template <> struct BitCountToEndMask_t< 4> { enum { MASK = 0x0000000f }; }; +template <> struct BitCountToEndMask_t< 5> { enum { MASK = 0x0000001f }; }; +template <> struct BitCountToEndMask_t< 6> { enum { MASK = 0x0000003f }; }; +template <> struct BitCountToEndMask_t< 7> { enum { MASK = 0x0000007f }; }; +template <> struct BitCountToEndMask_t< 8> { enum { MASK = 0x000000ff }; }; +template <> struct BitCountToEndMask_t< 9> { enum { MASK = 0x000001ff }; }; +template <> struct BitCountToEndMask_t<10> { enum { MASK = 0x000003ff }; }; +template <> struct BitCountToEndMask_t<11> { enum { MASK = 0x000007ff }; }; +template <> struct BitCountToEndMask_t<12> { enum { MASK = 0x00000fff }; }; +template <> struct BitCountToEndMask_t<13> { enum { MASK = 0x00001fff }; }; +template <> struct BitCountToEndMask_t<14> { enum { MASK = 0x00003fff }; }; +template <> struct BitCountToEndMask_t<15> { enum { MASK = 0x00007fff }; }; +template <> struct BitCountToEndMask_t<16> { enum { MASK = 0x0000ffff }; }; +template <> struct BitCountToEndMask_t<17> { enum { MASK = 0x0001ffff }; }; +template <> struct BitCountToEndMask_t<18> { enum { MASK = 0x0003ffff }; }; +template <> struct BitCountToEndMask_t<19> { enum { MASK = 0x0007ffff }; }; +template <> struct BitCountToEndMask_t<20> { enum { MASK = 0x000fffff }; }; +template <> struct BitCountToEndMask_t<21> { enum { MASK = 0x001fffff }; }; +template <> struct BitCountToEndMask_t<22> { enum { MASK = 0x003fffff }; }; +template <> struct BitCountToEndMask_t<23> { enum { MASK = 0x007fffff }; }; +template <> struct BitCountToEndMask_t<24> { enum { MASK = 0x00ffffff }; }; +template <> struct BitCountToEndMask_t<25> { enum { MASK = 0x01ffffff }; }; +template <> struct BitCountToEndMask_t<26> { enum { MASK = 0x03ffffff }; }; +template <> struct BitCountToEndMask_t<27> { enum { MASK = 0x07ffffff }; }; +template <> struct BitCountToEndMask_t<28> { enum { MASK = 0x0fffffff }; }; +template <> struct BitCountToEndMask_t<29> { enum { MASK = 0x1fffffff }; }; +template <> struct BitCountToEndMask_t<30> { enum { MASK = 0x3fffffff }; }; +template <> struct BitCountToEndMask_t<31> { enum { MASK = 0x7fffffff }; }; + +template +class CFixedBitVecBase +{ +public: + bool IsFixedSize() const { return true; } + int GetNumBits(void) const { return NUM_BITS; } + void Resize(int numBits, bool bClearAll = false) { Assert(numBits == NUM_BITS); if (bClearAll) Plat_FastMemset(m_Ints, 0, NUM_INTS * sizeof(uint32)); } + + int GetNumDWords() const { return NUM_INTS; } + uint32* Base() { return m_Ints; } + const uint32* Base() const { return m_Ints; } + + int FindNextSetBit(int iStartBit) const; + +protected: + CFixedBitVecBase() {} + CFixedBitVecBase(int numBits) { Assert(numBits == NUM_BITS); } + + void ValidateOperand(const CFixedBitVecBase& operand) const { } + +public: + unsigned GetEndMask() const { return static_cast(BitCountToEndMask_t::MASK); } + +private: + enum + { + NUM_INTS = (NUM_BITS + (BITS_PER_INT - 1)) / BITS_PER_INT + }; + + uint32 m_Ints[(NUM_BITS + (BITS_PER_INT - 1)) / BITS_PER_INT]; +}; + +class CVarBitVec : public CBitVecT< CVarBitVecBase > +{ +public: + CVarBitVec() + { + } + + CVarBitVec(int numBits) + : CBitVecT< CVarBitVecBase >(numBits) + { + } +}; + +class CLargeVarBitVec : public CBitVecT< CVarBitVecBase > +{ +public: + CLargeVarBitVec() + { + } + + CLargeVarBitVec(int numBits) + : CBitVecT< CVarBitVecBase >(numBits) + { + } +}; + +template < int NUM_BITS > +class CBitVec : public CBitVecT< CFixedBitVecBase > +{ +public: + CBitVec() + { + } + + CBitVec(int numBits) + : CBitVecT< CFixedBitVecBase >(numBits) + { + } +}; + + +typedef CBitVec<32> CDWordBitVec; + +template +inline CVarBitVecBase::CVarBitVecBase() +{ + Plat_FastMemset(this, 0, sizeof(*this)); +} + +template +inline CVarBitVecBase::CVarBitVecBase(int numBits) +{ + Assert(numBits); + m_numBits = numBits; + + m_numInts = CalcNumIntsForBits(numBits); + m_pInt = NULL; + AllocInts(m_numInts); +} + +template +inline CVarBitVecBase::CVarBitVecBase(const CVarBitVecBase& from) +{ + if (from.m_numInts) + { + m_numBits = from.m_numBits; + m_numInts = from.m_numInts; + m_pInt = NULL; + AllocInts(m_numInts); + memcpy(m_pInt, from.m_pInt, m_numInts * sizeof(int)); + } + else + memset(this, 0, sizeof(*this)); +} + +template +inline CVarBitVecBase& CVarBitVecBase::operator=(const CVarBitVecBase& from) +{ + Resize(from.GetNumBits()); + if (m_pInt) + memcpy(m_pInt, from.m_pInt, m_numInts * sizeof(int)); + return (*this); +} + +template +inline CVarBitVecBase::~CVarBitVecBase(void) +{ + FreeInts(); +} + +template +inline void CVarBitVecBase::Attach(uint32* pBits, int numBits) +{ + FreeInts(); + m_numBits = numBits; + m_numInts = CalcNumIntsForBits(numBits); + if (m_numInts > 1) + { + m_pInt = pBits; + } + else + { + m_iBitStringStorage = *pBits; + m_pInt = &m_iBitStringStorage; + free(pBits); + } +} + +template +inline bool CVarBitVecBase::Detach(uint32** ppBits, int* pNumBits) +{ + if (!m_numBits) + { + return false; + } + + *pNumBits = m_numBits; + if (m_numInts > 1) + { + *ppBits = m_pInt; + } + else + { + *ppBits = (uint32*)malloc(sizeof(uint32)); + **ppBits = m_iBitStringStorage; + free(m_pInt); + } + + memset(this, 0, sizeof(*this)); + return true; +} + +template +inline CBitVecT::CBitVecT() +{ + COMPILE_TIME_ASSERT(sizeof(int) == 4); + + ClearAll(); +} + +template +inline CBitVecT::CBitVecT(int numBits) + : BASE_OPS(numBits) +{ + COMPILE_TIME_ASSERT(sizeof(int) == 4); + + ClearAll(); +} + +template +inline CBitVecAccessor CBitVecT::operator[](int i) +{ + Assert(i >= 0 && i < this->GetNumBits()); + return CBitVecAccessor(this->Base(), i); +} + + +template +inline void CBitVecT::Init(int val) +{ + if (this->Base()) + Plat_FastMemset(this->Base(), (val) ? 0xff : 0, this->GetNumDWords() * sizeof(int)); +} + +template +inline uint32 CBitVecT::Get(uint32 bitNum) const +{ + Assert(bitNum < (uint32)this->GetNumBits()); + const uint32* pInt = this->Base() + BitVec_Int(bitNum); + return (*pInt & BitVec_Bit(bitNum)); +} + +template +inline bool CBitVecT::IsBitSet(int bitNum) const +{ + Assert(bitNum >= 0 && bitNum < this->GetNumBits()); + const uint32* pInt = this->Base() + BitVec_Int(bitNum); + return ((*pInt & BitVec_Bit(bitNum)) != 0); +} + +template +inline void CBitVecT::Set(int bitNum) +{ + Assert(bitNum >= 0 && bitNum < this->GetNumBits()); + uint32* pInt = this->Base() + BitVec_Int(bitNum); + *pInt |= BitVec_Bit(bitNum); +} + +template +inline bool CBitVecT::TestAndSet(int bitNum) +{ + Assert(bitNum >= 0 && bitNum < this->GetNumBits()); + uint32 bitVecBit = BitVec_Bit(bitNum); + uint32* pInt = this->Base() + BitVec_Int(bitNum); + bool bResult = ((*pInt & bitVecBit) != 0); + *pInt |= bitVecBit; + return bResult; +} + +template +inline void CBitVecT::Clear(int bitNum) +{ + Assert(bitNum >= 0 && bitNum < this->GetNumBits()); + uint32* pInt = this->Base() + BitVec_Int(bitNum); + *pInt &= ~BitVec_Bit(bitNum); +} + +template +inline void CBitVecT::Set(int bitNum, bool bNewVal) +{ + uint32* pInt = this->Base() + BitVec_Int(bitNum); + uint32 bitMask = BitVec_Bit(bitNum); + if (bNewVal) + { + *pInt |= bitMask; + } + else + { + *pInt &= ~bitMask; + } +} + +template +inline void CBitVecT::Set(uint32 offset, uint32 mask) +{ + uint32* pInt = this->Base() + offset; + *pInt |= mask; +} + +template +inline void CBitVecT::Clear(uint32 offset, uint32 mask) +{ + uint32* pInt = this->Base() + offset; + *pInt &= ~mask; +} + +template +inline uint32 CBitVecT::Get(uint32 offset, uint32 mask) +{ + uint32* pInt = this->Base() + offset; + return (*pInt & mask); +} + +template +inline void CBitVecT::And(const CBitVecT& addStr, CBitVecT* out) const +{ + this->ValidateOperand(addStr); + this->ValidateOperand(*out); + + uint32* pDest = out->Base(); + const uint32* pOperand1 = this->Base(); + const uint32* pOperand2 = addStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] & pOperand2[i]; + } +} + +template +inline void CBitVecT::Or(const CBitVecT& orStr, CBitVecT* out) const +{ + this->ValidateOperand(orStr); + this->ValidateOperand(*out); + + uint32* pDest = out->Base(); + const uint32* pOperand1 = this->Base(); + const uint32* pOperand2 = orStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] | pOperand2[i]; + } +} + +template +inline void CBitVecT::Xor(const CBitVecT& xorStr, CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pOperand1 = this->Base(); + const uint32* pOperand2 = xorStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] ^ pOperand2[i]; + } +} + +template +inline void CBitVecT::Not(CBitVecT* out) const +{ + this->ValidateOperand(*out); + + uint32* pDest = out->Base(); + const uint32* pOperand = this->Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = ~(pOperand[i]); + } +} + +template +inline void CBitVecT::CopyTo(CBitVecT* out) const +{ + out->Resize(this->GetNumBits()); + + this->ValidateOperand(*out); + Assert(out != this); + + memcpy(out->Base(), this->Base(), this->GetNumDWords() * sizeof(int)); +} + +template +inline bool CBitVecT::IsAllClear(void) const +{ + (const_cast(this))->Base()[this->GetNumDWords() - 1] &= CBitVecT::GetEndMask(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + if (this->Base()[i] != 0) + { + return false; + } + } + return true; +} + +template +inline bool CBitVecT::IsAllSet(void) const +{ + (const_cast(this))->Base()[this->GetNumDWords() - 1] |= ~CBitVecT::GetEndMask(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + if (this->Base()[i] != ~0) + { + return false; + } + } + return true; +} + +template +inline void CBitVecT::SetAll(void) +{ + if (this->Base()) + Plat_FastMemset(this->Base(), 0xff, this->GetNumDWords() * sizeof(int)); +} + +template +inline void CBitVecT::ClearAll(void) +{ + if (this->Base()) + Plat_FastMemset(this->Base(), 0, this->GetNumDWords() * sizeof(int)); +} + +template +inline void CBitVecT::Copy(const CBitVecT& other, int nBits) +{ + if (nBits == -1) + { + nBits = other.GetNumBits(); + } + + this->Resize(nBits); + + this->ValidateOperand(other); + Assert(&other != this); + + memcpy(this->Base(), other.Base(), this->GetNumDWords() * sizeof(uint32)); +} + +template +inline bool CBitVecT::Compare(const CBitVecT& other, int nBits) const +{ + if (nBits == -1) + { + if (other.GetNumBits() != this->GetNumBits()) + { + return false; + } + + nBits = other.GetNumBits(); + } + + if (nBits > other.GetNumBits() || nBits > this->GetNumBits()) + { + return false; + } + + (const_cast(this))->Base()[this->GetNumDWords() - 1] &= CBitVecT::GetEndMask(); + (const_cast(&other))->Base()[this->GetNumDWords() - 1] &= other.CBitVecT::GetEndMask(); + + int nBytes = PAD_NUMBER(nBits, 8) >> 3; + + return (memcmp(this->Base(), other.Base(), nBytes) == 0); +} + +template +inline uint32 CBitVecT::GetDWord(int i) const +{ + Assert(i >= 0 && i < this->GetNumDWords()); + return this->Base()[i]; +} + +template +inline void CBitVecT::SetDWord(int i, uint32 val) +{ + Assert(i >= 0 && i < this->GetNumDWords()); + this->Base()[i] = val; +} + +inline unsigned GetStartBitMask(int startBit) +{ + static unsigned int g_StartMask[32] = + { + 0xffffffff, + 0xfffffffe, + 0xfffffffc, + 0xfffffff8, + 0xfffffff0, + 0xffffffe0, + 0xffffffc0, + 0xffffff80, + 0xffffff00, + 0xfffffe00, + 0xfffffc00, + 0xfffff800, + 0xfffff000, + 0xffffe000, + 0xffffc000, + 0xffff8000, + 0xffff0000, + 0xfffe0000, + 0xfffc0000, + 0xfff80000, + 0xfff00000, + 0xffe00000, + 0xffc00000, + 0xff800000, + 0xff000000, + 0xfe000000, + 0xfc000000, + 0xf8000000, + 0xf0000000, + 0xe0000000, + 0xc0000000, + 0x80000000, + }; + + return g_StartMask[startBit & 31]; +} + +template +inline int CVarBitVecBase::FindNextSetBit(int startBit) const +{ + if (startBit < GetNumBits()) + { + int wordIndex = BitVec_Int(startBit); + unsigned int startMask = GetStartBitMask(startBit); + int lastWord = GetNumDWords() - 1; + + if ((GetNumBits() % BITS_PER_INT) != 0) + { + unsigned int elem = Base()[wordIndex]; + elem &= startMask; + if (wordIndex == lastWord) + { + elem &= (GetEndMask()); + if (elem) + return FirstBitInWord(elem, wordIndex << 5); + } + else + { + if (elem) + return FirstBitInWord(elem, wordIndex << 5); + + for (int i = wordIndex + 1; i < lastWord; i++) + { + elem = Base()[i]; + if (elem) + return FirstBitInWord(elem, i << 5); + } + elem = Base()[lastWord] & GetEndMask(); + if (elem) + return FirstBitInWord(elem, lastWord << 5); + } + } + else + { + const uint32* RESTRICT pCurElem = Base() + wordIndex; + unsigned int elem = *pCurElem; + elem &= startMask; + do + { + if (elem) + return FirstBitInWord(elem, wordIndex << 5); + ++pCurElem; + elem = *pCurElem; + ++wordIndex; + } while (wordIndex <= lastWord); + } + + } + + return -1; +} + +template +inline int CFixedBitVecBase::FindNextSetBit(int startBit) const +{ + if (startBit < NUM_BITS) + { + int wordIndex = BitVec_Int(startBit); + unsigned int startMask = GetStartBitMask(startBit); + + if ((NUM_BITS % BITS_PER_INT) != 0) + { + unsigned int elem = Base()[wordIndex]; + elem &= startMask; + if (wordIndex == NUM_INTS - 1) + { + elem &= (GetEndMask()); + if (elem) + return FirstBitInWord(elem, wordIndex << 5); + } + else + { + if (elem) + return FirstBitInWord(elem, wordIndex << 5); + + for (int i = wordIndex + 1; i < NUM_INTS - 1; i++) + { + elem = Base()[i]; + if (elem) + return FirstBitInWord(elem, i << 5); + } + elem = Base()[NUM_INTS - 1] & GetEndMask(); + if (elem) + return FirstBitInWord(elem, (NUM_INTS - 1) << 5); + } + } + else + { + const uint32* RESTRICT pCurElem = Base() + wordIndex; + unsigned int elem = *pCurElem; + elem &= startMask; + do + { + if (elem) + return FirstBitInWord(elem, wordIndex << 5); + ++pCurElem; + elem = *pCurElem; + ++wordIndex; + } while (wordIndex <= NUM_INTS - 1); + } + + } + + return -1; +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<256> >::And(const CBitVecT& addStr, CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pOperand1 = Base(); + const uint32* pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; + pDest[3] = pOperand1[3] & pOperand2[3]; + pDest[4] = pOperand1[4] & pOperand2[4]; + pDest[5] = pOperand1[5] & pOperand2[5]; + pDest[6] = pOperand1[6] & pOperand2[6]; + pDest[7] = pOperand1[7] & pOperand2[7]; +} + +template<> +FORCEINLINE_TEMPLATE bool CBitVecT< CFixedBitVecBase<256> >::IsAllClear(void) const +{ + const uint32* pInts = Base(); + return (pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 && pInts[4] == 0 && pInts[5] == 0 && pInts[6] == 0 && pInts[7] == 0); +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<256> >::CopyTo(CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; + pDest[3] = pInts[3]; + pDest[4] = pInts[4]; + pDest[5] = pInts[5]; + pDest[6] = pInts[6]; + pDest[7] = pInts[7]; +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<128> >::And(const CBitVecT& addStr, CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pOperand1 = Base(); + const uint32* pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; + pDest[3] = pOperand1[3] & pOperand2[3]; +} + +template<> +FORCEINLINE_TEMPLATE bool CBitVecT< CFixedBitVecBase<128> >::IsAllClear(void) const +{ + const uint32* pInts = Base(); + return (pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0); +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<128> >::CopyTo(CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; + pDest[3] = pInts[3]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<96> >::And(const CBitVecT& addStr, CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pOperand1 = Base(); + const uint32* pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<96> >::IsAllClear(void) const +{ + const uint32* pInts = Base(); + return (pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<96> >::CopyTo(CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<64> >::And(const CBitVecT& addStr, CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pOperand1 = Base(); + const uint32* pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<64> >::IsAllClear(void) const +{ + const uint32* pInts = Base(); + return (pInts[0] == 0 && pInts[1] == 0); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<64> >::CopyTo(CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<32> >::And(const CBitVecT& addStr, CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pOperand1 = Base(); + const uint32* pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<32> >::IsAllClear(void) const +{ + const uint32* pInts = Base(); + + return (pInts[0] == 0); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<32> >::CopyTo(CBitVecT* out) const +{ + uint32* pDest = out->Base(); + const uint32* pInts = Base(); + + pDest[0] = pInts[0]; +} + +template <> +inline uint32 CBitVecT< CFixedBitVecBase<32> >::Get(uint32 bitNum) const +{ + return (*Base() & BitVec_Bit(bitNum)); +} + +template <> +inline bool CBitVecT< CFixedBitVecBase<32> >::IsBitSet(int bitNum) const +{ + return ((*Base() & BitVec_Bit(bitNum)) != 0); +} + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Set(int bitNum) +{ + *Base() |= BitVec_Bit(bitNum); +} + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Clear(int bitNum) +{ + *Base() &= ~BitVec_Bit(bitNum); +} + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Set(int bitNum, bool bNewVal) +{ + uint32 bitMask = BitVec_Bit(bitNum); + if (bNewVal) + { + *Base() |= bitMask; + } + else + { + *Base() &= ~bitMask; + } +} + + +#include "memdbgon.h" + +template +inline void CVarBitVecBase::Resize(int resizeNumBits, bool bClearAll) +{ + Assert(resizeNumBits >= 0 && ((BITCOUNTTYPE)resizeNumBits == resizeNumBits)); + + int newIntCount = CalcNumIntsForBits(resizeNumBits); + if (newIntCount != GetNumDWords()) + { + if (Base()) + { + ReallocInts(newIntCount); + if (!bClearAll && resizeNumBits >= GetNumBits()) + { + Base()[GetNumDWords() - 1] &= GetEndMask(); + Plat_FastMemset(Base() + GetNumDWords(), 0, (newIntCount - GetNumDWords()) * sizeof(int)); + } + } + else + { + AllocInts(newIntCount); + bClearAll = true; + } + + m_numInts = newIntCount; + } + else if (!bClearAll && resizeNumBits >= GetNumBits() && Base()) + { + Base()[GetNumDWords() - 1] &= GetEndMask(); + } + + if (bClearAll && Base()) + { + Plat_FastMemset(Base(), 0, newIntCount * sizeof(int)); + } + + m_numBits = resizeNumBits; +} + +template +inline void CVarBitVecBase::AllocInts(int numInts) +{ + Assert(!m_pInt); + + if (numInts == 0) + return; + + if (numInts == 1) + { + m_pInt = &m_iBitStringStorage; + return; + } + + m_pInt = (uint32*)malloc(numInts * sizeof(int)); +} + + +template +inline void CVarBitVecBase::ReallocInts(int numInts) +{ + Assert(Base()); + if (numInts == 0) + { + FreeInts(); + return; + } + + if (m_pInt == &m_iBitStringStorage) + { + if (numInts != 1) + { + m_pInt = ((uint32*)malloc(numInts * sizeof(int))); + *m_pInt = m_iBitStringStorage; + } + + return; + } + + if (numInts == 1) + { + m_iBitStringStorage = *m_pInt; + free(m_pInt); + m_pInt = &m_iBitStringStorage; + return; + } + + m_pInt = (uint32*)realloc(m_pInt, numInts * sizeof(int)); +} + + +template +inline void CVarBitVecBase::FreeInts(void) +{ + if (m_numInts > 1) + { + free(m_pInt); + } + m_pInt = NULL; +} + +#include "memdbgoff.h" + +inline CBitVecAccessor::CBitVecAccessor(uint32* pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + + +inline void CBitVecAccessor::operator=(int val) +{ + if (val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator uint32() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + +#endif +``` + +`SpyCustom/sdk/bone_accessor.h`: + +```h +#ifndef BONE_ACCESSOR_H +#define BONE_ACCESSOR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "studio.h" + + +class C_BaseAnimating; + + +class CBoneAccessor +{ +public: + + CBoneAccessor(); + CBoneAccessor(matrix3x4_t* pBones); + +#if defined( CLIENT_DLL ) + void Init(const C_BaseAnimating* pAnimating, matrix3x4_t* pBones); +#endif + + int GetReadableBones(); + void SetReadableBones(int flags); + + int GetWritableBones(); + void SetWritableBones(int flags); + + const matrix3x4_t& GetBone(int iBone) const; + const matrix3x4_t& operator[](int iBone) const; + matrix3x4_t& GetBoneForWrite(int iBone); + + matrix3x4_t* GetBoneArrayForWrite() const; + +private: + +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + void SanityCheckBone(int iBone, bool bReadable) const; +#endif + + const C_BaseAnimating* m_pAnimating; + + matrix3x4_t* m_pBones; + + int m_ReadableBones; + int m_WritableBones; +}; + + +inline CBoneAccessor::CBoneAccessor() +{ + m_pAnimating = NULL; + m_pBones = NULL; + m_ReadableBones = m_WritableBones = 0; +} + +inline CBoneAccessor::CBoneAccessor(matrix3x4_t* pBones) +{ + m_pAnimating = NULL; + m_pBones = pBones; +} + +#if defined( CLIENT_DLL ) +inline void CBoneAccessor::Init(const C_BaseAnimating* pAnimating, matrix3x4_t* pBones) +{ + m_pAnimating = pAnimating; + m_pBones = pBones; +} +#endif + +inline int CBoneAccessor::GetReadableBones() +{ + return m_ReadableBones; +} + +inline void CBoneAccessor::SetReadableBones(int flags) +{ + m_ReadableBones = flags; +} + +inline int CBoneAccessor::GetWritableBones() +{ + return m_WritableBones; +} + +inline void CBoneAccessor::SetWritableBones(int flags) +{ + m_WritableBones = flags; +} + +inline const matrix3x4_t& CBoneAccessor::GetBone(int iBone) const +{ +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + SanityCheckBone(iBone, true); +#endif + return m_pBones[iBone]; +} + +inline const matrix3x4_t& CBoneAccessor::operator[](int iBone) const +{ +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + SanityCheckBone(iBone, true); +#endif + return m_pBones[iBone]; +} + +inline matrix3x4_t& CBoneAccessor::GetBoneForWrite(int iBone) +{ +#if defined( CLIENT_DLL ) && defined( _DEBUG ) + SanityCheckBone(iBone, false); +#endif + return m_pBones[iBone]; +} + +inline matrix3x4_t* CBoneAccessor::GetBoneArrayForWrite(void) const +{ + return m_pBones; +} + +#endif +``` + +`SpyCustom/sdk/bone_merge_cache.h`: + +```h +#ifndef BONE_MERGE_CACHE_H +#define BONE_MERGE_CACHE_H +#ifdef _WIN32 +#pragma once +#endif + + +class C_BaseAnimating; +class CStudioHdr; + + +#include "vector.h" + + +class CBoneMergeCache +{ +public: + + CBoneMergeCache(); + + void Init(C_BaseAnimating* pOwner); + + void UpdateCache(); + + void MergeMatchingBones(int boneMask); + + void CopyParentToChild(const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask); + void CopyChildToParent(const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask); + + int IsBoneMerged(int iBone) const; + + bool GetAimEntOrigin(Vector* pAbsOrigin, QAngle* pAbsAngles); + + bool GetRootBone(matrix3x4_t& rootBone); + +private: + + C_BaseAnimating* m_pOwner; + + C_BaseAnimating* m_pFollow; + CStudioHdr* m_pFollowHdr; + const studiohdr_t* m_pFollowRenderHdr; + CStudioHdr* m_pOwnerHdr; + + int m_nFollowBoneSetupMask; + + class CMergedBone + { + public: + unsigned short m_iMyBone; + unsigned short m_iParentBone; + }; + + CUtlVector m_MergedBones; + CUtlVector m_BoneMergeBits; +}; + + +inline int CBoneMergeCache::IsBoneMerged(int iBone) const +{ + if (m_pOwnerHdr) + return m_BoneMergeBits[iBone >> 3] & (1 << (iBone & 7)); + else + return 0; +} + + +#endif +``` + +`SpyCustom/sdk/bspfile.h`: + +```h +#ifndef BSPFILE_H +#define BSPFILE_H +#pragma once + +#ifndef MATHLIB_H +#include "mathlib.h" +#endif + +#include "vector4d.h" +#include "datamap.h" +#include "bumpvects.h" +#include "compressed_light_cube.h" + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'V') + +#define MINBSPVERSION 19 +#define BSPVERSION 21 + + +#define MAX_BRUSH_LIGHTMAP_DIM_WITHOUT_BORDER 32 +#define MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER 35 + +#define MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER 125 +#define MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER 128 + + +#define MAX_LIGHTMAP_DIM_WITHOUT_BORDER MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER +#define MAX_LIGHTMAP_DIM_INCLUDING_BORDER MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER + +#define MAX_LIGHTSTYLES 64 + + +#define MIN_MAP_DISP_POWER 2 +#define MAX_MAP_DISP_POWER 4 + +#define MAX_DISP_CORNER_NEIGHBORS 4 + +#define NUM_DISP_POWER_VERTS(power) ( ((1 << (power)) + 1) * ((1 << (power)) + 1) ) +#define NUM_DISP_POWER_TRIS(power) ( (1 << (power)) * (1 << (power)) * 2 ) + +#if !defined( BSP_USE_LESS_MEMORY ) +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 16384 +#define MAX_MAP_TEXINFO 12288 +#define MAX_MAP_TEXDATA 2048 +#define MAX_MAP_DISPINFO 2048 +#define MAX_MAP_DISP_VERTS ( MAX_MAP_DISPINFO * ((1<> (16 - OVERLAY_RENDER_ORDER_NUM_BITS)); +} + + +struct doverlayfade_t +{ + DECLARE_BYTESWAP_DATADESC(); + + float flFadeDistMinSq; + float flFadeDistMaxSq; +}; + + +struct doverlaysystemlevel_t +{ + DECLARE_BYTESWAP_DATADESC(); + + unsigned char nMinCPULevel; + unsigned char nMaxCPULevel; + unsigned char nMinGPULevel; + unsigned char nMaxGPULevel; +}; + + +#define WATEROVERLAY_BSP_FACE_COUNT 256 +#define WATEROVERLAY_RENDER_ORDER_NUM_BITS 2 +#define WATEROVERLAY_NUM_RENDER_ORDERS (1<> (16 - WATEROVERLAY_RENDER_ORDER_NUM_BITS)); +} + +#ifndef _DEF_BYTE_ +#define _DEF_BYTE_ +typedef unsigned char byte; +typedef unsigned short word; +#endif + + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + + +struct epair_t +{ + epair_t* next; + char* key; + char* value; +}; + +#define MAX_LIGHTMAPPAGE_WIDTH 256 +#define MAX_LIGHTMAPPAGE_HEIGHT 128 +typedef struct nameForDatadesc_dlightmappage_t +{ + DECLARE_BYTESWAP_DATADESC(); + byte data[MAX_LIGHTMAPPAGE_WIDTH * MAX_LIGHTMAPPAGE_HEIGHT]; + byte palette[256 * 4]; +} dlightmappage_t; + +typedef struct nameForDatadesc_dlightmappageinfo_t +{ + DECLARE_BYTESWAP_DATADESC(); + byte page; + byte offset[2]; + byte pad; + ColorRGBExp32 avgColor; +} dlightmappageinfo_t; + +#endif +``` + +`SpyCustom/sdk/bspflags.h`: + +```h +#ifndef BSPFLAGS_H +#define BSPFLAGS_H + +#ifdef _WIN32 +#pragma once +#endif + +#define CONTENTS_EMPTY 0 + +#define CONTENTS_SOLID 0x1 +#define CONTENTS_WINDOW 0x2 +#define CONTENTS_AUX 0x4 +#define CONTENTS_GRATE 0x8 +#define CONTENTS_SLIME 0x10 +#define CONTENTS_WATER 0x20 +#define CONTENTS_BLOCKLOS 0x40 +#define CONTENTS_OPAQUE 0x80 +#define LAST_VISIBLE_CONTENTS 0x80 + +#define ALL_VISIBLE_CONTENTS (LAST_VISIBLE_CONTENTS | (LAST_VISIBLE_CONTENTS-1)) + +#define CONTENTS_TESTFOGVOLUME 0x100 +#define CONTENTS_UNUSED 0x200 + +#define CONTENTS_UNUSED6 0x400 + +#define CONTENTS_TEAM1 0x800 +#define CONTENTS_TEAM2 0x1000 + +#define CONTENTS_IGNORE_NODRAW_OPAQUE 0x2000 + +#define CONTENTS_MOVEABLE 0x4000 + +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +#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 + +#define CONTENTS_MONSTER 0x2000000 +#define CONTENTS_DEBRIS 0x4000000 +#define CONTENTS_DETAIL 0x8000000 +#define CONTENTS_TRANSLUCENT 0x10000000 +#define CONTENTS_LADDER 0x20000000 +#define CONTENTS_HITBOX 0x40000000 + + +#define SURF_LIGHT 0x0001 +#define SURF_SKY2D 0x0002 +#define SURF_SKY 0x0004 +#define SURF_WARP 0x0008 +#define SURF_TRANS 0x0010 +#define SURF_NOPORTAL 0x0020 +#define SURF_TRIGGER 0x0040 +#define SURF_NODRAW 0x0080 + +#define SURF_HINT 0x0100 + +#define SURF_SKIP 0x0200 +#define SURF_NOLIGHT 0x0400 +#define SURF_BUMPLIGHT 0x0800 +#define SURF_NOSHADOWS 0x1000 +#define SURF_NODECALS 0x2000 +#define SURF_NOCHOP 0x4000 +#define SURF_HITBOX 0x8000 + + + +#define MASK_ALL (0xFFFFFFFF) +#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +#define MASK_NPCSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +#define MASK_WATER (CONTENTS_WATER|CONTENTS_MOVEABLE|CONTENTS_SLIME) +#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_OPAQUE) +#define MASK_OPAQUE_AND_NPCS (MASK_OPAQUE|CONTENTS_MONSTER) +#define MASK_BLOCKLOS (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_BLOCKLOS) +#define MASK_BLOCKLOS_AND_NPCS (MASK_BLOCKLOS|CONTENTS_MONSTER) +#define MASK_VISIBLE (MASK_OPAQUE|CONTENTS_IGNORE_NODRAW_OPAQUE) +#define MASK_VISIBLE_AND_NPCS (MASK_OPAQUE_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE) +#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_HITBOX) +#define MASK_SHOT_HULL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_GRATE) +#define MASK_SHOT_PORTAL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER) +#define MASK_SOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_GRATE) +#define MASK_PLAYERSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_PLAYERCLIP|CONTENTS_GRATE) +#define MASK_NPCSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) +#define MASK_NPCWORLDSTATIC (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) +#define MASK_SPLITAREAPORTAL (CONTENTS_WATER|CONTENTS_SLIME) + +#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN) + +#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_GRATE) + +#endif +``` + +`SpyCustom/sdk/bumpvects.h`: + +```h +#ifndef BUMPVECTS_H +#define BUMPVECTS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib.h" + +#define OO_SQRT_2 0.70710676908493042f +#define OO_SQRT_3 0.57735025882720947f +#define OO_SQRT_6 0.40824821591377258f +#define OO_SQRT_2_OVER_3 0.81649661064147949f + +#define NUM_BUMP_VECTS 3 + +const TableVector g_localBumpBasis[NUM_BUMP_VECTS] = +{ + { OO_SQRT_2_OVER_3, 0.0f, OO_SQRT_3 }, + { -OO_SQRT_6, OO_SQRT_2, OO_SQRT_3 }, + { -OO_SQRT_6, -OO_SQRT_2, OO_SQRT_3 } +}; + +void GetBumpNormals(const Vector& sVect, const Vector& tVect, const Vector& flatNormal, + const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS]); + +#endif +``` + +`SpyCustom/sdk/byteswap.h`: + +```h +#ifndef BYTESWAP_H +#define BYTESWAP_H +#if defined(_WIN32) +#pragma once +#endif + +#include "datamap.h" + +class CByteswap +{ +public: + CByteswap() + { + SetTargetBigEndian(IsMachineBigEndian()); + } + + void SwapFieldToTargetEndian(void* pOutputBuffer, void* pData, typedescription_t* pField); + + void SwapFieldsToTargetEndian(void* pOutputBuffer, void* pBaseData, datamap_t* pDataMap); + + template inline void SwapFieldsToTargetEndian(T* pOutputBuffer, void* pBaseData, unsigned int objectCount = 1) + { + for (unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer) + { + SwapFieldsToTargetEndian((void*)pOutputBuffer, pBaseData, &T::m_DataMap); + pBaseData = (byte*)pBaseData + sizeof(T); + } + } + + template inline void SwapFieldsToTargetEndian(T* pOutputBuffer, unsigned int objectCount = 1) + { + SwapFieldsToTargetEndian(pOutputBuffer, (void*)pOutputBuffer, objectCount); + } + + static bool IsMachineBigEndian() + { + short nIsBigEndian = 1; + + return (bool)(0 == *(char*)&nIsBigEndian); + } + + inline void SetTargetBigEndian(bool bigEndian) + { + m_bBigEndian = bigEndian; + m_bSwapBytes = IsMachineBigEndian() != bigEndian; + } + + inline void FlipTargetEndian(void) + { + m_bSwapBytes = !m_bSwapBytes; + m_bBigEndian = !m_bBigEndian; + } + + inline void ActivateByteSwapping(bool bActivate) + { + SetTargetBigEndian(IsMachineBigEndian() != bActivate); + } + + inline bool IsSwappingBytes(void) + { + return m_bSwapBytes; + } + + inline bool IsTargetBigEndian(void) + { + return m_bBigEndian; + } + + template inline int SourceIsNativeEndian(T input, T nativeConstant) + { + if (input == nativeConstant) + return 1; + + int output; + LowLevelByteSwap(&output, &input); + if (output == nativeConstant) + return 0; + + assert(0); + return -1; + } + + template inline void SwapBuffer(T* outputBuffer, T* inputBuffer = NULL, int count = 1) + { + assert(count >= 0); + assert(outputBuffer); + + if (count <= 0 || !outputBuffer) + return; + + if (inputBuffer == NULL) + { + inputBuffer = outputBuffer; + } + + for (int i = 0; i < count; i++) + { + LowLevelByteSwap(&outputBuffer[i], &inputBuffer[i]); + } + } + + template inline void SwapBufferToTargetEndian(T* outputBuffer, T* inputBuffer = NULL, int count = 1) + { + assert(count >= 0); + assert(outputBuffer); + + if (count <= 0 || !outputBuffer) + return; + + if (inputBuffer == NULL) + { + inputBuffer = outputBuffer; + } + + if (!m_bSwapBytes || (sizeof(T) == 1)) + { + if (!inputBuffer) + return; + + memcpy(outputBuffer, inputBuffer, count * sizeof(T)); + return; + + } + + for (int i = 0; i < count; i++) + { + LowLevelByteSwap(&outputBuffer[i], &inputBuffer[i]); + } + } + +private: + template static void LowLevelByteSwap(T* output, T* input) + { + T temp = *output; +#if defined( _X360 ) + DWORD* word = (DWORD*)input; + switch (sizeof(T)) + { + case 8: + { + __storewordbytereverse(*word, 0, &temp); + __storewordbytereverse(*(word + 1), 4, &temp); + } + break; + + case 4: + __storewordbytereverse(*word, 0, &temp); + break; + + case 2: + __storeshortbytereverse(*input, 0, &temp); + break; + + default: + Assert("Invalid size in CByteswap::LowLevelByteSwap" && 0); + } +#else + for (int i = 0; i < sizeof(T); i++) + { + ((unsigned char*)&temp)[i] = ((unsigned char*)input)[sizeof(T) - (i + 1)]; + } +#endif + Q_memcpy(output, &temp, sizeof(T)); + } + + unsigned int m_bSwapBytes : 1; + unsigned int m_bBigEndian : 1; +}; + +#endif +``` + +`SpyCustom/sdk/c_baseanimating.h`: + +```h +#ifndef C_BASEANIMATING_H +#define C_BASEANIMATING_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "studio.h" +#include "utlvector.h" +#include "ragdoll.h" +#include "mouthinfo.h" +#include "ai_activity.h" +#include "animationlayer.h" +#include "sequence_Transitioner.h" +#include "bone_accessor.h" +#include "bone_merge_cache.h" +#include "ragdoll_shared.h" +#include "threadtools.h" +#include "idatacache.h" + +#include "baseentity_shared.h" + +#define LIPSYNC_POSEPARAM_NAME "mouth" +#define NUM_HITBOX_FIRES 10 + +class IRagdoll; +class CIKContext; +class CIKState; +class ConVar; +class C_RopeKeyframe; +class CBoneBitList; +class CBoneList; +class KeyValues; +class CJiggleBones; +class IBoneSetup; +FORWARD_DECLARE_HANDLE(memhandle_t); +typedef unsigned short MDLHandle_t; + +extern ConVar vcollide_wireframe; + + +struct ClientModelRenderInfo_t : public ModelRenderInfo_t +{ + matrix3x4_t lightingOffset; + + matrix3x4_t modelToWorld; +}; + +struct RagdollInfo_t +{ + bool m_bActive; + float m_flSaveTime; + int m_nNumBones; + Vector m_rgBonePos[MAXSTUDIOBONES]; + Quaternion m_rgBoneQuaternion[MAXSTUDIOBONES]; +}; + + +class CAttachmentData +{ +public: + matrix3x4_t m_AttachmentToWorld; + QAngle m_angRotation; + Vector m_vOriginVelocity; + int m_nLastFramecount : 31; + int m_bAnglesComputed : 1; +}; + + +typedef unsigned int ClientSideAnimationListHandle_t; + +#define INVALID_CLIENTSIDEANIMATION_LIST_HANDLE (ClientSideAnimationListHandle_t)~0 + + +class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback +{ +public: + DECLARE_CLASS(C_BaseAnimating, C_BaseEntity); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + enum + { + NUM_POSEPAREMETERS = 24, + NUM_BONECTRLS = 4 + }; + + C_BaseAnimating(); + ~C_BaseAnimating(); + + virtual C_BaseAnimating* GetBaseAnimating() { return this; } + + bool UsesPowerOfTwoFrameBufferTexture(void); + + virtual bool Interpolate(float currentTime); + virtual void Simulate(); + virtual void Release(); + + float GetAnimTimeInterval(void) const; + + virtual unsigned char GetClientSideFade(void); + + virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); + virtual float SetBoneController(int iController, float flValue); + + LocalFlexController_t GetNumFlexControllers(void); + const char* GetFlexDescFacs(int iFlexDesc); + const char* GetFlexControllerName(LocalFlexController_t iFlexController); + const char* GetFlexControllerType(LocalFlexController_t iFlexController); + + virtual void GetAimEntOrigin(IClientEntity* pAttachedTo, Vector* pAbsOrigin, QAngle* pAbsAngles); + + bool ComputeHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + bool ComputeEntitySpaceHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + + bool HitboxToWorldTransforms(matrix3x4_t* pHitboxToWorld[MAXSTUDIOBONES]); + + float ClampCycle(float cycle, bool isLooping); + virtual void GetPoseParameters(CStudioHdr* pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM]); + virtual void BuildTransformations(CStudioHdr* pStudioHdr, Vector* pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList& boneComputed); + virtual void ApplyBoneMatrixTransform(matrix3x4_t& transform); + virtual int VPhysicsGetObjectList(IPhysicsObject** pList, int listMax); + + virtual bool SetupBones(matrix3x4_t* pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime); + virtual void UpdateIKLocks(float currentTime); + virtual void CalculateIKLocks(float currentTime); + virtual bool ShouldDraw(); + virtual int DrawModel(int flags); + virtual int InternalDrawModel(int flags); + virtual bool OnInternalDrawModel(ClientModelRenderInfo_t* pInfo); + virtual bool OnPostInternalDrawModel(ClientModelRenderInfo_t* pInfo); + void DoInternalDrawModel(ClientModelRenderInfo_t* pInfo, DrawModelState_t* pState, matrix3x4_t* pBoneToWorldArray = NULL); + + virtual CMouthInfo* GetMouth(); + virtual void ControlMouth(CStudioHdr* pStudioHdr); + + virtual void DoAnimationEvents(CStudioHdr* pStudio); + virtual void FireEvent(const Vector& origin, const QAngle& angles, int event, const char* options); + virtual void FireObsoleteEvent(const Vector& origin, const QAngle& angles, int event, const char* options); + virtual const char* ModifyEventParticles(const char* token) { return token; } + + virtual bool DispatchMuzzleEffect(const char* options, bool isFirstPerson); + + virtual void ValidateModelIndex(void); + virtual CStudioHdr* OnNewModel(void); + CStudioHdr* GetModelPtr() const; + void InvalidateMdlCache(); + + virtual void SetPredictable(bool state); + void UseClientSideAnimation(); + + virtual void StandardBlendingRules(CStudioHdr* pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask); + void UnragdollBlend(CStudioHdr* hdr, Vector pos[], Quaternion q[], float currentTime); + + void MaintainSequenceTransitions(IBoneSetup& boneSetup, float flCycle, Vector pos[], Quaternion q[]); + virtual void AccumulateLayers(IBoneSetup& boneSetup, Vector pos[], Quaternion q[], float currentTime); + + virtual void ChildLayerBlend(Vector pos[], Quaternion q[], float currentTime, int boneMask); + + int LookupAttachment(const char* pAttachmentName); + int LookupRandomAttachment(const char* pAttachmentNameSubstring); + + int LookupPoseParameter(CStudioHdr* pStudioHdr, const char* szName); + inline int LookupPoseParameter(const char* szName) { return LookupPoseParameter(GetModelPtr(), szName); } + + float SetPoseParameter(CStudioHdr* pStudioHdr, const char* szName, float flValue); + inline float SetPoseParameter(const char* szName, float flValue) { return SetPoseParameter(GetModelPtr(), szName, flValue); } + float SetPoseParameter(CStudioHdr* pStudioHdr, int iParameter, float flValue); + inline float SetPoseParameter(int iParameter, float flValue) { return SetPoseParameter(GetModelPtr(), iParameter, flValue); } + + float GetPoseParameter(int iPoseParameter); + + bool GetPoseParameterRange(int iPoseParameter, float& minValue, float& maxValue); + + int LookupBone(const char* szName); + void GetBonePosition(int iBone, Vector& origin, QAngle& angles); + void GetBoneTransform(int iBone, matrix3x4_t& pBoneToWorld); + + int GetHitboxBone(int hitboxIndex); + + virtual void AttachEntityToBone(C_BaseAnimating* attachTarget, int boneIndexAttached = -1, Vector bonePosition = Vector(0, 0, 0), QAngle boneAngles = QAngle(0, 0, 0)); + void AddBoneAttachment(C_BaseAnimating* newBoneAttachment); + void RemoveBoneAttachment(C_BaseAnimating* boneAttachment); + void RemoveBoneAttachments(); + void DestroyBoneAttachments(); + void MoveBoneAttachments(C_BaseAnimating* attachTarget); + int GetNumBoneAttachments(); + C_BaseAnimating* GetBoneAttachment(int i); + virtual void NotifyBoneAttached(C_BaseAnimating* attachTarget); + virtual void UpdateBoneAttachments(void); + + virtual void PreDataUpdate(DataUpdateType_t updateType); + virtual void PostDataUpdate(DataUpdateType_t updateType); + virtual int RestoreData(const char* context, int slot, int type); + + virtual void NotifyShouldTransmit(ShouldTransmitState_t state); + virtual void OnPreDataChanged(DataUpdateType_t updateType); + virtual void OnDataChanged(DataUpdateType_t updateType); + virtual void AddEntity(void); + + void ForceClientSideAnimationOn(); + + void AddToClientSideAnimationList(); + void RemoveFromClientSideAnimationList(); + + virtual bool IsSelfAnimating(); + virtual void ResetLatched(); + + virtual void GetRenderBounds(Vector& theMins, Vector& theMaxs); + virtual const Vector& GetRenderOrigin(void); + virtual const QAngle& GetRenderAngles(void); + + virtual bool GetSoundSpatialization(SpatializationInfo_t& info); + + bool GetAttachment(const char* szName, Vector& absOrigin); + bool GetAttachment(const char* szName, Vector& absOrigin, QAngle& absAngles); + + virtual bool GetAttachment(int number, Vector& origin); + virtual bool GetAttachment(int number, Vector& origin, QAngle& angles); + virtual bool GetAttachment(int number, matrix3x4_t& matrix); + virtual bool GetAttachmentVelocity(int number, Vector& originVel, Quaternion& angleVel); + + bool GetAttachmentLocal(int iAttachment, matrix3x4_t& attachmentToLocal); + bool GetAttachmentLocal(int iAttachment, Vector& origin, QAngle& angles); + bool GetAttachmentLocal(int iAttachment, Vector& origin); + + bool GetRootBone(matrix3x4_t& rootBone); + + virtual ShadowType_t ShadowCastType(); + + virtual CollideType_t GetCollideType(void); + + virtual bool TestCollision(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr); + virtual bool TestHitboxes(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr); + + bool IsRagdoll() const; + bool IsAboutToRagdoll() const; + virtual C_BaseAnimating* BecomeRagdollOnClient(); + C_BaseAnimating* CreateRagdollCopy(); + bool InitAsClientRagdoll(const matrix3x4_t* pDeltaBones0, const matrix3x4_t* pDeltaBones1, const matrix3x4_t* pCurrentBonePosition, float boneDt, bool bFixedConstraints = false); + void IgniteRagdoll(C_BaseAnimating* pSource); + void TransferDissolveFrom(C_BaseAnimating* pSource); + virtual void SaveRagdollInfo(int numbones, const matrix3x4_t& cameraTransform, CBoneAccessor& pBoneToWorld); + virtual bool RetrieveRagdollInfo(Vector* pos, Quaternion* q); + virtual void Clear(void); + void ClearRagdoll(); + void CreateUnragdollInfo(C_BaseAnimating* pRagdoll); + void ForceSetupBonesAtTime(matrix3x4_t* pBonesOut, float flTime); + virtual void GetRagdollInitBoneArrays(matrix3x4_t* pDeltaBones0, matrix3x4_t* pDeltaBones1, matrix3x4_t* pCurrentBones, float boneDt); + + virtual int GetBody() { return m_nBody; } + virtual int GetSkin() { return m_nSkin; } + + bool IsOnFire() { return ((GetFlags() & FL_ONFIRE) != 0); } + + inline float GetPlaybackRate(); + inline void SetPlaybackRate(float rate); + + void SetModelScale(float scale, float change_duration = 0.0f); + float GetModelScale() const { return m_flModelScale; } + inline bool IsModelScaleFractional() const; + inline bool IsModelScaled() const; + void UpdateModelScale(void); + virtual void RefreshCollisionBounds(void); + + int GetSequence(); + virtual void SetSequence(int nSequence); + inline void ResetSequence(int nSequence); + float GetSequenceGroundSpeed(CStudioHdr* pStudioHdr, int iSequence); + inline float GetSequenceGroundSpeed(int iSequence) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); } + bool IsSequenceLooping(CStudioHdr* pStudioHdr, int iSequence); + inline bool IsSequenceLooping(int iSequence) { return IsSequenceLooping(GetModelPtr(), iSequence); } + float GetSequenceMoveDist(CStudioHdr* pStudioHdr, int iSequence); + void GetSequenceLinearMotion(int iSequence, Vector* pVec); + void GetBlendedLinearVelocity(Vector* pVec); + int LookupSequence(const char* label); + int LookupActivity(const char* label); + char const* GetSequenceName(int iSequence); + char const* GetSequenceActivityName(int iSequence); + Activity GetSequenceActivity(int iSequence); + KeyValues* GetSequenceKeyValues(int iSequence); + virtual void StudioFrameAdvance(); + + virtual float FrameAdvance(float flInterval = 0.0f); + virtual float GetSequenceCycleRate(CStudioHdr* pStudioHdr, int iSequence); + virtual void UpdateClientSideAnimation(); + void ClientSideAnimationChanged(); + virtual unsigned int ComputeClientSideAnimationFlags(); + + virtual void ResetClientsideFrame(void) { SetCycle(0); } + + void SetCycle(float flCycle); + float GetCycle() const; + + void SetBodygroup(int iGroup, int iValue); + int GetBodygroup(int iGroup); + + const char* GetBodygroupName(int iGroup); + int FindBodygroupByName(const char* name); + int GetBodygroupCount(int iGroup); + int GetNumBodyGroups(void); + + class CBoneCache* GetBoneCache(CStudioHdr* pStudioHdr); + void SetHitboxSet(int setnum); + void SetHitboxSetByName(const char* setname); + int GetHitboxSet(void); + char const* GetHitboxSetName(void); + int GetHitboxSetCount(void); + void DrawClientHitboxes(float duration = 0.0f, bool monocolor = false); + + C_BaseAnimating* FindFollowedEntity(); + + virtual bool IsActivityFinished(void) { return m_bSequenceFinished; } + inline bool IsSequenceFinished(void); + inline bool SequenceLoops(void) { return m_bSequenceLoops; } + + virtual void UncorrectViewModelAttachment(Vector& vOrigin) {} + + void InvalidateBoneCache(); + bool IsBoneCacheValid() const; + void GetCachedBoneMatrix(int boneIndex, matrix3x4_t& out); + + const matrix3x4_t& GetBone(int iBone) const; + matrix3x4_t& GetBoneForWrite(int iBone); + + struct AutoAllowBoneAccess + { + AutoAllowBoneAccess(bool bAllowForNormalModels, bool bAllowForViewModels); + ~AutoAllowBoneAccess(void); + }; + static void PushAllowBoneAccess(bool bAllowForNormalModels, bool bAllowForViewModels, char const* tagPush); + static void PopBoneAccess(char const* tagPop); + static void ThreadedBoneSetup(); + static void InitBoneSetupThreadPool(); + static void ShutdownBoneSetupThreadPool(); + + static void InvalidateBoneCaches(); + + virtual void VPhysicsUpdate(IPhysicsObject* pPhysics); + + void DisableMuzzleFlash(); + virtual void DoMuzzleFlash(); + bool ShouldMuzzleFlash() const; + + virtual void ProcessMuzzleFlashEvent(); + + static void UpdateClientSideAnimations(); + + void InitModelEffects(void); + + virtual void SetServerIntendedCycle(float intended) { (void)intended; } + virtual float GetServerIntendedCycle(void) { return -1.0f; } + + int SelectWeightedSequence(int activity); + void ResetSequenceInfo(void); + float SequenceDuration(void); + float SequenceDuration(CStudioHdr* pStudioHdr, int iSequence); + inline float SequenceDuration(int iSequence) { return SequenceDuration(GetModelPtr(), iSequence); } + int FindTransitionSequence(int iCurrentSequence, int iGoalSequence, int* piDir); + + void RagdollMoved(void); + + virtual void GetToolRecordingState(KeyValues* msg); + virtual void CleanupToolRecordingState(KeyValues* msg); + + void SetReceivedSequence(void); + virtual bool ShouldResetSequenceOnNewModel(void); + + virtual bool IsViewModel() const; + +protected: + virtual void FormatViewModelAttachment(int nAttachment, matrix3x4_t& attachmentToWorld) {} + + bool IsBoneAccessAllowed() const; + CMouthInfo& MouthInfo(); + + virtual bool IsMenuModel() const; + + virtual int GetStudioBody(void) { return m_nBody; } + + virtual bool CalcAttachments(); + +private: + virtual float LastBoneChangedTime() { return FLT_MAX; } + + CBoneList* RecordBones(CStudioHdr* hdr, matrix3x4_t* pBoneState); + + bool PutAttachment(int number, const matrix3x4_t& attachmentToWorld); + void TermRopes(); + + void DelayedInitModelEffects(void); + + void UpdateRelevantInterpolatedVars(); + void AddBaseAnimatingInterpolatedVars(); + void RemoveBaseAnimatingInterpolatedVars(); + +public: + CRagdoll* m_pRagdoll; + + int m_nSkin; + + int m_nBody; + + int m_nHitboxSet; + + CSequenceTransitioner m_SequenceTransitioner; + +protected: + CIKContext* m_pIk; + + int m_iEyeAttachment; + + float m_flPlaybackRate; + + bool m_bStoreRagdollInfo; + RagdollInfo_t* m_pRagdollInfo; + Vector m_vecForce; + int m_nForceBone; + + unsigned long m_iMostRecentModelBoneCounter; + unsigned long m_iMostRecentBoneSetupRequest; + int m_iPrevBoneMask; + int m_iAccumulatedBoneMask; + + CBoneAccessor m_BoneAccessor; + CThreadFastMutex m_BoneSetupLock; + + ClientSideAnimationListHandle_t m_ClientSideAnimationListHandle; + + bool m_bClientSideFrameReset; + + CUtlVector > m_BoneAttachments; + int m_boneIndexAttached; + Vector m_bonePosition; + QAngle m_boneAngles; + CHandle m_pAttachedTo; + +protected: + + float m_fadeMinDist; + float m_fadeMaxDist; + float m_flFadeScale; + +private: + + float m_flGroundSpeed; + float m_flLastEventCheck; + bool m_bSequenceFinished; + bool m_bSequenceLoops; + + CMouthInfo m_mouth; + + CNetworkVar(float, m_flModelScale); + + float m_flPoseParameter[MAXSTUDIOPOSEPARAM]; + CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter; + float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM]; + + int m_nPrevSequence; + int m_nRestoreSequence; + + CUtlLinkedList m_Ropes; + + float m_flPrevEventCycle; + int m_nEventSequence; + + float m_flEncodedController[MAXSTUDIOBONECTRLS]; + CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS > m_iv_flEncodedController; + float m_flOldEncodedController[MAXSTUDIOBONECTRLS]; + + bool m_bClientSideAnimation; + bool m_bLastClientSideFrameReset; + + int m_nNewSequenceParity; + int m_nResetEventsParity; + + int m_nPrevNewSequenceParity; + int m_nPrevResetEventsParity; + + bool m_builtRagdoll; + Vector m_vecPreRagdollMins; + Vector m_vecPreRagdollMaxs; + + int m_nSequence; + bool m_bReceivedSequence; + +protected: + float m_flCycle; + CInterpolatedVar< float > m_iv_flCycle; + float m_flOldCycle; + bool m_bNoModelParticles; + +private: + float m_flOldModelScale; + int m_nOldSequence; + CBoneMergeCache* m_pBoneMergeCache; + CUtlVector< matrix3x4_t > m_CachedBoneData; + memhandle_t m_hitboxBoneCacheHandle; + float m_flLastBoneSetupTime; + CJiggleBones* m_pJiggleBones; + + CUtlVector m_Attachments; + + void SetupBones_AttachmentHelper(CStudioHdr* pStudioHdr); + + EHANDLE m_hLightingOrigin; + EHANDLE m_hLightingOriginRelative; + + CNetworkVar(unsigned char, m_nMuzzleFlashParity); + unsigned char m_nOldMuzzleFlashParity; + + bool m_bInitModelEffects; + + bool m_bDynamicModelAllowed; + bool m_bDynamicModelPending; + bool m_bResetSequenceInfoOnLoad; + CRefCountedModelIndex m_AutoRefModelIndex; +public: + void EnableDynamicModels() { m_bDynamicModelAllowed = true; } + bool IsDynamicModelLoading() const { return m_bDynamicModelPending; } +private: + virtual void OnModelLoadComplete(const model_t* pModel); + +private: + void LockStudioHdr(); + void UnlockStudioHdr(); + mutable CStudioHdr* m_pStudioHdr; + mutable MDLHandle_t m_hStudioHdr; + CThreadFastMutex m_StudioHdrInitLock; +}; + +enum +{ + RAGDOLL_FRICTION_OFF = -2, + RAGDOLL_FRICTION_NONE, + RAGDOLL_FRICTION_IN, + RAGDOLL_FRICTION_HOLD, + RAGDOLL_FRICTION_OUT, +}; + +class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify +{ + +public: + C_ClientRagdoll(bool bRestoring = true); + DECLARE_CLASS(C_ClientRagdoll, C_BaseAnimating); + DECLARE_DATADESC(); + + virtual void OnPVSStatusChanged(bool bInPVS); + + virtual void Release(void); + virtual void SetupWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights); + virtual void ImpactTrace(trace_t* pTrace, int iDamageType, const char* pCustomImpactName); + void ClientThink(void); + void ReleaseRagdoll(void) { m_bReleaseRagdoll = true; } + bool ShouldSavePhysics(void) { return true; } + virtual void OnSave(); + virtual void OnRestore(); + virtual int ObjectCaps(void) { return BaseClass::ObjectCaps() | FCAP_SAVE_NON_NETWORKABLE; } + virtual IPVSNotify* GetPVSNotifyInterface() { return this; } + + void HandleAnimatedFriction(void); + virtual void SUB_Remove(void); + + void FadeOut(void); + virtual float LastBoneChangedTime(); + + bool m_bFadeOut; + bool m_bImportant; + float m_flEffectTime; + +private: + int m_iCurrentFriction; + int m_iMinFriction; + int m_iMaxFriction; + float m_flFrictionModTime; + float m_flFrictionTime; + + int m_iFrictionAnimState; + bool m_bReleaseRagdoll; + + bool m_bFadingOut; + + float m_flScaleEnd[NUM_HITBOX_FIRES]; + float m_flScaleTimeStart[NUM_HITBOX_FIRES]; + float m_flScaleTimeEnd[NUM_HITBOX_FIRES]; +}; + +inline void C_BaseAnimating::ResetSequence(int nSequence) +{ + SetSequence(nSequence); + ResetSequenceInfo(); +} + +inline float C_BaseAnimating::GetPlaybackRate() +{ + return m_flPlaybackRate; +} + +inline void C_BaseAnimating::SetPlaybackRate(float rate) +{ + m_flPlaybackRate = rate; +} + +inline const matrix3x4_t& C_BaseAnimating::GetBone(int iBone) const +{ + return m_BoneAccessor.GetBone(iBone); +} + +inline matrix3x4_t& C_BaseAnimating::GetBoneForWrite(int iBone) +{ + return m_BoneAccessor.GetBoneForWrite(iBone); +} + + +inline bool C_BaseAnimating::ShouldMuzzleFlash() const +{ + return m_nOldMuzzleFlashParity != m_nMuzzleFlashParity; +} + +inline float C_BaseAnimating::GetCycle() const +{ + return m_flCycle; +} + +inline CStudioHdr* C_BaseAnimating::GetModelPtr() const +{ + if (IsDynamicModelLoading()) + return NULL; + +#ifdef _DEBUG +#endif + if (!m_pStudioHdr) + { + const_cast(this)->LockStudioHdr(); + } + Assert(m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID); + return m_pStudioHdr; +} + + +inline void C_BaseAnimating::InvalidateMdlCache() +{ + if (m_pStudioHdr) + { + UnlockStudioHdr(); + delete m_pStudioHdr; + m_pStudioHdr = NULL; + } +} + + +inline bool C_BaseAnimating::IsModelScaleFractional() const +{ + COMPILE_TIME_ASSERT(sizeof(m_flModelScale) == sizeof(int)); + return *((const int*)&m_flModelScale) < 0x3f800000; +} + +inline bool C_BaseAnimating::IsModelScaled() const +{ + return (m_flModelScale > 1.0f + FLT_EPSILON || m_flModelScale < 1.0f - FLT_EPSILON); +} + +inline int C_BaseAnimating::GetSequence() +{ + return m_nSequence; +} + +inline bool C_BaseAnimating::IsSequenceFinished(void) +{ + return m_bSequenceFinished; +} + +inline float C_BaseAnimating::SequenceDuration(void) +{ + return SequenceDuration(GetSequence()); +} + + +inline CMouthInfo& C_BaseAnimating::MouthInfo() +{ + return m_mouth; +} + + +void GetColumn(matrix3x4_t& src, int column, Vector& dest); +void SetColumn(Vector& src, int column, matrix3x4_t& dest); + +EXTERN_RECV_TABLE(DT_BaseAnimating); + + +extern void DevMsgRT(PRINTF_FORMAT_STRING char const* pMsg, ...); + +#endif +``` + +`SpyCustom/sdk/c_baseanimatingoverlay.h`: + +```h +#ifndef C_BASEANIMATINGOVERLAY_H +#define C_BASEANIMATINGOVERLAY_H +#pragma once + +#include "c_baseanimating.h" + +#define CBaseAnimatingOverlay C_BaseAnimatingOverlay + + +class C_BaseAnimatingOverlay : public C_BaseAnimating +{ +public: + DECLARE_CLASS(C_BaseAnimatingOverlay, C_BaseAnimating); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + + C_BaseAnimatingOverlay(); + + virtual CStudioHdr* OnNewModel(); + + C_AnimationLayer* GetAnimOverlay(int i); + void SetNumAnimOverlays(int num); + int GetNumAnimOverlays() const; + + virtual void GetRenderBounds(Vector& theMins, Vector& theMaxs); + + void CheckForLayerChanges(CStudioHdr* hdr, float currentTime); + + virtual void AccumulateLayers(IBoneSetup& boneSetup, Vector pos[], Quaternion q[], float currentTime); + virtual void DoAnimationEvents(CStudioHdr* pStudioHdr); + + enum + { + MAX_OVERLAYS = 15, + }; + + CUtlVector < C_AnimationLayer > m_AnimOverlay; + + CUtlVector < CInterpolatedVar< C_AnimationLayer > > m_iv_AnimOverlay; + + float m_flOverlayPrevEventCycle[MAX_OVERLAYS]; + +private: + C_BaseAnimatingOverlay(const C_BaseAnimatingOverlay&); +}; + + +EXTERN_RECV_TABLE(DT_BaseAnimatingOverlay); + + +#endif +``` + +`SpyCustom/sdk/c_basecombatcharacter.h`: + +```h +#ifndef C_BASECOMBATCHARACTER_H +#define C_BASECOMBATCHARACTER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "c_baseflex.h" +#ifdef GLOWS_ENABLE +#include "glow_outline_effect.h" +#endif + +class C_BaseCombatWeapon; +class C_WeaponCombatShield; + +#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f + +class C_BaseCombatCharacter : public C_BaseFlex +{ + DECLARE_CLASS(C_BaseCombatCharacter, C_BaseFlex); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_BaseCombatCharacter(void); + virtual ~C_BaseCombatCharacter(void); + + virtual void OnPreDataChanged(DataUpdateType_t updateType); + virtual void OnDataChanged(DataUpdateType_t updateType); + + virtual bool IsBaseCombatCharacter(void) { return true; }; + virtual C_BaseCombatCharacter* MyCombatCharacterPointer(void) { return this; } + + enum FieldOfViewCheckType { USE_FOV, DISREGARD_FOV }; + bool IsAbleToSee(const CBaseEntity* entity, FieldOfViewCheckType checkFOV); + bool IsAbleToSee(C_BaseCombatCharacter* pBCC, FieldOfViewCheckType checkFOV); + + virtual bool IsLookingTowards(const CBaseEntity* target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE) const; + virtual bool IsLookingTowards(const Vector& target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE) const; + + virtual bool IsInFieldOfView(CBaseEntity* entity) const; + virtual bool IsInFieldOfView(const Vector& pos) const; + + enum LineOfSightCheckType + { + IGNORE_NOTHING, + IGNORE_ACTORS + }; + virtual bool IsLineOfSightClear(CBaseEntity* entity, LineOfSightCheckType checkType = IGNORE_NOTHING) const; + virtual bool IsLineOfSightClear(const Vector& pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity* entityToIgnore = NULL) const; + + + void RemoveAmmo(int iCount, int iAmmoIndex); + void RemoveAmmo(int iCount, const char* szName); + void RemoveAllAmmo(); + int GetAmmoCount(int iAmmoIndex) const; + int GetAmmoCount(char* szName) const; + + C_BaseCombatWeapon* Weapon_OwnsThisType(const char* pszWeapon, int iSubType = 0) const; + virtual bool Weapon_Switch(C_BaseCombatWeapon* pWeapon, int viewmodelindex = 0); + virtual bool Weapon_CanSwitchTo(C_BaseCombatWeapon* pWeapon); + + bool SwitchToNextBestWeapon(C_BaseCombatWeapon* pCurrent); + + virtual C_BaseCombatWeapon* GetActiveWeapon(void) const; + int WeaponCount() const; + C_BaseCombatWeapon* GetWeapon(int i) const; + + void SetAmmoCount(int iCount, int iAmmoIndex); + + float GetNextAttack() const { return m_flNextAttack; } + void SetNextAttack(float flWait) { m_flNextAttack = flWait; } + + virtual int BloodColor(); + + void SetBloodColor(int nBloodColor); + + virtual void DoMuzzleFlash(); + +#ifdef GLOWS_ENABLE + CGlowObject* GetGlowObject(void) { return m_pGlowEffect; } + virtual void GetGlowEffectColor(float* r, float* g, float* b); +#endif + +public: + + float m_flNextAttack; + +protected: + +#ifdef GLOWS_ENABLE + virtual void UpdateGlowEffect(void); + virtual void DestroyGlowEffect(void); +#endif + + int m_bloodColor; + +private: + bool ComputeLOS(const Vector& vecEyePosition, const Vector& vecTarget) const; + + CNetworkArray(int, m_iAmmo, MAX_AMMO_TYPES); + + CHandle m_hMyWeapons[MAX_WEAPONS]; + CHandle< C_BaseCombatWeapon > m_hActiveWeapon; + +#ifdef GLOWS_ENABLE + bool m_bGlowEnabled; + bool m_bOldGlowEnabled; + CGlowObject* m_pGlowEffect; +#endif + +private: + C_BaseCombatCharacter(const C_BaseCombatCharacter&); + + +#ifdef INVASION_CLIENT_DLL +public: + virtual void Release(void); + virtual void SetDormant(bool bDormant); + virtual void OnPreDataChanged(DataUpdateType_t updateType); + virtual void OnDataChanged(DataUpdateType_t updateType); + virtual void ClientThink(void); + + virtual bool CanBePoweredUp(void) { return true; } + bool HasPowerup(int iPowerup) { return (m_iPowerups & (1 << iPowerup)) != 0; }; + virtual void PowerupStart(int iPowerup, bool bInitial); + virtual void PowerupEnd(int iPowerup); + void RemoveAllPowerups(void); + + void AddEMPEffect(float flSize); + void AddBuffEffect(float flSize); + + C_WeaponCombatShield* GetShield(void); + +public: + int m_iPowerups; + int m_iPrevPowerups; +#endif + +}; + +inline C_BaseCombatCharacter* ToBaseCombatCharacter(C_BaseEntity* pEntity) +{ + if (!pEntity || !pEntity->IsBaseCombatCharacter()) + return NULL; + +#if _DEBUG + return dynamic_cast(pEntity); +#else + return static_cast(pEntity); +#endif +} + +inline int C_BaseCombatCharacter::WeaponCount() const +{ + return MAX_WEAPONS; +} + +inline C_BaseCombatWeapon* C_BaseCombatCharacter::GetWeapon(int i) const +{ + Assert((i >= 0) && (i < MAX_WEAPONS)); + return m_hMyWeapons[i].Get(); +} + +EXTERN_RECV_TABLE(DT_BaseCombatCharacter); + +#endif +``` + +`SpyCustom/sdk/c_baseentity.h`: + +```h +#ifndef CBASEENT +#define CBASEENT + +#pragma once + +//#include "icliententity.h" +#include "NetVarManager.hpp" +#include "PatternScan.hpp" +#include "netvars.hpp" + + +namespace VirtualMethod +{ + template + constexpr T call(void* classBase, Args... args) noexcept + { + return (*reinterpret_cast(classBase))[Idx](classBase, args...); + } +} + +#define VIRTUAL_METHOD(returnType, name, idx, args, argsRaw) \ +returnType name args noexcept \ +{ \ + return VirtualMethod::callargsRaw; \ +} + +#define CONCAT(a, b) a##b +#define PAD_NAME(n) CONCAT(pad, n) +#define PAD(size) \ +private: \ + std::byte PAD_NAME(__COUNTER__) [size]; \ +public: + + class ICollideable + { + public: + virtual HANDLE* GetEntityHandle() = 0; + virtual Vector& OBBMins_() = 0; + virtual Vector& OBBMaxs_() = 0; + }; + + class C_BaseEntity : public IClientEntity + { + public: + + NETVAR_OFFSET(GetIndex, "CBaseEntity", "m_bIsAutoaimTarget", +0x4, int); + NETVAR(GetModelIndex, "CBaseEntity", "m_nModelIndex", unsigned); + + NETVAR(Ragdoll, "CCSPlayer", "m_hRagdoll", int); + + NETVAR2(GetViewmodelArmConfig, "DT_CSPlayer", "m_pViewmodelArmConfig", PlayerViewmodelArmConfig*); + NETVAR2(GetArmsModel, "DT_CSPlayer", "m_szArmsModel", char*); + + NETVAR_OFFSET(m_dwBoneMatrix, "CBaseAnimating", "m_nForceBone", +0x1C, uintptr_t); + + Vector GetBonePosition(int iBone) { + uintptr_t bm = m_dwBoneMatrix(); + matrix3x4_t boneMatrix = *(matrix3x4_t*) (bm +iBone * sizeof(matrix3x4_t)) ; + return Vector(boneMatrix[0][3], boneMatrix[1][3], boneMatrix[2][3]); + } + + NETVAR(body, "CBaseAnimating", "m_nBody", int); + NETVAR(GetModelScale, "CBaseAnimating", "m_flModelScale", float); + NETVAR(GetScaleType, "CBaseAnimating", "m_ScaleType", float); + NETVAR(GetFrozen, "CBaseAnimating", "m_flFrozen", float); + + NETVAR(GetPoseParameter, "CBaseAnimating", "m_flPoseParameter", float); + + NETVAR(GetMins, "CBaseEntity", "m_vecMins", Vector); + NETVAR(GetMaxs, "CBaseEntity", "m_vecMaxs", Vector); + NETVAR(GetSimulationTime, "CBaseEntity", "m_flSimulationTime", float); + + NETVAR2(IsScoped, "DT_CSPlayer", "m_bIsScoped", bool); + NETVAR2(GetViewOffset, "DT_CSPlayer", "m_vecViewOffset[0]", Vector); + NETVAR2(GetVelocity, "DT_CSPlayer", "m_vecVelocity[0]", Vector); + + NETVAR2(GetGroundEntity, "DT_BasePlayer", "m_hGroundEntity", int); + NETVAR2(GetCollisionGroup, "DT_CSPlayer", "m_CollisionGroup", int); + + NETVAR2(GetColorRender, "DT_BaseEntity", "m_clrRender", int); + + int GetSequenceActivity(int sequence, studiohdr_t* hdr) + { + static auto getSequenceActivity = (DWORD)(FindPatternV2("client.dll", "55 8B EC 53 8B 5D 08 56 8B F1 83")); + static auto GetSequenceActivity = reinterpret_cast(getSequenceActivity); + return GetSequenceActivity(this, hdr, sequence); + } + + char* GetSequenceActivity(int sequence) + { + static auto getSequenceActivity = (DWORD)(FindPatternV2("client.dll", "55 8B EC 83 7D 08 FF 56 8B F1")); + static auto GetSequenceActivity = reinterpret_cast(getSequenceActivity); + return GetSequenceActivity(this, 0, sequence); + } + + void SendViewModelMatchingSequence(int sequence) + { + printf("Set new sequence %d\n",sequence); + typedef void(__thiscall* OriginalFn)(void*, int); + return getvfunc(this, 246)(this, sequence); + } + + bool IsVisible(C_BaseEntity* pEntity, const Vector& vecEnd) + { + const Vector vecStart = this->GetViewPos(); + + Ray_t ray; ray.Init(vecStart, vecEnd); + CTraceFilter filter(this); + + //Trace_t trace = { }; + CGameTrace trace = {}; + iff.g_pEnginetrace->TraceRay(ray, MASK_SHOT, &filter, &trace); + + // trace check + if ((trace.IsVisible() || trace.m_pEnt == pEntity)) + return true; + + return false; + } + + + }; + + class C_BaseCombatCharacter : public C_BaseEntity + { + public: + NETVAR(GetWeapons, "CBaseCombatCharacter", "m_hMyWeapons", std::array); + PNETVAR(GetWearables, "CBaseCombatCharacter", "m_hMyWearables", CBaseHandle); + NETVAR(GetActiveWeapon, "CBaseCombatCharacter", "m_hActiveWeapon", CBaseHandle); + }; + + class C_BasePlayer : public C_BaseCombatCharacter + { + public: + NETVAR(GetLifeState, "CBasePlayer", "m_lifeState", int); + NETVAR(GetViewModel, "CBasePlayer", "m_hViewModel[0]", CBaseHandle); + + NETVAR(GetOrigin, "CBaseEntity", "m_vecOrigin", Vector); + NETVAR(GetAngles, "CBaseEntity", "m_angRotation", Vector); + NETVAR(GetHealth, "CBasePlayer", "m_iHealth", int); + NETVAR2(GetArmorValue, "DT_CSPlayer", "m_ArmorValue", int); + NETVAR(GetViewOffset, "CBasePlayer", "m_vecViewOffset[0]", Vector); + NETVAR(GetTeam, "CBaseEntity", "m_iTeamNum", int); + + NETVAR2(GetFlags, "DT_CSPlayer", "m_fFlags", int); + NETVAR_OFFSET(GetMoveType, "CBaseEntity", "m_nRenderMode", +0x1, int); + + NETVAR2(GetNightvision, "DT_CSPlayer", "m_bNightVisionOn", bool); + NETVAR2(GetNightvisionAlpha, "DT_CSPlayer", "m_flNightVisionAlpha", float); + + NETVAR2(GetTickBase, "DT_BasePlayer", "m_nTickBase", unsigned); + NETVAR2(GetObserverTarget, "DT_BasePlayer", "m_hObserverTarget", short); + + NETVAR2(GetAccount, "DT_CSPlayer", "m_iAccount", int); + NETVAR2(GetAimPunchAngle, "DT_CSPlayer", "m_aimPunchAngle", Vector); + NETVAR2(GetViewPunchAngle, "DT_CSPlayer", "m_viewPunchAngle", Vector); + + NETVAR2(GetFlashMaxAlpha, "DT_CSPlayer", "m_flFlashMaxAlpha", float); + NETVAR2(GetLowerBodyYawTarget, "DT_CSPlayer", "m_flLowerBodyYawTarget", float); + NETVAR2(HasImmunity, "DT_CSPlayer", "m_bGunGameImmunity", bool); + + /* + bool isDormant() + { + static DWORD bDormantOffset = (DWORD)(*(PVOID**)(FindPatternV2(XorStr("client.dll"), XorStr("8A 81 ? ? ? ? C3 32 C0")) + 0x2)) + 8; + auto addr = std::uintptr_t(this) + bDormantOffset; + return *reinterpret_cast>(addr); + } + */ + + bool IsPlayer() + { + // @xref: "effects/nightvision" + typedef bool(__thiscall* OriginalFn)(void*); + return getvfunc(this, 157)(this); + } + + inline bool IsPlayerValid(); + + + }; + + class C_BaseCombatWeapon : public C_BaseEntity + { + public: + NETVAR(GetViewModelIndex, "CBaseCombatWeapon", "m_iViewModelIndex", int); + NETVAR(GetWorldModelIndex, "CBaseCombatWeapon", "m_iWorldModelIndex", int); + NETVAR(GetWorldDroppedModelIndex, "CBaseCombatWeapon", "m_iWorldDroppedModelIndex", int); + NETVAR(GetWeaponWorldModel, "CBaseCombatWeapon", "m_hWeaponWorldModel", CBaseHandle); + }; + + class C_BaseAttributableItem : public C_BaseCombatWeapon + { + public: + NETVAR(GetAccountID, "CBaseAttributableItem", "m_iAccountID", int); + NETVAR(GetItemDefinitionIndex, "CBaseAttributableItem", "m_iItemDefinitionIndex", short); + NETVAR(GetItemIDHigh, "CBaseAttributableItem", "m_iItemIDHigh", int); + NETVAR(GetEntityQuality, "CBaseAttributableItem", "m_iEntityQuality", int); + NETVAR(GetCustomName, "CBaseAttributableItem", "m_szCustomName", char[32]); + NETVAR(GetFallbackPaintKit, "CBaseAttributableItem", "m_nFallbackPaintKit", unsigned); + NETVAR(GetFallbackSeed, "CBaseAttributableItem", "m_nFallbackSeed", unsigned); + NETVAR(GetFallbackWear, "CBaseAttributableItem", "m_flFallbackWear", float); + NETVAR(GetFallbackStatTrak, "CBaseAttributableItem", "m_nFallbackStatTrak", unsigned); + NETVAR(initialized, "CBaseAttributableItem", "m_bInitialized", bool) + }; + + class C_BaseViewModel : public C_BaseEntity + { + public: + NETVAR(GetOwner, "CBaseViewModel", "m_hOwner", CBaseHandle); + NETVAR(GetWeapon, "CBaseViewModel", "m_hWeapon", CBaseHandle); + NETPROP(GetSequenceProp, "CBaseViewModel", "m_nSequence"); + + NETVAR(GetSequence, "CBaseViewModel", "m_nSequence", int); + }; + + class C_PlayerResource + { + public: + NETPROP(GetTeamProp, "CPlayerResource", "m_iTeam"); + }; + + class C_CS_PlayerResource : public C_PlayerResource + { + public: + NETVAR(GetRanks, "CCSPlayerResource", "m_iCompetitiveRanking", int[MAX_PLAYERS]); + NETVAR(GetRankType, "CCSPlayerResource", "m_iCompetitiveRankType", int[MAX_PLAYERS]); + NETVAR(GetWins, "CCSPlayerResource", "m_iCompetitiveWins", int[MAX_PLAYERS]); + NETVAR(GetLevel, "CCSPlayerResource", "m_nPersonaDataPublicLevel", int[MAX_PLAYERS]); + NETVAR(GetComLeader, "CCSPlayerResource", "m_nPersonaDataPublicCommendsLeader", int[MAX_PLAYERS]); + NETVAR(GetComTeacher, "CCSPlayerResource", "m_nPersonaDataPublicCommendsTeacher", int[MAX_PLAYERS]); + NETVAR(GetComFriendly, "CCSPlayerResource", "m_nPersonaDataPublicCommendsFriendly", int[MAX_PLAYERS]); + + NETVAR(GetClanTags, "CCSPlayerResource", "m_szClan", char[MAX_PLAYERS][32]); + NETVAR(GetCoins, "CCSPlayerResource", "m_nActiveCoinRank", unsigned[MAX_PLAYERS]); + NETVAR(GetMusicKits, "CCSPlayerResource", "m_nMusicID", unsigned[MAX_PLAYERS]); + + NETVAR2(GetKills, "DT_CSPlayerResource", "m_iKills", unsigned[MAX_PLAYERS]); + NETVAR2(GetAssists, "DT_CSPlayerResource", "m_iAssists", unsigned[MAX_PLAYERS]); + NETVAR2(GetDeaths, "DT_CSPlayerResource", "m_iDeaths", unsigned[MAX_PLAYERS]); + + NETVAR(GetMVPs, "CCSPlayerResource", "m_iMVPs", int[MAX_PLAYERS]); + NETVAR(GetScore, "CCSPlayerResource", "m_iScore", int[MAX_PLAYERS]); + + NETVAR(IsVIP, "CCSPlayerResource", "m_iPlayerVIP", int[MAX_PLAYERS]); + + NETVAR(GetTotalCashSpent, "CCSPlayerResource", "m_iTotalCashSpent", int[MAX_PLAYERS]); + NETVAR(GetCashSpentThisRound, "CCSPlayerResource", "m_iCashSpentThisRound", int[MAX_PLAYERS]); + NETVAR(GetMatchStats_CashEarned_Total, "CCSPlayerResource", "m_iMatchStats_CashEarned_Total", int[MAX_PLAYERS]); + + NETVAR2(IsAlive, "DT_CSPlayerResource", "m_bAlive", bool[MAX_PLAYERS]); + NETVAR2(IsConnected, "DT_CSPlayerResource", "m_bConnected", bool[MAX_PLAYERS]); + + static C_CS_PlayerResource** GetPlayerResource() + { + const auto team_arr_prop = C_CS_PlayerResource::GetTeamProp(); + const auto team_prop = team_arr_prop->m_pDataTable->m_pProps; + const auto proxy_addr = std::uintptr_t(team_prop->m_ProxyFn); + printfdbg("PlayerResource proxy_addr ptr: %x\n", proxy_addr + 0x10); + return *reinterpret_cast(proxy_addr + 0x10); + } + }; + + class CBaseWeaponWorldModel : public C_BaseEntity + { + public: + }; + + class C_GameRulesProxy : public C_BaseEntity + { + public: + NETVAR2(IsBombPlanted, "DT_CSGameRulesProxy", "m_bBombPlanted", bool); + }; + + class C_Precipitation : public C_BaseEntity + { + public: + NETVAR2(GetPrecipitationType, "DT_Precipitation", "m_nPrecipType", PrecipitationType_t); + }; + + class CPlantedC4 : public C_BaseEntity + { + public: + NETVAR2(IsBombTicking, "DT_PlantedC4", "m_bBombTicking", bool); + NETVAR2(GetC4Blow, "DT_PlantedC4", "m_flC4Blow", float); + NETVAR2(GetTimerLength, "DT_PlantedC4", "m_flTimerLength", float); + NETVAR2(GetDefuseLength, "DT_PlantedC4", "m_flDefuseLength", float); + NETVAR2(GetDefuseCountDown, "DT_PlantedC4", "m_flDefuseCountDown", float); + NETVAR2(IsBombDefused, "DT_PlantedC4", "m_bBombDefused", bool); + NETVAR2(GetBombDefuser, "DT_PlantedC4", "m_hBombDefuser", int); + NETVAR2(IsHaveBombDefuser, "DT_PlantedC4", "m_hBombDefuser", bool); + NETVAR2(GetBombSite, "DT_PlantedC4", "m_nBombSite", unsigned); + }; + + + /* + class CColliderable + { + public: + + Vector& OBBMins() + { + using OriginalFn = Vector& (__thiscall* )(void*); + return getvfunc(this, 1)(this); + } + + Vector& OBBMaxs() + { + typedef Vector&(__thiscall* OriginalFn)(void*); + return getvfunc(this, 2)(this); + } + + }; + */ + + +#endif + +``` + +`SpyCustom/sdk/c_baseflex.h`: + +```h +#ifndef C_STUDIOFLEX_H +#define C_STUDIOFLEX_H +#pragma once + + +#include "c_baseanimating.h" +#include "c_baseanimatingoverlay.h" +#include "sceneentity_shared.h" + +#include "utlvector.h" + +class CFlexSceneFile +{ +public: + enum + { + MAX_FLEX_FILENAME = 128, + }; + + char filename[MAX_FLEX_FILENAME]; + void* buffer; +}; + +struct Emphasized_Phoneme; +class CSentence; + +enum +{ + PHONEME_CLASS_WEAK = 0, + PHONEME_CLASS_NORMAL, + PHONEME_CLASS_STRONG, + + NUM_PHONEME_CLASSES +}; + +struct FS_LocalToGlobal_t +{ + explicit FS_LocalToGlobal_t() : + m_Key(0), + m_nCount(0), + m_Mapping(0) + { + } + + explicit FS_LocalToGlobal_t(const flexsettinghdr_t* key) : + m_Key(key), + m_nCount(0), + m_Mapping(0) + { + } + + void SetCount(int count) + { + Assert(!m_Mapping); + Assert(count > 0); + m_nCount = count; + m_Mapping = new int[m_nCount]; + Q_memset(m_Mapping, 0, m_nCount * sizeof(int)); + } + + FS_LocalToGlobal_t(const FS_LocalToGlobal_t& src) + { + m_Key = src.m_Key; + delete m_Mapping; + m_Mapping = new int[src.m_nCount]; + Q_memcpy(m_Mapping, src.m_Mapping, src.m_nCount * sizeof(int)); + + m_nCount = src.m_nCount; + } + + ~FS_LocalToGlobal_t() + { + delete m_Mapping; + m_nCount = 0; + m_Mapping = 0; + } + + const flexsettinghdr_t* m_Key; + int m_nCount; + int* m_Mapping; +}; + +bool FlexSettingLessFunc(const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs); + +class IHasLocalToGlobalFlexSettings +{ +public: + virtual void EnsureTranslations(const flexsettinghdr_t* pSettinghdr) = 0; +}; + +struct Emphasized_Phoneme +{ + char classname[64]; + bool required; + bool basechecked; + const flexsettinghdr_t* base; + const flexsetting_t* exp; + + bool valid; + float amount; +}; + +class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings +{ + DECLARE_CLASS(C_BaseFlex, C_BaseAnimatingOverlay); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + C_BaseFlex(); + virtual ~C_BaseFlex(); + + virtual void Spawn(); + + virtual void InitPhonemeMappings(); + + void SetupMappings(char const* pchFileRoot); + + virtual CStudioHdr* OnNewModel(void); + + virtual void StandardBlendingRules(CStudioHdr* hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask); + + virtual void OnThreadedDrawSetup(); + + virtual void BuildTransformations(CStudioHdr* pStudioHdr, Vector* pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList& boneComputed); + static void LinkToGlobalFlexControllers(CStudioHdr* hdr); + virtual void SetupWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights); + virtual bool SetupGlobalWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights); + static void RunFlexDelay(int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights, float& flFlexDelayTime); + virtual void SetupLocalWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights); + virtual bool UsesFlexDelayedWeights(); + + static void RunFlexRules(CStudioHdr* pStudioHdr, float* dest); + + virtual Vector SetViewTarget(CStudioHdr* pStudioHdr); + + virtual bool GetSoundSpatialization(SpatializationInfo_t& info); + + virtual void GetToolRecordingState(KeyValues* msg); + + void AddFlexAnimation(CSceneEventInfo* info); + + void SetFlexWeight(LocalFlexController_t index, float value); + float GetFlexWeight(LocalFlexController_t index); + + LocalFlexController_t FindFlexController(const char* szName); + +public: + Vector m_viewtarget; + CInterpolatedVar< Vector > m_iv_viewtarget; + float m_flexWeight[MAXSTUDIOFLEXCTRL]; + CInterpolatedVarArray< float, MAXSTUDIOFLEXCTRL > m_iv_flexWeight; + + int m_blinktoggle; + + static int AddGlobalFlexController(const char* szName); + static char const* GetGlobalFlexControllerName(int idx); + +public: + + void StartChoreoScene(CChoreoScene* scene); + void RemoveChoreoScene(CChoreoScene* scene); + + virtual bool StartSceneEvent(CSceneEventInfo* info, CChoreoScene* scene, CChoreoEvent* event, CChoreoActor* actor, C_BaseEntity* pTarget); + + virtual void ProcessSceneEvents(bool bFlexEvents); + + virtual bool ProcessSceneEvent(bool bFlexEvents, CSceneEventInfo* info, CChoreoScene* scene, CChoreoEvent* event); + + virtual bool ProcessSequenceSceneEvent(CSceneEventInfo* info, CChoreoScene* scene, CChoreoEvent* event); + + void ClearSceneEvents(CChoreoScene* scene, bool canceled); + + virtual bool ClearSceneEvent(CSceneEventInfo* info, bool fastKill, bool canceled); + + void AddSceneEvent(CChoreoScene* scene, CChoreoEvent* event, C_BaseEntity* pTarget = NULL, bool bClientSide = false); + + void RemoveSceneEvent(CChoreoScene* scene, CChoreoEvent* event, bool fastKill); + + bool CheckSceneEvent(float currenttime, CChoreoScene* scene, CChoreoEvent* event); + + virtual bool CheckSceneEventCompletion(CSceneEventInfo* info, float currenttime, CChoreoScene* scene, CChoreoEvent* event); + + int FlexControllerLocalToGlobal(const flexsettinghdr_t* pSettinghdr, int key); + + virtual void EnsureTranslations(const flexsettinghdr_t* pSettinghdr); + + void* FindSceneFile(const char* filename); + +private: + + bool RequestStartSequenceSceneEvent(CSceneEventInfo* info, CChoreoScene* scene, CChoreoEvent* event, CChoreoActor* actor, CBaseEntity* pTarget); + + bool ProcessFlexAnimationSceneEvent(CSceneEventInfo* info, CChoreoScene* scene, CChoreoEvent* event); + bool ProcessFlexSettingSceneEvent(CSceneEventInfo* info, CChoreoScene* scene, CChoreoEvent* event); + void AddFlexSetting(const char* expr, float scale, + const flexsettinghdr_t* pSettinghdr, bool newexpression); + + CUtlVector < CSceneEventInfo > m_SceneEvents; + CUtlVector < CChoreoScene* > m_ActiveChoreoScenes; + + bool HasSceneEvents() const; + +private: + CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal; + + float m_blinktime; + int m_prevblinktoggle; + + int m_iBlink; + LocalFlexController_t m_iEyeUpdown; + LocalFlexController_t m_iEyeRightleft; + bool m_bSearchedForEyeFlexes; + int m_iMouthAttachment; + + float m_flFlexDelayTime; + float* m_flFlexDelayedWeight; + int m_cFlexDelayedWeight; + + static int g_numflexcontrollers; + static char* g_flexcontroller[MAXSTUDIOFLEXCTRL * 4]; + static float g_flexweight[MAXSTUDIOFLEXDESC]; + +protected: + + Emphasized_Phoneme m_PhonemeClasses[NUM_PHONEME_CLASSES]; + +private: + + C_BaseFlex(const C_BaseFlex&); + + const flexsetting_t* FindNamedSetting(const flexsettinghdr_t* pSettinghdr, const char* expr); + + void ProcessVisemes(Emphasized_Phoneme* classes); + void AddVisemesForSentence(Emphasized_Phoneme* classes, float emphasis_intensity, CSentence* sentence, float t, float dt, bool juststarted); + void AddViseme(Emphasized_Phoneme* classes, float emphasis_intensity, int phoneme, float scale, bool newexpression); + bool SetupEmphasisBlend(Emphasized_Phoneme* classes, int phoneme); + void ComputeBlendedSetting(Emphasized_Phoneme* classes, float emphasis_intensity); + +#ifdef HL2_CLIENT_DLL +public: + + Vector m_vecLean; + CInterpolatedVar< Vector > m_iv_vecLean; + Vector m_vecShift; + CInterpolatedVar< Vector > m_iv_vecShift; +#endif +}; + + +class CFlexSceneFileManager : CAutoGameSystem +{ +public: + + CFlexSceneFileManager() : CAutoGameSystem("CFlexSceneFileManager") + { + } + + virtual bool Init(); + virtual void Shutdown(); + + void EnsureTranslations(IHasLocalToGlobalFlexSettings* instance, const flexsettinghdr_t* pSettinghdr); + void* FindSceneFile(IHasLocalToGlobalFlexSettings* instance, const char* filename, bool allowBlockingIO); + +private: + void DeleteSceneFiles(); + + CUtlVector< CFlexSceneFile* > m_FileList; +}; + + +inline bool C_BaseFlex::HasSceneEvents() const +{ + return m_SceneEvents.Count() != 0; +} + + +EXTERN_RECV_TABLE(DT_BaseFlex); + +float* GetVisemeWeights(int phoneme); + + +#endif + +``` + +`SpyCustom/sdk/c_baseplayer.h`: + +```h +#ifndef C_BASEPLAYER_H +#define C_BASEPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_playerlocaldata.h" +#include "c_basecombatcharacter.h" + +#include "usercmd.h" +#include "shareddefs.h" +#include "timedevent.h" +#include "smartptr.h" + +#include "igameevents.h" +#include "GameEventListener.h" + +#if defined USES_ECON_ITEMS +#include "econ_item.h" +#include "game_item_schema.h" +#include "econ_item_view.h" +#endif + +class C_BaseCombatWeapon; +class C_BaseViewModel; +class C_FuncLadder; +class CFlashlightEffect; +class C_EconWearable; + +extern int g_nKillCamMode; +extern int g_nKillCamTarget1; +extern int g_nKillCamTarget2; + +class C_CommandContext +{ +public: + bool needsprocessing; + + CUserCmd cmd; + int command_number; +}; + +class C_PredictionError +{ +public: + float time; + Vector error; +}; + +#define CHASE_CAM_DISTANCE_MIN 16.0f +#define CHASE_CAM_DISTANCE_MAX 96.0f +#define WALL_OFFSET 6.0f + + +bool IsInFreezeCam(void); + +class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener +{ +public: + DECLARE_CLASS(C_BasePlayer, C_BaseCombatCharacter); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + C_BasePlayer(); + virtual ~C_BasePlayer(); + + virtual void Spawn(void); + virtual void SharedSpawn(); + virtual bool GetSteamID(CSteamID* pID); + + virtual void OnPreDataChanged(DataUpdateType_t updateType); + virtual void OnDataChanged(DataUpdateType_t updateType); + + virtual void PreDataUpdate(DataUpdateType_t updateType); + virtual void PostDataUpdate(DataUpdateType_t updateType); + + virtual void ReceiveMessage(int classID, bf_read& msg); + + virtual void OnRestore(); + + virtual void AddEntity(void); + + virtual void MakeTracer(const Vector& vecTracerSrc, const trace_t& tr, int iTracerType); + + virtual void GetToolRecordingState(KeyValues* msg); + + virtual float GetPlayerMaxSpeed(); + + void SetAnimationExtension(const char* pExtension); + + C_BaseViewModel* GetViewModel(int viewmodelindex = 0, bool bObserverOK = true); + C_BaseCombatWeapon* GetActiveWeapon(void) const; + const char* GetTracerType(void); + + virtual void CalcView(Vector& eyeOrigin, QAngle& eyeAngles, float& zNear, float& zFar, float& fov); + virtual void CalcViewModelView(const Vector& eyeOrigin, const QAngle& eyeAngles); + + + void SmoothViewOnStairs(Vector& eyeOrigin); + virtual float CalcRoll(const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed); + void CalcViewRoll(QAngle& eyeAngles); + void CreateWaterEffects(void); + + virtual void SetPlayerUnderwater(bool state); + void UpdateUnderwaterState(void); + bool IsPlayerUnderwater(void) { return m_bPlayerUnderwater; } + + virtual Vector Weapon_ShootPosition(); + virtual void Weapon_DropPrimary(void) {} + + virtual Vector GetAutoaimVector(float flScale); + void SetSuitUpdate(const char* name, int fgroup, int iNoRepeat); + + virtual bool CreateMove(float flInputSampleTime, CUserCmd* pCmd); + virtual void AvoidPhysicsProps(CUserCmd* pCmd); + + virtual void PlayerUse(void); + CBaseEntity* FindUseEntity(void); + virtual bool IsUseableEntity(CBaseEntity* pEntity, unsigned int requiredCaps); + + virtual bool IsPlayer(void) const { return true; } + virtual int GetHealth() const { return m_iHealth; } + + int GetBonusProgress() const { return m_iBonusProgress; } + int GetBonusChallenge() const { return m_iBonusChallenge; } + + virtual int GetObserverMode() const; + void SetObserverMode(int iNewMode); + virtual CBaseEntity* GetObserverTarget() const; + void SetObserverTarget(EHANDLE hObserverTarget); + + bool AudioStateIsUnderwater(Vector vecMainViewOrigin); + + bool IsObserver() const; + bool IsHLTV() const; + bool IsReplay() const; + void ResetObserverMode(); + bool IsBot(void) const { return false; } + + virtual Vector EyePosition(); + virtual const QAngle& EyeAngles(); + void EyePositionAndVectors(Vector* pPosition, Vector* pForward, Vector* pRight, Vector* pUp); + virtual const QAngle& LocalEyeAngles(); + + virtual IRagdoll* GetRepresentativeRagdoll() const; + + virtual void GetRagdollInitBoneArrays(matrix3x4_t* pDeltaBones0, matrix3x4_t* pDeltaBones1, matrix3x4_t* pCurrentBones, float boneDt); + + void EyeVectors(Vector* pForward, Vector* pRight = NULL, Vector* pUp = NULL); + void CacheVehicleView(void); + + + bool IsSuitEquipped(void) { return m_Local.m_bWearingSuit; }; + + virtual void TeamChange(int iNewTeam); + + void Flashlight(void); + void UpdateFlashlight(void); + + virtual bool IsAllowedToSwitchWeapons(void) { return !IsObserver(); } + virtual C_BaseCombatWeapon* GetActiveWeaponForSelection(void); + + virtual C_BaseAnimating* GetRenderedWeaponModel(); + + virtual bool IsOverridingViewmodel(void) { return false; }; + virtual int DrawOverriddenViewmodel(C_BaseViewModel* pViewmodel, int flags) { return 0; }; + + virtual float GetDefaultAnimSpeed(void) { return 1.0; } + + void SetMaxSpeed(float flMaxSpeed) { m_flMaxspeed = flMaxSpeed; } + float MaxSpeed() const { return m_flMaxspeed; } + + virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } + + virtual bool ShouldReceiveProjectedTextures(int flags) + { + return false; + } + + + bool IsLocalPlayer(void) const; + + virtual void ThirdPersonSwitch(bool bThirdperson); + static bool LocalPlayerInFirstPersonView(); + static bool ShouldDrawLocalPlayer(); + static C_BasePlayer* GetLocalPlayer(void); + int GetUserID(void); + virtual bool CanSetSoundMixer(void); + virtual int GetVisionFilterFlags(bool bWeaponsCheck = false) { return 0x00; } + bool HasVisionFilterFlags(int nFlags, bool bWeaponsCheck = false) { return (GetVisionFilterFlags(bWeaponsCheck) & nFlags) == nFlags; } + virtual void CalculateVisionUsingCurrentFlags(void) {} + void BuildFirstPersonMeathookTransformations(CStudioHdr* hdr, Vector* pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList& boneComputed, const char* pchHeadBoneName); + + bool InFirstPersonView(); + bool ShouldDrawThisPlayer(); + + virtual bool ViewModel_IsTransparent(void); + virtual bool ViewModel_IsUsingFBTexture(void); + +#if !defined( NO_ENTITY_PREDICTION ) + void AddToPlayerSimulationList(C_BaseEntity* other); + void SimulatePlayerSimulatedEntities(void); + void RemoveFromPlayerSimulationList(C_BaseEntity* ent); + void ClearPlayerSimulationList(void); +#endif + + virtual void PhysicsSimulate(void); + virtual unsigned int PhysicsSolidMaskForEntity(void) const { return MASK_PLAYERSOLID; } + + virtual bool ShouldPredict(void); + + virtual void PreThink(void); + virtual void PostThink(void); + + virtual void ItemPreFrame(void); + virtual void ItemPostFrame(void); + virtual void AbortReload(void); + + virtual void SelectLastItem(void); + virtual void Weapon_SetLast(C_BaseCombatWeapon* pWeapon); + virtual bool Weapon_ShouldSetLast(C_BaseCombatWeapon* pOldWeapon, C_BaseCombatWeapon* pNewWeapon) { return true; } + virtual bool Weapon_ShouldSelectItem(C_BaseCombatWeapon* pWeapon); + virtual bool Weapon_Switch(C_BaseCombatWeapon* pWeapon, int viewmodelindex = 0); + virtual C_BaseCombatWeapon* GetLastWeapon(void) { return m_hLastWeapon.Get(); } + void ResetAutoaim(void); + virtual void SelectItem(const char* pstr, int iSubType = 0); + + virtual void UpdateClientData(void); + + virtual float GetFOV(void); + int GetDefaultFOV(void) const; + virtual bool IsZoomed(void) { return false; } + bool SetFOV(CBaseEntity* pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0); + void ClearZoomOwner(void); + + float GetFOVDistanceAdjustFactor(); + + virtual void ViewPunch(const QAngle& angleOffset); + void ViewPunchReset(float tolerance = 0); + + void UpdateButtonState(int nUserCmdButtonMask); + int GetImpulse(void) const; + + virtual void Simulate(); + + virtual bool ShouldInterpolate(); + + virtual bool ShouldDraw(); + virtual int DrawModel(int flags); + + virtual void OverrideView(CViewSetup* pSetup); + + const char* GetPlayerName(); + virtual const Vector GetPlayerMins(void) const; + virtual const Vector GetPlayerMaxs(void) const; + + bool IsPlayerDead(); + bool IsPoisoned(void) { return m_Local.m_bPoisoned; } + + C_BaseEntity* GetUseEntity(); + + IClientVehicle* GetVehicle(); + + bool IsInAVehicle() const { return (NULL != m_hVehicle.Get()) ? true : false; } + virtual void SetVehicleRole(int nRole); + void LeaveVehicle(void); + + bool UsingStandardWeaponsInVehicle(void); + + virtual void SetAnimation(PLAYER_ANIM playerAnim); + + float GetTimeBase(void) const; + float GetFinalPredictedTime() const; + + bool IsInVGuiInputMode() const; + bool IsInViewModelVGuiInputMode() const; + + C_CommandContext* GetCommandContext(); + + int CurrentCommandNumber() const; + const CUserCmd* GetCurrentUserCommand() const; + + const QAngle& GetPunchAngle(); + void SetPunchAngle(const QAngle& angle); + + float GetWaterJumpTime() const; + void SetWaterJumpTime(float flWaterJumpTime); + float GetSwimSoundTime(void) const; + void SetSwimSoundTime(float flSwimSoundTime); + + float GetDeathTime(void) { return m_flDeathTime; } + + void SetPreviouslyPredictedOrigin(const Vector& vecAbsOrigin); + const Vector& GetPreviouslyPredictedOrigin() const; + + virtual float GetMinFOV() const; + + virtual void DoMuzzleFlash(); + virtual void PlayPlayerJingle(); + + virtual void UpdateStepSound(surfacedata_t* psurface, const Vector& vecOrigin, const Vector& vecVelocity); + virtual void PlayStepSound(Vector& vecOrigin, surfacedata_t* psurface, float fvol, bool force); + virtual surfacedata_t* GetFootstepSurface(const Vector& origin, const char* surfaceName); + virtual void GetStepSoundVelocities(float* velwalk, float* velrun); + virtual void SetStepSoundTime(stepsoundtimes_t iStepSoundTime, bool bWalking); + virtual const char* GetOverrideStepSound(const char* pszBaseStepSoundName) { return pszBaseStepSoundName; } + + virtual void OnEmitFootstepSound(const CSoundParameters& params, const Vector& vecOrigin, float fVolume) {} + + void NotePredictionError(const Vector& vDelta); + + void GetPredictionErrorSmoothingVector(Vector& vOffset); + + virtual void ExitLadder() {} + surfacedata_t* GetLadderSurface(const Vector& origin); + + surfacedata_t* GetSurfaceData(void) { return m_pSurfaceData; } + + void SetLadderNormal(Vector vecLadderNormal) { m_vecLadderNormal = vecLadderNormal; } + + virtual CHintSystem* Hints(void) { return NULL; } + bool ShouldShowHints(void) { return Hints() ? Hints()->ShouldShowHints() : false; } + bool HintMessage(int hint, bool bForce = false, bool bOnlyIfClear = false) { return Hints() ? Hints()->HintMessage(hint, bForce, bOnlyIfClear) : false; } + void HintMessage(const char* pMessage) { if (Hints()) Hints()->HintMessage(pMessage); } + + virtual IMaterial* GetHeadLabelMaterial(void); + + fogparams_t* GetFogParams(void) { return &m_CurrentFog; } + void FogControllerChanged(bool bSnap); + void UpdateFogController(void); + void UpdateFogBlend(void); + + float GetFOVTime(void) { return m_flFOVTime; } + + virtual void OnAchievementAchieved(int iAchievement) {} + + bool ShouldAnnounceAchievement(void) { return m_flNextAchievementAnnounceTime < gpGlobals->curtime; } + void SetNextAchievementAnnounceTime(float flTime) { m_flNextAchievementAnnounceTime = flTime; } + +#if defined USES_ECON_ITEMS + void UpdateWearables(); + C_EconWearable* GetWearable(int i) { return m_hMyWearables[i]; } + int GetNumWearables(void) { return m_hMyWearables.Count(); } +#endif + + bool HasFiredWeapon(void) { return m_bFiredWeapon; } + void SetFiredWeapon(bool bFlag) { m_bFiredWeapon = bFlag; } + + virtual bool CanUseFirstPersonCommand(void) { return true; } + +protected: + fogparams_t m_CurrentFog; + EHANDLE m_hOldFogController; + +public: + int m_StuckLast; + + CNetworkVarEmbedded(CPlayerLocalData, m_Local); + +#if defined USES_ECON_ITEMS + CNetworkVarEmbedded(CAttributeList, m_AttributeList); +#endif + + CPlayerState pl; + + int m_iFOV; + int m_iFOVStart; + float m_flFOVTime; + int m_iDefaultFOV; + EHANDLE m_hZoomOwner; + bool m_fOnTarget; + + char m_szAnimExtension[32]; + + int m_afButtonLast; + int m_afButtonPressed; + int m_afButtonReleased; + + int m_nButtons; + + CUserCmd* m_pCurrentCommand; + + EHANDLE m_hConstraintEntity; + Vector m_vecConstraintCenter; + float m_flConstraintRadius; + float m_flConstraintWidth; + float m_flConstraintSpeedFactor; + +protected: + + void CalcPlayerView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + void CalcVehicleView(IClientVehicle* pVehicle, Vector& eyeOrigin, QAngle& eyeAngles, + float& zNear, float& zFar, float& fov); + virtual void CalcObserverView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual Vector GetChaseCamViewOffset(CBaseEntity* target); + void CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual void CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + + virtual float GetDeathCamInterpolationTime(); + + virtual void CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual void CalcFreezeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + + void DetermineVguiInputMode(CUserCmd* pCmd); + + virtual void SetLocalViewAngles(const QAngle& viewAngles); + virtual void SetViewAngles(const QAngle& ang); + + surfacedata_t* GetGroundSurface(); + + virtual void FireGameEvent(IGameEvent* event); + +protected: + bool JustEnteredVehicle(); + + int m_iObserverMode; + EHANDLE m_hObserverTarget; + float m_flObserverChaseDistance; + Vector m_vecFreezeFrameStart; + float m_flFreezeFrameStartTime; + float m_flFreezeFrameDistance; + bool m_bWasFreezeFraming; + float m_flDeathTime; + + float m_flStepSoundTime; + bool m_IsFootprintOnLeft; + +private: + C_BasePlayer& operator=(const C_BasePlayer& src); + C_BasePlayer(const C_BasePlayer&); + + EHANDLE m_hVehicle; + EHANDLE m_hOldVehicle; + EHANDLE m_hUseEntity; + + float m_flMaxspeed; + + int m_iBonusProgress; + int m_iBonusChallenge; + + CInterpolatedVar< Vector > m_iv_vecViewOffset; + + Vector m_vecWaterJumpVel; + float m_flWaterJumpTime; + int m_nImpulse; + + float m_flSwimSoundTime; + Vector m_vecLadderNormal; + + QAngle m_vecOldViewAngles; + + bool m_bWasFrozen; + int m_flPhysics; + + int m_nTickBase; + int m_nFinalPredictedTick; + + EHANDLE m_pCurrentVguiScreen; + + bool m_bFiredWeapon; + + + CFlashlightEffect* m_pFlashlight; + + typedef CHandle CBaseCombatWeaponHandle; + CNetworkVar(CBaseCombatWeaponHandle, m_hLastWeapon); + +#if !defined( NO_ENTITY_PREDICTION ) + CUtlVector< CHandle< C_BaseEntity > > m_SimulatedByThisPlayer; +#endif + + CHandle< C_BaseViewModel > m_hViewModel[MAX_VIEWMODELS]; + + float m_flOldPlayerZ; + float m_flOldPlayerViewOffsetZ; + + Vector m_vecVehicleViewOrigin; + QAngle m_vecVehicleViewAngles; + float m_flVehicleViewFOV; + int m_nVehicleViewSavedFrame; + + int m_iOldAmmo[MAX_AMMO_TYPES]; + + C_CommandContext m_CommandContext; + + float m_flWaterSurfaceZ; + bool m_bResampleWaterSurface; + TimedEvent m_tWaterParticleTimer; + CSmartPtr m_pWaterEmitter; + + bool m_bPlayerUnderwater; + + friend class CPrediction; + + friend class CTFGameMovementRecon; + friend class CGameMovement; + friend class CTFGameMovement; + friend class CHL1GameMovement; + friend class CCSGameMovement; + friend class CHL2GameMovement; + friend class CDODGameMovement; + friend class CPortalGameMovement; + + float GetStepSize(void) const { return m_Local.m_flStepSize; } + + float m_flNextAvoidanceTime; + float m_flAvoidanceRight; + float m_flAvoidanceForward; + float m_flAvoidanceDotForward; + float m_flAvoidanceDotRight; + +protected: + virtual bool IsDucked(void) const { return m_Local.m_bDucked; } + virtual bool IsDucking(void) const { return m_Local.m_bDucking; } + virtual float GetFallVelocity(void) { return m_Local.m_flFallVelocity; } + void ForceSetupBonesAtTimeFakeInterpolation(matrix3x4_t* pBonesOut, float curtimeOffset); + + float m_flLaggedMovementValue; + + Vector m_vecPredictionError; + float m_flPredictionErrorTime; + + Vector m_vecPreviouslyPredictedOrigin; + + char m_szLastPlaceName[MAX_PLACE_NAME_LENGTH]; + + int m_surfaceProps; + surfacedata_t* m_pSurfaceData; + float m_surfaceFriction; + char m_chTextureType; + + bool m_bSentFreezeFrame; + float m_flFreezeZOffset; + + float m_flNextAchievementAnnounceTime; + + int m_nForceVisionFilterFlags; + +#if defined USES_ECON_ITEMS + CUtlVector > m_hMyWearables; +#endif + +private: + + struct StepSoundCache_t + { + StepSoundCache_t() : m_usSoundNameIndex(0) {} + CSoundParameters m_SoundParameters; + unsigned short m_usSoundNameIndex; + }; + StepSoundCache_t m_StepSoundCache[2]; + +public: + + const char* GetLastKnownPlaceName(void) const { return m_szLastPlaceName; } + + float GetLaggedMovementValue(void) { return m_flLaggedMovementValue; } + bool ShouldGoSouth(Vector vNPCForward, Vector vNPCRight); + + void SetOldPlayerZ(float flOld) { m_flOldPlayerZ = flOld; } +}; + +EXTERN_RECV_TABLE(DT_BasePlayer); + +inline C_BasePlayer* ToBasePlayer(C_BaseEntity* pEntity) +{ + if (!pEntity || !pEntity->IsPlayer()) + return NULL; + +#if _DEBUG + Assert(dynamic_cast(pEntity) != NULL); +#endif + + return static_cast(pEntity); +} + +inline C_BaseEntity* C_BasePlayer::GetUseEntity() +{ + return m_hUseEntity; +} + + +inline IClientVehicle* C_BasePlayer::GetVehicle() +{ + C_BaseEntity* pVehicleEnt = m_hVehicle.Get(); + return pVehicleEnt ? pVehicleEnt->GetClientVehicle() : NULL; +} + +inline bool C_BasePlayer::IsObserver() const +{ + return (GetObserverMode() != OBS_MODE_NONE); +} + +inline int C_BasePlayer::GetImpulse(void) const +{ + return m_nImpulse; +} + + +inline C_CommandContext* C_BasePlayer::GetCommandContext() +{ + return &m_CommandContext; +} + +inline int CBasePlayer::CurrentCommandNumber() const +{ + Assert(m_pCurrentCommand); + return m_pCurrentCommand->command_number; +} + +inline const CUserCmd* CBasePlayer::GetCurrentUserCommand() const +{ + Assert(m_pCurrentCommand); + return m_pCurrentCommand; +} + +#endif +``` + +`SpyCustom/sdk/c_basetempentity.h`: + +```h +#ifndef C_BASETEMPENTITY_H +#define C_BASETEMPENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "client_class.h" +#include "iclientnetworkable.h" +#include "c_recipientfilter.h" + + +class C_BaseTempEntity : public IClientUnknown, public IClientNetworkable + +{ +public: + DECLARE_CLASS_NOBASE(C_BaseTempEntity); + DECLARE_CLIENTCLASS(); + + C_BaseTempEntity(void); + virtual ~C_BaseTempEntity(void); + + +public: + + virtual void SetRefEHandle(const CBaseHandle& handle) { Assert(false); } + virtual const CBaseHandle& GetRefEHandle() const { return *((CBaseHandle*)0); } + + virtual IClientUnknown* GetIClientUnknown() { return this; } + virtual ICollideable* GetCollideable() { return 0; } + virtual IClientNetworkable* GetClientNetworkable() { return this; } + virtual IClientRenderable* GetClientRenderable() { return 0; } + virtual IClientEntity* GetIClientEntity() { return 0; } + virtual C_BaseEntity* GetBaseEntity() { return 0; } + virtual IClientThinkable* GetClientThinkable() { return 0; } + virtual IClientModelRenderable* GetClientModelRenderable() { return 0; } + virtual IClientAlphaProperty* GetClientAlphaProperty() { return 0; } + +public: + + virtual void Release(); + virtual void NotifyShouldTransmit(ShouldTransmitState_t state); + virtual void PreDataUpdate(DataUpdateType_t updateType); + virtual void PostDataUpdate(DataUpdateType_t updateType); + virtual void OnPreDataChanged(DataUpdateType_t updateType); + virtual void OnDataChanged(DataUpdateType_t updateType); + virtual void SetDormant(bool bDormant); + virtual bool IsDormant(void); + virtual int entindex(void) const; + virtual void ReceiveMessage(int classID, bf_read& msg); + virtual void* GetDataTableBasePtr(); + virtual void SetDestroyedOnRecreateEntities(void); + +public: + + void NetworkStateChanged() {} + void NetworkStateChanged(void* pVar) {} + + virtual bool Init(int entnum, int iSerialNum); + + virtual void Precache(void); + + virtual bool ShouldDestroy(void) { return false; }; + + C_BaseTempEntity* GetNext(void); + + static C_BaseTempEntity* GetList(void); + + C_BaseTempEntity* GetNextDynamic(void); + + void GetColorModulation(float* color) + { + assert(color); + color[0] = color[1] = color[2] = 1.0f; + } + + virtual bool ShouldReceiveProjectedTextures(int flags) { return false; } + +public: + static C_BaseTempEntity* GetDynamicList(); + + static void PrecacheTempEnts(void); + + static void ClearDynamicTempEnts(void); + + static void CheckDynamicTempEnts(void); + +private: + + C_BaseTempEntity* m_pNext; + C_BaseTempEntity* m_pNextDynamic; + + static C_BaseTempEntity* s_pTempEntities; + static C_BaseTempEntity* s_pDynamicEntities; +}; + + +#endif +``` + +`SpyCustom/sdk/c_input.h`: + +```h +#pragma once + +#include "usercmd.h" +#define MULTIPLAYER_BACKUP 150 + +class bf_write; +class bf_read; + +class CVerifiedUserCmd +{ +public: + CUserCmd m_cmd; + CRC32_t m_crc; +}; + +class CInput +{ +public: + virtual void Init_All(void); + virtual void Shutdown_All(void); + virtual int GetButtonBits(int); + virtual void CreateMove(int sequence_number, float input_sample_frametime, bool active); + virtual void ExtraMouseSample(float frametime, bool active); + virtual bool WriteUsercmdDeltaToBuffer(bf_write* buf, int from, int to, bool isnewcommand); + virtual void EncodeUserCmdToBuffer(bf_write& buf, int slot); + virtual void DecodeUserCmdFromBuffer(bf_read& buf, int slot); + + + inline CUserCmd* GetUserCmd(int sequence_number); + inline CVerifiedUserCmd* GetVerifiedCmd(int sequence_number); + + bool m_fTrackIRAvailable; + bool m_fMouseInitialized; + bool m_fMouseActive; + bool m_fJoystickAdvancedInit; + char pad_0x08[0x2C]; + void* m_pKeys; + char pad_0x38[0x6C]; + bool m_fCameraInterceptingMouse; + bool m_fCameraInThirdPerson; + bool m_fCameraMovingWithMouse; + Vector m_vecCameraOffset; + bool m_fCameraDistanceMove; + int m_nCameraOldX; + int m_nCameraOldY; + int m_nCameraX; + int m_nCameraY; + bool m_CameraIsOrthographic; + QAngle m_angPreviousViewAngles; + QAngle m_angPreviousViewAnglesTilt; + float m_flLastForwardMove; + int m_nClearInputState; + CUserCmd* m_pCommands; + CVerifiedUserCmd* m_pVerifiedCommands; +}; + +CUserCmd* CInput::GetUserCmd(int sequence_number) +{ + return &m_pCommands[sequence_number % MULTIPLAYER_BACKUP]; +} + +CVerifiedUserCmd* CInput::GetVerifiedCmd(int sequence_number) +{ + return &m_pVerifiedCommands[sequence_number % MULTIPLAYER_BACKUP]; +} + + +#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_LOOKSPIN (1 << 25) +``` + +`SpyCustom/sdk/c_pixel_visibility.h`: + +```h +#ifndef C_PIXEL_VISIBILITY_H +#define C_PIXEL_VISIBILITY_H +#ifdef _WIN32 +#pragma once +#endif + + +const float PIXELVIS_DEFAULT_PROXY_SIZE = 2.0f; +const float PIXELVIS_DEFAULT_FADE_TIME = 0.0625f; + +typedef int pixelvis_handle_t; +struct pixelvis_queryparams_t +{ + pixelvis_queryparams_t() + { + bSetup = false; + } + + void Init(const Vector& origin, float proxySizeIn = PIXELVIS_DEFAULT_PROXY_SIZE, float proxyAspectIn = 1.0f, float fadeTimeIn = PIXELVIS_DEFAULT_FADE_TIME) + { + position = origin; + proxySize = proxySizeIn; + proxyAspect = proxyAspectIn; + fadeTime = fadeTimeIn; + bSetup = true; + bSizeInScreenspace = false; + } + + Vector position; + float proxySize; + float proxyAspect; + float fadeTime; + bool bSetup; + bool bSizeInScreenspace; +}; + +float PixelVisibility_FractionVisible(const pixelvis_queryparams_t& params, pixelvis_handle_t* queryHandle); +float StandardGlowBlend(const pixelvis_queryparams_t& params, pixelvis_handle_t* queryHandle, int rendermode, int renderfx, int alpha, float* pscale); + +void PixelVisibility_ShiftVisibilityViews(int iSourceViewID, int iDestViewID); + +void PixelVisibility_EndCurrentView(); +void PixelVisibility_EndScene(); +float GlowSightDistance(const Vector& glowOrigin, bool bShouldTrace); + +bool PixelVisibility_IsAvailable(); + +#endif +``` + +`SpyCustom/sdk/c_playerlocaldata.h`: + +```h +#ifndef C_PLAYERLOCALDATA_H +#define C_PLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "vector.h" +#include "playernet_vars.h" +#include "interpolatedvar.h" +#include "predictable_entity.h" + +class CPlayerLocalData +{ +public: + DECLARE_PREDICTABLE(); + DECLARE_CLASS_NOBASE(CPlayerLocalData); + DECLARE_EMBEDDED_NETWORKVAR(); + + CPlayerLocalData() : + m_iv_vecPunchAngle("CPlayerLocalData::m_iv_vecPunchAngle"), + m_iv_vecPunchAngleVel("CPlayerLocalData::m_iv_vecPunchAngleVel") + { + m_iv_vecPunchAngle.Setup(&m_vecPunchAngle.m_Value, LATCH_SIMULATION_VAR); + m_iv_vecPunchAngleVel.Setup(&m_vecPunchAngleVel.m_Value, LATCH_SIMULATION_VAR); + m_flFOVRate = 0; + } + + unsigned char m_chAreaBits[MAX_AREA_STATE_BYTES]; + unsigned char m_chAreaPortalBits[MAX_AREA_PORTAL_STATE_BYTES]; + + int m_iHideHUD; + + float m_flFOVRate; + + + bool m_bDucked; + bool m_bDucking; + bool m_bInDuckJump; + float m_flDucktime; + float m_flDuckJumpTime; + float m_flJumpTime; + int m_nStepside; + float m_flFallVelocity; + int m_nOldButtons; + Vector m_vecClientBaseVelocity; + CNetworkQAngle(m_vecPunchAngle); + CInterpolatedVar< QAngle > m_iv_vecPunchAngle; + + CNetworkQAngle(m_vecPunchAngleVel); + CInterpolatedVar< QAngle > m_iv_vecPunchAngleVel; + bool m_bDrawViewmodel; + bool m_bWearingSuit; + bool m_bPoisoned; + float m_flStepSize; + bool m_bAllowAutoMovement; + + sky3dparams_t m_skybox3d; + fogplayerparams_t m_PlayerFog; + audioparams_t m_audio; + + bool m_bSlowMovement; + +}; + +#endif +``` + +`SpyCustom/sdk/c_recipientfilter.h`: + +```h +#ifndef C_RECIPIENTFILTER_H +#define C_RECIPIENTFILTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "irecipientfilter.h" +#include "utlvector.h" +#include "c_baseentity.h" +#include "soundflags.h" +#include "bitvec.h" + +class C_BasePlayer; +class C_Team; + +class C_RecipientFilter : public IRecipientFilter +{ +public: + C_RecipientFilter(); + virtual ~C_RecipientFilter(); + + virtual bool IsReliable(void) const; + + virtual int GetRecipientCount(void) const; + virtual int GetRecipientIndex(int slot) const; + + virtual bool IsInitMessage(void) const { return false; }; + +public: + + void CopyFrom(const C_RecipientFilter& src); + + void Reset(void); + + void MakeReliable(void); + + void AddAllPlayers(void); + void AddRecipientsByPVS(const Vector& origin); + void AddRecipientsByPAS(const Vector& origin); + void AddRecipient(C_BasePlayer* player); + void RemoveRecipient(C_BasePlayer* player); + void AddRecipientsByTeam(C_Team* team); + void RemoveRecipientsByTeam(C_Team* team); + + void UsePredictionRules(void); + bool IsUsingPredictionRules(void) const; + + bool IgnorePredictionCull(void) const; + void SetIgnorePredictionCull(bool ignore); + + void AddPlayersFromBitMask(CPlayerBitVec& playerbits); + + void RemoveSplitScreenPlayers(); + +private: + + bool m_bReliable; + bool m_bInitMessage; + CUtlVector< int > m_Recipients; + bool m_bUsingPredictionRules; + bool m_bIgnorePredictionCull; +}; + +class CSingleUserRecipientFilter : public C_RecipientFilter +{ +public: + CSingleUserRecipientFilter(C_BasePlayer* player) + { + AddRecipient(player); + } +}; + +class CBroadcastRecipientFilter : public C_RecipientFilter +{ +public: + CBroadcastRecipientFilter(void) + { + AddAllPlayers(); + } +}; + +class CReliableBroadcastRecipientFilter : public CBroadcastRecipientFilter +{ +public: + CReliableBroadcastRecipientFilter(void) + { + MakeReliable(); + } +}; + +class CPASFilter : public C_RecipientFilter +{ +public: + CPASFilter(const Vector& origin) + { + AddRecipientsByPAS(origin); + } +}; + +class CPASAttenuationFilter : public CPASFilter +{ +public: + CPASAttenuationFilter(C_BaseEntity* entity, float attenuation = ATTN_NORM) : + CPASFilter(entity->GetAbsOrigin()) + { + } + + CPASAttenuationFilter(const Vector& origin, float attenuation = ATTN_NORM) : + CPASFilter(origin) + { + } + + CPASAttenuationFilter(C_BaseEntity* entity, const char* lookupSound) : + CPASFilter(entity->GetAbsOrigin()) + { + } + + CPASAttenuationFilter(const Vector& origin, const char* lookupSound) : + CPASFilter(origin) + { + } + + CPASAttenuationFilter(C_BaseEntity* entity, const char* lookupSound, HSOUNDSCRIPTHANDLE& handle) : + CPASFilter(entity->GetAbsOrigin()) + { + } + + CPASAttenuationFilter(const Vector& origin, const char* lookupSound, HSOUNDSCRIPTHANDLE& handle) : + CPASFilter(origin) + { + } +}; + +class CPVSFilter : public C_RecipientFilter +{ +public: + CPVSFilter(const Vector& origin) + { + AddRecipientsByPVS(origin); + } +}; + +class CLocalPlayerFilter : public C_RecipientFilter +{ +public: + CLocalPlayerFilter(void); +}; + +#endif +``` + +`SpyCustom/sdk/c_te_legacytempents.h`: + +```h +#if !defined( C_TE_LEGACYTEMPENTS_H ) +#define C_TE_LEGACYTEMPENTS_H +#ifdef _WIN32 +#pragma once +#endif + +class C_BaseEntity; +class C_LocalTempEntity; +struct model_t; + +#include "mempool.h" +#include "UtlLinkedList.h" + +#include "particlemgr.h" +typedef CParticleSubTexture* PMaterialHandle; +#include "cliententitylist.h" + +#if defined( SDK_DLL ) +enum +{ + CS_SHELL_9MM = 0, + CS_SHELL_57, + CS_SHELL_12GAUGE, + CS_SHELL_556, + CS_SHELL_762NATO, + CS_SHELL_338MAG, +}; +#endif + +abstract_class ITempEnts +{ +public: + virtual ~ITempEnts() {} + + virtual void Init(void) = 0; + virtual void Shutdown(void) = 0; + virtual void LevelInit() = 0; + virtual void LevelShutdown() = 0; + + virtual void Update(void) = 0; + virtual void Clear(void) = 0; + + virtual void BloodSprite(const Vector& org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size) = 0; + virtual void RicochetSprite(const Vector& pos, model_t* pmodel, float duration, float scale) = 0; + virtual void MuzzleFlash(int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson) = 0; + virtual void MuzzleFlash(const Vector& pos1, const QAngle& angles, int type, ClientEntityHandle_t hEntity, bool firstPerson) = 0; + virtual C_LocalTempEntity* SpawnTempModel(model_t* pModel, const Vector& vecOrigin, const QAngle& vecAngles, const Vector& vecVelocity, float flLifeTime, int iFlags) = 0; + virtual void BreakModel(const Vector& pos, const QAngle& angles, const Vector& size, const Vector& dir, float random, float life, int count, int modelIndex, char flags) = 0; + virtual void Bubbles(const Vector& mins, const Vector& maxs, float height, int modelIndex, int count, float speed) = 0; + virtual void BubbleTrail(const Vector& start, const Vector& end, float flWaterZ, int modelIndex, int count, float speed) = 0; + virtual void Sprite_Explode(C_LocalTempEntity* pTemp, float scale, int flags) = 0; + virtual void FizzEffect(C_BaseEntity* pent, int modelIndex, int density, int current) = 0; + virtual C_LocalTempEntity* DefaultSprite(const Vector& pos, int spriteIndex, float framerate) = 0; + virtual void Sprite_Smoke(C_LocalTempEntity* pTemp, float scale) = 0; + virtual C_LocalTempEntity* TempSprite(const Vector& pos, const Vector& dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags, const Vector& normal = vec3_origin) = 0; + virtual void AttachTentToPlayer(int client, int modelIndex, float zoffset, float life) = 0; + virtual void KillAttachedTents(int client) = 0; + virtual void Sprite_Spray(const Vector& pos, const Vector& dir, int modelIndex, int count, int speed, int iRand) = 0; + virtual void Sprite_Trail(const Vector& vecStart, const Vector& vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed) = 0; + virtual void RocketFlare(const Vector& pos) = 0; + virtual void PlaySound(C_LocalTempEntity* pTemp, float damp) = 0; + virtual void PhysicsProp(int modelindex, int skin, const Vector& pos, const QAngle& angles, const Vector& vel, int flags, int effects = 0) = 0; + virtual C_LocalTempEntity* ClientProjectile(const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAccel, int modelindex, int lifetime, CBaseEntity* pOwner, const char* pszImpactEffect = NULL, const char* pszParticleEffect = NULL) = 0; +}; + + +class CTempEnts : public ITempEnts +{ +public: + CTempEnts(void); + virtual ~CTempEnts(void); +public: + virtual void Init(void); + virtual void Shutdown(void); + + virtual void LevelInit(); + + virtual void LevelShutdown(); + + virtual void Update(void); + virtual void Clear(void); + + virtual void BloodSprite(const Vector& org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size); + virtual void RicochetSprite(const Vector& pos, model_t* pmodel, float duration, float scale); + + virtual void MuzzleFlash(int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson); + virtual void MuzzleFlash(const Vector& pos1, const QAngle& angles, int type, ClientEntityHandle_t hEntity, bool firstPerson = false); + + virtual void BreakModel(const Vector& pos, const QAngle& angles, const Vector& size, const Vector& dir, float random, float life, int count, int modelIndex, char flags); + virtual void Bubbles(const Vector& mins, const Vector& maxs, float height, int modelIndex, int count, float speed); + virtual void BubbleTrail(const Vector& start, const Vector& end, float height, int modelIndex, int count, float speed); + virtual void Sprite_Explode(C_LocalTempEntity* pTemp, float scale, int flags); + virtual void FizzEffect(C_BaseEntity* pent, int modelIndex, int density, int current); + virtual C_LocalTempEntity* DefaultSprite(const Vector& pos, int spriteIndex, float framerate); + virtual void Sprite_Smoke(C_LocalTempEntity* pTemp, float scale); + virtual C_LocalTempEntity* TempSprite(const Vector& pos, const Vector& dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags, const Vector& normal = vec3_origin); + virtual void AttachTentToPlayer(int client, int modelIndex, float zoffset, float life); + virtual void KillAttachedTents(int client); + virtual void Sprite_Spray(const Vector& pos, const Vector& dir, int modelIndex, int count, int speed, int iRand); + void Sprite_Trail(const Vector& vecStart, const Vector& vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed); + + virtual void PlaySound(C_LocalTempEntity* pTemp, float damp); + virtual C_LocalTempEntity* SpawnTempModel(model_t* pModel, const Vector& vecOrigin, const QAngle& vecAngles, const Vector& vecVelocity, float flLifeTime, int iFlags); + void RocketFlare(const Vector& pos); + void PhysicsProp(int modelindex, int skin, const Vector& pos, const QAngle& angles, const Vector& vel, int flags, int effects = 0); + C_LocalTempEntity* ClientProjectile(const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelindex, int lifetime, CBaseEntity* pOwner, const char* pszImpactEffect = NULL, const char* pszParticleEffect = NULL); + +private: + enum + { + MAX_TEMP_ENTITIES = 500, + MAX_TEMP_ENTITY_SPRITES = 200, + MAX_TEMP_ENTITY_STUDIOMODEL = 50, + }; + + CClassMemoryPool< C_LocalTempEntity > m_TempEntsPool; + CUtlLinkedList< C_LocalTempEntity*, unsigned short > m_TempEnts; + + struct model_t* m_pSpriteMuzzleFlash[10]; + struct model_t* m_pSpriteAR2Flash[4]; + struct model_t* m_pShells[3]; + struct model_t* m_pSpriteCombineFlash[2]; + +#if defined ( SDK_DLL ) + struct model_t* m_pCS_9MMShell; + struct model_t* m_pCS_57Shell; + struct model_t* m_pCS_12GaugeShell; + struct model_t* m_pCS_556Shell; + struct model_t* m_pCS_762NATOShell; + struct model_t* m_pCS_338MAGShell; +#endif + +protected: + C_LocalTempEntity* TempEntAlloc(const Vector& org, model_t* model); + C_LocalTempEntity* TempEntAllocHigh(const Vector& org, model_t* model); + +private: + + inline void CacheMuzzleFlashes(void); + PMaterialHandle m_Material_MuzzleFlash_Player[4]; + PMaterialHandle m_Material_MuzzleFlash_NPC[4]; + PMaterialHandle m_Material_Combine_MuzzleFlash_Player[2]; + PMaterialHandle m_Material_Combine_MuzzleFlash_NPC[2]; + +private: + CTempEnts(const CTempEnts&); + + void TempEntFree(int index); + C_LocalTempEntity* TempEntAlloc(); + bool FreeLowPriorityTempEnt(); + + int AddVisibleTempEntity(C_LocalTempEntity* pEntity); + + void MuzzleFlash_AR2_Player(const Vector& origin, const QAngle& angles, ClientEntityHandle_t hEntity); + void MuzzleFlash_AR2_NPC(const Vector& origin, const QAngle& angles, ClientEntityHandle_t hEntity); + + void MuzzleFlash_SMG1_Player(ClientEntityHandle_t hEntity, int attachmentIndex); + void MuzzleFlash_SMG1_NPC(ClientEntityHandle_t hEntity, int attachmentIndex); + + void MuzzleFlash_Shotgun_Player(ClientEntityHandle_t hEntity, int attachmentIndex); + void MuzzleFlash_Shotgun_NPC(ClientEntityHandle_t hEntity, int attachmentIndex); + + void MuzzleFlash_Pistol_Player(ClientEntityHandle_t hEntity, int attachmentIndex); + void MuzzleFlash_Pistol_NPC(ClientEntityHandle_t hEntity, int attachmentIndex); + + void MuzzleFlash_Combine_Player(ClientEntityHandle_t hEntity, int attachmentIndex); + void MuzzleFlash_Combine_NPC(ClientEntityHandle_t hEntity, int attachmentIndex); + + void MuzzleFlash_357_Player(ClientEntityHandle_t hEntity, int attachmentIndex); + + void MuzzleFlash_RPG_NPC(ClientEntityHandle_t hEntity, int attachmentIndex); +}; + + +extern ITempEnts* tempents; + + +#endif +``` + +`SpyCustom/sdk/cdll_client_int.h`: + +```h +#ifndef CDLL_CLIENT_INT_H +#define CDLL_CLIENT_INT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iclientnetworkable.h" +#include "utllinkedlist.h" +#include "cdll_int.h" +#include "shareddefs.h" +#include "eiface.h" +#include "tier3.h" +#include "tier2_logging.h" + +#include "shareddefs.h" + + +class IVModelRender; +class IVEngineClient; +class IVModelRender; +class IVEfx; +class IVRenderView; +class IVDebugOverlay; +class IMaterialSystem; +class IMaterialSystemStub; +class IDataCache; +class IMDLCache; +class IVModelInfoClient; +class IEngineVGui; +class ISpatialPartition; +class IBaseClientDLL; +class ISpatialPartition; +class IFileSystem; +class IStaticPropMgrClient; +class IShadowMgr; +class IEngineSound; +class IMatSystemSurface; +class IMaterialSystemHardwareConfig; +class ISharedGameRules; +class IEngineTrace; +class IGameUIFuncs; +class IGameEventManager2; +class IPhysicsGameTrace; +class CGlobalVarsBase; +class IClientTools; +class C_BaseAnimating; +class IColorCorrectionSystem; +class IInputSystem; +class ISceneFileCache; +class IXboxSystem; +class IAvi; +class IBik; +class CSteamAPIContext; +class IReplayHistoryManager; +class ISoundEmitterSystemBase; +enum CPULevel_t; +enum GPULevel_t; + +extern IVModelRender* modelrender; +extern IVEngineClient* engine; +extern IVModelRender* modelrender; +extern IVEfx* effects; +extern IVRenderView* render; +extern IVDebugOverlay* debugoverlay; +extern IMaterialSystemStub* materials_stub; +extern IVModelInfoClient* modelinfo; +extern IEngineVGui* enginevgui; +extern ISpatialPartition* partition; +extern IBaseClientDLL* clientdll; +extern IFileSystem* filesystem; +extern IStaticPropMgrClient* staticpropmgr; +extern IShadowMgr* shadowmgr; +extern IEngineSound* enginesound; +extern IEngineTrace* enginetrace; +extern IFileLoggingListener* filelogginglistener; +extern IGameUIFuncs* gameuifuncs; +extern IGameEventManager2* gameeventmanager; +extern IPhysicsGameTrace* physgametrace; +extern CGlobalVarsBase* gpGlobals; +extern IClientTools* clienttools; +extern IInputSystem* inputsystem; +extern ISceneFileCache* scenefilecache; +extern IXboxSystem* xboxsystem; +extern IAvi* avi; +extern IBik* bik; +extern IUploadGameStats* gamestatsuploader; +extern CSteamAPIContext* steamapicontext; +extern ISoundEmitterSystemBase* soundemitterbase; + +#ifdef INFESTED_DLL +class IASW_Mission_Chooser; +extern IASW_Mission_Chooser* missionchooser; +#endif +#if defined( REPLAY_ENABLED ) +extern IReplayHistoryManager* g_pReplayHistoryManager; +#endif + +CPULevel_t GetCPULevel(); +CPULevel_t GetActualCPULevel(); +GPULevel_t GetGPULevel(); +void ConfigureCurrentSystemLevel(); + +extern bool g_bLevelInitialized; +extern bool g_bTextMode; +extern bool g_bEngineIsHLTV; + +bool AddDataChangeEvent(IClientNetworkable* ent, DataUpdateType_t updateType, int* pStoredEvent); + +void ClearDataChangedEvent(int iStoredEvent); + +void PrecacheMaterial(const char* pMaterialName); + +int GetMaterialIndex(const char* pMaterialName); + +const char* GetMaterialNameFromIndex(int nIndex); + +int PrecacheParticleSystem(const char* pParticleSystemName); +int GetParticleSystemIndex(const char* pParticleSystemName); +const char* GetParticleSystemNameFromIndex(int nIndex); + + +void PrecacheEffect(const char* pEffectName); + + +void TrackBoneSetupEnt(C_BaseAnimating* pEnt); + +bool IsEngineThreaded(); + +class CVGuiScreenSizeSplitScreenPlayerGuard +{ +public: + CVGuiScreenSizeSplitScreenPlayerGuard(bool bActive, int slot, int nOldSlot); + CVGuiScreenSizeSplitScreenPlayerGuard(bool bActive, C_BaseEntity* pEntity, int nOldSlot); + ~CVGuiScreenSizeSplitScreenPlayerGuard(); +private: + + bool m_bNoRestore; + bool m_bOldSetting; + int m_nOldSize[2]; +}; + +class CSetActiveSplitScreenPlayerGuard : public CVGuiScreenSizeSplitScreenPlayerGuard +{ +public: + CSetActiveSplitScreenPlayerGuard(char const* pchContext, int nLine, int slot, int nOldSlot, bool bSetVguiScreenSize); + CSetActiveSplitScreenPlayerGuard(char const* pchContext, int nLine, C_BaseEntity* pEntity, int nOldSlot, bool bSetVguiScreenSize); + ~CSetActiveSplitScreenPlayerGuard(); +private: + bool m_bChanged; + char const* m_pchContext; + int m_nLine; + int m_nSaveSlot; + bool m_bSaveGetLocalPlayerAllowed; +}; + +class CHackForGetLocalPlayerAccessAllowedGuard +{ +public: + CHackForGetLocalPlayerAccessAllowedGuard(char const* pszContext, bool bOldSlot); + ~CHackForGetLocalPlayerAccessAllowedGuard(); +private: + bool m_bChanged; + char const* m_pszContext; + bool m_bSaveGetLocalPlayerAllowed; +}; + +class CVGuiAbsPosSplitScreenPlayerGuard +{ +public: + CVGuiAbsPosSplitScreenPlayerGuard(int slot, int nOldSlot, bool bInvert = false); + ~CVGuiAbsPosSplitScreenPlayerGuard(); +private: + bool m_bNoRestore; +}; + +int FirstValidSplitScreenSlot(); +int NextValidSplitScreenSlot(int i); +bool IsValidSplitScreenSlot(int i); +void IterateRemoteSplitScreenViewSlots_Push(bool bSet); +void IterateRemoteSplitScreenViewSlots_Pop(void); +class C_BasePlayer; +void AddRemoteSplitScreenViewPlayer(C_BasePlayer* pPlayer); +void RemoveRemoteSplitScreenViewPlayer(C_BasePlayer* pPlayer); +C_BasePlayer* GetSplitScreenViewPlayer(int nSlot); +bool IsLocalSplitScreenPlayer(int nSlot); + +#if defined( SPLIT_SCREEN_STUBS ) + +#define VGUI_SCREENSIZE_SPLITSCREEN_GUARD( slot ) +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ) +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( entity ) + +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( slot ) +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT_VGUI( entity ) + +#define HACK_GETLOCALPLAYER_GUARD( desc ) +#define VGUI_ABSPOS_SPLITSCREEN_GUARD( slot ) +#define VGUI_ABSPOS_SPLITSCREEN_GUARD_INVERT( slot ) + +#define FOR_EACH_VALID_SPLITSCREEN_PLAYER( iteratorName ) for ( int iteratorName = 0; iteratorName == 0; ++iteratorName ) + +#define ASSERT_LOCAL_PLAYER_RESOLVABLE() +#define ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE() +#define GET_ACTIVE_SPLITSCREEN_SLOT() ( 0 ) + +FORCEINLINE uint32 ComputeSplitscreenRenderingFlags(IClientRenderable* pRenderable) +{ + return 0xFFFFFFFF; +} + +#else + +#define VGUI_SCREENSIZE_SPLITSCREEN_GUARD( slot ) CVGuiScreenSizeSplitScreenPlayerGuard s_VGuiSSGuard( slot, engine->GetActiveSplitScreenPlayerSlot() ); +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ) CSetActiveSplitScreenPlayerGuard g_SSGuard( __FILE__, __LINE__, slot, engine->GetActiveSplitScreenPlayerSlot(), false ); +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( entity ) CSetActiveSplitScreenPlayerGuard g_SSEGuard( __FILE__, __LINE__, entity, engine->GetActiveSplitScreenPlayerSlot(), false ); + +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( slot ) CSetActiveSplitScreenPlayerGuard g_SSGuardNoVgui( __FILE__, __LINE__, slot, engine->GetActiveSplitScreenPlayerSlot(), true ); +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT_VGUI( entity ) CSetActiveSplitScreenPlayerGuard g_SSEGuardNoVgui( __FILE__, __LINE__, entity, engine->GetActiveSplitScreenPlayerSlot(), true ); + + +#define HACK_GETLOCALPLAYER_GUARD( desc ) CHackForGetLocalPlayerAccessAllowedGuard g_HackGLPGuard( desc, engine->IsLocalPlayerResolvable() ); +#define VGUI_ABSPOS_SPLITSCREEN_GUARD( slot ) CVGuiAbsPosSplitScreenPlayerGuard s_VGuiAbsPosGuard( slot, engine->GetActiveSplitScreenPlayerSlot() ); +#define VGUI_ABSPOS_SPLITSCREEN_GUARD_INVERT( slot ) CVGuiAbsPosSplitScreenPlayerGuard s_VGuiAbsPosGuard( slot, engine->GetActiveSplitScreenPlayerSlot(), true ); + +#define FOR_EACH_VALID_SPLITSCREEN_PLAYER( iteratorName ) \ + for ( int iteratorName = FirstValidSplitScreenSlot(); \ + iteratorName != -1; \ + iteratorName = NextValidSplitScreenSlot( iteratorName ) ) + +#if defined( SS_SHIPPING_ASSERTS ) +#define ASSERT_LOCAL_PLAYER_RESOLVABLE() _AssertMsg( engine->IsLocalPlayerResolvable(), _T("Assertion Failed: ") _T("engine->IsLocalPlayerResolvable()"), ((void)0), false ) +#else +#define ASSERT_LOCAL_PLAYER_RESOLVABLE() Assert( engine->IsLocalPlayerResolvable() ); +#endif + +#if defined( SS_SHIPPING_ASSERTS ) +#define ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE() _AssertMsg( !engine->IsLocalPlayerResolvable(), _T("Assertion Failed: ") _T("!engine->IsLocalPlayerResolvable()"), ((void)0), false ) +#else +#define ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE() Assert( !engine->IsLocalPlayerResolvable() ); +#endif + +#define GET_ACTIVE_SPLITSCREEN_SLOT() engine->GetActiveSplitScreenPlayerSlot() + +FORCEINLINE uint32 ComputeSplitscreenRenderingFlags(IClientRenderable* pRenderable) +{ + if (IsSplitScreenSupported()) + { + int nFlags = 0; + for (int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i) + { + if (pRenderable->ShouldDrawForSplitScreenUser(i)) + { + nFlags |= 1 << i; + } + } + return nFlags; + } + + return 0xFFFFFFFF; +} + +#endif + +inline C_BasePlayer* GetSplitScreenViewPlayer(void) { return GetSplitScreenViewPlayer(GET_ACTIVE_SPLITSCREEN_SLOT()); }; +inline bool IsLocalSplitScreenPlayer(void) { return IsLocalSplitScreenPlayer(GET_ACTIVE_SPLITSCREEN_SLOT()); }; + +int XBX_GetActiveUserId(); + +#define XBX_GetPrimaryUserId() _Use_XBX_GetActiveUserId_Instead + +#endif +``` + +`SpyCustom/sdk/cdll_int.h`: + +```h +#ifndef CDLL_INT_H +#define CDLL_INT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "sdk/basetypes.h" +#include "sdk/interface.h" +#include "sdk/mathlib.h" +#include "sdk/const.h" +#include "sdk/checksum_crc.h" +#include "sdk/datamap.h" +#include "sdk/bitbuf.h" +#include "sdk/ButtonCode.h" +#include "sdk/modes.h" + +#if !defined( _X360 ) +#include "sdk/xboxstubs.h" +#endif + +#include "sdk/jobthread.h" +#include "sdk/VGUI.h" + +#include "../GetVfunc.hpp" + +struct SpatializationInfo_t; +class IClientEntity; + +class ClientClass; +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; +class VMatrix; +struct ScreenFade_t; +struct ScreenShake_t; +class CViewSetup; +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; + +struct player_info_t +{ +public: + char __pad0[0x8]; + union { + long long xuid; + struct { + int xuidlow; + int xuidhigh; + }; + }; + char name[128]; + int userid; + char guid[33]; + unsigned int friendsid; + char friendsname[128]; + bool fakeplayer; + bool ishltv; + unsigned int customfiles[4]; + unsigned char filesdownloaded; +}; + +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 +}; + +enum RenderViewInfo_t +{ + RENDERVIEW_UNSPECIFIED = 0, + RENDERVIEW_DRAWVIEWMODEL = (1 << 0), + RENDERVIEW_DRAWHUD = (1 << 1), + RENDERVIEW_SUPPRESSMONITORRENDERING = (1 << 2), +}; + +DECLARE_POINTER_HANDLE(LightCacheHandle_t); + + +struct OcclusionParams_t +{ + float m_flMaxOccludeeArea; + float m_flMinOccluderArea; +}; + + +#define VENGINE_CLIENT_RANDOM_INTERFACE_VERSION "VEngineRandom001" + +#define VENGINE_CLIENT_INTERFACE_VERSION "VEngineClient014" +#define VENGINE_CLIENT_INTERFACE_VERSION_13 "VEngineClient013" + +abstract_class IVEngineClient013 +{ +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, player_info_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 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(Vector& va) = 0; + 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 Key_SetBinding(ButtonCode_t code, const char* pBinding) = 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 HideLoadingPlaque(void) = 0; + + virtual void Con_NPrintf(int pos, PRINTF_FORMAT_STRING const char* fmt, ...) = 0; + virtual void Con_NXPrintf(const struct con_nprint_s* info, PRINTF_FORMAT_STRING 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; + +#if defined(_PS3) + virtual void Sound_ServerUpdateSoundsPS3(void) = 0; +#endif + + 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 char const* GetLevelNameShort(void) = 0; + virtual char const* GetMapGroupName(void) = 0; +#if !defined( NO_VOICE ) + virtual struct IVoiceTweak_s* GetVoiceTweakAPI(void) = 0; + virtual void SetVoiceCasterID(uint32 casterID) = 0; +#endif + 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 int GetFrustumList(Frustum_t** pList, int listMax) = 0; + virtual bool ShouldUseAreaFrustum(int area) = 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 int GetOcclusionViewId() const = 0; + + virtual void* SaveAllocMemory(size_t num, size_t size) = 0; + virtual void SaveFreeMemory(void* pSaveMem) = 0; + + virtual INetChannelInfo* GetNetChannelInfo(void) = 0; + //virtual INetChannel* GetNetChannelInfo(void) = 0; + + virtual void DebugDrawPhysCollide(const CPhysCollide* pCollide, IMaterial* pMaterial, matrix3x4_t& 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 float GetTimescale(void) const = 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 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 bool MapHasLightMapAlphaData(void) = 0; + + virtual int GetAppID() = 0; + + virtual Vector GetLightForPointFast(const Vector& pos, bool bClamp) = 0; + + virtual void ClientCmd_Unrestricted(const char* szCmdString, bool fromConsoleOrKeybind = false) = 0; + virtual void ClientCmd_Unrestricted(const char* szCmdString, bool fromConsoleOrKeybind, int nUserSlot, bool bCheckValidSlot = true) = 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; + +#if defined( USE_SDL ) + virtual void GetMouseDelta(int& x, int& y, bool bIgnoreNextMouseDelta = false) = 0; +#endif + + 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; + +}; + +abstract_class IVEngineClient : public IVEngineClient013 +{ +public: + virtual uint GetProtocolVersion() = 0; + virtual bool IsWindowedMode() = 0; + + virtual void FlashWindow() = 0; + + virtual int GetClientVersion() const = 0; + + virtual bool IsActiveApp() = 0; + + virtual void DisconnectInternal() = 0; + + virtual int GetInstancesRunningCount() = 0; +}; + + +abstract_class IBaseClientDLL +{ +public: + virtual int Connect(CreateInterfaceFn appSystemFactory, CGlobalVarsBase * pGlobals) = 0; + virtual void Disconnect() = 0; + virtual int Init(CreateInterfaceFn appSystemFactory, CGlobalVarsBase* pGlobals) = 0; + virtual void PostInit() = 0; + virtual void Shutdown(void) = 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 bool ShouldDrawDropdownConsole() = 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 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(int nSlot, bf_write* buf, int from, int to, bool isnewcommand) = 0; + virtual void EncodeUserCmdToBuffer(int nSlot, bf_write& buf, int slot) = 0; + virtual void DecodeUserCmdFromBuffer(int nSlot, 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, int iSsSlot, qboolean bTalking) = 0; + virtual bool PlayerAudible(int iPlayerIndex) = 0; + virtual void InstallStringTableCallback(char const* tableName) = 0; + virtual void FrameStageNotify(ClientFrameStage_t curStage) = 0; //37 + + //virtual bool DispatchUserMessage(int msg_type, int32 nFlags, int size, const void* msg) = 0; + + + bool DispatchUserMessage(int msg_type, int32 nFlags, int size, const void* msg) + { + typedef bool(__stdcall* DispatchUserMessageFn)(int, int32, int, const void*); + //printf("DispatchUserMessageFn %x\n", this); + return getvfunc(this, 38)(msg_type, nFlags, size, msg); + } + + + 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 OnDemoPlaybackRestart() = 0; + virtual void OnDemoPlaybackStop() = 0; + virtual void SetDemoPlaybackHighlightXuid(uint64 xuid, bool bLowlights) = 0; + virtual void ShowHighlightSkippingMessage(bool bState, int nCurrentTick = 0, int nTickStart = 0, int nTickStop = 0) = 0; + + virtual void RecordDemoPolishUserInput(int nCmdIndex) = 0; + + virtual bool CacheReplayRagdolls(const char* pFilename, int nStartTick) = 0; + + virtual void ReplayUI_SendMessage(KeyValues* pMsg) = 0; + + virtual void* GetReplayFactory() = 0; + + virtual void ClearLocalPlayerReplayPtr() = 0; + + virtual void unk(); + + 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 void WriteReplayScreenshot(void* params) = 0; + + virtual void UpdateReplayScreenshotCache() = 0; + + virtual bool GetPlayerView(CViewSetup& playerView) = 0; + + virtual bool ShouldHideLoadingPlaque(void) = 0; + + virtual void InvalidateMdlCache() = 0; + + virtual void IN_SetSampleTime(float frametime) = 0; + + virtual void OnActiveSplitscreenPlayerChanged(int nNewSlot) = 0; + virtual void OnSplitScreenStateChanged() = 0; + + virtual int GetSpectatorTarget(void* pObserverMode) = 0; + + virtual void CenterStringOff() = 0; + + virtual void OnScreenSizeChanged(int nOldWidth, int nOldHeight) = 0; + + virtual void* InstantiateMaterialProxy(const char* proxyName) = 0; + + virtual vgui::VPANEL GetFullscreenClientDLLVPanel(void) = 0; + + virtual void MarkEntitiesAsTouching(IClientEntity* e1, IClientEntity* e2) = 0; + + virtual void OnKeyBindingChanged(ButtonCode_t buttonCode, char const* pchKeyName, char const* pchNewBinding) = 0; + + virtual void SetBlurFade(float scale) = 0; + + virtual void ResetHudCloseCaption() = 0; + + virtual bool HandleGameUIEvent(const InputEvent_t& event) = 0; + + virtual bool GetSoundSpatialization(SpatializationInfo_t& info) = 0; + + virtual void Hud_SaveStarted() = 0; + + virtual void ShutdownMovies() = 0; + + virtual void GetStatus(char* buffer, int bufsize) = 0; + +#if defined ( CSTRIKE15 ) + virtual bool IsChatRaised(void) = 0; + virtual bool IsRadioPanelRaised(void) = 0; + virtual bool IsBindMenuRaised(void) = 0; + virtual bool IsTeamMenuRaised(void) = 0; + virtual bool IsLoadingScreenRaised(void) = 0; + +#endif + +#if defined(_PS3) + virtual int GetDrawFlags(void) = 0; + virtual int GetBuildViewID(void) = 0; + virtual bool IsSPUBuildWRJobsOn(void) = 0; + virtual void CacheFrustumData(Frustum_t* pFrustum, Frustum_t* pAreaFrustum, void* pRenderAreaBits, int numArea, bool bViewerInSolidSpace) = 0; + virtual void* GetBuildViewVolumeCuller(void) = 0; + virtual Frustum_t* GetBuildViewFrustum(void) = 0; + virtual Frustum_t* GetBuildViewAreaFrustum(void) = 0; + virtual unsigned char* GetBuildViewRenderAreaBits(void) = 0; +#else + virtual bool IsBuildWRThreaded(void) = 0; + virtual void QueueBuildWorldListJob(CJob* pJob) = 0; + virtual void CacheFrustumData(const Frustum_t& frustum, const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t,16 > >& aeraFrustums) = 0; + virtual const Frustum_t* GetBuildViewFrustum(void) const = 0; + virtual const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t,16 > >* GetBuildViewAeraFrustums(void) const = 0; +#endif + + virtual bool IsSubscribedMap(const char* pchMapName, bool bOnlyOnDisk) = 0; + virtual bool IsFeaturedMap(const char* pchMapName, bool bOnlyOnDisk) = 0; + + virtual void DownloadCommunityMapFile(int id) = 0; + + virtual float GetUGCFileDownloadProgress(int id) = 0; + + virtual void RecordUIEvent(const char* szEvent) = 0; + + virtual float FindInventoryItemWithMaxAttributeValue(char const* szItemType, char const* szAttrClass) = 0; + + virtual void DetermineSubscriptionKvToAdvertise(KeyValues* kvLocalPlayer) = 0; + + virtual bool ValidateSignedEvidenceHeader(char const* szKey, void const* pvHeader, void* pPlaybackParameters) = 0; + virtual void PrepareSignedEvidenceData(void* pvData, int numBytes, int const* pPlaybackParameters) = 0; + virtual bool ShouldSkipEvidencePlayback(int const* pPlaybackParameters) = 0; + + virtual void* GetScaleformSlotInitController() = 0; + + virtual bool IsConnectedUserInfoChangeAllowed(IConVar* pCvar) = 0; + + virtual char const* GetRichPresenceStatusString() = 0; + + virtual bool CanStopRecordDemo(char* errorMsg, int length) const = 0; + + virtual void OnHltvReplay(const int& msg) = 0; + virtual void OnHltvReplayTick() = 0; + virtual int GetHltvReplayDelay() = 0; + + virtual void OnDemoPlaybackTimeJump() = 0; + virtual void OnCommandDuringPlayback(char const* cmd) = 0; + + virtual void RetireAllPlayerDecals(bool bRenderContextValid) = 0; + virtual void EngineGotvSyncPacket(const void* pPkt) = 0; + virtual int GetInEyeEntity() const = 0; + virtual void OnTickPre(int tickcount) = 0; +}; + +#define CLIENT_DLL_INTERFACE_VERSION "VClient018" + +abstract_class IClientDLLSharedAppSystems +{ +public: + virtual int Count() = 0; + virtual char const* GetDllName(int idx) = 0; + virtual char const* GetInterfaceName(int idx) = 0; +}; + +#define CLIENT_DLL_SHARED_APPSYSTEMS "VClientDllSharedAppSystems001" + +#endif + +``` + +`SpyCustom/sdk/cdll_util.h`: + +```h +#if !defined( UTIL_H ) +#define UTIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "soundflags.h" +#include "vector.h" +#include "shareddefs.h" + +#include "shake.h" +#include "imageformat.h" +#include "ispatialpartition.h" +#include "MaterialSystemUtil.h" + +class Vector; +class QAngle; +class IMaterial; +class ITexture; +class IClientEntity; +class CHudTexture; +class CGameTrace; +class C_BaseEntity; + +struct Ray_t; +struct client_textmessage_t; +typedef CGameTrace trace_t; + +namespace vgui +{ + typedef unsigned long HFont; +}; + + + +extern bool g_MakingDevShots; + +int ScreenHeight(void); +int ScreenWidth(void); + +#define XRES(x) ( x * ( ( float )ScreenWidth() / 640.0 ) ) +#define YRES(y) ( y * ( ( float )ScreenHeight() / 480.0 ) ) + +int UTIL_ComputeStringWidth(vgui::HFont& font, const char* str); +int UTIL_ComputeStringWidth(vgui::HFont& font, const wchar_t* str); +float UTIL_AngleDiff(float destAngle, float srcAngle); +void UTIL_Bubbles(const Vector& mins, const Vector& maxs, int count); +void UTIL_Smoke(const Vector& origin, const float scale, const float framerate); +void UTIL_ImpactTrace(trace_t* pTrace, int iDamageType, const char* pCustomImpactName = NULL); +int UTIL_PrecacheDecal(const char* name, bool preload = false); +void UTIL_EmitAmbientSound(C_BaseEntity* entity, const Vector& vecOrigin, const char* samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch); +void UTIL_SetOrigin(C_BaseEntity* entity, const Vector& vecOrigin); +void UTIL_ScreenShake(const Vector& center, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake = false); +byte* UTIL_LoadFileForMe(const char* filename, int* pLength); +void UTIL_FreeFile(byte* buffer); +void UTIL_MakeSafeName(const char* oldName, OUT_Z_CAP(newNameBufSize) char* newName, int newNameBufSize); +const char* UTIL_SafeName(const char* oldName); +void UTIL_ReplaceKeyBindings(const wchar_t* inbuf, int inbufsizebytes, OUT_Z_BYTECAP(outbufsizebytes) wchar_t* outbuf, int outbufsizebytes); + +unsigned char UTIL_ComputeEntityFade(C_BaseEntity* pEntity, float flMinDist, float flMaxDist, float flFadeScale); + +client_textmessage_t* TextMessageGet(const char* pName); + +char* VarArgs(PRINTF_FORMAT_STRING const char* format, ...); + + +int GetSpectatorTarget(); +int GetSpectatorMode(void); +bool IsPlayerIndex(int index); +int GetLocalPlayerIndex(void); +int GetLocalPlayerVisionFilterFlags(bool bWeaponsCheck = false); +bool IsLocalPlayerUsingVisionFilterFlags(int nFlags, bool bWeaponsCheck = false); +int GetLocalPlayerTeam(void); +bool IsLocalPlayerSpectator(void); +void NormalizeAngles(QAngle& angles); +void InterpolateAngles(const QAngle& start, const QAngle& end, QAngle& output, float frac); +void InterpolateVector(float frac, const Vector& src, const Vector& dest, Vector& output); + +const char* nexttoken(char* token, const char* str, char sep); + +enum +{ + LIGHT_INDEX_TE_DYNAMIC = 0x10000000, + LIGHT_INDEX_PLAYER_BRIGHT = 0x20000000, + LIGHT_INDEX_MUZZLEFLASH = 0x40000000, +}; + +void UTIL_PrecacheOther(const char* szClassname); + +void UTIL_SetTrace(trace_t& tr, const Ray_t& ray, C_BaseEntity* edict, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept); + +bool GetVectorInScreenSpace(Vector pos, int& iX, int& iY, Vector* vecOffset = NULL); +bool GetVectorInHudSpace(Vector pos, int& iX, int& iY, Vector* vecOffset = NULL); +bool GetTargetInScreenSpace(C_BaseEntity* pTargetEntity, int& iX, int& iY, Vector* vecOffset = NULL); +bool GetTargetInHudSpace(C_BaseEntity* pTargetEntity, int& iX, int& iY, Vector* vecOffset = NULL); + +class C_BasePlayer; +void ClientPrint(C_BasePlayer* player, int msg_dest, const char* msg_name, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL, const char* param4 = NULL); + +int UTIL_EntitiesInBox(C_BaseEntity** pList, int listMax, const Vector& mins, const Vector& maxs, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS); +int UTIL_EntitiesInSphere(C_BaseEntity** pList, int listMax, const Vector& center, float radius, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS); +int UTIL_EntitiesAlongRay(C_BaseEntity** pList, int listMax, const Ray_t& ray, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS); + +#define MAX_SPHERE_QUERY 256 +class CEntitySphereQuery +{ +public: + CEntitySphereQuery(const Vector& center, float radius, int flagMask = 0, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS); + C_BaseEntity* GetCurrentEntity(); + inline void NextEntity() { m_listIndex++; } + +private: + int m_listIndex; + int m_listCount; + C_BaseEntity* m_pList[MAX_SPHERE_QUERY]; +}; + +C_BaseEntity* CreateEntityByName(const char* className); +template< class T > +T* _CreateEntity(T* newClass, const char* className) +{ + T* newEnt = dynamic_cast(CreateEntityByName(className)); + if (!newEnt) + { + Warning("classname %s used to create wrong class type\n", className); + Assert(0); + } + + return newEnt; +} + +#define CREATE_ENTITY( newClass, className ) _CreateEntity( (newClass*)NULL, className ) +#define CREATE_UNSAVED_ENTITY( newClass, className ) _CreateEntityTemplate( (newClass*)NULL, className ) + +inline bool FStrEq(const char* sz1, const char* sz2) +{ + return (sz1 == sz2 || V_stricmp(sz1, sz2) == 0); +} + +void UTIL_BoundToWorldSize(Vector* pVecPos); + +void UTIL_IncrementMapKey(const char* pszCustomKey); + +int UTIL_GetMapKeyCount(const char* pszCustomKey); + +bool UTIL_HasLoadedAnyMap(); + +#endif +``` + +`SpyCustom/sdk/checksum_crc.h`: + +```h +#ifndef CHECKSUM_CRC_H +#define CHECKSUM_CRC_H +#ifdef _WIN32 +#pragma once +#endif + +typedef unsigned int CRC32_t; + +void CRC32_Init(CRC32_t* pulCRC); +void CRC32_ProcessBuffer(CRC32_t* pulCRC, const void* p, int len); +void CRC32_Final(CRC32_t* pulCRC); +CRC32_t CRC32_GetTableEntry(unsigned int slot); + +inline CRC32_t CRC32_ProcessSingleBuffer(const void* p, int len) +{ + CRC32_t crc; + + CRC32_Init(&crc); + CRC32_ProcessBuffer(&crc, p, len); + CRC32_Final(&crc); + + return crc; +} + +#endif +``` + +`SpyCustom/sdk/checksum_md5.h`: + +```h +#ifndef CHECKSUM_MD5_H +#define CHECKSUM_MD5_H + +#ifdef _WIN32 +#pragma once +#endif + +#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); +} + +// + + +#endif +``` + +`SpyCustom/sdk/client_class.h`: + +```h +#if !defined( CLIENT_CLASS_H ) +#define CLIENT_CLASS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "dt_recv.h" + +class Vector; +class CMouthInfo; + + +#include "iclientrenderable.h" +#include "iclientnetworkable.h" + + +class ClientClass; +extern ClientClass* g_pClientClassHead; + +typedef IClientNetworkable* (*CreateClientClassFn)(int entnum, int serialNum); +typedef IClientNetworkable* (*CreateEventFn)(); + +class ClientClass +{ +public: + ClientClass(const char* pNetworkName, CreateClientClassFn createFn, CreateEventFn createEventFn, RecvTable* pRecvTable) + { + m_pNetworkName = pNetworkName; + m_pCreateFn = createFn; + m_pCreateEventFn = createEventFn; + m_pRecvTable = pRecvTable; + + m_pNext = g_pClientClassHead; + g_pClientClassHead = this; + } + + const char* GetName() + { + return m_pNetworkName; + } + +public: + CreateClientClassFn m_pCreateFn; + CreateEventFn m_pCreateEventFn; + const char* m_pNetworkName; + RecvTable* m_pRecvTable; + ClientClass* m_pNext; + int m_ClassID; +}; + +#define DECLARE_CLIENTCLASS() \ + virtual int YouForgotToImplementOrDeclareClientClass();\ + virtual ClientClass* GetClientClass();\ + static RecvTable *m_pClassRecvTable; \ + DECLARE_CLIENTCLASS_NOBASE() + + +#define ALLOW_DATATABLES_PRIVATE_ACCESS() \ + template friend int ClientClassInit(T *); + + +#define DECLARE_CLIENTCLASS_NOBASE ALLOW_DATATABLES_PRIVATE_ACCESS + +#define IMPLEMENT_CLIENTCLASS(clientClassName, dataTable, serverClassName) \ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName) \ + static IClientNetworkable* _##clientClassName##_CreateObject( int entnum, int serialNum ) \ + { \ + clientClassName *pRet = new clientClassName; \ + if ( !pRet ) \ + return 0; \ + pRet->Init( entnum, serialNum ); \ + return pRet; \ + } \ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + _##clientClassName##_CreateObject, \ + NULL,\ + &dataTable::g_RecvTable); + +#define IMPLEMENT_CLIENTCLASS_FACTORY(clientClassName, dataTable, serverClassName, factory) \ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName) \ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + factory, \ + NULL,\ + &dataTable::g_RecvTable); + +#define IMPLEMENT_CLIENTCLASS_DT(clientClassName, dataTable, serverClassName)\ + IMPLEMENT_CLIENTCLASS(clientClassName, dataTable, serverClassName)\ + BEGIN_RECV_TABLE(clientClassName, dataTable) + +#define IMPLEMENT_CLIENTCLASS_DT_NOBASE(clientClassName, dataTable, serverClassName)\ + IMPLEMENT_CLIENTCLASS(clientClassName, dataTable, serverClassName)\ + BEGIN_RECV_TABLE_NOBASE(clientClassName, dataTable) + + +#define IMPLEMENT_CLIENTCLASS_EVENT(clientClassName, dataTable, serverClassName)\ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName)\ + static clientClassName __g_##clientClassName; \ + static IClientNetworkable* _##clientClassName##_CreateObject() {return &__g_##clientClassName;}\ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + NULL,\ + _##clientClassName##_CreateObject, \ + &dataTable::g_RecvTable); + +#define IMPLEMENT_CLIENTCLASS_EVENT_DT(clientClassName, dataTable, serverClassName)\ + namespace dataTable {extern RecvTable g_RecvTable;}\ + IMPLEMENT_CLIENTCLASS_EVENT(clientClassName, dataTable, serverClassName)\ + BEGIN_RECV_TABLE(clientClassName, dataTable) + + +#define IMPLEMENT_CLIENTCLASS_EVENT_POINTER(clientClassName, dataTable, serverClassName, ptr)\ + INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName)\ + static IClientNetworkable* _##clientClassName##_CreateObject() {return ptr;}\ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + NULL,\ + _##clientClassName##_CreateObject, \ + &dataTable::g_RecvTable); + +#define IMPLEMENT_CLIENTCLASS_EVENT_NONSINGLETON(clientClassName, dataTable, serverClassName)\ + static IClientNetworkable* _##clientClassName##_CreateObject() \ + { \ + clientClassName *p = new clientClassName; \ + if ( p ) \ + p->Init( -1, 0 ); \ + return p; \ + } \ + ClientClass __g_##clientClassName##ClientClass(#serverClassName, \ + NULL,\ + _##clientClassName##_CreateObject, \ + &dataTable::g_RecvTable); + + +#define INTERNAL_IMPLEMENT_CLIENTCLASS_PROLOGUE(clientClassName, dataTable, serverClassName) \ + namespace dataTable {extern RecvTable g_RecvTable;}\ + extern ClientClass __g_##clientClassName##ClientClass;\ + RecvTable* clientClassName::m_pClassRecvTable = &dataTable::g_RecvTable;\ + int clientClassName::YouForgotToImplementOrDeclareClientClass() {return 0;}\ + ClientClass* clientClassName::GetClientClass() {return &__g_##clientClassName##ClientClass;} + +#endif +``` + +`SpyCustom/sdk/client_render_handle.h`: + +```h +#ifndef CLIENT_RENDER_HANDLE_H +#define CLIENT_RENDER_HANDLE_H +#ifdef _WIN32 +#pragma once +#endif + + +class IClientRenderable; + + +typedef unsigned short ClientRenderHandle_t; + +enum +{ + INVALID_CLIENT_RENDER_HANDLE = (ClientRenderHandle_t)0xffff, +}; + + +#endif +``` + +`SpyCustom/sdk/client_thinklist.h`: + +```h +#ifndef CLIENT_THINKLIST_H +#define CLIENT_THINKLIST_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "igamesystem.h" +#include "utllinkedlist.h" +#include "cliententitylist.h" +#include "iclientthinkable.h" +#include "utlrbtree.h" + + +#define CLIENT_THINK_ALWAYS -1293 +#define CLIENT_THINK_NEVER -1 + + +#define INVALID_THINK_HANDLE ClientThinkList()->GetInvalidThinkHandle() + + +class CClientThinkList : public IGameSystemPerFrame +{ +public: + + CClientThinkList(); + virtual ~CClientThinkList(); + + virtual char const* Name() { return "CClientThinkList"; } + virtual bool IsPerFrame() { return true; } + + void SetNextClientThink(ClientEntityHandle_t hEnt, float nextTime); + + void RemoveThinkable(ClientEntityHandle_t hEnt); + + ClientThinkHandle_t GetInvalidThinkHandle(); + + void PerformThinkFunctions(); + + void AddToDeleteList(ClientEntityHandle_t hEnt); + void RemoveFromDeleteList(ClientEntityHandle_t hEnt); + +public: + + virtual bool Init(); + virtual void PostInit() {}; + virtual void Shutdown(); + virtual void LevelInitPreEntity(); + virtual void LevelInitPostEntity() {} + virtual void LevelShutdownPreEntity(); + virtual void LevelShutdownPostEntity(); + virtual void PreRender(); + virtual void PostRender() { } + virtual void Update(float frametime); + virtual void OnSave() {} + virtual void OnRestore() {} + virtual void SafeRemoveIfDesired() {} + +private: + struct ThinkEntry_t + { + ClientEntityHandle_t m_hEnt; + float m_flNextClientThink; + float m_flLastClientThink; + int m_nIterEnum; + }; + + struct ThinkListChanges_t + { + ClientEntityHandle_t m_hEnt; + ClientThinkHandle_t m_hThink; + float m_flNextTime; + }; + +private: + void SetNextClientThink(ClientThinkHandle_t hThink, float nextTime); + void RemoveThinkable(ClientThinkHandle_t hThink); + void PerformThinkFunction(ThinkEntry_t* pEntry, float curtime); + ThinkEntry_t* GetThinkEntry(ClientThinkHandle_t hThink); + void CleanUpDeleteList(); + + void AddEntityToFrameThinkList(ThinkEntry_t* pEntry, bool bAlwaysChain, int& nCount, ThinkEntry_t** ppFrameThinkList); + +private: + CUtlLinkedList m_ThinkEntries; + + CUtlVector m_aDeleteList; + CUtlVector m_aChangeList; + + int m_nIterEnum; + bool m_bInThinkLoop; +}; + + +inline ClientThinkHandle_t CClientThinkList::GetInvalidThinkHandle() +{ + return (ClientThinkHandle_t)(uintp)m_ThinkEntries.InvalidIndex(); +} + + +inline CClientThinkList::ThinkEntry_t* CClientThinkList::GetThinkEntry(ClientThinkHandle_t hThink) +{ + return &m_ThinkEntries[(unsigned long)hThink]; +} + + +inline CClientThinkList* ClientThinkList() +{ + extern CClientThinkList g_ClientThinkList; + return &g_ClientThinkList; +} + + +#endif +``` + +`SpyCustom/sdk/client_virtualreality.h`: + +```h +#ifndef CLIENTVIRTUALREALITY_H +#define CLIENTVIRTUALREALITY_H +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier3.h" +#include "iclientvirtualreality.h" +#include "view_shared.h" + +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 CClientVirtualReality : public CTier3AppSystem< IClientVirtualReality > +{ + typedef CTier3AppSystem< IClientVirtualReality > BaseClass; + +public: + + CClientVirtualReality(); + ~CClientVirtualReality(); + + virtual bool Connect(CreateInterfaceFn factory); + virtual void Disconnect(); + virtual void* QueryInterface(const char* pInterfaceName); + + virtual InitReturnVal_t Init(); + virtual void Shutdown(); + + void StartupComplete(); + + virtual void DrawMainMenu() OVERRIDE; + + + bool OverrideView(CViewSetup* pViewMiddle, Vector* pViewModelOrigin, QAngle* pViewModelAngles, HeadtrackMovementMode_t hmmMovementOverride); + bool OverrideStereoView(CViewSetup* pViewMiddle, CViewSetup* pViewLeft, CViewSetup* pViewRight); + bool OverridePlayerMotion(float flInputSampleFrametime, const QAngle& oldAngles, const QAngle& curAngles, const Vector& curMotion, QAngle* pNewAngles, Vector* pNewMotion); + bool OverrideWeaponHudAimVectors(Vector* pAimOrigin, Vector* pAimDirection); + bool CurrentlyZoomed(); + void OverrideTorsoTransform(const Vector& position, const QAngle& angles); + void CancelTorsoTransformOverride(); + bool CanOverlayHudQuad(); + void GetHUDBounds(Vector* pViewer, Vector* pUL, Vector* pUR, Vector* pLL, Vector* pLR); + void RenderHUDQuad(bool bBlackout, bool bTranslucent); + float GetZoomedModeMagnification(); + bool ProcessCurrentTrackingState(float fGameFOV); + const VMatrix& GetHudProjectionFromWorld(); + void GetTorsoRelativeAim(Vector* pPosition, QAngle* pAngles); + float GetHUDDistance(); + bool ShouldRenderHUDInWorld(); + const VMatrix& GetWorldFromMidEye() const { return m_WorldFromMidEyeNoDebugCam; } + void OverrideViewModelTransform(Vector& vmorigin, QAngle& vmangles, bool bUseLargeOverride); + void AlignTorsoAndViewToWeapon(); + void PostProcessFrame(StereoEye_t eEye); + void OverlayHUDQuadWithUndistort(const CViewSetup& view, bool bDoUndistort, bool bBlackout, bool bTranslucent); + + void Activate(); + void Deactivate(); + +private: + HeadtrackMovementMode_t m_hmmMovementActual; + + VMatrix m_WorldFromMidEye; + + float m_fHudHorizontalFov; + VMatrix m_WorldFromHud; + VMatrix m_HudProjectionFromWorld; + float m_fHudHalfWidth; + float m_fHudHalfHeight; + + VMatrix m_TorsoFromMideye; + + VMatrix m_WorldFromMidEyeNoDebugCam; + + VMatrix m_WorldFromWeapon; + + QAngle m_PlayerTorsoAngle; + Vector m_PlayerTorsoOrigin; + Vector m_PlayerLastMovement; + + QAngle m_PlayerViewAngle; + Vector m_PlayerViewOrigin; + + float m_WorldZoomScale; + + QAngle m_OverrideTorsoAngle; + QAngle m_OverrideTorsoOffset; + bool m_bOverrideTorsoAngle; + + int m_iAlignTorsoAndViewToWeaponCountdown; + + bool m_bMotionUpdated; + + RTime32 m_rtLastMotionSample; + + bool m_bNonVRWindowed; + int m_nNonVRWidth; + int m_nNonVRHeight; +#if defined( USE_SDL ) + int m_nNonVRSDLDisplayIndex; +#endif + bool m_bNonVRRawInput; +}; + +extern CClientVirtualReality g_ClientVirtualReality; + +#endif +``` + +`SpyCustom/sdk/cliententitylist.h`: + +```h +#if !defined( CLIENTENTITYLIST_H ) +#define CLIENTENTITYLIST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include "icliententitylist.h" +#include "iclientunknown.h" +#include "utllinkedlist.h" +#include "utlvector.h" +#include "icliententityinternal.h" +#include "ispatialpartition.h" +#include "cdll_util.h" +#include "entitylist_base.h" +#include "utlmap.h" + +class C_Beam; +class C_BaseViewModel; +class C_BaseEntity; + + +#define INPVS_YES 0x0001 +#define INPVS_THISFRAME 0x0002 +#define INPVS_NEEDSNOTIFY 0x0004 + +class IClientEntityListener; + +abstract_class C_BaseEntityClassList +{ +public: + C_BaseEntityClassList(); + ~C_BaseEntityClassList(); + virtual void LevelShutdown() = 0; + + C_BaseEntityClassList* m_pNextClassList; +}; + +template< class T > +class C_EntityClassList : public C_BaseEntityClassList +{ +public: + virtual void LevelShutdown() { m_pClassList = NULL; } + + void Insert(T* pEntity) + { + pEntity->m_pNext = m_pClassList; + m_pClassList = pEntity; + } + + void Remove(T* pEntity) + { + T** pPrev = &m_pClassList; + T* pCur = *pPrev; + while (pCur) + { + if (pCur == pEntity) + { + *pPrev = pCur->m_pNext; + return; + } + pPrev = &pCur->m_pNext; + pCur = *pPrev; + } + } + + static T* m_pClassList; +}; + + +#define INVALID_CLIENTENTITY_HANDLE CBaseHandle( INVALID_EHANDLE_INDEX ) + + +class CClientEntityList : public CBaseEntityList, public IClientEntityList +{ + friend class C_BaseEntityIterator; + friend class C_AllBaseEntityIterator; + +public: + CClientEntityList(void); + virtual ~CClientEntityList(void); + + void Release(); + + +public: + + virtual IClientNetworkable* GetClientNetworkable(int entnum); + virtual IClientEntity* GetClientEntity(int entnum); + + virtual int NumberOfEntities(bool bIncludeNonNetworkable = false); + + virtual IClientUnknown* GetClientUnknownFromHandle(ClientEntityHandle_t hEnt); + virtual IClientNetworkable* GetClientNetworkableFromHandle(ClientEntityHandle_t hEnt); + virtual IClientEntity* GetClientEntityFromHandle(ClientEntityHandle_t hEnt); + + virtual int GetHighestEntityIndex(void); + + virtual void SetMaxEntities(int maxents); + virtual int GetMaxEntities(); + + +protected: + + virtual void OnAddEntity(IHandleEntity* pEnt, CBaseHandle handle); + virtual void OnRemoveEntity(IHandleEntity* pEnt, CBaseHandle handle); + + +public: + + IClientUnknown* GetListedEntity(int entnum); + + C_BaseEntity* GetBaseEntity(int entnum); + ICollideable* GetCollideable(int entnum); + + IClientRenderable* GetClientRenderableFromHandle(ClientEntityHandle_t hEnt); + C_BaseEntity* GetBaseEntityFromHandle(ClientEntityHandle_t hEnt); + ICollideable* GetCollideableFromHandle(ClientEntityHandle_t hEnt); + IClientThinkable* GetClientThinkableFromHandle(ClientEntityHandle_t hEnt); + + ClientEntityHandle_t EntIndexToHandle(int entnum); + int HandleToEntIndex(ClientEntityHandle_t handle); + + bool IsHandleValid(ClientEntityHandle_t handle) const; + + C_BaseEntity* GetEnt(int entnum) { return GetBaseEntity(entnum); } + + void RecomputeHighestEntityUsed(void); + + + C_BaseEntity* FirstBaseEntity() const; + C_BaseEntity* NextBaseEntity(C_BaseEntity* pEnt) const; + + class CPVSNotifyInfo + { + public: + IPVSNotify* m_pNotify; + IClientRenderable* m_pRenderable; + unsigned char m_InPVSStatus; + unsigned short m_PVSNotifiersLink; + }; + + CUtlLinkedList& GetPVSNotifiers(); + + CUtlVector m_entityListeners; + + void AddListenerEntity(IClientEntityListener* pListener); + void RemoveListenerEntity(IClientEntityListener* pListener); + + void NotifyCreateEntity(C_BaseEntity* pEnt); + void NotifyRemoveEntity(C_BaseEntity* pEnt); + +private: + + struct EntityCacheInfo_t + { + IClientNetworkable* m_pNetworkable; + unsigned short m_BaseEntitiesIndex; + }; + + int m_iNumServerEnts; + int m_iMaxServerEnts; + + int m_iNumClientNonNetworkable; + + int m_iMaxUsedServerIndex; + + EntityCacheInfo_t m_EntityCacheInfo[NUM_ENT_ENTRIES]; + + CUtlLinkedList m_BaseEntities; + + +private: + + void AddPVSNotifier(IClientUnknown* pUnknown); + void RemovePVSNotifier(IClientUnknown* pUnknown); + + CUtlLinkedList m_PVSNotifyInfos; + CUtlMap m_PVSNotifierMap; +}; + + +class C_AllBaseEntityIterator +{ +public: + C_AllBaseEntityIterator(); + + void Restart(); + C_BaseEntity* Next(); + +private: + unsigned short m_CurBaseEntity; +}; + +class C_BaseEntityIterator +{ +public: + C_BaseEntityIterator(); + + void Restart(); + C_BaseEntity* Next(); + +private: + unsigned short m_CurBaseEntity; +}; + +inline bool CClientEntityList::IsHandleValid(ClientEntityHandle_t handle) const +{ + return handle.Get() != 0; +} + +inline IClientUnknown* CClientEntityList::GetListedEntity(int entnum) +{ + return (IClientUnknown*)LookupEntityByNetworkIndex(entnum); +} + +inline IClientUnknown* CClientEntityList::GetClientUnknownFromHandle(ClientEntityHandle_t hEnt) +{ + return (IClientUnknown*)LookupEntity(hEnt); +} + +inline CUtlLinkedList& CClientEntityList::GetPVSNotifiers() +{ + return m_PVSNotifyInfos; +} + + +inline ClientEntityHandle_t CClientEntityList::EntIndexToHandle(int entnum) +{ + if (entnum < -1) + return INVALID_EHANDLE_INDEX; + IClientUnknown* pUnk = GetListedEntity(entnum); + return pUnk ? pUnk->GetRefEHandle() : INVALID_EHANDLE_INDEX; +} + + +extern CClientEntityList* cl_entitylist; + +inline CClientEntityList& ClientEntityList() +{ + return *cl_entitylist; +} + +class IClientEntityListener +{ +public: + virtual void OnEntityCreated(C_BaseEntity* pEntity) {}; + virtual void OnEntityDeleted(C_BaseEntity* pEntity) {}; +}; + + +#endif +``` + +`SpyCustom/sdk/clientleafsystem.h`: + +```h +#if !defined( CLIENTLEAFSYSTEM_H ) +#define CLIENTLEAFSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "IGameSystem.h" +#include "IClientLeafSystem.h" +#include "IVRenderView.h" +#include "mempool.h" +#include "refcount.h" + +#include "ivrenderview.h" + +struct WorldListInfo_t; +class IClientRenderable; +class Vector; +class CGameTrace; +typedef CGameTrace trace_t; +struct Ray_t; +class Vector2D; +class CStaticProp; + + + + + +enum +{ + DETAIL_PROP_RENDER_HANDLE = (ClientRenderHandle_t)0xfffe +}; + + +struct DistanceFadeInfo_t +{ + float m_flMaxDistSqr; + float m_flMinDistSqr; + float m_flFalloffFactor; +}; + + +class CClientRenderablesList : public CRefCounted<> +{ + DECLARE_FIXEDSIZE_ALLOCATOR(CClientRenderablesList); + +public: + enum + { + MAX_GROUP_ENTITIES = 4096, + MAX_BONE_SETUP_DEPENDENCY = 64, + }; + + struct CEntry + { + IClientRenderable* m_pRenderable; + unsigned short m_iWorldListInfoLeaf; + RenderableInstance_t m_InstanceData; + uint8 m_nModelType : 7; + uint8 m_TwoPass : 1; + }; + + DistanceFadeInfo_t m_DetailFade; + CEntry m_RenderGroups[RENDER_GROUP_COUNT][MAX_GROUP_ENTITIES]; + int m_RenderGroupCounts[RENDER_GROUP_COUNT]; + int m_nBoneSetupDependencyCount; + IClientRenderable* m_pBoneSetupDependency[MAX_BONE_SETUP_DEPENDENCY]; +}; + + +class CViewModelRenderablesList +{ +public: + enum + { + VM_GROUP_OPAQUE = 0, + VM_GROUP_TRANSLUCENT, + VM_GROUP_COUNT, + }; + + struct CEntry + { + IClientRenderable* m_pRenderable; + RenderableInstance_t m_InstanceData; + }; + + typedef CUtlVectorFixedGrowable< CEntry, 32 > RenderGroups_t; + + RenderGroups_t m_RenderGroups[VM_GROUP_COUNT]; +}; + + +struct SetupRenderInfo_t +{ + WorldListInfo_t* m_pWorldListInfo; + CClientRenderablesList* m_pRenderList; + Vector m_vecRenderOrigin; + Vector m_vecRenderForward; + int m_nRenderFrame; + int m_nDetailBuildFrame; + float m_flRenderDistSq; + int m_nViewID; + bool m_bDrawDetailObjects : 1; + bool m_bDrawTranslucentObjects : 1; + + SetupRenderInfo_t() + { + m_bDrawDetailObjects = true; + m_bDrawTranslucentObjects = true; + } +}; + + +struct ScreenSizeComputeInfo_t +{ + VMatrix m_matViewProj; + Vector m_vecViewUp; + int m_nViewportHeight; +}; + +void ComputeScreenSizeInfo(ScreenSizeComputeInfo_t* pInfo); +float ComputeScreenSize(const Vector& vecOrigin, float flRadius, const ScreenSizeComputeInfo_t& info); + + +typedef unsigned short ClientLeafShadowHandle_t; +enum +{ + CLIENT_LEAF_SHADOW_INVALID_HANDLE = (ClientLeafShadowHandle_t)~0 +}; + + +abstract_class IClientLeafShadowEnum +{ +public: + virtual void EnumShadow(ClientShadowHandle_t userId) = 0; +}; + + +class CClientLeafSubSystemData +{ +public: + virtual ~CClientLeafSubSystemData(void) + { + } +}; + + +#define CLSUBSYSTEM_DETAILOBJECTS 0 +#define N_CLSUBSYSTEMS 1 + + + +abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameSystemPerFrame +{ +public: + virtual void AddRenderable(IClientRenderable * pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled = 0xFFFFFFFF) = 0; + + virtual bool IsRenderableInPVS(IClientRenderable* pRenderable) = 0; + + virtual void SetSubSystemDataInLeaf(int leaf, int nSubSystemIdx, CClientLeafSubSystemData* pData) = 0; + virtual CClientLeafSubSystemData* GetSubSystemDataInLeaf(int leaf, int nSubSystemIdx) = 0; + + virtual void SetDetailObjectsInLeaf(int leaf, int firstDetailObject, int detailObjectCount) = 0; + virtual void GetDetailObjectsInLeaf(int leaf, int& firstDetailObject, int& detailObjectCount) = 0; + + virtual void DrawDetailObjectsInLeaf(int leaf, int frameNumber, int& firstDetailObject, int& detailObjectCount) = 0; + + virtual bool ShouldDrawDetailObjectsInLeaf(int leaf, int frameNumber) = 0; + + virtual void RenderableChanged(ClientRenderHandle_t handle) = 0; + + virtual void BuildRenderablesList(const SetupRenderInfo_t& info) = 0; + + virtual void CollateViewModelRenderables(CViewModelRenderablesList* pList) = 0; + + virtual void DrawStaticProps(bool enable) = 0; + + virtual void DrawSmallEntities(bool enable) = 0; + + virtual ClientLeafShadowHandle_t AddShadow(ClientShadowHandle_t userId, unsigned short flags) = 0; + virtual void RemoveShadow(ClientLeafShadowHandle_t h) = 0; + + virtual void ProjectShadow(ClientLeafShadowHandle_t handle, int nLeafCount, const int* pLeafList) = 0; + + virtual void ProjectFlashlight(ClientLeafShadowHandle_t handle, int nLeafCount, const int* pLeafList) = 0; + + virtual void EnumerateShadowsInLeaves(int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum) = 0; + + virtual int GetRenderableLeaves(ClientRenderHandle_t handle, int leaves[128]) = 0; + + virtual bool GetRenderableLeaf(ClientRenderHandle_t handle, int* pOutLeaf, const int* pInIterator = 0, int* pOutIterator = 0) = 0; + + virtual void EnableAlternateSorting(ClientRenderHandle_t handle, bool bEnable) = 0; + + virtual void RenderWithViewModels(ClientRenderHandle_t handle, bool bEnable) = 0; + virtual bool IsRenderingWithViewModels(ClientRenderHandle_t handle) const = 0; + + virtual void SetTranslucencyType(ClientRenderHandle_t handle, RenderableTranslucencyType_t nType) = 0; + virtual RenderableTranslucencyType_t GetTranslucencyType(ClientRenderHandle_t handle) const = 0; + virtual void SetModelType(ClientRenderHandle_t handle, RenderableModelType_t nType = RENDERABLE_MODEL_UNKNOWN_TYPE) = 0; + virtual void EnableSplitscreenRendering(ClientRenderHandle_t handle, uint32 nFlags) = 0; + + virtual void EnableRendering(ClientRenderHandle_t handle, bool bEnable) = 0; + + virtual void EnableBloatedBounds(ClientRenderHandle_t handle, bool bEnable) = 0; + + virtual void DisableCachedRenderBounds(ClientRenderHandle_t handle, bool bDisable) = 0; + + virtual void RecomputeRenderableLeaves() = 0; + + virtual void DisableLeafReinsertion(bool bDisable) = 0; + + virtual RenderGroup_t GenerateRenderListEntry(IClientRenderable* pRenderable, CClientRenderablesList::CEntry& entryOut) = 0; +}; + + +extern IClientLeafSystem* g_pClientLeafSystem; +inline IClientLeafSystem* ClientLeafSystem() +{ + return g_pClientLeafSystem; +} + + +#endif + +``` + +`SpyCustom/sdk/clientmode_shared.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENTMODE_NORMAL_H ) +#define CLIENTMODE_NORMAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iclientmode.h" +#include "GameEventListener.h" +#include "baseviewport.h" + + +class CBaseHudChat; +class CBaseHudWeaponSelection; +class CViewSetup; +class C_BaseEntity; +class C_BasePlayer; + +namespace vgui +{ +class Panel; +} + +//============================================================================= +// HPE_BEGIN: +// [tj] Moved this from the .cpp file so derived classes could access it +//============================================================================= + +#define ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME 10 + +//============================================================================= +// HPE_END +//============================================================================= + +class CReplayReminderPanel; + +#define USERID2PLAYER(i) ToBasePlayer( ClientEntityList().GetEnt( engine->GetPlayerForUserID( i ) ) ) + +extern IClientMode *GetClientModeNormal(); // must be implemented + +// This class implements client mode functionality common to HL2 and TF2. +/* +class ClientModeShared : public IClientMode, public CGameEventListener +{ +// IClientMode overrides. +public: + DECLARE_CLASS_NOBASE( ClientModeShared ); + + ClientModeShared(); + virtual ~ClientModeShared(); + + virtual void Init(); + virtual void InitViewport(); + virtual void VGui_Shutdown(); + virtual void Shutdown(); + + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); + + virtual void Enable(); + virtual void Disable(); + virtual void Layout(); + + virtual void ReloadScheme( void ); + virtual void OverrideView( CViewSetup *pSetup ); + virtual bool ShouldDrawDetailObjects( ); + virtual bool ShouldDrawEntity(C_BaseEntity *pEnt); + virtual bool ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ); + virtual bool ShouldDrawViewModel(); + virtual bool ShouldDrawParticles( ); + virtual bool ShouldDrawCrosshair( void ); + virtual bool ShouldBlackoutAroundHUD() OVERRIDE; + virtual HeadtrackMovementMode_t ShouldOverrideHeadtrackControl() OVERRIDE; + virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ); + virtual void PreRender(CViewSetup *pSetup); + virtual void PostRender(); + virtual void PostRenderVGui(); + virtual void ProcessInput(bool bActive); + virtual bool CreateMove( float flInputSampleTime, CUserCmd *cmd ); + virtual void Update(); + + // Input + virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + virtual void OverrideMouseInput( float *x, float *y ); + virtual void StartMessageMode( int iMessageModeType ); + virtual vgui::Panel *GetMessagePanel(); + + virtual void ActivateInGameVGuiContext( vgui::Panel *pPanel ); + virtual void DeactivateInGameVGuiContext(); + + // The mode can choose to not draw fog + virtual bool ShouldDrawFog( void ); + + virtual float GetViewModelFOV( void ); + virtual vgui::Panel* GetViewport() { return m_pViewport; } + // Gets at the viewports vgui panel animation controller, if there is one... + virtual vgui::AnimationController *GetViewportAnimationController() + { return m_pViewport->GetAnimationController(); } + + virtual void FireGameEvent( IGameEvent *event ); + + virtual bool CanRecordDemo( char *errorMsg, int length ) const { return true; } + + virtual int HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + virtual void ComputeVguiResConditions( KeyValues *pkvConditions ) OVERRIDE; + + //============================================================================= + // HPE_BEGIN: + // [menglish] Save server information shown to the client in a persistent place + //============================================================================= + + virtual wchar_t* GetServerName() { return NULL; } + virtual void SetServerName(wchar_t* name) {}; + virtual wchar_t* GetMapName() { return NULL; } + virtual void SetMapName(wchar_t* name) {}; + + //============================================================================= + // HPE_END + //============================================================================= + + virtual bool DoPostScreenSpaceEffects( const CViewSetup *pSetup ); + + virtual void DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent, + const char *pSound, bool bDlg ); + + virtual bool IsInfoPanelAllowed() OVERRIDE { return true; } + virtual void InfoPanelDisplayed() OVERRIDE { } + virtual bool IsHTMLInfoPanelAllowed() OVERRIDE { return true; } + +//protected: + void* ptr1; + void* ptr2; + CBaseViewport *m_pViewport; + + void DisplayReplayReminder(); + +//private: + virtual void UpdateReplayMessages(); + + void ClearReplayMessageList(); + +#if defined( REPLAY_ENABLED ) + float m_flReplayStartRecordTime; + float m_flReplayStopRecordTime; + CReplayReminderPanel *m_pReplayReminderPanel; +#endif + + // Message mode handling + // All modes share a common chat interface + CBaseHudChat *m_pChatElement; + vgui::HCursor m_CursorNone; + CBaseHudWeaponSelection *m_pWeaponSelection; + int m_nRootSize[2]; +}; +*/ + +class ClientModeShared : public IClientMode, public CGameEventListener +{ + // IClientMode overrides. +public: + DECLARE_CLASS_NOBASE(ClientModeShared); + + ClientModeShared(); + virtual ~ClientModeShared(); + virtual void Init(); + virtual void InitViewport(); + virtual void VGui_Shutdown(); + virtual void Shutdown(); + virtual void Enable(); + virtual void EnableWithRootPanel(vgui::VPANEL pRoot); + virtual void Disable(); + virtual void Layout(bool bForce = false); + virtual vgui::Panel* GetViewport(); + virtual vgui::Panel* GetPanelFromViewport(const char* pchNamePath); + virtual vgui::AnimationController* GetViewportAnimationController() { return m_pViewport->GetAnimationController(); }; + virtual void ProcessInput(bool bActive); + virtual bool ShouldDrawDetailObjects(); + virtual bool ShouldDrawEntity(C_BaseEntity* pEnt); + virtual bool ShouldDrawLocalPlayer(C_BasePlayer* pPlayer); + virtual bool ShouldDrawParticles(); + virtual bool ShouldDrawFog(void); + virtual void OverrideView(CViewSetup* pSetup); + virtual void OverrideAudioState(AudioState_t* pAudioState) { return; } + virtual int KeyInput(int down, ButtonCode_t keynum, const char* pszCurrentBinding); + virtual void StartMessageMode(int iMessageModeType); + virtual vgui::Panel* GetMessagePanel(); + virtual void OverrideMouseInput(float* x, float* y); + virtual bool CreateMove(float flInputSampleTime, CUserCmd* cmd); + virtual void LevelInit(const char* newmap); + virtual void LevelShutdown(void); + virtual bool ShouldDrawViewModel(void); + virtual bool ShouldDrawCrosshair(void); + virtual void AdjustEngineViewport(int& x, int& y, int& width, int& height); //29 + // Called before rendering a view. + virtual void PreRender(CViewSetup* pSetup) { return; }; // 30 just returns + // Called after everything is rendered. + virtual void PostRender(void); + virtual void PostRenderVGui(void); + virtual void ActivateInGameVGuiContext(vgui::Panel* pPanel); + virtual void DeactivateInGameVGuiContext(void); + virtual float GetViewModelFOV(void); + virtual bool CanRecordDemo(char* errorMsg, int length) const { return true; } + virtual wchar_t* GetServerName(void); + virtual void SetServerName(char* name); + virtual wchar_t* GetMapName(void); + virtual void SetMapName(char* name); // 40 + virtual void OnColorCorrectionWeightsReset(void); + virtual float GetColorCorrectionScale(void) const; + virtual int HudElementKeyInput(int down, ButtonCode_t keynum, const char* pszCurrentBinding); + virtual bool DoPostScreenSpaceEffects(const CViewSetup* pSetup); // 44 +public: + // Called every frame. + virtual void Update(); + virtual void SetBlurFade(float scale) {}; + virtual float GetBlurFade(void) { return 0.0f; }; + virtual void ReloadScheme(void); + virtual void ReloadSchemeWithRoot(unsigned int root); + virtual void OverrideRenderBounds(int& a1, int& a2, int& a3, int& a4, int& a5, int& a6); // 50 + virtual void FireGameEvent(IGameEvent* gameEvent); // 51 + + int GetSplitScreenPlayerSlot() const; + +public: + void* ptr1; + void* ptr2; + CBaseViewport* m_pViewport; + // Message mode handling + // All modes share a common chat interface + CHudChat* m_pChatElement; + vgui::HCursor m_CursorNone; + CBaseHudWeaponSelection* m_pWeaponSelection; + int m_nRootSize[2]; +}; + +#endif // CLIENTMODE_NORMAL_H +``` + +`SpyCustom/sdk/cmodel.h`: + +```h +#ifndef CMODEL_H +#define CMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "trace.h" +#include "dbg.h" +#include "basehandle.h" + +struct edict_t; +struct model_t; + +#include "bspflags.h" +#define AREA_SOLID 1 +#define AREA_TRIGGERS 2 + +#include "vcollide.h" + +struct cmodel_t +{ + Vector mins, maxs; + Vector origin; + int headnode; + + vcollide_t vcollisionData; +}; + +struct csurface_t +{ + const char* name; + short surfaceProps; + unsigned short flags; +}; + +struct Ray_t +{ + + + VectorAligned m_Start; + VectorAligned m_Delta; + VectorAligned m_StartOffset; + VectorAligned m_Extents; + const matrix3x4_t* m_pWorldAxisTransform; + bool m_IsRay; + bool m_IsSwept; + + Ray_t() : m_pWorldAxisTransform(NULL) {} + + void Init(Vector const& start, Vector const& end) + { + m_Delta = end - start; + + m_IsSwept = (m_Delta.LengthSqr() != 0); + + m_Extents.Init(); + + m_pWorldAxisTransform = NULL; + m_IsRay = true; + + m_StartOffset.Init(); + m_Start = start; + } + + Vector InvDelta() const + { + Vector vecInvDelta; + for (int iAxis = 0; iAxis < 3; ++iAxis) + { + if (m_Delta[iAxis] != 0.0f) + { + vecInvDelta[iAxis] = 1.0f / m_Delta[iAxis]; + } + else + { + vecInvDelta[iAxis] = FLT_MAX; + } + } + return vecInvDelta; + } + +private: +}; + + +#endif + + +#include "gametrace.h" +``` + +`SpyCustom/sdk/collisionproperty.h`: + +```h +#ifndef COLLISIONPROPERTY_H +#define COLLISIONPROPERTY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkvar.h" +#include "ICollideable.h" +#include "vector.h" +#include "ispatialpartition.h" + + +class CBaseEntity; +class IHandleEntity; +class QAngle; +class Vector; +struct Ray_t; +class IPhysicsObject; + + +void UpdateDirtySpatialPartitionEntities(); + + +enum SurroundingBoundsType_t +{ + USE_OBB_COLLISION_BOUNDS = 0, + USE_BEST_COLLISION_BOUNDS, + USE_HITBOXES, + USE_SPECIFIED_BOUNDS, + USE_GAME_CODE, + USE_ROTATION_EXPANDED_BOUNDS, + USE_COLLISION_BOUNDS_NEVER_VPHYSICS, + + SURROUNDING_TYPE_BIT_COUNT = 3 +}; + + +class CCollisionProperty : public ICollideable +{ + DECLARE_CLASS_NOBASE(CCollisionProperty); + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_PREDICTABLE(); + +#ifdef GAME_DLL + DECLARE_DATADESC(); +#endif + +public: + CCollisionProperty(); + ~CCollisionProperty(); + + void Init(CBaseEntity* pEntity); + + virtual IHandleEntity* GetEntityHandle(); + virtual const Vector& OBBMinsPreScaled() const { return m_vecMinsPreScaled.Get(); } + virtual const Vector& OBBMaxsPreScaled() const { return m_vecMaxsPreScaled.Get(); } + virtual const Vector& OBBMins() const { return m_vecMins.Get(); } + virtual const Vector& OBBMaxs() const { return m_vecMaxs.Get(); } + virtual void WorldSpaceTriggerBounds(Vector* pVecWorldMins, Vector* pVecWorldMaxs) const; + virtual bool TestCollision(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr); + virtual bool TestHitboxes(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr); + virtual int GetCollisionModelIndex(); + virtual const model_t* GetCollisionModel(); + virtual const Vector& GetCollisionOrigin() const; + virtual const QAngle& GetCollisionAngles() const; + virtual const matrix3x4_t& CollisionToWorldTransform() const; + virtual SolidType_t GetSolid() const; + virtual int GetSolidFlags() const; + virtual IClientUnknown* GetIClientUnknown(); + virtual int GetCollisionGroup() const; + virtual void WorldSpaceSurroundingBounds(Vector* pVecMins, Vector* pVecMaxs); + virtual bool ShouldTouchTrigger(int triggerSolidFlags) const; + virtual const matrix3x4_t* GetRootParentToWorldTransform() const; + +public: + void CreatePartitionHandle(); + void DestroyPartitionHandle(); + unsigned short GetPartitionHandle() const; + + void MarkPartitionHandleDirty(); + + void SetCollisionBounds(const Vector& mins, const Vector& maxs); + + void RefreshScaledCollisionBounds(void); + + void UseTriggerBounds(bool bEnable, float flBloat = 0.0f); + + void SetSurroundingBoundsType(SurroundingBoundsType_t type, const Vector* pMins = NULL, const Vector* pMaxs = NULL); + + void SetSolid(SolidType_t val); + + const Vector& OBBSize() const; + + float BoundingRadius() const; + float BoundingRadius2D() const; + + const Vector& OBBCenter() const; + + const Vector& WorldSpaceCenter() const; + + void ClearSolidFlags(void); + void RemoveSolidFlags(int flags); + void AddSolidFlags(int flags); + bool IsSolidFlagSet(int flagMask) const; + void SetSolidFlags(int flags); + bool IsSolid() const; + + void UpdatePartition(); + + bool IsBoundsDefinedInEntitySpace() const; + + const Vector& CollisionToWorldSpace(const Vector& in, Vector* pResult) const; + + const Vector& WorldToCollisionSpace(const Vector& in, Vector* pResult) const; + + const Vector& WorldDirectionToCollisionSpace(const Vector& in, Vector* pResult) const; + + void RandomPointInBounds(const Vector& vecNormalizedMins, const Vector& vecNormalizedMaxs, Vector* pPoint) const; + + bool IsPointInBounds(const Vector& vecWorldPt) const; + + void WorldSpaceAABB(Vector* pWorldMins, Vector* pWorldMaxs) const; + + const Vector& CollisionSpaceMins(void) const; + + const Vector& CollisionSpaceMaxs(void) const; + + const Vector& NormalizedToCollisionSpace(const Vector& in, Vector* pResult) const; + + const Vector& NormalizedToWorldSpace(const Vector& in, Vector* pResult) const; + + const Vector& WorldToNormalizedSpace(const Vector& in, Vector* pResult) const; + + const Vector& CollisionToNormalizedSpace(const Vector& in, Vector* pResult) const; + + void CalcNearestPoint(const Vector& vecWorldPt, Vector* pVecNearestWorldPt) const; + + float CalcDistanceFromPoint(const Vector& vecWorldPt) const; + + bool DoesRotationInvalidateSurroundingBox() const; + + bool DoesVPhysicsInvalidateSurroundingBox() const; + + void MarkSurroundingBoundsDirty(); + + float ComputeSupportMap(const Vector& vecDirection) const; + +private: + void CollisionAABBToWorldAABB(const Vector& entityMins, const Vector& entityMaxs, Vector* pWorldMins, Vector* pWorldMaxs) const; + + void ComputeVPhysicsSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + + bool ComputeHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + bool ComputeEntitySpaceHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + + void ComputeCollisionSurroundingBox(bool bUseVPhysics, Vector* pVecWorldMins, Vector* pVecWorldMaxs); + + void ComputeRotationExpandedBounds(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + + void ComputeSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); + + void CheckForUntouch(); + + void UpdateServerPartitionMask(); + + CBaseEntity* GetOuter(); + const CBaseEntity* GetOuter() const; + +private: + CBaseEntity* m_pOuter; + + CNetworkVector(m_vecMinsPreScaled); + CNetworkVector(m_vecMaxsPreScaled); + CNetworkVector(m_vecMins); + CNetworkVector(m_vecMaxs); + float m_flRadius; + + CNetworkVar(unsigned short, m_usSolidFlags); + + SpatialPartitionHandle_t m_Partition; + CNetworkVar(unsigned char, m_nSurroundType); + + CNetworkVar(unsigned char, m_nSolidType); + CNetworkVar(unsigned char, m_triggerBloat); + + CNetworkVector(m_vecSpecifiedSurroundingMinsPreScaled); + CNetworkVector(m_vecSpecifiedSurroundingMaxsPreScaled); + CNetworkVector(m_vecSpecifiedSurroundingMins); + CNetworkVector(m_vecSpecifiedSurroundingMaxs); + +#if 0 + short m_surroundingMins[3]; + short m_surroundingMaxs[3]; +#else + Vector m_vecSurroundingMins; + Vector m_vecSurroundingMaxs; +#endif + + friend class CBaseEntity; +}; + + +#ifdef CLIENT_DLL +EXTERN_RECV_TABLE(DT_CollisionProperty); +#else +EXTERN_SEND_TABLE(DT_CollisionProperty); +#endif + + +inline CBaseEntity* CCollisionProperty::GetOuter() +{ + return m_pOuter; +} + +inline const CBaseEntity* CCollisionProperty::GetOuter() const +{ + return m_pOuter; +} + + +inline unsigned short CCollisionProperty::GetPartitionHandle() const +{ + return m_Partition; +} + + +inline const Vector& CCollisionProperty::OBBSize() const +{ + Vector& temp = AllocTempVector(); + VectorSubtract(m_vecMaxs, m_vecMins, temp); + return temp; +} + + +inline float CCollisionProperty::BoundingRadius() const +{ + return m_flRadius; +} + + +inline bool CCollisionProperty::IsBoundsDefinedInEntitySpace() const +{ + return ((m_usSolidFlags & FSOLID_FORCE_WORLD_ALIGNED) == 0) && + (m_nSolidType != SOLID_BBOX) && (m_nSolidType != SOLID_NONE); +} + +inline void CCollisionProperty::ClearSolidFlags(void) +{ + SetSolidFlags(0); +} + +inline void CCollisionProperty::RemoveSolidFlags(int flags) +{ + SetSolidFlags(m_usSolidFlags & ~flags); +} + +inline void CCollisionProperty::AddSolidFlags(int flags) +{ + SetSolidFlags(m_usSolidFlags | flags); +} + +inline int CCollisionProperty::GetSolidFlags(void) const +{ + return m_usSolidFlags; +} + +inline bool CCollisionProperty::IsSolidFlagSet(int flagMask) const +{ + return (m_usSolidFlags & flagMask) != 0; +} + +inline bool CCollisionProperty::IsSolid() const +{ + return ::IsSolid((SolidType_t)(unsigned char)m_nSolidType, m_usSolidFlags); +} + + +inline const Vector& CCollisionProperty::OBBCenter() const +{ + Vector& vecResult = AllocTempVector(); + VectorLerp(m_vecMins, m_vecMaxs, 0.5f, vecResult); + return vecResult; +} + + +inline const Vector& CCollisionProperty::WorldSpaceCenter() const +{ + Vector& vecResult = AllocTempVector(); + CollisionToWorldSpace(OBBCenter(), &vecResult); + return vecResult; +} + + +inline const Vector& CCollisionProperty::CollisionToWorldSpace(const Vector& in, Vector* pResult) const +{ + if (!IsBoundsDefinedInEntitySpace() || (GetCollisionAngles() == vec3_angle)) + { + VectorAdd(in, GetCollisionOrigin(), *pResult); + } + else + { + VectorTransform(in, CollisionToWorldTransform(), *pResult); + } + return *pResult; +} + + +inline const Vector& CCollisionProperty::WorldToCollisionSpace(const Vector& in, Vector* pResult) const +{ + if (!IsBoundsDefinedInEntitySpace() || (GetCollisionAngles() == vec3_angle)) + { + VectorSubtract(in, GetCollisionOrigin(), *pResult); + } + else + { + VectorITransform(in, CollisionToWorldTransform(), *pResult); + } + return *pResult; +} + + +inline const Vector& CCollisionProperty::WorldDirectionToCollisionSpace(const Vector& in, Vector* pResult) const +{ + if (!IsBoundsDefinedInEntitySpace() || (GetCollisionAngles() == vec3_angle)) + { + *pResult = in; + } + else + { + VectorIRotate(in, CollisionToWorldTransform(), *pResult); + } + return *pResult; +} + + +inline void CCollisionProperty::WorldSpaceAABB(Vector* pWorldMins, Vector* pWorldMaxs) const +{ + CollisionAABBToWorldAABB(m_vecMins, m_vecMaxs, pWorldMins, pWorldMaxs); +} + + +inline const Vector& CCollisionProperty::CollisionSpaceMins(void) const +{ + return m_vecMins; +} + +inline const Vector& CCollisionProperty::CollisionSpaceMaxs(void) const +{ + return m_vecMaxs; +} + + +inline bool CCollisionProperty::DoesRotationInvalidateSurroundingBox() const +{ + if (IsSolidFlagSet(FSOLID_ROOT_PARENT_ALIGNED)) + return true; + + switch (m_nSurroundType) + { + case USE_COLLISION_BOUNDS_NEVER_VPHYSICS: + case USE_OBB_COLLISION_BOUNDS: + case USE_BEST_COLLISION_BOUNDS: + return IsBoundsDefinedInEntitySpace(); + + case USE_HITBOXES: + case USE_GAME_CODE: + return true; + + case USE_ROTATION_EXPANDED_BOUNDS: + case USE_SPECIFIED_BOUNDS: + return false; + + default: + Assert(0); + return true; + } +} + + +#endif +``` + +`SpyCustom/sdk/commandmenu.h`: + +```h +//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + + +#ifndef COMMANDMENU_H +#define COMMANDMENU_H + +#include "Menu.h" +#include "iviewport.h" +#include "filesystem.h" +#include "utlstack.h" +#include "utlvector.h" +#include "keyvalues.h" + +using namespace vgui; + +class CommandMenu : public Menu +{ +private: + DECLARE_CLASS_SIMPLE( CommandMenu, Menu ); + + typedef struct + { + Menu * menu; + int itemnr; + } CommandMenuItem; + + public: + CommandMenu( Panel *parent, const char *panelName, IViewPort * viewport ); + ~CommandMenu(); + + bool LoadFromFile(const char * fileName); // load menu from file (via KeyValues) + void UpdateMenu(); // call to update all menu items, check buttons etc + void RebuildMenu(); // rebuilds menu respecting changed game state (map, team etc) + void ClearMenu(); // destroy menu + + public: + // overwrite these in your derived class + // virtual CommandMenu * CommandMenu::Factory(Panel *parent, const char *panelName, IViewPort * viewport = NULL, IFileSystem * pFileSytem = NULL); // overwrite + virtual int AddCustomItem(KeyValues * params, Menu * menu) {return 0;} // return MenuItem nr + virtual void UpdateCustomItem(KeyValues * params, MenuItem * item ) {}; // maybe change your item + virtual void OnCustomItem(KeyValues * params) {}; // a custom item was pressed + virtual bool CheckRules(const char *rule, const char *ruledata); // check a menu item rule + virtual void SetVisible(bool state); + + // DON'T touch anything below ! + + protected: + + void OnMessage(const KeyValues *params, VPANEL fromPanel); + void StartNewSubMenu(KeyValues * params); + void FinishSubMenu(); + void AddMenuCommandItem(KeyValues * params); + void AddMenuCustomItem(KeyValues * params); + void AddMenuToggleItem(KeyValues * params); + bool LoadFromKeyValuesInternal(KeyValues * key, int depth); + bool LoadFromKeyValues( KeyValues * key); // + + KeyValues * GetKeyValues(); // returns keyValues for current menu or NULL + + + IViewPort * m_ViewPort; // viewport interface + Menu * m_CurrentMenu; // Current menu while building CommandComoboBox + char m_CurrentTeam[4]; + char m_CurrentMap[256]; + + KeyValues* m_MenuKeys; + + CUtlStackm_pMenuStack; + CUtlVectorm_MenuItems; +}; + +#endif // COMMANDMENU_H +``` + +`SpyCustom/sdk/commonmacros.h`: + +```h +#ifndef COMMONMACROS_H +#define COMMONMACROS_H + +#ifdef _WIN32 +#pragma once +#endif + +#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)) + +template +inline bool IsPowerOfTwo(T value) +{ + return (value & (value - (T)1)) == (T)0; +} + +#ifndef REFERENCE +#define REFERENCE(arg) ((void)arg) +#endif + +#define CONST_INTEGER_AS_STRING(x) #x +#define __HACK_LINE_AS_STRING__(x) CONST_INTEGER_AS_STRING(x) +#define __LINE__AS_STRING __HACK_LINE_AS_STRING__(__LINE__) + +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif + +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) + +#if defined(__cplusplus) && \ + !defined(MIDL_PASS) && \ + !defined(RC_INVOKED) && \ + (_MSC_FULL_VER >= 13009466) && \ + !defined(SORTPP_PASS) + +#if !defined(UNALIGNED) +#if defined(_M_IA64) || defined(_M_AMD64) +#define UNALIGNED __unaligned +#else +#define UNALIGNED +#endif +#endif + +extern "C++" +template +char(*RtlpNumberOf(UNALIGNED T(&)[N]))[N]; + +#ifdef _PREFAST_ +#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))+0) +#else +#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))) +#endif + +#else +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) +#endif + +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#define Q_ARRAYSIZE(p) ARRAYSIZE(p) + +template< typename IndexType, typename T, unsigned int N > +IndexType ClampedArrayIndex(const T(&buffer)[N], IndexType index) +{ + NOTE_UNUSED(buffer); + return clamp(index, 0, (IndexType)N - 1); +} + +template< typename T, unsigned int N > +T ClampedArrayElement(const T(&buffer)[N], unsigned int uIndex) +{ + if (uIndex >= N) + uIndex = N - 1; + return buffer[uIndex]; +} + +#endif +``` + +`SpyCustom/sdk/compressed_light_cube.h`: + +```h +#ifndef COMPRESSED_LIGHT_CUBE_H +#define COMPRESSED_LIGHT_CUBE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib.h" + + +struct CompressedLightCube +{ + DECLARE_BYTESWAP_DATADESC(); + ColorRGBExp32 m_Color[6]; +}; + + +#endif +``` + +`SpyCustom/sdk/compressed_vector.h`: + +```h +#ifndef COMPRESSED_VECTOR_H +#define COMPRESSED_VECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +#include "basetypes.h" + +#include + +#include "dbg.h" +#include "vector.h" + +#include "mathlib.h" + +#if defined( _X360 ) +#pragma bitfield_order( push, lsb_to_msb ) +#endif +class Vector32 +{ +public: + Vector32(void); + Vector32(vec_t X, vec_t Y, vec_t Z); + + Vector32& operator=(const Vector& vOther); + operator Vector (); + +private: + unsigned short x : 10; + unsigned short y : 10; + unsigned short z : 10; + unsigned short exp : 2; +}; + +inline Vector32& Vector32::operator=(const Vector& vOther) +{ + CHECK_VALID(vOther); + + static float expScale[4] = { 4.0f, 16.0f, 32.f, 64.f }; + + float fmax = Max(fabs(vOther.x), fabs(vOther.y)); + fmax = Max(fmax, (float)fabs(vOther.z)); + + for (exp = 0; exp < 3; exp++) + { + if (fmax < expScale[exp]) + break; + } + Assert(fmax < expScale[exp]); + + float fexp = 512.0f / expScale[exp]; + + x = Clamp((int)(vOther.x * fexp) + 512, 0, 1023); + y = Clamp((int)(vOther.y * fexp) + 512, 0, 1023); + z = Clamp((int)(vOther.z * fexp) + 512, 0, 1023); + return *this; +} + + +inline Vector32::operator Vector () +{ + Vector tmp; + + static float expScale[4] = { 4.0f, 16.0f, 32.f, 64.f }; + + float fexp = expScale[exp] / 512.0f; + + tmp.x = (((int)x) - 512) * fexp; + tmp.y = (((int)y) - 512) * fexp; + tmp.z = (((int)z) - 512) * fexp; + return tmp; +} + + +class Normal32 +{ +public: + Normal32(void); + Normal32(vec_t X, vec_t Y, vec_t Z); + + Normal32& operator=(const Vector& vOther); + operator Vector (); + +private: + unsigned short x : 15; + unsigned short y : 15; + unsigned short zneg : 1; +}; + + +inline Normal32& Normal32::operator=(const Vector& vOther) +{ + CHECK_VALID(vOther); + + x = Clamp((int)(vOther.x * 16384) + 16384, 0, 32767); + y = Clamp((int)(vOther.y * 16384) + 16384, 0, 32767); + zneg = (vOther.z < 0); + return *this; +} + + +inline Normal32::operator Vector () +{ + Vector tmp; + + tmp.x = ((int)x - 16384) * (1 / 16384.0); + tmp.y = ((int)y - 16384) * (1 / 16384.0); + tmp.z = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y); + if (zneg) + tmp.z = -tmp.z; + return tmp; +} + + +class Quaternion64 +{ +public: + Quaternion64(void); + Quaternion64(vec_t X, vec_t Y, vec_t Z); + + Quaternion64& operator=(const Quaternion& vOther); + operator Quaternion (); +private: + uint64 x : 21; + uint64 y : 21; + uint64 z : 21; + uint64 wneg : 1; +}; + + +inline Quaternion64::operator Quaternion () +{ + Quaternion tmp; + + tmp.x = ((int)x - 1048576) * (1 / 1048576.5f); + tmp.y = ((int)y - 1048576) * (1 / 1048576.5f); + tmp.z = ((int)z - 1048576) * (1 / 1048576.5f); + tmp.w = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z); + if (wneg) + tmp.w = -tmp.w; + return tmp; +} + +inline Quaternion64& Quaternion64::operator=(const Quaternion& vOther) +{ + CHECK_VALID(vOther); + + x = Clamp((int)(vOther.x * 1048576) + 1048576, 0, 2097151); + y = Clamp((int)(vOther.y * 1048576) + 1048576, 0, 2097151); + z = Clamp((int)(vOther.z * 1048576) + 1048576, 0, 2097151); + wneg = (vOther.w < 0); + return *this; +} + +class Quaternion48 +{ +public: + Quaternion48(void); + Quaternion48(vec_t X, vec_t Y, vec_t Z); + + Quaternion48& operator=(const Quaternion& vOther); + operator Quaternion (); +private: + unsigned short x : 16; + unsigned short y : 16; + unsigned short z : 15; + unsigned short wneg : 1; +}; + + +inline Quaternion48::operator Quaternion () +{ + Quaternion tmp; + + tmp.x = ((int)x - 32768) * (1 / 32768.0); + tmp.y = ((int)y - 32768) * (1 / 32768.0); + tmp.z = ((int)z - 16384) * (1 / 16384.0); + tmp.w = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z); + if (wneg) + tmp.w = -tmp.w; + return tmp; +} + +inline Quaternion48& Quaternion48::operator=(const Quaternion& vOther) +{ + CHECK_VALID(vOther); + + x = Clamp((int)(vOther.x * 32768) + 32768, 0, 65535); + y = Clamp((int)(vOther.y * 32768) + 32768, 0, 65535); + z = Clamp((int)(vOther.z * 16384) + 16384, 0, 32767); + wneg = (vOther.w < 0); + return *this; +} + +class Quaternion32 +{ +public: + Quaternion32(void); + Quaternion32(vec_t X, vec_t Y, vec_t Z); + + Quaternion32& operator=(const Quaternion& vOther); + operator Quaternion (); +private: + unsigned int x : 11; + unsigned int y : 10; + unsigned int z : 10; + unsigned int wneg : 1; +}; + + +inline Quaternion32::operator Quaternion () +{ + Quaternion tmp; + + tmp.x = ((int)x - 1024) * (1 / 1024.0); + tmp.y = ((int)y - 512) * (1 / 512.0); + tmp.z = ((int)z - 512) * (1 / 512.0); + tmp.w = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z); + if (wneg) + tmp.w = -tmp.w; + return tmp; +} + +inline Quaternion32& Quaternion32::operator=(const Quaternion& vOther) +{ + CHECK_VALID(vOther); + + x = Clamp((int)(vOther.x * 1024) + 1024, 0, 2047); + y = Clamp((int)(vOther.y * 512) + 512, 0, 1023); + z = Clamp((int)(vOther.z * 512) + 512, 0, 1023); + wneg = (vOther.w < 0); + return *this; +} + + +const int float32bias = 127; +const int float16bias = 15; + +const float maxfloat16bits = 65504.0f; + +class float16 +{ +public: + void Init() { m_storage.rawWord = 0; } + unsigned short GetBits() const + { + return m_storage.rawWord; + } + float GetFloat() const + { + return Convert16bitFloatTo32bits(m_storage.rawWord); + } + void SetFloat(float in) + { + m_storage.rawWord = ConvertFloatTo16bits(in); + } + + bool IsInfinity() const + { + return m_storage.bits.biased_exponent == 31 && m_storage.bits.mantissa == 0; + } + bool IsNaN() const + { + return m_storage.bits.biased_exponent == 31 && m_storage.bits.mantissa != 0; + } + + bool operator==(const float16 other) const { return m_storage.rawWord == other.m_storage.rawWord; } + bool operator!=(const float16 other) const { return m_storage.rawWord != other.m_storage.rawWord; } + +protected: + union float32bits + { + float rawFloat; + struct + { + unsigned int mantissa : 23; + unsigned int biased_exponent : 8; + unsigned int sign : 1; + } bits; + }; + + union float16bits + { + unsigned short rawWord; + struct + { + unsigned short mantissa : 10; + unsigned short biased_exponent : 5; + unsigned short sign : 1; + } bits; + }; + + static bool IsNaN(float16bits in) + { + return in.bits.biased_exponent == 31 && in.bits.mantissa != 0; + } + static bool IsInfinity(float16bits in) + { + return in.bits.biased_exponent == 31 && in.bits.mantissa == 0; + } + + static unsigned short ConvertFloatTo16bits(float input) + { + if (input > maxfloat16bits) + input = maxfloat16bits; + else if (input < -maxfloat16bits) + input = -maxfloat16bits; + + float16bits output; + float32bits inFloat; + + inFloat.rawFloat = input; + + output.bits.sign = inFloat.bits.sign; + + if ((inFloat.bits.biased_exponent == 0) && (inFloat.bits.mantissa == 0)) + { + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; + } + else if ((inFloat.bits.biased_exponent == 0) && (inFloat.bits.mantissa != 0)) + { + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; + } + else if ((inFloat.bits.biased_exponent == 0xff) && (inFloat.bits.mantissa == 0)) + { +#if 0 + output.bits.mantissa = 0; + output.bits.biased_exponent = 31; +#else + output.bits.mantissa = 0x3ff; + output.bits.biased_exponent = 0x1e; +#endif + } + else if ((inFloat.bits.biased_exponent == 0xff) && (inFloat.bits.mantissa != 0)) + { +#if 0 + output.bits.mantissa = 1; + output.bits.biased_exponent = 31; +#else + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; +#endif + } + else + { + int new_exp = inFloat.bits.biased_exponent - 127; + + if (new_exp < -24) + { + output.bits.mantissa = 0; + output.bits.biased_exponent = 0; + } + + if (new_exp < -14) + { + output.bits.biased_exponent = 0; + unsigned int exp_val = (unsigned int)(-14 - (inFloat.bits.biased_exponent - float32bias)); + if (exp_val > 0 && exp_val < 11) + { + output.bits.mantissa = (1 << (10 - exp_val)) + (inFloat.bits.mantissa >> (13 + exp_val)); + } + } + else if (new_exp > 15) + { +#if 0 + output.bits.mantissa = 0; + output.bits.biased_exponent = 31; +#else + output.bits.mantissa = 0x3ff; + output.bits.biased_exponent = 0x1e; +#endif + } + else + { + output.bits.biased_exponent = new_exp + 15; + output.bits.mantissa = (inFloat.bits.mantissa >> 13); + } + } + return output.rawWord; + } + + static float Convert16bitFloatTo32bits(unsigned short input) + { + float32bits output; + const float16bits& inFloat = *((float16bits*)&input); + + if (IsInfinity(inFloat)) + { + return maxfloat16bits * ((inFloat.bits.sign == 1) ? -1.0f : 1.0f); + } + if (IsNaN(inFloat)) + { + return 0.0; + } + if (inFloat.bits.biased_exponent == 0 && inFloat.bits.mantissa != 0) + { + const float half_denorm = (1.0f / 16384.0f); + float mantissa = ((float)(inFloat.bits.mantissa)) / 1024.0f; + float sgn = (inFloat.bits.sign) ? -1.0f : 1.0f; + output.rawFloat = sgn * mantissa * half_denorm; + } + else + { + unsigned mantissa = inFloat.bits.mantissa; + unsigned biased_exponent = inFloat.bits.biased_exponent; + unsigned sign = ((unsigned)inFloat.bits.sign) << 31; + biased_exponent = ((biased_exponent - float16bias + float32bias) * (biased_exponent != 0)) << 23; + mantissa <<= (23 - 10); + + *((unsigned*)&output) = (mantissa | biased_exponent | sign); + } + + return output.rawFloat; + } + + + float16bits m_storage; +}; + +class float16_with_assign : public float16 +{ +public: + float16_with_assign() {} + float16_with_assign(float f) { m_storage.rawWord = ConvertFloatTo16bits(f); } + + float16& operator=(const float16& other) { m_storage.rawWord = ((float16_with_assign&)other).m_storage.rawWord; return *this; } + float16& operator=(const float& other) { m_storage.rawWord = ConvertFloatTo16bits(other); return *this; } + operator float() const { return Convert16bitFloatTo32bits(m_storage.rawWord); } +}; + +class Vector48 +{ +public: + Vector48(void) {} + Vector48(vec_t X, vec_t Y, vec_t Z) { x.SetFloat(X); y.SetFloat(Y); z.SetFloat(Z); } + + Vector48& operator=(const Vector& vOther); + operator Vector (); + + const float operator[](int i) const { return (((float16*)this)[i]).GetFloat(); } + + float16 x; + float16 y; + float16 z; +}; + +inline Vector48& Vector48::operator=(const Vector& vOther) +{ + CHECK_VALID(vOther); + + x.SetFloat(vOther.x); + y.SetFloat(vOther.y); + z.SetFloat(vOther.z); + return *this; +} + + +inline Vector48::operator Vector () +{ + Vector tmp; + + tmp.x = x.GetFloat(); + tmp.y = y.GetFloat(); + tmp.z = z.GetFloat(); + + return tmp; +} + +class Vector2d32 +{ +public: + Vector2d32(void) {} + Vector2d32(vec_t X, vec_t Y) { x.SetFloat(X); y.SetFloat(Y); } + + Vector2d32& operator=(const Vector& vOther); + Vector2d32& operator=(const Vector2D& vOther); + + operator Vector2D (); + + void Init(vec_t ix = 0.f, vec_t iy = 0.f); + + float16_with_assign x; + float16_with_assign y; +}; + +inline Vector2d32& Vector2d32::operator=(const Vector2D& vOther) +{ + x.SetFloat(vOther.x); + y.SetFloat(vOther.y); + return *this; +} + +inline Vector2d32::operator Vector2D () +{ + Vector2D tmp; + + tmp.x = x.GetFloat(); + tmp.y = y.GetFloat(); + + return tmp; +} + +inline void Vector2d32::Init(vec_t ix, vec_t iy) +{ + x.SetFloat(ix); + y.SetFloat(iy); +} + +#if defined( _X360 ) +#pragma bitfield_order( pop ) +#endif + +#endif + +``` + +`SpyCustom/sdk/const.h`: + +```h +#ifndef CONST_H +#define CONST_H + +#ifdef _WIN32 +#pragma once +#endif + +#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 + +#ifdef _X360 +#define MAX_PLAYERS_PER_CLIENT XUSER_MAX_COUNT +#else +#define MAX_PLAYERS_PER_CLIENT 1 +#endif + +#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<& commands) = 0; +}; + +class ConCommandBase +{ + friend class CCvar; + friend class ConVar; + friend class ConCommand; + friend void ConVar_Register(int nCVarFlag, IConCommandBaseAccessor* pAccessor); + friend class CDefaultCvar; + +public: + ConCommandBase(void); + ConCommandBase(const char* pName, const char* pHelpString = 0, + int flags = 0); + + virtual ~ConCommandBase(void); + + virtual bool IsCommand(void) const; + + virtual bool IsFlagSet(int flag) const; + virtual void AddFlags(int flags); + virtual void RemoveFlags(int flags); + virtual int GetFlags() const; + virtual const char* GetName(void) const; + + virtual const char* GetHelpText(void) const; + + const ConCommandBase* GetNext(void) const; + ConCommandBase* GetNext(void); + + virtual bool IsRegistered(void) const; + + virtual CVarDLLIdentifier_t GetDLLIdentifier() const; + + virtual void Create(const char* pName, const char* pHelpString = 0, + int flags = 0); + + virtual void Init(); + void Shutdown(); + + char* CopyString(const char* from); + + 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; +}; + + +class CCommand +{ +public: + CCommand(); + CCommand(int nArgC, const char** ppArgV); + bool Tokenize(const char* pCommand, characterset_t* pBreakSet = NULL); + void Reset(); + + int ArgC() const; + const char** ArgV() const; + const char* ArgS() const; + const char* GetCommandString() const; + const char* operator[](int nIndex) const; + const char* Arg(int nIndex) const; + + const char* FindArg(const char* pName) const; + int FindArgInt(const char* pName, int nDefaultVal) const; + + static int MaxCommandLength(); + static characterset_t* DefaultBreakSet(); + +private: + enum + { + COMMAND_MAX_ARGC = 64, + COMMAND_MAX_LENGTH = 512, + }; + + int m_nArgc; + int m_nArgv0Size; + char m_pArgSBuffer[COMMAND_MAX_LENGTH]; + char m_pArgvBuffer[COMMAND_MAX_LENGTH]; + const char* m_ppArgv[COMMAND_MAX_ARGC]; +}; + +inline int CCommand::MaxCommandLength() +{ + return COMMAND_MAX_LENGTH - 1; +} + +inline int CCommand::ArgC() const +{ + return m_nArgc; +} + +inline const char** CCommand::ArgV() const +{ + return m_nArgc ? (const char**)m_ppArgv : NULL; +} + +inline const char* CCommand::ArgS() const +{ + return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; +} + +inline const char* CCommand::GetCommandString() const +{ + return m_nArgc ? m_pArgSBuffer : ""; +} + +inline const char* CCommand::Arg(int nIndex) const +{ + if (nIndex < 0 || nIndex >= m_nArgc) + return ""; + return m_ppArgv[nIndex]; +} + +inline const char* CCommand::operator[](int nIndex) const +{ + return Arg(nIndex); +} + + +class ConCommand : public ConCommandBase +{ + friend class CCvar; + +public: + typedef ConCommandBase BaseClass; + + ConCommand(const char* pName, FnCommandCallbackVoid_t callback, + const char* pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0); + ConCommand(const char* pName, FnCommandCallback_t callback, + const char* pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0); + ConCommand(const char* pName, ICommandCallback* pCallback, + const char* pHelpString = 0, int flags = 0, ICommandCompletionCallback* pCommandCompletionCallback = 0); + + virtual ~ConCommand(void); + + virtual bool IsCommand(void) const; + + virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands); + + virtual bool CanAutoComplete(void); + + 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 +{ + friend class CCvar; + friend class ConVarRef; + +public: + typedef ConCommandBase BaseClass; + + ConVar(const char* pName, const char* pDefaultValue, int flags = 0); + + ConVar(const char* pName, const char* pDefaultValue, int flags, + const char* pHelpString); + ConVar(const char* pName, const char* pDefaultValue, int flags, + const char* pHelpString, bool bMin, float fMin, bool bMax, float fMax); + ConVar(const char* pName, const char* pDefaultValue, int flags, + const char* pHelpString, FnChangeCallback_t callback); + ConVar(const char* pName, const char* pDefaultValue, int flags, + const char* pHelpString, bool bMin, float fMin, bool bMax, float fMax, + FnChangeCallback_t callback); + + virtual ~ConVar(void); + + virtual bool IsFlagSet(int flag) const; + virtual const char* GetHelpText(void) const; + virtual bool IsRegistered(void) const; + virtual const char* GetName(void) const; + virtual const char* GetBaseName(void) const; + virtual int GetSplitScreenPlayerSlot() const; + virtual void AddFlags(int flags); + virtual int GetFlags() const; + virtual bool IsCommand(void) const; + + void InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke = true); + + void RemoveChangeCallback(FnChangeCallback_t callbackToRemove); + + int GetChangeCallbackCount() const { return m_pParent->m_fnChangeCallbacks.Count(); } + FnChangeCallback_t GetChangeCallback(int slot) const { return m_pParent->m_fnChangeCallbacks[slot]; } + + + FORCEINLINE_CVAR float GetFloat(void) const; + FORCEINLINE_CVAR int GetInt(void) const; + FORCEINLINE_CVAR Color GetColor(void) const; + FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); } + FORCEINLINE_CVAR char const* GetString(void) const; + + template T Get(void) const; + template T Get(T*) const; + + virtual void SetValue(const char* value); + virtual void SetValue(float value); + virtual void SetValue(int value); + virtual void SetValue(Color value); + + void Revert(void); + bool HasMin() const; + bool HasMax() const; + + struct CVValue_t + { + char* m_pszString; + int m_StringLength; + float m_fValue; + int m_nValue; + }; + + bool GetMin(float& minVal) const; + bool GetMax(float& maxVal) const; + float GetMinValue() const; + float GetMaxValue() const; + const char* GetDefault(void) const; + FORCEINLINE_CVAR CVValue_t& GetRawValue() + { + return m_Value; + } + FORCEINLINE_CVAR const CVValue_t& GetRawValue() const + { + return m_Value; + } + + bool InternalSetColorFromString(const char* value); + virtual void InternalSetValue(const char* value); + virtual void InternalSetFloatValue(float fNewValue); + virtual void InternalSetIntValue(int nValue); + virtual void InternalSetColorValue(Color value); + virtual bool ClampValue(float& value); + virtual void ChangeStringValue(const char* tempVal, float flOldValue); + + virtual void Create(const char* pName, const char* pDefaultValue, int flags = 0, + const char* pHelpString = 0, bool bMin = false, float fMin = 0.0, + bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0); + + virtual void Init(); + int GetFlags() { return m_pParent->m_nFlags; } +public: + + ConVar* m_pParent; + + const char* m_pszDefaultValue; + + CVValue_t m_Value; + bool m_bHasMin; + float m_fMinVal; + bool m_bHasMax; + float m_fMaxVal; + + CUtlVector m_fnChangeCallbacks; +}; + + +FORCEINLINE_CVAR float ConVar::GetFloat(void) const +{ + uint32_t xored = *(uint32_t*)&m_pParent->m_Value.m_fValue ^ (uint32_t)this; + return *(float*)&xored; +} + +FORCEINLINE_CVAR int ConVar::GetInt(void) const +{ + return (int)(m_pParent->m_Value.m_nValue ^ (int)this); +} + + +FORCEINLINE_CVAR const char* ConVar::GetString(void) const +{ + if (m_nFlags & FCVAR_NEVER_AS_STRING) + return "FCVAR_NEVER_AS_STRING"; + char const* str = m_pParent->m_Value.m_pszString; + return str ? str : ""; +} + +class ConVarRef +{ +public: + ConVarRef(const char* pName); + ConVarRef(const char* pName, bool bIgnoreMissing); + ConVarRef(IConVar* pConVar); + + void Init(const char* pName, bool bIgnoreMissing); + bool IsValid() const; + bool IsFlagSet(int nFlags) const; + IConVar* GetLinkedConVar(); + + float GetFloat(void) const; + int GetInt(void) const; + bool GetBool() const { return !!GetInt(); } + const char* GetString(void) const; + + void SetValue(const char* pValue); + void SetValue(float flValue); + void SetValue(int nValue); + void SetValue(bool bValue); + + const char* GetName() const; + + const char* GetDefault() const; + +private: + IConVar* m_pConVar; + ConVar* m_pConVarState; +}; + + +FORCEINLINE_CVAR bool ConVarRef::IsFlagSet(int nFlags) const +{ + return (m_pConVar->IsFlagSet(nFlags) != 0); +} + +FORCEINLINE_CVAR IConVar* ConVarRef::GetLinkedConVar() +{ + return m_pConVar; +} + +FORCEINLINE_CVAR const char* ConVarRef::GetName() const +{ + return m_pConVar->GetName(); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue(const char* pValue) +{ + m_pConVar->SetValue(pValue); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue(float flValue) +{ + m_pConVar->SetValue(flValue); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue(int nValue) +{ + m_pConVar->SetValue(nValue); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue(bool bValue) +{ + m_pConVar->SetValue(bValue ? 1 : 0); +} + +FORCEINLINE_CVAR const char* ConVarRef::GetDefault() const +{ + return m_pConVarState->m_pszDefaultValue; +} + + +void ConVar_Register(int nCVarFlag = 0, IConCommandBaseAccessor* pAccessor = NULL); +void ConVar_Unregister(); + + +void ConVar_PrintFlags(const ConCommandBase* var); +void ConVar_PrintDescription(const ConCommandBase* pVar); + + +#pragma warning (disable : 4355 ) + +template< class T > +class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback +{ + typedef ConCommand BaseClass; + typedef void (T::* FnMemberCommandCallback_t)(const CCommand& command); + typedef int (T::* FnMemberCommandCompletionCallback_t)(const char* pPartial, CUtlVector< CUtlString >& commands); + +public: + CConCommandMemberAccessor(T* pOwner, const char* pName, FnMemberCommandCallback_t callback, const char* pHelpString = 0, + int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0) : + BaseClass(pName, this, pHelpString, flags, (completionFunc != 0) ? this : NULL) + { + m_pOwner = pOwner; + m_Func = callback; + m_CompletionFunc = completionFunc; + } + + ~CConCommandMemberAccessor() + { + Shutdown(); + } + + void SetOwner(T* pOwner) + { + m_pOwner = pOwner; + } + + virtual void CommandCallback(const CCommand& command) + { + Assert(m_pOwner && m_Func); + (m_pOwner->*m_Func)(command); + } + + virtual int CommandCompletionCallback(const char* pPartial, CUtlVector< CUtlString >& commands) + { + Assert(m_pOwner && m_CompletionFunc); + return (m_pOwner->*m_CompletionFunc)(pPartial, commands); + } + +private: + T* m_pOwner; + FnMemberCommandCallback_t m_Func; + FnMemberCommandCompletionCallback_t m_CompletionFunc; +}; + +#pragma warning ( default : 4355 ) + + +#define CON_COMMAND( name, description ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_F( name, description, flags ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description, flags ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description, flags, completion ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_EXTERN( name, _funcname, description ) \ + void _funcname( const CCommand &args ); \ + static ConCommand name##_command( #name, _funcname, description ); \ + void _funcname( const CCommand &args ) + +#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \ + void _funcname( const CCommand &args ); \ + static ConCommand name##_command( #name, _funcname, description, flags ); \ + void _funcname( const CCommand &args ) + +#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \ + void _funcname( const CCommand &args ); \ + friend class CCommandMemberInitializer_##_funcname; \ + class CCommandMemberInitializer_##_funcname \ + { \ + public: \ + CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \ + { \ + m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \ + } \ + private: \ + CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \ + }; \ + \ + CCommandMemberInitializer_##_funcname m_##_funcname##_register; \ + + +#endif +``` + +`SpyCustom/sdk/coordsize.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef COORDSIZE_H +#define COORDSIZE_H +#pragma once + +#include "worldsize.h" + +// OVERALL Coordinate Size Limits used in COMMON.C MSG_*BitCoord() Routines (and someday the HUD) +#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 DIST_EPSILON (0.03125) + +// Verify that coordsize.h and worldsize.h are consistently defined +#if (MAX_COORD_INTEGER != (1<IsHLTV() || engine->IsPlayingDemo()) && engine->GetConnectionDataProtocol() <= OLD_CROUCH_PROTOCOL_INDEX; } +#endif +#endif + +template< class T > +class CUtlVectorInitialized : public CUtlVector< T > +{ +public: + CUtlVectorInitialized(T* pMemory, int numElements) : CUtlVector< T >(pMemory, numElements) + { + CUtlVector< T >::SetSize(numElements); + } +}; + +namespace TeamJoinFailedReason +{ + enum Type + { + CHANGED_TOO_OFTEN, + BOTH_TEAMS_FULL, + TERRORISTS_FULL, + CTS_FULL, + CANT_JOIN_SPECTATOR, + HUMANS_CAN_ONLY_JOIN_TS, + HUMANS_CAN_ONLY_JOIN_CTS, + TOO_MANY_TS, + TOO_MANY_CTS, + }; +}; + +#define CS_HOSTAGE_TRANSTIME_PICKUP 0.1 +#define CS_HOSTAGE_TRANSTIME_DROP 0.25 +#define CS_HOSTAGE_TRANSTIME_RESCUE 4.0 + +enum EHostageStates_t +{ + k_EHostageStates_Idle = 0, + k_EHostageStates_BeingUntied, + k_EHostageStates_GettingPickedUp, + k_EHostageStates_BeingCarried, + k_EHostageStates_FollowingPlayer, + k_EHostageStates_GettingDropped, + k_EHostageStates_Rescued, + k_EHostageStates_Dead, +}; + +#define CONSTANT_UNITS_SMOKEGRENADERADIUS 166 +#define CONSTANT_UNITS_GENERICGRENADERADIUS 115 + +const float SmokeGrenadeRadius = CONSTANT_UNITS_SMOKEGRENADERADIUS; +const float FlashbangGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS; +const float HEGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS; +const float MolotovGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS; +const float DecoyGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS; + + +#define ADDON_FLASHBANG_1 0x0001 +#define ADDON_FLASHBANG_2 0x0002 +#define ADDON_HE_GRENADE 0x0004 +#define ADDON_SMOKE_GRENADE 0x0008 +#define ADDON_C4 0x0010 +#define ADDON_DEFUSEKIT 0x0020 +#define ADDON_PRIMARY 0x0040 +#define ADDON_PISTOL 0x0080 +#define ADDON_PISTOL2 0x0100 +#define ADDON_DECOY 0x0200 +#define ADDON_KNIFE 0x0400 +#define ADDON_MASK 0x0800 +#define ADDON_TAGRENADE 0x1000 +#define NUM_ADDON_BITS 13 + +#define ADDON_CLIENTSIDE_HOLIDAY_HAT ( 0x1 << NUM_ADDON_BITS ) +#define ADDON_CLIENTSIDE_GHOST ( 0x2 << NUM_ADDON_BITS ) +#define ADDON_CLIENTSIDE_ASSASSINATION_TARGET ( 0x4 << NUM_ADDON_BITS ) +#define NUM_CLIENTSIDE_ADDON_BITS 3 + + +#define WEAPON_SLOT_RIFLE 0 +#define WEAPON_SLOT_PISTOL 1 +#define WEAPON_SLOT_KNIFE 2 +#define WEAPON_SLOT_GRENADES 3 +#define WEAPON_SLOT_C4 4 + +#define WEAPON_SLOT_FIRST 0 +#define WEAPON_SLOT_LAST 4 + + +#define TEAM_TERRORIST 2 +#define TEAM_CT 3 +#define TEAM_MAXCOUNT 4 + +#define TEAM_TERRORIST_BASE0 TEAM_TERRORIST - 2 +#define TEAM_CT_BASE0 TEAM_CT - 2 + +#define CS_DEATH_ANIMATION_TIME 0.5 + +#define CS_KILLS_FOR_DOMINATION 4 + +#define CS_DEATH_DOMINATION 0x0001 +#define CS_DEATH_REVENGE 0x0002 + + +#define DMG_HEADSHOT (DMG_LASTGENERICFLAG<<1) + + +struct PlayerViewmodelArmConfig +{ + const char* szPlayerModelSearchSubStr; + const char* szSkintoneIndex; + const char* szAssociatedGloveModel; + const char* szAssociatedSleeveModel; + const char* szAssociatedSleeveModelEconOverride; +}; + +enum CSPlayerState +{ + STATE_ACTIVE = 0, + + STATE_WELCOME, + + STATE_PICKINGTEAM, + STATE_PICKINGCLASS, + + STATE_DEATH_ANIM, + STATE_DEATH_WAIT_FOR_KEY, + STATE_OBSERVER_MODE, + + STATE_GUNGAME_RESPAWN, + STATE_DORMANT, + + NUM_PLAYER_STATES +}; + + +enum e_RoundEndReason +{ + Invalid_Round_End_Reason = -1, + RoundEndReason_StillInProgress = 0, + Target_Bombed = 1, + VIP_Escaped = 2, + VIP_Assassinated = 3, + Terrorists_Escaped = 4, + CTs_PreventEscape = 5, + Escaping_Terrorists_Neutralized = 6, + Bomb_Defused = 7, + CTs_Win = 8, + Terrorists_Win = 9, + Round_Draw = 10, + All_Hostages_Rescued = 11, + Target_Saved = 12, + Hostages_Not_Rescued = 13, + Terrorists_Not_Escaped = 14, + VIP_Not_Escaped = 15, + Game_Commencing = 16, + Terrorists_Surrender = 17, + CTs_Surrender = 18, + Terrorists_Planted = 19, + CTs_ReachedHostage = 20, + RoundEndReason_Count = 21, +}; + +enum GamePhase +{ + GAMEPHASE_WARMUP_ROUND, + GAMEPHASE_PLAYING_STANDARD, + GAMEPHASE_PLAYING_FIRST_HALF, + GAMEPHASE_PLAYING_SECOND_HALF, + GAMEPHASE_HALFTIME, + GAMEPHASE_MATCH_ENDED, + GAMEPHASE_MAX +}; + +enum GrenadeType_t +{ + GRENADE_TYPE_EXPLOSIVE, + GRENADE_TYPE_FLASH, + GRENADE_TYPE_FIRE, + GRENADE_TYPE_DECOY, + GRENADE_TYPE_SMOKE, + GRENADE_TYPE_SENSOR, + + GRENADE_TYPE_TOTAL, +}; + +#define PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f) +#define GLOWUPDATE_DEFAULT_THINK_INTERVAL 0.2f + +#define CS_MAX_PLAYER_MODELS 10 +#define MAX_MODEL_STRING_SIZE 256 + +#define CS_CLASS_NONE 0 + +#define MAX_ENDMATCH_VOTE_PANELS 10 +const PlayerViewmodelArmConfig* GetPlayerViewmodelArmConfigForPlayerModel(const char* szPlayerModel); + +class PlayerModelInfo +{ +public: + PlayerModelInfo(); + +#if !defined( CLIENT_DLL ) + + bool IsTClass(int classID); + bool IsCTClass(int classID); + + int GetFirstTClass(void) const { return 1; } + int GetFirstCTClass(void) const { return m_NumTModels + 1; } + int GetFirstClass(void) const { return GetFirstTClass(); } + + int GetLastTClass(void) const { return m_NumTModels; } + int GetLastCTClass(void) const { return m_NumTModels + m_NumCTModels; } + int GetLastClass(void) const { return GetLastCTClass(); } + + int GetNextClassForTeam(int team); + + const char* GetClassName(int classID); + const char* GetClassModelPath(int classID); + + int GetNumTModels(void) const { return m_NumTModels; } + int GetNumCTModels(void) const { return m_NumCTModels; } + + void InitializeForCurrentMap(void); + +private: + void AddModel(const char* modelName); + void SetTViewModelArms(const char* modelName); + void SetCTViewModelArms(const char* modelName); + +#endif + +public: + static const char* g_customizationModelCT; + static const char* g_customizationModelT; + static const char* g_defaultTModel; + static const char* g_defaultCTModel; + + static PlayerModelInfo* GetPtr(void) { return &s_PlayerModelInfo; } + +private: + static PlayerModelInfo s_PlayerModelInfo; + +#if !defined( CLIENT_DLL ) + char m_ClassModelPaths[CS_MAX_PLAYER_MODELS][MAX_MODEL_STRING_SIZE]; + char m_ClassNames[CS_MAX_PLAYER_MODELS][MAX_MODEL_STRING_SIZE]; + char m_mapName[MAX_MODEL_STRING_SIZE]; + + int m_NumTModels; + int m_NumCTModels; + int m_NumModels; + int m_nNextClassT; + int m_nNextClassCT; +#endif +}; + +enum CSMvpReason_t +{ + CSMVP_UNDEFINED = 0, + CSMVP_ELIMINATION, + CSMVP_BOMBPLANT, + CSMVP_BOMBDEFUSE, + CSMVP_HOSTAGERESCUE, + + CSMVP_GUNGAMEWINNER, +}; + +#define CS_MUZZLEFLASH_NONE -1 +#define CS_MUZZLEFLASH_NORM 0 +#define CS_MUZZLEFLASH_X 1 + +extern const char* pszWinPanelCategoryHeaders[]; + +namespace AcquireResult +{ + enum Type + { + Allowed, + InvalidItem, + AlreadyOwned, + AlreadyPurchased, + ReachedGrenadeTypeLimit, + ReachedGrenadeTotalLimit, + NotAllowedByTeam, + NotAllowedByMap, + NotAllowedByMode, + NotAllowedForPurchase, + NotAllowedByProhibition, + }; +} + +namespace AcquireMethod +{ + enum Type + { + PickUp, + Buy, + }; +} + +namespace QuestProgress +{ + enum Reason + { + QUEST_NONINITIALIZED, + + QUEST_OK, + + QUEST_NOT_ENOUGH_PLAYERS, + + QUEST_WARMUP, + + QUEST_NOT_CONNECTED_TO_STEAM, + + QUEST_NONOFFICIAL_SERVER, + + QUEST_NO_ENTITLEMENT, + + QUEST_NO_QUEST, + + QUEST_PLAYER_IS_BOT, + + QUEST_WRONG_MAP, + QUEST_WRONG_MODE, + + QUEST_NOT_SYNCED_WITH_SERVER, + + QUEST_REASON_MAX, + }; + + const int QuestReasonBits = 4; + COMPILE_TIME_ASSERT(QUEST_REASON_MAX <= (1 << QuestReasonBits)); + + const char* ReasonString(Reason reason); +} + +#endif +``` + +`SpyCustom/sdk/cs_view_scene.h`: + +```h +#ifndef CS_VIEW_SCENE_H +#define CS_VIEW_SCENE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "viewrender.h" + +class CCSViewRender : public CViewRender +{ +public: + CCSViewRender(); + + virtual void Init(void); + + virtual void GetScreenFadeDistances(float* min, float* max); + + virtual void Render2DEffectsPreHUD(const CViewSetup& view); + virtual void Render2DEffectsPostHUD(const CViewSetup& view); + virtual void RenderPlayerSprites(void); + + void PerformFlashbangEffect(const CViewSetup& view); + void PerformNightVisionEffect(const CViewSetup& view); + + ITexture* m_pFlashTexture; +}; + +#endif +``` + +`SpyCustom/sdk/cs_weapon_parse.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CS_WEAPON_PARSE_H +#define CS_WEAPON_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef CLIENT_DLL +#define CWeaponCSBase C_WeaponCSBase +#endif + +#include "weapon_parse.h" +#include "econ_item_constants.h" + + + +class CWeaponCSBase; + +//-------------------------------------------------------------------------------------------------------- +enum CSWeaponType +{ + WEAPONTYPE_KNIFE = 0, + WEAPONTYPE_PISTOL, + WEAPONTYPE_SUBMACHINEGUN, + WEAPONTYPE_RIFLE, + WEAPONTYPE_SHOTGUN, + WEAPONTYPE_SNIPER_RIFLE, + WEAPONTYPE_MACHINEGUN, + WEAPONTYPE_C4, + WEAPONTYPE_GRENADE, + WEAPONTYPE_EQUIPMENT, + WEAPONTYPE_STACKABLEITEM, + WEAPONTYPE_UNKNOWN +}; + + +/* + NOTE!!!! Please try not to change the order. If you need to add something, please add it to the end. + Anytime the order of the weaponID's change, we need to updated a bunch of tables in a couple DB's. Also, + changing the order can invalidate saved queries and in general makes using the OGS stats difficult. +*/ +//-------------------------------------------------------------------------------------------------------- + +enum ItemDefinitionIndex +{ + ITEM_NONE = 0, + WEAPON_DEAGLE = 1, + WEAPON_ELITE = 2, + WEAPON_FIVESEVEN = 3, + WEAPON_GLOCK = 4, + WEAPON_AK47 = 7, + WEAPON_AUG = 8, + WEAPON_AWP = 9, + WEAPON_FAMAS = 10, + WEAPON_G3SG1 = 11, + WEAPON_GALILAR = 13, + WEAPON_M249 = 14, + WEAPON_M4A1 = 16, + WEAPON_MAC10 = 17, + WEAPON_P90 = 19, + WEAPON_UMP45 = 24, + WEAPON_XM1014 = 25, + WEAPON_BIZON = 26, + WEAPON_MAG7 = 27, + WEAPON_NEGEV = 28, + WEAPON_SAWEDOFF = 29, + WEAPON_TEC9 = 30, + WEAPON_TASER = 31, + WEAPON_HKP2000 = 32, + WEAPON_MP7 = 33, + WEAPON_MP9 = 34, + WEAPON_NOVA = 35, + WEAPON_P250 = 36, + WEAPON_SCAR20 = 38, + WEAPON_SG553 = 39, + WEAPON_SSG08 = 40, + WEAPON_KNIFE_GOLD = 41, + WEAPON_KNIFE = 42, + WEAPON_FLASHBANG = 43, + WEAPON_HEGRENADE = 44, + WEAPON_SMOKEGRENADE = 45, + WEAPON_MOLOTOV = 46, + WEAPON_DECOY = 47, + WEAPON_INCGRENADE = 48, + WEAPON_C4 = 49, + WEAPON_KNIFE_T = 59, + WEAPON_M4A1_SILENCER = 60, + WEAPON_USP_SILENCER = 61, + WEAPON_CZ75A = 63, + WEAPON_REVOLVER = 64, + WEAPON_KNIFE_BAYONET = 500, + WEAPON_KNIFE_FLIP = 505, + WEAPON_KNIFE_GUT = 506, + WEAPON_KNIFE_KARAMBIT = 507, + WEAPON_KNIFE_M9_BAYONET = 508, + WEAPON_KNIFE_TACTICAL = 509, + WEAPON_KNIFE_FALCHION = 512, + WEAPON_KNIFE_SURVIVAL_BOWIE = 514, + WEAPON_KNIFE_BUTTERFLY = 515, + WEAPON_KNIFE_PUSH = 516, + GLOVE_STUDDED_BLOODHOUND = 5027, + GLOVE_T_SIDE = 5028, + GLOVE_CT_SIDE = 5029, + GLOVE_SPORTY = 5030, + GLOVE_SLICK = 5031, + GLOVE_LEATHER_WRAP = 5032, + GLOVE_MOTORCYCLE = 5033, + GLOVE_SPECIALIST = 5034, + MAX_ITEMDEFINITIONINDEX +}; + +using CSWeaponID = ItemDefinitionIndex; +/* +enum CSWeaponID +{ + WEAPON_NONE = 0, + + WEAPON_FIRST, + + WEAPON_DEAGLE = WEAPON_FIRST, + WEAPON_ELITE, + WEAPON_FIVESEVEN, + WEAPON_GLOCK, + WEAPON_P228, + WEAPON_USP, + + WEAPON_AK47, + WEAPON_AUG, + WEAPON_AWP, + WEAPON_FAMAS, + WEAPON_G3SG1, + WEAPON_GALIL, + WEAPON_GALILAR, + WEAPON_M249, + WEAPON_M3, + WEAPON_M4A1, + WEAPON_MAC10, + WEAPON_MP5NAVY, + WEAPON_P90, + WEAPON_SCOUT, + WEAPON_SG550, + WEAPON_SG552, + WEAPON_TMP, + WEAPON_UMP45, + WEAPON_XM1014, + + WEAPON_BIZON, + WEAPON_MAG7, + WEAPON_NEGEV, + WEAPON_SAWEDOFF, + WEAPON_TEC9, + WEAPON_TASER, + + WEAPON_HKP2000, + WEAPON_MP7, + WEAPON_MP9, + WEAPON_NOVA, + WEAPON_P250, + WEAPON_SCAR17, + WEAPON_SCAR20, + WEAPON_SG556, + WEAPON_SSG08, + WEAPON_LAST = WEAPON_SSG08, + + ITEM_FIRST, + WEAPON_KNIFE_GG = ITEM_FIRST, + WEAPON_KNIFE, + + WEAPON_FLASHBANG, + WEAPON_HEGRENADE, + WEAPON_SMOKEGRENADE, + WEAPON_MOLOTOV, + WEAPON_DECOY, + WEAPON_INCGRENADE, + WEAPON_TAGRENADE, + WEAPON_C4, + ITEM_MAX = WEAPON_C4, + + EQUIPMENT_FIRST, + ITEM_KEVLAR = EQUIPMENT_FIRST, + ITEM_ASSAULTSUIT, + ITEM_HEAVYASSAULTSUIT, + ITEM_NVG, + ITEM_DEFUSER, + ITEM_CUTTERS, + EQUIPMENT_MAX, + + WEAPON_HEALTHSHOT, + + WEAPON_MAX = EQUIPMENT_MAX, // number of weapons weapon index +}; +*/ + +#define MAX_EQUIPMENT (EQUIPMENT_MAX - EQUIPMENT_FIRST) + +enum +{ + ITEM_PRICE_KEVLAR = 650, + ITEM_PRICE_HELMET = 350, + ITEM_PRICE_ASSAULTSUIT = ITEM_PRICE_KEVLAR + ITEM_PRICE_HELMET, + ITEM_PRICE_HEAVYASSAULTSUIT = 1250, + ITEM_PRICE_DEFUSEKIT = 400, + ITEM_PRICE_NVG = 1250, +}; + + +struct WeaponPaintableMaterial_t; + + +void PrepareEquipmentInfo(void); + +class WeaponRecoilData +{ +public: + + WeaponRecoilData(); + ~WeaponRecoilData(); + + void GetRecoilOffsets(CWeaponCSBase* pWeapon, int iMode, int iIndex, float& fAngle, float& fMagnitude); + void GenerateRecoilPatternForItemDefinition(item_definition_index_t idx); + +private: + + struct RecoilOffset + { + float fAngle; + float fMagnitude; + }; + + struct RecoilData + { + item_definition_index_t iItemDefIndex; + RecoilOffset recoilTable[2][64]; + }; + + CUtlMap< item_definition_index_t, RecoilData* > m_mapRecoilTables; + + void GenerateRecoilTable(RecoilData* data); + +}; + +//-------------------------------------------------------------------------------------------------------- +class CCSWeaponInfo : public FileWeaponInfo_t +{ +public: + DECLARE_CLASS_GAMEROOT(CCSWeaponInfo, FileWeaponInfo_t); + + CCSWeaponInfo(); + + virtual void Parse(::KeyValues* pKeyValuesData, const char* szWeaponName); + + // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result. + virtual void RefreshDynamicParameters() { GenerateRecoilTable(); } + + const char* GetZoomInSound(void) const { return m_szZoomINSound; } + const char* GetZoomOutSound(void) const { return m_szZoomOUTSound; } + + const Vector& GetSmokeColor() const { return m_vSmokeColor; } + + // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result. + void GetRecoilOffsets(int iMode, int iIndex, float& fAngle, float& fMagnitude) const; + +//protected: + + CSWeaponType m_WeaponType; + int m_iTeam; // Which team can have this weapon. TEAM_UNASSIGNED if both can have it. + +public: + + CSWeaponID m_weaponId; + + + + + int GetWeaponPrice(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool IsFullAuto(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool HasSilencer(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetBullets(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetCycleTime(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetHeatPerShot(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoveryTimeCrouch(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoveryTimeStand(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoveryTimeCrouchFinal(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoveryTimeStandFinal(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetRecoveryTransitionStartBullet(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetRecoveryTransitionEndBullet(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + int GetRecoilSeed(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetFlinchVelocityModifierLarge(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetFlinchVelocityModifierSmall(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetTimeToIdleAfterFire(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetIdleInterval(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRange(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRangeModifier(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetDamage(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetPenetration(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetCrosshairDeltaDistance(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetCrosshairMinDistance(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + float GetInaccuracyAltSwitch(void) const { return m_fInaccuracyAltSwitch; }; + + float GetInaccuracyPitchShift(void) const { return m_fInaccuracyPitchShift; } + float GetInaccuracyAltSoundThreshhold(void) const { return m_fInaccuracyAltSoundThreshold; } + + float GetMaxSpeed(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + float GetSpread(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyCrouch(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyStand(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyJumpInitial(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyJump(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyLand(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyLadder(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyFire(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + float GetInaccuracyMove(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + + float GetInaccuracyReload(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f) const; + + float GetRecoilAngle(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoilAngleVariance(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoilMagnitude(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetRecoilMagnitudeVariance(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetTracerFrequency(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + int GetPrimaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetSecondaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetDefaultPrimaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetDefaultSecondaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + int GetKillAward(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool HasBurstMode(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool IsRevolver(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool HasAlternateFastSlowReload(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetArmorRatio(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool HasTraditionalScope(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool CannotShootUnderwater(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool DoesUnzoomAfterShot(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + bool DoesHideViewModelWhenZoomed(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetBucketSlot(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetZoomLevels(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + int GetZoomFOV1(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetZoomFOV2(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetZoomTime0(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetZoomTime1(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + float GetZoomTime2(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + int GetPrimaryReserveAmmoMax(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + int GetSecondaryReserveAmmoMax(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const; + + + CSWeaponType GetWeaponType(const CEconItemView* pWepView = NULL) const; + const char* GetAddonLocation(const CEconItemView* pWepView = NULL) const; + const char* GetEjectBrassEffectName(const CEconItemView* pWepView = NULL) const; + const char* GetTracerEffectName(const CEconItemView* pWepView = NULL) const; + const char* GetMuzzleFlashEffectName_1stPerson(const CEconItemView* pWepView = NULL) const; + const char* GetMuzzleFlashEffectName_1stPersonAlt(const CEconItemView* pWepView = NULL) const; + const char* GetMuzzleFlashEffectName_3rdPerson(const CEconItemView* pWepView = NULL) const; + const char* GetMuzzleFlashEffectName_3rdPersonAlt(const CEconItemView* pWepView = NULL) const; + const char* GetHeatEffectName(const CEconItemView* pWepView = NULL) const; + const char* GetPlayerAnimationExtension(const CEconItemView* pWepView = NULL) const; + void SetUsedByTeam(int nTeam) { m_iTeam = nTeam; } + int GetUsedByTeam(const CEconItemView* pWepView = NULL) const; + + bool CanBeUsedWithShield() const { return m_bCanUseWithShield; } + float GetBotAudibleRange() const { return m_flBotAudibleRange; } + const char* GetWrongTeamMsg() const { return m_WrongTeamMsg; } + const char* GetAnimExtension() const { return m_szAnimExtension; } + const char* GetShieldViewModel() const { return m_szShieldViewModel; } + const char* GetSilencerModel() const { return m_szSilencerModel; } + float GetAddonScale() const { return m_flAddonScale; } + float GetThrowVelocity() const { return m_fThrowVelocity; } + + const char* GetAddonModel(const CEconItemView* pWepView = NULL) const; + const CUtlVector< WeaponPaintableMaterial_t >* GetPaintData(const CEconItemView* pWepView = NULL) const; + + // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result. + void GenerateRecoilTable(); + + void SetWeaponPrice(int price) { m_iWeaponPrice = price; }; + void SetWeaponType(CSWeaponType type) { m_WeaponType = type; }; + +//private: + static bool m_bCSWeaponInfoLookupInitialized; + + bool m_bFullAuto; // is this a fully automatic weapon? + float m_flHeatPerShot; + int m_iWeaponPrice; + float m_flArmorRatio; + float m_flMaxSpeed[2]; // How fast the player can run while this is his primary weapon. + + int m_iCrosshairMinDistance; + int m_iCrosshairDeltaDistance; + + // Parameters for FX_FireBullets: + float m_flPenetration; + int m_iDamage; + float m_flRange; + float m_flRangeModifier; + int m_iBullets; + float m_flCycleTime; + float m_flCycleTimeAlt; + + char m_szHeatEffectName[MAX_WEAPON_STRING]; + + Vector m_vSmokeColor; + + char m_szMuzzleFlashEffectName_1stPerson[MAX_WEAPON_STRING]; + char m_szMuzzleFlashEffectName_3rdPerson[MAX_WEAPON_STRING]; + char m_szEjectBrassEffectName[MAX_WEAPON_STRING]; + char m_szTracerEffectName[MAX_WEAPON_STRING]; + int m_iTracerFequency; + + // variables for new accuracy model + float m_fSpread[2]; + float m_fInaccuracyCrouch[2]; + float m_fInaccuracyStand[2]; + float m_fInaccuracyJump[2]; + float m_fInaccuracyLand[2]; + float m_fInaccuracyLadder[2]; + float m_fInaccuracyImpulseFire[2]; + float m_fInaccuracyMove[2]; + float m_fRecoveryTimeStand; + float m_fRecoveryTimeCrouch; + float m_fRecoveryTimeStandFinal; + float m_fRecoveryTimeCrouchFinal; + float m_fInaccuracyReload; + float m_fInaccuracyAltSwitch; + float m_fInaccuracyPitchShift; + float m_fInaccuracyAltSoundThreshold; + float m_fRecoilAngle[2]; + float m_fRecoilAngleVariance[2]; + float m_fRecoilMagnitude[2]; + float m_fRecoilMagnitudeVariance[2]; + int m_iRecoilSeed; + + float m_fFlinchVelocityModifierLarge; // velocity modifier for anyone hit by this weapon + float m_fFlinchVelocityModifierSmall; // velocity modifier for anyone hit by this weapon + + // Delay until the next idle animation after shooting. + float m_flTimeToIdleAfterFire; + float m_flIdleInterval; + + // recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result. + struct RecoilOffset + { + float fAngle; + float fMagnitude; + }; + RecoilOffset m_recoilTable[2][64]; + + + int m_iZoomLevels; + int m_iZoomFov[3]; + float m_fZoomTime[3]; + bool m_bHideViewModelZoomed; + char m_szZoomINSound[MAX_WEAPON_STRING]; + char m_szZoomOUTSound[MAX_WEAPON_STRING]; + + float m_flBotAudibleRange; // How far away a bot can hear this weapon. + + bool m_bCanUseWithShield; + + char m_WrongTeamMsg[32]; // Reference to a string describing the error if someone tries to buy + // this weapon but they're on the wrong team to have it. + // Zero-length if no specific message for this weapon. + + char m_szAnimExtension[16]; + char m_szShieldViewModel[64]; + + char m_szAddonModel[MAX_WEAPON_STRING]; // If this is set, it is used as the addon model. Otherwise, szWorldModel is used. + char m_szAddonLocation[MAX_WEAPON_STRING]; //If this is set, the weapon will look for an attachment location with this name. Otherwize the default is used based on weapon type. + char m_szSilencerModel[MAX_WEAPON_STRING]; // Alternate model with silencer attached + + float m_flAddonScale; + + // grenade throw parameters + float m_fThrowVelocity; + + int m_iKillAward; + + +}; + + +//-------------------------------------------------------------------------------------------------------- +// Utility conversion functions +//-------------------------------------------------------------------------------------------------------- +const char* WeaponClassAsString(CSWeaponType weaponType); +CSWeaponType WeaponClassFromString(const char* weaponType); +CSWeaponType WeaponClassFromWeaponID(CSWeaponID weaponID); +const char* WeaponIdAsString(CSWeaponID weaponID); +CSWeaponID WeaponIdFromString(const char* szWeaponName); +const char* WeaponIDToAlias(int id); +CSWeaponID AliasToWeaponID(const char* szAlias); +const CCSWeaponInfo* GetWeaponInfo(CSWeaponID weaponID); +bool IsGunWeapon(CSWeaponType weaponType); + + + + + +// +class IWeaponSystem +{ + virtual void unused0() = 0; + virtual void unused1() = 0; +public: + virtual CCSWeaponInfo* GetWpnData(ItemDefinitionIndex) = 0; +}; + +// + + + + + +#endif // CS_WEAPON_PARSE_H +``` + +`SpyCustom/sdk/datamap.h`: + +```h +#ifndef DATAMAP_H +#define DATAMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef VECTOR_H +#include "vector.h" +#endif + +#include "utlvector.h" + +#include "memdbgon.h" + +class SINGLE_INHERITANCE CBaseEntity; +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 DECLARE_FIELD_SIZE( _fieldType, _fieldSize ) \ + template< > class CDatamapFieldSizeDeducer<_fieldType> { public: enum { SIZE = _fieldSize }; static int FieldSize() { return _fieldSize; } }; +#define FIELD_SIZE( _fieldType ) CDatamapFieldSizeDeducer<_fieldType>::SIZE +#define FIELD_BITS( _fieldType ) (FIELD_SIZE( _fieldType ) * 8) + +DECLARE_FIELD_SIZE(FIELD_FLOAT, sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_STRING, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_VECTOR, 3 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_VECTOR2D, 2 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_QUATERNION, 4 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_INTEGER, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_BOOLEAN, sizeof(char)) +DECLARE_FIELD_SIZE(FIELD_SHORT, sizeof(short)) +DECLARE_FIELD_SIZE(FIELD_CHARACTER, sizeof(char)) +DECLARE_FIELD_SIZE(FIELD_COLOR32, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_CLASSPTR, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_EHANDLE, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_EDICT, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_POSITION_VECTOR, 3 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_TIME, sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_TICK, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_MODELNAME, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_SOUNDNAME, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_INPUT, sizeof(int)) +#ifdef POSIX +DECLARE_FIELD_SIZE(FIELD_FUNCTION, sizeof(uint64)) +#else +DECLARE_FIELD_SIZE(FIELD_FUNCTION, sizeof(int*)) +#endif +DECLARE_FIELD_SIZE(FIELD_VMATRIX, 16 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_VMATRIX_WORLDSPACE, 16 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_MATRIX3X4_WORLDSPACE, 12 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_INTERVAL, 2 * sizeof(float)) +DECLARE_FIELD_SIZE(FIELD_MODELINDEX, sizeof(int)) +DECLARE_FIELD_SIZE(FIELD_MATERIALINDEX, sizeof(int)) + + +#define ARRAYSIZE2D(p) (sizeof(p)/sizeof(p[0][0])) +#define SIZE_OF_ARRAY(p) _ARRAYSIZE(p) + +#define _FIELD(name,fieldtype,count,flags,mapname,tolerance) { fieldtype, #name, { offsetof(classNameTypedef, name), 0 }, count, flags, mapname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, tolerance } +#define DEFINE_FIELD_NULL { FIELD_VOID,0, {0,0},0,0,0,0,0,0} +#define DEFINE_FIELD(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_KEYFIELD(name,fieldtype, mapname) _FIELD(name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_KEYFIELD_NOT_SAVED(name,fieldtype, mapname)_FIELD(name, fieldtype, 1, FTYPEDESC_KEY, mapname, 0 ) +#define DEFINE_AUTO_ARRAY(name,fieldtype) _FIELD(name, fieldtype, SIZE_OF_ARRAY(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_AUTO_ARRAY_KEYFIELD(name,fieldtype,mapname) _FIELD(name, fieldtype, SIZE_OF_ARRAY(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_ARRAY(name,fieldtype, count) _FIELD(name, fieldtype, count, FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(edict_t, name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE, #name, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(edict_t, name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE | FTYPEDESC_GLOBAL, #name, 0 ) +#define DEFINE_GLOBAL_FIELD(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_GLOBAL | FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_GLOBAL_KEYFIELD(name,fieldtype, mapname) _FIELD(name, fieldtype, 1, FTYPEDESC_GLOBAL | FTYPEDESC_KEY | FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_CUSTOM_FIELD(name,datafuncs) { FIELD_CUSTOM, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, datafuncs, NULL } +#define DEFINE_CUSTOM_KEYFIELD(name,datafuncs,mapname) { FIELD_CUSTOM, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE | FTYPEDESC_KEY, mapname, datafuncs, NULL } +#define DEFINE_AUTO_ARRAY2D(name,fieldtype) _FIELD(name, fieldtype, ARRAYSIZE2D(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_BITFIELD(name,fieldtype,bitcount) DEFINE_ARRAY(name,fieldtype,((bitcount+FIELD_BITS(fieldtype)-1)&~(FIELD_BITS(fieldtype)-1)) / FIELD_BITS(fieldtype) ) +#define DEFINE_INDEX(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_INDEX, NULL, 0 ) + +#define DEFINE_EMBEDDED( name ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name.m_DataMap), sizeof( ((classNameTypedef *)0)->name ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_OVERRIDE( name, overridetype ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &((overridetype *)0)->m_DataMap, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDEDBYREF( name ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE | FTYPEDESC_PTR, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( *(((classNameTypedef *)0)->name) ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_ARRAY( name, count ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, count, FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( ((classNameTypedef *)0)->name[0] ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_AUTO_ARRAY( name ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, SIZE_OF_ARRAY( ((classNameTypedef *)0)->name ), FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( ((classNameTypedef *)0)->name[0] ), NULL, 0, 0.0f } + +#ifndef NO_ENTITY_PREDICTION + +#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &fieldtype::m_PredMap } + +#define DEFINE_PRED_TYPEDESCRIPTION_PTR( name, fieldtype ) \ + { FIELD_EMBEDDED, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_SAVE | FTYPEDESC_PTR, NULL, NULL, NULL, &fieldtype::m_PredMap } + +#else + +#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) DEFINE_FIELD_NULL +#define DEFINE_PRED_TYPEDESCRIPTION_PTR( name, fieldtype ) DEFINE_FIELD_NULL + +#endif + +#define DEFINE_PRED_FIELD(name,fieldtype, flags) _FIELD(name, fieldtype, 1, flags, NULL, 0.0f ) +#define DEFINE_PRED_ARRAY(name,fieldtype, count,flags) _FIELD(name, fieldtype, count, flags, NULL, 0.0f ) +#define DEFINE_FIELD_NAME(localname,netname,fieldtype) _FIELD(localname, fieldtype, 1, 0, #netname, 0.0f ) +#define DEFINE_PRED_FIELD_TOL(name,fieldtype, flags,tolerance) _FIELD(name, fieldtype, 1, flags, NULL, tolerance ) +#define DEFINE_PRED_ARRAY_TOL(name,fieldtype, count,flags,tolerance) _FIELD(name, fieldtype, count, flags, NULL, tolerance) +#define DEFINE_FIELD_NAME_TOL(localname,netname,fieldtolerance) _FIELD(localname, fieldtype, 1, 0, #netname, tolerance ) + +#define DEFINE_INPUT( name, fieldtype, inputname ) { fieldtype, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_INPUT | FTYPEDESC_SAVE | FTYPEDESC_KEY, inputname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ) } +#define DEFINE_INPUTFUNC( fieldtype, inputname, inputfunc ) { fieldtype, #inputfunc, { NULL, NULL }, 1, FTYPEDESC_INPUT, inputname, NULL, static_cast (&classNameTypedef::inputfunc) } + +class ISaveRestoreOps; +extern ISaveRestoreOps* eventFuncs; +#define DEFINE_OUTPUT( name, outputname ) { FIELD_CUSTOM, #name, { offsetof(classNameTypedef, name), 0 }, 1, FTYPEDESC_OUTPUT | FTYPEDESC_SAVE | FTYPEDESC_KEY, outputname, eventFuncs } + +#define DEFINE_FUNCTION_RAW( function, func_type ) { FIELD_VOID, nameHolder.GenerateName(#function), { NULL, NULL }, 1, FTYPEDESC_FUNCTIONTABLE, NULL, NULL, (inputfunc_t)((func_type)(&classNameTypedef::function)) } +#define DEFINE_FUNCTION( function ) DEFINE_FUNCTION_RAW( function, inputfunc_t ) + + +#define FTYPEDESC_GLOBAL 0x0001 +#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 (CBaseEntity::* 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; + +#if defined( _DEBUG ) + bool bValidityChecked; +#endif +}; + + +#define DECLARE_SIMPLE_DATADESC() \ + static datamap_t m_DataMap; \ + static datamap_t *GetBaseMap(); \ + template friend void DataMapAccess(T *, datamap_t **p); \ + template friend datamap_t *DataMapInit(T *); + +#define DECLARE_DATADESC() \ + DECLARE_SIMPLE_DATADESC() \ + virtual datamap_t *GetDataDescMap( void ); + +#define BEGIN_DATADESC( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \ + datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_DATADESC_NO_BASE( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \ + datamap_t *className::GetBaseMap() { return NULL; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_SIMPLE_DATADESC( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetBaseMap() { return NULL; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_SIMPLE_DATADESC_( className, BaseClass ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_DATADESC_GUTS( className ) \ + template datamap_t *DataMapInit(T *); \ + template <> datamap_t *DataMapInit( className * ); \ + namespace className##_DataDescInit \ + { \ + datamap_t *g_DataMapHolder = DataMapInit( (className *)NULL ); \ + } \ + \ + template <> datamap_t *DataMapInit( className * ) \ + { \ + typedef className classNameTypedef; \ + static CDatadescGeneratedNameHolder nameHolder(#className); \ + className::m_DataMap.baseMap = className::GetBaseMap(); \ + static typedescription_t dataDesc[] = \ + { \ + { FIELD_VOID,0, {0,0},0,0,0,0,0,0}, + +#define END_DATADESC() \ + }; \ + \ + if ( sizeof( dataDesc ) > sizeof( dataDesc[0] ) ) \ + { \ + classNameTypedef::m_DataMap.dataNumFields = SIZE_OF_ARRAY( dataDesc ) - 1; \ + classNameTypedef::m_DataMap.dataDesc = &dataDesc[1]; \ + } \ + else \ + { \ + classNameTypedef::m_DataMap.dataNumFields = 1; \ + classNameTypedef::m_DataMap.dataDesc = dataDesc; \ + } \ + return &classNameTypedef::m_DataMap; \ + } + +#define IMPLEMENT_NULL_SIMPLE_DATADESC( derivedClass ) \ + BEGIN_SIMPLE_DATADESC( derivedClass ) \ + END_DATADESC() + +#define IMPLEMENT_NULL_SIMPLE_DATADESC_( derivedClass, baseClass ) \ + BEGIN_SIMPLE_DATADESC_( derivedClass, baseClass ) \ + END_DATADESC() + +#define IMPLEMENT_NULL_DATADESC( derivedClass ) \ + BEGIN_DATADESC( derivedClass ) \ + END_DATADESC() + +#define BEGIN_BITFIELD( name ) \ + union \ + { \ + char name; \ + struct \ + { + +#define END_BITFIELD() \ + }; \ + }; + +#define DECLARE_BYTESWAP_DATADESC() DECLARE_SIMPLE_DATADESC() +#define BEGIN_BYTESWAP_DATADESC(name) BEGIN_SIMPLE_DATADESC(name) +#define BEGIN_BYTESWAP_DATADESC_(name,base) BEGIN_SIMPLE_DATADESC_(name,base) +#define END_BYTESWAP_DATADESC() END_DATADESC() + +template +inline void DataMapAccess(T* ignored, datamap_t** p) +{ + *p = &T::m_DataMap; +} + +class CDatadescGeneratedNameHolder +{ +public: + CDatadescGeneratedNameHolder(const char* pszBase) + : m_pszBase(pszBase) + { + m_nLenBase = strlen(m_pszBase); + } + + ~CDatadescGeneratedNameHolder() + { + for (int i = 0; i < m_Names.Count(); i++) + { + delete m_Names[i]; + } + } + + const char* GenerateName(const char* pszIdentifier) + { + char* pBuf = new char[m_nLenBase + strlen(pszIdentifier) + 1]; + strcpy(pBuf, m_pszBase); + strcat(pBuf, pszIdentifier); + m_Names.AddToTail(pBuf); + return pBuf; + } + +private: + const char* m_pszBase; + size_t m_nLenBase; + CUtlVector m_Names; +}; + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/dbg.h`: + +```h +#ifndef DBG_H +#define DBG_H + +#if !defined(__SPU__) + + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "basetypes.h" +#include "dbgflag.h" +#include "logging.h" +#include +#include +#include + +#ifdef TIER0_DLL_EXPORT +#define DBG_INTERFACE DLL_EXPORT +#define DBG_OVERLOAD DLL_GLOBAL_EXPORT +#define DBG_CLASS DLL_CLASS_EXPORT +#else +#define DBG_INTERFACE DLL_IMPORT +#define DBG_OVERLOAD DLL_GLOBAL_IMPORT +#define DBG_CLASS DLL_CLASS_IMPORT +#endif + +class Color; + + +PLATFORM_INTERFACE void _ExitOnFatalAssert(const tchar* pFile, int line); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( "", 0 ) +#else +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( pFile, line ) +#endif + +PLATFORM_INTERFACE bool ShouldUseNewAssertDialog(); + +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +PLATFORM_INTERFACE bool DoNewAssertDialog(const tchar* pFile, int line, const tchar* pExpression); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( "", 0, "" ) +#else +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( pFile, line, pExpression ) +#endif + +PLATFORM_INTERFACE bool AreAllAssertsDisabled(); +PLATFORM_INTERFACE void SetAllAssertsDisabled(bool bAssertsEnabled); + +PLATFORM_INTERFACE bool IsAssertDialogDisabled(); +PLATFORM_INTERFACE void SetAssertDialogDisabled(bool bAssertDialogDisabled); + +typedef void (*AssertFailedNotifyFunc_t)(const char* pchFile, int nLine, const char* pchMessage); +PLATFORM_INTERFACE void SetAssertFailedNotifyFunc(AssertFailedNotifyFunc_t func); +PLATFORM_INTERFACE void CallAssertFailedNotifyFunc(const char* pchFile, int nLine, const char* pchMessage); + +#if defined( LINUX ) +PLATFORM_INTERFACE void SetAssertDialogParent(struct SDL_Window* window); +PLATFORM_INTERFACE struct SDL_Window* GetAssertDialogParent(); +#endif + +#ifdef _PREFAST_ +#define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0) +#define _AssertMsgOnce( _exp, _msg, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0) +#define DBGFLAG_ASSERT +#define DBGFLAG_ASSERTFATAL +#define DBGFLAG_ASSERTDEBUG + +#define Q_ASSERT( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#else +#define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + LoggingResponse_t ret = Log_Assert( "%s (%d) : %s\n", __TFILE__, __LINE__, static_cast( _msg ) ); \ + CallAssertFailedNotifyFunc( __TFILE__, __LINE__, _msg ); \ + _executeExp; \ + if ( ret == LR_DEBUGGER ) \ + { \ + if ( ShouldUseNewAssertDialog() ) \ + { \ + if ( DbgFlagMacro_DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + } \ + if ( _bFatal ) \ + DbgFlagMacro_ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + +#define _AssertMsgOnce( _exp, _msg, _bFatal ) \ + do { \ + static bool fAsserted; \ + if (!fAsserted ) \ + { \ + _AssertMsg( _exp, _msg, (fAsserted = true), _bFatal ); \ + } \ + } while (0) +#endif + +#ifdef DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true ) +#define AssertFatalOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), true ) +#define AssertFatalMsg( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), true ) +#define AssertFatalMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, true ) +#define AssertFatalFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true ) +#define AssertFatalEquals( _exp, _expectedValue ) AssertFatalMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) AssertFatalMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define VerifyFatal( _exp ) AssertFatal( _exp ) +#define VerifyEqualsFatal( _exp, _expectedValue ) AssertFatalEquals( _exp, _expectedValue ) +#define DbgVerifyFatal( _exp ) AssertFatal( _exp ) + +#define AssertFatalMsg1( _exp, _msg, a1 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1 ))) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2 ))) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3 ))) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4 ))) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ))) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ))) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ))) + +#else + +#define AssertFatal( _exp ) ((void)0) +#define AssertFatalOnce( _exp ) ((void)0) +#define AssertFatalMsg( _exp, _msg ) ((void)0) +#define AssertFatalMsgOnce( _exp, _msg ) ((void)0) +#define AssertFatalFunc( _exp, _f ) ((void)0) +#define AssertFatalEquals( _exp, _expectedValue ) ((void)0) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define VerifyFatal( _exp ) (_exp) +#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp) +#define DbgVerifyFatal( _exp ) (_exp) + +#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif + +#if defined(_CERT) || defined(_RETAIL) +#define AssertAligned(PTR) +#define AssertAlignedWidth(PTR, width) +#define AssertAlignedConsole(PTR) +#else +# if defined( _X360 ) +# define AssertAlignedWidth( PTR, width ) __twnei( intp(PTR) & ( width - 1 ), 0 ) +# define AssertAligned( PTR ) AssertAlignedWidth( PTR, 16 ) +# define AssertAlignedConsole( PTR ) AssertAlignedWidth( PTR, 4 ) +# elif defined( DBGFLAG_ASSERT ) +# define AssertAlignedWidth( adr, width ) Assert( ( ( ( intp ) ( adr ) ) & ( width - 1 ) ) == 0 ) +# define AssertAligned( adr ) AssertAlignedWidth( adr, 16 ) +# define AssertAlignedConsole(adr) +# else +# define AssertAlignedWidth(PTR, width) +# define AssertAligned(PTR) +# define AssertAlignedConsole(PTR) +# endif +#endif + +#ifdef DBGFLAG_ASSERT + +#define Assert( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsg_( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false ) +#define AssertOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), false ) +#define AssertMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, false ) +#define AssertFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), _f, false ) +#define AssertEquals( _exp, _expectedValue ) AssertMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) AssertMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define Verify( _exp ) ( _exp ) +#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue ) +#ifndef DbgVerify +#define DbgVerify( _exp ) Assert( _exp ) +#endif + +#ifdef _DEBUG +#define DbgAssert( _exp ) Assert( _exp ) +#else +#define DbgAssert( _exp ) ((void)0) +#endif + +#ifdef _DEBUG +#define DbgAssert( _exp ) Assert( _exp ) +#else +#define DbgAssert( _exp ) ((void)0) +#endif + +#define AssertMsg( _exp, _msg ) AssertMsg_( _exp, _T( _msg ) ) +#define AssertMsg1( _exp, _msg, a1 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1 )) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2 )) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3 )) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4 )) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5 )) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6 )) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7 )) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8 )) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8, a9 )) ) + +#else + +#define Assert( _exp ) ((void)0) +#define AssertOnce( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertMsgOnce( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) +#define VerifyEquals( _exp, _expectedValue ) (_exp) +#ifndef DbgVerify +#define DbgVerify( _exp ) (_exp) +#endif +#define DbgAssert( _exp ) ((void)0) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif + +#define AssertDbg( X ) DbgAssert( X ) + + +#define AssertAnalyze( _exp ) Assert( _exp ) +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define AssertAlways( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsgAlways( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false ) + + +#define FILE_LINE_FUNCTION_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" __FUNCTION__ ":" +#define FILE_LINE_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" +#define FUNCTION_LINE_STRING __FUNCTION__ "(" STRINGIFY(__LINE__) "): " + + +#define MESSAGE(msg) message(__FILE__ "(" FUNCTION_LINE_TOSTRING(__LINE__) "): " msg) + +PLATFORM_INTERFACE LoggingChannelID_t LOG_GENERAL; + +DECLARE_LOGGING_CHANNEL(LOG_ASSERT); +DECLARE_LOGGING_CHANNEL(LOG_CONSOLE); +DECLARE_LOGGING_CHANNEL(LOG_DEVELOPER); +DECLARE_LOGGING_CHANNEL(LOG_DEVELOPER_CONSOLE); +DECLARE_LOGGING_CHANNEL(LOG_DEVELOPER_VERBOSE); + +PLATFORM_INTERFACE void Error(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); +PLATFORM_INTERFACE void Error_SpewCallStack(int iMaxCallStackLength, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); +#define Plat_FatalError( ... ) do { Log_Error( LOG_GENERAL, ##__VA_ARGS__ ); Plat_ExitProcess( EXIT_FAILURE ); } while( 0 ) + +#if defined( DBGFLAG_STRINGS_STRIP ) + +#define Msg( ... ) ((void)0) +#define Warning( ... ) ((void)0) +#define Warning_SpewCallStack( ... ) ((void)0) +#define DevMsg( ... ) ((void)0) +#define DevWarning( ... ) ((void)0) +#define ConColorMsg( ... ) ((void)0) +#define ConMsg( ... ) ((void)0) +#define ConDMsg( ... ) ((void)0) +#define COM_TimestampedLog( ... ) ((void)0) + +#else + +PLATFORM_INTERFACE void Msg(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); +PLATFORM_INTERFACE void Warning(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); +PLATFORM_INTERFACE void Warning_SpewCallStack(int iMaxCallStackLength, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); + +#ifdef _PS3 + +PLATFORM_OVERLOAD void DevMsg(int level, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); +PLATFORM_OVERLOAD void DevWarning(int level, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); + +PLATFORM_INTERFACE void DevMsg(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); +PLATFORM_INTERFACE void DevWarning(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); + +PLATFORM_INTERFACE void ConColorMsg(const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); +PLATFORM_INTERFACE void ConMsg(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); + +#else + +PLATFORM_INTERFACE void DevMsg(int level, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); +PLATFORM_INTERFACE void DevWarning(int level, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); + +PLATFORM_OVERLOAD void DevMsg(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); +PLATFORM_OVERLOAD void DevWarning(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); + +PLATFORM_OVERLOAD void ConColorMsg(const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(2, 3); +PLATFORM_OVERLOAD void ConMsg(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); + +#endif + +PLATFORM_INTERFACE void ConDMsg(PRINTF_FORMAT_STRING const tchar* pMsg, ...) FMTFUNCTION(1, 2); + +PLATFORM_INTERFACE void COM_TimestampedLog(PRINTF_FORMAT_STRING char const* fmt, ...) FMTFUNCTION(1, 2); + +#endif + +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +#ifdef _DEBUG +#define DebugMsg(...) DevMsg(__VA_ARGS__) +#else +#define DebugMsg(...) +#endif + +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Enable(bool bEnable); +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Length(int iMaxCallStackLength); + +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Enable(bool bEnable); +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Length(int iMaxCallStackLength); + + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_CODE_NOSCOPE( _code ) _code +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() + +#else + +#define DBG_CODE( _code ) ((void)0) +#define DBG_CODE_NOSCOPE( _code ) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif + + +#ifdef _DEBUG +template +inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) +{ + Assert(static_cast(pSource) == dynamic_cast(pSource)); + return static_cast(pSource); +} +#else +#define assert_cast static_cast +#endif + +PLATFORM_INTERFACE void _AssertValidReadPtr(void* ptr, int count = 1); +PLATFORM_INTERFACE void _AssertValidWritePtr(void* ptr, int count = 1); +PLATFORM_INTERFACE void _AssertValidReadWritePtr(void* ptr, int count = 1); +PLATFORM_INTERFACE void _AssertValidStringPtr(const tchar* ptr, int maxchar); + +#ifdef DBGFLAG_ASSERT +inline void AssertValidStringPtr(const tchar* ptr, int maxchar = 0xFFFFFF) { _AssertValidStringPtr(ptr, maxchar); } +template inline void AssertValidReadPtr(T* ptr, int count = 1) { _AssertValidReadPtr((void*)ptr, count); } +template inline void AssertValidWritePtr(T* ptr, int count = 1) { _AssertValidWritePtr((void*)ptr, count); } +template inline void AssertValidReadWritePtr(T* ptr, int count = 1) { _AssertValidReadWritePtr((void*)ptr, count); } +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +#else + +inline void AssertValidStringPtr(const tchar* ptr, int maxchar = 0xFFFFFF) { } +template inline void AssertValidReadPtr(T* ptr, int count = 1) { } +template inline void AssertValidWritePtr(T* ptr, int count = 1) { } +template inline void AssertValidReadWritePtr(T* ptr, int count = 1) { } +#define AssertValidThis() +#endif + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int* pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int* m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +#ifdef POSIX +#define Tier0Internal_sntprintf snprintf +#define Tier0Internal_vsntprintf vsnprintf +#define Tier0Internal_vsnprintf vsnprintf +#else +#define Tier0Internal_sntprintf _sntprintf +#define Tier0Internal_vsntprintf _vsntprintf +#define Tier0Internal_vsnprintf _vsnprintf +#endif + +#include "valve_off.h" +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(PRINTF_FORMAT_STRING const tchar* pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + Tier0Internal_vsntprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf) - 1] = 0; + } + + operator const tchar* () const + { + return m_szBuf; + } + +private: + tchar m_szBuf[256]; +}; +#include "valve_on.h" + +#if defined( _WIN32 ) && !defined( _X360 ) + +#ifdef _DEBUG +#pragma comment(compiler) +#endif + +#endif + +#ifdef _DEBUG + +template< class Type > +class CDataWatcher +{ +public: + const Type& operator=(const Type& val) + { + return Set(val); + } + + const Type& operator=(const CDataWatcher& val) + { + return Set(val.m_Value); + } + + const Type& Set(const Type& val) + { + m_Value = val; + return m_Value; + } + + Type& GetForModify() + { + return m_Value; + } + + const Type& operator+=(const Type& val) + { + return Set(m_Value + val); + } + + const Type& operator-=(const Type& val) + { + return Set(m_Value - val); + } + + const Type& operator/=(const Type& val) + { + return Set(m_Value / val); + } + + const Type& operator*=(const Type& val) + { + return Set(m_Value * val); + } + + const Type& operator^=(const Type& val) + { + return Set(m_Value ^ val); + } + + const Type& operator|=(const Type& val) + { + return Set(m_Value | val); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++(int) + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--(int) + { + Type val = m_Value; + (*this -= 1); + return val; + } + + template< class C > + const Type& operator&=(C val) + { + return Set(m_Value & val); + } + + operator const Type& () const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +}; + +#else + +template< class Type > +class CDataWatcher +{ +private: + CDataWatcher(); +}; + +#endif + +#ifdef IS_WINDOWS_PC + +typedef void* HardwareBreakpointHandle_t; + +enum EHardwareBreakpointType +{ + BREAKPOINT_EXECUTE = 0, + BREAKPOINT_WRITE, + BREAKPOINT_READWRITE, +}; + +enum EHardwareBreakpointSize +{ + BREAKPOINT_SIZE_1 = 1, + BREAKPOINT_SIZE_2 = 2, + BREAKPOINT_SIZE_4 = 4, + BREAKPOINT_SIZE_8 = 8, +}; + +PLATFORM_INTERFACE HardwareBreakpointHandle_t SetHardwareBreakpoint(EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void* pvLocation); +PLATFORM_INTERFACE bool ClearHardwareBreakpoint(HardwareBreakpointHandle_t handle); + +class CHardwareBreakPointScopeGuard +{ +public: + CHardwareBreakPointScopeGuard(const void* pvLocation, size_t nLocationSize, EHardwareBreakpointType eType = BREAKPOINT_WRITE) + { + EHardwareBreakpointSize eSize = BREAKPOINT_SIZE_4; + switch (nLocationSize) + { + case 1: + eSize = BREAKPOINT_SIZE_1; + break; + case 2: + eSize = BREAKPOINT_SIZE_2; + break; + case 4: + eSize = BREAKPOINT_SIZE_4; + break; + case 8: + eSize = BREAKPOINT_SIZE_8; + break; + default: + Warning(_T("SetHardwareBreakpoint can only work with 1, 2, 4 or 8 byte data fields.")); + break; + } + + m_hBreakPoint = SetHardwareBreakpoint(eType, eSize, pvLocation); + m_bActive = m_hBreakPoint != (HardwareBreakpointHandle_t)0; + } + + ~CHardwareBreakPointScopeGuard() + { + Release(); + } + + void Release() + { + if (!m_bActive) + return; + ClearHardwareBreakpoint(m_hBreakPoint); + } + +private: + bool m_bActive; + HardwareBreakpointHandle_t m_hBreakPoint; +}; + +#endif + +#else + +#define Assert( _exp ) ((void)0) +#define AssertOnce( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertMsgOnce( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) +#define VerifyEquals( _exp, _expectedValue ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) + +#define AssertFatal( _exp ) ((void)0) +#define AssertFatalOnce( _exp ) ((void)0) +#define AssertFatalMsg( _exp, _msg ) ((void)0) +#define AssertFatalMsgOnce( _exp, _msg ) ((void)0) +#define AssertFatalFunc( _exp, _f ) ((void)0) +#define AssertFatalEquals( _exp, _expectedValue ) ((void)0) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define VerifyFatal( _exp ) (_exp) +#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp) + +#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#define AssertAligned(PTR) + +#endif + + +#endif +``` + +`SpyCustom/sdk/dbgflag.h`: + +```h +#ifndef DBGFLAG_H +#define DBGFLAG_H +#ifdef _WIN32 +#pragma once +#endif + + +#undef DBGFLAG_MEMORY +#undef DBGFLAG_MEMORY_NEWDEL +#undef DBGFLAG_VALIDATE +#undef DBGFLAG_ASSERT +#undef DBGFLAG_ASSERTFATAL +#undef DBGFLAG_ASSERTDLG +#undef DBGFLAG_STRINGS + +#if defined( _DEBUG ) && !defined( PS3MEMOVERRIDEWRAP ) + +#define DBGFLAG_MEMORY +#ifdef _SERVER +#define DBGFLAG_MEMORY_NEWDEL +#endif +#ifdef STEAM +#define DBGFLAG_VALIDATE +#endif +#define DBGFLAG_ASSERT +#define DBGFLAG_ASSERTFATAL +#define DBGFLAG_ASSERTDLG +#define DBGFLAG_STRINGS + + +#else +#ifdef STEAM +#define DBGFLAG_ASSERT +#endif +#define DBGFLAG_ASSERTFATAL +#define DBGFLAG_ASSERTDLG + +#endif + +#if defined( _CERT ) +#define DBGFLAG_STRINGS_STRIP +#endif + +#endif +``` + +`SpyCustom/sdk/deformations.h`: + +```h +#ifndef DEFORMATIONS_H +#define DEFORMATIONS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.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; + + FORCEINLINE BoxDeformation_t(void) + { + m_eType = DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE; + m_SourceMins.Init(0, 0, 0); + m_SourceMaxes.Init(-1, -1, -1); + + m_ClampMins.Init(-FLT_MAX, -FLT_MAX, -FLT_MAX); + m_ClampMaxes.Init(FLT_MAX, FLT_MAX, FLT_MAX); + } + +}; + + + +#endif +``` + +`SpyCustom/sdk/dlight.h`: + +```h +#if !defined ( DLIGHTH ) +#define DLIGHTH +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" + +enum +{ + DLIGHT_NO_WORLD_ILLUMINATION = 0x1, + DLIGHT_NO_MODEL_ILLUMINATION = 0x2, + + DLIGHT_ADD_DISPLACEMENT_ALPHA = 0x4, + DLIGHT_SUBTRACT_DISPLACEMENT_ALPHA = 0x8, + DLIGHT_DISPLACEMENT_MASK = (DLIGHT_ADD_DISPLACEMENT_ALPHA | DLIGHT_SUBTRACT_DISPLACEMENT_ALPHA), +}; + +struct dlight_t +{ + int flags; + Vector origin; + float radius; + ColorRGBExp32 color; + float die; + float decay; + float minlight; + int key; + int style; + + Vector m_Direction; + float m_InnerAngle; + float m_OuterAngle; + + float GetRadius() const + { + return radius; + } + + float GetRadiusSquared() const + { + return radius * radius; + } + + float IsRadiusGreaterThanZero() const + { + return radius > 0.0f; + } +}; + +#endif +``` + +`SpyCustom/sdk/dmattributetypes.h`: + +```h +#ifndef DMATTRIBUTETYPES_H +#define DMATTRIBUTETYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utlstring.h" +#include "uniqueid.h" +#include "color.h" +#include "vector2d.h" +#include "vector.h" +#include "vector4d.h" +#include "vmatrix.h" +#include "dmelementhandle.h" +#include "utlsymbollarge.h" +#include "timeutils.h" + + +typedef UniqueId_t DmObjectId_t; + + +struct DmUnknownAttribute_t +{ + bool operator==(const DmUnknownAttribute_t& src) const { return true; } +}; + + +struct DmElementAttribute_t +{ + DmElementAttribute_t() : m_ElementType(UTL_INVAL_SYMBOL_LARGE) {} + + operator DmElementHandle_t& () { return m_Handle; } + operator const DmElementHandle_t& () const { return m_Handle; } + + DmElementHandle_t m_Handle; + CUtlSymbolLarge m_ElementType; +}; + +struct DmElementArray_t : public CUtlVector< DmElementHandle_t > +{ + DmElementArray_t() : m_ElementType(UTL_INVAL_SYMBOL_LARGE) {} + + CUtlSymbolLarge m_ElementType; +}; + + +enum DmAttributeType_t +{ + AT_UNKNOWN = 0, + + AT_FIRST_VALUE_TYPE, + + AT_ELEMENT = AT_FIRST_VALUE_TYPE, + AT_INT, + AT_FLOAT, + AT_BOOL, + AT_STRING, + AT_VOID, + AT_TIME, + AT_COLOR, + AT_VECTOR2, + AT_VECTOR3, + AT_VECTOR4, + AT_QANGLE, + AT_QUATERNION, + AT_VMATRIX, + + AT_FIRST_ARRAY_TYPE, + + AT_ELEMENT_ARRAY = AT_FIRST_ARRAY_TYPE, + AT_INT_ARRAY, + AT_FLOAT_ARRAY, + AT_BOOL_ARRAY, + AT_STRING_ARRAY, + AT_VOID_ARRAY, + AT_TIME_ARRAY, + AT_COLOR_ARRAY, + AT_VECTOR2_ARRAY, + AT_VECTOR3_ARRAY, + AT_VECTOR4_ARRAY, + AT_QANGLE_ARRAY, + AT_QUATERNION_ARRAY, + AT_VMATRIX_ARRAY, + AT_TYPE_COUNT, + + AT_TYPE_INVALID, +}; + +const char* GetTypeString(DmAttributeType_t type); + +inline bool IsValueType(DmAttributeType_t type) +{ + return type >= AT_FIRST_VALUE_TYPE && type < AT_FIRST_ARRAY_TYPE; +} + +inline bool IsArrayType(DmAttributeType_t type) +{ + return type >= AT_FIRST_ARRAY_TYPE && type < AT_TYPE_COUNT; +} + +inline bool IsTopological(DmAttributeType_t type) +{ + return type == AT_ELEMENT || type == AT_ELEMENT_ARRAY; +} + +inline DmAttributeType_t ValueTypeToArrayType(DmAttributeType_t type) +{ + Assert(IsValueType(type)); + return (DmAttributeType_t)((type - AT_FIRST_VALUE_TYPE) + AT_FIRST_ARRAY_TYPE); +} + +inline DmAttributeType_t ArrayTypeToValueType(DmAttributeType_t type) +{ + Assert(IsArrayType(type)); + return (DmAttributeType_t)((type - AT_FIRST_ARRAY_TYPE) + AT_FIRST_VALUE_TYPE); +} + +inline int NumComponents(DmAttributeType_t type) +{ + switch (type) + { + case AT_BOOL: + case AT_INT: + case AT_FLOAT: + case AT_TIME: + return 1; + + case AT_VECTOR2: + return 2; + + case AT_VECTOR3: + case AT_QANGLE: + return 3; + + case AT_COLOR: + case AT_VECTOR4: + case AT_QUATERNION: + return 4; + + case AT_VMATRIX: + return 16; + + case AT_ELEMENT: + case AT_STRING: + case AT_VOID: + default: + return 0; + } +} + +template< typename T > +inline float GetComponent(const T& value, int i) +{ + Assert(0); + return 0.0f; +} + +template <> inline float GetComponent(const bool& value, int i) +{ + Assert(i == 0); + return value ? 1.0f : 0.0f; +} + +template <> inline float GetComponent(const int& value, int i) +{ + Assert(i == 0); + return float(value); +} + +template <> inline float GetComponent(const float& value, int i) +{ + Assert(i == 0); + return value; +} + +template <> inline float GetComponent(const DmeTime_t& value, int i) +{ + Assert(i == 0); + return value.GetSeconds(); +} + +template <> inline float GetComponent(const Vector2D& value, int i) +{ + return value[i]; +} + +template <> inline float GetComponent(const Vector& value, int i) +{ + return value[i]; +} + +template <> inline float GetComponent(const QAngle& value, int i) +{ + return value[i]; +} + +template <> inline float GetComponent(const Color& value, int i) +{ + return value[i]; +} + +template <> inline float GetComponent(const Vector4D& value, int i) +{ + return value[i]; +} + +template <> inline float GetComponent(const Quaternion& value, int i) +{ + return value[i]; +} + +template <> inline float GetComponent(const VMatrix& value, int i) +{ + return value.Base()[i]; +} + + +template +class CDmAttributeInfo +{ +private: + enum { ATTRIBUTE_TYPE = AT_TYPE_INVALID }; + + typedef T StorageType_t; + friend class CDmxAttribute; + + static DmAttributeType_t AttributeType() + { + return AT_TYPE_INVALID; + } + + static const char* AttributeTypeName() + { + return "invalid"; + } + + static void SetDefaultValue(T& value) + { + Assert(0); + } +}; + + +template <> +class CDmAttributeInfo< DmUnknownAttribute_t > +{ +public: + enum { ATTRIBUTE_TYPE = AT_UNKNOWN }; + + typedef DmUnknownAttribute_t StorageType_t; + + static DmAttributeType_t AttributeType() + { + return AT_UNKNOWN; + } + + static const char* AttributeTypeName() + { + return "unknown"; + } + + static void SetDefaultValue(DmUnknownAttribute_t& value) + { + Assert(0); + } +}; + + +#define DECLARE_ATTRIBUTE_TYPE_INTERNAL( _className, _storageType, _attributeType, _attributeName, _defaultSetStatement ) \ + template< > class CDmAttributeInfo< _className > \ + { \ + public: \ + enum { ATTRIBUTE_TYPE = _attributeType }; \ + typedef _storageType StorageType_t; \ + static DmAttributeType_t AttributeType() { return _attributeType; } \ + static const char *AttributeTypeName() { return _attributeName; } \ + static void SetDefaultValue( _className& value ) { _defaultSetStatement } \ + }; \ + +#define DECLARE_ATTRIBUTE_ARRAY_TYPE_INTERNAL( _className, _storageType, _attributeType, _attributeName ) \ + template< > class CDmAttributeInfo< CUtlVector<_className> > \ + { \ + public: \ + enum { ATTRIBUTE_TYPE = _attributeType }; \ + typedef _storageType StorageType_t; \ + static DmAttributeType_t AttributeType() { return _attributeType; } \ + static const char *AttributeTypeName() { return _attributeName; } \ + static void SetDefaultValue( CUtlVector< _className >& value ) { value.RemoveAll(); } \ + }; \ + +#define DECLARE_ATTRIBUTE_TYPE( _className, _attributeType, _attributeName, _defaultSetStatement ) \ + DECLARE_ATTRIBUTE_TYPE_INTERNAL( _className, _className, _attributeType, _attributeName, _defaultSetStatement ) + +#define DECLARE_ATTRIBUTE_ARRAY_TYPE( _className, _attributeType, _attributeName )\ + DECLARE_ATTRIBUTE_ARRAY_TYPE_INTERNAL( _className, CUtlVector< _className >, _attributeType, _attributeName ) + +DECLARE_ATTRIBUTE_TYPE(int, AT_INT, "int", value = 0; ) +DECLARE_ATTRIBUTE_TYPE(float, AT_FLOAT, "float", value = 0.0f; ) +DECLARE_ATTRIBUTE_TYPE(bool, AT_BOOL, "bool", value = false; ) +DECLARE_ATTRIBUTE_TYPE(Color, AT_COLOR, "color", value.SetColor(0, 0, 0, 255); ) +DECLARE_ATTRIBUTE_TYPE(Vector2D, AT_VECTOR2, "vector2", value.Init(0.0f, 0.0f); ) +DECLARE_ATTRIBUTE_TYPE(Vector, AT_VECTOR3, "vector3", value.Init(0.0f, 0.0f, 0.0f); ) +DECLARE_ATTRIBUTE_TYPE(Vector4D, AT_VECTOR4, "vector4", value.Init(0.0f, 0.0f, 0.0f, 0.0f); ) +DECLARE_ATTRIBUTE_TYPE(QAngle, AT_QANGLE, "qangle", value.Init(0.0f, 0.0f, 0.0f); ) +DECLARE_ATTRIBUTE_TYPE(Quaternion, AT_QUATERNION, "quaternion", value.Init(0.0f, 0.0f, 0.0f, 1.0f); ) +DECLARE_ATTRIBUTE_TYPE(VMatrix, AT_VMATRIX, "matrix", MatrixSetIdentity(value); ) +DECLARE_ATTRIBUTE_TYPE(CUtlSymbolLarge, AT_STRING, "string", value = UTL_INVAL_SYMBOL_LARGE; ) +DECLARE_ATTRIBUTE_TYPE(CUtlBinaryBlock, AT_VOID, "binary", value.Set(NULL, 0); ) +DECLARE_ATTRIBUTE_TYPE(DmeTime_t, AT_TIME, "time", value.SetTenthsOfMS(0); ) +DECLARE_ATTRIBUTE_TYPE_INTERNAL(DmElementHandle_t, DmElementAttribute_t, AT_ELEMENT, "element", value = DMELEMENT_HANDLE_INVALID; ) + +DECLARE_ATTRIBUTE_ARRAY_TYPE(int, AT_INT_ARRAY, "int_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(float, AT_FLOAT_ARRAY, "float_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(bool, AT_BOOL_ARRAY, "bool_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(Color, AT_COLOR_ARRAY, "color_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(Vector2D, AT_VECTOR2_ARRAY, "vector2_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(Vector, AT_VECTOR3_ARRAY, "vector3_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(Vector4D, AT_VECTOR4_ARRAY, "vector4_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(QAngle, AT_QANGLE_ARRAY, "qangle_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(Quaternion, AT_QUATERNION_ARRAY, "quaternion_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(VMatrix, AT_VMATRIX_ARRAY, "matrix_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(CUtlSymbolLarge, AT_STRING_ARRAY, "string_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(CUtlBinaryBlock, AT_VOID_ARRAY, "binary_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE(DmeTime_t, AT_TIME_ARRAY, "time_array") +DECLARE_ATTRIBUTE_ARRAY_TYPE_INTERNAL(DmElementHandle_t, DmElementArray_t, AT_ELEMENT_ARRAY, "element_array") + + +#endif +``` + +`SpyCustom/sdk/dmelementhandle.h`: + +```h +#ifndef DMELEMENTHANDLE_H +#define DMELEMENTHANDLE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#define PERFORM_HANDLE_TYPECHECKING 0 +#if PERFORM_HANDLE_TYPECHECKING + +struct DmElementHandle_t +{ + DmElementHandle_t() : handle(0xffffffff) {} + explicit DmElementHandle_t(int h) : handle(h) {} + inline bool operator==(const DmElementHandle_t& h) const { return handle == h.handle; } + inline bool operator!=(const DmElementHandle_t& h) const { return handle != h.handle; } + inline bool operator<(const DmElementHandle_t& h) const { return handle < h.handle; } + int handle; +}; +const DmElementHandle_t DMELEMENT_HANDLE_INVALID; + +#else + +enum DmElementHandle_t +{ + DMELEMENT_HANDLE_INVALID = 0xffffffff +}; + +#endif + + + +#endif +``` + +`SpyCustom/sdk/dmxattribute.h`: + +```h +#ifndef DMXATTRIBUTE_H +#define DMXATTRIBUTE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dmattributetypes.h" +#include "utlvector.h" +#include "utlrbtree.h" +#include "utlsymbol.h" +#include "mempool.h" +#include "dmxloader.h" + + +class CDmxElement; + + + + + +#define DECLARE_DMX_ATTRIBUTE_TYPE_INTERNAL( _className, _storageType, _attributeType, _attributeName, _defaultSetStatement ) \ + template< > class CDmAttributeInfo< _className > \ + { \ + private: \ + enum { ATTRIBUTE_TYPE = _attributeType }; \ + typedef _storageType StorageType_t; \ + static DmAttributeType_t AttributeType() { return _attributeType; } \ + static const char *AttributeTypeName() { return _attributeName; } \ + static void SetDefaultValue( _className& value ) { _defaultSetStatement } \ + friend class CDmxAttribute; \ + friend class CDmxElement; \ + }; \ + +#define DECLARE_DMX_ATTRIBUTE_ARRAY_TYPE_INTERNAL( _className, _storageType, _attributeType, _attributeName ) \ + template< > class CDmAttributeInfo< CUtlVector<_className> > \ + { \ + private: \ + enum { ATTRIBUTE_TYPE = _attributeType }; \ + typedef _storageType StorageType_t; \ + static DmAttributeType_t AttributeType() { return _attributeType; } \ + static const char *AttributeTypeName() { return _attributeName; } \ + static void SetDefaultValue( CUtlVector< _className >& value ) { value.RemoveAll(); } \ + friend class CDmxAttribute; \ + friend class CDmxElement; \ + }; \ + +#define DECLARE_DMX_ATTRIBUTE_TYPE( _className, _attributeType, _attributeName, _defaultSetStatement ) \ + DECLARE_DMX_ATTRIBUTE_TYPE_INTERNAL( _className, _className, _attributeType, _attributeName, _defaultSetStatement ) + +#define DECLARE_DMX_ATTRIBUTE_ARRAY_TYPE( _className, _attributeType, _attributeName )\ + DECLARE_DMX_ATTRIBUTE_ARRAY_TYPE_INTERNAL( _className, CUtlVector< _className >, _attributeType, _attributeName ) + + + +DECLARE_DMX_ATTRIBUTE_TYPE(CDmxElement*, AT_ELEMENT, "element", value = 0; ) +DECLARE_DMX_ATTRIBUTE_ARRAY_TYPE(CDmxElement*, AT_ELEMENT_ARRAY, "element_array") + +DECLARE_DMX_ATTRIBUTE_TYPE(CUtlString, AT_STRING, "string", value.Set(NULL); ) +DECLARE_DMX_ATTRIBUTE_ARRAY_TYPE(CUtlString, AT_STRING_ARRAY, "string_array") + + +class CDmxAttribute +{ + DECLARE_DMX_ALLOCATOR(); + +public: + DmAttributeType_t GetType() const; + const char* GetTypeString() const; + template< class T > bool IsA() const; + + const char* GetName() const; + CUtlSymbolLarge GetNameSymbol() const; + void SetName(const char* pName); + + template< class T > const T& GetValue() const; + template< class T > const CUtlVector< T >& GetArray() const; + const char* GetValueString() const; + + template< class T > void SetValue(const T& value); + void SetValue(const char* pString); + void SetValue(char* pString); + void SetValue(const void* pBuffer, size_t nLen); + void SetValue(const CDmxAttribute* pAttribute); + + template< class T > CUtlVector< T >& GetArrayForEdit(); + + void SetToDefaultValue(); + + void SetValueFromString(const char* pValue); + const char* GetValueAsString(char* pBuffer, size_t nBufLen) const; + + int GetArrayCount() const; + + bool Unserialize(DmAttributeType_t type, CUtlBuffer& buf); + bool UnserializeElement(DmAttributeType_t type, CUtlBuffer& buf); + bool Serialize(CUtlBuffer& buf) const; + bool SerializeElement(int nIndex, CUtlBuffer& buf) const; + bool SerializesOnMultipleLines() const; + + static int AttributeDataSize(DmAttributeType_t type); + static DmAttributeType_t ArrayAttributeBasicType(DmAttributeType_t type); + +private: + CDmxAttribute(const char* pAttributeName); + CDmxAttribute(CUtlSymbolLarge attributeName); + ~CDmxAttribute(); + + void AllocateDataMemory(DmAttributeType_t type); + void AllocateDataMemory_AndConstruct(DmAttributeType_t type); + void FreeDataMemory(); + + + void SetValue(DmAttributeType_t type, const void* pSrc, int nLen); + void SetArrayValue(DmAttributeType_t type, const void* pSrc, int nDataTypeSize, int nArrayLength, int nSrcStride); + void GetArrayValue(DmAttributeType_t type, void* pDest, int nDataTypeSize, int nArrayLength, const char* pDefaultString = NULL) const; + void SetArrayCount(int nArrayCount); + const void* GetArrayBase(void) const; + + template < class VT, class T > void ConstructDataMemory(void); + template < class VT, class T > void DestructDataMemory(void); + template < class VT, class T > void SetArrayCount(int nArrayCount); + template < class VT, class T > void GetArrayCount(int& nArrayCount) const; + template < class VT, class T > void GetArrayBase(const void*& pBasePtr) const; + template < class VT, class T > void SerializesOnMultipleLines(bool& bResult) const; + template < class VT, class T > void SerializeType(bool& bSuccess, CUtlBuffer& buf) const; + template < class VT, class T > void SerializeTypedElement(bool& bSuccess, int nIndex, CUtlBuffer& buf) const; + template < class VT, class T > void UnserializeType(bool& bSuccess, CUtlBuffer& buf); + template < class VT, class T > void UnserializeTypedElement(bool& bSuccess, CUtlBuffer& buf); + template < class VT, class T > void SetDefaultValue(void); + + + DmAttributeType_t m_Type; + CUtlSymbolLarge m_Name; + void* m_pData; + + static CUtlSymbolTableLargeMT s_AttributeNameSymbols; + + friend class CDmxElement; + +public: + + static const char* s_pAttributeTypeName[AT_TYPE_COUNT]; + +}; + + +inline DmAttributeType_t CDmxAttribute::GetType() const +{ + return m_Type; +} + +template< class T > inline bool CDmxAttribute::IsA() const +{ + return GetType() == CDmAttributeInfo< T >::ATTRIBUTE_TYPE; +} + +inline CUtlSymbolLarge CDmxAttribute::GetNameSymbol() const +{ + return m_Name; +} + + +template< class T > void CDmxAttribute::SetValue(const T& value) +{ + AllocateDataMemory(CDmAttributeInfo::AttributeType()); + CopyConstruct((T*)m_pData, value); +} + + +inline const char* CDmxAttribute::GetValueString() const +{ + if (m_Type == AT_STRING) + return *(CUtlString*)m_pData; + return ""; +} + +template< class T > +inline const T& CDmxAttribute::GetValue() const +{ + if (CDmAttributeInfo::AttributeType() == m_Type) + return *(T*)m_pData; + + static T defaultValue; + CDmAttributeInfo::SetDefaultValue(defaultValue); + return defaultValue; +} + +template< class T > +inline const CUtlVector< T >& CDmxAttribute::GetArray() const +{ + if (CDmAttributeInfo< CUtlVector< T > >::AttributeType() == m_Type) + return *(CUtlVector< T >*)m_pData; + + static CUtlVector defaultArray; + return defaultArray; +} + +template< class T > +inline CUtlVector< T >& CDmxAttribute::GetArrayForEdit() +{ + if (CDmAttributeInfo< CUtlVector< T > >::AttributeType() == m_Type) + return *(CUtlVector< T >*)m_pData; + + AllocateDataMemory(CDmAttributeInfo< CUtlVector< T > >::AttributeType()); + Construct((CUtlVector*)m_pData); + return *(CUtlVector< T >*)m_pData; +} + +#endif +``` + +`SpyCustom/sdk/dmxelement.h`: + +```h +#ifndef DMXELEMENT_H +#define DMXELEMENT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dmattributetypes.h" +#include "utlvector.h" +#include "utlrbtree.h" +#include "utlsymbol.h" +#include "mempool.h" +#include "utlsortvector.h" +#include "dmxattribute.h" + + +class CDmxAttributeLess +{ +public: + bool Less(const CDmxAttribute* pAttribute1, const CDmxAttribute* pAttribute2, void* pContext) + { + return (pAttribute1 ? pAttribute1->GetNameSymbol() : CUtlSymbolLarge(UTL_INVAL_SYMBOL_LARGE)) < (pAttribute2 ? pAttribute2->GetNameSymbol() : CUtlSymbolLarge(UTL_INVAL_SYMBOL_LARGE)); + } +}; + + +enum BitfieldType_t +{ + BITFIELD_TYPE_NONE, + BITFIELD_TYPE_BOOL, + BITFIELD_TYPE_CHAR, + BITFIELD_TYPE_UNSIGNED_CHAR, + BITFIELD_TYPE_BYTE = BITFIELD_TYPE_UNSIGNED_CHAR, + BITFIELD_TYPE_SHORT, + BITFIELD_TYPE_UNSIGNED_SHORT, + BITFIELD_TYPE_INT, + BITFIELD_TYPE_UNSIGNED_INT, +}; + +struct DmxElementUnpackStructure_t +{ + const char* m_pAttributeName; + const char* m_pDefaultString; + DmAttributeType_t m_AttributeType; + int m_nOffset; + int m_nSize; + int m_nBitOffset; + BitfieldType_t m_BitfieldType; + const void* m_pUserData; + + const char* m_pTypeName; + const DmxElementUnpackStructure_t* m_pSub; + + int m_nArrayLength; +}; + +#define NO_BIT_OFFSET -1 +#define UTL_STRING_SIZE -1 +#define NO_USER_DATA NULL +#define NO_EMBEDDED_TYPENAME NULL +#define NO_EMBEDDED_STRUCT_PTR NULL +#define NOT_A_BITFIELD BITFIELD_TYPE_NONE +#define NOT_AN_ARRAY 0 + +#define DECLARE_DMXELEMENT_UNPACK() \ + template friend DmxElementUnpackStructure_t *DmxElementUnpackInit(T *); + +#define BEGIN_DMXELEMENT_UNPACK( _structName ) \ + template DmxElementUnpackStructure_t *DmxElementUnpackInit(T *); \ + template <> DmxElementUnpackStructure_t *DmxElementUnpackInit<_structName>( _structName * ); \ + namespace _structName##_UnpackInit \ + { \ + static DmxElementUnpackStructure_t *s_pUnpack = DmxElementUnpackInit( (_structName *)NULL ); \ + } \ + \ + template <> DmxElementUnpackStructure_t *DmxElementUnpackInit<_structName>( _structName * ) \ + { \ + typedef _structName DestStructType_t; \ + static DmxElementUnpackStructure_t unpack[] = \ + { \ + +#define DMXELEMENT_UNPACK_FLTX4( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, CDmAttributeInfo::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( fltx4 ), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, + +#define DMXELEMENT_UNPACK_EMBEDDED( _typeName, _attributeName, _varName, _embeddedUnpackStructure ) \ + { _attributeName, "", AT_TYPE_COUNT, offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, _typeName, _embeddedUnpackStructure, NOT_AN_ARRAY }, + +#define DMXELEMENT_UNPACK_BASECLASS( _structName, _baseClass ) \ + { "Baseclass unpack", "", AT_TYPE_COUNT, size_cast< int >((intp) static_cast< _baseClass * >( (_structName*)0)), 0, NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, #_baseClass, DmxElementUnpackInit<_baseClass>( (_baseClass *)0 ), NOT_AN_ARRAY }, + +#define DMXELEMENT_UNPACK_BASECLASS_NAMESPACE( _namespace, _structName, _baseClass ) \ + { "Baseclass unpack", "", AT_TYPE_COUNT, size_cast< int >((intp) static_cast< _baseClass * >( (_structName*)0)), 0, NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, #_baseClass, DmxElementUnpackInit##_namespace<_baseClass>( (_baseClass *)0 ), NOT_AN_ARRAY }, + +#define VGUI_UNPACK_BASEPANEL() \ + DMXELEMENT_UNPACK_BASECLASS_NAMESPACE( vgui, DestStructType_t, DestStructType_t::BaseClass ) \ + +#define DMXELEMENT_UNPACK_FIELD( _attributeName, _defaultString, _type, _varName ) \ + { _attributeName, _defaultString, CDmAttributeInfo<_type>::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_FIELD_STRING( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_FIELD_UTLSTRING( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), UTL_STRING_SIZE, NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_SHORT( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, AT_INT, offsetof( DestStructType_t, _varName ), sizeof( short ), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_CHAR( _attributeName, _defaultString, _varName ) \ + { _attributeName, _defaultString, AT_INT, offsetof( DestStructType_t, _varName ), sizeof( char ), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_BITFIELD( _attributeName, _defaultString, _bitfieldType, _varName ) \ + { _attributeName, _defaultString, CDmAttributeInfo::AttributeType(), DestStructType_t::Get##_varName##ByteOffset(), DestStructType_t::Get##_varName##BitCount(), DestStructType_t::Get##_varName##BitOffset(), _bitfieldType, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, + +#define DMXELEMENT_UNPACK_FIELD_ARRAY( _attributeName, _defaultString, _type, _varName ) \ + { _attributeName, _defaultString, CDmAttributeInfo< CUtlVector< _type > >::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName[0]), NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, ARRAYSIZE( ((DestStructType_t *)0)->_varName ) }, + + +#define DMXELEMENT_UNPACK_FIELD_USERDATA( _attributeName, _defaultString, _type, _varName, _userData ) \ + { _attributeName, _defaultString, CDmAttributeInfo<_type>::AttributeType(), offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NO_BIT_OFFSET, NOT_A_BITFIELD, _userData, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_FIELD_STRING_USERDATA( _attributeName, _defaultString, _varName, _userData ) \ + { _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NO_BIT_OFFSET, NOT_A_BITFIELD, _userData, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, +#define DMXELEMENT_UNPACK_FIELD_UTLSTRING_USERDATA( _attributeName, _defaultString, _varName, _userData ) \ + { _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), UTL_STRING_SIZE, NO_BIT_OFFSET, NOT_A_BITFIELD, _userData, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR, NOT_AN_ARRAY }, + +#define END_DMXELEMENT_UNPACK( _structName, _varName ) \ + { NULL, NULL, AT_UNKNOWN, 0, 0, NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR } \ + }; \ + return unpack; \ + } \ + DmxElementUnpackStructure_t *_varName = _structName##_UnpackInit::s_pUnpack; + +#define END_DMXELEMENT_UNPACK_TEMPLATE( _structName, _varName ) \ + { NULL, NULL, AT_UNKNOWN, 0, 0, NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR } \ + }; \ + return unpack; \ + } \ + template<> DmxElementUnpackStructure_t *_varName = _structName##_UnpackInit::s_pUnpack; + +#define BEGIN_DMXELEMENT_NAMESPACE_UNPACK( _nameSpace, _structName ) \ + template DmxElementUnpackStructure_t *DmxElementUnpackInit(T *); \ + template <> DmxElementUnpackStructure_t *_nameSpace::DmxElementUnpackInit<_nameSpace::_structName>( _nameSpace::_structName * ); \ + namespace _structName##_UnpackInit \ + { \ + static DmxElementUnpackStructure_t *s_pUnpack = _nameSpace::DmxElementUnpackInit( (_nameSpace::_structName *)NULL ); \ + } \ + \ + template <> DmxElementUnpackStructure_t *_nameSpace::DmxElementUnpackInit<_nameSpace::_structName>( _nameSpace::_structName * ) \ + { \ + typedef _nameSpace::_structName DestStructType_t; \ + static DmxElementUnpackStructure_t unpack[] = \ + { \ + +#if defined( _PS3 ) && defined( __GCC__ ) +#define DECLARE_DMXELEMENT_UNPACK_NAMESPACE( _namespace ) \ + template friend DmxElementUnpackStructure_t *_namespace::DmxElementUnpackInit##_namespace(T *); \ + private: \ + static DmxElementUnpackStructure_t *s_pUnpackParams; \ + public: \ + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const { return s_pUnpackParams; } +#else +#define DECLARE_DMXELEMENT_UNPACK_NAMESPACE( _namespace ) \ + template friend DmxElementUnpackStructure_t *DmxElementUnpackInit##_namespace(T *); \ + private: \ + static DmxElementUnpackStructure_t *s_pUnpackParams; \ + public: \ + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const { return s_pUnpackParams; } +#endif + +#define BEGIN_DMXELEMENT_UNPACK_NAMESPACE_SIMPLE( _namespace, _structName ) \ + BEGIN_DMXELEMENT_UNPACK_NAMESPACE( _namespace, _structName ) \ + VGUI_UNPACK_BASEPANEL() \ + +#define BEGIN_DMXELEMENT_UNPACK_NAMESPACE_SIMPLE_NO_BASE( _namespace, _structName ) \ + BEGIN_DMXELEMENT_UNPACK_NAMESPACE( _namespace, _structName ) \ + +#define BEGIN_DMXELEMENT_UNPACK_NAMESPACE( _namespace, _structName ) \ + namespace _namespace { \ + template DmxElementUnpackStructure_t *DmxElementUnpackInit##_namespace(T *); \ + template <> DmxElementUnpackStructure_t *DmxElementUnpackInit##_namespace<_structName>( _namespace::_structName * ); \ + namespace _namespace##_structName##_UnpackInit \ + { \ + static DmxElementUnpackStructure_t *s_pUnpack = _namespace::DmxElementUnpackInit##_namespace( (_namespace::_structName *)NULL ); \ + } \ + \ + template <> DmxElementUnpackStructure_t *DmxElementUnpackInit##_namespace<_structName>( _namespace::_structName * ) \ + { \ + typedef _structName DestStructType_t; \ + static DmxElementUnpackStructure_t unpack[] = \ + { \ + +#define END_DMXELEMENT_UNPACK_NAMESPACE( _namespace, _structName, _varName ) \ + { NULL, NULL, AT_UNKNOWN, 0, 0, NO_BIT_OFFSET, NOT_A_BITFIELD, NO_USER_DATA, NO_EMBEDDED_TYPENAME, NO_EMBEDDED_STRUCT_PTR } \ + }; \ + return unpack; \ + } \ + DmxElementUnpackStructure_t *_structName::_varName = _namespace##_structName##_UnpackInit::s_pUnpack; \ + } \ + +template inline T GetAllOnesNumber() +{ + T temp = 0; + return (T)~temp; +} + +template <> inline bool GetAllOnesNumber() +{ + return true; +} + +#define DECLARE_DMXELEMENT_BITFIELD( _fieldName, _type, _structName ) \ + class CBitFieldInfo_##_fieldName \ + { \ + public: \ + CBitFieldInfo_##_fieldName () \ + { \ + const int nSize = ( sizeof(_structName) + 3 ) & ~0x3; \ + unsigned char pBuf[nSize] = {}; \ + (( _structName * )pBuf)->_fieldName = GetAllOnesNumber<_type>(); \ + _type *pTest = (_type *)pBuf; \ + for ( int i = 0; i < sizeof(_structName); ++i ) \ + { \ + if ( pTest[i] == 0 ) \ + continue; \ + \ + for ( int j = 0; j < 8*sizeof(_type); ++j ) \ + { \ + unsigned int temp = ((unsigned int)pTest[i]) & ( 1 << j ) ; \ + if ( temp == 0 ) \ + continue; \ + \ + m_nByteOffset = i*sizeof(_type) + j / 8; \ + m_nBitOffset = j & 0x7; \ + \ + int k; \ + for ( k = j+1; k < 8*sizeof(_type); ++k ) \ + { \ + unsigned int temp = ((unsigned int)pTest[i]) & ( 1 << k ) ; \ + if ( temp != 0 ) \ + continue; \ + break; \ + } \ + m_nBitCount = k - j; \ + break; \ + } \ + break; \ + } \ + } \ + \ + int GetByteOffset() const \ + { \ + return m_nByteOffset; \ + } \ + \ + int GetBitCount() const \ + { \ + return m_nBitCount; \ + } \ + \ + int GetBitOffset() const \ + { \ + return m_nBitOffset; \ + } \ + \ + private: \ + int m_nByteOffset; \ + int m_nBitCount; \ + int m_nBitOffset; \ + }; \ + \ + static int Get##_fieldName##BitCount() \ + { \ + CBitFieldInfo_##_fieldName info; \ + return info.GetBitCount(); \ + } \ + \ + static int Get##_fieldName##ByteOffset() \ + { \ + CBitFieldInfo_##_fieldName info; \ + return info.GetByteOffset(); \ + } \ + \ + static int Get##_fieldName##BitOffset() \ + { \ + CBitFieldInfo_##_fieldName info; \ + return info.GetBitOffset(); \ + } \ + friend class CBitFieldInfo_##_fieldName; \ + + +extern CUtlSymbolTableLargeMT g_DmxAttributeStrings; + +class CDmxElement +{ + DECLARE_DMX_ALLOCATOR(); + +public: + bool HasAttribute(const char* pAttributeName) const; + CDmxAttribute* GetAttribute(const char* pAttributeName); + const CDmxAttribute* GetAttribute(const char* pAttributeName) const; + int AttributeCount() const; + CDmxAttribute* GetAttribute(int nIndex); + const CDmxAttribute* GetAttribute(int nIndex) const; + CUtlSymbolLarge GetType() const; + const char* GetTypeString() const; + const char* GetName() const; + const DmObjectId_t& GetId() const; + + void LockForChanges(bool bLock); + CDmxAttribute* AddAttribute(const char* pAttributeName); + void RemoveAttribute(const char* pAttributeName); + void RemoveAttributeByPtr(CDmxAttribute* pAttribute); + void RemoveAllAttributes(); + void RenameAttribute(const char* pAttributeName, const char* pNewName); + + const char* GetValueString(const char* pAttributeName) const; + template< class T > const T& GetValue(const char* pAttributeName) const; + template< class T > const T& GetValue(const char* pAttributeName, const T& defaultValue) const; + + template< class T > const CUtlVector& GetArray(const char* pAttributeName) const; + template< class T > const CUtlVector& GetArray(const char* pAttributeName, const CUtlVector& defaultValue) const; + + void SetName(const char* pName); + CDmxAttribute* SetValue(const char* pAttributeName, const char* pString); + CDmxAttribute* SetValue(const char* pAttributeName, void* pBuffer, int nLen); + template< class T > CDmxAttribute* SetValue(const char* pAttributeName, const T& value); + + void UnpackIntoStructure(void* pData, const DmxElementUnpackStructure_t* pUnpack) const; + + void AddAttributesFromStructure(const void* pData, const DmxElementUnpackStructure_t* pUnpack); + +private: + typedef CUtlSortVector< CDmxAttribute*, CDmxAttributeLess > AttributeList_t; + + CDmxElement(const char* pType); + ~CDmxElement(); + + void RemoveAllElementsRecursive(); + + void AddElementsToDelete(CUtlVector< CDmxElement* >& elementsToDelete); + + void Resort() const; + + int FindAttribute(const char* pAttributeName) const; + int FindAttribute(CUtlSymbolLarge attributeName) const; + + void SetId(const DmObjectId_t& id); + + bool IsLocked() const; + + template void UnpackBitfield(T* pDest2, const DmxElementUnpackStructure_t* pUnpack, const CDmxAttribute* pAttribute) const; + + AttributeList_t m_Attributes; + DmObjectId_t m_Id; + CUtlSymbolLarge m_Type; + char m_nLockCount; + mutable bool m_bResortNeeded : 1; + bool m_bIsMarkedForDeletion : 1; + + static CUtlSymbolTableLargeMT s_TypeSymbols; + + friend class CDmxSerializer; + friend class CDmxSerializerKeyValues2; + friend void CleanupDMX(CDmxElement* pElement); + friend CDmxElement* CreateDmxElement(const char* pType); +}; + + +inline bool CDmxElement::IsLocked() const +{ + return m_nLockCount > 0; +} + +inline const char* CDmxElement::GetValueString(const char* pAttributeName) const +{ + const CDmxAttribute* pAttribute = GetAttribute(pAttributeName); + if (pAttribute) + return pAttribute->GetValueString(); + return ""; +} + +template< class T > +inline const T& CDmxElement::GetValue(const char* pAttributeName) const +{ + const CDmxAttribute* pAttribute = GetAttribute(pAttributeName); + if (pAttribute) + return pAttribute->GetValue(); + + static T defaultValue; + CDmAttributeInfo::SetDefaultValue(defaultValue); + return defaultValue; +} + +template< class T > +inline const T& CDmxElement::GetValue(const char* pAttributeName, const T& defaultValue) const +{ + const CDmxAttribute* pAttribute = GetAttribute(pAttributeName); + if (pAttribute) + return pAttribute->GetValue(); + return defaultValue; +} + +template< class T > +inline const CUtlVector& CDmxElement::GetArray(const char* pAttributeName) const +{ + const CDmxAttribute* pAttribute = GetAttribute(pAttributeName); + if (pAttribute) + return pAttribute->GetArray(); + + static CUtlVector defaultValue; + return defaultValue; +} + +template< class T > +inline const CUtlVector& CDmxElement::GetArray(const char* pAttributeName, const CUtlVector& defaultValue) const +{ + const CDmxAttribute* pAttribute = GetAttribute(pAttributeName); + if (pAttribute) + return pAttribute->GetArray(); + return defaultValue; +} + + +CDmxElement* CreateDmxElement(const char* pType); + + +class CDmxElementModifyScope +{ +public: + CDmxElementModifyScope(CDmxElement* pElement) : m_pElement(pElement) + { + m_pElement->LockForChanges(true); + } + ~CDmxElementModifyScope() + { + Release(); + } + void Release() + { + if (m_pElement) + { + m_pElement->LockForChanges(false); + m_pElement = NULL; + } + } +private: + CDmxElement* m_pElement; +}; + + +inline CDmxAttribute* CDmxElement::SetValue(const char* pAttributeName, const char* pString) +{ + CDmxElementModifyScope modify(this); + CDmxAttribute* pAttribute = AddAttribute(pAttributeName); + pAttribute->SetValue(pString); + return pAttribute; +} + +inline CDmxAttribute* CDmxElement::SetValue(const char* pAttributeName, void* pBuffer, int nLen) +{ + CDmxElementModifyScope modify(this); + CDmxAttribute* pAttribute = AddAttribute(pAttributeName); + pAttribute->SetValue(pBuffer, nLen); + return pAttribute; +} + +template< class T > +inline CDmxAttribute* CDmxElement::SetValue(const char* pAttributeName, const T& value) +{ + CDmxElementModifyScope modify(this); + CDmxAttribute* pAttribute = AddAttribute(pAttributeName); + pAttribute->SetValue(value); + return pAttribute; +} + + +#endif +``` + +`SpyCustom/sdk/dmxloader.h`: + +```h +#ifndef DMXLOADER_H +#define DMXLOADER_H + +#ifdef _WIN32 +#pragma once +#endif + +class CUtlBuffer; +class CDmxElement; + + +bool SerializeDMX(CUtlBuffer& buf, CDmxElement* pRoot, const char* pFileName = NULL); +bool SerializeDMX(const char* pFileName, const char* pPathID, bool bTextMode, CDmxElement* pRoot); + +bool UnserializeDMX(CUtlBuffer& buf, CDmxElement** ppRoot, const char* pFileName = NULL); +bool UnserializeDMX(const char* pFileName, const char* pPathID, bool bTextMode, CDmxElement** ppRoot); + +void BeginDMXContext(); +void EndDMXContext(bool bDecommitMemory); +void DecommitDMXMemory(); + + +class CDMXContextHelper +{ +public: + CDMXContextHelper(bool bDecommitMemory) { m_bDecommitMemory = bDecommitMemory; BeginDMXContext(); } + ~CDMXContextHelper() { EndDMXContext(m_bDecommitMemory); } + +private: + bool m_bDecommitMemory; +}; + +#define DECLARE_DMX_CONTEXT( ) CDMXContextHelper __dmxContextHelper( true ); +#define DECLARE_DMX_CONTEXT_NODECOMMIT( ) CDMXContextHelper __dmxContextHelper( false ); +#define DECLARE_DMX_CONTEXT_DECOMMIT( _decommit ) CDMXContextHelper __dmxContextHelper( _decommit ); + + +void* DMXAlloc(size_t size); + + +#define DECLARE_DMX_ALLOCATOR( ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_( "DMXAlloc" ); return DMXAlloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_( "DMXAlloc" ); return DMXAlloc(size); } \ + inline void operator delete( void* p ) { } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { } \ + +#endif +``` + +`SpyCustom/sdk/dt_common.h`: + +```h +#ifndef DATATABLE_COMMON_H +#define DATATABLE_COMMON_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "dbg.h" +#include "strtools.h" +#include + +#ifdef LINUX +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#define MAX_DATATABLES 1024 +#define MAX_DATATABLE_PROPS 4096 + +#define MAX_ARRAY_ELEMENTS 2048 + +#define HIGH_DEFAULT -121121.121121f + +#define BITS_FULLRES -1 +#define BITS_WORLDCOORD -2 + +#define DT_MAX_STRING_BITS 9 +#define DT_MAX_STRING_BUFFERSIZE (1<varName ) + +#define PROPSIZEOF(className, varName) sizeof(((className*)0)->varName) + + +#define SPROP_UNSIGNED (1<<0) + +#define SPROP_COORD (1<<1) +#define SPROP_NOSCALE (1<<2) + +#define SPROP_ROUNDDOWN (1<<3) + +#define SPROP_ROUNDUP (1<<4) + +#define SPROP_NORMAL (1<<5) + +#define SPROP_EXCLUDE (1<<6) + +#define SPROP_XYZE (1<<7) + +#define SPROP_INSIDEARRAY (1<<8) +#define SPROP_PROXY_ALWAYS_YES (1<<9) +#define SPROP_CHANGES_OFTEN (1<<10) + +#define SPROP_IS_A_VECTOR_ELEM (1<<11) + +#define SPROP_COLLAPSIBLE (1<<12) +#define SPROP_COORD_MP (1<<13) +#define SPROP_COORD_MP_LOWPRECISION (1<<14) +#define SPROP_COORD_MP_INTEGRAL (1<<15) + +#define SPROP_VARINT SPROP_NORMAL + +#define SPROP_NUMFLAGBITS_NETWORKED 16 + +#define SPROP_ENCODED_AGAINST_TICKCOUNT (1<<16) + +#define SPROP_NUMFLAGBITS 17 + +#define SIZEOF_IGNORE -1 + + +#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, + DPT_DataTable, +#if 0 + DPT_Quaternion, +#endif + +#ifdef SUPPORTS_INT64 + DPT_Int64, +#endif + + DPT_NUMSendPropTypes + +} SendPropType; + + +class DVariant +{ +public: + DVariant() { m_Type = DPT_Float; } + DVariant(float val) { m_Type = DPT_Float; m_Float = val; } + + const char* ToString() + { + static char text[128]; + + switch (m_Type) + { + case DPT_Int: + Q_snprintf(text, sizeof(text), "%i", m_Int); + break; + case DPT_Float: + Q_snprintf(text, sizeof(text), "%.3f", m_Float); + break; + case DPT_Vector: + Q_snprintf(text, sizeof(text), "(%.3f,%.3f,%.3f)", + m_Vector[0], m_Vector[1], m_Vector[2]); + break; + case DPT_VectorXY: + Q_snprintf(text, sizeof(text), "(%.3f,%.3f)", + m_Vector[0], m_Vector[1]); + break; +#if 0 + case DPT_Quaternion: + Q_snprintf(text, sizeof(text), "(%.3f,%.3f,%.3f %.3f)", + m_Vector[0], m_Vector[1], m_Vector[2], m_Vector[3]); + break; +#endif + case DPT_String: + if (m_pString) + return m_pString; + else + return "NULL"; + break; + case DPT_Array: + Q_snprintf(text, sizeof(text), "Array"); + break; + case DPT_DataTable: + Q_snprintf(text, sizeof(text), "DataTable"); + break; +#ifdef SUPPORTS_INT64 + case DPT_Int64: + Q_snprintf(text, sizeof(text), "%I64d", m_Int64); + break; +#endif + default: + Q_snprintf(text, sizeof(text), "DVariant type %i unknown", m_Type); + break; + } + + return text; + } + + union + { + float m_Float; + int m_Int; + const char* m_pString; + void* m_pData; +#if 0 + float m_Vector[4]; +#else + float m_Vector[3]; +#endif + + int64 m_Int64; + }; + SendPropType m_Type; +}; + + +inline int NumBitsForCount(int nMaxElements) +{ + int nBits = 0; + while (nMaxElements > 0) + { + ++nBits; + nMaxElements >>= 1; + } + return nBits; +} + + +#endif +``` + +`SpyCustom/sdk/dt_recv.h`: + +```h +#ifndef DATATABLE_RECV_H +#define DATATABLE_RECV_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dt_common.h" +#include "dbg.h" + + +#define ADDRESSPROXY_NONE -1 + + +class RecvTable; +class RecvProp; + + +class CRecvProxyData +{ +public: + const RecvProp* m_pRecvProp; + + DVariant m_Value; + + int m_iElement; + + int m_ObjectID; +}; + + +typedef void (*RecvVarProxyFn)(const CRecvProxyData* pData, void* pStruct, void* pOut); + +typedef void (*ArrayLengthRecvProxyFn)(void* pStruct, int objectID, int currentArrayLength); + + +typedef void (*DataTableRecvVarProxyFn)(const RecvProp* pProp, void** pOut, void* pData, int objectID); + + +class CStandardRecvProxies +{ +public: + CStandardRecvProxies(); + + RecvVarProxyFn m_Int32ToInt8; + RecvVarProxyFn m_Int32ToInt16; + RecvVarProxyFn m_Int32ToInt32; + RecvVarProxyFn m_FloatToFloat; + RecvVarProxyFn m_VectorToVector; +#ifdef SUPPORTS_INT64 + RecvVarProxyFn m_Int64ToInt64; +#endif +}; +extern CStandardRecvProxies g_StandardRecvProxies; + + +class CRecvDecoder; + + +class RecvProp +{ +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); + + RecvProp* GetArrayProp() const; + void SetArrayProp(RecvProp* pProp); + + void SetArrayLengthProxy(ArrayLengthRecvProxyFn proxy); + ArrayLengthRecvProxyFn GetArrayLengthProxy() const; + + bool IsInsideArray() const; + void SetInsideArray(); + + const void* GetExtraData() const; + void SetExtraData(const void* pData); + + const char* GetParentArrayPropName(); + void SetParentArrayPropName(const char* pArrayPropName); + +public: + + const char* m_pVarName; + SendPropType m_RecvType; + int m_Flags; + int m_StringBufferSize; + + + bool m_bInsideArray; + + const void* m_pExtraData; + + RecvProp* m_pArrayProp; + ArrayLengthRecvProxyFn m_ArrayLengthProxy; + + RecvVarProxyFn m_ProxyFn; + DataTableRecvVarProxyFn m_DataTableProxyFn; + + RecvTable* m_pDataTable; + int m_Offset; + + int m_ElementStride; + int m_nElements; + + 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(); + + void SetInitialized(bool bInitialized); + bool IsInitialized() const; + + void SetInMainList(bool bInList); + bool IsInMainList() const; + + +public: + + RecvProp* m_pProps; + int m_nProps; + + CRecvDecoder* m_pDecoder; + + const char* m_pNetTableName; + + + 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; +} + + +#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)), + +#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]) + +#define RECVINFO_NOSIZE(varName) #varName, offsetof(currentRecvDTClass, varName) +#define RECVINFO_DT(varName) RECVINFO_NOSIZE(varName) +#define RECVINFO_DTNAME(varName,remoteVarName) #remoteVarName, offsetof(currentRecvDTClass, varName) + + +void RecvProxy_FloatToFloat(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_VectorToVector(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_VectorXYToVectorXY(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_QuaternionToQuaternion(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_Int32ToInt8(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_Int32ToInt16(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_StringToString(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_Int32ToInt32(const CRecvProxyData* pData, void* pStruct, void* pOut); +#ifdef SUPPORTS_INT64 +void RecvProxy_Int64ToInt64(const CRecvProxyData* pData, void* pStruct, void* pOut); +#endif + +void DataTableRecvProxy_StaticDataTable(const RecvProp* pProp, void** pOut, void* pData, int objectID); + +void DataTableRecvProxy_PointerDataTable(const RecvProp* pProp, void** pOut, void* pData, int objectID); + + +RecvProp RecvPropFloat( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int flags = 0, + RecvVarProxyFn varProxy = RecvProxy_FloatToFloat +); + +RecvProp RecvPropVector( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int flags = 0, + RecvVarProxyFn varProxy = RecvProxy_VectorToVector +); + +RecvProp RecvPropVectorXY( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int flags = 0, + RecvVarProxyFn varProxy = RecvProxy_VectorXYToVectorXY +); + +#define RecvPropQAngles RecvPropVector + +#if 0 + +RecvProp RecvPropQuaternion( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int flags = 0, + RecvVarProxyFn varProxy = RecvProxy_QuaternionToQuaternion +); +#endif + +RecvProp RecvPropInt( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + 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 +); + +RecvProp InternalRecvPropArray( + const int elementCount, + const int elementStride, + const char* pName, + ArrayLengthRecvProxyFn proxy +); + + +#define RecvPropVirtualArray( arrayLengthProxy, maxArrayLength, varTemplate, propertyName ) \ + varTemplate, \ + InternalRecvPropArray( \ + maxArrayLength, \ + 0, \ + #propertyName, \ + arrayLengthProxy \ + ) + + +#define RecvPropVariableLengthArray( arrayLengthProxy, varTemplate, arrayName ) \ + varTemplate, \ + InternalRecvPropArray( \ + sizeof(((currentRecvDTClass*)0)->arrayName) / PROPSIZEOF(currentRecvDTClass, arrayName[0]), \ + PROPSIZEOF(currentRecvDTClass, arrayName[0]), \ + #arrayName, \ + arrayLengthProxy \ + ) + + +#define RecvPropArray( varTemplate, arrayName ) \ + RecvPropVariableLengthArray( 0, varTemplate, arrayName ) + + +#define RecvPropArray2( arrayLengthProxy, varTemplate, elementCount, elementStride, arrayName ) \ + varTemplate, \ + InternalRecvPropArray( elementCount, elementStride, #arrayName, arrayLengthProxy ) + + +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 +``` + +`SpyCustom/sdk/dt_send.h`: + +```h +#ifndef DATATABLE_SEND_H +#define DATATABLE_SEND_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dt_common.h" +#include "dbg.h" +#include "const.h" +#include "bitvec.h" + + +typedef void (*SendVarProxyFn)(const SendProp* pProp, const void* pStructBase, const void* pData, DVariant* pOut, int iElement, int objectID); + +class CSendProxyRecipients; + +typedef void* (*SendTableProxyFn)( + const SendProp* pProp, + const void* pStructBase, + const void* pData, + CSendProxyRecipients* pRecipients, + int objectID); + + +class CNonModifiedPointerProxy +{ +public: + CNonModifiedPointerProxy(SendTableProxyFn fn); + +public: + + SendTableProxyFn m_Fn; + CNonModifiedPointerProxy* m_pNext; +}; + + +#define REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( sendProxyFn ) static CNonModifiedPointerProxy __proxy_##sendProxyFn( sendProxyFn ); + + +class CStandardSendProxiesV1 +{ +public: + CStandardSendProxiesV1(); + + SendVarProxyFn m_Int8ToInt32; + SendVarProxyFn m_Int16ToInt32; + SendVarProxyFn m_Int32ToInt32; + + SendVarProxyFn m_UInt8ToInt32; + SendVarProxyFn m_UInt16ToInt32; + SendVarProxyFn m_UInt32ToInt32; + + SendVarProxyFn m_FloatToFloat; + SendVarProxyFn m_VectorToVector; + +#ifdef SUPPORTS_INT64 + SendVarProxyFn m_Int64ToInt64; + SendVarProxyFn m_UInt64ToInt64; +#endif +}; + +class CStandardSendProxies : public CStandardSendProxiesV1 +{ +public: + CStandardSendProxies(); + + SendTableProxyFn m_DataTableToDataTable; + SendTableProxyFn m_SendLocalDataTable; + CNonModifiedPointerProxy** m_ppNonModifiedPointerProxies; +}; + +extern CStandardSendProxies g_StandardSendProxies; + + +#define MAX_DATATABLE_PROXIES 32 + +class CSendProxyRecipients +{ +public: + void SetAllRecipients(); + void ClearAllRecipients(); + + void SetRecipient(int iClient); + void ClearRecipient(int iClient); + + void SetOnly(int iClient); + +public: + CBitVec< ABSOLUTE_PLAYER_LIMIT > m_Bits; +}; + +inline void CSendProxyRecipients::SetAllRecipients() +{ + m_Bits.SetAll(); +} + +inline void CSendProxyRecipients::ClearAllRecipients() +{ + m_Bits.ClearAll(); +} + +inline void CSendProxyRecipients::SetRecipient(int iClient) +{ + m_Bits.Set(iClient); +} + +inline void CSendProxyRecipients::ClearRecipient(int iClient) +{ + m_Bits.Clear(iClient); +} + +inline void CSendProxyRecipients::SetOnly(int iClient) +{ + m_Bits.ClearAll(); + m_Bits.Set(iClient); +} + + + +typedef int (*ArrayLengthSendProxyFn)(const void* pStruct, int objectID); + + + +class RecvProp; +class SendTable; +class CSendTablePrecalc; + + +#define DATATABLE_PROXY_INDEX_NOPROXY 255 +#define DATATABLE_PROXY_INDEX_INVALID 254 + +class SendProp +{ +public: + SendProp(); + virtual ~SendProp(); + + void Clear(); + + int GetOffset() const; + void SetOffset(int i); + + SendVarProxyFn GetProxyFn() const; + void SetProxyFn(SendVarProxyFn f); + + SendTableProxyFn GetDataTableProxyFn() const; + void SetDataTableProxyFn(SendTableProxyFn f); + + SendTable* GetDataTable() const; + void SetDataTable(SendTable* pTable); + + char const* GetExcludeDTName() const; + + const char* GetParentArrayPropName() const; + void SetParentArrayPropName(char* pArrayPropName); + + const char* GetName() const; + + bool IsSigned() const; + + bool IsExcludeProp() const; + + bool IsInsideArray() const; + void SetInsideArray(); + + void SetArrayProp(SendProp* pProp); + SendProp* GetArrayProp() const; + + void SetArrayLengthProxy(ArrayLengthSendProxyFn fn); + ArrayLengthSendProxyFn GetArrayLengthProxy() const; + + int GetNumElements() const; + void SetNumElements(int nElements); + + int GetNumArrayLengthBits() const; + + int GetElementStride() const; + + SendPropType GetType() const; + + int GetFlags() const; + void SetFlags(int flags); + + const void* GetExtraData() const; + void SetExtraData(const void* pData); + +public: + + RecvProp* m_pMatchingRecvProp; + SendPropType m_Type; + int m_nBits; + float m_fLowValue; + float m_fHighValue; + + SendProp* m_pArrayProp; + ArrayLengthSendProxyFn m_ArrayLengthProxy; + + int m_nElements; + int m_ElementStride; + + const char* m_pExcludeDTName; + const char* m_pParentArrayPropName; + + const char* m_pVarName; + float m_fHighLowMul; + +private: + + int m_Flags; + + SendVarProxyFn m_ProxyFn; + SendTableProxyFn m_DataTableProxyFn; + + SendTable* m_pDataTable; + + int m_Offset; + + const void* m_pExtraData; +}; + + +inline int SendProp::GetOffset() const +{ + return m_Offset; +} + +inline void SendProp::SetOffset(int i) +{ + m_Offset = i; +} + +inline SendVarProxyFn SendProp::GetProxyFn() const +{ + Assert(m_Type != DPT_DataTable); + return m_ProxyFn; +} + +inline void SendProp::SetProxyFn(SendVarProxyFn f) +{ + m_ProxyFn = f; +} + +inline SendTableProxyFn SendProp::GetDataTableProxyFn() const +{ + Assert(m_Type == DPT_DataTable); + return m_DataTableProxyFn; +} + +inline void SendProp::SetDataTableProxyFn(SendTableProxyFn f) +{ + m_DataTableProxyFn = f; +} + +inline SendTable* SendProp::GetDataTable() const +{ + return m_pDataTable; +} + +inline void SendProp::SetDataTable(SendTable* pTable) +{ + m_pDataTable = pTable; +} + +inline char const* SendProp::GetExcludeDTName() const +{ + return m_pExcludeDTName; +} + +inline const char* SendProp::GetParentArrayPropName() const +{ + return m_pParentArrayPropName; +} + +inline void SendProp::SetParentArrayPropName(char* pArrayPropName) +{ + Assert(!m_pParentArrayPropName); + m_pParentArrayPropName = pArrayPropName; +} + +inline const char* SendProp::GetName() const +{ + return m_pVarName; +} + + +inline bool SendProp::IsSigned() const +{ + return !(m_Flags & SPROP_UNSIGNED); +} + +inline bool SendProp::IsExcludeProp() const +{ + return (m_Flags & SPROP_EXCLUDE) != 0; +} + +inline bool SendProp::IsInsideArray() const +{ + return (m_Flags & SPROP_INSIDEARRAY) != 0; +} + +inline void SendProp::SetInsideArray() +{ + m_Flags |= SPROP_INSIDEARRAY; +} + +inline void SendProp::SetArrayProp(SendProp* pProp) +{ + m_pArrayProp = pProp; +} + +inline SendProp* SendProp::GetArrayProp() const +{ + return m_pArrayProp; +} + +inline void SendProp::SetArrayLengthProxy(ArrayLengthSendProxyFn fn) +{ + m_ArrayLengthProxy = fn; +} + +inline ArrayLengthSendProxyFn SendProp::GetArrayLengthProxy() const +{ + return m_ArrayLengthProxy; +} + +inline int SendProp::GetNumElements() const +{ + return m_nElements; +} + +inline void SendProp::SetNumElements(int nElements) +{ + m_nElements = nElements; +} + +inline int SendProp::GetElementStride() const +{ + return m_ElementStride; +} + +inline SendPropType SendProp::GetType() const +{ + return m_Type; +} + +inline int SendProp::GetFlags() const +{ + return m_Flags; +} + +inline void SendProp::SetFlags(int flags) +{ + Assert(!(flags & ~((1 << SPROP_NUMFLAGBITS) - 1))); + m_Flags = flags; +} + +inline const void* SendProp::GetExtraData() const +{ + return m_pExtraData; +} + +inline void SendProp::SetExtraData(const void* pData) +{ + m_pExtraData = pData; +} + + +class SendTable +{ +public: + + typedef SendProp PropType; + + SendTable(); + SendTable(SendProp* pProps, int nProps, const char* pNetTableName); + ~SendTable(); + + void Construct(SendProp* pProps, int nProps, const char* pNetTableName); + + const char* GetName() const; + + int GetNumProps() const; + SendProp* GetProp(int i); + + bool IsInitialized() const; + void SetInitialized(bool bInitialized); + + void SetWriteFlag(bool bHasBeenWritten); + bool GetWriteFlag() const; + + bool HasPropsEncodedAgainstTickCount() const; + void SetHasPropsEncodedAgainstTickcount(bool bState); + +public: + + SendProp* m_pProps; + int m_nProps; + + const char* m_pNetTableName; + + CSendTablePrecalc* m_pPrecalc; + + +protected: + bool m_bInitialized : 1; + bool m_bHasBeenWritten : 1; + bool m_bHasPropsEncodedAgainstCurrentTickCount : 1; +}; + + +inline const char* SendTable::GetName() const +{ + return m_pNetTableName; +} + + +inline int SendTable::GetNumProps() const +{ + return m_nProps; +} + + +inline SendProp* SendTable::GetProp(int i) +{ + Assert(i >= 0 && i < m_nProps); + return &m_pProps[i]; +} + + +inline bool SendTable::IsInitialized() const +{ + return m_bInitialized; +} + + +inline void SendTable::SetInitialized(bool bInitialized) +{ + m_bInitialized = bInitialized; +} + + +inline bool SendTable::GetWriteFlag() const +{ + return m_bHasBeenWritten; +} + + +inline void SendTable::SetWriteFlag(bool bHasBeenWritten) +{ + m_bHasBeenWritten = bHasBeenWritten; +} + +inline bool SendTable::HasPropsEncodedAgainstTickCount() const +{ + return m_bHasPropsEncodedAgainstCurrentTickCount; +} + +inline void SendTable::SetHasPropsEncodedAgainstTickcount(bool bState) +{ + m_bHasPropsEncodedAgainstCurrentTickCount = bState; +} + +#define BEGIN_SEND_TABLE(className, tableName) \ + BEGIN_SEND_TABLE_NOBASE(className, tableName) \ + SendPropDataTable("baseclass", 0, className::BaseClass::m_pClassSendTable, SendProxy_DataTableToDataTable), + +#define BEGIN_SEND_TABLE_NOBASE(className, tableName) \ + template int ServerClassInit(T *); \ + namespace tableName { \ + struct ignored; \ + } \ + template <> int ServerClassInit(tableName::ignored *); \ + namespace tableName { \ + SendTable g_SendTable;\ + int g_SendTableInit = ServerClassInit((tableName::ignored *)NULL); \ + } \ + template <> int ServerClassInit(tableName::ignored *) \ + { \ + typedef className currentSendDTClass; \ + static const char *g_pSendTableName = #tableName; \ + SendTable &sendTable = tableName::g_SendTable; \ + static SendProp g_SendProps[] = { \ + SendPropInt("should_never_see_this", 0, sizeof(int)), + +#define END_SEND_TABLE() \ + };\ + sendTable.Construct(g_SendProps+1, sizeof(g_SendProps) / sizeof(SendProp) - 1, g_pSendTableName);\ + return 1; \ + } + + +#define SENDINFO(varName) #varName, offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName) +#define SENDINFO_ARRAY(varName) #varName, offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName[0]) +#define SENDINFO_ARRAY3(varName) #varName, offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName[0]), sizeof(((currentSendDTClass*)0)->varName)/sizeof(((currentSendDTClass*)0)->varName[0]) +#define SENDINFO_ARRAYELEM(varName, i) #varName "[" #i "]", offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName[i]), sizeof(((currentSendDTClass*)0)->varName[0]) +#define SENDINFO_NETWORKARRAYELEM(varName, i)#varName "[" #i "]", offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0]) + +#define SENDINFO_VECTORELEM(varName, i) #varName "[" #i "]", -(int)offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0]) + +#define SENDINFO_STRUCTELEM(varName) #varName, offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName.m_Value) +#define SENDINFO_STRUCTARRAYELEM(varName, i)#varName "[" #i "]", offsetof(currentSendDTClass, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0]) + +#define SENDINFO_NOCHECK(varName) #varName, offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName) +#define SENDINFO_STRING_NOCHECK(varName) #varName, offsetof(currentSendDTClass, varName) +#define SENDINFO_DT(varName) #varName, offsetof(currentSendDTClass, varName) +#define SENDINFO_DT_NAME(varName, remoteVarName) #remoteVarName, offsetof(currentSendDTClass, varName) +#define SENDINFO_NAME(varName,remoteVarName) #remoteVarName, offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName) + + + + +void SendProxy_QAngles(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_AngleToFloat(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_FloatToFloat(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_VectorToVector(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_VectorXYToVectorXY(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +#if 0 +void SendProxy_QuaternionToQuaternion(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +#endif + +void SendProxy_Int8ToInt32(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_Int16ToInt32(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_Int32ToInt32(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +#ifdef SUPPORTS_INT64 +void SendProxy_Int64ToInt64(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +#endif +void SendProxy_StringToString(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); + +void* SendProxy_DataTableToDataTable(const SendProp* pProp, const void* pStructBase, const void* pData, CSendProxyRecipients* pRecipients, int objectID); + +void* SendProxy_DataTablePtrToDataTable(const SendProp* pProp, const void* pStructBase, const void* pData, CSendProxyRecipients* pRecipients, int objectID); + +void* SendProxy_SendLocalDataTable(const SendProp* pProp, const void* pStruct, const void* pVarData, CSendProxyRecipients* pRecipients, int objectID); + + +SendProp SendPropFloat( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = 32, + int flags = 0, + float fLowValue = 0.0f, + float fHighValue = HIGH_DEFAULT, + SendVarProxyFn varProxy = SendProxy_FloatToFloat +); + +SendProp SendPropVector( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = 32, + int flags = SPROP_NOSCALE, + float fLowValue = 0.0f, + float fHighValue = HIGH_DEFAULT, + SendVarProxyFn varProxy = SendProxy_VectorToVector +); + +SendProp SendPropVectorXY( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = 32, + int flags = SPROP_NOSCALE, + float fLowValue = 0.0f, + float fHighValue = HIGH_DEFAULT, + SendVarProxyFn varProxy = SendProxy_VectorXYToVectorXY +); + +#if 0 +SendProp SendPropQuaternion( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = 32, + int flags = SPROP_NOSCALE, + float fLowValue = 0.0f, + float fHighValue = HIGH_DEFAULT, + SendVarProxyFn varProxy = SendProxy_QuaternionToQuaternion +); +#endif + +SendProp SendPropAngle( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = 32, + int flags = 0, + SendVarProxyFn varProxy = SendProxy_AngleToFloat +); + +SendProp SendPropQAngles( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = 32, + int flags = 0, + SendVarProxyFn varProxy = SendProxy_QAngles +); + +SendProp SendPropInt( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int nBits = -1, + int flags = 0, + SendVarProxyFn varProxy = 0 +); + +inline SendProp SendPropModelIndex(const char* pVarName, int offset, int sizeofVar = SIZEOF_IGNORE) +{ + return SendPropInt(pVarName, offset, sizeofVar, SP_MODEL_INDEX_BITS, 0); +} + +SendProp SendPropString( + const char* pVarName, + int offset, + int bufferLen, + int flags = 0, + SendVarProxyFn varProxy = SendProxy_StringToString); + +SendProp SendPropDataTable( + const char* pVarName, + int offset, + SendTable* pTable, + SendTableProxyFn varProxy = SendProxy_DataTableToDataTable +); + +SendProp SendPropArray3( + const char* pVarName, + int offset, + int sizeofVar, + int elements, + SendProp pArrayProp, + SendTableProxyFn varProxy = SendProxy_DataTableToDataTable +); + + + +SendProp InternalSendPropArray( + const int elementCount, + const int elementStride, + const char* pName, + ArrayLengthSendProxyFn proxy +); + + +#define SendPropArray( varTemplate, arrayName ) \ + SendPropVariableLengthArray( \ + 0, \ + varTemplate, \ + arrayName ) + +#define SendPropVirtualArray( arrayLengthSendProxy, maxArrayLength, varTemplate, propertyName ) \ + varTemplate, \ + InternalSendPropArray( \ + maxArrayLength, \ + 0, \ + #propertyName, \ + arrayLengthSendProxy \ + ) + + +#define SendPropVariableLengthArray( arrayLengthSendProxy, varTemplate, arrayName ) \ + varTemplate, \ + InternalSendPropArray( \ + sizeof(((currentSendDTClass*)0)->arrayName) / PROPSIZEOF(currentSendDTClass, arrayName[0]), \ + PROPSIZEOF(currentSendDTClass, arrayName[0]), \ + #arrayName, \ + arrayLengthSendProxy \ + ) + +#define SendPropArray2( arrayLengthSendProxy, varTemplate, elementCount, elementStride, arrayName ) \ + varTemplate, \ + InternalSendPropArray( elementCount, elementStride, #arrayName, arrayLengthSendProxy ) + + + + +SendProp SendPropExclude( + const char* pDataTableName, + const char* pPropName +); + + +#endif +``` + +`SpyCustom/sdk/econ_item_constants.h`: + +```h +#ifndef ACTUAL_ECON_ITEM_CONSTANTS_H +#define ACTUAL_ECON_ITEM_CONSTANTS_H +#ifdef _WIN32 +#pragma once +#endif + +typedef uint32 item_price_t; +typedef uint8 item_transaction_quantity_t; + +class CLocalizationProvider; + +#define TESTITEM_DEFINITIONS_BEGIN_AT 32000 +#define TESTITEM_DEFINITIONS_COUNT 16 + +enum EEconTypeID +{ + k_EEconTypeItem = 1, + k_EEconTypePersonaDataPublic = 2, + k_EEconTypeGameAccountClient = 7, + k_EEconTypeGameAccount = 8, + k_EEconTypeEquipInstance = 31, + k_EEconTypeDefaultEquippedDefinitionInstance = 42, + k_EEconTypeDefaultEquippedDefinitionInstanceClient = 43, + k_EEconTypeCoupon = 45, + k_EEconTypeQuest = 46, +}; + +enum EItemAction +{ + k_EItemActionInvalid = -1, + k_EItemActionGSCreate = 0, + k_EItemActionUnpurchase = 1, + k_EItemActionDelete = 2, + k_EItemActionAwardAchievement = 3, + k_EItemActionBanned = 4, + k_EItemActionQuantityChanged = 5, + k_EItemActionRestored = 6, + k_EItemActionAwardTime = 7, + k_EItemActionManualCreate = 8, + k_EItemActionDrop = 9, + k_EItemActionPickUp = 10, + k_EItemActionCraftDestroy = 11, + k_EItemActionCraftCreate = 12, + k_EItemActionLimitExceeded = 13, + k_EItemActionPurchase = 14, + k_EItemActionNameChanged_Add = 15, + k_EItemActionUnlockCrate_Add = 16, + k_EItemActionPaintItem_Add = 17, + k_EItemActionAutoGrantItem = 18, + k_EItemActionCrossGameAchievement = 19, + k_EItemActionAddItemToSocket_Add = 20, + k_EItemActionAddSocketToItem_Add = 21, + k_EItemActionRemoveSocketItem_Add = 22, + k_EItemActionCustomizeItemTexture_Add = 23, + k_EItemActionItemTraded_Add = 24, + k_EItemActionUseItem = 25, + k_EItemActionAwardGift_Receiver = 26, + k_EItemActionNameChanged_Remove = 27, + k_EItemActionUnlockCrate_Remove = 28, + k_EItemActionPaintItem_Remove = 29, + k_EItemActionAddItemToSocket_Remove = 30, + k_EItemActionAddSocketToItem_Remove = 31, + k_EItemActionRemoveSocketItem_Remove = 32, + k_EItemActionCustomizeItemTexture_Remove = 33, + k_EItemActionItemTraded_Remove = 34, + k_EItemActionUnpackItemBundle = 35, + k_EItemActionCreateItemFromBundle = 36, + k_EItemActionAwardStorePromotionItem = 37, + k_EItemActionConvertItem = 38, + k_EItemActionEarnedItem = 39, + k_EItemActionAwardGift_Giver = 40, + k_EItemActionRefundedItem = 41, + k_EItemActionAwardThirdPartyPromo = 42, + k_EItemActionRemoveItemName_Remove = 43, + k_EItemActionRemoveItemName_Add = 44, + k_EItemActionRemoveItemPaint_Remove = 45, + k_EItemActionRemoveItemPaint_Add = 46, + k_EItemActionHalloweenDrop = 47, + k_EItemActionSteamWorkshopContributor = 48, + + k_EItemActionSupportDelete = 50, + k_EItemActionSupportCreatedByUndo = 51, + k_EItemActionSupportDeletedByUndo = 52, + k_EItemActionSupportQuantityChangedByUndo = 53, + k_EItemActionSupportRename_Add = 54, + k_EItemActionSupportRename_Remove = 55, + k_EItemActionSupportDescribe_Add = 56, + k_EItemActionSupportDescribe_Remove = 57, + + k_EItemActionPeriodicScoreReward_Add = 58, + k_EItemActionPeriodicScoreReward_Remove = 59, + k_EItemActionStrangePartApply_Add = 60, + k_EItemActionStrangePartApply_Remove = 61, + + k_EItemActionPennantUpgradeApply_Add = 62, + k_EItemActionPennantUpgradeApply_Remove = 63, + + k_EItemActionPaintKitItem_Add = 64, + k_EItemActionPaintKitItem_Remove = 65, + + k_EItemActionUpgradeChallengeCoin_Add = 66, + k_EItemActionUpgradeChallengeCoin_Remove = 67, + + k_EItemActionStickerApply_Add = 68, + k_EItemActionStickerApply_Remove = 69, + k_EItemActionStickerRemove_Add = 70, + k_EItemActionStickerRemove_Remove = 71, + + k_EItemActionGrantQuestReward_Add = 72, + k_EItemActionGrantQuestReward_Remove = 73, + k_EItemActionApplyQuestProgress_Add = 74, + k_EItemActionApplyQuestProgress_Remove = 75, + + k_EItemActionPurchaseUnlockCrate_Add = 76, + k_EItemActionPurchaseUnlockCrate_Remove = 77, + + k_EItemActionSwapStatTrak_Add = 78, + k_EItemActionSwapStatTrak_Remove = 79, + + k_EItemActionPurchaseConsumedAsNonItem = 80, + + k_EItemActionDev_ClientLootListRoll = 90, + + k_EItemActionGiftWrap_Add = 100, + k_EItemActionGiftWrap_Remove = 101, + k_EItemActionGiftDelivery_Add = 102, + k_EItemActionGiftDelivery_Remove = 103, + k_EItemActionGiftUnwrap_Add = 104, + k_EItemActionGiftUnwrap_Remove = 105, + k_EItemActionPackageItem = 106, + k_EItemActionPackageItem_Revoked = 107, + k_EItemActionHandleMapToken = 108, + k_EItemActionCafeOrSchoolItem_Remove = 109, + k_EItemActionVACBanned_Remove = 110, + k_EItemActionUpgradeThirdPartyPromo = 111, + k_EItemActionExpired = 112, + k_EItemActionTradeRollback_Add = 113, + k_EItemActionTradeRollback_Remove = 114, + k_EItemActionCDKeyGrant = 115, + k_EItemActionCDKeyRevoke = 116, + k_EItemActionWeddingRing_Add = 117, + k_EItemActionWeddingRing_Remove = 118, + k_EItemActionWeddingRing_AddPartner = 119, + k_EItemActionEconSetUnowned = 120, + k_EItemActionEconSetOwned = 121, + + k_EItemActionRemoveItemCraftIndex_Remove = 150, + k_EItemActionRemoveItemCraftIndex_Add = 151, + k_EItemActionRemoveItemMakersMark_Remove = 152, + k_EItemActionRemoveItemMakersMark_Add = 153, + + k_EItemActionCollectItem_CollectedItem = 154, + k_EItemActionCollectItem_UpdateCollection = 155, + k_EItemActionCollectItem_RemoveCollection = 156, + k_EItemActionCollectItem_RedeemCollectionReward = 157, + + k_EItemActionPreviewItem_BeginPreviewPeriod = 158, + k_EItemActionPreviewItem_EndPreviewPeriodExpired = 159, + k_EItemActionPreviewItem_EndPreviewPeriodItemBought = 160, + + k_EItemActionRecycling = 161, + k_EItemActionAwardXP = 162, + k_EItemActionTournamentDrop = 163, + k_EItemDiretideReward = 164, + + + k_EItemDiretideEggAddOnModify = 165, + k_EItemDiretideEssenceRemove = 166, + k_EItemDiretideEggRemoveOnModify = 167, + + k_EItemActionUnpackItems = 168, + + k_EItemActionUnlockStyle = 169, + k_EItemActionUnlockStyle_Remove = 170, + + k_EItemActionTutorialDrop = 171, + + k_EItemActionAutographAdd = 172, + k_EItemActionAutographRemove = 173, + + k_EItemActionApplyIntermediateStickerWear = 174, + k_EItemActionTemplateItemGrant = 175, + + k_EItemActionCoinCampaignProgress = 176, + + k_EItemActionMarket_Add = 177, + k_EItemActionMarket_Remove = 178, +}; +extern const char* PchNameFromEItemAction(EItemAction eAction); +extern const char* PchNameFromEItemActionUnsafe(EItemAction eAction); + +extern bool BIsActionCreative(EItemAction); +extern bool BIsActionDestructive(EItemAction); + +enum EItemActionMissingBehavior { kEItemAction_FriendlyNameLookup_ReturnNULLIfMissing, kEItemAction_FriendlyNameLookup_ReturnDummyStringIfMissing }; +extern const char* PchFriendlyNameFromEItemAction(EItemAction eAction, EItemActionMissingBehavior eMissingBehavior); +extern const char* PchLocalizedNameFromEItemAction(EItemAction eAction, CLocalizationProvider& localizationProvider); + + +enum EEconOwnershipAction +{ + k_EEconOwnershipAction_Invalid = 0, + + k_EEconOwnershipAction_TradeBase = 100, + k_EEconOwnershipAction_TradeCommit = 101, + k_EEconOwnershipAction_TradeRollback = 102, +}; + +enum eEconItemFlags_Deprecated +{ + kDeprecated_EconItemFlag_AchievementGrantedItem = 1 << 0, + kDeprecated_EconItemFlag_CannotTrade = 1 << 1, + kDeprecated_EconItemFlag_Purchased = 1 << 2, + kDeprecated_EconItemFlag_CannotBeUsedInCrafting = 1 << 3, + kDeprecated_EconItemFlag_Promotion = 1 << 4, +}; + +enum eEconItemFlags +{ + kEconItemFlag_CannotTrade = 1 << 0, + kEconItemFlag_CannotBeUsedInCrafting = 1 << 1, + kEconItemFlag_CanBeTradedByFreeAccounts = 1 << 2, + kEconItemFlag_NonEconomy = 1 << 3, + +#ifdef CLIENT_DLL +#ifdef TF_CLIENT_DLL + kEconItemFlagClient_ForceBlueTeam = 1 << 5, +#endif + kEconItemFlagClient_StoreItem = 1 << 6, + kEconItemFlagClient_Preview = 1 << 7, +#endif + + kEconItemFlags_CheckFlags_CannotTrade = kEconItemFlag_CannotTrade, + kEconItemFlags_CheckFlags_NotUsableInCrafting = kEconItemFlag_CannotBeUsedInCrafting, + + kEconItemFlags_CheckFlags_AllGCFlags = kEconItemFlags_CheckFlags_CannotTrade | kEconItemFlags_CheckFlags_NotUsableInCrafting, +}; + +enum eEconItemOrigin +{ + kEconItemOrigin_Invalid = -1, + + kEconItemOrigin_Drop = 0, + kEconItemOrigin_Achievement, + kEconItemOrigin_Purchased, + kEconItemOrigin_Traded, + kEconItemOrigin_Crafted, + kEconItemOrigin_StorePromotion, + kEconItemOrigin_Gifted, + kEconItemOrigin_SupportGranted, + kEconItemOrigin_FoundInCrate, + kEconItemOrigin_Earned, + kEconItemOrigin_ThirdPartyPromotion, + kEconItemOrigin_GiftWrapped, + kEconItemOrigin_HalloweenDrop, + kEconItemOrigin_PackageItem, + kEconItemOrigin_Foreign, + kEconItemOrigin_CDKey, + kEconItemOrigin_CollectionReward, + kEconItemOrigin_PreviewItem, + kEconItemOrigin_SteamWorkshopContribution, + kEconItemOrigin_PeriodicScoreReward, + kEconItemOrigin_Recycling, + kEconItemOrigin_TournamentDrop, + kEconItemOrigin_StockItem, + KEconItemOrigin_QuestReward, + KEconItemOrigin_LevelUpReward, + + kEconItemOrigin_Max, +}; +extern const char* PchNameFromeEconItemOrigin(eEconItemOrigin eOrigin); + +typedef uint64 itemid_t; +typedef uint16 item_definition_index_t; +typedef uint16 attrib_definition_index_t; +typedef uint32 attrib_value_t; + +typedef uint32 equip_region_mask_t; +typedef uint8 style_index_t; + +const uint64 INVALID_ITEM_ID = (itemid_t)-1; +const item_definition_index_t INVALID_ITEM_DEF_INDEX = ((item_definition_index_t)-1); +const attrib_definition_index_t INVALID_ATTRIB_DEF_INDEX = ((attrib_definition_index_t)-1); + +#define DEFAULT_NUM_BACKPACK_SLOTS_PER_PAGE 100 +#define DEFAULT_NUM_BACKPACK_SLOTS 1000 +#define DEFAULT_NUM_BACKPACK_SLOTS_FREE_TRIAL_ACCOUNT 100 +#define MAX_NUM_BACKPACK_SLOTS 2000 + +#define MIN_ITEM_LEVEL 0 +#define MAX_ITEM_LEVEL 100 + +#define MAX_ATTRIBUTES_PER_ITEM 32 +#define MAX_ATTRIBUTE_DESCRIPTION_LENGTH ( 256 / sizeof( locchar_t ) ) + +#define MAX_ITEM_NAME_LENGTH 128 +#define MAX_ITEM_DESC_LENGTH 256 +#define MAX_ITEM_LONG_DESC_LENGTH 2048 +#define MAX_ITEM_CUSTOM_NAME_LENGTH 40 +#define MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE ((4 * MAX_ITEM_CUSTOM_NAME_LENGTH) + 1) +#define MAX_ITEM_CUSTOM_DESC_LENGTH 80 +#define MAX_ITEM_CUSTOM_DESC_DATABASE_SIZE ((4 * MAX_ITEM_CUSTOM_DESC_LENGTH) + 1) + +#define MAX_CLAIM_CODE_LENGTH 128 + +#define MAX_ITEMS_BEFORE_YIELD 50 + +#define RGB_INT_RED 12073019 +#define RGB_INT_BLUE 5801378 + +const int k_nCustomImageSize = 256; +const int k_nMaxCustomImageFileSize = k_nCustomImageSize * k_nCustomImageSize * 4 + 4 * 1024; + +typedef int32 entityquality_t; +enum EEconItemQuality +{ + AE_UNDEFINED = -1, + + AE_NORMAL = 0, + AE_GENUINE = 1, + AE_VINTAGE, + AE_UNUSUAL, + AE_UNIQUE, + AE_COMMUNITY, + AE_DEVELOPER, + AE_SELFMADE, + AE_CUSTOMIZED, + AE_STRANGE, + AE_COMPLETED, + AE_HAUNTED, + AE_TOURNAMENT, + AE_FAVORED, + + AE_MAX_TYPES, +}; + + +enum attrib_colors_t +{ + ATTRIB_COL_LEVEL = 0, + ATTRIB_COL_NEUTRAL, + ATTRIB_COL_POSITIVE, + ATTRIB_COL_NEGATIVE, + ATTRIB_COL_ITEMSET_NAME, + ATTRIB_COL_ITEMSET_EQUIPPED, + ATTRIB_COL_ITEMSET_MISSING, + ATTRIB_COL_BUNDLE_ITEM, + ATTRIB_COL_LIMITED_USE, + ATTRIB_COL_ITEM_FLAGS, + ATTRIB_COL_RARITY_DEFAULT, + ATTRIB_COL_RARITY_COMMON, + ATTRIB_COL_RARITY_UNCOMMON, + ATTRIB_COL_RARITY_RARE, + ATTRIB_COL_RARITY_MYTHICAL, + ATTRIB_COL_RARITY_LEGENDARY, + ATTRIB_COL_RARITY_ANCIENT, + ATTRIB_COL_RARITY_IMMORTAL, + ATTRIB_COL_RARITY_ARCANA, + ATTRIB_COL_STRANGE, + ATTRIB_COL_UNUSUAL, + + NUM_ATTRIB_COLORS, +}; + + +#define AE_USE_SCRIPT_VALUE 9999 + +const char* EconQuality_GetQualityString(EEconItemQuality eQuality); +const char* EconQuality_GetColorString(EEconItemQuality eQuality); +const char* EconQuality_GetLocalizationString(EEconItemQuality eQuality); + +int EconQuality_GetRarityScore(EEconItemQuality eQuality); + +int EconRarity_CombinedItemAndPaintRarity(int nItemDefRarity, int nPaintRarity); + +int EconWear_ToIntCategory(float flWear); +float EconWear_FromIntCategory(int nWearCategory); + +int EconMinutes_ToRoundMinHrsCategory(float flMinutes); +float EconMinutes_FromRoundMinHrsCategory(int nRoundMinHrsCategory); + +int EconTintID_ToRoundCategory(uint32 unTintID); +uint32 EconTintID_FromRoundCategory(int nRoundCategory); + +extern attrib_colors_t GetAttribColorIndexForName(const char* pszName); + +extern const char* GetColorNameForAttribColor(attrib_colors_t unAttribColor); +extern const char* GetHexColorForAttribColor(attrib_colors_t unAttribColor); + +entityquality_t GetItemQualityFromString(const char* sQuality); + +enum recipecategories_t +{ + RECIPE_CATEGORY_CRAFTINGITEMS = 0, + RECIPE_CATEGORY_COMMONITEMS, + RECIPE_CATEGORY_RAREITEMS, + RECIPE_CATEGORY_SPECIAL, + + NUM_RECIPE_CATEGORIES +}; +extern const char* g_szRecipeCategoryStrings[NUM_RECIPE_CATEGORIES]; + +enum kill_eater_event_t +{ + kKillEaterEvent_PlayerKill = 0, + kKillEaterEvent_MVPs, + + +}; + +bool EventRequiresVictim(kill_eater_event_t ke_event); + +#define KILL_EATER_RANK_LEVEL_BLOCK_NAME "KillEaterRank" + +int GetKillEaterAttrPairCount(); +const class CEconItemAttributeDefinition* GetKillEaterAttrPair_Score(int i); +const class CEconItemAttributeDefinition* GetKillEaterAttrPair_Type(int i); +bool GetKillEaterAttrPair_IsUserCustomizable(int i); + + +enum unacknowledged_item_inventory_positions_t +{ + UNACK_ITEM_DROPPED = 1, + UNACK_ITEM_CRAFTED, + UNACK_ITEM_TRADED, + UNACK_ITEM_PURCHASED, + UNACK_ITEM_FOUND_IN_CRATE, + UNACK_ITEM_GIFTED, + UNACK_ITEM_SUPPORT, + UNACK_ITEM_PROMOTION, + UNACK_ITEM_EARNED, + UNACK_ITEM_REFUNDED, + UNACK_ITEM_GIFT_WRAPPED, + UNACK_ITEM_FOREIGN, + UNACK_ITEM_COLLECTION_REWARD, + UNACK_ITEM_PREVIEW_ITEM, + UNACK_ITEM_PREVIEW_ITEM_PURCHASED, + UNACK_ITEM_PERIODIC_SCORE_REWARD, + UNACK_ITEM_RECYCLING, + UNACK_ITEM_TOURNAMENT_DROP, + UNACK_ITEM_QUEST_REWARD, + UNACK_ITEM_LEVEL_UP_REWARD, +#ifdef ENABLE_STORE_RENTAL_BACKEND + UNACK_ITEM_RENTAL_PURCHASE, +#endif + + UNACK_NUM_METHODS, +}; + +extern const char* g_pszItemPickupMethodStrings[UNACK_NUM_METHODS]; +extern const char* g_pszItemPickupMethodStringsUnloc[UNACK_NUM_METHODS]; +extern const char* g_pszItemFoundMethodStrings[UNACK_NUM_METHODS]; + +enum +{ + kGCItemSort_NoSort = 0, + + kGCItemSort_SortByName = 1, + kGCItemSort_SortByDefIndex = 2, + kGCItemSort_SortByRarity = 3, + kGCItemSort_SortByType = 4, + kGCItemSort_SortByQuality = 5, + + kGCItemSort_GameSpecificBase = 100, +}; + +enum +{ + kTFGCItemSort_SortByClass = kGCItemSort_GameSpecificBase + 1, + kTFGCItemSort_SortBySlot = kGCItemSort_GameSpecificBase + 2, + kDOTAGCItemSort_SortByHero = kGCItemSort_GameSpecificBase + 3, +}; + +enum +{ + kBackendPosition_Unacked = 1 << 30, + kBackendPosition_Reserved = 1 << 31, + + kBackendPositionMask_Position = 0x0000ffff, + kBackendPositionMask_FormatFlags = (kBackendPosition_Unacked | kBackendPosition_Reserved), +}; + +inline void SetBackpackPosition(uint32* pPosition, uint32 iPackPosition) +{ + (*pPosition) = iPackPosition; + + (*pPosition) &= ~kBackendPosition_Unacked; +} + +inline bool IsUnacknowledged(uint32 iBackendPosition) +{ + return (iBackendPosition == 0 || (iBackendPosition & kBackendPosition_Unacked) != 0); +} + +inline int ExtractBackpackPositionFromBackend(uint32 iBackendPosition) +{ + if (IsUnacknowledged(iBackendPosition)) + return 0; + + return iBackendPosition & kBackendPositionMask_Position; +} + +inline unacknowledged_item_inventory_positions_t GetUnacknowledgedReason(uint32 iBackendPosition) +{ + return (unacknowledged_item_inventory_positions_t)(iBackendPosition &= ~kBackendPositionMask_FormatFlags); +} + +inline uint32 GetUnacknowledgedPositionFor(unacknowledged_item_inventory_positions_t iMethod) +{ + return (iMethod | kBackendPosition_Unacked | kBackendPosition_Reserved); +} + +enum EEconItemPreviewEventIDs +{ + k_EEconItemPreview_Start = 1, + k_EEconItemPreview_Expired = 2, + k_EEconItemPreview_ItemPurchased = 3, +}; + +enum EHoliday +{ + kHoliday_None = 0, + kHoliday_Halloween, + kHoliday_Christmas, + kHoliday_FullMoon, + kHoliday_HalloweenOrFullMoon, + kHoliday_Easter, + + kHolidayCount, +}; + +enum ECartItemType +{ + kCartItem_Purchase, + kCartItem_TryOutUpgrade, + kCartItem_Rental_1Day, + kCartItem_Rental_3Day, + kCartItem_Rental_7Day, +}; + +void GetHexStringFromPaintColor(float flPaint, char* pszRGB); +inline bool IsRentalCartItemType(ECartItemType eCartType) +{ + return eCartType == kCartItem_Rental_1Day + || eCartType == kCartItem_Rental_3Day + || eCartType == kCartItem_Rental_7Day; +} + + +#endif +``` + +`SpyCustom/sdk/econ_item_interface.h`: + +```h +#ifndef ECONITEMINTERFACE_H +#define ECONITEMINTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "game_item_schema.h" + +class CAttribute_String; + +template < typename T > +struct StripConstIfPresent { typedef T ResultType; }; + +template < typename T > struct StripConstIfPresent { typedef T ResultType; }; + +template < typename T, typename U > +struct AreTypesIdentical { enum { kValue = false }; }; + +template < typename T > struct AreTypesIdentical { enum { kValue = true }; }; + +template < typename T> +struct IsValidAttributeValueTypeImpl { enum { kValue = false }; }; + +template < > struct IsValidAttributeValueTypeImpl { enum { kValue = true }; }; +template < > struct IsValidAttributeValueTypeImpl { enum { kValue = true }; }; +template < > struct IsValidAttributeValueTypeImpl { enum { kValue = true }; }; +template < > struct IsValidAttributeValueTypeImpl { enum { kValue = true }; }; + +template < typename T > +struct IsValidAttributeValueType : public IsValidAttributeValueTypeImpl< typename StripConstIfPresent::ResultType > { }; + +class IEconItemAttributeIterator +{ +public: + virtual ~IEconItemAttributeIterator() { } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, attrib_value_t value) = 0; + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, float value) = 0; + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const CAttribute_String& value) = 0; + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const Vector& value) = 0; +}; + +class CEconItemSpecificAttributeIterator : public IEconItemAttributeIterator +{ + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, attrib_value_t value) { return true; } + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const CAttribute_String& value) { return true; } + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const Vector& value) { return true; } +}; + + +class IEconItemUntypedAttributeIterator : public IEconItemAttributeIterator +{ +public: + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, attrib_value_t) OVERRIDE + { + return OnIterateAttributeValueUntyped(pAttrDef); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, float) OVERRIDE + { + return OnIterateAttributeValueUntyped(pAttrDef); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const CAttribute_String&) OVERRIDE + { + return OnIterateAttributeValueUntyped(pAttrDef); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const Vector&) OVERRIDE + { + return OnIterateAttributeValueUntyped(pAttrDef); + } + +private: + virtual bool OnIterateAttributeValueUntyped(const CEconItemAttributeDefinition* pAttrDef) = 0; +}; + +class CAttributeIterator_HasAttribute : public IEconItemUntypedAttributeIterator +{ +public: + CAttributeIterator_HasAttribute(const CEconItemAttributeDefinition* pAttrDef) + : m_pAttrDef(pAttrDef) + , m_bFound(false) + { + Assert(m_pAttrDef); + } + + bool WasFound() const + { + return m_bFound; + } + +private: + bool OnIterateAttributeValueUntyped(const CEconItemAttributeDefinition* pAttrDef) OVERRIDE + { + if (m_pAttrDef == pAttrDef) + { + m_bFound = true; + } + + return !m_bFound; + } + +private: + const CEconItemAttributeDefinition* m_pAttrDef; + bool m_bFound; +}; + +template < typename TActualTypeInMemory, typename TTreatAsThisType = TActualTypeInMemory > +class CAttributeIterator_GetTypedAttributeValue : public IEconItemAttributeIterator +{ +public: + CAttributeIterator_GetTypedAttributeValue(const CEconItemAttributeDefinition* pAttrDef, TTreatAsThisType* outpValue) + : m_pAttrDef(pAttrDef) + , m_outpValue(outpValue) + , m_bFound(false) + { + COMPILE_TIME_ASSERT(IsValidAttributeValueType::kValue); + + COMPILE_TIME_ASSERT(((AreTypesIdentical::kValue && AreTypesIdentical::kValue) || + (AreTypesIdentical::kValue && AreTypesIdentical::kValue) || + AreTypesIdentical::kValue)); + + Assert(m_pAttrDef); + Assert(outpValue); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, attrib_value_t value) OVERRIDE + { + return OnIterateAttributeValueTyped(pAttrDef, value); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, float value) OVERRIDE + { + return OnIterateAttributeValueTyped(pAttrDef, value); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const CAttribute_String& value) OVERRIDE + { + return OnIterateAttributeValueTyped(pAttrDef, value); + } + + virtual bool OnIterateAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const Vector& value) OVERRIDE + { + return OnIterateAttributeValueTyped(pAttrDef, value); + } + + bool WasFound() const + { + return m_bFound; + } + +private: + template < typename TAnyOtherType > + bool OnIterateAttributeValueTyped(const CEconItemAttributeDefinition* pAttrDef, const TAnyOtherType& value) + { + COMPILE_TIME_ASSERT(IsValidAttributeValueType::kValue); + + AssertMsg(m_pAttrDef != pAttrDef, "Incorrect type found for attribute during iteration."); + + return true; + } + + bool OnIterateAttributeValueTyped(const CEconItemAttributeDefinition* pAttrDef, const TActualTypeInMemory& value) + { + if (m_pAttrDef == pAttrDef) + { + m_bFound = true; + CopyAttributeValueToOutput(&value, reinterpret_cast(m_outpValue)); + } + + return !m_bFound; + } + +private: + static void CopyAttributeValueToOutput(const TActualTypeInMemory* pValue, TTreatAsThisType* out_pValue) + { + COMPILE_TIME_ASSERT(sizeof(TActualTypeInMemory) == sizeof(TTreatAsThisType)); + + Assert(pValue); + Assert(out_pValue); + + *out_pValue = *reinterpret_cast(pValue); + } + +private: + const CEconItemAttributeDefinition* m_pAttrDef; + TTreatAsThisType* m_outpValue; + bool m_bFound; +}; + +void CopyStringAttributeValueToCharPointerOutput(const CAttribute_String* pValue, const char** out_pValue); + +template < > +inline void CAttributeIterator_GetTypedAttributeValue::CopyAttributeValueToOutput(const CAttribute_String* pValue, const char** out_pValue) +{ + CopyStringAttributeValueToCharPointerOutput(pValue, out_pValue); +} + +template < typename TAttributeContainerType > +bool FindAttribute(const TAttributeContainerType* pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition* pAttrDef) +{ + if (!pAttrDef) + return false; + + CAttributeIterator_HasAttribute it(pAttrDef); + pSomethingThatHasAnIterateAttributesFunction->IterateAttributes(&it); + return it.WasFound(); +} + +template < typename TActualTypeInMemory, typename TTreatAsThisType, typename TAttributeContainerType > +bool FindAttribute_UnsafeBitwiseCast(const TAttributeContainerType* pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition* pAttrDef, TTreatAsThisType* out_pValue) +{ + if (!pAttrDef) + return false; + + CAttributeIterator_GetTypedAttributeValue it(pAttrDef, out_pValue); + pSomethingThatHasAnIterateAttributesFunction->IterateAttributes(&it); + return it.WasFound(); +} + +template < typename TAttributeContainerType, typename T > +bool FindAttribute(const TAttributeContainerType* pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition* pAttrDef, T* out_pValue) +{ + return FindAttribute_UnsafeBitwiseCast(pSomethingThatHasAnIterateAttributesFunction, pAttrDef, out_pValue); +} + +class IEconItemInterface +{ +public: + virtual ~IEconItemInterface() { } + + bool FindAttribute(const CEconItemAttributeDefinition* pAttrDef) const + { + return ::FindAttribute(this, pAttrDef); + } + + template < typename T > + bool FindAttribute(const CEconItemAttributeDefinition* pAttrDef, T* out_pValue) const + { + return ::FindAttribute(this, pAttrDef, out_pValue); + } + + virtual int GetCustomPaintKitIndex(void) const; + virtual int GetCustomPaintKitSeed(void) const; + virtual float GetCustomPaintKitWear(float flWearDefault = 0.0f) const; + + virtual float GetStickerAttributeBySlotIndexFloat(int nSlotIndex, EStickerAttributeType type, float flDefault) const; + virtual uint32 GetStickerAttributeBySlotIndexInt(int nSlotIndex, EStickerAttributeType type, uint32 uiDefault) const; + + virtual bool IsTradable() const; + virtual bool IsMarketable() const; + virtual bool IsCommodity() const; + virtual bool IsUsableInCrafting() const; + virtual bool IsHiddenFromDropList() const; + + virtual RTime32 GetExpirationDate() const; + + virtual const GameItemDefinition_t* GetItemDefinition() const = 0; + + virtual uint32 GetAccountID() const = 0; + virtual uint64 GetItemID() const = 0; + virtual int32 GetQuality() const = 0; + virtual int32 GetRarity() const = 0; + virtual uint8 GetFlags() const = 0; + virtual eEconItemOrigin GetOrigin() const = 0; + virtual uint16 GetQuantity() const = 0; + virtual uint32 GetItemLevel() const = 0; + virtual bool GetInUse() const = 0; + + virtual const char* GetCustomName() const = 0; + virtual const char* GetCustomDesc() const = 0; + + virtual int GetItemSetIndex() const = 0; + + virtual void IterateAttributes(IEconItemAttributeIterator* pIterator) const = 0; + + bool IsPotentiallyTradable() const; + + RTime32 GetCacheRefreshDateTime() const; + + RTime32 GetTradableAfterDateTime() const; + RTime32 GetUseAfterDateTime() const; +}; + +#endif +``` + +`SpyCustom/sdk/econ_item_schema.h`: + +```h +#ifndef ECONITEMSCHEMA_H +#define ECONITEMSCHEMA_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +#include +#include "steamtypes.h" +#include "keyvalues.h" +#include "utldict.h" +#include "econ_item_constants.h" +#include "UtlStringMap.h" + +#include "item_selection_criteria.h" +#include "bitvec.h" +#include "smartptr.h" +#include "random.h" +#include "imaterialsystem.h" + +#include "expressioncalculator.h" + +#if defined(CLIENT_DLL) || defined(GAME_DLL) +#include "weapon_parse.h" +#include "ivmodelinfo.h" +#include "ivmodelrender.h" +#endif + +class CEconItem; +#ifdef SOURCE1 +#include "gamestringpool.h" +#endif + +class CEconItemSchema; +class CEconSharedObjectCache; +class CSOItemRecipe; +class CStickerList; + +class CTimedItemRewardDefinition; +void Helper_TemporaryBuildCopyOfLootlistForQuestDrop(CTimedItemRewardDefinition& build, const CTimedItemRewardDefinition* pDescReward, char const* szGameModeExclude); + +#define MAX_PAINT_DATA_NAME 128 + +#define MAX_STICKER_DATA_PATH 128 + +#define DEFAULT_EMBROIDER_NCOLORS 10 +#define DEFAULT_EMBROIDER_GAMMA 0.8 + +enum CraftFilter_t +{ + CRAFT_FILTER_TRADEUP = -3, + CRAFT_FILTER_COLLECT = -2, +}; + +enum EQuestVar_t +{ + k_EQuestVar_First, + k_EQuestVar_Last +}; + +class CEconItemRarityDefinition +{ +public: + CEconItemRarityDefinition(void); + CEconItemRarityDefinition(const CEconItemRarityDefinition& that); + CEconItemRarityDefinition& operator=(const CEconItemRarityDefinition& rhs); + + ~CEconItemRarityDefinition(void) { } + + bool BInitFromKV(KeyValues* pKVItem, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + int32 GetDBValue(void) const { return m_nValue; } + const char* GetName(void) const { return !m_strName.IsEmpty() ? m_strName.String() : "unknown"; } + const char* GetLocKey(void) const { return m_strLocKey.String(); } + const char* GetWepLocKey(void) const { return m_strWepLocKey.String(); } + const char* GetLootList(void) const { return m_strLootList.String(); } + const char* GetRecycleLootList(void) const { return m_strRecycleLootList.String(); } + const char* GetDropSound(void) const { return m_strDropSound.String(); } + attrib_colors_t GetAttribColor(void) const { return m_iAttribColor; } + const char* GetNextRarity(void) const { return m_strNextRarity.String(); } + int GetWhiteCount(void) const { return m_iWhiteCount; } + int GetBlackCount(void) const { return m_iBlackCount; } + float GetWeight(void) const { return m_flWeight; } + +private: + + int32 m_nValue; + + attrib_colors_t m_iAttribColor; + + CUtlString m_strName; + + CUtlString m_strLocKey; + CUtlString m_strWepLocKey; + + CUtlString m_strLootList; + CUtlString m_strRecycleLootList; + CUtlString m_strDropSound; + + CUtlString m_strNextRarity; + + int m_iWhiteCount; + int m_iBlackCount; + + float m_flWeight; +}; + +typedef int econ_tag_handle_t; +typedef uint16 equipped_class_t; +typedef uint16 equipped_slot_t; +typedef uint8 equipped_preset_t; + +#define INVALID_ECON_TAG_HANDLE ((econ_tag_handle_t)-1) +#define INVALID_EQUIPPED_SLOT ((equipped_slot_t)-1) +#define INVALID_EQUIPPED_SLOT_BITPACKED 0x3F +#define INVALID_STYLE_INDEX ((style_index_t)-1) +#define INVALID_PRESET_INDEX ((equipped_preset_t)-1) + +union attribute_data_union_t +{ + float asFloat; + uint32 asUint32; + byte* asBlobPointer; +}; + +struct static_attrib_t +{ + static_attrib_t() + { + iDefIndex = 0; + m_value.asBlobPointer = NULL; + m_bForceGCToGenerate = false; + + } + + attrib_definition_index_t iDefIndex; + attribute_data_union_t m_value; + bool m_bForceGCToGenerate; + + bool BInitFromKV_MultiLine(const char* pszContext, KeyValues* pKVAttribute, CUtlVector* pVecErrors); + + bool BInitFromKV_SingleLine(const char* pszContext, KeyValues* pKVAttribute, CUtlVector* pVecErrors); + + const class CEconItemAttributeDefinition* GetAttributeDefinition() const; +}; + +enum EWebResourceStatus +{ + kWebResource_InvalidName, + kWebResource_NotLoaded, + kWebResource_Loading, + kWebResource_Loaded, +}; + +struct WeaponPaintableMaterial_t +{ + char m_szName[MAX_PAINT_DATA_NAME]; + char m_szOriginalMaterialName[MAX_PAINT_DATA_NAME]; + char m_szFolderName[MAX_PAINT_DATA_NAME]; + int m_nViewModelSize; + int m_nWorldModelSize; + float m_flWeaponLength; + float m_flUVScale; + bool m_bBaseTextureOverride; + bool m_bMirrorPattern; +}; + +struct InventoryImageData_t +{ + QAngle* m_pCameraAngles; + Vector* m_pCameraOffset; + float m_cameraFOV; + LightDesc_t* m_pLightDesc[MATERIAL_MAX_LIGHT_COUNT]; + bool m_bOverrideDefaultLight; +}; + +struct StickerData_t +{ + char m_szStickerModelPath[MAX_STICKER_DATA_PATH]; + char m_szStickerMaterialPath[MAX_STICKER_DATA_PATH]; + Vector m_vWorldModelProjectionStart; + Vector m_vWorldModelProjectionEnd; + char m_szStickerBoneParentName[32]; +}; + +class CEconItemQualityDefinition +{ +public: + CEconItemQualityDefinition(void); + CEconItemQualityDefinition(const CEconItemQualityDefinition& that); + CEconItemQualityDefinition& operator=(const CEconItemQualityDefinition& rhs); + + ~CEconItemQualityDefinition(void) { } + + bool BInitFromKV(KeyValues* pKVItem, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + + int32 GetDBValue(void) const { return m_nValue; } + const char* GetName(void) const { return !m_strName.IsEmpty() ? m_strName.Get() : "unknown"; } + uint32 GetWeight(void) const { return m_unWeight; } + bool GetRequiresExplicitMatches(void) const { return m_bExplicitMatchesOnly; } + bool CanSupportSet(void) const { return m_bCanSupportSet; } + const char* GetHexColor(void) const { return !m_strHexColor.IsEmpty() ? m_strHexColor.Get() : "B2B2B2"; } + +private: + + int32 m_nValue; + + CUtlConstString m_strName; + + uint32 m_unWeight; + + bool m_bExplicitMatchesOnly; + + bool m_bCanSupportSet; + + CUtlConstString m_strHexColor; +}; + +class CEconColorDefinition +{ +public: + bool BInitFromKV(KeyValues* pKVColor, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + const char* GetName(void) const { return m_strName.Get(); } + const char* GetColorName(void) const { return m_strColorName.Get(); } + const char* GetHexColor(void) const { return m_strHexColor.Get(); } + +private: + CUtlConstString m_strName; + + CUtlConstString m_strColorName; + + CUtlConstString m_strHexColor; +}; + +class CEconGraffitiTintDefinition +{ +public: + bool BInitFromKV(KeyValues* pKVColor, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + int GetID(void) const { return m_nID; } + const char* GetColorName(void) const { return m_strColorName.Get(); } + const char* GetHexColor(void) const { return m_strHexColor.Get(); } + uint32 GetHexColorRGB(void) const { return m_unHexColorRGB; } + +private: + int m_nID; + + CUtlConstString m_strColorName; + + CUtlConstString m_strHexColor; + uint32 m_unHexColorRGB; +}; + +class CEconMusicDefinition +{ +public: + bool BInitFromKV(KeyValues* pKVMusicDef, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + uint32 GetID(void) const { return nID; } + const char* GetName(void) const { return m_strName.Get(); } + const char* GetNameLocToken(void) const { return m_strNameLocToken.Get(); } + const char* GetDescription(void) const { return m_strLocDescription.Get(); } + const char* GetInventoryImage(void) const { return m_strInventoryImage.Get(); } + const char* GetPedestalDisplayModel(void) const { return m_strPedestalDisplayModel.Get(); } + + const char* GetIconURLSmall() const { return m_sIconURLSmall; } + const char* GetIconURLLarge() const { return m_sIconURLLarge; } + void SetIconURLSmall(const char* szURL) { m_sIconURLSmall = szURL; } + void SetIconURLLarge(const char* szURL) { m_sIconURLLarge = szURL; } + +private: + + int nID; + CUtlConstString m_strName; + CUtlConstString m_strNameLocToken; + CUtlConstString m_strLocDescription; + CUtlConstString m_strPedestalDisplayModel; + CUtlConstString m_strInventoryImage; + + CUtlConstString m_sIconURLSmall; + CUtlConstString m_sIconURLLarge; +}; + + +class CEconQuestDefinition; + +struct quest_event_t +{ + quest_event_t(int nStartDay, const char* pchHHMM, int nDurationInMinutes, const char* strTimeZone, CEconQuestDefinition* pQuestDef, RTime32 start, RTime32 end) : m_strHHMM(pchHHMM), + m_rtEventStart(start), + m_rtEventEnd(end), + m_nStartDay(nStartDay), + m_nDurationInMinutes(nDurationInMinutes), + m_pQuestDef(pQuestDef), + m_strTimeZone(strTimeZone) {} + RTime32 m_rtEventStart; + RTime32 m_rtEventEnd; + int m_nDurationInMinutes; + int m_nStartDay; + CEconQuestDefinition* m_pQuestDef; + CUtlConstString m_strHHMM; + CUtlConstString m_strTimeZone; + + +}; + +typedef CUtlVector QuestEvents_t; +typedef CUtlMap< RTime32, quest_event_t*, int, CDefLess< RTime32 > > QuestEventsSchedule_t; + + +class CEconQuestDefinition +{ +public: + bool BInitFromKV(KeyValues* pKVQuestDef, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + uint32 GetID(void) const { return nID; } + const char* GetName(void) const { return m_strName.Get(); } + + const char* GetGameMode(void) const { return m_strGameMode.Get(); } + const char* GetMapGroup(void) const { return m_strMapGroup.Get(); } + const char* GetMap(void) const { return m_strMap.Get(); } + const char* GetRewardLootList(void) const { return m_strRewardLootList.Get(); } + + const char* GetQuestExpression(void) const { return m_strExpr; } + const char* GetQuestBonusExpression(void) const { return m_strBonusExpr; } + + const uint32 GetDifficulty(void) const { return m_nDifficulty; } + const uint32 GetOperationalPoints(void) const { return m_nOperationalPoints; } + const uint32 GetXPReward(void) const { return m_nXPReward; } + const uint32 GetTargetTeam(void) const { return m_nTargetTeam; } + + const uint32 GetXPBonusPercent(void) const { return m_nXPBonusPercent; } + + const CCopyableUtlVector< uint32 >& GetQuestPoints(void) const { return m_vecQuestPoints; } + + const char* GetQuestConVars(void) const { return m_strQuestConVars.Get(); } + const bool IsAnEvent(void) const { return m_bIsAnEvent; } + + static void TokenizeQuestExpression(const char* szExpression, KeyValues* pKVExpressionTokens); + static bool IsQuestExpressionValid(const char* pszQuestExpr); + static void ZeroOutQuestExpressionVariables(CExpressionCalculator& expQuest); + static void SetQuestExpressionVariable(CExpressionCalculator& expQuest, EQuestVar_t questVar, float flValue); + +private: + + int nID; + CUtlConstString m_strName; + + CUtlConstString m_strMapGroup; + CUtlConstString m_strMap; + CUtlConstString m_strGameMode; + CUtlConstString m_strRewardLootList; + + CUtlConstString m_strExpr; + CUtlConstString m_strBonusExpr; + + CCopyableUtlVector< uint32 > m_vecQuestPoints; + bool m_bIsAnEvent; + + uint32 m_nDifficulty; + uint32 m_nOperationalPoints; + uint32 m_nXPReward; + + uint32 m_nXPBonusPercent; + uint32 m_nTargetTeam; + + CUtlConstString m_strQuestConVars; + +#ifdef CLIENT_DLL + +public: + const char* GetNameLocToken(void) const { return m_strNameLocToken.Get(); } + const char* GetShortNameLocToken(void) const { return m_strShortNameLocToken.Get(); } + const char* GetDescriptionLocToken(void) const { return m_strDescriptionLocToken.Get(); } + const char* GetHudDesscriptionLocToken(void) const { return m_strHudDescriptionLocToken.Get(); } + const char* GetBonusLocToken(void) const { return m_strLocBonus.Get(); } + KeyValues* GetStringTokens(void) const { return m_kvStringTokens; } + const char* GetIcon(void) const { return m_strIcon; } + + static void PopulateQuestStringTokens(CEconQuestDefinition& questDef, KeyValues& kvExpressionTokens, KeyValues& kvStringTokens, bool bBonus = false); + +private: + CUtlConstString m_strNameLocToken; + CUtlConstString m_strShortNameLocToken; + CUtlConstString m_strDescriptionLocToken; + CUtlConstString m_strHudDescriptionLocToken; + KeyValues* m_kvStringTokens; + CUtlConstString m_strLocBonus; + CUtlConstString m_strIcon; + +#endif + +}; + + + +class CEconCampaignDefinition +{ +public: + + class CEconCampaignNodeDefinition + { + public: + +#ifdef CLIENT_DLL + class CEconCampaignNodeStoryBlockDefinition + { + public: + bool BInitFromKV(int nCampaignIndex, int nNodeID, KeyValues* pKVCampaignNodeStoryBlockDef, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + const char* GetContentFile(void) const { return m_strContentFile.Get(); } + const char* GetCharacterName(void) const { return m_strCharacterName.Get(); } + const char* GetStoryBlockExpression(void) const { return m_strExpr.Get(); } + const char* GetDescription(void) const { return m_strDescription.Get(); } + + float EvaluateStoryBlockExpression(CEconItemView* pCampaignCoin) const; + + private: + CUtlConstString m_strContentFile; + CUtlConstString m_strCharacterName; + CUtlConstString m_strExpr; + CUtlConstString m_strDescription; + }; + + const CUtlVector< CEconCampaignNodeStoryBlockDefinition* >& GetStoryBlocks(void) const { return m_vecStoryBlocks; } + + CEconCampaignNodeStoryBlockDefinition* GetBestScoringStoryBlock(CEconItemView* pCampaignCoin) const; + + private: + CUtlVector< CEconCampaignNodeStoryBlockDefinition* > m_vecStoryBlocks; + public: +#endif + + bool BInitFromKV(int nCampaignIndex, KeyValues* pKVCampaignNodeDef, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + const uint32 GetID(void) const { return m_nID; } + const uint32 GetQuestIndex(void) const { return m_nQuestIndex; } + const CUtlVector< uint32 >& GetNextNodes(void) const { return m_vecNextNodes; } + const uint32 GetCampaignID(void) const { return m_CampaignID; } + + + + private: + + uint32 m_nID; + uint32 m_nQuestIndex; + uint32 m_CampaignID; + CUtlVector< uint32 > m_vecNextNodes; + + + + }; + + typedef CUtlMap > CampaignNodeDefinitionsList_t; + + bool BInitFromKV(KeyValues* pKVCampaignDef, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + const uint32 GetID(void) const { return m_nID; } + const char* GetNameLocToken(void) const { return m_strNameLocToken.Get(); } + const char* GetDescription(void) const { return m_strLocDescription.Get(); } + const CampaignNodeDefinitionsList_t& GetStartNodes(void) const { return m_mapStartNodes; } + const CampaignNodeDefinitionsList_t& GetCampaignNodes(void) const { return m_mapCampaignNodes; } + uint32 GetSeasonNumber() const { return m_nSeasonNumber; } + + void GetAccessibleCampaignNodes(const uint32 unCampaignCompletionBitfield, CUtlVector< CEconCampaignNodeDefinition* >& vecAccessibleNodes); + void Helper_RecursiveGetAccessibleCampaignNodes(const uint32 unCampaignCompletionBitfield, const CEconCampaignNodeDefinition* pNode, CUtlVector< CEconCampaignNodeDefinition* >& vecAccessibleNodes); + + +private: + + int m_nID; + CUtlConstString m_strName; + CUtlConstString m_strNameLocToken; + CUtlConstString m_strLocDescription; + CampaignNodeDefinitionsList_t m_mapCampaignNodes; + CampaignNodeDefinitionsList_t m_mapStartNodes; + uint32 m_nSeasonNumber; + +}; + +bool ResolveQuestIdToCampaignAndIndex(uint16 unQuestID, uint32& unCampaignID, uint32& unCamapaignNodeID); +void TokenizeCalculatorExpression(const char* szExpression, KeyValues* pKVExpressionTokens); + +struct item_list_entry_t +{ + item_list_entry_t() + { + memset(this, 0, sizeof(*this)); + m_nPaintKitSeed = -2; + m_flPaintKitWear = -2; + } + + bool operator==(const item_list_entry_t other) const + { + return ( + (m_nItemDef == other.m_nItemDef) && + (m_nPaintKit == other.m_nPaintKit) && + (m_nPaintKitSeed == other.m_nPaintKitSeed) && + (m_flPaintKitWear == other.m_flPaintKitWear) && + (m_nStickerKit == other.m_nStickerKit) && + (m_nMusicKit == other.m_nMusicKit) && + (m_bIsNestedList == other.m_bIsNestedList) && + (m_bIsUnusualList == other.m_bIsUnusualList) && + (m_bAlreadyUsedInRecursiveCreation == m_bAlreadyUsedInRecursiveCreation) + ); + } + + bool InitFromName(const char* pchName); + + int m_nItemDef; + + int m_nPaintKit; + int m_nPaintKitSeed; + float m_flPaintKitWear; + + uint32 m_nStickerKit; + + uint32 m_nMusicKit; + + bool m_bIsNestedList; + bool m_bIsUnusualList; + mutable bool m_bAlreadyUsedInRecursiveCreation; +}; + +class CEconItemSetDefinition : public IEconItemSetDefinition +{ +public: + CEconItemSetDefinition(void); + CEconItemSetDefinition(const CEconItemSetDefinition& that); + CEconItemSetDefinition& operator=(const CEconItemSetDefinition& rhs); + + ~CEconItemSetDefinition(void) {} + + virtual bool BInitFromKV(KeyValues* pKVItemSet, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + virtual const char* GetName(void) const { return m_pszName; } + virtual const char* GetLocKey(void) const { return m_pszLocalizedName; } + virtual const char* GetUnlocalizedName(void) const { return m_pszUnlocalizedName; } + virtual int GetBundle(void) const { return m_iBundleItemDef; } + virtual int GetItemCount(void) const { return m_ItemEntries.Count(); } + virtual int GetItemDef(int iIndex) const { return m_ItemEntries[iIndex].m_nItemDef; } + virtual int GetItemPaintKit(int iIndex) const { return m_ItemEntries[iIndex].m_nPaintKit; } + virtual int GetItemRarity(int iIndex) const; + virtual int GetHighestItemRarityValue(void) const; + virtual item_definition_index_t GetCraftReward(void) const { return m_nCraftReward; } + +public: + + const char* m_pszName; + const char* m_pszLocalizedName; + const char* m_pszUnlocalizedName; + const char* m_pszLocalizedDescription; + CUtlVector m_ItemEntries; + int m_iBundleItemDef; + bool m_bIsCollection; + bool m_bIsHiddenSet; + item_definition_index_t m_nCraftReward; + + struct itemset_attrib_t + { + int m_iAttribDefIndex; + attrib_value_t m_valValue; + }; + CUtlVector m_iAttributes; +}; + +struct favored_lootlist_t +{ + favored_lootlist_t() + { + iHeroID = 0; + iBonus = 0; + } + + favored_lootlist_t& operator=(const favored_lootlist_t& rhs) + { + iHeroID = rhs.iHeroID; + iBonus = rhs.iBonus; + return *this; + } + + uint iHeroID; + uint iBonus; +}; + +class CEconLootListDefinition : public IEconLootListDefinition +{ +public: + CEconLootListDefinition(void); + CEconLootListDefinition(const CEconLootListDefinition& that); + CEconLootListDefinition& operator=(const CEconLootListDefinition& rhs); + + ~CEconLootListDefinition(void); + + bool AddRandomAtrributes(KeyValues* pRandomAttributesKV, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + bool BInitFromKV(KeyValues* pKVLootList, KeyValues* pKVRandomAttributeTemplates, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL, bool bServerList = false); + virtual const char* GetName() const { return m_pszName; } + const CUtlVector& GetLootListContents() const { return m_ItemEntries; } + virtual float GetWeight(int iIdx) const { return m_flWeights[iIdx]; } + virtual KeyValues* GenerateKeyValues() const; + virtual bool IsServerList() const { return m_bServerList; } + virtual bool HasUnusualLoot() const; + virtual int GetAdditionalDropCount(void) const { return m_AdditionalDrops.Count(); } + virtual bool GetAdditionalDrop(int iIndex, CUtlString& strLootList, float& flChance) const; + + virtual int GetRandomAttributeGroupCount(void) const { return m_RandomAttribs.Count(); } + virtual bool GetRandomAttributeGroup(int iIndex, float& flChance, float& flTotalWeight) const; + virtual int GetRandomAttributeCount(int iGroup) const; + virtual bool GetRandomAttribute(int iGroup, int iIndex, float& flWeight, int& iValue, int& iDefIndex) const; + + virtual void PurgeItems(void); + + bool GetPublicListContents() const + { + return true; + } + + struct loot_list_additional_drop_t + { + float m_fChance; + bool m_bPremiumOnly; + const char* m_pszLootListDefName; + }; + CUtlVector m_AdditionalDrops; + +protected: + const char* m_pszName; + + CUtlVector m_ItemEntries; + uint32 m_unHeroID; + + bool m_bPublicListContents; +#ifndef GC_DLL + bool m_bWillProduceStatTrak; +#endif + float m_flTotalWeight; + CUtlVector m_flWeights; + + struct lootlist_attrib_t + { + static_attrib_t m_staticAttrib; + float m_flWeight; + float m_flRangeMin; + float m_flRangeMax; + + CCopyableUtlVector< uint32 > m_vecValues; + + bool BInitFromKV(const char* pszContext, KeyValues* pKVKey, CEconItemSchema& pschema, CUtlVector* pVecErrors); + }; + + struct random_attrib_t + { + float m_flChanceOfRandomAttribute; + float m_flTotalAttributeWeight; + bool m_bPickAllAttributes; + CUtlVector m_RandomAttributes; + }; + + CUtlVector m_RandomAttribs; + bool m_bServerList; +}; + +class CEconCraftingRecipeDefinition +{ +public: + CEconCraftingRecipeDefinition(void); + virtual ~CEconCraftingRecipeDefinition(void) { } + + bool BInitFromKV(KeyValues* pKVItem, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + bool BInitFromSet(const IEconItemSetDefinition* pSet, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + virtual void CopyPolymorphic(const CEconCraftingRecipeDefinition* pSourceDef) { *this = *pSourceDef; } + + void SetDefinitionIndex(uint32 iIndex) { m_nDefIndex = iIndex; } + int32 GetDefinitionIndex(void) const { return m_nDefIndex; } + const char* GetName(void) const { return !m_strName.IsEmpty() ? m_strName.String() : "unknown"; } + const char* GetName_A(void) const { return !m_strN_A.IsEmpty() ? m_strN_A.String() : "unknown"; } + const char* GetDescInputs(void) const { return !m_strDescInputs.IsEmpty() ? m_strDescInputs.String() : "unknown"; } + const char* GetDescOutputs(void) const { return !m_strDescOutputs.IsEmpty() ? m_strDescOutputs.String() : "unknown"; } + + const char* GetDescI_A(void) const { return !m_strDI_A.IsEmpty() ? m_strDI_A.String() : "unknown"; } + const char* GetDescI_B(void) const { return !m_strDI_B.IsEmpty() ? m_strDI_B.String() : "unknown"; } + const char* GetDescI_C(void) const { return !m_strDI_C.IsEmpty() ? m_strDI_C.String() : "unknown"; } + const char* GetDescO_A(void) const { return !m_strDO_A.IsEmpty() ? m_strDO_A.String() : "unknown"; } + const char* GetDescO_B(void) const { return !m_strDO_B.IsEmpty() ? m_strDO_B.String() : "unknown"; } + const char* GetDescO_C(void) const { return !m_strDO_C.IsEmpty() ? m_strDO_C.String() : "unknown"; } + + const wchar_t* GetLocName(void) const { return m_wszName; } + const wchar_t* GetLocDescription(void) const { return m_wszDesc; } + + void SetDisabled(bool bDisabled) { m_bDisabled = bDisabled; } + bool IsDisabled(void) const { return m_bDisabled; } + bool RequiresAllSameClass(void) { return m_bRequiresAllSameClass; } + bool RequiresAllSameSlot(void) { return m_bRequiresAllSameSlot; } + bool IsAlwaysKnown(void) const { return m_bAlwaysKnown; } + bool IsPremiumAccountOnly(void) const { return m_bPremiumAccountOnly; } + recipecategories_t GetCategory(void) const { return m_iCategory; } + int GetFilter(void) const { return m_iFilter; } + void SetFilter(int nFilter) { m_iFilter = nFilter; } + int GetTotalInputItemsRequired(void) const; + int GetTotalOutputItems(void) const { return m_OutputItemsCriteria.Count(); } + + virtual bool ItemListMatchesInputs(const CUtlVector< CEconItem* >& vecCraftingItems, bool bAllowPartialMatch = false) const; + + const CUtlVector* GetInputItems(void) const { return &m_InputItemsCriteria; } + const CUtlVector& GetInputItemDupeCounts(void) const { return m_InputItemDupeCounts; } + const CUtlVector& GetOutputItems(void) const { return m_OutputItemsCriteria; } + + bool BSerializeToMsg(CSOItemRecipe& msg) const; + bool BDeserializeFromMsg(const CSOItemRecipe& msg); + +private: + void GenerateLocStrings(void); + +protected: + int32 m_nDefIndex; + + CUtlString m_strName; + CUtlString m_strN_A; + CUtlString m_strDescInputs; + CUtlString m_strDescOutputs; + CUtlString m_strDI_A; + CUtlString m_strDI_B; + CUtlString m_strDI_C; + CUtlString m_strDO_A; + CUtlString m_strDO_B; + CUtlString m_strDO_C; + + wchar_t m_wszName[64]; + wchar_t m_wszDesc[512]; + + bool m_bDisabled; + bool m_bRequiresAllSameClass; + bool m_bRequiresAllSameSlot; + int m_iCacheClassUsageForOutputFromItem; + int m_iCacheSlotUsageForOutputFromItem; + int m_iCacheSetForOutputFromItem; + bool m_bAlwaysKnown; + bool m_bPremiumAccountOnly; + recipecategories_t m_iCategory; + int m_iFilter; + + CUtlVector m_InputItemsCriteria; + CUtlVector m_InputItemDupeCounts; + + CUtlVector m_OutputItemsCriteria; +}; + +enum +{ + ATTDESCFORM_VALUE_IS_PERCENTAGE, + ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE, + ATTDESCFORM_VALUE_IS_ADDITIVE, + ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE, + ATTDESCFORM_VALUE_IS_OR, + ATTDESCFORM_VALUE_IS_DATE, + ATTDESCFORM_VALUE_IS_ACCOUNT_ID, + ATTDESCFORM_VALUE_IS_PARTICLE_INDEX, + ATTDESCFORM_VALUE_IS_ITEM_DEF, + ATTDESCFORM_VALUE_IS_COLOR, + ATTDESCFORM_VALUE_IS_GAME_TIME, + ATTDESCFORM_VALUE_IS_MINS_AS_HOURS, + ATTDESCFORM_VALUE_IS_REPLACE, +}; + +enum attrib_effect_types_t +{ + ATTRIB_EFFECT_NEUTRAL = 0, + ATTRIB_EFFECT_POSITIVE, + ATTRIB_EFFECT_NEGATIVE, + + NUM_EFFECT_TYPES, +}; + +enum EAssetClassAttrExportRule_t +{ + k_EAssetClassAttrExportRule_Default = 0, + k_EAssetClassAttrExportRule_Bucketed = (1 << 0), + k_EAssetClassAttrExportRule_Skip = (1 << 1), + k_EAssetClassAttrExportRule_GCOnly = (1 << 2), +}; + +class CEconItemAttributeDefinition : public IEconItemAttributeDefinition +{ +public: + CEconItemAttributeDefinition(void); + CEconItemAttributeDefinition(const CEconItemAttributeDefinition& that); + CEconItemAttributeDefinition& operator=(const CEconItemAttributeDefinition& rhs); + + ~CEconItemAttributeDefinition(void); + + bool BInitFromKV(KeyValues* pKVAttribute, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + virtual attrib_definition_index_t GetDefinitionIndex(void) const { return m_nDefIndex; } + virtual const char* GetDefinitionName(void) const { return m_pszDefinitionName; } + + virtual KeyValues* GetRawDefinition(void) const { return m_pKVAttribute; } + + bool IsHidden(void) const { return m_bHidden; } + bool BForceWebSchemaOutput(void) const { return m_bWebSchemaOutputForced; } + bool IsStoredAsInteger(void) const { return m_bStoredAsInteger; } + bool IsStoredAsFloat(void) const { return !m_bStoredAsInteger; } + bool IsInstanceData() const { return m_bInstanceData; } + EAssetClassAttrExportRule_t GetAssetClassAttrExportRule() const { return m_eAssetClassAttrExportRule; } + uint32 GetAssetClassBucket() const { return m_unAssetClassBucket; } + int GetDescriptionFormat(void) const { return m_iDescriptionFormat; } + int GetScore(void) const { return m_iScore; } + virtual const char* GetDescriptionString(void) const { return m_pszDescriptionString; } + const char* GetArmoryDescString(void) const { return m_pszArmoryDesc; } + virtual const char* GetAttributeClass(void) const { return m_pszAttributeClass; } + attrib_effect_types_t GetEffectType(void) const { return m_iEffectType; } + + const class ISchemaAttributeType* GetAttributeType(void) const { return m_pAttrType; } + +#ifndef GC_DLL + void ClearStringCache(void) const { m_iszAttributeClass = NULL_STRING; } + string_t GetCachedClass(void) const + { + if (m_iszAttributeClass == NULL_STRING && m_pszAttributeClass) + { + m_iszAttributeClass = AllocPooledString(m_pszAttributeClass); + } + return m_iszAttributeClass; + } +#endif + +private: + KeyValues* m_pKVAttribute; + + attrib_definition_index_t m_nDefIndex; + + const class ISchemaAttributeType* m_pAttrType; + + bool m_bHidden; + + bool m_bWebSchemaOutputForced; + + bool m_bStoredAsInteger; + + bool m_bInstanceData; + EAssetClassAttrExportRule_t m_eAssetClassAttrExportRule; + uint32 m_unAssetClassBucket; + + attrib_effect_types_t m_iEffectType; + + int m_iDescriptionFormat; + const char* m_pszDescriptionString; + + const char* m_pszDescriptionTag; + + const char* m_pszArmoryDesc; + int m_iScore; + + const char* m_pszDefinitionName; + + const char* m_pszAttributeClass; + +#if defined(CLIENT_DLL) || defined(GAME_DLL) || defined(GC) + mutable string_t m_iszAttributeClass; +#endif + +}; + +class CEconSoundMaterialDefinition +{ +public: + CEconSoundMaterialDefinition(void); + CEconSoundMaterialDefinition(const CEconSoundMaterialDefinition& that); + CEconSoundMaterialDefinition& operator=(const CEconSoundMaterialDefinition& rhs); + + ~CEconSoundMaterialDefinition(void) { } + + bool BInitFromKV(KeyValues* pKVItem, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + int32 GetID(void) const { return m_nID; } + const char* GetName(void) const { return !m_strName.IsEmpty() ? m_strName.String() : "unknown"; } + + const char* GetStartDragSound(void) const { return m_strStartDragSound.Get(); } + const char* GetEndDragSound(void) const { return m_strEndDragSound.Get(); } + const char* GetEquipSound(void) const { return m_strEquipSound.Get(); } + +private: + + int32 m_nID; + + CUtlString m_strName; + + CUtlString m_strStartDragSound; + CUtlString m_strEndDragSound; + + CUtlString m_strEquipSound; +}; + + +#define MAX_VISUALS_CUSTOM_SOUNDS 10 + + +#if defined(CLIENT_DLL) || defined(GAME_DLL) +enum +{ + kAttachedModelDisplayFlag_WorldModel = 0x01, + kAttachedModelDisplayFlag_ViewModel = 0x02, + + kAttachedModelDisplayFlag_MaskAll = kAttachedModelDisplayFlag_WorldModel | kAttachedModelDisplayFlag_ViewModel, +}; + +struct attachedmodel_t +{ + const char* m_pszModelName; + int m_iModelDisplayFlags; +}; + +struct attachedparticle_t +{ + int m_iParticleIndex; + int m_nStyle; +}; + +enum wearableanimplayback_t +{ + WAP_ON_SPAWN, + WAP_START_BUILDING, + WAP_STOP_BUILDING, + + NUM_WAP_TYPES, +}; + +struct animation_on_wearable_t +{ + int iActivity; + const char* pszActivity; + wearableanimplayback_t iPlayback; + const char* pszReplacement; + int iReplacement; + const char* pszSequence; + const char* pszRequiredItem; + const char* pszScene; + float flFrequency; +}; + +struct sound_on_wearable_t +{ + const char* pszSound; + const char* pszReplacement; +}; + +struct particle_on_wearable_t +{ + const char* pszParticle; + const char* pszReplacement; + bool bFlyingCourierEffect; +}; + +struct particlesnapshot_on_wearable_t +{ + const char* pszParticleSnapshot; + const char* pszReplacement; +}; + +struct particle_control_point_on_wearable_t +{ + const char* pszParticle; + int nParticleControlPoint; + Vector vecCPValue; +}; + +struct codecontrolledbodygroupdata_t +{ + const char* pFuncName; + void* pFunc; +}; + +#endif + +struct style_unlock_info +{ + const char* pszItemName; + int iPrice; + int iStylePreReq; + const char* pszAttrib; + uint32 iAttribValue; + + bool IsLockable() const + { + return pszItemName || pszAttrib; + } + + bool HasUnlockPrice() const + { + return iPrice && pszItemName; + } + + bool HasUnlockAttrib() const + { + return iAttribValue && pszAttrib; + } +}; + +class CEconStyleInfo +{ +public: + CEconStyleInfo() + { + m_iIndex = 0; + m_iSkin = 0; + m_iIcon = 0; + m_pszName = NULL; + m_pszBasePlayerModel = NULL; + m_UnlockInfo.pszItemName = NULL; + m_UnlockInfo.iPrice = 0; + m_UnlockInfo.iStylePreReq = 0; + m_UnlockInfo.pszAttrib = NULL; + m_UnlockInfo.iAttribValue = 0; + } + + virtual ~CEconStyleInfo() + { + } + + virtual void BInitFromKV(KeyValues* pKVItem, CEconItemSchema& pschema, CUtlVector* pVecErrors); + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + virtual void GeneratePrecacheModelStringsForStyle(CUtlVector* out_pVecModelStrings) const; +#endif + + int GetSkin() const + { + return m_iSkin; + } + + int GetIndex() const { return m_iIndex; } + const char* GetName() const { return m_pszName; } + const char* GetBasePlayerDisplayModel() const { return m_pszBasePlayerModel; } + const CUtlVector& GetAdditionalHideBodygroups() const { return m_vecAdditionalHideBodygroups; } + int GetIcon() const { return m_iIcon; } + const style_unlock_info* GetUnlockInfo() const { return &m_UnlockInfo; } + +protected: + int m_iIndex; + int m_iSkin; + int m_iIcon; + const char* m_pszName; + const char* m_pszBasePlayerModel; + CUtlVector m_vecAdditionalHideBodygroups; + style_unlock_info m_UnlockInfo; +}; + +struct courier_t +{ + const char* m_pszModelName; + int m_iTeam; +}; + +struct announcer_preview_t +{ + CUtlString m_strFileName; + CUtlString m_strCaption; +}; + +struct ability_icon_replacement_t +{ + CUtlString m_strAbilityName; + CUtlString m_strReplacement; +}; + +enum EAssetModifier +{ + AM_Invalid = -1, + AM_Activity, + AM_Announcer, + AM_AnnouncerPreview, + AM_HudSkin, + AM_AbilityName, + AM_Sound, + AM_Speech, + AM_Particle, + AM_ParticleSnapshot, + AM_ParticleControlPoint, + AM_EntityModel, + AM_ViewModel, + AM_EntityScale, + AM_Icon, + AM_AbilityIcon, + AM_Courier, + AM_CourierFlying, + AM_HeroModelChange, + AM_MAX +}; + +struct AssetModifier +{ + EAssetModifier m_Type; + CUtlString m_strAsset; + CUtlString m_strModifier; + float m_flModifier; + float m_flFrequency; + int m_iStyle; +}; + +struct AssetInfo +{ + AssetInfo() + { +#if defined(CLIENT_DLL) || defined(GAME_DLL) + iHideParentBodyGroup = -1; + + m_ModifiedBodyGroupNames.SetLessFunc(StringLessThan); + m_CodeControlledBodyGroupNames.SetLessFunc(StringLessThan); + + iSkin = 0; + bUsePerClassBodygroups = false; + m_pszMaterialOverride = NULL; + m_pszParticleEffect = NULL; + m_pszParticleSnapshot = NULL; + for (int i = 0; i < MAX_VISUALS_CUSTOM_SOUNDS; i++) + { + m_pszCustomSounds[i] = NULL; + } + + for (int i = 0; i < NUM_SHOOT_SOUND_TYPES; i++) + { + m_pszWeaponSoundReplacements[i] = NULL; + } + + m_iViewModelBodyGroupOverride = -1; + m_iViewModelBodyGroupStateOverride = -1; + m_iWorldModelBodyGroupOverride = -1; + m_iWorldModelBodyGroupStateOverride = -1; + + m_pszSpeechConcept = NULL; + m_pszChatMessage = NULL; + m_pszAnnouncerName.Clear(); + m_pszAnnouncerResource.Clear(); + m_pszEntityModel = NULL; + m_pszViewModel = NULL; + m_pszEntityClass = NULL; + m_flScaleSize = 1.f; + m_pszScaleClass = NULL; + m_bSkipModelCombine = false; + + m_pszPrimaryAmmo = NULL; + m_pszWeaponTypeString = NULL; + m_pszAddonLocation = NULL; + m_pszEjectBrassEffect = NULL; + m_pszTracerEffect = NULL; + m_pszMuzzleFlashEffect1stPerson = NULL; + m_pszMuzzleFlashEffect1stPersonAlt = NULL; + m_pszMuzzleFlashEffect3rdPerson = NULL; + m_pszMuzzleFlashEffect3rdPersonAlt = NULL; + m_pszHeatEffect = NULL; + m_pszPlayerAnimationExtension = NULL; + + m_pszOriginalIcon = NULL; + m_pszNewIcon = NULL; + + m_mapAssetModifiers.SetLessFunc(DefLessFunc(int)); + + +#endif + } + + ~AssetInfo() + { + m_Styles.PurgeAndDeleteElements(); + } + + void AddAssetModifier(AssetModifier* newMod); + CUtlVector* GetAssetModifiers(EAssetModifier type); + const char* GetModifierByAsset(EAssetModifier type, const char* pszAsset, int iStyle = -1); + const char* GetAssetByModifier(EAssetModifier type, const char* pszModifier, int iStyle = -1); + + CUtlMap< int, CUtlVector* > m_mapAssetModifiers; + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + int iHideParentBodyGroup; + CUtlMap m_ModifiedBodyGroupNames; + CUtlMap m_CodeControlledBodyGroupNames; + int iSkin; + bool bUsePerClassBodygroups; + CUtlVector m_AttachedModels; + CUtlVector m_AttachedParticles; + CUtlVector m_Animations; + CUtlVector m_Sounds; + CUtlVector m_Particles; + CUtlVector m_ParticleSnapshots; + CUtlVector m_ParticleControlPoints; + const char* m_pszCustomSounds[MAX_VISUALS_CUSTOM_SOUNDS]; + const char* m_pszMaterialOverride; + const char* m_pszMuzzleFlash; + const char* m_pszTracerEffect; + const char* m_pszParticleEffect; + const char* m_pszParticleSnapshot; + const char* m_pszWeaponSoundReplacements[NUM_SHOOT_SOUND_TYPES]; + + const char* m_pszPrimaryAmmo; + const char* m_pszWeaponTypeString; + const char* m_pszAddonLocation; + const char* m_pszEjectBrassEffect; + const char* m_pszMuzzleFlashEffect1stPerson; + const char* m_pszMuzzleFlashEffect1stPersonAlt; + const char* m_pszMuzzleFlashEffect3rdPerson; + const char* m_pszMuzzleFlashEffect3rdPersonAlt; + const char* m_pszHeatEffect; + const char* m_pszPlayerAnimationExtension; + + int m_iViewModelBodyGroupOverride; + int m_iViewModelBodyGroupStateOverride; + int m_iWorldModelBodyGroupOverride; + int m_iWorldModelBodyGroupStateOverride; + bool m_bSkipModelCombine; + CUtlVector m_vecAnimationModifiers; + + const char* m_pszSpeechConcept; + const char* m_pszChatMessage; + + CUtlString m_pszAnnouncerName; + CUtlString m_pszAnnouncerResource; + CUtlVector< announcer_preview_t > m_vecAnnouncerPreview; + + CUtlString m_pszHudSkinName; + + CUtlString m_pszAbilityName; + + const char* m_pszEntityModel; + const char* m_pszViewModel; + const char* m_pszEntityClass; + + float m_flScaleSize; + const char* m_pszScaleClass; + + const char* m_pszOriginalIcon; + const char* m_pszNewIcon; + + CUtlVector< ability_icon_replacement_t > m_vecAbilityIconReplacements; + + +#endif + + CUtlVector m_Styles; +}; + +enum item_capabilities_t +{ + ITEM_CAP_NONE = 0, + ITEM_CAP_PAINTABLE = 1 << 0, + ITEM_CAP_NAMEABLE = 1 << 1, + ITEM_CAP_DECODABLE = 1 << 2, + ITEM_CAP_CAN_DELETE = 1 << 3, + ITEM_CAP_CAN_CUSTOMIZE_TEXTURE = 1 << 4, + ITEM_CAP_USABLE = 1 << 5, + ITEM_CAP_USABLE_GC = 1 << 6, + ITEM_CAP_CAN_GIFT_WRAP = 1 << 7, + ITEM_CAP_USABLE_OUT_OF_GAME = 1 << 8, + ITEM_CAP_CAN_COLLECT = 1 << 9, + ITEM_CAP_CAN_CRAFT_COUNT = 1 << 10, + ITEM_CAP_CAN_CRAFT_MARK = 1 << 11, + ITEM_CAP_PAINTABLE_TEAM_COLORS = 1 << 12, + ITEM_CAP_CAN_BE_RESTORED = 1 << 13, + ITEM_CAP_CAN_USE_STRANGE_PARTS = 1 << 14, + ITEM_CAP_PAINTABLE_UNUSUAL = 1 << 15, + ITEM_CAP_CAN_INCREMENT = 1 << 16, + ITEM_CAP_USES_ESSENCE = 1 << 17, + ITEM_CAP_AUTOGRAPH = 1 << 18, + ITEM_CAP_RECIPE = 1 << 19, + ITEM_CAP_CAN_STICKER = 1 << 20, + ITEM_CAP_STATTRACK_SWAP = 1 << 21, + NUM_ITEM_CAPS = 22, +}; + +enum { ITEM_CAP_DEFAULT = ITEM_CAP_NONE }; +enum { ITEM_CAP_TOOL_DEFAULT = ITEM_CAP_NONE }; + +struct bundleinfo_t +{ + CUtlVector vecItemEntries; +}; + +#ifdef CLIENT_DLL +namespace vgui +{ + class Panel; +} +#endif + +class IEconConsumable +{ + +}; + +class IEconItemInterface; + +class IEconTool +{ + friend class CEconSharedToolSupport; + +public: + IEconTool(const char* pszTypeName, const char* pszUseString, const char* pszUsageRestriction, item_capabilities_t unCapabilities, KeyValues* pUsageKV) + : m_pszTypeName(pszTypeName) + , m_pszUseString(pszUseString) + , m_pszUsageRestriction(pszUsageRestriction) + , m_unCapabilities(unCapabilities) + { + if (pUsageKV) + { + KeyValues* pBonusItemDefs = pUsageKV->FindKey("bonus_itemdefs"); + if (pBonusItemDefs) + { + FOR_EACH_SUBKEY(pBonusItemDefs, pBonusItemDef) + { + m_vecBonusItemDef.AddToTail(atoi(pBonusItemDef->GetName())); + } + } + } + } + + virtual ~IEconTool() { } + + const char* GetUsageRestriction() const { return m_pszUsageRestriction; } + item_capabilities_t GetCapabilities() const { return m_unCapabilities; } + + virtual bool CanApplyTo(const IEconItemInterface* pTool, const IEconItemInterface* pToolSubject) const { Assert(pTool); Assert(pToolSubject); return true; } + virtual bool ShouldDisplayQuantity(const IEconItemInterface* pTool) const; + virtual bool RequiresToolEscrowPeriod() const { return false; } + + virtual bool IsValid() const { return true; } + + const char* GetTypeName() const { return m_pszTypeName; } + const char* GetUseString() const { return m_pszUseString; } + + int GetBonusItemDefCount(void) const { return m_vecBonusItemDef.Count(); } + int GetBonusItemDef(int i) const { return m_vecBonusItemDef[i]; } + + virtual IEconConsumable* CreateEconConsumable() const + { + Assert(!"IEconTool::CreateEconConsumable(): unimplemented call!"); + return NULL; + } + +#ifdef CLIENT_DLL + virtual bool ShouldShowContainedItemPanel(const IEconItemInterface* pItem) const { Assert(!"IEconTool::ShouldShowContainedItemPanel(): we don't expect this to be called on anything besides gifts!"); return false; } + virtual const char* GetUseCommandLocalizationToken(const IEconItemInterface* pItem, const char* pszDefault = "#ApplyOnItem") const; + + virtual void OnClientUseConsumable(class C_EconItemView* pItem) const + { + Assert(!"IEconTool::OnClientUseConsumable(): unimplemented call!"); + } + + virtual void OnClientApplyTool(class C_EconItemView* pTool, class C_EconItemView* pSubject) const + { + Assert(!"IEconTool::OnClientApplyTool(): unimplemented call!"); + } + virtual void OnClientApplyCommit(class C_EconItemView* pTool, class C_EconItemView* pSubject) const + { + Assert(!"IEconTool::OnClientApplyCommit(): unimplemented call!"); + } +#endif + +private: + const char* m_pszTypeName; + const char* m_pszUseString; + const char* m_pszUsageRestriction; + item_capabilities_t m_unCapabilities; + CUtlVector m_vecBonusItemDef; +}; + +enum EItemType +{ + k_EItemTypeNone, + k_EItemTypeCoupon, + k_EItemTypeCampaign, + k_EItemTypeSelfOpeningPurchase, + k_EItemTypeOperationCoin, + k_EItemTypePrestigeCoin, + k_EItemTypeTool, +}; +const char* PchNameFromEItemType(EItemType eType); + +enum EItemSlot +{ + k_EItemSlotNone, + k_EItemSlotMelee, + k_EItemSlotSecondary, + k_EItemSlotSMG, + k_EItemSlotRifle, + k_EItemSlotHeavy, + k_EItemSlotFlair, + k_EItemSlotMusicKit, +}; +const char* PchNameFromEItemSlot(EItemSlot eSlot); +EItemSlot EItemSlotFromName(const char* pchName); + +class CEconItemDefinition : public IEconItemDefinition +{ +public: + CEconItemDefinition(void); + virtual ~CEconItemDefinition(void); + + void PurgeStaticAttributes(void); + +public: + virtual bool BInitFromKV(KeyValues* pKVItem, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); +#if defined(CLIENT_DLL) || defined(GAME_DLL) + virtual bool BInitFromTestItemKVs(int iNewDefIndex, KeyValues* pKVItem, CEconItemSchema& pschema); + virtual void GeneratePrecacheModelStrings(bool bDynamicLoad, CUtlVector* out_pVecModelStrings) const; + virtual void GeneratePrecacheSoundStrings(CUtlVector* out_pVecSoundStrings) const; + virtual void GeneratePrecacheEffectStrings(CUtlVector* out_pVecEffectStrings) const; +#endif + virtual void CopyPolymorphic(const CEconItemDefinition* pSourceDef) { *this = *pSourceDef; } + + bool BInitItemMappings(CEconItemSchema& pschema, CUtlVector* pVecErrors); + + virtual void BInitVisualBlockFromKV(KeyValues* pKVItem, IEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + void BInitStylesBlockFromKV(KeyValues* pKVStyles, CEconItemSchema& pschema, AssetInfo* pAssetInfo, CUtlVector* pVecErrors); + bool BInitAlternateIconsFromKV(KeyValues* pKVAlternateIcons, CEconItemSchema& pschema, AssetInfo* pAssetInfo, CUtlVector* pVecErrors); + + virtual item_definition_index_t GetDefinitionIndex(void) const { return m_nDefIndex; } + const CUtlVector& GetAssociatedItemsDefIndexes() const { return m_nAssociatedItemsDefIndexes; } + virtual const char* GetPrefabName(void) const { return m_szPrefab; } + bool BEnabled(void) const { return m_bEnabled; } + bool BLoadOnDemand(void) const { return m_bLoadOnDemand; } + bool BHasBeenLoaded(void) const { return m_bHasBeenLoaded; } + const char* GetDefinitionName(void) const { return m_pszDefinitionName; } + const char* GetItemClass(void) const { return m_pszItemClassname; } + virtual const char* GetItemBaseName(void) const { return m_pszItemBaseName; } + const char* GetBrassModelOverride(void) const { return m_pszBrassModelOverride; } + virtual const char* GetItemTypeName(void) const { return m_pszItemTypeName; } + virtual uint32 GetItemTypeID(void) const { return m_unItemTypeID; } + uint8 GetMinLevel(void) const { return m_unMinItemLevel; } + uint8 GetMaxLevel(void) const { return m_unMaxItemLevel; } + virtual uint8 GetRarity(void) const { return m_nItemRarity; } + uint8 GetQuality(void) const { return m_nItemQuality; } + uint8 GetForcedQuality(void) const { return m_nForcedItemQuality; } + uint8 GetDefaultDropQuality(void) const { return m_nDefaultDropItemQuality; } + uint8 GetDefaultDropQuantity(void) const { return m_nDefaultDropQuantity; } + KeyValues* GetRawDefinition(void) const { return m_pKVItem; } + const CUtlVector& GetStaticAttributes(void) const { return m_vecStaticAttributes; } + uint32 GetNumConcreteItems() const { return m_unNumConcreteItems; } + int GetSoundMaterialID() const { return m_nSoundMaterialID; } + + bool IsHidden(void) const { return m_bHidden; } + bool IsImported(void) const { return m_bImported; } + bool IsOnePerAccountCDKEY(void) const { return m_bOnePerAccountCDKEY; } + bool IsAllowedInMatch(void) const { return m_bAllowedInThisMatch; } + virtual bool IsBaseItem(void) const { return m_bBaseItem; } + virtual bool IsDefaultSlotItem(void) const { return m_bDefaultSlotItem; } + virtual bool IsBundle(void) const { return m_BundleInfo != NULL; } + bool HasProperName(void) const { return m_bProperName; } + const char* GetClassToken(void) const { return m_pszClassToken; } + const char* GetSlotToken(void) const { return m_pszSlotToken; } + bool ShouldAttachToHands(void) const { return m_bAttachToHands; } + bool ShouldAttachToHandsVMOnly(void) const { return m_bAttachToHandsVMOnly; } + bool ShouldFlipViewmodels(void) const { return m_bFlipViewModel; } + int GetInventoryImagePosition(int iIndex) const { Assert(iIndex >= 0 && iIndex < 2); return m_iInventoryImagePosition[iIndex]; } + int GetInventoryImageSize(int iIndex) const { Assert(iIndex >= 0 && iIndex < 2); return m_iInventoryImageSize[iIndex]; } + int GetDropType(void) const { return m_iDropType; } + const char* GetHolidayRestriction(void) const { return m_pszHolidayRestriction; } + int GetSubType(void) const { return m_iSubType; } + item_capabilities_t GetCapabilities(void) const { return m_iCapabilities; } + void AddItemSet(int nIndex); + const CUtlVector< int >& GetItemSets(void) const; + int GetArmoryRemap(void) const { return m_iArmoryRemap; } + int GetStoreRemap(void) const { return m_iStoreRemap; } + virtual int GetLoadoutSlot(void) const { return 0; } + virtual int GetHeroID(void) const { return 0; } + KeyValues* GetPortraitsKV(void) const { return m_pPortraitsKV; } + KeyValues* GetPortraitKVForModel(const char* pszModelName) const; + + AssetInfo* GetAssetInfo() const { return m_pAssetInfo; } + + bool IsTool() const { return m_pTool != NULL; } + bool IsToolAndNotACrate() const { return (IsTool() && GetEconTool() && V_strcmp(GetEconTool()->GetTypeName(), "supply_crate") != 0); } + const IEconTool* GetEconTool() const { return m_pTool; } + template < class T > + const T* GetTypedEconTool() const { return dynamic_cast(GetEconTool()); } + + virtual bool IsPreviewableInStore() const { return true; } + + const bundleinfo_t* GetBundleInfo(void) const { return m_BundleInfo; } + virtual int GetBundleItemCount(void) const { return m_BundleInfo ? m_BundleInfo->vecItemEntries.Count() : 0; } + virtual int GetBundleItem(int iIndex) const { return m_BundleInfo ? m_BundleInfo->vecItemEntries[iIndex].m_nItemDef : -1; } + virtual int GetBundleItemPaintKitID(int iIndex) const { return m_BundleInfo ? m_BundleInfo->vecItemEntries[iIndex].m_nPaintKit : -1; } + + const CUtlVector< const CEconItemDefinition* >& GetContainingBundles() const { return m_vecContainingBundleItemDefs; } + uint32 GetContainingBundleCount() const { return m_vecContainingBundleItemDefs.Count(); } + + typedef CUtlVector< uint32 > WorkshopContributorList_t; + + void AddSteamWorkshopContributor(uint32 unAccountID) { if (m_vecSteamWorkshopContributors.InvalidIndex() == m_vecSteamWorkshopContributors.Find(unAccountID)) { m_vecSteamWorkshopContributors.AddToTail(unAccountID); } } + const WorkshopContributorList_t& GetSteamWorkshopContributors() const { return m_vecSteamWorkshopContributors; } + bool BIsSteamWorkshopItem() const { return m_vecSteamWorkshopContributors.Count() > 0; } + + const char* GetIconClassname(void) const { return m_pszItemIconClassname; } + const char* GetLogClassname(void) const { return m_pszItemLogClassname; } + const char* GetInventoryModel(void) const { return m_pszInventoryModel; } + virtual const char* GetInventoryImage(void) const { return m_pszInventoryImage; } + const char* GetInventoryOverlayImage(int idx) const { if (m_pszInventoryOverlayImages.IsValidIndex(idx)) return m_pszInventoryOverlayImages[idx]; else return NULL; } + int GetInventoryOverlayImageCount(void) const { return m_pszInventoryOverlayImages.Count(); } + const char* GetIconURLSmall() const { return m_sIconURLSmall; } + const char* GetIconURLLarge() const { return m_sIconURLLarge; } + void SetIconURLSmall(const char* szURL) { m_sIconURLSmall = szURL; } + void SetIconURLLarge(const char* szURL) { m_sIconURLLarge = szURL; } + virtual const char* GetBasePlayerDisplayModel() const { return m_pszBaseDisplayModel; } + virtual const char* GetWorldDisplayModel() const { return m_pszWorldDisplayModel; } + virtual const char* GetWorldDroppedModel() const { return m_pszWorldDroppedModel; } + + virtual const char* GetIconDisplayModel() const; + virtual const char* GetBuyMenuDisplayModel() const; + virtual const char* GetPedestalDisplayModel() const; + virtual const char* GetMagazineModel() const; + virtual const char* GetScopeLensMaskModel() const; + virtual const char* GetUidModel() const; + virtual const char* GetStatTrakModelByType(uint32 nType) const; + + virtual const int GetNumSupportedStickerSlots() const; + virtual const char* GetStickerSlotModelBySlotIndex(uint32 nIndex) const; + virtual const Vector& GetStickerSlotWorldProjectionStartBySlotIndex(uint32 nIndex) const; + virtual const Vector& GetStickerSlotWorldProjectionEndBySlotIndex(uint32 nIndex) const; + virtual const char* GetStickerWorldModelBoneParentNameBySlotIndex(uint32 nIndex) const; + virtual const char* GetStickerSlotMaterialBySlotIndex(uint32 nIndex) const; + virtual const char* GetIconDefaultImage() const { return m_pszIconDefaultImage; } + virtual const char* GetExtraWearableModel(void) const { return m_pszWorldExtraWearableModel; } + virtual const char* GetParticleFile(void) const { return m_pszParticleFile; } + virtual const char* GetParticleSnapshotFile(void) const { return m_pszParticleSnapshotFile; } + const CUtlVector< WeaponPaintableMaterial_t >* GetPaintData(void) const { return &m_PaintData; } + const InventoryImageData_t* GetInventoryImageData(void) const { return m_pInventoryImageData; } + virtual const char* GetItemDesc(void) const { return m_pszItemDesc; } + const char* GetArmoryDescString(void) const { return m_pszArmoryDesc; } + RTime32 GetExpirationDate(void) const { return m_rtExpiration; } + RTime32 GetDefCreationDate(void) const { return m_rtDefCreation; } + bool ShouldShowInArmory(void) const { return m_bShouldShowInArmory; } + bool IsActingAsAWearable(void) const { return m_bActAsWearable; } + bool GetHideBodyGroupsDeployedOnly(void) const { return m_bHideBodyGroupsDeployedOnly; } + virtual bool IsPackBundle(void) const { return m_bIsPackBundle; } + virtual bool IsPackItem(void) const { return NULL != m_pOwningPackBundle; } + CEconItemDefinition* GetOwningPackBundle() { return m_pOwningPackBundle; } + const CEconItemDefinition* GetOwningPackBundle() const { return m_pOwningPackBundle; } +#if ECONITEM_DATABASE_AUDIT_TABLES_FEATURE + const char* GetDatabaseAuditTableName(void) const { return m_pszDatabaseAuditTable; } +#endif + const char* GetAlternateIcon(int iAlternateIcon) const; + + equip_region_mask_t GetEquipRegionMask(void) const { return m_unEquipRegionMask; } + equip_region_mask_t GetEquipRegionConflictMask(void) const { return m_unEquipRegionConflictMask; } + + void SetAllowedInMatch(bool bAllowed) { m_bAllowedInThisMatch = bAllowed; } + void SetHasBeenLoaded(bool bLoaded) { m_bHasBeenLoaded = bLoaded; } + + bool BRandomProxy(void) const { return NULL != m_pProxyCriteria; } + CItemSelectionCriteria* PProxyCriteria(void) const { return m_pProxyCriteria; } + + uint32 RollItemLevel(void) const; + + const char* GetFirstSaleDate(void) const; + + virtual bool IsRecent(void) const { return false; } + + void IterateAttributes(class IEconItemAttributeIterator* pIterator) const; + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + int GetNumAttachedModels() const; + attachedmodel_t* GetAttachedModelData(int iIdx) const; + int GetNumAttachedParticles() const; + attachedparticlesystem_t* GetAttachedParticleData(int iIdx) const; + bool IsAttachedParticleDataValidForStyle(int iIdx, int nStyle) const; + int GetNumAnimations() const; + animation_on_wearable_t* GetAnimationData(int iIdx) const; + int GetNumAnimationModifiers() const; + const char* GetAnimationModifier(int iIdx) const; + + Activity GetActivityOverride(Activity baseAct) const; + const char* GetReplacementForActivityOverride(Activity baseAct) const; + int GetNumSounds() const; + sound_on_wearable_t* GetSoundData(int iIdx) const; + const char* GetReplacementSound(const char* pszSoundName) const; + int GetNumParticles() const; + particle_on_wearable_t* GetParticleData(int iIdx) const; + const char* GetReplacementParticleEffect(const char* pszParticleName) const; + int GetNumParticleSnapshots() const; + particlesnapshot_on_wearable_t* GetParticleSnapshotData(int iIdx) const; + const char* GetReplacementParticleSnapshot(const char* pszParticleSnapshotName) const; + + int GetNumParticleControlPoints() const; + particle_control_point_on_wearable_t* GetParticleControlPointData(int iIdx) const; + + bool GetReplacementControlPoint(int nIndex, const char* pszParticleName, int& nOutputCP, Vector& nCPValue) const; + + virtual bool IsContentStreamable() const; + + const char* GetAnnouncerName() const; + const char* GetAnnouncerResource() const; + + const char* GetEntityOverrideModel() const; + const char* GetViewOverrideModel() const; + const char* GetEntityOverrideClass() const; + + const char* GetHeroModelChangeModel() const; + + const char* GetUIOverrideIcon() const; + const char* GetUIOverrideOriginalIcon() const; + + const char* GetUIOverrideAbilityIcon(const char* pszAbilityName) const; + + const char* GetScaleOverrideClass() const; + float GetScaleOverrideSize() const; + + bool SkipModelCombine(void) const; + + const char* GetMuzzleFlash() const; + const char* GetTracerEffect() const; + const char* GetParticleEffect() const; + const char* GetParticleSnapshot() const; + const char* GetMaterialOverride() const; + const char* GetCustomSound(int iSound) const; + const char* GetWeaponReplacementSound( int iSound) const; + + const char* GetPrimaryAmmo(void) const; + const char* GetWeaponTypeString(void) const; + const char* GetAddonLocation(void) const; + const char* GetEjectBrassEffect(void) const; + const char* GetMuzzleFlashEffect1stPerson(void) const; + const char* GetMuzzleFlashEffect1stPersonAlt(void) const; + const char* GetMuzzleFlashEffect3rdPerson(void) const; + const char* GetMuzzleFlashEffect3rdPersonAlt(void) const; + const char* GetHeatEffect(void) const; + const char* GetPlayerAnimationExtension(void) const; + + int GetHiddenParentBodygroup() const; + int GetNumModifiedBodyGroups() const; + const char* GetModifiedBodyGroup(int i, int& body) const; + bool UsesPerClassBodygroups() const; + int GetNumCodeControlledBodyGroups() const; + const char* GetCodeControlledBodyGroup(int i, struct codecontrolledbodygroupdata_t& ccbgd) const; + + int GetViewmodelBodygroupOverride() const; + int GetViewmodelBodygroupStateOverride() const; + int GetWorldmodelBodygroupOverride() const; + int GetWorldmodelBodygroupStateOverride() const; + +#endif + + style_index_t GetNumStyles() const; + const CEconStyleInfo* GetStyleInfo(style_index_t unStyle) const; + + + int GetPopularitySeed() const { return m_nPopularitySeed; } + + bool HasEconTag(econ_tag_handle_t tag) const { return m_vecTags.IsValidIndex(m_vecTags.Find(tag)); } + + bool ShoulDisableStyleSelector(void) const { return m_bDisableStyleSelection; } + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + int GetStyleSkin(style_index_t unStyle) const; +#endif + + virtual bool IsPublicItem(void) const { return m_bPublicItem; } + virtual bool IgnoreInCollectionView(void) const { return m_bIgnoreInCollectionView; } + + const char* GetLootListName(void) const { return m_pszLootListName; } + + + EItemType GetItemType() const { return m_eItemType; } + bool GetAllowPurchaseStandalone() const { return m_bAllowPurchaseStandalone; } + +private: + KeyValues* m_pKVItem; + + item_definition_index_t m_nDefIndex; + + CUtlVector< item_definition_index_t > m_nAssociatedItemsDefIndexes; + + bool m_bEnabled; + + const char* m_szPrefab; + + uint8 m_unMinItemLevel; + uint8 m_unMaxItemLevel; + + uint8 m_nItemRarity; + + uint8 m_nItemQuality; + uint8 m_nForcedItemQuality; + uint8 m_nDefaultDropItemQuality; + + uint8 m_nDefaultDropQuantity; + + CUtlVector m_vecStaticAttributes; + + uint8 m_nPopularitySeed; + + KeyValues* m_pPortraitsKV; + + const char* m_pszItemBaseName; + bool m_bProperName; + const char* m_pszItemTypeName; + + uint32 m_unItemTypeID; + + const char* m_pszItemDesc; + + RTime32 m_rtExpiration; + + RTime32 m_rtDefCreation; + + const char* m_pszInventoryModel; + const char* m_pszInventoryImage; + CUtlVector m_pszInventoryOverlayImages; + int m_iInventoryImagePosition[2]; + int m_iInventoryImageSize[2]; + + const char* m_pszBaseDisplayModel; + bool m_bLoadOnDemand; + bool m_bHasBeenLoaded; + + bool m_bHideBodyGroupsDeployedOnly; + + const char* m_pszWorldDisplayModel; + const char* m_pszWorldExtraWearableModel; + + const char* m_pszWorldDroppedModel; + char m_szWorldDroppedModel[80]; + + CUtlVector m_vStickerModels; + + const char* m_pszIconDefaultImage; + + bool m_bAttachToHands; + bool m_bAttachToHandsVMOnly; + + bool m_bFlipViewModel; + + bool m_bActAsWearable; + + mutable CUtlVector< int > m_iItemSets; + + AssetInfo* m_pAssetInfo; + + EItemType m_eItemType; + bool m_bAllowPurchaseStandalone; + + const char* m_pszBrassModelOverride; + + IEconTool* m_pTool; + bundleinfo_t* m_BundleInfo; + item_capabilities_t m_iCapabilities; + + uint32 m_unNumConcreteItems; + + int m_nSoundMaterialID; + + bool m_bDisableStyleSelection; + + CUtlString m_sIconURLSmall; + CUtlString m_sIconURLLarge; + + const char* m_pszParticleFile; + const char* m_pszParticleSnapshotFile; + + const char* m_pszLootListName; + + CUtlVector m_nCharacterPaintKitIndices; + +protected: + CUtlVector< WeaponPaintableMaterial_t > m_PaintData; + InventoryImageData_t* m_pInventoryImageData; + +private: + + const char* m_pszItemClassname; + + const char* m_pszItemLogClassname; + + const char* m_pszItemIconClassname; + + const char* m_pszDefinitionName; + +#if ECONITEM_DATABASE_AUDIT_TABLES_FEATURE + const char* m_pszDatabaseAuditTable; +#endif + + bool m_bHidden; + bool m_bShouldShowInArmory; + bool m_bBaseItem; + bool m_bDefaultSlotItem; + bool m_bImported; + bool m_bOnePerAccountCDKEY; + + bool m_bIsPackBundle; + + CEconItemDefinition* m_pOwningPackBundle; + + const char* m_pszArmoryDesc; + + int m_iArmoryRemap; + int m_iStoreRemap; + const char* m_pszArmoryRemap; + const char* m_pszStoreRemap; + + const char* m_pszClassToken; + const char* m_pszSlotToken; + + int m_iDropType; + + const char* m_pszHolidayRestriction; + + int m_iSubType; + + bool m_bAllowedInThisMatch; + + CItemSelectionCriteria* m_pProxyCriteria; + + equip_region_mask_t m_unEquipRegionMask; + equip_region_mask_t m_unEquipRegionConflictMask; + + CUtlMap* m_pMapAlternateIcons; + + CUtlVector m_vecTags; + CUtlVector m_vecContainingBundleItemDefs; + WorkshopContributorList_t m_vecSteamWorkshopContributors; + + friend class CEconItemSchema; + bool m_bPublicItem; + bool m_bIgnoreInCollectionView; +}; + +inline style_index_t CEconItemDefinition::GetNumStyles() const +{ + const AssetInfo* pAssetInfo = GetAssetInfo(); + + if (!pAssetInfo) + return 0; + + return pAssetInfo->m_Styles.Count(); +} + +inline const CEconStyleInfo* CEconItemDefinition::GetStyleInfo(style_index_t unStyle) const +{ + const AssetInfo* pAssetInfo = GetAssetInfo(); + if (!pAssetInfo || !pAssetInfo->m_Styles.IsValidIndex(unStyle)) + return NULL; + + return pAssetInfo->m_Styles[unStyle]; +} + +#if defined(CLIENT_DLL) || defined(GAME_DLL) +inline int CEconItemDefinition::GetNumAttachedModels() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_AttachedModels.Count(); +} + +inline attachedmodel_t* CEconItemDefinition::GetAttachedModelData(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + Assert(iIdx < GetAssetInfo()->m_AttachedModels.Count()); + if (iIdx >= GetAssetInfo()->m_AttachedModels.Count()) + return NULL; + + return &GetAssetInfo()->m_AttachedModels[iIdx]; +} + +inline int CEconItemDefinition::GetNumAnimations() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_Animations.Count(); +} + +inline animation_on_wearable_t* CEconItemDefinition::GetAnimationData(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + Assert(iIdx < GetAssetInfo()->m_Animations.Count()); + if (iIdx < 0 || iIdx >= GetAssetInfo()->m_Animations.Count()) + return NULL; + + return &GetAssetInfo()->m_Animations[iIdx]; +} + +inline int CEconItemDefinition::GetNumAnimationModifiers() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_vecAnimationModifiers.Count(); +} + +inline const char* CEconItemDefinition::GetAnimationModifier(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + if (iIdx < 0 || iIdx >= GetAssetInfo()->m_vecAnimationModifiers.Count()) + return NULL; + + return GetAssetInfo()->m_vecAnimationModifiers[iIdx]; +} + +inline const char* CEconItemDefinition::GetAnnouncerName() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszAnnouncerName; +} + +inline const char* CEconItemDefinition::GetAnnouncerResource() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszAnnouncerResource; +} + +inline const char* CEconItemDefinition::GetUIOverrideIcon() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszNewIcon; +} + +inline const char* CEconItemDefinition::GetUIOverrideOriginalIcon() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszOriginalIcon; +} + +inline const char* CEconItemDefinition::GetUIOverrideAbilityIcon(const char* pszAbilityName) const +{ + if (!pszAbilityName) + return NULL; + + if (!GetAssetInfo()) + return NULL; + + FOR_EACH_VEC(GetAssetInfo()->m_vecAbilityIconReplacements, i) + { + ability_icon_replacement_t* pszAbilityReplacement = &GetAssetInfo()->m_vecAbilityIconReplacements.Element(i); + if (pszAbilityReplacement) + { + if (!Q_strcmp(pszAbilityName, pszAbilityReplacement->m_strAbilityName)) + { + return pszAbilityReplacement->m_strReplacement; + } + } + } + + return NULL; +} + +inline const char* CEconItemDefinition::GetEntityOverrideModel() const +{ + if (!GetAssetInfo()) + return NULL; + + CUtlVector* pAssetModifierList = GetAssetInfo()->GetAssetModifiers(AM_EntityModel); + if (pAssetModifierList && pAssetModifierList->Count() > 0) + return pAssetModifierList->Element(0)->m_strModifier.String(); + + return NULL; +} + +inline const char* CEconItemDefinition::GetViewOverrideModel() const +{ + if (!GetAssetInfo()) + return NULL; + + CUtlVector* pAssetModifierList = GetAssetInfo()->GetAssetModifiers(AM_ViewModel); + if (pAssetModifierList && pAssetModifierList->Count() > 0) + return pAssetModifierList->Element(0)->m_strModifier.String(); + + return NULL; +} + +inline const char* CEconItemDefinition::GetEntityOverrideClass() const +{ + if (!GetAssetInfo()) + return NULL; + + CUtlVector* pAssetModifierList = GetAssetInfo()->GetAssetModifiers(AM_EntityModel); + if (pAssetModifierList && pAssetModifierList->Count() > 0) + return pAssetModifierList->Element(0)->m_strAsset.String(); + + return NULL; +} + +inline const char* CEconItemDefinition::GetScaleOverrideClass() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszScaleClass; +} + +inline const char* CEconItemDefinition::GetHeroModelChangeModel() const +{ + if (!GetAssetInfo()) + return NULL; + + CUtlVector* pAssetModifierList = GetAssetInfo()->GetAssetModifiers(AM_HeroModelChange); + if (pAssetModifierList && pAssetModifierList->Count() > 0) + return pAssetModifierList->Element(0)->m_strModifier.String(); + + return NULL; +} + +inline float CEconItemDefinition::GetScaleOverrideSize() const +{ + if (!GetAssetInfo()) + return 0.0f; + + return GetAssetInfo()->m_flScaleSize; +} + +inline bool CEconItemDefinition::SkipModelCombine(void) const +{ + if (!GetAssetInfo()) + return false; + + return GetAssetInfo()->m_bSkipModelCombine; +} + +inline int CEconItemDefinition::GetNumSounds() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_Sounds.Count(); +} + +inline sound_on_wearable_t* CEconItemDefinition::GetSoundData(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + Assert(iIdx < GetAssetInfo()->m_Sounds.Count()); + if (iIdx >= GetAssetInfo()->m_Sounds.Count()) + return NULL; + + return &GetAssetInfo()->m_Sounds[iIdx]; +} + +inline int CEconItemDefinition::GetNumParticles() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_Particles.Count(); +} + +inline particle_on_wearable_t* CEconItemDefinition::GetParticleData(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + Assert(iIdx < GetAssetInfo()->m_Particles.Count()); + if (iIdx >= GetAssetInfo()->m_Particles.Count()) + return NULL; + + return &GetAssetInfo()->m_Particles[iIdx]; +} + +inline int CEconItemDefinition::GetNumParticleSnapshots() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_ParticleSnapshots.Count(); +} + +inline particlesnapshot_on_wearable_t* CEconItemDefinition::GetParticleSnapshotData(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + Assert(iIdx < GetAssetInfo()->m_ParticleSnapshots.Count()); + if (iIdx >= GetAssetInfo()->m_ParticleSnapshots.Count()) + return NULL; + + return &GetAssetInfo()->m_ParticleSnapshots[iIdx]; +} + +inline int CEconItemDefinition::GetNumParticleControlPoints() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_ParticleControlPoints.Count(); +} + +inline particle_control_point_on_wearable_t* CEconItemDefinition::GetParticleControlPointData(int iIdx) const +{ + if (!GetAssetInfo()) + return NULL; + + Assert(iIdx < GetAssetInfo()->m_ParticleControlPoints.Count()); + if (iIdx >= GetAssetInfo()->m_ParticleControlPoints.Count()) + return NULL; + + return &GetAssetInfo()->m_ParticleControlPoints[iIdx]; +} + +inline int CEconItemDefinition::GetNumAttachedParticles() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_AttachedParticles.Count(); +} + +inline const char* CEconItemDefinition::GetMaterialOverride() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszMaterialOverride; +} + + +inline const char* CEconItemDefinition::GetMuzzleFlash() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszMuzzleFlash; +} + +inline const char* CEconItemDefinition::GetTracerEffect() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszTracerEffect; +} + +inline const char* CEconItemDefinition::GetParticleEffect() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszParticleEffect; +} + +inline const char* CEconItemDefinition::GetParticleSnapshot() const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszParticleSnapshot; +} + +inline int CEconItemDefinition::GetHiddenParentBodygroup() const +{ + if (!GetAssetInfo()) + return -1; + + return GetAssetInfo()->iHideParentBodyGroup; +} + +inline int CEconItemDefinition::GetNumModifiedBodyGroups() const +{ + if (!GetAssetInfo()) + return -1; + + return GetAssetInfo()->m_ModifiedBodyGroupNames.Count(); +} + +inline const char* CEconItemDefinition::GetModifiedBodyGroup(int i, int& body) const +{ + if (!GetAssetInfo()) + return NULL; + + body = GetAssetInfo()->m_ModifiedBodyGroupNames[i]; + return GetAssetInfo()->m_ModifiedBodyGroupNames.Key(i); +} + +inline int CEconItemDefinition::GetNumCodeControlledBodyGroups() const +{ + if (!GetAssetInfo()) + return -1; + + return GetAssetInfo()->m_CodeControlledBodyGroupNames.Count(); +} + +inline const char* CEconItemDefinition::GetCodeControlledBodyGroup(int i, codecontrolledbodygroupdata_t& ccbgd) const +{ + if (!GetAssetInfo()) + return NULL; + + ccbgd = GetAssetInfo()->m_CodeControlledBodyGroupNames[i]; + return GetAssetInfo()->m_CodeControlledBodyGroupNames.Key(i); +} + +#if defined(CLIENT_DLL) || defined(GAME_DLL) +inline int CEconItemDefinition::GetStyleSkin(style_index_t unStyle) const +{ + const CEconStyleInfo* pStyle = GetStyleInfo(unStyle); + + return pStyle + ? pStyle->GetSkin() + : -1; +} +#endif + +inline int CEconItemDefinition::GetViewmodelBodygroupOverride() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_iViewModelBodyGroupOverride; +} + +inline int CEconItemDefinition::GetViewmodelBodygroupStateOverride() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_iViewModelBodyGroupStateOverride; +} + +inline int CEconItemDefinition::GetWorldmodelBodygroupOverride() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_iWorldModelBodyGroupOverride; +} + +inline int CEconItemDefinition::GetWorldmodelBodygroupStateOverride() const +{ + if (!GetAssetInfo()) + return 0; + + return GetAssetInfo()->m_iWorldModelBodyGroupStateOverride; +} + +inline bool CEconItemDefinition::UsesPerClassBodygroups() const +{ + if (!GetAssetInfo()) + return false; + + return GetAssetInfo()->bUsePerClassBodygroups; +} + +inline const char* CEconItemDefinition::GetCustomSound(int iSound) const +{ + if (!GetAssetInfo()) + return NULL; + if (iSound < 0 || iSound >= MAX_VISUALS_CUSTOM_SOUNDS) + return NULL; + return GetAssetInfo()->m_pszCustomSounds[iSound]; +} + +inline const char* CEconItemDefinition::GetWeaponReplacementSound( int iSound) const +{ + if (!GetAssetInfo()) + return NULL; + if (iSound < 0 || iSound >= NUM_SHOOT_SOUND_TYPES) + return NULL; + return GetAssetInfo()->m_pszWeaponSoundReplacements[iSound]; +} + +inline const char* CEconItemDefinition::GetPrimaryAmmo(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszPrimaryAmmo; +} + +inline const char* CEconItemDefinition::GetWeaponTypeString(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszWeaponTypeString; +} + +inline const char* CEconItemDefinition::GetAddonLocation(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszAddonLocation; +} + +inline const char* CEconItemDefinition::GetEjectBrassEffect(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszEjectBrassEffect; +} + +inline const char* CEconItemDefinition::GetMuzzleFlashEffect1stPerson(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszMuzzleFlashEffect1stPerson; +} + +inline const char* CEconItemDefinition::GetMuzzleFlashEffect1stPersonAlt(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszMuzzleFlashEffect1stPersonAlt; +} + +inline const char* CEconItemDefinition::GetMuzzleFlashEffect3rdPerson(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszMuzzleFlashEffect3rdPerson; +} + +inline const char* CEconItemDefinition::GetMuzzleFlashEffect3rdPersonAlt(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszMuzzleFlashEffect3rdPersonAlt; +} + +inline const char* CEconItemDefinition::GetHeatEffect(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszHeatEffect; +} + +inline const char* CEconItemDefinition::GetPlayerAnimationExtension(void) const +{ + if (!GetAssetInfo()) + return NULL; + + return GetAssetInfo()->m_pszPlayerAnimationExtension; +} + +#endif + +class CTimedItemRewardDefinition +{ +public: + CTimedItemRewardDefinition(void); + CTimedItemRewardDefinition(const CTimedItemRewardDefinition& that); + CTimedItemRewardDefinition& operator=(const CTimedItemRewardDefinition& rhs); + + ~CTimedItemRewardDefinition(void); + + bool BInitFromKV(KeyValues* pKVTimedReward, CEconItemSchema& pschema, CUtlVector* pVecErrors = NULL); + + uint32 GetRandomFrequency(void) const { return RandomFloat(m_unMinFreq, m_unMaxFreq); } + uint32 GetMinFrequency(void) const { return m_unMinFreq; } + uint32 GetMaxFrequency(void) const { return m_unMaxFreq; } + + float GetChance(void) const; + RTime32 GetForcedBaselineAdjustmentTime(void) const { return m_rtForcedBaselineAdjustment; } + RTime32 GetForcedLastDropAdjustmentTime(void) const { return m_rtForcedLastDropTimeAdjustment; } + uint32 GetHoursInRewardPeriod(void) const { return m_unHoursInRewardPeriod; } + uint32 GetHoursBetweenDropsRealtime(void) const { return m_unHoursBetweenDropsRealtime; } + uint32 GetTotalPointsForPeriod(float flHoursOfPlaytimeInPeriod) const + { + float flHours = flHoursOfPlaytimeInPeriod; + if (flHours <= 0.0f) + return 0; + + uint32 unPoints = 0; + uint32 numPointsToProrate = 0; + uint32 nHoursPlayed = (uint32)flHours; + if (!nHoursPlayed) + { + numPointsToProrate = (m_arrTotalPointsBasedOnHoursPlayed.Count()) ? m_arrTotalPointsBasedOnHoursPlayed.Head() : m_unPointsPerHourOverplayed; + } + else if (uint32 numHoursToCreditFromTable = MIN(nHoursPlayed, (uint32)m_arrTotalPointsBasedOnHoursPlayed.Count())) + { + nHoursPlayed -= numHoursToCreditFromTable; + flHours -= numHoursToCreditFromTable; + unPoints += m_arrTotalPointsBasedOnHoursPlayed[numHoursToCreditFromTable - 1]; + numPointsToProrate = (numHoursToCreditFromTable < (uint32)m_arrTotalPointsBasedOnHoursPlayed.Count()) + ? (m_arrTotalPointsBasedOnHoursPlayed[numHoursToCreditFromTable] - m_arrTotalPointsBasedOnHoursPlayed[numHoursToCreditFromTable - 1]) + : m_unPointsPerHourOverplayed; + } + + if (nHoursPlayed) + { + unPoints += nHoursPlayed * m_unPointsPerHourOverplayed; + numPointsToProrate = m_unPointsPerHourOverplayed; + flHours -= nHoursPlayed; + } + + unPoints += flHours * numPointsToProrate; + return unPoints; + } + uint32 GetPointsPerPeriodRollover(void) const { return m_unPointsPerPeriodRollover; } + + const CItemSelectionCriteria& GetCriteria(void) const { return m_criteria; } + int GetLootListCount(void) const { return m_arrLootLists.Count(); } + const CEconLootListDefinition* GetLootList(int iLootListIdx = 0) const { return m_arrLootLists.IsValidIndex(iLootListIdx) ? m_arrLootLists[iLootListIdx] : NULL; } +private: + uint32 m_unMinFreq; + uint32 m_unMaxFreq; + + RTime32 m_rtForcedBaselineAdjustment; + RTime32 m_rtForcedLastDropTimeAdjustment; + uint32 m_unHoursInRewardPeriod; + uint32 m_unHoursBetweenDropsRealtime; + CUtlVector< uint32 > m_arrTotalPointsBasedOnHoursPlayed; + uint32 m_unPointsPerHourOverplayed; + uint32 m_unPointsPerPeriodRollover; + + float m_flChance; + + + CItemSelectionCriteria m_criteria; + CUtlVector< const CEconLootListDefinition* > m_arrLootLists; + + CUtlVector< const CEconLootListDefinition* > m_arrDynamicLootLists; +}; + +class CItemLevelingDefinition +{ +public: + CItemLevelingDefinition(void); + CItemLevelingDefinition(const CItemLevelingDefinition& that); + CItemLevelingDefinition& operator=(const CItemLevelingDefinition& rhs); + + ~CItemLevelingDefinition(void); + + bool BInitFromKV(KeyValues* pKVItemLevel, CEconItemSchema& pschema, const char* pszLevelBlockName, CUtlVector* pVecErrors = NULL); + + uint32 GetLevel(void) const { return m_unLevel; } + uint32 GetRequiredScore(void) const { return m_unRequiredScore; } + const char* GetNameLocalizationKey(void) const { return m_pszLocalizedName_LocalStorage; } + +private: + uint32 m_unLevel; + uint32 m_unRequiredScore; + char* m_pszLocalizedName_LocalStorage; +}; + +struct AchievementAward_t +{ + AchievementAward_t(const AchievementAward_t& rhs) + : m_sNativeName(rhs.m_sNativeName), + m_unSourceAppId(rhs.m_unSourceAppId), + m_unAuditData(rhs.m_unAuditData) + { + m_vecDefIndex.CopyArray(rhs.m_vecDefIndex.Base(), rhs.m_vecDefIndex.Count()); + } + AchievementAward_t() {} + + CUtlString m_sNativeName; + AppId_t m_unSourceAppId; + uint32 m_unAuditData; + CUtlVector m_vecDefIndex; +}; + +enum eTimedRewardType +{ + kTimedRewards_Reward, + kTimedRewards_PremiumTimedDrop, + kTimedRewards_Crate, + kTimedRewards_Operation, + kTimedRewards_Capsule, + kTimedRewards_Quest, + kTimedRewards_FreeSprayDropsOct2016, + kNumTimedRewards +}; + +struct kill_eater_score_type_t +{ + int32 m_nValue; + const char* m_pszTypeString; + const char* m_pszModelAttributeString; + const char* m_pszLevelBlockName; + bool m_bUseLevelBlock; +}; + +class CWebResource +{ +public: + CWebResource() : m_bOnDemand(false), m_pKeyValues(NULL), m_fnLoadCallback(NULL) {} + CWebResource(const CWebResource& other) + { + m_strName = other.m_strName; + m_strURL = other.m_strURL; + m_bOnDemand = other.m_bOnDemand; + m_pKeyValues = other.m_pKeyValues->MakeCopy(); + m_fnLoadCallback = other.m_fnLoadCallback; + } + ~CWebResource() { m_pKeyValues->deleteThis(); } + + CUtlString m_strName; + CUtlString m_strURL; + bool m_bOnDemand; + KeyValues* m_pKeyValues; + void (*m_fnLoadCallback)(const char*, KeyValues*); + + static bool s_Initialized; +}; + +class CForeignAppImports +{ +public: + CForeignAppImports() : m_mapDefinitions(DefLessFunc(uint16)) {} + + void AddMapping(uint16 unForeignDefIndex, const CEconItemDefinition* pDefn); + const CEconItemDefinition* FindMapping(uint16 unForeignDefIndex) const; + +private: + CUtlMap< uint16, const CEconItemDefinition*> m_mapDefinitions; +}; + +class ISchemaAttributeType +{ +public: + virtual ~ISchemaAttributeType() { } + + virtual unsigned int GetTypeUniqueIdentifier() const = 0; + + virtual void LoadEconAttributeValue(CEconItem* pTargetItem, const CEconItemAttributeDefinition* pAttrDef, const union attribute_data_union_t& value) const = 0; + + virtual void ConvertEconAttributeValueToByteStream(const union attribute_data_union_t& value, std::string* out_psBytes) const = 0; + + virtual bool BConvertStringToEconAttributeValue(const CEconItemAttributeDefinition* pAttrDef, const char* pszValue, union attribute_data_union_t* out_pValue) const = 0; + + virtual void ConvertEconAttributeValueToString(const CEconItemAttributeDefinition* pAttrDef, const attribute_data_union_t& value, std::string* out_ps) const = 0; + + virtual void LoadByteStreamToEconAttributeValue(CEconItem* pTargetItem, const CEconItemAttributeDefinition* pAttrDef, const std::string& sBytes) const = 0; + + virtual void InitializeNewEconAttributeValue(attribute_data_union_t* out_pValue) const = 0; + + virtual void UnloadEconAttributeValue(union attribute_data_union_t* out_pValue) const = 0; + + virtual bool OnIterateAttributeValue(class IEconItemAttributeIterator* pIterator, const CEconItemAttributeDefinition* pAttrDef, const attribute_data_union_t& value) const = 0; + + virtual bool BSupportsGameplayModificationAndNetworking() const { return false; } +}; + + + + +struct CAppliedStickerInfo_t +{ + int nID; + float flWearMin; + float flWearMax; + float flScale; + float flRotate; +}; + +class CStickerKit +{ +public: + + CStickerKit(const CStickerKit& rhs) + : sName(rhs.sName), + sDescriptionString(rhs.sDescriptionString), + sItemName(rhs.sItemName), + sMaterialPath(rhs.sMaterialPath), + m_strInventoryImage(rhs.m_strInventoryImage) + { + nID = rhs.nID; + nRarity = rhs.nRarity; + flRotateStart = rhs.flRotateStart; + flRotateEnd = rhs.flRotateEnd; + flScaleMin = rhs.flScaleMin; + flScaleMax = rhs.flScaleMax; + flWearMin = rhs.flWearMin; + flWearMax = rhs.flWearMax; + bMaterialPathIsAbsolute = rhs.bMaterialPathIsAbsolute; + + m_nEventID = rhs.m_nEventID; + m_nEventTeamID = rhs.m_nEventTeamID; + m_nPlayerID = rhs.m_nPlayerID; + + m_pKVItem = rhs.m_pKVItem ? rhs.m_pKVItem->MakeCopy() : NULL; + } + + CStickerKit(void) + { + nID = 0; + nRarity = 1; + flRotateStart = 0.0f; + flRotateEnd = 0.0f; + flScaleMax = flScaleMin = 1.0f; + flWearMin = 0.0f; + flWearMax = 1.0f; + bMaterialPathIsAbsolute = false; + + m_nEventID = 0; + m_nEventTeamID = 0; + m_nPlayerID = 0; + + m_pKVItem = NULL; + } + + ~CStickerKit() + { + if (m_pKVItem) + m_pKVItem->deleteThis(); + m_pKVItem = NULL; + } + + bool InitFromKeyValues(KeyValues* pKVEntry, const CStickerKit* pDefault, CUtlVector* pVecErrors = NULL); + bool GenerateStickerApplicationInfo(CAppliedStickerInfo_t* pInfo) const; + + int nID; + int nRarity; + CUtlString sName; + CUtlString sDescriptionString; + CUtlString sItemName; + CUtlString sMaterialPath; + CUtlString sMaterialPathNoDrips; + CUtlString m_strInventoryImage; + + int m_nEventID; + int m_nEventTeamID; + int m_nPlayerID; + + bool bMaterialPathIsAbsolute; + + float flRotateStart; + float flRotateEnd; + + float flScaleMin; + float flScaleMax; + + float flWearMin; + float flWearMax; + + const char* GetInventoryImage(void) const { return m_strInventoryImage; } + + const char* GetIconURLSmall() const { return m_sIconURLSmall; } + const char* GetIconURLLarge() const { return m_sIconURLLarge; } + void SetIconURLSmall(const char* szURL) { m_sIconURLSmall = szURL; } + void SetIconURLLarge(const char* szURL) { m_sIconURLLarge = szURL; } + + KeyValues* GetRawDefinition(void) const { return m_pKVItem; } + +private: + CUtlString m_sIconURLSmall; + CUtlString m_sIconURLLarge; + KeyValues* m_pKVItem; +}; + +class CStickerList +{ +public: + CStickerList(const CStickerList& rhs) + { + flWearMin = rhs.flWearMin; + flWearMax = rhs.flWearMax; + + flTotalWeight = rhs.flTotalWeight; + arrElements.AddMultipleToTail(rhs.arrElements.Count(), rhs.arrElements.Base()); + } + CStickerList() + { + flWearMin = 0.0f; + flWearMax = 1.0f; + + flTotalWeight = 0.0f; + } + + bool InitFromKeyValues(KeyValues* pKVEntry, CUtlVector* pVecErrors = NULL); + + bool GenerateStickerApplicationInfo(CAppliedStickerInfo_t* pInfo) const; + + struct sticker_list_entry_t + { + const CStickerList* pList; + const CStickerKit* pKit; + float flWeight; + }; + CUtlVector< sticker_list_entry_t > arrElements; + float flTotalWeight; + + float flWearMin; + float flWearMax; +}; + +class CPaintKit +{ +public: + enum { NUM_COLORS = 4 }; + + CPaintKit(const CPaintKit& rhs) + : sName(rhs.sName), + sDescriptionString(rhs.sDescriptionString), + sDescriptionTag(rhs.sDescriptionTag), + sVmtPath(rhs.sVmtPath), + sPattern(rhs.sPattern), + sLogoMaterial(rhs.sLogoMaterial) + { + nID = rhs.nID; + + kvVmtOverrides = rhs.kvVmtOverrides->MakeCopy(); + + bBaseDiffuseOverride = rhs.bBaseDiffuseOverride; + nRarity = rhs.nRarity; + nStyle = rhs.nStyle; + flWearDefault = rhs.flWearDefault; + flWearRemapMin = rhs.flWearRemapMin; + flWearRemapMax = rhs.flWearRemapMax; + nFixedSeed = rhs.nFixedSeed; + uchPhongExponent = rhs.uchPhongExponent; + uchPhongAlbedoBoost = rhs.uchPhongAlbedoBoost; + uchPhongIntensity = rhs.uchPhongIntensity; + flPatternScale = rhs.flPatternScale; + flPatternOffsetXStart = rhs.flPatternOffsetXStart; + flPatternOffsetXEnd = rhs.flPatternOffsetXEnd; + flPatternOffsetYStart = rhs.flPatternOffsetYStart; + flPatternOffsetYEnd = rhs.flPatternOffsetYEnd; + flPatternRotateStart = rhs.flPatternRotateStart; + flPatternRotateEnd = rhs.flPatternRotateEnd; + flLogoScale = rhs.flLogoScale; + flLogoOffsetX = rhs.flLogoOffsetX; + flLogoOffsetY = rhs.flLogoOffsetY; + flLogoRotation = rhs.flLogoRotation; + bIgnoreWeaponSizeScale = rhs.bIgnoreWeaponSizeScale; + nViewModelExponentOverrideSize = rhs.nViewModelExponentOverrideSize; + bOnlyFirstMaterial = rhs.bOnlyFirstMaterial; + + memcpy(rgbaLogoColor, rhs.rgbaLogoColor, sizeof(rgbaLogoColor)); + memcpy(rgbaLogoColor, rhs.rgbaLogoColor, sizeof(rgbaLogoColor)); + } + + CPaintKit(void) + { + nID = 0; + + kvVmtOverrides = nullptr; + + bBaseDiffuseOverride = false; + nRarity = 1; + nStyle = 0; + flWearDefault = 0.5f; + flWearRemapMin = 0.0f; + flWearRemapMax = 1.0f; + nFixedSeed = 0; + uchPhongExponent = 16; + uchPhongAlbedoBoost = 0; + uchPhongIntensity = 255; + flPatternScale = 0.5f; + flPatternOffsetXStart = 0.0f; + flPatternOffsetXEnd = 0.0f; + flPatternOffsetYStart = 0.0f; + flPatternOffsetYEnd = 0.0f; + flPatternRotateStart = 0.0f; + flPatternRotateEnd = 0.0f; + flLogoScale = 1.8f; + flLogoOffsetX = 1.0f; + flLogoOffsetY = 2.0f; + flLogoRotation = 0.0f; + bIgnoreWeaponSizeScale = false; + nViewModelExponentOverrideSize = 256; + bOnlyFirstMaterial = false; + + memset(rgbaColor, 128, sizeof(rgbaColor)); + memset(rgbaLogoColor, 128, sizeof(rgbaLogoColor)); + } + + ~CPaintKit() + { + if (kvVmtOverrides) + { + kvVmtOverrides->deleteThis(); + kvVmtOverrides = nullptr; + } + } + + bool InitFromKeyValues(KeyValues* pKVEntry, const CPaintKit* pDefault, bool bHandleAbsolutePaths = false); + void FillKeyValuesForWorkshop(KeyValues* pKVToFill) const; + + int nID; + CUtlString sName; + CUtlString sDescriptionString; + CUtlString sDescriptionTag; + + CUtlString sPattern; + CUtlString sLogoMaterial; + bool bBaseDiffuseOverride; + int nRarity; + int nStyle; + Color rgbaColor[NUM_COLORS]; + Color rgbaLogoColor[NUM_COLORS]; + float flWearDefault; + float flWearRemapMin; + float flWearRemapMax; + unsigned char nFixedSeed; + unsigned char uchPhongExponent; + unsigned char uchPhongAlbedoBoost; + unsigned char uchPhongIntensity; + float flPatternScale; + float flPatternOffsetXStart; + float flPatternOffsetXEnd; + float flPatternOffsetYStart; + float flPatternOffsetYEnd; + float flPatternRotateStart; + float flPatternRotateEnd; + float flLogoScale; + float flLogoOffsetX; + float flLogoOffsetY; + float flLogoRotation; + bool bIgnoreWeaponSizeScale; + int nViewModelExponentOverrideSize; + bool bOnlyFirstMaterial; + + CUtlString sVmtPath; + KeyValues* kvVmtOverrides; +}; + +class AlternateIconData_t +{ +public: + AlternateIconData_t() + { + } + + const char* GetInventoryImage(void) const { return sSimpleName; } + + const char* GetIconURLSmall() const { return m_sIconURLSmall; } + const char* GetIconURLLarge() const { return m_sIconURLLarge; } + void SetIconURLSmall(const char* szURL) { m_sIconURLSmall = szURL; } + void SetIconURLLarge(const char* szURL) { m_sIconURLLarge = szURL; } + + CUtlString sSimpleName; + CUtlString sLargeSimpleName; + +private: + CUtlString m_sIconURLSmall; + CUtlString m_sIconURLLarge; +}; + +class CProPlayerData +{ +public: + + CProPlayerData(const CProPlayerData& rhs) + { + m_nAccountID = rhs.m_nAccountID; + m_sName = rhs.m_sName; + m_sCode = rhs.m_sCode; + m_rtDOB = rhs.m_rtDOB; + m_sGeo = rhs.m_sGeo; + + m_pKVItem = rhs.m_pKVItem ? rhs.m_pKVItem->MakeCopy() : NULL; + } + + CProPlayerData(void) + { + m_nAccountID = 0; + m_rtDOB = 0; + m_pKVItem = NULL; + } + + ~CProPlayerData() + { + if (m_pKVItem) + m_pKVItem->deleteThis(); + m_pKVItem = NULL; + } + + bool BInitFromKeyValues(KeyValues* pDef, CUtlVector* pVecErrors = NULL); + + KeyValues* GetRawDefinition(void) const { return m_pKVItem; } + uint32 GetAccountID() const { return m_nAccountID; } + char const* GetName() const { return m_sName; } + char const* GetCode() const { return m_sCode; } + RTime32 GetDOB() const { return m_rtDOB; } + char const* GetGeo() const { return m_sGeo; } + +private: + KeyValues* m_pKVItem; + uint32 m_nAccountID; + CUtlString m_sName; + CUtlString m_sCode; + RTime32 m_rtDOB; + CUtlString m_sGeo; +}; + +typedef CUtlDict ArmoryStringDict_t; +typedef CUtlDict< CUtlVector* > LevelBlockDict_t; +typedef CUtlMap KillEaterScoreMap_t; + +struct attr_type_t +{ + CUtlConstString m_sName; + const ISchemaAttributeType* m_pAttrType; + + attr_type_t(const char* pszName, const ISchemaAttributeType* pAttrType) + : m_sName(pszName) + , m_pAttrType(pAttrType) + { + } +}; + +#if defined(CLIENT_DLL) || defined(GAME_DLL) +class IDelayedSchemaData +{ +public: + virtual ~IDelayedSchemaData() {} + virtual bool InitializeSchema(CEconItemSchema* pItemSchema) = 0; + +protected: + bool InitializeSchemaInternal(CEconItemSchema* pItemSchema, CUtlBuffer& bufRawData, bool bInitAsBinary, uint32 nExpectedVersion); +}; +#endif + +class CEconStorePriceSheet; + +class CEconItemSchema : public IEconItemSchema +{ +public: + CEconItemSchema(); + +private: + CEconItemSchema(const CEconItemSchema& rhs); + CEconItemSchema& operator=(CEconItemSchema& rhs); + +public: + virtual ~CEconItemSchema(void) { Reset(); }; + + virtual bool BInit(const char* fileName, const char* pathID, CUtlVector* pVecErrors = NULL); + bool BInitBinaryBuffer(CUtlBuffer& buffer, CUtlVector* pVecErrors = NULL); + bool BInitTextBuffer(CUtlBuffer& buffer, CUtlVector* pVecErrors = NULL); + + uint32 GetVersion() const { return m_unVersion; } + uint32 GetResetCount() const { return m_unResetCount; } + + static CUniformRandomStream& GetRandomStream() { return m_RandomStream; } + + static uint32 CalculateKeyValuesVersion(KeyValues* pKV); + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + void MaybeInitFromBuffer(IDelayedSchemaData* pDelayedSchemaData); + + bool BInitFromDelayedBuffer(); +#endif + + equipped_class_t GetFirstValidClass() const { return m_unFirstValidClass; } + equipped_class_t GetLastValidClass() const { return m_unLastValidClass; } + bool IsValidClass(equipped_class_t unClass) { return unClass >= m_unFirstValidClass && unClass <= m_unLastValidClass; } + equipped_slot_t GetFirstValidItemSlot() const { return m_unFirstValidItemSlot; } + equipped_slot_t GetLastValidItemSlot() const { return m_unLastValidItemSlot; } + bool IsValidItemSlot(equipped_slot_t unSlot) { return unSlot >= m_unFirstValidItemSlot && unSlot <= m_unLastValidItemSlot; } + uint32 GetNumAllowedItemPresets() const { return m_unNumItemPresets; } + bool IsValidPreset(equipped_preset_t unPreset) const { return unPreset <= m_unNumItemPresets; } + uint32 GetMinLevel() const { return m_unMinLevel; } + uint32 GetMaxLevel() const { return m_unMaxLevel; } + uint32 GetSumQualityWeights() const { return m_unSumQualityWeights; } + + typedef CUtlHashMapLarge ItemDefinitionMap_t; + const ItemDefinitionMap_t& GetItemDefinitionMap() const { return m_mapItems; } + + typedef CUtlMap > SortedItemDefinitionMap_t; + const SortedItemDefinitionMap_t& GetSortedItemDefinitionMap() const { return m_mapItemsSorted; } + + typedef CUtlDict LootListDefinitionDict_t; + const LootListDefinitionDict_t& GetLootLists() const { return m_dictLootLists; } + + typedef CUtlMap > RevolvingLootListDefinitionMap_t; + const RevolvingLootListDefinitionMap_t& GetRevolvingLootLists() const { return m_mapRevolvingLootLists; } + const RevolvingLootListDefinitionMap_t& GetQuestRewardLootLists() const { return m_mapQuestRewardLootLists; } + + typedef CUtlMap BodygroupStateMap_t; + const BodygroupStateMap_t& GetDefaultBodygroupStateMap() const { return m_mapDefaultBodygroupState; } + + typedef CUtlVector ColorDefinitionsList_t; + + typedef CUtlMap > MusicDefinitionsList_t; + typedef CUtlMap > QuestDefinitionsList_t; + typedef CUtlMap > CampaignDefinitionsList_t; + + + const MusicDefinitionsList_t& GetMusicDefinitionMap() const { return m_mapMusicDefs; } + + const CEconItemDefinition* GetDefaultItemDefinition() const { return m_pDefaultItemDefinition; } + IEconItemDefinition* GetDefaultItemDefinitionInterface() { return m_pDefaultItemDefinition; } + + const CUtlMap >& GetQualityDefinitionMap() const { return m_mapQualities; } + + typedef CUtlVector< CEconItemAttributeDefinition* > EconAttrDefsContainer_t; + EconAttrDefsContainer_t& GetAttributeDefinitionContainer() { return m_mapAttributesContainer; } + const EconAttrDefsContainer_t& GetAttributeDefinitionContainer() const { return m_mapAttributesContainer; } + + typedef CUtlMap > RecipeDefinitionMap_t; + const RecipeDefinitionMap_t& GetRecipeDefinitionMap() const { return m_mapRecipes; } + const CUtlMap& GetItemSets() const { return m_mapItemSets; } + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + const ArmoryStringDict_t& GetArmoryDataItemClasses() const { return m_dictArmoryItemClassesDataStrings; } + const ArmoryStringDict_t& GetArmoryDataItemTypes() const { return m_dictArmoryItemTypesDataStrings; } + const ArmoryStringDict_t& GetArmoryDataItems() const { return m_dictArmoryItemDataStrings; } + const ArmoryStringDict_t& GetArmoryDataAttributes() const { return m_dictArmoryAttributeDataStrings; } +#endif + + const CTimedItemRewardDefinition* GetTimedReward(eTimedRewardType type) const; + + const CEconLootListDefinition* GetLootListByName(const char* pListName, int* out_piIndex = NULL) const; + const CEconLootListDefinition* GetLootListByIndex(int iIdx) const { return m_dictLootLists.IsValidIndex(iIdx) ? &(m_dictLootLists[iIdx]) : NULL; } + + virtual void PurgeLootLists(void) { m_dictLootLists.Purge(); } + virtual const IEconLootListDefinition* GetLootListInterfaceByName(const char* pListName, int* out_piIndex = NULL) { return GetLootListByName(pListName, out_piIndex); } + virtual const IEconLootListDefinition* GetLootListInterfaceByIndex(int iIdx) const { return GetLootListByIndex(iIdx); } + virtual const int GetLootListIndex(const char* pListName) { return m_dictLootLists.Find(pListName); } + virtual const int GetLootListInterfaceCount(void) const { return m_dictLootLists.Count(); } + + const CEconItemSetDefinition* GetItemSet(const char* pSetName, int* piIndex = NULL) const; + const CEconItemSetDefinition* GetItemSetByIndex(int iIdx) const { return m_mapItemSets.IsValidIndex(iIdx) ? &(m_mapItemSets[iIdx]) : NULL; } + + uint8 GetDefaultQuality() const { return AE_UNIQUE; } + + virtual int GetItemSetCount(void) const { return m_mapItemSets.Count(); } + virtual const IEconItemSetDefinition* GetItemSet(int iIndex) const; + + void AssignDefaultBodygroupState(const char* pszBodygroupName, int iValue); + + equip_region_mask_t GetEquipRegionMaskByName(const char* pRegionName) const; + + struct EquipRegion + { + CUtlConstString m_sName; + unsigned int m_unBitIndex; + equip_region_mask_t m_unMask; + }; + + typedef CUtlVector EquipRegionsList_t; + const EquipRegionsList_t& GetEquipRegionsList() const { return m_vecEquipRegionsList; } + + virtual KeyValues* FindDefinitionPrefabByName(const char* pszPrefabName) const; + + equip_region_mask_t GetEquipRegionBitMaskByName(const char* pRegionName) const; + + CUtlVector< CEconItemDefinition* >& GetBundles() { return m_vecBundles; } + +private: + void SetEquipRegionConflict(int iRegion, unsigned int unBit); + int GetEquipRegionIndexByName(const char* pRegionName) const; + +public: + bool BGetItemQualityFromName(const char* pchName, uint8* nQuality) const; + const CEconItemQualityDefinition* GetQualityDefinition(int nQuality) const; + const CEconItemQualityDefinition* GetQualityDefinitionByName(const char* pszDefName) const; + virtual int GetQualityDefinitionCount(void) { return m_mapQualities.Count(); } + virtual const char* GetQualityName(uint8 iQuality); + virtual int GetQualityIndex(const char* pszQuality); + bool BGetItemRarityFromName(const char* pchName, uint8* nRarity) const; + const CEconItemRarityDefinition* GetRarityDefinitionByMapIndex(int nRarityIndex) const; + const CEconItemRarityDefinition* GetRarityDefinition(int nRarity) const; + const CEconItemRarityDefinition* GetRarityDefinitionByName(const char* pszDefName) const; + virtual int GetRarityDefinitionCount(void) const { return m_mapRarities.Count(); } + virtual const char* GetRarityName(uint8 iRarity); + virtual const char* GetRarityLocKey(uint8 iRarity); + virtual const char* GetRarityColor(uint8 iRarity); + virtual const char* GetRarityLootList(uint8 iRarity); + virtual int GetRarityIndex(const char* pszRarity); + CEconItemDefinition* GetItemDefinitionMutable(int iItemIndex, bool bNoDefault = false); + const CEconItemDefinition* GetItemDefinition(int iItemIndex, bool bNoDefault = false) const; + const CEconItemDefinition* GetItemDefinitionByMapIndex(int iMapIndex) const; + const CEconItemAttributeDefinition* GetAttributeDefinition(int iAttribIndex) const; + virtual const IEconItemAttributeDefinition* GetAttributeDefinitionInterface(int iAttribIndex) const { return GetAttributeDefinition(iAttribIndex); } + const CEconItemAttributeDefinition* GetAttributeDefinitionByName(const char* pszDefName) const; + const CEconCraftingRecipeDefinition* GetRecipeDefinition(int iRecipeIndex) const; + int GetPaintKitDefinitionCount(void) const { return m_mapPaintKits.Count(); } + void AddPaintKitDefinition(int iPaintKitID, CPaintKit* pPaintKit); + void RemovePaintKitDefinition(int iPaintKitID); + const unsigned int GetPaintKitCount() const; + const CPaintKit* GetPaintKitDefinition(int iPaintKitID) const; + const CPaintKit* GetPaintKitDefinitionByMapIndex(int iMapIndex); + const CPaintKit* GetPaintKitDefinitionByName(const char* pchName) const; + + int GetStickerKitDefinitionCount(void) const { return m_mapStickerKits.Count(); } + void AddStickerKitDefinition(int iStickerKitID, CStickerKit* pStickerKit); + void RemoveStickerKitDefinition(int iStickerKitID); + const CStickerKit* GetStickerKitDefinition(int iStickerKitID) const; + const CStickerKit* GetStickerKitDefinitionByMapIndex(int iMapIndex); + const CStickerKit* GetStickerKitDefinitionByName(const char* pchName) const; + const CStickerList* GetStickerListDefinitionByName(const char* pchName) const; + const CEconMusicDefinition* GetMusicKitDefinitionByName(const char* pchName) const; + + const CEconColorDefinition* GetColorDefinitionByName(const char* pszDefName) const; + + int GetGraffitiTintMaxValidDefID() const { return m_nMaxValidGraffitiTintDefID; } + const CEconGraffitiTintDefinition* GetGraffitiTintDefinitionByID(int nID) const; + const CEconGraffitiTintDefinition* GetGraffitiTintDefinitionByName(const char* pszDefName) const; + + const CEconMusicDefinition* GetMusicDefinition(uint32 unMusicID) const; + + CEconQuestDefinition* GetQuestDefinition(uint32 unQuestID) const; + const QuestDefinitionsList_t& GetQuestDefinitionMap(void) const { return m_mapQuestDefs; } + + const QuestEventsSchedule_t& GetAndUpdateQuestEventsSchedule(void); + const QuestEvents_t& GetQuestEvents(void) const { return m_vecQuestEvents; } + + CEconCampaignDefinition* GetCampaignDefinition(uint32 unCampaignID) const; + const CampaignDefinitionsList_t& GetCampaignDefinitionMap(void) const { return m_mapCampaignDefs; } + + virtual int GetToolType(const char* pszToolType) const { return -1; } + virtual int GetNumPrefabs(void) { return m_mapDefinitionPrefabs.Count(); } + virtual const char* GetPrefabName(int idx) { return m_mapDefinitionPrefabs.Key(idx); } + + const CEconSoundMaterialDefinition* GetSoundMaterialDefinitionByID(int nSoundMaterialID) const; + const CEconSoundMaterialDefinition* GetSoundMaterialDefinitionByName(const char* pszSoundMaterialName) const; + virtual const char* GetSoundMaterialNameByID(int nSoundMaterialID); + virtual int GetSoundMaterialID(const char* pszSoundMaterial); + + virtual int GetSoundMaterialCount(void) { return m_mapSoundMaterials.Count(); } + virtual int GetSoundMaterialIDByIndex(int nIndex); + +#ifdef CLIENT_DLL + EWebResourceStatus LoadWebResource(CUtlString pszName, void (*fnCallback)(const char*, KeyValues*), bool bForceReload = false); + void SetWebResource(CUtlString strName, KeyValues* pResourceKV); +#endif + + const CProPlayerData* GetProPlayerDataByAccountID(uint32 unAccountID) const; + const CUtlVector< const CProPlayerData* >* GetProPlayersDataForEventIDTeamID(int nEventID, int nTeamID) const; + + virtual uint32 GetHeroID(const char* pszHeroName) { return 0; } + + bool BCanGSCreateItems(uint32 unIP) const; + const AchievementAward_t* GetAchievementRewardByDefIndex(uint16 usDefIndex) const; + bool BHasAchievementRewards(void) const { return (m_dictAchievementRewards.Count() > 0); } + + static CUtlString ComputeAchievementName(AppId_t unAppID, const char* pchNativeAchievementName); + + CEconItemDefinition* GetItemDefinitionByName(const char* pszDefName); + const CEconItemDefinition* GetItemDefinitionByName(const char* pszDefName) const; + + attachedparticlesystem_t* GetAttributeControlledParticleSystem(int id); + attachedparticlesystem_t* GetAttributeControlledParticleSystemByIndex(int id); + attachedparticlesystem_t* FindAttributeControlledParticleSystem(const char* pchSystemName, int* outID = NULL); + typedef CUtlMap > ParticleDefinitionMap_t; + const ParticleDefinitionMap_t& GetAttributeControlledParticleSystems() const { return m_mapAttributeControlledParticleSystems; } + virtual int GetNumAttributeControlledParticleSystems() const { return GetAttributeControlledParticleSystems().Count(); } + + const KillEaterScoreMap_t& GetKillEaterScoreTypes() const { return m_mapKillEaterScoreTypes; } + + const kill_eater_score_type_t* FindKillEaterScoreType(uint32 unScoreType) const; + + const CUtlVector& GetAttributeTypes() const { return m_vecAttributeTypes; } + const ISchemaAttributeType* GetAttributeType(const char* pszAttrTypeName) const; + + const LevelBlockDict_t& GetItemLevelingDataDict() const { return m_vecItemLevelingData; } + + const CUtlVector* GetItemLevelingData(const char* pszLevelBlockName) const + { + LevelBlockDict_t::IndexType_t i = m_vecItemLevelingData.Find(pszLevelBlockName); + if (i == LevelBlockDict_t::InvalidIndex()) + return NULL; + + return m_vecItemLevelingData[i]; + } + + const CItemLevelingDefinition* GetItemLevelForScore(const char* pszLevelBlockName, uint32 unScore) const; + const char* GetKillEaterScoreTypeLocString(uint32 unScoreType) const; + bool GetKillEaterScoreTypeUseLevelData(uint32 unScoreType) const; + const char* GetKillEaterScoreTypeLevelingDataName(uint32 unScoreType) const; +#if defined(CLIENT_DLL) || defined(GAME_DLL) + virtual void ItemTesting_CreateTestDefinition(int iCloneFromItemDef, int iNewDef, KeyValues* pNewKV); + virtual void ItemTesting_DiscardTestDefinition(int iDef); +#endif + + econ_tag_handle_t GetHandleForTag(const char* pszTagName); + + typedef CUtlDict EconTagDict_t; + +public: + virtual CEconItemDefinition* CreateEconItemDefinition() { return new CEconItemDefinition; } + virtual CEconCraftingRecipeDefinition* CreateCraftingRecipeDefinition() { return new CEconCraftingRecipeDefinition; } + virtual CEconStyleInfo* CreateEconStyleInfo() { return new CEconStyleInfo; } + + virtual IEconTool* CreateEconToolImpl(const char* pszToolType, const char* pszUseString, const char* pszUsageRestriction, item_capabilities_t unCapabilities, KeyValues* pUsageKV); + virtual int GetItemDefinitionCount() { return m_mapItems.Count(); } + + AlternateIconData_t* GetAlternateIcon(uint64 ullAlternateIcon); + + typedef CUtlMap< uint64, AlternateIconData_t, int, CDefLess > AlternateIconsMap_t; + AlternateIconsMap_t& GetAlternateIconsMap() { return m_mapAlternateIcons; } + + +protected: + virtual void Reset(void); + + virtual KeyValues* GetRawDefinition(void) const { return m_pKVRawDefinition; } + virtual IEconItemDefinition* GetItemDefinitionInterface(int iDefIndex) { return GetItemDefinitionMutable(iDefIndex, true); } + virtual int GetLoadoutSlotCount() { return 0; } + virtual const char* GetLoadoutSlotName(int iSlot) { return NULL; } + virtual int GetLoadoutSlot(const char* pszSlotName) { return 0; } + virtual int GetCharacterSlotType(int iCharacter, int iSlot) { return 0; } + virtual int GetCharacterID(const char* pszCharacterName) { return 0; } + virtual bool DeleteItemDefinition(int iDefIndex); + virtual int GetCharacterCount(void) { return 0; } + virtual const char* GetCharacterName(int iCharacter) { return NULL; } + virtual const char* GetCharacterModel(int iCharacter) { return NULL; } + + virtual int CalculateNumberOfConcreteItems(const CEconItemDefinition* pItemDef); + + virtual bool BInitItems(KeyValues* pKVItems, CUtlVector* pVecErrors); + virtual bool BInitItemMappings(CUtlVector* pVecErrors); + virtual bool BInitBundles(CUtlVector* pVecErrors); + virtual bool BInitPaymentRules(CUtlVector* pVecErrors); + virtual bool BInitItemSets(KeyValues* pKVItemSets, CUtlVector* pVecErrors); + +private: + bool BInitGameInfo(KeyValues* pKVGameInfo, CUtlVector* pVecErrors); + bool BInitAttributeTypes(CUtlVector* pVecErrors); + bool BInitDefinitionPrefabs(KeyValues* pKVPrefabs, CUtlVector* pVecErrors); + bool BInitRarities(KeyValues* pKVRarities, CUtlVector* pVecErrors); + bool BInitQualities(KeyValues* pKVAttributes, CUtlVector* pVecErrors); + bool BInitColors(KeyValues* pKVColors, CUtlVector* pVecErrors); + bool BInitGraffitiTints(KeyValues* pKVColors, CUtlVector* pVecErrors); + bool BInitAttributes(KeyValues* pKVAttributes, CUtlVector* pVecErrors); + bool BInitEquipRegions(KeyValues* pKVEquipRegions, CUtlVector* pVecErrors); + bool BInitEquipRegionConflicts(KeyValues* pKVEquipRegions, CUtlVector* pVecErrors); + bool BInitTimedRewards(KeyValues* pKVTimeRewards, CUtlVector* pVecErrors); + bool BInitAchievementRewards(KeyValues* pKVTimeRewards, CUtlVector* pVecErrors); + bool BInitRecipes(KeyValues* pKVRecipes, CUtlVector* pVecErrors); + virtual bool BInitLootLists(KeyValues* pKVLootLists, KeyValues* pKVRandomAttributeTemplates, CUtlVector* pVecErrors, bool bServerLists); + bool BInitRevolvingLootLists(KeyValues* pKVRevolvingLootLists, CUtlVector* pVecErrors); + bool BInitQuestRewardLootLists(KeyValues* pKVQuestRewardLootLists, CUtlVector* pVecErrors); +#ifdef TF_CLIENT_DLL + bool BInitConcreteItemCounts(CUtlVector* pVecErrors); +#endif + bool BInitItemLevels(KeyValues* pKVItemLevels, CUtlVector* pVecErrors); + bool BInitKillEaterScoreTypes(KeyValues* pKVItemLevels, CUtlVector* pVecErrors); + bool BInitAlternateIcons(KeyValues* pKVAlternateIcons, CUtlVector* pVecErrors); + bool BInitAlternateIcon(uint64 ullAltIconKey, char const* szSimpleName, KeyValues* pKVAlternateIcon, CUtlVector* pVecErrors); + bool BInitStickerKits(KeyValues* pKVStickerKits, CUtlVector* pVecErrors); + bool BInitSoundMaterials(KeyValues* pKVSoundMaterials, CUtlVector* pVecErrors); + bool BInitStickerLists(KeyValues* pKVStickerKits, CUtlVector* pVecErrors); + + bool BInitPaintKits(KeyValues* pKVPaintKits, CUtlVector* pVecErrors); + bool BInitPaintKitsRarity(KeyValues* pKVPaintKitsRarity, CUtlVector* pVecErrors); + + bool BInitMusicDefs(KeyValues* pKVMusicDefs, CUtlVector* pVecErrors); + + bool BInitQuestDefs(KeyValues* pKVQuestDefs, CUtlVector* pVecErrors); + + bool BInitQuestEvents(KeyValues* pKVQuestEvents, CUtlVector* pVecErrors); + + bool BInitCampaignDefs(KeyValues* pKVCampaignDefs, CUtlVector* pVecErrors); + + bool BInitProPlayers(KeyValues* pKVData, CUtlVector* pVecErrors); + +#ifdef CLIENT_DLL + bool BInitWebResources(KeyValues* pKVWebResources, CUtlVector* pVecErrors); +#endif + + bool BPostSchemaInitStartupChecks(CUtlVector* pVecErrors); + + virtual attachedparticlesystem_t GetAttachedParticleSystemInfo(KeyValues* pParticleSystemKV, int32 nItemIndex) const; + virtual bool BInitAttributeControlledParticleSystems(KeyValues* pKVParticleSystems, CUtlVector* pVecErrors); +#if defined(CLIENT_DLL) || defined(GAME_DLL) + bool BInitArmoryData(KeyValues* pKVArmoryData, CUtlVector* pVecErrors); +#else + bool BInitExperiements(KeyValues* pKVExperiments, CUtlVector* pVecErrors); + bool BInitForeignImports(CUtlVector* pVecErrors); + + CForeignAppImports* FindOrAddAppImports(AppId_t unAppID); +#endif + +protected: + virtual bool BInitSchema(KeyValues* pKVRawDefinition, CUtlVector* pVecErrors = NULL); +private: + bool m_bSchemaUpdatesEnabled; + + uint32 m_unResetCount; + + KeyValues* m_pKVRawDefinition; + uint32 m_unVersion; + + equipped_class_t m_unFirstValidClass; + equipped_class_t m_unLastValidClass; + + equipped_slot_t m_unFirstValidItemSlot; + equipped_slot_t m_unLastValidItemSlot; + + uint32 m_unNumItemPresets; + + uint32 m_unMinLevel; + uint32 m_unMaxLevel; + + uint32 m_unSumQualityWeights; + + CUtlVector m_vecAttributeTypes; + + CUtlMap > m_mapRarities; + + CUtlMap > m_mapQualities; + + ItemDefinitionMap_t m_mapItems; + + SortedItemDefinitionMap_t m_mapItemsSorted; + + CEconItemDefinition* m_pDefaultItemDefinition; + + EconAttrDefsContainer_t m_mapAttributesContainer; + + RecipeDefinitionMap_t m_mapRecipes; + + CUtlMap m_mapItemSets; + + CUtlMap > m_mapRevolvingLootLists; + + CUtlMap > m_mapQuestRewardLootLists; + + LootListDefinitionDict_t m_dictLootLists; + + CUtlVector m_vecTimedRewards; + + CUtlDict m_dictWebResources; + + AlternateIconsMap_t m_mapAlternateIcons; + + CUtlDict< AchievementAward_t*, int > m_dictAchievementRewards; + CUtlMap< uint32, AchievementAward_t*, int, CDefLess > m_mapAchievementRewardsByData; + + CUtlMap > m_mapPaintKits; + + CUtlMap > m_mapStickerKits; + CUtlDict< CStickerKit*, int > m_dictStickerKits; + + CUtlDict< CStickerList*, int > m_dictStickerLists; + + CUtlMap > m_mapAttributeControlledParticleSystems; + + EquipRegionsList_t m_vecEquipRegionsList; + + CUtlMap m_mapDefinitionPrefabs; + + ColorDefinitionsList_t m_vecColorDefs; + CUtlVector< CEconGraffitiTintDefinition* > m_vecGraffitiTintDefs; + CUtlStringMap< CEconGraffitiTintDefinition* > m_mapGraffitiTintByName; + int m_nMaxValidGraffitiTintDefID; + + MusicDefinitionsList_t m_mapMusicDefs; + + QuestDefinitionsList_t m_mapQuestDefs; + + CampaignDefinitionsList_t m_mapCampaignDefs; + + QuestEvents_t m_vecQuestEvents; + QuestEventsSchedule_t m_mapQuestEventsSchedule; + + typedef CUtlMap< uint32, CProPlayerData*, int, CDefLess< uint32 > > MapProPlayersByAccountID_t; + typedef CUtlStringMap< CProPlayerData* > MapProPlayersByName_t; + typedef CUtlMap< uint64, CUtlVector< const CProPlayerData* >*, int, CDefLess< uint64 > > MapProPlayersByEventIDTeamID_t; + MapProPlayersByAccountID_t m_mapProPlayersByAccountID; + MapProPlayersByName_t m_mapProPlayersByCode; + MapProPlayersByEventIDTeamID_t m_mapProPlayersByEventIDTeamID; + + CUtlMap > m_mapSoundMaterials; + + BodygroupStateMap_t m_mapDefaultBodygroupState; + + EconTagDict_t m_dictTags; + + KillEaterScoreMap_t m_mapKillEaterScoreTypes; + + LevelBlockDict_t m_vecItemLevelingData; + +#if defined(CLIENT_DLL) || defined(GAME_DLL) + ArmoryStringDict_t m_dictArmoryItemTypesDataStrings; + ArmoryStringDict_t m_dictArmoryItemClassesDataStrings; + ArmoryStringDict_t m_dictArmoryAttributeDataStrings; + ArmoryStringDict_t m_dictArmoryItemDataStrings; + + IDelayedSchemaData* m_pDelayedSchemaData; +#endif + + CUtlVector< CEconItemDefinition* > m_vecBundles; + + static CUniformRandomStream m_RandomStream; + + bool m_bSchemaParsingItems; +}; + +extern CEconItemSchema& GEconItemSchema(); + +template < class T > +class CSchemaFieldHandle +{ +public: + explicit CSchemaFieldHandle(const char* szName) + : m_szName(szName) + { + m_pRef = GetTypedRef(); + m_unSchemaGeneration = GEconItemSchema().GetResetCount(); +#if _DEBUG + m_unVersion_Debug = GEconItemSchema().GetVersion(); +#endif + } + + operator const T* (void) const + { + uint32 unSchemaGeneration = GEconItemSchema().GetResetCount(); + if (m_unSchemaGeneration != unSchemaGeneration) + { + m_pRef = GetTypedRef(); + m_unSchemaGeneration = unSchemaGeneration; +#if _DEBUG + m_unVersion_Debug = GEconItemSchema().GetVersion(); +#endif + } + +#if _DEBUG + Assert(m_unVersion_Debug == GEconItemSchema().GetVersion()); +#endif + return m_pRef; + } + + const T* operator->(void) const + { + return static_cast(*this); + } + + const char* GetName(void) const + { + return m_szName; + } + +private: + const T* GetTypedRef() const; + +private: + const char* m_szName; + + mutable const T* m_pRef; + mutable uint32 m_unSchemaGeneration; +#if _DEBUG + mutable uint32 m_unVersion_Debug; +#endif +}; + +template < > +inline const CEconColorDefinition* CSchemaFieldHandle::GetTypedRef(void) const +{ + return GEconItemSchema().GetColorDefinitionByName(m_szName); +} + +template < > +inline const CEconItemAttributeDefinition* CSchemaFieldHandle::GetTypedRef(void) const +{ + return GEconItemSchema().GetAttributeDefinitionByName(m_szName); +} + +template < > +inline const CEconItemDefinition* CSchemaFieldHandle::GetTypedRef(void) const +{ + return GEconItemSchema().GetItemDefinitionByName(m_szName); +} + +template < > +inline const CEconLootListDefinition* CSchemaFieldHandle::GetTypedRef(void) const +{ + return GEconItemSchema().GetLootListByName(m_szName); +} + +typedef CSchemaFieldHandle CSchemaColorDefHandle; +typedef CSchemaFieldHandle CSchemaMusicDefHandle; +typedef CSchemaFieldHandle CSchemaAttributeDefHandle; +typedef CSchemaFieldHandle CSchemaItemDefHandle; +typedef CSchemaFieldHandle CSchemaLootListDefHandle; + +inline const CEconItemAttributeDefinition* static_attrib_t::GetAttributeDefinition() const +{ + return GEconItemSchema().GetAttributeDefinition(iDefIndex); +} + +int StringFieldToInt(const char* szValue, const char** pValueStrings, int iNumStrings, bool bDontAssert = false); +int StringFieldToInt(const char* szValue, const CUtlVector& vecValueStrings, bool bDontAssert = false); + +enum EStickerAttributeType +{ + k_EStickerAttribute_ID, + k_EStickerAttribute_Wear, + k_EStickerAttribute_Scale, + k_EStickerAttribute_Rotation, + k_EStickerAttribute_Count, +}; +const int g_nNumStickerAttrs = 6; +const CSchemaAttributeDefHandle& GetStickerAttributeDefHandle(int attrNum, EStickerAttributeType type); + +enum ECampaignAttributeType +{ + k_ECampaignAttribute_CompletionBitfield, + k_ECampaignAttribute_LastCompletedQuest, + +}; +const int g_nNumCampaigns = 8; +const CSchemaAttributeDefHandle& GetCampaignAttributeDefHandle(int nCampaignID, ECampaignAttributeType type); + +extern const uint32 g_unNumWearBuckets; +uint64 Helper_GetAlternateIconKeyForWeaponPaintWearItem(item_definition_index_t nDefIdx, uint32 nPaintId, uint32 nWear); + +uint64 Helper_GetAlternateIconKeyForTintedStickerItem(uint32 nStickerKitID, uint32 unTintID); + + +#endif +``` + +`SpyCustom/sdk/econ_item_view.h`: + +```h +#ifndef ECON_ITEM_CONSTANTS_H +#define ECON_ITEM_CONSTANTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "game_item_schema.h" +#include "econ_item_constants.h" +#include "localization_provider.h" +#include "econ_item_interface.h" +#include "econ_item.h" +#include "utlhashtable.h" + +#if defined(CLIENT_DLL) +#include "iclientrenderable.h" + +#if defined(CSTRIKE15) +#include "custommaterialowner.h" +#endif + +#include "icompositetexturegenerator.h" + +#endif + +#include "MaterialSystemUtil.h" + +#if defined(TF_DLL) +#include "tf_item_schema.h" +#endif + +#if defined(CLIENT_DLL) +#define CEconItemView C_EconItemView + +#if defined(CSTRIKE15) +typedef void (*ImageReadyCallback_t)(const CEconItemView* pItemView, CUtlBuffer& rawImageRgba, int nWidth, int nHeight, uint64 nItemID); +struct RenderToRTData_t; +class CMergedMDL; +#endif + +#endif + +#include "econ_item_view_helpers.h" + +#define RGB_INT_RED 12073019 +#define RGB_INT_BLUE 5801378 +#define ECON_ITEM_GENERATED_ICON_WIDTH 512 +#define ECON_ITEM_GENERATED_ICON_HEIGHT 384 +#define ECON_ITEM_GENERATED_PINBOARD_ICON_WIDTH 512 +#define ECON_ITEM_GENERATED_PINBOARD_ICON_HEIGHT 384 +#define ECON_ITEM_GENERATED_ICON_DIR "resource/Flash/econ/weapons/cached/" + +#define SCHEMA_BASE_ITEM_MAX 499 + +class CEconItemAttribute; +class CAttributeManager; + +#if defined(CSTRIKE_CLIENT_DLL) +class IVisualsDataProcessor; +#endif + +struct stickerMaterialReference_t +{ + CMaterialReference m_pMaterialReferenceFirstPerson; + CMaterialReference m_pMaterialReferenceThirdPerson; + int m_nSlotIndex; +}; + +class CAttributeList +{ + friend class CEconItemView; + friend class CTFPlayer; + + DECLARE_CLASS_NOBASE(CAttributeList); +public: + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_DATADESC(); + + CAttributeList(); + CAttributeList& operator=(const CAttributeList& src); + + void Init(); + void SetManager(CAttributeManager* pManager); + + void IterateAttributes(class IEconItemAttributeIterator* pIterator); + + void DestroyAllAttributes(void); + +private: + void AddAttribute(CEconItemAttribute* pAttribute); + void SetOrAddAttributeValueByName(const char* pszAttribDefName, float flValue); + + void RemoveAttribute(const char* pszAttribDefName); + void RemoveAttributeByIndex(int iIndex); + +public: + CEconItemAttribute* GetAttributeByName(const char* pszAttribDefName); + const CEconItemAttribute* GetAttributeByName(const char* pszAttribDefName) const; + + CEconItemAttribute* GetAttributeByClass(const char* szAttribClass); + const CEconItemAttribute* GetAttributeByClass(const char* szAttribClass) const; + + CEconItemAttribute* GetAttributeByDefIndex(uint16 unAttrDefIndex); + const CEconItemAttribute* GetAttributeByDefIndex(uint16 unAttrDefIndex) const; + + + void SetValue(CEconItemAttribute* pAttrib, float flValue); + + void UpdateManagerCache(void); + +private: + int GetNumAttributes(void) const { return m_Attributes.Count(); } + CEconItemAttribute* GetAttribute(int iIndex) { Assert(iIndex >= 0 && iIndex < m_Attributes.Count()); return &m_Attributes[iIndex]; } + const CEconItemAttribute* GetAttribute(int iIndex) const { Assert(iIndex >= 0 && iIndex < m_Attributes.Count()); return &m_Attributes[iIndex]; } + + CUtlVector m_Attributes; + + CAttributeManager* m_pManager; +}; + +class CEconItemAttribute +{ + DECLARE_CLASS_NOBASE(CEconItemAttribute); +public: + DECLARE_EMBEDDED_NETWORKVAR(); + + CEconItemAttribute(const attrib_definition_index_t iAttributeIndex, float flValue); + CEconItemAttribute(const attrib_definition_index_t iAttributeIndex, uint32 unValue); + + CEconItemAttribute& operator=(const CEconItemAttribute& val); + attrib_definition_index_t GetAttribIndex(void) const { return m_iAttributeDefinitionIndex; } + void SetAttribIndex(attrib_definition_index_t iIndex) { m_iAttributeDefinitionIndex = iIndex; } + + const CEconItemAttributeDefinition* GetStaticData(void) const; + + float GetValue(void) const; + + uint32 GetIntValue(void) const; + + float GetInitialValue(void) const { return m_flInitialValue; } + int GetRefundableCurrency(void) const { return m_nRefundableCurrency; } + void AddRefundableCurrency(int nAdd) { m_nRefundableCurrency += nAdd; } + void RemovedRefundableCurrency(int nSubtract) { m_nRefundableCurrency -= nSubtract; } + + bool GetSetBonus(void) { return m_bSetBonus; } + void SetSetBonus(bool bBonus) { m_bSetBonus = bBonus; } + +private: + void SetValue(float flValue); + + void SetIntValue(uint32 unValue); + + friend class CAttributeList; + friend class CEconItemSystem; + + void Init(void); + +private: + CNetworkVar(attrib_definition_index_t, m_iAttributeDefinitionIndex); + + CNetworkVar(float, m_flValue); + + CNetworkVar(float, m_flInitialValue); + CNetworkVar(int, m_nRefundableCurrency); + + CNetworkVar(bool, m_bSetBonus); + +public: + CEconItemAttribute(void); +}; + +#if defined(CLIENT_DLL) +class CEconItemView : public CDefaultClientRenderable, public IEconItemInterface, public CCustomMaterialOwner +#else +class CEconItemView : public IEconItemInterface +#endif +{ +#if defined(CLIENT_DLL) || defined(GAME_DLL) + DECLARE_CLASS_NOBASE(CEconItemView); +public: + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_DATADESC(); +#endif + +public: + CEconItemView(); + CEconItemView(const CEconItemView& src); + virtual ~CEconItemView(); + CEconItemView& operator=(const CEconItemView& src); + bool operator==(const CEconItemView& other) const; + bool operator!=(const CEconItemView& other) const { return !operator==(other); } + + virtual const GameItemDefinition_t* GetItemDefinition() const + { + return GetStaticData(); + } + +public: + + virtual int32 GetQuality() const; + virtual int32 GetRarity() const; + virtual style_index_t GetStyle() const; + virtual uint8 GetFlags() const; + virtual eEconItemOrigin GetOrigin() const; + virtual uint16 GetQuantity() const; + + virtual const char* GetCustomName() const; + virtual const char* GetCustomDesc() const; + + virtual int GetItemSetIndex() const; + + virtual bool GetInUse() const { return GetSOCData() ? GetSOCData()->GetInUse() : false; } + + virtual void IterateAttributes(class IEconItemAttributeIterator* pIterator) const OVERRIDE; + + bool IsValid(void) const { return m_bInitialized; } + void Invalidate(void); + + void Init(int iDefIndex, int iQuality, int iLevel, uint32 iAccountID = 0); + void SetInitialized(bool bInit) { m_bInitialized = bInit; } + bool Init(CEconItem* pItem); + + const GameItemDefinition_t* GetStaticData(void) const; + + void SetNonSOEconItem(CEconItem* pItem) { m_pNonSOEconItem = pItem; } + + void MarkDescriptionDirty(void); + + virtual bool IsStyleUnlocked(int iStyle) const; + +private: + void EnsureDescriptionIsBuilt(void) const; +public: + void SetGrayedOutReason(const char* pszGrayedOutReason); + + void SetItemIndex(item_definition_index_t iIndex) { m_iItemDefinitionIndex = iIndex; MarkDescriptionDirty(); } + item_definition_index_t GetItemIndex(void) const { return m_iItemDefinitionIndex; } + + void SetItemQuality(int iQuality) { m_iEntityQuality = iQuality; MarkDescriptionDirty(); } + int GetItemQuality(void) const { return m_iEntityQuality; } + void SetItemLevel(uint32 unLevel) { m_iEntityLevel = unLevel; MarkDescriptionDirty(); } + uint32 GetItemLevel(void) const { return m_iEntityLevel; } + + int GetItemQuantity() const; +#ifdef CLIENT_DLL + void SetIsStoreItem(bool bIsStoreItem) { m_bIsStoreItem = bIsStoreItem; MarkDescriptionDirty(); } + void SetIsTradeItem(bool bIsTradeItem) { m_bIsTradeItem = bIsTradeItem; MarkDescriptionDirty(); } + void SetItemQuantity(int iQuantity) { m_iEntityQuantity = iQuantity; MarkDescriptionDirty(); } + void SetClientItemFlags(uint8 unFlags); + void SetItemRarityOverride(int iRarity) { m_iRarityOverride = iRarity; MarkDescriptionDirty(); } + void SetItemQualityOverride(int iQuality) { m_iQualityOverride = iQuality; MarkDescriptionDirty(); } + void SetItemStyleOverride(style_index_t unNewStyleOverride); +#endif + style_index_t GetItemStyle() const; + + void SetItemID(itemid_t iIdx) { m_iItemID = iIdx; m_iItemIDHigh = (m_iItemID >> 32); m_iItemIDLow = (m_iItemID & 0xFFFFFFFF); } +#ifdef CLIENT_DLL + virtual itemid_t GetItemID(void) const { uint64 iTmp = ((((int64)m_iItemIDHigh) << 32) | m_iItemIDLow); return (itemid_t)iTmp; } +#else + itemid_t GetItemID(void) const { return m_iItemID; } +#endif + uint32 GetItemIDHigh(void) const { return m_iItemIDHigh; } + uint32 GetItemIDLow(void) const { return m_iItemIDLow; } + + itemid_t GetFauxItemIDFromDefinitionIndex(void) const; + + uint32 GetAccountID(void) const { return m_iAccountID; } + + void SetInventoryPosition(uint32 iPosition) { m_iInventoryPosition = iPosition; } + const uint32 GetInventoryPosition(void) const { return m_iInventoryPosition; } + + const char* GetInventoryModel(void); + const char* GetInventoryImage(void) const; + bool HasGeneratedInventoryImage(void) const; + bool GetInventoryImageData(int* iPosition, int* iSize); + const char* GetInventoryOverlayImage(int idx); + int GetInventoryOverlayImageCount(void); + + IMaterial* GetToolStickerMaterial(void); + bool IsStickerTool(void); + + const char* GetPlayerDisplayModel(int iClass = 0) const; + + const char* GetWorldDisplayModel(); + const char* GetExtraWearableModel(); + const char* GetIconDisplayModel(); + const char* GetBuyMenuDisplayModel(); + const char* GetWorldDroppedModel(); + const char* GetPedestalDisplayModel(); + const char* GetMagazineModel(); + + const char* GetScopeLensMaskModel(); + + const char* GetStatTrakModelByType(int nStatTrakType); + + const char* GetUidModel(); + + int GetAnimationSlot(void); + + int GetDropType(void); + + void DestroyAllAttributes(void); + + void AddAttribute(CEconItemAttribute* pAttribute); + + void SetOrAddAttributeValueByName(const char* pszAttribDefName, float flValue); + + void InitNetworkedDynamicAttributesForDemos(void); + void UpdateNetworkedDynamicAttributesForDemos(attrib_definition_index_t nDef, float flNewValue); + +#if defined(CSTRIKE_CLIENT_DLL) + void UpdateGeneratedMaterial(bool bIgnorePicMip = false, CompositeTextureSize_t diffuseTextureSize = COMPOSITE_TEXTURE_SIZE_512); +#endif + + const char* GetStickerSlotModelBySlotIndex(int nIndex); + int GetNumSupportedStickerSlots(void); + Vector GetStickerSlotWorldProjectionStartBySlotIndex(int nIndex); + Vector GetStickerSlotWorldProjectionEndBySlotIndex(int nIndex); + const char* GetStickerWorldModelBoneParentNameBySlotIndex(int nIndex); + const char* GetStickerSlotMaterialBySlotIndex(int nIndex); + IMaterial* GetStickerIMaterialBySlotIndex(int nIndex, bool bThirdPerson = false); + void GenerateStickerMaterials(void); + bool ItemHasAnyStickersApplied(void); + bool ItemHasAnyFreeStickerSlots(void); + int GetStickerSlotFirstFreeFromIndex(int nIndex = 0); + + + void SetCustomNameOverride(const char* pszCustomName); + + virtual void GenerateKillEaterTypeVector(void); + virtual void GetKillEaterTypes(CUtlSortVector& types); + virtual int32 GetKillEaterValueByType(uint32 uKillEaterType); + + + bool m_bKillEaterTypesCached; + CUtlSortVector m_vCachedKillEaterTypes; + int m_nKillEaterValuesCacheFrame; + CUtlHashtable m_vCachedKillEaterValues; + +private: + void Cleanup(void); + +#if defined(CSTRIKE_CLIENT_DLL) + void CreateCustomWeaponMaterials(int nWeaponId, bool bIgnorePicMip, CompositeTextureSize_t diffuseTextureSize = COMPOSITE_TEXTURE_SIZE_512); + void CreateCustomClothingMaterials(const char* pchSkinIdent, int nSlotId, int nTeam, bool bIgnorePicMip, CompositeTextureSize_t diffuseTextureSize = COMPOSITE_TEXTURE_SIZE_512); + +public: + void Update(void); + void SaveInventoryImageAsPNG(int nWidth, int nHeight); + const CUtlBuffer* GetInventoryImageRgba(int nWidth, int nHeight, ImageReadyCallback_t pImageReadyCallback); + bool CanGenerateInventoryImageRgba(void); + void ClearInventoryImageRgba(void); + bool LoadCachedInventoryImage(void); + void SaveInventoryImage(CUtlBuffer& rawImageRgba); + void GenerateCachedInventoryImageName(); + + static void CleanInventoryImageCacheDir(void); + + void FinishLoadCachedInventoryImage(void* pData, int numReadBytes, FSAsyncStatus_t asyncStatus); + + enum AsyncFixupState_t + { + AFS_Init, + AFS_LoadingInProgress, + AFS_LoadingDone, + AFS_FixupDone, + } m_asyncFixupState; + + int m_nNumAsyncReadBytes; + FSAsyncStatus_t m_asyncStatus; + CUtlBuffer m_inventoryImageRgba; + +private: + static bool m_sbHasCleanedInventoryImageCacheDir; + + bool m_bInventoryImageRgbaRequested; + bool m_bInventoryImageTriedCache; + ImageReadyCallback_t m_pImageReadyCallback; + int m_nInventoryImageRgbaWidth; + int m_nInventoryImageRgbaHeight; + + FSAsyncControl_t m_hAsyncControl; + + char m_szCurrentLoadCachedFileName[MAX_PATH]; + + RenderToRTData_t* m_pRenderToRTData; + IVTFTexture* m_pScratchVTF; + CMergedMDL* m_pRenderToRTMDL; +#endif + + CUtlVector< stickerMaterialReference_t > m_pStickerMaterials; + + + + + void RemoveAttribute(const char* pszAttribDefName); + +public: + + const bool GetCombinedAttributeClassValue(float& flValue, string_t iszAttribClass) const; + + CEconItemAttribute* GetAttributeByClass(const char* szAttribClass); + const CEconItemAttribute* GetAttributeByClass(const char* szAttribClass) const; + CEconItemAttribute* GetAttributeByDefIndex(int iAttributeDefIndex); + const CEconItemAttribute* GetAttributeByDefIndex(int iAttributeDefIndex) const; + CEconItemAttribute* GetAttributeByName(const char* pszAttribDefName); + const CEconItemAttribute* GetAttributeByName(const char* pszAttribDefName) const; + + int GetNumAttributes(void) const { return m_AttributeList.GetNumAttributes(); } + CEconItemAttribute* GetAttribute(int iIndex) { return m_AttributeList.GetAttribute(iIndex); } + const CEconItemAttribute* GetAttribute(int iIndex) const { return m_AttributeList.GetAttribute(iIndex); } + CAttributeList* GetAttributeList(void) { return m_AttributeList.Get(); } + const CAttributeList* GetAttributeList(void) const { return m_AttributeList.Get(); } + + int GetModifiedRGBValue(bool bAltColor = false); + int GetCustomPaintKitIndex(void) const; + + const char* GetCustomPaintKitDbgName(void) const; + + bool CanCollect(CEconItemView& subject); + + uint64 GetCustomUserTextureID(); + const CPaintKit* GetCustomPaintKit(void) const; + + CEconItem* GetSOCData(void) const; + + bool IsEquipped(void) const { return GetSOCData() && GetSOCData()->IsEquipped(); } + bool IsEquippedForClass(equipped_class_t unClass) const { return GetSOCData() && GetSOCData()->IsEquippedForClass(unClass); } + void UpdateEquippedState(equipped_class_t unClass, equipped_slot_t unSlot) { if (GetSOCData()) { GetSOCData()->UpdateEquippedState(unClass, unSlot); } } + equipped_slot_t GetEquippedPositionForClass(equipped_class_t unClass) const { return GetSOCData() ? GetSOCData()->GetEquippedPositionForClass(unClass) : INVALID_EQUIPPED_SLOT; } + + EItemSlot GetSlot(void) const { return EItemSlotFromName(GetItemDefinition()->GetRawDefinition()->GetString("item_slot")); } + + int GetQualityParticleType(); + + int GetSkin() const; + +#if defined(CSTRIKE_CLIENT_DLL) + IVisualsDataProcessor* GetVisualsDataProcessor(int nIndex) { return (nIndex < m_ppVisualsDataProcessors.Count()) ? m_ppVisualsDataProcessors[nIndex] : NULL; } + IVisualsDataProcessor* GetVisualsDataProcessorByName(const char* szName) const; + + static CEconItemView* FindOrCreateEconItemViewForItemID(uint64 uiItemId); +#else + typedef CUtlMap< itemid_t, uint64, int, CDefLess< itemid_t > > UtlMapLookupByID_t; + static UtlMapLookupByID_t s_mapLookupByID; +#endif + +#if defined ( GAME_DLL ) + void UpdateNetworkedCustomName(); +#endif + +protected: + CNetworkVar(item_definition_index_t, m_iItemDefinitionIndex); + + CNetworkVar(int, m_iEntityQuality); + + CNetworkVar(uint32, m_iEntityLevel); + + itemid_t m_iItemID; + CNetworkVar(uint32, m_iItemIDHigh); + CNetworkVar(uint32, m_iItemIDLow); + + CNetworkVar(uint32, m_iAccountID); + + CNetworkVar(uint32, m_iInventoryPosition); + + CEconItem* m_pNonSOEconItem; + + CNetworkVar(bool, m_bInitialized); + +#if defined( CLIENT_DLL ) + bool m_bIsStoreItem; + bool m_bIsTradeItem; + int m_iEntityQuantity; + int m_iRarityOverride; + int m_iQualityOverride; + uint8 m_unClientFlags; + + style_index_t m_unOverrideStyle; + +public: + const wchar_t* GetItemName(bool bUncustomized = false) const; + + const class CEconItemDescription* GetDescription() const { EnsureDescriptionIsBuilt(); return m_pDescription; } + +private: + mutable class CEconItemDescription* m_pDescription; + mutable char* m_pszGrayedOutReason; + +#endif +#if defined(CSTRIKE_CLIENT_DLL) + CUtlVector< IVisualsDataProcessor* > m_ppVisualsDataProcessors; +#endif + +protected: + +#if defined(CLIENT_DLL) + virtual const Vector& GetRenderOrigin(void) { return vec3_origin; } + virtual const QAngle& GetRenderAngles(void) { return vec3_angle; } + virtual bool ShouldDraw(void) { return false; } + virtual bool IsTransparent(void) { return false; } + virtual const matrix3x4_t& RenderableToWorldTransform() { static matrix3x4_t mat; SetIdentityMatrix(mat); return mat; } + virtual void GetRenderBounds(Vector& mins, Vector& maxs) { return; } +#endif + +private: + CNetworkVarEmbedded(CAttributeList, m_AttributeList); + CNetworkVarEmbedded(CAttributeList, m_NetworkedDynamicAttributesForDemos); + + CNetworkString(m_szCustomName, MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE); + + char m_szCustomNameOverride[MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE]; + GCSDK::CAutoPtr< char > m_autoptrInventoryImageGeneratedPath; +}; + +#endif +``` + +`SpyCustom/sdk/edict.h`: + +```h +#ifndef EDICT_H +#define EDICT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" +#include "cmodel.h" +#include "const.h" +#include "iserverentity.h" +#include "globalvars_base.h" +#include "ICollideable.h" +#include "iservernetworkable.h" +#include "bitvec.h" +#include "convar.h" + +struct edict_t; + + +enum MapLoadType_t +{ + MapLoad_NewGame = 0, + MapLoad_LoadGame, + MapLoad_Transition, + MapLoad_Background, +}; + + +class CGlobalVars : public CGlobalVarsBase +{ +public: + + CGlobalVars(bool bIsClient); + +public: + + string_t mapname; + string_t mapGroupName; + int mapversion; + string_t startspot; + MapLoadType_t eLoadType; + bool bMapLoadFailed; + + bool deathmatch; + bool coop; + bool teamplay; + int maxEntities; + + int serverCount; + edict_t* pEdicts; +}; + +inline CGlobalVars::CGlobalVars(bool bIsClient) : + CGlobalVarsBase(bIsClient) +{ + serverCount = 0; +} + + +class CPlayerState; +class IServerNetworkable; +class IServerEntity; + + +#define FL_EDICT_CHANGED (1<<0) +#define FL_EDICT_FREE (1<<1) +#define FL_EDICT_FULL (1<<2) + +#define FL_EDICT_FULLCHECK (0<<0) +#define FL_EDICT_ALWAYS (1<<3) +#define FL_EDICT_DONTSEND (1<<4) +#define FL_EDICT_PVSCHECK (1<<5) + +#define FL_EDICT_PENDING_DORMANT_CHECK (1<<6) + +#define FL_EDICT_DIRTY_PVS_INFORMATION (1<<7) + +#define FL_FULL_EDICT_CHANGED (1<<8) + + +#define MAX_CHANGE_OFFSETS 19 +#define MAX_EDICT_CHANGE_INFOS 100 + + +class CEdictChangeInfo +{ +public: + unsigned short m_ChangeOffsets[MAX_CHANGE_OFFSETS]; + unsigned short m_nChangeOffsets; +}; + +class CSharedEdictChangeInfo +{ +public: + CSharedEdictChangeInfo() + { + m_iSerialNumber = 1; + } + + unsigned short m_iSerialNumber; + +#ifdef NETWORK_VARS_ENABLED + CEdictChangeInfo m_ChangeInfos[MAX_EDICT_CHANGE_INFOS]; + unsigned short m_nChangeInfos; +#endif +}; +extern CSharedEdictChangeInfo* g_pSharedChangeInfo; + +class IChangeInfoAccessor +{ +public: + inline void SetChangeInfo(unsigned short info) + { + m_iChangeInfo = info; + } + + inline void SetChangeInfoSerialNumber(unsigned short sn) + { + m_iChangeInfoSerialNumber = sn; + } + + inline unsigned short GetChangeInfo() const + { + return m_iChangeInfo; + } + + inline unsigned short GetChangeInfoSerialNumber() const + { + return m_iChangeInfoSerialNumber; + } + +private: + unsigned short m_iChangeInfo; + unsigned short m_iChangeInfoSerialNumber; +}; + +class CBaseEdict +{ +public: + + IServerEntity* GetIServerEntity(); + const IServerEntity* GetIServerEntity() const; + + IServerNetworkable* GetNetworkable(); + IServerUnknown* GetUnknown(); + + void SetEdict(IServerUnknown* pUnk, bool bFullEdict); + + int AreaNum() const; + const char* GetClassName() const; + + bool IsFree() const; + void SetFree(); + void ClearFree(); + + bool HasStateChanged() const; + void ClearStateChanged(); + void StateChanged(); + void StateChanged(unsigned short offset); + + void ClearTransmitState(); + + void SetChangeInfo(unsigned short info); + void SetChangeInfoSerialNumber(unsigned short sn); + unsigned short GetChangeInfo() const; + unsigned short GetChangeInfoSerialNumber() const; + +public: + +#ifdef _XBOX + unsigned short m_fStateFlags; +#else + int m_fStateFlags; +#endif + + int m_NetworkSerialNumber; + + IServerNetworkable* m_pNetworkable; + +protected: + IServerUnknown* m_pUnk; + + +public: + + IChangeInfoAccessor* GetChangeAccessor(); + const IChangeInfoAccessor* GetChangeAccessor() const; + friend void InitializeEntityDLLFields(edict_t* pEdict); +}; + + +inline IServerEntity* CBaseEdict::GetIServerEntity() +{ + if (m_fStateFlags & FL_EDICT_FULL) + return (IServerEntity*)m_pUnk; + else + return 0; +} + +inline bool CBaseEdict::IsFree() const +{ + return (m_fStateFlags & FL_EDICT_FREE) != 0; +} + + + +inline bool CBaseEdict::HasStateChanged() const +{ + return (m_fStateFlags & FL_EDICT_CHANGED) != 0; +} + +inline void CBaseEdict::ClearStateChanged() +{ + m_fStateFlags &= ~(FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED); + SetChangeInfoSerialNumber(0); +} + +inline void CBaseEdict::StateChanged() +{ + m_fStateFlags |= (FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED); +} + +inline void CBaseEdict::StateChanged(unsigned short offset) +{ +#ifdef NETWORK_VARS_ENABLED + if (m_fStateFlags & FL_FULL_EDICT_CHANGED) + return; + + m_fStateFlags |= FL_EDICT_CHANGED; + + IChangeInfoAccessor* accessor = GetChangeAccessor(); + + if (accessor->GetChangeInfoSerialNumber() == g_pSharedChangeInfo->m_iSerialNumber) + { + CEdictChangeInfo* p = &g_pSharedChangeInfo->m_ChangeInfos[accessor->GetChangeInfo()]; + + for (unsigned short i = 0; i < p->m_nChangeOffsets; i++) + if (p->m_ChangeOffsets[i] == offset) + return; + + if (p->m_nChangeOffsets == MAX_CHANGE_OFFSETS) + { + accessor->SetChangeInfoSerialNumber(0); + m_fStateFlags |= FL_FULL_EDICT_CHANGED; + } + else + { + p->m_ChangeOffsets[p->m_nChangeOffsets++] = offset; + } + } + else + { + if (g_pSharedChangeInfo->m_nChangeInfos == MAX_EDICT_CHANGE_INFOS) + { + accessor->SetChangeInfoSerialNumber(0); + m_fStateFlags |= FL_FULL_EDICT_CHANGED; + } + else + { + accessor->SetChangeInfo(g_pSharedChangeInfo->m_nChangeInfos); + g_pSharedChangeInfo->m_nChangeInfos++; + + accessor->SetChangeInfoSerialNumber(g_pSharedChangeInfo->m_iSerialNumber); + + CEdictChangeInfo* p = &g_pSharedChangeInfo->m_ChangeInfos[accessor->GetChangeInfo()]; + p->m_ChangeOffsets[0] = offset; + p->m_nChangeOffsets = 1; + } + } +#else + StateChanged(); +#endif +} + + + +inline void CBaseEdict::SetFree() +{ + m_fStateFlags |= FL_EDICT_FREE; +} + +inline void CBaseEdict::ClearFree() +{ + m_fStateFlags &= ~FL_EDICT_FREE; +} + +inline void CBaseEdict::ClearTransmitState() +{ + m_fStateFlags &= ~(FL_EDICT_ALWAYS | FL_EDICT_PVSCHECK | FL_EDICT_DONTSEND); +} + +inline const IServerEntity* CBaseEdict::GetIServerEntity() const +{ + if (m_fStateFlags & FL_EDICT_FULL) + return (IServerEntity*)m_pUnk; + else + return 0; +} + +inline IServerUnknown* CBaseEdict::GetUnknown() +{ + return m_pUnk; +} + +inline IServerNetworkable* CBaseEdict::GetNetworkable() +{ + return m_pNetworkable; +} + +inline void CBaseEdict::SetEdict(IServerUnknown* pUnk, bool bFullEdict) +{ + m_pUnk = pUnk; + if ((pUnk != NULL) && bFullEdict) + { + m_fStateFlags = FL_EDICT_FULL; + } + else + { + m_fStateFlags = 0; + } +} + +inline int CBaseEdict::AreaNum() const +{ + if (!m_pUnk) + return 0; + + return m_pNetworkable->AreaNum(); +} + +inline const char* CBaseEdict::GetClassName() const +{ + if (!m_pUnk) + return ""; + return m_pNetworkable->GetClassName(); +} + +inline void CBaseEdict::SetChangeInfo(unsigned short info) +{ + GetChangeAccessor()->SetChangeInfo(info); +} + +inline unsigned short CBaseEdict::GetChangeInfo() const +{ + return GetChangeAccessor()->GetChangeInfo(); +} + +inline unsigned short CBaseEdict::GetChangeInfoSerialNumber() const +{ + return GetChangeAccessor()->GetChangeInfoSerialNumber(); +} + +struct edict_t : public CBaseEdict +{ +public: + ICollideable* GetCollideable(); +}; + +inline ICollideable* edict_t::GetCollideable() +{ + IServerEntity* pEnt = GetIServerEntity(); + if (pEnt) + return pEnt->GetCollideable(); + else + return NULL; +} + + +#endif +``` + +`SpyCustom/sdk/ehandle.h`: + +```h +#ifndef EHANDLE_H +#define EHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( _DEBUG ) && defined( GAME_DLL ) +#include "tier0/dbg.h" +#include "cbase.h" +#endif + + +#include "const.h" +#include "basehandle.h" +#include "entitylist_base.h" + +#include "icliententitylist.h" +class IHandleEntity; + + +inline IHandleEntity* CBaseHandle::Get() const +{ + extern IClientEntityList* g_pEntityList; + return ((CBaseEntityList*)g_pEntityList)->LookupEntity(*this); +} + + +template< class T > +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 +inline CHandle CHandle::FromIndex(int index) +{ + CHandle ret; + ret.m_Index = index; + return ret; +} + + +template +inline T* CHandle::Get() const +{ + return (T*)CBaseHandle::Get(); +} + + +template +inline CHandle::operator T* () +{ + return Get(); +} + +template +inline CHandle::operator T* () const +{ + return Get(); +} + + +template +inline bool CHandle::operator !() const +{ + return !Get(); +} + +template +inline bool CHandle::operator==(T* val) const +{ + return Get() == val; +} + +template +inline bool CHandle::operator!=(T* val) const +{ + return Get() != val; +} + +template +void CHandle::Set(const T* pVal) +{ + CBaseHandle::Set(reinterpret_cast(pVal)); +} + +template +inline const CBaseHandle& CHandle::operator=(const T* val) +{ + Set(val); + return *this; +} + +template +T* CHandle::operator -> () const +{ + return Get(); +} + + +#endif +``` + +`SpyCustom/sdk/eiface.h`: + +```h +#ifndef EIFACE_H +#define EIFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "icvar.h" +#include "edict.h" +#include "vplane.h" +#include "iserverentity.h" +#include "ivmodelinfo.h" +#include "soundflags.h" +#include "bitvec.h" +#include "iserverplugin.h" +#include "bitbuf.h" +#include "checksum_crc.h" +#include "iclient.h" + +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct typedescription_t; +class CSaveRestoreData; +struct datamap_t; +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +struct studiohdr_t; +class CBaseEntity; +class CRestore; +class CSave; +class variant_t; +struct vcollide_t; +class IRecipientFilter; +class CBaseEntity; +class ITraceFilter; +struct client_textmessage_t; +class INetChannelInfo; +class ISpatialPartition; +class IScratchPad3D; +class CStandardSendProxies; +class IAchievementMgr; +class CGamestatsData; +class CSteamID; +class ISPSharedMemory; +class CGamestatsData; +class CEngineHltvInfo_t; +class INetMessage; +class HltvReplayParams_t; + +namespace google +{ + namespace protobuf + { + class Message; + } +} + +typedef struct player_info_s player_info_t; + +typedef uint64 PublishedFileId_t; + +#ifdef _WIN32 +#define DLLEXPORT __stdcall +#else +#define DLLEXPORT +#endif + +#define INTERFACEVERSION_VENGINESERVER "VEngineServer023" + +struct bbox_t +{ + Vector mins; + Vector maxs; +}; + +abstract_class IVEngineServer +{ +public: + virtual void ChangeLevel(const char* s1, const char* s2) = 0; + + virtual int IsMapValid(const char* filename) = 0; + + virtual bool IsDedicatedServer(void) = 0; + + virtual int IsInEditMode(void) = 0; + + virtual KeyValues* GetLaunchOptions(void) = 0; + + virtual int PrecacheModel(const char* s, bool preload = false) = 0; + virtual int PrecacheSentenceFile(const char* s, bool preload = false) = 0; + virtual int PrecacheDecal(const char* name, bool preload = false) = 0; + virtual int PrecacheGeneric(const char* s, bool preload = false) = 0; + + virtual bool IsModelPrecached(char const* s) const = 0; + virtual bool IsDecalPrecached(char const* s) const = 0; + virtual bool IsGenericPrecached(char const* s) const = 0; + + virtual int GetClusterForOrigin(const Vector& org) = 0; + virtual int GetPVSForCluster(int cluster, int outputpvslength, unsigned char* outputpvs) = 0; + virtual bool CheckOriginInPVS(const Vector& org, const unsigned char* checkpvs, int checkpvssize) = 0; + virtual bool CheckBoxInPVS(const Vector& mins, const Vector& maxs, const unsigned char* checkpvs, int checkpvssize) = 0; + + virtual int GetPlayerUserId(const edict_t* e) = 0; + virtual const char* GetPlayerNetworkIDString(const edict_t* e) = 0; + virtual bool IsUserIDInUse(int userID) = 0; + virtual int GetLoadingProgressForUserID(int userID) = 0; + + virtual int GetEntityCount(void) = 0; + + virtual INetChannelInfo* GetPlayerNetInfo(int playerIndex) = 0; + + virtual edict_t* CreateEdict(int iForceEdictIndex = -1) = 0; + virtual void RemoveEdict(edict_t* e) = 0; + + virtual void* PvAllocEntPrivateData(long cb) = 0; + virtual void FreeEntPrivateData(void* pEntity) = 0; + + virtual void* SaveAllocMemory(size_t num, size_t size) = 0; + virtual void SaveFreeMemory(void* pSaveMem) = 0; + + virtual void EmitAmbientSound(int entindex, const Vector& pos, const char* samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float delay = 0.0f) = 0; + + virtual void FadeClientVolume(const edict_t* pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds) = 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 ServerCommand(const char* str) = 0; + virtual void ServerExecute(void) = 0; + virtual void ClientCommand(edict_t* pEdict, const char* szFmt, ...) FMTFUNCTION(3, 4) = 0; + + virtual void LightStyle(int style, const char* val) = 0; + + virtual void StaticDecal(const Vector& originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority) = 0; + + virtual void Message_DetermineMulticastRecipients(bool usepas, const Vector& origin, CPlayerBitVec& playerbits) = 0; + + virtual bf_write* EntityMessageBegin(int ent_index, ServerClass* ent_class, bool reliable) = 0; + + virtual void MessageEnd(void) = 0; + + virtual void SendUserMessage(IRecipientFilter& filter, int message, const google::protobuf::Message& msg) = 0; + + virtual void ClientPrintf(edict_t* pEdict, const char* szMsg) = 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 void SetView(const edict_t* pClient, const edict_t* pViewent) = 0; + + virtual void CrosshairAngle(const edict_t* pClient, float pitch, float yaw) = 0; + + virtual void GetGameDir(char* szGetGameDir, int maxlength) = 0; + + virtual int CompareFileTime(const char* filename1, const char* filename2, int* iCompare) = 0; + + virtual bool LockNetworkStringTables(bool lock) = 0; + + virtual edict_t* CreateFakeClient(const char* netname) = 0; + + virtual const char* GetClientConVarValue(int clientIndex, const char* name) = 0; + + virtual const char* ParseFile(const char* data, char* token, int maxlen) = 0; + virtual bool CopyFile(const char* source, const char* destination) = 0; + + virtual void ResetPVS(byte* pvs, int pvssize) = 0; + virtual void AddOriginToPVS(const Vector& origin) = 0; + + virtual void SetAreaPortalState(int portalNumber, int isOpen) = 0; + + virtual void PlaybackTempEntity(IRecipientFilter& filter, float delay, const void* pSender, const SendTable* pST, int classID) = 0; + virtual int CheckHeadnodeVisible(int nodenum, const byte* pvs, int vissize) = 0; + virtual int CheckAreasConnected(int area1, int area2) = 0; + virtual int GetArea(const Vector& origin) = 0; + virtual void GetAreaBits(int area, unsigned char* bits, int buflen) = 0; + virtual bool GetAreaPortalPlane(Vector const& vViewOrigin, int portalKey, VPlane* pPlane) = 0; + + virtual bool LoadGameState(char const* pMapName, bool createPlayers) = 0; + virtual void LoadAdjacentEnts(const char* pOldLevel, const char* pLandmarkName) = 0; + virtual void ClearSaveDir() = 0; + + virtual const char* GetMapEntitiesString() = 0; + + virtual client_textmessage_t* TextMessageGet(const char* pName) = 0; + + virtual void LogPrint(const char* msg) = 0; + virtual bool IsLogEnabled() = 0; + virtual void BuildEntityClusterList(edict_t* pEdict, PVSInfo_t* pPVSInfo) = 0; + + virtual void SolidMoved(edict_t* pSolidEnt, ICollideable* pSolidCollide, const Vector* pPrevAbsOrigin, bool testSurroundingBoundsOnly) = 0; + virtual void TriggerMoved(edict_t* pTriggerEnt, bool testSurroundingBoundsOnly) = 0; + + virtual ISpatialPartition* CreateSpatialPartition(const Vector& worldmin, const Vector& worldmax) = 0; + virtual void DestroySpatialPartition(ISpatialPartition*) = 0; + + virtual void DrawMapToScratchPad(IScratchPad3D* pPad, unsigned long iFlags) = 0; + + virtual const CBitVec* GetEntityTransmitBitsForClient(int iClientIndex) = 0; + + virtual bool IsPaused() = 0; + + virtual float GetTimescale(void) const = 0; + + virtual void ForceExactFile(const char* s) = 0; + virtual void ForceModelBounds(const char* s, const Vector& mins, const Vector& maxs) = 0; + virtual void ClearSaveDirAfterClientLoad() = 0; + + virtual void SetFakeClientConVarValue(edict_t* pEntity, const char* cvar, const char* value) = 0; + + virtual void ForceSimpleMaterial(const char* s) = 0; + + virtual int IsInCommentaryMode(void) = 0; + + virtual bool IsLevelMainMenuBackground(void) = 0; + + virtual void SetAreaPortalStates(const int* portalNumbers, const int* isOpen, int nPortals) = 0; + + virtual void NotifyEdictFlagsChange(int iEdict) = 0; + + virtual const CCheckTransmitInfo* GetPrevCheckTransmitInfo(edict_t* pPlayerEdict) = 0; + + virtual CSharedEdictChangeInfo* GetSharedEdictChangeInfo() = 0; + + virtual void AllowImmediateEdictReuse() = 0; + + virtual bool IsInternalBuild(void) = 0; + + virtual IChangeInfoAccessor* GetChangeAccessor(const edict_t* pEdict) = 0; + + virtual char const* GetMostRecentlyLoadedFileName() = 0; + virtual char const* GetSaveFileName() = 0; + + virtual void CleanUpEntityClusterList(PVSInfo_t* pPVSInfo) = 0; + + virtual void SetAchievementMgr(IAchievementMgr*) = 0; + virtual IAchievementMgr* GetAchievementMgr() = 0; + + virtual int GetAppID() = 0; + + virtual bool IsLowViolence() = 0; + + virtual bool IsAnyClientLowViolence() = 0; + + virtual QueryCvarCookie_t StartQueryCvarValue(edict_t* pPlayerEntity, const char* pName) = 0; + + virtual void InsertServerCommand(const char* str) = 0; + + virtual bool GetPlayerInfo(int ent_num, player_info_t* pinfo) = 0; + + virtual bool IsClientFullyAuthenticated(edict_t* pEdict) = 0; + + virtual void SetDedicatedServerBenchmarkMode(bool bBenchmarkMode) = 0; + + virtual bool IsSplitScreenPlayer(int ent_num) = 0; + virtual edict_t* GetSplitScreenPlayerAttachToEdict(int ent_num) = 0; + virtual int GetNumSplitScreenUsersAttachedToEdict(int ent_num) = 0; + virtual edict_t* GetSplitScreenPlayerForEdict(int ent_num, int nSlot) = 0; + + virtual bool IsOverrideLoadGameEntsOn() = 0; + + virtual void ForceFlushEntity(int iEntity) = 0; + + virtual ISPSharedMemory* GetSinglePlayerSharedMemorySpace(const char* szName, int ent_num = MAX_EDICTS) = 0; + + virtual void* AllocLevelStaticData(size_t bytes) = 0; + + virtual int GetClusterCount() = 0; + virtual int GetAllClusterBounds(bbox_t* pBBoxList, int maxBBox) = 0; + + virtual bool IsCreatingReslist() = 0; + virtual bool IsCreatingXboxReslist() = 0; + virtual bool IsDedicatedServerForXbox() = 0; + virtual bool IsDedicatedServerForPS3() = 0; + + virtual void Pause(bool bPause, bool bForce = false) = 0; + + virtual void SetTimescale(float flTimescale) = 0; + + virtual void SetGamestatsData(CGamestatsData* pGamestatsData) = 0; + virtual CGamestatsData* GetGamestatsData() = 0; + + virtual const CSteamID* GetClientSteamID(const edict_t* pPlayerEdict, bool bValidatedIDOnly = false) = 0; + + virtual const CSteamID* GetGameServerSteamID() = 0; + + virtual void HostValidateSession() = 0; + + virtual void RefreshScreenIfNecessary() = 0; + + virtual bool HasPaintmap() = 0; + + virtual bool SpherePaintSurface(const model_t* pModel, const Vector&, unsigned char, float, float) = 0; + + virtual void SphereTracePaintSurface(const model_t* pModel, const Vector&, const Vector&, float, CUtlVector&) = 0; + + virtual void RemoveAllPaint() = 0; + + virtual void PaintAllSurfaces(unsigned char) = 0; + virtual void RemovePaint(const model_t* pModel) = 0; + + virtual void ClientCommandKeyValues(edict_t* pEdict, KeyValues* pCommand) = 0; + + virtual uint64 GetClientXUID(edict_t* pPlayerEdict) = 0; + virtual bool IsActiveApp() = 0; + + virtual void SetNoClipEnabled(bool bEnabled) = 0; + + virtual void GetPaintmapDataRLE(CUtlVector& mapdata) = 0; + virtual void LoadPaintmapDataRLE(CUtlVector& mapdata) = 0; + virtual void SendPaintmapDataToClient(edict_t* pEdict) = 0; + + virtual float GetLatencyForChoreoSounds() = 0; + + virtual CrossPlayPlatform_t GetClientCrossPlayPlatform(int ent_num) = 0; + + virtual void EnsureInstanceBaseline(int ent_num) = 0; + + virtual bool ReserveServerForQueuedGame(const char* szReservationPayload) = 0; + + virtual bool GetEngineHltvInfo(CEngineHltvInfo_t& out) = 0; + + virtual void AddHltvRelayProxyWhitelist(uint32 octet1, uint32 octet2, uint32 octet3, uint32 octet4, uint32 prefix) = 0; + + virtual int GetServerVersion() const = 0; + + virtual void UpdateHltvExternalViewers(uint32 totalSpectators, uint32 spectatorsLinkedToSteam) = 0; + + virtual bool WasShutDownRequested(void) const = 0; + virtual void* StartClientHltvReplay(int client , const HltvReplayParams_t&) = 0; + virtual void* StopClientHltvReplay(int client) = 0; + virtual int GetClientHltvReplayDelay(int client) = 0; + virtual bool HasHltvReplay(void) = 0; + virtual bool ClientCanStartHltvReplay(int client) = 0; + virtual int ClientResetReplayRequestTime(int client) = 0; + virtual bool AnyClientsInHltvReplayMode(void) = 0; +}; + +#define INTERFACEVERSION_SERVERGAMEDLL "ServerGameDLL005" + +abstract_class IServerGameDLL +{ +public: + virtual bool DLLInit(CreateInterfaceFn engineFactory, + CreateInterfaceFn physicsFactory, + CreateInterfaceFn fileSystemFactory, + CGlobalVars * pGlobals) = 0; + + virtual bool GameInit(void) = 0; + + virtual bool LevelInit(char const* pMapName, + char const* pMapEntities, char const* pOldLevel, + char const* pLandmarkName, bool loadGame, bool background) = 0; + + virtual void ServerActivate(edict_t* pEdictList, int edictCount, int clientMax) = 0; + + virtual void GameFrame(bool simulating) = 0; + + virtual void PreClientUpdate(bool simulating) = 0; + + virtual void LevelShutdown(void) = 0; + virtual void GameShutdown(void) = 0; + + virtual void DLLShutdown(void) = 0; + + virtual float GetTickInterval(void) const = 0; + + virtual ServerClass* GetAllServerClasses(void) = 0; + + virtual const char* GetGameDescription(void) = 0; + + virtual void CreateNetworkStringTables(void) = 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 SaveGlobalState(CSaveRestoreData*) = 0; + virtual void RestoreGlobalState(CSaveRestoreData*) = 0; + virtual void PreSave(CSaveRestoreData*) = 0; + virtual void Save(CSaveRestoreData*) = 0; + virtual void GetSaveComment(char* comment, int maxlength, float flMinutes, float flSeconds, bool bNoTime = false) = 0; + virtual void WriteSaveHeaders(CSaveRestoreData*) = 0; + virtual void ReadRestoreHeaders(CSaveRestoreData*) = 0; + virtual void Restore(CSaveRestoreData*, bool) = 0; + virtual bool IsRestoring() = 0; + virtual bool SupportsSaveRestore() = 0; + + virtual int CreateEntityTransitionList(CSaveRestoreData*, int) = 0; + virtual void BuildAdjacentMapList(void) = 0; + + virtual CStandardSendProxies* GetStandardSendProxies() = 0; + + virtual void PostInit() = 0; + virtual void Think(bool finalTick) = 0; + +#ifdef _XBOX + virtual void GetTitleName(const char* pMapName, char* pTitleBuff, int titleBuffSize) = 0; +#endif + + virtual void PreSaveGameLoaded(char const* pSaveName, bool bCurrentlyInGame) = 0; + + virtual bool ShouldHideServer(void) = 0; + + virtual void InvalidateMdlCache() = 0; + + virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t* pPlayerEntity, EQueryCvarValueStatus eStatus, const char* pCvarName, const char* pCvarValue) = 0; + + virtual void PostToolsInit() = 0; + + virtual void GameServerSteamAPIActivated(bool bActivated) = 0; + + virtual void ApplyGameSettings(KeyValues* pKV) = 0; + + virtual void GetMatchmakingTags(char* buf, size_t bufSize) = 0; + + virtual void ServerHibernationUpdate(bool bHibernating) = 0; + + virtual bool ShouldPreferSteamAuth() = 0; + + virtual bool ShouldAllowDirectConnect() = 0; + virtual bool FriendsReqdForDirectConnect() = 0; + virtual bool IsLoadTestServer() = 0; + virtual bool IsValveDS() = 0; + virtual KeyValues* GetExtendedServerInfoForNewClient() = 0; + virtual void UpdateGCInformation() = 0; + virtual void ReportGCQueuedMatchStart(int32 iReservationStage, uint32* puiConfirmedAccounts, int numConfirmedAccounts) = 0; + + virtual PublishedFileId_t GetUGCMapFileID(const char* mapName) = 0; + virtual void GetMatchmakingGameData(char* buf, size_t bufSize) = 0; + virtual bool HasPendingMapDownloads() const = 0; + virtual void UpdateUGCMap(PublishedFileId_t file) = 0; + virtual int GetMessageEncryptionKey(INetMessage* msg) = 0; + virtual bool ShouldHoldGameServerReservation(float flTime) = 0; + virtual bool OnPureServerFileValidationFailure(edict_t* pPlayer, const char* pszPathID, const char* pszFileName, + CRC32_t crcIOSequence, int eFileHashType, int cbFileLen, int nPackFileNumber, int nPackFileID) = 0; + virtual void PrecacheParticleSystemFile(const char* pszFilename) = 0; + virtual void ClientConnectionValidatePreNetChan(bool, const char*, int, unsigned long long) = 0; + virtual void OnEngineClientNetworkEvent(edict_t*, unsigned long long, int, void*) = 0; + virtual void GetNewestSubscribedFiles() = 0; + virtual bool ValidateAndAddActiveCaster(const CSteamID&) = 0; +}; + +#define VENGINE_SERVER_RANDOM_INTERFACE_VERSION "VEngineRandom001" + +#define INTERFACEVERSION_SERVERGAMEENTS "ServerGameEnts001" +abstract_class IServerGameEnts +{ +public: + virtual ~IServerGameEnts() {} + + virtual void MarkEntitiesAsTouching(edict_t * e1, edict_t * e2) = 0; + + virtual void FreeContainingEntity(edict_t*) = 0; + + virtual edict_t* BaseEntityToEdict(CBaseEntity* pEnt) = 0; + virtual CBaseEntity* EdictToBaseEntity(edict_t* pEdict) = 0; + + virtual void CheckTransmit(CCheckTransmitInfo* pInfo, const unsigned short* pEdictIndices, int nEdicts) = 0; + + virtual void PrepareForFullUpdate(edict_t* pEdict) = 0; +}; + +#define INTERFACEVERSION_SERVERGAMECLIENTS "ServerGameClients004" + +abstract_class IServerGameClients +{ +public: + virtual void GetPlayerLimits(int& minplayers, int& maxplayers, int& defaultMaxPlayers) const = 0; + + virtual bool ClientConnect(edict_t* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) = 0; + + virtual void ClientActive(edict_t* pEntity, bool bLoadGame) = 0; + + virtual void ClientFullyConnect(edict_t* pEntity) = 0; + + virtual void ClientDisconnect(edict_t* pEntity) = 0; + + virtual void ClientPutInServer(edict_t* pEntity, char const* playername) = 0; + + virtual void ClientCommand(edict_t* pEntity, const CCommand& args) = 0; + + virtual void SetCommandClient(int index) = 0; + + virtual void ClientSettingsChanged(edict_t* pEdict) = 0; + + virtual void ClientSetupVisibility(edict_t* pViewEntity, edict_t* pClient, unsigned char* pvs, int pvssize) = 0; + + virtual float ProcessUsercmds(edict_t* player, bf_read* buf, int numcmds, int totalcmds, + int dropped_packets, bool ignore, bool paused) = 0; + + virtual void PostClientMessagesSent(void) = 0; + + virtual CPlayerState* GetPlayerState(edict_t* player) = 0; + + virtual void ClientEarPosition(edict_t* pEntity, Vector* pEarOrigin) = 0; + + virtual bool ClientReplayEvent(edict_t* player, void* event ) = 0; + + virtual int GetReplayDelay(edict_t* player, int& entity) = 0; + + virtual void GetBugReportInfo(char* buf, int buflen) = 0; + + virtual void ClientVoice(edict_t* pEdict) = 0; + + virtual void NetworkIDValidated(const char* pszUserName, const char* pszNetworkID, CSteamID steamID) = 0; + + virtual int GetMaxSplitscreenPlayers() = 0; + + virtual int GetMaxHumanPlayers() = 0; + + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) = 0; + + virtual void ClientNameHandler(unsigned long long steamid, const char* name) = 0; +}; + +#define INTERFACEVERSION_UPLOADGAMESTATS "ServerUploadGameStats001" + +abstract_class IUploadGameStats +{ +public: + virtual bool UploadGameStats( + char const* mapname, + unsigned int blobversion, + unsigned int blobsize, + const void* pvBlobData) = 0; + + virtual void InitConnection(void) = 0; + + virtual void UpdateConnection(void) = 0; + + virtual bool IsGameStatsLoggingEnabled() = 0; + + virtual void GetPseudoUniqueId(char* buf, size_t bufsize) = 0; + + virtual bool IsCyberCafeUser(void) = 0; + + virtual bool IsHDREnabled(void) = 0; +}; + +#define INTERFACEVERSION_PLUGINHELPERSCHECK "PluginHelpersCheck001" + +abstract_class IPluginHelpersCheck +{ +public: + virtual bool CreateMessage(const char* plugin, edict_t * pEntity, DIALOG_TYPE type, KeyValues * data) = 0; +}; + +abstract_class IServerDLLSharedAppSystems +{ +public: + virtual int Count() = 0; + virtual char const* GetDllName(int idx) = 0; + virtual char const* GetInterfaceName(int idx) = 0; +}; + +#define SERVER_DLL_SHARED_APPSYSTEMS "VServerDllSharedAppSystems001" + +#define INTERFACEVERSION_SERVERGAMETAGS "ServerGameTags001" + +abstract_class IServerGameTags +{ +public: + virtual void GetTaggedConVarList(KeyValues * pCvarTagList) = 0; +}; + +extern IVEngineServer* g_pEngineServer; +extern IServerGameDLL* g_pServerGameDLL; + +#endif +``` + +`SpyCustom/sdk/enginetrace.h`: + +```h +#ifndef ENGINETRACE_H +#define ENGINETRACE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "IEngineTrace.h" + +extern IEngineTrace* g_pEngineTraceServer; +extern IEngineTrace* g_pEngineTraceClient; + + +void EngineTraceRenderRayCasts(); + + +#endif +``` + +`SpyCustom/sdk/entitylist.h`: + +```h +#ifndef ENTITYLIST_H +#define ENTITYLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +class CBaseEntity; +class IEntityListener; + +class CBaseEntityClassList +{ +public: + CBaseEntityClassList(); + ~CBaseEntityClassList(); + virtual void LevelShutdownPostEntity() = 0; + + CBaseEntityClassList* m_pNextClassList; +}; + +template< class T > +class CEntityClassList : public CBaseEntityClassList +{ +public: + virtual void LevelShutdownPostEntity() { m_pClassList = NULL; } + + void Insert(T* pEntity) + { + pEntity->m_pNext = m_pClassList; + m_pClassList = pEntity; + } + + void Remove(T* pEntity) + { + T** pPrev = &m_pClassList; + T* pCur = *pPrev; + while (pCur) + { + if (pCur == pEntity) + { + *pPrev = pCur->m_pNext; + return; + } + pPrev = &pCur->m_pNext; + pCur = *pPrev; + } + } + + static T* m_pClassList; +}; + +abstract_class IEntityFindFilter +{ +public: + virtual bool ShouldFindEntity(CBaseEntity * pEntity) = 0; + virtual CBaseEntity* GetFilterResult(void) = 0; +}; + +class CGlobalEntityList : public CBaseEntityList +{ +public: +private: + int m_iHighestEnt; + int m_iNumEnts; + int m_iNumEdicts; + + bool m_bClearingEntities; + CUtlVector m_entityListeners; + +public: + CBaseHandle AddNetworkableEntity(IHandleEntity* pEnt, int index, int iForcedSerialNum = -1); + CBaseHandle AddNonNetworkableEntity(IHandleEntity* pEnt); + + void UpdateName(IHandleEntity* pEnt, CBaseHandle hEnt); + void UpdateName(IHandleEntity* pEnt); + + IServerNetworkable* GetServerNetworkable(CBaseHandle hEnt) const; + CBaseNetworkable* GetBaseNetworkable(CBaseHandle hEnt) const; + CBaseEntity* GetBaseEntity(CBaseHandle hEnt) const; + edict_t* GetEdict(CBaseHandle hEnt) const; + + int NumberOfEntities(void); + int NumberOfEdicts(void); + + void AddToDeleteList(IServerNetworkable* ent); + void CleanupDeleteList(void); + int ResetDeleteList(void); + + void Clear(void); + + bool IsClearingEntities() { return m_bClearingEntities; } + + void AddListenerEntity(IEntityListener* pListener); + void RemoveListenerEntity(IEntityListener* pListener); + + void ReportEntityFlagsChanged(CBaseEntity* pEntity, unsigned int flagsOld, unsigned int flagsNow); + void AddPostClientMessageEntity(CBaseEntity* pEntity); + void PostClientMessagesSent(); + + void NotifyCreateEntity(CBaseEntity* pEnt); + void NotifySpawn(CBaseEntity* pEnt); + void NotifyRemoveEntity(CBaseEntity* pEnt); + CBaseEntity* NextEnt(CBaseEntity* pCurrentEnt); + CBaseEntity* FirstEnt() { return NextEnt(NULL); } + + template< class T > + T* NextEntByClass(T* start) + { + for (CBaseEntity* x = NextEnt(start); x; x = NextEnt(x)) + { + start = dynamic_cast(x); + if (start) + return start; + } + return NULL; + } + + bool IsEntityPtr(void* pTest); + CBaseEntity* FindEntityByClassname(CBaseEntity* pStartEntity, const char* szName); + CBaseEntity* FindEntityByName(CBaseEntity* pStartEntity, const char* szName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL, IEntityFindFilter* pFilter = NULL); + CBaseEntity* FindEntityByName(CBaseEntity* pStartEntity, string_t iszName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL, IEntityFindFilter* pFilter = NULL) + { + return FindEntityByName(pStartEntity, STRING(iszName), pSearchingEntity, pActivator, pCaller, pFilter); + } + CBaseEntity* FindEntityInSphere(CBaseEntity* pStartEntity, const Vector& vecCenter, float flRadius); + CBaseEntity* FindEntityByTarget(CBaseEntity* pStartEntity, const char* szName); + CBaseEntity* FindEntityByModel(CBaseEntity* pStartEntity, const char* szModelName); + CBaseEntity* FindEntityByOutputTarget(CBaseEntity* pStartEntity, string_t iTarget); + + CBaseEntity* FindEntityByNameNearest(const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityByNameWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityByClassnameNearest(const char* szName, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByClassnameNearest2D(const char* szName, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByClassnameWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByClassnameWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecMins, const Vector& vecMaxs); + + CBaseEntity* FindEntityGeneric(CBaseEntity* pStartEntity, const char* szName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityGenericWithin(CBaseEntity* pStartEntity, const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + CBaseEntity* FindEntityGenericNearest(const char* szName, const Vector& vecSrc, float flRadius, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + + CBaseEntity* FindEntityNearestFacing(const Vector& origin, const Vector& facing, float threshold); + CBaseEntity* FindEntityClassNearestFacing(const Vector& origin, const Vector& facing, float threshold, char* classname); + CBaseEntity* FindEntityByNetname(CBaseEntity* pStartEntity, const char* szModelName); + + CBaseEntity* FindEntityProcedural(const char* szName, CBaseEntity* pSearchingEntity = NULL, CBaseEntity* pActivator = NULL, CBaseEntity* pCaller = NULL); + + CBaseEntity* FindEntityByClassnameFast(CBaseEntity* pStartEntity, string_t iszClassname); + CBaseEntity* FindEntityByClassnameNearestFast(string_t iszClassname, const Vector& vecSrc, float flRadius); + CBaseEntity* FindEntityByNameFast(CBaseEntity* pStartEntity, string_t iszName); + + CGlobalEntityList(); + +protected: + + virtual void OnAddEntity(IHandleEntity* pEnt, CBaseHandle handle); + virtual void OnRemoveEntity(IHandleEntity* pEnt, CBaseHandle handle); + +}; + +extern CGlobalEntityList gEntList; + + +inline CBaseHandle CGlobalEntityList::AddNetworkableEntity(IHandleEntity* pEnt, int index, int iForcedSerialNum) +{ + CBaseHandle h = CBaseEntityList::AddNetworkableEntity(pEnt, index, iForcedSerialNum); + UpdateName(pEnt, h); + return h; +} + +inline CBaseHandle CGlobalEntityList::AddNonNetworkableEntity(IHandleEntity* pEnt) +{ + CBaseHandle h = CBaseEntityList::AddNonNetworkableEntity(pEnt); + UpdateName(pEnt, h); + return h; +} + +inline edict_t* CGlobalEntityList::GetEdict(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetNetworkable()->GetEdict(); + else + return NULL; +} + +inline CBaseNetworkable* CGlobalEntityList::GetBaseNetworkable(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetNetworkable()->GetBaseNetworkable(); + else + return NULL; +} + +inline IServerNetworkable* CGlobalEntityList::GetServerNetworkable(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetNetworkable(); + else + return NULL; +} + +inline CBaseEntity* CGlobalEntityList::GetBaseEntity(CBaseHandle hEnt) const +{ + IServerUnknown* pUnk = static_cast(LookupEntity(hEnt)); + if (pUnk) + return pUnk->GetBaseEntity(); + else + return NULL; +} + + +#if 0 + +template +inline bool FindEntityByName(const char* pszName, ENT_TYPE** ppResult) +{ + CBaseEntity* pBaseEntity = gEntList.FindEntityByName(NULL, pszName); + + if (pBaseEntity) + *ppResult = dynamic_cast(pBaseEntity); + else + *ppResult = NULL; + + return (*ppResult != NULL); +} + +template <> +inline bool FindEntityByName(const char* pszName, CBaseEntity** ppResult) +{ + *ppResult = gEntList.FindEntityByName(NULL, pszName); + return (*ppResult != NULL); +} + +template <> +inline bool FindEntityByName(const char* pszName, CAI_BaseNPC** ppResult) +{ + CBaseEntity* pBaseEntity = gEntList.FindEntityByName(NULL, pszName); + + if (pBaseEntity) + *ppResult = pBaseEntity->MyNPCPointer(); + else + *ppResult = NULL; + + return (*ppResult != NULL); +} +#endif +struct entitem_t +{ + EHANDLE hEnt; + struct entitem_t* pNext; + + static void* operator new(size_t stAllocateBlock); + static void* operator new(size_t stAllocateBlock, int nBlockUse, const char* pFileName, int nLine); + static void operator delete(void* pMem); + static void operator delete(void* pMem, int nBlockUse, const char* pFileName, int nLine) { operator delete(pMem); } +}; + +class CEntityList +{ +public: + CEntityList(); + ~CEntityList(); + + int m_iNumItems; + entitem_t* m_pItemList; + + void AddEntity(CBaseEntity*); + void DeleteEntity(CBaseEntity*); +}; + +enum notify_system_event_t +{ + NOTIFY_EVENT_TELEPORT = 0, + NOTIFY_EVENT_DESTROY, +}; + +struct notify_teleport_params_t +{ + Vector prevOrigin; + QAngle prevAngles; + bool physicsRotate; +}; + +struct notify_destroy_params_t +{ +}; + +struct notify_system_event_params_t +{ + union + { + const notify_teleport_params_t* pTeleport; + const notify_destroy_params_t* pDestroy; + }; + notify_system_event_params_t(const notify_teleport_params_t* pInTeleport) { pTeleport = pInTeleport; } + notify_system_event_params_t(const notify_destroy_params_t* pInDestroy) { pDestroy = pInDestroy; } +}; + + +abstract_class INotify +{ +public: + virtual void AddEntity(CBaseEntity * pNotify, CBaseEntity * pWatched) = 0; + + virtual void RemoveEntity(CBaseEntity* pNotify, CBaseEntity* pWatched) = 0; + + virtual void ReportNamedEvent(CBaseEntity* pEntity, const char* pEventName) = 0; + + virtual void ReportSystemEvent(CBaseEntity* pEntity, notify_system_event_t eventType, const notify_system_event_params_t& params) = 0; + + inline void ReportDestroyEvent(CBaseEntity* pEntity) + { + notify_destroy_params_t destroy; + ReportSystemEvent(pEntity, NOTIFY_EVENT_DESTROY, notify_system_event_params_t(&destroy)); + } + + inline void ReportTeleportEvent(CBaseEntity* pEntity, const Vector& prevOrigin, const QAngle& prevAngles, bool physicsRotate) + { + notify_teleport_params_t teleport; + teleport.prevOrigin = prevOrigin; + teleport.prevAngles = prevAngles; + teleport.physicsRotate = physicsRotate; + ReportSystemEvent(pEntity, NOTIFY_EVENT_TELEPORT, notify_system_event_params_t(&teleport)); + } + + virtual void ClearEntity(CBaseEntity* pNotify) = 0; +}; + +class IEntityListener +{ +public: + virtual void OnEntityCreated(CBaseEntity* pEntity) {}; + virtual void OnEntitySpawned(CBaseEntity* pEntity) {}; + virtual void OnEntityDeleted(CBaseEntity* pEntity) {}; +}; + +extern INotify* g_pNotify; + +void EntityTouch_Add(CBaseEntity* pEntity); +void EntityTouch_Remove(CBaseEntity* pEntity); +int AimTarget_ListCount(); +int AimTarget_ListCopy(CBaseEntity* pList[], int listMax); +CBaseEntity* AimTarget_ListElement(int iIndex); +void AimTarget_ForceRepopulateList(); + +void SimThink_EntityChanged(CBaseEntity* pEntity); +int SimThink_ListCount(); +int SimThink_ListCopy(CBaseEntity* pList[], int listMax); + +#endif +``` + +`SpyCustom/sdk/entitylist_base.h`: + +```h +#ifndef ENTITYLIST_BASE_H +#define ENTITYLIST_BASE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "const.h" +#include "basehandle.h" +#include "utllinkedlist.h" +#include "ihandleentity.h" + + +class CEntInfo +{ +public: + IHandleEntity* m_pEntity; + int m_SerialNumber; + CEntInfo* m_pPrev; + CEntInfo* m_pNext; + + void ClearLinks(); +}; + + +class CBaseEntityList +{ +public: + CBaseEntityList(); + ~CBaseEntityList(); + + CBaseHandle AddNetworkableEntity(IHandleEntity* pEnt, int index, int iForcedSerialNum = -1); + CBaseHandle AddNonNetworkableEntity(IHandleEntity* pEnt); + void RemoveEntity(CBaseHandle handle); + + CBaseHandle GetNetworkableHandle(int iEntity) const; + + IHandleEntity* LookupEntity(const CBaseHandle& handle) const; + IHandleEntity* LookupEntityByNetworkIndex(int edictIndex) const; + + CBaseHandle FirstHandle() const; + CBaseHandle NextHandle(CBaseHandle hEnt) const; + static CBaseHandle InvalidHandle(); + + const CEntInfo* FirstEntInfo() const; + const CEntInfo* NextEntInfo(const CEntInfo* pInfo) const; + const CEntInfo* GetEntInfoPtr(const CBaseHandle& hEnt) const; + const CEntInfo* GetEntInfoPtrByIndex(int index) const; + +protected: + + virtual void OnAddEntity(IHandleEntity* pEnt, CBaseHandle handle); + + virtual void OnRemoveEntity(IHandleEntity* pEnt, CBaseHandle handle); + + +private: + + CBaseHandle AddEntityAtSlot(IHandleEntity* pEnt, int iSlot, int iForcedSerialNum); + void RemoveEntityAtSlot(int iSlot); + + +private: + + class CEntInfoList + { + public: + CEntInfoList(); + + const CEntInfo* Head() const { return m_pHead; } + const CEntInfo* Tail() const { return m_pTail; } + CEntInfo* Head() { return m_pHead; } + CEntInfo* Tail() { return m_pTail; } + void AddToHead(CEntInfo* pElement) { LinkAfter(NULL, pElement); } + void AddToTail(CEntInfo* pElement) { LinkBefore(NULL, pElement); } + + void LinkBefore(CEntInfo* pBefore, CEntInfo* pElement); + void LinkAfter(CEntInfo* pBefore, CEntInfo* pElement); + void Unlink(CEntInfo* pElement); + bool IsInList(CEntInfo* pElement); + + private: + CEntInfo* m_pHead; + CEntInfo* m_pTail; + }; + + int GetEntInfoIndex(const CEntInfo* pEntInfo) const; + + + CEntInfo m_EntPtrArray[NUM_ENT_ENTRIES]; + CEntInfoList m_activeList; + CEntInfoList m_freeNonNetworkableList; +}; + + +inline int CBaseEntityList::GetEntInfoIndex(const CEntInfo* pEntInfo) const +{ + Assert(pEntInfo); + int index = (int)(pEntInfo - m_EntPtrArray); + Assert(index >= 0 && index < NUM_ENT_ENTRIES); + return index; +} + +inline CBaseHandle CBaseEntityList::GetNetworkableHandle(int iEntity) const +{ + Assert(iEntity >= 0 && iEntity < MAX_EDICTS); + if (m_EntPtrArray[iEntity].m_pEntity) + return CBaseHandle(iEntity, m_EntPtrArray[iEntity].m_SerialNumber); + else + return CBaseHandle(); +} + + +inline IHandleEntity* CBaseEntityList::LookupEntity(const CBaseHandle& handle) const +{ + if (handle.m_Index == INVALID_EHANDLE_INDEX) + return NULL; + + const CEntInfo* pInfo = &m_EntPtrArray[handle.GetEntryIndex()]; + if (pInfo->m_SerialNumber == handle.GetSerialNumber()) + return (IHandleEntity*)pInfo->m_pEntity; + else + return NULL; +} + + +inline IHandleEntity* CBaseEntityList::LookupEntityByNetworkIndex(int edictIndex) const +{ + if (edictIndex < 0) + return NULL; + + Assert(edictIndex < NUM_ENT_ENTRIES); + return (IHandleEntity*)m_EntPtrArray[edictIndex].m_pEntity; +} + + +inline CBaseHandle CBaseEntityList::FirstHandle() const +{ + if (!m_activeList.Head()) + return INVALID_EHANDLE_INDEX; + + int index = GetEntInfoIndex(m_activeList.Head()); + return CBaseHandle(index, m_EntPtrArray[index].m_SerialNumber); +} + +inline CBaseHandle CBaseEntityList::NextHandle(CBaseHandle hEnt) const +{ + int iSlot = hEnt.GetEntryIndex(); + CEntInfo* pNext = m_EntPtrArray[iSlot].m_pNext; + if (!pNext) + return INVALID_EHANDLE_INDEX; + + int index = GetEntInfoIndex(pNext); + + return CBaseHandle(index, m_EntPtrArray[index].m_SerialNumber); +} + +inline CBaseHandle CBaseEntityList::InvalidHandle() +{ + return INVALID_EHANDLE_INDEX; +} + +inline const CEntInfo* CBaseEntityList::FirstEntInfo() const +{ + return m_activeList.Head(); +} + +inline const CEntInfo* CBaseEntityList::NextEntInfo(const CEntInfo* pInfo) const +{ + return pInfo->m_pNext; +} + +inline const CEntInfo* CBaseEntityList::GetEntInfoPtr(const CBaseHandle& hEnt) const +{ + int iSlot = hEnt.GetEntryIndex(); + return &m_EntPtrArray[iSlot]; +} + +inline const CEntInfo* CBaseEntityList::GetEntInfoPtrByIndex(int index) const +{ + return &m_EntPtrArray[index]; +} + +#endif +``` + +`SpyCustom/sdk/expressioncalculator.h`: + +```h +#ifndef MATHLIB_EXPRESSION_CALCULATOR_H +#define MATHLIB_EXPRESSION_CALCULATOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlstring.h" +#include "utlstack.h" +#include "utlvector.h" + + +class CExpressionCalculator +{ +public: + CExpressionCalculator(const char* expr = NULL) : m_expr(expr) {} + + CExpressionCalculator(const CExpressionCalculator& x); + CExpressionCalculator& operator=(const CExpressionCalculator& x); + +public: + void SetExpression(const char* expr) + { + m_expr = expr; + } + + void SetVariable(const char* var, float value); + void SetVariable(int nVariableIndex, float value); + void ModifyVariable(const char* var, float value); + + int FindVariableIndex(const char* var); + + bool Evaluate(float& value); + + bool BuildVariableListFromExpression(); + + int VariableCount(); + const char* VariableName(int nIndex); + +private: + bool ParseExpr(const char*& expr); + bool ParseConditional(const char*& expr); + bool ParseOr(const char*& expr); + bool ParseAnd(const char*& expr); + bool ParseEquality(const char*& expr); + bool ParseLessGreater(const char*& expr); + bool ParseAddSub(const char*& expr); + bool ParseDivMul(const char*& expr); + bool ParseUnary(const char*& expr); + bool ParsePrimary(const char*& expr); + bool Parse1ArgFunc(const char*& expr); + bool Parse2ArgFunc(const char*& expr); + bool Parse3ArgFunc(const char*& expr); + bool Parse5ArgFunc(const char*& expr); + + CUtlString m_expr; + CUtlVector< CUtlString > m_varNames; + CUtlVector m_varValues; + CUtlStack m_stack; + bool m_bIsBuildingArgumentList; +}; + +float EvaluateExpression(char const* pExprString, float flValueToReturnIfFailure); + + +#endif +``` + +`SpyCustom/sdk/exprevaluator.h`: + +```h +#ifndef EXPREVALUATOR_H +#define EXPREVALUATOR_H + +#if defined( _WIN32 ) +#pragma once +#endif + +static const char OR_OP = '|'; +static const char AND_OP = '&'; +static const char NOT_OP = '!'; + +#define MAX_IDENTIFIER_LEN 128 +enum Kind { CONDITIONAL, NOT, LITERAL }; + +struct ExprNode +{ + ExprNode* left; + ExprNode* right; + Kind kind; + union + { + char cond; + bool value; + } data; +}; + +typedef ExprNode* ExprTree; + +typedef bool (*GetSymbolProc_t)(const char* pKey); +typedef void (*SyntaxErrorProc_t)(const char* pReason); + +class CExpressionEvaluator +{ +public: + CExpressionEvaluator(); + ~CExpressionEvaluator(); + bool Evaluate(bool& result, const char* pInfixExpression, GetSymbolProc_t pGetSymbolProc = 0, SyntaxErrorProc_t pSyntaxErrorProc = 0); + +private: + CExpressionEvaluator(CExpressionEvaluator&); + + char GetNextToken(void); + void FreeNode(ExprNode* pNode); + ExprNode* AllocateNode(void); + void FreeTree(ExprTree& node); + bool IsConditional(bool& bCondition, const char token); + bool IsNotOp(const char token); + bool IsIdentifierOrConstant(const char token); + bool MakeExprNode(ExprTree& tree, char token, Kind kind, ExprTree left, ExprTree right); + bool MakeFactor(ExprTree& tree); + bool MakeTerm(ExprTree& tree); + bool MakeExpression(ExprTree& tree); + bool BuildExpression(void); + bool SimplifyNode(ExprTree& node); + + ExprTree m_ExprTree; + char m_CurToken; + const char* m_pExpression; + int m_CurPosition; + char m_Identifier[MAX_IDENTIFIER_LEN]; + GetSymbolProc_t m_pGetSymbolProc; + SyntaxErrorProc_t m_pSyntaxErrorProc; + bool m_bSetup; +}; + +#endif +``` + +`SpyCustom/sdk/fasttimer.h`: + +```h +#ifndef FASTTIMER_H +#define FASTTIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _WIN32 +#include +#endif + +#include +#include "platform.h" + +PLATFORM_INTERFACE uint64 g_ClockSpeed; +#if defined( _X360 ) && defined( _CERT ) +PLATFORM_INTERFACE unsigned long g_dwFakeFastCounter; +#endif + +PLATFORM_INTERFACE double g_ClockSpeedMicrosecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedMillisecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedSecondsMultiplier; + +class CCycleCount +{ + friend class CFastTimer; + +public: + CCycleCount(); + CCycleCount(uint64 cycles); + + void Sample(); + + void Init(); + void Init(float initTimeMsec); + void Init(double initTimeMsec) { Init((float)initTimeMsec); } + void Init(uint64 cycles); + bool IsLessThan(CCycleCount const& other) const; + + unsigned long GetCycles() const; + uint64 GetLongCycles() const; + + unsigned long GetMicroseconds() const; + uint64 GetUlMicroseconds() const; + double GetMicrosecondsF() const; + void SetMicroseconds(unsigned long nMicroseconds); + + unsigned long GetMilliseconds() const; + double GetMillisecondsF() const; + + double GetSeconds() const; + + CCycleCount& operator+=(CCycleCount const& other); + + static void Add(CCycleCount const& rSrc1, CCycleCount const& rSrc2, CCycleCount& dest); + + static void Sub(CCycleCount const& rSrc1, CCycleCount const& rSrc2, CCycleCount& dest); + + static uint64 GetTimestamp(); + + uint64 m_Int64; +}; + +class PLATFORM_CLASS CClockSpeedInit +{ +public: + CClockSpeedInit() + { + Init(); + } + + static void Init(); +}; + +class CFastTimer +{ +public: + void Start(); + void End(); + + const CCycleCount& GetDuration() const; + CCycleCount GetDurationInProgress() const; + + static inline int64 GetClockSpeed(); + +private: + CCycleCount m_Duration; +#ifdef DEBUG_FASTTIMER + bool m_bRunning; +#endif +}; + + +class CTimeScope +{ +public: + CTimeScope(CFastTimer* pTimer); + ~CTimeScope(); + +private: + CFastTimer* m_pTimer; +}; + +inline CTimeScope::CTimeScope(CFastTimer* pTotal) +{ + m_pTimer = pTotal; + m_pTimer->Start(); +} + +inline CTimeScope::~CTimeScope() +{ + m_pTimer->End(); +} + +class CTimeAdder +{ +public: + CTimeAdder(CCycleCount* pTotal); + ~CTimeAdder(); + + void End(); + +private: + CCycleCount* m_pTotal; + CFastTimer m_Timer; +}; + +inline CTimeAdder::CTimeAdder(CCycleCount* pTotal) +{ + m_pTotal = pTotal; + m_Timer.Start(); +} + +inline CTimeAdder::~CTimeAdder() +{ + End(); +} + +inline void CTimeAdder::End() +{ + if (m_pTotal) + { + m_Timer.End(); + *m_pTotal += m_Timer.GetDuration(); + m_pTotal = 0; + } +} + + + +#define PROFILE_SCOPE(name) \ + class C##name##ACC : public CAverageCycleCounter \ + { \ + public: \ + ~C##name##ACC() \ + { \ + Msg("%-48s: %6.3f avg (%8.1f total, %7.3f peak, %5d iters)\n", \ + #name, \ + GetAverageMilliseconds(), \ + GetTotalMilliseconds(), \ + GetPeakMilliseconds(), \ + GetIters() ); \ + } \ + }; \ + static C##name##ACC name##_ACC; \ + CAverageTimeMarker name##_ATM( &name##_ACC ) + +#define TIME_SCOPE(name) \ + class CTimeScopeMsg_##name \ + { \ + public: \ + CTimeScopeMsg_##name() { m_Timer.Start(); } \ + ~CTimeScopeMsg_##name() \ + { \ + m_Timer.End(); \ + Msg( #name "time: %.4fms\n", m_Timer.GetDuration().GetMillisecondsF() ); \ + } \ + private: \ + CFastTimer m_Timer; \ + } name##_TSM; + + +class CAverageCycleCounter +{ +public: + CAverageCycleCounter(); + + void Init(); + void MarkIter(const CCycleCount& duration); + + unsigned GetIters() const; + + double GetAverageMilliseconds() const; + double GetTotalMilliseconds() const; + double GetPeakMilliseconds() const; + +private: + unsigned m_nIters; + CCycleCount m_Total; + CCycleCount m_Peak; +}; + +class CAverageTimeMarker +{ +public: + CAverageTimeMarker(CAverageCycleCounter* pCounter); + ~CAverageTimeMarker(); + +private: + CAverageCycleCounter* m_pCounter; + CFastTimer m_Timer; +}; + + +inline CCycleCount::CCycleCount() +{ + Init((uint64)0); +} + +inline CCycleCount::CCycleCount(uint64 cycles) +{ + Init(cycles); +} + +inline void CCycleCount::Init() +{ + Init((uint64)0); +} + +inline void CCycleCount::Init(float initTimeMsec) +{ + if (g_ClockSpeedMillisecondsMultiplier > 0) + Init((uint64)(initTimeMsec / g_ClockSpeedMillisecondsMultiplier)); + else + Init((uint64)0); +} + +inline void CCycleCount::Init(uint64 cycles) +{ + m_Int64 = cycles; +} + +inline void CCycleCount::Sample() +{ + m_Int64 = Plat_Rdtsc(); +} + +inline CCycleCount& CCycleCount::operator+=(CCycleCount const& other) +{ + m_Int64 += other.m_Int64; + return *this; +} + + +inline void CCycleCount::Add(CCycleCount const& rSrc1, CCycleCount const& rSrc2, CCycleCount& dest) +{ + dest.m_Int64 = rSrc1.m_Int64 + rSrc2.m_Int64; +} + +inline void CCycleCount::Sub(CCycleCount const& rSrc1, CCycleCount const& rSrc2, CCycleCount& dest) +{ + dest.m_Int64 = rSrc1.m_Int64 - rSrc2.m_Int64; +} + +inline uint64 CCycleCount::GetTimestamp() +{ + CCycleCount c; + c.Sample(); + return c.GetLongCycles(); +} + +inline bool CCycleCount::IsLessThan(CCycleCount const& other) const +{ + return m_Int64 < other.m_Int64; +} + + +inline unsigned long CCycleCount::GetCycles() const +{ + return (unsigned long)m_Int64; +} + +inline uint64 CCycleCount::GetLongCycles() const +{ + return m_Int64; +} + +inline unsigned long CCycleCount::GetMicroseconds() const +{ + return (unsigned long)((m_Int64 * 1000000) / g_ClockSpeed); +} + +inline uint64 CCycleCount::GetUlMicroseconds() const +{ + return ((m_Int64 * 1000000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMicrosecondsF() const +{ + return (double)(m_Int64 * g_ClockSpeedMicrosecondsMultiplier); +} + + +inline void CCycleCount::SetMicroseconds(unsigned long nMicroseconds) +{ + m_Int64 = ((uint64)nMicroseconds * g_ClockSpeed) / 1000000; +} + + +inline unsigned long CCycleCount::GetMilliseconds() const +{ + return (unsigned long)((m_Int64 * 1000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMillisecondsF() const +{ + return (double)(m_Int64 * g_ClockSpeedMillisecondsMultiplier); +} + + +inline double CCycleCount::GetSeconds() const +{ + return (double)(m_Int64 * g_ClockSpeedSecondsMultiplier); +} + + +inline void CFastTimer::Start() +{ + m_Duration.Sample(); +#ifdef DEBUG_FASTTIMER + m_bRunning = true; +#endif +} + + +inline void CFastTimer::End() +{ + CCycleCount cnt; + cnt.Sample(); + if (IsX360()) + { + if ((uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64) + { + cnt.m_Int64 += 0x100000000LL; + } + } + + m_Duration.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + +#ifdef DEBUG_FASTTIMER + m_bRunning = false; +#endif +} + +inline CCycleCount CFastTimer::GetDurationInProgress() const +{ + CCycleCount cnt; + cnt.Sample(); + if (IsX360()) + { + if ((uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64) + { + cnt.m_Int64 += 0x100000000LL; + } + } + + CCycleCount result; + result.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + + return result; +} + + +inline int64 CFastTimer::GetClockSpeed() +{ + return g_ClockSpeed; +} + + +inline CCycleCount const& CFastTimer::GetDuration() const +{ +#ifdef DEBUG_FASTTIMER + assert(!m_bRunning); +#endif + return m_Duration; +} + + +inline CAverageCycleCounter::CAverageCycleCounter() + : m_nIters(0) +{ +} + +inline void CAverageCycleCounter::Init() +{ + m_Total.Init(); + m_Peak.Init(); + m_nIters = 0; +} + +inline void CAverageCycleCounter::MarkIter(const CCycleCount& duration) +{ + ++m_nIters; + m_Total += duration; + if (m_Peak.IsLessThan(duration)) + m_Peak = duration; +} + +inline unsigned CAverageCycleCounter::GetIters() const +{ + return m_nIters; +} + +inline double CAverageCycleCounter::GetAverageMilliseconds() const +{ + if (m_nIters) + return (m_Total.GetMillisecondsF() / (double)m_nIters); + else + return 0; +} + +inline double CAverageCycleCounter::GetTotalMilliseconds() const +{ + return m_Total.GetMillisecondsF(); +} + +inline double CAverageCycleCounter::GetPeakMilliseconds() const +{ + return m_Peak.GetMillisecondsF(); +} + +inline CAverageTimeMarker::CAverageTimeMarker(CAverageCycleCounter* pCounter) +{ + m_pCounter = pCounter; + m_Timer.Start(); +} + +inline CAverageTimeMarker::~CAverageTimeMarker() +{ + m_Timer.End(); + m_pCounter->MarkIter(m_Timer.GetDuration()); +} + + +class CLimitTimer +{ +public: + CLimitTimer() {} + CLimitTimer(uint64 cMicroSecDuration) { SetLimit(cMicroSecDuration); } + void SetLimit(uint64 m_cMicroSecDuration); + bool BLimitReached() const; + + int CMicroSecOverage() const; + uint64 CMicroSecLeft() const; + +private: + uint64 m_lCycleLimit; +}; + + +inline void CLimitTimer::SetLimit(uint64 cMicroSecDuration) +{ + uint64 dlCycles = ((uint64)cMicroSecDuration * g_ClockSpeed) / (uint64)1000000L; + CCycleCount cycleCount; + cycleCount.Sample(); + m_lCycleLimit = cycleCount.GetLongCycles() + dlCycles; +} + + +inline bool CLimitTimer::BLimitReached() const +{ + CCycleCount cycleCount; + cycleCount.Sample(); + return (cycleCount.GetLongCycles() >= m_lCycleLimit); +} + + +inline int CLimitTimer::CMicroSecOverage() const +{ + CCycleCount cycleCount; + cycleCount.Sample(); + uint64 lcCycles = cycleCount.GetLongCycles(); + + if (lcCycles < m_lCycleLimit) + return 0; + + return((int)((lcCycles - m_lCycleLimit) * (uint64)1000000L / g_ClockSpeed)); +} + + +inline uint64 CLimitTimer::CMicroSecLeft() const +{ + CCycleCount cycleCount; + cycleCount.Sample(); + uint64 lcCycles = cycleCount.GetLongCycles(); + + if (lcCycles >= m_lCycleLimit) + return 0; + + return((uint64)((m_lCycleLimit - lcCycles) * (uint64)1000000L / g_ClockSpeed)); +} + + +#endif +``` + +`SpyCustom/sdk/filesystem.h`: + +```h +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +#include "threadtools.h" +#include "memalloc.h" +#include "tslist.h" +#include "interface.h" +#include "utlsymbol.h" +#include "utlstring.h" +#include "functors.h" +#include "checksum_crc.h" +#include "checksum_md5.h" +#include "utlqueue.h" +#include "iappsystem.h" +#include "tier2.h" +#ifdef _PS3 +#include +#include +struct HddCacheFileStatus; +extern char gSrcGameDataPath[]; +class CFileGroupSystem; +#endif + +class CUtlBuffer; +class KeyValues; +class IFileList; + +typedef void* FileHandle_t; +typedef int FileFindHandle_t; +typedef void (*FileSystemLoggingFunc_t)(const char* fileName, const char* accessType); +typedef int WaitForResourcesHandle_t; + +#ifdef _X360 +typedef void* HANDLE; +#endif + +#define FILESYSTEM_MAX_SEARCH_PATHS 128 + +enum FileSystemSeek_t +{ + FILESYSTEM_SEEK_HEAD = SEEK_SET, + FILESYSTEM_SEEK_CURRENT = SEEK_CUR, + FILESYSTEM_SEEK_TAIL = SEEK_END, +}; + +enum +{ + FILESYSTEM_INVALID_FIND_HANDLE = -1 +}; + +enum FileWarningLevel_t +{ + FILESYSTEM_WARNING = -1, + + FILESYSTEM_WARNING_QUIET = 0, + + FILESYSTEM_WARNING_REPORTUNCLOSED, + + FILESYSTEM_WARNING_REPORTUSAGE, + + FILESYSTEM_WARNING_REPORTALLACCESSES, + + FILESYSTEM_WARNING_REPORTALLACCESSES_READ, + + FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, + + FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC, + +}; + +enum PathTypeFilter_t +{ + FILTER_NONE = 0, + FILTER_CULLPACK = 1, + FILTER_CULLNONPACK = 2, + FILTER_CULLLOCALIZED = 3, + FILTER_CULLLOCALIZED_ANY = 4, +}; + +enum +{ + PATH_IS_NORMAL = 0x00, + PATH_IS_PACKFILE = 0x01, + PATH_IS_MAPPACKFILE = 0x02, + PATH_IS_DVDDEV = 0x04, +}; +typedef uint32 PathTypeQuery_t; + +#define IS_PACKFILE( n ) ( n & ( PATH_IS_PACKFILE | PATH_IS_MAPPACKFILE ) ) +#define IS_DVDDEV( n ) ( n & PATH_IS_DVDDEV ) + +enum DVDMode_t +{ + DVDMODE_OFF = 0, + DVDMODE_STRICT = 1, + DVDMODE_DEV = 2, + DVDMODE_DEV_VISTA = 3, +}; + +#ifdef _PS3 + +enum FsState_t +{ + FS_STATE_INIT = 0, + FS_STATE_LEVEL_LOAD = 1, + FS_STATE_LEVEL_RUN = 2, + FS_STATE_LEVEL_RESTORE = 3, + FS_STATE_LEVEL_LOAD_END = 4, + FS_STATE_EXITING = 5 +}; + +enum Ps3FileType_t +{ + PS3_FILETYPE_WAV, + PS3_FILETYPE_ANI, + PS3_FILETYPE_BSP, + PS3_FILETYPE_VMT, + PS3_FILETYPE_QPRE, + PS3_FILETYPE_OTHER, + PS3_FILETYPE_DIR, + PS3_FILETYPE_UNKNOWN +}; + + +#endif + +#if defined( TRACK_BLOCKING_IO ) +enum FileBlockingWarning_t +{ + FILESYSTEM_BLOCKING_SYNCHRONOUS = 0, + FILESYSTEM_BLOCKING_ASYNCHRONOUS_BLOCK, + FILESYSTEM_BLOCKING_ASYNCHRONOUS, + FILESYSTEM_BLOCKING_CALLBACKTIMING, + + FILESYSTEM_BLOCKING_NUMBINS, +}; + +#pragma pack(1) +class FileBlockingItem +{ +public: + enum + { + FB_ACCESS_OPEN = 1, + FB_ACCESS_CLOSE = 2, + FB_ACCESS_READ = 3, + FB_ACCESS_WRITE = 4, + FB_ACCESS_APPEND = 5, + FB_ACCESS_SIZE = 6 + }; + + FileBlockingItem() : + m_ItemType((FileBlockingWarning_t)0), + m_flElapsed(0.0f), + m_nAccessType(0) + { + SetFileName(NULL); + } + + FileBlockingItem(int type, char const* filename, float elapsed, int accessType) : + m_ItemType((FileBlockingWarning_t)type), + m_flElapsed(elapsed), + m_nAccessType(accessType) + { + SetFileName(filename); + } + + void SetFileName(char const* filename) + { + if (!filename) + { + m_szFilename[0] = 0; + return; + } + + int len = Q_strlen(filename); + if (len >= sizeof(m_szFilename)) + { + Q_strncpy(m_szFilename, &filename[len - sizeof(m_szFilename) + 1], sizeof(m_szFilename)); + } + else + { + Q_strncpy(m_szFilename, filename, sizeof(m_szFilename)); + } + } + + char const* GetFileName() const + { + return m_szFilename; + } + + FileBlockingWarning_t m_ItemType; + float m_flElapsed; + byte m_nAccessType; +private: + + char m_szFilename[32]; +}; +#pragma pack() + +class IBlockingFileItemList +{ +public: + + virtual void LockMutex() = 0; + virtual void UnlockMutex() = 0; + + virtual int First() const = 0; + virtual int Next(int i) const = 0; + virtual int InvalidIndex() const = 0; + + virtual const FileBlockingItem& Get(int index) const = 0; + + virtual void Reset() = 0; +}; + +#endif + +enum FilesystemMountRetval_t +{ + FILESYSTEM_MOUNT_OK = 0, + FILESYSTEM_MOUNT_FAILED, +}; + +enum SearchPathAdd_t +{ + PATH_ADD_TO_HEAD, + PATH_ADD_TO_TAIL, + PATH_ADD_TO_TAIL_ATINDEX, +}; + +enum FilesystemOpenExFlags_t +{ + FSOPEN_UNBUFFERED = (1 << 0), + FSOPEN_FORCE_TRACK_CRC = (1 << 1), + FSOPEN_NEVERINPACK = (1 << 2), +}; + +#define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 + +struct FileSystemStatistics +{ + CInterlockedUInt nReads, + nWrites, + nBytesRead, + nBytesWritten, + nSeeks; +}; + +typedef void* (*FSAllocFunc_t)(const char* pszFilename, unsigned nBytes); + + +typedef void (*FSDirtyDiskReportFunc_t)(); + + +DECLARE_POINTER_HANDLE(FSAsyncControl_t); +DECLARE_POINTER_HANDLE(FSAsyncFile_t); +const FSAsyncFile_t FS_INVALID_ASYNC_FILE = (FSAsyncFile_t)(0x0000ffff); + + +enum FSAsyncStatus_t +{ + FSASYNC_ERR_ALIGNMENT = -6, + FSASYNC_ERR_FAILURE = -5, + FSASYNC_ERR_READING = -4, + FSASYNC_ERR_NOMEMORY = -3, + FSASYNC_ERR_UNKNOWNID = -2, + FSASYNC_ERR_FILEOPEN = -1, + FSASYNC_OK = 0, + FSASYNC_STATUS_PENDING, + FSASYNC_STATUS_INPROGRESS, + FSASYNC_STATUS_ABORTED, + FSASYNC_STATUS_UNSERVICED, +}; + +enum FSAsyncFlags_t +{ + FSASYNC_FLAGS_ALLOCNOFREE = (1 << 0), + FSASYNC_FLAGS_FREEDATAPTR = (1 << 1), + FSASYNC_FLAGS_SYNC = (1 << 2), + FSASYNC_FLAGS_NULLTERMINATE = (1 << 3), +}; + +enum EFileCRCStatus +{ + k_eFileCRCStatus_CantOpenFile, + k_eFileCRCStatus_GotCRC, + k_eFileCRCStatus_FileInVPK, +}; + +enum ECacheCRCType +{ + k_eCacheCRCType_SingleFile, + k_eCacheCRCType_Directory, + k_eCacheCRCType_Directory_Recursive +}; + +struct FileAsyncRequest_t; +typedef void (*FSAsyncCallbackFunc_t)(const FileAsyncRequest_t& request, int nBytesRead, FSAsyncStatus_t err); + +typedef void (*FSAsyncScanAddFunc_t)(void* pContext, char* pFoundPath, char* pFoundFile); +typedef void (*FSAsyncScanCompleteFunc_t)(void* pContext, FSAsyncStatus_t err); + +struct FileAsyncRequest_t +{ + FileAsyncRequest_t() { memset(this, 0, sizeof(*this)); hSpecificAsyncFile = FS_INVALID_ASYNC_FILE; } + const char* pszFilename; + void* pData; + int nOffset; + int nBytes; + FSAsyncCallbackFunc_t pfnCallback; + void* pContext; + int priority; + unsigned flags; + const char* pszPathID; + FSAsyncFile_t hSpecificAsyncFile; + FSAllocFunc_t pfnAlloc; +}; + + +struct FileHash_t +{ + enum EFileHashType_t + { + k_EFileHashTypeUnknown = 0, + k_EFileHashTypeEntireFile = 1, + k_EFileHashTypeIncompleteFile = 2, + }; + FileHash_t() + { + m_eFileHashType = FileHash_t::k_EFileHashTypeUnknown; + m_cbFileLen = 0; + m_PackFileID = 0; + m_nPackFileNumber = 0; + } + int m_eFileHashType; + CRC32_t m_crcIOSequence; + MD5Value_t m_md5contents; + int m_cbFileLen; + int m_PackFileID; + int m_nPackFileNumber; + + bool operator==(const FileHash_t& src) const + { + return m_crcIOSequence == src.m_crcIOSequence && + m_md5contents == src.m_md5contents && + m_eFileHashType == src.m_eFileHashType; + } + bool operator!=(const FileHash_t& src) const + { + return m_crcIOSequence != src.m_crcIOSequence || + m_md5contents != src.m_md5contents || + m_eFileHashType != src.m_eFileHashType; + } + +}; + +class CUnverifiedFileHash +{ +public: + char m_PathID[MAX_PATH]; + char m_Filename[MAX_PATH]; + int m_nFileFraction; + FileHash_t m_FileHash; +}; + +class CUnverifiedCRCFile +{ +public: + char m_PathID[MAX_PATH]; + char m_Filename[MAX_PATH]; + CRC32_t m_CRC; +}; + + +#define WHITELIST_SPEW_WHILE_LOADING 0x0001 +#define WHITELIST_SPEW_RELOAD_FILES 0x0002 +#define WHITELIST_SPEW_DONT_RELOAD_FILES 0x0004 + + + +#define DLC_LICENSE_ID( x ) ( ( ( (unsigned int)( x ) ) >> 24 ) & 0x000000FF ) +#define DLC_LICENSE_MINORVERSION( x ) ( ( ( (unsigned int)( x ) ) >> 16 ) & 0x000000FF ) +#define DLC_LICENSE_FLAGS( x ) ( ( ( (unsigned int)( x ) ) & 0x0000FFFF ) ) + +#define DLCFLAGS_PRESENCE_ONLY 0x0001 + + + +#define BASEFILESYSTEM_INTERFACE_VERSION "VBaseFileSystem011" + +abstract_class IThreadedFileMD5Processor +{ +public: + virtual int SubmitThreadedMD5Request(uint8 * pubBuffer, int cubBuffer, int PackFileID, int nPackFileNumber, int nPackFileFraction) = 0; + virtual bool BlockUntilMD5RequestComplete(int iRequest, MD5Value_t* pMd5ValueOut) = 0; + virtual bool IsMD5RequestComplete(int iRequest, MD5Value_t* pMd5ValueOut) = 0; +}; + +abstract_class IBaseFileSystem +{ +public: + virtual int Read(void* pOutput, int size, FileHandle_t file) = 0; + virtual int Write(void const* pInput, int size, FileHandle_t file) = 0; + + virtual FileHandle_t Open(const char* pFileName, const char* pOptions, const char* pathID = 0) = 0; + virtual void Close(FileHandle_t file) = 0; + + + virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) = 0; + virtual unsigned int Tell(FileHandle_t file) = 0; + virtual unsigned int Size(FileHandle_t file) = 0; + virtual unsigned int Size(const char* pFileName, const char* pPathID = 0) = 0; + + virtual void Flush(FileHandle_t file) = 0; + virtual bool Precache(const char* pFileName, const char* pPathID = 0) = 0; + + virtual bool FileExists(const char* pFileName, const char* pPathID = 0) = 0; + virtual bool IsFileWritable(char const* pFileName, const char* pPathID = 0) = 0; + virtual bool SetFileWritable(char const* pFileName, bool writable, const char* pPathID = 0) = 0; + + virtual long GetFileTime(const char* pFileName, const char* pPathID = 0) = 0; + + virtual bool ReadFile(const char* pFileName, const char* pPath, CUtlBuffer& buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL) = 0; + virtual bool WriteFile(const char* pFileName, const char* pPath, CUtlBuffer& buf) = 0; + virtual bool UnzipFile(const char* pFileName, const char* pPath, const char* pDestination) = 0; +}; + +abstract_class IIoStats +{ +public: + virtual void OnFileSeek(int nTimeInMs) = 0; + virtual void OnFileRead(int nTimeInMs, int nBytesRead) = 0; + virtual void OnFileOpen(const char* pFileName) = 0; + + virtual int GetNumberOfFileSeeks() = 0; + virtual int GetTimeInFileSeek() = 0; + + virtual int GetNumberOfFileReads() = 0; + virtual int GetTimeInFileReads() = 0; + virtual int GetFileReadTotalSize() = 0; + + virtual int GetNumberOfFileOpens() = 0; + + virtual void Reset() = 0; + +protected: + virtual ~IIoStats() + { + } +}; + +abstract_class IFileSystem : public IAppSystem, public IBaseFileSystem +{ +public: + virtual bool IsSteam() const = 0; + + virtual FilesystemMountRetval_t MountSteamContent(int nExtraAppId = -1) = 0; + + virtual void AddSearchPath(const char* pPath, const char* pathID, SearchPathAdd_t addType = PATH_ADD_TO_TAIL) = 0; + virtual bool RemoveSearchPath(const char* pPath, const char* pathID = 0) = 0; + + virtual void RemoveAllSearchPaths(void) = 0; + + virtual void RemoveSearchPaths(const char* szPathID) = 0; + + virtual void MarkPathIDByRequestOnly(const char* pPathID, bool bRequestOnly) = 0; + + virtual bool IsFileInReadOnlySearchPath(const char* pPath, const char* pathID = 0) = 0; + + virtual const char* RelativePathToFullPath(const char* pFileName, const char* pPathID, char* pLocalPath, int localPathBufferSize, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t* pPathType = NULL) = 0; +#if IsGameConsole() + virtual bool GetPackFileInfoFromRelativePath(const char* pFileName, const char* pPathID, char* pPackPath, int nPackPathBufferSize, int64& nPosition, int64& nLength) = 0; +#endif + virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) = 0; + + virtual bool AddPackFile(const char* fullpath, const char* pathID) = 0; + + virtual void RemoveFile(char const* pRelativePath, const char* pathID = 0) = 0; + + virtual bool RenameFile(char const* pOldPath, char const* pNewPath, const char* pathID = 0) = 0; + + virtual void CreateDirHierarchy(const char* path, const char* pathID = 0) = 0; + + virtual bool IsDirectory(const char* pFileName, const char* pathID = 0) = 0; + + virtual void FileTimeToString(char* pStrip, int maxCharsIncludingTerminator, long fileTime) = 0; + + virtual void SetBufferSize(FileHandle_t file, unsigned nBytes) = 0; + + virtual bool IsOk(FileHandle_t file) = 0; + + virtual bool EndOfFile(FileHandle_t file) = 0; + + virtual char* ReadLine(char* pOutput, int maxChars, FileHandle_t file) = 0; +#if ! defined(SWIG) + virtual int FPrintf(FileHandle_t file, PRINTF_FORMAT_STRING const char* pFormat, ...) FMTFUNCTION(3, 4) = 0; +#else + virtual int FPrintf(FileHandle_t file, const char* pFormat, ...) FMTFUNCTION(3, 4) = 0; +#endif + + virtual CSysModule* LoadModule(const char* pFileName, const char* pPathID = 0, bool bValidatedDllOnly = true) = 0; + virtual void UnloadModule(CSysModule* pModule) = 0; + + virtual const char* FindFirst(const char* pWildCard, FileFindHandle_t* pHandle) = 0; + virtual const char* FindNext(FileFindHandle_t handle) = 0; + virtual bool FindIsDirectory(FileFindHandle_t handle) = 0; + virtual void FindClose(FileFindHandle_t handle) = 0; + + virtual const char* FindFirstEx( + const char* pWildCard, + const char* pPathID, + FileFindHandle_t* pHandle + ) = 0; + + virtual void FindFileAbsoluteList(CUtlVector< CUtlString >& outAbsolutePathNames, const char* pWildCard, const char* pPathID) = 0; + + virtual const char* GetLocalPath(const char* pFileName, char* pLocalPath, int localPathBufferSize) = 0; + + virtual bool FullPathToRelativePath(const char* pFullpath, char* pRelative, int maxlen) = 0; + + virtual bool GetCurrentDirectory(char* pDirectory, int maxlen) = 0; + + virtual FileNameHandle_t FindOrAddFileName(char const* pFileName) = 0; + virtual bool String(const FileNameHandle_t& handle, char* buf, int buflen) = 0; + + FSAsyncStatus_t AsyncRead(const FileAsyncRequest_t& request, FSAsyncControl_t* phControl = NULL) { return AsyncReadMultiple(&request, 1, phControl); } + virtual FSAsyncStatus_t AsyncReadMultiple(const FileAsyncRequest_t* pRequests, int nRequests, FSAsyncControl_t* phControls = NULL) = 0; + virtual FSAsyncStatus_t AsyncAppend(const char* pFileName, const void* pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t* pControl = NULL) = 0; + virtual FSAsyncStatus_t AsyncAppendFile(const char* pAppendToFileName, const char* pAppendFromFileName, FSAsyncControl_t* pControl = NULL) = 0; + virtual void AsyncFinishAll(int iToPriority = 0) = 0; + virtual void AsyncFinishAllWrites() = 0; + virtual FSAsyncStatus_t AsyncFlush() = 0; + virtual bool AsyncSuspend() = 0; + virtual bool AsyncResume() = 0; + + virtual FSAsyncStatus_t AsyncBeginRead(const char* pszFile, FSAsyncFile_t* phFile) = 0; + virtual FSAsyncStatus_t AsyncEndRead(FSAsyncFile_t hFile) = 0; + + virtual FSAsyncStatus_t AsyncFinish(FSAsyncControl_t hControl, bool wait = true) = 0; + virtual FSAsyncStatus_t AsyncGetResult(FSAsyncControl_t hControl, void** ppData, int* pSize) = 0; + virtual FSAsyncStatus_t AsyncAbort(FSAsyncControl_t hControl) = 0; + virtual FSAsyncStatus_t AsyncStatus(FSAsyncControl_t hControl) = 0; + virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) = 0; + virtual void AsyncAddRef(FSAsyncControl_t hControl) = 0; + virtual void AsyncRelease(FSAsyncControl_t hControl) = 0; + + virtual WaitForResourcesHandle_t WaitForResources(const char* resourcelist) = 0; + virtual bool GetWaitForResourcesProgress(WaitForResourcesHandle_t handle, float* progress , bool* complete ) = 0; + virtual void CancelWaitForResources(WaitForResourcesHandle_t handle) = 0; + + virtual int HintResourceNeed(const char* hintlist, int forgetEverything) = 0; + virtual bool IsFileImmediatelyAvailable(const char* pFileName) = 0; + + virtual void GetLocalCopy(const char* pFileName) = 0; + + virtual void PrintOpenedFiles(void) = 0; + virtual void PrintSearchPaths(void) = 0; + + virtual void SetWarningFunc(void (*pfnWarning)(const char* fmt, ...)) = 0; + virtual void SetWarningLevel(FileWarningLevel_t level) = 0; + virtual void AddLoggingFunc(void (*pfnLogFunc)(const char* fileName, const char* accessType)) = 0; + virtual void RemoveLoggingFunc(FileSystemLoggingFunc_t logFunc) = 0; + + virtual const FileSystemStatistics* GetFilesystemStatistics() = 0; + +#if defined( _PS3 ) + virtual void LogFileAccess(const char* pFullFileName) = 0; + + virtual bool PrefetchFile(const char* pFileName, int nPriority, bool bPersist) = 0; + virtual bool PrefetchFile(const char* pFileName, int nPriority, bool bPersist, int64 nOffset, int64 nSize) = 0; + virtual void FlushCache() = 0; + virtual void SuspendPrefetches(const char* pWhy) = 0; + virtual void ResumePrefetches(const char* pWhy) = 0; + + virtual void OnSaveStateChanged(bool bSaving) = 0; + + virtual bool IsPrefetchingDone() = 0; + +#endif + virtual FileHandle_t OpenEx(const char* pFileName, const char* pOptions, unsigned flags = 0, const char* pathID = 0, char** ppszResolvedFilename = NULL) = 0; + + virtual int ReadEx(void* pOutput, int sizeDest, int size, FileHandle_t file) = 0; + virtual int ReadFileEx(const char* pFileName, const char* pPath, void** ppBuf, bool bNullTerminate = false, bool bOptimalAlloc = false, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL) = 0; + + virtual FileNameHandle_t FindFileName(char const* pFileName) = 0; + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking(bool state) = 0; + virtual bool IsBlockingFileAccessEnabled() const = 0; + + virtual IBlockingFileItemList* RetrieveBlockingFileAccessInfo() = 0; +#endif + + virtual void SetupPreloadData() = 0; + virtual void DiscardPreloadData() = 0; + + enum KeyValuesPreloadType_t + { + TYPE_VMT, + TYPE_SOUNDEMITTER, + TYPE_SOUNDSCAPE, + TYPE_SOUNDOPERATORS, + NUM_PRELOAD_TYPES + }; + + virtual KeyValues* LoadKeyValues(KeyValuesPreloadType_t type, char const* filename, char const* pPathID = 0) = 0; + virtual bool LoadKeyValues(KeyValues& head, KeyValuesPreloadType_t type, char const* filename, char const* pPathID = 0) = 0; + + virtual FSAsyncStatus_t AsyncWrite(const char* pFileName, const void* pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t* pControl = NULL) = 0; + virtual FSAsyncStatus_t AsyncWriteFile(const char* pFileName, const CUtlBuffer* pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t* pControl = NULL) = 0; + FSAsyncStatus_t AsyncReadCreditAlloc(const FileAsyncRequest_t& request, const char* pszFile, int line, FSAsyncControl_t* phControl = NULL) { return AsyncReadMultipleCreditAlloc(&request, 1, pszFile, line, phControl); } + virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc(const FileAsyncRequest_t* pRequests, int nRequests, const char* pszFile, int line, FSAsyncControl_t* phControls = NULL) = 0; + + virtual FSAsyncStatus_t AsyncDirectoryScan(const char* pSearchSpec, bool recurseFolders, void* pContext, FSAsyncScanAddFunc_t pfnAdd, FSAsyncScanCompleteFunc_t pfnDone, FSAsyncControl_t* pControl = NULL) = 0; + + virtual bool GetFileTypeForFullPath(char const* pFullPath, wchar_t* buf, size_t bufSizeInBytes) = 0; + + virtual bool ReadToBuffer(FileHandle_t hFile, CUtlBuffer& buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL) = 0; + + virtual bool GetOptimalIOConstraints(FileHandle_t hFile, unsigned* pOffsetAlign, unsigned* pSizeAlign, unsigned* pBufferAlign) = 0; + inline unsigned GetOptimalReadSize(FileHandle_t hFile, unsigned nLogicalSize); + virtual void* AllocOptimalReadBuffer(FileHandle_t hFile, unsigned nSize = 0, unsigned nOffset = 0) = 0; + virtual void FreeOptimalReadBuffer(void*) = 0; + + virtual void BeginMapAccess() = 0; + virtual void EndMapAccess() = 0; + + virtual bool FullPathToRelativePathEx(const char* pFullpath, const char* pPathId, char* pRelative, int maxlen) = 0; + + virtual int GetPathIndex(const FileNameHandle_t& handle) = 0; + virtual long GetPathTime(const char* pPath, const char* pPathID) = 0; + + virtual DVDMode_t GetDVDMode() = 0; + + virtual void EnableWhitelistFileTracking(bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes) = 0; + + virtual void RegisterFileWhitelist(IFileList* pWantCRCList, IFileList* pAllowFromDiskList, IFileList** pFilesToReload) = 0; + + virtual void MarkAllCRCsUnverified() = 0; + + virtual void CacheFileCRCs(const char* pPathname, ECacheCRCType eType, IFileList* pFilter) = 0; + virtual EFileCRCStatus CheckCachedFileHash(const char* pPathID, const char* pRelativeFilename, int nFileFraction, FileHash_t* pFileHash) = 0; + + virtual int GetUnverifiedFileHashes(CUnverifiedFileHash* pFiles, int nMaxFiles) = 0; + + virtual int GetWhitelistSpewFlags() = 0; + virtual void SetWhitelistSpewFlags(int flags) = 0; + + virtual void InstallDirtyDiskReportFunc(FSDirtyDiskReportFunc_t func) = 0; + + virtual bool IsLaunchedFromXboxHDD() = 0; + virtual bool IsInstalledToXboxHDDCache() = 0; + virtual bool IsDVDHosted() = 0; + virtual bool IsInstallAllowed() = 0; + + virtual int GetSearchPathID(char* pPath, int nMaxLen) = 0; + virtual bool FixupSearchPathsAfterInstall() = 0; + + virtual FSDirtyDiskReportFunc_t GetDirtyDiskReportFunc() = 0; + + virtual void AddVPKFile(char const* pszName, SearchPathAdd_t addType = PATH_ADD_TO_TAIL) = 0; + virtual void RemoveVPKFile(char const* pszName) = 0; + virtual void GetVPKFileNames(CUtlVector& destVector) = 0; + virtual void RemoveAllMapSearchPaths() = 0; + virtual void SyncDvdDevCache() = 0; + + virtual bool GetStringFromKVPool(CRC32_t poolKey, unsigned int key, char* pOutBuff, int buflen) = 0; + + virtual bool DiscoverDLC(int iController) = 0; + virtual int IsAnyDLCPresent(bool* pbDLCSearchPathMounted = NULL) = 0; + virtual bool GetAnyDLCInfo(int iDLC, unsigned int* pLicenseMask, wchar_t* pTitleBuff, int nOutTitleSize) = 0; + virtual int IsAnyCorruptDLC() = 0; + virtual bool GetAnyCorruptDLCInfo(int iCorruptDLC, wchar_t* pTitleBuff, int nOutTitleSize) = 0; + virtual bool AddDLCSearchPaths() = 0; + virtual bool IsSpecificDLCPresent(unsigned int nDLCPackage) = 0; + + virtual void SetIODelayAlarm(float flThreshhold) = 0; + + virtual bool AddXLSPUpdateSearchPath(const void* pData, int nSize) = 0; + + virtual IIoStats* GetIoStats() = 0; + + virtual void CacheAllVPKFileHashes(bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes) = 0; + virtual bool CheckVPKFileHash(int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t& md5Value) = 0; + + virtual void GetVPKFileStatisticsKV(KeyValues* pKV) = 0; + +}; + +#if defined( _X360 ) && !defined( _CERT ) +extern char g_szXboxProfileLastFileOpened[MAX_PATH]; +#define SetLastProfileFileRead( s ) Q_strncpy( g_szXboxProfileLastFileOpened, sizeof( g_szXboxProfileLastFileOpened), pFileName ) +#define GetLastProfileFileRead() (&g_szXboxProfileLastFileOpened[0]) +#else +#define SetLastProfileFileRead( s ) ((void)0) +#define GetLastProfileFileRead() NULL +#endif + +#if defined( _X360 ) && defined( _BASETSD_H_ ) +class CXboxDiskCacheSetter +{ +public: + CXboxDiskCacheSetter(SIZE_T newSize) + { + m_oldSize = XGetFileCacheSize(); + XSetFileCacheSize(newSize); + } + + ~CXboxDiskCacheSetter() + { + XSetFileCacheSize(m_oldSize); + } +private: + SIZE_T m_oldSize; +}; +#define DISK_INTENSIVE() CXboxDiskCacheSetter cacheSetter( 1024*1024 ) +#else +#define DISK_INTENSIVE() ((void)0) +#endif + +inline unsigned IFileSystem::GetOptimalReadSize(FileHandle_t hFile, unsigned nLogicalSize) +{ + unsigned align; + if (GetOptimalIOConstraints(hFile, &align, NULL, NULL)) + return AlignValue(nLogicalSize, align); + else + return nLogicalSize; +} + +#include "filesystem_passthru.h" + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define AsyncRead( a, b ) AsyncReadCreditAlloc( a, __FILE__, __LINE__, b ) +#define AsyncReadMutiple( a, b, c ) AsyncReadMultipleCreditAlloc( a, b, __FILE__, __LINE__, c ) +#endif + + + + +#endif +``` + +`SpyCustom/sdk/filesystem_passthru.h`: + +```h +#ifndef FILESYSTEM_PASSTHRU_H +#define FILESYSTEM_PASSTHRU_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "filesystem.h" +#include +#include + +#ifdef AsyncRead +#undef AsyncRead +#undef AsyncReadMutiple +#endif + +template +class CInternalFileSystemPassThru : public Base +{ +public: + CInternalFileSystemPassThru() + { + m_pBaseFileSystemPassThru = NULL; + } + virtual void InitPassThru(IBaseFileSystem* pBaseFileSystemPassThru) + { + m_pBaseFileSystemPassThru = pBaseFileSystemPassThru; + } + virtual int Read(void* pOutput, int size, FileHandle_t file) { return m_pBaseFileSystemPassThru->Read(pOutput, size, file); } + virtual int Write(void const* pInput, int size, FileHandle_t file) { return m_pBaseFileSystemPassThru->Write(pInput, size, file); } + virtual FileHandle_t Open(const char* pFileName, const char* pOptions, const char* pathID) { return m_pBaseFileSystemPassThru->Open(pFileName, pOptions, pathID); } + virtual void Close(FileHandle_t file) { m_pBaseFileSystemPassThru->Close(file); } + virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) { m_pBaseFileSystemPassThru->Seek(file, pos, seekType); } + virtual unsigned int Tell(FileHandle_t file) { return m_pBaseFileSystemPassThru->Tell(file); } + virtual unsigned int Size(FileHandle_t file) { return m_pBaseFileSystemPassThru->Size(file); } + virtual unsigned int Size(const char* pFileName, const char* pPathID) { return m_pBaseFileSystemPassThru->Size(pFileName, pPathID); } + virtual void Flush(FileHandle_t file) { m_pBaseFileSystemPassThru->Flush(file); } + virtual bool Precache(const char* pFileName, const char* pPathID) { return m_pBaseFileSystemPassThru->Precache(pFileName, pPathID); } + virtual bool FileExists(const char* pFileName, const char* pPathID) { return m_pBaseFileSystemPassThru->FileExists(pFileName, pPathID); } + virtual bool IsFileWritable(char const* pFileName, const char* pPathID) { return m_pBaseFileSystemPassThru->IsFileWritable(pFileName, pPathID); } + virtual bool SetFileWritable(char const* pFileName, bool writable, const char* pPathID) { return m_pBaseFileSystemPassThru->SetFileWritable(pFileName, writable, pPathID); } + virtual long GetFileTime(const char* pFileName, const char* pPathID) { return m_pBaseFileSystemPassThru->GetFileTime(pFileName, pPathID); } + virtual bool ReadFile(const char* pFileName, const char* pPath, CUtlBuffer& buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL) { return m_pBaseFileSystemPassThru->ReadFile(pFileName, pPath, buf, nMaxBytes, nStartingByte, pfnAlloc); } + virtual bool WriteFile(const char* pFileName, const char* pPath, CUtlBuffer& buf) { return m_pBaseFileSystemPassThru->WriteFile(pFileName, pPath, buf); } + virtual bool UnzipFile(const char* pFileName, const char* pPath, const char* pDestination) { return m_pBaseFileSystemPassThru->UnzipFile(pFileName, pPath, pDestination); } + +protected: + IBaseFileSystem* m_pBaseFileSystemPassThru; +}; + + +class CBaseFileSystemPassThru : public CInternalFileSystemPassThru +{ +public: +}; + + +class CFileSystemPassThru : public CInternalFileSystemPassThru +{ +public: + typedef CInternalFileSystemPassThru BaseClass; + + CFileSystemPassThru() + { + m_pFileSystemPassThru = NULL; + } + virtual void InitPassThru(IFileSystem* pFileSystemPassThru, bool bBaseOnly) + { + if (!bBaseOnly) + m_pFileSystemPassThru = pFileSystemPassThru; + + BaseClass::InitPassThru(pFileSystemPassThru); + } + + virtual bool Connect(CreateInterfaceFn factory) { return m_pFileSystemPassThru->Connect(factory); } + virtual void Disconnect() { m_pFileSystemPassThru->Disconnect(); } + virtual void* QueryInterface(const char* pInterfaceName) { return m_pFileSystemPassThru->QueryInterface(pInterfaceName); } + virtual InitReturnVal_t Init() { return m_pFileSystemPassThru->Init(); } + virtual void Shutdown() { m_pFileSystemPassThru->Shutdown(); } + virtual const AppSystemInfo_t* GetDependencies() { return m_pFileSystemPassThru->GetDependencies(); } + virtual AppSystemTier_t GetTier() { return m_pFileSystemPassThru->GetTier(); } + virtual void Reconnect(CreateInterfaceFn factory, const char* pInterfaceName) { m_pFileSystemPassThru->Reconnect(factory, pInterfaceName); } + + virtual void RemoveAllSearchPaths(void) { m_pFileSystemPassThru->RemoveAllSearchPaths(); } + virtual void AddSearchPath(const char* pPath, const char* pathID, SearchPathAdd_t addType) { m_pFileSystemPassThru->AddSearchPath(pPath, pathID, addType); } + virtual bool RemoveSearchPath(const char* pPath, const char* pathID) { return m_pFileSystemPassThru->RemoveSearchPath(pPath, pathID); } + virtual void RemoveFile(char const* pRelativePath, const char* pathID) { m_pFileSystemPassThru->RemoveFile(pRelativePath, pathID); } + virtual bool RenameFile(char const* pOldPath, char const* pNewPath, const char* pathID) { return m_pFileSystemPassThru->RenameFile(pOldPath, pNewPath, pathID); } + virtual void CreateDirHierarchy(const char* path, const char* pathID) { m_pFileSystemPassThru->CreateDirHierarchy(path, pathID); } + virtual bool IsDirectory(const char* pFileName, const char* pathID) { return m_pFileSystemPassThru->IsDirectory(pFileName, pathID); } + virtual void FileTimeToString(char* pStrip, int maxCharsIncludingTerminator, long fileTime) { m_pFileSystemPassThru->FileTimeToString(pStrip, maxCharsIncludingTerminator, fileTime); } + virtual void SetBufferSize(FileHandle_t file, unsigned nBytes) { m_pFileSystemPassThru->SetBufferSize(file, nBytes); } + virtual bool IsOk(FileHandle_t file) { return m_pFileSystemPassThru->IsOk(file); } + virtual bool EndOfFile(FileHandle_t file) { return m_pFileSystemPassThru->EndOfFile(file); } + virtual char* ReadLine(char* pOutput, int maxChars, FileHandle_t file) { return m_pFileSystemPassThru->ReadLine(pOutput, maxChars, file); } + virtual int FPrintf(FileHandle_t file, const char* pFormat, ...) + { + char str[8192]; + va_list marker; + va_start(marker, pFormat); + _vsnprintf(str, sizeof(str), pFormat, marker); + va_end(marker); + return m_pFileSystemPassThru->FPrintf(file, "%s", str); + } + virtual CSysModule* LoadModule(const char* pFileName, const char* pPathID, bool bValidatedDllOnly) { return m_pFileSystemPassThru->LoadModule(pFileName, pPathID, bValidatedDllOnly); } + virtual void UnloadModule(CSysModule* pModule) { m_pFileSystemPassThru->UnloadModule(pModule); } + virtual const char* FindFirst(const char* pWildCard, FileFindHandle_t* pHandle) { return m_pFileSystemPassThru->FindFirst(pWildCard, pHandle); } + virtual const char* FindNext(FileFindHandle_t handle) { return m_pFileSystemPassThru->FindNext(handle); } + virtual bool FindIsDirectory(FileFindHandle_t handle) { return m_pFileSystemPassThru->FindIsDirectory(handle); } + virtual void FindClose(FileFindHandle_t handle) { m_pFileSystemPassThru->FindClose(handle); } + virtual void FindFileAbsoluteList(CUtlVector< CUtlString >& outAbsolutePathNames, const char* pWildCard, const char* pPathID) { m_pFileSystemPassThru->FindFileAbsoluteList(outAbsolutePathNames, pWildCard, pPathID); } + virtual const char* GetLocalPath(const char* pFileName, char* pLocalPath, int localPathBufferSize) { return m_pFileSystemPassThru->GetLocalPath(pFileName, pLocalPath, localPathBufferSize); } + virtual bool FullPathToRelativePath(const char* pFullpath, char* pRelative, int maxlen) { return m_pFileSystemPassThru->FullPathToRelativePath(pFullpath, pRelative, maxlen); } + virtual bool GetCurrentDirectory(char* pDirectory, int maxlen) { return m_pFileSystemPassThru->GetCurrentDirectory(pDirectory, maxlen); } + virtual void PrintOpenedFiles(void) { m_pFileSystemPassThru->PrintOpenedFiles(); } + virtual void PrintSearchPaths(void) { m_pFileSystemPassThru->PrintSearchPaths(); } + virtual void SetWarningFunc(void (*pfnWarning)(const char* fmt, ...)) { m_pFileSystemPassThru->SetWarningFunc(pfnWarning); } + virtual void SetWarningLevel(FileWarningLevel_t level) { m_pFileSystemPassThru->SetWarningLevel(level); } + virtual void AddLoggingFunc(void (*pfnLogFunc)(const char* fileName, const char* accessType)) { m_pFileSystemPassThru->AddLoggingFunc(pfnLogFunc); } + virtual void RemoveLoggingFunc(FileSystemLoggingFunc_t logFunc) { m_pFileSystemPassThru->RemoveLoggingFunc(logFunc); } + virtual FSAsyncStatus_t AsyncReadMultiple(const FileAsyncRequest_t* pRequests, int nRequests, FSAsyncControl_t* pControls) { return m_pFileSystemPassThru->AsyncReadMultiple(pRequests, nRequests, pControls); } + virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc(const FileAsyncRequest_t* pRequests, int nRequests, const char* pszFile, int line, FSAsyncControl_t* pControls) { return m_pFileSystemPassThru->AsyncReadMultipleCreditAlloc(pRequests, nRequests, pszFile, line, pControls); } + virtual FSAsyncStatus_t AsyncDirectoryScan(const char* pSearchSpec, bool recurseFolders, void* pContext, FSAsyncScanAddFunc_t pfnAdd, FSAsyncScanCompleteFunc_t pfnDone, FSAsyncControl_t* pControl = NULL) { return m_pFileSystemPassThru->AsyncDirectoryScan(pSearchSpec, recurseFolders, pContext, pfnAdd, pfnDone, pControl); } + virtual FSAsyncStatus_t AsyncFinish(FSAsyncControl_t hControl, bool wait) { return m_pFileSystemPassThru->AsyncFinish(hControl, wait); } + virtual FSAsyncStatus_t AsyncGetResult(FSAsyncControl_t hControl, void** ppData, int* pSize) { return m_pFileSystemPassThru->AsyncGetResult(hControl, ppData, pSize); } + virtual FSAsyncStatus_t AsyncAbort(FSAsyncControl_t hControl) { return m_pFileSystemPassThru->AsyncAbort(hControl); } + virtual FSAsyncStatus_t AsyncStatus(FSAsyncControl_t hControl) { return m_pFileSystemPassThru->AsyncStatus(hControl); } + virtual FSAsyncStatus_t AsyncFlush() { return m_pFileSystemPassThru->AsyncFlush(); } + virtual void AsyncAddRef(FSAsyncControl_t hControl) { m_pFileSystemPassThru->AsyncAddRef(hControl); } + virtual void AsyncRelease(FSAsyncControl_t hControl) { m_pFileSystemPassThru->AsyncRelease(hControl); } + virtual FSAsyncStatus_t AsyncBeginRead(const char* pszFile, FSAsyncFile_t* phFile) { return m_pFileSystemPassThru->AsyncBeginRead(pszFile, phFile); } + virtual FSAsyncStatus_t AsyncEndRead(FSAsyncFile_t hFile) { return m_pFileSystemPassThru->AsyncEndRead(hFile); } + virtual const FileSystemStatistics* GetFilesystemStatistics() { return m_pFileSystemPassThru->GetFilesystemStatistics(); } + + +#if defined( _PS3 ) + virtual Ps3FileType_t GetPs3FileType(const char* path) { return PS3_FILETYPE_UNKNOWN; } + virtual void LogFileAccess(const char* pFullFileName) { } + + virtual bool PrefetchFile(const char* pFileName, int nPriority, bool bPersist) { return m_pFileSystemPassThru->PrefetchFile(pFileName, nPriority, bPersist); } + virtual bool PrefetchFile(const char* pFileName, int nPriority, bool bPersist, int64 nOffset, int64 nSize) { return m_pFileSystemPassThru->PrefetchFile(pFileName, nPriority, bPersist, nOffset, nSize); } + virtual void FlushCache() { m_pFileSystemPassThru->FlushCache(); } + virtual void SuspendPrefetches(const char* pWhy) { m_pFileSystemPassThru->SuspendPrefetches(pWhy); } + virtual void ResumePrefetches(const char* pWhy) { m_pFileSystemPassThru->ResumePrefetches(pWhy); } + virtual void OnSaveStateChanged(bool bSaving) { m_pFileSystemPassThru->OnSaveStateChanged(bSaving); } + virtual bool IsPrefetchingDone() { return m_pFileSystemPassThru->IsPrefetchingDone(); } +#endif + + virtual WaitForResourcesHandle_t WaitForResources(const char* resourcelist) { return m_pFileSystemPassThru->WaitForResources(resourcelist); } + virtual bool GetWaitForResourcesProgress(WaitForResourcesHandle_t handle, + float* progress, bool* complete) { + return m_pFileSystemPassThru->GetWaitForResourcesProgress(handle, progress, complete); + } + virtual void CancelWaitForResources(WaitForResourcesHandle_t handle) { m_pFileSystemPassThru->CancelWaitForResources(handle); } + virtual int HintResourceNeed(const char* hintlist, int forgetEverything) { return m_pFileSystemPassThru->HintResourceNeed(hintlist, forgetEverything); } + virtual bool IsFileImmediatelyAvailable(const char* pFileName) { return m_pFileSystemPassThru->IsFileImmediatelyAvailable(pFileName); } + virtual void GetLocalCopy(const char* pFileName) { m_pFileSystemPassThru->GetLocalCopy(pFileName); } + virtual FileNameHandle_t FindOrAddFileName(char const* pFileName) { return m_pFileSystemPassThru->FindOrAddFileName(pFileName); } + virtual FileNameHandle_t FindFileName(char const* pFileName) { return m_pFileSystemPassThru->FindFileName(pFileName); } + virtual bool String(const FileNameHandle_t& handle, char* buf, int buflen) { return m_pFileSystemPassThru->String(handle, buf, buflen); } + virtual bool IsOk2(FileHandle_t file) { return IsOk(file); } + virtual void RemoveSearchPaths(const char* szPathID) { m_pFileSystemPassThru->RemoveSearchPaths(szPathID); } + virtual bool IsSteam() const { return m_pFileSystemPassThru->IsSteam(); } + virtual FilesystemMountRetval_t MountSteamContent(int nExtraAppId = -1) { return m_pFileSystemPassThru->MountSteamContent(nExtraAppId); } + + virtual const char* FindFirstEx( + const char* pWildCard, + const char* pPathID, + FileFindHandle_t* pHandle + ) { + return m_pFileSystemPassThru->FindFirstEx(pWildCard, pPathID, pHandle); + } + virtual void MarkPathIDByRequestOnly(const char* pPathID, bool bRequestOnly) { m_pFileSystemPassThru->MarkPathIDByRequestOnly(pPathID, bRequestOnly); } + virtual bool IsFileInReadOnlySearchPath(const char* pPath, const char* pathID) { return m_pFileSystemPassThru->IsFileInReadOnlySearchPath(pPath, pathID); } + + virtual bool AddPackFile(const char* fullpath, const char* pathID) { return m_pFileSystemPassThru->AddPackFile(fullpath, pathID); } + virtual FSAsyncStatus_t AsyncAppend(const char* pFileName, const void* pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t* pControl) { return m_pFileSystemPassThru->AsyncAppend(pFileName, pSrc, nSrcBytes, bFreeMemory, pControl); } + virtual FSAsyncStatus_t AsyncWrite(const char* pFileName, const void* pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t* pControl) { return m_pFileSystemPassThru->AsyncWrite(pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl); } + virtual FSAsyncStatus_t AsyncWriteFile(const char* pFileName, const CUtlBuffer* pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t* pControl) { return m_pFileSystemPassThru->AsyncWriteFile(pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl); } + virtual FSAsyncStatus_t AsyncAppendFile(const char* pDestFileName, const char* pSrcFileName, FSAsyncControl_t* pControl) { return m_pFileSystemPassThru->AsyncAppendFile(pDestFileName, pSrcFileName, pControl); } + virtual void AsyncFinishAll(int iToPriority) { m_pFileSystemPassThru->AsyncFinishAll(iToPriority); } + virtual void AsyncFinishAllWrites() { m_pFileSystemPassThru->AsyncFinishAllWrites(); } + virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) { return m_pFileSystemPassThru->AsyncSetPriority(hControl, newPriority); } + virtual bool AsyncSuspend() { return m_pFileSystemPassThru->AsyncSuspend(); } + virtual bool AsyncResume() { return m_pFileSystemPassThru->AsyncResume(); } + virtual const char* RelativePathToFullPath(const char* pFileName, const char* pPathID, char* pLocalPath, int localPathBufferSize, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t* pPathType = NULL) { return m_pFileSystemPassThru->RelativePathToFullPath(pFileName, pPathID, pLocalPath, localPathBufferSize, pathFilter, pPathType); } +#if IsGameConsole() + virtual bool GetPackFileInfoFromRelativePath(const char* pFileName, const char* pPathID, char* pPackPath, int nPackPathBufferSize, int64& nPosition, int64& nLength) { return m_pFileSystemPassThru->GetPackFileInfoFromRelativePath(pFileName, pPathID, pPackPath, nPackPathBufferSize, nPosition, nLength); } +#endif + + virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) { return m_pFileSystemPassThru->GetSearchPath(pathID, bGetPackFiles, pPath, nMaxLen); } + + virtual FileHandle_t OpenEx(const char* pFileName, const char* pOptions, unsigned flags = 0, const char* pathID = 0, char** ppszResolvedFilename = NULL) { return m_pFileSystemPassThru->OpenEx(pFileName, pOptions, flags, pathID, ppszResolvedFilename); } + virtual int ReadEx(void* pOutput, int destSize, int size, FileHandle_t file) { return m_pFileSystemPassThru->ReadEx(pOutput, destSize, size, file); } + virtual int ReadFileEx(const char* pFileName, const char* pPath, void** ppBuf, bool bNullTerminate, bool bOptimalAlloc, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL) { return m_pFileSystemPassThru->ReadFileEx(pFileName, pPath, ppBuf, bNullTerminate, bOptimalAlloc, nMaxBytes, nStartingByte, pfnAlloc); } + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking(bool state) { m_pFileSystemPassThru->EnableBlockingFileAccessTracking(state); } + virtual bool IsBlockingFileAccessEnabled() const { return m_pFileSystemPassThru->IsBlockingFileAccessEnabled(); } + + virtual IBlockingFileItemList* RetrieveBlockingFileAccessInfo() { return m_pFileSystemPassThru->RetrieveBlockingFileAccessInfo(); } +#endif + virtual void SetupPreloadData() {} + virtual void DiscardPreloadData() {} + + virtual KeyValues* LoadKeyValues(KeyValuesPreloadType_t type, char const* filename, char const* pPathID = 0) { return m_pFileSystemPassThru->LoadKeyValues(type, filename, pPathID); } + virtual bool LoadKeyValues(KeyValues& head, KeyValuesPreloadType_t type, char const* filename, char const* pPathID = 0) { return m_pFileSystemPassThru->LoadKeyValues(head, type, filename, pPathID); } + + virtual bool GetFileTypeForFullPath(char const* pFullPath, OUT_Z_BYTECAP(bufSizeInBytes) wchar_t* buf, size_t bufSizeInBytes) { return m_pFileSystemPassThru->GetFileTypeForFullPath(pFullPath, buf, bufSizeInBytes); } + + virtual bool GetOptimalIOConstraints(FileHandle_t hFile, unsigned* pOffsetAlign, unsigned* pSizeAlign, unsigned* pBufferAlign) { return m_pFileSystemPassThru->GetOptimalIOConstraints(hFile, pOffsetAlign, pSizeAlign, pBufferAlign); } + virtual void* AllocOptimalReadBuffer(FileHandle_t hFile, unsigned nSize, unsigned nOffset) { return m_pFileSystemPassThru->AllocOptimalReadBuffer(hFile, nOffset, nSize); } + virtual void FreeOptimalReadBuffer(void* p) { m_pFileSystemPassThru->FreeOptimalReadBuffer(p); } + + virtual void BeginMapAccess() { m_pFileSystemPassThru->BeginMapAccess(); } + virtual void EndMapAccess() { m_pFileSystemPassThru->EndMapAccess(); } + + virtual bool ReadToBuffer(FileHandle_t hFile, CUtlBuffer& buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL) { return m_pFileSystemPassThru->ReadToBuffer(hFile, buf, nMaxBytes, pfnAlloc); } + virtual bool FullPathToRelativePathEx(const char* pFullPath, const char* pPathId, char* pRelative, int nMaxLen) { return m_pFileSystemPassThru->FullPathToRelativePathEx(pFullPath, pPathId, pRelative, nMaxLen); } + virtual int GetPathIndex(const FileNameHandle_t& handle) { return m_pFileSystemPassThru->GetPathIndex(handle); } + virtual long GetPathTime(const char* pPath, const char* pPathID) { return m_pFileSystemPassThru->GetPathTime(pPath, pPathID); } + + virtual DVDMode_t GetDVDMode() { return m_pFileSystemPassThru->GetDVDMode(); } + + virtual void EnableWhitelistFileTracking(bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes) + { + m_pFileSystemPassThru->EnableWhitelistFileTracking(bEnable, bCacheAllVPKHashes, bRecalculateAndCheckHashes); + } + + virtual void RegisterFileWhitelist(IFileList* pForceMatchList, IFileList* pAllowFromDiskList, IFileList** pFilesToReload) + { + m_pFileSystemPassThru->RegisterFileWhitelist(pForceMatchList, pAllowFromDiskList, pFilesToReload); + } + virtual void MarkAllCRCsUnverified() + { + m_pFileSystemPassThru->MarkAllCRCsUnverified(); + } + virtual void CacheFileCRCs(const char* pPathname, ECacheCRCType eType, IFileList* pFilter) + { + return m_pFileSystemPassThru->CacheFileCRCs(pPathname, eType, pFilter); + } + virtual EFileCRCStatus CheckCachedFileHash(const char* pPathID, const char* pRelativeFilename, int nFileFraction, FileHash_t* pFileHash) + { + return m_pFileSystemPassThru->CheckCachedFileHash(pPathID, pRelativeFilename, nFileFraction, pFileHash); + } + virtual int GetUnverifiedFileHashes(CUnverifiedFileHash* pFiles, int nMaxFiles) + { + return m_pFileSystemPassThru->GetUnverifiedFileHashes(pFiles, nMaxFiles); + } + virtual int GetWhitelistSpewFlags() + { + return m_pFileSystemPassThru->GetWhitelistSpewFlags(); + } + virtual void SetWhitelistSpewFlags(int spewFlags) + { + m_pFileSystemPassThru->SetWhitelistSpewFlags(spewFlags); + } + virtual void InstallDirtyDiskReportFunc(FSDirtyDiskReportFunc_t func) { m_pFileSystemPassThru->InstallDirtyDiskReportFunc(func); } + + virtual bool IsLaunchedFromXboxHDD() { return m_pFileSystemPassThru->IsLaunchedFromXboxHDD(); } + virtual bool IsInstalledToXboxHDDCache() { return m_pFileSystemPassThru->IsInstalledToXboxHDDCache(); } + virtual bool IsDVDHosted() { return m_pFileSystemPassThru->IsDVDHosted(); } + virtual bool IsInstallAllowed() { return m_pFileSystemPassThru->IsInstallAllowed(); } + virtual int GetSearchPathID(char* pPath, int nMaxLen) { return m_pFileSystemPassThru->GetSearchPathID(pPath, nMaxLen); } + virtual bool FixupSearchPathsAfterInstall() { return m_pFileSystemPassThru->FixupSearchPathsAfterInstall(); } + + virtual FSDirtyDiskReportFunc_t GetDirtyDiskReportFunc() { return m_pFileSystemPassThru->GetDirtyDiskReportFunc(); } + + virtual void AddVPKFile(char const* pPkName, SearchPathAdd_t addType = PATH_ADD_TO_TAIL) { m_pFileSystemPassThru->AddVPKFile(pPkName, addType); } + virtual void RemoveVPKFile(char const* pPkName) { m_pFileSystemPassThru->RemoveVPKFile(pPkName); } + virtual void GetVPKFileNames(CUtlVector& destVector) { m_pFileSystemPassThru->GetVPKFileNames(destVector); } + + virtual void RemoveAllMapSearchPaths(void) { m_pFileSystemPassThru->RemoveAllMapSearchPaths(); } + + virtual void SyncDvdDevCache(void) { m_pFileSystemPassThru->SyncDvdDevCache(); } + + virtual bool GetStringFromKVPool(CRC32_t poolKey, unsigned int key, char* pOutBuff, int buflen) { return m_pFileSystemPassThru->GetStringFromKVPool(poolKey, key, pOutBuff, buflen); } + + virtual bool DiscoverDLC(int iController) { return m_pFileSystemPassThru->DiscoverDLC(iController); } + virtual int IsAnyDLCPresent(bool* pbDLCSearchPathMounted = NULL) { return m_pFileSystemPassThru->IsAnyDLCPresent(pbDLCSearchPathMounted); } + virtual bool GetAnyDLCInfo(int iDLC, unsigned int* pLicenseMask, wchar_t* pTitleBuff, int nOutTitleSize) { return m_pFileSystemPassThru->GetAnyDLCInfo(iDLC, pLicenseMask, pTitleBuff, nOutTitleSize); } + virtual int IsAnyCorruptDLC() { return m_pFileSystemPassThru->IsAnyCorruptDLC(); } + virtual bool GetAnyCorruptDLCInfo(int iCorruptDLC, wchar_t* pTitleBuff, int nOutTitleSize) { return m_pFileSystemPassThru->GetAnyCorruptDLCInfo(iCorruptDLC, pTitleBuff, nOutTitleSize); } + virtual bool AddDLCSearchPaths() { return m_pFileSystemPassThru->AddDLCSearchPaths(); } + virtual bool IsSpecificDLCPresent(unsigned int nDLCPackage) { return m_pFileSystemPassThru->IsSpecificDLCPresent(nDLCPackage); } + virtual void SetIODelayAlarm(float flThreshhold) { m_pFileSystemPassThru->SetIODelayAlarm(flThreshhold); } + virtual bool AddXLSPUpdateSearchPath(const void* pData, int nSize) { return m_pFileSystemPassThru->AddXLSPUpdateSearchPath(pData, nSize); } + virtual IIoStats* GetIoStats() { return m_pFileSystemPassThru->GetIoStats(); } + + virtual void CacheAllVPKFileHashes(bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes) + { + return m_pFileSystemPassThru->CacheAllVPKFileHashes(bCacheAllVPKHashes, bRecalculateAndCheckHashes); + } + virtual bool CheckVPKFileHash(int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t& md5Value) + { + return m_pFileSystemPassThru->CheckVPKFileHash(PackFileID, nPackFileNumber, nFileFraction, md5Value); + } + virtual void GetVPKFileStatisticsKV(KeyValues* pKV) { m_pFileSystemPassThru->GetVPKFileStatisticsKV(pKV); } + +protected: + IFileSystem* m_pFileSystemPassThru; +}; + + +#endif +``` + +`SpyCustom/sdk/flashlighteffect.h`: + +```h +#ifndef FLASHLIGHTEFFECT_H +#define FLASHLIGHTEFFECT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "MaterialSystemUtil.h" + + +class CountdownTimer +{ +public: +#ifdef CLIENT_DLL + DECLARE_PREDICTABLE(); +#endif + DECLARE_CLASS_NOBASE(CountdownTimer); + DECLARE_EMBEDDED_NETWORKVAR(); + + CountdownTimer(void); + + void Reset(void) + { + m_timestamp = Now() + m_duration; + } + + void Start(float duration) + { + m_timestamp = Now() + duration; + m_duration = duration; + } + + void StartFromTime(float startTime, float duration) + { + m_timestamp = startTime + duration; + m_duration = duration; + } + + void Invalidate(void) + { + m_timestamp = -1.0f; + } + + bool HasStarted(void) const + { + return (m_timestamp > 0.0f); + } + + bool IsElapsed(void) const + { + return (Now() > m_timestamp); + } + + float GetElapsedTime(void) const + { + return Now() - m_timestamp + m_duration; + } + + float GetRemainingTime(void) const + { + return (m_timestamp - Now()); + } + + float GetCountdownDuration(void) const + { + return (m_timestamp > 0.0f) ? m_duration : 0.0f; + } + + float GetRemainingRatio(void) const + { + if (HasStarted()) + { + float left = GetRemainingTime() / m_duration; + if (left < 0.0f) + return 0.0f; + if (left > 1.0f) + return 1.0f; + return left; + } + + return 0.0f; + } + +private: + CNetworkVar(float, m_duration); + CNetworkVar(float, m_timestamp); + float Now(void) const; +}; + +struct dlight_t; + + + + +class CFlashlightEffect +{ +public: + + CFlashlightEffect(int nEntIndex = 0, const char* pszTextureName = NULL, float flFov = 0.0f, float flFarZ = 0.0f, float flLinearAtten = 0.0f); + ~CFlashlightEffect(); + + void UpdateLight(int nEntIdx, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, float flFov, + float flFarZ, float flLinearAtten, bool castsShadows, const char* pTextureName); + void UpdateLight(int nEntIdx, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, float flFov, + bool castsShadows, ITexture* pFlashlightTexture, const Vector& vecBrightness, bool bTracePlayers = true); + + void TurnOn(); + void TurnOff(); + void SetMuzzleFlashEnabled(bool bEnabled, float flBrightness); + bool IsOn(void) { return m_bIsOn; } + + ClientShadowHandle_t GetFlashlightHandle(void) { return m_FlashlightHandle; } + void SetFlashlightHandle(ClientShadowHandle_t Handle) { m_FlashlightHandle = Handle; } + + const char* GetFlashlightTextureName(void) const + { + return m_textureName; + } + + int GetEntIndex(void) const + { + return m_nEntIndex; + } + + bool UpdateDefaultFlashlightState(FlashlightState_t& state, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, + const Vector& vecUp, bool castsShadows, bool bTracePlayers = true); + bool ComputeLightPosAndOrientation(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, + Vector& vecFinalPos, Quaternion& quatOrientation, bool bTracePlayers); + void LightOff(); + + void UpdateFlashlightTexture(const char* pTextureName); + void UpdateLightTopDown(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp); + + bool m_bIsOn; + int m_nEntIndex; + ClientShadowHandle_t m_FlashlightHandle; + + bool m_bMuzzleFlashEnabled; + float m_flMuzzleFlashBrightness; + + float m_flFov; + float m_flFarZ; + float m_flLinearAtten; + bool m_bCastsShadows; + + float m_flCurrentPullBackDist; + + CTextureReference m_FlashlightTexture; + + CTextureReference m_MuzzleFlashTexture; + + char m_textureName[64]; +}; + +class CHeadlightEffect : public CFlashlightEffect +{ +public: + + CHeadlightEffect(); + ~CHeadlightEffect(); + + virtual void UpdateLight(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, int nDistance); +}; + + + +class CFlashlightEffectManager +{ +private: + CFlashlightEffect* m_pFlashlightEffect; + const char* m_pFlashlightTextureName; + int m_nFlashlightEntIndex; + float m_flFov; + float m_flFarZ; + float m_flLinearAtten; + int m_nMuzzleFlashFrameCountdown; + CountdownTimer m_muzzleFlashTimer; + float m_flMuzzleFlashBrightness; + bool m_bFlashlightOn; + int m_nFXComputeFrame; + bool m_bFlashlightOverride; + +public: + CFlashlightEffectManager() : m_pFlashlightEffect(NULL), m_pFlashlightTextureName(NULL), m_nFlashlightEntIndex(-1), m_flFov(0.0f), + m_flFarZ(0.0f), m_flLinearAtten(0.0f), m_nMuzzleFlashFrameCountdown(0), m_flMuzzleFlashBrightness(1.0f), + m_bFlashlightOn(false), m_nFXComputeFrame(-1), m_bFlashlightOverride(false) {} + + void TurnOnFlashlight(int nEntIndex = 0, const char* pszTextureName = NULL, float flFov = 0.0f, float flFarZ = 0.0f, float flLinearAtten = 0.0f) + { + m_pFlashlightTextureName = pszTextureName; + m_nFlashlightEntIndex = nEntIndex; + m_flFov = flFov; + m_flFarZ = flFarZ; + m_flLinearAtten = flLinearAtten; + m_bFlashlightOn = true; + + if (m_bFlashlightOverride) + { + return; + } + + if (!m_pFlashlightEffect) + { + if (pszTextureName) + { + m_pFlashlightEffect = new CFlashlightEffect(m_nFlashlightEntIndex, pszTextureName, flFov, flFarZ, flLinearAtten); + } + else + { + m_pFlashlightEffect = new CFlashlightEffect(m_nFlashlightEntIndex); + } + + if (!m_pFlashlightEffect) + { + return; + } + } + + m_pFlashlightEffect->TurnOn(); + } + + void TurnOffFlashlight(bool bForce = false) + { + m_pFlashlightTextureName = NULL; + m_bFlashlightOn = false; + + if (bForce) + { + m_bFlashlightOverride = false; + m_nMuzzleFlashFrameCountdown = 0; + m_muzzleFlashTimer.Invalidate(); + delete m_pFlashlightEffect; + m_pFlashlightEffect = NULL; + return; + } + + if (m_bFlashlightOverride) + { + return; + } + + if (m_nMuzzleFlashFrameCountdown == 0 && m_muzzleFlashTimer.IsElapsed()) + { + delete m_pFlashlightEffect; + m_pFlashlightEffect = NULL; + } + } + + bool IsFlashlightOn() const { return m_bFlashlightOn; } + + void UpdateFlashlight(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, float flFov, bool castsShadows, + float flFarZ, float flLinearAtten, const char* pTextureName = NULL); + void SetEntityIndex(int index) + { + m_nFlashlightEntIndex = index; + } + + void TriggerMuzzleFlash() + { + } + + const char* GetFlashlightTextureName(void) const + { + return m_pFlashlightTextureName; + } + + int GetFlashlightEntIndex(void) const + { + return m_nFlashlightEntIndex; + } + + void EnableFlashlightOverride(bool bEnable) + { + m_bFlashlightOverride = bEnable; + + if (!m_bFlashlightOverride) + { + if (m_bFlashlightOn && m_pFlashlightEffect == NULL) + { + TurnOnFlashlight(m_nFlashlightEntIndex, m_pFlashlightTextureName, m_flFov, m_flFarZ, m_flLinearAtten); + } + else if (!m_bFlashlightOn && m_pFlashlightEffect) + { + delete m_pFlashlightEffect; + m_pFlashlightEffect = NULL; + } + } + } + + void UpdateFlashlightOverride(bool bFlashlightOn, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, + float flFov, bool castsShadows, ITexture* pFlashlightTexture, const Vector& vecBrightness) + { + Assert(m_bFlashlightOverride); + if (!m_bFlashlightOverride) + { + return; + } + + if (bFlashlightOn && !m_pFlashlightEffect) + { + m_pFlashlightEffect = new CFlashlightEffect(m_nFlashlightEntIndex); + } + else if (!bFlashlightOn && m_pFlashlightEffect) + { + delete m_pFlashlightEffect; + m_pFlashlightEffect = NULL; + } + + if (m_pFlashlightEffect) + { + m_pFlashlightEffect->UpdateLight(m_nFlashlightEntIndex, vecPos, vecDir, vecRight, vecUp, flFov, castsShadows, pFlashlightTexture, vecBrightness, false); + } + } +}; + + + + + +#endif + +``` + +`SpyCustom/sdk/fltx4.h`: + +```h +#ifndef FLTX4_H +#define FLTX4_H + +#if defined(GNUC) +#define USE_STDC_FOR_SIMD 0 +#else +#define USE_STDC_FOR_SIMD 0 +#endif + +#if (!defined(PLATFORM_PPC) && (USE_STDC_FOR_SIMD == 0)) +#define _SSE1 1 +#endif + +#if USE_STDC_FOR_SIMD +#error "hello" +typedef union +{ + float m128_f32[4]; + uint32 m128_u32[4]; +} fltx4; + +typedef fltx4 i32x4; +typedef fltx4 u32x4; + +#ifdef _PS3 +typedef fltx4 u32x4; +typedef fltx4 i32x4; +#endif +typedef fltx4 bi32x4; + +#elif ( defined( _PS3 ) ) + +typedef union +{ + vec_float4 vmxf; + vec_int4 vmxi; + vec_uint4 vmxui; +#if defined(__SPU__) + vec_uint4 vmxbi; +#else + __vector bool vmxbi; +#endif + + struct + { + float x; + float y; + float z; + float w; + }; + + float m128_f32[4]; + uint32 m128_u32[4]; + int32 m128_i32[4]; + +} fltx4_union; + +typedef vec_float4 fltx4; +typedef vec_uint4 u32x4; +typedef vec_int4 i32x4; + +#if defined(__SPU__) +typedef vec_uint4 bi32x4; +#else +typedef __vector bool bi32x4; +#endif + +#define DIFFERENT_NATIVE_VECTOR_TYPES + +#elif ( defined( _X360 ) ) + +typedef union +{ + __vector4 vmx; + float m128_f32[4]; + uint32 m128_u32[4]; +} fltx4_union; + +typedef __vector4 fltx4; +typedef __vector4 i32x4; +typedef __vector4 u32x4; +typedef fltx4 bi32x4; +#else + +typedef __m128 fltx4; +typedef __m128 i32x4; +typedef __m128 u32x4; +typedef __m128i shortx8; +typedef fltx4 bi32x4; + +#endif + +#endif +``` + +`SpyCustom/sdk/functors.h`: + +```h +#ifndef FUNCTORS_H +#define FUNCTORS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "platform.h" +#include "refcount.h" +#include "utlenvelope.h" +#include + + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_0 +#define FUNC_TEMPLATE_ARG_PARAMS_0 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_0 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_0 +#define FUNC_ARG_MEMBERS_0 +#define FUNC_ARG_FORMAL_PARAMS_0 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_0 +#define FUNC_CALL_ARGS_INIT_0 +#define FUNC_SOLO_CALL_ARGS_INIT_0 +#define FUNC_CALL_MEMBER_ARGS_0 +#define FUNC_CALL_ARGS_0 +#define FUNC_CALL_DATA_ARGS_0( _var ) +#define FUNC_FUNCTOR_CALL_ARGS_0 +#define FUNC_TEMPLATE_FUNC_PARAMS_0 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_0 +#define FUNC_VALIDATION_STRING_0 Q_snprintf( pString, nBufLen, "method( void )" ); +#define FUNC_SEPARATOR_0 + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_1 typename ARG_TYPE_1 +#define FUNC_TEMPLATE_ARG_PARAMS_1 , typename ARG_TYPE_1 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_1 , ARG_TYPE_1 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_1 ARG_TYPE_1 +#define FUNC_ARG_MEMBERS_1 ARG_TYPE_1 m_arg1 +#define FUNC_ARG_FORMAL_PARAMS_1 , const ARG_TYPE_1 &arg1 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_1 const ARG_TYPE_1 &arg1 +#define FUNC_CALL_ARGS_INIT_1 , m_arg1( arg1 ) +#define FUNC_SOLO_CALL_ARGS_INIT_1 : m_arg1( arg1 ) +#define FUNC_CALL_MEMBER_ARGS_1 m_arg1 +#define FUNC_CALL_ARGS_1 arg1 +#define FUNC_CALL_DATA_ARGS_1( _var ) _var->m_arg1 +#define FUNC_FUNCTOR_CALL_ARGS_1 , arg1 +#define FUNC_TEMPLATE_FUNC_PARAMS_1 , typename FUNC_ARG_TYPE_1 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_1 FUNC_ARG_TYPE_1 +#define FUNC_VALIDATION_STRING_1 Q_snprintf( pString, nBufLen, "method( %s )", typeid( ARG_TYPE_1 ).name() ); +#define FUNC_SEPARATOR_1 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_2 typename ARG_TYPE_1, typename ARG_TYPE_2 +#define FUNC_TEMPLATE_ARG_PARAMS_2 , typename ARG_TYPE_1, typename ARG_TYPE_2 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_2 , ARG_TYPE_1, ARG_TYPE_2 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_2 ARG_TYPE_1, ARG_TYPE_2 +#define FUNC_ARG_MEMBERS_2 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2 +#define FUNC_ARG_FORMAL_PARAMS_2 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_2 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2 +#define FUNC_CALL_ARGS_INIT_2 , m_arg1( arg1 ), m_arg2( arg2 ) +#define FUNC_SOLO_CALL_ARGS_INIT_2 : m_arg1( arg1 ), m_arg2( arg2 ) +#define FUNC_CALL_MEMBER_ARGS_2 m_arg1, m_arg2 +#define FUNC_CALL_ARGS_2 arg1, arg2 +#define FUNC_CALL_DATA_ARGS_2( _var ) _var->m_arg1, _var->m_arg2 +#define FUNC_FUNCTOR_CALL_ARGS_2 , arg1, arg2 +#define FUNC_TEMPLATE_FUNC_PARAMS_2 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_2 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2 +#define FUNC_VALIDATION_STRING_2 Q_snprintf( pString, nBufLen, "method( %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name() ); +#define FUNC_SEPARATOR_2 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_3 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3 +#define FUNC_TEMPLATE_ARG_PARAMS_3 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_3 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_3 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3 +#define FUNC_ARG_MEMBERS_3 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3 +#define FUNC_ARG_FORMAL_PARAMS_3 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_3 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3 +#define FUNC_CALL_ARGS_INIT_3 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ) +#define FUNC_SOLO_CALL_ARGS_INIT_3 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ) +#define FUNC_CALL_MEMBER_ARGS_3 m_arg1, m_arg2, m_arg3 +#define FUNC_CALL_ARGS_3 arg1, arg2, arg3 +#define FUNC_CALL_DATA_ARGS_3( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3 +#define FUNC_FUNCTOR_CALL_ARGS_3 , arg1, arg2, arg3 +#define FUNC_TEMPLATE_FUNC_PARAMS_3 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_3 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3 +#define FUNC_VALIDATION_STRING_3 Q_snprintf( pString, nBufLen, "method( %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name() ); +#define FUNC_SEPARATOR_3 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_4 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4 +#define FUNC_TEMPLATE_ARG_PARAMS_4 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_4 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_4 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4 +#define FUNC_ARG_MEMBERS_4 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4 +#define FUNC_ARG_FORMAL_PARAMS_4 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_4 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4 +#define FUNC_CALL_ARGS_INIT_4 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ) +#define FUNC_SOLO_CALL_ARGS_INIT_4 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ) +#define FUNC_CALL_MEMBER_ARGS_4 m_arg1, m_arg2, m_arg3, m_arg4 +#define FUNC_CALL_ARGS_4 arg1, arg2, arg3, arg4 +#define FUNC_CALL_DATA_ARGS_4( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4 +#define FUNC_FUNCTOR_CALL_ARGS_4 , arg1, arg2, arg3, arg4 +#define FUNC_TEMPLATE_FUNC_PARAMS_4 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_4 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4 +#define FUNC_VALIDATION_STRING_4 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name() ); +#define FUNC_SEPARATOR_4 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_5 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5 +#define FUNC_TEMPLATE_ARG_PARAMS_5 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_5 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_5 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5 +#define FUNC_ARG_MEMBERS_5 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5 +#define FUNC_ARG_FORMAL_PARAMS_5 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_5 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5 +#define FUNC_CALL_ARGS_INIT_5 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ) +#define FUNC_SOLO_CALL_ARGS_INIT_5 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ) +#define FUNC_CALL_MEMBER_ARGS_5 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5 +#define FUNC_CALL_ARGS_5 arg1, arg2, arg3, arg4, arg5 +#define FUNC_CALL_DATA_ARGS_5( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5 +#define FUNC_FUNCTOR_CALL_ARGS_5 , arg1, arg2, arg3, arg4, arg5 +#define FUNC_TEMPLATE_FUNC_PARAMS_5 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_5 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5 +#define FUNC_VALIDATION_STRING_5 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name() ); +#define FUNC_SEPARATOR_5 , + + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_6 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6 +#define FUNC_TEMPLATE_ARG_PARAMS_6 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_6 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_6 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6 +#define FUNC_ARG_MEMBERS_6 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6 +#define FUNC_ARG_FORMAL_PARAMS_6 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_6 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6 +#define FUNC_CALL_ARGS_INIT_6 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ) +#define FUNC_SOLO_CALL_ARGS_INIT_6 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ) +#define FUNC_CALL_MEMBER_ARGS_6 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6 +#define FUNC_CALL_ARGS_6 arg1, arg2, arg3, arg4, arg5, arg6 +#define FUNC_CALL_DATA_ARGS_6( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6 +#define FUNC_FUNCTOR_CALL_ARGS_6 , arg1, arg2, arg3, arg4, arg5, arg6 +#define FUNC_TEMPLATE_FUNC_PARAMS_6 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_6 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6 +#define FUNC_VALIDATION_STRING_6 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name() ); +#define FUNC_SEPARATOR_6 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_7 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7 +#define FUNC_TEMPLATE_ARG_PARAMS_7 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_7 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_7 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7 +#define FUNC_ARG_MEMBERS_7 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; +#define FUNC_ARG_FORMAL_PARAMS_7 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_7 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7 +#define FUNC_CALL_ARGS_INIT_7 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ) +#define FUNC_SOLO_CALL_ARGS_INIT_7 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ) +#define FUNC_CALL_MEMBER_ARGS_7 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7 +#define FUNC_CALL_ARGS_7 arg1, arg2, arg3, arg4, arg5, arg6, arg7 +#define FUNC_CALL_DATA_ARGS_7( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7 +#define FUNC_FUNCTOR_CALL_ARGS_7 , arg1, arg2, arg3, arg4, arg5, arg6, arg7 +#define FUNC_TEMPLATE_FUNC_PARAMS_7 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_7 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7 +#define FUNC_VALIDATION_STRING_7 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name() ); +#define FUNC_SEPARATOR_7 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_8 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8 +#define FUNC_TEMPLATE_ARG_PARAMS_8 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_8 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_8 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8 +#define FUNC_ARG_MEMBERS_8 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; +#define FUNC_ARG_FORMAL_PARAMS_8 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_8 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8 +#define FUNC_CALL_ARGS_INIT_8 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ) +#define FUNC_SOLO_CALL_ARGS_INIT_8 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ) +#define FUNC_CALL_MEMBER_ARGS_8 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8 +#define FUNC_CALL_ARGS_8 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 +#define FUNC_CALL_DATA_ARGS_8( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8 +#define FUNC_FUNCTOR_CALL_ARGS_8 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 +#define FUNC_TEMPLATE_FUNC_PARAMS_8 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_8 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8 +#define FUNC_VALIDATION_STRING_8 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name() ); +#define FUNC_SEPARATOR_8 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_9 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9 +#define FUNC_TEMPLATE_ARG_PARAMS_9 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_9 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_9 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9 +#define FUNC_ARG_MEMBERS_9 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; +#define FUNC_ARG_FORMAL_PARAMS_9 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_9 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9 +#define FUNC_CALL_ARGS_INIT_9 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ) +#define FUNC_SOLO_CALL_ARGS_INIT_9 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ) +#define FUNC_CALL_MEMBER_ARGS_9 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9 +#define FUNC_CALL_ARGS_9 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 +#define FUNC_CALL_DATA_ARGS_9( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9 +#define FUNC_FUNCTOR_CALL_ARGS_9 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 +#define FUNC_TEMPLATE_FUNC_PARAMS_9 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_9 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9 +#define FUNC_VALIDATION_STRING_9 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name() ); +#define FUNC_SEPARATOR_9 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_10 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10 +#define FUNC_TEMPLATE_ARG_PARAMS_10 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_10 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_10 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10 +#define FUNC_ARG_MEMBERS_10 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; +#define FUNC_ARG_FORMAL_PARAMS_10 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_10 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10 +#define FUNC_CALL_ARGS_INIT_10 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ) +#define FUNC_SOLO_CALL_ARGS_INIT_10 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ) +#define FUNC_CALL_MEMBER_ARGS_10 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10 +#define FUNC_CALL_ARGS_10 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +#define FUNC_CALL_DATA_ARGS_10( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10 +#define FUNC_FUNCTOR_CALL_ARGS_10 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +#define FUNC_TEMPLATE_FUNC_PARAMS_10 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_10 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10 +#define FUNC_VALIDATION_STRING_10 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name() ); +#define FUNC_SEPARATOR_10 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_11 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11 +#define FUNC_TEMPLATE_ARG_PARAMS_11 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_11 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_11 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11 +#define FUNC_ARG_MEMBERS_11 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11 +#define FUNC_ARG_FORMAL_PARAMS_11 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_11 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11 +#define FUNC_CALL_ARGS_INIT_11 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ) +#define FUNC_SOLO_CALL_ARGS_INIT_11 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ) +#define FUNC_CALL_MEMBER_ARGS_11 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11 +#define FUNC_CALL_ARGS_11 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 +#define FUNC_CALL_DATA_ARGS_11( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11 +#define FUNC_FUNCTOR_CALL_ARGS_11 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 +#define FUNC_TEMPLATE_FUNC_PARAMS_11 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_11 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11 +#define FUNC_VALIDATION_STRING_11 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name() ); +#define FUNC_SEPARATOR_11 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_12 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12 +#define FUNC_TEMPLATE_ARG_PARAMS_12 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_12 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_12 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12 +#define FUNC_ARG_MEMBERS_12 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12 +#define FUNC_ARG_FORMAL_PARAMS_12 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_12 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12 +#define FUNC_CALL_ARGS_INIT_12 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ) +#define FUNC_SOLO_CALL_ARGS_INIT_12 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ) +#define FUNC_CALL_MEMBER_ARGS_12 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12 +#define FUNC_CALL_ARGS_12 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 +#define FUNC_CALL_DATA_ARGS_12( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12 +#define FUNC_FUNCTOR_CALL_ARGS_12 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 +#define FUNC_TEMPLATE_FUNC_PARAMS_12 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_12 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12 +#define FUNC_VALIDATION_STRING_12 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name() ); +#define FUNC_SEPARATOR_12 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_13 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13 +#define FUNC_TEMPLATE_ARG_PARAMS_13 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_13 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_13 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13 +#define FUNC_ARG_MEMBERS_13 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13 +#define FUNC_ARG_FORMAL_PARAMS_13 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_13 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13 +#define FUNC_CALL_ARGS_INIT_13 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ) +#define FUNC_SOLO_CALL_ARGS_INIT_13 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ) +#define FUNC_CALL_MEMBER_ARGS_13 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13 +#define FUNC_CALL_ARGS_13 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 +#define FUNC_CALL_DATA_ARGS_13( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12, _var->m_arg13 +#define FUNC_FUNCTOR_CALL_ARGS_13 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 +#define FUNC_TEMPLATE_FUNC_PARAMS_13 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_13 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13 +#define FUNC_VALIDATION_STRING_13 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name(), typeid( ARG_TYPE_13 ).name() ); +#define FUNC_SEPARATOR_13 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_14 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14 +#define FUNC_TEMPLATE_ARG_PARAMS_14 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_14 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_14 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14 +#define FUNC_ARG_MEMBERS_14 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13; ARG_TYPE_14 m_arg14 +#define FUNC_ARG_FORMAL_PARAMS_14 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_14 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14 +#define FUNC_CALL_ARGS_INIT_14 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 ) +#define FUNC_SOLO_CALL_ARGS_INIT_14 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 ) +#define FUNC_CALL_MEMBER_ARGS_14 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14 +#define FUNC_CALL_ARGS_14 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 +#define FUNC_CALL_DATA_ARGS_14( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12, _var->m_arg13, _var->m_arg14 +#define FUNC_FUNCTOR_CALL_ARGS_14 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 +#define FUNC_TEMPLATE_FUNC_PARAMS_14 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13, typename FUNC_ARG_TYPE_14 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_14 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14 +#define FUNC_VALIDATION_STRING_14 Q_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name(), typeid( ARG_TYPE_13 ).name(), typeid( ARG_TYPE_14 ).name() ); +#define FUNC_SEPARATOR_14 , + +#define FUNC_GENERATE_ALL_BUT0( INNERMACRONAME ) \ + INNERMACRONAME(1); \ + INNERMACRONAME(2); \ + INNERMACRONAME(3); \ + INNERMACRONAME(4); \ + INNERMACRONAME(5); \ + INNERMACRONAME(6); \ + INNERMACRONAME(7); \ + INNERMACRONAME(8); \ + INNERMACRONAME(9); \ + INNERMACRONAME(10);\ + INNERMACRONAME(11);\ + INNERMACRONAME(12);\ + INNERMACRONAME(13);\ + INNERMACRONAME(14) + +#define FUNC_GENERATE_ALL( INNERMACRONAME ) \ + INNERMACRONAME(0); \ + FUNC_GENERATE_ALL_BUT0( INNERMACRONAME ) + + +abstract_class CFunctor : public IRefCounted +{ +public: + CFunctor() + { +#ifdef DEBUG + m_nUserID = 0; +#endif + } + virtual ~CFunctor() {} + virtual void operator()() = 0; + + unsigned m_nUserID; +}; + + +abstract_class CFunctorData : public IRefCounted +{ +public: + virtual void ComputeValidationString(char* pString, size_t nBufLen) const = 0; +}; + +abstract_class CFunctorCallback : public IRefCounted +{ +public: + virtual bool IsEqual(CFunctorCallback * pSrc) const = 0; + virtual void operator()(CFunctorData* pData) = 0; + virtual void ComputeValidationString(char* pString, size_t nBufLen) const = 0; + virtual const char* GetImplClassName() const = 0; + virtual const void* GetTarget() const = 0; +}; + + +template +inline T RefToVal(const T& item) +{ + return item; +} + + +template +class CLateBoundPtr +{ +public: + CLateBoundPtr(T** ppObject) + : m_ppObject(ppObject) + { + } + + T* operator->() { return *m_ppObject; } + T& operator *() { return **m_ppObject; } + operator T* () const { return (T*)(*m_ppObject); } + operator void* () { return *m_ppObject; } + +private: + T** m_ppObject; +}; + + +class CFuncMemPolicyNone +{ +public: + static void OnAcquire(void* pObject) {} + static void OnRelease(void* pObject) {} +}; + +template +class CFuncMemPolicyRefCount +{ +public: + static void OnAcquire(OBJECT_TYPE_PTR pObject) { pObject->AddRef(); } + static void OnRelease(OBJECT_TYPE_PTR pObject) { pObject->Release(); } +}; + + +template +class CMemberFuncProxyBase +{ +public: + bool operator==(const CMemberFuncProxyBase& src) const + { + return m_pfnProxied == src.m_pfnProxied && m_pObject == src.m_pObject; + } + + const void* GetTarget() const + { + return m_pObject; + } + +protected: + CMemberFuncProxyBase(OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied) + : m_pObject(pObject), + m_pfnProxied(pfnProxied) + { + MEM_POLICY::OnAcquire(m_pObject); + } + + ~CMemberFuncProxyBase() + { + MEM_POLICY::OnRelease(m_pObject); + } + + void Set(OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied) + { + m_pfnProxied = pfnProxied; + m_pObject = pObject; + } + + void OnCall() + { + Assert((void*)m_pObject != NULL); + } + + FUNCTION_TYPE m_pfnProxied; + OBJECT_TYPE_PTR m_pObject; +}; + + +#define DEFINE_MEMBER_FUNC_PROXY( N ) \ + template \ + class CMemberFuncProxy##N : public CMemberFuncProxyBase \ + { \ + public: \ + CMemberFuncProxy##N( OBJECT_TYPE_PTR pObject = NULL, FUNCTION_TYPE pfnProxied = NULL ) \ + : CMemberFuncProxyBase( pObject, pfnProxied ) \ + { \ + } \ + \ + void operator()( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \ + { \ + this->OnCall(); \ + ((*this->m_pObject).*this->m_pfnProxied)( FUNC_CALL_ARGS_##N ); \ + } \ + } + +FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNC_PROXY); + + +#include "memdbgon.h" + +typedef CRefCounted1 CFunctorBase; + +#define DEFINE_FUNCTOR_TEMPLATE(N) \ + template \ + class CFunctor##N : public CFunctorBase \ + { \ + public: \ + CFunctor##N( FUNC_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_pfnProxied( pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \ + void operator()() { m_pfnProxied(FUNC_CALL_MEMBER_ARGS_##N); } \ + \ + private: \ + FUNC_TYPE m_pfnProxied; \ + FUNC_ARG_MEMBERS_##N; \ + } + +FUNC_GENERATE_ALL(DEFINE_FUNCTOR_TEMPLATE); + +#define DEFINE_MEMBER_FUNCTOR( N ) \ + template \ + class CMemberFunctor##N : public FUNCTOR_BASE \ + { \ + public: \ + CMemberFunctor##N( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_Proxy( pObject, pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \ + void operator()() { m_Proxy(FUNC_CALL_MEMBER_ARGS_##N); } \ + \ + private: \ + CMemberFuncProxy##N m_Proxy; \ + FUNC_ARG_MEMBERS_##N; \ + }; + + +FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNCTOR); + +typedef CRefCounted1 CFunctorDataBase; +class CFunctorCallbackBase : public CRefCounted1 +{ +protected: + virtual void ValidateFunctorData(CFunctorData* pData) + { +#ifdef _DEBUG + char pDataString[1024]; + char pCallbackString[1024]; + ComputeValidationString(pCallbackString, sizeof(pCallbackString)); + pData->ComputeValidationString(pDataString, sizeof(pDataString)); + bool bMatch = !Q_stricmp(pDataString, pCallbackString); + if (!bMatch) + { + Warning("Functor doesn't match data!\n\tExpected:\t%s\n\tEncountered:\t%s\n", + pCallbackString, pDataString); + Assert(0); + } +#endif + } +}; + +#define DEFINE_FUNCTOR_DATA_TEMPLATE(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + class CFunctorData##N : public CFunctorDataBase \ + { \ + public: \ + CFunctorData##N( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) FUNC_SOLO_CALL_ARGS_INIT_##N {} \ + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \ + FUNC_ARG_MEMBERS_##N; \ + } + +class CFunctorData0 : public CFunctorDataBase +{ +public: + CFunctorData0() {} + virtual void ComputeValidationString(char* pString, size_t nBufLen_) const { int nBufLen = (int)nBufLen_; FUNC_VALIDATION_STRING_0 } +}; + +FUNC_GENERATE_ALL_BUT0(DEFINE_FUNCTOR_DATA_TEMPLATE); + +#define DEFINE_FUNCTOR_CALLBACK_TEMPLATE(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + class CFunctorCallback##N : public CFunctorCallbackBase \ + { \ + typedef void (*Callback_t)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ); \ + public: \ + CFunctorCallback##N( Callback_t pfnProxied ) : m_pfnProxied( pfnProxied ) {} \ + void operator()( CFunctorData *pFunctorDataBase ) \ + { \ + ValidateFunctorData( pFunctorDataBase ); \ + CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N > *pFunctorData = static_cast< CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >* >( pFunctorDataBase ); \ + m_pfnProxied( FUNC_CALL_DATA_ARGS_##N(pFunctorData) ); \ + } \ + virtual bool IsEqual( CFunctorCallback *pSrc ) const { return !Q_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) && ( m_pfnProxied == static_cast< CFunctorCallback##N * >( pSrc )->m_pfnProxied ); } \ + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \ + virtual const char *GetImplClassName() const { return "CFunctorCallback" #N; } \ + virtual const void *GetTarget() const { return m_pfnProxied; } \ + private: \ + Callback_t m_pfnProxied; \ + } + +class CFunctorCallback0 : public CFunctorCallbackBase +{ + typedef void (*Callback_t)(); +public: + CFunctorCallback0(Callback_t pfnProxied) : m_pfnProxied(pfnProxied) {} + void operator()(CFunctorData* pFunctorDataBase) + { + ValidateFunctorData(pFunctorDataBase); + m_pfnProxied(); + } + virtual void ComputeValidationString(char* pString, size_t nBufLen_) const { int nBufLen = (int)nBufLen_; FUNC_VALIDATION_STRING_0 } + virtual bool IsEqual(CFunctorCallback* pSrc) const + { + if (Q_stricmp(GetImplClassName(), pSrc->GetImplClassName())) + return false; + return m_pfnProxied == static_cast(pSrc)->m_pfnProxied; + } + virtual const char* GetImplClassName() const { return "CFunctorCallback0"; } + virtual const void* GetTarget() const { return (void*)m_pfnProxied; } +private: + Callback_t m_pfnProxied; +}; + +FUNC_GENERATE_ALL_BUT0(DEFINE_FUNCTOR_CALLBACK_TEMPLATE); + +#define DEFINE_MEMBER_FUNCTOR_CALLBACK_TEMPLATE( N ) \ + template < class FUNCTION_CLASS FUNC_TEMPLATE_ARG_PARAMS_##N, class MEM_POLICY = CFuncMemPolicyNone > \ + class CMemberFunctorCallback##N : public CFunctorCallbackBase \ + { \ + typedef void (FUNCTION_CLASS::*MemberCallback_t)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ); \ + public: \ + CMemberFunctorCallback##N( FUNCTION_CLASS *pObject, MemberCallback_t pfnProxied ) : m_Proxy( pObject, pfnProxied ) {} \ + void operator()( CFunctorData *pFunctorDataBase ) \ + { \ + ValidateFunctorData( pFunctorDataBase ); \ + CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N > *pFunctorData = static_cast< CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >* >( pFunctorDataBase ); \ + m_Proxy( FUNC_CALL_DATA_ARGS_##N( pFunctorData ) ); \ + } \ + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \ + virtual bool IsEqual( CFunctorCallback *pSrc ) const { return !Q_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) && ( m_Proxy == static_cast< CMemberFunctorCallback##N* >( pSrc )->m_Proxy ); } \ + virtual const char *GetImplClassName() const { return "CMemberFunctorCallback" #N; } \ + virtual const void *GetTarget() const { return m_Proxy.GetTarget(); } \ + private: \ + CMemberFuncProxy##N< FUNCTION_CLASS *, MemberCallback_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, MEM_POLICY> m_Proxy; \ + } + +template < class FUNCTION_CLASS, class MEM_POLICY = CFuncMemPolicyNone > +class CMemberFunctorCallback0 : public CFunctorCallbackBase +{ + typedef void (FUNCTION_CLASS::* MemberCallback_t)(); +public: + CMemberFunctorCallback0(FUNCTION_CLASS* pObject, MemberCallback_t pfnProxied) : m_Proxy(pObject, pfnProxied) {} + void operator()(CFunctorData* pFunctorDataBase) + { + ValidateFunctorData(pFunctorDataBase); + m_Proxy(); + } + virtual void ComputeValidationString(char* pString, size_t nBufLen) const { FUNC_VALIDATION_STRING_0 } + virtual bool IsEqual(CFunctorCallback* pSrc) const + { + if (Q_stricmp(GetImplClassName(), pSrc->GetImplClassName())) + return false; + return m_Proxy == static_cast(pSrc)->m_Proxy; + } + virtual const char* GetImplClassName() const { return "CMemberFunctorCallback0"; } + virtual const void* GetTarget() const { return m_Proxy.GetTarget(); } +private: + CMemberFuncProxy0< FUNCTION_CLASS*, MemberCallback_t, MEM_POLICY > m_Proxy; +}; + +FUNC_GENERATE_ALL_BUT0(DEFINE_MEMBER_FUNCTOR_CALLBACK_TEMPLATE); + + +#define DEFINE_NONMEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateFunctor(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \ + return new CFunctor##N( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } + +FUNC_GENERATE_ALL(DEFINE_NONMEMBER_FUNCTOR_FACTORY); + +#define DEFINE_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNCTOR_FACTORY); + +#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL(DEFINE_CONST_MEMBER_FUNCTOR_FACTORY); + +#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY); + +#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY); + +#define DEFINE_FUNCTOR_DATA_FACTORY(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + inline CFunctorData *CreateFunctorData( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >( FUNC_CALL_ARGS_##N ); \ + } + +inline CFunctorData* CreateFunctorData() +{ + return new CFunctorData0(); +} + +FUNC_GENERATE_ALL_BUT0(DEFINE_FUNCTOR_DATA_FACTORY); + +#define DEFINE_FUNCTOR_CALLBACK_FACTORY(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + inline CFunctorCallback *CreateFunctorCallback( void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ + { \ + return new CFunctorCallback##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >( pfnProxied ); \ + } + +inline CFunctorCallback* CreateFunctorCallback(void (*pfnProxied)()) +{ + return new CFunctorCallback0(pfnProxied); +} + +FUNC_GENERATE_ALL_BUT0(DEFINE_FUNCTOR_CALLBACK_FACTORY); + +#define DEFINE_MEMBER_FUNCTOR_CALLBACK_FACTORY(N) \ + template < typename FUNCTION_CLASS FUNC_TEMPLATE_ARG_PARAMS_##N > \ + inline CFunctorCallback *CreateFunctorCallback( FUNCTION_CLASS *pObject, void ( FUNCTION_CLASS::*pfnProxied )( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ + { \ + return new CMemberFunctorCallback##N< FUNCTION_CLASS FUNC_BASE_TEMPLATE_ARG_PARAMS_##N >( pObject, pfnProxied ); \ + } + +FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNCTOR_CALLBACK_FACTORY); + + +#define DEFINE_NONMEMBER_FUNCTOR_DIRECT(N) \ + template \ + inline void FunctorDirectCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + (*pfnProxied)( FUNC_CALL_ARGS_##N ); \ +} + +FUNC_GENERATE_ALL(DEFINE_NONMEMBER_FUNCTOR_DIRECT); + + +#define DEFINE_MEMBER_FUNCTOR_DIRECT(N) \ + template \ + inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNCTOR_DIRECT); + +#define DEFINE_CONST_MEMBER_FUNCTOR_DIRECT(N) \ + template \ + inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL(DEFINE_CONST_MEMBER_FUNCTOR_DIRECT); + +#include "memdbgoff.h" + +class CDefaultFunctorFactory +{ +public: + FUNC_GENERATE_ALL(DEFINE_NONMEMBER_FUNCTOR_FACTORY); + FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNCTOR_FACTORY); + FUNC_GENERATE_ALL(DEFINE_CONST_MEMBER_FUNCTOR_FACTORY); + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY); + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY); +}; + +template +class CCustomizedFunctorFactory +{ +public: + void SetAllocator(CAllocator* pAllocator) + { + m_pAllocator = pAllocator; + } + +#define DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateFunctor( FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \ + return new (m_pAllocator->Alloc( sizeof(CFunctor##N) )) CFunctor##N( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } + + FUNC_GENERATE_ALL(DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM); + +#define DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N) )) CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL(DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM); + +#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N) )) CMemberFunctor##N(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL(DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM); + +#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N >) )) CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM); + +#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template \ + inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N >) )) CMemberFunctor##N >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM); + +private: + CAllocator* m_pAllocator; + +}; + +#endif +``` + +`SpyCustom/sdk/fx.h`: + +```h +#if !defined( FX_H ) +#define FX_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" +#include "c_pixel_visibility.h" +#include "mathlib.h" +typedef CBaseHandle ClientEntityHandle_t; +#include "smartptr.h" + +class Vector; +class CGameTrace; +typedef CGameTrace trace_t; +enum +{ + FX_ENERGYSPLASH_EXPLOSIVE = 0x1, + FX_ENERGYSPLASH_SMOKE = 0x2, + FX_ENERGYSPLASH_LITTLESPARKS = 0x4, + FX_ENERGYSPLASH_BIGSPARKS = 0x8, + FX_ENERGYSPLASH_BIGSPARKSCOLLIDE = 0x10, + FX_ENERGYSPLASH_ENERGYBALLS = 0x20, + FX_ENERGYSPLASH_DLIGHT = 0x40, + + FX_ENERGYSPLASH_DEFAULT = ~FX_ENERGYSPLASH_EXPLOSIVE, + FX_ENERGYSPLASH_DEFAULT_EXPLOSIVE = ~0, +}; + +bool FX_GetAttachmentTransform(ClientEntityHandle_t hEntity, int attachmentIndex, matrix3x4_t& transform); +bool FX_GetAttachmentTransform(ClientEntityHandle_t hEntity, int attachmentIndex, Vector* origin, QAngle* angles); + +void FX_RicochetSound(const Vector& pos); + +void FX_AntlionImpact(const Vector& pos, trace_t* tr); +void FX_DebrisFlecks(const Vector& origin, trace_t* trace, char materialType, int iScale, bool bNoFlecks = false); +void FX_Tracer(Vector& start, Vector& end, int velocity, bool makeWhiz = true); +void FX_GunshipTracer(Vector& start, Vector& end, int velocity, bool makeWhiz = true); +void FX_StriderTracer(Vector& start, Vector& end, int velocity, bool makeWhiz = true); +void FX_HunterTracer(Vector& start, Vector& end, int velocity, bool makeWhiz = true); +void FX_PlayerTracer(Vector& start, Vector& end); +void FX_BulletPass(Vector& start, Vector& end); +void FX_MetalSpark(const Vector& position, const Vector& direction, const Vector& surfaceNormal, int iScale = 1); +void FX_MetalScrape(Vector& position, Vector& normal); +void FX_Sparks(const Vector& pos, int nMagnitude, int nTrailLength, const Vector& vecDir, float flWidth, float flMinSpeed, float flMaxSpeed, char* pSparkMaterial = NULL); +void FX_ElectricSpark(const Vector& pos, int nMagnitude, int nTrailLength, const Vector* vecDir); +void FX_BugBlood(Vector& pos, Vector& dir, Vector& vWorldMins, Vector& vWorldMaxs); +void FX_Blood(Vector& pos, Vector& dir, float r, float g, float b, float a); +void FX_CreateImpactDust(Vector& origin, Vector& normal); +void FX_EnergySplash(const Vector& pos, const Vector& normal, int nFlags = FX_ENERGYSPLASH_DEFAULT); +void FX_MicroExplosion(Vector& position, Vector& normal); +void FX_Explosion(Vector& origin, Vector& normal, char materialType); +void FX_ConcussiveExplosion(Vector& origin, Vector& normal); +void FX_DustImpact(const Vector& origin, trace_t* tr, int iScale); +void FX_DustImpact(const Vector& origin, trace_t* tr, float flScale); +void FX_MuzzleEffect(const Vector& origin, const QAngle& angles, float scale, ClientEntityHandle_t hEntity, unsigned char* pFlashColor = NULL, bool bOneFrame = false); +void FX_MuzzleEffectAttached(float scale, ClientEntityHandle_t hEntity, int attachmentIndex, unsigned char* pFlashColor = NULL, bool bOneFrame = false); +void FX_StriderMuzzleEffect(const Vector& origin, const QAngle& angles, float scale, ClientEntityHandle_t hEntity, unsigned char* pFlashColor = NULL); +void FX_GunshipMuzzleEffect(const Vector& origin, const QAngle& angles, float scale, ClientEntityHandle_t hEntity, unsigned char* pFlashColor = NULL); +void FX_Smoke(const Vector& origin, const Vector& velocity, float scale, int numParticles, float flDietime, unsigned char* pColor, int iAlpha, const char* pMaterial, float flRoll, float flRollDelta); + +void FX_Smoke(const Vector& origin, const QAngle& angles, float scale, int numParticles, unsigned char* pColor = NULL, int iAlpha = -1); +void FX_Dust(const Vector& vecOrigin, const Vector& vecDirection, float flSize, float flSpeed); +void FX_CreateGaussExplosion(const Vector& pos, const Vector& dir, int type); +void FX_GaussTracer(Vector& start, Vector& end, int velocity, bool makeWhiz = true); +void FX_TracerSound(const Vector& start, const Vector& end, int iTracerType); + +void UTIL_GetNormalizedColorTintAndLuminosity(const Vector& color, Vector* tint = NULL, float* luminosity = NULL); + +bool EffectOccluded(const Vector& pos, pixelvis_handle_t* queryHandle = 0); + +class CTeslaInfo +{ +public: + Vector m_vPos; + QAngle m_vAngles; + int m_nEntIndex; + char* m_pszSpriteName; + float m_flBeamWidth; + int m_nBeams; + Vector m_vColor; + float m_flTimeVisible; + float m_flRadius; +}; + +void FX_Tesla(const CTeslaInfo& teslaInfo); + +#include "particle_parse.h" + +class CEffectData +{ +public: + Vector m_vOrigin; + Vector m_vStart; + Vector m_vNormal; + QAngle 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; + +public: + CEffectData() + { + m_vOrigin.Init(); + m_vStart.Init(); + m_vNormal.Init(); + m_vAngles.Init(); + + m_fFlags = 0; + m_nEntIndex = 0; + m_flScale = 1.f; + m_nAttachmentIndex = 0; + m_nSurfaceProp = 0; + + m_flMagnitude = 0.0f; + m_flRadius = 0.0f; + + m_nMaterial = 0; + m_nDamageType = 0; + m_nHitBox = 0; + + m_nColor = 0; + + m_bCustomColors = false; + m_CustomColors.m_vecColor1.Init(1.f, 1.f, 1.f); + m_CustomColors.m_vecColor2.Init(1.f, 1.f, 1.f); + + m_bControlPoint1 = false; + m_ControlPoint1.m_eParticleAttachment = PATTACH_ABSORIGIN; + m_ControlPoint1.m_vecOffset.Init(); + } + + int GetEffectNameIndex() { return m_iEffectName; } + +private: + int m_iEffectName; +}; + + +#endif +``` + +`SpyCustom/sdk/game_item_schema.h`: + +```h +#ifndef GAME_ITEM_SCHEMA_H +#define GAME_ITEM_SCHEMA_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL) +class CTFItemSchema; +class CTFItemDefinition; +class CTFItemSystem; + +typedef CTFItemSchema GameItemSchema_t; +typedef CTFItemDefinition GameItemDefinition_t; +typedef CTFItemSystem GameItemSystem_t; + +#include "tf_item_schema.h" +#elif defined( DOTA_CLIENT_DLL ) || defined( DOTA_DLL ) || defined ( DOTA_GC_DLL ) +class CDOTAItemSchema; +class CDOTAItemDefinition; +class CDOTAItemSystem; + +typedef CDOTAItemSchema GameItemSchema_t; +typedef CDOTAItemDefinition GameItemDefinition_t; +typedef CDOTAItemSystem GameItemSystem_t; + +#include "econ/dota_item_schema.h" +#elif defined( PORTAL2 ) || defined( PORTAL2_GC_DLL ) +class CPortal2ItemSchema; +class CPortal2ItemDefinition; +class CPortal2ItemSystem; + +typedef CPortal2ItemSchema GameItemSchema_t; +typedef CPortal2ItemDefinition GameItemDefinition_t; +typedef CPortal2ItemSystem GameItemSystem_t; + +#include "portal2_item_schema.h" +#elif defined( CSTRIKE15 ) || defined( CSTRIKE_GC_DLL ) +class CCStrike15ItemSchema; +class CCStrike15ItemDefinition; +class CCStrike15ItemSystem; + +typedef CCStrike15ItemSchema GameItemSchema_t; +typedef CCStrike15ItemDefinition GameItemDefinition_t; +typedef CCStrike15ItemSystem GameItemSystem_t; + +#include "cstrike15_item_schema.h" +#else +class CEconItemSchema; +class CEconItemDefinition; +class CEconItemSystem; + +typedef CEconItemSchema GameItemSchema_t; +typedef CEconItemDefinition GameItemDefinition_t; +typedef CEconItemSystem GameItemSystem_t; + +#include "econ_item_schema.h" +#endif + +extern GameItemSchema_t* GetItemSchema(); + +#endif +``` + +`SpyCustom/sdk/gameconsole.h`: + +```h +#ifndef GAMECONSOLE_H +#define GAMECONSOLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "IGameConsole.h" + +class CGameConsoleDialog; + +class CGameConsole : public IGameConsole +{ +public: + CGameConsole(); + ~CGameConsole(); + + void Initialize(); + + virtual void Activate(); + virtual void Hide(); + virtual void Clear(); + + void HideImmediately(void); + + virtual bool IsConsoleVisible(); + + void ActivateDelayed(float time); + + void SetParent(int parent); + + void Shutdown(void); + + static void OnCmdCondump(); +private: + + bool m_bInitialized; + CGameConsoleDialog* m_pConsole; +}; + +extern CGameConsole& GameConsole(); + +#endif +``` + +`SpyCustom/sdk/gamemovement.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( GAMEMOVEMENT_H ) +#define GAMEMOVEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "igamemovement.h" +#include "cmodel.h" +#include "vprof.h" + +#define CTEXTURESMAX 512 // max number of textures loaded +#define CBTEXTURENAMEMAX 13 // only load first n chars of name + +#define GAMEMOVEMENT_DUCK_TIME 1000 // ms +#define GAMEMOVEMENT_JUMP_TIME 510 // ms approx - based on the 21 unit height jump +#define GAMEMOVEMENT_JUMP_HEIGHT 21.0f // units +#define GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS ( TIME_TO_UNDUCK_MSECS ) // ms +#define GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS_INV ( GAMEMOVEMENT_DUCK_TIME - GAMEMOVEMENT_TIME_TO_UNDUCK_MSECS ) + +enum +{ + SPEED_CROPPED_RESET = 0, + SPEED_CROPPED_DUCK = 1, + SPEED_CROPPED_WEAPON = 2, +}; + +struct surfacedata_t; + +class CBasePlayer; + +class CGameMovement : public IGameMovement +{ +public: + DECLARE_CLASS_NOBASE( CGameMovement ); + + CGameMovement( void ); + virtual ~CGameMovement( void ); + + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ); + virtual void Reset( void ); + virtual void StartTrackPredictionErrors( CBasePlayer *pPlayer ); + virtual void FinishTrackPredictionErrors( CBasePlayer *pPlayer ); + virtual void DiffPrint( PRINTF_FORMAT_STRING char const *fmt, ... ); + virtual const Vector& GetPlayerMins( bool ducked ) const; + virtual const Vector& GetPlayerMaxs( bool ducked ) const; + virtual const Vector& GetPlayerViewOffset( bool ducked ) const; + virtual void SetupMovementBounds( CMoveData *pMove ); + + virtual bool IsMovingPlayerStuck( void ) const; + virtual CBasePlayer *GetMovingPlayer( void ) const; + virtual void UnblockPusher( CBasePlayer *pPlayer, CBaseEntity *pPusher ); + +// For sanity checking getting stuck on CMoveData::SetAbsOrigin + virtual void TracePlayerBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm ); + + // wrapper around tracehull to allow tracelistdata optimizations + void GameMovementTraceHull( const Vector& start, const Vector& end, const Vector &mins, const Vector &maxs, unsigned int fMask, ITraceFilter *pFilter, trace_t *pTrace ); + +#define BRUSH_ONLY true + virtual unsigned int PlayerSolidMask( bool brushOnly = false, CBasePlayer *testPlayer = NULL ) const; ///< returns the solid mask for the given player, so bots can have a more-restrictive set + CBasePlayer *player; + CMoveData *GetMoveData() { return mv; } +protected: + // Input/Output for this movement + CMoveData *mv; + + int m_nOldWaterLevel; + float m_flWaterEntryTime; + int m_nOnLadder; + + Vector m_vecForward; + Vector m_vecRight; + Vector m_vecUp; + + + // Does most of the player movement logic. + // Returns with origin, angles, and velocity modified in place. + // were contacted during the move. + virtual void PlayerMove( void ); + + // Set ground data, etc. + void FinishMove( void ); + + virtual float CalcRoll( const QAngle &angles, const Vector &velocity, float rollangle, float rollspeed ); + + // helper function for decaying punch angles over time with exponential and linear terms + void DecayAngles( QAngle& v, float fExp, float fLin, float dT ); + + virtual void DecayViewPunchAngle( void ); + + virtual void CheckWaterJump(void ); + + virtual void WaterMove( void ); + + virtual void WaterJump( void ); + + // Handles both ground friction and water friction + virtual void Friction( void ); + + virtual void AirAccelerate( Vector& wishdir, float wishspeed, float accel ); + + virtual void AirMove( void ); + + virtual bool CanAccelerate(); + virtual void Accelerate( Vector& wishdir, float wishspeed, float accel); + + // Only used by players. Moves along the ground when player is a MOVETYPE_WALK. + virtual void WalkMove( void ); + + // Try to keep a walking player on the ground when running down slopes etc + virtual void StayOnGround( void ); + + // Handle MOVETYPE_WALK. + virtual void FullWalkMove(); + + // allow overridden versions to respond to jumping + virtual void OnJump( float fImpulse ) {} + virtual void OnLand( float fVelocity ) {} + + // Implement this if you want to know when the player collides during OnPlayerMove + virtual void OnTryPlayerMoveCollision( trace_t &tr ) {} + + virtual const Vector& GetPlayerMins( void ) const; // uses local player + virtual const Vector& GetPlayerMaxs( void ) const; // uses local player + + typedef enum + { + GROUND = 0, + STUCK, + LADDER, + LADDER_WEDGE + } IntervalType_t; + + virtual int GetCheckInterval( IntervalType_t type ); + + // Useful for things that happen periodically. This lets things happen on the specified interval, but + // spaces the events onto different frames for different players so they don't all hit their spikes + // simultaneously. + bool CheckInterval( IntervalType_t type ); + + + // Decompoosed gravity + virtual void StartGravity( void ); + virtual void FinishGravity( void ); + + // Apply normal ( undecomposed ) gravity + virtual void AddGravity( void ); + + // Handle movement in noclip mode. + void FullNoClipMove( float factor, float maxacceleration ); + + // Returns true if he started a jump (ie: should he play the jump animation)? + virtual bool CheckJumpButton( void ); // Overridden by each game. + + // Dead player flying through air., e.g. + virtual void FullTossMove( void ); + + // Player is a Observer chasing another player + void FullObserverMove( void ); + + // Handle movement when in MOVETYPE_LADDER mode. + virtual void FullLadderMove(); + + // The basic solid body movement clip that slides along multiple planes + virtual int TryPlayerMove( Vector *pFirstDest=NULL, trace_t *pFirstTrace=NULL ); + + virtual bool LadderMove( void ); + virtual bool OnLadder( trace_t &trace ); + virtual float LadderDistance( void ) const { return 2.0f; } ///< Returns the distance a player can be from a ladder and still attach to it + virtual unsigned int LadderMask( void ) const { return MASK_PLAYERSOLID; } + virtual float ClimbSpeed( void ) const { return MAX_CLIMB_SPEED; } + virtual float LadderLateralMultiplier( void ) const { return 1.0f; } + + // special case code when starting the Ladder MoveType + void OnStartMoveTypeLadder( void ); + + // See if the player has a bogus velocity value. + void CheckVelocity( void ); + + // Does not change the entities velocity at all + void PushEntity( Vector& push, trace_t *pTrace ); + + // Slide off of the impacting object + // returns the blocked flags: + // 0x01 == floor + // 0x02 == step / wall + virtual int ClipVelocity( Vector& in, Vector& normal, Vector& out, float overbounce ); + + // If pmove.origin is in a solid position, + // try nudging slightly on all axis to + // allow for the cut precision of the net coordinates +#ifdef PORTAL + virtual +#endif + int CheckStuck( void ); + + // Check if the point is in water. + // Sets refWaterLevel and refWaterType appropriately. + // If in water, applies current to baseVelocity, and returns true. + virtual bool CheckWater( void ); + virtual void GetWaterCheckPosition( int waterLevel, Vector *pos ); + + // Determine if player is in water, on ground, etc. + virtual void CategorizePosition( void ); + + virtual void CheckParameters( void ); + + virtual void ReduceTimers( void ); + + virtual void CheckFalling( void ); + + virtual void PlayerRoughLandingEffects( float fvol ); + + void PlayerWaterSounds( void ); + + void ResetGetWaterContentsForPointCache(); + int GetWaterContentsForPointCached( const Vector &point, int slot ); + + // Ducking + virtual void Duck( void ); + virtual void HandleDuckingSpeedCrop(); + virtual void FinishUnDuck( void ); + virtual void FinishDuck( void ); + virtual bool CanUnduck(); + virtual void UpdateDuckJumpEyeOffset( void ); + virtual bool CanUnDuckJump( trace_t &trace ); + virtual void StartUnDuckJump( void ); + virtual void FinishUnDuckJump( trace_t &trace ); + virtual void SetDuckedEyeOffset( float duckFraction ); + virtual void FixPlayerCrouchStuck( bool moveup ); + + float SplineFraction( float value, float scale ); + + virtual void CategorizeGroundSurface( trace_t &pm ); + + virtual bool InWater( void ); + + // Commander view movement + void IsometricMove( void ); + + // Traces the player bbox as it is swept from start to end + virtual CBaseHandle TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm ); + + // Checks to see if we should actually jump + void PlaySwimSound(); + + bool IsDead( void ) const; + + // Figures out how the constraint should slow us down + float ComputeConstraintSpeedFactor( void ); + + virtual void SetGroundEntity( trace_t *pm ); + + virtual void StepMove( Vector &vecDestination, trace_t &trace ); + + bool CheckValidStandableGroundCandidate( trace_t &pm, float flStandableZ ); + +protected: + virtual ITraceFilter *LockTraceFilter( int collisionGroup ); + virtual void UnlockTraceFilter( ITraceFilter *&pFilter ); + + // Performs the collision resolution for fliers. + void PerformFlyCollisionResolution( trace_t &pm, Vector &move ); + + virtual bool GameHasLadders() const; + + enum + { + // eyes, waist, feet points (since they are all deterministic + MAX_PC_CACHE_SLOTS = 3, + }; + + // Cache used to remove redundant calls to GetPointContents() for water. + int m_CachedGetPointContents[ MAX_PLAYERS ][ MAX_PC_CACHE_SLOTS ]; + Vector m_CachedGetPointContentsPoint[ MAX_PLAYERS ][ MAX_PC_CACHE_SLOTS ]; + +//private: + int m_iSpeedCropped; + + bool m_bProcessingMovement; + bool m_bInStuckTest; + + float m_flStuckCheckTime[MAX_PLAYERS+1][2]; // Last time we did a full test + + // special function for teleport-with-duck for episodic +#ifdef HL2_EPISODIC +public: + void ForceDuck( void ); + +#endif + void *m_pTraceListData; + + int m_nTraceCount; +}; + + + + +#endif // GAMEMOVEMENT_H +``` + +`SpyCustom/sdk/gamerules.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef GAMERULES_H +#define GAMERULES_H +#ifdef _WIN32 +#pragma once +#endif + +// Debug history should be disabled in release builds +//#define DISABLE_DEBUG_HISTORY + +#ifdef CLIENT_DLL + // CEG interface functions: + #define ALLOW_TEXTCHAT_FLAG 0xAD1A + DWORD InitHudAllowTextChatFlag( void ); + + #define ALLOW_PROPER_TINT_FLAG 0x8E3C + DWORD InitUiAllowProperTintFlag( void ); + +#endif + +#ifdef CLIENT_DLL + + //#include "c_baseentity.h" + + #define CGameRules C_GameRules + #define CGameRulesProxy C_GameRulesProxy + +#else + + #include "baseentity.h" + #include "recipientfilter.h" + +#endif + +#include "igamesystem.h" +#include "gamerules_register.h" + +#include "networkvar.h" + + +//#include "items.h" +class CBaseCombatWeapon; +class CBaseCombatCharacter; +class CBasePlayer; +class CItem; +class CAmmoDef; + +extern ConVar sk_autoaim_mode; + +// Autoaiming modes +enum +{ + AUTOAIM_NONE = 0, // No autoaim at all. + AUTOAIM_ON, // Autoaim is on. + AUTOAIM_ON_CONSOLE, // Autoaim is on, including enhanced features for Console gaming (more assistance, etc) +}; + +// weapon respawning return codes +enum +{ + GR_NONE = 0, + + GR_WEAPON_RESPAWN_YES, + GR_WEAPON_RESPAWN_NO, + + GR_AMMO_RESPAWN_YES, + GR_AMMO_RESPAWN_NO, + + GR_ITEM_RESPAWN_YES, + GR_ITEM_RESPAWN_NO, + + GR_PLR_DROP_GUN_ALL, + GR_PLR_DROP_GUN_ACTIVE, + GR_PLR_DROP_GUN_NO, + + GR_PLR_DROP_AMMO_ALL, + GR_PLR_DROP_AMMO_ACTIVE, + GR_PLR_DROP_AMMO_NO, +}; + +// Player relationship return codes +enum +{ + GR_NOTTEAMMATE = 0, + GR_TEAMMATE, + GR_ENEMY, + GR_ALLY, + GR_NEUTRAL, +}; + + +// This class has the data tables and gets the CGameRules data to the client. +class C_BaseEntity; +class CGameRulesProxy; + + +abstract_class CGameRules : public CMemZeroOnNew, public CAutoGameSystemPerFrame +{ +public: + DECLARE_CLASS_GAMEROOT( CGameRules, CAutoGameSystemPerFrame ); + + virtual char const *Name() { return "CGameRules"; } + + // Stuff shared between client and server. + + CGameRules(void); + + virtual ~CGameRules( void ); + + virtual bool Init(); + + // Damage Queries - these need to be implemented by the various subclasses (single-player, multi-player, etc). + // The queries represent queries against damage types and properties. + virtual bool Damage_IsTimeBased( int iDmgType ) = 0; // Damage types that are time-based. + virtual bool Damage_ShouldGibCorpse( int iDmgType ) = 0; // Damage types that gib the corpse. + virtual bool Damage_ShowOnHUD( int iDmgType ) = 0; // Damage types that have client HUD art. + virtual bool Damage_NoPhysicsForce( int iDmgType ) = 0; // Damage types that don't have to supply a physics force & position. + virtual bool Damage_ShouldNotBleed( int iDmgType ) = 0; // Damage types that don't make the player bleed. + //Temp: These will go away once DamageTypes become enums. + virtual int Damage_GetTimeBased( void ) = 0; // Actual bit-fields. + virtual int Damage_GetShouldGibCorpse( void ) = 0; + virtual int Damage_GetShowOnHud( void ) = 0; + virtual int Damage_GetNoPhysicsForce( void )= 0; + virtual int Damage_GetShouldNotBleed( void ) = 0; + +// Ammo Definitions + //CAmmoDef* GetAmmoDef(); + + virtual bool SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); // Switch to the next best weapon + virtual CBaseCombatWeapon *GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ); // I can't use this weapon anymore, get me the next best one. + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + + virtual int DefaultFOV( void ) { return 90; } + + // This function is here for our CNetworkVars. + inline void NetworkStateChanged() + { + // Forward the call to the entity that will send the data. + //CGameRulesProxy::NotifyNetworkStateChanged(); + } + + inline void NetworkStateChanged( void *pVar ) + { + // Forward the call to the entity that will send the data. + //CGameRulesProxy::NotifyNetworkStateChanged(); + } + + // Get the view vectors for this mod. + virtual const CViewVectors* GetViewVectors() const; + +// Damage rules for ammo types + virtual float GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ); + virtual float GetDamageMultiplier( void ) { return 1.0f; } + +// Functions to verify the single/multiplayer status of a game + virtual bool IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) + + virtual const unsigned char *GetEncryptionKey() { return NULL; } + + virtual bool InRoundRestart( void ) { return false; } + + virtual bool CheckAchievementsEnabled( int iAchievementID ) { return true; } + + virtual void RegisterScriptFunctions( void ){ }; + + virtual void ClientCommandKeyValues( void *pEntity, KeyValues *pKeyValues ) {} + + // IsConnectedUserInfoChangeAllowed allows to override FCVAR_NOT_CONNECTED rule when + // player is on team spectator or team unassigned for example + // Default and previous engine implementation will never allow FCVAR_NOT_CONNECTED cvars + // to be changed while connected to a game server + virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer ) { return false; } + +#ifdef CLIENT_DLL + + virtual bool IsBonusChallengeTimeBased( void ); + virtual bool AllowThirdPersonCamera() { return true; } + +#else + + virtual void GetTaggedConVarList( KeyValues *pCvarTagList ) {} + + +// CBaseEntity overrides. +public: + +// Setup + virtual void OnBeginChangeLevel( const char *nextMapName, KeyValues *saveData ) {} ///< called just before a trigger_changelevel starts a changelevel + + // Called when game rules are destroyed by CWorld + virtual void LevelShutdown( void ) { return; }; + + virtual void Precache( void ); + + virtual void RefreshSkillData( bool forceUpdate );// fill skill data struct with proper values + + // Called each frame. This just forwards the call to Think(). + virtual void FrameUpdatePostEntityThink(); + + virtual void Think( void ); // GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. + virtual bool IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg NPCs don't spawn in deathmatch). + + // Called at the end of GameFrame (i.e. after all game logic has run this frame) + virtual void EndGameFrame( void ); + + virtual bool IsSkillLevel( int iLevel ) { return GetSkillLevel() == iLevel; } + virtual int GetSkillLevel() { return g_iSkillLevel; } + virtual void OnSkillLevelChanged( int iNewLevel ) {}; + virtual void SetSkillLevel( int iLevel ) + { + int oldLevel = g_iSkillLevel; + + if ( iLevel < 1 ) + { + iLevel = 1; + } + else if ( iLevel > 3 ) + { + iLevel = 3; + } + + g_iSkillLevel = iLevel; + + if( g_iSkillLevel != oldLevel ) + { + OnSkillLevelChanged( g_iSkillLevel ); + } + } + + virtual bool FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? + virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ) = 0;// should the player switch to this weapon? + +// Functions to verify the single/multiplayer status of a game + virtual bool IsDeathmatch( void ) = 0;//is this a deathmatch game? + virtual bool IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? + virtual bool IsCoOp( void ) = 0;// is this a coop game? + virtual const char *GetGameDescription( void ) { return "Half-Life 2"; } // this is the game name that gets seen in the server browser + +// Client connection/disconnection + virtual bool ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) = 0;// a client just connected to the server (player hasn't spawned yet) + virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server + virtual bool ShouldTimeoutClient( int nUserID, float flTimeSinceLastReceived ) { return false; } // return true to disconnect client due to timeout (used to do stricter timeouts when the game is sure the client isn't loading a map) + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? + virtual bool FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker? + virtual bool ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } + virtual float GetAutoAimScale( CBasePlayer *pPlayer ) { return 1.0f; } + virtual int GetAutoAimMode() { return AUTOAIM_ON; } + + virtual bool ShouldUseRobustRadiusDamage(CBaseEntity *pEntity) { return false; } + virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ); + // Let the game rules specify if fall death should fade screen to black + virtual bool FlPlayerFallDeathDoesScreenFade( CBasePlayer *pl ) { return TRUE; } + + virtual bool AllowDamage( CBaseEntity *pVictim, const CTakeDamageInfo &info ) = 0; + + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game + virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted + virtual bool FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? + virtual CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. + virtual bool IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer ); + + virtual bool AllowAutoTargetCrosshair( void ) { return TRUE; }; + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); // handles the user commands; returns TRUE if command handled properly + virtual void ClientSettingsChanged( CBasePlayer *pPlayer ); // the player has changed cvars + + virtual bool CanClientCustomizeOwnIdentity() { return true; } + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? + virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ) = 0;// Called each time a player dies + virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )= 0;// Call this from within a GameRules class to report an obituary. + virtual const char *GetDamageCustomString( const CTakeDamageInfo &info ) { return NULL; } + + + virtual bool IgnorePlayerKillCommand( void ) const { return false; } + +// Weapon Damage + // Determines how much damage Player's attacks inflict, based on skill level. + virtual float AdjustPlayerDamageInflicted( float damage ) { return damage; } + virtual void AdjustPlayerDamageTaken( CTakeDamageInfo *pInfo ) {}; // Base class does nothing. + +// Weapon retrieval + virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );// The player is touching an CBaseCombatWeapon, do I give it to him? + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon ) = 0;// should this weapon respawn? + virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ) = 0;// when may this weapon respawn? + virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? + virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon ) = 0;// where in the world should this weapon respawn? + +// Item retrieval + virtual bool CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item? + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit) + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn? + virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn? + virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn? + virtual QAngle VecItemRespawnAngles( CItem *pItem ) = 0;// what angles should this item use when respawing? + +// Ammo retrieval + virtual bool CanHaveAmmo( CBaseCombatCharacter *pPlayer, int iAmmoIndex ); // can this player take more of this ammo? + virtual bool CanHaveAmmo( CBaseCombatCharacter *pPlayer, const char *szName ); + virtual void PlayerGotAmmo( CBaseCombatCharacter *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world + virtual float GetAmmoQuantityScale( int iAmmoIndex ) { return 1.0f; } + +// AI Definitions + virtual void InitDefaultAIRelationships( void ) { return; } + virtual const char* AIClassText(int classType) { return NULL; } + virtual int NumEntityClasses() const { return LAST_SHARED_ENTITY_CLASS; } + virtual int NumFactions() const { return LAST_SHARED_FACTION; } + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? + virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? + +// Teamplay stuff + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? + virtual bool PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker, bool bTeamOnly ) = 0; + virtual void CheckChatText( CBasePlayer *pPlayer, char *pText ) { return; } + + virtual int GetTeamIndex( const char *pTeamName ) { return -1; } + virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } + virtual bool IsValidTeam( const char *pTeamName ) { return true; } + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, bool bKill, bool bGib ) {} + virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } + virtual void UpdateClientData( CBasePlayer *pPlayer ) { }; + virtual bool IsTeamChangeSilent( CBasePlayer *pPlayer, int iTeamNum, bool bAutoTeam, bool bSilent ) { return bSilent; } + +// Sounds + virtual bool PlayTextureSounds( void ) { return TRUE; } + virtual bool PlayFootstepSounds( CBasePlayer *pl ) { return TRUE; } + virtual bool AllowSoundscapes( void ) { return TRUE; } + +// NPCs + virtual bool FAllowNPCs( void ) = 0;//are NPCs allowed + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) {} + + // trace line rules + virtual float WeaponTraceEntity( CBaseEntity *pEntity, const Vector &vecStart, const Vector &vecEnd, unsigned int mask, trace_t *ptr ); + + // Setup g_pPlayerResource (some mods use a different entity type here). + virtual void CreateStandardEntities(); + + // Team name, etc shown in chat and dedicated server console + virtual const char *GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ); + + // Location name shown in chat + virtual const char *GetChatLocation( bool bTeamOnly, CBasePlayer *pPlayer ) { return NULL; } + + // VGUI format string for chat, if desired + virtual const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer ) { return NULL; } + + // Whether props that are on fire should get a DLIGHT. + virtual bool ShouldBurningPropsEmitLight() { return false; } + + virtual bool CanEntityBeUsePushed( CBaseEntity *pEnt ) { return true; } + + virtual void CreateCustomNetworkStringTables( void ) { } + + // Game Achievements (server version) + virtual void MarkAchievement ( IRecipientFilter& filter, char const *pchAchievementName ); + + virtual void ResetMapCycleTimeStamp( void ){ return; } + + virtual void OnNavMeshLoad( void ) { return; } + + virtual void UpdateGameplayStatsFromSteam( void ) { return; } + + virtual edict_t *DoFindClientInPVS( edict_t *pEdict, unsigned char *pvs, unsigned pvssize ); +#endif + + virtual const char *GetGameTypeName( void ){ return NULL; } + virtual int GetGameType( void ){ return 0; } + + virtual bool ForceSplitScreenPlayersOnToSameTeam() { return true; } + + virtual bool IsTopDown() { return false; } + virtual const QAngle& GetTopDownMovementAxis() { return vec3_angle; } + + // Assume the game doesn't care + virtual int GetMaxHumanPlayers() const { return -1; } +}; + + +#ifndef CLIENT_DLL + void InstallGameRules(); + + // Create user messages for game here, calls into static player class creation functions + void RegisterUserMessages( void ); +#endif + + +extern ConVar g_Language; + + +//----------------------------------------------------------------------------- +// Gets us at the game rules +//----------------------------------------------------------------------------- + +extern CGameRules *g_pGameRules; + +inline CGameRules* GameRules() +{ + return g_pGameRules; +} + +#ifdef PORTAL2 +bool IsGameRulesMultiplayer(); +#endif + +#endif // GAMERULES_H +``` + +`SpyCustom/sdk/gamerules_register.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef GAMERULES_REGISTER_H +#define GAMERULES_REGISTER_H +#ifdef _WIN32 +#pragma once +#endif + + +// Each game rules class must register using this in it's .cpp file. +#if !defined(_STATIC_LINKED) +#define REGISTER_GAMERULES_CLASS( className ) \ + void __CreateGameRules_##className() { new className; } \ + static CGameRulesRegister __g_GameRulesRegister_##className( #className, __CreateGameRules_##className ); +#else +#define REGISTER_GAMERULES_CLASS( className ) \ + void MAKE_NAME_UNIQUE(__CreateGameRules_)##className() { new className; } \ + static CGameRulesRegister __g_GameRulesRegister_##className( #className, MAKE_NAME_UNIQUE(__CreateGameRules_)##className ); +#endif + +class CGameRulesRegister +{ +public: + typedef void (*CreateGameRulesFn)(); + + CGameRulesRegister( const char *pClassName, CreateGameRulesFn fn ); + + // Allocates the gamerules object associated with this class. + void CreateGameRules(); + + static CGameRulesRegister* FindByName( const char *pName ); + +private: + const char *m_pClassName; + CreateGameRulesFn m_pFn; + CGameRulesRegister *m_pNext; // Links it into the global list. + + static CGameRulesRegister *s_pHead; + +}; + + + +#ifdef CLIENT_DLL + + // The client forwards this call so the game rules manager can create the appropriate + // game rules class. + void InstallStringTableCallback_GameRules( const char *tableName ); + +#else + + // Server calls this at startup. + void CreateNetworkStringTables_GameRules(); + + // Server calls this to install a specific game rules object. The class should have been registered + // with REGISTER_GAMERULES_CLASS. + void CreateGameRulesObject( const char *pClassName ); + +#endif + + +#endif // GAMERULES_REGISTER_H +``` + +`SpyCustom/sdk/gamestringpool.h`: + +```h +#ifndef GAMESTRINGPOOL_H +#define GAMESTRINGPOOL_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#if !defined( GC ) +class IGameSystem; +#endif + +string_t AllocPooledString(const char* pszValue); +#define AllocPooledStringConstant( pszValue ) AllocPooledString( pszValue ) +string_t FindPooledString(const char* pszValue); +void RemovePooledString(const char* pszValue); + +#define AssertIsValidString( s ) AssertMsg( s == NULL_STRING || s == FindPooledString( STRING(s) ), "Invalid string " #s ); + +#if !defined( GC ) +IGameSystem* GameStringSystem(); +#endif + +class CGameString +{ +public: + CGameString() : + m_iszString(NULL_STRING), m_pszString(NULL), m_iSerial(0) + { + + } + + CGameString(const char* pszString, bool bCopy = false) : + m_iszString(NULL_STRING), m_pszString(NULL), m_iSerial(0) + { + Set(pszString, bCopy); + } + + ~CGameString() + { + if (m_bCopy) + free((void*)m_pszString); + } + + void Set(const char* pszString, bool bCopy = false) + { + if (m_bCopy && m_pszString) + free((void*)m_pszString); + m_iszString = NULL_STRING; + m_pszString = (!bCopy) ? pszString : strdup(pszString); + } + + void SetFastNoCopy(string_t iszString) + { + m_iszString = iszString; + m_iSerial = gm_iSerialNumber; + } + + bool IsSerialNumberOutOfDate(void) const + { + return m_iSerial != gm_iSerialNumber; + } + + string_t Get() const + { + if (m_iszString == NULL_STRING || IsSerialNumberOutOfDate()) + { + if (!m_pszString) + return NULL_STRING; + + m_iszString = AllocPooledString(m_pszString); + m_iSerial = gm_iSerialNumber; + } + + return m_iszString; + } + + operator const char* () const + { + return (m_pszString) ? m_pszString : ""; + } + +#ifndef NO_STRING_T + operator string_t() const + { + return Get(); + } +#endif + + static void IncrementSerialNumber() + { + gm_iSerialNumber++; + } + +private: + mutable string_t m_iszString; + const char* m_pszString; + mutable int m_iSerial; + bool m_bCopy; + + + static int gm_iSerialNumber; + +}; + +#endif +``` + +`SpyCustom/sdk/gametrace.h`: + +```h +#ifndef GAMETRACE_H +#define GAMETRACE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "cmodel.h" +#include "utlvector.h" +#include "ihandleentity.h" +#include "ispatialpartition.h" + +#if defined( CLIENT_DLL ) +class C_BaseEntity; +#else +class CBaseEntity; +#endif + + +class CGameTrace : public CBaseTrace +{ +public: + + bool DidHitWorld() const; + + bool DidHitNonWorldEntity() const; + + int GetEntityIndex() const; + + bool DidHit() const; + + inline bool IsVisible() const + { + return (fraction > 0.97f); + } + +#if defined( ENGINE_DLL ) + void SetEdict(edict_t* pEdict); + edict_t* GetEdict() const; +#endif + + +public: + + float fractionleftsolid; + csurface_t surface; + int hitgroup; + short physicsbone; + std::uint16_t uWorldSurfaceIndex; // index of the msurface2_t, if applicable + C_BaseEntity* m_pEnt; + int hitbox; + + CGameTrace() {} + +private: + CGameTrace(const CGameTrace& vOther); +}; + + +inline bool CGameTrace::DidHit() const +{ + return fraction < 1 || allsolid || startsolid; +} + + +typedef CGameTrace trace_t; + +#define TLD_DEF_LEAF_MAX 256 +#define TLD_DEF_ENTITY_MAX 1024 + +class CTraceListData : public IPartitionEnumerator +{ +public: + + CTraceListData(int nLeafMax = TLD_DEF_LEAF_MAX, int nEntityMax = TLD_DEF_ENTITY_MAX) + { + MEM_ALLOC_CREDIT(); + m_nLeafCount = 0; + m_aLeafList.SetSize(nLeafMax); + + m_nEntityCount = 0; + m_aEntityList.SetSize(nEntityMax); + } + + ~CTraceListData() + { + m_nLeafCount = 0; + m_aLeafList.RemoveAll(); + + m_nEntityCount = 0; + m_aEntityList.RemoveAll(); + } + + void Reset(void) + { + m_nLeafCount = 0; + m_nEntityCount = 0; + } + + bool IsEmpty(void) const { return (m_nLeafCount == 0 && m_nEntityCount == 0); } + + int LeafCount(void) const { return m_nLeafCount; } + int LeafCountMax(void) const { return m_aLeafList.Count(); } + void LeafCountReset(void) { m_nLeafCount = 0; } + + int EntityCount(void) const { return m_nEntityCount; } + int EntityCountMax(void) const { return m_aEntityList.Count(); } + void EntityCountReset(void) { m_nEntityCount = 0; } + + void AddLeaf(int iLeaf) + { + if (m_nLeafCount >= m_aLeafList.Count()) + { + DevMsg("CTraceListData: Max leaf count along ray exceeded!\n"); + m_aLeafList.AddMultipleToTail(m_aLeafList.Count()); + } + + m_aLeafList[m_nLeafCount] = iLeaf; + m_nLeafCount++; + } + + IterationRetval_t EnumElement(IHandleEntity* pHandleEntity) + { + if (m_nEntityCount >= m_aEntityList.Count()) + { + DevMsg("CTraceListData: Max entity count along ray exceeded!\n"); + m_aEntityList.AddMultipleToTail(m_aEntityList.Count()); + } + + m_aEntityList[m_nEntityCount] = pHandleEntity; + m_nEntityCount++; + + return ITERATION_CONTINUE; + } + +public: + + int m_nLeafCount; + CUtlVector m_aLeafList; + + int m_nEntityCount; + CUtlVector m_aEntityList; +}; + +#endif +``` + +`SpyCustom/sdk/generichash.h`: + +```h +#ifndef GENERICHASH_H +#define GENERICHASH_H + +#if defined(_WIN32) +#pragma once +#endif + +unsigned FASTCALL HashString(const char* pszKey); +unsigned FASTCALL HashStringCaseless(const char* pszKey); +unsigned FASTCALL HashStringCaselessConventional(const char* pszKey); +unsigned FASTCALL Hash4(const void* pKey); +unsigned FASTCALL Hash8(const void* pKey); +unsigned FASTCALL Hash12(const void* pKey); +unsigned FASTCALL Hash16(const void* pKey); +unsigned FASTCALL HashBlock(const void* pKey, unsigned size); + +unsigned FASTCALL HashInt(const int key); + +FORCEINLINE uint32 HashIntAlternate(uint32 n) +{ + n = (n + 0x7ed55d16) + (n << 12); + n = (n ^ 0xc761c23c) ^ (n >> 19); + n = (n + 0x165667b1) + (n << 5); + n = (n + 0xd3a2646c) ^ (n << 9); + n = (n + 0xfd7046c5) + (n << 3); + n = (n ^ 0xb55a4f09) ^ (n >> 16); + return n; +} + +inline unsigned HashIntConventional(const int n) +{ + unsigned hash = 0xAAAAAAAA + (n & 0xFF); + hash = (hash << 5) + hash + ((n >> 8) & 0xFF); + hash = (hash << 5) + hash + ((n >> 16) & 0xFF); + hash = (hash << 5) + hash + ((n >> 24) & 0xFF); + + return hash; + +} + +template +inline unsigned HashItem(const T& item) +{ + if (sizeof(item) == 4) + return Hash4(&item); + else if (sizeof(item) == 8) + return Hash8(&item); + else if (sizeof(item) == 12) + return Hash12(&item); + else if (sizeof(item) == 16) + return Hash16(&item); + else + return HashBlock(&item, sizeof(item)); +} + +template <> inline unsigned HashItem(const int& key) +{ + return HashInt(key); +} + +template <> inline unsigned HashItem(const unsigned& key) +{ + return HashInt((int)key); +} + +template<> inline unsigned HashItem(const char* const& pszKey) +{ + return HashString(pszKey); +} + +template<> inline unsigned HashItem(char* const& pszKey) +{ + return HashString(pszKey); +} + + +uint32 MurmurHash2(const void* key, int len, uint32 seed); + +uint32 MurmurHash2LowerCase(char const* pString, uint32 nSeed); + +uint64 MurmurHash64(const void* key, int len, uint32 seed); + + +#endif +``` + +`SpyCustom/sdk/globalvars_base.h`: + +```h +#ifndef GLOBALVARS_BASE_H +#define GLOBALVARS_BASE_H + +#ifdef _WIN32 +#pragma once +#endif + +class CSaveRestoreData; + +class CGlobalVarsBase +{ +public: + + CGlobalVarsBase(bool bIsClient); + + bool IsClient() const; + + int GetNetworkBase(int nTick, int nEntity); + +public: + + float realtime; + int framecount; + float absoluteframetime; + + float absoluteframestarttimestddev; + + float curtime; + + float frametime; + int maxClients; + + int tickcount; + + float interval_per_tick; + + float interpolation_amount; + int simTicksThisFrame; + + int network_protocol; + + CSaveRestoreData* pSaveData; + +private: + bool m_bClient; + + bool m_bRemoteClient; + + int nTimestampNetworkingBase; + int nTimestampRandomizeWindow; + +}; + +inline int CGlobalVarsBase::GetNetworkBase(int nTick, int nEntity) +{ + int nEntityMod = nEntity % nTimestampRandomizeWindow; + int nBaseTick = nTimestampNetworkingBase * (int)((nTick - nEntityMod) / nTimestampNetworkingBase); + return nBaseTick; +} + +inline CGlobalVarsBase::CGlobalVarsBase(bool bIsClient) : + m_bClient(bIsClient), + nTimestampNetworkingBase(100), + nTimestampRandomizeWindow(32) +{ +} + +inline bool CGlobalVarsBase::IsClient() const +{ + return m_bClient; +} + +#endif +``` + +`SpyCustom/sdk/glow_outline_effect.h`: + +```h +//============ Copyright (c) Valve Corporation, All rights reserved. ============ +// +// Functionality to render a glowing outline around client renderable objects. +// +//=============================================================================== + +#ifndef GLOW_OUTLINE_EFFECT_H +#define GLOW_OUTLINE_EFFECT_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "utlvector.h" +#include "vector.h" +#include "interfaces.hpp" + +class C_BaseEntity; +class CViewSetup; +class CMatRenderContextPtr; + +static const int GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS = -1; + +enum GlowRenderStyle_t +{ + GLOWRENDERSTYLE_DEFAULT = 0, + GLOWRENDERSTYLE_RIMGLOW3D, + GLOWRENDERSTYLE_EDGE_HIGHLIGHT, + GLOWRENDERSTYLE_EDGE_HIGHLIGHT_PULSE, + GLOWRENDERSTYLE_COUNT, +}; + +class CGlowObjectManager +{ +public: + CGlowObjectManager() : + m_nFirstFreeSlot( GlowObjectDefinition_t::END_OF_FREE_LIST ) + { + } + + int RegisterGlowObject( C_BaseEntity *pEntity, const Vector &vGlowColor, float flGlowAlpha, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded, int nSplitScreenSlot ) + { + int nIndex; + if ( m_nFirstFreeSlot == GlowObjectDefinition_t::END_OF_FREE_LIST ) + { + nIndex = m_GlowObjectDefinitions.AddToTail(); + } + else + { + nIndex = m_nFirstFreeSlot; + m_nFirstFreeSlot = m_GlowObjectDefinitions[nIndex].m_nNextFreeSlot; + } + + m_GlowObjectDefinitions[nIndex].m_flGlowPulseOverdrive = 0.0f; + m_GlowObjectDefinitions[nIndex].m_bGlowAlphaCappedByRenderAlpha = false; + m_GlowObjectDefinitions[nIndex].m_flGlowAlphaFunctionOfMaxVelocity = 0.0f; + m_GlowObjectDefinitions[nIndex].m_flGlowAlphaMax = 1.0f; + m_GlowObjectDefinitions[nIndex].m_pEntity = pEntity; + m_GlowObjectDefinitions[nIndex].m_vGlowColor = vGlowColor; + m_GlowObjectDefinitions[nIndex].m_flGlowAlpha = flGlowAlpha; + m_GlowObjectDefinitions[nIndex].m_bRenderWhenOccluded = bRenderWhenOccluded; + m_GlowObjectDefinitions[nIndex].m_bRenderWhenUnoccluded = bRenderWhenUnoccluded; + m_GlowObjectDefinitions[nIndex].m_bFullBloomRender = false; + m_GlowObjectDefinitions[nIndex].m_nFullBloomStencilTestValue = 0; + m_GlowObjectDefinitions[nIndex].m_nSplitScreenSlot = nSplitScreenSlot; + m_GlowObjectDefinitions[nIndex].m_nNextFreeSlot = GlowObjectDefinition_t::ENTRY_IN_USE; + m_GlowObjectDefinitions[nIndex].m_nRenderStyle = GLOWRENDERSTYLE_DEFAULT; + + return nIndex; + } + + int AddGlowBox( Vector vecOrigin, QAngle angOrientation, Vector mins, Vector maxs, Color colColor, float flLifetime ) + { + return 0; /* + int nIndex = m_GlowBoxDefinitions.AddToTail(); + m_GlowBoxDefinitions[nIndex].m_vPosition = vecOrigin; + m_GlowBoxDefinitions[nIndex].m_angOrientation = angOrientation; + m_GlowBoxDefinitions[nIndex].m_vMins = mins; + m_GlowBoxDefinitions[nIndex].m_vMaxs = maxs; + m_GlowBoxDefinitions[nIndex].m_colColor = colColor; + m_GlowBoxDefinitions[nIndex].m_flBirthTimeIndex = iff.g_pGlobals->curtime; + m_GlowBoxDefinitions[nIndex].m_flTerminationTimeIndex = iff.g_pGlobals->curtime + flLifetime; + return nIndex; + */ + } + + void UnregisterGlowObject( int nGlowObjectHandle ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + + m_GlowObjectDefinitions[nGlowObjectHandle].m_nNextFreeSlot = m_nFirstFreeSlot; + m_GlowObjectDefinitions[nGlowObjectHandle].m_pEntity = NULL; + m_nFirstFreeSlot = nGlowObjectHandle; + } + + void UnregisterGlowObject( C_BaseEntity *pEntity ) + { + for ( int i=0; i= GLOWRENDERSTYLE_DEFAULT && nNewRenderStyle < GLOWRENDERSTYLE_COUNT ); + m_GlowObjectDefinitions[nGlowObjectHandle].m_nRenderStyle = nNewRenderStyle; + } + + void SetFullBloomRender( int nGlowObjectHandle, bool bFullBloomRender, int nStencilTestValue ) + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + m_GlowObjectDefinitions[nGlowObjectHandle].m_bFullBloomRender = bFullBloomRender; + m_GlowObjectDefinitions[nGlowObjectHandle].m_nFullBloomStencilTestValue = nStencilTestValue; + } + + bool IsRenderingWhenOccluded( int nGlowObjectHandle ) const + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + return m_GlowObjectDefinitions[nGlowObjectHandle].m_bRenderWhenOccluded; + } + + bool IsRenderingWhenUnoccluded( int nGlowObjectHandle ) const + { + Assert( !m_GlowObjectDefinitions[nGlowObjectHandle].IsUnused() ); + return m_GlowObjectDefinitions[nGlowObjectHandle].m_bRenderWhenUnoccluded; + } + + void RenderGlowEffects( const CViewSetup *pSetup, int nSplitScreenSlot ); + +//private: + + + void ApplyEntityGlowEffects( const CViewSetup *pSetup, int nSplitScreenSlot, CMatRenderContextPtr &pRenderContext, float flBloomScale, int x, int y, int w, int h ); + + void RenderGlowBoxes( int iPass, CMatRenderContextPtr &pRenderContext ); + + struct GlowObjectDefinition_t + { + bool ShouldDraw( int nSlot ) const { + return 0;// m_pEntity && (m_nSplitScreenSlot == GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS || m_nSplitScreenSlot == nSlot) && (m_bRenderWhenOccluded || m_bRenderWhenUnoccluded) && m_pEntity->ShouldDraw(); + } + bool IsUnused() const { + return m_nNextFreeSlot != GlowObjectDefinition_t::ENTRY_IN_USE; + } + void DrawModel(); + + + // Linked list of free slots + int m_nNextFreeSlot; + + C_BaseEntity* m_pEntity; + Vector m_vGlowColor; + float m_flGlowAlpha; + + bool m_bGlowAlphaCappedByRenderAlpha; + float m_flGlowAlphaFunctionOfMaxVelocity; + float m_flGlowAlphaMax; + float m_flGlowPulseOverdrive; + bool m_bRenderWhenOccluded; + bool m_bRenderWhenUnoccluded; + bool m_bFullBloomRender; + int m_nFullBloomStencilTestValue; // only render full bloom objects if stencil is equal to this value (value of -1 implies no stencil test) + int m_nRenderStyle; + int m_nSplitScreenSlot; + + + // Special values for GlowObjectDefinition_t::m_nNextFreeSlot + static const int END_OF_FREE_LIST = -1; + static const int ENTRY_IN_USE = -2; + }; + + void RenderGlowModels( const CViewSetup *pSetup, int nSplitScreenSlot, CMatRenderContextPtr &pRenderContext, CUtlVector &vecGlowObjects ); + + void DownSampleAndBlurRT( const CViewSetup *pSetup, CMatRenderContextPtr &pRenderContext, float flBloomScale, ITexture *pRtFullFrame, ITexture *pRtQuarterSize0, ITexture *pRtQuarterSize1 ); + + CUtlVector< GlowObjectDefinition_t > m_GlowObjectDefinitions; + int m_nFirstFreeSlot; + + struct GlowBoxDefinition_t + { + Vector m_vPosition; + QAngle m_angOrientation; + Vector m_vMins; + Vector m_vMaxs; + float m_flBirthTimeIndex; + float m_flTerminationTimeIndex; //when to die + Color m_colColor; + }; + + CUtlVector< GlowBoxDefinition_t > m_GlowBoxDefinitions; + +}; + +CGlowObjectManager &GlowObjectManager(); + +class CGlowObject +{ +public: + CGlowObject( C_BaseEntity *pEntity, const Vector &vGlowColor = Vector( 1.0f, 1.0f, 1.0f ), float flGlowAlpha = 1.0f, bool bRenderWhenOccluded = false, bool bRenderWhenUnoccluded = false, int nSplitScreenSlot = GLOW_FOR_ALL_SPLIT_SCREEN_SLOTS ) + { + m_nGlowObjectHandle = GlowObjectManager().RegisterGlowObject( pEntity, vGlowColor, flGlowAlpha, bRenderWhenOccluded, bRenderWhenUnoccluded, nSplitScreenSlot ); + } + + ~CGlowObject() + { + GlowObjectManager().UnregisterGlowObject( m_nGlowObjectHandle ); + } + + void SetGlowAlphaPulseOverdrive( float flAdditionalAlpha ) + { + //this value is added to existing glow alpha, and fades away in a few frames + GlowObjectManager().SetGlowAlphaPulseOverdrive( m_nGlowObjectHandle, flAdditionalAlpha ); + } + + void SetGlowAlphaCappedByRenderAlpha( bool bGlowAlphaCappedByRenderAlpha ) + { + GlowObjectManager().SetGlowAlphaCappedByRenderAlpha( m_nGlowObjectHandle, bGlowAlphaCappedByRenderAlpha ); + } + + void SetGlowAlphaFunctionOfMaxVelocity( float flMaxVelocity ) + { + GlowObjectManager().SetGlowAlphaFunctionOfMaxVelocity( m_nGlowObjectHandle, flMaxVelocity ); + } + + void SetGlowAlphaMax( float flGlowAlphaMax ) + { + GlowObjectManager().SetGlowAlphaMax( m_nGlowObjectHandle, flGlowAlphaMax ); + } + + void SetEntity( C_BaseEntity *pEntity ) + { + GlowObjectManager().SetEntity( m_nGlowObjectHandle, pEntity ); + } + + void SetColor( const Vector &vGlowColor ) + { + GlowObjectManager().SetColor( m_nGlowObjectHandle, vGlowColor ); + } + + void SetAlpha( float flAlpha ) + { + GlowObjectManager().SetAlpha( m_nGlowObjectHandle, flAlpha ); + } + + void SetRenderFlags( bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + GlowObjectManager().SetRenderFlags( m_nGlowObjectHandle, bRenderWhenOccluded, bRenderWhenUnoccluded ); + } + + void SetRenderStyle( GlowRenderStyle_t nNewRenderStyle ) + { + GlowObjectManager().SetRenderStyle( m_nGlowObjectHandle, nNewRenderStyle ); + } + + void SetFullBloomRender( bool bFullBloomRender, int nStencilTestValue = -1 ) + { + return GlowObjectManager().SetFullBloomRender( m_nGlowObjectHandle, bFullBloomRender, nStencilTestValue ); + } + + bool IsRenderingWhenOccluded() const + { + return GlowObjectManager().IsRenderingWhenOccluded( m_nGlowObjectHandle ); + } + + bool IsRenderingWhenUnoccluded() const + { + return GlowObjectManager().IsRenderingWhenUnoccluded( m_nGlowObjectHandle ); + } + + bool IsRendering() const + { + return IsRenderingWhenOccluded() || IsRenderingWhenUnoccluded(); + } + + // Add more accessors/mutators here as needed + +private: + int m_nGlowObjectHandle; + + // Assignment & copy-construction disallowed + CGlowObject( const CGlowObject &other ); + CGlowObject& operator=( const CGlowObject &other ); +}; + +#endif // GLOW_OUTLINE_EFFECT_H +``` + +`SpyCustom/sdk/groundlink.h`: + +```h +#ifndef GROUNDLINK_H +#define GROUNDLINK_H +#ifdef _WIN32 +#pragma once +#endif + +struct groundlink_t +{ + EHANDLE entity; + groundlink_t* nextLink; + groundlink_t* prevLink; +}; + +#endif +``` + +`SpyCustom/sdk/htmlmessages.h`: + +```h +#ifndef HTMLMESSAGES_H +#define HTMLMESSAGES_H + +#ifdef _WIN32 +#pragma once +#endif + +enum EHTMLCommands +{ + eHTMLCommands_KeyUp, + eHTMLCommands_KeyDown, + eHTMLCommands_KeyChar, + eHTMLCommands_MouseDown, + eHTMLCommands_MouseUp, + eHTMLCommands_MouseDblClick, + eHTMLCommands_MouseWheel, + eHTMLCommands_MouseMove, + eHTMLCommands_MouseLeave, + + eHTMLCommands_BrowserCreate, + eHTMLCommands_BrowserRemove, + eHTMLCommands_BrowserErrorStrings, + eHTMLCommands_BrowserSize, + eHTMLCommands_BrowserPosition, + eHTMLCommands_PostURL, + eHTMLCommands_StopLoad, + eHTMLCommands_Reload, + eHTMLCommands_GoForward, + eHTMLCommands_GoBack, + eHTMLCommands_Copy, + eHTMLCommands_Paste, + eHTMLCommands_ExecuteJavaScript, + eHTMLCommands_SetFocus, + eHTMLCommands_HorizontalScrollBarSize, + eHTMLCommands_VerticalScrollBarSize, + eHTMLCommands_Find, + eHTMLCommands_StopFind, + eHTMLCommands_SetHorizontalScroll, + eHTMLCommands_SetVerticalScroll, + eHTMLCommands_SetZoomLevel, + eHTMLCommands_ViewSource, + eHTMLCommands_NeedsPaintResponse, + eHTMLCommands_AddHeader, + eHTMLCommands_GetZoom, + eHTMLCommands_FileLoadDialogResponse, + eHTMLCommands_LinkAtPosition, + eHTMLCommands_ZoomToElementAtPosition, + eHTMLCommands_SavePageToJPEG, + eHTMLCommands_JSAlert, + eHTMLCommands_JSConfirm, + eHTMLCommands_CanGoBackandForward, + eHTMLCommands_OpenSteamURL, + eHTMLCommands_SizePopup, + eHTMLCommands_SetCookie, + eHTMLCommands_SetTargetFrameRate, + eHTMLCommands_FullRepaint, + eHTMLCommands_SetPageScale, + eHTMLCommands_RequestFullScreen, + eHTMLCommands_ExitFullScreen, + eHTMLCommands_GetCookiesForURL, + eHTMLCommands_ZoomToCurrentlyFocusedNode, + eHTMLCommands_CloseFullScreenFlashIfOpen, + eHTMLCommands_PauseFullScreenFlashMovieIfOpen, + eHTMLCommands_GetFocusedNodeValue, + + eHTMLCommands_BrowserCreateResponse, + eHTMLCommands_BrowserReady, + eHTMLCommands_URLChanged, + eHTMLCommands_FinishedRequest, + eHTMLCommands_StartRequest, + eHTMLCommands_ShowPopup, + eHTMLCommands_HidePopup, + eHTMLCommands_OpenNewTab, + eHTMLCommands_PopupHTMLWindow, + eHTMLCommands_PopupHTMLWindowResponse, + eHTMLCommands_SetHTMLTitle, + eHTMLCommands_LoadingResource, + eHTMLCommands_StatusText, + eHTMLCommands_SetCursor, + eHTMLCommands_FileLoadDialog, + eHTMLCommands_ShowToolTip, + eHTMLCommands_UpdateToolTip, + eHTMLCommands_HideToolTip, + eHTMLCommands_SearchResults, + eHTMLCommands_Close, + eHTMLCommands_VerticalScrollBarSizeResponse, + eHTMLCommands_HorizontalScrollBarSizeResponse, + eHTMLCommands_GetZoomResponse, + eHTMLCommands_StartRequestResponse, + eHTMLCommands_NeedsPaint, + eHTMLCommands_LinkAtPositionResponse, + eHTMLCommands_ZoomToElementAtPositionResponse, + eHTMLCommands_JSDialogResponse, + eHTMLCommands_ScaleToValueResponse, + eHTMLCommands_RequestFullScreenResponse, + eHTMLCommands_GetCookiesForURLResponse, + eHTMLCommands_NodeGotFocus, + eHTMLCommands_SavePageToJPEGResponse, + eHTMLCommands_GetFocusedNodeValueResponse, + + eHTMLCommands_None, + +}; + +#endif +``` + +`SpyCustom/sdk/hud.h`: + +```h +#ifndef HUD_H +#define HUD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utldict.h" +#include "convar.h" +#include "VGUI.h" +#include "Color.h" +#include "bitbuf.h" + +namespace vgui +{ + class IScheme; +} + +typedef struct wrect_s +{ + int left; + int right; + int top; + int bottom; +} wrect_t; + +class CHudTexture +{ +public: + CHudTexture(); + CHudTexture& operator =(const CHudTexture& src); + virtual ~CHudTexture(); + + int Width() const + { + return rc.right - rc.left; + } + + int Height() const + { + return rc.bottom - rc.top; + } + + void Precache(void); + + int EffectiveWidth(float flScale) const; + int EffectiveHeight(float flScale) const; + + void DrawSelf(int x, int y, const Color& clr) const; + void DrawSelf(int x, int y, int w, int h, const Color& clr) const; + void DrawSelfCropped(int x, int y, int cropx, int cropy, int cropw, int croph, Color clr) const; + void DrawSelfCropped(int x, int y, int cropx, int cropy, int cropw, int croph, int finalWidth, int finalHeight, Color clr) const; + + char szShortName[64]; + char szTextureFile[64]; + + bool bRenderUsingFont; + bool bPrecached; + char cCharacterInFont; + vgui::HFont hFont; + + int textureId; + float texCoords[4]; + + wrect_t rc; +}; + +#include "hudtexturehandle.h" + +class CHudElement; +class CHudRenderGroup; + +class CHud +{ +public: + static const int HUDPB_HORIZONTAL; + static const int HUDPB_VERTICAL; + static const int HUDPB_HORIZONTAL_INV; + +public: + CHud(); + ~CHud(); + + void Init(void); + void VidInit(void); + void Shutdown(void); + void LevelInit(void); + void LevelShutdown(void); + + void ResetHUD(void); + + void OnRestore(); + + void Think(); + + void ProcessInput(bool bActive); + void UpdateHud(bool bActive); + + void InitColors(vgui::IScheme* pScheme); + + void AddHudElement(CHudElement* pHudElement); + void RemoveHudElement(CHudElement* pHudElement); + CHudElement* FindElement(const char* pName); + + bool IsHidden(int iHudFlags); + + float GetSensitivity(); + float GetFOVSensitivityAdjust(); + + void DrawProgressBar(int x, int y, int width, int height, float percentage, Color& clr, unsigned char type); + void DrawIconProgressBar(int x, int y, CHudTexture* icon, CHudTexture* icon2, float percentage, Color& clr, int type); + + CHudTexture* GetIcon(const char* szIcon); + + CHudTexture* AddUnsearchableHudIconToList(CHudTexture& texture); + CHudTexture* AddSearchableHudIconToList(CHudTexture& texture); + + void RefreshHudTextures(); + + void MsgFunc_ResetHUD(bf_read& msg); + void MsgFunc_SendAudio(bf_read& msg); + + int LookupRenderGroupIndexByName(const char* pszGroupName); + bool LockRenderGroup(int iGroupIndex, CHudElement* pLocker = NULL); + bool UnlockRenderGroup(int iGroupIndex, CHudElement* pLocker = NULL); + bool IsRenderGroupLockedFor(CHudElement* pHudElement, int iGroupIndex); + int RegisterForRenderGroup(const char* pszGroupName); + int AddHudRenderGroup(const char* pszGroupName); + bool DoesRenderGroupExist(int iGroupIndex); + + void SetScreenShotTime(float flTime) { m_flScreenShotTime = flTime; } + +public: + + int m_iKeyBits; +#ifndef _XBOX + float m_flMouseSensitivity; + float m_flMouseSensitivityFactor; +#endif + float m_flFOVSensitivityAdjust; + + Color m_clrNormal; + Color m_clrCaution; + Color m_clrYellowish; + + CUtlVector< CHudElement* > m_HudList; + +private: + void InitFonts(); + + void SetupNewHudTexture(CHudTexture* t); + + bool m_bHudTexturesLoaded; + + CUtlDict< CHudTexture*, int > m_Icons; + + CUtlVector< const char* > m_RenderGroupNames; + CUtlMap< int, CHudRenderGroup* > m_RenderGroups; + + float m_flScreenShotTime; +}; + +extern CHud gHUD; + +extern vgui::HFont g_hFontTrebuchet24; + +void LoadHudTextures(CUtlDict< CHudTexture*, int >& list, const char* szFilenameWithoutExtension, const unsigned char* pICEKey); + +void GetHudSize(int& w, int& h); + +#endif +``` + +`SpyCustom/sdk/hud_basechat.h`: + +```h +#ifndef HUD_BASECHAT_H +#define HUD_BASECHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include "Panel.h" +#include "vgui_basepanel.h" +#include "Frame.h" +#include "TextEntry.h" +#include "RichText.h" +#include "Button.h" +#include "CheckButton.h" + +class CBaseHudChatInputLine; +class CBaseHudChatEntry; +class CHudChatFilterPanel; + +namespace vgui +{ + class IScheme; +}; + +#define CHATLINE_NUM_FLASHES 8.0f +#define CHATLINE_FLASH_TIME 5.0f +#define CHATLINE_FADE_TIME 1.0f + +#define CHAT_HISTORY_FADE_TIME 0.25f +#define CHAT_HISTORY_IDLE_TIME 15.0f +#define CHAT_HISTORY_IDLE_FADE_TIME 2.5f +#define CHAT_HISTORY_ALPHA 127 + +extern Color g_ColorBlue; +extern Color g_ColorRed; +extern Color g_ColorGreen; +extern Color g_ColorDarkGreen; +extern Color g_ColorYellow; +extern Color g_ColorGrey; + +extern ConVar cl_showtextmsg; + +enum ChatFilters +{ + CHAT_FILTER_NONE = 0, + CHAT_FILTER_JOINLEAVE = 0x000001, + CHAT_FILTER_NAMECHANGE = 0x000002, + CHAT_FILTER_PUBLICCHAT = 0x000004, + CHAT_FILTER_SERVERMSG = 0x000008, + CHAT_FILTER_TEAMCHANGE = 0x000010, + CHAT_FILTER_ACHIEVEMENT = 0x000020, + +}; + + +enum TextColor +{ + COLOR_NORMAL = 1, + COLOR_USEOLDCOLORS = 2, + COLOR_PLAYERNAME = 3, + COLOR_LOCATION = 4, + COLOR_ACHIEVEMENT = 5, + COLOR_CUSTOM = 6, + COLOR_HEXCODE = 7, + COLOR_HEXCODE_ALPHA = 8, + COLOR_MAX +}; + +struct TextRange +{ + TextRange() { preserveAlpha = false; } + int start; + int end; + Color color; + bool preserveAlpha; +}; + +void StripEndNewlineFromString(char* str); +void StripEndNewlineFromString(wchar_t* str); + +char* ConvertCRtoNL(char* str); +wchar_t* ConvertCRtoNL(wchar_t* str); +wchar_t* ReadLocalizedString(bf_read& msg, OUT_Z_BYTECAP(outSizeInBytes) wchar_t* pOut, int outSizeInBytes, bool bStripNewline, OUT_Z_CAP(originalSize) char* originalString = NULL, int originalSize = 0); +wchar_t* ReadChatTextString(bf_read& msg, OUT_Z_BYTECAP(outSizeInBytes) wchar_t* pOut, int outSizeInBytes); +char* RemoveColorMarkup(char* str); + +inline wchar_t* CloneWString(const wchar_t* str) +{ + const int nLen = V_wcslen(str) + 1; + wchar_t* cloneStr = new wchar_t[nLen]; + const int nSize = nLen * sizeof(wchar_t); + V_wcsncpy(cloneStr, str, nSize); + return cloneStr; +} + +class CBaseHudChatLine : public vgui::RichText +{ + typedef vgui::RichText BaseClass; + +public: + CBaseHudChatLine(vgui::Panel* parent, const char* panelName); + ~CBaseHudChatLine(); + + void SetExpireTime(void); + + bool IsReadyToExpire(void); + + void Expire(void); + + float GetStartTime(void); + + int GetCount(void); + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + + vgui::HFont GetFont() { return m_hFont; } + + Color GetTextColor(void) { return m_clrText; } + void SetNameLength(int iLength) { m_iNameLength = iLength; } + void SetNameColor(Color cColor) { m_clrNameColor = cColor; } + + virtual void PerformFadeout(void); + virtual void InsertAndColorizeText(wchar_t* buf, int clientIndex); + virtual void Colorize(int alpha = 255); + + + void SetNameStart(int iStart) { m_iNameStart = iStart; } + +protected: + int m_iNameLength; + vgui::HFont m_hFont; + + Color m_clrText; + Color m_clrNameColor; + + float m_flExpireTime; + + CUtlVector< TextRange > m_textRanges; + wchar_t* m_text; + + int m_iNameStart; + +private: + float m_flStartTime; + int m_nCount; + + vgui::HFont m_hFontMarlett; + + +private: + CBaseHudChatLine(const CBaseHudChatLine&); +}; + + +class CHudChatHistory : public vgui::RichText +{ + DECLARE_CLASS_SIMPLE(CHudChatHistory, vgui::RichText); +public: + + CHudChatHistory(vgui::Panel* pParent, const char* panelName); + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); +}; + +class CHudChatFilterButton : public vgui::Button +{ + DECLARE_CLASS_SIMPLE(CHudChatFilterButton, vgui::Button); + +public: + + CHudChatFilterButton(vgui::Panel* pParent, const char* pName, const char* pText); + + virtual void DoClick(void); +}; + +class CHudChatFilterCheckButton : public vgui::CheckButton +{ + DECLARE_CLASS_SIMPLE(CHudChatFilterCheckButton, vgui::CheckButton); + +public: + + CHudChatFilterCheckButton(vgui::Panel* pParent, const char* pName, const char* pText, int iFlag); + + int GetFilterFlag(void) { return m_iFlag; } + +private: + + int m_iFlag; +}; + + +class CBaseHudChat : public CHudElement, public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE(CBaseHudChat, vgui::EditablePanel); +public: + DECLARE_MULTIPLY_INHERITED(); + + enum + { + CHAT_INTERFACE_LINES = 6, + MAX_CHARS_PER_LINE = 128 + }; + + explicit CBaseHudChat(const char* pElementName); + ~CBaseHudChat(); + + static CBaseHudChat* GetHudChat(void); + + virtual void CreateChatInputLine(void); + virtual void CreateChatLines(void); + + virtual void Init(void); + + void LevelInit(const char* newmap); + void LevelShutdown(void); + + void MsgFunc_TextMsg(const char* pszName, int iSize, void* pbuf); + + virtual void Printf(int iFilter, PRINTF_FORMAT_STRING const char* fmt, ...); + virtual void ChatPrintf(int iPlayerIndex, int iFilter, PRINTF_FORMAT_STRING const char* fmt, ...) FMTFUNCTION(4, 5); + virtual void ChatPrintfW(int iPlayerIndex, int iFilter, const wchar_t* wszNotice); + + virtual void StartMessageMode(int iMessageModeType); + virtual void StopMessageMode(void); + void Send(void); + + //MESSAGE_FUNC(OnChatEntrySend, "ChatEntrySend"); + //MESSAGE_FUNC(OnChatEntryStopMessageMode, "ChatEntryStopMessageMode"); + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + virtual void Paint(void); + virtual void OnTick(void); + virtual void Reset(); + + vgui::Panel* GetInputPanel(void); + + static int m_nLineCounter; + + virtual int GetChatInputOffset(void); + + virtual void FireGameEvent(IGameEvent* event); + + CHudChatHistory* GetChatHistory(); + + void FadeChatHistory(); + float m_flHistoryFadeTime; + float m_flHistoryIdleTime; + + virtual void MsgFunc_SayText(bf_read& msg); + virtual void MsgFunc_SayText2(bf_read& msg); + virtual void MsgFunc_TextMsg(bf_read& msg); + virtual void MsgFunc_VoiceSubtitle(bf_read& msg); + + + CBaseHudChatInputLine* GetChatInput(void) { return m_pChatInput; } + CHudChatFilterPanel* GetChatFilterPanel(void); + + virtual int GetFilterFlags(void) { return m_iFilterFlags; } + void SetFilterFlag(int iFilter); + + virtual void SetChatPrompt(int iMessageModeType); + + virtual Color GetDefaultTextColor(void); + virtual Color GetTextColorForClient(TextColor colorNum, int clientIndex); + virtual Color GetClientColor(int clientIndex); + + virtual int GetFilterForString(const char* pString); + + virtual const char* GetDisplayedSubtitlePlayerName(int clientIndex); + + bool IsVoiceSubtitle(void) { return m_bEnteringVoice; } + void SetVoiceSubtitleState(bool bState) { m_bEnteringVoice = bState; } + //int GetMessageMode(void) { return m_nMessageMode; } + + //void SetCustomColor(Color colNew) { m_ColorCustom = colNew; } + //void SetCustomColor(const char* pszColorName); + +protected: + CBaseHudChatLine* FindUnusedChatLine(void); + + CBaseHudChatInputLine* m_pChatInput; + CBaseHudChatLine* m_ChatLine; + int m_iFontHeight; + + CHudChatHistory* m_pChatHistory; + + CHudChatFilterButton* m_pFiltersButton; + CHudChatFilterPanel* m_pFilterPanel; + + //Color m_ColorCustom; + +private: + void Clear(void); + + int ComputeBreakChar(int width, const char* text, int textlen); + + int m_nMessageMode; + + //int m_nVisibleHeight; + + vgui::HFont m_hChatFont; + + int m_iFilterFlags; + bool m_bEnteringVoice; + +}; + +class CBaseHudChatEntry : public vgui::TextEntry +{ + typedef vgui::TextEntry BaseClass; +public: + CBaseHudChatEntry(vgui::Panel* parent, char const* panelName, vgui::Panel* pChat) + : BaseClass(parent, panelName) + { + SetCatchEnterKey(true); + SetAllowNonAsciiCharacters(true); + SetDrawLanguageIDAtLeft(true); + m_pHudChat = pChat; + } + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme) + { + BaseClass::ApplySchemeSettings(pScheme); + + SetPaintBorderEnabled(false); + } + + virtual void OnKeyCodeTyped(vgui::KeyCode code) + { + if (code == KEY_ENTER || code == KEY_PAD_ENTER || code == KEY_ESCAPE) + { + if (code != KEY_ESCAPE) + { + if (m_pHudChat) + { + PostMessage(m_pHudChat, new KeyValues("ChatEntrySend")); + } + } + + if (m_pHudChat) + { + PostMessage(m_pHudChat, new KeyValues("ChatEntryStopMessageMode")); + } + } + else if (code == KEY_TAB) + { + return; + } + else + { + BaseClass::OnKeyCodeTyped(code); + } + } + +private: + vgui::Panel* m_pHudChat; +}; + +class CBaseHudChatInputLine : public vgui::Panel +{ + typedef vgui::Panel BaseClass; + +public: + CBaseHudChatInputLine(vgui::Panel* parent, char const* panelName); + + void SetPrompt(const wchar_t* prompt); + void ClearEntry(void); + void SetEntry(const wchar_t* entry); + void GetMessageText(OUT_Z_BYTECAP(buffersizebytes) wchar_t* buffer, int buffersizebytes); + + virtual void PerformLayout(); + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + + vgui::Panel* GetInputPanel(void); + virtual vgui::VPANEL GetCurrentKeyFocus() { return m_pInput->GetVPanel(); } + + virtual void Paint() + { + BaseClass::Paint(); + } + + vgui::Label* GetPrompt(void) { return m_pPrompt; } + +protected: + vgui::Label* m_pPrompt; + CBaseHudChatEntry* m_pInput; +}; + + +class CHudChatFilterPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE(CHudChatFilterPanel, vgui::EditablePanel); + +public: + + CHudChatFilterPanel(vgui::Panel* pParent, const char* pName); + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + MESSAGE_FUNC_PTR(OnFilterButtonChecked, "CheckButtonChecked", panel); + + CBaseHudChat* GetChatParent(void) { return dynamic_cast (GetParent()); } + + virtual void SetVisible(bool state); + +private: + +}; + +#endif +``` + +`SpyCustom/sdk/hud_element_helper.h`: + +```h +#ifndef HUD_ELEMENT_HELPER_H +#define HUD_ELEMENT_HELPER_H +#ifdef _WIN32 +#pragma once +#endif + +class CHudElement; + +class CHudElementHelper +{ +public: + static CHudElementHelper* m_sHelpers; + static void CreateAllElements(void); + +public: + CHudElementHelper(CHudElement* (*pfnCreate)(void), int depth); + + CHudElementHelper* GetNext(void); + +private: + CHudElementHelper* m_pNext; + CHudElement* (*m_pfnCreate)(void); + + int m_iDepth; +}; + +#define DECLARE_HUDELEMENT( className ) \ + static CHudElement *Create_##className( void ) \ + { \ + return new className( #className ); \ + }; \ + static CHudElementHelper g_##className##_Helper( Create_##className, 50 ); + +#define DECLARE_HUDELEMENT_DEPTH( className, depth ) \ + static CHudElement *Create_##className( void ) \ + { \ + return new className( #className ); \ + }; \ + static CHudElementHelper g_##className##_Helper( Create_##className, depth ); + +#define DECLARE_NAMED_HUDELEMENT( className, panelName ) \ + static CHudElement *Create_##panelName( void ) \ + { \ + return new className( #panelName ); \ + }; \ + static CHudElementHelper g_##panelName##_Helper( Create_##panelName, 50 ); + +#define GET_HUDELEMENT( className ) \ + ( className *)gHUD.FindElement( #className ) + +#define GET_NAMED_HUDELEMENT( className, panelName ) \ + ( className *)gHUD.FindElement( #panelName ) + + +#define DECLARE_MULTIPLY_INHERITED() \ + void *operator new( size_t stAllocateBlock ) \ + { \ + return CHudElement::operator new ( stAllocateBlock ); \ + } \ + void* operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ) \ + { \ + return CHudElement::operator new ( stAllocateBlock, nBlockUse, pFileName, nLine ); \ + } \ + void operator delete( void *pMem ) \ + { \ + CHudElement::operator delete ( pMem ); \ + } \ + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) \ + { \ + CHudElement::operator delete ( pMem, nBlockUse, pFileName, nLine ); \ + } + +#define IMPLEMENT_OPERATORS_NEW_AND_DELETE DECLARE_MULTIPLY_INHERITED + +#endif +``` + +`SpyCustom/sdk/hudelement.h`: + +```h +#if !defined( HUDELEMENT_H ) +#define HUDELEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud.h" +#include "hud_element_helper.h" +#include "networkvar.h" +#include "GameEventListener.h" +#include "memdbgon.h" + +#include "panel2d.h" + +#undef new + +class CHudElement : public CGameEventListener +{ +public: + DECLARE_CLASS_NOBASE(CHudElement); + + CHudElement() {} + explicit CHudElement(const char* pElementName); + virtual ~CHudElement(); + + virtual void SetHud(CHud* pHud); + + virtual void Init(void) { return; } + + virtual void VidInit(void) { return; } + + virtual void LevelInit(void) { return; }; + virtual void LevelShutdown(void) { return; }; + + virtual void Reset(void) { return; } + + virtual void ProcessInput(void) { return; } + + // Called once per frame whether the element is visible or not + virtual void Think(void) { return; } + + // Called when time warping occurs, i.e. when instant replay rewinds or forwards client's time + virtual void OnTimeJump(void) { return; } + + virtual const char* GetName(void) const { return m_pElementName; }; + + virtual bool ShouldDraw(void); + + virtual bool IsActive(void) { return m_bActive; }; + virtual void SetActive(bool bActive); + + virtual void SetHiddenBits(int iBits); + + virtual void SetIgnoreGlobalHudDisable(bool hide); + virtual bool GetIgnoreGlobalHudDisable(void); + + bool IsParentedToClientDLLRootPanel() const; + void SetParentedToClientDLLRootPanel(bool parented); + + // Return true if this HUD element expects an entry in HudLayout.res + virtual bool WantsHudLayoutEntry(void) const { return true; } + + void* operator new(size_t stAllocateBlock) + { + Assert(stAllocateBlock != 0); + void* pMem = malloc(stAllocateBlock); + memset(pMem, 0, stAllocateBlock); + return pMem; + } + + void* operator new(size_t stAllocateBlock, int nBlockUse, const char* pFileName, int nLine) + { + Assert(stAllocateBlock != 0); + void* pMem = MemAlloc_Alloc(stAllocateBlock, pFileName, nLine); + memset(pMem, 0, stAllocateBlock); + return pMem; + } + + void operator delete(void* pMem) + { +#if defined( _DEBUG ) + int size = _msize(pMem); + memset(pMem, 0xcd, size); +#endif + free(pMem); + } + + void operator delete(void* pMem, int nBlockUse, const char* pFileName, int nLine) + { + operator delete(pMem); + } + + void SetNeedsRemove(bool needsremove); + + void RegisterForRenderGroup(const char* pszName); + void UnregisterForRenderGroup(const char* pszGroupName); + void HideLowerPriorityHudElementsInGroup(const char* pszGroupName); + void UnhideLowerPriorityHudElementsInGroup(const char* pszGroupName); + + virtual int GetRenderGroupPriority(); + + void SetSplitScreenPlayerSlot(int nSlot); + int GetSplitScreenPlayerSlot() const; + + virtual void OnSplitScreenStateChanged() {} + +public: + + virtual void FireGameEvent(IGameEvent* event) {} + +//protected: + void InitCHudElementAfterConstruction(const char* pElementName); + +public: + + bool m_bActive; + +//protected: + int m_iHiddenBits; + int m_nSplitScreenPlayerSlot; + bool m_ignoreGlobalHudDisable; + +//private: + const char* m_pElementName; + bool m_bNeedsRemove; + bool m_bIsParentedToClientDLLRootPanel; + + CUtlVector< int > m_HudRenderGroups; + CHud* m_pHud; + + // + panorama::CPanel2D* GetPanel2D() + { + return reinterpret_cast(uintptr_t(this) - 0x14); + } +}; + +#include "utlpriorityqueue.h" + +inline bool RenderGroupLessFunc(CHudElement* const& lhs, CHudElement* const& rhs) +{ + return (lhs->GetRenderGroupPriority() < rhs->GetRenderGroupPriority()); +} + +class CHudRenderGroup +{ +public: + CHudRenderGroup() + { + m_pLockingElements.SetLessFunc(RenderGroupLessFunc); + bHidden = false; + } + + bool bHidden; + CUtlPriorityQueue< CHudElement* > m_pLockingElements; +}; + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/hudtexturehandle.h`: + +```h +#ifndef HUDTEXTUREHANDLE_H +#define HUDTEXTUREHANDLE_H +#ifdef _WIN32 +#pragma once +#endif + +class CHudTexture; + +class CHudTextureHandle +{ +public: + CHudTextureHandle() + { + m_pValue = NULL; + } + + const CHudTextureHandle& operator=(const CHudTexture* t) + { + m_pValue = (CHudTexture*)t; + return *this; + } + + void Set(CHudTexture* t) + { + m_pValue = t; + } + + CHudTexture* Get() + { + return m_pValue; + } + + operator CHudTexture* () + { + return m_pValue; + } + + operator CHudTexture* () const + { + return m_pValue; + } + + CHudTexture* operator->() const + { + return m_pValue; + } + +private: + CHudTexture* m_pValue; +}; + +#endif +``` + +`SpyCustom/sdk/ichromehtmlwrapper.h`: + +```h +#ifndef ICHROMEHTMLWRAPPER_H +#define ICHROMEHTMLWRAPPER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "htmlmessages.h" + +class CUtlString; +class IHTMLResponses; +struct HTMLCommandBuffer_t; + + +class IHTMLChromeController +{ +public: + virtual ~IHTMLChromeController() {} + + virtual bool Init(const char* pchHTMLCacheDir, const char* pchCookiePath) = 0; + virtual void Shutdown() = 0; + virtual bool RunFrame() = 0; + + + virtual void SetWebCookie(const char* pchHostname, const char* pchKey, const char* pchValue, const char* pchPath, RTime32 nExpires = 0) = 0; + virtual void GetWebCookiesForURL(CUtlString* pstrValue, const char* pchURL, const char* pchName) = 0; + + virtual void SetClientBuildID(uint64 ulBuildID) = 0; + + virtual bool BHasPendingMessages() = 0; + + virtual void CreateBrowser(IHTMLResponses* pBrowser, bool bPopupWindow, const char* pchUserAgentIdentifier) = 0; + virtual void RemoveBrowser(IHTMLResponses* pBrowser) = 0; + + virtual void WakeThread() = 0; + virtual HTMLCommandBuffer_t* GetFreeCommandBuffer(EHTMLCommands eCmd, int iBrowser) = 0; + virtual void PushCommand(HTMLCommandBuffer_t*) = 0; + +#ifdef DBGFLAG_VALIDATE + virtual void Validate(CValidator& validator, const char* pchName) = 0; + + virtual bool ChromePrepareForValidate() = 0; + virtual bool ChromeResumeFromValidate() = 0; +#endif + + virtual void SetCefThreadTargetFrameRate(uint32 nFPS) = 0; +}; + +#define CHROMEHTML_CONTROLLER_INTERFACE_VERSION "ChromeHTML_Controller_001" + + +#endif +``` + +`SpyCustom/sdk/iclassmap.h`: + +```h +#ifndef ICLASSMAP_H +#define ICLASSMAP_H +#ifdef _WIN32 +#pragma once +#endif + +class C_BaseEntity; +typedef C_BaseEntity* (*DISPATCHFUNCTION)(void); + +class IClassMap +{ +public: + virtual ~IClassMap() {} + + virtual void Add(const char* mapname, const char* classname, int size, DISPATCHFUNCTION factory = 0) = 0; + virtual char const* Lookup(const char* classname) = 0; + virtual C_BaseEntity* CreateEntity(const char* mapname) = 0; + virtual int GetClassSize(const char* classname) = 0; +}; + +extern IClassMap& GetClassMap(); + + +#endif +``` + +`SpyCustom/sdk/iclient.h`: + +```h +#ifndef ICLIENT_H +#define ICLIENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "inetmsghandler.h" +#include "platform.h" +#include "userid.h" +#include "utlvector.h" + +class IServer; +class INetMessage; +struct NetMessageCvar_t; +//class CMsg_CVars; +#include "../ProtobuffMessages.h" + +enum CrossPlayPlatform_t +{ + CROSSPLAYPLATFORM_UNKNOWN = 0, + CROSSPLAYPLATFORM_PC, + CROSSPLAYPLATFORM_X360, + CROSSPLAYPLATFORM_PS3, + + CROSSPLAYPLATFORM_LAST = CROSSPLAYPLATFORM_PS3, +}; + +inline bool IsCrossPlayPlatformAConsole(CrossPlayPlatform_t platform) +{ + return (platform == CROSSPLAYPLATFORM_X360) || (platform == CROSSPLAYPLATFORM_PS3); +} + +#if defined( _GAMECONSOLE ) +# if defined( PLATFORM_X360 ) +# define CROSSPLAYPLATFORM_THISPLATFORM CROSSPLAYPLATFORM_X360 +# elif defined( PLATFORM_PS3 ) +# define CROSSPLAYPLATFORM_THISPLATFORM CROSSPLAYPLATFORM_PS3 +# else +#pragma message( "Unknown console, please update this platform definition" ) +# define CROSSPLAYPLATFORM_THISPLATFORM CROSSPLAYPLATFORM_UNKNOWN +# endif +#else +# define CROSSPLAYPLATFORM_THISPLATFORM CROSSPLAYPLATFORM_PC +#endif + +struct HltvReplayParams_t +{ + HltvReplayParams_t() + { + m_nPrimaryTargetEntIndex = 0; + m_flPlaybackSpeed = 1.0f; + m_flDelay = 10.0f; + m_flStopAt = 0.0f; + m_flSlowdownBeginAt = 0; + m_flSlowdownEndAt = 0; + m_flSlowdownRate = 1.0f; + m_bAbortCurrentReplay = false; + } + int m_nPrimaryTargetEntIndex; + float m_flDelay; + float m_flStopAt; + float m_flPlaybackSpeed; + float m_flSlowdownBeginAt; + float m_flSlowdownEndAt; + float m_flSlowdownRate; + bool m_bAbortCurrentReplay; +}; + +abstract_class IClient : public INetChannelHandler +{ +public: + virtual ~IClient() {} + + virtual void Connect(const char* szName, int nUserID, INetChannel * pNetChannel, bool bFakePlayer, CrossPlayPlatform_t clientPlatform, const CMsg_CVars * pVecCvars = NULL) = 0; + + virtual void Inactivate(void) = 0; + + virtual void Reconnect(void) = 0; + + virtual void Disconnect(const char* reason) = 0; + + virtual bool ChangeSplitscreenUser(int nSplitScreenUserSlot) = 0; + + virtual int GetPlayerSlot() const = 0; + virtual int GetUserID() const = 0; + virtual const USERID_t GetNetworkID() const = 0; + virtual const char* GetClientName() const = 0; + virtual INetChannel* GetNetChannel() = 0; + virtual IServer* GetServer() = 0; + virtual const char* GetUserSetting(const char* cvar) const = 0; + virtual const char* GetNetworkIDString() const = 0; + + virtual void SetRate(int nRate, bool bForce) = 0; + virtual int GetRate(void) const = 0; + + virtual void SetUpdateRate(float fUpdateRate, bool bForce) = 0; + virtual float GetUpdateRate(void) const = 0; + + virtual void Clear(void) = 0; + + virtual int GetMaxAckTickCount() const = 0; + + virtual bool ExecuteStringCommand(const char* s) = 0; + virtual bool SendNetMsg(INetMessage& msg, bool bForceReliable = false, bool bVoice = false) = 0; + virtual void ClientPrintf(const char* fmt, ...) = 0; + +virtual bool IsConnected(void) const = 0; +virtual bool IsSpawned(void) const = 0; +virtual bool IsActive(void) const = 0; +virtual bool IsFakeClient(void) const = 0; +virtual bool IsHLTV(void) const = 0; +#if defined( REPLAY_ENABLED ) +virtual bool IsReplay(void) const = 0; +#endif +virtual bool IsHearingClient(int index) const = 0; +virtual bool IsProximityHearingClient(int index) const = 0; + +virtual void SetMaxRoutablePayloadSize(int nMaxRoutablePayloadSize) = 0; + +virtual bool IsSplitScreenUser(void) const = 0; + +virtual bool CheckConnect(void) = 0; + +virtual bool IsLowViolenceClient(void) const = 0; + +virtual IClient* GetSplitScreenOwner() = 0; + +virtual int GetNumPlayers() = 0; + +virtual bool IsHumanPlayer() const = 0; + +virtual CrossPlayPlatform_t GetClientPlatform() const = 0; + +virtual bool StartHltvReplay(const HltvReplayParams_t& params) = 0; +virtual void StopHltvReplay() = 0; +virtual int GetHltvReplayDelay() = 0; +virtual const char* GetHltvReplayStatus()const { return ""; } +virtual bool CanStartHltvReplay() = 0; +virtual void ResetReplayRequestTime() = 0; +}; + +#endif + +``` + +`SpyCustom/sdk/icliententity.h`: + +```h +#ifndef ICLIENTENTITY_H +#define ICLIENTENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iclientrenderable.h" +#include "iclientnetworkable.h" +#include "iclientthinkable.h" +#include "string_t.h" + + + +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +class CMouthInfo; +class IClientEntityInternal; +struct SpatializationInfo_t; + + + +abstract_class IClientEntity : public IClientUnknown, public IClientRenderable, public IClientNetworkable, public IClientThinkable +{ +public: + + + virtual void Release(void) = 0; + virtual void Unknown000(void) = 0; + Vector& GetAbsOrigin() + { + typedef Vector& (__thiscall* GetAbsOriginFn)(void*); + return getvfunc(this, 10)(this); + } + + Vector& GetAbsAngles(void) + { + typedef Vector& (__thiscall* GetAbsAnglesFn)(void*); + return getvfunc(this, 11)(this); + } + + const void SetModelIndex(int index) + { + typedef void (__thiscall* SetModelIndexFn)(void*, int); + return getvfunc(this, 75)(this, index); + } + + void preDataUpdate(int updateType) + { + typedef void(__thiscall* SetModelIndexFn)(void*, int); + return getvfunc(this, 2)(this + sizeof(uintptr_t) * 2, updateType); + } + + Vector GetViewPos() + { + static auto EyePosition = reinterpret_cast( + FindPatternV2("client.dll", "55 8B EC 56 8B 75 08 57 8B F9 56 8B 07 FF 90") + ); + + Vector output; + EyePosition(this, &output); + return output; + } + + virtual CMouthInfo* GetMouth(void) = 0; + + virtual bool GetSoundSpatialization(SpatializationInfo_t& info) = 0; + + virtual bool IsBlurred(void) = 0; +#if 0 + virtual string_t GetModelName(void) const = 0; +#endif + + int GetIndex() + { + return *(int*)((uintptr_t)this + 0x64); + } + + +}; + + +#endif + +``` + +`SpyCustom/sdk/icliententityinternal.h`: + +```h +#ifndef ICLIENTENTITYINTERNAL_H +#define ICLIENTENTITYINTERNAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "icliententity.h" +#include "clientleafsystem.h" + +class ClientClass; + + +typedef CBaseHandle ClientEntityHandle_t; +typedef unsigned short SpatialPartitionHandle_t; + + + +#endif +``` + +`SpyCustom/sdk/icliententitylist.h`: + +```h +#if !defined( ICLIENTENTITYLIST_H ) +#define ICLIENTENTITYLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +class IClientEntity; +class ClientClass; +class IClientNetworkable; +class CBaseHandle; +class IClientUnknown; + + +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; +}; + +#define VCLIENTENTITYLIST_INTERFACE_VERSION "VClientEntityList003" + +#endif +``` + +`SpyCustom/sdk/iclientmode.h`: + +```h +#ifndef ICLIENTMODE_H +#define ICLIENTMODE_H + +#include "VGUI.h" +#include "client_virtualreality.h" + +class CViewSetup; +class C_BaseEntity; +class C_BasePlayer; +class CUserCmd; + +namespace vgui +{ + class Panel; + class AnimationController; +} + +enum +{ + MM_NONE = 0, + MM_SAY, + MM_SAY_TEAM, +}; + +abstract_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 vgui::Panel* GetViewport() = 0; + + virtual vgui::AnimationController* GetViewportAnimationController() = 0; + + virtual void ProcessInput(bool bActive) = 0; + + virtual bool ShouldDrawDetailObjects() = 0; + virtual bool ShouldDrawEntity(C_BaseEntity* pEnt) = 0; + virtual bool ShouldDrawLocalPlayer(C_BasePlayer* 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 vgui::Panel* GetMessagePanel() = 0; + virtual void OverrideMouseInput(float* x, float* y) = 0; + virtual bool CreateMove(float flInputSampleTime, CUserCmd* cmd) = 0; + + virtual void LevelInit(const char* newmap) = 0; + virtual void LevelShutdown(void) = 0; + + 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(vgui::Panel* pPanel) = 0; + virtual void DeactivateInGameVGuiContext() = 0; + virtual float GetViewModelFOV(void) = 0; + + virtual bool CanRecordDemo(char* errorMsg, int length) const = 0; + + virtual void ComputeVguiResConditions(KeyValues* pkvConditions) = 0; + + 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; + + public: + + 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; +}; + +extern IClientMode* g_pClientMode; + +#endif +``` + +`SpyCustom/sdk/iclientnetworkable.h`: + +```h +#ifndef ICLIENTNETWORKABLE_H +#define ICLIENTNETWORKABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iclientunknown.h" +#include "bitbuf.h" + + +class IClientEntity; +class ClientClass; + + +enum ShouldTransmitState_t +{ + SHOULDTRANSMIT_START = 0, + + SHOULDTRANSMIT_END +}; + +enum DataUpdateType_t +{ + DATA_UPDATE_CREATED = 0, +DATA_UPDATE_DATATABLE_CHANGED, +}; + +abstract_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 void __unkn(void) = 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; +}; + + +#endif +``` + +`SpyCustom/sdk/iclientrenderable.h`: + +```h +#ifndef ICLIENTRENDERABLE_H +#define ICLIENTRENDERABLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib.h" +#include "interface.h" +#include "iclientunknown.h" +#include "client_render_handle.h" +#include "ivmodelrender.h" + +struct model_t; +struct matrix3x4_t; + +extern void DefaultRenderBoundsWorldspace(IClientRenderable* pRenderable, Vector& absMins, Vector& absMaxs); + +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, +}; + + +abstract_class IPVSNotify +{ +public: + virtual void OnPVSStatusChanged(bool bInPVS) = 0; +}; + +struct RenderableInstance_t +{ + uint8 m_nAlpha; +}; + +abstract_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_t* pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime) = 0; + + virtual void SetupWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights) = 0; + virtual void DoAnimationEvents(void) = 0; + + 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_t& 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_t& 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; +}; + + +abstract_class CDefaultClientRenderable : public IClientUnknown, public IClientRenderable +{ +public: + CDefaultClientRenderable() + { + m_hRenderHandle = INVALID_CLIENT_RENDER_HANDLE; + } + + virtual const Vector & GetRenderOrigin(void) = 0; + virtual const QAngle& GetRenderAngles(void) = 0; + virtual const matrix3x4_t& RenderableToWorldTransform() = 0; + virtual bool ShouldDraw(void) = 0; + virtual void OnThreadedDrawSetup() {} + virtual int GetRenderFlags(void) { return 0; } + virtual ClientShadowHandle_t GetShadowHandle() const + { + return CLIENTSHADOW_INVALID_HANDLE; + } + + virtual ClientRenderHandle_t& RenderHandle() + { + return m_hRenderHandle; + } + + virtual int GetBody() { return 0; } + virtual int GetSkin() { return 0; } + virtual bool UsesFlexDelayedWeights() { return false; } + + virtual const model_t* GetModel() const { return NULL; } + virtual int DrawModel(int flags) { return 0; } + virtual bool LODTest() { return true; } + virtual bool SetupBones(matrix3x4_t* pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime) { return true; } + virtual void SetupWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights) {} + virtual void DoAnimationEvents(void) {} + virtual IPVSNotify* GetPVSNotifyInterface() { return NULL; } + virtual void GetRenderBoundsWorldspace(Vector& absMins, Vector& absMaxs) { DefaultRenderBoundsWorldspace(this, absMins, absMaxs); } + + virtual void GetColorModulation(float* color) + { + Assert(color); + color[0] = color[1] = color[2] = 1.0f; + } + + virtual bool ShouldReceiveProjectedTextures(int flags) + { + return false; + } + + virtual bool GetShadowCastDistance(float* pDist, ShadowType_t shadowType) const { return false; } + virtual bool GetShadowCastDirection(Vector* pDirection, ShadowType_t shadowType) const { return false; } + + virtual void GetShadowRenderBounds(Vector& mins, Vector& maxs, ShadowType_t shadowType) + { + GetRenderBounds(mins, maxs); + } + + virtual bool IsShadowDirty() { return false; } + virtual void MarkShadowDirty(bool bDirty) {} + virtual IClientRenderable* GetShadowParent() { return NULL; } + virtual IClientRenderable* FirstShadowChild() { return NULL; } + virtual IClientRenderable* NextShadowPeer() { return NULL; } + virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } + virtual void CreateModelInstance() {} + virtual ModelInstanceHandle_t GetModelInstance() { return MODEL_INSTANCE_INVALID; } + + virtual int LookupAttachment(const char* pAttachmentName) { return -1; } + virtual bool GetAttachment(int number, Vector& origin, QAngle& angles) { return false; } + virtual bool GetAttachment(int number, matrix3x4_t& matrix) { return false; } + virtual bool ComputeLightingOrigin(int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t& matrix, Vector& transformedLightingCenter) { return false; } + + virtual float* GetRenderClipPlane() { return NULL; } + + virtual void RecordToolMessage() {} + virtual bool ShouldDrawForSplitScreenUser(int nSlot) { return true; } + virtual uint8 OverrideAlphaModulation(uint8 nAlpha) { return nAlpha; } + virtual uint8 OverrideShadowAlphaModulation(uint8 nAlpha) { return nAlpha; } + virtual void* GetClientModelRenderable() { return 0; } + + public: + virtual void SetRefEHandle(const CBaseHandle& handle) { Assert(false); } + virtual const CBaseHandle& GetRefEHandle() const { Assert(false); return *((CBaseHandle*)0); } + + virtual IClientUnknown* GetIClientUnknown() { return this; } + virtual ICollideable* GetCollideable() { return 0; } + virtual IClientRenderable* GetClientRenderable() { return this; } + virtual IClientNetworkable* GetClientNetworkable() { return 0; } + virtual IClientEntity* GetIClientEntity() { return 0; } + virtual C_BaseEntity* GetBaseEntity() { return 0; } + virtual IClientThinkable* GetClientThinkable() { return 0; } + virtual void* GetClientAlphaProperty() { return 0; } + + + public: + ClientRenderHandle_t m_hRenderHandle; +}; + + +#endif +``` + +`SpyCustom/sdk/iclientshadowmgr.h`: + +```h +#ifndef ICLIENTSHADOWMGR_H +#define ICLIENTSHADOWMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "igamesystem.h" +#include "icliententityinternal.h" +#include "ishadowmgr.h" +#include "ivrenderview.h" +#include "itoolentity.h" + +#include "IGameSystem.h" + +struct FlashlightState_t; + + +enum ShadowReceiver_t +{ + SHADOW_RECEIVER_BRUSH_MODEL = 0, + SHADOW_RECEIVER_STATIC_PROP, + SHADOW_RECEIVER_STUDIO_MODEL, +}; + + +class IClientShadowMgr : public IGameSystemPerFrame +{ +public: + virtual ClientShadowHandle_t CreateShadow(ClientEntityHandle_t entity, int nEntIndex, int flags, void* pSplitScreenBits = 0) = 0; + virtual void DestroyShadow(ClientShadowHandle_t handle) = 0; + + virtual ClientShadowHandle_t CreateFlashlight(const FlashlightState_t& lightState) = 0; + virtual void UpdateFlashlightState(ClientShadowHandle_t shadowHandle, const FlashlightState_t& lightState) = 0; + virtual void DestroyFlashlight(ClientShadowHandle_t handle) = 0; + + virtual ClientShadowHandle_t CreateProjection(const FlashlightState_t& lightState) = 0; + virtual void UpdateProjectionState(ClientShadowHandle_t shadowHandle, const FlashlightState_t& lightState) = 0; + virtual void DestroyProjection(ClientShadowHandle_t handle) = 0; + + virtual void UpdateProjectedTexture(ClientShadowHandle_t handle, bool force = false) = 0; + + virtual void AddToDirtyShadowList(ClientShadowHandle_t handle, bool force = false) = 0; + virtual void AddToDirtyShadowList(IClientRenderable* pRenderable, bool force = false) = 0; + + virtual void AddShadowToReceiver(ClientShadowHandle_t handle, + IClientRenderable* pRenderable, ShadowReceiver_t type) = 0; + + virtual void RemoveAllShadowsFromReceiver( + IClientRenderable* pRenderable, ShadowReceiver_t type) = 0; + + virtual void ComputeShadowTextures(const CViewSetup& view, int leafCount, WorldListLeafData_t* pLeafList) = 0; + + virtual void UnlockAllShadowDepthTextures() = 0; + + virtual void RenderShadowTexture(int w, int h) = 0; + + virtual void SetShadowDirection(const Vector& dir) = 0; + virtual const Vector& GetShadowDirection() const = 0; + + virtual void SetShadowColor(unsigned char r, unsigned char g, unsigned char b) = 0; + virtual void SetShadowDistance(float flMaxDistance) = 0; + virtual void SetShadowBlobbyCutoffArea(float flMinArea) = 0; + virtual void SetFalloffBias(ClientShadowHandle_t handle, unsigned char ucBias) = 0; + + virtual void MarkRenderToTextureShadowDirty(ClientShadowHandle_t handle) = 0; + + virtual void AdvanceFrame() = 0; + + virtual void SetFlashlightTarget(ClientShadowHandle_t shadowHandle, EHANDLE targetEntity) = 0; + + virtual void SetFlashlightLightWorld(ClientShadowHandle_t shadowHandle, bool bLightWorld) = 0; + + virtual void SetShadowsDisabled(bool bDisabled) = 0; + + virtual void ComputeShadowDepthTextures(const CViewSetup& pView, bool bSetup = false) = 0; + + virtual void DrawVolumetrics(const CViewSetup& view) = 0; + + virtual void SetShadowFromWorldLightsEnabled(bool bEnable) = 0; + + virtual void DrawDeferredShadows(const CViewSetup& view, int leafCount, WorldListLeafData_t* pLeafList) = 0; + + virtual void InitRenderTargets() = 0; + + virtual void ReprojectShadows() = 0; + + virtual void UpdateSplitscreenLocalPlayerShadowSkip() = 0; + + virtual void GetFrustumExtents(ClientShadowHandle_t handle, Vector& vecMin, Vector& vecMax) = 0; + + virtual void ShutdownRenderTargets(void) = 0; +}; + + + +extern IClientShadowMgr* g_pClientShadowMgr; + +#endif +``` + +`SpyCustom/sdk/iclientthinkable.h`: + +```h +#ifndef ICLIENTTHINKABLE_H +#define ICLIENTTHINKABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iclientunknown.h" + + +class CClientThinkHandlePtr; +typedef CClientThinkHandlePtr* ClientThinkHandle_t; + + +abstract_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; +}; + + +#endif + +``` + +`SpyCustom/sdk/iclientunknown.h`: + +```h +#ifndef ICLIENTUNKNOWN_H +#define ICLIENTUNKNOWN_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "platform.h" +#include "ihandleentity.h" + +class IClientNetworkable; +class C_BaseEntity; +class IClientRenderable; +class ICollideable; +class IClientEntity; +class IClientThinkable; + + + +abstract_class IClientUnknown : public IHandleEntity +{ +public: + virtual ICollideable * GetCollideable() = 0; + virtual IClientNetworkable* GetClientNetworkable() = 0; + virtual IClientRenderable* GetClientRenderable() = 0; + virtual IClientEntity* GetIClientEntity() = 0; + virtual C_BaseEntity* GetBaseEntity() = 0; + virtual IClientThinkable* GetClientThinkable() = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/iclientvirtualreality.h`: + +```h +#ifndef ICLIENTVIRTUALREALITY_H +#define ICLIENTVIRTUALREALITY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "refcount.h" +#include "IAppSystem.h" + +#define CLIENTVIRTUALREALITY_INTERFACE_VERSION "ClientVirtualReality001" + + + +abstract_class IClientVirtualReality : public IAppSystem +{ +public: + virtual ~IClientVirtualReality() {} + + 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 void DrawMainMenu() = 0; +}; + + + +extern IClientVirtualReality* g_pClientVR; + + +#endif + +``` + +`SpyCustom/sdk/icommandline.h`: + +```h +#ifndef TIER0_ICOMMANDLINE_H +#define TIER0_ICOMMANDLINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" + + +abstract_class ICommandLine +{ +public: + virtual void CreateCmdLine(const char* commandline) = 0; + virtual void CreateCmdLine(int argc, char** argv) = 0; + virtual const char* GetCmdLine(void) const = 0; + + virtual const char* CheckParm(const char* psz, const char** ppszValue = 0) const = 0; + virtual bool HasParm(const char* psz) const = 0; + virtual void RemoveParm(const char* parm) = 0; + virtual void AppendParm(const char* pszParm, const char* pszValues) = 0; + + virtual const char* ParmValue(const char* psz, const char* pDefaultVal = 0) const = 0; + virtual int ParmValue(const char* psz, int nDefaultVal) const = 0; + virtual float ParmValue(const char* psz, float flDefaultVal) const = 0; + + virtual int ParmCount() const = 0; + virtual int FindParm(const char* psz) const = 0; + virtual const char* GetParm(int nIndex) const = 0; + + virtual void SetParm(int nIndex, char const* pNewParm) = 0; + + virtual const char** GetParms() const = 0; +}; + +PLATFORM_INTERFACE ICommandLine* CommandLine(); + + +PLATFORM_INTERFACE const tchar* Plat_GetCommandLine(); +#ifndef _WIN32 +PLATFORM_INTERFACE void Plat_SetCommandLine(const char* cmdLine); +#endif +PLATFORM_INTERFACE const char* Plat_GetCommandLineA(); + + +#endif + +``` + +`SpyCustom/sdk/iconvar.h`: + +```h +#ifndef ICONVAR_H +#define ICONVAR_H + +#if _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include "platform.h" +#include "strtools.h" + + +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_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD ) + +typedef void (*FnChangeCallback_t)(IConVar* var, const char* pOldValue, float flOldValue); + + +abstract_class IConVar +{ +public: + virtual void SetValue(const char* pValue) = 0; + virtual void SetValue(float flValue) = 0; + virtual void SetValue(int nValue) = 0; + + virtual void SetValue(Color value) = 0; + virtual const char* GetName(void) const = 0; + virtual const char* GetBaseName(void) const = 0; + virtual bool IsFlagSet(int nFlag) const = 0; + virtual int GetSplitScreenPlayerSlot() const = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/icvar.h`: + +```h +#ifndef ICVAR_H +#define ICVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "IAppSystem.h" +#include "iconvar.h" + +class ConCommandBase; +class ConCommand; +class ConVar; +class Color; + + +typedef int CVarDLLIdentifier_t; + + +abstract_class IConsoleDisplayFunc +{ +public: + virtual void ColorPrint(const Color & clr, const char* pMessage) = 0; + virtual void Print(const char* pMessage) = 0; + virtual void DPrint(const char* pMessage) = 0; +}; + + +#define CVAR_QUERY_INTERFACE_VERSION "VCvarQuery001" +abstract_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 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& 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; +}; + +#define CVAR_INTERFACE_VERSION "VEngineCvar004" + + +extern ICvar* g_pCVar; + + +#endif +``` + +`SpyCustom/sdk/idatacache.h`: + +```h +#ifndef IDATACACHE_H +#define IDATACACHE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "dbg.h" +#include "IAppSystem.h" + +class IDataCache; + +#define DATACACHE_INTERFACE_VERSION "VDataCache003" + +typedef uint32 DataCacheClientID_t; + + +FORWARD_DECLARE_HANDLE(memhandle_t); +typedef memhandle_t DataCacheHandle_t; +#define DC_INVALID_HANDLE ((DataCacheHandle_t)0) + +struct DataCacheLimits_t +{ + DataCacheLimits_t(unsigned _nMaxBytes = (unsigned)-1, unsigned _nMaxItems = (unsigned)-1, unsigned _nMinBytes = 0, unsigned _nMinItems = 0) + : nMaxBytes(_nMaxBytes), + nMaxItems(_nMaxItems), + nMinBytes(_nMinBytes), + nMinItems(_nMinItems) + { + } + + unsigned nMaxBytes; + unsigned nMaxItems; + + unsigned nMinBytes; + unsigned nMinItems; +}; + +struct DataCacheStatus_t +{ + unsigned nBytes; + unsigned nItems; + + unsigned nBytesLocked; + unsigned nItemsLocked; + + unsigned nFindRequests; + unsigned nFindHits; +}; + +enum DataCacheOptions_t +{ + DC_TRACE_ACTIVITY = (1 << 0), + DC_FORCE_RELOCATE = (1 << 1), + DC_ALWAYS_MISS = (1 << 2), + DC_VALIDATE = (1 << 3), +}; + + +enum DataCacheReportType_t +{ + DC_SUMMARY_REPORT, + DC_DETAIL_REPORT, + DC_DETAIL_REPORT_LRU, +}; + + +enum DataCacheNotificationType_t +{ + DC_NONE, + + DC_AGE_DISCARD, + + DC_FLUSH_DISCARD, + + DC_REMOVED, + + DC_RELOCATE, + + DC_PRINT_INF0, +}; + +struct DataCacheNotification_t +{ + DataCacheNotificationType_t type; + const char* pszSectionName; + DataCacheClientID_t clientId; + const void* pItemData; + unsigned nItemSize; +}; + +const int DC_MAX_CLIENT_NAME = 15; +const int DC_MAX_ITEM_NAME = 511; + +enum DataCacheRemoveResult_t +{ + DC_OK, + DC_NOT_FOUND, + DC_LOCKED, +}; + +enum DataCacheAddFlags_t +{ + DCAF_LOCK = (1 << 0), + DCAF_DEFAULT = 0, +}; + + + +abstract_class IDataCacheSection +{ +public: + virtual IDataCache * GetSharedCache() = 0; + virtual const char* GetName() = 0; + + virtual void SetLimits(const DataCacheLimits_t& limits) = 0; + virtual void SetOptions(unsigned options) = 0; + + + virtual void GetStatus(DataCacheStatus_t* pStatus, DataCacheLimits_t* pLimits = NULL) = 0; + + + virtual void EnsureCapacity(unsigned nBytes, unsigned nItems = 1) = 0; + + + virtual bool Add(DataCacheClientID_t clientId, const void* pItemData, unsigned size, DataCacheHandle_t* pHandle) = 0; + + virtual DataCacheHandle_t Find(DataCacheClientID_t clientId) = 0; + + + virtual DataCacheRemoveResult_t Remove(DataCacheHandle_t handle, const void** ppItemData, unsigned* pItemSize = NULL, bool bNotify = false) = 0; + DataCacheRemoveResult_t Remove(DataCacheHandle_t handle, bool bNotify = false) { return Remove(handle, NULL, NULL, bNotify); } + + + virtual bool IsPresent(DataCacheHandle_t handle) = 0; + + + virtual void* Lock(DataCacheHandle_t handle) = 0; + + + virtual int Unlock(DataCacheHandle_t handle) = 0; + + + virtual void* Get(DataCacheHandle_t handle, bool bFrameLock = false) = 0; + virtual void* GetNoTouch(DataCacheHandle_t handle, bool bFrameLock = false) = 0; + + virtual int BeginFrameLocking() = 0; + virtual bool IsFrameLocking() = 0; + virtual void* FrameLock(DataCacheHandle_t handle) = 0; + virtual int EndFrameLocking() = 0; + virtual int* GetFrameUnlockCounterPtr() = 0; + + + virtual int GetLockCount(DataCacheHandle_t handle) = 0; + virtual int BreakLock(DataCacheHandle_t handle) = 0; + + + virtual bool Touch(DataCacheHandle_t handle) = 0; + + + virtual bool Age(DataCacheHandle_t handle) = 0; + + + virtual unsigned Flush(bool bUnlockedOnly = true, bool bNotify = true) = 0; + + + virtual unsigned Purge(unsigned nBytes) = 0; + + + virtual void OutputReport(DataCacheReportType_t reportType = DC_SUMMARY_REPORT) = 0; + + virtual void UpdateSize(DataCacheHandle_t handle, unsigned int nNewSize) = 0; + + + virtual void LockMutex() = 0; + virtual void UnlockMutex() = 0; + + virtual bool AddEx(DataCacheClientID_t clientId, const void* pItemData, unsigned size, unsigned flags, DataCacheHandle_t* pHandle) = 0; +}; + + +abstract_class IDataCacheClient +{ +public: + virtual bool HandleCacheNotification(const DataCacheNotification_t & notification) = 0; + + + virtual bool GetItemName(DataCacheClientID_t clientId, const void* pItem, char* pDest, unsigned nMaxLen) = 0; +}; + +class CDefaultDataCacheClient : public IDataCacheClient +{ +public: + virtual bool HandleCacheNotification(const DataCacheNotification_t& notification) + { + switch (notification.type) + { + case DC_AGE_DISCARD: + case DC_FLUSH_DISCARD: + case DC_REMOVED: + default: + Assert(0); + return false; + } + return false; + } + + virtual bool GetItemName(DataCacheClientID_t clientId, const void* pItem, char* pDest, unsigned nMaxLen) + { + return false; + } +}; + + +abstract_class IDataCache : public IAppSystem +{ +public: + virtual void SetSize(int nMaxBytes) = 0; + virtual void SetOptions(unsigned options) = 0; + virtual void SetSectionLimits(const char* pszSectionName, const DataCacheLimits_t& limits) = 0; + + + virtual void GetStatus(DataCacheStatus_t* pStatus, DataCacheLimits_t* pLimits = NULL) = 0; + + + virtual IDataCacheSection* AddSection(IDataCacheClient* pClient, const char* pszSectionName, const DataCacheLimits_t& limits = DataCacheLimits_t(), bool bSupportFastFind = false) = 0; + + + virtual void RemoveSection(const char* pszClientName, bool bCallFlush = true) = 0; + void RemoveSection(IDataCacheSection* pSection, bool bCallFlush = true) { if (pSection) RemoveSection(pSection->GetName()); } + + + virtual IDataCacheSection* FindSection(const char* pszClientName) = 0; + + + virtual unsigned Purge(unsigned nBytes) = 0; + + + virtual unsigned Flush(bool bUnlockedOnly = true, bool bNotify = true) = 0; + + + virtual void OutputReport(DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char* pszSection = NULL) = 0; +}; + +template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE* > +class CManagedDataCacheClient : public CDefaultDataCacheClient +{ +public: + typedef CManagedDataCacheClient CCacheClientBaseClass; + + CManagedDataCacheClient() + : m_pCache(NULL) + { + } + + void Init(IDataCache* pSharedCache, const char* pszSectionName, const DataCacheLimits_t& limits = DataCacheLimits_t(), bool bSupportFastFind = false) + { + if (!m_pCache) + { + m_pCache = pSharedCache->AddSection(this, pszSectionName, limits, bSupportFastFind); + } + } + + void Shutdown() + { + if (m_pCache) + { + m_pCache->GetSharedCache()->RemoveSection(m_pCache); + m_pCache = NULL; + } + } + + LOCK_TYPE CacheGet(DataCacheHandle_t handle, bool bFrameLock = true) + { + return (LOCK_TYPE)(((STORAGE_TYPE*)m_pCache->Get(handle, bFrameLock))->GetData()); + } + + LOCK_TYPE CacheGetNoTouch(DataCacheHandle_t handle) + { + return (LOCK_TYPE)(((STORAGE_TYPE*)m_pCache->GetNoTouch(handle))->GetData()); + } + + LOCK_TYPE CacheLock(DataCacheHandle_t handle) + { + return (LOCK_TYPE)(((STORAGE_TYPE*)m_pCache->Lock(handle))->GetData()); + } + + int CacheUnlock(DataCacheHandle_t handle) + { + return m_pCache->Unlock(handle); + } + + void CacheTouch(DataCacheHandle_t handle) + { + m_pCache->Touch(handle); + } + + void CacheRemove(DataCacheHandle_t handle, bool bNotify = true) + { + m_pCache->Remove(handle, bNotify); + } + + void CacheFlush() + { + m_pCache->Flush(); + } + + DataCacheHandle_t CacheCreate(const CREATE_PARAMS& createParams, unsigned flags = DCAF_DEFAULT) + { + m_pCache->EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); + STORAGE_TYPE* pStore = STORAGE_TYPE::CreateResource(createParams); + DataCacheHandle_t handle; + m_pCache->AddEx((DataCacheClientID_t)pStore, pStore, pStore->Size(), flags, &handle); + return handle; + } + + void CacheLockMutex() + { + m_pCache->LockMutex(); + } + + void CacheUnlockMutex() + { + m_pCache->UnlockMutex(); + } + + bool HandleCacheNotification(const DataCacheNotification_t& notification) + { + switch (notification.type) + { + case DC_AGE_DISCARD: + case DC_FLUSH_DISCARD: + case DC_REMOVED: + { + STORAGE_TYPE* p = (STORAGE_TYPE*)notification.clientId; + p->DestroyResource(); + } + return true; + default: + return CDefaultDataCacheClient::HandleCacheNotification(notification); + } + } + + +protected: + + ~CManagedDataCacheClient() + { + Shutdown(); + } + + IDataCacheSection* GetCacheSection() + { + return m_pCache; + } + +private: + IDataCacheSection* m_pCache; + +}; + +#endif +``` + +`SpyCustom/sdk/iefx.h`: + +```h +#if !defined( IEFX_H ) +#define IEFX_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "vector.h" +#include "dlight.h" + +struct model_t; +struct dlight_t; +class IMaterial; + +#define MAX_DLIGHTS 32 + +abstract_class IVEfx +{ +public: + virtual int Draw_DecalIndexFromName(char* name) = 0; + + virtual void DecalShoot(int textureIndex, int entity, + const model_t* model, const Vector& model_origin, const QAngle& model_angles, + const Vector& position, const Vector* saxis, int flags) = 0; + + virtual void DecalColorShoot(int textureIndex, int entity, + const model_t* model, const Vector& model_origin, const QAngle& model_angles, + const Vector& position, const Vector* saxis, int flags, const color32& rgbaColor) = 0; + + virtual void PlayerDecalShoot(IMaterial* material, void* userdata, int entity, const model_t* model, + const Vector& model_origin, const Vector& model_angles, + const Vector& position, const Vector* saxis, int flags, const color32& rgbaColor) = 0; + + virtual dlight_t* CL_AllocDlight(int key) = 0; + + virtual dlight_t* CL_AllocElight(int key) = 0; + + virtual int CL_GetActiveDLights(dlight_t* pList[MAX_DLIGHTS]) = 0; + + virtual const char* Draw_DecalNameFromIndex(int nIndex) = 0; + + virtual dlight_t* GetElightByKey(int key) = 0; +}; + +#define VENGINE_EFFECTS_INTERFACE_VERSION "VEngineEffects001" + +extern IVEfx* effects; + +#endif +``` + +`SpyCustom/sdk/ienginetrace.h`: + +```h +#ifndef ENGINE_IENGINETRACE_H +#define ENGINE_IENGINETRACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basehandle.h" +#include "utlvector.h" +#include "vector4d.h" + +#include "bspflags.h" + +class Vector; +class IHandleEntity; +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +class ICollideable; +class QAngle; +class CTraceListData; +class CPhysCollide; +struct cplane_t; + +enum TraceType_t +{ + TRACE_EVERYTHING = 0, + TRACE_WORLD_ONLY, + TRACE_ENTITIES_ONLY, + TRACE_EVERYTHING_FILTER_PROPS, +}; + +abstract_class ITraceFilter +{ +public: + virtual bool ShouldHitEntity(IHandleEntity * pEntity, int contentsMask) = 0; + virtual TraceType_t GetTraceType() const = 0; +}; + +#include +class CTraceFilter : public ITraceFilter +{ + using FilterCallbackFn = std::function; +public: + + CTraceFilter(const IHandleEntity* pSkipEntity, TraceType_t iTraceType = TRACE_EVERYTHING) + : pSkip((void*)pSkipEntity), iTraceType(iTraceType) { } + + CTraceFilter(FilterCallbackFn&& checkCallback, TraceType_t iTraceType = TRACE_EVERYTHING) + : checkCallback(std::move(checkCallback)), iTraceType(iTraceType) { } + + bool ShouldHitEntity(IHandleEntity* pEntityHandle, int ) + { + return !(pEntityHandle == pSkip); + } + virtual TraceType_t GetTraceType() const + { + return TRACE_EVERYTHING; + } + void* pSkip; + FilterCallbackFn checkCallback = nullptr; + TraceType_t iTraceType = TRACE_EVERYTHING; +}; + +class CTraceFilterEntitiesOnly : public ITraceFilter +{ +public: + virtual TraceType_t GetTraceType() const + { + return TRACE_ENTITIES_ONLY; + } +}; + + +class CTraceFilterWorldOnly : public ITraceFilter +{ +public: + bool ShouldHitEntity(IHandleEntity* pServerEntity, int contentsMask) + { + return false; + } + virtual TraceType_t GetTraceType() const + { + return TRACE_WORLD_ONLY; + } +}; + +class CTraceFilterWorldAndPropsOnly : public ITraceFilter +{ +public: + bool ShouldHitEntity(IHandleEntity* pServerEntity, int contentsMask) + { + return false; + } + virtual TraceType_t GetTraceType() const + { + return TRACE_EVERYTHING; + } +}; + +class CTraceFilterHitAll : public CTraceFilter +{ +public: + virtual bool ShouldHitEntity(IHandleEntity* pServerEntity, int contentsMask) + { + return true; + } +}; + + +abstract_class IEntityEnumerator +{ +public: + virtual bool EnumEntity(IHandleEntity * pHandleEntity) = 0; +}; + + +#define INTERFACEVERSION_ENGINETRACE_SERVER "EngineTraceServer003" +#define INTERFACEVERSION_ENGINETRACE_CLIENT "EngineTraceClient003" +abstract_class IEngineTrace +{ +public: + virtual int GetPointContents(const Vector& vecAbsPosition, int contentsMask = MASK_ALL, IHandleEntity** ppEntity = nullptr) = 0; + + + virtual int GetPointContents_WorldOnly(const Vector& vecAbsPosition, int contentsMask = MASK_ALL) = 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, CGameTrace* 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; +}; + +#endif +``` + +`SpyCustom/sdk/ifilelist.h`: + +```h +#ifndef IFILELIST_H +#define IFILELIST_H +#ifdef _WIN32 +#endif + + +class IFileList +{ +public: + virtual bool IsFileInList(const char* pFilename) = 0; + virtual void Release() = 0; +}; + + +#endif + +``` + +`SpyCustom/sdk/igameconsole.h`: + +```h +#ifndef IGAMECONSOLE_H +#define IGAMECONSOLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + + +class IGameConsole : public IBaseInterface +{ +public: + virtual void Activate() = 0; + + virtual void Initialize() = 0; + + virtual void Hide() = 0; + + virtual void Clear() = 0; + + virtual bool IsConsoleVisible() = 0; + + virtual void SetParent(int parent) = 0; +}; + +#define GAMECONSOLE_INTERFACE_VERSION "GameConsole004" + +#endif +``` + +`SpyCustom/sdk/igameevents.h`: + +```h +#if !defined( IGAMEEVENTS_H ) +#define IGAMEEVENTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + + +#define INTERFACEVERSION_GAMEEVENTSMANAGER "GAMEEVENTSMANAGER001" +#define INTERFACEVERSION_GAMEEVENTSMANAGER2 "GAMEEVENTSMANAGER002" + +#include "bitbuf.h" +#define NULL 0x0 +#define EVENT_DEBUG_ID_INIT 42 +#define EVENT_DEBUG_ID_SHUTDOWN 13 + + +#define MAX_EVENT_NAME_LENGTH 32 +#define MAX_EVENT_BITS 9 +#define MAX_EVENT_NUMBER (1<oldbuttons; + float m_flForwardMove; + float m_flSideMove; + float m_flUpMove; + + float m_flMaxSpeed; + float m_flClientMaxSpeed; + + // Variables from the player edict (sv_player) or entvars on the client. + // These are copied in here before calling and copied out after calling. + Vector m_vecVelocity; // edict::velocity // Current movement direction. + //Vector m_vecTrailingVelocity; + //float m_flTrailingVelocityTime; + QAngle m_vecAngles; // edict::angles + QAngle m_vecOldAngles; + +// Output only + float m_outStepHeight; // how much you climbed this move + Vector m_outWishVel; // This is where you tried + Vector m_outJumpVel; // This is your jump velocity + + // Movement constraints (radius 0 means no constraint) + Vector m_vecConstraintCenter; + float m_flConstraintRadius; + float m_flConstraintWidth; + float m_flConstraintSpeedFactor; + //bool m_bConstraintPastRadius; ///< If no, do no constraining past Radius. If yes, cap them to SpeedFactor past radius + + float u0[5]; + + void SetAbsOrigin( const Vector &vec ); + const Vector &GetAbsOrigin() const; + +//private: + Vector m_vecAbsOrigin; // edict::origin +}; + +inline const Vector &CMoveData::GetAbsOrigin() const +{ + return m_vecAbsOrigin; +} + +#if !defined( CLIENT_DLL ) && defined( _DEBUG ) +// We only ever want this code path on the server side in a debug build +// and you have to uncomment the code below and rebuild to have the test operate. +//#define PLAYER_GETTING_STUCK_TESTING + +#endif + +#if !defined( PLAYER_GETTING_STUCK_TESTING ) + +// This is implemented with a more exhaustive test in gamemovement.cpp. We check if the origin being requested is +// inside solid, which it never should be +inline void CMoveData::SetAbsOrigin( const Vector &vec ) +{ + m_vecAbsOrigin = vec; +} + +#endif + + +//----------------------------------------------------------------------------- +// Purpose: The basic player movement interface +//----------------------------------------------------------------------------- + +abstract_class IGameMovement +{ +public: + virtual ~IGameMovement( void ) {} + + // Process the current movement command + virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ) = 0; + virtual void Reset( void ) = 0; + virtual void StartTrackPredictionErrors( CBasePlayer *pPlayer ) = 0; + virtual void FinishTrackPredictionErrors( CBasePlayer *pPlayer ) = 0; + virtual void DiffPrint( PRINTF_FORMAT_STRING char const *fmt, ... ) = 0; + + // Allows other parts of the engine to find out the normal and ducked player bbox sizes + virtual Vector const& GetPlayerMins( bool ducked ) const = 0; + virtual Vector const& GetPlayerMaxs( bool ducked ) const = 0; + virtual Vector const& GetPlayerViewOffset( bool ducked ) const = 0; + + virtual bool IsMovingPlayerStuck( void ) const = 0; + virtual CBasePlayer *GetMovingPlayer( void ) const = 0; + virtual void UnblockPusher( CBasePlayer *pPlayer, CBaseEntity *pPusher ) = 0; + + virtual void SetupMovementBounds( CMoveData *pMove ) = 0; + + void ProcessMovement_v(C_BaseEntity* player, CMoveData* move) { + typedef bool(__thiscall* OriginalFn)(void*, C_BaseEntity*, CMoveData*); + getvfunc(this, 2)(this, player, move); + } + + void StartTrackPredictionErrors_v(C_BaseEntity* player) { + typedef void(__thiscall* OriginalFn)(void*, C_BaseEntity*); + getvfunc(this, 4)(this, player); + } + + void FinishTrackPredictionErrors_v(C_BaseEntity* player) { + typedef void(__thiscall* OriginalFn)(void*, C_BaseEntity*); + getvfunc(this, 5)(this, player); + } + +}; + + +#endif // IGAMEMOVEMENT_H +``` + +`SpyCustom/sdk/igametypes.h`: + +```h +//========= Copyright (c) 1996-2011, Valve Corporation, All rights reserved. ============// +// +// Purpose: Game types and modes +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IGAME_TYPES_H +#define IGAME_TYPES_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utlstring.h" +#include "keyvalues.h" + +abstract_class IGameTypes +{ +public: + struct WeaponProgression + { + WeaponProgression() + : m_Kills(0) + { + } + + CUtlString m_Name; + int m_Kills; + }; + +public: + virtual ~IGameTypes() {} + + // Initialization. "force" will reload the data from file even if this interface has already been initialized. + virtual bool Initialize(bool force = false) = 0; + virtual bool IsInitialized(void) const = 0; + + // + // Game Types and Modes + // + + // Set the game type and mode convars from the given strings. + virtual bool SetGameTypeAndMode(const char* gameType, const char* gameMode) = 0; + virtual bool GetGameTypeAndModeFromAlias(const char* modeAlias, int& iOutGameType, int& iOutGameMode) = 0; + virtual bool SetGameTypeAndMode(int nGameType, int nGameMode) = 0; + virtual void SetAndParseExtendedServerInfo(KeyValues* pExtendedServerInfo) = 0; + virtual void CheckShouldSetDefaultGameModeAndType(const char* szMapNameFull) = 0; + + // Get the indexes for the current game type and mode. + virtual int GetCurrentGameType() const = 0; + virtual int GetCurrentGameMode() const = 0; + + virtual const char* GetCurrentMapName() = 0; + + // Get the current game type and mode UI strings. + virtual const char* GetCurrentGameTypeNameID(void) = 0; + virtual const char* GetCurrentGameModeNameID(void) = 0; + + // Apply the game mode convars for the current game type and mode. + virtual bool ApplyConvarsForCurrentMode(bool isMultiplayer) = 0; + + // Output the values of the convars for the current game mode. + virtual void DisplayConvarsForCurrentMode(void) = 0; + + // Returns the weapon progression for the current game type and mode. + virtual const CUtlVector< WeaponProgression >* GetWeaponProgressionForCurrentModeCT(void) = 0; + virtual const CUtlVector< WeaponProgression >* GetWeaponProgressionForCurrentModeT(void) = 0; + + virtual int GetNoResetVoteThresholdForCurrentModeCT(void) = 0; + virtual int GetNoResetVoteThresholdForCurrentModeT(void) = 0; + + virtual const char* GetGameTypeFromInt(int gameType) = 0; + virtual const char* GetGameModeFromInt(int gameType, int gameMode) = 0; + + virtual bool GetGameModeAndTypeIntsFromStrings(const char* szGameType, const char* szGameMode, int& iOutGameType, int& iOutGameMode) = 0; + virtual bool GetGameModeAndTypeNameIdsFromStrings(const char* szGameType, const char* szGameMode, const char*& szOutGameTypeNameId, const char*& szOutGameModeNameId) = 0; + + + virtual bool CreateOrUpdateWorkshopMapGroup(const char* szName, const CUtlStringList& vecMapNames) = 0; + virtual bool IsWorkshopMapGroup(const char* szMapGroupName) = 0; + + // + // Maps + // + + // Get maps from mapgroup and get mapgroup from type and mode + virtual const char* GetRandomMapGroup(const char* gameType, const char* gameMode) = 0; + virtual const char* GetFirstMap(const char* mapGroup) = 0; + virtual const char* GetRandomMap(const char* mapGroup) = 0; + virtual const char* GetNextMap(const char* mapGroup, const char* mapName) = 0; + + virtual int GetMaxPlayersForTypeAndMode(int iType, int iMode) = 0; + + virtual bool IsValidMapGroupName(const char* mapGroup) = 0; + virtual bool IsValidMapInMapGroup(const char* mapGroup, const char* mapName) = 0; + virtual bool IsValidMapGroupForTypeAndMode(const char* mapGroup, const char* gameType, const char* gameMode) = 0; + + // Apply the convars for the given map. + virtual bool ApplyConvarsForMap(const char* mapName, bool isMultiplayer) = 0; + + // Get specifics about a map. + virtual bool GetMapInfo(const char* mapName, uint32& richPresence) = 0; + + // Returns the available character model names (T or CT) for the given map. + virtual const CUtlStringList* GetTModelsForMap(const char* mapName) = 0; + virtual const CUtlStringList* GetCTModelsForMap(const char* mapName) = 0; + virtual const CUtlStringList* GetHostageModelsForMap(const char* mapName) = 0; + virtual const int GetDefaultGameTypeForMap(const char* mapName) = 0; + virtual const int GetDefaultGameModeForMap(const char* mapName) = 0; + + // Returns the view model arms name (T or CT) for the given map. + virtual const char* GetTViewModelArmsForMap(const char* mapName) = 0; + virtual const char* GetCTViewModelArmsForMap(const char* mapName) = 0; + + // Item requirements for the map + virtual const char* GetRequiredAttrForMap(const char* mapName) = 0; + virtual int GetRequiredAttrValueForMap(const char* mapName) = 0; + virtual const char* GetRequiredAttrRewardForMap(const char* mapName) = 0; + virtual int GetRewardDropListForMap(const char* mapName) = 0; + + // Map group properties + virtual const CUtlStringList* GetMapGroupMapList(const char* mapGroup) = 0; + + virtual bool GetRunMapWithDefaultGametype() = 0; + virtual void SetRunMapWithDefaultGametype(bool bDefaultGametype) = 0; + + virtual bool GetLoadingScreenDataIsCorrect() = 0; + virtual void SetLoadingScreenDataIsCorrect(bool bLoadingScreenDataIsCorrect) = 0; + + // + // Custom Bot Difficulty for Offline games + // + + // Sets the bot difficulty for Offline games. + virtual bool SetCustomBotDifficulty(int botDiff) = 0; + + // Returns the bot difficulty for Offline games. + virtual int GetCustomBotDifficulty(void) = 0; + + virtual int GetCurrentServerNumSlots(void) = 0; + virtual int GetCurrentServerSettingInt(const char* szSetting, int iDefaultValue = 0) = 0; + + virtual bool GetGameTypeFromMode(const char* szGameMode, const char*& pszGameTypeOut) = 0; + + virtual bool LoadMapEntry(KeyValues* pKV) = 0; +}; + +#define VENGINE_GAMETYPES_VERSION "VENGINE_GAMETYPES_VERSION002" + +#endif // IGAME_TYPES_H +``` + +`SpyCustom/sdk/iglobalvarsbase.h`: + +```h +#pragma once + +class IGlobalVarsBase +{ +public: + float realtime; + int framecount; + float absoluteframetime; + float absoluteframestarttimestddev; + float curtime; + float frametime; + int maxClients; + int tickcount; + float interval_per_tick; + float interpolation_amount; + int simTicksThisFrame; + int network_protocol; + void* pSaveData; +private: + bool m_bClient; +public: + bool m_bRemoteClient; +private: + int nTimestampNetworkingBase; + int nTimestampRandomizeWindow; +}; + +``` + +`SpyCustom/sdk/ihandleentity.h`: + +```h +#ifndef IHANDLEENTITY_H +#define IHANDLEENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseHandle; + + +class IHandleEntity +{ +public: + virtual ~IHandleEntity() {} + virtual void SetRefEHandle(const CBaseHandle& handle) = 0; + virtual const CBaseHandle& GetRefEHandle() const = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/iinputsystem.h`: + +```h +#ifndef IINPUTSYSTEM_H +#define IINPUTSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "IAppSystem.h" + +#include "InputEnums.h" +#include "ButtonCode.h" +#include "AnalogCode.h" + +#define INPUTSYSTEM_INTERFACE_VERSION "InputSystemVersion001" +abstract_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 = INVALID_USER_ID) = 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; +}; + + +#endif +``` + +`SpyCustom/sdk/imageformat.h`: + +```h +#ifndef IMAGEFORMAT_H +#define IMAGEFORMAT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include + +enum NormalDecodeMode_t +{ + NORMAL_DECODE_NONE = 0, + NORMAL_DECODE_ATI2N = 1, + NORMAL_DECODE_ATI2N_ALPHA = 2 +}; + +#ifdef _WIN32 +typedef enum _D3DFORMAT D3DFORMAT; +#endif + +#pragma warning(disable : 4514) + +enum ImageFormat +{ + IMAGE_FORMAT_UNKNOWN = -1, + IMAGE_FORMAT_RGBA8888 = 0, + IMAGE_FORMAT_ABGR8888, + IMAGE_FORMAT_RGB888, + IMAGE_FORMAT_BGR888, + IMAGE_FORMAT_RGB565, + IMAGE_FORMAT_I8, + IMAGE_FORMAT_IA88, + IMAGE_FORMAT_P8, + IMAGE_FORMAT_A8, + IMAGE_FORMAT_RGB888_BLUESCREEN, + IMAGE_FORMAT_BGR888_BLUESCREEN, + IMAGE_FORMAT_ARGB8888, + IMAGE_FORMAT_BGRA8888, + IMAGE_FORMAT_DXT1, + IMAGE_FORMAT_DXT3, + IMAGE_FORMAT_DXT5, + IMAGE_FORMAT_BGRX8888, + IMAGE_FORMAT_BGR565, + IMAGE_FORMAT_BGRX5551, + IMAGE_FORMAT_BGRA4444, + IMAGE_FORMAT_DXT1_ONEBITALPHA, + IMAGE_FORMAT_BGRA5551, + IMAGE_FORMAT_UV88, + IMAGE_FORMAT_UVWQ8888, + IMAGE_FORMAT_RGBA16161616F, + IMAGE_FORMAT_RGBA16161616, + IMAGE_FORMAT_UVLX8888, + IMAGE_FORMAT_R32F, + 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, + +#if defined( _X360 ) + IMAGE_FORMAT_X360_DST16, + IMAGE_FORMAT_X360_DST24, + IMAGE_FORMAT_X360_DST24F, + IMAGE_FORMAT_LINEAR_BGRX8888, + IMAGE_FORMAT_LINEAR_RGBA8888, + IMAGE_FORMAT_LINEAR_ABGR8888, + IMAGE_FORMAT_LINEAR_ARGB8888, + IMAGE_FORMAT_LINEAR_BGRA8888, + IMAGE_FORMAT_LINEAR_RGB888, + IMAGE_FORMAT_LINEAR_BGR888, + IMAGE_FORMAT_LINEAR_BGRX5551, + IMAGE_FORMAT_LINEAR_I8, + IMAGE_FORMAT_LINEAR_RGBA16161616, + + IMAGE_FORMAT_LE_BGRX8888, + IMAGE_FORMAT_LE_BGRA8888, +#endif + + NUM_IMAGE_FORMATS +}; + +#if defined( POSIX ) || defined( DX_TO_GL_ABSTRACTION ) +typedef enum _D3DFORMAT +{ + D3DFMT_INDEX16, + D3DFMT_D16, + D3DFMT_D24S8, + D3DFMT_A8R8G8B8, + D3DFMT_A4R4G4B4, + D3DFMT_X8R8G8B8, + D3DFMT_R5G6R5, + D3DFMT_X1R5G5B5, + D3DFMT_A1R5G5B5, + D3DFMT_L8, + D3DFMT_A8L8, + D3DFMT_A, + D3DFMT_DXT1, + D3DFMT_DXT3, + D3DFMT_DXT5, + D3DFMT_V8U8, + D3DFMT_Q8W8V8U8, + D3DFMT_X8L8V8U8, + D3DFMT_A16B16G16R16F, + D3DFMT_A16B16G16R16, + D3DFMT_R32F, + D3DFMT_A32B32G32R32F, + D3DFMT_R8G8B8, + D3DFMT_D24X4S4, + D3DFMT_A8, + D3DFMT_R5G6B5, + D3DFMT_D15S1, + D3DFMT_D24X8, + D3DFMT_VERTEXDATA, + D3DFMT_INDEX32, + + D3DFMT_NV_INTZ = 0x5a544e49, + D3DFMT_NV_RAWZ = 0x5a574152, + + D3DFMT_NV_NULL = 0x4c4c554e, + + D3DFMT_ATI_D16 = 0x36314644, + D3DFMT_ATI_D24S8 = 0x34324644, + + D3DFMT_ATI_2N = 0x32495441, + D3DFMT_ATI_1N = 0x31495441, + + D3DFMT_UNKNOWN +} D3DFORMAT; +#endif + +struct BGRA8888_t +{ + unsigned char b; + unsigned char g; + unsigned char r; + unsigned char a; + inline BGRA8888_t& operator=(const BGRA8888_t& in) + { + *(unsigned int*)this = *(unsigned int*)∈ + return *this; + } +}; + +struct RGBA8888_t +{ + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + inline RGBA8888_t& operator=(const BGRA8888_t& in) + { + r = in.r; + g = in.g; + b = in.b; + a = in.a; + return *this; + } +}; + +struct RGB888_t +{ + unsigned char r; + unsigned char g; + unsigned char b; + inline RGB888_t& operator=(const BGRA8888_t& in) + { + r = in.r; + g = in.g; + b = in.b; + return *this; + } + inline bool operator==(const RGB888_t& in) const + { + return (r == in.r) && (g == in.g) && (b == in.b); + } + inline bool operator!=(const RGB888_t& in) const + { + return (r != in.r) || (g != in.g) || (b != in.b); + } +}; + +struct BGR888_t +{ + unsigned char b; + unsigned char g; + unsigned char r; + inline BGR888_t& operator=(const BGRA8888_t& in) + { + r = in.r; + g = in.g; + b = in.b; + return *this; + } +}; + +#if defined( _X360 ) +#pragma bitfield_order( push, lsb_to_msb ) +#endif +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; + } +}; +#if defined( _X360 ) +#pragma bitfield_order( pop ) +#endif + +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; + } +}; + +#define ARTWORK_GAMMA ( 2.2f ) +#define IMAGE_MAX_DIM ( 2048 ) + + +struct ImageFormatInfo_t +{ + const char* m_pName; + int m_NumBytes; + int m_NumRedBits; + int m_NumGreeBits; + int m_NumBlueBits; + int m_NumAlphaBits; + bool m_IsCompressed; +}; + + +namespace ImageLoader +{ + + bool GetInfo(const char* fileName, int* width, int* height, enum ImageFormat* imageFormat, float* sourceGamma); + int GetMemRequired(int width, int height, int depth, ImageFormat imageFormat, bool mipmap); + int GetMipMapLevelByteOffset(int width, int height, enum ImageFormat imageFormat, int skipMipLevels); + void GetMipMapLevelDimensions(int* width, int* height, int skipMipLevels); + int GetNumMipMapLevels(int width, int height, int depth = 1); + bool Load(unsigned char* imageData, const char* fileName, int width, int height, enum ImageFormat imageFormat, float targetGamma, bool mipmap); + bool Load(unsigned char* imageData, FILE* fp, int width, int height, + enum ImageFormat imageFormat, float targetGamma, bool mipmap); + + bool ConvertImageFormat(const unsigned char* src, enum ImageFormat srcImageFormat, + unsigned char* dst, enum ImageFormat dstImageFormat, + int width, int height, int srcStride = 0, int dstStride = 0); + + void PreConvertSwapImageData(unsigned char* pImageData, int nImageSize, ImageFormat imageFormat, int width = 0, int stride = 0); + void PostConvertSwapImageData(unsigned char* pImageData, int nImageSize, ImageFormat imageFormat, int width = 0, int stride = 0); + void ByteSwapImageData(unsigned char* pImageData, int nImageSize, ImageFormat imageFormat, int width = 0, int stride = 0); + bool IsFormatValidForConversion(ImageFormat fmt); + + ImageFormat D3DFormatToImageFormat(D3DFORMAT format); + D3DFORMAT ImageFormatToD3DFormat(ImageFormat format); + + enum + { + RESAMPLE_NORMALMAP = 0x1, + RESAMPLE_ALPHATEST = 0x2, + RESAMPLE_NICE_FILTER = 0x4, + RESAMPLE_CLAMPS = 0x8, + RESAMPLE_CLAMPT = 0x10, + RESAMPLE_CLAMPU = 0x20, + }; + + struct ResampleInfo_t + { + + ResampleInfo_t() : m_nFlags(0), m_flAlphaThreshhold(0.4f), m_flAlphaHiFreqThreshhold(0.4f), m_nSrcDepth(1), m_nDestDepth(1) + { + m_flColorScale[0] = 1.0f, m_flColorScale[1] = 1.0f, m_flColorScale[2] = 1.0f, m_flColorScale[3] = 1.0f; + m_flColorGoal[0] = 0.0f, m_flColorGoal[1] = 0.0f, m_flColorGoal[2] = 0.0f, m_flColorGoal[3] = 0.0f; + } + + unsigned char* m_pSrc; + unsigned char* m_pDest; + + int m_nSrcWidth; + int m_nSrcHeight; + int m_nSrcDepth; + + int m_nDestWidth; + int m_nDestHeight; + int m_nDestDepth; + + float m_flSrcGamma; + float m_flDestGamma; + + float m_flColorScale[4]; + float m_flColorGoal[4]; + + float m_flAlphaThreshhold; + float m_flAlphaHiFreqThreshhold; + + int m_nFlags; + }; + + bool ResampleRGBA8888(const ResampleInfo_t& info); + bool ResampleRGBA16161616(const ResampleInfo_t& info); + bool ResampleRGB323232F(const ResampleInfo_t& info); + + void ConvertNormalMapRGBA8888ToDUDVMapUVLX8888(const unsigned char* src, int width, int height, + unsigned char* dst_); + void ConvertNormalMapRGBA8888ToDUDVMapUVWQ8888(const unsigned char* src, int width, int height, + unsigned char* dst_); + void ConvertNormalMapRGBA8888ToDUDVMapUV88(const unsigned char* src, int width, int height, + unsigned char* dst_); + + void ConvertIA88ImageToNormalMapRGBA8888(const unsigned char* src, int width, + int height, unsigned char* dst, + float bumpScale); + + void NormalizeNormalMapRGBA8888(unsigned char* src, int numTexels); + + + void GammaCorrectRGBA8888(unsigned char* src, unsigned char* dst, + int width, int height, int depth, float srcGamma, float dstGamma); + + + void ConstructGammaTable(unsigned char* pTable, float srcGamma, float dstGamma); + + + void GammaCorrectRGBA8888(unsigned char* pSrc, unsigned char* pDst, + int width, int height, int depth, unsigned char* pGammaTable); + + + void GenerateMipmapLevels(unsigned char* pSrc, unsigned char* pDst, int width, + int height, int depth, ImageFormat imageFormat, float srcGamma, float dstGamma, + int numLevels = 0); + + + bool RotateImageLeft(const unsigned char* src, unsigned char* dst, + int widthHeight, ImageFormat imageFormat); + bool RotateImage180(const unsigned char* src, unsigned char* dst, + int widthHeight, ImageFormat imageFormat); + bool FlipImageVertically(void* pSrc, void* pDst, int nWidth, int nHeight, ImageFormat imageFormat, int nDstStride = 0); + bool FlipImageHorizontally(void* pSrc, void* pDst, int nWidth, int nHeight, ImageFormat imageFormat, int nDstStride = 0); + bool SwapAxes(unsigned char* src, + int widthHeight, ImageFormat imageFormat); + + + ImageFormatInfo_t const& ImageFormatInfo(ImageFormat fmt); + + + inline char const* GetName(ImageFormat fmt) + { + return ImageFormatInfo(fmt).m_pName; + } + + + inline int SizeInBytes(ImageFormat fmt) + { + return ImageFormatInfo(fmt).m_NumBytes; + } + + inline bool IsTransparent(ImageFormat fmt) + { + return ImageFormatInfo(fmt).m_NumAlphaBits > 0; + } + + + inline bool IsCompressed(ImageFormat fmt) + { + return ImageFormatInfo(fmt).m_IsCompressed; + } + + inline bool HasChannelLargerThan8Bits(ImageFormat fmt) + { + ImageFormatInfo_t info = ImageFormatInfo(fmt); + return (info.m_NumRedBits > 8 || info.m_NumGreeBits > 8 || info.m_NumBlueBits > 8 || info.m_NumAlphaBits > 8); + } + + +} + + +#endif +``` + +`SpyCustom/sdk/imaterial.h`: + +```h +#ifndef IMATERIAL_H +#define IMATERIAL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "imageformat.h" +#include "imaterialsystem.h" + +class IMaterialVar; +class ITexture; +class IMaterialProxy; +class Vector; + +#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) )) + +inline VertexFormat_t VERTEX_TEXCOORD_SIZE(int nIndex, int nNumCoords) +{ + uint64 n64 = nNumCoords; + uint64 nShift = TEX_COORD_SIZE_BIT + (3 * nIndex); + return n64 << nShift; +} + + + +inline int VertexFlags(VertexFormat_t vertexFormat) +{ + return static_cast (vertexFormat & ((1 << (VERTEX_LAST_BIT + 1)) - 1)); +} + +inline int NumBoneWeights(VertexFormat_t vertexFormat) +{ + return static_cast ((vertexFormat >> VERTEX_BONE_WEIGHT_BIT) & 0x7); +} + +inline int UserDataSize(VertexFormat_t vertexFormat) +{ + return static_cast ((vertexFormat >> USER_DATA_SIZE_BIT) & 0x7); +} + +inline int TexCoordSize(int nTexCoordIndex, VertexFormat_t vertexFormat) +{ + return static_cast ((vertexFormat >> (TEX_COORD_SIZE_BIT + 3 * nTexCoordIndex)) & 0x7); +} + +inline bool UsesVertexShader(VertexFormat_t vertexFormat) +{ + return (vertexFormat & VERTEX_FORMAT_VERTEX_SHADER) != 0; +} + +inline VertexCompressionType_t CompressionType(VertexFormat_t vertexFormat) +{ + if (vertexFormat & VERTEX_FORMAT_COMPRESSED) + return VERTEX_COMPRESSION_ON; + else + return VERTEX_COMPRESSION_NONE; +} + + +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 +}; + +inline void Detect_VertexElement_t_Changes(VertexElement_t element) +{ + Assert(VERTEX_ELEMENT_NUMELEMENTS == 48); + switch (element) + { + case VERTEX_ELEMENT_POSITION: Assert(VERTEX_ELEMENT_POSITION == 0); break; + case VERTEX_ELEMENT_NORMAL: Assert(VERTEX_ELEMENT_NORMAL == 1); break; + case VERTEX_ELEMENT_COLOR: Assert(VERTEX_ELEMENT_COLOR == 2); break; + case VERTEX_ELEMENT_SPECULAR: Assert(VERTEX_ELEMENT_SPECULAR == 3); break; + case VERTEX_ELEMENT_TANGENT_S: Assert(VERTEX_ELEMENT_TANGENT_S == 4); break; + case VERTEX_ELEMENT_TANGENT_T: Assert(VERTEX_ELEMENT_TANGENT_T == 5); break; + case VERTEX_ELEMENT_WRINKLE: Assert(VERTEX_ELEMENT_WRINKLE == 6); break; + case VERTEX_ELEMENT_BONEINDEX: Assert(VERTEX_ELEMENT_BONEINDEX == 7); break; + case VERTEX_ELEMENT_BONEWEIGHTS1: Assert(VERTEX_ELEMENT_BONEWEIGHTS1 == 8); break; + case VERTEX_ELEMENT_BONEWEIGHTS2: Assert(VERTEX_ELEMENT_BONEWEIGHTS2 == 9); break; + case VERTEX_ELEMENT_BONEWEIGHTS3: Assert(VERTEX_ELEMENT_BONEWEIGHTS3 == 10); break; + case VERTEX_ELEMENT_BONEWEIGHTS4: Assert(VERTEX_ELEMENT_BONEWEIGHTS4 == 11); break; + case VERTEX_ELEMENT_USERDATA1: Assert(VERTEX_ELEMENT_USERDATA1 == 12); break; + case VERTEX_ELEMENT_USERDATA2: Assert(VERTEX_ELEMENT_USERDATA2 == 13); break; + case VERTEX_ELEMENT_USERDATA3: Assert(VERTEX_ELEMENT_USERDATA3 == 14); break; + case VERTEX_ELEMENT_USERDATA4: Assert(VERTEX_ELEMENT_USERDATA4 == 15); break; + case VERTEX_ELEMENT_TEXCOORD1D_0: Assert(VERTEX_ELEMENT_TEXCOORD1D_0 == 16); break; + case VERTEX_ELEMENT_TEXCOORD1D_1: Assert(VERTEX_ELEMENT_TEXCOORD1D_1 == 17); break; + case VERTEX_ELEMENT_TEXCOORD1D_2: Assert(VERTEX_ELEMENT_TEXCOORD1D_2 == 18); break; + case VERTEX_ELEMENT_TEXCOORD1D_3: Assert(VERTEX_ELEMENT_TEXCOORD1D_3 == 19); break; + case VERTEX_ELEMENT_TEXCOORD1D_4: Assert(VERTEX_ELEMENT_TEXCOORD1D_4 == 20); break; + case VERTEX_ELEMENT_TEXCOORD1D_5: Assert(VERTEX_ELEMENT_TEXCOORD1D_5 == 21); break; + case VERTEX_ELEMENT_TEXCOORD1D_6: Assert(VERTEX_ELEMENT_TEXCOORD1D_6 == 22); break; + case VERTEX_ELEMENT_TEXCOORD1D_7: Assert(VERTEX_ELEMENT_TEXCOORD1D_7 == 23); break; + case VERTEX_ELEMENT_TEXCOORD2D_0: Assert(VERTEX_ELEMENT_TEXCOORD2D_0 == 24); break; + case VERTEX_ELEMENT_TEXCOORD2D_1: Assert(VERTEX_ELEMENT_TEXCOORD2D_1 == 25); break; + case VERTEX_ELEMENT_TEXCOORD2D_2: Assert(VERTEX_ELEMENT_TEXCOORD2D_2 == 26); break; + case VERTEX_ELEMENT_TEXCOORD2D_3: Assert(VERTEX_ELEMENT_TEXCOORD2D_3 == 27); break; + case VERTEX_ELEMENT_TEXCOORD2D_4: Assert(VERTEX_ELEMENT_TEXCOORD2D_4 == 28); break; + case VERTEX_ELEMENT_TEXCOORD2D_5: Assert(VERTEX_ELEMENT_TEXCOORD2D_5 == 29); break; + case VERTEX_ELEMENT_TEXCOORD2D_6: Assert(VERTEX_ELEMENT_TEXCOORD2D_6 == 30); break; + case VERTEX_ELEMENT_TEXCOORD2D_7: Assert(VERTEX_ELEMENT_TEXCOORD2D_7 == 31); break; + case VERTEX_ELEMENT_TEXCOORD3D_0: Assert(VERTEX_ELEMENT_TEXCOORD3D_0 == 32); break; + case VERTEX_ELEMENT_TEXCOORD3D_1: Assert(VERTEX_ELEMENT_TEXCOORD3D_1 == 33); break; + case VERTEX_ELEMENT_TEXCOORD3D_2: Assert(VERTEX_ELEMENT_TEXCOORD3D_2 == 34); break; + case VERTEX_ELEMENT_TEXCOORD3D_3: Assert(VERTEX_ELEMENT_TEXCOORD3D_3 == 35); break; + case VERTEX_ELEMENT_TEXCOORD3D_4: Assert(VERTEX_ELEMENT_TEXCOORD3D_4 == 36); break; + case VERTEX_ELEMENT_TEXCOORD3D_5: Assert(VERTEX_ELEMENT_TEXCOORD3D_5 == 37); break; + case VERTEX_ELEMENT_TEXCOORD3D_6: Assert(VERTEX_ELEMENT_TEXCOORD3D_6 == 38); break; + case VERTEX_ELEMENT_TEXCOORD3D_7: Assert(VERTEX_ELEMENT_TEXCOORD3D_7 == 39); break; + case VERTEX_ELEMENT_TEXCOORD4D_0: Assert(VERTEX_ELEMENT_TEXCOORD4D_0 == 40); break; + case VERTEX_ELEMENT_TEXCOORD4D_1: Assert(VERTEX_ELEMENT_TEXCOORD4D_1 == 41); break; + case VERTEX_ELEMENT_TEXCOORD4D_2: Assert(VERTEX_ELEMENT_TEXCOORD4D_2 == 42); break; + case VERTEX_ELEMENT_TEXCOORD4D_3: Assert(VERTEX_ELEMENT_TEXCOORD4D_3 == 43); break; + case VERTEX_ELEMENT_TEXCOORD4D_4: Assert(VERTEX_ELEMENT_TEXCOORD4D_4 == 44); break; + case VERTEX_ELEMENT_TEXCOORD4D_5: Assert(VERTEX_ELEMENT_TEXCOORD4D_5 == 45); break; + case VERTEX_ELEMENT_TEXCOORD4D_6: Assert(VERTEX_ELEMENT_TEXCOORD4D_6 == 46); break; + case VERTEX_ELEMENT_TEXCOORD4D_7: Assert(VERTEX_ELEMENT_TEXCOORD4D_7 == 47); break; + default: + Assert(0); + break; + } +} + +#define COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 0 +#define COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 1 +#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 + +inline int GetVertexElementSize(VertexElement_t element, VertexCompressionType_t compressionType) +{ + Detect_VertexElement_t_Changes(element); + + if (compressionType == VERTEX_COMPRESSION_ON) + { + switch (element) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + case VERTEX_ELEMENT_NORMAL: + return (2 * sizeof(short)); + case VERTEX_ELEMENT_USERDATA4: + return (2 * sizeof(short)); +#else + case VERTEX_ELEMENT_NORMAL: + return (4 * sizeof(unsigned char)); + case VERTEX_ELEMENT_USERDATA4: + return (0); +#endif + case VERTEX_ELEMENT_BONEWEIGHTS1: + case VERTEX_ELEMENT_BONEWEIGHTS2: + return (2 * sizeof(short)); + default: + break; + } + } + + switch (element) + { + case VERTEX_ELEMENT_POSITION: return (3 * sizeof(float)); + case VERTEX_ELEMENT_NORMAL: return (3 * sizeof(float)); + case VERTEX_ELEMENT_COLOR: return (4 * sizeof(unsigned char)); + case VERTEX_ELEMENT_SPECULAR: return (4 * sizeof(unsigned char)); + case VERTEX_ELEMENT_TANGENT_S: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TANGENT_T: return (3 * sizeof(float)); + case VERTEX_ELEMENT_WRINKLE: return (1 * sizeof(float)); + case VERTEX_ELEMENT_BONEINDEX: return (4 * sizeof(unsigned char)); + case VERTEX_ELEMENT_BONEWEIGHTS1: return (1 * sizeof(float)); + case VERTEX_ELEMENT_BONEWEIGHTS2: return (2 * sizeof(float)); + case VERTEX_ELEMENT_BONEWEIGHTS3: return (3 * sizeof(float)); + case VERTEX_ELEMENT_BONEWEIGHTS4: return (4 * sizeof(float)); + case VERTEX_ELEMENT_USERDATA1: return (1 * sizeof(float)); + case VERTEX_ELEMENT_USERDATA2: return (2 * sizeof(float)); + case VERTEX_ELEMENT_USERDATA3: return (3 * sizeof(float)); + case VERTEX_ELEMENT_USERDATA4: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_0: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_1: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_2: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_3: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_4: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_5: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_6: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD1D_7: return (1 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_0: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_1: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_2: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_3: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_4: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_5: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_6: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD2D_7: return (2 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_0: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_1: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_2: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_3: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_4: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_5: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_6: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD3D_7: return (3 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_0: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_1: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_2: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_3: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_4: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_5: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_6: return (4 * sizeof(float)); + case VERTEX_ELEMENT_TEXCOORD4D_7: return (4 * sizeof(float)); + default: + Assert(0); + return 0; + }; +} + + +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, +}; + + +abstract_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(); +} + +#endif +``` + +`SpyCustom/sdk/imaterialsystem.h`: + +```h +#ifndef IMATERIALSYSTEM_H +#define IMATERIALSYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#define OVERBRIGHT 2.0f +#define OO_OVERBRIGHT ( 1.0f / 2.0f ) +#define GAMMA 2.2f +#define TEXGAMMA 2.2f + +#include "interface.h" +#include "refcount.h" +#include "vector.h" +#include "vector4d.h" +#include "vmatrix.h" +#include "iappsystem.h" +#include "imageformat.h" +#include "texture_group_names.h" +#include "vtf.h" +#include "deformations.h" + +enum HDRType_t +{ + HDR_TYPE_NONE, + HDR_TYPE_INTEGER, + HDR_TYPE_FLOAT, +}; + +#include "imaterialsystemhardwareconfig.h" +#include "IColorCorrection.h" + +#if !defined( _GAMECONSOLE ) +#endif + +#if defined(_PS3) +typedef void* HPS3FONT; +class CPS3FontMetrics; +class CPS3CharMetrics; + +enum GpuDataTransferCache_t +{ + PS3GPU_DATA_TRANSFER_CREATECACHELINK = 0x80000000, + PS3GPU_DATA_TRANSFER_CACHE2REAL = 0x01000000, + PS3GPU_DATA_TRANSFER_REAL2CACHE = 0x02000000, + PS3GPU_DATA_TRANSFER_MASK = 0xFF000000, +}; +#endif + +class IMaterial; +class IMesh; +class IVertexBuffer; +class IIndexBuffer; +struct MaterialSystem_Config_t; +class VMatrix; +struct matrix3x4_t; +class ITexture; +struct MaterialSystemHardwareIdentifier_t; +class KeyValues; +class IShader; +class IVertexTexture; +class IMorph; +class IMatRenderContext; +class ICallQueue; +struct MorphWeight_t; +class IFileList; +struct VertexStreamSpec_t; +struct ShaderStencilState_t; +struct MeshInstanceData_t; +class IClientMaterialSystem; +class CPaintMaterial; +class IPaintmapDataManager; +class IPaintmapTextureManager; +struct GPUMemoryStats; +class ICustomMaterialManager; +class ICompositeTextureGenerator; + +typedef uint64 VertexFormat_t; + +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, +}; + +enum MaterialMatrixMode_t +{ + MATERIAL_VIEW = 0, + MATERIAL_PROJECTION, + + MATERIAL_MATRIX_UNUSED0, + MATERIAL_MATRIX_UNUSED1, + MATERIAL_MATRIX_UNUSED2, + MATERIAL_MATRIX_UNUSED3, + MATERIAL_MATRIX_UNUSED4, + MATERIAL_MATRIX_UNUSED5, + MATERIAL_MATRIX_UNUSED6, + MATERIAL_MATRIX_UNUSED7, + + MATERIAL_MODEL, + + NUM_MATRIX_MODES = MATERIAL_MODEL + 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_SUBD_QUADS_EXTRA, + MATERIAL_SUBD_QUADS_REG, + MATERIAL_INSTANCED_QUADS, + + MATERIAL_HETEROGENOUS +}; + +enum TessellationMode_t +{ + TESSELLATION_MODE_DISABLED = 0, + TESSELLATION_MODE_ACC_PATCHES_EXTRA, + TESSELLATION_MODE_ACC_PATCHES_REG +}; + +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, + MATERIAL_CULLMODE_NONE +}; + +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 +}; + + +#include "lightdesc.h" + +enum +{ + MATERIAL_MAX_LIGHT_COUNT = 4, +}; + +struct MaterialLightingState_t +{ + Vector m_vecAmbientCube[6]; + Vector m_vecLightingOrigin; + int m_nLocalLightCount; + LightDesc_t m_pLocalLightDesc[MATERIAL_MAX_LIGHT_COUNT]; + + MaterialLightingState_t& operator=(const MaterialLightingState_t& src) + { + memcpy(this, &src, sizeof(MaterialLightingState_t) - MATERIAL_MAX_LIGHT_COUNT * sizeof(LightDesc_t)); + size_t byteCount = src.m_nLocalLightCount * sizeof(LightDesc_t); + Assert(byteCount <= sizeof(m_pLocalLightDesc)); + memcpy(m_pLocalLightDesc, &src.m_pLocalLightDesc, byteCount); + return *this; + } +}; + + + +#define CREATERENDERTARGETFLAGS_HDR 0x00000001 +#define CREATERENDERTARGETFLAGS_AUTOMIPMAP 0x00000002 +#define CREATERENDERTARGETFLAGS_UNFILTERABLE_OK 0x00000004 +#define CREATERENDERTARGETFLAGS_NOEDRAM 0x00000008 +#define CREATERENDERTARGETFLAGS_TEMP 0x00000010 +#define CREATERENDERTARGETFLAGS_ALIASCOLORANDDEPTHSURFACES 0x00000020 + + +struct MaterialBatchData_t +{ + IMaterial* m_pMaterial; + matrix3x4_t* m_pModelToWorld; + const ITexture* m_pEnvCubemap; + int m_nLightmapPageId; + MaterialPrimitiveType_t m_nPrimType; + int m_nIndexOffset; + int m_nIndexCount; + int m_nVertexOffsetInBytes; + const IIndexBuffer* m_pIndexBuffer; + const IVertexBuffer* m_pVertexBuffer; +}; + + +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, + MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID = -4, +}; + + +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_nMinDXSupportLevel; + 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 UberlightState_t +{ + UberlightState_t() + { + m_fNearEdge = 2.0f; + m_fFarEdge = 100.0f; + m_fCutOn = 10.0f; + m_fCutOff = 650.0f; + m_fShearx = 0.0f; + m_fSheary = 0.0f; + m_fWidth = 0.3f; + m_fWedge = 0.05f; + m_fHeight = 0.3f; + m_fHedge = 0.05f; + m_fRoundness = 0.8f; + } + + float m_fNearEdge; + float m_fFarEdge; + float m_fCutOn; + float m_fCutOff; + float m_fShearx; + float m_fSheary; + float m_fWidth; + float m_fWedge; + float m_fHeight; + float m_fHedge; + float m_fRoundness; + + IMPLEMENT_OPERATOR_EQUAL(UberlightState_t); +}; + +struct FlashlightState_t +{ + FlashlightState_t() + { + m_bEnableShadows = false; + m_bDrawShadowFrustum = false; + m_flShadowMapResolution = 1024.0f; + m_flShadowFilterSize = 3.0f; + m_flShadowSlopeScaleDepthBias = 16.0f; + m_flShadowDepthBias = 0.0005f; + m_flShadowJitterSeed = 0.0f; + m_flShadowAtten = 0.0f; + m_flAmbientOcclusion = 0.0f; + m_nShadowQuality = 0; + m_bShadowHighRes = false; + + m_bScissor = false; + m_nLeft = -1; + m_nTop = -1; + m_nRight = -1; + m_nBottom = -1; + + m_bUberlight = false; + + m_bVolumetric = false; + m_flNoiseStrength = 0.8f; + m_flFlashlightTime = 0.0f; + m_nNumPlanes = 64; + m_flPlaneOffset = 0.0f; + m_flVolumetricIntensity = 1.0f; + + m_bOrtho = false; + m_fOrthoLeft = -1.0f; + m_fOrthoRight = 1.0f; + m_fOrthoTop = -1.0f; + m_fOrthoBottom = 1.0f; + + m_fBrightnessScale = 1.0f; + m_pSpotlightTexture = NULL; + m_pProjectedMaterial = NULL; + m_bShareBetweenSplitscreenPlayers = false; + } + + Vector m_vecLightOrigin; + Quaternion m_quatOrientation; + float m_NearZ; + float m_FarZ; + float m_fHorizontalFOVDegrees; + float m_fVerticalFOVDegrees; + bool m_bOrtho; + float m_fOrthoLeft; + float m_fOrthoRight; + float m_fOrthoTop; + float m_fOrthoBottom; + float m_fQuadraticAtten; + float m_fLinearAtten; + float m_fConstantAtten; + float m_FarZAtten; + float m_Color[4]; + float m_fBrightnessScale; + ITexture* m_pSpotlightTexture; + IMaterial* m_pProjectedMaterial; + 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; + float m_flAmbientOcclusion; + int m_nShadowQuality; + bool m_bShadowHighRes; + + float m_flProjectionSize; + float m_flProjectionRotation; + + bool m_bUberlight; + UberlightState_t m_uberlightState; + + bool m_bVolumetric; + float m_flNoiseStrength; + float m_flFlashlightTime; + int m_nNumPlanes; + float m_flPlaneOffset; + float m_flVolumetricIntensity; + bool m_bShareBetweenSplitscreenPlayers; + + bool DoScissor() const { return m_bScissor; } + int GetLeft() const { return m_nLeft; } + int GetTop() const { return m_nTop; } + int GetRight() const { return m_nRight; } + int GetBottom() const { return m_nBottom; } + +private: + + friend class CShadowMgr; + + bool m_bScissor; + int m_nLeft; + int m_nTop; + int m_nRight; + int m_nBottom; + + IMPLEMENT_OPERATOR_EQUAL(FlashlightState_t); +}; + +#define MAX_CASCADED_SHADOW_MAPPING_CASCADES (4) + +#define CASCADED_SHADOW_MAPPING_CONSTANT_BUFFER_SIZE (26) + +struct CascadedShadowMappingState_t +{ + uint m_nNumCascades; + bool m_bIsRenderingViewModels; + + Vector4D m_vLightColor; + + Vector m_vLightDir; + float m_flPadding1; + + struct + { + float m_flInvShadowTextureWidth; + float m_flInvShadowTextureHeight; + float m_flHalfInvShadowTextureWidth; + float m_flHalfInvShadowTextureHeight; + } m_TexParams; + + struct + { + float m_flShadowTextureWidth; + float m_flShadowTextureHeight; + float m_flSplitLerpFactorBase; + float m_flSplitLerpFactorInvRange; + } m_TexParams2; + + struct + { + float m_flDistLerpFactorBase; + float m_flDistLerpFactorInvRange; + float m_flUnused0; + float m_flUnused1; + } m_TexParams3; + + VMatrix m_matWorldToShadowTexMatrices[MAX_CASCADED_SHADOW_MAPPING_CASCADES]; + Vector4D m_vCascadeAtlasUVOffsets[MAX_CASCADED_SHADOW_MAPPING_CASCADES]; + + Vector4D m_vCamPosition; +}; + +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, + MATERIAL_RESTORE_RELEASE_MANAGED_RESOURCES = 0x2, +}; + + +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 +}; + + +enum AntiAliasingHintEnum_t +{ + AA_HINT_MESHES, + AA_HINT_TEXT, + AA_HINT_DEBUG_TEXT, + AA_HINT_HEAVY_UI_OVERLAY, + AA_HINT_ALIASING_PUSH, + AA_HINT_ALIASING_POP, + AA_HINT_POSTPROCESS, + AA_HINT_MOVIE, + AA_HINT_MENU +}; + +typedef void (*MaterialBufferReleaseFunc_t)(int nChangeFlags); +typedef void (*MaterialBufferRestoreFunc_t)(int nChangeFlags); +typedef void (*ModeChangeCallbackFunc_t)(void); +typedef void (*EndFrameCleanupFunc_t)(void); +typedef void (*OnLevelShutdownFunc_t)(void* pUserData); +typedef bool (*EndFramePriorToNextContextFunc_t)(void); + +typedef unsigned short MaterialHandle_t; + +DECLARE_POINTER_HANDLE(OcclusionQueryObjectHandle_t); +#define INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ( (OcclusionQueryObjectHandle_t)0 ) + +class IMaterialProxyFactory; +class ITexture; +class IMaterialSystemHardwareConfig; +class CShadowMgr; + +DECLARE_POINTER_HANDLE(MaterialLock_t); + +struct MaterialTextureInfo_t +{ + int iExcludeInformation; +}; + +struct ApplicationPerformanceCountersInfo_t +{ + float msMain; + float msMST; + float msGPU; + float msFlip; + float msTotal; +}; + +struct ApplicationInstantCountersInfo_t +{ + uint m_nCpuActivityMask; + uint m_nDeferredWordsAllocated; +}; + + +struct WorldListIndicesInfo_t +{ + uint m_nTotalIndices; + uint m_nMaxBatchIndices; +}; + +struct AspectRatioInfo_t +{ + bool m_bIsWidescreen; + bool m_bIsHidef; + float m_flFrameBufferAspectRatio; + float m_flPhysicalAspectRatio; + float m_flFrameBuffertoPhysicalScalar; + float m_flPhysicalToFrameBufferScalar; + bool m_bInitialized; + + AspectRatioInfo_t() : + m_bIsWidescreen(false), + m_bIsHidef(false), + m_flFrameBufferAspectRatio(4.0f / 3.0f), + m_flPhysicalAspectRatio(4.0f / 3.0f), + m_flFrameBuffertoPhysicalScalar(1.0f), + m_flPhysicalToFrameBufferScalar(1.0f), + m_bInitialized(false) + { + } +}; + +abstract_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; + #ifdef _CERT + static + #else + virtual + #endif + void OnDebugEvent(const char* pEvent = "") {} + + 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 GetBackBufferDimensions(int& width, int& height) const = 0; + virtual ImageFormat GetBackBufferFormat() const = 0; + virtual const AspectRatioInfo_t& GetAspectRatioInfo() 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 uint32 GetCurrentFrameCount() = 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 AddEndFrameCleanupFunc(EndFrameCleanupFunc_t func) = 0; + virtual void RemoveEndFrameCleanupFunc(EndFrameCleanupFunc_t func) = 0; + + virtual void OnLevelShutdown() = 0; + virtual bool AddOnLevelShutdownFunc(OnLevelShutdownFunc_t func, void* pUserData) = 0; + virtual bool RemoveOnLevelShutdownFunc(OnLevelShutdownFunc_t func, void* pUserData) = 0; + + virtual void OnLevelLoadingComplete() = 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 EnableGBuffers() = 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 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 LoadKeyValuesFromVMTFile(KeyValues& vmtKeyValues, const char* pMaterialName, bool bUsesUNCFilename) = 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 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; + + #if defined( _X360 ) + + virtual ITexture* CreateGamerpicTexture(const char* pTextureName, + const char* pTextureGroupName, + int nFlags) = 0; + + virtual bool UpdateLocalGamerpicTexture(ITexture* pTexture, DWORD userIndex) = 0; + + virtual bool UpdateRemoteGamerpicTexture(ITexture* pTexture, XUID xuid) = 0; + + #endif + + 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 void CleanupLightmaps() = 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 bool IsStereoSupported() = 0; + virtual bool IsStereoActiveThisFrame() const = 0; + virtual void NVStereoUpdate() = 0; + + virtual void ClearBuffers(bool bClearColor, bool bClearDepth, bool bClearStencil = false) = 0; + + #if defined( _X360 ) + virtual void ListUsedMaterials(void) = 0; + virtual HXUIFONT OpenTrueTypeFont(const char* pFontname, int tall, int style) = 0; + virtual void CloseTrueTypeFont(HXUIFONT hFont) = 0; + virtual bool GetTrueTypeFontMetrics(HXUIFONT hFont, wchar_t wchFirst, wchar_t wchLast, XUIFontMetrics* pFontMetrics, XUICharMetrics* pCharMetrics) = 0; + virtual bool GetTrueTypeGlyphs(HXUIFONT hFont, int numChars, wchar_t* pWch, int* pOffsetX, int* pOffsetY, int* pWidth, int* pHeight, unsigned char* pRGBA, int* pRGBAOffset) = 0; + virtual void PersistDisplay() = 0; + virtual void* GetD3DDevice() = 0; + virtual bool OwnGPUResources(bool bEnable) = 0; + #elif defined(_PS3) + virtual void ListUsedMaterials(void) = 0; + virtual HPS3FONT OpenTrueTypeFont(const char* pFontname, int tall, int style) = 0; + virtual void CloseTrueTypeFont(HPS3FONT hFont) = 0; + virtual bool GetTrueTypeFontMetrics(HPS3FONT hFont, int nFallbackTall, wchar_t wchFirst, wchar_t wchLast, CPS3FontMetrics* pFontMetrics, CPS3CharMetrics* pCharMetrics) = 0; + virtual bool GetTrueTypeGlyphs(HPS3FONT hFont, int nFallbackTall, int numChars, wchar_t* pWch, int* pOffsetX, int* pOffsetY, int* pWidth, int* pHeight, unsigned char* pRGBA, int* pRGBAOffset) = 0; + + virtual bool PS3InitFontLibrary(unsigned fontFileCacheSizeInBytes, unsigned maxNumFonts) { return false; }; + virtual void PS3DumpFontLibrary() { return; } + virtual void* PS3GetFontLibPtr() { return NULL; } + #if 0 + struct PS3FontLibraryRAII + { + PS3FontLibraryRAII(IMaterialSystem* imatsys, + unsigned int fontFileCacheSizeInBytes = 256 * 1024, unsigned int maxNumFonts = 64) : m_pmatsys(imatsys) + { + imatsys->PS3InitFontLibrary(fontFileCacheSizeInBytes, maxNumFonts); +} +~PS3FontLibraryRAII() + { +m_pmatsys->PS3DumpFontLibrary(); +} + +IMaterialSystem* m_pmatsys; +}; +#endif + enum VRAMScreenShotInfoColorFormat_t + { + kX8R8G8B8 = 0, kX8B8G8R8 = 1, kR16G16B16X16 = 2 +}; +virtual void TransmitScreenshotToVX() = 0; + +virtual void CompactRsxLocalMemory(char const* szReason) = 0; +virtual void SetFlipPresentFrequency(int nNumVBlanks) = 0; +#endif + + virtual void SpinPresent(uint nFrames) = 0; + + virtual IMatRenderContext* GetRenderContext() = 0; + + virtual void BeginUpdateLightmaps(void) = 0; + virtual void EndUpdateLightmaps(void) = 0; + + virtual MaterialLock_t Lock() = 0; + virtual void Unlock(MaterialLock_t) = 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 = NULL) = 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, bool bUsingWeaponModelCache) = 0; + virtual void UpdateExcludedTextures(void) = 0; + virtual void ClearForceExcludes(void) = 0; + + virtual bool IsInFrame() const = 0; + + virtual void CompactMemory() = 0; + + virtual void GetGPUMemoryStats(GPUMemoryStats& stats) = 0; + + virtual void ReloadFilesInList(IFileList* pFilesToReload) = 0; + + virtual bool GetTextureInformation(char const* szTextureName, MaterialTextureInfo_t& info) const = 0; + + virtual void FinishRenderTargetAllocation(void) = 0; + + virtual void ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly(void) = 0; + virtual bool AllowThreading(bool bAllow, int nServiceThread) = 0; + + virtual bool GetRecommendedVideoConfig(KeyValues* pKeyValues) = 0; + + virtual IClientMaterialSystem* GetClientMaterialSystemInterface() = 0; + + virtual bool CanDownloadTextures() const = 0; + virtual int GetNumLightmapPages() const = 0; + + virtual void RegisterPaintmapDataManager(IPaintmapDataManager* pDataManager) = 0; + virtual void BeginUpdatePaintmaps(void) = 0; + virtual void EndUpdatePaintmaps(void) = 0; + virtual void UpdatePaintmap(int paintmap, BYTE* pPaintData, int numRects, Rect_t* pRects) = 0; + + virtual ITexture* CreateNamedMultiRenderTargetTexture(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 RefreshFrontBufferNonInteractive() = 0; + + virtual uint32 GetFrameTimestamps(ApplicationPerformanceCountersInfo_t& apci, ApplicationInstantCountersInfo_t& aici) = 0; + +#if defined( DX_TO_GL_ABSTRACTION ) && !defined( _GAMECONSOLE ) + virtual void DoStartupShaderPreloading(void) = 0; +#endif + + virtual void AddEndFramePriorToNextContextFunc(EndFramePriorToNextContextFunc_t func) = 0; + virtual void RemoveEndFramePriorToNextContextFunc(EndFramePriorToNextContextFunc_t func) = 0; + + virtual ICustomMaterialManager* GetCustomMaterialManager() = 0; + virtual ICompositeTextureGenerator* GetCompositeTextureGenerator() = 0; +}; + + +abstract_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, ITexture* pRenderTargetTexture = NULL) = 0; + virtual void ReadPixelsAsync(int x, int y, int width, int height, unsigned char* data, ImageFormat dstFormat, ITexture* pRenderTargetTexture = NULL, CThreadEvent* pPixelsReadEvent = NULL) = 0; + virtual void ReadPixelsAsyncGetResult(int x, int y, int width, int height, unsigned char* data, ImageFormat dstFormat, CThreadEvent* pGetResultEvent = NULL) = 0; + + virtual void SetLightingState(const MaterialLightingState_t& state) = 0; + virtual void SetLights(int nCount, const LightDesc_t* pLights) = 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_t const& matrix) = 0; + virtual void MultMatrix(VMatrix const& matrix) = 0; + virtual void MultMatrix(matrix3x4_t const& matrix) = 0; + virtual void MultMatrixLocal(VMatrix const& matrix) = 0; + virtual void MultMatrixLocal(matrix3x4_t const& matrix) = 0; + virtual void GetMatrix(MaterialMatrixMode_t matrixMode, VMatrix* matrix) = 0; + virtual void GetMatrix(MaterialMatrixMode_t matrixMode, matrix3x4_t* matrix) = 0; + virtual void LoadIdentity(void) = 0; + virtual void Ortho(double left, double top, double right, double bottom, double zNear, double zFar) = 0; + virtual void PerspectiveX(double fovx, double aspect, double zNear, double zFar) = 0; + virtual void PickMatrix(int x, int y, int width, int height) = 0; + virtual void Rotate(float angle, float x, float y, float z) = 0; + virtual void Translate(float x, float y, float z) = 0; + virtual void Scale(float x, float y, float z) = 0; + 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 FlipCullMode(void) = 0; + + virtual void BeginGeneratingCSMs() = 0; + virtual void EndGeneratingCSMs() = 0; + virtual void PerpareForCascadeDraw(int cascade, float fShadowSlopeScaleDepthBias, float fShadowDepthBias) = 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, VertexStreamSpec_t* pStreamSpec = 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() = 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 bDepthWriteEnable, bool bDepthTestEnable = true) = 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 bool IsCascadedShadowMapping() const = 0; + virtual void SetCascadedShadowMapping(bool bEnable) = 0; + virtual void SetCascadedShadowMappingState(const CascadedShadowMappingState_t& state, ITexture* pDepthTextureAtlas) = 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 bool IsCullingEnabledForSinglePassFlashlight() const = 0; + virtual void EnableCullingForSinglePassFlashlight(bool bEnable) = 0; + + virtual void ResetOcclusionQueryObject(OcclusionQueryObjectHandle_t) = 0; + + 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* LockRenderData(int nSizeInBytes) = 0; + virtual void UnlockRenderData(void* pData) = 0; + + template< class E > E* LockRenderDataTyped(int nCount, const E* pSrcData = NULL); + + virtual void AddRefRenderData() = 0; + virtual void ReleaseRenderData() = 0; + + virtual bool IsRenderData(const void* pData) const = 0; + + 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_t& 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 SetStencilState(const ShaderStencilState_t& state) = 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(MaterialPrimitiveType_t primType, 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 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 PushScissorRect(const int nLeft, const int nTop, const int nRight, const int nBottom) = 0; + virtual void PopScissorRect() = 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; + +#if defined( _X360 ) + virtual void PushVertexShaderGPRAllocation(int iVertexShaderCount = 64) = 0; + virtual void PopVertexShaderGPRAllocation(void) = 0; + + virtual void FlushHiStencil() = 0; + +#endif + +#if defined( _GAMECONSOLE ) + virtual void BeginConsoleZPass(const WorldListIndicesInfo_t& indicesInfo) = 0; + virtual void BeginConsoleZPass2(int nSlack) = 0; + virtual void EndConsoleZPass() = 0; +#endif + +#if defined( _PS3 ) + virtual void FlushTextureCache() = 0; +#endif + virtual void AntiAliasingHint(int nHint) = 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 SetNonInteractiveLogoTexture(ITexture* pTexture, float flNormalizedX, float flNormalizedY, float flNormalizedW, float flNormalizedH) = 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 FlipCulling(bool bFlipCulling) = 0; + + virtual void SetTextureRenderingParameter(int parm_number, ITexture* pTexture) = 0; + + virtual void EnableSinglePassFlashlightMode(bool bEnable) = 0; + + virtual bool SinglePassFlashlightModeEnabled() const = 0; + + virtual void DrawInstances(int nInstanceCount, const MeshInstanceData_t* pInstance) = 0; + + virtual void OverrideAlphaWriteEnable(bool bOverrideEnable, bool bAlphaWriteEnable) = 0; + virtual void OverrideColorWriteEnable(bool bOverrideEnable, bool bColorWriteEnable) = 0; + + virtual void ClearBuffersObeyStencilEx(bool bClearColor, bool bClearAlpha, bool bClearDepth) = 0; + + virtual int GetSubDBufferWidth() = 0; + virtual float* LockSubDBuffer(int nNumRows) = 0; + virtual void UnlockSubDBuffer() = 0; + + virtual void UpdateGameTime(float flTime) = 0; + + virtual void PrintfVA(char* fmt, va_list vargs) = 0; + virtual void Printf(char* fmt, ...) = 0; + virtual float Knob(char* knobname, float* setvalue = NULL) = 0; + +#if defined( INCLUDE_SCALEFORM ) + virtual void SetScaleformSlotViewport(int slot, int x, int y, int w, int h) = 0; + virtual void RenderScaleformSlot(int slot) = 0; + virtual void ForkRenderScaleformSlot(int slot) = 0; + virtual void JoinRenderScaleformSlot(int slot) = 0; + + virtual void SetScaleformCursorViewport(int x, int y, int w, int h) = 0; + virtual void RenderScaleformCursor() = 0; + + virtual void AdvanceAndRenderScaleformSlot(int slot) = 0; + virtual void AdvanceAndRenderScaleformCursor() = 0; +#endif + + virtual void SetRenderingPaint(bool bEnable) = 0; + + virtual ColorCorrectionHandle_t FindLookup(const char* pName) = 0; +}; + + +template< class E > inline E* IMatRenderContext::LockRenderDataTyped(int nCount, const E* pSrcData) +{ + int nSizeInBytes = nCount * sizeof(E); + E* pDstData = (E*)LockRenderData(nSizeInBytes); + if (pSrcData && pDstData) + { + memcpy(pDstData, pSrcData, nSizeInBytes); + } + return pDstData; +} + + +abstract_class IClientMaterialSystem +{ +public: + virtual unsigned int GetCurrentRecordingEntity() = 0; + virtual void PostToolMessage(unsigned int hEntity, KeyValues* pMsg) = 0; + virtual void SetMaterialProxyData(void* pProxyData) = 0; +}; + +#define VCLIENTMATERIALSYSTEM_INTERFACE_VERSION "VCLIENTMATERIALSYSTEM001" + + +class CMatRenderDataReference +{ +public: + CMatRenderDataReference(); + CMatRenderDataReference(IMatRenderContext* pRenderContext); + ~CMatRenderDataReference(); + void Lock(IMatRenderContext* pRenderContext); + void Release(); + +private: + IMatRenderContext* m_pRenderContext; +}; + + +inline CMatRenderDataReference::CMatRenderDataReference() +{ + m_pRenderContext = NULL; +} + +inline CMatRenderDataReference::CMatRenderDataReference(IMatRenderContext* pRenderContext) +{ + m_pRenderContext = NULL; + Lock(pRenderContext); +} + +inline CMatRenderDataReference::~CMatRenderDataReference() +{ + Release(); +} + +inline void CMatRenderDataReference::Lock(IMatRenderContext* pRenderContext) +{ + if (!m_pRenderContext) + { + m_pRenderContext = pRenderContext; + m_pRenderContext->AddRefRenderData(); + } +} + +inline void CMatRenderDataReference::Release() +{ + if (m_pRenderContext) + { + m_pRenderContext->ReleaseRenderData(); + m_pRenderContext = NULL; + } +} + + +template< typename E > +class CMatRenderData +{ +public: + CMatRenderData(IMatRenderContext* pRenderContext); + CMatRenderData(IMatRenderContext* pRenderContext, int nCount, const E* pSrcData = NULL); + ~CMatRenderData(); + E* Lock(int nCount, const E* pSrcData = NULL); + void Release(); + bool IsValid() const; + const E* Base() const; + E* Base(); + const E& operator[](int i) const; + E& operator[](int i); + +private: + IMatRenderContext* m_pRenderContext; + E* m_pRenderData; + int m_nCount; + bool m_bNeedsUnlock; +}; + +template< typename E > +inline CMatRenderData::CMatRenderData(IMatRenderContext* pRenderContext) +{ + m_pRenderContext = pRenderContext; + m_nCount = 0; + m_pRenderData = 0; + m_bNeedsUnlock = false; +} + +template< typename E > +inline CMatRenderData::CMatRenderData(IMatRenderContext* pRenderContext, int nCount, const E* pSrcData) +{ + m_pRenderContext = pRenderContext; + m_nCount = 0; + m_pRenderData = 0; + m_bNeedsUnlock = false; + Lock(nCount, pSrcData); +} + +template< typename E > +inline CMatRenderData::~CMatRenderData() +{ + Release(); +} + +template< typename E > +inline bool CMatRenderData::IsValid() const +{ + return m_pRenderData != NULL; +} + +template< typename E > +inline E* CMatRenderData::Lock(int nCount, const E* pSrcData) +{ + m_nCount = nCount; + if (pSrcData && m_pRenderContext->IsRenderData(pSrcData)) + { + m_pRenderData = const_cast(pSrcData); + m_pRenderContext->AddRefRenderData(); + m_bNeedsUnlock = false; + return m_pRenderData; + } + m_pRenderData = m_pRenderContext->LockRenderDataTyped(nCount, pSrcData); + m_bNeedsUnlock = true; + return m_pRenderData; +} + +template< typename E > +inline void CMatRenderData::Release() +{ + if (m_pRenderContext && m_pRenderData) + { + if (m_bNeedsUnlock) + { + m_pRenderContext->UnlockRenderData(m_pRenderData); + } + else + { + m_pRenderContext->ReleaseRenderData(); + } + } + m_pRenderData = NULL; + m_nCount = 0; + m_bNeedsUnlock = false; +} + +template< typename E > +inline E* CMatRenderData::Base() +{ + return m_pRenderData; +} + +template< typename E > +inline const E* CMatRenderData::Base() const +{ + return m_pRenderData; +} + +template< typename E > +inline E& CMatRenderData::operator[](int i) +{ + Assert((i >= 0) && (i < m_nCount)); + return m_pRenderData[i]; +} + +template< typename E > +inline const E& CMatRenderData::operator[](int i) const +{ + Assert((i >= 0) && (i < m_nCount)); + return m_pRenderData[i]; +} + + +class CMatRenderContextPtr : public CRefPtr +{ + typedef CRefPtr BaseClass; +public: + CMatRenderContextPtr() {} + CMatRenderContextPtr(IMatRenderContext* pInit) : BaseClass(pInit) { if (BaseClass::m_pObject) BaseClass::m_pObject->BeginRender(); } + CMatRenderContextPtr(IMaterialSystem* pFrom) : BaseClass(pFrom->GetRenderContext()) { if (BaseClass::m_pObject) BaseClass::m_pObject->BeginRender(); } + ~CMatRenderContextPtr() { if (BaseClass::m_pObject) BaseClass::m_pObject->EndRender(); } + + IMatRenderContext* operator=(IMatRenderContext* p) { if (p) p->BeginRender(); return BaseClass::operator=(p); } + + void SafeRelease() { if (BaseClass::m_pObject) BaseClass::m_pObject->EndRender(); BaseClass::SafeRelease(); } + void AssignAddRef(IMatRenderContext* pFrom) { if (BaseClass::m_pObject) BaseClass::m_pObject->EndRender(); BaseClass::AssignAddRef(pFrom); BaseClass::m_pObject->BeginRender(); } + + void GetFrom(IMaterialSystem* pFrom) { AssignAddRef(pFrom->GetRenderContext()); } + + +private: + CMatRenderContextPtr(const CMatRenderContextPtr& from); + void operator=(const CMatRenderContextPtr& from); + +}; + +#define PIX_VALVE_ORANGE 0xFFF5940F + +class PIXEvent +{ +public: + PIXEvent(IMatRenderContext* pRenderContext, const char* szName, unsigned long color = PIX_VALVE_ORANGE) + { + m_pRenderContext = pRenderContext; + Assert(m_pRenderContext); + Assert(szName); + m_pRenderContext->BeginPIXEvent(color, szName); + } + ~PIXEvent() + { + m_pRenderContext->EndPIXEvent(); + } +private: + IMatRenderContext* m_pRenderContext; +}; + + +#if ( defined( _X360 ) && ( defined( PROFILE ) || defined( _DEBUG ) ) ) +#define PIX_ENABLE 1 +#else +#define PIX_ENABLE 0 +#endif + + +#if PIX_ENABLE +# define PIXEVENT PIXEvent _pixEvent +#else +# define PIXEVENT +#endif + +#ifdef MATERIAL_SYSTEM_DEBUG_CALL_QUEUE +#include "tier1/callqueue.h" +#include "tier1/fmtstr.h" +static void DoMatSysQueueMark(IMaterialSystem* pMaterialSystem, const char* psz) +{ + CMatRenderContextPtr pRenderContext(pMaterialSystem); + if (pRenderContext->GetCallQueue()) + pRenderContext->GetCallQueue()->QueueCall(Plat_DebugString, CUtlEnvelope(psz)); +} + +#define MatSysQueueMark( pMaterialSystem, ...) DoMatSysQueueMark( pMaterialSystem, CFmtStr( __VA_ARGS__ ) ) +#else +#define MatSysQueueMark( msg, ...) ((void)0) +#endif + +#ifdef _GAMECONSOLE +#define MS_NO_DYNAMIC_BUFFER_COPY 1 +#endif + +#endif + +``` + +`SpyCustom/sdk/imaterialsystemhardwareconfig.h`: + +```h +#ifndef IMATERIALSYSTEMHARDWARECONFIG_H +#define IMATERIALSYSTEMHARDWARECONFIG_H + +#ifdef _WIN32 +#pragma once +#endif + +#if defined( DX_TO_GL_ABSTRACTION ) +#define IsPlatformOpenGL() true +#else +#define IsPlatformOpenGL() false +#endif + +#include "interface.h" +#include "imageformat.h" +#include "imaterialsystem.h" +FORCEINLINE bool IsOpenGL(void) +{ + return IsPlatformOpenGL(); +} + +enum VertexCompressionType_t +{ + VERTEX_COMPRESSION_INVALID = 0xFFFFFFFF, + + VERTEX_COMPRESSION_NONE = 0, + + VERTEX_COMPRESSION_ON = 1 +}; + + +#ifdef _GAMECONSOLE +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) \ +FORCEINLINE ret_type method const \ +{ \ + return xbox_return_value; \ +} + + +#else +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) \ +virtual ret_type method const = 0; +#endif + +enum ShadowFilterMode_t +{ + SHADOWFILTERMODE_DEFAULT = 0, + + NVIDIA_PCF = 0, + ATI_NO_PCF_FETCH4 = 1, + NVIDIA_PCF_CHEAP = 2, + ATI_NOPCF = 3, + + GAMECONSOLE_NINE_TAP_PCF = 0, + GAMECONSOLE_SINGLE_TAP_PCF = 1, + +#if defined( _GAMECONSOLE ) + SHADOWFILTERMODE_FIRST_CHEAP_MODE = GAMECONSOLE_SINGLE_TAP_PCF, +#else + SHADOWFILTERMODE_FIRST_CHEAP_MODE = NVIDIA_PCF_CHEAP, +#endif +}; + +enum CSMQualityMode_t +{ + CSMQUALITY_VERY_LOW, + CSMQUALITY_LOW, + CSMQUALITY_MEDIUM, + CSMQUALITY_HIGH, + + CSMQUALITY_TOTAL_MODES +}; + +enum CSMShaderMode_t +{ + CSMSHADERMODE_LOW_OR_VERY_LOW = 0, + CSMSHADERMODE_MEDIUM = 1, + CSMSHADERMODE_HIGH = 2, + CSMSHADERMODE_ATIFETCH4 = 3, + + CSMSHADERMODE_TOTAL_MODES +}; + +class IMaterialSystemHardwareConfig +{ +public: + virtual int GetFrameBufferColorDepth() const = 0; + virtual int GetSamplerCount() const = 0; + virtual bool HasSetDeviceGammaRamp() const = 0; + DEFCONFIGMETHOD(bool, SupportsStaticControlFlow(), true); + virtual VertexCompressionType_t SupportsCompressedVertices() const = 0; + virtual int MaximumAnisotropicLevel() const = 0; + virtual int MaxTextureWidth() const = 0; + virtual int MaxTextureHeight() const = 0; + virtual int TextureMemorySize() const = 0; + virtual bool SupportsMipmappedCubemaps() const = 0; + + virtual int NumVertexShaderConstants() const = 0; + virtual int NumPixelShaderConstants() const = 0; + virtual int MaxNumLights() 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 NeedsAAClamp() const = 0; + virtual bool NeedsATICentroidHack() 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 GetVertexSamplerCount() const = 0; + virtual int GetMaxVertexTextureDimension() const = 0; + + virtual int MaxTextureDepth() const = 0; + + virtual HDRType_t GetHDRType() const = 0; + virtual HDRType_t GetHardwareHDRType() const = 0; + + virtual bool SupportsStreamOffset() const = 0; + + virtual int StencilBufferBits() const = 0; + virtual int MaxViewports() const = 0; + + virtual void OverrideStreamOffsetSupport(bool bOverrideEnabled, bool bEnableSupport) = 0; + + virtual ShadowFilterMode_t GetShadowFilterMode(bool bForceLowQualityShadows, bool bPS30) const = 0; + + virtual int NeedsShaderSRGBConversion() const = 0; + + DEFCONFIGMETHOD(bool, UsesSRGBCorrectBlending(), IsX360()); + + virtual bool HasFastVertexTextures() const = 0; + virtual int MaxHWMorphBatchCount() const = 0; + + 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 float GetShadowDepthBias() const = 0; + virtual float GetShadowSlopeScaleDepthBias() const = 0; + + virtual bool PreferZPrepass() const = 0; + + virtual bool SuppressPixelShaderCentroidHackFixup() const = 0; + virtual bool PreferTexturesInHWMemory() const = 0; + virtual bool PreferHardwareSync() const = 0; + virtual bool ActualHasFastVertexTextures() const = 0; + + virtual bool SupportsShadowDepthTextures(void) const = 0; + virtual ImageFormat GetShadowDepthTextureFormat(void) const = 0; + virtual ImageFormat GetHighPrecisionShadowDepthTextureFormat(void) const = 0; + virtual ImageFormat GetNullTextureFormat(void) const = 0; + virtual int GetMinDXSupportLevel() const = 0; + virtual bool IsUnsupported() const = 0; + + virtual float GetLightMapScaleFactor() const = 0; + + virtual bool SupportsCascadedShadowMapping() const = 0; + virtual CSMQualityMode_t GetCSMQuality() const = 0; + virtual bool SupportsBilinearPCFSampling() const = 0; + virtual CSMShaderMode_t GetCSMShaderMode(CSMQualityMode_t nQualityLevel) const = 0; + virtual bool GetCSMAccurateBlending(void) const = 0; + virtual void SetCSMAccurateBlending(bool bEnable) = 0; + + virtual bool SupportsResolveDepth() const = 0; + virtual bool HasFullResolutionDepthTexture() const = 0; + +#if defined ( STDSHADER_DBG_DLL_EXPORT ) || defined( STDSHADER_DX9_DLL_EXPORT ) + inline bool SupportsPixelShaders_2_b() const { return GetDXSupportLevel() >= 92; } + inline bool SupportsPixelShaders_3_0() const { return GetDXSupportLevel() >= 95; } +#endif + + inline bool ShouldAlwaysUseShaderModel2bShaders() const { return IsOpenGL(); } + inline bool PlatformRequiresNonNullPixelShaders() const { return IsOpenGL(); } +}; + +#endif + +``` + +`SpyCustom/sdk/imdlcache.h`: + +```h +#ifndef IMDLCACHE_H +#define IMDLCACHE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "IAppSystem.h" + +struct studiohdr_t; +struct studiohwdata_t; +struct vcollide_t; +struct virtualmodel_t; +struct vertexFileHeader_t; + +namespace OptimizedModel +{ + 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, +}; + +abstract_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 +}; + +#define MDLCACHE_INTERFACE_VERSION "MDLCache004" + +abstract_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; +}; + +#define MDCACHE_FINE_GRAINED 1 + +#if defined(MDCACHE_FINE_GRAINED) +#define MDLCACHE_CRITICAL_SECTION_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache) +#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0)) +#elif defined(MDLCACHE_LEVEL_LOCKED) +#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0)) +#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0)) +#else +#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0)) +#define MDLCACHE_COARSE_LOCK_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache) +#endif +#define MDLCACHE_CRITICAL_SECTION() MDLCACHE_CRITICAL_SECTION_(mdlcache) +#define MDLCACHE_COARSE_LOCK() MDLCACHE_COARSE_LOCK_(mdlcache) + +#endif +``` + +`SpyCustom/sdk/imovehelper.h`: + +```h +#ifndef IMOVEHELPER_H +#define IMOVEHELPER_H + +#ifdef _WIN32 +#pragma once +#endif + + +enum PLAYER_ANIM; +class IPhysicsSurfaceProps; +class Vector; +struct model_t; +struct cmodel_t; +struct vcollide_t; +class CGameTrace; +enum soundlevel_t; + +enum +{ + WL_NotInWater = 0, + WL_Feet, + WL_Waist, + WL_Eyes +}; + + +typedef CBaseHandle EntityHandle_t; + + +#define INVALID_ENTITY_HANDLE INVALID_EHANDLE_INDEX + +abstract_class IMoveHelper +{ +public: + static IMoveHelper * GetSingleton() { return sm_pSingleton; } + + 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, PRINTF_FORMAT_STRING 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: + static void SetSingleton(IMoveHelper* pMoveHelper) { sm_pSingleton = pMoveHelper; } + + virtual ~IMoveHelper() {} + + static IMoveHelper* sm_pSingleton; + + + void SetHost_v(C_BaseEntity* player) { + typedef void(__thiscall* OriginalFn)(void*, C_BaseEntity*); + getvfunc(this, 1)(this, player); + } +}; + +#define IMPLEMENT_MOVEHELPER() \ + IMoveHelper* IMoveHelper::sm_pSingleton = 0 + +inline IMoveHelper* MoveHelper() +{ + return IMoveHelper::GetSingleton(); +} + +//movehelper_client.cpp +//https://github.com/perilouswithadollarsign/cstrike15_src/blob/f82112a2388b841d72cb62ca48ab1846dfcc11c8/game/client/movehelper_client.cpp + +class CMoveHelperClient : public IMoveHelper +{ +public: + CMoveHelperClient(void); + virtual ~CMoveHelperClient(void); + + char const* GetName(EntityHandle_t handle) const; + + // touch lists + virtual void ResetTouchList(void); + virtual bool AddToTouched(const trace_t& tr, const Vector& impactvelocity); + virtual void ProcessImpacts(void); + + // Numbered line printf + virtual void Con_NPrintf(int idx, char const* fmt, ...); + + virtual bool PlayerFallingDamage(void); + virtual void PlayerSetAnimation(PLAYER_ANIM eAnim); + + // These have separate server vs client impementations + virtual void StartSound(const Vector& origin, int channel, char const* sample, float volume, soundlevel_t soundlevel, int fFlags, int pitch); + virtual void StartSound(const Vector& origin, const char* soundname); + 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); + virtual IPhysicsSurfaceProps* GetSurfaceProps(void); + + virtual bool IsWorldEntity(const CBaseHandle& handle); + + inline void SetHost(C_BaseEntity* host); + +//private: + // results, tallied on client and server, but only used by server to run SV_Impact. + // we store off our velocity in the trace_t structure so that we can determine results + // of shoving boxes etc. around. + struct touchlist_t + { + Vector deltavelocity; + trace_t trace; + + touchlist_t() {} + + private: + touchlist_t(const touchlist_t& src); + }; + + CUtlVector m_TouchList; + + C_BaseEntity* m_pHost; +}; + + +//----------------------------------------------------------------------------- +// Indicates which entity we're going to move +//----------------------------------------------------------------------------- + +inline void CMoveHelperClient::SetHost(C_BaseEntity* host) +{ + m_pHost = host; + + // In case any stuff is ever left over, sigh... + ResetTouchList(); +} + + + + + +#endif +``` + +`SpyCustom/sdk/inetchannel.h`: + +```h +#ifndef INETCHANNEL_H +#define INETCHANNEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "inetchannelinfo.h" +#include "bitbuf.h" + +class IDemoRecorder; +class INetMessage; +class INetChannelHandler; +class INetChannelInfo; +typedef struct netpacket_s netpacket_t; +typedef struct netadr_s netadr_t; + +abstract_class INetChannel : public INetChannelInfo +{ +public: + virtual ~INetChannel(void) {}; + + virtual void SetDataRate(float rate) = 0; + virtual bool RegisterMessage(INetMessage* msg) = 0; + //virtual bool UnregisterMessage(INetMessageBinder* 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; +#ifdef POSIX + FORCEINLINE bool SendNetMsg(INetMessage const& msg, bool bForceReliable = false, bool bVoice = false) { return SendNetMsg(*((INetMessage*)&msg), bForceReliable, bVoice); } +#endif + 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; + + + std::byte pad0[0x14]; //0x0000 + bool bProcessingMessages; //0x0014 + bool bShouldDelete; //0x0015 + bool bStopProcessing; //0x0016 + std::byte pad1[0x1]; //0x0017 + int iOutSequenceNr; //0x0018 last send outgoing sequence number + int iInSequenceNr; //0x001C last received incoming sequence number + int iOutSequenceNrAck; //0x0020 last received acknowledge outgoing sequence number + int iOutReliableState; //0x0024 state of outgoing reliable data (0/1) flip flop used for loss detection + int iInReliableState; //0x0028 state of incoming reliable data + int iChokedPackets; //0x002C number of choked packets + std::byte pad2[0x414]; //0x0030 +}; + + +#endif + +``` + +`SpyCustom/sdk/inetchannelinfo.h`: + +```h +#if !defined( INETCHANNELINFO_H ) +#define INETCHANNELINFO_H +#ifdef _WIN32 +#pragma once +#endif + + +#define FLOW_OUTGOING 0 +#define FLOW_INCOMING 1 +#define MAX_FLOWS 2 + +class INetChannelInfo +{ +public: + + 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 + TEMPENTS, // temp entities + USERMESSAGES, // user messages + ENTMESSAGES, // entity messages + VOICE, // voice data + STRINGTABLE, // a stringtable update + MOVE, // client move cmds + STRINGCMD, // string command + SIGNON, // various signondata + PAINTMAP, // paintmap data + ENCRYPTED, // encrypted data + TOTAL, // must be last and is not a real group + }; + + enum ENetworkEventType_t + { + k_ENetworkEventType_Generic = 0, // Generic network event + k_ENetworkEventType_TimedOut = 1, // Network connection timed out + }; + + + 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; + + +}; + +#endif +``` + +`SpyCustom/sdk/inetmessage.h`: + +```h +#ifndef INETMESSAGE_H +#define INETMESSAGE_H + +#include "bitbuf.h" + +class INetMsgHandler; +class INetMessage; +class INetChannel; + +class INetMessage +{ +public: + virtual ~INetMessage() {}; + + virtual void SetNetChannel(INetChannel* netchan) { DebuggerBreak(); return; } + virtual void SetReliable(bool state) = 0; + + virtual bool Process(void) { DebuggerBreak(); return false; } + + virtual bool ReadFromBuffer(bf_read& buffer) = 0; + virtual bool WriteToBuffer(bf_write& buffer) const = 0; + + virtual bool IsReliable(void) const = 0; + + virtual int GetType(void) const = 0; + virtual int GetGroup(void) const = 0; + virtual const char* GetName(void) const = 0; + + virtual INetChannel* GetNetChannel(void) const { DebuggerBreak(); return NULL; } + + virtual const char* ToString(void) const = 0; + virtual size_t GetSize() const = 0; +}; + +class INetMessageBinder +{ +public: + virtual ~INetMessageBinder() {}; + + virtual int GetType(void) const = 0; + virtual void SetNetChannel(INetChannel* netchan) = 0; + virtual INetMessage* CreateFromBuffer(bf_read& buffer) = 0; + virtual bool Process(const INetMessage& src) = 0; +}; + +class INetChannelHandler +{ +public: + virtual ~INetChannelHandler(void) {}; + + virtual void ConnectionStart(INetChannel* chan) = 0; + virtual void ConnectionStop() = 0; + + virtual void ConnectionClosing(const char* reason) = 0; + + virtual void ConnectionCrashed(const char* reason) = 0; + + virtual void PacketStart(int incoming_sequence, int outgoing_acknowledged) = 0; + + virtual void PacketEnd(void) = 0; + + virtual void FileRequested(const char* fileName, unsigned int transferID, bool isReplayDemoFile) = 0; + + virtual void FileReceived(const char* fileName, unsigned int transferID, bool isReplayDemoFile) = 0; + + virtual void FileDenied(const char* fileName, unsigned int transferID, bool isReplayDemoFile) = 0; + + virtual void FileSent(const char* fileName, unsigned int transferID, bool isReplayDemoFile) = 0; + + virtual bool ChangeSplitscreenUser(int nSplitScreenUserSlot) = 0; +}; + +#endif + + + +``` + +`SpyCustom/sdk/inetmsghandler.h`: + +```h +#if !defined( INETMSGHANDLER_H ) +#define INETMSGHANDLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "inetmessage.h" + +class INetChannel; +typedef struct netpacket_s netpacket_t; + +/* +class INetChannelHandler +{ +public: + virtual ~INetChannelHandler(void) {}; + + virtual void ConnectionStart(INetChannel* chan) = 0; // called first time network channel is established + + virtual void ConnectionClosing(const char* reason) = 0; // network channel is being closed by remote site + + virtual void ConnectionCrashed(const char* reason) = 0; // network error occured + + virtual void PacketStart(int incoming_sequence, int outgoing_acknowledged) = 0; // called each time a new packet arrived + + virtual void PacketEnd(void) = 0; // all messages has been parsed + + virtual void FileRequested(const char* fileName, unsigned int transferID) = 0; // other side request a file for download + + virtual void FileReceived(const char* fileName, unsigned int transferID) = 0; // we received a file + + virtual void FileDenied(const char* fileName, unsigned int transferID) = 0; // a file request was denied by other side + + virtual void FileSent(const char* fileName, unsigned int transferID) = 0; // we sent a file +}; + + +#define PROCESS_NET_MESSAGE( name ) \ + virtual bool Process##name( NET_##name *msg ) + +#define PROCESS_SVC_MESSAGE( name ) \ + virtual bool Process##name( SVC_##name *msg ) + +#define PROCESS_CLC_MESSAGE( name ) \ + virtual bool Process##name( CLC_##name *msg ) + +#define PROCESS_MM_MESSAGE( name ) \ + virtual bool Process##name( MM_##name *msg ) + + +#define REGISTER_NET_MSG( name ) \ + NET_##name * p##name = new NET_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_SVC_MSG( name ) \ + SVC_##name * p##name = new SVC_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_CLC_MSG( name ) \ + CLC_##name * p##name = new CLC_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_MM_MSG( name ) \ + MM_##name * p##name = new MM_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +class NET_Tick; +class NET_StringCmd; +class NET_SetConVar; +class NET_SignonState; + + + +class INetMessageHandler +{ +public: + virtual ~INetMessageHandler(void) {}; + + PROCESS_NET_MESSAGE(Tick) = 0; + PROCESS_NET_MESSAGE(StringCmd) = 0; + PROCESS_NET_MESSAGE(SetConVar) = 0; + PROCESS_NET_MESSAGE(SignonState) = 0; +}; + + +class CLC_ClientInfo; +class CLC_Move; +class CLC_VoiceData; +class CLC_BaselineAck; +class CLC_ListenEvents; +class CLC_RespondCvarValue; +class CLC_FileCRCCheck; +class CLC_FileMD5Check; +class CLC_SaveReplay; +class CLC_CmdKeyValues; + + +class IClientMessageHandler : public INetMessageHandler +{ +public: + virtual ~IClientMessageHandler(void) {}; + + PROCESS_CLC_MESSAGE(ClientInfo) = 0; + PROCESS_CLC_MESSAGE(Move) = 0; + PROCESS_CLC_MESSAGE(VoiceData) = 0; + PROCESS_CLC_MESSAGE(BaselineAck) = 0; + PROCESS_CLC_MESSAGE(ListenEvents) = 0; + PROCESS_CLC_MESSAGE(RespondCvarValue) = 0; + PROCESS_CLC_MESSAGE(FileCRCCheck) = 0; + PROCESS_CLC_MESSAGE(FileMD5Check) = 0; +#if defined( REPLAY_ENABLED ) + PROCESS_CLC_MESSAGE(SaveReplay) = 0; +#endif + PROCESS_CLC_MESSAGE(CmdKeyValues) = 0; +}; + +class SVC_Print; +class SVC_ServerInfo; +class SVC_SendTable; +class SVC_ClassInfo; +class SVC_SetPause; +class SVC_CreateStringTable; +class SVC_UpdateStringTable; +class SVC_VoiceInit; +class SVC_VoiceData; +class SVC_Sounds; +class SVC_SetView; +class SVC_FixAngle; +class SVC_CrosshairAngle; +class SVC_BSPDecal; +class SVC_GameEvent; +class SVC_UserMessage; +class SVC_EntityMessage; +class SVC_PacketEntities; +class SVC_TempEntities; +class SVC_Prefetch; +class SVC_Menu; +class SVC_GameEventList; +class SVC_GetCvarValue; +class SVC_CmdKeyValues; + +class IServerMessageHandler : public INetMessageHandler +{ +public: + virtual ~IServerMessageHandler(void) {}; + + // Returns dem file protocol version, or, if not playing a demo, just returns PROTOCOL_VERSION + virtual int GetDemoProtocolVersion() const = 0; + + PROCESS_SVC_MESSAGE(Print) = 0; + PROCESS_SVC_MESSAGE(ServerInfo) = 0; + PROCESS_SVC_MESSAGE(SendTable) = 0; + PROCESS_SVC_MESSAGE(ClassInfo) = 0; + PROCESS_SVC_MESSAGE(SetPause) = 0; + PROCESS_SVC_MESSAGE(CreateStringTable) = 0; + PROCESS_SVC_MESSAGE(UpdateStringTable) = 0; + PROCESS_SVC_MESSAGE(VoiceInit) = 0; + PROCESS_SVC_MESSAGE(VoiceData) = 0; + PROCESS_SVC_MESSAGE(Sounds) = 0; + PROCESS_SVC_MESSAGE(SetView) = 0; + PROCESS_SVC_MESSAGE(FixAngle) = 0; + PROCESS_SVC_MESSAGE(CrosshairAngle) = 0; + PROCESS_SVC_MESSAGE(BSPDecal) = 0; + PROCESS_SVC_MESSAGE(GameEvent) = 0; + PROCESS_SVC_MESSAGE(UserMessage) = 0; + PROCESS_SVC_MESSAGE(EntityMessage) = 0; + PROCESS_SVC_MESSAGE(PacketEntities) = 0; + PROCESS_SVC_MESSAGE(TempEntities) = 0; + PROCESS_SVC_MESSAGE(Prefetch) = 0; + PROCESS_SVC_MESSAGE(Menu) = 0; + PROCESS_SVC_MESSAGE(GameEventList) = 0; + PROCESS_SVC_MESSAGE(GetCvarValue) = 0; + PROCESS_SVC_MESSAGE(CmdKeyValues) = 0; +}; + +class MM_Heartbeat; +class MM_ClientInfo; +class MM_JoinResponse; +class MM_RegisterResponse; +class MM_Migrate; +class MM_Mutelist; +class MM_Checkpoint; + +class IMatchmakingMessageHandler : public INetMessageHandler +{ +public: + virtual ~IMatchmakingMessageHandler(void) {}; + + PROCESS_MM_MESSAGE(Heartbeat) = 0; + PROCESS_MM_MESSAGE(ClientInfo) = 0; + PROCESS_MM_MESSAGE(JoinResponse) = 0; + PROCESS_MM_MESSAGE(RegisterResponse) = 0; + PROCESS_MM_MESSAGE(Migrate) = 0; + PROCESS_MM_MESSAGE(Mutelist) = 0; + PROCESS_MM_MESSAGE(Checkpoint) = 0; +}; +*/ + +class IConnectionlessPacketHandler +{ +public: + virtual ~IConnectionlessPacketHandler(void) {}; + + virtual bool ProcessConnectionlessPacket(netpacket_t* packet) = 0; +}; + + +#endif + +``` + +`SpyCustom/sdk/inetworksystem.h`: + +```h +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#ifndef INETWORKSYSTEM_H +#define INETWORKSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "iappsystem.h" + + +// This is the packet payload without any header bytes (which are attached for actual sending) +#define NET_MAX_PAYLOAD ( 262144 - 4) // largest message we can send in bytes +#define NET_MAX_PAYLOAD_BITS 18 // 2^NET_MAX_PAYLOAD_BITS > NET_MAX_PAYLOAD +// This is just the client_t->netchan.datagram buffer size (shouldn't ever need to be huge) +#define NET_MAX_DATAGRAM_PAYLOAD 4000 // = maximum unreliable playload size + +// UDP has 28 byte headers +#define UDP_HEADER_SIZE (20+8) // IP = 20, UDP = 8 + +#define MAX_ROUTABLE_PAYLOAD 1200 // x360 requires <= 1260, but now that listen servers can support "steam" mediated sockets, steam enforces 1200 byte limit + +#if (MAX_ROUTABLE_PAYLOAD & 3) != 0 +#error Bit buffers must be a multiple of 4 bytes +#endif + +#define MIN_ROUTABLE_PAYLOAD 16 // minimum playload size + +#define NETMSG_TYPE_BITS 8 // must be 2^NETMSG_TYPE_BITS > SVC_LASTMSG + +// This is the payload plus any header info (excluding UDP header) + +#define HEADER_BYTES 9 // 2*4 bytes seqnr, 1 byte flags + +// Pad this to next higher 16 byte boundary +// This is the largest packet that can come in/out over the wire, before processing the header +// bytes will be stripped by the networking channel layer +#define NET_MAX_MESSAGE PAD_NUMBER( ( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 ) + +#define NET_HEADER_FLAG_SPLITPACKET -2 +#define NET_HEADER_FLAG_COMPRESSEDPACKET -3 + +//----------------------------------------------------------------------------- +// Forward declarations: +//----------------------------------------------------------------------------- +class INetworkMessageHandler; +class INetworkMessage; +class INetChannel; +class INetworkMessageFactory; +class bf_read; +class bf_write; +typedef struct netadr_s netadr_t; +class CNetPacket; + + +//----------------------------------------------------------------------------- +// Default ports +//----------------------------------------------------------------------------- +enum +{ + NETWORKSYSTEM_DEFAULT_SERVER_PORT = 27001, + NETWORKSYSTEM_DEFAULT_CLIENT_PORT = 27002 +}; + + +//----------------------------------------------------------------------------- +// This interface encompasses a one-way communication path between two +//----------------------------------------------------------------------------- +typedef int ConnectionHandle_t; + +enum ConnectionStatus_t +{ + CONNECTION_STATE_DISCONNECTED = 0, + CONNECTION_STATE_CONNECTING, + CONNECTION_STATE_CONNECTION_FAILED, + CONNECTION_STATE_CONNECTED, +}; + + +//----------------------------------------------------------------------------- +// This interface encompasses a one-way communication path between two machines +//----------------------------------------------------------------------------- +// +// abstract_class INetChannel +// { +// public: +// // virtual INetworkMessageHandler *GetMsgHandler( void ) const = 0; +// virtual const netadr_t &GetRemoteAddress( void ) const = 0; +// +// // send a net message +// // NOTE: There are special connect/disconnect messages? +// virtual bool AddNetMsg( INetworkMessage *msg, bool bForceReliable = false ) = 0; +// // virtual bool RegisterMessage( INetworkMessage *msg ) = 0; +// +// virtual ConnectionStatus_t GetConnectionState( ) = 0; +// +// /* +// virtual ConnectTo( const netadr_t& to ) = 0; +// virtual Disconnect() = 0; +// +// virtual const netadr_t& GetLocalAddress() = 0; +// +// virtual const netadr_t& GetRemoteAddress() = 0; +// */ +// }; + + +//----------------------------------------------------------------------------- +// Network event types + structures +//----------------------------------------------------------------------------- +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 +{ + INetChannel *m_pChannel; +}; + +struct NetworkDisconnectionEvent_t : public NetworkEvent_t +{ + INetChannel *m_pChannel; +}; + +struct NetworkMessageReceivedEvent_t : public NetworkEvent_t +{ + INetChannel *m_pChannel; + INetworkMessage *m_pNetworkMessage; +}; + + +//----------------------------------------------------------------------------- +// Main interface for low-level networking (packet sending). This is a low-level interface +//----------------------------------------------------------------------------- +abstract_class INetworkSystem : public IAppSystem +{ +public: + // Installs network message factories to be used with all connections + virtual bool RegisterMessage( INetworkMessage *msg ) = 0; + + // Start, shutdown a server + virtual bool StartServer( unsigned short nServerListenPort = NETWORKSYSTEM_DEFAULT_SERVER_PORT ) = 0; + virtual void ShutdownServer( ) = 0; + + // Process server-side network messages + virtual void ServerReceiveMessages() = 0; + virtual void ServerSendMessages() = 0; + + // Start, shutdown a client + virtual bool StartClient( unsigned short nClientListenPort = NETWORKSYSTEM_DEFAULT_CLIENT_PORT ) = 0; + virtual void ShutdownClient( ) = 0; + + // Process client-side network messages + virtual void ClientSendMessages() = 0; + virtual void ClientReceiveMessages() = 0; + + // Connect, disconnect a client to a server + virtual INetChannel* ConnectClientToServer( const char *pServer, int nServerListenPort = NETWORKSYSTEM_DEFAULT_SERVER_PORT ) = 0; + virtual void DisconnectClientFromServer( INetChannel* pChan ) = 0; + + // Event queue + virtual NetworkEvent_t *FirstNetworkEvent( ) = 0; + virtual NetworkEvent_t *NextNetworkEvent( ) = 0; + + // Returns the local host name + virtual const char* GetLocalHostName( void ) const = 0; + virtual const char* GetLocalAddress( void ) const = 0; + + /* + // NOTE: Server methods + // NOTE: There's only 1 client INetChannel ever + // There can be 0-N server INetChannels. + virtual INetChannel* CreateConnection( bool bIsClientConnection ) = 0; + // Add methods for setting unreliable payloads + */ +}; + + +#endif // INETWORKSYSTEM_H +``` + +`SpyCustom/sdk/interface.h`: + +```h +#ifndef INTERFACE_H +#define INTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +class IBaseInterface +{ +public: + virtual ~IBaseInterface() {} +}; + +#if !defined( _X360 ) +#define CREATEINTERFACE_PROCNAME "CreateInterface" +#else +#define CREATEINTERFACE_PROCNAME ((const char*)1) +#endif + +typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); +typedef void* (*InstantiateInterfaceFn)(); + +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char* pName); + +public: + InstantiateInterfaceFn m_CreateFn; + const char* m_pName; + + InterfaceReg* m_pNext; + static InterfaceReg* s_pInterfaceRegs; +}; + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); +#else +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \ + } +#endif + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static void* __Create##className##_interface() {return static_cast( new className );} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); +#else +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##_interface() {return static_cast( new className );} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \ + } +#endif + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \ + static void* __Create##className##interfaceName##_interface() {return static_cast( &globalVarName );} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); +#else +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##interfaceName##_interface() {return static_cast( &globalVarName );} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \ + } +#endif + +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, , interfaceName, versionName, globalVarName) + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#else +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static className __g_##className##_singleton; \ + } \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#endif + +class CSysModule; + +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + +void* CreateInterface(const char* pName, int* pReturnCode); + +#if defined( _X360 ) +DLL_EXPORT void* CreateInterfaceThunk(const char* pName, int* pReturnCode); +#endif + +extern CreateInterfaceFn Sys_GetFactory(CSysModule* pModule); +extern CreateInterfaceFn Sys_GetFactory(const char* pModuleName); +extern CreateInterfaceFn Sys_GetFactoryThis(void); + +enum Sys_Flags +{ + SYS_NOFLAGS = 0x00, + SYS_NOLOAD = 0x01 +}; + +extern CSysModule* Sys_LoadModule(const char* pModuleName, Sys_Flags flags = SYS_NOFLAGS); +extern void Sys_UnloadModule(CSysModule* pModule); + +bool Sys_LoadInterface( + const char* pModuleName, + const char* pInterfaceVersionName, + CSysModule** pOutModule, + void** pOutInterface); + +bool Sys_IsDebuggerPresent(); + +class CDllDemandLoader +{ +public: + CDllDemandLoader(char const* pchModuleName); + virtual ~CDllDemandLoader(); + CreateInterfaceFn GetFactory(); + void Unload(); + +private: + + char const* m_pchModuleName; + CSysModule* m_hModule; + bool m_bLoadAttempted; +}; + +#endif + +``` + +`SpyCustom/sdk/interpolatedvar.h`: + +```h +#ifndef INTERPOLATEDVAR_H +#define INTERPOLATEDVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utllinkedlist.h" +#include "rangecheckedvar.h" +#include "lerp_functions.h" +#include "animationlayer.h" +#include "convar.h" + + +#include "memdbgon.h" + +#define COMPARE_HISTORY(a,b) \ + ( memcmp( m_VarHistory[a].GetValue(), m_VarHistory[b].GetValue(), sizeof(Type)*GetMaxCount() ) == 0 ) + + +#define LATCH_ANIMATION_VAR (1<<0) +#define LATCH_SIMULATION_VAR (1<<1) + +#define EXCLUDE_AUTO_LATCH (1<<2) +#define EXCLUDE_AUTO_INTERPOLATE (1<<3) + +#define INTERPOLATE_LINEAR_ONLY (1<<4) +#define INTERPOLATE_OMIT_UPDATE_LAST_NETWORKED (1<<5) + + + +#define EXTRA_INTERPOLATION_HISTORY_STORED 0.05f +extern float g_flLastPacketTimestamp; + +inline void Interpolation_SetLastPacketTimeStamp(float timestamp) +{ + Assert(timestamp > 0); + g_flLastPacketTimestamp = timestamp; +} + + +class CInterpolationContext +{ +public: + + CInterpolationContext() + { + m_bOldAllowExtrapolation = s_bAllowExtrapolation; + m_flOldLastTimeStamp = s_flLastTimeStamp; + + s_bAllowExtrapolation = false; + + m_pNext = s_pHead; + s_pHead = this; + } + + ~CInterpolationContext() + { + s_bAllowExtrapolation = m_bOldAllowExtrapolation; + s_flLastTimeStamp = m_flOldLastTimeStamp; + + Assert(s_pHead == this); + s_pHead = m_pNext; + } + + static void EnableExtrapolation(bool state) + { + s_bAllowExtrapolation = state; + } + + static bool IsThereAContext() + { + return s_pHead != NULL; + } + + static bool IsExtrapolationAllowed() + { + return s_bAllowExtrapolation; + } + + static void SetLastTimeStamp(float timestamp) + { + s_flLastTimeStamp = timestamp; + } + + static float GetLastTimeStamp() + { + return s_flLastTimeStamp; + } + + +private: + + CInterpolationContext* m_pNext; + bool m_bOldAllowExtrapolation; + float m_flOldLastTimeStamp; + + static CInterpolationContext* s_pHead; + static bool s_bAllowExtrapolation; + static float s_flLastTimeStamp; +}; + + +extern ConVar cl_extrapolate_amount; + + +template< class T > +inline T ExtrapolateInterpolatedVarType(const T& oldVal, const T& newVal, float divisor, float flExtrapolationAmount) +{ + return newVal; +} + +inline Vector ExtrapolateInterpolatedVarType(const Vector& oldVal, const Vector& newVal, float divisor, float flExtrapolationAmount) +{ + return Lerp(1.0f + flExtrapolationAmount * divisor, oldVal, newVal); +} + +inline float ExtrapolateInterpolatedVarType(const float& oldVal, const float& newVal, float divisor, float flExtrapolationAmount) +{ + return Lerp(1.0f + flExtrapolationAmount * divisor, oldVal, newVal); +} + +inline QAngle ExtrapolateInterpolatedVarType(const QAngle& oldVal, const QAngle& newVal, float divisor, float flExtrapolationAmount) +{ + return Lerp(1.0f + flExtrapolationAmount * divisor, oldVal, newVal); +} + + +abstract_class IInterpolatedVar +{ +public: + virtual ~IInterpolatedVar() {} + + 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; +}; + +template< typename Type, bool IS_ARRAY > +struct CInterpolatedVarEntryBase +{ + CInterpolatedVarEntryBase() + { + value = NULL; + count = 0; + changetime = 0; + } + ~CInterpolatedVarEntryBase() + { + delete[] value; + value = NULL; + } + + void FastTransferFrom(CInterpolatedVarEntryBase& src) + { + Assert(!value); + value = src.value; + count = src.count; + changetime = src.changetime; + src.value = 0; + src.count = 0; + } + + CInterpolatedVarEntryBase& operator=(const CInterpolatedVarEntryBase& src) + { + delete[] value; + value = NULL; + count = 0; + if (src.value) + { + count = src.count; + value = new Type[count]; + for (int i = 0; i < count; i++) + { + value[i] = src.value[i]; + } + } + return *this; + } + + Type* GetValue() { return value; } + const Type* GetValue() const { return value; } + + void Init(int maxCount) + { + if (!maxCount) + { + DeleteEntry(); + } + else + { + if (maxCount != count) + { + DeleteEntry(); + } + + if (!value) + { + count = maxCount; + value = new Type[maxCount]; + } + } + Assert(count == maxCount); + } + Type* NewEntry(const Type* pValue, int maxCount, float time) + { + changetime = time; + Init(maxCount); + if (value && maxCount) + { + memcpy(value, pValue, maxCount * sizeof(Type)); + } + return value; + } + + void DeleteEntry() + { + delete[] value; + value = NULL; + count = 0; + } + + float changetime; + int count; + Type* value; + +private: + CInterpolatedVarEntryBase(const CInterpolatedVarEntryBase& src); +}; + +template +struct CInterpolatedVarEntryBase +{ + CInterpolatedVarEntryBase() {} + ~CInterpolatedVarEntryBase() {} + + const Type* GetValue() const { return &value; } + Type* GetValue() { return &value; } + + void Init(int maxCount) + { + Assert(maxCount == 1); + } + Type* NewEntry(const Type* pValue, int maxCount, float time) + { + Assert(maxCount == 1); + changetime = time; + memcpy(&value, pValue, maxCount * sizeof(Type)); + return &value; + } + void FastTransferFrom(CInterpolatedVarEntryBase& src) + { + *this = src; + } + + void DeleteEntry() {} + + float changetime; + Type value; +}; + +template +class CSimpleRingBuffer +{ +public: + CSimpleRingBuffer(int startSize = 4) + { + m_pElements = 0; + m_maxElement = 0; + m_firstElement = 0; + m_count = 0; + m_growSize = 16; + EnsureCapacity(startSize); + } + ~CSimpleRingBuffer() + { + delete[] m_pElements; + m_pElements = NULL; + } + + inline int Count() const { return m_count; } + + int Head() const { return (m_count > 0) ? 0 : InvalidIndex(); } + + bool IsIdxValid(int i) const { return (i >= 0 && i < m_count) ? true : false; } + bool IsValidIndex(int i) const { return IsIdxValid(i); } + static int InvalidIndex() { return -1; } + + T& operator[](int i) + { + Assert(IsIdxValid(i)); + i += m_firstElement; + i = WrapRange(i); + return m_pElements[i]; + } + + const T& operator[](int i) const + { + Assert(IsIdxValid(i)); + i += m_firstElement; + i = WrapRange(i); + return m_pElements[i]; + } + + void EnsureCapacity(int capSize) + { + if (capSize > m_maxElement) + { + int newMax = m_maxElement + ((capSize + m_growSize - 1) / m_growSize) * m_growSize; + T* pNew = new T[newMax]; + for (int i = 0; i < m_maxElement; i++) + { + pNew[i].FastTransferFrom(m_pElements[WrapRange(i + m_firstElement)]); + } + m_firstElement = 0; + m_maxElement = newMax; + delete[] m_pElements; + m_pElements = pNew; + } + } + + int AddToHead() + { + EnsureCapacity(m_count + 1); + int i = m_firstElement + m_maxElement - 1; + m_count++; + i = WrapRange(i); + m_firstElement = i; + return 0; + } + + int AddToHead(const T& elem) + { + AddToHead(); + m_pElements[m_firstElement] = elem; + return 0; + } + + int AddToTail() + { + EnsureCapacity(m_count + 1); + m_count++; + return WrapRange(m_firstElement + m_count - 1); + } + + void RemoveAll() + { + m_count = 0; + m_firstElement = 0; + } + + void RemoveAtHead() + { + if (m_count > 0) + { + m_firstElement = WrapRange(m_firstElement + 1); + m_count--; + } + } + + void Truncate(int newLength) + { + if (newLength < m_count) + { + Assert(newLength >= 0); + m_count = newLength; + } + } + +private: + inline int WrapRange(int i) const + { + return (i >= m_maxElement) ? (i - m_maxElement) : i; + } + + T* m_pElements; + unsigned short m_maxElement; + unsigned short m_firstElement; + unsigned short m_count; + unsigned short m_growSize; +}; + +template< typename Type, bool IS_ARRAY> +class CInterpolatedVarArrayBase : public IInterpolatedVar +{ +public: + friend class CInterpolatedVarPrivate; + + CInterpolatedVarArrayBase(const char* pDebugName = "no debug name"); + virtual ~CInterpolatedVarArrayBase(); + + +public: + + virtual void Setup(void* pValue, int type); + virtual void SetInterpolationAmount(float seconds); + virtual void NoteLastNetworkedValue(); + virtual bool NoteChanged(float changetime, bool bUpdateLastNetworkedValue); + virtual void Reset(); + virtual int Interpolate(float currentTime); + virtual int GetType() const; + virtual void RestoreToLastNetworked(); + virtual void Copy(IInterpolatedVar* pInSrc); + virtual const char* GetDebugName() { return m_pDebugName; } + + +public: + + bool NoteChanged(float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue); + int Interpolate(float currentTime, float interpolation_amount); + + void DebugInterpolate(Type* pOut, float currentTime); + + void GetDerivative(Type* pOut, float currentTime); + void GetDerivative_SmoothVelocity(Type* pOut, float currentTime); + + void ClearHistory(); + void AddToHead(float changeTime, const Type* values, bool bFlushNewer); + const Type& GetPrev(int iArrayIndex = 0) const; + const Type& GetCurrent(int iArrayIndex = 0) const; + + float GetInterval() const; + bool IsValidIndex(int i); + Type* GetHistoryValue(int index, float& changetime, int iArrayIndex = 0); + int GetHead() { return 0; } + int GetNext(int i) + { + int next = i + 1; + if (!m_VarHistory.IsValidIndex(next)) + return m_VarHistory.InvalidIndex(); + return next; + } + + void SetHistoryValuesForItem(int item, Type& value); + void SetLooping(bool looping, int iArrayIndex = 0); + + void SetMaxCount(int newmax); + int GetMaxCount() const; + + float GetOldestEntry(); + + void SetDebugName(const char* pName) { m_pDebugName = pName; } + virtual void SetDebug(bool bDebug) { m_bDebug = bDebug; } + bool GetInterpolationInfo(float currentTime, int* pNewer, int* pOlder, int* pOldest); + +protected: + + typedef CInterpolatedVarEntryBase CInterpolatedVarEntry; + typedef CSimpleRingBuffer< CInterpolatedVarEntry > CVarHistory; + friend class CInterpolationInfo; + + class CInterpolationInfo + { + public: + bool m_bHermite; + int oldest; + int older; + int newer; + float frac; + }; + + +protected: + + void RemoveOldEntries(float oldesttime); + void RemoveEntriesPreviousTo(float flTime); + + bool GetInterpolationInfo( + CInterpolationInfo* pInfo, + float currentTime, + float interpolation_amount, + int* pNoMoreChanges); + + void TimeFixup_Hermite( + CInterpolatedVarEntry& fixup, + CInterpolatedVarEntry*& prev, + CInterpolatedVarEntry*& start, + CInterpolatedVarEntry*& end); + + void TimeFixup2_Hermite( + CInterpolatedVarEntry& fixup, + CInterpolatedVarEntry*& prev, + CInterpolatedVarEntry*& start, + float dt + ); + + void _Extrapolate( + Type* pOut, + CInterpolatedVarEntry* pOld, + CInterpolatedVarEntry* pNew, + float flDestinationTime, + float flMaxExtrapolationAmount + ); + + void _Interpolate(Type* out, float frac, CInterpolatedVarEntry* start, CInterpolatedVarEntry* end); + void _Interpolate_Hermite(Type* out, float frac, CInterpolatedVarEntry* pOriginalPrev, CInterpolatedVarEntry* start, CInterpolatedVarEntry* end, bool looping = false); + + void _Derivative_Hermite(Type* out, float frac, CInterpolatedVarEntry* pOriginalPrev, CInterpolatedVarEntry* start, CInterpolatedVarEntry* end); + void _Derivative_Hermite_SmoothVelocity(Type* out, float frac, CInterpolatedVarEntry* b, CInterpolatedVarEntry* c, CInterpolatedVarEntry* d); + void _Derivative_Linear(Type* out, CInterpolatedVarEntry* start, CInterpolatedVarEntry* end); + + bool ValidOrder(); + +protected: + Type* m_pValue; + CVarHistory m_VarHistory; + Type* m_LastNetworkedValue; + float m_LastNetworkedTime; + byte m_fType; + byte m_nMaxCount; + byte* m_bLooping; + float m_InterpolationAmount; + const char* m_pDebugName; + bool m_bDebug : 1; +}; + + +template< typename Type, bool IS_ARRAY > +inline CInterpolatedVarArrayBase::CInterpolatedVarArrayBase(const char* pDebugName) +{ + m_pDebugName = pDebugName; + m_pValue = NULL; + m_fType = LATCH_ANIMATION_VAR; + m_InterpolationAmount = 0.0f; + m_nMaxCount = 0; + m_LastNetworkedTime = 0; + m_LastNetworkedValue = NULL; + m_bLooping = NULL; + m_bDebug = false; +} + +template< typename Type, bool IS_ARRAY > +inline CInterpolatedVarArrayBase::~CInterpolatedVarArrayBase() +{ + ClearHistory(); + delete[] m_bLooping; + delete[] m_LastNetworkedValue; +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::Setup(void* pValue, int type) +{ + m_pValue = (Type*)pValue; + m_fType = type; +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetInterpolationAmount(float seconds) +{ + m_InterpolationAmount = seconds; +} + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::GetType() const +{ + return m_fType; +} + +template< typename Type, bool IS_ARRAY > +void CInterpolatedVarArrayBase::NoteLastNetworkedValue() +{ + memcpy(m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof(Type)); + m_LastNetworkedTime = g_flLastPacketTimestamp; +} + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::NoteChanged(float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue) +{ + Assert(m_pValue); + + bool bRet = true; + if (m_VarHistory.Count()) + { + if (memcmp(m_pValue, m_VarHistory[0].GetValue(), sizeof(Type) * m_nMaxCount) == 0) + { + bRet = false; + } + } + + if (m_bDebug) + { + char const* pDiffString = bRet ? "differs" : "identical"; + + } + + AddToHead(changetime, m_pValue, true); + + if (bUpdateLastNetworkedValue) + { + NoteLastNetworkedValue(); + } + +#if 0 + RemoveOldEntries(gpGlobals->curtime - interpolation_amount - 2.0f); +#else +#endif + + return bRet; +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::NoteChanged(float changetime, bool bUpdateLastNetworkedValue) +{ + return NoteChanged(changetime, m_InterpolationAmount, bUpdateLastNetworkedValue); +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::RestoreToLastNetworked() +{ + Assert(m_pValue); + memcpy(m_pValue, m_LastNetworkedValue, m_nMaxCount * sizeof(Type)); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::ClearHistory() +{ + for (int i = 0; i < m_VarHistory.Count(); i++) + { + m_VarHistory[i].DeleteEntry(); + } + m_VarHistory.RemoveAll(); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::AddToHead(float changeTime, const Type* values, bool bFlushNewer) +{ + MEM_ALLOC_CREDIT_CLASS(); + int newslot; + + if (bFlushNewer) + { + while (m_VarHistory.Count()) + { + if ((m_VarHistory[0].changetime + 0.0001f) > changeTime) + { + m_VarHistory.RemoveAtHead(); + } + else + { + break; + } + } + + newslot = m_VarHistory.AddToHead(); + } + else + { + newslot = m_VarHistory.AddToHead(); + for (int i = 1; i < m_VarHistory.Count(); i++) + { + if (m_VarHistory[i].changetime <= changeTime) + break; + m_VarHistory[newslot].FastTransferFrom(m_VarHistory[i]); + newslot = i; + } + } + + CInterpolatedVarEntry* e = &m_VarHistory[newslot]; + e->NewEntry(values, m_nMaxCount, changeTime); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::Reset() +{ + ClearHistory(); + + if (m_pValue) + { + memcpy(m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof(Type)); + } +} + + +template< typename Type, bool IS_ARRAY > +inline float CInterpolatedVarArrayBase::GetOldestEntry() +{ + float lastVal = 0; + if (m_VarHistory.Count()) + { + lastVal = m_VarHistory[m_VarHistory.Count() - 1].changetime; + } + return lastVal; +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::RemoveOldEntries(float oldesttime) +{ + int newCount = m_VarHistory.Count(); + for (int i = m_VarHistory.Count(); --i > 2; ) + { + if (m_VarHistory[i].changetime > oldesttime) + break; + newCount = i; + } + m_VarHistory.Truncate(newCount); +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::RemoveEntriesPreviousTo(float flTime) +{ + for (int i = 0; i < m_VarHistory.Count(); i++) + { + if (m_VarHistory[i].changetime < flTime) + { + m_VarHistory.Truncate(i + 3); + break; + } + } +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::GetInterpolationInfo( + typename CInterpolatedVarArrayBase::CInterpolationInfo* pInfo, + float currentTime, + float interpolation_amount, + int* pNoMoreChanges +) +{ + Assert(m_pValue); + + CVarHistory& varHistory = m_VarHistory; + + float targettime = currentTime - interpolation_amount; + + pInfo->m_bHermite = false; + pInfo->frac = 0; + pInfo->oldest = pInfo->older = pInfo->newer = varHistory.InvalidIndex(); + + for (int i = 0; i < varHistory.Count(); i++) + { + pInfo->older = i; + + float older_change_time = m_VarHistory[i].changetime; + if (older_change_time == 0.0f) + break; + + if (targettime < older_change_time) + { + pInfo->newer = pInfo->older; + continue; + } + + if (pInfo->newer == varHistory.InvalidIndex()) + { + pInfo->newer = pInfo->older; + + if (pNoMoreChanges) + *pNoMoreChanges = 1; + return true; + } + + float newer_change_time = varHistory[pInfo->newer].changetime; + float dt = newer_change_time - older_change_time; + if (dt > 0.0001f) + { + pInfo->frac = (targettime - older_change_time) / (newer_change_time - older_change_time); + pInfo->frac = MIN(pInfo->frac, 2.0f); + + int oldestindex = i + 1; + + if (!(m_fType & INTERPOLATE_LINEAR_ONLY) && varHistory.IsIdxValid(oldestindex)) + { + pInfo->oldest = oldestindex; + float oldest_change_time = varHistory[oldestindex].changetime; + float dt2 = older_change_time - oldest_change_time; + if (dt2 > 0.0001f) + { + pInfo->m_bHermite = true; + } + } + + if (pNoMoreChanges && pInfo->newer == m_VarHistory.Head()) + { + if (COMPARE_HISTORY(pInfo->newer, pInfo->older)) + { + if (!pInfo->m_bHermite || COMPARE_HISTORY(pInfo->newer, pInfo->oldest)) + *pNoMoreChanges = 1; + } + } + } + return true; + } + + if (pInfo->newer != varHistory.InvalidIndex()) + { + pInfo->older = pInfo->newer; + return true; + } + + + pInfo->newer = pInfo->older; + return (pInfo->older != varHistory.InvalidIndex()); +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::GetInterpolationInfo(float currentTime, int* pNewer, int* pOlder, int* pOldest) +{ + CInterpolationInfo info; + bool result = GetInterpolationInfo(&info, currentTime, m_InterpolationAmount, NULL); + + if (pNewer) + *pNewer = (int)info.newer; + + if (pOlder) + *pOlder = (int)info.older; + + if (pOldest) + *pOldest = (int)info.oldest; + + return result; +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::DebugInterpolate(Type* pOut, float currentTime) +{ + float interpolation_amount = m_InterpolationAmount; + + int noMoreChanges = 0; + + CInterpolationInfo info; + GetInterpolationInfo(&info, currentTime, interpolation_amount, &noMoreChanges); + + CVarHistory& history = m_VarHistory; + + if (info.m_bHermite) + { + _Interpolate_Hermite(pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer]); + } + else if (info.newer == info.older) + { + int realOlder = info.newer + 1; + if (CInterpolationContext::IsExtrapolationAllowed() && + IsValidIndex(realOlder) && + history[realOlder].changetime != 0.0 && + interpolation_amount > 0.000001f && + CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime) + { + _Extrapolate(pOut, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat()); + } + else + { + _Interpolate(pOut, info.frac, &history[info.older], &history[info.newer]); + } + } + else + { + _Interpolate(pOut, info.frac, &history[info.older], &history[info.newer]); + } +} + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::Interpolate(float currentTime, float interpolation_amount) +{ + int noMoreChanges = 0; + + CInterpolationInfo info; + if (!GetInterpolationInfo(&info, currentTime, interpolation_amount, &noMoreChanges)) + return noMoreChanges; + + + CVarHistory& history = m_VarHistory; + + if (m_bDebug) + { + Msg("%s Interpolate at %f%s\n", GetDebugName(), currentTime, noMoreChanges ? " [value will hold]" : ""); + } + + +#ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT + Type* backupValues = (Type*)_alloca(m_nMaxCount * sizeof(Type)); + memcpy(backupValues, m_pValue, sizeof(Type) * m_nMaxCount); +#endif + + if (info.m_bHermite) + { + _Interpolate_Hermite(m_pValue, info.frac, &history[info.oldest], &history[info.older], &history[info.newer]); + } + else if (info.newer == info.older) + { + int realOlder = info.newer + 1; + if (CInterpolationContext::IsExtrapolationAllowed() && + IsValidIndex(realOlder) && + history[realOlder].changetime != 0.0 && + interpolation_amount > 0.000001f && + CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime) + { + _Extrapolate(m_pValue, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat()); + } + else + { + _Interpolate(m_pValue, info.frac, &history[info.older], &history[info.newer]); + } + } + else + { + _Interpolate(m_pValue, info.frac, &history[info.older], &history[info.newer]); + } + +#ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT + if (memcmp(backupValues, m_pValue, sizeof(Type) * m_nMaxCount) != 0) + { + extern int g_nInterpolatedVarsChanged; + extern bool g_bRestoreInterpolatedVarValues; + + ++g_nInterpolatedVarsChanged; + + if (g_bRestoreInterpolatedVarValues) + { + memcpy(m_pValue, backupValues, sizeof(Type) * m_nMaxCount); + return noMoreChanges; + } + } +#endif + + RemoveEntriesPreviousTo(currentTime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED); + return noMoreChanges; +} + + +template< typename Type, bool IS_ARRAY > +void CInterpolatedVarArrayBase::GetDerivative(Type* pOut, float currentTime) +{ + CInterpolationInfo info; + if (!GetInterpolationInfo(&info, currentTime, m_InterpolationAmount, NULL)) + return; + + if (info.m_bHermite) + { + _Derivative_Hermite(pOut, info.frac, &m_VarHistory[info.oldest], &m_VarHistory[info.older], &m_VarHistory[info.newer]); + } + else + { + _Derivative_Linear(pOut, &m_VarHistory[info.older], &m_VarHistory[info.newer]); + } +} + + +template< typename Type, bool IS_ARRAY > +void CInterpolatedVarArrayBase::GetDerivative_SmoothVelocity(Type* pOut, float currentTime) +{ + CInterpolationInfo info; + if (!GetInterpolationInfo(&info, currentTime, m_InterpolationAmount, NULL)) + return; + + CVarHistory& history = m_VarHistory; + bool bExtrapolate = false; + int realOlder = 0; + + if (info.m_bHermite) + { + _Derivative_Hermite_SmoothVelocity(pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer]); + return; + } + else if (info.newer == info.older && CInterpolationContext::IsExtrapolationAllowed()) + { + realOlder = info.newer + 1; + if (IsValidIndex(realOlder) && history[realOlder].changetime != 0.0) + { + if (m_InterpolationAmount > 0.000001f && + CInterpolationContext::GetLastTimeStamp() <= (currentTime - m_InterpolationAmount)) + { + bExtrapolate = true; + } + } + } + + if (bExtrapolate) + { + _Derivative_Linear(pOut, &history[realOlder], &history[info.newer]); + + float flDestTime = currentTime - m_InterpolationAmount; + float diff = flDestTime - history[info.newer].changetime; + diff = clamp(diff, 0.f, cl_extrapolate_amount.GetFloat() * 2); + if (diff > cl_extrapolate_amount.GetFloat()) + { + float scale = 1 - (diff - cl_extrapolate_amount.GetFloat()) / cl_extrapolate_amount.GetFloat(); + for (int i = 0; i < m_nMaxCount; i++) + { + pOut[i] *= scale; + } + } + } + else + { + _Derivative_Linear(pOut, &history[info.older], &history[info.newer]); + } + +} + + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::Interpolate(float currentTime) +{ + return Interpolate(currentTime, m_InterpolationAmount); +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::Copy(IInterpolatedVar* pInSrc) +{ + CInterpolatedVarArrayBase* pSrc = dynamic_cast*>(pInSrc); + + if (!pSrc || pSrc->m_nMaxCount != m_nMaxCount) + { + if (pSrc) + { + AssertMsg3(false, "pSrc->m_nMaxCount (%i) != m_nMaxCount (%i) for %s.", pSrc->m_nMaxCount, m_nMaxCount, m_pDebugName); + } + else + { + AssertMsg(false, "pSrc was null in CInterpolatedVarArrayBase::Copy."); + } + + return; + } + + Assert((m_fType & ~EXCLUDE_AUTO_INTERPOLATE) == (pSrc->m_fType & ~EXCLUDE_AUTO_INTERPOLATE)); + Assert(m_pDebugName == pSrc->GetDebugName()); + + for (int i = 0; i < m_nMaxCount; i++) + { + m_LastNetworkedValue[i] = pSrc->m_LastNetworkedValue[i]; + m_bLooping[i] = pSrc->m_bLooping[i]; + } + + m_LastNetworkedTime = pSrc->m_LastNetworkedTime; + + m_VarHistory.RemoveAll(); + + for (int i = 0; i < pSrc->m_VarHistory.Count(); i++) + { + int newslot = m_VarHistory.AddToTail(); + + CInterpolatedVarEntry* dest = &m_VarHistory[newslot]; + CInterpolatedVarEntry* src = &pSrc->m_VarHistory[i]; + dest->NewEntry(src->GetValue(), m_nMaxCount, src->changetime); + } +} + +template< typename Type, bool IS_ARRAY > +inline const Type& CInterpolatedVarArrayBase::GetPrev(int iArrayIndex) const +{ + Assert(m_pValue); + Assert(iArrayIndex >= 0 && iArrayIndex < m_nMaxCount); + + if (m_VarHistory.Count() > 1) + { + return m_VarHistory[1].GetValue()[iArrayIndex]; + } + return m_pValue[iArrayIndex]; +} + +template< typename Type, bool IS_ARRAY > +inline const Type& CInterpolatedVarArrayBase::GetCurrent(int iArrayIndex) const +{ + Assert(m_pValue); + Assert(iArrayIndex >= 0 && iArrayIndex < m_nMaxCount); + + if (m_VarHistory.Count() > 0) + { + return m_VarHistory[0].GetValue()[iArrayIndex]; + } + return m_pValue[iArrayIndex]; +} + +template< typename Type, bool IS_ARRAY > +inline float CInterpolatedVarArrayBase::GetInterval() const +{ + if (m_VarHistory.Count() > 1) + { + return m_VarHistory[0].changetime - m_VarHistory[1].changetime; + } + + return 0.0f; +} + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::IsValidIndex(int i) +{ + return m_VarHistory.IsValidIndex(i); +} + +template< typename Type, bool IS_ARRAY > +inline Type* CInterpolatedVarArrayBase::GetHistoryValue(int index, float& changetime, int iArrayIndex) +{ + Assert(iArrayIndex >= 0 && iArrayIndex < m_nMaxCount); + if (m_VarHistory.IsIdxValid(index)) + { + CInterpolatedVarEntry* entry = &m_VarHistory[index]; + changetime = entry->changetime; + return &entry->GetValue()[iArrayIndex]; + } + else + { + changetime = 0.0f; + return NULL; + } +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetHistoryValuesForItem(int item, Type& value) +{ + Assert(item >= 0 && item < m_nMaxCount); + + for (int i = 0; i < m_VarHistory.Count(); i++) + { + CInterpolatedVarEntry* entry = &m_VarHistory[i]; + entry->GetValue()[item] = value; + } +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetLooping(bool looping, int iArrayIndex) +{ + Assert(iArrayIndex >= 0 && iArrayIndex < m_nMaxCount); + m_bLooping[iArrayIndex] = looping; +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::SetMaxCount(int newmax) +{ + bool changed = (newmax != m_nMaxCount) ? true : false; + + newmax = MAX(1, newmax); + + m_nMaxCount = newmax; + if (changed) + { + delete[] m_bLooping; + delete[] m_LastNetworkedValue; + m_bLooping = new byte[m_nMaxCount]; + m_LastNetworkedValue = new Type[m_nMaxCount]; + memset(m_bLooping, 0, sizeof(byte) * m_nMaxCount); + memset(m_LastNetworkedValue, 0, sizeof(Type) * m_nMaxCount); + + Reset(); + } +} + + +template< typename Type, bool IS_ARRAY > +inline int CInterpolatedVarArrayBase::GetMaxCount() const +{ + return m_nMaxCount; +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Interpolate(Type* out, float frac, CInterpolatedVarEntry* start, CInterpolatedVarEntry* end) +{ + Assert(start); + Assert(end); + + if (start == end) + { + for (int i = 0; i < m_nMaxCount; i++) + { + out[i] = end->GetValue()[i]; + Lerp_Clamp(out[i]); + } + return; + } + + Assert(frac >= 0.0f && frac <= 1.0f); + + for (int i = 0; i < m_nMaxCount; i++) + { + if (m_bLooping[i]) + { + out[i] = LoopingLerp(frac, start->GetValue()[i], end->GetValue()[i]); + } + else + { + out[i] = Lerp(frac, start->GetValue()[i], end->GetValue()[i]); + } + Lerp_Clamp(out[i]); + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Extrapolate( + Type* pOut, + CInterpolatedVarEntry* pOld, + CInterpolatedVarEntry* pNew, + float flDestinationTime, + float flMaxExtrapolationAmount +) +{ + if (fabs(pOld->changetime - pNew->changetime) < 0.001f || flDestinationTime <= pNew->changetime) + { + for (int i = 0; i < m_nMaxCount; i++) + pOut[i] = pNew->GetValue()[i]; + } + else + { + float flExtrapolationAmount = MIN(flDestinationTime - pNew->changetime, flMaxExtrapolationAmount); + + float divisor = 1.0f / (pNew->changetime - pOld->changetime); + for (int i = 0; i < m_nMaxCount; i++) + { + pOut[i] = ExtrapolateInterpolatedVarType(pOld->GetValue()[i], pNew->GetValue()[i], divisor, flExtrapolationAmount); + } + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::TimeFixup2_Hermite( + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry& fixup, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& prev, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& start, + float dt1 +) +{ + float dt2 = start->changetime - prev->changetime; + + if (fabs(dt1 - dt2) > 0.0001f && + dt2 > 0.0001f) + { + float frac = dt1 / dt2; + + fixup.changetime = start->changetime - dt1; + + for (int i = 0; i < m_nMaxCount; i++) + { + if (m_bLooping[i]) + { + fixup.GetValue()[i] = LoopingLerp(1 - frac, prev->GetValue()[i], start->GetValue()[i]); + } + else + { + fixup.GetValue()[i] = Lerp(1 - frac, prev->GetValue()[i], start->GetValue()[i]); + } + } + + prev = &fixup; + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::TimeFixup_Hermite( + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry& fixup, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& prev, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& start, + typename CInterpolatedVarArrayBase::CInterpolatedVarEntry*& end) +{ + TimeFixup2_Hermite(fixup, prev, start, end->changetime - start->changetime); +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Interpolate_Hermite( + Type* out, + float frac, + CInterpolatedVarEntry* prev, + CInterpolatedVarEntry* start, + CInterpolatedVarEntry* end, + bool looping) +{ + Assert(start); + Assert(end); + + CDisableRangeChecks disableRangeChecks; + + CInterpolatedVarEntry fixup; + fixup.Init(m_nMaxCount); + TimeFixup_Hermite(fixup, prev, start, end); + + for (int i = 0; i < m_nMaxCount; i++) + { + if (m_bLooping[i]) + { + out[i] = LoopingLerp_Hermite(frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i]); + } + else + { + out[i] = Lerp_Hermite(frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i]); + } + + Lerp_Clamp(out[i]); + } +} + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Derivative_Hermite( + Type* out, + float frac, + CInterpolatedVarEntry* prev, + CInterpolatedVarEntry* start, + CInterpolatedVarEntry* end) +{ + Assert(start); + Assert(end); + + CDisableRangeChecks disableRangeChecks; + + CInterpolatedVarEntry fixup; + fixup.value = (Type*)_alloca(sizeof(Type) * m_nMaxCount); + TimeFixup_Hermite(fixup, prev, start, end); + + float divisor = 1.0f / (end->changetime - start->changetime); + + for (int i = 0; i < m_nMaxCount; i++) + { + Assert(!m_bLooping[i]); + out[i] = Derivative_Hermite(frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i]); + out[i] *= divisor; + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Derivative_Hermite_SmoothVelocity( + Type* out, + float frac, + CInterpolatedVarEntry* b, + CInterpolatedVarEntry* c, + CInterpolatedVarEntry* d) +{ + CInterpolatedVarEntry fixup; + fixup.Init(m_nMaxCount); + TimeFixup_Hermite(fixup, b, c, d); + for (int i = 0; i < m_nMaxCount; i++) + { + Type prevVel = (c->GetValue()[i] - b->GetValue()[i]) / (c->changetime - b->changetime); + Type curVel = (d->GetValue()[i] - c->GetValue()[i]) / (d->changetime - c->changetime); + out[i] = Lerp(frac, prevVel, curVel); + } +} + + +template< typename Type, bool IS_ARRAY > +inline void CInterpolatedVarArrayBase::_Derivative_Linear( + Type* out, + CInterpolatedVarEntry* start, + CInterpolatedVarEntry* end) +{ + if (start == end || fabs(start->changetime - end->changetime) < 0.0001f) + { + for (int i = 0; i < m_nMaxCount; i++) + { + out[i] = start->GetValue()[i] * 0; + } + } + else + { + float divisor = 1.0f / (end->changetime - start->changetime); + for (int i = 0; i < m_nMaxCount; i++) + { + out[i] = (end->GetValue()[i] - start->GetValue()[i]) * divisor; + } + } +} + + +template< typename Type, bool IS_ARRAY > +inline bool CInterpolatedVarArrayBase::ValidOrder() +{ + float newestchangetime = 0.0f; + bool first = true; + for (int i = 0; i < m_VarHistory.Count(); i++) + { + CInterpolatedVarEntry* entry = &m_VarHistory[i]; + if (first) + { + first = false; + newestchangetime = entry->changetime; + continue; + } + + if (entry->changetime > newestchangetime) + { + Assert(0); + return false; + } + + newestchangetime = entry->changetime; + } + + return true; +} + +template< typename Type, int COUNT > +class CInterpolatedVarArray : public CInterpolatedVarArrayBase +{ +public: + CInterpolatedVarArray(const char* pDebugName = "no debug name") + : CInterpolatedVarArrayBase(pDebugName) + { + this->SetMaxCount(COUNT); + } +}; + + +template< typename Type > +class CInterpolatedVar : public CInterpolatedVarArrayBase< Type, false > +{ +public: + CInterpolatedVar(const char* pDebugName = NULL) + : CInterpolatedVarArrayBase< Type, false >(pDebugName) + { + this->SetMaxCount(1); + } +}; + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/iprediction.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IPREDICTION_H ) +#define IPREDICTION_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "sdk/interface.h" +#include "sdk/vector.h" // Solely to get at define for QAngle + + +class IMoveHelper; + +//----------------------------------------------------------------------------- +// Purpose: Engine interface into client side prediction system +//----------------------------------------------------------------------------- +abstract_class IPrediction +{ +public: + virtual ~IPrediction(void) {}; + + virtual void Init(void) = 0; + virtual void Shutdown(void) = 0; + + // Run prediction + virtual void Update + ( + int startframe, // World update ( un-modded ) most recently received + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ) = 0; + + // We are about to get a network update from the server. We know the update #, so we can pull any + // data purely predicted on the client side and transfer it to the new from data state. + virtual void PreEntityPacketReceived(int commands_acknowledged, int current_world_update_packet) = 0; + virtual void PostEntityPacketReceived(void) = 0; + virtual void PostNetworkDataReceived(int commands_acknowledged) = 0; + + virtual void OnReceivedUncompressedPacket(void) = 0; + + // The engine needs to be able to access a few predicted values + virtual void GetViewOrigin(Vector& org) = 0; + virtual void SetViewOrigin(Vector& org) = 0; + virtual void GetViewAngles(QAngle& ang) = 0; + virtual void SetViewAngles(QAngle& ang) = 0; + virtual void GetLocalViewAngles(QAngle& ang) = 0; + virtual void SetLocalViewAngles(QAngle& ang) = 0; +}; + +extern IPrediction* g_pClientSidePrediction; + +#define VCLIENT_PREDICTION_INTERFACE_VERSION "VClientPrediction001" + +// +/* +class CBaseEntity; +typedef CBaseEntity C_BaseEntity; +typedef CBaseEntity CBasePlayer; +typedef CBaseEntity C_BasePlayer; +typedef CBaseEntity CCSPlayer; +typedef CBaseEntity C_CSPlayer; +typedef CBaseEntity C_BaseCombatCharacter; +typedef CBaseEntity CBaseCombatCharacter; +*/ + +class CMoveData; +class IMoveHelper; +class CPDumpPanel; +struct typedescription_t; + +//#pragma pack(push, 1) +//#pragma pack(pop) + +//----------------------------------------------------------------------------- +// Purpose: Implements prediction in the client .dll +//----------------------------------------------------------------------------- +class CPrediction : public IPrediction +{ + // Construction +public: + DECLARE_CLASS_GAMEROOT(CPrediction, IPrediction); + + CPrediction(void); + virtual ~CPrediction(void); + + virtual void Init(void); + virtual void Shutdown(void); + + // Implement IPrediction +public: + + virtual void Update + ( + int startframe, // World update ( un-modded ) most recently received + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ); + + virtual void PreEntityPacketReceived(int commands_acknowledged, int current_world_update_packet); + virtual void PostEntityPacketReceived(void); + virtual void PostNetworkDataReceived(int commands_acknowledged); + virtual void OnReceivedUncompressedPacket(void); + // The engine needs to be able to access a few predicted values + virtual void GetViewOrigin(Vector& org); + virtual void SetViewOrigin(Vector& org); + virtual void GetViewAngles(QAngle& ang); + virtual void SetViewAngles(QAngle& ang); + + virtual void GetLocalViewAngles(QAngle& ang); + virtual void SetLocalViewAngles(QAngle& ang); + + virtual bool InPrediction(void) const; + virtual bool IsFirstTimePredicted(void) const; + virtual int GetLastAcknowledgedCommandNumber(void)const; + +#if !defined( NO_ENTITY_PREDICTION ) + virtual int GetIncomingPacketNumber(void) const; +#endif + + float GetIdealPitch(int nSlot) const + { + if (nSlot == -1) + { + return 0.0f; + } + return 0.f;// m_Split[nSlot].m_flIdealPitch; + } + + virtual void CheckMovingGround(C_BasePlayer* player, double frametime); + + virtual void RunCommand(C_BasePlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper); + + // Internal +public: //dylan changed from protected + virtual void SetupMove(C_BasePlayer* player, CUserCmd* ucmd, IMoveHelper* pHelper, CMoveData* move); + virtual void FinishMove(C_BasePlayer* player, CUserCmd* ucmd, CMoveData* move); + virtual void SetIdealPitch(int nSlot, C_BasePlayer* player, const Vector& origin, const QAngle& angles, const Vector& viewheight); + + void CheckError(int nSlot, C_BasePlayer* player, int commands_acknowledged); + + // Called before and after any movement processing + void StartCommand(C_BasePlayer* player, CUserCmd* cmd); + void FinishCommand(C_BasePlayer* player); + + // Helpers to call pre and post think for player, and to call think if a think function is set + void RunPreThink(C_BasePlayer* player); + void RunThink(C_BasePlayer* ent, double frametime); + void RunPostThink(C_BasePlayer* player); + + void _Update_New + ( + int nSlot, + bool received_new_world_update, + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ); + +private: + virtual void _Update + ( + int nSlot, + bool received_new_world_update, + bool validframe, // Is frame data valid + int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded) + int outgoing_command // Last command (most recent) sent to server (un-modded) + ); + + // Actually does the prediction work, returns false if an error occurred + bool PerformPrediction(int nSlot, C_BasePlayer* localPlayer, bool received_new_world_update, int incoming_acknowledged, int outgoing_command); + + void ShiftIntermediateDataForward(int nSlot, int slots_to_remove, int previous_last_slot); + void ShiftFirstPredictedIntermediateDataForward(int nSlot, int acknowledged); + void RestoreEntityToPredictedFrame(int nSlot, int predicted_frame); + int ComputeFirstCommandToExecute(int nSlot, bool received_new_world_update, int incoming_acknowledged, int outgoing_command); + int ComputeFirstCommandToExecute_New(CBaseEntity* pPlayer, int nSlot, bool received_new_world_update, int incoming_acknowledged, int outgoing_command); + + void DumpEntity(C_BaseEntity* ent, int commands_acknowledged); + + void ShutdownPredictables(void); + void ReinitPredictables(void); + + void RemoveStalePredictedEntities(int nSlot, int last_command_packet); + void RestoreOriginalEntityState(int nSlot); + void RunSimulation(int current_command, float curtime, CUserCmd* cmd, C_BasePlayer* LocalPlayer); + void Untouch(int nSlot); + void StorePredictionResults(int nSlot, int predicted_frame); + bool ShouldDumpEntity(C_BaseEntity* ent); + + void SmoothViewOnMovingPlatform(C_BasePlayer* pPlayer, Vector& offset); + +#if !defined( NO_ENTITY_PREDICTION ) + // Data +public: + // Last object the player was standing on + CHandle< C_BaseEntity > m_hLastGround; //0x4 + bool m_bInPrediction; //0x8 + bool m_bFirstTimePredicted; //0x9 + bool m_bEnginePaused; //0x0A + bool m_bOldCLPredictValue; //0x0B + int m_nPreviousStartFrame; //0x0C + int m_nIncomingPacketNumber; //0x10 + float m_flLastServerWorldTimeStamp; //0x14 + // Last network origin for local player + +#pragma pack(push, 1) + struct Split_t + { + Split_t() //note: incomplete + { + m_bFirstTimePredicted = false; + m_nCommandsPredicted = 0; + m_nServerCommandsAcknowledged = 0; + m_bPreviousAckHadErrors = false; + //m_flIdealPitch = 0.0f; + + } + + bool m_bFirstTimePredicted; //0x18 + char pad[3]; + int m_nCommandsPredicted; //0x1C + int m_nServerCommandsAcknowledged; //0x20 set in PostNetworkDataReceived + int m_bPreviousAckHadErrors; //0x24 set in PostNetworkDataReceived + int pad2; //0x28 + int m_nIncomingAcknowledged; //0x2C + char m_bUnknown; //0x30 set in PostNetworkDataReceived + char pad3[3]; //0x31 + + CUtlVector m_vecPredictionHandles; //0x34 + bool m_bUnknown2; + char pad4[3]; + //char pad4[12]; //0x34 + //int pad5; //0x40 set in PostNetworkDataReceived + //int pad6[2]; //0x44 + + //end 0x4C + };//size 0x34 bytes +#pragma pack(pop) + + Split_t m_Split[1]; //0x18 //MAX_SPLITSCREEN_PLAYERS + IGlobalVarsBase m_SavedVars; //0x4C + bool m_bPlayerOriginTypedescriptionSearched; + CUtlVector< const typedescription_t* > m_PlayerOriginTypeDescription; // A vector in cases where the .x, .y, and .z are separately listed + + CPDumpPanel* m_pPDumpPanel; + +#endif + + + bool InPrediction_v() { + typedef bool(__thiscall* o_in_prediction)(void*); + return getvfunc(this, 10)(this); + } + + void RunCommand_v(C_BaseEntity* player, CUserCmd* cmd, IMoveHelper* helper) { + typedef void(__thiscall* o_run_command)(void*, C_BaseEntity*, CUserCmd*, IMoveHelper*); + return getvfunc(this, 19)(this, player, cmd, helper); + } + + void SetupMove_v(C_BaseEntity* player, CUserCmd* cmd, IMoveHelper* helper, void* data) { + typedef void(__thiscall* o_setup_move)(void*, C_BaseEntity*, CUserCmd*, IMoveHelper*, void*); + return getvfunc(this, 20)(this, player, cmd, helper, data); + } + + void FinishMove_v(C_BaseEntity* player, CUserCmd* cmd, void* data) { + typedef void(__thiscall* o_finish_move)(void*, C_BaseEntity*, CUserCmd*, void*); + return getvfunc(this, 21)(this, player, cmd, data); + } + +}; + +#endif // IPREDICTION_H + +``` + +`SpyCustom/sdk/ipredictionsystem.h`: + +```h +#ifndef IPREDICTIONSYSTEM_H +#define IPREDICTIONSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "predictable_entity.h" + +class CBaseEntity; + +class IPredictionSystem +{ +public: + IPredictionSystem() + { + m_pNextSystem = g_pPredictionSystems; + g_pPredictionSystems = this; + + m_bSuppressEvent = false; + m_pSuppressHost = NULL; + + m_nStatusPushed = 0; + }; + + virtual ~IPredictionSystem() {}; + + IPredictionSystem* GetNext() + { + return m_pNextSystem; + } + + void SetSuppressEvent(bool state) + { + m_bSuppressEvent = state; + } + + void SetSuppressHost(CBaseEntity* host) + { + m_pSuppressHost = host; + } + + CBaseEntity const* GetSuppressHost(void) + { + if (DisableFiltering()) + { + return NULL; + } + + return m_pSuppressHost; + } + + bool CanPredict(void) const + { + if (DisableFiltering()) + { + return false; + } + + return !m_bSuppressEvent; + } + + static IPredictionSystem* g_pPredictionSystems; + + static void SuppressEvents(bool state) + { + IPredictionSystem* sys = g_pPredictionSystems; + while (sys) + { + sys->SetSuppressEvent(state); + sys = sys->GetNext(); + } + } + + static void SuppressHostEvents(CBaseEntity* host) + { + IPredictionSystem* sys = g_pPredictionSystems; + while (sys) + { + sys->SetSuppressHost(host); + sys = sys->GetNext(); + } + } + +private: + + static void Push(void) + { + IPredictionSystem* sys = g_pPredictionSystems; + while (sys) + { + sys->_Push(); + sys = sys->GetNext(); + } + } + + static void Pop(void) + { + IPredictionSystem* sys = g_pPredictionSystems; + while (sys) + { + sys->_Pop(); + sys = sys->GetNext(); + } + } + + void _Push(void) + { + ++m_nStatusPushed; + } + void _Pop(void) + { + --m_nStatusPushed; + } + + bool DisableFiltering(void) const + { + return (m_nStatusPushed > 0) ? true : false; + } + + IPredictionSystem* m_pNextSystem; + bool m_bSuppressEvent; + CBaseEntity* m_pSuppressHost; + + int m_nStatusPushed; + + friend class CDisablePredictionFiltering; +}; + +class CDisablePredictionFiltering +{ +public: + CDisablePredictionFiltering(bool disable = true) + { + m_bDisabled = disable; + if (m_bDisabled) + { + IPredictionSystem::Push(); + } + } + + ~CDisablePredictionFiltering(void) + { + if (m_bDisabled) + { + IPredictionSystem::Pop(); + } + } +private: + bool m_bDisabled; +}; + +#endif +``` + +`SpyCustom/sdk/irecipientfilter.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IRECIPIENTFILTER_H +#define IRECIPIENTFILTER_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Generic interface for routing messages to users +//----------------------------------------------------------------------------- +class IRecipientFilter +{ +public: + virtual ~IRecipientFilter() {} + + virtual bool IsReliable(void) const = 0; + virtual bool IsInitMessage(void) const = 0; + + virtual int GetRecipientCount(void) const = 0; + virtual int GetRecipientIndex(int slot) const = 0; +}; + +#endif // IRECIPIENTFILTER_H +``` + +`SpyCustom/sdk/iscenetokenprocessor.h`: + +```h +#ifndef ISCENETOKENPROCESSOR_H +#define ISCENETOKENPROCESSOR_H +#ifdef _WIN32 +#pragma once +#endif + +class ISceneTokenProcessor +{ +public: + virtual const char* CurrentToken(void) = 0; + virtual bool GetToken(bool crossline) = 0; + virtual bool TokenAvailable(void) = 0; + virtual void Error(PRINTF_FORMAT_STRING const char* fmt, ...) = 0; +}; + +#endif +``` + +`SpyCustom/sdk/iserverentity.h`: + +```h +#ifndef ISERVERENTITY_H +#define ISERVERENTITY_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "iserverunknown.h" +#include "string_t.h" + + + +struct Ray_t; +class ServerClass; +class ICollideable; +class IServerNetworkable; +class Vector; +class QAngle; + +class IServerEntity : public IServerUnknown +{ +public: + virtual ~IServerEntity() {} + + virtual int GetModelIndex(void) const = 0; + virtual string_t GetModelName(void) const = 0; + + virtual void SetModelIndex(int index) = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/iservernetworkable.h`: + +```h +#ifndef ISERVERNETWORKABLE_H +#define ISERVERNETWORKABLE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ihandleentity.h" +#include "basetypes.h" +#include "bitvec.h" +#include "const.h" +#include "bspfile.h" + + + +#define MAX_FAST_ENT_CLUSTERS 4 +#define MAX_ENT_CLUSTERS 64 +#define MAX_WORLD_AREAS 8 + + +class ServerClass; +class SendTable; +struct edict_t; +class CBaseEntity; +class CSerialEntity; +class CBaseNetworkable; + + +class CCheckTransmitInfo +{ +public: + edict_t* m_pClientEnt; + byte m_PVS[PAD_NUMBER(MAX_MAP_CLUSTERS, 8) / 8]; + int m_nPVSSize; + + CBitVec* m_pTransmitEdict; + CBitVec* m_pTransmitAlways; + + int m_AreasNetworked; + int m_Areas[MAX_WORLD_AREAS]; + + byte m_AreaFloodNums[MAX_MAP_AREAS]; + int m_nMapAreas; +}; + +struct PVSInfo_t +{ + short m_nHeadNode; + + short m_nClusterCount; + + unsigned short* m_pClusters; + + short m_nAreaNum; + short m_nAreaNum2; + + float m_vCenter[3]; + +private: + unsigned short m_pClustersInline[MAX_FAST_ENT_CLUSTERS]; + + friend class CVEngineServer; +}; + + +class IServerNetworkable +{ +public: + virtual IHandleEntity* GetEntityHandle() = 0; + + virtual ServerClass* GetServerClass() = 0; + + virtual edict_t* GetEdict() const = 0; + + virtual const char* GetClassName() const = 0; + virtual void Release() = 0; + + virtual int AreaNum() const = 0; + + virtual CBaseNetworkable* GetBaseNetworkable() = 0; + virtual CBaseEntity* GetBaseEntity() = 0; + virtual PVSInfo_t* GetPVSInfo() = 0; + +protected: + virtual ~IServerNetworkable() {} +}; + + +#endif +``` + +`SpyCustom/sdk/iserverplugin.h`: + +```h +#ifndef ISERVERPLUGIN_H +#define ISERVERPLUGIN_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "edict.h" +#include "interface.h" +#include "KeyValues.h" + +class CCommand; + +typedef enum +{ + PLUGIN_CONTINUE = 0, + PLUGIN_OVERRIDE, + PLUGIN_STOP, +} PLUGIN_RESULT; + + +typedef enum +{ + eQueryCvarValueStatus_ValueIntact = 0, + eQueryCvarValueStatus_CvarNotFound = 1, + eQueryCvarValueStatus_NotACvar = 2, + eQueryCvarValueStatus_CvarProtected = 3 +} EQueryCvarValueStatus; + + +typedef int QueryCvarCookie_t; +#define InvalidQueryCvarCookie -1 + + +#define INTERFACEVERSION_ISERVERPLUGINCALLBACKS_VERSION_1 "ISERVERPLUGINCALLBACKS001" +#define INTERFACEVERSION_ISERVERPLUGINCALLBACKS_VERSION_2 "ISERVERPLUGINCALLBACKS002" +#define INTERFACEVERSION_ISERVERPLUGINCALLBACKS "ISERVERPLUGINCALLBACKS003" + +abstract_class IServerPluginCallbacks +{ +public: + virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) = 0; + + virtual void Unload(void) = 0; + + virtual void Pause(void) = 0; + + virtual void UnPause(void) = 0; + + virtual const char* GetPluginDescription(void) = 0; + + virtual void LevelInit(char const* pMapName) = 0; + + virtual void ServerActivate(edict_t* pEdictList, int edictCount, int clientMax) = 0; + + virtual void GameFrame(bool simulating) = 0; + + virtual void LevelShutdown(void) = 0; + + virtual void ClientActive(edict_t* pEntity) = 0; + + virtual void ClientDisconnect(edict_t* pEntity) = 0; + + virtual void ClientPutInServer(edict_t* pEntity, char const* playername) = 0; + + virtual void SetCommandClient(int index) = 0; + + virtual void ClientSettingsChanged(edict_t* pEdict) = 0; + + virtual PLUGIN_RESULT ClientConnect(bool* bAllowConnect, edict_t* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) = 0; + + virtual PLUGIN_RESULT ClientCommand(edict_t* pEntity, const CCommand& args) = 0; + + virtual PLUGIN_RESULT NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) = 0; + + virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t* pPlayerEntity, EQueryCvarValueStatus eStatus, const char* pCvarName, const char* pCvarValue) = 0; + + virtual void OnEdictAllocated(edict_t* edict) = 0; + virtual void OnEdictFreed(const edict_t* edict) = 0; +}; + +#define INTERFACEVERSION_ISERVERPLUGINHELPERS "ISERVERPLUGINHELPERS001" + + +typedef enum +{ + DIALOG_MSG = 0, + DIALOG_MENU, + DIALOG_TEXT, + DIALOG_ENTRY, + DIALOG_ASKCONNECT +} DIALOG_TYPE; + +abstract_class IServerPluginHelpers +{ +public: + virtual void CreateMessage(edict_t * pEntity, DIALOG_TYPE type, KeyValues * data, IServerPluginCallbacks * plugin) = 0; + virtual void ClientCommand(edict_t* pEntity, const char* cmd) = 0; + + virtual QueryCvarCookie_t StartQueryCvarValue(edict_t* pEntity, const char* pName) = 0; +}; + +#endif +``` + +`SpyCustom/sdk/iserverunknown.h`: + +```h +#ifndef ISERVERUNKNOWN_H +#define ISERVERUNKNOWN_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "ihandleentity.h" + +class ICollideable; +class IServerNetworkable; +class CBaseEntity; + + +class IServerUnknown : public IHandleEntity +{ +public: + virtual ICollideable* GetCollideable() = 0; + virtual IServerNetworkable* GetNetworkable() = 0; + virtual CBaseEntity* GetBaseEntity() = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/ishadowmgr.h`: + +```h +#ifndef ISHADOWMGR_H +#define ISHADOWMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "vmatrix.h" + + +class IMaterial; +class Vector; +class Vector2D; +struct model_t; +typedef unsigned short ModelInstanceHandle_t; +class IClientRenderable; +class ITexture; + +#define ENGINE_SHADOWMGR_INTERFACE_VERSION "VEngineShadowMgr002" + + +enum ShadowFlags_t +{ + SHADOW_FLAGS_FLASHLIGHT = (1 << 0), + SHADOW_FLAGS_SHADOW = (1 << 1), + SHADOW_FLAGS_LAST_FLAG = SHADOW_FLAGS_SHADOW +}; + +#define SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SHADOW ) + + + +typedef unsigned short ShadowHandle_t; + +enum +{ + SHADOW_HANDLE_INVALID = (ShadowHandle_t)~0 +}; + + +enum ShadowCreateFlags_t +{ + SHADOW_CACHE_VERTS = (1 << 0), + SHADOW_FLASHLIGHT = (1 << 1), + + SHADOW_LAST_FLAG = SHADOW_FLASHLIGHT, +}; + + +struct ShadowInfo_t +{ + VMatrix m_WorldToShadow; + + float m_FalloffOffset; + float m_MaxDist; + float m_FalloffAmount; + Vector2D m_TexOrigin; + Vector2D m_TexSize; + unsigned char m_FalloffBias; +}; + +struct FlashlightState_t; + +abstract_class IShadowMgr +{ +public: + virtual ShadowHandle_t CreateShadow(IMaterial * pMaterial, IMaterial * pModelMaterial, void* pBindProxy, int creationFlags) = 0; + virtual void DestroyShadow(ShadowHandle_t handle) = 0; + + virtual void SetShadowMaterial(ShadowHandle_t handle, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy) = 0; + + virtual void ProjectShadow(ShadowHandle_t handle, const Vector& origin, + const Vector& projectionDir, const VMatrix& worldToShadow, const Vector2D& size, + int nLeafCount, const int* pLeafList, + float maxHeight, float falloffOffset, float falloffAmount, const Vector& vecCasterOrigin) = 0; + + virtual void ProjectFlashlight(ShadowHandle_t handle, const VMatrix& worldToShadow, int nLeafCount, const int* pLeafList) = 0; + + virtual const ShadowInfo_t& GetInfo(ShadowHandle_t handle) = 0; + + virtual const Frustum_t& GetFlashlightFrustum(ShadowHandle_t handle) = 0; + + virtual void AddShadowToBrushModel(ShadowHandle_t handle, + model_t* pModel, const Vector& origin, const QAngle& angles) = 0; + + virtual void RemoveAllShadowsFromBrushModel(model_t* pModel) = 0; + + virtual void SetShadowTexCoord(ShadowHandle_t handle, float x, float y, float w, float h) = 0; + + virtual void AddShadowToModel(ShadowHandle_t shadow, ModelInstanceHandle_t instance) = 0; + virtual void RemoveAllShadowsFromModel(ModelInstanceHandle_t instance) = 0; + + virtual void ClearExtraClipPlanes(ShadowHandle_t shadow) = 0; + virtual void AddExtraClipPlane(ShadowHandle_t shadow, const Vector& normal, float dist) = 0; + + virtual void EnableShadow(ShadowHandle_t shadow, bool bEnable) = 0; + + virtual void SetFalloffBias(ShadowHandle_t shadow, unsigned char ucBias) = 0; + + virtual void UpdateFlashlightState(ShadowHandle_t shadowHandle, const FlashlightState_t& lightState) = 0; + + virtual void DrawFlashlightDepthTexture() = 0; + + virtual void AddFlashlightRenderable(ShadowHandle_t shadow, IClientRenderable* pRenderable) = 0; + virtual ShadowHandle_t CreateShadowEx(IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags) = 0; + + virtual void SetFlashlightDepthTexture(ShadowHandle_t shadowHandle, ITexture* pFlashlightDepthTexture, unsigned char ucShadowStencilBit) = 0; + + virtual const FlashlightState_t& GetFlashlightState(ShadowHandle_t handle) = 0; + + virtual void SetFlashlightRenderState(ShadowHandle_t handle) = 0; +}; + + +#endif +``` + +`SpyCustom/sdk/ispatialpartition.h`: + +```h +#ifndef ISPATIALPARTITION_H +#define ISPATIALPARTITION_H + +#include "interface.h" + +class Vector; +struct Ray_t; +class IHandleEntity; + + +#define INTERFACEVERSION_SPATIALPARTITION "SpatialPartition001" + +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), +}; + +#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 +}; + + +abstract_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; +}; + +#endif + + +``` + +`SpyCustom/sdk/isteamapplist.h`: + +```h +//====== 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 "isteamclient.h" +#include "steamtypes.h" + +//----------------------------------------------------------------------------- +// Purpose: This is a restricted interface that can only be used by previously approved apps, +// contact your Steam Account Manager if you believe you need access to this API. +// This interface lets you detect installed apps for the local Steam client, useful for debugging tools +// to offer lists of apps to debug via Steam. +//----------------------------------------------------------------------------- +class ISteamAppList +{ +public: + virtual uint32 GetNumInstalledApps() = 0; + virtual uint32 GetInstalledApps( AppId_t *pvecAppID, uint32 unMaxAppIDs ) = 0; + + virtual int GetAppName( AppId_t nAppID, 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" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +//--------------------------------------------------------------------------------- +// Purpose: Sent when a new app is installed +//--------------------------------------------------------------------------------- +DEFINE_CALLBACK( SteamAppInstalled_t, k_iSteamAppListCallbacks + 1 ); + CALLBACK_MEMBER( 0, AppId_t, m_nAppID ) // ID of the app that installs +END_DEFINE_CALLBACK_1() + + +//--------------------------------------------------------------------------------- +// Purpose: Sent when an app is uninstalled +//--------------------------------------------------------------------------------- +DEFINE_CALLBACK( SteamAppUninstalled_t, k_iSteamAppListCallbacks + 2 ); + CALLBACK_MEMBER( 0, AppId_t, m_nAppID ) // ID of the app that installs +END_DEFINE_CALLBACK_1() + + +#pragma pack( pop ) +#endif // ISTEAMAPPLIST_H +``` + +`SpyCustom/sdk/isteamapps.h`: + +```h +//====== 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 + +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) + + virtual CSteamID GetAppOwner() = 0; // returns the SteamID of the original owner. If different from current user, it's borrowed + + // Returns the associated launch param if the game is run via steam://run///?param1=value1;param2=value2;param3=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. + 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; +}; + +#define STEAMAPPS_INTERFACE_VERSION "STEAMAPPS_INTERFACE_VERSION008" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +//----------------------------------------------------------------------------- +// Purpose: posted after the user gains ownership of DLC & that DLC is installed +//----------------------------------------------------------------------------- +struct DlcInstalled_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 5 }; + AppId_t m_nAppID; // AppID of the DLC +}; + + +//----------------------------------------------------------------------------- +// Purpose: possible results when registering an activation code +//----------------------------------------------------------------------------- +enum ERegisterActivationCodeResult +{ + k_ERegisterActivationCodeResultOK = 0, + k_ERegisterActivationCodeResultFail = 1, + k_ERegisterActivationCodeResultAlreadyRegistered = 2, + k_ERegisterActivationCodeResultTimeout = 3, + k_ERegisterActivationCodeAlreadyOwned = 4, +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to RegisterActivationCode() +//----------------------------------------------------------------------------- +struct RegisterActivationCodeResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 8 }; + ERegisterActivationCodeResult m_eResult; + uint32 m_unPackageRegistered; // package that was registered. Only set on success +}; + + +//--------------------------------------------------------------------------------- +// Purpose: posted after the user gains executes a steam url with query parameters +// such as steam://run///?param1=value1;param2=value2;param3=value3; etc +// while the game is already running. The new params can be queried +// with GetLaunchQueryParam. +//--------------------------------------------------------------------------------- +struct NewLaunchQueryParameters_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]; +}; + + +#pragma pack( pop ) +#endif // ISTEAMAPPS_H +``` + +`SpyCustom/sdk/isteamcontroller.h`: + +```h +//====== Copyright 1996-2013, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to valve controller +// +//============================================================================= + +#ifndef ISTEAMCONTROLLER_H +#define ISTEAMCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +#define STEAM_CONTROLLER_MAX_COUNT 16 + +#define STEAM_CONTROLLER_MAX_ANALOG_ACTIONS 16 + +#define STEAM_CONTROLLER_MAX_DIGITAL_ACTIONS 128 + +#define STEAM_CONTROLLER_MAX_ORIGINS 8 + +// 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 + +enum ESteamControllerPad +{ + k_ESteamControllerPad_Left, + k_ESteamControllerPad_Right +}; + +enum EControllerSource +{ + k_EControllerSource_None, + k_EControllerSource_LeftTrackpad, + k_EControllerSource_RightTrackpad, + k_EControllerSource_Joystick, + k_EControllerSource_ABXY, + k_EControllerSource_Switch, + k_EControllerSource_LeftTrigger, + k_EControllerSource_RightTrigger, + k_EControllerSource_Gyro, + k_EControllerSource_Count +}; + +enum EControllerSourceMode +{ + k_EControllerSourceMode_None, + k_EControllerSourceMode_Dpad, + k_EControllerSourceMode_Buttons, + k_EControllerSourceMode_FourButtons, + k_EControllerSourceMode_AbsoluteMouse, + k_EControllerSourceMode_RelativeMouse, + k_EControllerSourceMode_JoystickMove, + k_EControllerSourceMode_JoystickCamera, + k_EControllerSourceMode_ScrollWheel, + k_EControllerSourceMode_Trigger, + k_EControllerSourceMode_TouchMenu, + k_EControllerSourceMode_MouseJoystick, + k_EControllerSourceMode_MouseRegion +}; + +enum EControllerActionOrigin +{ + 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, + + k_EControllerActionOrigin_Count +}; + +// 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 ) + +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; +}; + +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Native Steam controller support 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. + 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( ControllerHandle_t *handlesOut ) = 0; + + // Invokes the Steam overlay and brings up the binding screen + // Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode + virtual bool ShowBindingPanel( ControllerHandle_t controllerHandle ) = 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; + + // 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 + virtual int GetDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, 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 + virtual int GetAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin *originsOut ) = 0; + + virtual void StopAnalogActionMomentum( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction ) = 0; + + // Trigger a haptic pulse on a controller + virtual void TriggerHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ) = 0; + + virtual void TriggerRepeatedHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ) = 0; +}; + +#define STEAMCONTROLLER_INTERFACE_VERSION "SteamController003" + +#endif // ISTEAMCONTROLLER_H +``` + +`SpyCustom/sdk/isteamfriends.h`: + +```h +//====== Copyright (C) 1996-2008, 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 "isteamclient.h" +#include "steamclientpublic.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 = 7, + + // 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_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, + 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 isteamclient.h must be included +#endif +struct FriendGameInfo_t +{ + CGameID m_gameID; + uint32 m_unGameIP; + uint16 m_usGamePort; + uint16 m_usQueryPort; + CSteamID m_steamIDLobby; +}; +#pragma pack( pop ) + +// maximum number of characters in a user's name. Two flavors; one for UTF-8 and one for UTF-16. +// The UTF-8 version has to be very generous to accomodate characters that get large when encoded +// in UTF-8. +enum +{ + k_cchPersonaNameMax = 128, + k_cwchPersonaNameMax = 32, +}; + +//----------------------------------------------------------------------------- +// Purpose: user restriction flags +//----------------------------------------------------------------------------- +enum EUserRestriction +{ + k_nUserRestrictionNone = 0, // no known chat/content restriction + k_nUserRestrictionUnknown = 1, // we don't know yet (user offline) + k_nUserRestrictionAnyChat = 2, // user is not allowed to (or can't) send/recv any chat + k_nUserRestrictionVoiceChat = 4, // user is not allowed to (or can't) send/recv voice chat + k_nUserRestrictionGroupChat = 8, // user is not allowed to (or can't) send/recv group chat + k_nUserRestrictionRating = 16, // user is too young according to rating in current region + k_nUserRestrictionGameInvites = 32, // user cannot send or recv game invites (e.g. mobile) + k_nUserRestrictionTrading = 64, // user cannot participate in trading (console, mobile) +}; + +//----------------------------------------------------------------------------- +// Purpose: information about user sessions +//----------------------------------------------------------------------------- +struct FriendSessionStateInfo_t +{ + uint32 m_uiOnlineSessionInstances; + uint8 m_uiPublishedToFriendsSessionInstance; +}; + + + +// size limit on chat room or member metadata +const uint32 k_cubChatMetadataMax = 8192; + +// size limits on Rich Presence data +enum { k_cchMaxRichPresenceKeys = 20 }; +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: 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. + 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, 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. + 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, OUT_ARRAY_CALL(nMembersCount, GetFriendsGroupMembersCount, friendsGroupID ) CSteamID *pOutSteamIDMembers, int nMembersCount ) = 0; + + // returns true if the specified user meets any of the criteria specified in iFriendFlags + // iFriendFlags can be the union (binary or, |) of one or more k_EFriendFlags values + virtual bool HasFriend( CSteamID steamIDFriend, int iFriendFlags ) = 0; + + // clan (group) iteration and access functions + virtual int GetClanCount() = 0; + virtual CSteamID GetClanByIndex( int iClan ) = 0; + virtual const char *GetClanName( CSteamID steamIDClan ) = 0; + virtual const char *GetClanTag( CSteamID steamIDClan ) = 0; + // returns the most recent information we have about what's happening in a clan + virtual bool GetClanActivityCounts( CSteamID steamIDClan, int *pnOnline, int *pnInGame, int *pnChatting ) = 0; + // for clans a user is a member of, they will have reasonably up-to-date information, but for others you'll have to download the info to have the latest + virtual SteamAPICall_t DownloadClanActivityCounts( 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 are "Friends", "Community", "Players", "Settings", "OfficialGameGroup", "Stats", "Achievements" + 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 ) = 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 + 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 + // Up to 20 different keys can be set + // There are two magic keys: + // "status" - a UTF-8 string that will show up in the 'view game info' dialog in the Steam friends list + // "connect" - a UTF-8 string that contains the command-line for how a friend can connect to a game + // GetFriendRichPresence() returns an empty string "" if no value is set + // SetRichPresence() to a NULL or an empty string deletes the key + // You can iterate the current set of keys for a friend with GetFriendRichPresenceKeyCount() + // and GetFriendRichPresenceKeyByIndex() (typically only used for debugging) + virtual bool SetRichPresence( const char *pchKey, const char *pchValue ) = 0; + virtual void ClearRichPresence() = 0; + virtual const char *GetFriendRichPresence( CSteamID steamIDFriend, const char *pchKey ) = 0; + virtual int GetFriendRichPresenceKeyCount( CSteamID steamIDFriend ) = 0; + virtual const char *GetFriendRichPresenceKeyByIndex( CSteamID steamIDFriend, int iKey ) = 0; + // Requests rich presence for a specific user. + virtual void RequestFriendRichPresence( CSteamID steamIDFriend ) = 0; + + // rich invite support + // if the target accepts the invite, the pchConnectString gets added to the command-line for launching the game + // if the game is already running, a GameRichPresenceJoinRequested_t callback is posted containing the connect string + // invites can only be sent to friends + virtual bool InviteUserToGame( CSteamID steamIDFriend, const char *pchConnectString ) = 0; + + // recently-played-with friends iteration + // this iterates the entire list of users recently played with, across games + // GetFriendCoplayTime() returns as a unix time + virtual int GetCoplayFriendCount() = 0; + virtual CSteamID GetCoplayFriend( int iCoplayFriend ) = 0; + virtual int GetFriendCoplayTime( CSteamID steamIDFriend ) = 0; + virtual AppId_t GetFriendCoplayGame( CSteamID steamIDFriend ) = 0; + + // chat interface for games + // this allows in-game access to group (clan) chats from in the game + // the behavior is somewhat sophisticated, because the user may or may not be already in the group chat from outside the game or in the overlay + // use ActivateGameOverlayToUser( "chat", steamIDClan ) to open the in-game overlay version of the chat + 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, 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 + CALL_RESULT( FriendsGetFollowerCount_t ) + virtual SteamAPICall_t GetFollowerCount( CSteamID steamID ) = 0; + CALL_RESULT( FriendsIsFollowing_t ) + virtual SteamAPICall_t IsFollowing( CSteamID steamID ) = 0; + CALL_RESULT( FriendsEnumerateFollowingList_t ) + virtual SteamAPICall_t EnumerateFollowingList( uint32 unStartIndex ) = 0; +}; + +#define STEAMFRIENDS_INTERFACE_VERSION "SteamFriends015" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#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_EPersonaChangeFacebookInfo = 0x0800, + k_EPersonaChangeNickname = 0x1000, + k_EPersonaChangeSteamLevel = 0x2000, +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted when game overlay activates or deactivates +// the game can use this to be pause or resume single player games +//----------------------------------------------------------------------------- +struct GameOverlayActivated_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 31 }; + uint8 m_bActive; // true if it's just been activated, false otherwise +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a different game server from their friends list +// game client should attempt to connect to specified server when this is received +//----------------------------------------------------------------------------- +struct GameServerChangeRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 32 }; + char m_rgchServer[64]; // server address ("127.0.0.1:27015", "tf2.valvesoftware.com") + char m_rgchPassword[64]; // server password, if any +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a lobby from their friends list +// game client should attempt to connect to specified lobby when this is received +//----------------------------------------------------------------------------- +struct GameLobbyJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 33 }; + CSteamID m_steamIDLobby; + + // The friend they did the join via (will be invalid if not directly via a friend) + // + // On PS3, the friend will be invalid if this was triggered by a PSN invite via the XMB, but + // the account type will be console user so you can tell at least that this was from a PSN friend + // rather than a Steam friend. + CSteamID m_steamIDFriend; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when an avatar is loaded in from a previous GetLargeFriendAvatar() call +// if the image wasn't already available +//----------------------------------------------------------------------------- +struct AvatarImageLoaded_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 34 }; + CSteamID m_steamID; // steamid the avatar has been loaded for + int m_iImage; // the image index of the now loaded image + int m_iWide; // width of the loaded image + int m_iTall; // height of the loaded image +}; + + +//----------------------------------------------------------------------------- +// Purpose: marks the return of a request officer list call +//----------------------------------------------------------------------------- +struct ClanOfficerListResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 35 }; + CSteamID m_steamIDClan; + int m_cOfficers; + uint8 m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating updated data about friends rich presence information +//----------------------------------------------------------------------------- +struct FriendRichPresenceUpdate_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 36 }; + CSteamID m_steamIDFriend; // friend who's rich presence has changed + AppId_t m_nAppID; // the appID of the game (should always be the current game) +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a game from their friends list +// rich presence will have been set with the "connect" key which is set here +//----------------------------------------------------------------------------- +struct GameRichPresenceJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 37 }; + CSteamID m_steamIDFriend; // the friend they did the join via (will be invalid if not directly via a friend) + char m_rgchConnect[k_cchMaxRichPresenceValueLength]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received for a clan chat the game has joined +//----------------------------------------------------------------------------- +struct GameConnectedClanChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 38 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has joined a clan chat +//----------------------------------------------------------------------------- +struct GameConnectedChatJoin_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 39 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has left the chat we're in +//----------------------------------------------------------------------------- +struct GameConnectedChatLeave_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 40 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + bool m_bKicked; // true if admin kicked + bool m_bDropped; // true if Steam connection dropped +}; + + +//----------------------------------------------------------------------------- +// Purpose: a DownloadClanActivityCounts() call has finished +//----------------------------------------------------------------------------- +struct DownloadClanActivityCountsResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 41 }; + bool m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a JoinClanChatRoom() call has finished +//----------------------------------------------------------------------------- +struct JoinClanChatRoomCompletionResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 42 }; + CSteamID m_steamIDClanChat; + EChatRoomEnterResponse m_eChatRoomEnterResponse; +}; + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received from a user +//----------------------------------------------------------------------------- +struct GameConnectedFriendChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 43 }; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +struct FriendsGetFollowerCount_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 44 }; + EResult m_eResult; + CSteamID m_steamID; + int m_nCount; +}; + + +struct FriendsIsFollowing_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 45 }; + EResult m_eResult; + CSteamID m_steamID; + bool m_bIsFollowing; +}; + + +struct FriendsEnumerateFollowingList_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 46 }; + EResult m_eResult; + CSteamID m_rgSteamID[ k_cEnumerateFollowersMax ]; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; +}; + +//----------------------------------------------------------------------------- +// Purpose: reports the result of an attempt to change the user's persona name +//----------------------------------------------------------------------------- +struct SetPersonaNameResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 47 }; + + bool m_bSuccess; // true if name change succeeded completely. + bool m_bLocalSuccess; // true if name change was retained locally. (We might not have been able to communicate with Steam) + EResult m_result; // detailed result code +}; + + +#pragma pack( pop ) + +#endif // ISTEAMFRIENDS_H +``` + +`SpyCustom/sdk/isteamgamecoordinator.h`: + +```h +//====== 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 "steamtypes.h" +#include "steamclientpublic.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(int unMsgType, const void *pubData, int cubData ) = 0; + + // returns true if there is a message waiting from the game coordinator + virtual bool IsMessageAvailable(int*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(int*punMsgType, void *pubDest, int cubDest, int*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 isteamclient.h must be included +#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 +``` + +`SpyCustom/sdk/isteamhtmlsurface.h`: + +```h +//====== 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 "isteamclient.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. + // + 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 + virtual void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers ) = 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; + + // 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 + IGNOREATTR() + virtual void FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelectedFiles ) = 0; +}; + +#define STEAMHTMLSURFACE_INTERFACE_VERSION "STEAMHTMLSURFACE_INTERFACE_VERSION_003" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +//----------------------------------------------------------------------------- +// Purpose: The browser is ready for use +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_BrowserReady_t, k_iSteamHTMLSurfaceCallbacks + 1 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // this browser is now fully created and ready to navigate to pages +END_DEFINE_CALLBACK_1() + + +//----------------------------------------------------------------------------- +// Purpose: the browser has a pending paint +//----------------------------------------------------------------------------- +DEFINE_CALLBACK(HTML_NeedsPaint_t, k_iSteamHTMLSurfaceCallbacks + 2) +CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the browser that needs the paint +CALLBACK_MEMBER(1, const char *, pBGRA ) // a pointer to the B8G8R8A8 data for this surface, valid until SteamAPI_RunCallbacks is next called +CALLBACK_MEMBER(2, uint32, unWide) // the total width of the pBGRA texture +CALLBACK_MEMBER(3, uint32, unTall) // the total height of the pBGRA texture +CALLBACK_MEMBER(4, uint32, unUpdateX) // the offset in X for the damage rect for this update +CALLBACK_MEMBER(5, uint32, unUpdateY) // the offset in Y for the damage rect for this update +CALLBACK_MEMBER(6, uint32, unUpdateWide) // the width of the damage rect for this update +CALLBACK_MEMBER(7, uint32, unUpdateTall) // the height of the damage rect for this update +CALLBACK_MEMBER(8, uint32, unScrollX) // the page scroll the browser was at when this texture was rendered +CALLBACK_MEMBER(9, uint32, unScrollY) // the page scroll the browser was at when this texture was rendered +CALLBACK_MEMBER(10, float, flPageScale) // the page scale factor on this page when rendered +CALLBACK_MEMBER(11, uint32, unPageSerial) // incremented on each new page load, you can use this to reject draws while navigating to new pages +END_DEFINE_CALLBACK_12() + + +//----------------------------------------------------------------------------- +// Purpose: The browser wanted to navigate to a new page +// NOTE - you MUST call AllowStartRequest in response to this callback +//----------------------------------------------------------------------------- +DEFINE_CALLBACK(HTML_StartRequest_t, k_iSteamHTMLSurfaceCallbacks + 3) +CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the handle of the surface navigating +CALLBACK_MEMBER(1, const char *, pchURL) // the url they wish to navigate to +CALLBACK_MEMBER(2, const char *, pchTarget) // the html link target type (i.e _blank, _self, _parent, _top ) +CALLBACK_MEMBER(3, const char *, pchPostData ) // any posted data for the request +CALLBACK_MEMBER(4, bool, bIsRedirect) // true if this was a http/html redirect from the last load request +END_DEFINE_CALLBACK_5() + + +//----------------------------------------------------------------------------- +// Purpose: The browser has been requested to close due to user interaction (usually from a javascript window.close() call) +//----------------------------------------------------------------------------- +DEFINE_CALLBACK(HTML_CloseBrowser_t, k_iSteamHTMLSurfaceCallbacks + 4) +CALLBACK_MEMBER(0, HHTMLBrowser, unBrowserHandle) // the handle of the surface +END_DEFINE_CALLBACK_1() + + +//----------------------------------------------------------------------------- +// Purpose: the browser is navigating to a new url +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_URLChanged_t, k_iSteamHTMLSurfaceCallbacks + 5 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface navigating +CALLBACK_MEMBER( 1, const char *, pchURL ) // the url they wish to navigate to +CALLBACK_MEMBER( 2, const char *, pchPostData ) // any posted data for the request +CALLBACK_MEMBER( 3, bool, bIsRedirect ) // true if this was a http/html redirect from the last load request +CALLBACK_MEMBER( 4, const char *, pchPageTitle ) // the title of the page +CALLBACK_MEMBER( 5, bool, bNewNavigation ) // true if this was from a fresh tab and not a click on an existing page +END_DEFINE_CALLBACK_6() + + +//----------------------------------------------------------------------------- +// Purpose: A page is finished loading +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_FinishedRequest_t, k_iSteamHTMLSurfaceCallbacks + 6 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchURL ) // +CALLBACK_MEMBER( 2, const char *, pchPageTitle ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: a request to load this url in a new tab +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_OpenLinkInNewTab_t, k_iSteamHTMLSurfaceCallbacks + 7 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchURL ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: the page has a new title now +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_ChangedTitle_t, k_iSteamHTMLSurfaceCallbacks + 8 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchTitle ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: results from a search +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_SearchResults_t, k_iSteamHTMLSurfaceCallbacks + 9 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, unResults ) // +CALLBACK_MEMBER( 2, uint32, unCurrentMatch ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: page history status changed on the ability to go backwards and forward +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_CanGoBackAndForward_t, k_iSteamHTMLSurfaceCallbacks + 10 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, bool, bCanGoBack ) // +CALLBACK_MEMBER( 2, bool, bCanGoForward ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: details on the visibility and size of the horizontal scrollbar +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_HorizontalScroll_t, k_iSteamHTMLSurfaceCallbacks + 11 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, unScrollMax ) // +CALLBACK_MEMBER( 2, uint32, unScrollCurrent ) // +CALLBACK_MEMBER( 3, float, flPageScale ) // +CALLBACK_MEMBER( 4, bool , bVisible ) // +CALLBACK_MEMBER( 5, uint32, unPageSize ) // +END_DEFINE_CALLBACK_6() + + +//----------------------------------------------------------------------------- +// Purpose: details on the visibility and size of the vertical scrollbar +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_VerticalScroll_t, k_iSteamHTMLSurfaceCallbacks + 12 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, unScrollMax ) // +CALLBACK_MEMBER( 2, uint32, unScrollCurrent ) // +CALLBACK_MEMBER( 3, float, flPageScale ) // +CALLBACK_MEMBER( 4, bool, bVisible ) // +CALLBACK_MEMBER( 5, uint32, unPageSize ) // +END_DEFINE_CALLBACK_6() + + +//----------------------------------------------------------------------------- +// Purpose: response to GetLinkAtPosition call +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_LinkAtPosition_t, k_iSteamHTMLSurfaceCallbacks + 13 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, x ) // NOTE - Not currently set +CALLBACK_MEMBER( 2, uint32, y ) // NOTE - Not currently set +CALLBACK_MEMBER( 3, const char *, pchURL ) // +CALLBACK_MEMBER( 4, bool, bInput ) // +CALLBACK_MEMBER( 5, bool, bLiveLink ) // +END_DEFINE_CALLBACK_6() + + + +//----------------------------------------------------------------------------- +// Purpose: show a Javascript alert dialog, call JSDialogResponse +// when the user dismisses this dialog (or right away to ignore it) +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_JSAlert_t, k_iSteamHTMLSurfaceCallbacks + 14 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMessage ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: show a Javascript confirmation dialog, call JSDialogResponse +// when the user dismisses this dialog (or right away to ignore it) +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_JSConfirm_t, k_iSteamHTMLSurfaceCallbacks + 15 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMessage ) // +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: when received show a file open dialog +// then call FileLoadDialogResponse with the file(s) the user selected. +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_FileOpenDialog_t, k_iSteamHTMLSurfaceCallbacks + 16 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchTitle ) // +CALLBACK_MEMBER( 2, const char *, pchInitialFile ) // +END_DEFINE_CALLBACK_3() + + +//----------------------------------------------------------------------------- +// Purpose: a new html window has been created +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_NewWindow_t, k_iSteamHTMLSurfaceCallbacks + 21 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the current surface +CALLBACK_MEMBER( 1, const char *, pchURL ) // the page to load +CALLBACK_MEMBER( 2, uint32, unX ) // the x pos into the page to display the popup +CALLBACK_MEMBER( 3, uint32, unY ) // the y pos into the page to display the popup +CALLBACK_MEMBER( 4, uint32, unWide ) // the total width of the pBGRA texture +CALLBACK_MEMBER( 5, uint32, unTall ) // the total height of the pBGRA texture +CALLBACK_MEMBER( 6, HHTMLBrowser, unNewWindow_BrowserHandle ) // the handle of the new window surface +END_DEFINE_CALLBACK_7() + + +//----------------------------------------------------------------------------- +// Purpose: change the cursor to display +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_SetCursor_t, k_iSteamHTMLSurfaceCallbacks + 22 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, uint32, eMouseCursor ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: informational message from the browser +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_StatusText_t, k_iSteamHTMLSurfaceCallbacks + 23 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: show a tooltip +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_ShowToolTip_t, k_iSteamHTMLSurfaceCallbacks + 24 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: update the text of an existing tooltip +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_UpdateToolTip_t, k_iSteamHTMLSurfaceCallbacks + 25 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +CALLBACK_MEMBER( 1, const char *, pchMsg ) // the EMouseCursor to display +END_DEFINE_CALLBACK_2() + + +//----------------------------------------------------------------------------- +// Purpose: hide the tooltip you are showing +//----------------------------------------------------------------------------- +DEFINE_CALLBACK( HTML_HideToolTip_t, k_iSteamHTMLSurfaceCallbacks + 26 ) +CALLBACK_MEMBER( 0, HHTMLBrowser, unBrowserHandle ) // the handle of the surface +END_DEFINE_CALLBACK_1() + + +#pragma pack( pop ) + + +#endif // ISTEAMHTMLSURFACE_H +``` + +`SpyCustom/sdk/isteamhttp.h`: + +```h +//====== 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 "isteamclient.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; + + // Set that https request should require verified SSL certificate via machines certificate trust store + 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_VERSION002" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct HTTPRequestCompleted_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 1 }; + + // Handle value for the request that has completed. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + // This will be true if we actually got any sort of response from the server (even an error). + // It will be false if we failed due to an internal error or client side network failure. + bool m_bRequestSuccessful; + + // Will be the HTTP status code value returned by the server, k_EHTTPStatusCode200OK is the normal + // OK response, if you get something else you probably need to treat it as a failure. + EHTTPStatusCode m_eStatusCode; + + uint32 m_unBodySize; // Same as GetHTTPResponseBodySize() +}; + + +struct HTTPRequestHeadersReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 2 }; + + // Handle value for the request that has received headers. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; +}; + +struct HTTPRequestDataReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 3 }; + + // Handle value for the request that has received data. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + + // Offset to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cOffset; + + // Size to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cBytesReceived; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMHTTP_H +``` + +`SpyCustom/sdk/isteaminventory.h`: + +```h +//====== 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 "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#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; + + +//----------------------------------------------------------------------------- +// 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 + METHOD_DESC(Find out the status of an asynchronous inventory result handle.) + virtual EResult GetResultStatus( SteamInventoryResult_t resultHandle ) = 0; + + // Copies the contents of a result set into a flat array. The specific + // contents of the result set depend on which query which was used. + METHOD_DESC(Copies the contents of a result set into a flat array. The specific contents of the result set depend on which query which was used.) + virtual bool GetResultItems( SteamInventoryResult_t resultHandle, + OUT_ARRAY_COUNT( punOutItemsArraySize,Output array) SteamItemDetails_t *pOutItemsArray, + uint32 *punOutItemsArraySize ) = 0; + + // Returns the server time at which the result was generated. Compare against + // the value of IClientUtils::GetServerRealTime() to determine age. + METHOD_DESC(Returns the server time at which the result was generated. Compare against the value of IClientUtils::GetServerRealTime() to determine age.) + virtual uint32 GetResultTimestamp( SteamInventoryResult_t resultHandle ) = 0; + + // Returns true if the result belongs to the target steam ID, false if the + // result does not. This is important when using DeserializeResult, to verify + // that a remote player is not pretending to have a different user's inventory. + METHOD_DESC(Returns true if the result belongs to the target steam ID or false if the result does not. This is important when using DeserializeResult to verify that a remote player is not pretending to have a different users inventory.) + virtual bool CheckResultSteamID( SteamInventoryResult_t resultHandle, CSteamID steamIDExpected ) = 0; + + // Destroys a result handle and frees all associated memory. + METHOD_DESC(Destroys a result handle and frees all associated memory.) + virtual void DestroyResult( SteamInventoryResult_t resultHandle ) = 0; + + + // INVENTORY ASYNC QUERY + // + + // Captures the entire state of the current user's Steam inventory. + // You must call DestroyResult on this handle when you are done with it. + // Returns false and sets *pResultHandle to zero if inventory is unavailable. + // Note: calls to this function are subject to rate limits and may return + // cached results if called too frequently. It is suggested that you call + // this function only when you are about to display the user's full inventory, + // or if you expect that the inventory may have changed. + METHOD_DESC(Captures the entire state of the current users Steam inventory.) + virtual bool GetAllItems( SteamInventoryResult_t *pResultHandle ) = 0; + + + // Captures the state of a subset of the current user's Steam inventory, + // identified by an array of item instance IDs. The results from this call + // can be serialized and passed to other players to "prove" that the current + // user owns specific items, without exposing the user's entire inventory. + // For example, you could call GetItemsByID with the IDs of the user's + // currently equipped cosmetic items and serialize this to a buffer, and + // then transmit this buffer to other players upon joining a game. + METHOD_DESC(Captures the state of a subset of the current users Steam inventory identified by an array of item instance IDs.) + virtual bool GetItemsByID( SteamInventoryResult_t *pResultHandle, 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, 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, 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 insecure, and could + // be abused by hacked clients. It is, however, very useful as a development cheat or as + // a means of prototyping item-related features for your game. The use of GenerateItems can + // be restricted to certain item definitions or fully blocked via the Steamworks website. + // 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, ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, 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. + METHOD_DESC(GrantPromoItems() checks the list of promotional items for which the user may be eligible and grants the items (one time only).) + virtual bool GrantPromoItems( SteamInventoryResult_t *pResultHandle ) = 0; + + // AddPromoItem() / AddPromoItems() are restricted versions of GrantPromoItems(). Instead of + // scanning for all eligible promotional items, the check is restricted to a single item + // definition or set of item definitions. This can be useful if your game has custom UI for + // showing a specific promo item to the user. + virtual bool AddPromoItem( SteamInventoryResult_t *pResultHandle, SteamItemDef_t itemDef ) = 0; + virtual bool AddPromoItems( SteamInventoryResult_t *pResultHandle, 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. Similar to GenerateItems, punArrayQuantity + // can be NULL or else an array of the same length as pArrayItems which describe the quantity + // of each item to destroy. ConsumeItem can be restricted to certain item definitions or + // fully blocked via the Steamworks website to minimize support/abuse issues such as the + // clasic "my brother borrowed my laptop and deleted all of my rare items". + METHOD_DESC(ConsumeItem() removes items from the inventory permanently.) + virtual bool ConsumeItem( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemConsume, uint32 unQuantity ) = 0; + + // ExchangeItems() is an atomic combination of GenerateItems and DestroyItems. It can be + // used to implement crafting recipes or transmutations, or items which unpack themselves + // into other items. Like GenerateItems, this is a flexible and dangerous API which is + // meant for rapid prototyping. You can configure restrictions on ExchangeItems via the + // Steamworks website, such as limiting it to a whitelist of input/output combinations + // corresponding to recipes. + // (Note: although GenerateItems may be hard or impossible to use securely in your game, + // ExchangeItems is perfectly reasonable to use once the whitelists are set accordingly.) + virtual bool ExchangeItems( SteamInventoryResult_t *pResultHandle, + ARRAY_COUNT(unArrayGenerateLength) const SteamItemDef_t *pArrayGenerate, ARRAY_COUNT(unArrayGenerateLength) const uint32 *punArrayGenerateQuantity, uint32 unArrayGenerateLength, + ARRAY_COUNT(unArrayDestroyLength) const SteamItemInstanceID_t *pArrayDestroy, 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 + // + + // Applications which use timed-drop mechanics should call SendItemDropHeartbeat() when + // active gameplay begins, and at least once every two minutes afterwards. The backend + // performs its own time calculations, so the precise timing of the heartbeat is not + // critical as long as you send at least one heartbeat every two minutes. Calling the + // function more often than that is not harmful, it will simply have no effect. Note: + // players may be able to spoof this message by hacking their client, so you should not + // attempt to use this as a mechanism to restrict playtime credits. It is simply meant + // to distinguish between being in any kind of gameplay situation vs the main menu or + // a pre-game launcher window. (If you are stingy with handing out playtime credit, it + // will only encourage players to run bots or use mouse/kb event simulators.) + // + // Playtime credit accumulation can be capped on a daily or weekly basis through your + // Steamworks configuration. + // + METHOD_DESC(Applications which use timed-drop mechanics should call SendItemDropHeartbeat() when active gameplay begins and at least once every two minutes afterwards.) + 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. It is primarily useful during testing and development, + // where you may wish to perform experiments with different types of drops. + METHOD_DESC(Playtime credit must be consumed and turned into item drops by your game.) + virtual bool TriggerItemDrop( SteamInventoryResult_t *pResultHandle, SteamItemDef_t dropListDefinition ) = 0; + + + // IN-GAME TRADING + // + // TradeItems() implements limited in-game trading of items, if you prefer not to use + // the overlay or an in-game web browser to perform Steam Trading through the website. + // You should implement a UI where both players can see and agree to a trade, and then + // each client should call TradeItems simultaneously (+/- 5 seconds) with matching + // (but reversed) parameters. The result is the same as if both players performed a + // Steam Trading transaction through the web. Each player will get an inventory result + // confirming the removal or quantity changes of the items given away, and the new + // item instance id numbers and quantities of the received items. + // (Note: new item instance IDs are generated whenever an item changes ownership.) + virtual bool TradeItems( SteamInventoryResult_t *pResultHandle, CSteamID steamIDTradePartner, + ARRAY_COUNT(nArrayGiveLength) const SteamItemInstanceID_t *pArrayGive, ARRAY_COUNT(nArrayGiveLength) const uint32 *pArrayGiveQuantity, uint32 nArrayGiveLength, + ARRAY_COUNT(nArrayGetLength) const SteamItemInstanceID_t *pArrayGet, 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. + METHOD_DESC(LoadItemDefinitions triggers the automatic load and refresh of item definitions.) + virtual bool LoadItemDefinitions() = 0; + + // GetItemDefinitionIDs returns the set of all defined item definition IDs (which are + // defined via Steamworks configuration, and not necessarily contiguous integers). + // If pItemDefIDs is null, the call will return true and *punItemDefIDsArraySize will + // contain the total size necessary for a subsequent call. Otherwise, the call will + // return false if and only if there is not enough space in the output array. + virtual bool GetItemDefinitionIDs( + OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs, + 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. + virtual bool GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPropertyName, + OUT_STRING_COUNT(punValueBufferSize) char *pchValueBuffer, uint32 *punValueBufferSize ) = 0; +}; + +#define STEAMINVENTORY_INTERFACE_VERSION "STEAMINVENTORY_INTERFACE_V001" + + +// SteamInventoryResultReady_t callbacks are fired whenever asynchronous +// results transition from "Pending" to "OK" or an error state. There will +// always be exactly one callback per handle. +struct SteamInventoryResultReady_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 0 }; + SteamInventoryResult_t m_handle; + EResult m_result; +}; + + +// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems +// successfully returns a result which is newer / fresher than the last +// known result. (It will not trigger if the inventory hasn't changed, +// or if results from two overlapping calls are reversed in flight and +// the earlier result is already known to be stale/out-of-date.) +// The normal ResultReady callback will still be triggered immediately +// afterwards; this is an additional notification for your convenience. +struct SteamInventoryFullUpdate_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 1 }; + SteamInventoryResult_t m_handle; +}; + + +// A SteamInventoryDefinitionUpdate_t callback is triggered whenever +// item definitions have been updated, which could be in response to +// LoadItemDefinitions() or any other async request which required +// a definition update in order to process results from the server. +struct SteamInventoryDefinitionUpdate_t +{ + enum { k_iCallback = k_iClientInventoryCallbacks + 2 }; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMCONTROLLER_H +``` + +`SpyCustom/sdk/isteammatchmaking.h`: + +```h +//====== 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 "steamtypes.h" +#include "steamclientpublic.h" +#include "matchmakingtypes.h" +#include "isteamclient.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 +}; + +// 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 + } + } + */ + // + 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) + 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 + 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, 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, 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 + CALL_BACK( LobbyChatUpdate_t ); +}; +#define STEAMMATCHMAKING_INTERFACE_VERSION "SteamMatchMaking009" + + +//----------------------------------------------------------------------------- +// 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, 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, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFavoritesServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestHistoryServerList( AppId_t iApp, ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestSpectatorServerList( AppId_t iApp, 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" + +// 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 ) ) + + +//----------------------------------------------------------------------------- +// Callbacks for ISteamMatchmaking (which go through the regular Steam callback registration system) +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// 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; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMMATCHMAKING +``` + +`SpyCustom/sdk/isteammusic.h`: + +```h +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMMUSIC_H +#define ISTEAMMUSIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.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" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +DEFINE_CALLBACK( PlaybackStatusHasChanged_t, k_iSteamMusicCallbacks + 1 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( VolumeHasChanged_t, k_iSteamMusicCallbacks + 2 ) + CALLBACK_MEMBER( 0, float, m_flNewVolume ) +END_DEFINE_CALLBACK_1() + +#pragma pack( pop ) + + +#endif // #define ISTEAMMUSIC_H +``` + +`SpyCustom/sdk/isteammusicremote.h`: + +```h +//============ Copyright (c) Valve Corporation, All rights reserved. ============ + +#ifndef ISTEAMMUSICREMOTE_H +#define ISTEAMMUSICREMOTE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.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" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +DEFINE_CALLBACK( MusicPlayerRemoteWillActivate_t, k_iSteamMusicRemoteCallbacks + 1) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerRemoteWillDeactivate_t, k_iSteamMusicRemoteCallbacks + 2 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerRemoteToFront_t, k_iSteamMusicRemoteCallbacks + 3 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWillQuit_t, k_iSteamMusicRemoteCallbacks + 4 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPlay_t, k_iSteamMusicRemoteCallbacks + 5 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPause_t, k_iSteamMusicRemoteCallbacks + 6 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPlayPrevious_t, k_iSteamMusicRemoteCallbacks + 7 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsPlayNext_t, k_iSteamMusicRemoteCallbacks + 8 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( MusicPlayerWantsShuffled_t, k_iSteamMusicRemoteCallbacks + 9 ) + CALLBACK_MEMBER( 0, bool, m_bShuffled ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerWantsLooped_t, k_iSteamMusicRemoteCallbacks + 10 ) + CALLBACK_MEMBER(0, bool, m_bLooped ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerWantsVolume_t, k_iSteamMusicCallbacks + 11 ) + CALLBACK_MEMBER(0, float, m_flNewVolume) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerSelectsQueueEntry_t, k_iSteamMusicCallbacks + 12 ) + CALLBACK_MEMBER(0, int, nID ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerSelectsPlaylistEntry_t, k_iSteamMusicCallbacks + 13 ) + CALLBACK_MEMBER(0, int, nID ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( MusicPlayerWantsPlayingRepeatStatus_t, k_iSteamMusicRemoteCallbacks + 14 ) + CALLBACK_MEMBER(0, int, m_nPlayingRepeatStatus ) +END_DEFINE_CALLBACK_1() + +#pragma pack( pop ) + + + +#endif // #define ISTEAMMUSICREMOTE_H +``` + +`SpyCustom/sdk/isteamnetworking.h`: + +```h +//====== 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 "steamtypes.h" +#include "steamclientpublic.h" + + +// list of possible errors returned by SendP2PPacket() API +// these will be posted in the P2PSessionConnectFail_t callback +enum EP2PSessionError +{ + k_EP2PSessionErrorNone = 0, + k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game + k_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running + k_EP2PSessionErrorDestinationNotLoggedIn = 3, // target user isn't connected to Steam + k_EP2PSessionErrorTimeout = 4, // target isn't responding, perhaps not calling AcceptP2PSessionWithUser() + // corporate firewalls can also block this (NAT traversal is not firewall traversal) + // make sure that UDP ports 3478, 4379, and 4380 are open in an outbound direction + k_EP2PSessionErrorMax = 5 +}; + +// SendP2PPacket() send types +// Typically k_EP2PSendUnreliable is what you want for UDP-like packets, k_EP2PSendReliable for TCP-like packets +enum EP2PSend +{ + // Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare). + // The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or + // there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again. + k_EP2PSendUnreliable = 0, + + // As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first + // packet sent to a remote host almost guarantees the packet will be dropped. + // This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets + k_EP2PSendUnreliableNoDelay = 1, + + // Reliable message send. Can send up to 1MB of data in a single message. + // Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data. + k_EP2PSendReliable = 2, + + // As above, but applies the Nagle algorithm to the send - sends will accumulate + // until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm). + // Useful if you want to send a set of smaller messages but have the coalesced into a single packet + // Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then + // do a normal k_EP2PSendReliable to force all the buffered data to be sent. + k_EP2PSendReliableWithBuffering = 3, + +}; + + +// connection state to a specified user, returned by GetP2PSessionState() +// this is under-the-hood info about what's going on with a SendP2PPacket(), shouldn't be needed except for debuggin +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct P2PSessionState_t +{ + uint8 m_bConnectionActive; // true if we've got an active open connection + uint8 m_bConnecting; // true if we're currently trying to establish a connection + uint8 m_eP2PSessionError; // last error recorded (see enum above) + uint8 m_bUsingRelay; // true if it's going through a relay server (TURN) + int32 m_nBytesQueuedForSend; + int32 m_nPacketsQueuedForSend; + uint32 m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server. + uint16 m_nRemotePort; // Only exists for compatibility with older authentication api's +}; +#pragma pack( pop ) + + +// handle to a socket +typedef uint32 SNetSocket_t; // CreateP2PConnectionSocket() +typedef uint32 SNetListenSocket_t; // CreateListenSocket() + +// connection progress indicators, used by CreateP2PConnectionSocket() +enum ESNetSocketState +{ + k_ESNetSocketStateInvalid = 0, + + // communication is valid + k_ESNetSocketStateConnected = 1, + + // states while establishing a connection + k_ESNetSocketStateInitiated = 10, // the connection state machine has started + + // p2p connections + k_ESNetSocketStateLocalCandidatesFound = 11, // we've found our local IP info + k_ESNetSocketStateReceivedRemoteCandidates = 12,// we've received information from the remote machine, via the Steam back-end, about their IP info + + // direct connections + k_ESNetSocketStateChallengeHandshake = 15, // we've received a challenge packet from the server + + // failure states + k_ESNetSocketStateDisconnecting = 21, // the API shut it down, and we're in the process of telling the other end + k_ESNetSocketStateLocalDisconnect = 22, // the API shut it down, and we've completed shutdown + k_ESNetSocketStateTimeoutDuringConnect = 23, // we timed out while trying to creating the connection + k_ESNetSocketStateRemoteEndDisconnected = 24, // the remote end has disconnected from us + k_ESNetSocketStateConnectionBroken = 25, // connection has been broken; either the other end has disappeared or our local network connection has broke + +}; + +// describes how the socket is currently connected +enum ESNetSocketConnectionType +{ + k_ESNetSocketConnectionTypeNotConnected = 0, + k_ESNetSocketConnectionTypeUDP = 1, + k_ESNetSocketConnectionTypeUDPRelay = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for making connections and sending data between clients, +// traversing NAT's where possible +//----------------------------------------------------------------------------- +class ISteamNetworking +{ +public: + //////////////////////////////////////////////////////////////////////////////////////////// + // Session-less connection functions + // automatically establishes NAT-traversing or Relay server connections + + // Sends a P2P packet to the specified user + // UDP-like, unreliable and a max packet size of 1200 bytes + // the first packet send may be delayed as the NAT-traversal code runs + // if we can't get through to the user, an error will be posted via the callback P2PSessionConnectFail_t + // see EP2PSend enum above for the descriptions of the different ways of sending packets + // + // nChannel is a routing number you can use to help route message to different systems - you'll have to call ReadP2PPacket() + // with the same channel number in order to retrieve the data on the other end + // using different channels to talk to the same user will still use the same underlying p2p connection, saving on resources + virtual bool SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel = 0 ) = 0; + + // returns true if any data is available for read, and the amount of data that will need to be read + virtual bool IsP2PPacketAvailable( uint32 *pcubMsgSize, int nChannel = 0 ) = 0; + + // reads in a packet that has been sent from another user via SendP2PPacket() + // returns the size of the message and the steamID of the user who sent it in the last two parameters + // if the buffer passed in is too small, the message will be truncated + // this call is not blocking, and will return false if no data is available + virtual bool ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote, int nChannel = 0 ) = 0; + + // AcceptP2PSessionWithUser() should only be called in response to a P2PSessionRequest_t callback + // P2PSessionRequest_t will be posted if another user tries to send you a packet that you haven't talked to yet + // if you don't want to talk to the user, just ignore the request + // if the user continues to send you packets, another P2PSessionRequest_t will be posted periodically + // this may be called multiple times for a single user + // (if you've called SendP2PPacket() on the other user, this implicitly accepts the session request) + virtual bool AcceptP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PSessionWithUser() when you're done talking to a user, will free up resources under-the-hood + // if the remote user tries to send data to you again, another P2PSessionRequest_t callback will be posted + virtual bool CloseP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PChannelWithUser() when you're done talking to a user on a specific channel. Once all channels + // open channels to a user have been closed, the open session to the user will be closed and new data from this + // user will trigger a P2PSessionRequest_t callback + virtual bool CloseP2PChannelWithUser( CSteamID steamIDRemote, int nChannel ) = 0; + + // fills out P2PSessionState_t structure with details about the underlying connection to the user + // should only needed for debugging purposes + // returns false if no connection exists to the specified user + virtual bool GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState ) = 0; + + // Allow P2P connections to fall back to being relayed through the Steam servers if a direct connection + // or NAT-traversal cannot be established. Only applies to connections created after setting this value, + // or to existing connections that need to automatically reconnect after this value is set. + // + // P2P packet relay is allowed by default + virtual bool AllowP2PPacketRelay( bool bAllow ) = 0; + + + //////////////////////////////////////////////////////////////////////////////////////////// + // LISTEN / CONNECT style interface functions + // + // This is an older set of functions designed around the Berkeley TCP sockets model + // it's preferential that you use the above P2P functions, they're more robust + // and these older functions will be removed eventually + // + //////////////////////////////////////////////////////////////////////////////////////////// + + + // creates a socket and listens others to connect + // will trigger a SocketStatusCallback_t callback on another client connecting + // nVirtualP2PPort is the unique ID that the client will connect to, in case you have multiple ports + // this can usually just be 0 unless you want multiple sets of connections + // unIP is the local IP address to bind to + // pass in 0 if you just want the default local IP + // unPort is the port to use + // pass in 0 if you don't want users to be able to connect via IP/Port, but expect to be always peer-to-peer connections only + virtual SNetListenSocket_t CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay ) = 0; + + // creates a socket and begin connection to a remote destination + // can connect via a known steamID (client or game server), or directly to an IP + // on success will trigger a SocketStatusCallback_t callback + // on failure or timeout will trigger a SocketStatusCallback_t callback with a failure code in m_eSNetSocketState + virtual SNetSocket_t CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay ) = 0; + virtual SNetSocket_t CreateConnectionSocket( uint32 nIP, uint16 nPort, int nTimeoutSec ) = 0; + + // disconnects the connection to the socket, if any, and invalidates the handle + // any unread data on the socket will be thrown away + // if bNotifyRemoteEnd is set, socket will not be completely destroyed until the remote end acknowledges the disconnect + virtual bool DestroySocket( SNetSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + // destroying a listen socket will automatically kill all the regular sockets generated from it + virtual bool DestroyListenSocket( SNetListenSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + + // sending data + // must be a handle to a connected socket + // data is all sent via UDP, and thus send sizes are limited to 1200 bytes; after this, many routers will start dropping packets + // use the reliable flag with caution; although the resend rate is pretty aggressive, + // it can still cause stalls in receiving data (like TCP) + virtual bool SendDataOnSocket( SNetSocket_t hSocket, void *pubData, uint32 cubData, bool bReliable ) = 0; + + // receiving data + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + virtual bool IsDataAvailableOnSocket( SNetSocket_t hSocket, uint32 *pcubMsgSize ) = 0; + + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + virtual bool RetrieveDataFromSocket( SNetSocket_t hSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0; + + // checks for data from any socket that has been connected off this listen socket + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + // fills out *phSocket with the socket that data is available on + virtual bool IsDataAvailable( SNetListenSocket_t hListenSocket, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // retrieves data from any socket that has been connected off this listen socket + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + // fills out *phSocket with the socket that data is available on + virtual bool RetrieveData( SNetListenSocket_t hListenSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // returns information about the specified socket, filling out the contents of the pointers + virtual bool GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, uint32 *punIPRemote, uint16 *punPortRemote ) = 0; + + // returns which local port the listen socket is bound to + // *pnIP and *pnPort will be 0 if the socket is set to listen for P2P connections only + virtual bool GetListenSocketInfo( SNetListenSocket_t hListenSocket, uint32 *pnIP, uint16 *pnPort ) = 0; + + // returns true to describe how the socket ended up connecting + virtual ESNetSocketConnectionType GetSocketConnectionType( SNetSocket_t hSocket ) = 0; + + // max packet size, in bytes + virtual int GetMaxPacketSize( SNetSocket_t hSocket ) = 0; +}; +#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking005" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#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 +``` + +`SpyCustom/sdk/isteamugc.h`: + +```h +//====== 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 "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +typedef uint64 UGCQueryHandle_t; +typedef uint64 UGCUpdateHandle_t; + + +const UGCQueryHandle_t k_UGCQueryHandleInvalid = 0xffffffffffffffffull; +const UGCUpdateHandle_t k_UGCUpdateHandleInvalid = 0xffffffffffffffffull; + + +// Matching UGC types for queries +enum EUGCMatchingUGCType +{ + k_EUGCMatchingUGCType_Items = 0, // both mtx items and ready-to-use items + k_EUGCMatchingUGCType_Items_Mtx = 1, + k_EUGCMatchingUGCType_Items_ReadyToUse = 2, + k_EUGCMatchingUGCType_Collections = 3, + k_EUGCMatchingUGCType_Artwork = 4, + k_EUGCMatchingUGCType_Videos = 5, + k_EUGCMatchingUGCType_Screenshots = 6, + k_EUGCMatchingUGCType_AllGuides = 7, // both web guides and integrated guides + k_EUGCMatchingUGCType_WebGuides = 8, + k_EUGCMatchingUGCType_IntegratedGuides = 9, + k_EUGCMatchingUGCType_UsableInGame = 10, // ready-to-use items and integrated guides + k_EUGCMatchingUGCType_ControllerBindings = 11, + k_EUGCMatchingUGCType_GameManagedItems = 12, // game managed items (not managed by users) + k_EUGCMatchingUGCType_All = ~0, // return everything +}; + +// Different lists of published UGC for a user. +// If the current logged in user is different than the specified user, then some options may not be allowed. +enum EUserUGCList +{ + k_EUserUGCList_Published, + k_EUserUGCList_VotedOn, + k_EUserUGCList_VotedUp, + k_EUserUGCList_VotedDown, + k_EUserUGCList_WillVoteLater, + k_EUserUGCList_Favorited, + k_EUserUGCList_Subscribed, + k_EUserUGCList_UsedOrPlayed, + k_EUserUGCList_Followed, +}; + +// Sort order for user published UGC lists (defaults to creation order descending) +enum EUserUGCListSortOrder +{ + k_EUserUGCListSortOrder_CreationOrderDesc, + k_EUserUGCListSortOrder_CreationOrderAsc, + k_EUserUGCListSortOrder_TitleAsc, + k_EUserUGCListSortOrder_LastUpdatedDesc, + k_EUserUGCListSortOrder_SubscriptionDateDesc, + k_EUserUGCListSortOrder_VoteScoreDesc, + k_EUserUGCListSortOrder_ForModeration, +}; + +// Combination of sorting and filtering for queries across all UGC +enum EUGCQuery +{ + k_EUGCQuery_RankedByVote = 0, + k_EUGCQuery_RankedByPublicationDate = 1, + k_EUGCQuery_AcceptedForGameRankedByAcceptanceDate = 2, + k_EUGCQuery_RankedByTrend = 3, + k_EUGCQuery_FavoritedByFriendsRankedByPublicationDate = 4, + k_EUGCQuery_CreatedByFriendsRankedByPublicationDate = 5, + k_EUGCQuery_RankedByNumTimesReported = 6, + k_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate = 7, + k_EUGCQuery_NotYetRated = 8, + k_EUGCQuery_RankedByTotalVotesAsc = 9, + k_EUGCQuery_RankedByVotesUp = 10, + k_EUGCQuery_RankedByTextSearch = 11, + k_EUGCQuery_RankedByTotalUniqueSubscriptions = 12, +}; + +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, +}; + +enum EItemPreviewType +{ + k_EItemPreviewType_Image = 0, + k_EItemPreviewType_YouTubeVideo = 1, + k_EItemPreviewType_Sketchfab = 2, + k_EItemPreviewType_ReservedMax = 255, // you can specify your own types above this value +}; + +const uint32 kNumUGCResultsPerPage = 50; +const uint32 k_cchDeveloperMetadataMax = 5000; + +// Details for a single published file/UGC +struct SteamUGCDetails_t +{ + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; // The result of the operation. + EWorkshopFileType m_eFileType; // Type of the file + AppId_t m_nCreatorAppID; // ID of the app that created this file. + AppId_t m_nConsumerAppID; // ID of the app that will consume this file. + char m_rgchTitle[k_cchPublishedDocumentTitleMax]; // title of document + char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; // description of document + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + uint32 m_rtimeAddedToUserList; // time when the user added the published file to their list (not always applicable) + ERemoteStoragePublishedFileVisibility m_eVisibility; // visibility + bool m_bBanned; // whether the file was banned + bool m_bAcceptedForUse; // developer has specifically flagged this item as accepted in the Workshop + bool m_bTagsTruncated; // whether the list of tags was too long to be returned in the provided buffer + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + // file/url information + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + char m_pchFileName[k_cchFilenameMax]; // The cloud filename of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + char m_rgchURL[k_cchPublishedFileURLMax]; // URL (for a video or a website) + // voting information + uint32 m_unVotesUp; // number of votes up + uint32 m_unVotesDown; // number of votes down + float m_flScore; // calculated score + // collection details + uint32 m_unNumChildren; +}; + +//----------------------------------------------------------------------------- +// Purpose: Steam UGC support API +//----------------------------------------------------------------------------- +class ISteamUGC +{ +public: + + // Query UGC associated with a user. Creator app id or consumer app id must be valid and be set to the current running app. unPage should start at 1. + virtual UGCQueryHandle_t CreateQueryUserUGCRequest( AccountID_t unAccountID, EUserUGCList eListType, EUGCMatchingUGCType eMatchingUGCType, EUserUGCListSortOrder eSortOrder, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ) = 0; + + // Query for all matching UGC. Creator app id or consumer app id must be valid and be set to the current running app. unPage should start at 1. + virtual UGCQueryHandle_t CreateQueryAllUGCRequest( EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ) = 0; + + // Query for 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 + CALL_RESULT( SteamUGCQueryCompleted_t ) + virtual SteamAPICall_t SendQueryUGCRequest( UGCQueryHandle_t handle ) = 0; + + // Retrieve an individual result after receiving the callback for querying UGC + virtual bool GetQueryUGCResult( UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t *pDetails ) = 0; + virtual bool GetQueryUGCPreviewURL( UGCQueryHandle_t handle, uint32 index, OUT_STRING_COUNT(cchURLSize) char *pchURL, uint32 cchURLSize ) = 0; + virtual bool GetQueryUGCMetadata( UGCQueryHandle_t handle, uint32 index, 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, uint32 *pStatValue ) = 0; + virtual uint32 GetQueryUGCNumAdditionalPreviews( UGCQueryHandle_t handle, uint32 index ) = 0; + virtual bool GetQueryUGCAdditionalPreview( UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, OUT_STRING_COUNT(cchURLSize) char *pchURLOrVideoID, uint32 cchURLSize, 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, OUT_STRING_COUNT(cchKeySize) char *pchKey, uint32 cchKeySize, OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) = 0; + + // Release the request to free up memory, after retrieving results + virtual bool ReleaseQueryUGCRequest( UGCQueryHandle_t handle ) = 0; + + // Options to set for querying UGC + virtual bool AddRequiredTag( UGCQueryHandle_t handle, const char *pTagName ) = 0; + virtual bool AddExcludedTag( UGCQueryHandle_t handle, const char *pTagName ) = 0; + virtual bool 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 SetLanguage( UGCQueryHandle_t handle, const char *pchLanguage ) = 0; + virtual bool SetAllowCachedResponse( UGCQueryHandle_t handle, uint32 unMaxAgeSeconds ) = 0; + + // Options only for querying user UGC + virtual bool SetCloudFileNameFilter( UGCQueryHandle_t handle, const char *pMatchCloudFileName ) = 0; + + // Options only for querying all UGC + virtual bool SetMatchAnyTag( UGCQueryHandle_t handle, bool bMatchAnyTag ) = 0; + virtual bool SetSearchText( UGCQueryHandle_t handle, const char *pSearchText ) = 0; + virtual bool SetRankedByTrendDays( UGCQueryHandle_t handle, uint32 unDays ) = 0; + virtual bool AddRequiredKeyValueTag( UGCQueryHandle_t handle, const char *pKey, const char *pValue ) = 0; + + // DEPRECATED - Use CreateQueryUGCDetailsRequest call above instead! + virtual SteamAPICall_t RequestUGCDetails( PublishedFileId_t nPublishedFileID, uint32 unMaxAgeSeconds ) = 0; + + // Steam Workshop Creator API + 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 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) + + 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 + CALL_RESULT( SetUserItemVoteResult_t ) + virtual SteamAPICall_t SetUserItemVote( PublishedFileId_t nPublishedFileID, bool bVoteUp ) = 0; + CALL_RESULT( GetUserItemVoteResult_t ) + virtual SteamAPICall_t GetUserItemVote( PublishedFileId_t nPublishedFileID ) = 0; + CALL_RESULT( UserFavoriteItemsListChanged_t ) + virtual SteamAPICall_t AddItemToFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) = 0; + CALL_RESULT( UserFavoriteItemsListChanged_t ) + virtual SteamAPICall_t RemoveItemFromFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) = 0; + CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t ) + virtual SteamAPICall_t SubscribeItem( PublishedFileId_t nPublishedFileID ) = 0; // subscribe to this item, will be installed ASAP + 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, 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; +}; + +#define STEAMUGC_INTERFACE_VERSION "STEAMUGC_INTERFACE_VERSION008" + +//----------------------------------------------------------------------------- +// Purpose: Callback for querying UGC +//----------------------------------------------------------------------------- +struct SteamUGCQueryCompleted_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 1 }; + UGCQueryHandle_t m_handle; + EResult m_eResult; + uint32 m_unNumResultsReturned; + uint32 m_unTotalMatchingResults; + bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback for requesting details on one piece of UGC +//----------------------------------------------------------------------------- +struct SteamUGCRequestUGCDetailsResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 2 }; + SteamUGCDetails_t m_details; + bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache +}; + + +//----------------------------------------------------------------------------- +// Purpose: result for ISteamUGC::CreateItem() +//----------------------------------------------------------------------------- +struct CreateItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 3 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; // new item got this UGC PublishFileID + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: result for ISteamUGC::SubmitItemUpdate() +//----------------------------------------------------------------------------- +struct SubmitItemUpdateResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 4 }; + EResult m_eResult; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a Workshop item has been installed or updated +//----------------------------------------------------------------------------- +struct ItemInstalled_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 5 }; + AppId_t m_unAppID; + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of DownloadItem(), existing item files can be accessed again +//----------------------------------------------------------------------------- +struct DownloadItemResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 6 }; + AppId_t m_unAppID; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: result of AddItemToFavorites() or RemoveItemFromFavorites() +//----------------------------------------------------------------------------- +struct UserFavoriteItemsListChanged_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 7 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bWasAddRequest; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to SetUserItemVote() +//----------------------------------------------------------------------------- +struct SetUserItemVoteResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 8 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bVoteUp; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetUserItemVote() +//----------------------------------------------------------------------------- +struct GetUserItemVoteResult_t +{ + enum { k_iCallback = k_iClientUGCCallbacks + 9 }; + PublishedFileId_t m_nPublishedFileId; + EResult m_eResult; + bool m_bVotedUp; + bool m_bVotedDown; + bool m_bVoteSkipped; +}; + +#pragma pack( pop ) + +#endif // ISTEAMUGC_H +``` + +`SpyCustom/sdk/isteamuser.h`: + +```h +//====== 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 "isteamclient.h" " + +// structure that contains client callback data +// see callbacks documentation for more details +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct CallbackMsg_t +{ + HSteamUser m_hSteamUser; + int m_iCallback; + uint8 *m_pubParam; + int m_cubParam; +}; +#pragma pack( pop ) + +//----------------------------------------------------------------------------- +// Purpose: Result from RequestEncryptedAppTicket +//----------------------------------------------------------------------------- +struct EncryptedAppTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 54 }; + + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing and manipulating a steam account +// associated with one client instance +//----------------------------------------------------------------------------- +class ISteamUser +{ +public: + // returns the HSteamUser this interface represents + // this is only used internally by the API, and by a few select interfaces that support multi-user + virtual HSteamUser GetHSteamUser() = 0; + + // returns true if the Steam client current has a live connection to the Steam servers. + // If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy. + // The Steam client will automatically be trying to recreate the connection as often as possible. + virtual bool BLoggedOn() = 0; + + // returns the CSteamID of the account currently logged into the Steam client + // a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API + virtual CSteamID GetSteamID() = 0; + + // Multiplayer Authentication functions + + // InitiateGameConnection() starts the state machine for authenticating the game client with the game server + // It is the client portion of a three-way handshake between the client, the game server, and the steam servers + // + // Parameters: + // void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token. + // int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes. + // CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client + // CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( ) + // uint32 unIPServer, uint16 usPortServer - the IP address of the game server + // bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running) + // + // return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed + // The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process. + virtual int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0; + + // notify of disconnect + // needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call + virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0; + + // Legacy functions + + // used by only a few games to track usage events + virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0; + + // get the local storage folder for current Steam account to write application data, e.g. save games, configs etc. + // this will usually be something like "C:\Progam Files\Steam\userdata\\\local" + virtual bool GetUserDataFolder( char *pchBuffer, int cubBuffer ) = 0; + + // Starts voice recording. Once started, use GetVoice() to get the data + virtual void StartVoiceRecording( ) = 0; + + // Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for + // a little bit after this function is called. GetVoice() should continue to be called until it returns + // k_eVoiceResultNotRecording + virtual void StopVoiceRecording( ) = 0; + + // Determine the amount of captured audio data that is available in bytes. + // This provides both the compressed and uncompressed data. Please note that the uncompressed + // data is not the raw feed from the microphone: data may only be available if audible + // levels of speech are detected. + // nUncompressedVoiceDesiredSampleRate is necessary to know the number of bytes to return in pcbUncompressed - can be set to 0 if you don't need uncompressed (the usual case) + // If you're upgrading from an older Steamworks API, you'll want to pass in 11025 to nUncompressedVoiceDesiredSampleRate + virtual EVoiceResult GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed, uint32 nUncompressedVoiceDesiredSampleRate ) = 0; + + // Gets the latest voice data from the microphone. Compressed data is an arbitrary format, and is meant to be handed back to + // DecompressVoice() for playback later as a binary blob. Uncompressed data is 16-bit, signed integer, 11025Hz PCM format. + // Please note that the uncompressed data is not the raw feed from the microphone: data may only be available if audible + // levels of speech are detected, and may have passed through denoising filters, etc. + // This function should be called as often as possible once recording has started; once per frame at least. + // nBytesWritten is set to the number of bytes written to pDestBuffer. + // nUncompressedBytesWritten is set to the number of bytes written to pUncompressedDestBuffer. + // You must grab both compressed and uncompressed here at the same time, if you want both. + // Matching data that is not read during this call will be thrown away. + // GetAvailableVoice() can be used to determine how much data is actually available. + // If you're upgrading from an older Steamworks API, you'll want to pass in 11025 to nUncompressedVoiceDesiredSampleRate + virtual EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed, void *pUncompressedDestBuffer, uint32 cbUncompressedDestBufferSize, uint32 *nUncompressBytesWritten, uint32 nUncompressedVoiceDesiredSampleRate ) = 0; + + // Decompresses a chunk of compressed data produced by GetVoice(). + // nBytesWritten is set to the number of bytes written to pDestBuffer unless the return value is k_EVoiceResultBufferTooSmall. + // In that case, nBytesWritten is set to the size of the buffer required to decompress the given + // data. The suggested buffer size for the destination buffer is 22 kilobytes. + // The output format of the data is 16-bit signed at the requested samples per second. + // If you're upgrading from an older Steamworks API, you'll want to pass in 11025 to nDesiredSampleRate + virtual EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate ) = 0; + + // This returns the frequency of the voice data as it's stored internally; calling DecompressVoice() with this size will yield the best results + virtual uint32 GetVoiceOptimalSampleRate() = 0; + + // Retrieve ticket to be sent to the entity who wishes to authenticate you. + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Authenticate ticket from entity steamID to be sure it is valid and isnt reused + // Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // After receiving a user's authentication data, and passing it to BeginAuthSession, use this function + // to determine if the user owns downloadable content specified by the provided AppID. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam + // (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT. + virtual bool BIsBehindNAT() = 0; + + // set data to be replicated to friends so that they can join your game + // CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client + // uint32 unIPServer, uint16 usPortServer - the IP address of the game server + virtual void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer ) = 0; + + // Requests a ticket encrypted with an app specific shared key + // pDataToInclude, cbDataToInclude will be encrypted into the ticket + // ( This is asynchronous, you must wait for the ticket to be completed by the server ) + CALL_RESULT( EncryptedAppTicketResponse_t ) + virtual SteamAPICall_t RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude ) = 0; + + // retrieve a finished ticket + virtual bool GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Trading Card badges data access + // if you only have one set of cards, the series will be 1 + // the user has can have two different badges for a series; the regular (max level 5) and the foil (max level 1) + virtual int GetGameBadgeLevel( int nSeries, bool bFoil ) = 0; + + // gets the Steam Level of the user, as shown on their profile + virtual int GetPlayerSteamLevel() = 0; + + // Requests a URL which authenticates an in-game browser for store check-out, + // and then redirects to the specified URL. As long as the in-game browser + // accepts and handles session cookies, Steam microtransaction checkout pages + // will automatically recognize the user instead of presenting a login page. + // The result of this API call will be a StoreAuthURLResponse_t callback. + // NOTE: The URL has a very short lifetime to prevent history-snooping attacks, + // so you should only call this API when you are about to launch the browser, + // or else immediately navigate to the result URL using a hidden browser window. + // NOTE 2: The resulting authorization cookie has an expiration time of one day, + // so it would be a good idea to request and visit a new auth URL every 12 hours. + 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; + +}; + +#define STEAMUSER_INTERFACE_VERSION "SteamUser019" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a connections to the Steam back-end has been established +// this means the Steam client now has a working connection to the Steam servers +// usually this will have occurred before the game has launched, and should +// only be seen if the user has dropped connection due to a networking issue +// or a Steam server update +//----------------------------------------------------------------------------- +struct SteamServersConnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 1 }; +}; + +//----------------------------------------------------------------------------- +// Purpose: called when a connection attempt has failed +// this will occur periodically if the Steam client is not connected, +// and has failed in it's retry to establish a connection +//----------------------------------------------------------------------------- +struct SteamServerConnectFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 2 }; + EResult m_eResult; + bool m_bStillRetrying; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called if the client has lost connection to the Steam servers +// real-time services will be disabled until a matching SteamServersConnected_t has been posted +//----------------------------------------------------------------------------- +struct SteamServersDisconnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 3 }; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent by the Steam server to the client telling it to disconnect from the specified game server, +// which it may be in the process of or already connected to. +// The game client should immediately disconnect upon receiving this message. +// This can usually occur if the user doesn't have rights to play on the game server. +//----------------------------------------------------------------------------- +struct ClientGameServerDeny_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 13 }; + + uint32 m_uAppID; + uint32 m_unGameServerIP; + uint16 m_usGameServerPort; + uint16 m_bSecure; + uint32 m_uReason; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the callback system for this client is in an error state (and has flushed pending callbacks) +// When getting this message the client should disconnect from Steam, reset any stored Steam state and reconnect. +// This usually occurs in the rare event the Steam client has some kind of fatal error. +//----------------------------------------------------------------------------- +struct IPCFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 17 }; + enum EFailureType + { + k_EFailureFlushedCallbackQueue, + k_EFailurePipeFail, + }; + uint8 m_eFailureType; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Signaled whenever licenses change +//----------------------------------------------------------------------------- +struct LicensesUpdated_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 25 }; +}; + + +//----------------------------------------------------------------------------- +// callback for BeginAuthSession +//----------------------------------------------------------------------------- +struct ValidateAuthTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 43 }; + CSteamID m_SteamID; + EAuthSessionResponse m_eAuthSessionResponse; + CSteamID m_OwnerSteamID; // different from m_SteamID if borrowed +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a user has responded to a microtransaction authorization request +//----------------------------------------------------------------------------- +struct MicroTxnAuthorizationResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 52 }; + + uint32 m_unAppID; // AppID for this microtransaction + uint64 m_ulOrderID; // OrderID provided for the microtransaction + uint8 m_bAuthorized; // if user authorized transaction +}; + + + + +//----------------------------------------------------------------------------- +// 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]; +}; + + + +#pragma pack( pop ) + +#endif // ISTEAMUSER_H +``` + +`SpyCustom/sdk/isteamvideo.h`: + +```h +//====== 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 "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#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; +}; + +#define STEAMVIDEO_INTERFACE_VERSION "STEAMVIDEO_INTERFACE_V001" + +DEFINE_CALLBACK( BroadcastUploadStart_t, k_iClientVideoCallbacks + 4 ) +END_DEFINE_CALLBACK_0() + +DEFINE_CALLBACK( BroadcastUploadStop_t, k_iClientVideoCallbacks + 5 ) + CALLBACK_MEMBER( 0, EBroadcastUploadResult, m_eResult ) +END_DEFINE_CALLBACK_1() + +DEFINE_CALLBACK( GetVideoURLResult_t, k_iClientVideoCallbacks + 11 ) + CALLBACK_MEMBER( 0, EResult, m_eResult ) + CALLBACK_MEMBER( 1, AppId_t, m_unVideoAppID ) + CALLBACK_MEMBER( 2, char, m_rgchURL[256] ) +END_DEFINE_CALLBACK_1() + + +#pragma pack( pop ) + + +#endif // ISTEAMVIDEO_H +``` + +`SpyCustom/sdk/istudiorender.h`: + +```h +#ifndef ISTUDIORENDER_H +#define ISTUDIORENDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "vector.h" +#include "vector4d.h" +#include "utlbuffer.h" +#include "utlvector.h" +#include "imaterial.h" +#include "imaterialsystem.h" +#include "IAppSystem.h" +#include "imdlcache.h" +#include "studio.h" + + +struct studiohdr_t; +struct studiomeshdata_t; +class Vector; +struct LightDesc_t; +class IMaterial; +struct studiohwdata_t; +struct Ray_t; +class Vector4D; +class IMaterialSystem; +struct matrix3x4_t; +class IMesh; +struct vertexFileHeader_t; +struct FlashlightState_t; +class VMatrix; +namespace OptimizedModel { struct FileHeader_t; } +class IPooledVBAllocator; + +typedef void (*StudioRender_Printf_t)(PRINTF_FORMAT_STRING 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]; +}; + + + +DECLARE_POINTER_HANDLE(StudioDecalHandle_t); +#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; + CUtlVectorFixed m_Materials; +}; + +struct ColorMeshInfo_t +{ + IMesh* m_pMesh; + IPooledVBAllocator* m_pPooledVBAllocator; + int m_nVertOffsetInBytes; + int m_nNumVerts; +}; + +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_t m_PoseToWorld[MAXSTUDIOBONES]; +}; + + +struct model_array_instance_t +{ + matrix3x4_t modelToWorld; + +}; + +#define STUDIO_DATA_CACHE_INTERFACE_VERSION "VStudioDataCache005" + +abstract_class IStudioDataCache : public IAppSystem +{ +public: + virtual bool VerifyHeaders(studiohdr_t * pStudioHdr) = 0; + virtual vertexFileHeader_t* CacheVertexData(studiohdr_t* pStudioHdr) = 0; +}; + + +#define STUDIO_RENDER_INTERFACE_VERSION "VStudioRender025" + +abstract_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_t* 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_t* pBoneToWorld, float* pFlexWeights, float* pFlexDelayedWeights, const Vector& modelOrigin, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL) = 0; + + virtual void DrawModelStaticProp(const DrawModelInfo_t& drawInfo, const matrix3x4_t& modelToWorld, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL) = 0; + virtual void DrawStaticPropDecals(const DrawModelInfo_t& drawInfo, const matrix3x4_t& modelToWorld) = 0; + virtual void DrawStaticPropShadows(const DrawModelInfo_t& drawInfo, const matrix3x4_t& modelToWorld, int flags) = 0; + + 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_t* pBoneToWorld, + const Ray_t& ray, const Vector& decalUp, IMaterial* pDecalMaterial, float radius, int body, bool noPokethru = false, int maxLODToDecal = ADDDECAL_TO_ALL_LODS) = 0; + + 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_t* 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; +}; + +extern IStudioRender* g_pStudioRender; + +#endif +``` + +`SpyCustom/sdk/item_selection_criteria.h`: + +```h +#ifndef ITEM_SELECTION_CRITERIA_H +#define ITEM_SELECTION_CRITERIA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "game_item_schema.h" + +const int k_cchCreateItemLen = 64; + +enum EItemCriteriaOperator +{ + k_EOperator_String_EQ = 0, + k_EOperator_Not = 1, + k_EOperator_String_Not_EQ = 1, + k_EOperator_Float_EQ = 2, + k_EOperator_Float_Not_EQ = 3, + k_EOperator_Float_LT = 4, + k_EOperator_Float_Not_LT = 5, + k_EOperator_Float_LTE = 6, + k_EOperator_Float_Not_LTE = 7, + k_EOperator_Float_GT = 8, + k_EOperator_Float_Not_GT = 9, + k_EOperator_Float_GTE = 10, + k_EOperator_Float_Not_GTE = 11, + k_EOperator_Subkey_Contains = 12, + k_EOperator_Subkey_Not_Contains = 13, + + k_EItemCriteriaOperator_Count = 14, +}; + + +EItemCriteriaOperator EItemCriteriaOperatorFromName(const char* pch); +const char* PchNameFromEItemCriteriaOperator(int eItemCriteriaOperator); + +class CEconItemSchema; +class CEconItemDefinition; +class CEconItem; +class CSOItemCriteria; +class CSOItemCriteriaCondition; + +const uint8 k_unItemRarity_Any = 0xF; +const uint8 k_unItemQuality_Any = 0xF; + + +class CItemSelectionCriteria +{ +public: + CItemSelectionCriteria() : + m_bItemLevelSet(false), + m_unItemLevel(0), + m_bQualitySet(false), + m_nItemQuality(k_unItemQuality_Any), + m_bRaritySet(false), + m_nItemRarity(k_unItemRarity_Any), + m_unInitialInventory(0), + m_unInitialQuantity(1), + m_bForcedQualityMatch(false), + m_bIgnoreEnabledFlag(false), + m_bRecentOnly(false), + m_bIsLootList(false) + { + } + + CItemSelectionCriteria(const CItemSelectionCriteria& that); + CItemSelectionCriteria& operator=(const CItemSelectionCriteria& rhs); + ~CItemSelectionCriteria(); + + bool BItemLevelSet(void) const { return m_bItemLevelSet; } + uint32 GetItemLevel(void) const { Assert(m_bItemLevelSet); return m_unItemLevel; } + void SetItemLevel(uint32 unLevel) { m_unItemLevel = unLevel; m_bItemLevelSet = true; } + bool BQualitySet(void) const { return m_bQualitySet; } + int32 GetQuality(void) const { Assert(m_bQualitySet); return m_nItemQuality; } + void SetQuality(int32 nQuality) { m_nItemQuality = nQuality; m_bQualitySet = true; } + bool BRaritySet(void) const { return m_bRaritySet; } + int32 GetRarity(void) const { Assert(m_bRaritySet); return m_nItemRarity; } + void SetRarity(int32 nRarity) { m_nItemRarity = nRarity; m_bRaritySet = true; } + uint32 GetInitialInventory(void) const { return m_unInitialInventory; } + void SetInitialInventory(uint32 unInventory) { m_unInitialInventory = unInventory; } + uint32 GetInitialQuantity(void) const { return m_unInitialQuantity; } + void SetInitialQuantity(uint32 unQuantity) { m_unInitialQuantity = unQuantity; } + void SetExplicitQualityMatch(bool bExplicit) { m_bForcedQualityMatch = bExplicit; } + void SetIgnoreEnabledFlag(bool bIgnore) { m_bIgnoreEnabledFlag = bIgnore; } + void SetRecentOnly(bool bCheck) { m_bRecentOnly = bCheck; } + bool IsLootList(void) const { return m_bIsLootList; } + + bool BAddCondition(const char* pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired); + bool BAddCondition(const char* pszField, EItemCriteriaOperator eOp, const char* pszValue, bool bRequired); + int GetConditionsCount() { return m_vecConditions.Count(); } + const char* GetValueForFirstConditionOfFieldName(const char* pchName) const; + + bool BInitFromKV(KeyValues* pKVCriteria, const CEconItemSchema& schemaa); + bool BInitFromItemAndPaint(int nItemDef, int nPaintID, const CEconItemSchema& schemaa); + + bool BSerializeToMsg(CSOItemCriteria& msg) const; + bool BDeserializeFromMsg(const CSOItemCriteria& msg); + + bool BEvaluate(const CEconItemDefinition* pItemDef, const CEconItemSchema& pschema) const; + bool BEvaluate(const CEconItem* pItem, const CEconItemSchema& pschema) const; + +private: + class CCondition + { + public: + CCondition(const char* pszField, EItemCriteriaOperator eOp, bool bRequired) + : m_sField(pszField), m_EOp(eOp), m_bRequired(bRequired) + { + } + + virtual ~CCondition() { } + + bool BEvaluate(KeyValues* pKVItem) const; + + virtual bool BSerializeToMsg(CSOItemCriteriaCondition& msg) const; + + EItemCriteriaOperator GetEOp(void) const { return m_EOp; } + virtual const char* GetField(void) { return m_sField.Get(); } + virtual const char* GetValue(void) { Assert(0); return NULL; } + + protected: + virtual bool BInternalEvaluate(KeyValues* pKVItem) const = 0; + + CUtlString m_sField; + EItemCriteriaOperator m_EOp; + bool m_bRequired; + }; + + + class CStringCondition : public CCondition + { + public: + CStringCondition(const char* pszField, EItemCriteriaOperator eOp, const char* pszValue, bool bRequired) + : CCondition(pszField, eOp, bRequired), m_sValue(pszValue) + { + } + + virtual ~CStringCondition() { } + + virtual const char* GetValue(void) { return m_sValue.Get(); } + + protected: + virtual bool BInternalEvaluate(KeyValues* pKVItem) const; + virtual bool BSerializeToMsg(CSOItemCriteriaCondition& msg) const; + + CUtlString m_sValue; + }; + + + class CFloatCondition : public CCondition + { + public: + CFloatCondition(const char* pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired) + : CCondition(pszField, eOp, bRequired), m_flValue(flValue) + { + } + + virtual ~CFloatCondition() { } + + protected: + virtual bool BInternalEvaluate(KeyValues* pKVItem) const; + virtual bool BSerializeToMsg(CSOItemCriteriaCondition& msg) const; + + float m_flValue; + }; + + + class CSetCondition : public CCondition + { + public: + CSetCondition(const char* pszField, EItemCriteriaOperator eOp, const char* pszValue, bool bRequired) + : CCondition(pszField, eOp, bRequired), m_sValue(pszValue) + { + } + + virtual ~CSetCondition() { } + + protected: + virtual bool BInternalEvaluate(KeyValues* pKVItem) const; + + virtual bool BSerializeToMsg(CSOItemCriteriaCondition& msg) const; + + CUtlString m_sValue; + }; + + bool m_bItemLevelSet; + uint32 m_unItemLevel; + bool m_bQualitySet; + int32 m_nItemQuality; + bool m_bRaritySet; + int32 m_nItemRarity; + uint32 m_unInitialInventory; + uint32 m_unInitialQuantity; + bool m_bForcedQualityMatch; + bool m_bIgnoreEnabledFlag; + bool m_bRecentOnly; + bool m_bIsLootList; + + CUtlVector m_vecConditions; +}; + + +#endif +``` + +`SpyCustom/sdk/itempents.h`: + +```h +#if !defined( ITEMPENTS_H ) +#define ITEMPENTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "ipredictionsystem.h" +#include "shattersurfacetypes.h" +#include "irecipientfilter.h" + +class CEffectData; +class KeyValues; + + +abstract_class ITempEntsSystem : public IPredictionSystem +{ +public: + virtual bool SuppressTE(IRecipientFilter & filter) = 0; + virtual void ArmorRicochet(IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir) = 0; + virtual void BeamEntPoint(IRecipientFilter& filer, float delay, + int nStartEntity, const Vector* start, int nEndEntity, const Vector* end, + int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, + int r, int g, int b, int a, int speed) = 0; + virtual void BeamEnts(IRecipientFilter& filer, float delay, + int start, int end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, + int r, int g, int b, int a, int speed) = 0; + virtual void BeamFollow(IRecipientFilter& filter, float delay, + int iEntIndex, int modelIndex, int haloIndex, float life, float width, float endWidth, + float fadeLength, float r, float g, float b, float a) = 0; + virtual void BeamPoints(IRecipientFilter& filer, float delay, + const Vector* start, const Vector* end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, + int r, int g, int b, int a, int speed) = 0; + virtual void BeamLaser(IRecipientFilter& filer, float delay, + int start, int end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, float endWidth, int fadeLength, float amplitude, int r, int g, int b, int a, int speed) = 0; + virtual void BeamRing(IRecipientFilter& filer, float delay, + int start, int end, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, int spread, float amplitude, int r, int g, int b, int a, int speed, int flags = 0) = 0; + virtual void BeamRingPoint(IRecipientFilter& filer, float delay, + const Vector& center, float start_radius, float end_radius, int modelindex, int haloindex, int startframe, int framerate, + float life, float width, int spread, float amplitude, int r, int g, int b, int a, int speed, int flags = 0) = 0; + virtual void BeamSpline(IRecipientFilter& filer, float delay, + int points, Vector* rgPoints) = 0; + virtual void BloodStream(IRecipientFilter& filer, float delay, + const Vector* org, const Vector* dir, int r, int g, int b, int a, int amount) = 0; + virtual void BloodSprite(IRecipientFilter& filer, float delay, + const Vector* org, const Vector* dir, int r, int g, int b, int a, int size) = 0; + virtual void BreakModel(IRecipientFilter& filer, float delay, + const Vector& pos, const QAngle& angle, const Vector& size, const Vector& vel, + int modelindex, int randomization, int count, float time, int flags) = 0; + virtual void BSPDecal(IRecipientFilter& filer, float delay, + const Vector* pos, int entity, int index) = 0; + virtual void ProjectDecal(IRecipientFilter& filter, float delay, + const Vector* pos, const QAngle* angles, float distance, int index) = 0; + virtual void Bubbles(IRecipientFilter& filer, float delay, + const Vector* mins, const Vector* maxs, float height, int modelindex, int count, float speed) = 0; + virtual void BubbleTrail(IRecipientFilter& filer, float delay, + const Vector* mins, const Vector* maxs, float height, int modelindex, int count, float speed) = 0; + virtual void Decal(IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* start, int entity, int hitbox, int index) = 0; + virtual void DynamicLight(IRecipientFilter& filer, float delay, + const Vector* org, int r, int g, int b, int exponent, float radius, float time, float decay) = 0; + virtual void Explosion(IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float scale, int framerate, int flags, int radius, int magnitude, const Vector* normal = NULL, unsigned char materialType = 'C') = 0; + virtual void ShatterSurface(IRecipientFilter& filer, float delay, + const Vector* pos, const QAngle* angle, const Vector* vForce, const Vector* vForcePos, + float width, float height, float shardsize, ShatterSurface_t surfacetype, + int front_r, int front_g, int front_b, int back_r, int back_g, int back_b) = 0; + virtual void GlowSprite(IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float life, float size, int brightness) = 0; + virtual void FootprintDecal(IRecipientFilter& filer, float delay, const Vector* origin, const Vector* right, + int entity, int index, unsigned char materialType) = 0; + virtual void Fizz(IRecipientFilter& filer, float delay, + const CBaseEntity* ed, int modelindex, int density, int current) = 0; + virtual void KillPlayerAttachments(IRecipientFilter& filer, float delay, + int player) = 0; + virtual void LargeFunnel(IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, int reversed) = 0; + virtual void MetalSparks(IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir) = 0; + virtual void EnergySplash(IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir, bool bExplosive) = 0; + virtual void PlayerDecal(IRecipientFilter& filer, float delay, + const Vector* pos, int player, int entity) = 0; + virtual void ShowLine(IRecipientFilter& filer, float delay, + const Vector* start, const Vector* end) = 0; + virtual void Smoke(IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float scale, int framerate) = 0; + virtual void Sparks(IRecipientFilter& filer, float delay, + const Vector* pos, int nMagnitude, int nTrailLength, const Vector* pDir) = 0; + virtual void Sprite(IRecipientFilter& filer, float delay, + const Vector* pos, int modelindex, float size, int brightness) = 0; + virtual void SpriteSpray(IRecipientFilter& filer, float delay, + const Vector* pos, const Vector* dir, int modelindex, int speed, float noise, int count) = 0; + virtual void WorldDecal(IRecipientFilter& filer, float delay, + const Vector* pos, int index) = 0; + virtual void MuzzleFlash(IRecipientFilter& filer, float delay, + const Vector& start, const QAngle& angles, float scale, int type) = 0; + virtual void Dust(IRecipientFilter& filer, float delay, + const Vector& pos, const Vector& dir, float size, float speed) = 0; + virtual void GaussExplosion(IRecipientFilter& filer, float delay, + const Vector& pos, const Vector& dir, int type) = 0; + virtual void PhysicsProp(IRecipientFilter& filter, float delay, int modelindex, int skin, + const Vector& pos, const QAngle& angles, const Vector& vel, int flags, int effects) = 0; + + virtual void TriggerTempEntity(KeyValues* pKeyValues) = 0; + + virtual void ClientProjectile(IRecipientFilter& filter, float delay, + const Vector* vecOrigin, const Vector* vecVelocity, int modelindex, int lifetime, CBaseEntity* pOwner) = 0; +}; + +extern ITempEntsSystem* te; + +#endif +``` + +`SpyCustom/sdk/itexture.h`: + +```h +#ifndef ITEXTURE_H +#define ITEXTURE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "imageformat.h" + +class IVTFTexture; +class ITexture; +struct Rect_t; + +abstract_class ITextureRegenerator +{ +public: + virtual void RegenerateTextureBits(ITexture * pTexture, IVTFTexture * pVTFTexture, Rect_t * pRect) = 0; + + virtual void Release() = 0; + +}; + +abstract_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; + +#if defined( _X360 ) + virtual bool ClearTexture(int r, int g, int b, int a) = 0; + virtual bool CreateRenderTargetSurface(int width, int height, ImageFormat format, bool bSameAsTexture) = 0; +#endif + + 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(); +} + + +#endif +``` + +`SpyCustom/sdk/itoolentity.h`: + +```h +#ifndef ITOOLENTITY_H +#define ITOOLENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "utlvector.h" +#include "Color.h" +#include "basehandle.h" +#include "iclientrenderable.h" +#include "ishadowmgr.h" + + +class IServerEntity; +class IClientEntity; +class IToolSystem; +class IClientRenderable; +class Vector; +class QAngle; +class CBaseEntity; +class CBaseAnimating; +class CTakeDamageInfo; +class ITempEntsSystem; +class IEntityFactoryDictionary; + + +typedef unsigned int HTOOLHANDLE; +enum +{ + HTOOLHANDLE_INVALID = 0 +}; + + +enum ClientShadowFlags_t +{ + SHADOW_FLAGS_USE_RENDER_TO_TEXTURE = (SHADOW_FLAGS_LAST_FLAG << 1), + SHADOW_FLAGS_ANIMATING_SOURCE = (SHADOW_FLAGS_LAST_FLAG << 2), + SHADOW_FLAGS_USE_DEPTH_TEXTURE = (SHADOW_FLAGS_LAST_FLAG << 3), + CLIENT_SHADOW_FLAGS_LAST_FLAG = SHADOW_FLAGS_USE_DEPTH_TEXTURE +}; + + +typedef void* EntitySearchResult; + + +class IClientTools : public IBaseInterface +{ +public: + virtual HTOOLHANDLE AttachToEntity(EntitySearchResult entityToAttach) = 0; + virtual void DetachFromEntity(EntitySearchResult entityToDetach) = 0; + + virtual bool IsValidHandle(HTOOLHANDLE handle) = 0; + + virtual int GetNumRecordables() = 0; + virtual HTOOLHANDLE GetRecordable(int index) = 0; + + virtual EntitySearchResult NextEntity(EntitySearchResult currentEnt) = 0; + EntitySearchResult FirstEntity() { return NextEntity(NULL); } + + virtual void SetEnabled(HTOOLHANDLE handle, bool enabled) = 0; + virtual void SetRecording(HTOOLHANDLE handle, bool recording) = 0; + virtual bool ShouldRecord(HTOOLHANDLE handle) = 0; + + virtual HTOOLHANDLE GetToolHandleForEntityByIndex(int entindex) = 0; + + virtual int GetModelIndex(HTOOLHANDLE handle) = 0; + virtual const char* GetModelName(HTOOLHANDLE handle) = 0; + virtual const char* GetClassname(HTOOLHANDLE handle) = 0; + + virtual void AddClientRenderable(IClientRenderable* pRenderable, int renderGroup) = 0; + virtual void RemoveClientRenderable(IClientRenderable* pRenderable) = 0; + virtual void SetRenderGroup(IClientRenderable* pRenderable, int renderGroup) = 0; + virtual void MarkClientRenderableDirty(IClientRenderable* pRenderable) = 0; + virtual void UpdateProjectedTexture(ClientShadowHandle_t h, bool bForce) = 0; + + virtual bool DrawSprite(IClientRenderable* pRenderable, float scale, float frame, int rendermode, int renderfx, const Color& color, float flProxyRadius, int* pVisHandle) = 0; + + virtual EntitySearchResult GetLocalPlayer() = 0; + virtual bool GetLocalPlayerEyePosition(Vector& org, QAngle& ang, float& fov) = 0; + + virtual ClientShadowHandle_t CreateShadow(CBaseHandle handle, int nFlags) = 0; + virtual void DestroyShadow(ClientShadowHandle_t h) = 0; + + virtual ClientShadowHandle_t CreateFlashlight(const FlashlightState_t& lightState) = 0; + virtual void DestroyFlashlight(ClientShadowHandle_t h) = 0; + virtual void UpdateFlashlightState(ClientShadowHandle_t h, const FlashlightState_t& lightState) = 0; + + virtual void AddToDirtyShadowList(ClientShadowHandle_t h, bool force = false) = 0; + virtual void MarkRenderToTextureShadowDirty(ClientShadowHandle_t h) = 0; + + virtual void EnableRecordingMode(bool bEnable) = 0; + virtual bool IsInRecordingMode() const = 0; + + virtual void TriggerTempEntity(KeyValues* pKeyValues) = 0; + + virtual int GetOwningWeaponEntIndex(int entindex) = 0; + virtual int GetEntIndex(EntitySearchResult entityToAttach) = 0; + + virtual int FindGlobalFlexcontroller(char const* name) = 0; + virtual char const* GetGlobalFlexControllerName(int idx) = 0; + + virtual EntitySearchResult GetOwnerEntity(EntitySearchResult currentEnt) = 0; + + virtual bool IsPlayer(EntitySearchResult currentEnt) = 0; + virtual bool IsBaseCombatCharacter(EntitySearchResult currentEnt) = 0; + virtual bool IsNPC(EntitySearchResult currentEnt) = 0; + + virtual Vector GetAbsOrigin(HTOOLHANDLE handle) = 0; + virtual QAngle GetAbsAngles(HTOOLHANDLE handle) = 0; + + virtual void ReloadParticleDefintions(const char* pFileName, const void* pBufData, int nLen) = 0; + + virtual void PostToolMessage(KeyValues* pKeyValues) = 0; + + virtual void EnableParticleSystems(bool bEnable) = 0; + + virtual bool IsRenderingThirdPerson() const = 0; +}; + +#define VCLIENTTOOLS_INTERFACE_VERSION "VCLIENTTOOLS001" + + +class IServerTools : public IBaseInterface +{ +public: + virtual IServerEntity* GetIServerEntity(IClientEntity* pClientEntity) = 0; + virtual bool SnapPlayerToPosition(const Vector& org, const QAngle& ang, IClientEntity* pClientPlayer = NULL) = 0; + virtual bool GetPlayerPosition(Vector& org, QAngle& ang, IClientEntity* pClientPlayer = NULL) = 0; + virtual bool SetPlayerFOV(int fov, IClientEntity* pClientPlayer = NULL) = 0; + virtual int GetPlayerFOV(IClientEntity* pClientPlayer = NULL) = 0; + virtual bool IsInNoClipMode(IClientEntity* pClientPlayer = NULL) = 0; + + virtual CBaseEntity* FirstEntity(void) = 0; + virtual CBaseEntity* NextEntity(CBaseEntity* pEntity) = 0; + virtual CBaseEntity* FindEntityByHammerID(int iHammerID) = 0; + + virtual bool GetKeyValue(CBaseEntity* pEntity, const char* szField, char* szValue, int iMaxLen) = 0; + virtual bool SetKeyValue(CBaseEntity* pEntity, const char* szField, const char* szValue) = 0; + virtual bool SetKeyValue(CBaseEntity* pEntity, const char* szField, float flValue) = 0; + virtual bool SetKeyValue(CBaseEntity* pEntity, const char* szField, const Vector& vecValue) = 0; + + virtual CBaseEntity* CreateEntityByName(const char* szClassName) = 0; + virtual void DispatchSpawn(CBaseEntity* pEntity) = 0; + + virtual void ReloadParticleDefintions(const char* pFileName, const void* pBufData, int nLen) = 0; + + virtual void AddOriginToPVS(const Vector& org) = 0; + virtual void MoveEngineViewTo(const Vector& vPos, const QAngle& vAngles) = 0; + + virtual bool DestroyEntityByHammerId(int iHammerID) = 0; + virtual CBaseEntity* GetBaseEntityByEntIndex(int iEntIndex) = 0; + virtual void RemoveEntity(CBaseEntity* pEntity) = 0; + virtual void RemoveEntityImmediate(CBaseEntity* pEntity) = 0; + virtual IEntityFactoryDictionary* GetEntityFactoryDictionary(void) = 0; + + virtual void SetMoveType(CBaseEntity* pEntity, int val) = 0; + virtual void SetMoveType(CBaseEntity* pEntity, int val, int moveCollide) = 0; + virtual void ResetSequence(CBaseAnimating* pEntity, int nSequence) = 0; + virtual void ResetSequenceInfo(CBaseAnimating* pEntity) = 0; + + virtual void ClearMultiDamage(void) = 0; + virtual void ApplyMultiDamage(void) = 0; + virtual void AddMultiDamage(const CTakeDamageInfo& pTakeDamageInfo, CBaseEntity* pEntity) = 0; + virtual void RadiusDamage(const CTakeDamageInfo& info, const Vector& vecSrc, float flRadius, int iClassIgnore, CBaseEntity* pEntityIgnore) = 0; + + virtual ITempEntsSystem* GetTempEntsSystem(void) = 0; +}; + +typedef IServerTools IServerTools001; + +#define VSERVERTOOLS_INTERFACE_VERSION_1 "VSERVERTOOLS001" +#define VSERVERTOOLS_INTERFACE_VERSION "VSERVERTOOLS002" +#define VSERVERTOOLS_INTERFACE_VERSION_INT 2 + +class IServerChoreoTools : public IBaseInterface +{ +public: + + virtual EntitySearchResult NextChoreoEntity(EntitySearchResult currentEnt) = 0; + EntitySearchResult FirstChoreoEntity() { return NextChoreoEntity(NULL); } + virtual const char* GetSceneFile(EntitySearchResult sr) = 0; + + virtual int GetEntIndex(EntitySearchResult sr) = 0; + virtual void ReloadSceneFromDisk(int entindex) = 0; +}; + +#define VSERVERCHOREOTOOLS_INTERFACE_VERSION "VSERVERCHOREOTOOLS001" + +#endif +``` + +`SpyCustom/sdk/ivdebugoverlay.h`: + +```h +#ifndef IVDEBUGOVERLAY_H +#define IVDEBUGOVERLAY_H + +#ifdef _WIN32 +#pragma once +#endif + +class Vector; + +#define VDEBUG_OVERLAY_INTERFACE_VERSION "VDebugOverlay003" + +#define NDEBUG_PERSIST_TILL_NEXT_SERVER (0.0f) + +class OverlayText_t; + +abstract_class IVDebugOverlay +{ +public: + virtual void __unkn() = 0; + 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 Vector& origin, const Vector& mins, const Vector& max, Vector const& orientation, int r, int g, int b, int a, float duration) = 0; + virtual void AddSphereOverlay(const Vector& vOrigin, float flRadius, int nTheta, int nPhi, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector& p3, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration) = 0; + virtual void AddTextOverlay(const Vector& origin, float duration, const char* format, ...) = 0; + virtual void AddTextOverlay(const Vector& 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 Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle& angles, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddGridOverlay(const Vector& origin) = 0; + virtual void AddCoordFrameOverlay(const matrix3x4_t& frame, float flScale, int vColorTable[3][3] = NULL) = 0; + virtual int ScreenPosition(const Vector& point, Vector& screen) = 0; + virtual int ScreenPosition(float flXPos, float flYPos, Vector& screen) = 0; + virtual OverlayText_t* GetFirst(void) = 0; + virtual OverlayText_t* GetNext(OverlayText_t* current) = 0; + virtual void ClearDeadOverlays(void) = 0; + virtual void ClearAllOverlays() = 0; + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, const char* format, ...) = 0; + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, int r, int g, int b, int a, const char* format, ...) = 0; + virtual void AddLineOverlayAlpha(const Vector& origin, const Vector& dest, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddBoxOverlay2(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, const Color& faceColor, const Color& edgeColor, float duration) = 0; + virtual void PurgeTextOverlays() = 0; + virtual void DrawPill(const Vector& mins, const Vector& max, float& diameter, int r, int g, int b, int a, float duration) = 0; +}; +#endif +``` + +`SpyCustom/sdk/iviewport.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IVIEWPORT_H ) +#define IVIEWPORT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui.h" + +#include "viewport_panel_names.h" + +class KeyValues; + +abstract_class IViewPortPanel +{ + +public: + virtual ~IViewPortPanel() {}; + + virtual const char *GetName( void ) = 0;// return identifer name + virtual void SetData(KeyValues *data) = 0; // set ViewPortPanel data + virtual void Reset( void ) = 0; // clears internal state, deactivates it + virtual void Update( void ) = 0; // updates all (size, position, content, etc) + virtual bool NeedsUpdate( void ) = 0; // query panel if content needs to be updated + virtual bool HasInputElements( void ) = 0; // true if panel contains elments which accepts input + virtual void ReloadScheme( void ) {} + virtual bool CanReplace( const char *panelName ) const { return true; } // returns true if this panel can appear on top of the given panel + virtual bool CanBeReopened( void ) const { return true; } // returns true if this panel can be re-opened after being hidden by another panel + + virtual void ShowPanel( bool state ) = 0; // activate VGUI Frame + + // VGUI functions: + virtual vgui::VPANEL GetVPanel( void ) = 0; // returns VGUI panel handle + virtual bool IsVisible() = 0; // true if panel is visible + virtual void SetParent( vgui::VPANEL parent ) = 0; + + virtual bool WantsBackgroundBlurred( void ) = 0; + + virtual void UpdateVisibility( void ) {} + virtual void ViewportThink( void ) {} + virtual void LevelInit( void ) {} +}; + +abstract_class IViewPort +{ +public: + virtual void UpdateAllPanels( void ) = 0; + virtual void ShowPanel( const char *pName, bool state, KeyValues *data, bool autoDeleteData = true ) = 0; + virtual void ShowPanel( const char *pName, bool state ) = 0; + virtual void ShowPanel( IViewPortPanel* pPanel, bool state ) = 0; + virtual void ShowBackGround(bool bShow) = 0; + virtual IViewPortPanel* FindPanelByName(const char *szPanelName) = 0; + virtual IViewPortPanel* GetActivePanel( void ) = 0; + virtual void LevelInit( void ) = 0; + virtual void RecreatePanel( const char *szPanelName ) = 0; + virtual void PostMessageToPanel( const char *pName, KeyValues *pKeyValues ) = 0; +}; + +extern IViewPort *GetViewPortInterface(); +extern IViewPort *GetFullscreenViewPortInterface(); + +#endif // IVIEWPORT_H +``` + +`SpyCustom/sdk/iviewrender.h`: + +```h +#if !defined( IVIEWRENDER_H ) +#define IVIEWRENDER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "ivrenderview.h" + + +#define MAX_DEPTH_TEXTURE_SHADOWS 1 +#define MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS 0 + +#define MAX_DEPTH_TEXTURE_SHADOWS_TOOLS 8 +#define MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS_TOOLS 0 + + +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 = 0x80, + + DF_RENDER_PSEUDO_TRANSLUCENT_WATER = 0x100, + DF_WATERHEIGHT = 0x200, + DF_DRAW_SSAO = 0x400, + DF_DRAWSKYBOX = 0x800, + + DF_FUDGE_UP = 0x1000, + + DF_DRAW_ENTITITES = 0x2000, + + DF_SKIP_WORLD = 0x4000, + DF_SKIP_WORLD_DECALS_AND_OVERLAYS = 0x8000, + + DF_UNUSED5 = 0x10000, + DF_SAVEGAMESCREENSHOT = 0x20000, + DF_CLIP_SKYBOX = 0x40000, + + DF_DRAW_SIMPLE_WORLD_MODEL = 0x80000, + + DF_SHADOW_DEPTH_MAP = 0x100000, + + DF_FAST_ENTITY_RENDERING = 0x200000, + DF_DRAW_SIMPLE_WORLD_MODEL_WATER = 0x400000, +}; + +class CViewSetup; +class C_BaseEntity; +struct vrect_t; +class C_BaseViewModel; + +abstract_class IViewRender +{ +public: + virtual void Init(void) = 0; + + virtual void LevelInit(void) = 0; + virtual void LevelShutdown(void) = 0; + + virtual void Shutdown(void) = 0; + + virtual void OnRenderStart() = 0; + + virtual void Render(vrect_t* rect) = 0; + + virtual void RenderView(const CViewSetup& view, const CViewSetup& hudViewSetup, int nClearFlags, int whatToDraw) = 0; + + virtual int GetDrawFlags() = 0; + + virtual void StartPitchDrift(void) = 0; + virtual void StopPitchDrift(void) = 0; + + virtual VPlane* GetFrustum() = 0; + + virtual bool ShouldDrawBrushModels(void) = 0; + + virtual const CViewSetup* GetPlayerViewSetup(int nSlot = -1) 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) = 0; + + virtual void QueueOverlayRenderView(const CViewSetup& view, int nClearFlags, int whatToDraw) = 0; + + virtual float GetZNear() = 0; + virtual float GetZFar() = 0; + + virtual void GetScreenFadeDistances(float* pMin, float* pMax, float* pScale) = 0; + + virtual C_BaseEntity* GetCurrentlyDrawingEntity() = 0; + virtual void SetCurrentlyDrawingEntity(C_BaseEntity* pEnt) = 0; + + virtual bool UpdateShadowDepthTexture(ITexture* pRenderTarget, ITexture* pDepthTexture, const CViewSetup& shadowView, bool bRenderWorldAndObjects = true, bool bRenderViewModels = false) = 0; + + virtual void FreezeFrame(float flFreezeTime) = 0; + + virtual void InitFadeData(void) = 0; +}; + +extern IViewRender* view; + +#endif +``` + +`SpyCustom/sdk/iviewrender_beams.h`: + +```h +#if !defined( IVIEWRENDER_BEAMS_H ) +#define IVIEWRENDER_BEAMS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" +#include "beam_flags.h" +#include "tempentity.h" + +extern void SetBeamCreationAllowed(bool state); +extern bool BeamCreationAllowed(void); + + +class C_Beam; +class Beam_t; + +struct BeamTrail_t +{ + BeamTrail_t* next; + float die; + Vector org; + Vector vel; +}; + +struct BeamInfo_t +{ + int m_nType; + + C_BaseEntity* m_pStartEnt; + int m_nStartAttachment; + C_BaseEntity* 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 = TE_BEAMPOINTS; + m_nSegments = -1; + m_pszModelName = NULL; + m_pszHaloName = NULL; + m_nModelIndex = -1; + m_nHaloIndex = -1; + m_bRenderable = true; + m_nFlags = 0; + } +}; + + +abstract_class IViewRenderBeams +{ +public: +public: +public: + virtual void InitBeams(void) = 0; + virtual void ShutdownBeams(void) = 0; + virtual void ClearBeams(void) = 0; + + virtual void UpdateTempEntBeams() = 0; + + + virtual void DrawBeam(C_Beam* pbeam, ITraceFilter* pEntityBeamTraceFilter = NULL) = 0; + virtual void DrawBeam(Beam_t* pbeam) = 0; + + + virtual void KillDeadBeams(CBaseEntity* pEnt) = 0; + + 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; + + 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; +}; + +#endif + +``` + +`SpyCustom/sdk/ivmodelinfo.h`: + +```h +#ifndef IVMODELINFO_H +#define IVMODELINFO_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "dbg.h" +#include "gametrace.h" + +class IMaterial; +class KeyValues; +struct vcollide_t; +struct model_t; +class Vector; +class QAngle; +//class CGameTrace; +struct cplane_t; +typedef CGameTrace trace_t; +struct studiohdr_t; +struct virtualmodel_t; +typedef unsigned char byte; +struct virtualterrainparams_t; +class CPhysCollide; +typedef unsigned short MDLHandle_t; +class CUtlBuffer; +class IClientRenderable; + +class CStudioHdr; +enum RenderableTranslucencyType_t +{ + RENDERABLE_IS_OPAQUE = 0, + RENDERABLE_IS_TRANSLUCENT, + RENDERABLE_IS_TWO_PASS, +}; + +abstract_class IModelLoadCallback +{ +public: + virtual void OnModelLoadComplete(const model_t * pModel) = 0; + +protected: + ~IModelLoadCallback(); +}; + + +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; } +}; + + +#define VMODELINFO_CLIENT_INTERFACE_VERSION "VModelInfoClient006" +#define VMODELINFO_SERVER_INTERFACE_VERSION_3 "VModelInfoServer003" +#define VMODELINFO_SERVER_INTERFACE_VERSION "VModelInfoServer004" + +inline bool IsDynamicModelIndex(int modelindex) { return modelindex < -1; } +inline bool IsClientOnlyModelIndex(int modelindex) { return modelindex < -1 && (modelindex & 1); } + + +class IVModelInfo +{ +public: + virtual ~IVModelInfo(void) {} + virtual const model_t* GetModel(int modelindex) const = 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) const = 0; + virtual vcollide_t* GetVCollide(int modelindex) const = 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 Unused0() {}; + virtual void UNUSED() = 0; + virtual void UNUSE11D() = 0; + virtual RenderableTranslucencyType_t ComputeTranslucencyType(const model_t* model, int nSkin, int nBody) = 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 CStudioHdr* GetStudioHdr(MDLHandle_t handle) = 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 uint8_t* 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) const = 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, IClientRenderable** pClientRenderable) const = 0; + virtual const model_t* FindOrLoadModel(const char* name) const = 0; + 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 bool UsesEnvCubemap(const model_t* model) const = 0; + virtual bool UsesStaticLighting(const model_t* model) const = 0; +}; + +typedef IVModelInfo IVModelInfo003; + + +abstract_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; +}; + + +struct virtualterrainparams_t +{ + int index; +}; + + + + +#endif +``` + +`SpyCustom/sdk/ivmodelrender.h`: + +```h +#ifndef IVMODELRENDER_H +#define IVMODELRENDER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include "mathlib.h" +#include "istudiorender.h" +#include "idatacache.h" + +struct mstudioanimdesc_t; +struct mstudioseqdesc_t; +struct model_t; +class IClientRenderable; +class Vector; +struct studiohdr_t; +class IMaterial; +class CStudioHdr; +struct MaterialLightingState_t; + +FORWARD_DECLARE_HANDLE(LightCacheHandle_t); + + +struct DrawModelState_t +{ + studiohdr_t* m_pStudioHdr; + studiohwdata_t* m_pStudioHWData; + IClientRenderable* m_pRenderable; + const matrix3x4_t* m_pModelToWorld; + StudioDecalHandle_t m_decals; + int m_drawFlags; + int m_lod; +}; + + +#define VENGINE_HUDMODEL_INTERFACE_VERSION "VEngineModel016" + +typedef unsigned short ModelInstanceHandle_t; + +enum +{ + MODEL_INSTANCE_INVALID = (ModelInstanceHandle_t)~0 +}; + + +struct ModelRenderInfo_t +{ + Vector origin; + Vector angles; + char pad[4]; + IClientRenderable* pRenderable; + const model_t* pModel; + const matrix3x4_t* pModelToWorld; + const matrix3x4_t* pLightingOffset; + const Vector* pLightingOrigin; + int flags; + int entity_index; + int skin; + int body; + int hitboxset; + ModelInstanceHandle_t instance; + + ModelRenderInfo_t() + { + pModelToWorld = NULL; + pLightingOffset = NULL; + pLightingOrigin = NULL; + } +}; + +struct StaticPropRenderInfo_t +{ + const matrix3x4_t* pModelToWorld; + const model_t* pModel; + IClientRenderable* pRenderable; + Vector* pLightingOrigin; + short skin; + ModelInstanceHandle_t instance; +}; + +struct LightingQuery_t +{ +Vector m_LightingOrigin; +ModelInstanceHandle_t m_InstanceHandle; +bool m_bAmbientBoost; +}; + +struct StaticLightingQuery_t : public LightingQuery_t +{ +IClientRenderable * m_pRenderable; +}; +class IVModelRender +{ +public: + virtual int DrawModel(int flags, IClientRenderable* pRenderable, ModelInstanceHandle_t instance, int entity_index, const model_t* model, Vector const& origin, QAngle const& angles, int skin, int body, int hitboxset, const matrix3x4_t* modelToWorld = NULL, const matrix3x4_t* pLightingOffset = NULL) = 0; + virtual void ForcedMaterialOverride(IMaterial* newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL, int nOverrides = 0) = 0; + virtual bool IsForcedMaterialOverride(void) = 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, int maxLODToDecal) = 0; + virtual void RemoveAllDecals(ModelInstanceHandle_t handle) = 0; + virtual bool ModelHasDecals(ModelInstanceHandle_t handle) = 0; + virtual void RemoveAllDecalsFromAllModels() = 0; + virtual matrix3x4_t* DrawModelShadowSetup(IClientRenderable* pRenderable, int body, int skin, DrawModelInfo_t* pInfo, matrix3x4_t* pCustomBoneToWorld = NULL) = 0; + virtual void DrawModelShadow(IClientRenderable* pRenderable, const DrawModelInfo_t& info, matrix3x4_t* pCustomBoneToWorld = NULL) = 0; + 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_t** ppBoneToWorldOut) = 0; + virtual void DrawModelExecute(IMatRenderContext* ctx, const DrawModelState_t& state, const ModelRenderInfo_t& pInfo, matrix3x4_t* 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 SetupLightingEx(const Vector& vecCenter, ModelInstanceHandle_t handle) = 0; + virtual bool GetBrightestShadowingLightSource(const Vector& vecCenter, Vector& lightPos, Vector& lightBrightness, bool bAllowNonTaggedLights) = 0; + virtual void ComputeLightingState(int nCount, const LightingQuery_t* pQuery, MaterialLightingState_t* pState, ITexture** ppEnvCubemapTexture) = 0; + virtual void GetModelDecalHandles(StudioDecalHandle_t* pDecals, int nDecalStride, int nCount, const ModelInstanceHandle_t* pHandles) = 0; + virtual void ComputeStaticLightingState(int nCount, const StaticLightingQuery_t* pQuery, MaterialLightingState_t* pState, MaterialLightingState_t* pDecalState, ColorMeshInfo_t** ppStaticLighting, ITexture** ppEnvCubemapTexture, DataCacheHandle_t* pColorMeshHandles) = 0; + virtual void CleanupStaticLightingState(int nCount, DataCacheHandle_t* pColorMeshHandles) = 0; +}; + +#endif +``` + +`SpyCustom/sdk/ivrenderview.h`: + +```h +#if !defined( IVRENDERVIEW_H ) +#define IVRENDERVIEW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "vplane.h" +#include "interface.h" +#include "imaterialsystem.h" +#include "const.h" +#include "vertexcolor.h" +#include "refcount.h" + + + +class CViewSetup; +class CEngineSprite; +class IClientEntity; +class IMaterial; +struct model_t; +class IClientRenderable; +class IMatRenderContext; +class CVolumeCuller; + + +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_WORLD_GEOMETRY = 0x200, + DRAWWORLDLISTS_DRAW_DECALS_AND_OVERLAYS = 0x400, + DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL = 0x800, + DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL_WATER = 0x1000, + DRAWWORLDLISTS_DRAW_SKIP_DISPLACEMENTS = 0x2000, + DRAWWORLDLISTS_DRAW_SSAO = 0x4000, +}; + +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_t +{ + DEPTH_MODE_NORMAL = 0, + DEPTH_MODE_SHADOW = 1, + DEPTH_MODE_SSA0 = 2, + + DEPTH_MODE_MAX +}; + + +static const char* s_pMatSortGroupsString[] = +{ + "Sort: Abovewater", + "Sort: Underwater", + "Sort: IntersectsWater", + "Sort: WaterSurface", +}; + +typedef VPlane Frustum[FRUSTUM_NUMPLANES]; + + +typedef unsigned short LeafIndex_t; +enum +{ + INVALID_LEAF_INDEX = (LeafIndex_t)~0 +}; + + +#if 1 +struct WorldListLeafData_t +{ + LeafIndex_t leafIndex; + int16 waterData; + uint16 firstTranslucentSurface; + uint16 translucentSurfaceCount; +}; +#else +struct WorldListLeafData_t +{ + uint32 leafIndex; + int32 waterData; + uint32 firstTranslucentSurface; + uint32 translucentSurfaceCount; +}; +#endif +struct WorldListInfo_t +{ + int m_ViewFogVolume; + int m_LeafCount; + bool m_bHasWater; + WorldListLeafData_t* m_pLeafDataList; +}; + +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; + +private: + BrushVertex_t(const BrushVertex_t& src); +}; + +struct VisOverrideData_t +{ + Vector m_vecVisOrigin; + float m_fDistToAreaPortalTolerance; + + Vector m_vPortalCorners[4]; + bool m_bTrimFrustumToPortalCorners; + + Vector m_vPortalOrigin; + Vector m_vPortalForward; + float m_flPortalRadius; + +}; + + +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, +}; + + +struct BrushArrayInstanceData_t +{ + matrix3x4a_t* m_pBrushToWorld; + const model_t* m_pBrushModel; + Vector4D m_DiffuseModulation; + ShaderStencilState_t* m_pStencilState; +}; + + +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, const VisOverrideData_t* pVisOverrideData, VisibleFogVolumeInfo_t* pInfo) = 0; + + virtual IWorldRenderList* CreateWorldList() = 0; +#if defined(_PS3) + virtual IWorldRenderList* CreateWorldList_PS3(int viewID) = 0; + virtual void BuildWorldLists_PS3_Epilogue(IWorldRenderList* pList, WorldListInfo_t* pInfo, bool bShadowDepth) = 0; +#else + virtual void BuildWorldLists_Epilogue(IWorldRenderList* pList, WorldListInfo_t* pInfo, bool bShadowDepth) = 0; +#endif + 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(IMatRenderContext* pRenderContext, IWorldRenderList* pList, unsigned long flags, float waterZAdjust) = 0; + virtual void GetWorldListIndicesInfo(WorldListIndicesInfo_t* pIndicesInfoOut, IWorldRenderList* pList, unsigned long nFlags) = 0; + + virtual void DrawTopView(bool enable) = 0; + virtual void TopViewNoBackfaceCulling(bool bDisable) = 0; + virtual void TopViewNoVisCheck(bool bDisable) = 0; + virtual void TopViewBounds(Vector2D const& mins, Vector2D const& maxs) = 0; + virtual void SetTopViewVolumeCuller(const CVolumeCuller* pVolumeCuller) = 0; + + virtual void DrawLights(void) = 0; + virtual void DrawMaskEntities(void) = 0; + + virtual void DrawTranslucentSurfaces(IMatRenderContext* pRenderContext, IWorldRenderList* pList, int* pSortList, int sortCount, unsigned long flags) = 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, bool mapFullTextureToScreen = true) = 0; + virtual void OLD_SetProjectionMatrix(float fov, float zNear, float zFar) = 0; + virtual colorVec GetLightAtPoint(Vector& pos) = 0; + virtual int GetViewEntity(void) = 0; + virtual bool IsViewEntity(int entindex) = 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(IMatRenderContext* pRenderContext, const CViewSetup& view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes) = 0; + virtual void Push2DView(IMatRenderContext* pRenderContext, const CViewSetup& view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes) = 0; + virtual void PopView(IMatRenderContext* pRenderContext, Frustum frustumPlanes) = 0; + + virtual void SetMainView(const Vector& vecOrigin, const QAngle& angles) = 0; + + enum + { + VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS = 0x00000001 + }; + + 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_t DepthMode) = 0; + virtual void UpdateBrushModelLightmap(model_t* model, IClientRenderable* pRenderable) = 0; + virtual void BeginUpdateLightmaps(void) = 0; + virtual void EndUpdateLightmaps() = 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(IMatRenderContext* pRenderContext, 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; + + virtual bool DoesBrushModelNeedPowerOf2Framebuffer(const model_t* model) = 0; + + virtual void DrawBrushModelArray(IMatRenderContext* pContext, int nCount, const BrushArrayInstanceData_t* pInstanceData, int nModelTypeFlags) = 0; +}; + +#define VENGINE_RENDERVIEW_INTERFACE_VERSION "VEngineRenderView014" + +#if defined(_STATIC_LINKED) && defined(CLIENT_DLL) +namespace Client +{ + extern IVRenderView* render; +} +#else +extern IVRenderView* render; +#endif + +#endif +``` + +`SpyCustom/sdk/jobthread.h`: + +```h +#include +#include "threadtools.h" +#include "refcount.h" +#include "utllinkedlist.h" +#include "utlvector.h" +#include "functors.h" + +#include "vstdlib.h" + +#ifndef JOBTHREAD_H +#define JOBTHREAD_H + +#ifdef AddJob +#undef AddJob +#undef GetJob +#endif + +#ifdef VSTDLIB_DLL_EXPORT +#define JOB_INTERFACE DLL_EXPORT +#define JOB_OVERLOAD DLL_GLOBAL_EXPORT +#define JOB_CLASS DLL_CLASS_EXPORT +#else +#define JOB_INTERFACE DLL_IMPORT +#define JOB_OVERLOAD DLL_GLOBAL_IMPORT +#define JOB_CLASS DLL_CLASS_IMPORT +#endif + +#if defined( _WIN32 ) +#pragma once +#endif + +class CJob; + +enum JobStatusEnum_t +{ + JOB_OK, + JOB_STATUS_PENDING, + JOB_STATUS_INPROGRESS, + JOB_STATUS_ABORTED, + JOB_STATUS_UNSERVICED, +}; + +typedef int JobStatus_t; + +enum JobFlags_t +{ + JF_IO = (1 << 0), + JF_BOOST_THREAD = (1 << 1), + JF_SERIAL = (1 << 2), + JF_QUEUE = (1 << 3), +}; + +enum JobPriority_t +{ + JP_LOW, + JP_NORMAL, + JP_HIGH, + JP_IMMEDIATE, + + JP_NUM_PRIORITIES, + + JP_FRAME = JP_NORMAL, + JP_FRAME_SEGMENT = JP_HIGH, +}; + +#define TP_MAX_POOL_THREADS 64 +struct ThreadPoolStartParams_t +{ + ThreadPoolStartParams_t(bool bIOThreads = false, unsigned nThreads = (unsigned)-1, int* pAffinities = NULL, ThreeState_t fDistribute = TRS_NONE, unsigned nStackSize = (unsigned)-1, int iThreadPriority = SHRT_MIN) + : bIOThreads(bIOThreads), nThreads(nThreads), nThreadsMax(-1), fDistribute(fDistribute), nStackSize(nStackSize), iThreadPriority(iThreadPriority) + { + bExecOnThreadPoolThreadsOnly = false; +#if defined( DEDICATED ) && IsPlatformLinux() + bEnableOnLinuxDedicatedServer = false; +#endif + + bUseAffinityTable = (pAffinities != NULL) && (fDistribute == TRS_TRUE) && (nThreads != (unsigned)-1); + if (bUseAffinityTable) + { + nThreads = MIN(TP_MAX_POOL_THREADS, nThreads); + for (unsigned int i = 0; i < nThreads; i++) + { + iAffinityTable[i] = pAffinities[i]; + } + } + } + + int nThreads; + int nThreadsMax; + ThreeState_t fDistribute; + int nStackSize; + int iThreadPriority; + int iAffinityTable[TP_MAX_POOL_THREADS]; + + bool bIOThreads : 1; + bool bUseAffinityTable : 1; + bool bExecOnThreadPoolThreadsOnly : 1; +#if defined( DEDICATED ) && IsPlatformLinux() + bool bEnableOnLinuxDedicatedServer : 1; +#endif +}; + +typedef bool (*JobFilter_t)(CJob*); + +enum ThreadPoolMessages_t +{ + TPM_EXIT, + TPM_SUSPEND, +}; + +#ifdef Yield +#undef Yield +#endif + +abstract_class IThreadPool : public IRefCounted +{ +public: + virtual ~IThreadPool() {}; + + virtual bool Start(const ThreadPoolStartParams_t& startParams = ThreadPoolStartParams_t()) = 0; + virtual bool Stop(int timeout = TT_INFINITE) = 0; + + virtual unsigned GetJobCount() = 0; + virtual int NumThreads() = 0; + virtual int NumIdleThreads() = 0; + + virtual int SuspendExecution() = 0; + virtual int ResumeExecution() = 0; + + virtual int YieldWait(CThreadEvent** pEvents, int nEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE) = 0; + virtual int YieldWait(CJob**, int nJobs, bool bWaitAll = true, unsigned timeout = TT_INFINITE) = 0; + virtual void Yield(unsigned timeout) = 0; + + bool YieldWait(CThreadEvent& event, unsigned timeout = TT_INFINITE); + bool YieldWait(CJob*, unsigned timeout = TT_INFINITE); + + virtual void AddJob(CJob*) = 0; + + virtual void AddFunctor(CFunctor* pFunctor, CJob** ppJob = NULL, const char* pszDescription = NULL, unsigned flags = 0) { AddFunctorInternal(RetAddRef(pFunctor), ppJob, pszDescription, flags); } + + virtual void ChangePriority(CJob* p, JobPriority_t priority) = 0; + + int ExecuteAll(JobFilter_t pfnFilter = NULL) { return ExecuteToPriority(JP_LOW, pfnFilter); } + virtual int ExecuteToPriority(JobPriority_t toPriority, JobFilter_t pfnFilter = NULL) = 0; + virtual int AbortAll() = 0; + + virtual void AddPerFrameJob(CJob*) = 0; + + #define DEFINE_NONMEMBER_ADD_CALL(N) \ + template \ + CJob *AddCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + #define DEFINE_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + #define DEFINE_CONST_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + #define DEFINE_REF_COUNTING_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + #define DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL(N) \ + template \ + CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + if ( !NumIdleThreads() ) \ + { \ + pJob = GetDummyJob(); \ + FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \ + } \ + \ + return pJob; \ + } + + #define DEFINE_NONMEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + #define DEFINE_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + #define DEFINE_CONST_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + #define DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + return pJob; \ + } + + #define DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \ + template \ + CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + CJob *pJob; \ + AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \ + \ + return pJob; \ + } + + FUNC_GENERATE_ALL(DEFINE_NONMEMBER_ADD_CALL); + FUNC_GENERATE_ALL(DEFINE_MEMBER_ADD_CALL); + FUNC_GENERATE_ALL(DEFINE_CONST_MEMBER_ADD_CALL); + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_MEMBER_ADD_CALL); + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL); + FUNC_GENERATE_ALL(DEFINE_NONMEMBER_QUEUE_CALL); + FUNC_GENERATE_ALL(DEFINE_MEMBER_QUEUE_CALL); + FUNC_GENERATE_ALL(DEFINE_CONST_MEMBER_QUEUE_CALL); + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL); + FUNC_GENERATE_ALL(DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL); + + #undef DEFINE_NONMEMBER_ADD_CALL + #undef DEFINE_MEMBER_ADD_CALL + #undef DEFINE_CONST_MEMBER_ADD_CALL + #undef DEFINE_REF_COUNTING_MEMBER_ADD_CALL + #undef DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL + #undef DEFINE_NONMEMBER_QUEUE_CALL + #undef DEFINE_MEMBER_QUEUE_CALL + #undef DEFINE_CONST_MEMBER_QUEUE_CALL + #undef DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL + #undef DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL + +private: + virtual void AddFunctorInternal(CFunctor*, CJob** = NULL, const char* pszDescription = NULL, unsigned flags = 0) = 0; + + friend class CJob; + + virtual CJob* GetDummyJob() = 0; + +public: + virtual void Distribute(bool bDistribute = true, int* pAffinityTable = NULL) = 0; + + virtual bool Start(const ThreadPoolStartParams_t& startParams, const char* pszNameOverride) = 0; + + virtual int YieldWaitPerFrameJobs() = 0; +}; + +JOB_INTERFACE IThreadPool* CreateNewThreadPool(); +JOB_INTERFACE void DestroyThreadPool(IThreadPool* pPool); + +JOB_INTERFACE void RunThreadPoolTests(); + +JOB_INTERFACE IThreadPool* g_pThreadPool; +#ifdef _X360 +JOB_INTERFACE IThreadPool* g_pAlternateThreadPool; +#endif + +DECLARE_POINTER_HANDLE(ThreadPoolData_t); +#define JOB_NO_DATA ((ThreadPoolData_t)-1) + +class CJob : public CRefCounted1 +{ +public: + CJob(JobPriority_t priority = JP_NORMAL) + : m_status(JOB_STATUS_UNSERVICED), + m_ThreadPoolData(JOB_NO_DATA), + m_priority(priority), + m_flags(0), + m_pThreadPool(NULL), + m_CompleteEvent(true), + m_iServicingThread(-1) + { + } + + void SetPriority(JobPriority_t priority) { m_priority = priority; } + JobPriority_t GetPriority() const { return m_priority; } + + void SetFlags(unsigned flags) { m_flags = flags; } + unsigned GetFlags() const { return m_flags; } + + void SetServiceThread(int iServicingThread) { m_iServicingThread = (char)iServicingThread; } + int GetServiceThread() const { return m_iServicingThread; } + void ClearServiceThread() { m_iServicingThread = -1; } + + bool Executed() const { return (m_status == JOB_OK); } + bool CanExecute() const { return (m_status == JOB_STATUS_PENDING || m_status == JOB_STATUS_UNSERVICED); } + bool IsFinished() const { return (m_status != JOB_STATUS_PENDING && m_status != JOB_STATUS_INPROGRESS && m_status != JOB_STATUS_UNSERVICED); } + JobStatus_t GetStatus() const { return m_status; } + + bool TryLock() { return m_mutex.TryLock(); } + void Lock() { m_mutex.Lock(); } + void Unlock() { m_mutex.Unlock(); } + + bool WaitForFinish(uint32 dwTimeout = TT_INFINITE) { if (!this) return true; return (!IsFinished()) ? g_pThreadPool->YieldWait(this, dwTimeout) : true; } + bool WaitForFinishAndRelease(uint32 dwTimeout = TT_INFINITE) { if (!this) return true; bool bResult = WaitForFinish(dwTimeout); Release(); return bResult; } + CThreadEvent* AccessEvent() { return &m_CompleteEvent; } + + JobStatus_t Execute(); + JobStatus_t TryExecute(); + JobStatus_t ExecuteAndRelease() { JobStatus_t status = Execute(); Release(); return status; } + JobStatus_t TryExecuteAndRelease() { JobStatus_t status = TryExecute(); Release(); return status; } + + JobStatus_t Abort(bool bDiscard = true); + + virtual char const* Describe() { return "Job"; } + +private: + friend class CThreadPool; + + JobStatus_t m_status; + JobPriority_t m_priority; + CThreadMutex m_mutex; + unsigned char m_flags; + char m_iServicingThread; + short m_reserved; + ThreadPoolData_t m_ThreadPoolData; + IThreadPool* m_pThreadPool; + CThreadEvent m_CompleteEvent; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + void* m_ParentStackTrace[THREAD_PARENT_STACK_TRACE_LENGTH]; +#endif + +private: + CJob(const CJob& fromRequest); + void operator=(const CJob& fromRequest); + + virtual JobStatus_t DoExecute() = 0; + virtual JobStatus_t DoAbort(bool bDiscard) { return JOB_STATUS_ABORTED; } + virtual void DoCleanup() {} +}; + +class CFunctorJob : public CJob +{ +public: + CFunctorJob(CFunctor* pFunctor, const char* pszDescription = NULL) + : m_pFunctor(pFunctor) + { + if (pszDescription) + { + Q_strncpy(m_szDescription, pszDescription, sizeof(m_szDescription)); + } + else + { + m_szDescription[0] = 0; + } + } + + virtual JobStatus_t DoExecute() + { + (*m_pFunctor)(); + return JOB_OK; + } + + const char* Describe() + { + return m_szDescription; + } + +private: + CRefPtr m_pFunctor; + char m_szDescription[16]; +}; + +class CJobSet +{ +public: + CJobSet(CJob* pJob = NULL) + { + if (pJob) + { + m_jobs.AddToTail(pJob); + } + } + + CJobSet(CJob** ppJobs, int nJobs) + { + if (ppJobs) + { + m_jobs.AddMultipleToTail(nJobs, ppJobs); + } + } + + ~CJobSet() + { + for (int i = 0; i < m_jobs.Count(); i++) + { + m_jobs[i]->Release(); + } + } + + void operator+=(CJob* pJob) + { + m_jobs.AddToTail(pJob); + } + + void operator-=(CJob* pJob) + { + m_jobs.FindAndRemove(pJob); + } + + void Execute(bool bRelease = true) + { + for (int i = 0; i < m_jobs.Count(); i++) + { + m_jobs[i]->Execute(); + if (bRelease) + { + m_jobs[i]->Release(); + } + } + + if (bRelease) + { + m_jobs.RemoveAll(); + } + } + + void Abort(bool bRelease = true) + { + for (int i = 0; i < m_jobs.Count(); i++) + { + m_jobs[i]->Abort(); + if (bRelease) + { + m_jobs[i]->Release(); + } + } + + if (bRelease) + { + m_jobs.RemoveAll(); + } + } + + void WaitForFinish(bool bRelease = true) + { + for (int i = 0; i < m_jobs.Count(); i++) + { + m_jobs[i]->WaitForFinish(); + if (bRelease) + { + m_jobs[i]->Release(); + } + } + + if (bRelease) + { + m_jobs.RemoveAll(); + } + } + + void WaitForFinish(IThreadPool* pPool, bool bRelease = true) + { + pPool->YieldWait(m_jobs.Base(), m_jobs.Count()); + + if (bRelease) + { + for (int i = 0; i < m_jobs.Count(); i++) + { + m_jobs[i]->Release(); + } + + m_jobs.RemoveAll(); + } + } + +private: + CUtlVectorFixed m_jobs; +}; + +#define ThreadExecute g_pThreadPool->QueueCall +#define ThreadExecuteRef g_pThreadPool->QueueRefCall + +#define BeginExecuteParallel() do { CJobSet jobSet +#define EndExecuteParallel() jobSet.WaitForFinish( g_pThreadPool ); } while (0) + +#define ExecuteParallel jobSet += g_pThreadPool->QueueCall +#define ExecuteRefParallel jobSet += g_pThreadPool->QueueCallRef + + +#pragma warning(push) +#pragma warning(disable:4389) +#pragma warning(disable:4018) +#pragma warning(disable:4701) + +#define DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL(N) \ + template \ + void IterRangeParallel(FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_SEPARATOR_##N FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + const int MAX_THREADS = 16; \ + int nIdle = g_pThreadPool->NumIdleThreads(); \ + ITERTYPE1 range = to - from; \ + int nThreads = min( nIdle + 1, range ); \ + if ( nThreads > MAX_THREADS ) \ + { \ + nThreads = MAX_THREADS; \ + } \ + if ( nThreads < 2 ) \ + { \ + FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + ITERTYPE1 nIncrement = range / nThreads; \ + \ + CJobSet jobSet; \ + while ( --nThreads ) \ + { \ + ITERTYPE2 thisTo = from + nIncrement; \ + jobSet += g_pThreadPool->AddCall( pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \ + from = thisTo; \ + } \ + FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + jobSet.WaitForFinish( g_pThreadPool ); \ + } \ + \ + } + +FUNC_GENERATE_ALL(DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL); + +#define DEFINE_MEMBER_ITER_RANGE_PARALLEL(N) \ + template \ + void IterRangeParallel(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_SEPARATOR_##N FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + const int MAX_THREADS = 16; \ + int nIdle = g_pThreadPool->NumIdleThreads(); \ + ITERTYPE1 range = to - from; \ + int nThreads = min( nIdle + 1, range ); \ + if ( nThreads > MAX_THREADS ) \ + { \ + nThreads = MAX_THREADS; \ + } \ + if ( nThreads < 2 ) \ + { \ + FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } \ + else \ + { \ + ITERTYPE1 nIncrement = range / nThreads; \ + \ + CJobSet jobSet; \ + while ( --nThreads ) \ + { \ + ITERTYPE2 thisTo = from + nIncrement; \ + jobSet += g_pThreadPool->AddCall( pObject, pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \ + from = thisTo; \ + } \ + FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \ + jobSet.WaitForFinish( g_pThreadPool ); \ + } \ + \ + } + +FUNC_GENERATE_ALL(DEFINE_MEMBER_ITER_RANGE_PARALLEL); + + +template +class CJobItemProcessor +{ +public: + typedef T ItemType_t; + void Begin() {} + void End() {} +}; + +template +class CFuncJobItemProcessor : public CJobItemProcessor +{ +public: + void Init(void (*pfnProcess)(T&), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL) + { + m_pfnProcess = pfnProcess; + m_pfnBegin = pfnBegin; + m_pfnEnd = pfnEnd; + } + + void Begin() { if (m_pfnBegin) (*m_pfnBegin)(); } + void Process(T& item) { (*m_pfnProcess)(item); } + void End() { if (m_pfnEnd) (*m_pfnEnd)(); } + +protected: + void (*m_pfnProcess)(T&); + void (*m_pfnBegin)(); + void (*m_pfnEnd)(); +}; + +template +class CMemberFuncJobItemProcessor : public CJobItemProcessor +{ +public: + void Init(OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(T&), void (FUNCTION_CLASS::* pfnBegin)() = NULL, void (FUNCTION_CLASS::* pfnEnd)() = NULL) + { + m_pObject = pObject; + m_pfnProcess = pfnProcess; + m_pfnBegin = pfnBegin; + m_pfnEnd = pfnEnd; + } + + void Begin() { if (m_pfnBegin) ((*m_pObject).*m_pfnBegin)(); } + void Process(T& item) { ((*m_pObject).*m_pfnProcess)(item); } + void End() { if (m_pfnEnd) ((*m_pObject).*m_pfnEnd)(); } + +protected: + OBJECT_TYPE* m_pObject; + + void (FUNCTION_CLASS::* m_pfnProcess)(T&); + void (FUNCTION_CLASS::* m_pfnBegin)(); + void (FUNCTION_CLASS::* m_pfnEnd)(); +}; + +template +class CLoopFuncJobItemProcessor : public CJobItemProcessor +{ +public: + void Init(void (*pfnProcess)(T*, int, int), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL) + { + m_pfnProcess = pfnProcess; + m_pfnBegin = pfnBegin; + m_pfnEnd = pfnEnd; + } + + void Begin() { if (m_pfnBegin) (*m_pfnBegin)(); } + void Process(T* pContext, int nFirst, int nCount) { (*m_pfnProcess)(pContext, nFirst, nCount); } + void End() { if (m_pfnEnd) (*m_pfnEnd)(); } + +protected: + void (*m_pfnProcess)(T*, int, int); + void (*m_pfnBegin)(); + void (*m_pfnEnd)(); +}; + +template +class CLoopMemberFuncJobItemProcessor : public CJobItemProcessor +{ +public: + void Init(OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(T*, int, int), void (FUNCTION_CLASS::* pfnBegin)() = NULL, void (FUNCTION_CLASS::* pfnEnd)() = NULL) + { + m_pObject = pObject; + m_pfnProcess = pfnProcess; + m_pfnBegin = pfnBegin; + m_pfnEnd = pfnEnd; + } + + void Begin() { if (m_pfnBegin) ((*m_pObject).*m_pfnBegin)(); } + void Process(T* item, int nFirst, int nCount) { ((*m_pObject).*m_pfnProcess)(item, nFirst, nCount); } + void End() { if (m_pfnEnd) ((*m_pObject).*m_pfnEnd)(); } + +protected: + OBJECT_TYPE* m_pObject; + + void (FUNCTION_CLASS::* m_pfnProcess)(T*, int, int); + void (FUNCTION_CLASS::* m_pfnBegin)(); + void (FUNCTION_CLASS::* m_pfnEnd)(); +}; + + +#pragma warning(push) +#pragma warning(disable:4189) + +template +class CParallelProcessor +{ +public: + CParallelProcessor() + { + m_pItems = m_pLimit = 0; + } + + void Run(ITEM_TYPE* pItems, unsigned nItems, int nChunkSize = 1, int nMaxParallel = INT_MAX, IThreadPool* pThreadPool = NULL) + { + if (nItems == 0) + return; + +#if defined(_X360) + volatile int ignored = ID_TO_PREVENT_COMDATS_IN_PROFILES; +#endif + + m_nChunkSize = nChunkSize; + if (!pThreadPool) + { + pThreadPool = g_pThreadPool; + } + + m_pItems = pItems; + m_pLimit = pItems + nItems; + + int nJobs = nItems - 1; + + if (nJobs > nMaxParallel) + { + nJobs = nMaxParallel; + } + + if (!pThreadPool) + { + DoExecute(); + return; + } + + int nThreads = pThreadPool->NumThreads(); + if (nJobs > nThreads) + { + nJobs = nThreads; + } + + if (nJobs > 0) + { + CJob** jobs = (CJob**)stackalloc(nJobs * sizeof(CJob**)); + int i = nJobs; + + while (i--) + { + jobs[i] = pThreadPool->QueueCall(this, &CParallelProcessor::DoExecute); + } + + DoExecute(); + + for (i = 0; i < nJobs; i++) + { + jobs[i]->Abort(); + jobs[i]->Release(); + } + } + else + { + DoExecute(); + } + } + + ITEM_PROCESSOR_TYPE m_ItemProcessor; + +private: + void DoExecute() + { + if (m_pItems < m_pLimit) + { +#if defined(_X360) + volatile int ignored = ID_TO_PREVENT_COMDATS_IN_PROFILES; +#endif + m_ItemProcessor.Begin(); + + ITEM_TYPE* pLimit = m_pLimit; + + int nChunkSize = m_nChunkSize; + for (;;) + { + ITEM_TYPE* pCurrent = m_pItems.AtomicAdd(nChunkSize); + ITEM_TYPE* pLast = MIN(pLimit, pCurrent + nChunkSize); + while (pCurrent < pLast) + { + m_ItemProcessor.Process(*pCurrent); + pCurrent++; + } + if (pCurrent >= pLimit) + { + break; + } + } + m_ItemProcessor.End(); + } + } + CInterlockedPtr m_pItems; + ITEM_TYPE* m_pLimit; + int m_nChunkSize; + +}; + +#pragma warning(pop) + +template +inline void ParallelProcess(ITEM_TYPE* pItems, unsigned nItems, void (*pfnProcess)(ITEM_TYPE&), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pfnProcess, pfnBegin, pfnEnd); + processor.Run(pItems, nItems, 1, nMaxParallel); +} + +template +inline void ParallelProcess(ITEM_TYPE* pItems, unsigned nItems, OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(ITEM_TYPE&), void (FUNCTION_CLASS::* pfnBegin)() = NULL, void (FUNCTION_CLASS::* pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pObject, pfnProcess, pfnBegin, pfnEnd); + processor.Run(pItems, nItems, 1, nMaxParallel); +} + +template +inline void ParallelProcess(IThreadPool* pPool, ITEM_TYPE* pItems, unsigned nItems, void (*pfnProcess)(ITEM_TYPE&), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pfnProcess, pfnBegin, pfnEnd); + processor.Run(pItems, nItems, 1, nMaxParallel, pPool); +} + +template +inline void ParallelProcess(IThreadPool* pPool, ITEM_TYPE* pItems, unsigned nItems, OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(ITEM_TYPE&), void (FUNCTION_CLASS::* pfnBegin)() = NULL, void (FUNCTION_CLASS::* pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pObject, pfnProcess, pfnBegin, pfnEnd); + processor.Run(pItems, nItems, 1, nMaxParallel, pPool); +} + +template +inline void ParallelProcessChunks(ITEM_TYPE* pItems, unsigned nItems, void (*pfnProcess)(ITEM_TYPE&), int nChunkSize, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pfnProcess, NULL, NULL); + processor.Run(pItems, nItems, nChunkSize, nMaxParallel); +} + +template +inline void ParallelProcessChunks(ITEM_TYPE* pItems, unsigned nItems, OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(ITEM_TYPE&), int nChunkSize, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pObject, pfnProcess, NULL, NULL); + processor.Run(pItems, nItems, nChunkSize, nMaxParallel); +} + +template +inline void ParallelProcessChunks(IThreadPool* pPool, ITEM_TYPE* pItems, unsigned nItems, OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(ITEM_TYPE&), int nChunkSize, int nMaxParallel = INT_MAX) +{ + CParallelProcessor > processor; + processor.m_ItemProcessor.Init(pObject, pfnProcess, NULL, NULL); + processor.Run(pItems, nItems, nChunkSize, nMaxParallel, pPool); +} + + +template +class CParallelLoopProcessor +{ +public: + CParallelLoopProcessor() + { + m_nIndex = m_nLimit = 0; + m_nChunkCount = 0; + m_nActive = 0; + } + + void Run(CONTEXT_TYPE* pContext, int nBegin, int nItems, int nChunkCount, int nMaxParallel = INT_MAX, IThreadPool* pThreadPool = NULL) + { + if (!nItems) + return; + + if (!pThreadPool) + { + pThreadPool = g_pThreadPool; + } + + m_pContext = pContext; + m_nIndex = nBegin; + m_nLimit = nBegin + nItems; + nChunkCount = MAX(MIN(nItems, nChunkCount), 1); + m_nChunkCount = (nItems + nChunkCount - 1) / nChunkCount; + int nJobs = (nItems + m_nChunkCount - 1) / m_nChunkCount; + if (nJobs > nMaxParallel) + { + nJobs = nMaxParallel; + } + + if (!pThreadPool) + { + DoExecute(); + return; + } + + int nThreads = pThreadPool->NumThreads(); + if (nJobs > nThreads) + { + nJobs = nThreads; + } + + if (nJobs > 0) + { + CJob** jobs = (CJob**)stackalloc(nJobs * sizeof(CJob**)); + int i = nJobs; + + while (i--) + { + jobs[i] = pThreadPool->QueueCall(this, &CParallelLoopProcessor::DoExecute); + } + + DoExecute(); + + for (i = 0; i < nJobs; i++) + { + jobs[i]->Abort(); + jobs[i]->Release(); + } + } + else + { + DoExecute(); + } + } + + ITEM_PROCESSOR_TYPE m_ItemProcessor; + +private: + void DoExecute() + { + m_ItemProcessor.Begin(); + for (;;) + { + int nIndex = m_nIndex.AtomicAdd(m_nChunkCount); + if (nIndex < m_nLimit) + { + int nCount = MIN(m_nChunkCount, m_nLimit - nIndex); + m_ItemProcessor.Process(m_pContext, nIndex, nCount); + } + else + { + break; + } + } + m_ItemProcessor.End(); + --m_nActive; + } + + CONTEXT_TYPE* m_pContext; + CInterlockedInt m_nIndex; + int m_nLimit; + int m_nChunkCount; + CInterlockedInt m_nActive; +}; + +template < typename CONTEXT_TYPE > +inline void ParallelLoopProcess(IThreadPool* pPool, CONTEXT_TYPE* pContext, int nStart, int nCount, void (*pfnProcess)(CONTEXT_TYPE*, int, int), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelLoopProcessor< CONTEXT_TYPE, CLoopFuncJobItemProcessor< CONTEXT_TYPE > > processor; + processor.m_ItemProcessor.Init(pfnProcess, pfnBegin, pfnEnd); + processor.Run(pContext, nStart, nCount, 1, nMaxParallel, pPool); +} + +template < typename CONTEXT_TYPE, typename OBJECT_TYPE, typename FUNCTION_CLASS > +inline void ParallelLoopProcess(IThreadPool* pPool, CONTEXT_TYPE* pContext, int nStart, int nCount, OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(CONTEXT_TYPE*, int, int), void (FUNCTION_CLASS::* pfnBegin)() = NULL, void (FUNCTION_CLASS::* pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelLoopProcessor< CONTEXT_TYPE, CLoopMemberFuncJobItemProcessor > processor; + processor.m_ItemProcessor.Init(pObject, pfnProcess, pfnBegin, pfnEnd); + processor.Run(pContext, nStart, nCount, 1, nMaxParallel, pPool); +} + +template < typename CONTEXT_TYPE > +inline void ParallelLoopProcessChunks(IThreadPool* pPool, CONTEXT_TYPE* pContext, int nStart, int nCount, int nChunkSize, void (*pfnProcess)(CONTEXT_TYPE*, int, int), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelLoopProcessor< CONTEXT_TYPE, CLoopFuncJobItemProcessor< CONTEXT_TYPE > > processor; + processor.m_ItemProcessor.Init(pfnProcess, pfnBegin, pfnEnd); + processor.Run(pContext, nStart, nCount, nChunkSize, nMaxParallel, pPool); +} + +template < typename CONTEXT_TYPE, typename OBJECT_TYPE, typename FUNCTION_CLASS > +inline void ParallelLoopProcessChunks(IThreadPool* pPool, CONTEXT_TYPE* pContext, int nStart, int nCount, int nChunkSize, OBJECT_TYPE* pObject, void (FUNCTION_CLASS::* pfnProcess)(CONTEXT_TYPE*, int, int), void (FUNCTION_CLASS::* pfnBegin)() = NULL, void (FUNCTION_CLASS::* pfnEnd)() = NULL, int nMaxParallel = INT_MAX) +{ + CParallelLoopProcessor< CONTEXT_TYPE, CLoopMemberFuncJobItemProcessor > processor; + processor.m_ItemProcessor.Init(pObject, pfnProcess, pfnBegin, pfnEnd); + processor.Run(pContext, nStart, nCount, nChunkSize, nMaxParallel, pPool); +} + +template +class CParallelProcessorBase +{ +protected: + typedef CParallelProcessorBase ThisParallelProcessorBase_t; + typedef Derived ThisParallelProcessorDerived_t; + +public: + CParallelProcessorBase() + { + m_nActive = 0; + } + +protected: + void Run(int nMaxParallel = INT_MAX, int threadOverride = -1) + { + int i = g_pThreadPool->NumIdleThreads(); + + if (nMaxParallel < i) + { + i = nMaxParallel; + } + + while (i-- > 0) + { + if (threadOverride == -1 || i == threadOverride - 1) + { + ++m_nActive; + ThreadExecute(this, &ThisParallelProcessorBase_t::DoExecute)->Release(); + } + } + + if (threadOverride == -1 || threadOverride == 0) + { + ++m_nActive; + DoExecute(); + } + + while (m_nActive) + { + ThreadPause(); + } + } + +protected: + void OnBegin() {} + bool OnProcess() { return false; } + void OnEnd() {} + +private: + void DoExecute() + { + static_cast(this)->OnBegin(); + + while (static_cast(this)->OnProcess()) + continue; + + static_cast(this)->OnEnd(); + + --m_nActive; + } + + CInterlockedInt m_nActive; +}; + + + + +inline uintp FunctorExecuteThread(void* pParam) +{ + CFunctor* pFunctor = (CFunctor*)pParam; + (*pFunctor)(); + pFunctor->Release(); + return 0; +} + +inline ThreadHandle_t ThreadExecuteSoloImpl(CFunctor* pFunctor, const char* pszName = NULL); + + +inline ThreadHandle_t ThreadExecuteSolo(CJob* pJob) { return ThreadExecuteSoloImpl(CreateFunctor(pJob, &CJob::Execute), pJob->Describe()); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1) { return ThreadExecuteSoloImpl(CreateFunctor(a1), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2, T3 a3) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2, a3), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2, a3, a4), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2, a3, a4, a5), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2, a3, a4, a5, a6), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2, a3, a4, a5, a6, a7), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSolo(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) { return ThreadExecuteSoloImpl(CreateFunctor(a1, a2, a3, a4, a5, a6, a7, a8), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2, T3 a3) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2, a3), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2, a3, a4), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2, a3, a4, a5), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7), pszName); } + +template +inline ThreadHandle_t ThreadExecuteSoloRef(const char* pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) { return ThreadExecuteSoloImpl(CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7, a8), pszName); } + +inline bool IThreadPool::YieldWait(CThreadEvent& theEvent, unsigned timeout) +{ + CThreadEvent* pEvent = &theEvent; + return (YieldWait(&pEvent, 1, true, timeout) != TW_TIMEOUT); +} + +inline bool IThreadPool::YieldWait(CJob* pJob, unsigned timeout) +{ + return (YieldWait(&pJob, 1, true, timeout) != TW_TIMEOUT); +} + +inline JobStatus_t CJob::Execute() +{ + if (IsFinished()) + { + return m_status; + } + + AUTO_LOCK(m_mutex); + AddRef(); + + JobStatus_t result; + + switch (m_status) + { + case JOB_STATUS_UNSERVICED: + case JOB_STATUS_PENDING: + { + m_status = JOB_STATUS_INPROGRESS; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + { + CStackTop_ReferenceParentStack stackTop(m_ParentStackTrace, ARRAYSIZE(m_ParentStackTrace)); + result = m_status = DoExecute(); + } +#else + result = m_status = DoExecute(); +#endif + + DoCleanup(); + m_CompleteEvent.Set(); + break; + } + + case JOB_STATUS_INPROGRESS: + AssertMsg(0, "Mutex Should have protected use while processing"); + case JOB_OK: + case JOB_STATUS_ABORTED: + result = m_status; + break; + + default: + AssertMsg(m_status < JOB_OK, "Unknown job state"); + result = m_status; + } + + Release(); + + return result; +} + + +inline JobStatus_t CJob::TryExecute() +{ + if (!IsFinished() && TryLock()) + { + Execute(); + Unlock(); + } + return m_status; +} + +inline JobStatus_t CJob::Abort(bool bDiscard) +{ + if (IsFinished()) + { + return m_status; + } + + AUTO_LOCK(m_mutex); + AddRef(); + + JobStatus_t result; + + switch (m_status) + { + case JOB_STATUS_UNSERVICED: + case JOB_STATUS_PENDING: + { + result = m_status = DoAbort(bDiscard); + if (bDiscard) + DoCleanup(); + m_CompleteEvent.Set(); + } + break; + + case JOB_STATUS_ABORTED: + case JOB_STATUS_INPROGRESS: + case JOB_OK: + result = m_status; + break; + + default: + AssertMsg(m_status < JOB_OK, "Unknown job state"); + result = m_status; + } + + Release(); + + return result; +} + +#endif +``` + +`SpyCustom/sdk/keyvalues.h`: + +```h +#ifndef KEYVALUES_H +#define KEYVALUES_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#include "utlvector.h" +#include "color.h" +#include "exprevaluator.h" + +#define TRACK_KV_ADD( ptr, name ) track.AddKv( ptr, name ) +#define SPLIT_3_BYTES_INTO_1_AND_2( x1, x2, x3 ) do { x1 = (uint8)(x3); x2 = (uint16)( (x3) >> 8 ); } while( 0 ) + + +#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() ) + +#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() ) + +#define FOR_EACH_VALUE( kvRoot, kvValue ) \ + for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() ) + + +class IBaseFileSystem; +class CUtlBuffer; +class Color; +class CKeyValuesTokenReader; +class KeyValues; +class IKeyValuesDumpContext; +typedef void* FileHandle_t; +class CKeyValuesGrowableStringTable; + + +#define KV_BINARY_POOLED_FORMAT 0xAA + + +#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() ) + +#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() ) + +#define FOR_EACH_VALUE( kvRoot, kvValue ) \ + for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() ) + + +class KeyValues +{ + friend class CKeyValuesTokenReader; + +public: + static void SetUseGrowableStringTable(bool bUseGrowableTable); + + explicit KeyValues(const char* setName); + + class AutoDelete + { + public: + explicit inline AutoDelete(KeyValues* pKeyValues) : m_pKeyValues(pKeyValues) {} + explicit inline AutoDelete(const char* pchKVName) : m_pKeyValues(new KeyValues(pchKVName)) {} + inline ~AutoDelete(void) { delete m_pKeyValues; } + inline void Assign(KeyValues* pKeyValues) { m_pKeyValues = pKeyValues; } + inline KeyValues* Detach() { KeyValues* retval = m_pKeyValues; Assign(NULL); return retval; } + KeyValues* operator->() { return m_pKeyValues; } + operator KeyValues* () { return m_pKeyValues; } + private: + AutoDelete(AutoDelete const& x); + AutoDelete& operator= (AutoDelete const& x); + protected: + KeyValues* m_pKeyValues; + }; + + class AutoDeleteInline : public AutoDelete + { + public: + explicit inline AutoDeleteInline(KeyValues* pKeyValues) : AutoDelete(pKeyValues) {} + inline operator KeyValues* () const { return m_pKeyValues; } + inline KeyValues* Get() const { return m_pKeyValues; } + }; + + KeyValues(const char* setName, const char* firstKey, const char* firstValue); + KeyValues(const char* setName, const char* firstKey, const wchar_t* firstValue); + KeyValues(const char* setName, const char* firstKey, int firstValue); + KeyValues(const char* setName, const char* firstKey, const char* firstValue, const char* secondKey, const char* secondValue); + KeyValues(const char* setName, const char* firstKey, int firstValue, const char* secondKey, int secondValue); + + ~KeyValues(); + + const char* GetName() const; + void SetName(const char* setName); + + int GetNameSymbol() const; + int GetNameSymbolCaseSensitive() const; + + void UsesEscapeSequences(bool state); + bool LoadFromFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID = NULL); + + bool SaveToFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID = NULL, bool bWriteEmptySubkeys = false); + + bool LoadFromBuffer(char const* resourceName, const char* pBuffer, IBaseFileSystem* pFileSystem = NULL, const char* pPathID = NULL); + + bool LoadFromBuffer(char const* resourceName, CUtlBuffer& buf, IBaseFileSystem* pFileSystem = NULL, const char* pPathID = NULL); + + + + KeyValues* FindKey(const char* keyName, bool bCreate = false); + KeyValues* FindKey(int keySymbol) const; + KeyValues* CreateNewKey(); + void AddSubKey(KeyValues* pSubkey); + void RemoveSubKey(KeyValues* subKey); + void InsertSubKey(int nIndex, KeyValues* pSubKey); + bool ContainsSubKey(KeyValues* pSubKey); + void SwapSubKey(KeyValues* pExistingSubKey, KeyValues* pNewSubKey); + void ElideSubKey(KeyValues* pSubKey); + KeyValues* CreateKey(const char* keyName); + KeyValues* CreatePeerKey(const char* keyName); + + KeyValues* GetFirstSubKey() { return m_pSub; } + KeyValues* GetNextKey() { return m_pPeer; } + void SetNextKey(KeyValues* pDat); + + KeyValues* FindLastSubKey(); + + KeyValues* GetFirstTrueSubKey(); + KeyValues* GetNextTrueSubKey(); + + KeyValues* GetFirstValue(); + KeyValues* GetNextValue(); + + + int GetInt(const char* keyName = NULL, int defaultValue = 0); + uint64 GetUint64(const char* keyName = NULL, uint64 defaultValue = 0); + float GetFloat(const char* keyName = NULL, float defaultValue = 0.0f); + const char* GetString(const char* keyName = NULL, const char* defaultValue = ""); + const wchar_t* GetWString(const char* keyName = NULL, const wchar_t* defaultValue = L""); + void* GetPtr(const char* keyName = NULL, void* defaultValue = (void*)0); + Color GetColor(const char* keyName = NULL, const Color& defaultColor = Color(0, 0, 0, 0)); + bool GetBool(const char* keyName = NULL, bool defaultValue = false) { return GetInt(keyName, defaultValue ? 1 : 0) ? true : false; } + bool IsEmpty(const char* keyName = NULL); + + int GetInt(int keySymbol, int defaultValue = 0); + uint64 GetUint64(int keySymbol, uint64 defaultValue = 0); + float GetFloat(int keySymbol, float defaultValue = 0.0f); + const char* GetString(int keySymbol, const char* defaultValue = ""); + const wchar_t* GetWString(int keySymbol, const wchar_t* defaultValue = L""); + void* GetPtr(int keySymbol, void* defaultValue = (void*)0); + Color GetColor(int keySymbol ); + bool GetBool(int keySymbol, bool defaultValue = false) { return GetInt(keySymbol, defaultValue ? 1 : 0) ? true : false; } + bool IsEmpty(int keySymbol); + + void SetWString(const char* keyName, const wchar_t* value); + void SetString(const char* keyName, const char* value); + void SetInt(const char* keyName, int value); + void SetUint64(const char* keyName, uint64 value); + void SetFloat(const char* keyName, float value); + void SetPtr(const char* keyName, void* value); + void SetColor(const char* keyName, Color value); + void SetBool(const char* keyName, bool value) { SetInt(keyName, value ? 1 : 0); } + + void* operator new(size_t iAllocSize); + void* operator new(size_t iAllocSize, int nBlockUse, const char* pFileName, int nLine); + void operator delete(void* pMem); + void operator delete(void* pMem, int nBlockUse, const char* pFileName, int nLine); + + KeyValues& operator=(KeyValues& src); + + bool IsEqual(KeyValues* pRHS); + + void ChainKeyValue(KeyValues* pChain); + + void RecursiveSaveToFile(CUtlBuffer& buf, int indentLevel); + + bool WriteAsBinary(CUtlBuffer& buffer) const; + bool ReadAsBinary(CUtlBuffer& buffer, int nStackDepth = 0); + + bool WriteAsBinaryFiltered(CUtlBuffer& buffer); + bool ReadAsBinaryFiltered(CUtlBuffer& buffer, int nStackDepth = 0); + + KeyValues* MakeCopy(void) const; + + void CopySubkeys(KeyValues* pParent) const; + + void Clear(void); + + enum types_t + { + TYPE_NONE = 0, + TYPE_STRING, + TYPE_INT, + TYPE_FLOAT, + TYPE_PTR, + TYPE_WSTRING, + TYPE_COLOR, + TYPE_UINT64, + TYPE_COMPILED_INT_BYTE, + TYPE_COMPILED_INT_0, + TYPE_COMPILED_INT_1, + TYPE_NUMTYPES, + }; + types_t GetDataType(const char* keyName = NULL); + types_t GetDataType() const; + + void deleteThis(); + + void SetStringValue(char const* strValue); + + void UnpackIntoStructure(struct KeyValuesUnpackStructure const* pUnpackTable, void* pDest); + + bool ProcessResolutionKeys(const char* pResString); + + bool Dump(IKeyValuesDumpContext* pDump, int nIndentLevel = 0); + + enum MergeKeyValuesOp_t + { + MERGE_KV_ALL, + MERGE_KV_UPDATE, + MERGE_KV_DELETE, + MERGE_KV_BORROW, + }; + void MergeFrom(KeyValues* kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL); + + static KeyValues* FromString(char const* szName, char const* szStringVal, char const** ppEndOfParse = NULL); + + KeyValues* CreateKeyUsingKnownLastChild(const char* keyName, KeyValues* pLastChild); + void AddSubkeyUsingKnownLastChild(KeyValues* pSubKey, KeyValues* pLastChild); + + KeyValues(KeyValues&); + + + void RecursiveCopyKeyValues(KeyValues& src); + void RemoveEverything(); + void RecursiveSaveToFile(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel, bool bWriteEmptySubkeys = false); + void WriteConvertedString(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const char* pszString); + + void RecursiveLoadFromBuffer(char const* resourceName, CUtlBuffer& buf); + + void AppendIncludedKeys(CUtlVector< KeyValues* >& includedKeys); + void ParseIncludedKeys(char const* resourceName, const char* filetoinclude, + IBaseFileSystem* pFileSystem, const char* pPathID, CUtlVector< KeyValues* >& includedKeys); + + void MergeBaseKeys(CUtlVector< KeyValues* >& baseKeys); + void RecursiveMergeKeyValues(KeyValues* baseKV); + + void InternalWrite(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const void* pData, int len); + + void Init(); + const char* ReadToken(CUtlBuffer& buf, bool& wasQuoted, bool& wasConditional); + void WriteIndents(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel); + + void FreeAllocatedValue(); + void AllocateValueBlock(int size); + + bool ReadAsBinaryPooledFormat(CUtlBuffer& buf, IBaseFileSystem* pFileSystem, unsigned int poolKey, GetSymbolProc_t pfnEvaluateSymbolProc); + + bool EvaluateConditional(const char* str); + + uint32 m_iKeyName : 24; + uint32 m_iKeyNameCaseSensitive1 : 8; + + 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; + uint16 m_iKeyNameCaseSensitive2; + + uint32 m_iUnk1; + uint32 m_iUnk2; + + KeyValues* m_pPeer; + KeyValues* m_pSub; + KeyValues* m_pChain; + + GetSymbolProc_t m_pExpressionGetSymbolProc; + +private: + static int (*s_pfGetSymbolForString)(const char* name, bool bCreate); + static const char* (*s_pfGetStringForSymbol)(int symbol); + static CKeyValuesGrowableStringTable* s_pGrowableStringTable; + +public: + static int GetSymbolForStringClassic(const char* name, bool bCreate = true); + static const char* GetStringForSymbolClassic(int symbol); + + static int GetSymbolForStringGrowable(const char* name, bool bCreate = true); + static const char* GetStringForSymbolGrowable(int symbol); +}; + +typedef KeyValues::AutoDelete KeyValuesAD; + +enum KeyValuesUnpackDestinationTypes_t +{ + UNPACK_TYPE_FLOAT, + UNPACK_TYPE_VECTOR, + UNPACK_TYPE_VECTOR_COLOR, + UNPACK_TYPE_STRING, + UNPACK_TYPE_INT, + UNPACK_TYPE_FOUR_FLOATS, + UNPACK_TYPE_TWO_FLOATS, +}; + +#define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 } +#define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz } +#define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 } + +struct KeyValuesUnpackStructure +{ + char const* m_pKeyName; + char const* m_pKeyDefault; + KeyValuesUnpackDestinationTypes_t m_eDataType; + size_t m_nFieldOffset; + size_t m_nFieldSize; +}; + +inline int KeyValues::GetInt(int keySymbol, int defaultValue) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetInt((const char*)NULL, defaultValue) : defaultValue; +} + +inline uint64 KeyValues::GetUint64(int keySymbol, uint64 defaultValue) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetUint64((const char*)NULL, defaultValue) : defaultValue; +} + +inline float KeyValues::GetFloat(int keySymbol, float defaultValue) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetFloat((const char*)NULL, defaultValue) : defaultValue; +} + +inline const char* KeyValues::GetString(int keySymbol, const char* defaultValue) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetString((const char*)NULL, defaultValue) : defaultValue; +} + +inline const wchar_t* KeyValues::GetWString(int keySymbol, const wchar_t* defaultValue) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetWString((const char*)NULL, defaultValue) : defaultValue; +} + +inline void* KeyValues::GetPtr(int keySymbol, void* defaultValue) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetPtr((const char*)NULL, defaultValue) : defaultValue; +} + +inline Color KeyValues::GetColor(int keySymbol) +{ + Color defaultValue(0, 0, 0, 0); + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->GetColor() : defaultValue; +} + +inline bool KeyValues::IsEmpty(int keySymbol) +{ + KeyValues* dat = FindKey(keySymbol); + return dat ? dat->IsEmpty() : true; +} + + +class IKeyValuesDumpContext +{ +public: + virtual bool KvBeginKey(KeyValues* pKey, int nIndentLevel) = 0; + virtual bool KvWriteValue(KeyValues* pValue, int nIndentLevel) = 0; + virtual bool KvEndKey(KeyValues* pKey, int nIndentLevel) = 0; +}; + +class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext +{ +public: + virtual bool KvBeginKey(KeyValues* pKey, int nIndentLevel); + virtual bool KvWriteValue(KeyValues* pValue, int nIndentLevel); + virtual bool KvEndKey(KeyValues* pKey, int nIndentLevel); + +public: + virtual bool KvWriteIndent(int nIndentLevel); + virtual bool KvWriteText(char const* szText) = 0; +}; + +class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText +{ +public: + CKeyValuesDumpContextAsDevMsg(int nDeveloperLevel = 1) : m_nDeveloperLevel(nDeveloperLevel) {} + +public: + virtual bool KvBeginKey(KeyValues* pKey, int nIndentLevel); + virtual bool KvWriteText(char const* szText); + +protected: + int m_nDeveloperLevel; +}; + +inline bool KeyValuesDumpAsDevMsg(KeyValues* pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1) +{ + CKeyValuesDumpContextAsDevMsg ctx(nDeveloperLevel); + return pKeyValues->Dump(&ctx, nIndentLevel); +} + + +#endif + +``` + +`SpyCustom/sdk/l2cache.h`: + +```h +#ifndef CL2CACHE_H +#define CL2CACHE_H +#ifdef _WIN32 +#pragma once +#endif + +class P4Event_BSQ_cache_reference; + +class CL2Cache +{ +public: + + CL2Cache(); + ~CL2Cache(); + + void Start(void); + void End(void); + + int GetL2CacheMisses(void) + { + return m_iL2CacheMissCount; + } + +#ifdef DBGFLAG_VALIDATE + void Validate(CValidator& validator, tchar* pchName); +#endif + +private: + + int m_nID; + + P4Event_BSQ_cache_reference* m_pL2CacheEvent; + int64 m_i64Start; + int64 m_i64End; + int m_iL2CacheMissCount; +}; + +#endif + +``` + +`SpyCustom/sdk/lerp_functions.h`: + +```h +#ifndef LERP_FUNCTIONS_H +#define LERP_FUNCTIONS_H +#ifdef _WIN32 +#pragma once +#endif + + +template +inline T LoopingLerp(float flPercent, T flFrom, T flTo) +{ + T s = flTo * flPercent + flFrom * (1.0f - flPercent); + return s; +} + +template <> +inline float LoopingLerp(float flPercent, float flFrom, float flTo) +{ + if (fabs(flTo - flFrom) >= 0.5f) + { + if (flFrom < flTo) + flFrom += 1.0f; + else + flTo += 1.0f; + } + + float s = flTo * flPercent + flFrom * (1.0f - flPercent); + + s = s - (int)(s); + if (s < 0.0f) + s = s + 1.0f; + + return s; +} + +template +inline T Lerp_Hermite(const T& , float t, const T& p0, const T& p1, const T& p2) +{ + T d1 = p1 - p0; + T d2 = p2 - p1; + + T output; + float tSqr = t * t; + float tCube = t * tSqr; + + output = p1 * (2 * tCube - 3 * tSqr + 1); + output += p2 * (-2 * tCube + 3 * tSqr); + output += d1 * (tCube - 2 * tSqr + t); + output += d2 * (tCube - tSqr); + + return output; +} + + +template +inline T Derivative_Hermite(float t, const T& p0, const T& p1, const T& p2) +{ + T d1 = p1 - p0; + T d2 = p2 - p1; + + T output; + float tSqr = t * t; + + output = p1 * (6 * tSqr - 6 * t); + output += p2 * (-6 * tSqr + 6 * t); + output += d1 * (3 * tSqr - 4 * t + 1); + output += d2 * (3 * tSqr - 2 * t); + + return output; +} + + +inline void Lerp_Clamp(int val) +{ +} + +inline void Lerp_Clamp(float val) +{ +} + +inline void Lerp_Clamp(const Vector& val) +{ +} + +inline void Lerp_Clamp(const QAngle& val) +{ +} + + +template< class T, int minValue, int maxValue, int startValue > +inline void Lerp_Clamp(CRangeCheckedVar& val) +{ + val.Clamp(); +} + + +template<> +inline QAngle Lerp_Hermite(const QAngle&, float t, const QAngle& p0, const QAngle& p1, const QAngle& p2) +{ + return Lerp(t, p1, p2); +} + +template +inline T LoopingLerp_Hermite(T current, float t, T p0, T p1, T p2) +{ + return Lerp_Hermite(current, t, p0, p1, p2); +} + +template <> +inline float LoopingLerp_Hermite(float , float t, float p0, float p1, float p2) +{ + if (fabs(p1 - p0) > 0.5f) + { + if (p0 < p1) + p0 += 1.0f; + else + p1 += 1.0f; + } + + if (fabs(p2 - p1) > 0.5f) + { + if (p1 < p2) + { + p1 += 1.0f; + + if (abs(p1 - p0) > 0.5) + { + if (p0 < p1) + p0 += 1.0f; + else + p1 += 1.0f; + } + } + else + { + p2 += 1.0f; + } + } + + float s = Lerp_Hermite( 0.0f, t, p0, p1, p2); + + s = s - (int)(s); + if (s < 0.0f) + { + s = s + 1.0f; + } + + return s; +} + +template< int minValue, int maxValue, int startValue > +inline CRangeCheckedVar LoopingLerp_Hermite(CRangeCheckedVar current, float t, CRangeCheckedVar p0, CRangeCheckedVar p1, CRangeCheckedVar p2) +{ + return LoopingLerp_Hermite((float)current, t, (float)p0, (float)p1, (float)p2); +} + + +#endif +``` + +`SpyCustom/sdk/lightdesc.h`: + +```h +#ifndef LIGHTDESC_H +#define LIGHTDESC_H + +#include "ssemath.h" +#include "vector.h" + +enum LightType_t +{ + MATERIAL_LIGHT_DISABLE = 0, + MATERIAL_LIGHT_POINT, + MATERIAL_LIGHT_DIRECTIONAL, + MATERIAL_LIGHT_SPOT, +}; + +enum LightType_OptimizationFlags_t +{ + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 = 1, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 = 2, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 = 4, + LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED = 8, +}; + +struct LightDesc_t +{ + LightType_t m_Type; + 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; +protected: + float OneOver_ThetaDot_Minus_PhiDot; + float m_RangeSquared; +public: + + void RecalculateDerivedValues(void); + + LightDesc_t(void) + { + } + + LightDesc_t(const Vector& pos, const Vector& color) + { + InitPoint(pos, color); + } + + LightDesc_t(const Vector& pos, const Vector& color, const Vector& point_at, + float inner_cone_boundary, float outer_cone_boundary) + { + InitSpot(pos, color, point_at, inner_cone_boundary, outer_cone_boundary); + } + + void InitPoint(const Vector& pos, const Vector& color); + void InitDirectional(const Vector& dir, const Vector& color); + void InitSpot(const Vector& pos, const Vector& color, const Vector& point_at, + float inner_cone_boundary, float outer_cone_boundary); + + void ComputeLightAtPoints(const FourVectors& pos, const FourVectors& normal, + FourVectors& color, bool DoHalfLambert = false) const; + void ComputeNonincidenceLightAtPoints(const FourVectors& pos, FourVectors& color) const; + void ComputeLightAtPointsForDirectional(const FourVectors& pos, + const FourVectors& normal, + FourVectors& color, bool DoHalfLambert = false) const; + + void SetupOldStyleAttenuation(float fQuadatricAttn, float fLinearAttn, float fConstantAttn); + + void SetupNewStyleAttenuation(float fFiftyPercentDistance, float fZeroPercentDistance); + + + 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; + } +}; + + +inline void LightDesc_t::InitPoint(const Vector& pos, const Vector& color) +{ + m_Type = MATERIAL_LIGHT_POINT; + m_Color = color; + m_Position = pos; + m_Range = 0.0; + m_Attenuation0 = 1.0; + m_Attenuation1 = 0; + m_Attenuation2 = 0; + RecalculateDerivedValues(); +} + + +inline void LightDesc_t::InitDirectional(const Vector& dir, const Vector& color) +{ + m_Type = MATERIAL_LIGHT_DIRECTIONAL; + m_Color = color; + m_Direction = dir; + m_Range = 0.0; + m_Attenuation0 = 1.0; + m_Attenuation1 = 0; + m_Attenuation2 = 0; + RecalculateDerivedValues(); +} + + +inline void LightDesc_t::InitSpot(const Vector& pos, const Vector& color, const Vector& point_at, + float inner_cone_boundary, float outer_cone_boundary) +{ + m_Type = MATERIAL_LIGHT_SPOT; + m_Color = color; + m_Position = pos; + m_Direction = point_at; + m_Direction -= pos; + VectorNormalizeFast(m_Direction); + m_Falloff = 5.0; + m_Theta = inner_cone_boundary; + m_Phi = outer_cone_boundary; + + m_Range = 0.0; + + m_Attenuation0 = 1.0; + m_Attenuation1 = 0; + m_Attenuation2 = 0; + RecalculateDerivedValues(); +} + + +#endif + +``` + +`SpyCustom/sdk/localflexcontroller.h`: + +```h +#ifndef LOCALFLEXCONTROLLER_H +#define LOCALFLEXCONTROLLER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" + +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; } + + +#endif +``` + +`SpyCustom/sdk/logging.h`: + +```h +#ifndef LOGGING_H +#define LOGGING_H + +#if !defined(__SPU__) + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "color.h" +#include "icommandline.h" +#include + +#if defined( _X360 ) +#include "xbox/xbox_console.h" +#endif + +#if defined( _WIN32 ) || (defined(POSIX) && !defined(_GAMECONSOLE)) +#include "win32consoleio.h" +#endif + +class CLoggingSystem; +class CThreadFastMutex; + +const int MAX_LOGGING_MESSAGE_LENGTH = 2048; + +const int MAX_LOGGING_IDENTIFIER_LENGTH = 32; + +const int MAX_LOGGING_CHANNEL_COUNT = 256; + +const int MAX_LOGGING_TAG_COUNT = 1024; + +const int MAX_LOGGING_TAG_CHARACTER_COUNT = 8192; + +const int MAX_LOGGING_LISTENER_COUNT = 16; + +const Color UNSPECIFIED_LOGGING_COLOR(0, 0, 0, 0); + +typedef int LoggingChannelID_t; + +const LoggingChannelID_t INVALID_LOGGING_CHANNEL_ID = -1; + +enum LoggingSeverity_t +{ + LS_MESSAGE = 0, + + LS_WARNING = 1, + + LS_ASSERT = 2, + + LS_ERROR = 3, + + LS_HIGHEST_SEVERITY = 4, +}; + +enum LoggingResponse_t +{ + LR_CONTINUE, + LR_DEBUGGER, + LR_ABORT, +}; + +enum LoggingChannelFlags_t +{ + LCF_CONSOLE_ONLY = 0x00000001, + + LCF_DO_NOT_ECHO = 0x00000002, +}; + +typedef void (*RegisterTagsFunc)(); + +struct LoggingContext_t +{ + LoggingChannelID_t m_ChannelID; + LoggingChannelFlags_t m_Flags; + LoggingSeverity_t m_Severity; + Color m_Color; +}; + +class ILoggingListener +{ +public: + virtual void Log(const LoggingContext_t* pContext, const tchar* pMessage) = 0; +}; + +class ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog(const LoggingContext_t* pContext) = 0; +}; + +class CSimpleLoggingListener : public ILoggingListener +{ +public: + CSimpleLoggingListener(bool bQuietPrintf = false, bool bQuietDebugger = false) : + m_bQuietPrintf(bQuietPrintf), + m_bQuietDebugger(bQuietDebugger) + { + } + + virtual void Log(const LoggingContext_t* pContext, const tchar* pMessage) + { +#ifdef _X360 + if (!m_bQuietDebugger && XBX_IsConsoleConnected()) + { + XBX_DebugString(XMAKECOLOR(0, 0, 0), pMessage); + } + else +#endif + { +#if !defined( _CERT ) && !defined( DBGFLAG_STRINGS_STRIP ) + if (!m_bQuietPrintf) + { + _tprintf(_T("%s"), pMessage); + } +#endif + +#ifdef _WIN32 + if (!m_bQuietDebugger && Plat_IsInDebugSession()) + { + Plat_DebugString(pMessage); + } +#endif + } + } + + bool m_bQuietPrintf; + bool m_bQuietDebugger; +}; + +class CSimpleWindowsLoggingListener : public ILoggingListener +{ +public: + virtual void Log(const LoggingContext_t* pContext, const tchar* pMessage) + { + if (Plat_IsInDebugSession()) + { + Plat_DebugString(pMessage); + } + if (pContext->m_Severity == LS_ERROR) + { + if (Plat_IsInDebugSession()) + DebuggerBreak(); + + Plat_MessageBox("Error", pMessage); + } + } +}; + + +#if !defined(_GAMECONSOLE) +class CColorizedLoggingListener : public CSimpleLoggingListener +{ +public: + CColorizedLoggingListener(bool bQuietPrintf = false, bool bQuietDebugger = false) : CSimpleLoggingListener(bQuietPrintf, bQuietDebugger) + { + InitWin32ConsoleColorContext(&m_ColorContext); + } + + virtual void Log(const LoggingContext_t* pContext, const tchar* pMessage) + { + if (!m_bQuietPrintf) + { + int nPrevColor = -1; + + if (pContext->m_Color != UNSPECIFIED_LOGGING_COLOR) + { + nPrevColor = SetWin32ConsoleColor(&m_ColorContext, + pContext->m_Color.r(), pContext->m_Color.g(), pContext->m_Color.b(), + MAX(MAX(pContext->m_Color.r(), pContext->m_Color.g()), pContext->m_Color.b()) > 128); + } + + _tprintf(_T("%s"), pMessage); + + if (nPrevColor >= 0) + { + RestoreWin32ConsoleColor(&m_ColorContext, nPrevColor); + } + } + +#ifdef _WIN32 + if (!m_bQuietDebugger && Plat_IsInDebugSession()) + { + Plat_DebugString(pMessage); + } +#endif + } + + Win32ConsoleColorContext_t m_ColorContext; +}; +#endif + + +class CDefaultLoggingResponsePolicy : public ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog(const LoggingContext_t* pContext) + { + if (pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm("-noassert")) + { + return LR_DEBUGGER; + } + else if (pContext->m_Severity == LS_ERROR) + { + return LR_ABORT; + } + else + { + return LR_CONTINUE; + } + } +}; + +class CNonFatalLoggingResponsePolicy : public ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog(const LoggingContext_t* pContext) + { + if ((pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm("-noassert")) || pContext->m_Severity == LS_ERROR) + { + return LR_DEBUGGER; + } + else + { + return LR_CONTINUE; + } + } +}; + +class CLoggingSystem +{ +public: + struct LoggingChannel_t; + + CLoggingSystem(); + ~CLoggingSystem(); + + LoggingChannelID_t RegisterLoggingChannel(const char* pChannelName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t minimumSeverity = LS_MESSAGE, Color spewColor = UNSPECIFIED_LOGGING_COLOR); + + LoggingChannelID_t FindChannel(const char* pChannelName) const; + + int GetChannelCount() const { return m_nChannelCount; } + + LoggingChannel_t* GetChannel(LoggingChannelID_t channelID); + const LoggingChannel_t* GetChannel(LoggingChannelID_t channelID) const; + + bool HasTag(LoggingChannelID_t channelID, const char* pTag) const { return GetChannel(channelID)->HasTag(pTag); } + + bool IsValidChannelID(LoggingChannelID_t channelID) const { return (channelID >= 0) && (channelID < m_nChannelCount); } + + bool IsChannelEnabled(LoggingChannelID_t channelID, LoggingSeverity_t severity) const { return IsValidChannelID(channelID) && GetChannel(channelID)->IsEnabled(severity); } + + void SetChannelSpewLevel(LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity); + void SetChannelSpewLevelByName(const char* pName, LoggingSeverity_t minimumSeverity); + void SetChannelSpewLevelByTag(const char* pTag, LoggingSeverity_t minimumSeverity); + void SetGlobalSpewLevel(LoggingSeverity_t minimumSeverity); + + Color GetChannelColor(LoggingChannelID_t channelID) const { return GetChannel(channelID)->m_SpewColor; } + void SetChannelColor(LoggingChannelID_t channelID, Color color) { GetChannel(channelID)->m_SpewColor = color; } + + LoggingChannelFlags_t GetChannelFlags(LoggingChannelID_t channelID) const { return GetChannel(channelID)->m_Flags; } + void SetChannelFlags(LoggingChannelID_t channelID, LoggingChannelFlags_t flags) { GetChannel(channelID)->m_Flags = flags; } + + void AddTagToCurrentChannel(const char* pTagName); + + void PushLoggingState(bool bThreadLocal = false, bool bClearState = true); + void PopLoggingState(bool bThreadLocal = false); + + void RegisterLoggingListener(ILoggingListener* pListener); + + bool IsListenerRegistered(ILoggingListener* pListener); + + void ResetCurrentLoggingState(); + + void SetLoggingResponsePolicy(ILoggingResponsePolicy* pLoggingResponse); + + LoggingResponse_t LogDirect(LoggingChannelID_t channelID, LoggingSeverity_t severity, Color color, const tchar* pMessage); + + struct LoggingTag_t + { + const char* m_pTagName; + LoggingTag_t* m_pNextTag; + }; + + struct LoggingChannel_t + { + bool HasTag(const char* pTag) const + { + LoggingTag_t* pCurrentTag = m_pFirstTag; + while (pCurrentTag != NULL) + { + if (stricmp(pCurrentTag->m_pTagName, pTag) == 0) + { + return true; + } + pCurrentTag = pCurrentTag->m_pNextTag; + } + return false; + } + bool IsEnabled(LoggingSeverity_t severity) const { return severity >= m_MinimumSeverity; } + void SetSpewLevel(LoggingSeverity_t severity) { m_MinimumSeverity = severity; } + + LoggingChannelID_t m_ID; + LoggingChannelFlags_t m_Flags; + LoggingSeverity_t m_MinimumSeverity; + Color m_SpewColor; + char m_Name[MAX_LOGGING_IDENTIFIER_LENGTH]; + LoggingTag_t* m_pFirstTag; + }; + +private: + struct LoggingState_t + { + int m_nPreviousStackEntry; + + int m_nListenerCount; + ILoggingListener* m_RegisteredListeners[MAX_LOGGING_LISTENER_COUNT]; + + ILoggingResponsePolicy* m_pLoggingResponse; + }; + + LoggingState_t* GetCurrentState(); + const LoggingState_t* GetCurrentState() const; + + int FindUnusedStateIndex(); + LoggingTag_t* AllocTag(const char* pTagName); + + int m_nChannelCount; + LoggingChannel_t m_RegisteredChannels[MAX_LOGGING_CHANNEL_COUNT]; + + int m_nChannelTagCount; + LoggingTag_t m_ChannelTags[MAX_LOGGING_TAG_COUNT]; + + int m_nTagNamePoolIndex; + char m_TagNamePool[MAX_LOGGING_TAG_CHARACTER_COUNT]; + + CThreadFastMutex* m_pStateMutex; + + int m_nGlobalStateIndex; + + static const int MAX_LOGGING_STATE_COUNT = 16; + LoggingState_t m_LoggingStates[MAX_LOGGING_STATE_COUNT]; + + CDefaultLoggingResponsePolicy m_DefaultLoggingResponse; + + CSimpleLoggingListener m_DefaultLoggingListener; + +}; + +#ifdef DBGFLAG_STRINGS_STRIP +#define InternalMsg( Channel, Severity, ... ) do { if ( Severity == LS_ERROR && LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, ##__VA_ARGS__ ); } while( 0 ) +#else +#define InternalMsg( Channel, Severity, ... ) do { if ( LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, ##__VA_ARGS__ ); } while( 0 ) +#endif + +#define Log_Msg( Channel, ... ) InternalMsg( Channel, LS_MESSAGE, ##__VA_ARGS__ ) +#define Log_Warning( Channel, ... ) InternalMsg( Channel, LS_WARNING, ##__VA_ARGS__ ) +#define Log_Error( Channel, ... ) InternalMsg( Channel, LS_ERROR, ##__VA_ARGS__ ) +#ifdef DBGFLAG_STRINGS_STRIP +#define Log_Assert( ... ) LR_CONTINUE +#else +#define Log_Assert( Message, ... ) LoggingSystem_LogAssert( Message, ##__VA_ARGS__ ) +#endif + + +#define DECLARE_LOGGING_CHANNEL( Channel ) extern LoggingChannelID_t Channel + +#define DEFINE_LOGGING_CHANNEL_NO_TAGS( Channel, ChannelName, ... ) \ + LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, NULL, ##__VA_ARGS__ ) + +#define BEGIN_DEFINE_LOGGING_CHANNEL( Channel, ChannelName, ... ) \ + static void Register_##Channel##_Tags(); \ + LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, Register_##Channel##_Tags, ##__VA_ARGS__ ); \ + void Register_##Channel##_Tags() \ + { + +#define ADD_LOGGING_CHANNEL_TAG( Tag ) LoggingSystem_AddTagToCurrentChannel( Tag ) + +#define END_DEFINE_LOGGING_CHANNEL() \ + } + +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_RegisterLoggingChannel(const char* pName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t severity = LS_MESSAGE, Color color = UNSPECIFIED_LOGGING_COLOR); + +PLATFORM_INTERFACE void LoggingSystem_RegisterLoggingListener(ILoggingListener* pListener); +PLATFORM_INTERFACE void LoggingSystem_UnregisterLoggingListener(ILoggingListener* pListener); +PLATFORM_INTERFACE void LoggingSystem_ResetCurrentLoggingState(); +PLATFORM_INTERFACE void LoggingSystem_SetLoggingResponsePolicy(ILoggingResponsePolicy* pResponsePolicy); +PLATFORM_INTERFACE void LoggingSystem_PushLoggingState(bool bThreadLocal = false, bool bClearState = true); +PLATFORM_INTERFACE void LoggingSystem_PopLoggingState(bool bThreadLocal = false); + +PLATFORM_INTERFACE void LoggingSystem_AddTagToCurrentChannel(const char* pTagName); + +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_FindChannel(const char* pChannelName); +PLATFORM_INTERFACE int LoggingSystem_GetChannelCount(); +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetFirstChannelID(); +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetNextChannelID(LoggingChannelID_t channelID); +PLATFORM_INTERFACE const CLoggingSystem::LoggingChannel_t* LoggingSystem_GetChannel(LoggingChannelID_t channelID); + +PLATFORM_INTERFACE bool LoggingSystem_HasTag(LoggingChannelID_t channelID, const char* pTag); + +PLATFORM_INTERFACE bool LoggingSystem_IsChannelEnabled(LoggingChannelID_t channelID, LoggingSeverity_t severity); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevel(LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByName(const char* pName, LoggingSeverity_t minimumSeverity); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByTag(const char* pTag, LoggingSeverity_t minimumSeverity); +PLATFORM_INTERFACE void LoggingSystem_SetGlobalSpewLevel(LoggingSeverity_t minimumSeverity); + +PLATFORM_INTERFACE int32 LoggingSystem_GetChannelColor(LoggingChannelID_t channelID); +PLATFORM_INTERFACE void LoggingSystem_SetChannelColor(LoggingChannelID_t channelID, int color); + +PLATFORM_INTERFACE LoggingChannelFlags_t LoggingSystem_GetChannelFlags(LoggingChannelID_t channelID); +PLATFORM_INTERFACE void LoggingSystem_SetChannelFlags(LoggingChannelID_t channelID, LoggingChannelFlags_t flags); + +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_Log(LoggingChannelID_t channelID, LoggingSeverity_t severity, PRINTF_FORMAT_STRING const char* pMessageFormat, ...) FMTFUNCTION(3, 4); +PLATFORM_OVERLOAD LoggingResponse_t LoggingSystem_Log(LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, PRINTF_FORMAT_STRING const char* pMessageFormat, ...) FMTFUNCTION(4, 5); + +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogDirect(LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char* pMessage); +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogAssert(PRINTF_FORMAT_STRING const char* pMessageFormat, ...) FMTFUNCTION(1, 2); + +#endif + +#endif +``` + +`SpyCustom/sdk/math_pfns.h`: + +```h +#ifndef _MATH_PFNS_H_ +#define _MATH_PFNS_H_ + +#if defined( _X360 ) +#include +#endif + +#if !defined( _X360 ) + +extern float (*pfSqrt)(float x); +extern float (*pfRSqrt)(float x); +extern float (*pfRSqrtFast)(float x); +extern void (*pfFastSinCos)(float x, float* s, float* c); +extern float (*pfFastCos)(float x); + +#define FastSqrt(x) (*pfSqrt)(x) +#define FastRSqrt(x) (*pfRSqrt)(x) +#define FastRSqrtFast(x) (*pfRSqrtFast)(x) +#define FastSinCos(x,s,c) (*pfFastSinCos)(x,s,c) +#define FastCos(x) (*pfFastCos)(x) + +#if defined(__i386__) || defined(_M_IX86) +#undef FastSqrt +#define FastSqrt(x) ::sqrtf(x) +#endif + +#endif + +#if defined( _X360 ) + +FORCEINLINE float _VMX_Sqrt(float x) +{ + return __fsqrts(x); +} + +FORCEINLINE float _VMX_RSqrt(float x) +{ + float rroot = __frsqrte(x); + + return (0.5f * rroot) * (3.0f - (x * rroot) * rroot); +} + +FORCEINLINE float _VMX_RSqrtFast(float x) +{ + return __frsqrte(x); +} + +FORCEINLINE void _VMX_SinCos(float a, float* pS, float* pC) +{ + XMScalarSinCos(pS, pC, a); +} + +FORCEINLINE float _VMX_Cos(float a) +{ + return XMScalarCos(a); +} + +#define FastSqrt(x) _VMX_Sqrt(x) +#define FastRSqrt(x) _VMX_RSqrt(x) +#define FastRSqrtFast(x) _VMX_RSqrtFast(x) +#define FastSinCos(x,s,c) _VMX_SinCos(x,s,c) +#define FastCos(x) _VMX_Cos(x) + +#endif + +#endif +``` + +`SpyCustom/sdk/mathlib.h`: + +```h +#ifndef MATH_LIB_H +#define MATH_LIB_H + +#include +#include "basetypes.h" +#include "commonmacros.h" +#include "vector.h" +#include "vector2d.h" +#include "dbg.h" + +#include "math_pfns.h" + +#if defined(__i386__) || defined(_M_IX86) +#include +#endif + +#undef clamp + + +#ifdef FP_EXCEPTIONS_ENABLED +#include +#endif + +class FPExceptionDisabler +{ +public: +#ifdef FP_EXCEPTIONS_ENABLED + FPExceptionDisabler(); + ~FPExceptionDisabler(); + +private: + unsigned int mOldValues; +#else + FPExceptionDisabler() {} + ~FPExceptionDisabler() {} +#endif + +private: + FPExceptionDisabler(const FPExceptionDisabler&); + FPExceptionDisabler& operator=(const FPExceptionDisabler&); +}; + +class FPExceptionEnabler +{ +public: +#ifdef FP_EXCEPTIONS_ENABLED + FPExceptionEnabler(unsigned int enableBits = _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID); + ~FPExceptionEnabler(); + +private: + unsigned int mOldValues; +#else + FPExceptionEnabler(unsigned int enableBits = 0) + { + } + ~FPExceptionEnabler() + { + } +#endif + +private: + FPExceptionEnabler(const FPExceptionEnabler&); + FPExceptionEnabler& operator=(const FPExceptionEnabler&); +}; + + + +#ifdef DEBUG +FORCEINLINE float clamp(float val, float minVal, float maxVal) +{ + if (maxVal < minVal) + return maxVal; + else if (val < minVal) + return minVal; + else if (val > maxVal) + return maxVal; + else + return val; +} +#else +FORCEINLINE float clamp(float val, float minVal, float maxVal) +{ +#if defined(__i386__) || defined(_M_IX86) + _mm_store_ss(&val, + _mm_min_ss( + _mm_max_ss( + _mm_load_ss(&val), + _mm_load_ss(&minVal)), + _mm_load_ss(&maxVal))); +#else + val = fpmax(minVal, val); + val = fpmin(maxVal, val); +#endif + return val; +} +#endif + +template< class T > +inline T clamp(T const& val, T const& minVal, T const& maxVal) +{ + if (maxVal < minVal) + return maxVal; + else if (val < minVal) + return minVal; + else if (val > maxVal) + return maxVal; + else + return val; +} + + +struct cplane_t +{ + Vector normal; + float dist; + byte type; + byte signbits; + byte pad[2]; + +#ifdef VECTOR_NO_SLOW_OPERATIONS + cplane_t() {} + +private: + cplane_t(const cplane_t& vOther); +#endif +}; + +#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 + + +enum +{ + FRUSTUM_RIGHT = 0, + FRUSTUM_LEFT = 1, + FRUSTUM_TOP = 2, + FRUSTUM_BOTTOM = 3, + FRUSTUM_NEARZ = 4, + FRUSTUM_FARZ = 5, + FRUSTUM_NUMPLANES = 6 +}; + +extern int SignbitsForPlane(cplane_t* out); + +class Frustum_t +{ +public: + void SetPlane(int i, int nType, const Vector& vecNormal, float dist) + { + m_Plane[i].normal = vecNormal; + m_Plane[i].dist = dist; + m_Plane[i].type = nType; + m_Plane[i].signbits = SignbitsForPlane(&m_Plane[i]); + m_AbsNormal[i].Init(fabs(vecNormal.x), fabs(vecNormal.y), fabs(vecNormal.z)); + } + + inline const cplane_t* GetPlane(int i) const { return &m_Plane[i]; } + inline const Vector& GetAbsNormal(int i) const { return m_AbsNormal[i]; } + +private: + cplane_t m_Plane[FRUSTUM_NUMPLANES]; + Vector m_AbsNormal[FRUSTUM_NUMPLANES]; +}; + +float CalcFovY(float flFovX, float flScreenAspect); +float CalcFovX(float flFovY, float flScreenAspect); + +void GeneratePerspectiveFrustum(const Vector& origin, const QAngle& angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t& frustum); +void GeneratePerspectiveFrustum(const Vector& origin, const Vector& forward, const Vector& right, const Vector& up, float flZNear, float flZFar, float flFovX, float flFovY, Frustum_t& frustum); + +bool R_CullBox(const Vector& mins, const Vector& maxs, const Frustum_t& frustum); +bool R_CullBoxSkipNear(const Vector& mins, const Vector& maxs, const Frustum_t& frustum); + +struct matrix3x4_t +{ + matrix3x4_t() {} + matrix3x4_t( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23) + { + m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03; + m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13; + m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23; + } + + void Init(const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector& vecOrigin) + { + m_flMatVal[0][0] = xAxis.x; m_flMatVal[0][1] = yAxis.x; m_flMatVal[0][2] = zAxis.x; m_flMatVal[0][3] = vecOrigin.x; + m_flMatVal[1][0] = xAxis.y; m_flMatVal[1][1] = yAxis.y; m_flMatVal[1][2] = zAxis.y; m_flMatVal[1][3] = vecOrigin.y; + m_flMatVal[2][0] = xAxis.z; m_flMatVal[2][1] = yAxis.z; m_flMatVal[2][2] = zAxis.z; m_flMatVal[2][3] = vecOrigin.z; + } + + matrix3x4_t(const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector& vecOrigin) + { + Init(xAxis, yAxis, zAxis, vecOrigin); + } + + inline void Invalidate(void) + { + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 4; j++) + { + m_flMatVal[i][j] = VEC_T_NAN; + } + } + } + + float* operator[](int i) { Assert((i >= 0) && (i < 3)); return m_flMatVal[i]; } + const float* operator[](int i) const { Assert((i >= 0) && (i < 3)); return m_flMatVal[i]; } + float* Base() { return &m_flMatVal[0][0]; } + const float* Base() const { return &m_flMatVal[0][0]; } + + float m_flMatVal[3][4]; +}; + +#include "fltx4.h" + +class ALIGN16 matrix3x4a_t : public matrix3x4_t +{ +public: + matrix3x4a_t(const matrix3x4_t& src) { *this = src; }; + matrix3x4a_t& operator=(const matrix3x4_t& src) { memcpy(Base(), src.Base(), sizeof(float) * 3 * 4); return *this; }; + + matrix3x4a_t( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23) + { + AssertDbg(((size_t)Base() & 0xf) == 0); + m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03; + m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13; + m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23; + } + matrix3x4a_t() {} + + static FORCEINLINE bool TypeIsAlignedForSIMD(void) { return true; } + + + FORCEINLINE fltx4& SIMDRow(uint nIdx) { AssertDbg(nIdx < 3); return *((fltx4*)(&(m_flMatVal[nIdx]))); } + FORCEINLINE const fltx4& SIMDRow(uint nIdx) const { AssertDbg(nIdx < 3); return *((const fltx4*)(&(m_flMatVal[nIdx]))); } + +} ALIGN16_POST; + + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define M_PI_F ((float)(M_PI)) + +#ifndef RAD2DEG +#define RAD2DEG( x ) ( (float)(x) * (float)(180.f / M_PI_F) ) +#endif + +#ifndef DEG2RAD +#define DEG2RAD( x ) ( (float)(x) * (float)(M_PI_F / 180.f) ) +#endif + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 +#define SIDE_CROSS -2 + +#define ON_VIS_EPSILON 0.01 +#define EQUAL_EPSILON 0.001 + +extern bool s_bMathlibInitialized; + +extern const Vector vec3_origin; +extern const QAngle vec3_angle; +extern const Quaternion quat_identity; +extern const Vector vec3_invalid; +extern const int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +FORCEINLINE vec_t DotProduct(const vec_t* v1, const vec_t* v2) +{ + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} +FORCEINLINE void VectorSubtract(const vec_t* a, const vec_t* b, vec_t* c) +{ + c[0] = a[0] - b[0]; + c[1] = a[1] - b[1]; + c[2] = a[2] - b[2]; +} +FORCEINLINE void VectorAdd(const vec_t* a, const vec_t* b, vec_t* c) +{ + c[0] = a[0] + b[0]; + c[1] = a[1] + b[1]; + c[2] = a[2] + b[2]; +} +FORCEINLINE void VectorCopy(const vec_t* a, vec_t* b) +{ + b[0] = a[0]; + b[1] = a[1]; + b[2] = a[2]; +} +FORCEINLINE void VectorClear(vec_t* a) +{ + a[0] = a[1] = a[2] = 0; +} + +FORCEINLINE float VectorMaximum(const vec_t* v) +{ + return max(v[0], max(v[1], v[2])); +} + +FORCEINLINE float VectorMaximum(const Vector& v) +{ + return max(v.x, max(v.y, v.z)); +} + +FORCEINLINE void VectorScale(const float* in, vec_t scale, float* out) +{ + out[0] = in[0] * scale; + out[1] = in[1] * scale; + out[2] = in[2] * scale; +} + + +inline void VectorFill(vec_t* a, float b) +{ + a[0] = a[1] = a[2] = b; +} + +inline void VectorNegate(vec_t* a) +{ + a[0] = -a[0]; + a[1] = -a[1]; + a[2] = -a[2]; +} + + +#define Vector2Clear(x) {(x)[0]=(x)[1]=0;} +#define Vector2Negate(x) {(x)[0]=-((x)[0]);(x)[1]=-((x)[1]);} +#define Vector2Copy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];} +#define Vector2Subtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];} +#define Vector2Add(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];} +#define Vector2Scale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];} + +#define VECTOR_COPY( A, B ) do { (B)[0] = (A)[0]; (B)[1] = (A)[1]; (B)[2]=(A)[2]; } while(0) +#define DOT_PRODUCT( A, B ) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] ) + +FORCEINLINE void VectorMAInline(const float* start, float scale, const float* direction, float* dest) +{ + dest[0] = start[0] + direction[0] * scale; + dest[1] = start[1] + direction[1] * scale; + dest[2] = start[2] + direction[2] * scale; +} + +FORCEINLINE void VectorMAInline(const Vector& start, float scale, const Vector& direction, Vector& dest) +{ + dest.x = start.x + direction.x * scale; + dest.y = start.y + direction.y * scale; + dest.z = start.z + direction.z * scale; +} + +FORCEINLINE void VectorMA(const Vector& start, float scale, const Vector& direction, Vector& dest) +{ + VectorMAInline(start, scale, direction, dest); +} + +FORCEINLINE void VectorMA(const float* start, float scale, const float* direction, float* dest) +{ + VectorMAInline(start, scale, direction, dest); +} + + +int VectorCompare(const float* v1, const float* v2); + +inline float VectorLength(const float* v) +{ + return FastSqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + FLT_EPSILON); +} + +void CrossProduct(const float* v1, const float* v2, float* cross); + +qboolean VectorsEqual(const float* v1, const float* v2); + +inline vec_t RoundInt(vec_t in) +{ + return floor(in + 0.5f); +} + +int Q_log2(int val); + +void inline SinCos(float radians, float* sine, float* cosine) +{ +#if defined( _X360 ) + XMScalarSinCos(sine, cosine, radians); +#elif defined( PLATFORM_WINDOWS_PC32 ) + _asm + { + fld DWORD PTR[radians] + fsincos + + mov edx, DWORD PTR[cosine] + mov eax, DWORD PTR[sine] + + fstp DWORD PTR[edx] + fstp DWORD PTR[eax] + } +#elif defined( PLATFORM_WINDOWS_PC64 ) + *sine = sin(radians); + *cosine = cos(radians); +#elif defined( POSIX ) + register double __cosr, __sinr; + __asm ("fsincos" : "=t" (__cosr), "=u" (__sinr) : "0" (radians)); + + *sine = __sinr; + *cosine = __cosr; +#endif +} + +#define SIN_TABLE_SIZE 256 +#define FTOIBIAS 12582912.f +extern float SinCosTable[SIN_TABLE_SIZE]; + +inline float TableCos(float theta) +{ + union + { + int i; + float f; + } ftmp; + + ftmp.f = theta * (float)(SIN_TABLE_SIZE / (2.0f * M_PI)) + (FTOIBIAS + (SIN_TABLE_SIZE / 4)); + return SinCosTable[ftmp.i & (SIN_TABLE_SIZE - 1)]; +} + +inline float TableSin(float theta) +{ + union + { + int i; + float f; + } ftmp; + + ftmp.f = theta * (float)(SIN_TABLE_SIZE / (2.0f * M_PI)) + FTOIBIAS; + return SinCosTable[ftmp.i & (SIN_TABLE_SIZE - 1)]; +} + +template +FORCEINLINE T Square(T const& a) +{ + return a * a; +} + + +FORCEINLINE uint SmallestPowerOfTwoGreaterOrEqual(uint x) +{ + x -= 1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} + +FORCEINLINE uint LargestPowerOfTwoLessThanOrEqual(uint x) +{ + if (x >= 0x80000000) + return 0x80000000; + + return SmallestPowerOfTwoGreaterOrEqual(x + 1) >> 1; +} + + +void FloorDivMod(double numer, double denom, int* quotient, int* rem); +int GreatestCommonDivisor(int i1, int i2); + +bool IsDenormal(const float& val); + +enum +{ + PITCH = 0, + YAW, + ROLL +}; + +void MatrixAngles(const matrix3x4_t& matrix, float* angles); +void MatrixVectors(const matrix3x4_t& matrix, Vector* pForward, Vector* pRight, Vector* pUp); +void VectorTransform(const float* in1, const matrix3x4_t& in2, float* out); +void VectorITransform(const float* in1, const matrix3x4_t& in2, float* out); +void VectorRotate(const float* in1, const matrix3x4_t& in2, float* out); +void VectorRotate(const Vector& in1, const QAngle& in2, Vector& out); +void VectorRotate(const Vector& in1, const Quaternion& in2, Vector& out); +void VectorIRotate(const float* in1, const matrix3x4_t& in2, float* out); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +QAngle TransformAnglesToLocalSpace(const QAngle& angles, const matrix3x4_t& parentMatrix); +QAngle TransformAnglesToWorldSpace(const QAngle& angles, const matrix3x4_t& parentMatrix); + +#endif + +void MatrixInitialize(matrix3x4_t& mat, const Vector& vecOrigin, const Vector& vecXAxis, const Vector& vecYAxis, const Vector& vecZAxis); +void MatrixCopy(const matrix3x4_t& in, matrix3x4_t& out); +void MatrixInvert(const matrix3x4_t& in, matrix3x4_t& out); + +bool MatricesAreEqual(const matrix3x4_t& src1, const matrix3x4_t& src2, float flTolerance = 1e-5); + +void MatrixGetColumn(const matrix3x4_t& in, int column, Vector& out); +void MatrixSetColumn(const Vector& in, int column, matrix3x4_t& out); + +inline void MatrixGetTranslation(const matrix3x4_t& in, Vector& out) +{ + MatrixGetColumn(in, 3, out); +} + +inline void MatrixSetTranslation(const Vector& in, matrix3x4_t& out) +{ + MatrixSetColumn(in, 3, out); +} + +void MatrixScaleBy(const float flScale, matrix3x4_t& out); +void MatrixScaleByZero(matrix3x4_t& out); + +void ConcatRotations(const matrix3x4_t& in1, const matrix3x4_t& in2, matrix3x4_t& out); +void ConcatTransforms(const matrix3x4_t& in1, const matrix3x4_t& in2, matrix3x4_t& out); + +inline void MatrixMultiply(const matrix3x4_t& in1, const matrix3x4_t& in2, matrix3x4_t& out) +{ + ConcatTransforms(in1, in2, out); +} + +void QuaternionSlerp(const Quaternion& p, const Quaternion& q, float t, Quaternion& qt); +void QuaternionSlerpNoAlign(const Quaternion& p, const Quaternion& q, float t, Quaternion& qt); +void QuaternionBlend(const Quaternion& p, const Quaternion& q, float t, Quaternion& qt); +void QuaternionBlendNoAlign(const Quaternion& p, const Quaternion& q, float t, Quaternion& qt); +void QuaternionIdentityBlend(const Quaternion& p, float t, Quaternion& qt); +float QuaternionAngleDiff(const Quaternion& p, const Quaternion& q); +void QuaternionScale(const Quaternion& p, float t, Quaternion& q); +void QuaternionAlign(const Quaternion& p, const Quaternion& q, Quaternion& qt); +float QuaternionDotProduct(const Quaternion& p, const Quaternion& q); +void QuaternionConjugate(const Quaternion& p, Quaternion& q); +void QuaternionInvert(const Quaternion& p, Quaternion& q); +float QuaternionNormalize(Quaternion& q); +void QuaternionAdd(const Quaternion& p, const Quaternion& q, Quaternion& qt); +void QuaternionMult(const Quaternion& p, const Quaternion& q, Quaternion& qt); +void QuaternionMatrix(const Quaternion& q, matrix3x4_t& matrix); +void QuaternionMatrix(const Quaternion& q, const Vector& pos, matrix3x4_t& matrix); +void QuaternionAngles(const Quaternion& q, QAngle& angles); +void AngleQuaternion(const QAngle& angles, Quaternion& qt); +void QuaternionAngles(const Quaternion& q, RadianEuler& angles); +void AngleQuaternion(RadianEuler const& angles, Quaternion& qt); +void QuaternionAxisAngle(const Quaternion& q, Vector& axis, float& angle); +void AxisAngleQuaternion(const Vector& axis, float angle, Quaternion& q); +void BasisToQuaternion(const Vector& vecForward, const Vector& vecRight, const Vector& vecUp, Quaternion& q); +void MatrixQuaternion(const matrix3x4_t& mat, Quaternion& q); + +inline float MatrixRowDotProduct(const matrix3x4_t& in1, int row, const Vector& in2) +{ + Assert((row >= 0) && (row < 3)); + return DotProduct(in1[row], in2.Base()); +} + +inline float MatrixColumnDotProduct(const matrix3x4_t& in1, int col, const Vector& in2) +{ + Assert((col >= 0) && (col < 4)); + return in1[0][col] * in2[0] + in1[1][col] * in2[1] + in1[2][col] * in2[2]; +} + +int __cdecl BoxOnPlaneSide(const float* emins, const float* emaxs, const cplane_t* plane); + +inline float anglemod(float a) +{ + a = (360.f / 65536) * ((int)(a * (65536.f / 360.0f)) & 65535); + return a; +} + +inline float RemapVal(float val, float A, float B, float C, float D) +{ + if (A == B) + return val >= B ? D : C; + return C + (D - C) * (val - A) / (B - A); +} + +inline float RemapValClamped(float val, float A, float B, float C, float D) +{ + if (A == B) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + cVal = clamp(cVal, 0.0f, 1.0f); + + return C + (D - C) * cVal; +} + +template +FORCEINLINE T Lerp(float flPercent, T const& A, T const& B) +{ + return A + (B - A) * flPercent; +} + +FORCEINLINE float Sqr(float f) +{ + return f * f; +} + +static inline float FLerp(float f1, float f2, float i1, float i2, float x) +{ + return f1 + (f2 - f1) * (x - i1) / (i2 - i1); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +template<> FORCEINLINE QAngle Lerp(float flPercent, const QAngle& q1, const QAngle& q2) +{ + if (q1 == q2) + return q1; + + Quaternion src, dest; + + AngleQuaternion(q1, src); + AngleQuaternion(q2, dest); + + Quaternion result; + + QuaternionSlerp(src, dest, flPercent, result); + + QAngle output; + QuaternionAngles(result, output); + return output; +} + +#else + +#pragma error + +template<> FORCEINLINE QAngleByValue Lerp(float flPercent, const QAngleByValue& q1, const QAngleByValue& q2) +{ + if (q1 == q2) + return q1; + + Quaternion src, dest; + + AngleQuaternion(q1, src); + AngleQuaternion(q2, dest); + + Quaternion result; + + QuaternionSlerp(src, dest, flPercent, result); + + QAngleByValue output; + QuaternionAngles(result, output); + return output; +} + +#endif + + +template +FORCEINLINE void V_swap(T& x, T& y) +{ + T temp = x; + x = y; + y = temp; +} + +template FORCEINLINE T AVG(T a, T b) +{ + return (a + b) / 2; +} + +#define NELEMS(x) ARRAYSIZE(x) + +#define XYZ(v) (v).x,(v).y,(v).z + + +inline float Sign(float x) +{ + return (x < 0.0f) ? -1.0f : 1.0f; +} + +inline int ClampArrayBounds(int n, unsigned maxindex) +{ + unsigned int inrangemask = 0xFFFFFFFF + (((unsigned)n) > maxindex); + unsigned int lessthan0mask = 0xFFFFFFFF + (n >= 0); + + int result = (inrangemask & n); + + result |= ((~inrangemask) & (~lessthan0mask)) & maxindex; + + return result; +} + + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) + + +inline void AngleVectors(const QAngle& angles, Vector* forward) +{ + Assert(s_bMathlibInitialized); + Assert(forward); + + float sp, sy, cp, cy; + + SinCos(DEG2RAD(angles[YAW]), &sy, &cy); + SinCos(DEG2RAD(angles[PITCH]), &sp, &cp); + + forward->x = cp * cy; + forward->y = cp * sy; + forward->z = -sp; +} + +void AngleVectors(const QAngle& angles, Vector* forward, Vector* right, Vector* up); +void AngleVectorsTranspose(const QAngle& angles, Vector* forward, Vector* right, Vector* up); +void AngleMatrix(const QAngle& angles, matrix3x4_t& mat); +void AngleMatrix(const QAngle& angles, const Vector& position, matrix3x4_t& mat); +void AngleMatrix(const RadianEuler& angles, matrix3x4_t& mat); +void AngleMatrix(RadianEuler const& angles, const Vector& position, matrix3x4_t& mat); +void AngleIMatrix(const QAngle& angles, matrix3x4_t& mat); +void AngleIMatrix(const QAngle& angles, const Vector& position, matrix3x4_t& mat); +void AngleIMatrix(const RadianEuler& angles, matrix3x4_t& mat); +void VectorAngles(const Vector& forward, QAngle& angles); +void VectorAngles(const Vector& forward, const Vector& pseudoup, QAngle& angles); +void VectorMatrix(const Vector& forward, matrix3x4_t& mat); +void VectorVectors(const Vector& forward, Vector& right, Vector& up); +void SetIdentityMatrix(matrix3x4_t& mat); +void SetScaleMatrix(float x, float y, float z, matrix3x4_t& dst); +void MatrixBuildRotationAboutAxis(const Vector& vAxisOfRot, float angleDegrees, matrix3x4_t& dst); + +inline void SetScaleMatrix(float flScale, matrix3x4_t& dst) +{ + SetScaleMatrix(flScale, flScale, flScale, dst); +} + +inline void SetScaleMatrix(const Vector& scale, matrix3x4_t& dst) +{ + SetScaleMatrix(scale.x, scale.y, scale.z, dst); +} + +void MatrixTranspose(matrix3x4_t& mat); +void MatrixTranspose(const matrix3x4_t& src, matrix3x4_t& dst); +void MatrixInverseTranspose(const matrix3x4_t& src, matrix3x4_t& dst); + +inline void PositionMatrix(const Vector& position, matrix3x4_t& mat) +{ + MatrixSetColumn(position, 3, mat); +} + +inline void MatrixPosition(const matrix3x4_t& matrix, Vector& position) +{ + MatrixGetColumn(matrix, 3, position); +} + +inline void VectorRotate(const Vector& in1, const matrix3x4_t& in2, Vector& out) +{ + VectorRotate(&in1.x, in2, &out.x); +} + +inline void VectorIRotate(const Vector& in1, const matrix3x4_t& in2, Vector& out) +{ + VectorIRotate(&in1.x, in2, &out.x); +} + +inline void MatrixAngles(const matrix3x4_t& matrix, QAngle& angles) +{ + MatrixAngles(matrix, &angles.x); +} + +inline void MatrixAngles(const matrix3x4_t& matrix, QAngle& angles, Vector& position) +{ + MatrixAngles(matrix, angles); + MatrixPosition(matrix, position); +} + +inline void MatrixAngles(const matrix3x4_t& matrix, RadianEuler& angles) +{ + MatrixAngles(matrix, &angles.x); + + angles.Init(DEG2RAD(angles.z), DEG2RAD(angles.x), DEG2RAD(angles.y)); +} + +void MatrixAngles(const matrix3x4_t& mat, RadianEuler& angles, Vector& position); + +void MatrixAngles(const matrix3x4_t& mat, Quaternion& q, Vector& position); + +inline int VectorCompare(const Vector& v1, const Vector& v2) +{ + return v1 == v2; +} + +inline void VectorTransform(const Vector& in1, const matrix3x4_t& in2, Vector& out) +{ + VectorTransform(&in1.x, in2, &out.x); +} + +inline void VectorITransform(const Vector& in1, const matrix3x4_t& in2, Vector& out) +{ + VectorITransform(&in1.x, in2, &out.x); +} + +inline int BoxOnPlaneSide(const Vector& emins, const Vector& emaxs, const cplane_t* plane) +{ + return BoxOnPlaneSide(&emins.x, &emaxs.x, plane); +} + +inline void VectorFill(Vector& a, float b) +{ + a[0] = a[1] = a[2] = b; +} + +inline void VectorNegate(Vector& a) +{ + a[0] = -a[0]; + a[1] = -a[1]; + a[2] = -a[2]; +} + +inline vec_t VectorAvg(Vector& a) +{ + return (a[0] + a[1] + a[2]) / 3; +} + +inline int FASTCALL BoxOnPlaneSide2(const Vector& emins, const Vector& emaxs, const cplane_t* p, float tolerance = 0.f) +{ + Vector corners[2]; + + if (p->normal[0] < 0) + { + corners[0][0] = emins[0]; + corners[1][0] = emaxs[0]; + } + else + { + corners[1][0] = emins[0]; + corners[0][0] = emaxs[0]; + } + + if (p->normal[1] < 0) + { + corners[0][1] = emins[1]; + corners[1][1] = emaxs[1]; + } + else + { + corners[1][1] = emins[1]; + corners[0][1] = emaxs[1]; + } + + if (p->normal[2] < 0) + { + corners[0][2] = emins[2]; + corners[1][2] = emaxs[2]; + } + else + { + corners[1][2] = emins[2]; + corners[0][2] = emaxs[2]; + } + + int sides = 0; + + float dist1 = DotProduct(p->normal, corners[0]) - p->dist; + if (dist1 >= tolerance) + sides = 1; + + float dist2 = DotProduct(p->normal, corners[1]) - p->dist; + if (dist2 < -tolerance) + sides |= 2; + + return sides; +} + +void ClearBounds(Vector& mins, Vector& maxs); +void AddPointToBounds(const Vector& v, Vector& mins, Vector& maxs); + +void BuildGammaTable(float gamma, float texGamma, float brightness, int overbright); + +inline float TexLightToLinear(int c, int exponent) +{ + extern float power2_n[256]; + Assert(exponent >= -128 && exponent <= 127); + return (float)c * power2_n[exponent + 128]; +} + + +int LinearToTexture(float f); +int LinearToScreenGamma(float f); +float TextureToLinear(int c); + +struct ColorRGBExp32 +{ + byte r, g, b; + signed char exponent; +}; + +void ColorRGBExp32ToVector(const ColorRGBExp32& in, Vector& out); +void VectorToColorRGBExp32(const Vector& v, ColorRGBExp32& c); + +bool SolveQuadratic(float a, float b, float c, float& root1, float& root2); + +bool SolveInverseQuadratic(float x1, float y1, float x2, float y2, float x3, float y3, float& a, float& b, float& c); + +bool SolveInverseQuadraticMonotonic(float x1, float y1, float x2, float y2, + float x3, float y3, float& a, float& b, float& c); + + + + +bool SolveInverseReciprocalQuadratic(float x1, float y1, float x2, float y2, float x3, float y3, float& a, float& b, float& c); + +void VectorYawRotate(const Vector& in, float flYaw, Vector& out); + + +float Bias(float x, float biasAmt); + + +float Gain(float x, float biasAmt); + + +float SmoothCurve(float x); + + +float SmoothCurve_Tweak(float x, float flPeakPos = 0.5, float flPeakSharpness = 0.5); + + +inline float ExponentialDecay(float halflife, float dt) +{ + return expf(-0.69314718f / halflife * dt); +} + +inline float ExponentialDecay(float decayTo, float decayTime, float dt) +{ + return expf(logf(decayTo) / decayTime * dt); +} + +inline float ExponentialDecayIntegral(float decayTo, float decayTime, float dt) +{ + return (powf(decayTo, dt / decayTime) * decayTime - decayTime) / logf(decayTo); +} + +inline float SimpleSpline(float value) +{ + float valueSquared = value * value; + + return (3 * valueSquared - 2 * valueSquared * value); +} + +inline float SimpleSplineRemapVal(float val, float A, float B, float C, float D) +{ + if (A == B) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + return C + (D - C) * SimpleSpline(cVal); +} + +inline float SimpleSplineRemapValClamped(float val, float A, float B, float C, float D) +{ + if (A == B) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + cVal = clamp(cVal, 0.0f, 1.0f); + return C + (D - C) * SimpleSpline(cVal); +} + +FORCEINLINE int RoundFloatToInt(float f) +{ +#if defined(__i386__) || defined(_M_IX86) || defined( PLATFORM_WINDOWS_PC64 ) + return _mm_cvtss_si32(_mm_load_ss(&f)); +#elif defined( _X360 ) +#ifdef Assert + Assert(IsFPUControlWordSet()); +#endif + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw(f); + return pResult[1]; +#else +#error Unknown architecture +#endif +} + +FORCEINLINE unsigned char RoundFloatToByte(float f) +{ + int nResult = RoundFloatToInt(f); +#ifdef Assert + Assert((nResult & ~0xFF) == 0); +#endif + return (unsigned char)nResult; +} + +FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f) +{ +#if defined( _X360 ) +#ifdef Assert + Assert(IsFPUControlWordSet()); +#endif + union + { + double flResult; + int pIntResult[2]; + unsigned long pResult[2]; + }; + flResult = __fctiw(f); + Assert(pIntResult[1] >= 0); + return pResult[1]; +#else + +#if defined( PLATFORM_WINDOWS_PC64 ) + uint nRet = (uint)f; + if (nRet & 1) + { + if ((f - floor(f) >= 0.5)) + { + nRet++; + } + } + else + { + if ((f - floor(f) > 0.5)) + { + nRet++; + } + } + return nRet; +#else + unsigned char nResult[8]; + +#if defined( _WIN32 ) + __asm + { + fld f + fistp qword ptr nResult + } +#elif POSIX + __asm __volatile__( + "fistpl %0;": "=m" (nResult) : "t" (f) : "st" + ); +#endif + + return *((unsigned long*)nResult); +#endif +#endif +} + +FORCEINLINE bool IsIntegralValue(float flValue, float flTolerance = 0.001f) +{ + return fabs(RoundFloatToInt(flValue) - flValue) < flTolerance; +} + +FORCEINLINE int Float2Int(float a) +{ +#if defined( _X360 ) + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiwz(a); + return pResult[1]; +#else + return (int)a; +#endif +} + +inline int Floor2Int(float a) +{ + int RetVal; +#if defined( __i386__ ) + __m128 a128 = _mm_set_ss(a); + RetVal = _mm_cvtss_si32(a128); + __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal); + RetVal -= _mm_comigt_ss(rounded128, a128); +#else + RetVal = static_cast(floor(a)); +#endif + return RetVal; +} + +FORCEINLINE unsigned int FastFToC(float c) +{ +#if defined( __i386__ ) + union { float f; int i; } convert = { c * 255.0f + (float)(1 << 23) }; + return convert.i & 255; +#else + return Float2Int(c * 255.0f); +#endif +} + +FORCEINLINE int FastFloatToSmallInt(float c) +{ +#if defined( __i386__ ) + union { float f; int i; } convert = { c + (float)(3 << 22) }; + return (convert.i & ((1 << 23) - 1)) - (1 << 22); +#else + return Float2Int(c); +#endif +} + +inline float ClampToMsec(float in) +{ + int msec = Floor2Int(in * 1000.0f + 0.5f); + return 0.001f * msec; +} + +inline int Ceil2Int(float a) +{ + int RetVal; +#if defined( __i386__ ) + __m128 a128 = _mm_load_ss(&a); + RetVal = _mm_cvtss_si32(a128); + __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal); + RetVal += _mm_comilt_ss(rounded128, a128); +#else + RetVal = static_cast(ceil(a)); +#endif + return RetVal; +} + + +#define TriArea2D( A, B, C ) \ + ( 0.5f * ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) ) + +#define TriArea2DTimesTwo( A, B, C ) \ + ( ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) ) + + +inline void GetBarycentricCoords2D( + Vector2D const& A, + Vector2D const& B, + Vector2D const& C, + Vector2D const& pt, + float bcCoords[3]) +{ + float invTriArea = 1.0f / TriArea2DTimesTwo(A, B, C); + + bcCoords[0] = TriArea2DTimesTwo(B, C, pt) * invTriArea; + bcCoords[1] = TriArea2DTimesTwo(C, A, pt) * invTriArea; + bcCoords[2] = TriArea2DTimesTwo(A, B, pt) * invTriArea; +} + + +inline bool QuickBoxSphereTest( + const Vector& vOrigin, + float flRadius, + const Vector& bbMin, + const Vector& bbMax) +{ + return vOrigin.x - flRadius < bbMax.x&& vOrigin.x + flRadius > bbMin.x && + vOrigin.y - flRadius < bbMax.y&& vOrigin.y + flRadius > bbMin.y && + vOrigin.z - flRadius < bbMax.z&& vOrigin.z + flRadius > bbMin.z; +} + + +inline bool QuickBoxIntersectTest( + const Vector& vBox1Min, + const Vector& vBox1Max, + const Vector& vBox2Min, + const Vector& vBox2Max) +{ + return + vBox1Min.x < vBox2Max.x&& vBox1Max.x > vBox2Min.x && + vBox1Min.y < vBox2Max.y&& vBox1Max.y > vBox2Min.y && + vBox1Min.z < vBox2Max.z&& vBox1Max.z > vBox2Min.z; +} + + +extern float GammaToLinearFullRange(float gamma); +extern float LinearToGammaFullRange(float linear); +extern float GammaToLinear(float gamma); +extern float LinearToGamma(float linear); + +extern float SrgbGammaToLinear(float flSrgbGammaValue); +extern float SrgbLinearToGamma(float flLinearValue); +extern float X360GammaToLinear(float fl360GammaValue); +extern float X360LinearToGamma(float flLinearValue); +extern float SrgbGammaTo360Gamma(float flSrgbGammaValue); + +FORCEINLINE float LinearToVertexLight(float f) +{ + extern float lineartovertex[4096]; + + int i = RoundFloatToInt(f * 1024.f); + + if ((unsigned)i > 4095) + { + if (i < 0) + i = 0; + else + i = 4095; + } + + return lineartovertex[i]; +} + + +FORCEINLINE unsigned char LinearToLightmap(float f) +{ + extern unsigned char lineartolightmap[4096]; + + int i = RoundFloatToInt(f * 1024.f); + + if ((unsigned)i > 4095) + { + if (i < 0) + i = 0; + else + i = 4095; + } + + return lineartolightmap[i]; +} + +FORCEINLINE void ColorClamp(Vector& color) +{ + float maxc = max(color.x, max(color.y, color.z)); + if (maxc > 1.0f) + { + float ooMax = 1.0f / maxc; + color.x *= ooMax; + color.y *= ooMax; + color.z *= ooMax; + } + + if (color[0] < 0.f) color[0] = 0.f; + if (color[1] < 0.f) color[1] = 0.f; + if (color[2] < 0.f) color[2] = 0.f; +} + +inline void ColorClampTruncate(Vector& color) +{ + if (color[0] > 1.0f) color[0] = 1.0f; else if (color[0] < 0.0f) color[0] = 0.0f; + if (color[1] > 1.0f) color[1] = 1.0f; else if (color[1] < 0.0f) color[1] = 0.0f; + if (color[2] > 1.0f) color[2] = 1.0f; else if (color[2] < 0.0f) color[2] = 0.0f; +} + +void Catmull_Rom_Spline( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Catmull_Rom_Spline_Tangent( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Catmull_Rom_Spline_Integral( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Catmull_Rom_Spline_Integral( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + Vector& output); + +void Catmull_Rom_Spline_Normalize( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Catmull_Rom_Spline_Integral_Normalize( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Catmull_Rom_Spline_NormalizeX( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Catmull_Rom_Spline_NormalizeX( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Hermite_Spline( + const Vector& p1, + const Vector& p2, + const Vector& d1, + const Vector& d2, + float t, + Vector& output); + +float Hermite_Spline( + float p1, + float p2, + float d1, + float d2, + float t); + +void Hermite_Spline( + const Vector& p0, + const Vector& p1, + const Vector& p2, + float t, + Vector& output); + +float Hermite_Spline( + float p0, + float p1, + float p2, + float t); + + +void Hermite_SplineBasis(float t, float basis[]); + +void Hermite_Spline( + const Quaternion& q0, + const Quaternion& q1, + const Quaternion& q2, + float t, + Quaternion& output); + + +void Kochanek_Bartels_Spline( + float tension, + float bias, + float continuity, + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Kochanek_Bartels_Spline_NormalizeX( + float tension, + float bias, + float continuity, + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Cubic_Spline( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Cubic_Spline_NormalizeX( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void BSpline( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void BSpline_NormalizeX( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Parabolic_Spline( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +void Parabolic_Spline_NormalizeX( + const Vector& p1, + const Vector& p2, + const Vector& p3, + const Vector& p4, + float t, + Vector& output); + +FORCEINLINE float QuinticInterpolatingPolynomial(float t) +{ + return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); +} + +void GetInterpolationData(float const* pKnotPositions, + float const* pKnotValues, + int nNumValuesinList, + int nInterpolationRange, + float flPositionToInterpolateAt, + bool bWrap, + float* pValueA, + float* pValueB, + float* pInterpolationValue); + +float RangeCompressor(float flValue, float flMin, float flMax, float flBase); + +float CalcSqrDistanceToAABB(const Vector& mins, const Vector& maxs, const Vector& point); +void CalcClosestPointOnAABB(const Vector& mins, const Vector& maxs, const Vector& point, Vector& closestOut); +void CalcSqrDistAndClosestPointOnAABB(const Vector& mins, const Vector& maxs, const Vector& point, Vector& closestOut, float& distSqrOut); + +inline float CalcDistanceToAABB(const Vector& mins, const Vector& maxs, const Vector& point) +{ + float flDistSqr = CalcSqrDistanceToAABB(mins, maxs, point); + return sqrt(flDistSqr); +} + +void CalcClosestPointOnLine(const Vector& P, const Vector& vLineA, const Vector& vLineB, Vector& vClosest, float* t = 0); +float CalcDistanceToLine(const Vector& P, const Vector& vLineA, const Vector& vLineB, float* t = 0); +float CalcDistanceSqrToLine(const Vector& P, const Vector& vLineA, const Vector& vLineB, float* t = 0); + +void CalcClosestPointOnLineSegment(const Vector& P, const Vector& vLineA, const Vector& vLineB, Vector& vClosest, float* t = 0); +float CalcDistanceToLineSegment(const Vector& P, const Vector& vLineA, const Vector& vLineB, float* t = 0); +float CalcDistanceSqrToLineSegment(const Vector& P, const Vector& vLineA, const Vector& vLineB, float* t = 0); + +bool CalcLineToLineIntersectionSegment( + const Vector& p1, const Vector& p2, const Vector& p3, const Vector& p4, Vector* s1, Vector* s2, + float* t1, float* t2); + +void CalcClosestPointOnLine2D(Vector2D const& P, Vector2D const& vLineA, Vector2D const& vLineB, Vector2D& vClosest, float* t = 0); +float CalcDistanceToLine2D(Vector2D const& P, Vector2D const& vLineA, Vector2D const& vLineB, float* t = 0); +float CalcDistanceSqrToLine2D(Vector2D const& P, Vector2D const& vLineA, Vector2D const& vLineB, float* t = 0); +void CalcClosestPointOnLineSegment2D(Vector2D const& P, Vector2D const& vLineA, Vector2D const& vLineB, Vector2D& vClosest, float* t = 0); +float CalcDistanceToLineSegment2D(Vector2D const& P, Vector2D const& vLineA, Vector2D const& vLineB, float* t = 0); +float CalcDistanceSqrToLineSegment2D(Vector2D const& P, Vector2D const& vLineA, Vector2D const& vLineB, float* t = 0); + +void MathLib_Init(float gamma = 2.2f, float texGamma = 2.2f, float brightness = 0.0f, int overbright = 2.0f, bool bAllow3DNow = true, bool bAllowSSE = true, bool bAllowSSE2 = true, bool bAllowMMX = true); +bool MathLib_3DNowEnabled(void); +bool MathLib_MMXEnabled(void); +bool MathLib_SSEEnabled(void); +bool MathLib_SSE2Enabled(void); + +float Approach(float target, float value, float speed); +float ApproachAngle(float target, float value, float speed); +float AngleDiff(float destAngle, float srcAngle); +float AngleDistance(float next, float cur); +float AngleNormalize(float angle); + +float AngleNormalizePositive(float angle); + +bool AnglesAreEqual(float a, float b, float tolerance = 0.0f); + + +void RotationDeltaAxisAngle(const QAngle& srcAngles, const QAngle& destAngles, Vector& deltaAxis, float& deltaAngle); +void RotationDelta(const QAngle& srcAngles, const QAngle& destAngles, QAngle* out); + +void ComputeTrianglePlane(const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept); +int PolyFromPlane(Vector* outVerts, const Vector& normal, float dist, float fHalfScale = 9000.0f); +int ClipPolyToPlane(Vector* inVerts, int vertCount, Vector* outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon = 0.1f); +int ClipPolyToPlane_Precise(double* inVerts, int vertCount, double* outVerts, const double* normal, double dist, double fOnPlaneEpsilon = 0.1); + +void CalcTriangleTangentSpace(const Vector& p0, const Vector& p1, const Vector& p2, + const Vector2D& t0, const Vector2D& t1, const Vector2D& t2, + Vector& sVect, Vector& tVect); + +void TransformAABB(const matrix3x4_t& in1, const Vector& vecMinsIn, const Vector& vecMaxsIn, Vector& vecMinsOut, Vector& vecMaxsOut); + +void ITransformAABB(const matrix3x4_t& in1, const Vector& vecMinsIn, const Vector& vecMaxsIn, Vector& vecMinsOut, Vector& vecMaxsOut); + +void RotateAABB(const matrix3x4_t& in1, const Vector& vecMinsIn, const Vector& vecMaxsIn, Vector& vecMinsOut, Vector& vecMaxsOut); + +void IRotateAABB(const matrix3x4_t& in1, const Vector& vecMinsIn, const Vector& vecMaxsIn, Vector& vecMinsOut, Vector& vecMaxsOut); + +inline void MatrixTransformPlane(const matrix3x4_t& src, const cplane_t& inPlane, cplane_t& outPlane) +{ + VectorRotate(inPlane.normal, src, outPlane.normal); + outPlane.dist = inPlane.dist * DotProduct(outPlane.normal, outPlane.normal); + outPlane.dist += outPlane.normal.x * src[0][3] + outPlane.normal.y * src[1][3] + outPlane.normal.z * src[2][3]; +} + +inline void MatrixITransformPlane(const matrix3x4_t& src, const cplane_t& inPlane, cplane_t& outPlane) +{ + Vector vecTranslation; + MatrixGetColumn(src, 3, vecTranslation); + + Vector vecInvTranslation; + VectorIRotate(vecTranslation, src, vecInvTranslation); + + VectorIRotate(inPlane.normal, src, outPlane.normal); + outPlane.dist = inPlane.dist * DotProduct(outPlane.normal, outPlane.normal); + outPlane.dist -= outPlane.normal.x * vecInvTranslation[0] + outPlane.normal.y * vecInvTranslation[1] + outPlane.normal.z * vecInvTranslation[2]; +} + +int CeilPow2(int in); +int FloorPow2(int in); + +FORCEINLINE float* UnpackNormal_HEND3N(const unsigned int* pPackedNormal, float* pNormal) +{ + int temp[3]; + temp[0] = ((*pPackedNormal >> 0L) & 0x7ff); + if (temp[0] & 0x400) + { + temp[0] = 2048 - temp[0]; + } + temp[1] = ((*pPackedNormal >> 11L) & 0x7ff); + if (temp[1] & 0x400) + { + temp[1] = 2048 - temp[1]; + } + temp[2] = ((*pPackedNormal >> 22L) & 0x3ff); + if (temp[2] & 0x200) + { + temp[2] = 1024 - temp[2]; + } + pNormal[0] = (float)temp[0] * 1.0f / 1023.0f; + pNormal[1] = (float)temp[1] * 1.0f / 1023.0f; + pNormal[2] = (float)temp[2] * 1.0f / 511.0f; + return pNormal; +} + +FORCEINLINE unsigned int* PackNormal_HEND3N(const float* pNormal, unsigned int* pPackedNormal) +{ + int temp[3]; + + temp[0] = Float2Int(pNormal[0] * 1023.0f); + temp[1] = Float2Int(pNormal[1] * 1023.0f); + temp[2] = Float2Int(pNormal[2] * 511.0f); + + Assert(temp[0] >= -1023 && temp[0] <= 1023); + Assert(temp[1] >= -1023 && temp[1] <= 1023); + Assert(temp[2] >= -511 && temp[2] <= 511); + + *pPackedNormal = ((temp[2] & 0x3ff) << 22L) | + ((temp[1] & 0x7ff) << 11L) | + ((temp[0] & 0x7ff) << 0L); + return pPackedNormal; +} + +FORCEINLINE unsigned int* PackNormal_HEND3N(float nx, float ny, float nz, unsigned int* pPackedNormal) +{ + int temp[3]; + + temp[0] = Float2Int(nx * 1023.0f); + temp[1] = Float2Int(ny * 1023.0f); + temp[2] = Float2Int(nz * 511.0f); + + Assert(temp[0] >= -1023 && temp[0] <= 1023); + Assert(temp[1] >= -1023 && temp[1] <= 1023); + Assert(temp[2] >= -511 && temp[2] <= 511); + + *pPackedNormal = ((temp[2] & 0x3ff) << 22L) | + ((temp[1] & 0x7ff) << 11L) | + ((temp[0] & 0x7ff) << 0L); + return pPackedNormal; +} + +FORCEINLINE float* UnpackNormal_SHORT2(const unsigned int* pPackedNormal, float* pNormal, bool bIsTangent = FALSE) +{ + short iX = (*pPackedNormal & 0x0000FFFF); + short iY = (*pPackedNormal & 0xFFFF0000) >> 16; + + float zSign = +1; + if (iX < 0) + { + zSign = -1; + iX = -iX; + } + float tSign = +1; + if (iY < 0) + { + tSign = -1; + iY = -iY; + } + + pNormal[0] = (iX - 16384.0f) / 16384.0f; + pNormal[1] = (iY - 16384.0f) / 16384.0f; + pNormal[2] = zSign * sqrtf(1.0f - (pNormal[0] * pNormal[0] + pNormal[1] * pNormal[1])); + if (bIsTangent) + { + pNormal[3] = tSign; + } + + return pNormal; +} + +FORCEINLINE unsigned int* PackNormal_SHORT2(float nx, float ny, float nz, unsigned int* pPackedNormal, float binormalSign = +1.0f) +{ + nx += 1; + ny += 1; + nx *= 16384.0f; + ny *= 16384.0f; + + nx = max(nx, 1.0f); + ny = max(ny, 1.0f); + nx = min(nx, 32767.0f); + ny = min(ny, 32767.0f); + + if (nz < 0.0f) + nx = -nx; + + ny *= binormalSign; + + short sX = (short)nx; + short sY = (short)ny; + + *pPackedNormal = (sX & 0x0000FFFF) | (sY << 16); + + return pPackedNormal; +} + +FORCEINLINE unsigned int* PackNormal_SHORT2(const float* pNormal, unsigned int* pPackedNormal, float binormalSign = +1.0f) +{ + return PackNormal_SHORT2(pNormal[0], pNormal[1], pNormal[2], pPackedNormal, binormalSign); +} + +FORCEINLINE float* UnpackNormal_UBYTE4(const unsigned int* pPackedNormal, float* pNormal, bool bIsTangent = FALSE) +{ + unsigned char cX, cY; + if (bIsTangent) + { + cX = *pPackedNormal >> 16; + cY = *pPackedNormal >> 24; + } + else + { + cX = *pPackedNormal >> 0; + cY = *pPackedNormal >> 8; + } + + float x = cX - 128.0f; + float y = cY - 128.0f; + float z; + + float zSignBit = x < 0 ? 1.0f : 0.0f; + float tSignBit = y < 0 ? 1.0f : 0.0f; + float zSign = -(2 * zSignBit - 1); + float tSign = -(2 * tSignBit - 1); + + x = x * zSign - zSignBit; + y = y * tSign - tSignBit; + x = x - 64; + y = y - 64; + + float xSignBit = x < 0 ? 1.0f : 0.0f; + float ySignBit = y < 0 ? 1.0f : 0.0f; + float xSign = -(2 * xSignBit - 1); + float ySign = -(2 * ySignBit - 1); + + x = (x * xSign - xSignBit) / 63.0f; + y = (y * ySign - ySignBit) / 63.0f; + z = 1.0f - x - y; + + float oolen = 1.0f / sqrt(x * x + y * y + z * z); + x *= oolen * xSign; + y *= oolen * ySign; + z *= oolen * zSign; + + pNormal[0] = x; + pNormal[1] = y; + pNormal[2] = z; + if (bIsTangent) + { + pNormal[3] = tSign; + } + + return pNormal; +} + +FORCEINLINE unsigned int* PackNormal_UBYTE4(float nx, float ny, float nz, unsigned int* pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f) +{ + float xSign = nx < 0.0f ? -1.0f : 1.0f; + float ySign = ny < 0.0f ? -1.0f : 1.0f; + float zSign = nz < 0.0f ? -1.0f : 1.0f; + float tSign = binormalSign; + Assert((binormalSign == +1.0f) || (binormalSign == -1.0f)); + + float xSignBit = 0.5f * (1 - xSign); + float ySignBit = 0.5f * (1 - ySign); + float zSignBit = 0.5f * (1 - zSign); + float tSignBit = 0.5f * (1 - binormalSign); + + float absX = xSign * nx; + float absY = ySign * ny; + float absZ = zSign * nz; + + float xbits = absX / (absX + absY + absZ); + float ybits = absY / (absX + absY + absZ); + + xbits *= 63; + ybits *= 63; + + xbits = xbits * xSign - xSignBit; + ybits = ybits * ySign - ySignBit; + xbits += 64.0f; + ybits += 64.0f; + + xbits = xbits * zSign - zSignBit; + ybits = ybits * tSign - tSignBit; + + xbits += 128.0f; + ybits += 128.0f; + + unsigned char cX = (unsigned char)xbits; + unsigned char cY = (unsigned char)ybits; + + if (!bIsTangent) + *pPackedNormal = (cX << 0) | (cY << 8); + else + *pPackedNormal = (cX << 16) | (cY << 24); + + return pPackedNormal; +} + +FORCEINLINE unsigned int* PackNormal_UBYTE4(const float* pNormal, unsigned int* pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f) +{ + return PackNormal_UBYTE4(pNormal[0], pNormal[1], pNormal[2], pPackedNormal, bIsTangent, binormalSign); +} + + +void RGBtoHSV(const Vector& rgb, Vector& hsv); + + +void HSVtoRGB(const Vector& hsv, Vector& rgb); + + +float FastLog2(float i); +float FastPow2(float i); +float FastPow(float a, float b); +float FastPow10(float i); + +inline bool CloseEnough(float a, float b, float epsilon = EQUAL_EPSILON) +{ + return fabs(a - b) <= epsilon; +} + +inline bool CloseEnough(const Vector& a, const Vector& b, float epsilon = EQUAL_EPSILON) +{ + return fabs(a.x - b.x) <= epsilon && + fabs(a.y - b.y) <= epsilon && + fabs(a.z - b.z) <= epsilon; +} + +bool AlmostEqual(float a, float b, int maxUlps = 10); + +inline bool AlmostEqual(const Vector& a, const Vector& b, int maxUlps = 10) +{ + return AlmostEqual(a.x, b.x, maxUlps) && + AlmostEqual(a.y, b.y, maxUlps) && + AlmostEqual(a.z, b.z, maxUlps); +} + + +#endif +``` + +`SpyCustom/sdk/mem.h`: + +```h +#ifndef TIER0_MEM_H +#define TIER0_MEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#ifdef LINUX +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#include "platform.h" + +#if !defined(STATIC_TIER0) && !defined(_STATIC_LINKED) + +#ifdef TIER0_DLL_EXPORT +# define MEM_INTERFACE DLL_EXPORT +#else +# define MEM_INTERFACE DLL_IMPORT +#endif + +#else + +#define MEM_INTERFACE extern + +#endif + + + +MEM_INTERFACE void* MemAllocScratch(int nMemSize); +MEM_INTERFACE void MemFreeScratch(); + +#ifdef _LINUX +MEM_INTERFACE void ZeroMemory(void* mem, size_t length); +#endif + + +#endif +``` + +`SpyCustom/sdk/memalloc.h`: + +```h +#ifndef TIER0_MEMALLOC_H +#define TIER0_MEMALLOC_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifndef POSIX +#endif + +#if defined( _MEMTEST ) +#ifdef _WIN32 +#define USE_MEM_DEBUG 1 +#endif +#endif + +#define MEM_DEBUG_CLASSNAME 1 + +#include +#if defined( OSX ) +#include +#endif + +#include "mem.h" + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +struct _CrtMemState; + +#define MEMALLOC_VERSION 1 + +typedef size_t(*MemAllocFailHandler_t)(size_t); + +class IMemAlloc +{ +public: + virtual void* Alloc(size_t nSize) = 0; + virtual void* Realloc(void* pMem, size_t nSize) = 0; + virtual void Free(void* pMem) = 0; + virtual void* Expand_NoLongerSupported(void* pMem, size_t nSize) = 0; + + virtual void* Alloc(size_t nSize, const char* pFileName, int nLine) = 0; + virtual void* Realloc(void* pMem, size_t nSize, const char* pFileName, int nLine) = 0; + virtual void Free(void* pMem, const char* pFileName, int nLine) = 0; + virtual void* Expand_NoLongerSupported(void* pMem, size_t nSize, const char* pFileName, int nLine) = 0; + + virtual size_t GetSize(void* pMem) = 0; + + virtual void PushAllocDbgInfo(const char* pFileName, int nLine) = 0; + virtual void PopAllocDbgInfo() = 0; + + virtual long CrtSetBreakAlloc(long lNewBreakAlloc) = 0; + virtual int CrtSetReportMode(int nReportType, int nReportMode) = 0; + virtual int CrtIsValidHeapPointer(const void* pMem) = 0; + virtual int CrtIsValidPointer(const void* pMem, unsigned int size, int access) = 0; + virtual int CrtCheckMemory(void) = 0; + virtual int CrtSetDbgFlag(int nNewFlag) = 0; + virtual void CrtMemCheckpoint(_CrtMemState* pState) = 0; + + virtual void DumpStats() = 0; + virtual void DumpStatsFileBase(char const* pchFileBase) = 0; + + virtual void* CrtSetReportFile(int nRptType, void* hFile) = 0; + virtual void* CrtSetReportHook(void* pfnNewHook) = 0; + virtual int CrtDbgReport(int nRptType, const char* szFile, + int nLine, const char* szModule, const char* pMsg) = 0; + + virtual int heapchk() = 0; + + virtual bool IsDebugHeap() = 0; + + virtual void GetActualDbgInfo(const char*& pFileName, int& nLine) = 0; + virtual void RegisterAllocation(const char* pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime) = 0; + virtual void RegisterDeallocation(const char* pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime) = 0; + + virtual int GetVersion() = 0; + + virtual void CompactHeap() = 0; + + virtual MemAllocFailHandler_t SetAllocFailHandler(MemAllocFailHandler_t pfnMemAllocFailHandler) = 0; + + virtual void DumpBlockStats(void*) = 0; + +#if defined( _MEMTEST ) + virtual void SetStatsExtraInfo(const char* pMapName, const char* pComment) = 0; +#endif + + virtual size_t MemoryAllocFailed() = 0; + + virtual uint32 GetDebugInfoSize() = 0; + virtual void SaveDebugInfo(void* pvDebugInfo) = 0; + virtual void RestoreDebugInfo(const void* pvDebugInfo) = 0; + virtual void InitDebugInfo(void* pvDebugInfo, const char* pchRootFileName, int nLine) = 0; + + virtual void GlobalMemoryStatus(size_t* pUsedMemory, size_t* pFreeMemory) = 0; +}; + +MEM_INTERFACE IMemAlloc* g_pMemAlloc; + +#ifdef MEMALLOC_REGIONS +#ifndef MEMALLOC_REGION +#define MEMALLOC_REGION 0 +#endif +inline void* MemAlloc_Alloc(size_t nSize) +{ + return g_pMemAlloc->RegionAlloc(MEMALLOC_REGION, nSize); +} + +inline void* MemAlloc_Alloc(size_t nSize, const char* pFileName, int nLine) +{ + return g_pMemAlloc->RegionAlloc(MEMALLOC_REGION, nSize, pFileName, nLine); +} +#else +#undef MEMALLOC_REGION +inline void* MemAlloc_Alloc(size_t nSize) +{ + return g_pMemAlloc->Alloc(nSize); +} + +inline void* MemAlloc_Alloc(size_t nSize, const char* pFileName, int nLine) +{ + return g_pMemAlloc->Alloc(nSize, pFileName, nLine); +} +#endif +inline void MemAlloc_Free(void* ptr) +{ + g_pMemAlloc->Free(ptr); +} +inline void MemAlloc_Free(void* ptr, const char* pFileName, int nLine) +{ + g_pMemAlloc->Free(ptr, pFileName, nLine); +} + +inline bool ValueIsPowerOfTwo(size_t value) +{ + return (value & (value - 1)) == 0; +} + +inline void* MemAlloc_AllocAligned(size_t size, size_t align) +{ + unsigned char* pAlloc, * pResult; + + if (!IsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void*) ? align : sizeof(void*)) - 1; + + if ((pAlloc = (unsigned char*)g_pMemAlloc->Alloc(sizeof(void*) + align + size)) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)((size_t)(pAlloc + sizeof(void*) + align) & ~align); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void*)pResult; +} + +inline void* MemAlloc_AllocAligned(size_t size, size_t align, const char* pszFile, int nLine) +{ + unsigned char* pAlloc, * pResult; + + if (!IsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void*) ? align : sizeof(void*)) - 1; + + if ((pAlloc = (unsigned char*)g_pMemAlloc->Alloc(sizeof(void*) + align + size, pszFile, nLine)) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)((size_t)(pAlloc + sizeof(void*) + align) & ~align); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void*)pResult; +} + +inline void* MemAlloc_AllocAlignedUnattributed(size_t size, size_t align) +{ + unsigned char* pAlloc, * pResult; + + if (!ValueIsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void*) ? align : sizeof(void*)) - 1; + + if ((pAlloc = (unsigned char*)MemAlloc_Alloc(sizeof(void*) + align + size)) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)((size_t)(pAlloc + sizeof(void*) + align) & ~align); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void*)pResult; +} + +inline void* MemAlloc_AllocAlignedFileLine(size_t size, size_t align, const char* pszFile, int nLine) +{ + unsigned char* pAlloc, * pResult; + + if (!ValueIsPowerOfTwo(align)) + return NULL; + + align = (align > sizeof(void*) ? align : sizeof(void*)) - 1; + + if ((pAlloc = (unsigned char*)MemAlloc_Alloc(sizeof(void*) + align + size, pszFile, nLine)) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)((size_t)(pAlloc + sizeof(void*) + align) & ~align); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void*)pResult; +} + +inline void* MemAlloc_ReallocAligned(void* ptr, size_t size, size_t align) +{ + if (!IsPowerOfTwo(align)) + return NULL; + + if (((size_t)ptr & (align - 1)) != 0) + return NULL; + + if (!ptr) + return MemAlloc_AllocAligned(size, align); + + void* pAlloc, * pResult; + + pAlloc = ptr; + pAlloc = (void*)(((size_t)pAlloc & ~(sizeof(void*) - 1)) - sizeof(void*)); + pAlloc = *((void**)pAlloc); + + size_t nOffset = (size_t)ptr - (size_t)pAlloc; + size_t nOldSize = g_pMemAlloc->GetSize(pAlloc); + if (nOldSize >= size + nOffset) + return ptr; + + pResult = MemAlloc_AllocAligned(size, align); + memcpy(pResult, ptr, nOldSize - nOffset); + g_pMemAlloc->Free(pAlloc); + return pResult; +} + +inline void MemAlloc_FreeAligned(void* pMemBlock) +{ + void* pAlloc; + + if (pMemBlock == NULL) + return; + + pAlloc = pMemBlock; + + pAlloc = (void*)(((size_t)pAlloc & ~(sizeof(void*) - 1)) - sizeof(void*)); + + pAlloc = *((void**)pAlloc); + g_pMemAlloc->Free(pAlloc); +} + +inline void MemAlloc_FreeAligned(void* pMemBlock, const char* pFileName, int nLine) +{ + void* pAlloc; + + if (pMemBlock == NULL) + return; + + pAlloc = pMemBlock; + + pAlloc = (void*)(((size_t)pAlloc & ~(sizeof(void*) - 1)) - sizeof(void*)); + + pAlloc = *((void**)pAlloc); + g_pMemAlloc->Free(pAlloc, pFileName, nLine); +} + +inline size_t MemAlloc_GetSizeAligned(void* pMemBlock) +{ + void* pAlloc; + + if (pMemBlock == NULL) + return 0; + + pAlloc = pMemBlock; + + pAlloc = (void*)(((size_t)pAlloc & ~(sizeof(void*) - 1)) - sizeof(void*)); + + pAlloc = *((void**)pAlloc); + return g_pMemAlloc->GetSize(pAlloc) - ((byte*)pMemBlock - (byte*)pAlloc); +} + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ ) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo() +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#else +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)0) +#define MemAlloc_PopAllocDbgInfo() ((void)0) +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#endif + +#define MemAlloc_DumpStats() g_pMemAlloc->DumpStats() +#define MemAlloc_CompactHeap() g_pMemAlloc->CompactHeap() +#define MemAlloc_OutOfMemory() g_pMemAlloc->OutOfMemory() +#define MemAlloc_CompactIncremental() g_pMemAlloc->CompactIncremental() +#define MemAlloc_DumpStatsFileBase( _filename ) g_pMemAlloc->DumpStatsFileBase( _filename ) +#define MemAlloc_CrtCheckMemory() g_pMemAlloc->CrtCheckMemory() +#define MemAlloc_GlobalMemoryStatus( _usedMemory, _freeMemory ) g_pMemAlloc->GlobalMemoryStatus( _usedMemory, _freeMemory ) +#define MemAlloc_MemoryAllocFailed() g_pMemAlloc->MemoryAllocFailed() + +#define MemAlloc_GetDebugInfoSize() g_pMemAlloc->GetDebugInfoSize() +#define MemAlloc_SaveDebugInfo( pvDebugInfo ) g_pMemAlloc->SaveDebugInfo( pvDebugInfo ) +#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) g_pMemAlloc->RestoreDebugInfo( pvDebugInfo ) +#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) g_pMemAlloc->InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) +#define MemAlloc_GetSize( x ) g_pMemAlloc->GetSize( x ); +class CMemAllocAttributeAlloction +{ +public: + CMemAllocAttributeAlloction(const char* pszFile, int line) + { + MemAlloc_PushAllocDbgInfo(pszFile, line); + } + + ~CMemAllocAttributeAlloction() + { + MemAlloc_PopAllocDbgInfo(); + } +}; + +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) + +#if defined(_WIN32) && ( defined(_DEBUG) || defined(USE_MEM_DEBUG) ) + +#pragma warning(disable:4290) +#pragma warning(push) +#include + +#if defined(_CPPRTTI) && defined(MEM_DEBUG_CLASSNAME) +#define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( typeid(*this).name() ) +#define MEM_ALLOC_CLASSNAME(type) (typeid((type*)(0)).name()) +#else +#define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( __FILE__ ) +#define MEM_ALLOC_CLASSNAME(type) (__FILE__) +#endif + +#ifdef _MSC_VER +#define MEM_ALLOC_CREDIT_FUNCTION() MEM_ALLOC_CREDIT_( __FUNCTION__ ) +#else +#define MEM_ALLOC_CREDIT_FUNCTION() (__FILE__) +#endif + +#pragma warning(pop) +#else +#define MEM_ALLOC_CREDIT_CLASS() +#define MEM_ALLOC_CLASSNAME(type) NULL +#define MEM_ALLOC_CREDIT_FUNCTION() +#endif + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +struct MemAllocFileLine_t +{ + const char* pszFile; + int line; +}; + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \ + static CUtlMap g_##tag##Allocs( DefLessFunc( void *) ); \ + static const char *g_psz##tag##Alloc = strcpy( (char *)g_pMemAlloc->Alloc( strlen( #tag "Alloc" ) + 1, "intentional leak", 0 ), #tag "Alloc" ); + +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + g_pMemAlloc->GetActualDbgInfo( fileLine.pszFile, fileLine.line ); \ + if ( fileLine.pszFile != g_psz##tag##Alloc ) \ + { \ + g_##tag##Allocs.Insert( p, fileLine ); \ + } \ + \ + MemAlloc_RegisterAllocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + CUtlMap::IndexType_t iRecordedFileLine = g_##tag##Allocs.Find( p ); \ + if ( iRecordedFileLine != g_##tag##Allocs.InvalidIndex() ) \ + { \ + fileLine = g_##tag##Allocs[iRecordedFileLine]; \ + g_##tag##Allocs.RemoveAt( iRecordedFileLine ); \ + } \ + \ + MemAlloc_RegisterDeallocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#else + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +#endif + +#elif defined( POSIX ) + +#if defined( OSX ) +inline void* memalign(size_t alignment, size_t size) { void* pTmp = NULL; pTmp = malloc(size); return pTmp; } +#endif + +inline void* _aligned_malloc(size_t nSize, size_t align) { return memalign(align, nSize); } +inline void _aligned_free(void* ptr) { free(ptr); } + +inline void* MemAlloc_Alloc(size_t nSize, const char* pFileName = NULL, int nLine = 0) { return malloc(nSize); } +inline void MemAlloc_Free(void* ptr, const char* pFileName = NULL, int nLine = 0) { free(ptr); } + +inline void* MemAlloc_AllocAligned(size_t size, size_t align, const char* pszFile = NULL, int nLine = 0) { return memalign(align, size); } +inline void* MemAlloc_AllocAlignedFileLine(size_t size, size_t align, const char* pszFile = NULL, int nLine = 0) { return memalign(align, size); } +inline void MemAlloc_FreeAligned(void* pMemBlock, const char* pszFile = NULL, int nLine = 0) { free(pMemBlock); } + +#if defined( OSX ) +inline size_t _msize(void* ptr) { return malloc_size(ptr); } +#else +inline size_t _msize(void* ptr) { return malloc_usable_size(ptr); } +#endif + +inline void* MemAlloc_ReallocAligned(void* ptr, size_t size, size_t align) +{ + void* ptr_new_aligned = memalign(align, size); + + if (ptr_new_aligned) + { + size_t old_size = _msize(ptr); + size_t copy_size = (size < old_size) ? size : old_size; + + memcpy(ptr_new_aligned, ptr, copy_size); + free(ptr); + } + + return ptr_new_aligned; +} +#else +#define MemAlloc_GetDebugInfoSize() g_pMemAlloc->GetDebugInfoSize() +#define MemAlloc_SaveDebugInfo( pvDebugInfo ) g_pMemAlloc->SaveDebugInfo( pvDebugInfo ) +#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) g_pMemAlloc->RestoreDebugInfo( pvDebugInfo ) +#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) g_pMemAlloc->InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) + +#endif + +#if !defined(STEAM) && defined(NO_MALLOC_OVERRIDE) + +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) +#define MEM_ALLOC_CREDIT_FUNCTION() +#define MEM_ALLOC_CREDIT_CLASS() +#define MEM_ALLOC_CLASSNAME(type) NULL + +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_DumpStats() ((void)0) +#define MemAlloc_CompactHeap() ((void)0) +#define MemAlloc_OutOfMemory() ((void)0) +#define MemAlloc_CompactIncremental() ((void)0) +#define MemAlloc_DumpStatsFileBase( _filename ) ((void)0) +inline bool MemAlloc_CrtCheckMemory() { return true; } +inline void MemAlloc_GlobalMemoryStatus(size_t* pusedMemory, size_t* pfreeMemory) +{ + *pusedMemory = 0; + *pfreeMemory = 0; +} +#define MemAlloc_MemoryAllocFailed() 0 + +#define MemAlloc_GetDebugInfoSize() 0 +#define MemAlloc_SaveDebugInfo( pvDebugInfo ) ((void)0) +#define MemAlloc_RestoreDebugInfo( pvDebugInfo ) ((void)0) +#define MemAlloc_InitDebugInfo( pvDebugInfo, pchRootFileName, nLine ) ((void)0) + + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +#endif + + + +#if defined( POSIX ) && !defined( NO_HOOK_MALLOC ) +PLATFORM_INTERFACE void MemoryLogMessage(char const* s); +PLATFORM_INTERFACE void EnableMemoryLogging(bool bOnOff); +PLATFORM_INTERFACE void DumpMemoryLog(int nThresh); +PLATFORM_INTERFACE void DumpMemorySummary(void); +PLATFORM_INTERFACE void SetMemoryMark(void); +PLATFORM_INTERFACE void DumpChangedMemory(int nThresh); + +#else +FORCEINLINE void MemoryLogMessage(char const* s) +{ +} + +FORCEINLINE void EnableMemoryLogging(bool bOnOff) +{ +} +FORCEINLINE void DumpMemoryLog(int nThresh) +{ +} +FORCEINLINE void DumpMemorySummary(void) +{ +} +FORCEINLINE void SetMemoryMark(void) +{ +} +FORCEINLINE void DumpChangedMemory(int nThresh) +{ +} + +#endif + +#ifdef POSIX +PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage(void); +#else +FORCEINLINE size_t ApproximateProcessMemoryUsage(void) +{ + return 0; +} + +#endif + +struct aligned_tmp_t +{ +}; + +template< int bytesAlignment = 16, class T = aligned_tmp_t > +class CAlignedNewDelete : public T +{ + +public: + void* operator new(size_t nSize) + { + return MemAlloc_AllocAligned(nSize, bytesAlignment); + } + + void* operator new(size_t nSize, int nBlockUse, const char* pFileName, int nLine) + { + return MemAlloc_AllocAlignedFileLine(nSize, bytesAlignment, pFileName, nLine); + } + + void operator delete(void* pData) + { + if (pData) + { + MemAlloc_FreeAligned(pData); + } + } + + void operator delete(void* pData, int nBlockUse, const char* pFileName, int nLine) + { + if (pData) + { + MemAlloc_FreeAligned(pData, pFileName, nLine); + } + } +}; + + +#endif +``` + +`SpyCustom/sdk/memdbgoff.h`: + +```h +#ifdef MEM_OVERRIDE_ON + +#undef malloc +#undef realloc +#undef calloc +#undef free +#undef _expand +#undef _msize +#undef new +#undef _aligned_malloc +#undef _aligned_free +#undef _malloc_dbg + +#undef MEM_OVERRIDE_ON + +#endif +``` + +`SpyCustom/sdk/memdbgon.h`: + +```h +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +#if defined(_DEBUG) && !defined(USE_MEM_DEBUG) +#define USE_MEM_DEBUG 1 +#endif + +#if defined(NO_HOOK_MALLOC) +#undef USE_MEM_DEBUG +#endif + +#if (defined(_DEBUG) || !defined(_INC_CRTDBG)) || defined(MEMDBGON_H) + +#include "basetypes.h" +#ifdef _WIN32 +#include +#else +#include +#endif +#include +#include +#include "commonmacros.h" +#include "memalloc.h" + +#if defined(USE_MEM_DEBUG) +#if defined( POSIX ) + +#define _NORMAL_BLOCK 1 + +#include +#include +#include +#include +#if !defined( DID_THE_OPERATOR_NEW ) +#define DID_THE_OPERATOR_NEW +void* operator new(size_t nSize, int blah, const char* pFileName, int nLine); +void* operator new[](size_t nSize, int blah, const char* pFileName, int nLine); +#endif + +#else + +#if !defined(_DEBUG) +#define _DEBUG 1 +#include +#undef _DEBUG +#else +#include +#endif + +#endif +#endif + +#include "memdbgoff.h" + +#define MEM_OVERRIDE_ON 1 + +#undef malloc +#undef realloc +#undef calloc +#undef _expand +#undef free +#undef _msize +#undef _aligned_malloc +#undef _aligned_free + +#ifndef MEMDBGON_H +inline void* MemAlloc_InlineCallocMemset(void* pMem, size_t nCount, size_t nElementSize) +{ + memset(pMem, 0, nElementSize * nCount); + return pMem; +} +#endif + +#define calloc(c, s) MemAlloc_InlineCallocMemset(malloc(c*s), c, s) +#define free(p) g_pMemAlloc->Free( p ) +#define _msize(p) g_pMemAlloc->GetSize( p ) +#define _expand(p, s) _expand_NoLongerSupported(p, s) +#define _aligned_free( p ) MemAlloc_FreeAligned( p ) + +#if defined(USE_MEM_DEBUG) + +#define malloc(s) g_pMemAlloc->Alloc( s, __FILE__, __LINE__) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s, __FILE__, __LINE__ ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAligned( s, a, __FILE__, __LINE__ ) + +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) + +#if !defined( LINUX ) +#if defined(__AFX_H__) && defined(DEBUG_NEW) +#define new DEBUG_NEW +#else +#undef new +#define MEMALL_DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +#define new MEMALL_DEBUG_NEW +#endif +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define _wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) +#define wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) + +#if !defined(MEMDBGON_H) + +inline char* MemAlloc_StrDup(const char* pString, const char* pFileName, unsigned nLine) +{ + char* pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char*)g_pMemAlloc->Alloc(len, pFileName, nLine)) != NULL) + { + return strcpy(pMemory, pString); + } + + return NULL; +} + +inline wchar_t* MemAlloc_WcStrDup(const wchar_t* pString, const char* pFileName, unsigned nLine) +{ + wchar_t* pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t*)g_pMemAlloc->Alloc(len * sizeof(wchar_t), pFileName, nLine)) != NULL) + { + return wcscpy(pMemory, pString); + } + + return NULL; +} + +#endif + +#else +#define malloc(s) g_pMemAlloc->Alloc( s ) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAligned( s, a ) + +#ifndef _malloc_dbg +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) +#endif + +#undef new + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s) +#define strdup(s) MemAlloc_StrDup(s) +#define _wcsdup(s) MemAlloc_WcStrDup(s) +#define wcsdup(s) MemAlloc_WcStrDup(s) + +#if !defined(MEMDBGON_H) + +inline char* MemAlloc_StrDup(const char* pString) +{ + char* pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char*)g_pMemAlloc->Alloc(len)) != NULL) + { + return strcpy(pMemory, pString); + } + + return NULL; +} + +inline wchar_t* MemAlloc_WcStrDup(const wchar_t* pString) +{ + wchar_t* pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t*)g_pMemAlloc->Alloc(len * sizeof(wchar_t))) != NULL) + { + return wcscpy(pMemory, pString); + } + + return NULL; +} + +#endif + +#endif + +#define MEMDBGON_H + +#else + +#if defined(USE_MEM_DEBUG) +#ifndef _STATIC_LINKED +#pragma message ("Note: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build") +#else +#error "Error: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build. Not recoverable in static build" +#endif +#endif +#endif + +#else + +#include "memalloc.h" + +#endif +``` + +`SpyCustom/sdk/mempool.h`: + +```h +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "memalloc.h" +#include "tslist.h" +#include "platform.h" +#include "utlvector.h" +#include "utlrbtree.h" + +typedef void (*MemoryPoolReportFunc_t)(PRINTF_FORMAT_STRING char const* pMsg, ...); + +class CUtlMemoryPool +{ +public: + enum MemoryPoolGrowType_t + { + GROW_NONE = 0, + GROW_FAST = 1, + GROW_SLOW = 2 + }; + + CUtlMemoryPool(int blockSize, int numElements, int growMode = GROW_FAST, const char* pszAllocOwner = NULL, int nAlignment = 0); + ~CUtlMemoryPool(); + + void* Alloc(); + void* Alloc(size_t amount); + void* AllocZero(); + void* AllocZero(size_t amount); + void Free(void* pMem); + + void Clear(); + + static void SetErrorReportFunc(MemoryPoolReportFunc_t func); + + int Count() const { return m_BlocksAllocated; } + int PeakCount() const { return m_PeakAlloc; } + int BlockSize() const { return m_BlockSize; } + int Size() const; + + bool IsAllocationWithinPool(void* pMem) const; + +protected: + class CBlob + { + public: + CBlob* m_pPrev, * m_pNext; + int m_NumBytes; + char m_Data[1]; + char m_Padding[3]; + }; + + void Init(); + void AddNewBlob(); + void ReportLeaks(); + + int m_BlockSize; + int m_BlocksPerBlob; + + int m_GrowMode; + + int m_BlocksAllocated; + int m_PeakAlloc; + unsigned short m_nAlignment; + unsigned short m_NumBlobs; + void* m_pHeadOfFreeList; + const char* m_pszAllocOwner; + CBlob m_BlobHead; + + static MemoryPoolReportFunc_t g_ReportFunc; +}; + + +class CMemoryPoolMT : public CUtlMemoryPool +{ +public: + CMemoryPoolMT(int blockSize, int numElements, int growMode = GROW_FAST, const char* pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool(blockSize, numElements, growMode, pszAllocOwner, nAlignment) {} + + + void* Alloc() { AUTO_LOCK(m_mutex); return CUtlMemoryPool::Alloc(); } + void* Alloc(size_t amount) { AUTO_LOCK(m_mutex); return CUtlMemoryPool::Alloc(amount); } + void* AllocZero() { AUTO_LOCK(m_mutex); return CUtlMemoryPool::AllocZero(); } + void* AllocZero(size_t amount) { AUTO_LOCK(m_mutex); return CUtlMemoryPool::AllocZero(amount); } + void Free(void* pMem) { AUTO_LOCK(m_mutex); CUtlMemoryPool::Free(pMem); } + + void Clear() { AUTO_LOCK(m_mutex); return CUtlMemoryPool::Clear(); } +private: + CThreadFastMutex m_mutex; +}; + + +template< class T > +class CClassMemoryPool : public CUtlMemoryPool +{ +public: + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0) : + CUtlMemoryPool(sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment) {} + + T* Alloc(); + T* AllocZero(); + void Free(T* pMem); + + void Clear(); +}; + +template +class CAlignedMemPool +{ + enum + { + BLOCK_SIZE = COMPILETIME_MAX(ALIGN_VALUE(ITEM_SIZE, ALIGNMENT), 8), + }; + +public: + CAlignedMemPool(); + + void* Alloc(); + void Free(void* p); + + static int __cdecl CompareChunk(void* const* ppLeft, void* const* ppRight); + void Compact(); + + int NumTotal() { AUTO_LOCK(m_mutex); return m_Chunks.Count() * (CHUNK_SIZE / BLOCK_SIZE); } + int NumAllocated() { AUTO_LOCK(m_mutex); return NumTotal() - m_nFree; } + int NumFree() { AUTO_LOCK(m_mutex); return m_nFree; } + + int BytesTotal() { AUTO_LOCK(m_mutex); return NumTotal() * BLOCK_SIZE; } + int BytesAllocated() { AUTO_LOCK(m_mutex); return NumAllocated() * BLOCK_SIZE; } + int BytesFree() { AUTO_LOCK(m_mutex); return NumFree() * BLOCK_SIZE; } + + int ItemSize() { return ITEM_SIZE; } + int BlockSize() { return BLOCK_SIZE; } + int ChunkSize() { return CHUNK_SIZE; } + +private: + struct FreeBlock_t + { + FreeBlock_t* pNext; + byte reserved[BLOCK_SIZE - sizeof(FreeBlock_t*)]; + }; + + CUtlVector m_Chunks; + FreeBlock_t* m_pFirstFree; + int m_nFree; + CAllocator m_Allocator; + double m_TimeLastCompact; + + CThreadFastMutex m_mutex; +}; + +template +class CObjectPool +{ +public: + CObjectPool() + { + int i = nInitialCount; + while (i-- > 0) + { + m_AvailableObjects.PushItem(new T); + } + } + + ~CObjectPool() + { + Purge(); + } + + int NumAvailable() + { + return m_AvailableObjects.Count(); + } + + void Purge() + { + T* p = NULL; + while (m_AvailableObjects.PopItem(&p)) + { + delete p; + } + } + + T* GetObject(bool bCreateNewIfEmpty = bDefCreateNewIfEmpty) + { + T* p = NULL; + if (!m_AvailableObjects.PopItem(&p)) + { + p = (bCreateNewIfEmpty) ? new T : NULL; + } + return p; + } + + void PutObject(T* p) + { + m_AvailableObjects.PushItem(p); + } + +private: + CTSList m_AvailableObjects; +}; + +template +class CFixedBudgetMemoryPool +{ +public: + CFixedBudgetMemoryPool() + { + m_pBase = m_pLimit = 0; + COMPILE_TIME_ASSERT(ITEM_SIZE % 4 == 0); + } + + bool Owns(void* p) + { + return (p >= m_pBase && p < m_pLimit); + } + + void* Alloc() + { + MEM_ALLOC_CREDIT_CLASS(); +#ifndef USE_MEM_DEBUG + if (!m_pBase) + { + LOCAL_THREAD_LOCK(); + if (!m_pBase) + { + byte* pMemory = m_pBase = (byte*)malloc(ITEM_COUNT * ITEM_SIZE); + m_pLimit = m_pBase + (ITEM_COUNT * ITEM_SIZE); + + for (int i = 0; i < ITEM_COUNT; i++) + { + m_freeList.Push((TSLNodeBase_t*)pMemory); + pMemory += ITEM_SIZE; + } + } + } + + void* p = m_freeList.Pop(); + if (p) + return p; +#endif + return malloc(ITEM_SIZE); + } + + void Free(void* p) + { +#ifndef USE_MEM_DEBUG + if (Owns(p)) + m_freeList.Push((TSLNodeBase_t*)p); + else +#endif + free(p); + } + + void Clear() + { +#ifndef USE_MEM_DEBUG + if (m_pBase) + { + free(m_pBase); + } + m_pBase = m_pLimit = 0; + Construct(&m_freeList); +#endif + } + + bool IsEmpty() + { +#ifndef USE_MEM_DEBUG + if (m_pBase && m_freeList.Count() != ITEM_COUNT) + return false; +#endif + return true; + } + + enum + { + ITEM_SIZE = ALIGN_VALUE(PROVIDED_ITEM_SIZE, TSLIST_NODE_ALIGNMENT) + }; + + CTSListBase m_freeList; + byte* m_pBase; + byte* m_pLimit; +}; + +#define BIND_TO_FIXED_BUDGET_POOL( poolName ) \ + inline void* operator new( size_t size ) { return poolName.Alloc(); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return poolName.Alloc(); } \ + inline void operator delete( void* p ) { poolName.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { poolName.Free(p); } + + +template< class T > +inline T* CClassMemoryPool::Alloc() +{ + T* pRet; + + { + MEM_ALLOC_CREDIT_CLASS(); + pRet = (T*)CUtlMemoryPool::Alloc(); + } + + if (pRet) + { + Construct(pRet); + } + return pRet; +} + +template< class T > +inline T* CClassMemoryPool::AllocZero() +{ + T* pRet; + + { + MEM_ALLOC_CREDIT_CLASS(); + pRet = (T*)CUtlMemoryPool::AllocZero(); + } + + if (pRet) + { + Construct(pRet); + } + return pRet; +} + +template< class T > +inline void CClassMemoryPool::Free(T* pMem) +{ + if (pMem) + { + Destruct(pMem); + } + + CUtlMemoryPool::Free(pMem); +} + +template< class T > +inline void CClassMemoryPool::Clear() +{ + CUtlRBTree freeBlocks; + SetDefLessFunc(freeBlocks); + + void* pCurFree = m_pHeadOfFreeList; + while (pCurFree != NULL) + { + freeBlocks.Insert(pCurFree); + pCurFree = *((void**)pCurFree); + } + + for (CBlob* pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pCur->m_pNext) + { + int nElements = pCur->m_NumBytes / this->m_BlockSize; + T* p = (T*)AlignValue(pCur->m_Data, this->m_nAlignment); + T* pLimit = p + nElements; + while (p < pLimit) + { + if (freeBlocks.Find(p) == freeBlocks.InvalidIndex()) + { + Destruct(p); + } + p++; + } + } + + CUtlMemoryPool::Clear(); +} + + + + + +#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CUtlMemoryPool s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment ) + +#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CMemoryPoolMT s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void operator delete( void* p ) { s_pAllocator->Free(p); } \ + private: \ + static CUtlMemoryPool* s_pAllocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \ + CUtlMemoryPool* _class::s_pAllocator = _allocator + + +template +inline CAlignedMemPool::CAlignedMemPool() + : m_pFirstFree(0), + m_nFree(0), + m_TimeLastCompact(0) +{ + { COMPILE_TIME_ASSERT(sizeof(FreeBlock_t) >= BLOCK_SIZE); } + { COMPILE_TIME_ASSERT(ALIGN_VALUE(sizeof(FreeBlock_t), ALIGNMENT) == sizeof(FreeBlock_t)); } +} + +template +inline void* CAlignedMemPool::Alloc() +{ + AUTO_LOCK(m_mutex); + + if (!m_pFirstFree) + { + if (!GROWMODE && m_Chunks.Count()) + { + return NULL; + } + + FreeBlock_t* pNew = (FreeBlock_t*)m_Allocator.Alloc(CHUNK_SIZE); + Assert((unsigned)pNew % ALIGNMENT == 0); + m_Chunks.AddToTail(pNew); + m_nFree = CHUNK_SIZE / BLOCK_SIZE; + m_pFirstFree = pNew; + for (int i = 0; i < m_nFree - 1; i++) + { + pNew->pNext = pNew + 1; + pNew++; + } + pNew->pNext = NULL; + } + + void* p = m_pFirstFree; + m_pFirstFree = m_pFirstFree->pNext; + m_nFree--; + + return p; +} + +template +inline void CAlignedMemPool::Free(void* p) +{ + AUTO_LOCK(m_mutex); + + FreeBlock_t* pFree = ((FreeBlock_t*)p); + FreeBlock_t* pCur = m_pFirstFree; + FreeBlock_t* pPrev = NULL; + + while (pCur && pFree > pCur) + { + pPrev = pCur; + pCur = pCur->pNext; + } + + pFree->pNext = pCur; + + if (pPrev) + { + pPrev->pNext = pFree; + } + else + { + m_pFirstFree = pFree; + } + m_nFree++; + + if (m_nFree >= (CHUNK_SIZE / BLOCK_SIZE) * COMPACT_THRESHOLD) + { + double time = Plat_FloatTime(); + double compactTime = (m_nFree >= (CHUNK_SIZE / BLOCK_SIZE) * COMPACT_THRESHOLD * 4) ? 15.0 : 30.0; + if (m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time) + { + Compact(); + m_TimeLastCompact = time; + } + } +} + +template +inline void CAlignedMemPool::Compact() +{ + FreeBlock_t* pCur = m_pFirstFree; + FreeBlock_t* pPrev = NULL; + + m_Chunks.Sort(CompareChunk); + +#ifdef VALIDATE_ALIGNED_MEM_POOL + { + FreeBlock_t* p = m_pFirstFree; + while (p) + { + if (p->pNext && p > p->pNext) + { + __asm { int 3 } + } + p = p->pNext; + } + + for (int i = 0; i < m_Chunks.Count(); i++) + { + if (i + 1 < m_Chunks.Count()) + { + if (m_Chunks[i] > m_Chunks[i + 1]) + { + __asm { int 3 } + } + } + } + } +#endif + + int i; + + for (i = 0; i < m_Chunks.Count(); i++) + { + int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE; + FreeBlock_t* pChunkLimit = ((FreeBlock_t*)m_Chunks[i]) + nBlocksPerChunk; + int nFromChunk = 0; + if (pCur == m_Chunks[i]) + { + FreeBlock_t* pFirst = pCur; + while (pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit) + { + pCur = pCur->pNext; + nFromChunk++; + } + pCur = pFirst; + + } + + while (pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit) + { + if (nFromChunk != nBlocksPerChunk) + { + if (pPrev) + { + pPrev->pNext = pCur; + } + else + { + m_pFirstFree = pCur; + } + pPrev = pCur; + } + else if (pPrev) + { + pPrev->pNext = NULL; + } + else + { + m_pFirstFree = NULL; + } + + pCur = pCur->pNext; + } + + if (nFromChunk == nBlocksPerChunk) + { + m_Allocator.Free(m_Chunks[i]); + m_nFree -= nBlocksPerChunk; + m_Chunks[i] = 0; + } + } + + for (i = m_Chunks.Count() - 1; i >= 0; i--) + { + if (!m_Chunks[i]) + { + m_Chunks.FastRemove(i); + } + } +} + +#endif + +``` + +`SpyCustom/sdk/meshreader.h`: + +```h +#ifndef MESHREADER_H +#define MESHREADER_H + +#ifdef _WIN32 +#pragma once +#endif + + +class CBaseMeshReader : protected MeshDesc_t +{ +public: + + CBaseMeshReader(); + ~CBaseMeshReader(); + + void BeginRead( + IMesh* pMesh, + int firstVertex = 0, + int numVertices = 0, + int firstIndex = 0, + int numIndices = 0); + + void EndRead(); + + void BeginRead_Direct(const MeshDesc_t& desc, int numVertices, int nIndices); + + void Reset(); + + +protected: + IMesh* m_pMesh; + int m_MaxVertices; + int m_MaxIndices; +}; + + +class CMeshReader : public CBaseMeshReader +{ +public: +public: + int NumIndices() const; + unsigned short Index(int index) const; + + const Vector& Position(int iVertex) const; + + unsigned int Color(int iVertex) const; + + const float* TexCoord(int iVertex, int stage) const; + void TexCoord2f(int iVertex, int stage, float& s, float& t) const; + const Vector2D& TexCoordVector2D(int iVertex, int stage) const; + + int NumBoneWeights() const; + float Wrinkle(int iVertex) const; + + const Vector& Normal(int iVertex) const; + void Normal(int iVertex, Vector& vNormal) const; + + const Vector& TangentS(int iVertex) const; + const Vector& TangentT(int iVertex) const; + float BoneWeight(int iVertex) const; + +#ifdef NEW_SKINNING + float* BoneMatrix(int iVertex) const; +#else + unsigned char* BoneMatrix(int iVertex) const; +#endif +}; + + +inline CBaseMeshReader::CBaseMeshReader() +{ + m_pMesh = NULL; +} + +inline CBaseMeshReader::~CBaseMeshReader() +{ + Assert(!m_pMesh); +} + +inline void CBaseMeshReader::BeginRead( + IMesh* pMesh, + int firstVertex, + int numVertices, + int firstIndex, + int numIndices) +{ + Assert(pMesh && (!m_pMesh)); + + if (numVertices < 0) + { + numVertices = pMesh->VertexCount(); + } + + if (numIndices < 0) + { + numIndices = pMesh->IndexCount(); + } + + m_pMesh = pMesh; + m_MaxVertices = numVertices; + m_MaxIndices = numIndices; + + VertexCompressionType_t compressionType = CompressionType(pMesh->GetVertexFormat()); + Assert(compressionType == VERTEX_COMPRESSION_NONE); + if (compressionType != VERTEX_COMPRESSION_NONE) + { + Warning("Cannot use CBaseMeshReader with compressed vertices! Will get junk data or a crash.\n"); + } + + pMesh->ModifyBeginEx(true, firstVertex, numVertices, firstIndex, numIndices, *this); + + Reset(); +} + +inline void CBaseMeshReader::EndRead() +{ + Assert(m_pMesh); + m_pMesh->ModifyEnd(*this); + m_pMesh = NULL; +} + +inline void CBaseMeshReader::BeginRead_Direct(const MeshDesc_t& desc, int nVertices, int nIndices) +{ + MeshDesc_t* pThis = this; + *pThis = desc; + m_MaxVertices = nVertices; + m_MaxIndices = nIndices; + + Assert(desc.m_CompressionType == VERTEX_COMPRESSION_NONE); + if (desc.m_CompressionType != VERTEX_COMPRESSION_NONE) + { + Warning("Cannot use CBaseMeshReader with compressed vertices!\n"); + } +} + +inline void CBaseMeshReader::Reset() +{ +} + + + + +inline int CMeshReader::NumIndices() const +{ + return m_MaxIndices; +} + +inline unsigned short CMeshReader::Index(int index) const +{ + Assert((index >= 0) && (index < m_MaxIndices)); + return m_pIndices[index * m_nIndexSize]; +} + +inline const Vector& CMeshReader::Position(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + return *(Vector*)((char*)m_pPosition + iVertex * m_VertexSize_Position); +} + +inline unsigned int CMeshReader::Color(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + unsigned char* pColor = m_pColor + iVertex * m_VertexSize_Color; + return (pColor[0] << 16) | (pColor[1] << 8) | (pColor[2]) | (pColor[3] << 24); +} + +inline const float* CMeshReader::TexCoord(int iVertex, int iStage) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + return (float*)((char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage]); +} + +inline void CMeshReader::TexCoord2f(int iVertex, int iStage, float& s, float& t) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + float* p = (float*)((char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage]); + s = p[0]; + t = p[1]; +} + +inline const Vector2D& CMeshReader::TexCoordVector2D(int iVertex, int iStage) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + Vector2D* p = (Vector2D*)((char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage]); + return *p; +} + +inline float CMeshReader::Wrinkle(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + return *(float*)((char*)m_pWrinkle + iVertex * m_VertexSize_Wrinkle); +} + +inline int CMeshReader::NumBoneWeights() const +{ + return m_NumBoneWeights; +} + +inline const Vector& CMeshReader::Normal(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + return *(const Vector*)(const float*)((char*)m_pNormal + iVertex * m_VertexSize_Normal); +} + +inline void CMeshReader::Normal(int iVertex, Vector& vNormal) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + const float* p = (const float*)((char*)m_pNormal + iVertex * m_VertexSize_Normal); + vNormal.Init(p[0], p[1], p[2]); +} + +inline const Vector& CMeshReader::TangentS(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + return *(const Vector*)((char*)m_pTangentS + iVertex * m_VertexSize_TangentS); +} + +inline const Vector& CMeshReader::TangentT(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + return *(const Vector*)((char*)m_pTangentT + iVertex * m_VertexSize_TangentT); +} + +inline float CMeshReader::BoneWeight(int iVertex) const +{ + Assert(iVertex >= 0 && iVertex < m_MaxVertices); + float* p = (float*)((char*)m_pBoneWeight + iVertex * m_VertexSize_BoneWeight); + return *p; +} + +#endif + +``` + +`SpyCustom/sdk/meshutils.h`: + +```h +#ifndef MESHUTILS_H +#define MESHUTILS_H + +#ifdef _WIN32 +#pragma once +#endif + + +void GenerateSequentialIndexBuffer(unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex); +void GenerateQuadIndexBuffer(unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex); +void GeneratePolygonIndexBuffer(unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex); +void GenerateLineStripIndexBuffer(unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex); +void GenerateLineLoopIndexBuffer(unsigned short* pIndexMemory, int nIndexCount, int nFirstVertex); + + +#endif +``` + +`SpyCustom/sdk/messagebox.h`: + +```h +#ifndef MESSAGEBOX_H +#define MESSAGEBOX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui.h" +#include "Frame.h" + +#ifdef MessageBox +#undef MessageBox +#endif + +namespace vgui +{ + + class MessageBox : public Frame + { + DECLARE_CLASS_SIMPLE(MessageBox, Frame); + + public: + MessageBox(const char* title, const char* text, Panel* parent = NULL); + MessageBox(const wchar_t* wszTitle, const wchar_t* wszText, Panel* parent = NULL); + ~MessageBox(); + + virtual void DoModal(Frame* pFrameOver = NULL); + + virtual void ShowWindow(Frame* pFrameOver = NULL); + + virtual void SetCommand(const char* command); + virtual void SetCommand(KeyValues* command); + + virtual void SetOKButtonVisible(bool state); + + virtual void SetOKButtonText(const char* buttonText); + virtual void SetOKButtonText(const wchar_t* wszButtonText); + + void SetCancelButtonVisible(bool state); + void SetCancelButtonText(const char* buttonText); + void SetCancelButtonText(const wchar_t* wszButtonText); + void SetCancelCommand(KeyValues* command); + + virtual void DisableCloseButton(bool state); + + virtual void OnCommand(const char* pCommand); + + void ShowMessageBoxOverCursor(bool bEnable); + + protected: + virtual void PerformLayout(); + virtual void ApplySchemeSettings(IScheme* pScheme); + + protected: + Button* m_pOkButton; + Button* m_pCancelButton; + Label* m_pMessageLabel; + + private: + MESSAGE_FUNC(OnShutdownRequest, "ShutdownRequest"); + + void Init(); + + KeyValues* m_OkCommand; + KeyValues* m_CancelCommand; + vgui::Frame* m_pFrameOver; + bool m_bNoAutoClose : 1; + bool m_bShowMessageBoxOverCursor : 1; + }; + +} + + +#endif +``` + +`SpyCustom/sdk/minidump.h`: + +```h +#ifndef MINIDUMP_H +#define MINIDUMP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" + +PLATFORM_INTERFACE void SetMinidumpFilenamePrefix(const char* pszPrefix); + +PLATFORM_INTERFACE void SetMinidumpComment(const char* pszComment); + +PLATFORM_INTERFACE void WriteMiniDump(const char* pszFilenameSuffix = NULL); + +typedef void (*FnWMain)(int, tchar* []); +typedef void (*FnVoidPtrFn)(void*); + +#if defined(_WIN32) && !defined(_X360) + +typedef void (*FnWMain)(int, tchar* []); +typedef int (*FnWMainIntRet)(int, tchar* []); +typedef void (*FnVoidPtrFn)(void*); + +enum ECatchAndWriteMinidumpAction +{ + k_ECatchAndWriteMiniDumpAbort = 0, + k_ECatchAndWriteMiniDumpReThrow = 1, + k_ECatchAndWriteMiniDumpIgnore = 2, +}; + +PLATFORM_INTERFACE void CatchAndWriteMiniDump(FnWMain pfn, int argc, tchar* argv[]); +PLATFORM_INTERFACE void CatchAndWriteMiniDumpForVoidPtrFn(FnVoidPtrFn pfn, void* pv, bool bExitQuietly); + +PLATFORM_INTERFACE void CatchAndWriteMiniDumpEx(FnWMain pfn, int argc, tchar* argv[], ECatchAndWriteMinidumpAction eAction); +PLATFORM_INTERFACE int CatchAndWriteMiniDumpExReturnsInt(FnWMainIntRet pfn, int argc, tchar* argv[], ECatchAndWriteMinidumpAction eAction); +PLATFORM_INTERFACE void CatchAndWriteMiniDumpExForVoidPtrFn(FnVoidPtrFn pfn, void* pv, ECatchAndWriteMinidumpAction eAction); + +struct _EXCEPTION_POINTERS; + +typedef void (*FnMiniDump)(unsigned int uStructuredExceptionCode, _EXCEPTION_POINTERS* pExceptionInfo, const char* pszFilenameSuffix); +PLATFORM_INTERFACE FnMiniDump SetMiniDumpFunction(FnMiniDump pfn); + +PLATFORM_INTERFACE bool WriteMiniDumpUsingExceptionInfo( + unsigned int uStructuredExceptionCode, + _EXCEPTION_POINTERS* pExceptionInfo, + int minidumpType, + const char* pszFilenameSuffix = NULL, + tchar* ptchMinidumpFileNameBuffer = NULL +); + +PLATFORM_INTERFACE void MinidumpSetUnhandledExceptionFunction(FnMiniDump pfn); + +PLATFORM_INTERFACE void EnableCrashingOnCrashes(); + +#endif + +#endif +``` + +`SpyCustom/sdk/modelloader.h`: + +```h +#if !defined( MOD_LOADER_H ) +#define MOD_LOADER_H +#ifdef _WIN32 +#pragma once +#endif + +struct model_t; +class IMaterial; +class IFileList; + + +#include "utlmemory.h" + + +abstract_class IModelLoader +{ +public: + enum REFERENCETYPE + { + FMODELLOADER_NOTLOADEDORREFERENCED = 0, + FMODELLOADER_LOADED = (1 << 0), + + FMODELLOADER_SERVER = (1 << 1), + FMODELLOADER_CLIENT = (1 << 2), + FMODELLOADER_CLIENTDLL = (1 << 3), + FMODELLOADER_STATICPROP = (1 << 4), + FMODELLOADER_DETAILPROP = (1 << 5), + FMODELLOADER_REFERENCEMASK = (FMODELLOADER_SERVER | FMODELLOADER_CLIENT | FMODELLOADER_CLIENTDLL | FMODELLOADER_STATICPROP | FMODELLOADER_DETAILPROP), + + FMODELLOADER_TOUCHED_BY_PRELOAD = (1 << 15), + FMODELLOADER_LOADED_BY_PRELOAD = (1 << 16), + FMODELLOADER_TOUCHED_MATERIALS = (1 << 17), + }; + + enum ReloadType_t + { + RELOAD_LOD_CHANGED = 0, + RELOAD_EVERYTHING, + RELOAD_REFRESH_MODELS, + }; + + virtual void Init(void) = 0; + virtual void Shutdown(void) = 0; + + virtual int GetCount(void) = 0; + virtual model_t* GetModelForIndex(int i) = 0; + + virtual const char* GetName(const model_t* model) = 0; + + virtual void* GetExtraData(model_t* model) = 0; + + virtual int GetModelFileSize(const char* name) = 0; + + virtual model_t* GetModelForName(const char* name, REFERENCETYPE referencetype) = 0; + virtual model_t* ReferenceModel(const char* name, REFERENCETYPE referencetype) = 0; + virtual void UnreferenceModel(model_t* model, REFERENCETYPE referencetype) = 0; + virtual void UnreferenceAllModels(REFERENCETYPE referencetype) = 0; + + virtual void UnloadUnreferencedModels(void) = 0; + virtual void PurgeUnusedModels(void) = 0; + + virtual bool Map_GetRenderInfoAllocated(void) = 0; + virtual void Map_SetRenderInfoAllocated(bool allocated) = 0; + + virtual void Map_LoadDisplacements(model_t* model, bool bRestoring) = 0; + + virtual void Print(void) = 0; + + virtual bool Map_IsValid(char const* mapname) = 0; + + virtual void RecomputeSurfaceFlags(model_t* mod) = 0; + + virtual void Studio_ReloadModels(ReloadType_t reloadType) = 0; + + virtual bool IsLoaded(const model_t* mod) = 0; + + virtual bool LastLoadedMapHasHDRLighting(void) = 0; + + virtual void ReloadFilesInList(IFileList* pFilesToReload) = 0; + + virtual const char* GetActiveMapName(void) = 0; +}; + +extern IModelLoader* modelloader; + +class CMapLoadHelper +{ +public: + CMapLoadHelper(int lumpToLoad); + ~CMapLoadHelper(void); + + byte* LumpBase(void); + int LumpSize(void); + int LumpOffset(void); + int LumpVersion() const; + const char* GetMapName(void); + char* GetLoadName(void); + char* GetDiskName(void); + struct worldbrushdata_t* GetMap(void); + + static void Init(model_t* pMapModel, const char* pLoadname); + static void InitFromMemory(model_t* pMapModel, const void* pData, int nDataSize); + static void Shutdown(void); + static int GetRefCount(void); + + static void FreeLightingLump(); + + static int LumpSize(int lumpId); + static int LumpOffset(int lumpId); + + void LoadLumpElement(int nElemIndex, int nElemSize, void* pData); + void LoadLumpData(int offset, int size, void* pData); + +private: + int m_nLumpSize; + int m_nLumpOffset; + int m_nLumpVersion; + byte* m_pRawData; + byte* m_pData; + byte* m_pUncompressedData; + + int m_nLumpID; + char m_szLumpFilename[MAX_PATH]; +}; + +void Mod_RecomputeTranslucency(model_t* mod, int nSkin, int nBody, void * pClientRenderable); + +int Mod_GameLumpSize(int lumpId); +int Mod_GameLumpVersion(int lumpId); +bool Mod_LoadGameLump(int lumpId, void* pBuffer, int size); + +int Mod_GetMaterialCount(model_t* mod); + +int Mod_GetModelMaterials(model_t* mod, int count, IMaterial** ppMaterial); + +bool Mod_MarkWaterSurfaces(model_t* pModel); + +void ConnectMDLCacheNotify(); +void DisconnectMDLCacheNotify(); + +void InitStudioModelState(model_t* pModel); + +char* GetMapNameOnDisk(char* pDiskName, const char* pFullMapName, unsigned int nDiskNameSize); + +extern bool g_bLoadedMapHasBakedPropLighting; +extern bool g_bBakedPropLightingNoSeparateHDR; + +#endif +``` + +`SpyCustom/sdk/modes.h`: + +```h +#if !defined( MODES_H ) +#define MODES_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct vmode_s +{ + int width; + int height; + int bpp; + int refreshRate; +} vmode_t; + +#endif +``` + +`SpyCustom/sdk/mouthinfo.h`: + +```h +#if !defined( MOUTHINFO_H ) +#define MOUTHINFO_H +#ifdef _WIN32 +#pragma once +#endif + +class CAudioSource; + +#pragma pack(push,4) +class CVoiceData +{ +public: + CVoiceData(void) + { + m_flElapsed = 0.0f; + m_pAudioSource = NULL; + m_bIgnorePhonemes = false; + } + + void SetElapsedTime(float t) + { + m_flElapsed = t; + } + + float GetElapsedTime() const + { + return m_flElapsed; + } + + void SetSource(CAudioSource* source, bool bIgnorePhonemes) + { + m_pAudioSource = source; + m_bIgnorePhonemes = bIgnorePhonemes; + } + + bool ShouldIgnorePhonemes() const + { + return m_bIgnorePhonemes; + } + + CAudioSource* GetSource() + { + return m_pAudioSource; + } + +private: + float m_flElapsed; + CAudioSource* m_pAudioSource; + bool m_bIgnorePhonemes; +}; + +#define UNKNOWN_VOICE_SOURCE -1 + +class CMouthInfo +{ +public: + byte mouthopen; + byte sndcount; + int sndavg; + +public: + CMouthInfo(void) { m_nVoiceSources = 0; m_needsEnvelope = false; } + virtual ~CMouthInfo(void) { ClearVoiceSources(); } + + int GetNumVoiceSources(void); + CVoiceData* GetVoiceSource(int number); + + void ClearVoiceSources(void); + int GetIndexForSource(CAudioSource* source); + bool IsSourceReferenced(CAudioSource* source); + + CVoiceData* AddSource(CAudioSource* source, bool bIgnorePhonemes); + + void RemoveSource(CAudioSource* source); + void RemoveSourceByIndex(int index); + + bool IsActive(void); + bool NeedsEnvelope() { return m_needsEnvelope != 0; } + void ActivateEnvelope() { m_needsEnvelope = true; } + +private: + enum + { + MAX_VOICE_DATA = 4 + }; + + short m_nVoiceSources; + short m_needsEnvelope; + CVoiceData m_VoiceSources[MAX_VOICE_DATA]; +}; +#pragma pack(pop) + + +inline bool CMouthInfo::IsActive(void) +{ + return (GetNumVoiceSources() > 0) ? true : false; +} + +inline int CMouthInfo::GetNumVoiceSources(void) +{ + return m_nVoiceSources; +} + +inline CVoiceData* CMouthInfo::GetVoiceSource(int number) +{ + if (number < 0 || number >= m_nVoiceSources) + return NULL; + + return &m_VoiceSources[number]; +} + +inline void CMouthInfo::ClearVoiceSources(void) +{ + m_nVoiceSources = 0; +} + +inline int CMouthInfo::GetIndexForSource(CAudioSource* source) +{ + for (int i = 0; i < m_nVoiceSources; i++) + { + CVoiceData* v = &m_VoiceSources[i]; + if (!v) + continue; + + if (v->GetSource() == source) + return i; + } + + return UNKNOWN_VOICE_SOURCE; +} + +inline bool CMouthInfo::IsSourceReferenced(CAudioSource* source) +{ + if (GetIndexForSource(source) != UNKNOWN_VOICE_SOURCE) + return true; + + return false; +} + +inline void CMouthInfo::RemoveSource(CAudioSource* source) +{ + int idx = GetIndexForSource(source); + if (idx == UNKNOWN_VOICE_SOURCE) + return; + + RemoveSourceByIndex(idx); +} + +inline void CMouthInfo::RemoveSourceByIndex(int index) +{ + if (index < 0 || index >= m_nVoiceSources) + return; + + m_VoiceSources[index] = m_VoiceSources[--m_nVoiceSources]; +} + +inline CVoiceData* CMouthInfo::AddSource(CAudioSource* source, bool bIgnorePhonemes) +{ + int idx = GetIndexForSource(source); + if (idx == UNKNOWN_VOICE_SOURCE) + { + if (m_nVoiceSources < MAX_VOICE_DATA) + { + idx = m_nVoiceSources++; + } + else + { + return NULL; + } + } + + CVoiceData* data = &m_VoiceSources[idx]; + data->SetSource(source, bIgnorePhonemes); + data->SetElapsedTime(0.0f); + return data; +} + +#endif +``` + +`SpyCustom/sdk/netmessages.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef NETMESSAGES_H +#define NETMESSAGES_H + +#ifdef _WIN32 +#pragma once +#pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +#include "inetmessage.h" +#include "checksum_crc.h" +#include "checksum_md5.h" +#include "const.h" +#include "utlvector.h" +#include "qlimits.h" +#include "vector.h" +#include "soundflags.h" +#include "bitbuf.h" +#include "inetchannel.h" +#include "protocol.h" +#include "inetmsghandler.h" +#include "igameevents.h" +#include "bitvec.h" +#include "inetworksystem.h" +//#include "iserverplugin.h" +//#include "color.h" +#include "tslist.h" +#include "utldelegate.h" +#include "utlstring.h" +#include "tokenset.h" +#include "netmessages_signon.h" + +// eliminates a conflict with TYPE_BOOL in OSX +#ifdef TYPE_BOOL +#undef TYPE_BOOL +#endif + +//#include "netmessages.pb.h" +//https://github.com/pmrowla/hl2sdk-csgo/blob/master/public/engine/protobuf/netmessages.pb.h + + +#include + +template< int msgType, typename PB_OBJECT_TYPE, int groupType = INetChannelInfo::GENERIC, bool bReliable = true > +class CNetMessagePB : public INetMessage, public PB_OBJECT_TYPE +{ +public: + typedef CNetMessagePB< msgType, PB_OBJECT_TYPE, groupType, bReliable > MyType_t; + typedef PB_OBJECT_TYPE PBType_t; + static const int sk_Type = msgType; + + CNetMessagePB() : + m_bReliable( bReliable ) + { + } + + virtual ~CNetMessagePB() + { + } + + virtual bool ReadFromBuffer( bf_read &buffer ) + { + int size = buffer.ReadVarInt32(); + if ( size < 0 || size > NET_MAX_PAYLOAD ) + { + return false; + } + + // Check its valid + if ( size > buffer.GetNumBytesLeft() ) + { + return false; + } + + // If the read buffer is byte aligned, we can parse right out of it + if ( ( buffer.GetNumBitsRead() % 8 ) == 0 ) + { + bool parseResult = PB_OBJECT_TYPE::ParseFromArray( buffer.GetBasePointer() + buffer.GetNumBytesRead(), size ); + buffer.SeekRelative( size * 8 ); + return parseResult; + } + + // otherwise we have to do a temp allocation so we can read it all shifted +#ifdef NET_SHOW_UNALIGNED_MSGS + DevMsg("Warning: unaligned read of protobuf message %s (%d bytes)\n", PB_OBJECT_TYPE::GetTypeName().c_str(), size ); +#endif + + void *parseBuffer = stackalloc( size ); + if ( !buffer.ReadBytes( parseBuffer, size ) ) + { + return false; + } + + if ( ! PB_OBJECT_TYPE::ParseFromArray( parseBuffer, size ) ) + { + return false; + } + + return true; + } + + virtual bool WriteToBuffer( bf_write &buffer ) const + { + if ( !PB_OBJECT_TYPE::IsInitialized() ) + { + Msg("WriteToBuffer Message %s is not initialized! Probably missing required fields!\n", PB_OBJECT_TYPE::GetTypeName().c_str() ); + } + + int size = PB_OBJECT_TYPE::ByteSize(); + + // If the write is byte aligned we can go direct + if ( ( buffer.GetNumBitsWritten() % 8 ) == 0 ) + { + int sizeWithHeader = size + 1 + buffer.ByteSizeVarInt32( GetType() ) + buffer.ByteSizeVarInt32( size ); + + if ( buffer.GetNumBytesLeft() >= sizeWithHeader ) + { + buffer.WriteVarInt32( GetType() ); + buffer.WriteVarInt32( size ); + + if ( !PB_OBJECT_TYPE::SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )buffer.GetData() + buffer.GetNumBytesWritten() ) ) + { + return false; + } + + // Tell the buffer we just splatted into it + buffer.SeekToBit( buffer.GetNumBitsWritten() + ( size * 8 ) ); + return true; + } + + // Won't fit + return false; + } + + // otherwise we have to do a temp allocation so we can write it all shifted +#ifdef NET_SHOW_UNALIGNED_MSGS + DevMsg("Warning: unaligned write of protobuf message %s (%d bytes)\n", PB_OBJECT_TYPE::GetTypeName().c_str(), size ); +#endif + + void *serializeBuffer = stackalloc( size ); + + if ( ! PB_OBJECT_TYPE::SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )serializeBuffer ) ) + { + return false; + } + + buffer.WriteVarInt32( GetType() ); + buffer.WriteVarInt32( size ); + return buffer.WriteBytes( serializeBuffer, size ); + } + + virtual const char *ToString() const + { + m_toString = PB_OBJECT_TYPE::DebugString(); + return m_toString.c_str(); + } + + virtual int GetType() const + { + return msgType; + } + + virtual size_t GetSize() const + { + return sizeof( *this ); + } + + virtual const char *GetName() const + { + if ( s_typeName.empty() ) + { + s_typeName = PB_OBJECT_TYPE::GetTypeName(); + } + return s_typeName.c_str(); + } + + virtual int GetGroup() const + { + return groupType; + } + + virtual void SetReliable( bool state ) + { + m_bReliable = state; + } + + virtual bool IsReliable() const + { + return m_bReliable; + } + + virtual INetMessage *Clone() const + { + MyType_t *pClone = new MyType_t; + pClone->CopyFrom( *this ); + pClone->m_bReliable = m_bReliable; + + return pClone; + } + +protected: + bool m_bReliable; // true if message should be sent reliable + mutable std::string m_toString; // cached copy of ToString() + static std::string s_typeName; +}; + +template< int msgType, typename PB_OBJECT_TYPE, int groupType , bool bReliable > +std::string CNetMessagePB< msgType, PB_OBJECT_TYPE, groupType , bReliable >::s_typeName; + +class CNetMessageBinder +{ +public: + CNetMessageBinder() + : m_pBind( NULL ) + { + } + + ~CNetMessageBinder() + { + delete m_pBind; + } + + template< class _N > + void Bind( INetChannel *pNetChannel, CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > handler ) + { + delete m_pBind; + m_pBind = new BindParams<_N>( pNetChannel, handler ); + } + + void Unbind() + { + delete m_pBind; + m_pBind = NULL; + } + + bool IsBound() const + { + return m_pBind != NULL; + } + +private: + template < class _N > + struct BindParams : public INetMessageBinder + { + BindParams( INetChannel *pNetChannel, CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > handler ) + : m_NetChannel( pNetChannel ) + , m_handler( handler ) + { + if ( m_NetChannel ) + { + m_NetChannel->RegisterMessage( this ); + } + } + + virtual ~BindParams() + { + if ( m_NetChannel ) + { + m_NetChannel->UnregisterMessage( this ); + } + } + + virtual int GetType( void ) const + { + return _N::sk_Type; + } + + virtual void SetNetChannel(INetChannel * netchan) + { + if( m_NetChannel != netchan ) + { + if( m_NetChannel ) + m_NetChannel->UnregisterMessage( this ); + + m_NetChannel = netchan; + + if( m_NetChannel ) + m_NetChannel->RegisterMessage( this ); + } + } + + virtual INetMessage *CreateFromBuffer( bf_read &buffer ) + { + INetMessage *pMsg = new typename _N::MyType_t; + if ( !pMsg->ReadFromBuffer( buffer ) ) + { + delete pMsg; + return NULL; + } + return pMsg; + } + + virtual bool Process( const INetMessage &src ) + { + const typename _N::MyType_t &typedSrc = static_cast< const typename _N::MyType_t & >( src ); + + Assert( m_handler ); + if( m_handler ) + { + return m_handler( static_cast< typename _N::PBType_t const & >( typedSrc ) ); + } + return false; + } + + INetChannel *m_NetChannel; // netchannel this message is from/for + CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > m_handler; + }; + + INetMessageBinder *m_pBind; +}; + +/////////////////////////////////////////////////////////////////////////////////////// +// bidirectional net messages: +/////////////////////////////////////////////////////////////////////////////////////// + +class CNETMsg_Tick_t : public CNetMessagePB< net_Tick, CNETMsg_Tick > +{ +public: + static float FrametimeToFloat( uint32 frametime ) { return ( float )frametime / 1000000.0f; } + + CNETMsg_Tick_t( int tick, float host_computationtime, float host_computationtime_stddeviation, float host_framestarttime_std_deviation ) + { + SetReliable( false ); + set_tick( tick ); + set_host_computationtime( MIN( ( uint32 )( 1000000.0 * host_computationtime ), 1000000u ) ); + set_host_computationtime_std_deviation( MIN( ( uint32 )( 1000000.0 * host_computationtime_stddeviation ), 1000000u ) ); + set_host_framestarttime_std_deviation( MIN( ( uint32 )( 1000000.0 * host_framestarttime_std_deviation ), 1000000u ) ); + } +}; + +class CNETMsg_StringCmd_t : public CNetMessagePB< net_StringCmd, CNETMsg_StringCmd, INetChannelInfo::STRINGCMD > +{ +public: + CNETMsg_StringCmd_t( const char *command ) + { + set_command( command ); + } +}; + +class CNETMsg_PlayerAvatarData_t : public CNetMessagePB< net_PlayerAvatarData, CNETMsg_PlayerAvatarData, INetChannelInfo::PAINTMAP > +{ + // 12 KB player avatar 64x64 rgb only no alpha + // WARNING-WARNING-WARNING + // This message is extremely large for our net channels + // and must be pumped through special fragmented waiting list + // via chunk-based ack mechanism! + // See: INetChannel::EnqueueVeryLargeAsyncTransfer + // WARNING-WARNING-WARNING +public: + CNETMsg_PlayerAvatarData_t() {} + CNETMsg_PlayerAvatarData_t( uint32 unAccountID, void const *pvData, uint32 cbData ) + { + set_accountid( unAccountID ); + set_rgb( ( const char * ) pvData, cbData ); + } +}; + +class CNETMsg_SignonState_t : public CNetMessagePB< net_SignonState, CNETMsg_SignonState, INetChannelInfo::SIGNON > +{ +public: + CNETMsg_SignonState_t( int state, int spawncount ) + { + set_signon_state( state ); + set_spawn_count( spawncount ); + set_num_server_players( 0 ); + } +}; + +inline void NetMsgSetCVarUsingDictionary( CMsg_CVars::CVar *convar, char const * name, char const * value ) +{ + convar->set_value( value ); + + if ( 0 ) ( void ) 0; + /** Removed for partner depot **/ + else + { +#ifdef _DEBUG + DevWarning( "Missing dictionary entry for cvar '%s'\n", name ); +#endif + convar->set_name( name ); + } +} + +inline void NetMsgExpandCVarUsingDictionary( CMsg_CVars::CVar *convar ) +{ + if ( convar->has_name() ) + return; + switch ( convar->dictionary_name() ) + { + case 0: return; + /** Removed for partner depot **/ + default: + DevWarning( "Invalid dictionary entry for cvar # %d\n", convar->dictionary_name() ); + convar->set_name( "undefined" ); + break; + } +} + +inline const char * NetMsgGetCVarUsingDictionary( CMsg_CVars::CVar const &convar ) +{ + if ( convar.has_name() ) + return convar.name().c_str(); + switch ( convar.dictionary_name() ) + { + case 0: return ""; + /** Removed for partner depot **/ +default: + DevWarning( "Invalid dictionary entry for cvar # %d\n", convar.dictionary_name() ); + return "undefined"; + } +} + +class CNETMsg_SetConVar_t : public CNetMessagePB< net_SetConVar, CNETMsg_SetConVar, INetChannelInfo::STRINGCMD > +{ +public: + CNETMsg_SetConVar_t() {} + CNETMsg_SetConVar_t( const char * name, const char * value ) + { + AddToTail( name, value ); + } + void AddToTail( const char * name, const char * value ) + { + NetMsgSetCVarUsingDictionary( mutable_convars()->add_cvars(), name, value ); + } +}; + +typedef CNetMessagePB< net_NOP, CNETMsg_NOP > CNETMsg_NOP_t; +typedef CNetMessagePB< net_Disconnect, CNETMsg_Disconnect > CNETMsg_Disconnect_t; +typedef CNetMessagePB< net_File, CNETMsg_File > CNETMsg_File_t; +typedef CNetMessagePB< net_SplitScreenUser, CNETMsg_SplitScreenUser > CNETMsg_SplitScreenUser_t; + +/////////////////////////////////////////////////////////////////////////////////////// +// Client messages: Sent from the client to the server +/////////////////////////////////////////////////////////////////////////////////////// + +typedef CNetMessagePB< clc_SplitPlayerConnect, CCLCMsg_SplitPlayerConnect > CCLCMsg_SplitPlayerConnect_t; +typedef CNetMessagePB< clc_Move, CCLCMsg_Move, INetChannelInfo::MOVE, false > CCLCMsg_Move_t; +typedef CNetMessagePB< clc_ClientInfo, CCLCMsg_ClientInfo > CCLCMsg_ClientInfo_t; +typedef CNetMessagePB< clc_VoiceData, CCLCMsg_VoiceData, INetChannelInfo::VOICE, false > CCLCMsg_VoiceData_t; +typedef CNetMessagePB< clc_BaselineAck, CCLCMsg_BaselineAck > CCLCMsg_BaselineAck_t; +typedef CNetMessagePB< clc_ListenEvents, CCLCMsg_ListenEvents > CCLCMsg_ListenEvents_t; +typedef CNetMessagePB< clc_RespondCvarValue, CCLCMsg_RespondCvarValue > CCLCMsg_RespondCvarValue_t; +typedef CNetMessagePB< clc_LoadingProgress, CCLCMsg_LoadingProgress > CCLCMsg_LoadingProgress_t; +typedef CNetMessagePB< clc_CmdKeyValues, CCLCMsg_CmdKeyValues > CCLCMsg_CmdKeyValues_t; +typedef CNetMessagePB< clc_HltvReplay, CCLCMsg_HltvReplay > CCLCMsg_HltvReplay_t; + +class CCLCMsg_FileCRCCheck_t : public CNetMessagePB< clc_FileCRCCheck, CCLCMsg_FileCRCCheck > +{ +public: + // Warning: These routines may use the va() function... + static void SetPath( CCLCMsg_FileCRCCheck& msg, const char *path ); + static const char *GetPath( const CCLCMsg_FileCRCCheck& msg ); + static void SetFileName( CCLCMsg_FileCRCCheck& msg, const char *fileName ); + static const char *GetFileName( const CCLCMsg_FileCRCCheck& msg ); +}; + +/////////////////////////////////////////////////////////////////////////////////////// +// Server messages: Sent from the server to the client +/////////////////////////////////////////////////////////////////////////////////////// + +typedef CNetMessagePB< svc_ServerInfo, CSVCMsg_ServerInfo, INetChannelInfo::SIGNON > CSVCMsg_ServerInfo_t; +typedef CNetMessagePB< svc_ClassInfo, CSVCMsg_ClassInfo, INetChannelInfo::SIGNON > CSVCMsg_ClassInfo_t; +typedef CNetMessagePB< svc_SendTable, CSVCMsg_SendTable, INetChannelInfo::SIGNON > CSVCMsg_SendTable_t; +typedef CNetMessagePB< svc_Print, CSVCMsg_Print, INetChannelInfo::GENERIC, false > CSVCMsg_Print_t; +typedef CNetMessagePB< svc_SetPause, CSVCMsg_SetPause > CSVCMsg_SetPause_t; +typedef CNetMessagePB< svc_SetView, CSVCMsg_SetView > CSVCMsg_SetView_t; +typedef CNetMessagePB< svc_CreateStringTable, CSVCMsg_CreateStringTable, INetChannelInfo::SIGNON > CSVCMsg_CreateStringTable_t; +typedef CNetMessagePB< svc_UpdateStringTable, CSVCMsg_UpdateStringTable, INetChannelInfo::STRINGTABLE > CSVCMsg_UpdateStringTable_t; +typedef CNetMessagePB< svc_VoiceInit, CSVCMsg_VoiceInit, INetChannelInfo::SIGNON > CSVCMsg_VoiceInit_t; +typedef CNetMessagePB< svc_VoiceData, CSVCMsg_VoiceData, INetChannelInfo::VOICE, false > CSVCMsg_VoiceData_t; +typedef CNetMessagePB< svc_FixAngle, CSVCMsg_FixAngle, INetChannelInfo::GENERIC, false > CSVCMsg_FixAngle_t; +typedef CNetMessagePB< svc_Prefetch, CSVCMsg_Prefetch, INetChannelInfo::SOUNDS > CSVCMsg_Prefetch_t; +typedef CNetMessagePB< svc_CrosshairAngle, CSVCMsg_CrosshairAngle > CSVCMsg_CrosshairAngle_t; +typedef CNetMessagePB< svc_BSPDecal, CSVCMsg_BSPDecal > CSVCMsg_BSPDecal_t; +typedef CNetMessagePB< svc_SplitScreen, CSVCMsg_SplitScreen > CSVCMsg_SplitScreen_t; +typedef CNetMessagePB< svc_GetCvarValue, CSVCMsg_GetCvarValue > CSVCMsg_GetCvarValue_t; +typedef CNetMessagePB< svc_Menu, CSVCMsg_Menu, INetChannelInfo::GENERIC, false > CSVCMsg_Menu_t; +typedef CNetMessagePB< svc_UserMessage, CSVCMsg_UserMessage, INetChannelInfo::USERMESSAGES, false > CSVCMsg_UserMessage_t; +typedef CNetMessagePB< svc_PaintmapData, CSVCMsg_PaintmapData, INetChannelInfo::PAINTMAP > CSVCMsg_PaintmapData_t; +typedef CNetMessagePB< svc_GameEvent, CSVCMsg_GameEvent, INetChannelInfo::EVENTS > CSVCMsg_GameEvent_t; +typedef CNetMessagePB< svc_GameEventList, CSVCMsg_GameEventList > CSVCMsg_GameEventList_t; +typedef CNetMessagePB< svc_TempEntities, CSVCMsg_TempEntities, INetChannelInfo::TEMPENTS, false > CSVCMsg_TempEntities_t; +typedef CNetMessagePB< svc_PacketEntities, CSVCMsg_PacketEntities, INetChannelInfo::ENTITIES > CSVCMsg_PacketEntities_t; +typedef CNetMessagePB< svc_Sounds, CSVCMsg_Sounds, INetChannelInfo::SOUNDS > CSVCMsg_Sounds_t; +typedef CNetMessagePB< svc_EntityMessage, CSVCMsg_EntityMsg, INetChannelInfo::ENTMESSAGES, false > CSVCMsg_EntityMsg_t; +typedef CNetMessagePB< svc_CmdKeyValues, CSVCMsg_CmdKeyValues > CSVCMsg_CmdKeyValues_t; +typedef CNetMessagePB< svc_EncryptedData, CSVCMsg_EncryptedData, INetChannelInfo::ENCRYPTED > CSVCMsg_EncryptedData_t; +typedef CNetMessagePB< svc_HltvReplay, CSVCMsg_HltvReplay, INetChannelInfo::ENTITIES > CSVCMsg_HltvReplay_t; +typedef CNetMessagePB< svc_Broadcast_Command, CSVCMsg_Broadcast_Command, INetChannelInfo::STRINGCMD > CSVCMsg_Broadcast_Command_t; + + +/////////////////////////////////////////////////////////////////////////////////////// +// Utility classes +/////////////////////////////////////////////////////////////////////////////////////// + +class CmdKeyValuesHelper +{ +public: + + static void CLCMsg_SetKeyValues( CCLCMsg_CmdKeyValues& msg, const KeyValues *keyValues ); + static KeyValues* CLCMsg_GetKeyValues ( const CCLCMsg_CmdKeyValues& msg ); + + static void SVCMsg_SetKeyValues( CSVCMsg_CmdKeyValues& msg, const KeyValues *keyValues ); + static KeyValues *SVCMsg_GetKeyValues ( const CSVCMsg_CmdKeyValues& msg ); +}; + +class INetChannel; +class CmdEncryptedDataMessageCodec +{ +public: + static bool SVCMsg_EncryptedData_EncryptMessage( CSVCMsg_EncryptedData_t &msgEncryptedResult, INetMessage *pMsgPlaintextInput, char const *key ); + static bool SVCMsg_EncryptedData_Process( CSVCMsg_EncryptedData const &msgEncryptedInput, INetChannel *pProcessingChannel, char const *key ); +}; + +////////////////////////////////////////////////////////////////////////// +// Helper class to share network buffers in the entire process +////////////////////////////////////////////////////////////////////////// + +class net_scratchbuffer_t +{ +public: + net_scratchbuffer_t() + { + m_pBufferNetMaxMessage = sm_NetScratchBuffers.Get(); + if ( !m_pBufferNetMaxMessage ) + m_pBufferNetMaxMessage = new buffer_t; + } + ~net_scratchbuffer_t() + { + sm_NetScratchBuffers.PutObject( m_pBufferNetMaxMessage ); + } + byte * GetBuffer() const + { + return m_pBufferNetMaxMessage->buf; + } + int Size() const + { + return NET_MAX_MESSAGE; + } + +private: + struct buffer_t { byte buf[ NET_MAX_MESSAGE ]; }; + buffer_t *m_pBufferNetMaxMessage; // buffer that is allocated and returned to shared pool + +private: + net_scratchbuffer_t( const net_scratchbuffer_t& ); // FORBID + net_scratchbuffer_t& operator=( const net_scratchbuffer_t& ); // FORBID + static CTSPool< buffer_t > sm_NetScratchBuffers; +}; + +#endif // NETMESSAGES_H +``` + +`SpyCustom/sdk/networkstringtabledefs.h`: + +```h +#ifndef NETWORKSTRINGTABLEDEFS_H +#define NETWORKSTRINGTABLEDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +typedef int TABLEID; + +#define INVALID_STRING_TABLE -1 +const unsigned short INVALID_STRING_INDEX = (unsigned short)-1; + +#define MAX_TABLES 32 + +#define INTERFACENAME_NETWORKSTRINGTABLESERVER "VEngineServerStringTable001" +#define INTERFACENAME_NETWORKSTRINGTABLECLIENT "VEngineClientStringTable001" + +class INetworkStringTable; + +typedef void (*pfnStringChanged)(void* object, INetworkStringTable* stringTable, int stringNumber, char const* newString, void const* newData); + +class INetworkStringTable +{ +public: + + virtual ~INetworkStringTable(void) {}; + + virtual const char* GetTableName(void) const = 0; + virtual TABLEID GetTableId(void) const = 0; + virtual int GetNumStrings(void) const = 0; + virtual int GetMaxStrings(void) const = 0; + virtual int GetEntryBits(void) const = 0; + + virtual void SetTick(int tick) = 0; + virtual bool ChangedSinceTick(int tick) const = 0; + + virtual int AddString(bool bIsServer, const char* value, int length = -1, const void* userdata = 0) = 0; + + virtual const char* GetString(int stringNumber) = 0; + virtual void SetStringUserData(int stringNumber, int length, const void* userdata) = 0; + virtual const void* GetStringUserData(int stringNumber, int* length) = 0; + virtual int FindStringIndex(char const* string) = 0; + + virtual void SetStringChangedCallback(void* object, pfnStringChanged changeFunc) = 0; +}; + +class INetworkStringTableContainer +{ +public: + + virtual ~INetworkStringTableContainer(void) {}; + + virtual INetworkStringTable* CreateStringTable(const char* tableName, int maxentries, int userdatafixedsize = 0, int userdatanetworkbits = 0) = 0; + virtual void RemoveAllTables(void) = 0; + + virtual INetworkStringTable* FindTable(const char* tableName) const = 0; + virtual INetworkStringTable* GetTable(TABLEID stringTable) const = 0; + virtual int GetNumTables(void) const = 0; + + virtual INetworkStringTable* CreateStringTableEx(const char* tableName, int maxentries, int userdatafixedsize = 0, int userdatanetworkbits = 0, bool bIsFilenames = false) = 0; + virtual void SetAllowClientSideAddString(INetworkStringTable* table, bool bAllowClientSideAddString) = 0; +}; + +#endif +``` + +`SpyCustom/sdk/networkvar.h`: + +```h +#ifndef NETWORKVAR_H +#define NETWORKVAR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "dbg.h" +#include "convar.h" + +#if defined( CLIENT_DLL ) || defined( GAME_DLL ) +#include "basehandle.h" +#endif + + +#pragma warning( disable : 4284 ) + +#define MyOffsetOf( type, var ) ( (int)&((type*)0)->var ) + +#ifdef _DEBUG +extern bool g_bUseNetworkVars; +#define CHECK_USENETWORKVARS if(g_bUseNetworkVars) +#else +#define CHECK_USENETWORKVARS +#endif + +// +// Networkvar flags. +// +#define NETWORKVAR_IS_A_VECTOR 0x0001 // Is it any type of network vector? +#define NETWORKVAR_VECTOR_XYZ_FLAG 0x0002 // Is it a CNetworkVectorXYZ? +#define NETWORKVAR_VECTOR_XY_SEPARATEZ_FLAG 0x0004 // Is it a CNetworkVectorXY_SeparateZ? + +#define NETWORKVAR_ALL_FLAGS ( NETWORKVAR_IS_A_VECTOR | NETWORKVAR_VECTOR_XYZ_FLAG | NETWORKVAR_VECTOR_XY_SEPARATEZ_FLAG ) + + + +// network vars use memcmp when fields are set. To ensure proper behavior your +// object's memory should be initialized to zero. This happens for entities automatically +// use this for other classes. +class CMemZeroOnNew +{ +public: + void* operator new(size_t nSize) + { + void* pMem = MemAlloc_Alloc(nSize); + V_memset(pMem, 0, nSize); + return pMem; + } + + void* operator new(size_t nSize, int nBlockUse, const char* pFileName, int nLine) + { + void* pMem = MemAlloc_Alloc(nSize, pFileName, nLine); + V_memset(pMem, 0, nSize); + return pMem; + } + + void operator delete(void* pData) + { + if (pData) + { + g_pMemAlloc->Free(pData); + } + } + + void operator delete(void* pData, int nBlockUse, const char* pFileName, int nLine) + { + if (pData) + { + g_pMemAlloc->Free(pData, pFileName, nLine); + } + } +}; + +inline int InternalCheckDeclareClass(const char* pClassName, const char* pClassNameMatch, void* pTestPtr, void* pBasePtr) +{ + Assert(pTestPtr == pBasePtr); + + Assert((void*)pClassName == (void*)pClassNameMatch); + return 0; +} + + +template +inline int CheckDeclareClass_Access(T*, const char* pShouldBe) +{ + return T::CheckDeclareClass(pShouldBe); +} + +#ifndef _STATIC_LINKED +#ifdef _MSC_VER +#if defined(_DEBUG) && (_MSC_VER > 1200 ) +#define VALIDATE_DECLARE_CLASS 1 +#endif +#endif +#endif + +#ifdef VALIDATE_DECLARE_CLASS + +#define DECLARE_CLASS( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ + template friend int CheckDeclareClass_Access(T *, const char *pShouldBe); \ + static int CheckDeclareClass( const char *pShouldBe ) \ + { \ + InternalCheckDeclareClass( pShouldBe, #className, (ThisClass*)0xFFFFF, (BaseClass*)(ThisClass*)0xFFFFF ); \ + return CheckDeclareClass_Access( (BaseClass *)NULL, #baseClassName ); \ + } + +#define DECLARE_CLASS_GAMEROOT( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; \ + template friend int CheckDeclareClass_Access(T *, const char *pShouldBe); \ + static int CheckDeclareClass( const char *pShouldBe ) \ + { \ + return InternalCheckDeclareClass( pShouldBe, #className, (ThisClass*)0xFFFFF, (BaseClass*)(ThisClass*)0xFFFFF ); \ + } + +#define DECLARE_CLASS_NOFRIEND( className, baseClassName ) \ + DECLARE_CLASS( className, baseClassName ) + +#define DECLARE_CLASS_NOBASE( className ) \ + typedef className ThisClass; \ + template friend int CheckDeclareClass_Access(T *, const char *pShouldBe); \ + static int CheckDeclareClass( const char *pShouldBe ) \ + { \ + return InternalCheckDeclareClass( pShouldBe, #className, 0, 0 ); \ + } + +#else +#define DECLARE_CLASS( className, baseClassName ) \ + typedef baseClassName BaseClass; \ + typedef className ThisClass; + +#define DECLARE_CLASS_GAMEROOT( className, baseClassName ) DECLARE_CLASS( className, baseClassName ) +#define DECLARE_CLASS_NOFRIEND( className, baseClassName ) DECLARE_CLASS( className, baseClassName ) + +#define DECLARE_CLASS_NOBASE( className ) typedef className ThisClass; +#endif + + + + +class CBaseEntity; +class CAutoInitEntPtr +{ +public: + CAutoInitEntPtr() + { + m_pEnt = NULL; + } + CBaseEntity* m_pEnt; +}; + +#define DECLARE_NETWORKVAR_CHAIN() \ + CAutoInitEntPtr __m_pChainEntity; \ + void NetworkStateChanged() { CHECK_USENETWORKVARS __m_pChainEntity.m_pEnt->NetworkStateChanged(); } \ + void NetworkStateChanged( void *pVar ) { CHECK_USENETWORKVARS __m_pChainEntity.m_pEnt->NetworkStateChanged(); } + +#define IMPLEMENT_NETWORKVAR_CHAIN( varName ) \ + (varName)->__m_pChainEntity.m_pEnt = this; + + + +template< class T > +static inline void DispatchNetworkStateChanged(T* pObj) +{ + CHECK_USENETWORKVARS pObj->NetworkStateChanged(); +} +template< class T > +static inline void DispatchNetworkStateChanged(T* pObj, void* pVar) +{ + CHECK_USENETWORKVARS pObj->NetworkStateChanged(pVar); +} + + +#define DECLARE_EMBEDDED_NETWORKVAR() \ + template friend int ServerClassInit(T *); \ + template friend int ClientClassInit(T *); \ + virtual void NetworkStateChanged() {} virtual void NetworkStateChanged( void *pProp ) {} + +#define CNetworkVarEmbedded( type, name ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + static inline int GetOffset_##name() { return MyOffsetOf(ThisClass,name); } \ + typedef ThisClass ThisClass_##name; \ + class NetworkVar_##name : public type \ + { \ + template< class T > NetworkVar_##name& operator=( const T &val ) { *((type*)this) = val; return *this; } \ + public: \ + void CopyFrom( const type &src ) { *((type *)this) = src; NetworkStateChanged(); } \ + virtual void NetworkStateChanged() \ + { \ + DispatchNetworkStateChanged( (ThisClass_##name*)( ((char*)this) - GetOffset_##name() ) ); \ + } \ + virtual void NetworkStateChanged( void *pVar ) \ + { \ + DispatchNetworkStateChanged( (ThisClass_##name*)( ((char*)this) - GetOffset_##name() ), pVar ); \ + } \ + }; \ + NetworkVar_##name name; + +template +FORCEINLINE void NetworkVarConstruct(T& x) { x = T(0); } +FORCEINLINE void NetworkVarConstruct(color32_s& x) { x.r = x.g = x.b = x.a = 0; } + +template< class Type, class Changer > +class CNetworkVarBase +{ +public: + inline CNetworkVarBase() + { + NetworkVarConstruct(m_Value); + } + + template< class C > + const Type& operator=(const C& val) + { + return Set((const Type)val); + } + + template< class C > + const Type& operator=(const CNetworkVarBase< C, Changer >& val) + { + return Set((const Type)val.m_Value); + } + + const Type& Set(const Type& val) + { + if (memcmp(&m_Value, &val, sizeof(Type))) + { + NetworkStateChanged(); + m_Value = val; + } + return m_Value; + } + + Type& GetForModify() + { + NetworkStateChanged(); + return m_Value; + } + + template< class C > + const Type& operator+=(const C& val) + { + return Set(m_Value + (const Type)val); + } + + template< class C > + const Type& operator-=(const C& val) + { + return Set(m_Value - (const Type)val); + } + + template< class C > + const Type& operator/=(const C& val) + { + return Set(m_Value / (const Type)val); + } + + template< class C > + const Type& operator*=(const C& val) + { + return Set(m_Value * (const Type)val); + } + + template< class C > + const Type& operator^=(const C& val) + { + return Set(m_Value ^ (const Type)val); + } + + template< class C > + const Type& operator|=(const C& val) + { + return Set(m_Value | (const Type)val); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++(int) + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--(int) + { + Type val = m_Value; + (*this -= 1); + return val; + } + + template< class C > + const Type& operator&=(const C& val) + { + return Set(m_Value & (const Type)val); + } + + operator const Type& () const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +protected: + inline void NetworkStateChanged() + { + Changer::NetworkStateChanged(this); + } +}; + + +template< class Type, class Changer > +class CNetworkColor32Base : public CNetworkVarBase< Type, Changer > +{ +public: + inline void Init(byte rVal, byte gVal, byte bVal) + { + SetR(rVal); + SetG(gVal); + SetB(bVal); + } + inline void Init(byte rVal, byte gVal, byte bVal, byte aVal) + { + SetR(rVal); + SetG(gVal); + SetB(bVal); + SetA(aVal); + } + + const Type& operator=(const Type& val) + { + return this->Set(val); + } + + const Type& operator=(const CNetworkColor32Base& val) + { + return CNetworkVarBase::Set(val.m_Value); + } + + inline byte GetR() const { return CNetworkColor32Base::m_Value.r; } + inline byte GetG() const { return CNetworkColor32Base::m_Value.g; } + inline byte GetB() const { return CNetworkColor32Base::m_Value.b; } + inline byte GetA() const { return CNetworkColor32Base::m_Value.a; } + inline void SetR(byte val) { SetVal(CNetworkColor32Base::m_Value.r, val); } + inline void SetG(byte val) { SetVal(CNetworkColor32Base::m_Value.g, val); } + inline void SetB(byte val) { SetVal(CNetworkColor32Base::m_Value.b, val); } + inline void SetA(byte val) { SetVal(CNetworkColor32Base::m_Value.a, val); } + +protected: + inline void SetVal(byte& out, const byte& in) + { + if (out != in) + { + CNetworkVarBase< Type, Changer >::NetworkStateChanged(); + out = in; + } + } +}; + + +template< class Type, class Changer > +class CNetworkVectorBase : public CNetworkVarBase< Type, Changer > +{ +public: + inline void Init(float ix = 0, float iy = 0, float iz = 0) + { + SetX(ix); + SetY(iy); + SetZ(iz); + } + + const Type& operator=(const Type& val) + { + return CNetworkVarBase< Type, Changer >::Set(val); + } + + const Type& operator=(const CNetworkVectorBase& val) + { + return CNetworkVarBase::Set(val.m_Value); + } + + inline float GetX() const { return CNetworkVectorBase::m_Value.x; } + inline float GetY() const { return CNetworkVectorBase::m_Value.y; } + inline float GetZ() const { return CNetworkVectorBase::m_Value.z; } + inline float operator[](int i) const { return CNetworkVectorBase::m_Value[i]; } + + inline void SetX(float val) { DetectChange(CNetworkVectorBase::m_Value.x, val); } + inline void SetY(float val) { DetectChange(CNetworkVectorBase::m_Value.y, val); } + inline void SetZ(float val) { DetectChange(CNetworkVectorBase::m_Value.z, val); } + inline void Set(int i, float val) { DetectChange(CNetworkVectorBase::m_Value[i], val); } + + bool operator==(const Type& val) const + { + return CNetworkVectorBase::m_Value == (Type)val; + } + + bool operator!=(const Type& val) const + { + return CNetworkVectorBase::m_Value != (Type)val; + } + + const Type operator+(const Type& val) const + { + return CNetworkVectorBase::m_Value + val; + } + + const Type operator-(const Type& val) const + { + return CNetworkVectorBase::m_Value - val; + } + + const Type operator*(const Type& val) const + { + return CNetworkVectorBase::m_Value * val; + } + + const Type& operator*=(float val) + { + return CNetworkVarBase< Type, Changer >::Set(CNetworkVectorBase::m_Value * val); + } + + const Type operator*(float val) const + { + return CNetworkVectorBase::m_Value * val; + } + + const Type operator/(const Type& val) const + { + return CNetworkVectorBase::m_Value / val; + } + +private: + inline void DetectChange(float& out, float in) + { + if (out != in) + { + CNetworkVectorBase::NetworkStateChanged(); + out = in; + } + } +}; + + +template< class Type, class Changer > +class CNetworkQuaternionBase : public CNetworkVarBase< Type, Changer > +{ +public: + inline void Init(float ix = 0, float iy = 0, float iz = 0, float iw = 0) + { + SetX(ix); + SetY(iy); + SetZ(iz); + SetW(iw); + } + + const Type& operator=(const Type& val) + { + return CNetworkVarBase< Type, Changer >::Set(val); + } + + const Type& operator=(const CNetworkQuaternionBase& val) + { + return CNetworkVarBase::Set(val.m_Value); + } + + inline float GetX() const { return CNetworkQuaternionBase::m_Value.x; } + inline float GetY() const { return CNetworkQuaternionBase::m_Value.y; } + inline float GetZ() const { return CNetworkQuaternionBase::m_Value.z; } + inline float GetW() const { return CNetworkQuaternionBase::m_Value.w; } + inline float operator[](int i) const { return CNetworkQuaternionBase::m_Value[i]; } + + inline void SetX(float val) { DetectChange(CNetworkQuaternionBase::m_Value.x, val); } + inline void SetY(float val) { DetectChange(CNetworkQuaternionBase::m_Value.y, val); } + inline void SetZ(float val) { DetectChange(CNetworkQuaternionBase::m_Value.z, val); } + inline void SetW(float val) { DetectChange(CNetworkQuaternionBase::m_Value.w, val); } + inline void Set(int i, float val) { DetectChange(CNetworkQuaternionBase::m_Value[i], val); } + + bool operator==(const Type& val) const + { + return CNetworkQuaternionBase::m_Value == (Type)val; + } + + bool operator!=(const Type& val) const + { + return CNetworkQuaternionBase::m_Value != (Type)val; + } + + const Type operator+(const Type& val) const + { + return CNetworkQuaternionBase::m_Value + val; + } + + const Type operator-(const Type& val) const + { + return CNetworkQuaternionBase::m_Value - val; + } + + const Type operator*(const Type& val) const + { + return CNetworkQuaternionBase::m_Value * val; + } + + const Type& operator*=(float val) + { + return CNetworkQuaternionBase< Type, Changer >::Set(CNetworkQuaternionBase::m_Value * val); + } + + const Type operator*(float val) const + { + return CNetworkQuaternionBase::m_Value * val; + } + + const Type operator/(const Type& val) const + { + return CNetworkQuaternionBase::m_Value / val; + } + +private: + inline void DetectChange(float& out, float in) + { + if (out != in) + { + CNetworkQuaternionBase::NetworkStateChanged(); + out = in; + } + } +}; + + +#if defined( CLIENT_DLL ) || defined( GAME_DLL ) +inline void NetworkVarConstruct(CBaseHandle& x) {} + +template< class Type, class Changer > +class CNetworkHandleBase : public CNetworkVarBase< CBaseHandle, Changer > +{ +public: + const Type* operator=(const Type* val) + { + return Set(val); + } + + const Type& operator=(const CNetworkHandleBase& val) + { + const CBaseHandle& handle = CNetworkVarBase::Set(val.m_Value); + return *(const Type*)handle.Get(); + } + + bool operator !() const + { + return !CNetworkHandleBase::m_Value.Get(); + } + + operator Type* () const + { + return static_cast(CNetworkHandleBase::m_Value.Get()); + } + + const Type* Set(const Type* val) + { + if (CNetworkHandleBase::m_Value != val) + { + this->NetworkStateChanged(); + CNetworkHandleBase::m_Value = val; + } + return val; + } + + Type* Get() const + { + return static_cast(CNetworkHandleBase::m_Value.Get()); + } + + Type* operator->() const + { + return static_cast(CNetworkHandleBase::m_Value.Get()); + } + + bool operator==(const Type* val) const + { + return CNetworkHandleBase::m_Value == val; + } + + bool operator!=(const Type* val) const + { + return CNetworkHandleBase::m_Value != val; + } +}; + +#define CNetworkHandle( type, name ) CNetworkHandleInternal( type, name, NetworkStateChanged ) + +#define CNetworkHandleInternal( type, name, stateChangedFn ) \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkHandleBase, stateChangedFn ) +#endif + + +#define CNetworkVar( type, name ) \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVarBase, NetworkStateChanged ) + + +#define CNetworkVarForDerived( type, name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVarBase, NetworkStateChanged_##name ) + +#define CNetworkVectorForDerived( name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + CNetworkVectorInternal( Vector, name, NetworkStateChanged_##name ) + +#define CNetworkHandleForDerived( type, name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + CNetworkHandleInternal( type, name, NetworkStateChanged_##name ) + +#define CNetworkArrayForDerived( type, name, count ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} \ + CNetworkArrayInternal( type, name, count, NetworkStateChanged_##name ) + +#define IMPLEMENT_NETWORK_VAR_FOR_DERIVED( name ) \ + virtual void NetworkStateChanged_##name() { CHECK_USENETWORKVARS NetworkStateChanged(); } \ + virtual void NetworkStateChanged_##name( void *pVar ) { CHECK_USENETWORKVARS NetworkStateChanged( pVar ); } + + +#define CNetworkVarForDerived_OnByDefault( type, name ) \ + virtual void NetworkStateChanged_##name() { CHECK_USENETWORKVARS NetworkStateChanged(); } \ + virtual void NetworkStateChanged_##name( void *pVar ) { CHECK_USENETWORKVARS NetworkStateChanged( pVar ); } \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVarBase, NetworkStateChanged_##name ) + +#define DISABLE_NETWORK_VAR_FOR_DERIVED( name ) \ + virtual void NetworkStateChanged_##name() {} \ + virtual void NetworkStateChanged_##name( void *pVar ) {} + + + +#define CNetworkVector( name ) CNetworkVectorInternal( Vector, name, NetworkStateChanged ) +#define CNetworkQAngle( name ) CNetworkVectorInternal( QAngle, name, NetworkStateChanged ) + +#define CNetworkVectorInternal( type, name, stateChangedFn ) \ + NETWORK_VAR_START( type, name ) \ + NETWORK_VAR_END( type, name, CNetworkVectorBase, stateChangedFn ) + +#define CNetworkQuaternion( name ) \ + NETWORK_VAR_START( Quaternion, name ) \ + NETWORK_VAR_END( Quaternion, name, CNetworkQuaternionBase, NetworkStateChanged ) + +#define CNetworkColor32( name ) \ + NETWORK_VAR_START( color32, name ) \ + NETWORK_VAR_END( color32, name, CNetworkColor32Base, NetworkStateChanged ) + + +#define CNetworkString( name, length ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + typedef ThisClass MakeANetworkVar_##name; \ + class NetworkVar_##name \ + { \ + public: \ + NetworkVar_##name() { m_Value[0] = '\0'; } \ + operator const char*() const { return m_Value; } \ + const char* Get() const { return m_Value; } \ + char* GetForModify() \ + { \ + NetworkStateChanged(); \ + return m_Value; \ + } \ + protected: \ + inline void NetworkStateChanged() \ + { \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)this) - MyOffsetOf(ThisClass,name)))->NetworkStateChanged(); \ + } \ + private: \ + char m_Value[length]; \ + }; \ + NetworkVar_##name name; + + + + +#define CNetworkArrayInternal( type, name, count, stateChangedFn ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + typedef ThisClass MakeANetworkVar_##name; \ + class NetworkVar_##name \ + { \ + public: \ + inline NetworkVar_##name() \ + { \ + for ( int i = 0 ; i < count ; ++i ) \ + NetworkVarConstruct( m_Value[i] ); \ + } \ + template friend int ServerClassInit(T *); \ + const type& operator[]( int i ) const \ + { \ + return Get( i ); \ + } \ + \ + const type& Get( int i ) const \ + { \ + Assert( i >= 0 && i < count ); \ + return m_Value[i]; \ + } \ + \ + type& GetForModify( int i ) \ + { \ + Assert( i >= 0 && i < count ); \ + NetworkStateChanged( i ); \ + return m_Value[i]; \ + } \ + \ + void Set( int i, const type &val ) \ + { \ + Assert( i >= 0 && i < count ); \ + if( memcmp( &m_Value[i], &val, sizeof(type) ) ) \ + { \ + NetworkStateChanged( i ); \ + m_Value[i] = val; \ + } \ + } \ + const type* Base() const { return m_Value; } \ + int Count() const { return count; } \ + protected: \ + inline void NetworkStateChanged( int index ) \ + { \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)this) - MyOffsetOf(ThisClass,name)))->stateChangedFn( &m_Value[index] ); \ + } \ + type m_Value[count]; \ + }; \ + NetworkVar_##name name; + + +#define CNetworkArray( type, name, count ) CNetworkArrayInternal( type, name, count, NetworkStateChanged ) + + +#define NETWORK_VAR_START( type, name ) \ + class NetworkVar_##name; \ + friend class NetworkVar_##name; \ + typedef ThisClass MakeANetworkVar_##name; \ + class NetworkVar_##name \ + { \ + public: \ + template friend int ServerClassInit(T *); + + +#define NETWORK_VAR_END( type, name, base, stateChangedFn ) \ + public: \ + static inline void NetworkStateChanged( void *ptr ) \ + { \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)ptr) - MyOffsetOf(ThisClass,name)))->stateChangedFn( ptr ); \ + } \ + }; \ + base< type, NetworkVar_##name > name; + + + +#endif +``` + +`SpyCustom/sdk/panel2d.h`: + +```h +#pragma once + +//https://github.com/lua9520/source-engine-2018-hl2_src/blob/3bf9df6b2785fa6d951086978a3e66f49427166a/public/panorama/controls/panel2d.h + +#include "../PatternScan.hpp" +//#include "types.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wreorder" +//#include "utldelegateimpl.h" +#pragma GCC diagnostic pop +namespace panorama +{ + class CPanel2D; + + class IUIPanel; + class IUIEvent; + class IUIEngineFrameListener; + class IUIPanelStyle; + class IUIJSObject; + class IUIWindow; + class IUISettings; + class IUITextLayout; + class IUIInputEngine; + class IUILocalize; + class IUISoundSystem; + class IUISettings; + class IUILayoutManager; + class IUIFileSystem; + class IUIPanelClient; + + // E Prefix for enums? + class EFontStyle; + class EFontWeight; + class ETextAlign; + class EPanelRepaint; + class EStyleRepaint; + class EStyleFlags; + class EFocusMoveDirection; + class EMouseCanActivate; + class EAnimationTimingFunction; + class EAnimationDirection; + + class CUILength; + class CLayoutFile; + typedef unsigned short CPanoramaSymbol; + typedef unsigned long long PanelHandle_t; + class CJSONWebAPIParams; + class UIEventFactory; + class EPanelEventSource_t; + class CPanel2DFactory; + class RegisterJSType_t; + class RegisterJSScopeInfo_t; + class RegisterJSEntryInfo_t; + class KeyData_t; + class GamePadData_t; + class MouseData_t; + + + // Returned by the CreatePanel functions. TODO: Look at panelRefs this might be that. + class PanelWrapper { + public: + void* vtable; + IUIPanel* panel; + }; + + + struct ScrollBehavior_t; +} + +// xref "CPanel2D::BSetProperty" to BSetProperty (libclient) +namespace panorama +{ + class CPanel2D + { + public: + virtual panorama::IUIPanel* UIPanel(void) = 0; + virtual void OnDeletePanel(void) = 0; + virtual panorama::CPanoramaSymbol GetPanelType(void) = 0; + virtual void Paint(void) = 0; + virtual void sub_4554560() = 0; + virtual void sub_4554570() = 0; + virtual void OnContentSizeTraverse(float *, float *, float, float, bool) = 0; + virtual void OnLayoutTraverse(float, float) = 0; + virtual void OnKeyDown(panorama::KeyData_t const &) = 0; + virtual void OnKeyUp(panorama::KeyData_t const &) = 0; + virtual void OnKeyTyped(panorama::KeyData_t const &) = 0; + virtual void OnGamePadDown(panorama::GamePadData_t const &) = 0; + virtual void OnGamePadUp(panorama::GamePadData_t const &) = 0; + virtual void OnGamePadAnalog(panorama::GamePadData_t const &) = 0; + virtual void OnMouseButtonDown(panorama::MouseData_t const &) = 0; + virtual void OnMouseButtonUp(panorama::MouseData_t const &) = 0; + virtual void OnMouseButtonDoubleClick(panorama::MouseData_t const &) = 0; + virtual void OnMouseButtonTripleClick(panorama::MouseData_t const &) = 0; + virtual void OnMouseWheel(panorama::MouseData_t const &) = 0; + virtual void OnMouseMove(float, float) = 0; + virtual void OnClick(panorama::IUIPanel *panel, panorama::MouseData_t const &) = 0; + virtual void sub_23BF260() = 0; + virtual bool BIsClientPanelEvent(panorama::CPanoramaSymbol) = 0; + virtual bool sub_3BC94E0() = 0; + virtual void sub_4555580() = 0; + virtual bool BSetProperty(panorama::CPanoramaSymbol, const char *) = 0; + virtual bool BIsDelayedProperty(panorama::CPanoramaSymbol) = 0; + virtual void OnBeforeChildrenChanged(void) = 0; + virtual void OnRemoveChild(panorama::IUIPanel* child) = 0; + virtual void OnAfterChildrenChanged(void) = 0; + virtual void OnInitializedFromLayout(void) = 0; + virtual void OnStylesChanged(void) = 0; + virtual void OnChildStylesChanged(void) = 0; + virtual void OnVisibilityChanged(void) = 0; + virtual void OnSetFocusToNextPanel(int, panorama::EFocusMoveDirection, bool, float, float, float, float ,float) = 0; + virtual void* GetLocalizationParent(void) = 0; + virtual bool BRequiresContentClipLayer(void) = 0; + virtual void OnCallBeforeStyleAndLayout(void) = 0; + virtual void OnPanelEventSet(panorama::CPanoramaSymbol event) = 0; + virtual void* GetMouseCursor(void) = 0; + virtual void OnUIScaleFactorChanged(float scaleFactor) = 0; + virtual void SetupJavascriptObjectTemplate(void) = 0; + virtual void CreateNewVerticalScrollBar(float) = 0; + virtual void CreateNewHorizontalScrollBar(float) = 0; + virtual void HideTooltip(void) = 0; + virtual void GetDefaultInputFocus(void) = 0; + virtual void GetPositionWithinAncestor(panorama::CPanel2D* ancestor, float *x, float *y) = 0; + virtual void sub_23BF380() = 0; + virtual void sub_23BF390() = 0; // These are in these 6 somewhere + virtual void sub_23BF3A0() = 0; // panorama::CPanel2D::BCanCustomScrollUp(void) + virtual void sub_23BF3B0() = 0; // panorama::CPanel2D::BCanCustomScrollDown(void) + virtual void sub_23BF3C0() = 0; // panorama::CPanel2D::BCanCustomScrollLeft(void) + virtual void sub_23BF3D0() = 0; // panorama::CPanel2D::BCanCustomScrollRight(void) + virtual void UnloadImages(void) = 0; + virtual void ReloadImages(void) = 0; + virtual void DESTROY1() = 0; + virtual void DESTROY2() = 0; + virtual void GetContextUIBounds(float *x1, float *y1, float *x2, float *y2) = 0; + virtual void ScrollToXPercent(float value) = 0; + virtual void ScrollToYPercent(float value) = 0; + virtual void OnMoveUp(int) = 0; + virtual void OnMoveDown(int) = 0; + virtual void OnMoveLeft(int) = 0; + virtual void OnMoveRight(int) = 0; + virtual void OnTabForward(int) = 0; + virtual void OnTabBackward(int) = 0; + virtual void sub_23BF270() = 0; + virtual void sub_23BF290() = 0; + virtual void sub_4554580() = 0; + virtual bool IsClonable() = 0; + virtual panorama::CPanel2D* Clone(void) = 0; + virtual void ReSortChild(bool (*)(panorama::IUIPanelClient * const&,panorama::IUIPanelClient * const&),panorama::CPanel2D*) = 0; + virtual bool HasBeenLayedOut(void) = 0; + virtual void* AccessRenderingEngine(void) = 0; + virtual void sub_23BF420() = 0; + virtual void InitClonedPanel(panorama::CPanel2D* ) = 0; + virtual void AddDisabledFlagToChildren(void) = 0; + virtual void RemoveDisabledFlagFromChildren(void) = 0; + virtual void FireGameEvent(void* IGameEvent) = 0; + virtual void OnDOTAGameUIStateChange(int DotaGameUIStateOld, int DotaGameUIStateNew) = 0; + + //https://www.unknowncheats.me/forum/counterstrike-global-offensive/342743-finding-sigging-chud-pointer-chud-findelement.html + + void ShowAlert_v(const char* text, const int mode) + { + //How to find CPanel2D::ShowAlert + // 1. Search for "AlertVisible" + // 2. First and only cross - reference will be to ShowAlert + + static void* ptr = (void*)(FindPatternV2("client.dll", "55 8B EC A1 ? ? ? ? 83 EC 08 56 8B F1 57 A8 01 75 26 8B 0D ? ? ? ? 83 C8 01 A3 ? ? ? ? 68 ? ? ? ? 8B 01 FF 90 ? ? ? ? 66 A3 ? ? ? ? A1")); + static auto fn = reinterpret_cast(ptr); + + return fn(this, text, mode); + + } + + void HidePanel_v() + { + //How to find CPanel2D::HidePanel + // 1. Search for "HideFlash" + // 2. First cross - reference is to the HidePanel function + + /* + static auto fn = memory::follow_relative_jump(FindPatternV2("client.dll", "E8 ? ? ? ? 5F 5E 5B 8B E5 5D C2 04 00 8B D3 B9 ? ? ? ? E8 ? ? ? ? 85 C0 0F 85 ? ? ? ? 8B 44 24 14")) + .as(); + + return fn(this, false); + */ + } + }; +} +``` + +`SpyCustom/sdk/particle_iterators.h`: + +```h +#ifndef PARTICLE_ITERATORS_H +#define PARTICLE_ITERATORS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "imesh.h" +#include "particledraw.h" + + +#define NUM_PARTICLES_PER_BATCH 200 +#ifndef _XBOX +#define MAX_TOTAL_PARTICLES 2048 +#else +#define MAX_TOTAL_PARTICLES 1024 +#endif + + +class CParticleRenderIterator +{ + friend class CParticleMgr; + friend class CParticleEffectBinding; +public: + CParticleRenderIterator(); + + const Particle* GetFirst(); + const Particle* GetNext(float sortKey); + + ParticleDraw* GetParticleDraw() const; + + +private: + + void TestFlushBatch(); + + +private: + CParticleEffectBinding* m_pEffectBinding; + CEffectMaterial* m_pMaterial; + ParticleDraw* m_pParticleDraw; + CMeshBuilder* m_pMeshBuilder; + IMesh* m_pMesh; + bool m_bBucketSort; + + float m_MinZ; + float m_MaxZ; + float m_zCoords[MAX_TOTAL_PARTICLES]; + int m_nZCoords; + + Particle* m_pCur; + bool m_bGotFirst; + float m_flPrevZ; + int m_nParticlesInCurrentBatch; +}; + + +class CParticleSimulateIterator +{ + friend class CParticleMgr; + friend class CParticleEffectBinding; +public: + CParticleSimulateIterator(); + + Particle* GetFirst(); + Particle* GetNext(); + float GetTimeDelta() const; + + void RemoveParticle(Particle* pParticle); + void RemoveAllParticles(); + +private: + CParticleEffectBinding* m_pEffectBinding; + CEffectMaterial* m_pMaterial; + float m_flTimeDelta; + + bool m_bGotFirst; + Particle* m_pNextParticle; +}; + + +inline CParticleRenderIterator::CParticleRenderIterator() +{ + m_pCur = NULL; + m_bGotFirst = false; + m_flPrevZ = 0; + m_nParticlesInCurrentBatch = 0; + m_MinZ = 1e24; + m_MaxZ = -1e24; + m_nZCoords = 0; +} + +inline const Particle* CParticleRenderIterator::GetFirst() +{ + Assert(!m_bGotFirst); + m_bGotFirst = true; + + m_pCur = m_pMaterial->m_Particles.m_pNext; + if (m_pCur == &m_pMaterial->m_Particles) + return NULL; + + m_pParticleDraw->m_pSubTexture = m_pCur->m_pSubTexture; + return m_pCur; +} + +inline void CParticleRenderIterator::TestFlushBatch() +{ + ++m_nParticlesInCurrentBatch; + if (m_nParticlesInCurrentBatch >= NUM_PARTICLES_PER_BATCH) + { + m_pMeshBuilder->End(false, true); + m_pMeshBuilder->Begin(m_pMesh, MATERIAL_QUADS, NUM_PARTICLES_PER_BATCH * 4); + + m_nParticlesInCurrentBatch = 0; + } +} + +inline const Particle* CParticleRenderIterator::GetNext(float sortKey) +{ + Assert(m_bGotFirst); + Assert(m_pCur); + + TestFlushBatch(); + + Particle* pNext = m_pCur->m_pNext; + + if (m_bBucketSort) + { + m_MinZ = MIN(sortKey, m_MinZ); + m_MaxZ = MAX(sortKey, m_MaxZ); + + m_zCoords[m_nZCoords] = sortKey; + ++m_nZCoords; + } + else + { + if (m_pCur != m_pMaterial->m_Particles.m_pNext && m_flPrevZ > sortKey) + { + SwapParticles(m_pCur->m_pPrev, m_pCur); + } + else + { + m_flPrevZ = sortKey; + } + } + + m_pCur = pNext; + if (m_pCur == &m_pMaterial->m_Particles) + return NULL; + + m_pParticleDraw->m_pSubTexture = m_pCur->m_pSubTexture; + return m_pCur; +} + +inline ParticleDraw* CParticleRenderIterator::GetParticleDraw() const +{ + return m_pParticleDraw; +} + + +inline CParticleSimulateIterator::CParticleSimulateIterator() +{ + m_pNextParticle = NULL; +#ifdef _DEBUG + m_bGotFirst = false; +#endif +} + +inline Particle* CParticleSimulateIterator::GetFirst() +{ +#ifdef _DEBUG + if (m_bGotFirst) + { + Assert(m_pNextParticle == &m_pMaterial->m_Particles); + } +#endif + + Particle* pRet = m_pMaterial->m_Particles.m_pNext; + if (pRet == &m_pMaterial->m_Particles) + return NULL; + +#ifdef _DEBUG + m_bGotFirst = true; +#endif + + m_pNextParticle = pRet->m_pNext; + return pRet; +} + +inline Particle* CParticleSimulateIterator::GetNext() +{ + Particle* pRet = m_pNextParticle; + + if (pRet == &m_pMaterial->m_Particles) + return NULL; + + m_pNextParticle = pRet->m_pNext; + return pRet; +} + +inline void CParticleSimulateIterator::RemoveParticle(Particle* pParticle) +{ + m_pEffectBinding->RemoveParticle(pParticle); +} + +inline void CParticleSimulateIterator::RemoveAllParticles() +{ + Particle* pParticle = GetFirst(); + while (pParticle) + { + RemoveParticle(pParticle); + pParticle = GetNext(); + } +} + +inline float CParticleSimulateIterator::GetTimeDelta() const +{ + return m_flTimeDelta; +} + + +#endif +``` + +`SpyCustom/sdk/particle_parse.h`: + +```h +#ifndef PARTICLE_PARSE_H +#define PARTICLE_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" +#include "utlstring.h" +#include "ifilelist.h" + +enum ParticleAttachment_t +{ + PATTACH_ABSORIGIN = 0, + PATTACH_ABSORIGIN_FOLLOW, + PATTACH_CUSTOMORIGIN, + PATTACH_POINT, + PATTACH_POINT_FOLLOW, + + PATTACH_WORLDORIGIN, + + PATTACH_ROOTBONE_FOLLOW, + + MAX_PATTACH_TYPES, +}; + +extern int GetAttachTypeFromString(const char* pszString); + +#define PARTICLE_DISPATCH_FROM_ENTITY (1<<0) +#define PARTICLE_DISPATCH_RESET_PARTICLES (1<<1) + +struct te_tf_particle_effects_colors_t +{ + Vector m_vecColor1; + Vector m_vecColor2; +}; + +struct te_tf_particle_effects_control_point_t +{ + ParticleAttachment_t m_eParticleAttachment; + Vector m_vecOffset; +}; + +void ParseParticleEffects(bool bLoadSheets, bool bPrecache); +void ParseParticleEffectsMap(const char* pMapName, bool bLoadSheets, IFileList* pFilesToReload = NULL); + +void GetParticleManifest(CUtlVector& list); + +void PrecacheStandardParticleSystems(); + +class IFileList; +void ReloadParticleEffectsInList(IFileList* pFilesToReload); + +void DispatchParticleEffect(const char* pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity* pEntity, const char* pszAttachmentName, bool bResetAllParticlesOnEntity = false); +void DispatchParticleEffect(const char* pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity* pEntity = NULL, int iAttachmentPoint = -1, bool bResetAllParticlesOnEntity = false); +void DispatchParticleEffect(const char* pszParticleName, Vector vecOrigin, QAngle vecAngles, CBaseEntity* pEntity = NULL); +void DispatchParticleEffect(const char* pszParticleName, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity* pEntity = NULL); +void DispatchParticleEffect(int iEffectIndex, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity* pEntity = NULL); + +void DispatchParticleEffect(const char* pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity* pEntity, const char* pszAttachmentName, Vector vecColor1, Vector vecColor2, bool bUseColors = true, bool bResetAllParticlesOnEntity = false); +void DispatchParticleEffect(const char* pszParticleName, Vector vecOrigin, QAngle vecAngles, Vector vecColor1, Vector vecColor2, bool bUseColors = true, CBaseEntity* pEntity = NULL, int iAttachType = PATTACH_CUSTOMORIGIN); + + +void StopParticleEffects(CBaseEntity* pEntity); + + +#endif +``` + +`SpyCustom/sdk/particle_property.h`: + +```h +#ifndef PARTICLEPROPERTY_H +#define PARTICLEPROPERTY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "smartptr.h" +#include "globalvars_base.h" +#include "particles_new.h" +#include "particle_parse.h" + +class CBaseEntity; +class CNewParticleEffect; + +#ifdef CLIENT_DLL +#define INVALID_PARTICLE_ATTACHMENT 0 +#else +#define INVALID_PARTICLE_ATTACHMENT -1 +#endif + +struct ParticleControlPoint_t +{ + ParticleControlPoint_t() + { + iControlPoint = 0; + iAttachType = PATTACH_ABSORIGIN_FOLLOW; + iAttachmentPoint = 0; + vecOriginOffset = vec3_origin; + } + + int iControlPoint; + ParticleAttachment_t iAttachType; + int iAttachmentPoint; + Vector vecOriginOffset; + EHANDLE hEntity; +}; + +struct ParticleEffectList_t +{ + ParticleEffectList_t() + { + pParticleEffect = NULL; + } + + CUtlVector pControlPoints; + CSmartPtr pParticleEffect; +}; + +extern int GetAttachTypeFromString(const char* pszString); + +class CParticleProperty +{ + DECLARE_CLASS_NOBASE(CParticleProperty); + DECLARE_EMBEDDED_NETWORKVAR(); + DECLARE_PREDICTABLE(); + DECLARE_DATADESC(); + +public: + CParticleProperty(); + ~CParticleProperty(); + + void Init(CBaseEntity* pEntity); + CBaseEntity* GetOuter(void) { return m_pOuter; } + + CNewParticleEffect* Create(const char* pszParticleName, ParticleAttachment_t iAttachType, const char* pszAttachmentName); + CNewParticleEffect* Create(const char* pszParticleName, ParticleAttachment_t iAttachType, int iAttachmentPoint = INVALID_PARTICLE_ATTACHMENT, Vector vecOriginOffset = vec3_origin); + void AddControlPoint(CNewParticleEffect* pEffect, int iPoint, C_BaseEntity* pEntity, ParticleAttachment_t iAttachType, const char* pszAttachmentName = NULL, Vector vecOriginOffset = vec3_origin); + void AddControlPoint(int iEffectIndex, int iPoint, C_BaseEntity* pEntity, ParticleAttachment_t iAttachType, int iAttachmentPoint = INVALID_PARTICLE_ATTACHMENT, Vector vecOriginOffset = vec3_origin); + + inline void SetControlPointParent(CNewParticleEffect* pEffect, int whichControlPoint, int parentIdx); + void SetControlPointParent(int iEffectIndex, int whichControlPoint, int parentIdx); + + void StopEmission(CNewParticleEffect* pEffect = NULL, bool bWakeOnStop = false, bool bDestroyAsleepSystems = false); + void StopEmissionAndDestroyImmediately(CNewParticleEffect* pEffect = NULL); + + void StopParticlesInvolving(CBaseEntity* pEntity); + void StopParticlesNamed(const char* pszEffectName, bool bForceRemoveInstantly = false); + void StopParticlesWithNameAndAttachment(const char* pszEffectName, int iAttachmentPoint, bool bForceRemoveInstantly = false); + + void OnParticleSystemUpdated(CNewParticleEffect* pEffect, float flTimeDelta); + void OnParticleSystemDeleted(CNewParticleEffect* pEffect); + +#ifdef CLIENT_DLL + void OwnerSetDormantTo(bool bDormant); +#endif + + void ReplaceParticleEffect(CNewParticleEffect* pOldEffect, CNewParticleEffect* pNewEffect); + + void DebugPrintEffects(void); + + int FindEffect(const char* pEffectName, int nStart = 0); + inline CNewParticleEffect* GetParticleEffectFromIdx(int idx); + +private: + int GetParticleAttachment(C_BaseEntity* pEntity, const char* pszAttachmentName, const char* pszParticleName); + int FindEffect(CNewParticleEffect* pEffect); + void UpdateParticleEffect(ParticleEffectList_t* pEffect, bool bInitializing = false, int iOnlyThisControlPoint = -1); + void UpdateControlPoint(ParticleEffectList_t* pEffect, int iPoint, bool bInitializing); + +private: + CBaseEntity* m_pOuter; + CUtlVector m_ParticleEffects; + int m_iDormancyChangedAtFrame; + + friend class CBaseEntity; +}; + +#include "particle_property_inlines.h" + +#endif +``` + +`SpyCustom/sdk/particle_property_inlines.h`: + +```h +#ifndef PARTICLEPROPERTY_H +#pragma message("Do not include particle_property_inlines.h from anywhere other than particle_property.h!") +#pragma error +#endif + +#ifndef PARTICLEPROPERTY_INLINES_H +#define PARTICLEPROPERTY_INLINES_H +#ifdef _WIN32 +#pragma once +#endif + + +void CParticleProperty::SetControlPointParent(CNewParticleEffect* pEffect, int whichControlPoint, int parentIdx) +{ + pEffect->SetControlPointParent(whichControlPoint, parentIdx); +} + +CNewParticleEffect* CParticleProperty::GetParticleEffectFromIdx(int idx) +{ + return m_ParticleEffects[idx].pParticleEffect.GetObject(); +} + + + +#endif +``` + +`SpyCustom/sdk/particle_util.h`: + +```h +#ifndef PARTICLE_UTIL_H +#define PARTICLE_UTIL_H + +#include "IMesh.h" +#include "particledraw.h" +#include "particlemgr.h" +#include "cdll_client_int.h" +#include "timedevent.h" + + + +inline float FLerp(float minVal, float maxVal, float t) +{ + return minVal + (maxVal - minVal) * t; +} + +inline Vector VecLerp(const Vector& minVal, const Vector& maxVal, float t) +{ + return minVal + (maxVal - minVal) * t; +} + +inline float FRand(float minVal, float maxVal) +{ + return minVal + ((float)rand() / RAND_MAX) * (maxVal - minVal); +} + +inline void PhysicallySimulate(Vector& pos, Vector& velocity, const Vector& acceleration, const float fTimeDelta) +{ + pos = pos + (velocity + (acceleration * fTimeDelta * 0.5f)) * fTimeDelta; + velocity = velocity + acceleration * fTimeDelta; +} + + +inline Vector GetGravityVector() +{ + return Vector(0, 0, -150); +} + + +inline void RenderParticle_Color255SizeSpecularTCoord3( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size, + const unsigned char* specular, + const float tCoord +) +{ + if (alpha < 0.5f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha); + + pBuilder->Position3f(pos.x - size, pos.y - size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord3f(0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1], tCoord); + pBuilder->Specular3ubv(specular); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f(pos.x - size, pos.y + size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord3f(0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1], tCoord); + pBuilder->Specular3ubv(specular); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f(pos.x + size, pos.y + size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord3f(0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1], tCoord); + pBuilder->Specular3ubv(specular); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f(pos.x + size, pos.y - size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord3f(0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1], tCoord); + pBuilder->Specular3ubv(specular); + pBuilder->AdvanceVertex(); +} + + +inline void RenderParticle_Color255Size( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size) +{ + if (alpha < 0.5f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha); + + pBuilder->Position3f(pos.x - size, pos.y - size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord2f(0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMaxs[1]); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f(pos.x - size, pos.y + size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord2f(0, pDraw->m_pSubTexture->m_tCoordMins[0], pDraw->m_pSubTexture->m_tCoordMins[1]); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f(pos.x + size, pos.y + size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord2f(0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMins[1]); + pBuilder->AdvanceVertex(); + + pBuilder->Position3f(pos.x + size, pos.y - size, pos.z); + pBuilder->Color4ubv(ubColor); + pBuilder->TexCoord2f(0, pDraw->m_pSubTexture->m_tCoordMaxs[0], pDraw->m_pSubTexture->m_tCoordMaxs[1]); + pBuilder->AdvanceVertex(); +} + + +inline void RenderParticle_Color255SizeNormal( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size, + const Vector& vNormal) +{ + if (alpha < 0.5f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha); + +} + + +inline void RenderParticle_Color255SizeNormalAngle( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size, + const Vector& vNormal, + const float angle) +{ + if (alpha < 0.5f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha); + + float ca = (float)cos(angle); + float sa = (float)sin(angle); + +} + + +inline void RenderParticle_ColorSize( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size +) +{ + if (alpha < 0.001f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x * 254.9f); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y * 254.9f); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z * 254.9f); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha * 254.9f); + +} + + +inline void RenderParticle_ColorSizeAngle( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size, + const float angle) +{ + if (alpha < 0.001f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x * 254.9f); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y * 254.9f); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z * 254.9f); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha * 254.9f); + + float sa, ca; + SinCos(angle, &sa, &ca); + +} + +inline void RenderParticle_ColorSizeAngles( + ParticleDraw* pDraw, + const Vector& pos, + const Vector& color, + const float alpha, + const float size, + const QAngle& angles) +{ + if (alpha < 0.001f) + return; + + CMeshBuilder* pBuilder = pDraw->GetMeshBuilder(); + if (!pBuilder) + return; + + unsigned char ubColor[4]; + ubColor[0] = (unsigned char)RoundFloatToInt(color.x * 254.9f); + ubColor[1] = (unsigned char)RoundFloatToInt(color.y * 254.9f); + ubColor[2] = (unsigned char)RoundFloatToInt(color.z * 254.9f); + ubColor[3] = (unsigned char)RoundFloatToInt(alpha * 254.9f); + + Vector vNorm, vWidth, vHeight; + AngleVectors(angles, &vNorm, &vWidth, &vHeight); + + Vector vVertex = pos; +} + +inline float GetAlphaDistanceFade( + const Vector& pos, + const float fadeNearDist, + const float fadeFarDist) +{ + if (-pos.z > fadeFarDist) + { + return 1; + } + else if (-pos.z > fadeNearDist) + { + return (-pos.z - fadeNearDist) / (fadeFarDist - fadeNearDist); + } + else + { + return 0; + } +} + + +inline Vector WorldGetLightForPoint(const Vector& vPos, bool bClamp) +{ +#if defined(PARTICLEPROTOTYPE_APP) + return Vector(1, 1, 1); +#else + return engine->GetLightForPoint(vPos, bClamp); +#endif +} + +#endif +``` + +`SpyCustom/sdk/particledraw.h`: + +```h +#ifndef PARTICLEDRAW_H +#define PARTICLEDRAW_H + + +class IMaterial; +class CMeshBuilder; +class CParticleSubTexture; + + +class ParticleDraw +{ + friend class CParticleEffectBinding; + +public: + + ParticleDraw(); + + void Init(CMeshBuilder* pMeshBuilder, IMaterial* pMaterial, float fTimeDelta); + + float GetTimeDelta() const; + + CMeshBuilder* GetMeshBuilder(); + + CParticleSubTexture* m_pSubTexture; + +private: + CMeshBuilder* m_pMeshBuilder; + IMaterial* m_pMaterial; + float m_fTimeDelta; +}; + + + +inline ParticleDraw::ParticleDraw() +{ + m_pMaterial = 0; +} + +inline void ParticleDraw::Init(CMeshBuilder* pMeshBuilder, IMaterial* pMaterial, float fTimeDelta) +{ + m_pMeshBuilder = pMeshBuilder; + m_pMaterial = pMaterial; + m_fTimeDelta = fTimeDelta; +} + +inline float ParticleDraw::GetTimeDelta() const +{ + return m_fTimeDelta; +} + +inline CMeshBuilder* ParticleDraw::GetMeshBuilder() +{ + return m_pMeshBuilder; +} + +#endif +``` + +`SpyCustom/sdk/particlemgr.h`: + +```h + +#ifndef PARTICLEMGR_H +#define PARTICLEMGR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "imaterial.h" +#include "imaterialsystem.h" +#include "vector.h" +#include "vmatrix.h" +#include "Mathlib.h" +#include "iclientrenderable.h" +#include "clientleafsystem.h" +#include "fasttimer.h" +#include "utllinkedlist.h" +#include "UtlDict.h" +#ifdef WIN32 +#include +#else +#include +#endif +#include "utlintrusivelist.h" +#include "utlobjectreference.h" +#include "utlstring.h" + + +class IParticleEffect; +class IClientParticleListener; +struct Particle; +class ParticleDraw; +class CMeshBuilder; +class CUtlMemoryPool; +class CEffectMaterial; +class CParticleSimulateIterator; +class CParticleRenderIterator; +class IThreadPool; +class CParticleSystemDefinition; +class CParticleMgr; +class CNewParticleEffect; +class CParticleCollection; + +#define INVALID_MATERIAL_HANDLE NULL + + + +class CParticleSubTexture; +class CParticleSubTextureGroup; + + +struct Particle +{ + Particle* m_pPrev, * m_pNext; + + CParticleSubTexture* m_pSubTexture; + + Vector m_Pos; +}; + + +typedef CParticleSubTexture* PMaterialHandle; + +class CEffectMaterial +{ +public: + CEffectMaterial(); + +public: + CParticleSubTextureGroup* m_pGroup; + + Particle m_Particles; + CEffectMaterial* m_pHashedNext; +}; + + +class CParticleSubTextureGroup +{ +public: + CParticleSubTextureGroup(); + ~CParticleSubTextureGroup(); + + IMaterial* m_pPageMaterial; +}; + +class CParticleSubTexture +{ +public: + CParticleSubTexture(); + + float m_tCoordMins[2]; + float m_tCoordMaxs[2]; + + CParticleSubTextureGroup* m_pGroup; + CParticleSubTextureGroup m_DefaultGroup; +#ifdef _DEBUG + char* m_szDebugName; +#endif + + IMaterial* m_pMaterial; +}; + + +abstract_class IParticleEffect +{ + public: + + virtual ~IParticleEffect() {} + + virtual void Update(float fTimeDelta) {} + + virtual void StartRender(VMatrix & effectMatrix) {} + + virtual bool ShouldSimulate() const = 0; + virtual void SetShouldSimulate(bool bSim) = 0; + virtual void SimulateParticles(CParticleSimulateIterator* pIterator) = 0; + + virtual void RenderParticles(CParticleRenderIterator* pIterator) = 0; + + virtual void NotifyRemove() {} + + virtual void NotifyDestroyParticle(Particle* pParticle) {} + + virtual const Vector& GetSortOrigin() = 0; + + virtual const Vector* GetParticlePosition(Particle* pParticle) { return &pParticle->m_Pos; } + + virtual const char* GetEffectName() { return "???"; } +}; + +#define REGISTER_EFFECT( effect ) \ + IParticleEffect* effect##_Factory() \ + { \ + return new effect; \ + } \ + struct effect##_RegistrationHelper \ + { \ + effect##_RegistrationHelper() \ + { \ + ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \ + } \ + }; \ + static effect##_RegistrationHelper g_##effect##_RegistrationHelper + +#define REGISTER_EFFECT_USING_CREATE( effect ) \ + IParticleEffect* effect##_Factory() \ + { \ + return effect::Create( #effect ).GetObject(); \ + } \ + struct effect##_RegistrationHelper \ + { \ + effect##_RegistrationHelper() \ + { \ + ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \ + } \ + }; \ + static effect##_RegistrationHelper g_##effect##_RegistrationHelper + + +class CParticleEffectBinding : public CDefaultClientRenderable +{ + friend class CParticleMgr; + friend class CParticleSimulateIterator; + friend class CNewParticleEffect; + +public: + CParticleEffectBinding(); + ~CParticleEffectBinding(); + + +public: + + void SimulateParticles(float flTimeDelta); + + PMaterialHandle FindOrAddMaterial(const char* pMaterialName); + + Particle* AddParticle(int sizeInBytes, PMaterialHandle pMaterial); + + void SetBBox(const Vector& bbMin, const Vector& bbMax, bool bDisableAutoUpdate = true); + void GetWorldspaceBounds(Vector* pMins, Vector* pMaxs); + + const matrix3x4_t& GetLocalSpaceTransform() const; + void SetLocalSpaceTransform(const matrix3x4_t& transform); + + bool EnlargeBBoxToContain(const Vector& pt); + + void SetDrawThruLeafSystem(int bDraw); + + void SetDrawBeforeViewModel(int bDraw); + + int GetRemoveFlag() { return GetFlag(FLAGS_REMOVE); } + void SetRemoveFlag() { SetFlag(FLAGS_REMOVE, 1); } + + int GetAlwaysSimulate() { return GetFlag(FLAGS_ALWAYSSIMULATE); } + void SetAlwaysSimulate(int bAlwaysSimulate) { SetFlag(FLAGS_ALWAYSSIMULATE, bAlwaysSimulate); } + + void SetIsNewParticleSystem(void) { SetFlag(FLAGS_NEW_PARTICLE_SYSTEM, 1); } + int WasDrawnPrevFrame() { return GetFlag(FLAGS_DRAWN_PREVFRAME); } + void SetWasDrawnPrevFrame(int bWasDrawnPrevFrame) { SetFlag(FLAGS_DRAWN_PREVFRAME, bWasDrawnPrevFrame); } + + int IsEffectCameraSpace() { return GetFlag(FLAGS_CAMERASPACE); } + void SetEffectCameraSpace(int bCameraSpace) { SetFlag(FLAGS_CAMERASPACE, bCameraSpace); } + + int GetAutoApplyLocalTransform() const { return GetFlag(FLAGS_AUTOAPPLYLOCALTRANSFORM); } + void SetAutoApplyLocalTransform(int b) { SetFlag(FLAGS_AUTOAPPLYLOCALTRANSFORM, b); } + + int GetAutoUpdateBBox() { return GetFlag(FLAGS_AUTOUPDATEBBOX); } + void SetAutoUpdateBBox(int bAutoUpdate) { SetFlag(FLAGS_AUTOUPDATEBBOX, bAutoUpdate); } + + int GetNumActiveParticles(); + + void SetParticleCullRadius(float flMaxParticleRadius); + + int GetActiveParticleList(int nCount, Particle** ppParticleList); + + void DetectChanges(); + +private: + void SetFlag(int flag, int bOn) { if (bOn) m_Flags |= flag; else m_Flags &= ~flag; } + int GetFlag(int flag) const { return m_Flags & flag; } + + void Init(CParticleMgr* pMgr, IParticleEffect* pSim); + void Term(); + + void RemoveParticle(Particle* pParticle); + + void StartDrawMaterialParticles( + CEffectMaterial* pMaterial, + float flTimeDelta, + IMesh*& pMesh, + CMeshBuilder& builder, + ParticleDraw& particleDraw, + bool bWireframe); + + int DrawMaterialParticles( + bool bBucketSort, + CEffectMaterial* pMaterial, + float flTimeDelta, + bool bWireframe + ); + + void GrowBBoxFromParticlePositions(CEffectMaterial* pMaterial, bool& bboxSet, Vector& bbMin, Vector& bbMax); + + void RenderStart(VMatrix& mTempModel, VMatrix& mTempView); + void RenderEnd(VMatrix& mModel, VMatrix& mView); + + void BBoxCalcStart(Vector& bbMin, Vector& bbMax); + void BBoxCalcEnd(bool bboxSet, Vector& bbMin, Vector& bbMax); + + void DoBucketSort( + CEffectMaterial* pMaterial, + float* zCoords, + int nZCoords, + float minZ, + float maxZ); + + int GetRemovalInProgressFlag() { return GetFlag(FLAGS_REMOVALINPROGRESS); } + void SetRemovalInProgressFlag() { SetFlag(FLAGS_REMOVALINPROGRESS, 1); } + + int GetNeedsBBoxUpdate() { return GetFlag(FLAGS_NEEDS_BBOX_UPDATE); } + void SetNeedsBBoxUpdate(int bFirstUpdate) { SetFlag(FLAGS_NEEDS_BBOX_UPDATE, bFirstUpdate); } + + int GetFirstFrameFlag() { return GetFlag(FLAGS_FIRST_FRAME); } + void SetFirstFrameFlag(int bFirstUpdate) { SetFlag(FLAGS_FIRST_FRAME, bFirstUpdate); } + + int WasDrawn() { return GetFlag(FLAGS_DRAWN); } + void SetDrawn(int bDrawn) { SetFlag(FLAGS_DRAWN, bDrawn); } + + bool RecalculateBoundingBox(); + + CEffectMaterial* GetEffectMaterial(CParticleSubTexture* pSubTexture); + +public: + + virtual const Vector& GetRenderOrigin(void); + virtual const QAngle& GetRenderAngles(void); + virtual const matrix3x4_t& RenderableToWorldTransform(); + virtual void GetRenderBounds(Vector& mins, Vector& maxs); + virtual bool ShouldDraw(void); + virtual int DrawModel(int flags, const RenderableInstance_t& instance); + +private: + enum + { + FLAGS_REMOVE = (1 << 0), + FLAGS_REMOVALINPROGRESS = (1 << 1), + FLAGS_NEEDS_BBOX_UPDATE = (1 << 2), + FLAGS_AUTOUPDATEBBOX = (1 << 3), + FLAGS_ALWAYSSIMULATE = (1 << 4), + FLAGS_DRAWN = (1 << 5), + FLAGS_DRAWN_PREVFRAME = (1 << 6), + FLAGS_CAMERASPACE = (1 << 7), + FLAGS_DRAW_THRU_LEAF_SYSTEM = (1 << 8), + FLAGS_DRAW_BEFORE_VIEW_MODEL = (1 << 9), + FLAGS_AUTOAPPLYLOCALTRANSFORM = (1 << 10), + FLAGS_FIRST_FRAME = (1 << 11), + FLAGS_NEW_PARTICLE_SYSTEM = (1 << 12) + }; + + + VMatrix m_LocalSpaceTransform; + bool m_bLocalSpaceTransformIdentity; + + Vector m_Min; + Vector m_Max; + + Vector m_LastMin; + Vector m_LastMax; + + float m_flParticleCullRadius; + + unsigned short m_nActiveParticles; + + unsigned short m_FrameCode; + + unsigned short m_ListIndex; + + IParticleEffect* m_pSim; + CParticleMgr* m_pParticleMgr; + + int m_Flags; + + enum { EFFECT_MATERIAL_HASH_SIZE = 8 }; + CEffectMaterial* m_EffectMaterialHash[EFFECT_MATERIAL_HASH_SIZE]; + +#ifdef INFESTED_PARTICLES +public: +#endif + CUtlLinkedList m_Materials; + + unsigned short m_UpdateBBoxCounter; +}; + + +class CParticleLightInfo +{ +public: + Vector m_vPos; + Vector m_vColor; + float m_flIntensity; +}; + +typedef IParticleEffect* (*CreateParticleEffectFN)(); + +enum +{ + TOOLPARTICLESYSTEMID_INVALID = -1, +}; + + +class CParticleCollection; + +class CNonDrawingParticleSystem +{ +public: + CNonDrawingParticleSystem* m_pNext; + CNonDrawingParticleSystem* m_pPrev; + CParticleCollection* m_pSystem; + + FORCEINLINE CParticleCollection* operator()(void) const + { + return m_pSystem; + } + + FORCEINLINE CParticleCollection* Get(void) const + { + return m_pSystem; + } + + ~CNonDrawingParticleSystem(void); +}; + + + + +class CClientTools; + +class CParticleMgr +{ + friend class CParticleEffectBinding; + friend class CParticleCollection; + friend class CNonDrawingParticleSystem; + friend class CClientTools; + +public: + + CParticleMgr(); + virtual ~CParticleMgr(); + + bool Init(unsigned long nPreallocatedParticles, IMaterialSystem* pMaterial); + + void Term(); + + void LevelInit(); + + void RegisterEffect(const char* pEffectType, CreateParticleEffectFN func); + IParticleEffect* CreateEffect(const char* pEffectType); + + bool AddEffect(CParticleEffectBinding* pEffect, IParticleEffect* pSim); + void RemoveEffect(CParticleEffectBinding* pEffect); + + void AddEffect(CNewParticleEffect* pEffect); + void RemoveEffect(CNewParticleEffect* pEffect); + + void RemoveAllEffects(); + + void IncrementFrameCode(); + + void Simulate(float fTimeDelta); + + void PostRender(); + + void DrawBeforeViewModelEffects(); + + VMatrix& GetModelView(); + + Particle* AllocParticle(int size); + void FreeParticle(Particle*); + + PMaterialHandle GetPMaterial(const char* pMaterialName); + IMaterial* PMaterialToIMaterial(PMaterialHandle hMaterial); + + void RepairPMaterial(PMaterialHandle hMaterial); + + void GetDirectionalLightInfo(CParticleLightInfo& info) const; + void SetDirectionalLightInfo(const CParticleLightInfo& info); + + void SpewInfo(bool bDetail); + + void AddEffectListener(IClientParticleListener* pListener); + void RemoveEffectListener(IClientParticleListener* pListener); + + int AllocateToolParticleEffectId(); + + void RemoveAllNewEffects(); + + CNewParticleEffect* FirstNewEffect(); + CNewParticleEffect* NextNewEffect(CNewParticleEffect* pEffect); + + void RenderParticleSystems(bool bEnable); + bool ShouldRenderParticleSystems() const; + + void RemoveOldParticleEffects(float flTime); + int GetNumParticles() const { return m_nCurrentParticlesAllocated; } + + + CNonDrawingParticleSystem* CreateNonDrawingEffect(const char* pEffectName); + +private: + struct RetireInfo_t + { + CParticleCollection* m_pCollection; + float m_flScreenArea; + bool m_bFirstFrame; + }; + + void UpdateAllEffects(float flTimeDelta); + + void UpdateNewEffects(float flTimeDelta); + + void SpewActiveParticleSystems(); + + CParticleSubTextureGroup* FindOrAddSubTextureGroup(IMaterial* pPageMaterial); + + int ComputeParticleDefScreenArea(int nInfoCount, RetireInfo_t* pInfo, float* pTotalArea, CParticleSystemDefinition* pDef, + const CViewSetup& view, const VMatrix& worldToPixels, float flFocalDist); + + bool RetireParticleCollections(CParticleSystemDefinition* pDef, int nCount, RetireInfo_t* pInfo, float flScreenArea, float flMaxTotalArea); + void BuildParticleSimList(CUtlVector< CNewParticleEffect* >& list); + bool EarlyRetireParticleSystems(int nCount, CNewParticleEffect** ppEffects); + static int RetireSort(const void* p1, const void* p2); + +private: + + int m_nCurrentParticlesAllocated; + + CParticleLightInfo m_DirectionalLight; + + unsigned short m_FrameCode; + + bool m_bUpdatingEffects; + bool m_bRenderParticleEffects; + + CUtlLinkedList m_Effects; + + CUtlIntrusiveDList< CNewParticleEffect > m_NewEffects; + CUtlIntrusiveDList< CNonDrawingParticleSystem > m_NonDrawingParticleSystems; + + + + CUtlVector< IClientParticleListener*> m_effectListeners; + + IMaterialSystem* m_pMaterialSystem; + + VMatrix m_mModelView; + + CUtlVector m_SubTextureGroups; + CUtlDict m_SubTextures; + CParticleSubTexture m_DefaultInvalidSubTexture; + + CUtlMap< const char*, CreateParticleEffectFN > m_effectFactories; + + int m_nToolParticleEffectId; + + IThreadPool* m_pThreadPool[2]; +}; + +inline int CParticleMgr::AllocateToolParticleEffectId() +{ + return m_nToolParticleEffectId++; +} + +class IClientParticleListener +{ +public: + virtual void OnParticleEffectAdded(IParticleEffect* pEffect) = 0; + virtual void OnParticleEffectRemoved(IParticleEffect* pEffect) = 0; +}; + + + +float Helper_GetTime(); +float Helper_GetFrameTime(); +float Helper_RandomFloat(float minVal, float maxVal); +int Helper_RandomInt(int minVal, int maxVal); + + + +inline VMatrix& CParticleMgr::GetModelView() +{ + return m_mModelView; +} + + + +inline const matrix3x4_t& CParticleEffectBinding::GetLocalSpaceTransform() const +{ + return m_LocalSpaceTransform.As3x4(); +} + + + +CParticleMgr* ParticleMgr(); + + + + +struct StandardParticle_t : public Particle +{ + void SetColor(float r, float g, float b); + void SetAlpha(float a); + + Vector m_Velocity; + + float m_Lifetime; + + unsigned char m_EffectData; + unsigned short m_EffectDataWord; + + unsigned char m_Color[4]; +}; + + +inline void TransformParticle(const VMatrix& vMat, const Vector& vIn, Vector& vOut) +{ + vOut.x = vMat.m[0][0] * vIn.x + vMat.m[0][1] * vIn.y + vMat.m[0][2] * vIn.z + vMat.m[0][3]; + vOut.y = vMat.m[1][0] * vIn.x + vMat.m[1][1] * vIn.y + vMat.m[1][2] * vIn.z + vMat.m[1][3]; + vOut.z = vMat.m[2][0] * vIn.x + vMat.m[2][1] * vIn.y + vMat.m[2][2] * vIn.z + vMat.m[2][3]; +} + + +inline void StandardParticle_t::SetColor(float r, float g, float b) +{ + m_Color[0] = (unsigned char)(r * 255.9f); + m_Color[1] = (unsigned char)(g * 255.9f); + m_Color[2] = (unsigned char)(b * 255.9f); +} + +inline void StandardParticle_t::SetAlpha(float a) +{ + m_Color[3] = (unsigned char)(a * 255.9f); +} + + + +inline void UnlinkParticle(Particle* pParticle) +{ + pParticle->m_pPrev->m_pNext = pParticle->m_pNext; + pParticle->m_pNext->m_pPrev = pParticle->m_pPrev; +} + +inline void InsertParticleBefore(Particle* pInsert, Particle* pNext) +{ + pInsert->m_pNext = pNext; + pInsert->m_pPrev = pNext->m_pPrev; + pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert; +} + +inline void InsertParticleAfter(Particle* pInsert, Particle* pPrev) +{ + pInsert->m_pPrev = pPrev; + pInsert->m_pNext = pPrev->m_pNext; + + pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert; +} + +inline void SwapParticles(Particle* pPrev, Particle* pCur) +{ + UnlinkParticle(pCur); + InsertParticleBefore(pCur, pPrev); +} + + +#include "particle_iterators.h" + + +#endif + +``` + +`SpyCustom/sdk/particles.h`: + +```h +#ifndef PARTICLES_H +#define PARTICLES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib.h" +#include "vector.h" +#include "ssemath.h" +#include "imaterialsystem.h" +#include "dmxelement.h" +#include "utlintrusivelist.h" +#include "random.h" +#include "utlobjectreference.h" +#include "UtlStringMap.h" +#include "utlmap.h" +#include "MaterialSystemUtil.h" +#include "trace.h" +#include "utlsoacontainer.h" + +#if defined( CLIENT_DLL ) +#include "c_pixel_visibility.h" +#endif + +struct DmxElementUnpackStructure_t; +class CParticleSystemDefinition; +class CParticleCollection; +class CParticleOperatorInstance; +class CParticleSystemDictionary; +class CUtlBuffer; +class IParticleOperatorDefinition; +class CSheet; +class CMeshBuilder; +extern float s_pRandomFloats[]; + + +#define MAX_RANDOM_FLOATS 4096 +#define RANDOM_FLOAT_MASK ( MAX_RANDOM_FLOATS - 1 ) + + +#define MAX_PARTICLE_ATTRIBUTES 32 + +#define DEFPARTICLE_ATTRIBUTE( name, bit ) \ + const int PARTICLE_ATTRIBUTE_##name##_MASK = (1 << bit); \ + const int PARTICLE_ATTRIBUTE_##name = bit; + +DEFPARTICLE_ATTRIBUTE(XYZ, 0); + +DEFPARTICLE_ATTRIBUTE(LIFE_DURATION, 1); + +DEFPARTICLE_ATTRIBUTE(PREV_XYZ, 2); + +DEFPARTICLE_ATTRIBUTE(RADIUS, 3); + +DEFPARTICLE_ATTRIBUTE(ROTATION, 4); + +DEFPARTICLE_ATTRIBUTE(ROTATION_SPEED, 5); + +DEFPARTICLE_ATTRIBUTE(TINT_RGB, 6); + +DEFPARTICLE_ATTRIBUTE(ALPHA, 7); + +DEFPARTICLE_ATTRIBUTE(CREATION_TIME, 8); + +DEFPARTICLE_ATTRIBUTE(SEQUENCE_NUMBER, 9); + +DEFPARTICLE_ATTRIBUTE(TRAIL_LENGTH, 10); + +DEFPARTICLE_ATTRIBUTE(PARTICLE_ID, 11); + +DEFPARTICLE_ATTRIBUTE(YAW, 12); + +DEFPARTICLE_ATTRIBUTE(SEQUENCE_NUMBER1, 13); + +DEFPARTICLE_ATTRIBUTE(HITBOX_INDEX, 14); + +DEFPARTICLE_ATTRIBUTE(HITBOX_RELATIVE_XYZ, 15); + +DEFPARTICLE_ATTRIBUTE(ALPHA2, 16); + +DEFPARTICLE_ATTRIBUTE(TRACE_P0, 17); +DEFPARTICLE_ATTRIBUTE(TRACE_P1, 18); +DEFPARTICLE_ATTRIBUTE(TRACE_HIT_T, 19); +DEFPARTICLE_ATTRIBUTE(TRACE_HIT_NORMAL, 20); + + +#define MAX_PARTICLE_CONTROL_POINTS 64 + +#define ATTRIBUTES_WHICH_ARE_VEC3S_MASK ( PARTICLE_ATTRIBUTE_TRACE_P0_MASK | PARTICLE_ATTRIBUTE_TRACE_P1_MASK | \ + PARTICLE_ATTRIBUTE_TRACE_HIT_NORMAL | PARTICLE_ATTRIBUTE_XYZ_MASK | \ + PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | \ + PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK ) +#define ATTRIBUTES_WHICH_ARE_0_TO_1 (PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK) +#define ATTRIBUTES_WHICH_ARE_ANGLES (PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK ) +#define ATTRIBUTES_WHICH_ARE_INTS (PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK ) + +#if defined( _X360 ) +#define MAX_PARTICLES_IN_A_SYSTEM 2000 +#else +#define MAX_PARTICLES_IN_A_SYSTEM 5000 +#endif + +#define MEASURE_PARTICLE_PERF 0 + + +enum ParticleFunctionType_t +{ + FUNCTION_RENDERER = 0, + FUNCTION_OPERATOR, + FUNCTION_INITIALIZER, + FUNCTION_EMITTER, + FUNCTION_CHILDREN, + FUNCTION_FORCEGENERATOR, + FUNCTION_CONSTRAINT, + PARTICLE_FUNCTION_COUNT +}; + +struct CParticleVisibilityInputs +{ + float m_flCameraBias; + float m_flInputMin; + float m_flInputMax; + float m_flAlphaScaleMin; + float m_flAlphaScaleMax; + float m_flRadiusScaleMin; + float m_flRadiusScaleMax; + float m_flProxyRadius; + float m_flBBoxScale; + bool m_bUseBBox; + int m_nCPin; +}; + +struct ModelHitBoxInfo_t +{ + Vector m_vecBoxMins; + Vector m_vecBoxMaxes; + matrix3x4_t m_Transform; +}; + +class CModelHitBoxesInfo +{ +public: + float m_flLastUpdateTime; + float m_flPrevLastUpdateTime; + int m_nNumHitBoxes; + int m_nNumPrevHitBoxes; + ModelHitBoxInfo_t* m_pHitBoxes; + ModelHitBoxInfo_t* m_pPrevBoxes; + + bool CurAndPrevValid(void) const + { + return (m_nNumHitBoxes && (m_nNumPrevHitBoxes == m_nNumHitBoxes)); + } + + CModelHitBoxesInfo(void) + { + m_flLastUpdateTime = -1; + m_nNumHitBoxes = 0; + m_nNumPrevHitBoxes = 0; + m_pHitBoxes = NULL; + m_pPrevBoxes = NULL; + } + + ~CModelHitBoxesInfo(void) + { + if (m_pHitBoxes) + delete[] m_pHitBoxes; + if (m_pPrevBoxes) + delete[] m_pPrevBoxes; + } + +}; + + + + +#define PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION "VParticleSystemQuery001" + +class IParticleSystemQuery : public IAppSystem +{ +public: + virtual void GetLightingAtPoint(const Vector& vecOrigin, Color& tint) = 0; + virtual void TraceLine(const Vector& vecAbsStart, + const Vector& vecAbsEnd, unsigned int mask, + const class IHandleEntity* ignore, + int collisionGroup, + CBaseTrace* ptr) = 0; + + virtual bool MovePointInsideControllingObject(CParticleCollection* pParticles, + void* pObject, + Vector* pPnt) + { + return true; + } + + virtual bool IsPointInControllingObjectHitBox( + CParticleCollection* pParticles, + int nControlPointNumber, Vector vecPos, bool bBBoxOnly = false) + { + return true; + } + + virtual int GetCollisionGroupFromName(const char* pszCollisionGroupName) + { + return 0; + } + + virtual void GetRandomPointsOnControllingObjectHitBox( + CParticleCollection* pParticles, + int nControlPointNumber, + int nNumPtsOut, + float flBBoxScale, + int nNumTrysToGetAPointInsideTheModel, + Vector* pPntsOut, + Vector vecDirectionBias, + Vector* pHitBoxRelativeCoordOut = NULL, + int* pHitBoxIndexOut = NULL) = 0; + + + virtual int GetControllingObjectHitBoxInfo( + CParticleCollection* pParticles, + int nControlPointNumber, + int nBufSize, + ModelHitBoxInfo_t* pHitBoxOutputBuffer) + { + return 0; + } + + virtual Vector GetLocalPlayerPos(void) + { + return vec3_origin; + } + + virtual void GetLocalPlayerEyeVectors(Vector* pForward, Vector* pRight = NULL, Vector* pUp = NULL) + { + *pForward = vec3_origin; + *pRight = vec3_origin; + *pUp = vec3_origin; + } + + virtual float GetPixelVisibility(int* pQueryHandle, const Vector& vecOrigin, float flScale) = 0; + + virtual void SetUpLightingEnvironment(const Vector& pos) + { + } +}; + + +typedef int ParticleSystemHandle_t; + +class CParticleSystemMgr +{ +public: + CParticleSystemMgr(); + ~CParticleSystemMgr(); + + bool Init(IParticleSystemQuery* pQuery); + + void AddBuiltinSimulationOperators(void); + void AddBuiltinRenderingOperators(void); + + + + void AddParticleOperator(ParticleFunctionType_t nOpType, IParticleOperatorDefinition* pOpFactory); + + bool ReadParticleConfigFile(const char* pFileName, bool bPrecache, bool bDecommitTempMemory = true); + bool ReadParticleConfigFile(CUtlBuffer& buf, bool bPrecache, bool bDecommitTempMemory = true, const char* pFileName = NULL); + void DecommitTempMemory(); + + bool WriteParticleConfigFile(const char* pParticleSystemName, CUtlBuffer& buf, bool bPreventNameBasedLookup = false); + bool WriteParticleConfigFile(const DmObjectId_t& id, CUtlBuffer& buf, bool bPreventNameBasedLookup = false); + + CParticleCollection* CreateParticleCollection(const char* pParticleSystemName, float flDelay = 0.0f, int nRandomSeed = 0); + + CParticleCollection* CreateParticleCollection(const DmObjectId_t& id, float flDelay = 0.0f, int nRandomSeed = 0); + + bool IsParticleSystemDefined(const char* pParticleSystemName); + bool IsParticleSystemDefined(const DmObjectId_t& id); + + ParticleSystemHandle_t GetParticleSystemIndex(const char* pParticleSystemName); + + const char* GetParticleSystemNameFromIndex(ParticleSystemHandle_t iIndex); + + int GetParticleSystemCount(void); + + CUtlVector< IParticleOperatorDefinition*>& GetAvailableParticleOperatorList(ParticleFunctionType_t nWhichList); + + const DmxElementUnpackStructure_t* GetParticleSystemDefinitionUnpackStructure(); + + void ShouldLoadSheets(bool bLoadSheets); + CSheet* FindOrLoadSheet(char const* pszFname, ITexture* pTexture); + CSheet* FindOrLoadSheet(IMaterial* pMaterial); + void FlushAllSheets(void); + + + void ResetRenderCache(void); + void AddToRenderCache(CParticleCollection* pParticles); + void DrawRenderCache(bool bShadowDepth); + + IParticleSystemQuery* Query(void) { return m_pQuery; } + + const char* GetParticleFieldName(int nParticleField) const; + + CParticleSystemDefinition* FindParticleSystem(const char* pName); + CParticleSystemDefinition* FindParticleSystem(const DmObjectId_t& id); + + void CommitProfileInformation(bool bCommit); + + void DumpProfileInformation(void); + + void PrecacheParticleSystem(const char* pName); + void UncacheAllParticleSystems(); + + void SetLastSimulationTime(float flTime); + float GetLastSimulationTime() const; + + int Debug_GetTotalParticleCount() const; + bool Debug_FrameWarningNeededTestAndReset(); + float ParticleThrottleScaling() const; + bool ParticleThrottleRandomEnable() const; + + void TallyParticlesRendered(int nVertexCount, int nIndexCount = 0); + +private: + struct RenderCache_t + { + IMaterial* m_pMaterial; + CUtlVector< CParticleCollection* > m_ParticleCollections; + }; + + struct BatchStep_t + { + CParticleCollection* m_pParticles; + CParticleOperatorInstance* m_pRenderer; + void* m_pContext; + int m_nFirstParticle; + int m_nParticleCount; + int m_nVertCount; + }; + + struct Batch_t + { + int m_nVertCount; + int m_nIndexCount; + CUtlVector< BatchStep_t > m_BatchStep; + }; + + bool ReadParticleDefinitions(CUtlBuffer& buf, const char* pFileName, bool bPrecache, bool bDecommitTempMemory); + void AddParticleSystem(CDmxElement* pParticleSystem); + + CDmxElement* CreateParticleDmxElement(const DmObjectId_t& id); + CDmxElement* CreateParticleDmxElement(const char* pParticleSystemName); + + bool WriteParticleConfigFile(CDmxElement* pParticleSystem, CUtlBuffer& buf, bool bPreventNameBasedLookup); + + void BuildBatchList(int iRenderCache, IMatRenderContext* pRenderContext, CUtlVector< Batch_t >& batches); + + CUtlVector m_ParticleOperators[PARTICLE_FUNCTION_COUNT]; + + CParticleSystemDictionary* m_pParticleSystemDictionary; + + typedef CUtlStringMap< CSheet* > SheetsCache_t; + SheetsCache_t m_SheetList; + + void AttachKillList(CParticleCollection* pParticles); + void DetachKillList(CParticleCollection* pParticles); + + CParticleCollection* m_pVisualizedParticles; + DmObjectId_t m_VisualizedOperatorId; + IParticleSystemQuery* m_pQuery; + CUtlVector< RenderCache_t > m_RenderCache; + IMaterial* m_pShadowDepthMaterial; + float m_flLastSimulationTime; + + bool m_bDidInit; + bool m_bUsingDefaultQuery; + bool m_bShouldLoadSheets; + + int m_nNumFramesMeasured; + + enum { c_nNumFramesTracked = 10 }; + int m_nParticleVertexCountHistory[c_nNumFramesTracked]; + float m_fParticleCountScaling; + int m_nParticleIndexCount; + int m_nParticleVertexCount; + bool m_bFrameWarningNeeded; + + friend class CParticleSystemDefinition; + friend class CParticleCollection; +}; + +extern CParticleSystemMgr* g_pParticleSystemMgr; + + +enum ParticleOperatorId_t +{ + OPERATOR_GENERIC = -2, + OPERATOR_SINGLETON = -1, + + OPERATOR_PI_POSITION, + OPERATOR_PI_RADIUS, + OPERATOR_PI_ALPHA, + OPERATOR_PI_TINT_RGB, + OPERATOR_PI_ROTATION, + OPERATOR_PI_YAW, + + OPERATOR_ID_COUNT, +}; + + +class IParticleOperatorDefinition +{ +public: + virtual const char* GetName() const = 0; + virtual CParticleOperatorInstance* CreateInstance(const DmObjectId_t& id) const = 0; + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const = 0; + virtual ParticleOperatorId_t GetId() const = 0; + virtual bool IsObsolete() const = 0; + virtual size_t GetClassSize() const = 0; + +#if MEASURE_PARTICLE_PERF + float m_flMaxExecutionTime; + float m_flTotalExecutionTime; + float m_flUncomittedTime; + + FORCEINLINE void RecordExecutionTime(float flETime) + { + m_flUncomittedTime += flETime; + m_flMaxExecutionTime = MAX(m_flMaxExecutionTime, flETime); + } + + FORCEINLINE float TotalRecordedExecutionTime(void) const + { + return m_flTotalExecutionTime; + } + + FORCEINLINE float MaximumRecordedExecutionTime(void) const + { + return m_flMaxExecutionTime; + } +#endif +}; + + +class CParticleOperatorInstance +{ +public: + void* operator new(size_t nSize); + void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine); + void operator delete(void* pData); + void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine); + + virtual void InitParams(CParticleSystemDefinition* pDef, CDmxElement* pElement) + { + } + + virtual size_t GetRequiredContextBytes() const + { + return 0; + } + + virtual void InitializeContextData(CParticleCollection* pParticles, void* pContext) const + { + } + + virtual uint32 GetWrittenAttributes(void) const = 0; + virtual uint32 GetReadAttributes(void) const = 0; + virtual uint64 GetReadControlPointMask() const + { + return 0; + } + + virtual uint32 GetReadInitialAttributes(void) const + { + return 0; + } + + virtual void Operate(CParticleCollection* pParticles, float flOpStrength, void* pContext) const + { + } + + virtual void Render(IMatRenderContext* pRenderContext, + CParticleCollection* pParticles, void* pContext) const + { + } + + virtual bool IsBatchable() const + { + return true; + } + + virtual void RenderUnsorted(CParticleCollection* pParticles, void* pContext, IMatRenderContext* pRenderContext, CMeshBuilder& meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount) const + { + } + + virtual int GetParticlesToRender(CParticleCollection* pParticles, void* pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int* pVertsUsed, int* pIndicesUsed) const + { + *pVertsUsed = 0; + *pIndicesUsed = 0; + return 0; + } + + + virtual uint32 Emit(CParticleCollection* pParticles, float flOpCurStrength, + void* pContext) const + { + return 0; + } + + virtual void StopEmission(CParticleCollection* pParticles, void* pContext, bool bInfiniteOnly = false) const + { + } + virtual void StartEmission(CParticleCollection* pParticles, void* pContext, bool bInfiniteOnly = false) const + { + } + virtual void Restart(CParticleCollection* pParticles, void* pContext) {} + + virtual void InitParticleSystem(CParticleCollection* pParticles, void* pContext) const + { + } + + + virtual void AddForces(FourVectors* AccumulatedForces, + CParticleCollection* pParticles, + int nBlocks, + float flCurStrength, + void* pContext) const + { + } + + + virtual void SetupConstraintPerFrameData(CParticleCollection* pParticles, + void* pContext) const + { + } + + + virtual bool EnforceConstraint(int nStartBlock, + int nNumBlocks, + CParticleCollection* pParticles, + void* pContext, + int nNumValidParticlesInLastChunk) const + { + return false; + } + + virtual bool IsFinalConstraint(void) const + { + return false; + } + + virtual bool InitMultipleOverride() + { + return false; + } + + + virtual bool IsScrubSafe() + { + return false; + } + + virtual void InitNewParticlesScalar(CParticleCollection* pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void* pContext) const + { + } + + virtual void InitNewParticlesBlock(CParticleCollection* pParticles, int start_block, int n_blocks, int attribute_write_mask, void* pContext) const + { + InitNewParticlesScalar(pParticles, 4 * start_block, 4 * n_blocks, attribute_write_mask, pContext); + } + + void InitNewParticles(CParticleCollection* pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void* pContext) const; + + + virtual bool MayCreateMoreParticles(CParticleCollection* pParticles, void* pContext) const + { + return false; + } + + const IParticleOperatorDefinition* GetDefinition() + { + return m_pDef; + } + + virtual bool ShouldRunBeforeEmitters(void) const + { + return false; + } + + virtual bool RequiresOrderInvariance(void) const + { + return false; + } + + virtual void SkipToTime(float flTime, CParticleCollection* pParticles, void* pContext) const {} + + const DmObjectId_t& GetId() { return m_Id; } + + virtual void Render(CParticleCollection* pParticles) const {} + + int RandomInt(int nMin, int nMax) + { + Assert(0); + return 0; + } + + float RandomFloat(float flMinVal = 0.0f, float flMaxVal = 1.0f) + { + Assert(0); + return 0.0f; + } + + float RandomFloatExp(float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f) + { + Assert(0); + return 0.0f; + } + + float m_flOpStartFadeInTime; + float m_flOpEndFadeInTime; + float m_flOpStartFadeOutTime; + float m_flOpEndFadeOutTime; + float m_flOpFadeOscillatePeriod; + + virtual ~CParticleOperatorInstance(void) + { + } + +protected: + void InitScalarAttributeRandomRangeBlock(int nAttributeId, float fMinValue, float fMaxValue, + CParticleCollection* pParticles, int nStartBlock, int nBlockCount) const; + void InitScalarAttributeRandomRangeExpBlock(int nAttributeId, float fMinValue, float fMaxValue, float fExp, + CParticleCollection* pParticles, int nStartBlock, int nBlockCount) const; + void AddScalarAttributeRandomRangeBlock(int nAttributeId, float fMinValue, float fMaxValue, float fExp, + CParticleCollection* pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert) const; + +private: + friend class CParticleCollection; + + const IParticleOperatorDefinition* m_pDef; + void SetDefinition(const IParticleOperatorDefinition* pDef, const DmObjectId_t& id) + { + m_pDef = pDef; + CopyUniqueId(id, &m_Id); + } + + DmObjectId_t m_Id; + + template friend class CParticleOperatorDefinition; +}; + +class CParticleRenderOperatorInstance : public CParticleOperatorInstance +{ +public: + + CParticleVisibilityInputs VisibilityInputs; +}; + +template < class T > +class CParticleOperatorDefinition : public IParticleOperatorDefinition +{ +public: + CParticleOperatorDefinition(const char* pFactoryName, ParticleOperatorId_t id, bool bIsObsolete) : m_pFactoryName(pFactoryName), m_Id(id) + { +#if MEASURE_PARTICLE_PERF + m_flTotalExecutionTime = 0.0f; + m_flMaxExecutionTime = 0.0f; + m_flUncomittedTime = 0.0f; +#endif + m_bIsObsolete = bIsObsolete; + } + + virtual const char* GetName() const + { + return m_pFactoryName; + } + + virtual ParticleOperatorId_t GetId() const + { + return m_Id; + } + + virtual CParticleOperatorInstance* CreateInstance(const DmObjectId_t& id) const + { + CParticleOperatorInstance* pOp = new T; + pOp->SetDefinition(this, id); + return pOp; + } + + virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const + { + return m_pUnpackParams; + } + + virtual bool IsObsolete() const + { + return m_bIsObsolete; + } + + virtual size_t GetClassSize() const + { + return sizeof(T); + } + +private: + const char* m_pFactoryName; + ParticleOperatorId_t m_Id; + bool m_bIsObsolete; + static DmxElementUnpackStructure_t* m_pUnpackParams; +}; + +#define DECLARE_PARTICLE_OPERATOR( _className ) \ + DECLARE_DMXELEMENT_UNPACK() \ + friend class CParticleOperatorDefinition<_className > + +#define DEFINE_PARTICLE_OPERATOR( _className, _operatorName, _id ) \ + static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, false ) + +#define DEFINE_PARTICLE_OPERATOR_OBSOLETE( _className, _operatorName, _id ) \ + static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, true ) + +#define BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \ + BEGIN_DMXELEMENT_UNPACK( _className ) \ + DMXELEMENT_UNPACK_FIELD( "operator start fadein","0", float, m_flOpStartFadeInTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator end fadein","0", float, m_flOpEndFadeInTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator start fadeout","0", float, m_flOpStartFadeOutTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator end fadeout","0", float, m_flOpEndFadeOutTime ) \ + DMXELEMENT_UNPACK_FIELD( "operator fade oscillate","0", float, m_flOpFadeOscillatePeriod ) + +#define END_PARTICLE_OPERATOR_UNPACK( _className ) \ + END_DMXELEMENT_UNPACK_TEMPLATE( _className, CParticleOperatorDefinition<_className>::m_pUnpackParams ) + +#define BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( _className ) \ + BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Input Control Point Number", "-1", int, VisibilityInputs.m_nCPin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Radius", "1.0", float, VisibilityInputs.m_flProxyRadius ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility input minimum","0", float, VisibilityInputs.m_flInputMin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility input maximum","1", float, VisibilityInputs.m_flInputMax ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale minimum","0", float, VisibilityInputs.m_flAlphaScaleMin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale maximum","1", float, VisibilityInputs.m_flAlphaScaleMax ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale minimum","1", float, VisibilityInputs.m_flRadiusScaleMin ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale maximum","1", float, VisibilityInputs.m_flRadiusScaleMax ) \ + DMXELEMENT_UNPACK_FIELD( "Visibility Camera Depth Bias", "0", float, VisibilityInputs.m_flCameraBias ) + +#define REGISTER_PARTICLE_OPERATOR( _type, _className ) \ + g_pParticleSystemMgr->AddParticleOperator( _type, &s_##_className##Factory ) + + + +enum +{ + PCFLAGS_FIRST_FRAME = 0x1, + PCFLAGS_PREV_CONTROL_POINTS_INITIALIZED = 0x2, +}; + + + +#define DEBUG_PARTICLE_SORT 0 + +struct ParticleRenderData_t +{ + float m_flSortKey; + int m_nIndex; + float m_flRadius; +#if VALVE_LITTLE_ENDIAN + uint8 m_nAlpha; + uint8 m_nAlphaPad[3]; +#else + uint8 m_nAlphaPad[3]; + uint8 m_nAlpha; +#endif +}; + +struct ExtendedParticleRenderData_t : ParticleRenderData_t +{ + float m_flX; + float m_flY; + float m_flZ; + float m_flPad; +}; + + +typedef struct ALIGN16 _FourInts +{ + int32 m_nValue[4]; +} ALIGN16_POST FourInts; + + + +struct CPathParameters +{ + int m_nStartControlPointNumber; + int m_nEndControlPointNumber; + int m_nBulgeControl; + float m_flBulge; + float m_flMidPoint; + + void ClampControlPointIndices(void) + { + m_nStartControlPointNumber = MAX(0, MIN(MAX_PARTICLE_CONTROL_POINTS - 1, m_nStartControlPointNumber)); + m_nEndControlPointNumber = MAX(0, MIN(MAX_PARTICLE_CONTROL_POINTS - 1, m_nEndControlPointNumber)); + } +}; + +struct CParticleVisibilityData +{ + float m_flAlphaVisibility; + float m_flRadiusVisibility; + float m_flCameraBias; + bool m_bUseVisibility; +}; + +struct CParticleControlPoint +{ + Vector m_Position; + Vector m_PrevPosition; + + Vector m_ForwardVector; + Vector m_UpVector; + Vector m_RightVector; + + void* m_pObject; + + int m_nParent; +}; + + +struct CParticleSIMDTransformation +{ + FourVectors m_v4Origin; + FourVectors m_v4Fwd; + FourVectors m_v4Up; + FourVectors m_v4Right; + + + FORCEINLINE void VectorRotate(FourVectors& InPnt) + { + fltx4 fl4OutX = SubSIMD(AddSIMD(MulSIMD(InPnt.x, m_v4Fwd.x), MulSIMD(InPnt.z, m_v4Up.x)), MulSIMD(InPnt.y, m_v4Right.x)); + fltx4 fl4OutY = SubSIMD(AddSIMD(MulSIMD(InPnt.x, m_v4Fwd.y), MulSIMD(InPnt.z, m_v4Up.y)), MulSIMD(InPnt.y, m_v4Right.y)); + InPnt.z = SubSIMD(AddSIMD(MulSIMD(InPnt.x, m_v4Fwd.z), MulSIMD(InPnt.z, m_v4Up.z)), MulSIMD(InPnt.y, m_v4Right.z)); + InPnt.x = fl4OutX; + InPnt.y = fl4OutY; + } + + FORCEINLINE void VectorTransform(FourVectors& InPnt) + { + VectorRotate(InPnt); + InPnt.x = AddSIMD(InPnt.x, m_v4Origin.x); + InPnt.y = AddSIMD(InPnt.y, m_v4Origin.y); + InPnt.z = AddSIMD(InPnt.z, m_v4Origin.z); + } +}; + +#define NUM_COLLISION_CACHE_MODES 4 + + +struct CUtlString_simple { + char* buffer; + int capacity; + int grow_size; + int length; +}; + +class CParticleSystemDefinition { + BYTE pad_0[308]; +public: + CUtlString_simple m_Name; +}; + +struct CParticleAttributeAddressTable { + float* m_pAttributes[MAX_PARTICLE_ATTRIBUTES]; + size_t m_nFloatStrides[MAX_PARTICLE_ATTRIBUTES]; + + FORCEINLINE float* FloatAttributePtr(int nAttribute, int nParticleNumber) const { + int block_ofs = nParticleNumber / 4; + return m_pAttributes[nAttribute] + + m_nFloatStrides[nAttribute] * block_ofs + + (nParticleNumber & 3); + } + +}; + +class CParticleCollection { + BYTE pad_0[48]; +public: + int m_nActiveParticles; +private: + BYTE pad_1[12]; +public: + CUtlReference m_pDef; +private: + BYTE pad_2[60]; +public: + CParticleCollection* m_pParent; +private: + BYTE pad_3[84]; +public: + CParticleAttributeAddressTable m_ParticleAttributes; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif + +``` + +`SpyCustom/sdk/particles_new.h`: + +```h +#ifndef PARTICLES_NEW_H +#define PARTICLES_NEW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particlemgr.h" +#include "particles.h" +#include "particlesphererenderer.h" +#include "smartptr.h" +#include "particles_simple.h" +#include "utlobjectreference.h" + + +class CNewParticleEffect : public IParticleEffect, public CParticleCollection, public CDefaultClientRenderable +{ +public: + DECLARE_CLASS_NOBASE(CNewParticleEffect); + DECLARE_REFERENCED_CLASS(CNewParticleEffect); + +public: + friend class CRefCountAccessor; + + CNewParticleEffect* m_pNext; + CNewParticleEffect* m_pPrev; + + void SetSortOrigin(const Vector& vSortOrigin); + bool ShouldDraw(void); + virtual bool IsTransparent(void); + virtual bool IsTwoPass(void); + virtual bool UsesPowerOfTwoFrameBufferTexture(void); + virtual bool UsesFullFrameBufferTexture(void); + const QAngle& GetRenderAngles(void); + const matrix3x4_t& RenderableToWorldTransform(); + void GetRenderBounds(Vector& mins, Vector& maxs); + + void DetectChanges(void); + const Vector& GetRenderOrigin(void); + PMaterialHandle GetPMaterial(const char* name); + bool RecalculateBoundingBox(); + Particle* AddParticle(unsigned int particleSize, PMaterialHandle material, const Vector& origin); + const char* GetEffectName(); + void SetDontRemove(bool bSet); + void SetDrawn(bool bDrawn); + void SetFirstFrameFlag(bool bFirst); + void SetNeedsBBoxUpdate(bool bNeedsUpdate); + void SetAutoUpdateBBox(bool bNeedsUpdate); + void SetRemoveFlag(void); + bool GetRemoveFlag(void); + bool GetFirstFrameFlag(void); + bool GetNeedsBBoxUpdate(void); + bool GetAutoUpdateBBox(void); + bool ShouldPerformCullCheck() const; + void MarkShouldPerformCullCheck(bool bEnable); + CBaseEntity* GetOwner(void) { return m_hOwner; } + void SetOwner(CBaseEntity* pOwner) { m_hOwner = pOwner; } + CNewParticleEffect* ReplaceWith(const char* pParticleSystemName); + + static CSmartPtr Create(CBaseEntity* pOwner, const char* pParticleSystemName, + const char* pDebugName = NULL); + static CSmartPtr Create(CBaseEntity* pOwner, CParticleSystemDefinition* pDef, + const char* pDebugName = NULL); + virtual int DrawModel(int flags); + + void DebugDrawBbox(bool bCulled); + +public: + void StopEmission(bool bInfiniteOnly = false, bool bRemoveAllParticles = false, bool bWakeOnStop = false); + void SetDormant(bool bDormant); + void SetControlPoint(int nWhichPoint, const Vector& v); + void SetControlPointEntity(int nWhichPoint, CBaseEntity* pEntity); + void SetControlPointOrientation(int nWhichPoint, const Quaternion& q); + void SetControlPointOrientation(int nWhichPoint, const Vector& forward, const Vector& right, const Vector& up); + void SetControlPointForwardVector(int nWhichPoint, const Vector& v); + void SetControlPointUpVector(int nWhichPoint, const Vector& v); + void SetControlPointRightVector(int nWhichPoint, const Vector& v); + + FORCEINLINE EHANDLE const& GetControlPointEntity(int nWhichPoint) + { + return m_hControlPointOwners[nWhichPoint]; + } + + +public: + + virtual void SimulateParticles(CParticleSimulateIterator* pIterator) + { + } + virtual void RenderParticles(CParticleRenderIterator* pIterator) + { + } + + virtual void SetParticleCullRadius(float radius); + virtual void NotifyRemove(void); + virtual const Vector& GetSortOrigin(void); + + virtual void Update(float flTimeDelta); + + void SetDynamicallyAllocated(bool bDynamic = true); + + virtual bool ShouldSimulate() const { return m_bSimulate; } + virtual void SetShouldSimulate(bool bSim) { m_bSimulate = bSim; } + + int AllocateToolParticleEffectId(); + int GetToolParticleEffectId() const; + CNewParticleEffect(CBaseEntity* pOwner, const char* pEffectName); + CNewParticleEffect(CBaseEntity* pOwner, CParticleSystemDefinition* pEffect); + virtual ~CNewParticleEffect(); + +protected: + int IsReleased(); + + const char* m_pDebugName; + + bool m_bDontRemove : 1; + bool m_bRemove : 1; + bool m_bDrawn : 1; + bool m_bNeedsBBoxUpdate : 1; + bool m_bIsFirstFrame : 1; + bool m_bAutoUpdateBBox : 1; + bool m_bAllocated : 1; + bool m_bSimulate : 1; + bool m_bShouldPerformCullCheck : 1; + + int m_nToolParticleEffectId; + Vector m_vSortOrigin; + EHANDLE m_hOwner; + EHANDLE m_hControlPointOwners[MAX_PARTICLE_CONTROL_POINTS]; + + Vector m_LastMin; + Vector m_LastMax; + +private: + void AddRef(); + void Release(); + void RecordControlPointOrientation(int nWhichPoint); + void Construct(); + + int m_RefCount; + CNewParticleEffect(const CNewParticleEffect&); +}; + + +inline int CNewParticleEffect::GetToolParticleEffectId() const +{ + return m_nToolParticleEffectId; +} + +inline int CNewParticleEffect::AllocateToolParticleEffectId() +{ + m_nToolParticleEffectId = ParticleMgr()->AllocateToolParticleEffectId(); + return m_nToolParticleEffectId; +} + +inline void CNewParticleEffect::SetSortOrigin(const Vector& vSortOrigin) +{ + m_vSortOrigin = vSortOrigin; +} + +inline const Vector& CNewParticleEffect::GetSortOrigin(void) +{ + return m_vSortOrigin; +} + +inline bool CNewParticleEffect::ShouldDraw(void) +{ + return true; +} + +inline bool CNewParticleEffect::IsTransparent(void) +{ + return CParticleCollection::IsTranslucent(); +} + +inline const QAngle& CNewParticleEffect::GetRenderAngles(void) +{ + return vec3_angle; +} + +inline const matrix3x4_t& CNewParticleEffect::RenderableToWorldTransform() +{ + static matrix3x4_t mat; + SetIdentityMatrix(mat); + PositionMatrix(GetRenderOrigin(), mat); + return mat; +} + +inline Vector const& CNewParticleEffect::GetRenderOrigin(void) +{ + return m_vSortOrigin; +} + +inline PMaterialHandle CNewParticleEffect::GetPMaterial(const char* name) +{ + Assert(0); + return NULL; +} + +inline Particle* CNewParticleEffect::AddParticle(unsigned int particleSize, PMaterialHandle material, const Vector& origin) +{ + Assert(0); + return NULL; +} + + +inline const char* CNewParticleEffect::GetEffectName() +{ + return GetName(); +} + +inline void CNewParticleEffect::SetDontRemove(bool bSet) +{ + m_bDontRemove = bSet; +} + +inline void CNewParticleEffect::SetDrawn(bool bDrawn) +{ + m_bDrawn = bDrawn; +} + +inline void CNewParticleEffect::SetFirstFrameFlag(bool bFirst) +{ + m_bIsFirstFrame = bFirst; +} + +inline void CNewParticleEffect::SetDynamicallyAllocated(bool bDynamic) +{ + m_bAllocated = bDynamic; +} + +inline void CNewParticleEffect::SetNeedsBBoxUpdate(bool bNeedsUpdate) +{ + m_bNeedsBBoxUpdate = bNeedsUpdate; +} + +inline void CNewParticleEffect::SetAutoUpdateBBox(bool bNeedsUpdate) +{ + m_bAutoUpdateBBox = bNeedsUpdate; +} + +inline void CNewParticleEffect::SetRemoveFlag(void) +{ + m_bRemove = true; +} + +inline bool CNewParticleEffect::GetRemoveFlag(void) +{ + return m_bRemove; +} + +inline bool CNewParticleEffect::GetFirstFrameFlag(void) +{ + return m_bIsFirstFrame; +} + +inline bool CNewParticleEffect::GetNeedsBBoxUpdate(void) +{ + return m_bNeedsBBoxUpdate; +} + +inline bool CNewParticleEffect::GetAutoUpdateBBox(void) +{ + return m_bAutoUpdateBBox; +} + +inline bool CNewParticleEffect::ShouldPerformCullCheck() const +{ + return m_bShouldPerformCullCheck; +} + +inline void CNewParticleEffect::MarkShouldPerformCullCheck(bool bEnable) +{ + m_bShouldPerformCullCheck = bEnable; +} + +inline CSmartPtr CNewParticleEffect::Create(CBaseEntity* pOwner, const char* pParticleSystemName, const char* pDebugName) +{ + CNewParticleEffect* pRet = new CNewParticleEffect(pOwner, pParticleSystemName); + pRet->m_pDebugName = pDebugName; + pRet->SetDynamicallyAllocated(true); + return pRet; +} + +inline CSmartPtr CNewParticleEffect::Create(CBaseEntity* pOwner, CParticleSystemDefinition* pDef, const char* pDebugName) +{ + CNewParticleEffect* pRet = new CNewParticleEffect(pOwner, pDef); + pRet->m_pDebugName = pDebugName; + pRet->SetDynamicallyAllocated(true); + return pRet; +} + +typedef CUtlReference HPARTICLEFFECT; + + +#endif +``` + +`SpyCustom/sdk/particles_simple.h`: + +```h +#ifndef PARTICLES_SIMPLE_H +#define PARTICLES_SIMPLE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "particlemgr.h" +#include "ParticleSphereRenderer.h" +#include "smartptr.h" + + +class CParticleEffect : public IParticleEffect +{ +public: + DECLARE_CLASS_NOBASE(CParticleEffect); + + friend class CRefCountAccessor; + + void SetSortOrigin(const Vector& vSortOrigin); + + PMaterialHandle GetPMaterial(const char* name); + + Particle* AddParticle(unsigned int particleSize, PMaterialHandle material, const Vector& origin); + + CParticleEffectBinding& GetBinding() { return m_ParticleEffect; } + + const char* GetEffectName(); + + void AddFlags(int iFlags) { m_Flags |= iFlags; } + void RemoveFlags(int iFlags) { m_Flags &= ~iFlags; } + + void SetDontRemove(bool bSet) + { + if (bSet) + AddFlags(FLAG_DONT_REMOVE); + else + RemoveFlags(FLAG_DONT_REMOVE); + } + +public: + + virtual void SetParticleCullRadius(float radius); + virtual void NotifyRemove(void); + virtual const Vector& GetSortOrigin(); + virtual void NotifyDestroyParticle(Particle* pParticle); + virtual void Update(float flTimeDelta); + + void SetDynamicallyAllocated(bool bDynamic = true); + + virtual bool ShouldSimulate() const { return m_bSimulate; } + virtual void SetShouldSimulate(bool bSim) { m_bSimulate = bSim; } + + int AllocateToolParticleEffectId(); + int GetToolParticleEffectId() const; +protected: + CParticleEffect(const char* pDebugName); + virtual ~CParticleEffect(); + + int IsReleased(); + + enum + { + FLAG_ALLOCATED = (1 << 1), + FLAG_DONT_REMOVE = (1 << 2), + }; + + char const* m_pDebugName; + + CParticleEffectBinding m_ParticleEffect; + Vector m_vSortOrigin; + + int m_Flags; + + bool m_bSimulate; + int m_nToolParticleEffectId; + +private: + void AddRef(); + void Release(); + + int m_RefCount; + CParticleEffect(const CParticleEffect&); +}; + +inline int CParticleEffect::GetToolParticleEffectId() const +{ + return m_nToolParticleEffectId; +} + +inline int CParticleEffect::AllocateToolParticleEffectId() +{ + m_nToolParticleEffectId = ParticleMgr()->AllocateToolParticleEffectId(); + return m_nToolParticleEffectId; +} + + +enum SimpleParticleFlag_t +{ + SIMPLE_PARTICLE_FLAG_WINDBLOWN = 0x1, + SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY = 0x2 +}; + +class SimpleParticle : public Particle +{ +public: + SimpleParticle() : m_iFlags(0) {} + + Vector m_vecVelocity; + float m_flRoll; + float m_flDieTime; + float m_flLifetime; + unsigned char m_uchColor[3]; + unsigned char m_uchStartAlpha; + unsigned char m_uchEndAlpha; + unsigned char m_uchStartSize; + unsigned char m_uchEndSize; + unsigned char m_iFlags; + float m_flRollDelta; +}; + + + +class CSimpleEmitter : public CParticleEffect +{ +public: + + DECLARE_CLASS(CSimpleEmitter, CParticleEffect); + + static CSmartPtr Create(const char* pDebugName); + + virtual void SimulateParticles(CParticleSimulateIterator* pIterator); + virtual void RenderParticles(CParticleRenderIterator* pIterator); + + void SetNearClip(float nearClipMin, float nearClipMax); + + void SetDrawBeforeViewModel(bool state = true); + + SimpleParticle* AddSimpleParticle(PMaterialHandle hMaterial, const Vector& vOrigin, float flDieTime = 3, unsigned char uchSize = 10); + + void SetShouldDrawForSplitScreenUser(int nSlot); + +protected: + CSimpleEmitter(const char* pDebugName = NULL); + virtual ~CSimpleEmitter(); + + virtual float UpdateAlpha(const SimpleParticle* pParticle); + virtual float UpdateScale(const SimpleParticle* pParticle); + virtual float UpdateRoll(SimpleParticle* pParticle, float timeDelta); + virtual void UpdateVelocity(SimpleParticle* pParticle, float timeDelta); + virtual Vector UpdateColor(const SimpleParticle* pParticle); + + float m_flNearClipMin; + float m_flNearClipMax; + + int m_nSplitScreenPlayerSlot; + + +private: + CSimpleEmitter(const CSimpleEmitter&); +}; + +class CEmberEffect : public CSimpleEmitter +{ +public: + CEmberEffect(const char* pDebugName); + static CSmartPtr Create(const char* pDebugName); + + virtual void UpdateVelocity(SimpleParticle* pParticle, float timeDelta); + virtual Vector UpdateColor(const SimpleParticle* pParticle); + +private: + CEmberEffect(const CEmberEffect&); +}; + + +class CFireSmokeEffect : public CSimpleEmitter +{ +public: + CFireSmokeEffect(const char* pDebugName); + static CSmartPtr Create(const char* pDebugName); + + virtual void UpdateVelocity(SimpleParticle* pParticle, float timeDelta); + virtual float UpdateAlpha(const SimpleParticle* pParticle); + +protected: + VPlane m_planeClip; + +private: + CFireSmokeEffect(const CFireSmokeEffect&); +}; + + +class CFireParticle : public CSimpleEmitter +{ +public: + CFireParticle(const char* pDebugName); + static CSmartPtr Create(const char* pDebugName); + + virtual Vector UpdateColor(const SimpleParticle* pParticle); + +private: + CFireParticle(const CFireParticle&); +}; + + +#endif +``` + +`SpyCustom/sdk/platform.h`: + +```h +#ifndef PLATFORM_H +#define PLATFORM_H + +#if defined( _X360 ) +#define NO_STEAM +#define NO_VOICE +#define _XBOX +#include +#include +#include +#include +#include +#include +#include +#undef _XBOX +#endif + +#include "wchartypes.h" +#include "basetypes.h" +#include "valve_off.h" + +#ifdef _DEBUG +#if !defined( PLAT_COMPILE_TIME_ASSERT ) +#define PLAT_COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#endif +#else +#if !defined( PLAT_COMPILE_TIME_ASSERT ) +#define PLAT_COMPILE_TIME_ASSERT( pred ) +#endif +#endif + +#ifdef _WIN32 +#pragma once +#endif + +#define NEW_SOFTWARE_LIGHTING + +#ifdef POSIX +#include +#include +#include +#include +#endif + +#include +#include + + +#include + +#include "valve_minmax_on.h" + +#ifdef _RETAIL +#define IsRetail() true +#else +#define IsRetail() false +#endif + +#ifdef _DEBUG +#define IsRelease() false +#define IsDebug() true +#else +#define IsRelease() true +#define IsDebug() false +#endif + +#define IsXbox() false + +#ifdef _WIN32 +#define IsLinux() false +#define IsOSX() false +#define IsPosix() false +#define PLATFORM_WINDOWS 1 +#ifndef _X360 +#define IsWindows() true +#define IsPC() true +#define IsConsole() false +#define IsX360() false +#define IsPS3() false +#define IS_WINDOWS_PC +#define PLATFORM_WINDOWS_PC 1 +#ifdef _WIN64 +#define IsPlatformWindowsPC64() true +#define IsPlatformWindowsPC32() false +#define PLATFORM_WINDOWS_PC64 1 +#else +#define IsPlatformWindowsPC64() false +#define IsPlatformWindowsPC32() true +#define PLATFORM_WINDOWS_PC32 1 +#endif +#else +#define PLATFORM_X360 1 +#ifndef _CONSOLE +#define _CONSOLE +#endif +#define IsWindows() false +#define IsPC() false +#define IsConsole() true +#define IsX360() true +#define IsPS3() false +#endif +#if defined( DX_TO_GL_ABSTRACTION ) +#define IsPlatformOpenGL() true +#else +#define IsPlatformOpenGL() false +#endif +#elif defined(POSIX) +#define IsPC() true +#define IsWindows() false +#define IsConsole() false +#define IsX360() false +#define IsPS3() false +#if defined( LINUX ) +#define IsLinux() true +#else +#define IsLinux() false +#endif + +#if defined( OSX ) +#define IsOSX() true +#else +#define IsOSX() false +#endif + +#define IsPosix() true +#define IsPlatformOpenGL() true +#else +#error +#endif + +typedef unsigned char uint8; +typedef signed char int8; + +#if defined(__x86_64__) || defined(_WIN64) +#define X64BITS +#endif + +#if defined( _WIN32 ) + +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; + +#ifdef PLATFORM_64BITS +typedef __int64 intp; +typedef unsigned __int64 uintp; +#else +typedef __int32 intp; +typedef unsigned __int32 uintp; +#endif + +#if defined( _X360 ) +#ifdef __m128 +#undef __m128 +#endif +#define __m128 __vector4 +#endif + +#define OVERRIDE override + +#else + +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; +#ifdef X64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif +typedef void* HWND; + +#undef OVERRIDE +#if defined(__clang__) +#define OVERRIDE override +#pragma GCC diagnostic ignored "-Wc++11-extensions" +#else +#define OVERRIDE +#endif + +#endif + +typedef uint32 RTime32; + +typedef float float32; +typedef double float64; + +typedef unsigned int uint; + +#ifdef _MSC_VER +#pragma once +#if _MSC_FULL_VER > 160000000 +#if _MSC_FULL_VER < 160040219 +#error You must install VS 2010 SP1 +#endif +#else +#if _MSC_FULL_VER < 140050727 +#error You must install VS 2005 SP1 +#endif +#endif +#endif + +#ifdef _MSC_VER +#define SINGLE_INHERITANCE __single_inheritance +#define MULTIPLE_INHERITANCE __multiple_inheritance +#else +#define SINGLE_INHERITANCE +#define MULTIPLE_INHERITANCE +#endif + +#ifdef _MSC_VER +#define NO_VTABLE __declspec( novtable ) +#else +#define NO_VTABLE +#endif + +#ifdef _MSC_VER +#define NORETURN __declspec( noreturn ) +#else +#define NORETURN +#endif + +#ifndef _X360 +#define abstract_class class +#else +#define abstract_class class NO_VTABLE +#endif + + +#define VALVE_RAND_MAX 0x7fff + + + +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#elif POSIX +#if defined( OSX ) && defined( CARBON_WORKAROUND ) +#define DWORD unsigned int +#else +typedef unsigned int DWORD; +#endif +typedef unsigned short WORD; +typedef void* HINSTANCE; +#define _MAX_PATH PATH_MAX +#define __cdecl +#define __stdcall +#define __declspec + +#endif + + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +#ifdef _WIN32 +#define MAX_UNICODE_PATH 32767 +#else +#define MAX_UNICODE_PATH MAX_PATH +#endif + +#define MAX_UNICODE_PATH_IN_UTF8 MAX_UNICODE_PATH*4 + +#ifdef GNUC +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#else +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + + +#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) + +#if defined( _WIN32 ) && !defined( _X360 ) +#define DebuggerBreak() __debugbreak() +#elif defined( _X360 ) +#define DebuggerBreak() DebugBreak() +#else +#ifdef OSX +#define DebuggerBreak() if ( Plat_IsInDebugSession() ) { __asm ( "int $3" ); } else { raise(SIGTRAP); } +#else +#define DebuggerBreak() raise(SIGTRAP) +#endif +#endif +#define DebuggerBreakIfDebugging() if ( !Plat_IsInDebugSession() ) ; else DebuggerBreak() + +#ifndef EXPORT +#ifdef _WIN32 +#define EXPORT _declspec( dllexport ) +#else +#define EXPORT +#endif +#endif + +#if defined __i386__ && !defined __linux__ +#define id386 1 +#else +#define id386 0 +#endif + +#ifdef _WIN32 +#define DECL_ALIGN(x) __declspec(align(x)) + +#elif GNUC +#define DECL_ALIGN(x) __attribute__((aligned(x))) +#else +#define DECL_ALIGN(x) +#endif + +#ifdef _MSC_VER +#define ALIGN4 DECL_ALIGN(4) +#define ALIGN8 DECL_ALIGN(8) +#define ALIGN16 DECL_ALIGN(16) +#define ALIGN32 DECL_ALIGN(32) +#define ALIGN128 DECL_ALIGN(128) + +#define ALIGN4_POST +#define ALIGN8_POST +#define ALIGN16_POST +#define ALIGN32_POST +#define ALIGN128_POST +#elif defined( GNUC ) +#define ALIGN4 +#define ALIGN8 +#define ALIGN16 +#define ALIGN32 +#define ALIGN128 + +#define ALIGN4_POST DECL_ALIGN(4) +#define ALIGN8_POST DECL_ALIGN(8) +#define ALIGN16_POST DECL_ALIGN(16) +#define ALIGN32_POST DECL_ALIGN(32) +#define ALIGN128_POST DECL_ALIGN(128) +#else +#error +#endif + +#ifdef __GNUC__ +#define COMPILE_TIME_ASSERT( pred ) typedef int UNIQUE_ID[ (pred) ? 1 : -1 ] +#else +#if _MSC_VER >= 1600 +#define COMPILE_TIME_ASSERT( pred ) static_assert( pred, "Compile time assert constraint is not true: " #pred ) +#else +#define COMPILE_TIME_ASSERT( pred ) typedef char compile_time_assert_type[(pred) ? 1 : -1]; +#endif +#endif +#define ASSERT_INVARIANT( pred ) COMPILE_TIME_ASSERT( pred ) + +#if defined( PLATFORM_WINDOWS_PC ) + void Plat_MessageBox(const char* pTitle, const tchar * pMessage); +#else +#define Plat_MessageBox( t, m ) ((void)0) +#endif +#define DebuggerBreakIfDebugging() if ( !Plat_IsInDebugSession() ) ; else DebuggerBreak() +void Plat_GetModuleFilename(char* pOut, int nMaxBytes); +void Plat_ExitProcess(int nCode); + +void Plat_ExitProcessWithError(int nCode, bool bGenerateMinidump = false); +#if defined( PLATFORM_X360 ) || defined( _PS3 ) +#ifndef _GAMECONSOLE +#define _GAMECONSOLE +#endif +#define IsPC() 0 +#define IsGameConsole() 1 +#else +#define IsPC() 1 +#define IsGameConsole() 0 +#endif + + +inline int64 CastPtrToInt64(const void* p) +{ + return (int64)((uintp)p); +} + +#include "annotations.h" + +#define INT_TO_POINTER( i ) (void *)( ( i ) + (char *)NULL ) +#define POINTER_TO_INT( p ) ( (int)(uintp)( p ) ) + + +#if defined( GNUC ) +#define stackalloc( _size ) alloca( ALIGN_VALUE( _size, 16 ) ) +#ifdef _LINUX +#define mallocsize( _p ) ( malloc_usable_size( _p ) ) +#elif defined(OSX) +#define mallocsize( _p ) ( malloc_size( _p ) ) +#else +#error +#endif +#elif defined ( _WIN32 ) +#define stackalloc( _size ) _alloca( ALIGN_VALUE( _size, 16 ) ) +#define mallocsize( _p ) ( _msize( _p ) ) +#endif + +#define stackfree( _p ) 0 + +#ifdef POSIX +#define CONSTRUCT_EARLY __attribute__((init_priority(101))) +#else +#define CONSTRUCT_EARLY +#endif + +#if defined(_MSC_VER) +#define SELECTANY __declspec(selectany) +#define RESTRICT __restrict +#define RESTRICT_FUNC __declspec(restrict) +#define FMTFUNCTION( a, b ) +#elif defined(GNUC) +#define SELECTANY __attribute__((weak)) +#if defined(LINUX) && !defined(DEDICATED) +#define RESTRICT +#else +#define RESTRICT __restrict +#endif +#define RESTRICT_FUNC +#define FMTFUNCTION( fmtargnumber, firstvarargnumber ) __attribute__ (( format( __printf__, fmtargnumber, firstvarargnumber ))) +#else +#define SELECTANY static +#define RESTRICT +#define RESTRICT_FUNC +#define FMTFUNCTION( a, b ) +#endif + +#if defined( _WIN32 ) + +#define DLL_EXPORT extern "C" __declspec( dllexport ) +#define DLL_IMPORT extern "C" __declspec( dllimport ) + +#define DLL_CLASS_EXPORT __declspec( dllexport ) +#define DLL_CLASS_IMPORT __declspec( dllimport ) + +#define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) +#define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) + +#define DLL_LOCAL + +#elif defined GNUC +#define DLL_EXPORT extern "C" __attribute__ ((visibility("default"))) +#define DLL_IMPORT extern "C" + +#define DLL_CLASS_EXPORT __attribute__ ((visibility("default"))) +#define DLL_CLASS_IMPORT + +#define DLL_GLOBAL_EXPORT extern __attribute ((visibility("default"))) +#define DLL_GLOBAL_IMPORT extern + +#define DLL_LOCAL __attribute__ ((visibility("hidden"))) + +#else +#error "Unsupported Platform." +#endif + +#if defined( _WIN32 ) && !defined( _X360 ) +#define STDCALL __stdcall +#define FASTCALL __fastcall +#define FORCEINLINE __forceinline +#define FORCEINLINE_TEMPLATE __forceinline +#elif defined( _X360 ) +#define STDCALL __stdcall +#ifdef FORCEINLINE +#undef FORCEINLINE +#endif +#define FORCEINLINE __forceinline +#define FORCEINLINE_TEMPLATE __forceinline +#else +#define STDCALL +#define FASTCALL +#ifdef _LINUX_DEBUGGABLE +#define FORCEINLINE +#else +#define FORCEINLINE inline __attribute__ ((always_inline)) +#endif +#define FORCEINLINE_TEMPLATE inline +#endif + +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +#ifdef _MSC_VER +#define HINT(THE_HINT) __assume((THE_HINT)) +#else +#define HINT(THE_HINT) 0 +#endif + +#define UNREACHABLE() { Assert(0); HINT(0); } + +#define NO_DEFAULT default: UNREACHABLE(); + + +#ifdef _WIN32 + +#pragma warning(disable : 4514) +#pragma warning(disable : 4100) +#pragma warning(disable : 4127) +#pragma warning(disable : 4512) +#pragma warning(disable : 4611) +#pragma warning(disable : 4710) +#pragma warning(disable : 4702) +#pragma warning(disable : 4505) +#pragma warning(disable : 4239) +#pragma warning(disable : 4097) +#pragma warning(disable : 4324) +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) +#pragma warning(disable : 4786) +#pragma warning(disable : 4250) +#pragma warning(disable : 4201) +#pragma warning(disable : 4481) +#pragma warning(disable : 4748) + +#if _MSC_VER >= 1300 +#pragma warning(disable : 4511) +#pragma warning(disable : 4121) +#pragma warning(disable : 4530) +#endif + +#if _MSC_VER >= 1400 +#pragma warning(disable : 4996) +#endif + + +#endif + +#if defined( LINUX ) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406 +#define GCC_DIAG_STR(s) #s +#define GCC_DIAG_JOINSTR(x,y) GCC_DIAG_STR(x ## y) +#define GCC_DIAG_DO_PRAGMA(x) _Pragma (#x) +#define GCC_DIAG_PRAGMA(x) GCC_DIAG_DO_PRAGMA(GCC diagnostic x) + +#define GCC_DIAG_PUSH_OFF(x) GCC_DIAG_PRAGMA(push) GCC_DIAG_PRAGMA(ignored GCC_DIAG_JOINSTR(-W,x)) +#define GCC_DIAG_POP() GCC_DIAG_PRAGMA(pop) +#else +#define GCC_DIAG_PUSH_OFF(x) +#define GCC_DIAG_POP() +#endif + +#ifdef LINUX +#pragma GCC diagnostic ignored "-Wconversion-null" +#pragma GCC diagnostic ignored "-Wpointer-arith" +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +#ifdef OSX +#pragma GCC diagnostic ignored "-Wconversion-null" +#pragma GCC diagnostic ignored "-Wnull-arithmetic" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#pragma GCC diagnostic ignored "-Wswitch" +#endif + + +#if !defined( _WIN64 ) +#pragma warning( disable : 4267 ) +#pragma warning( disable : 4311 ) +#pragma warning( disable : 4312 ) +#endif + + +#ifdef POSIX +#define _stricmp stricmp +#define strcmpi stricmp +#define stricmp strcasecmp +#define _vsnprintf vsnprintf +#define _alloca alloca +#ifdef _snprintf +#undef _snprintf +#endif +#define _snprintf snprintf +#define GetProcAddress dlsym +#define _chdir chdir +#define _strnicmp strnicmp +#define strnicmp strncasecmp +#define _getcwd getcwd +#define _snwprintf swprintf +#define swprintf_s swprintf +#define wcsicmp _wcsicmp +#define _wcsicmp wcscmp +#define _finite finite +#define _tempnam tempnam +#define _unlink unlink +#define _access access +#define _mkdir(dir) mkdir( dir, S_IRWXU | S_IRWXG | S_IRWXO ) +#define _wtoi(arg) wcstol(arg, NULL, 10) +#define _wtoi64(arg) wcstoll(arg, NULL, 10) + +typedef uint32 HMODULE; +typedef void* HANDLE; +#endif + +#ifndef _X360 + +static FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} +static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} + +#else + +#define fsel __fsel + +#endif + + +#if !defined( _X360 ) +#if defined( _MSC_VER ) + +#if defined( PLATFORM_WINDOWS_PC64 ) +inline void SetupFPUControlWord() +{ +} +#else +inline void SetupFPUControlWordForceExceptions() +{ + uint16 tmpCtrlW; + __asm + { + fnclex + fnstcw word ptr[tmpCtrlW] + and [tmpCtrlW], 0FCC0h + or [tmpCtrlW], 0230h + fldcw word ptr[tmpCtrlW] + } +} + +#ifdef CHECK_FLOAT_EXCEPTIONS + +inline void SetupFPUControlWord() +{ + SetupFPUControlWordForceExceptions(); +} + +#else + +inline void SetupFPUControlWord() +{ + uint16 tmpCtrlW; + __asm + { + fnstcw word ptr[tmpCtrlW] + and [tmpCtrlW], 0FCC0h + or [tmpCtrlW], 023Fh + fldcw word ptr[tmpCtrlW] + } +} + +#endif +#endif + +#else + +inline void SetupFPUControlWord() +{ + __volatile unsigned short int __cw; + __asm __volatile("fnstcw %0" : "=m" (__cw)); + __cw = __cw & 0x0FCC0; + __cw = __cw | 0x023F; + __asm __volatile("fldcw %0" : : "m" (__cw)); +} + +#endif + +#else + +#ifdef _DEBUG +FORCEINLINE bool IsFPUControlWordSet() +{ + float f = 0.996f; + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw(f); + return (pResult[1] == 1); +} +#endif + +inline void SetupFPUControlWord() +{ + __emit(0xFF80010C); + + __vector4 a = { 0.0f, 0.0f, 0.0f, 0.0f }; + a; + __asm + { + mtvscr a; + } +} + +#endif + +template +inline T WordSwapC(T w) +{ + uint16 temp; + + temp = ((*((uint16*)&w) & 0xff00) >> 8); + temp |= ((*((uint16*)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template +inline T DWordSwapC(T dw) +{ + uint32 temp; + + temp = *((uint32*)&dw) >> 24; + temp |= ((*((uint32*)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32*)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32*)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +template +inline T QWordSwapC(T dw) +{ + PLAT_COMPILE_TIME_ASSERT(sizeof(dw) == sizeof(uint64)); + + uint64 temp; + + temp = *((uint64*)&dw) >> 56; + temp |= ((*((uint64*)&dw) & 0x00FF000000000000ull) >> 40); + temp |= ((*((uint64*)&dw) & 0x0000FF0000000000ull) >> 24); + temp |= ((*((uint64*)&dw) & 0x000000FF00000000ull) >> 8); + temp |= ((*((uint64*)&dw) & 0x00000000FF000000ull) << 8); + temp |= ((*((uint64*)&dw) & 0x0000000000FF0000ull) << 24); + temp |= ((*((uint64*)&dw) & 0x000000000000FF00ull) << 40); + temp |= ((*((uint64*)&dw) & 0x00000000000000FFull) << 56); + + return *((T*)&temp); +} + +#if defined( _X360 ) + +#define WordSwap WordSwap360Intr +#define DWordSwap DWordSwap360Intr + +template +inline T WordSwap360Intr(T w) +{ + T output; + __storeshortbytereverse(w, 0, &output); + return output; +} + +template +inline T DWordSwap360Intr(T dw) +{ + T output; + __storewordbytereverse(dw, 0, &output); + return output; +} + +#elif defined( _MSC_VER ) && !defined( PLATFORM_WINDOWS_PC64 ) + +#define WordSwap WordSwapAsm +#define DWordSwap DWordSwapAsm + +#pragma warning(push) +#pragma warning (disable:4035) + +template +inline T WordSwapAsm(T w) +{ + __asm + { + mov ax, w + xchg al, ah + } +} + +template +inline T DWordSwapAsm(T dw) +{ + __asm + { + mov eax, dw + bswap eax + } +} + +#pragma warning(pop) + +#else + +#define WordSwap WordSwapC +#define DWordSwap DWordSwapC + +#endif + +#define QWordSwap QWordSwapC + +#if defined(__i386__) && !defined(VALVE_LITTLE_ENDIAN) +#define VALVE_LITTLE_ENDIAN 1 +#endif + +#if defined( _SGI_SOURCE ) || defined( _X360 ) +#define VALVE_BIG_ENDIAN 1 +#endif + +#define SafeSwapFloat( pOut, pIn ) (*((uint*)pOut) = DWordSwap( *((uint*)pIn) )) + +#if defined(VALVE_LITTLE_ENDIAN) + +#define BigShort( val ) WordSwap( val ) +#define BigWord( val ) WordSwap( val ) +#define BigLong( val ) DWordSwap( val ) +#define BigDWord( val ) DWordSwap( val ) +#define LittleShort( val ) ( val ) +#define LittleWord( val ) ( val ) +#define LittleLong( val ) ( val ) +#define LittleDWord( val ) ( val ) +#define LittleQWord( val ) ( val ) +#define SwapShort( val ) BigShort( val ) +#define SwapWord( val ) BigWord( val ) +#define SwapLong( val ) BigLong( val ) +#define SwapDWord( val ) BigDWord( val ) + +#define BigFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define LittleFloat( pOut, pIn ) ( *pOut = *pIn ) +#define SwapFloat( pOut, pIn ) BigFloat( pOut, pIn ) + +#elif defined(VALVE_BIG_ENDIAN) + +#define BigShort( val ) ( val ) +#define BigWord( val ) ( val ) +#define BigLong( val ) ( val ) +#define BigDWord( val ) ( val ) +#define LittleShort( val ) WordSwap( val ) +#define LittleWord( val ) WordSwap( val ) +#define LittleLong( val ) DWordSwap( val ) +#define LittleDWord( val ) DWordSwap( val ) +#define LittleQWord( val ) QWordSwap( val ) +#define SwapShort( val ) LittleShort( val ) +#define SwapWord( val ) LittleWord( val ) +#define SwapLong( val ) LittleLong( val ) +#define SwapDWord( val ) LittleDWord( val ) + +#define BigFloat( pOut, pIn ) ( *pOut = *pIn ) +#define LittleFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define SwapFloat( pOut, pIn ) LittleFloat( pOut, pIn ) + +#else + +inline short BigShort(short val) { int test = 1; return (*(char*)&test == 1) ? WordSwap(val) : val; } +inline uint16 BigWord(uint16 val) { int test = 1; return (*(char*)&test == 1) ? WordSwap(val) : val; } +inline long BigLong(long val) { int test = 1; return (*(char*)&test == 1) ? DWordSwap(val) : val; } +inline uint32 BigDWord(uint32 val) { int test = 1; return (*(char*)&test == 1) ? DWordSwap(val) : val; } +inline short LittleShort(short val) { int test = 1; return (*(char*)&test == 1) ? val : WordSwap(val); } +inline uint16 LittleWord(uint16 val) { int test = 1; return (*(char*)&test == 1) ? val : WordSwap(val); } +inline long LittleLong(long val) { int test = 1; return (*(char*)&test == 1) ? val : DWordSwap(val); } +inline uint32 LittleDWord(uint32 val) { int test = 1; return (*(char*)&test == 1) ? val : DWordSwap(val); } +inline uint64 LittleQWord(uint64 val) { int test = 1; return (*(char*)&test == 1) ? val : QWordSwap(val); } +inline short SwapShort(short val) { return WordSwap(val); } +inline uint16 SwapWord(uint16 val) { return WordSwap(val); } +inline long SwapLong(long val) { return DWordSwap(val); } +inline uint32 SwapDWord(uint32 val) { return DWordSwap(val); } + +inline void BigFloat(float* pOut, const float* pIn) { int test = 1; (*(char*)&test == 1) ? SafeSwapFloat(pOut, pIn) : (*pOut = *pIn); } +inline void LittleFloat(float* pOut, const float* pIn) { int test = 1; (*(char*)&test == 1) ? (*pOut = *pIn) : SafeSwapFloat(pOut, pIn); } +inline void SwapFloat(float* pOut, const float* pIn) { SafeSwapFloat(pOut, pIn); } + +#endif + +#if _X360 +FORCEINLINE unsigned long LoadLittleDWord(const unsigned long* base, unsigned int dwordIndex) +{ + return __loadwordbytereverse(dwordIndex << 2, base); +} + +FORCEINLINE void StoreLittleDWord(unsigned long* base, unsigned int dwordIndex, unsigned long dword) +{ + __storewordbytereverse(dword, dwordIndex << 2, base); +} +#else +FORCEINLINE unsigned long LoadLittleDWord(const unsigned long* base, unsigned int dwordIndex) +{ + return LittleDWord(base[dwordIndex]); +} + +FORCEINLINE uint32 LoadLittleDWord(const uint32* base, unsigned int dwordIndex) +{ + return LittleDWord(base[dwordIndex]); +} + +FORCEINLINE void StoreLittleDWord(unsigned long* base, unsigned int dwordIndex, unsigned long dword) +{ + base[dwordIndex] = LittleDWord(dword); +} + +FORCEINLINE void StoreLittleDWord(uint32* base, unsigned int dwordIndex, unsigned long dword) +{ + base[dwordIndex] = LittleDWord(dword); +} + +#endif + + +#ifndef STATIC_TIER0 + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#define PLATFORM_CLASS DLL_CLASS_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#define PLATFORM_CLASS DLL_CLASS_IMPORT +#endif + +#else + +#define PLATFORM_INTERFACE extern +#define PLATFORM_OVERLOAD +#define PLATFORM_CLASS + +#endif + + +PLATFORM_INTERFACE void Plat_SetBenchmarkMode(bool bBenchmarkMode); +PLATFORM_INTERFACE bool Plat_IsInBenchmarkMode(); + + +PLATFORM_INTERFACE double Plat_FloatTime(); +PLATFORM_INTERFACE unsigned int Plat_MSTime(); +PLATFORM_INTERFACE char* Plat_asctime(const struct tm* tm, char* buf); +PLATFORM_INTERFACE char* Plat_ctime(const time_t* timep, char* buf, size_t bufsize); +PLATFORM_INTERFACE struct tm* Plat_gmtime(const time_t* timep, struct tm* result); +PLATFORM_INTERFACE time_t Plat_timegm(struct tm* timeptr); +PLATFORM_INTERFACE struct tm* Plat_localtime(const time_t* timep, struct tm* result); + +#if defined( _WIN32 ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) +extern "C" unsigned __int64 __rdtsc(); +#pragma intrinsic(__rdtsc) +#endif + +inline uint64 Plat_Rdtsc() +{ +#if defined( _X360 ) + return (uint64)__mftb32(); +#elif defined( _WIN64 ) + return (uint64)__rdtsc(); +#elif defined( _WIN32 ) +#if defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) + return (uint64)__rdtsc(); +#else + __asm rdtsc; + __asm ret; +#endif +#elif defined( __i386__ ) + uint64 val; + __asm__ __volatile__("rdtsc" : "=A" (val)); + return val; +#elif defined( __x86_64__ ) + uint32 lo, hi; + __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi)); + return (((uint64)hi) << 32) | lo; +#else +#error +#endif +} + +#define Sys_FloatTime Plat_FloatTime + +#define DISALLOW_OPERATOR_EQUAL( _classname ) \ + private: \ + _classname &operator=( const _classname & ); \ + public: + +#define IMPLEMENT_OPERATOR_EQUAL( _classname ) \ + public: \ + _classname &operator=( const _classname &src ) \ + { \ + memcpy( this, &src, sizeof(_classname) ); \ + return *this; \ + } + +struct CPUInformation +{ + int m_Size; + + bool m_bRDTSC : 1, + m_bCMOV : 1, + m_bFCMOV : 1, + m_bSSE : 1, + m_bSSE2 : 1, + m_b3DNow : 1, + m_bMMX : 1, + m_bHT : 1; + + uint8 m_nLogicalProcessors; + uint8 m_nPhysicalProcessors; + + bool m_bSSE3 : 1, + m_bSSSE3 : 1, + m_bSSE4a : 1, + m_bSSE41 : 1, + m_bSSE42 : 1; + + int64 m_Speed; + + tchar* m_szProcessorID; + + CPUInformation() : m_Size(0) {} +}; + +PLATFORM_INTERFACE const CPUInformation* GetCPUInformation(); + +PLATFORM_INTERFACE float GetCPUUsage(); + +PLATFORM_INTERFACE void GetCurrentDate(int* pDay, int* pMonth, int* pYear); + +PLATFORM_INTERFACE void InitPME(); +PLATFORM_INTERFACE void ShutdownPME(); + +PLATFORM_INTERFACE void Plat_SetHardwareDataBreakpoint(const void* pAddress, int nWatchBytes, bool bBreakOnRead); + +PLATFORM_INTERFACE void Plat_ApplyHardwareDataBreakpointsToNewThread(unsigned long dwThreadID); + +PLATFORM_INTERFACE const tchar* Plat_GetCommandLine(); +#ifndef _WIN32 +PLATFORM_INTERFACE void Plat_SetCommandLine(const char* cmdLine); +#endif +PLATFORM_INTERFACE const char* Plat_GetCommandLineA(); + +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + +PLATFORM_INTERFACE void* Plat_SimpleLog(const tchar* file, int line); + +#if _X360 +#define Plat_FastMemset XMemSet +#define Plat_FastMemcpy XMemCpy +#else +#define Plat_FastMemset memset +#define Plat_FastMemcpy memcpy +#endif + +#if defined(_WIN32) || defined(LINUX) || defined(OSX) +PLATFORM_INTERFACE bool Plat_IsInDebugSession(bool bForceRecheck = false); +PLATFORM_INTERFACE void Plat_DebugString(const char*); +#else +inline bool Plat_IsInDebugSession(bool bForceRecheck = false) { return false; } +#define Plat_DebugString(s) ((void)0) +#endif + +PLATFORM_INTERFACE bool Is64BitOS(); + + +#define XBOX_DVD_SECTORSIZE 2048 +#define XBOX_DVD_ECC_SIZE 32768 +#define XBOX_HDD_SECTORSIZE 512 + +#define WM_XREMOTECOMMAND (WM_USER + 100) +#define WM_XCONTROLLER_KEY (WM_USER + 101) +#define WM_SYS_UI (WM_USER + 102) +#define WM_SYS_SIGNINCHANGED (WM_USER + 103) +#define WM_SYS_STORAGEDEVICESCHANGED (WM_USER + 104) +#define WM_SYS_PROFILESETTINGCHANGED (WM_USER + 105) +#define WM_SYS_MUTELISTCHANGED (WM_USER + 106) +#define WM_SYS_INPUTDEVICESCHANGED (WM_USER + 107) +#define WM_SYS_INPUTDEVICECONFIGCHANGED (WM_USER + 108) +#define WM_LIVE_CONNECTIONCHANGED (WM_USER + 109) +#define WM_LIVE_INVITE_ACCEPTED (WM_USER + 110) +#define WM_LIVE_LINK_STATE_CHANGED (WM_USER + 111) +#define WM_LIVE_CONTENT_INSTALLED (WM_USER + 112) +#define WM_LIVE_MEMBERSHIP_PURCHASED (WM_USER + 113) +#define WM_LIVE_VOICECHAT_AWAY (WM_USER + 114) +#define WM_LIVE_PRESENCE_CHANGED (WM_USER + 115) +#define WM_FRIENDS_PRESENCE_CHANGED (WM_USER + 116) +#define WM_FRIENDS_FRIEND_ADDED (WM_USER + 117) +#define WM_FRIENDS_FRIEND_REMOVED (WM_USER + 118) +#define WM_CUSTOM_GAMEBANNERPRESSED (WM_USER + 119) +#define WM_CUSTOM_ACTIONPRESSED (WM_USER + 120) +#define WM_XMP_STATECHANGED (WM_USER + 121) +#define WM_XMP_PLAYBACKBEHAVIORCHANGED (WM_USER + 122) +#define WM_XMP_PLAYBACKCONTROLLERCHANGED (WM_USER + 123) + +inline const char* GetPlatformExt(void) +{ + return IsX360() ? ".360" : ""; +} + +#define XBOX_PROCESSOR_0 ( 1<<0 ) +#define XBOX_PROCESSOR_1 ( 1<<1 ) +#define XBOX_PROCESSOR_2 ( 1<<2 ) +#define XBOX_PROCESSOR_3 ( 1<<3 ) +#define XBOX_PROCESSOR_4 ( 1<<4 ) +#define XBOX_PROCESSOR_5 ( 1<<5 ) + +#define XBOX_CORE_0_HWTHREAD_0 XBOX_PROCESSOR_0 +#define XBOX_CORE_0_HWTHREAD_1 XBOX_PROCESSOR_1 +#define XBOX_CORE_1_HWTHREAD_0 XBOX_PROCESSOR_2 +#define XBOX_CORE_1_HWTHREAD_1 XBOX_PROCESSOR_3 +#define XBOX_CORE_2_HWTHREAD_0 XBOX_PROCESSOR_4 +#define XBOX_CORE_2_HWTHREAD_1 XBOX_PROCESSOR_5 + +#include "fasttimer.h" + +#if defined( _X360 ) +#include "xbox/xbox_core.h" +#endif + +template +inline T* Construct(T* pMemory) +{ + return ::new(pMemory) T; +} + +template +inline T* Construct(T* pMemory, ARG1 a1) +{ + return ::new(pMemory) T(a1); +} + +template +inline T* Construct(T* pMemory, ARG1 a1, ARG2 a2) +{ + return ::new(pMemory) T(a1, a2); +} + +template +inline T* Construct(T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3) +{ + return ::new(pMemory) T(a1, a2, a3); +} + +template +inline T* Construct(T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4) +{ + return ::new(pMemory) T(a1, a2, a3, a4); +} + +template +inline T* Construct(T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4, ARG5 a5) +{ + return ::new(pMemory) T(a1, a2, a3, a4, a5); +} + +template +inline void ConstructOneArg(T* pMemory, P const& arg) +{ + ::new(pMemory) T(arg); +} + +template +inline void ConstructTwoArg(T* pMemory, P1 const& arg1, P2 const& arg2) +{ + ::new(pMemory) T(arg1, arg2); +} + +template +inline void ConstructThreeArg(T* pMemory, P1 const& arg1, P2 const& arg2, P3 const& arg3) +{ + ::new(pMemory) T(arg1, arg2, arg3); +} + +template +inline T* CopyConstruct(T* pMemory, T const& src) +{ + return ::new(pMemory) T(src); +} + +template +inline void Destruct(T* pMemory) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset(reinterpret_cast(pMemory), 0xDD, sizeof(T)); +#endif +} + + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (uint8 *)this - offsetof( OuterType, OuterMember ) ) ) + + +PLATFORM_INTERFACE bool vtune(bool resume); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template \ +RETURN_TYPE FASTCALL __Function_##NAME::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + +#if 0 + +PLATFORM_INTERFACE void* Plat_GetProcAddress(const char* pszModule, const char* pszName); + +template +class CDynamicFunction +{ +public: + CDynamicFunction(const char* pszModule, const char* pszName, FUNCPTR_TYPE pfnFallback = NULL) + { + m_pfn = pfnFallback; + void* pAddr = Plat_GetProcAddress(pszModule, pszName); + if (pAddr) + { + m_pfn = (FUNCPTR_TYPE)pAddr; + } + } + + operator bool() { return m_pfn != NULL; } + bool operator !() { return !m_pfn; } + operator FUNCPTR_TYPE() { return m_pfn; } + +private: + FUNCPTR_TYPE m_pfn; +}; +#endif + + +#include "valve_on.h" + +#if defined(TIER0_DLL_EXPORT) +extern "C" int V_tier0_stricmp(const char* s1, const char* s2); +#undef stricmp +#undef strcmpi +#define stricmp(s1,s2) V_tier0_stricmp( s1, s2 ) +#define strcmpi(s1,s2) V_tier0_stricmp( s1, s2 ) +#endif + + +#endif +``` + +`SpyCustom/sdk/playernet_vars.h`: + +```h +#ifndef PLAYERNET_VARS_H +#define PLAYERNET_VARS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shared_classnames.h" +#include "networkvar.h" +#include "datamap.h" + +#define NUM_AUDIO_LOCAL_SOUNDS 8 + +struct fogparams_t +{ + DECLARE_CLASS_NOBASE(fogparams_t); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + bool operator !=(const fogparams_t& other) const; + + CNetworkVector(dirPrimary); + CNetworkColor32(colorPrimary); + CNetworkColor32(colorSecondary); + CNetworkColor32(colorPrimaryLerpTo); + CNetworkColor32(colorSecondaryLerpTo); + CNetworkVar(float, start); + CNetworkVar(float, end); + CNetworkVar(float, farz); + CNetworkVar(float, maxdensity); + + CNetworkVar(float, startLerpTo); + CNetworkVar(float, endLerpTo); + CNetworkVar(float, lerptime); + CNetworkVar(float, duration); + CNetworkVar(bool, enable); + CNetworkVar(bool, blend); +}; + +#ifdef CLIENT_DLL +#define CFogController C_FogController +#endif + +class CFogController; + +struct fogplayerparams_t +{ + DECLARE_CLASS_NOBASE(fogplayerparams_t); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + CNetworkHandle(CFogController, m_hCtrl); + float m_flTransitionTime; + + color32 m_OldColor; + float m_flOldStart; + float m_flOldEnd; + + color32 m_NewColor; + float m_flNewStart; + float m_flNewEnd; + + fogplayerparams_t() + { + m_hCtrl.Set(NULL); + m_flTransitionTime = -1.0f; + m_OldColor.r = m_OldColor.g = m_OldColor.b = m_OldColor.a = 0; + m_flOldStart = 0.0f; + m_flOldEnd = 0.0f; + m_NewColor.r = m_NewColor.g = m_NewColor.b = m_NewColor.a = 0; + m_flNewStart = 0.0f; + m_flNewEnd = 0.0f; + } +}; + +struct sky3dparams_t +{ + DECLARE_CLASS_NOBASE(sky3dparams_t); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + CNetworkVar(int, scale); + CNetworkVector(origin); + CNetworkVar(int, area); + + CNetworkVarEmbedded(fogparams_t, fog); +}; + +struct audioparams_t +{ + DECLARE_CLASS_NOBASE(audioparams_t); + DECLARE_EMBEDDED_NETWORKVAR(); + +#ifndef CLIENT_DLL + DECLARE_SIMPLE_DATADESC(); +#endif + + CNetworkArray(Vector, localSound, NUM_AUDIO_LOCAL_SOUNDS) + CNetworkVar(int, soundscapeIndex); + CNetworkVar(int, localBits); + CNetworkHandle(CBaseEntity, ent); +}; + + +#endif +``` + +`SpyCustom/sdk/precipitation_shared.h`: + +```h +#ifndef PRECIPITATION_SHARED_H +#define PRECIPITATION_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +enum PrecipitationType_t +{ + PRECIPITATION_TYPE_RAIN = 0, + PRECIPITATION_TYPE_SNOW, + PRECIPITATION_TYPE_ASH, + PRECIPITATION_TYPE_SNOWFALL, + PRECIPITATION_TYPE_PARTICLERAIN, + PRECIPITATION_TYPE_PARTICLEASH, + PRECIPITATION_TYPE_PARTICLERAINSTORM, + PRECIPITATION_TYPE_PARTICLESNOW, + NUM_PRECIPITATION_TYPES +}; + + +#endif +``` + +`SpyCustom/sdk/predictable_entity.h`: + +```h +#ifndef PREDICTABLE_ENTITY_H +#define PREDICTABLE_ENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#include "predictioncopy.h" +#include "shared_classnames.h" + +#ifndef NO_ENTITY_PREDICTION +#define UsePrediction() 1 +#else +#define UsePrediction() 0 +#endif + +#if defined( CLIENT_DLL ) + +#include "iclassmap.h" +#include "recvproxy.h" + +class SendTable; + +#else + +#include "sendproxy.h" + +#endif + +#if defined( CLIENT_DLL ) + +#define DECLARE_NETWORKCLASS() \ + DECLARE_CLIENTCLASS() + +#define DECLARE_NETWORKCLASS_NOBASE() \ + DECLARE_CLIENTCLASS_NOBASE() + +#else + +#define DECLARE_NETWORKCLASS() \ + DECLARE_SERVERCLASS() + +#define DECLARE_NETWORKCLASS_NOBASE() \ + DECLARE_SERVERCLASS_NOBASE() + +#endif + +#if defined( CLIENT_DLL ) + +#ifndef NO_ENTITY_PREDICTION +#define DECLARE_PREDICTABLE() \ + public: \ + static typedescription_t m_PredDesc[]; \ + static datamap_t m_PredMap; \ + virtual datamap_t *GetPredDescMap( void ); \ + template friend datamap_t *PredMapInit(T *) +#else +#define DECLARE_PREDICTABLE() template friend datamap_t *PredMapInit(T *) +#endif + +#ifndef NO_ENTITY_PREDICTION +#define BEGIN_PREDICTION_DATA( className ) \ + datamap_t className::m_PredMap = { 0, 0, #className, &BaseClass::m_PredMap }; \ + datamap_t *className::GetPredDescMap( void ) { return &m_PredMap; } \ + BEGIN_PREDICTION_DATA_GUTS( className ) + +#define BEGIN_PREDICTION_DATA_NO_BASE( className ) \ + datamap_t className::m_PredMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetPredDescMap( void ) { return &m_PredMap; } \ + BEGIN_PREDICTION_DATA_GUTS( className ) + +#define BEGIN_PREDICTION_DATA_GUTS( className ) \ + template datamap_t *PredMapInit(T *); \ + template <> datamap_t *PredMapInit( className * ); \ + namespace className##_PredDataDescInit \ + { \ + datamap_t *g_PredMapHolder = PredMapInit( (className *)NULL ); \ + } \ + \ + template <> datamap_t *PredMapInit( className * ) \ + { \ + typedef className classNameTypedef; \ + static typedescription_t predDesc[] = \ + { \ + { FIELD_VOID,0, {0,0},0,0,0,0,0,0}, + +#define END_PREDICTION_DATA() \ + }; \ + \ + if ( sizeof( predDesc ) > sizeof( predDesc[0] ) ) \ + { \ + classNameTypedef::m_PredMap.dataNumFields = ARRAYSIZE( predDesc ) - 1; \ + classNameTypedef::m_PredMap.dataDesc = &predDesc[1]; \ + } \ + else \ + { \ + classNameTypedef::m_PredMap.dataNumFields = 1; \ + classNameTypedef::m_PredMap.dataDesc = predDesc; \ + } \ + return &classNameTypedef::m_PredMap; \ + } +#else +#define BEGIN_PREDICTION_DATA( className ) \ + template <> inline datamap_t *PredMapInit( className * ) \ + { \ + if ( 0 ) \ + { \ + typedef className classNameTypedef; \ + typedescription_t predDesc[] = \ + { \ + { FIELD_VOID,0, {0,0},0,0,0,0,0,0}, + +#define BEGIN_PREDICTION_DATA_NO_BASE( className ) BEGIN_PREDICTION_DATA( className ) + +#define END_PREDICTION_DATA() \ + }; \ + predDesc[0].flags = 0; \ + } \ + } +#endif + +#else + +#define DECLARE_PREDICTABLE() +#define BEGIN_PREDICTION_DATA( className ) +#define END_PREDICTION_DATA() + +#endif + +#if defined( CLIENT_DLL ) + +#define LINK_ENTITY_TO_CLASS( localName, className ) \ + static C_BaseEntity *C##className##Factory( void ) \ + { \ + return static_cast< C_BaseEntity * >( new className ); \ + }; \ + class C##localName##Foo \ + { \ + public: \ + C##localName##Foo( void ) \ + { \ + GetClassMap().Add( #localName, #className, sizeof( className ), \ + &C##className##Factory ); \ + } \ + }; \ + static C##localName##Foo g_C##localName##Foo; + +#define BEGIN_NETWORK_TABLE( className, tableName ) BEGIN_RECV_TABLE( className, tableName ) +#define BEGIN_NETWORK_TABLE_NOBASE( className, tableName ) BEGIN_RECV_TABLE_NOBASE( className, tableName ) + +#define END_NETWORK_TABLE END_RECV_TABLE + +#define IMPLEMENT_NETWORKCLASS_ALIASED(className, dataTable) \ + IMPLEMENT_CLIENTCLASS( C_##className, dataTable, C##className ) +#define IMPLEMENT_NETWORKCLASS(className, dataTable) \ + IMPLEMENT_CLIENTCLASS(className, dataTable, className) +#define IMPLEMENT_NETWORKCLASS_DT(className, dataTable) \ + IMPLEMENT_CLIENTCLASS_DT(className, dataTable, className) + +#else + +#define BEGIN_NETWORK_TABLE( className, tableName ) BEGIN_SEND_TABLE( className, tableName ) +#define BEGIN_NETWORK_TABLE_NOBASE( className, tableName ) BEGIN_SEND_TABLE_NOBASE( className, tableName ) + +#define END_NETWORK_TABLE END_SEND_TABLE + +#define IMPLEMENT_NETWORKCLASS_ALIASED(className, dataTable) \ + IMPLEMENT_SERVERCLASS( C##className, dataTable ) +#define IMPLEMENT_NETWORKCLASS(className, dataTable) \ + IMPLEMENT_SERVERCLASS(className, dataTable) +#define IMPLEMENT_NETWORKCLASS_DT(className, dataTable) \ + IMPLEMENT_SERVERCLASS_ST(className, dataTable) + +#endif + +abstract_class IPredictableList +{ +public: + virtual CBaseEntity* GetPredictable(int slot) = 0; + virtual int GetPredictableCount(void) = 0; +}; + +extern IPredictableList* predictables; + +#endif +``` + +`SpyCustom/sdk/predictableid.h`: + +```h +#ifndef PREDICTABLEID_H +#define PREDICTABLEID_H +#ifdef _WIN32 +#pragma once +#endif + +#if !defined( NO_ENTITY_PREDICTION ) +class CPredictableId +{ +public: + CPredictableId(void); + + static void ResetInstanceCounters(void); + + bool IsActive(void) const; + + void Init(int player, int command, const char* classname, const char* module, int line); + + int GetPlayer(void) const; + int GetHash(void) const; + int GetInstanceNumber(void) const; + int GetCommandNumber(void) const; + + void SetAcknowledged(bool ack); + bool GetAcknowledged(void) const; + + int GetRaw(void) const; + void SetRaw(int raw); + + char const* Describe(void) const; + + bool operator ==(const CPredictableId& other) const; + bool operator !=(const CPredictableId& other) const; +private: + void SetCommandNumber(int commandNumber); + void SetPlayer(int playerIndex); + void SetInstanceNumber(int counter); + + struct bitfields + { + unsigned int ack : 1; + unsigned int player : 5; + unsigned int command : 10; + unsigned int hash : 12; + unsigned int instance : 4; + } m_PredictableID; +}; + +FORCEINLINE void NetworkVarConstruct(CPredictableId& x) {} + +#endif + +#endif +``` + +`SpyCustom/sdk/predictioncopy.h`: + +```h +#ifndef PREDICTIONCOPY_H +#define PREDICTIONCOPY_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "datamap.h" +#include "ehandle.h" +#include "utlstring.h" + +#if defined( CLIENT_DLL ) +class C_BaseEntity; +typedef CHandle EHANDLE; + +#if defined( _DEBUG ) +class IGameSystem; +IGameSystem* GetPredictionCopyTester(void); +#endif + +#else +class CBaseEntity; +typedef CHandle EHANDLE; +#endif + +enum +{ + PC_EVERYTHING = 0, + PC_NON_NETWORKED_ONLY, + PC_NETWORKED_ONLY, +}; + +#define PC_DATA_PACKED true +#define PC_DATA_NORMAL false + +typedef void (*FN_FIELD_COMPARE)(const char* classname, const char* fieldname, const char* fieldtype, + bool networked, bool noterrorchecked, bool differs, bool withintolerance, const char* value); + +class CPredictionCopy +{ +public: + typedef enum + { + DIFFERS = 0, + IDENTICAL, + WITHINTOLERANCE, + } difftype_t; + + CPredictionCopy(int type, void* dest, bool dest_packed, void const* src, bool src_packed, + bool counterrors = false, bool reporterrors = false, bool performcopy = true, + bool describefields = false, FN_FIELD_COMPARE func = NULL); + + void CopyShort(difftype_t dt, short* outvalue, const short* invalue, int count); + void CopyInt(difftype_t dt, int* outvalue, const int* invalue, int count); + void CopyBool(difftype_t dt, bool* outvalue, const bool* invalue, int count); + void CopyFloat(difftype_t dt, float* outvalue, const float* invalue, int count); + void CopyString(difftype_t dt, char* outstring, const char* instring); + void CopyVector(difftype_t dt, Vector& outValue, const Vector& inValue); + void CopyVector(difftype_t dt, Vector* outValue, const Vector* inValue, int count); + void CopyQuaternion(difftype_t dt, Quaternion& outValue, const Quaternion& inValue); + void CopyQuaternion(difftype_t dt, Quaternion* outValue, const Quaternion* inValue, int count); + void CopyEHandle(difftype_t dt, EHANDLE* outvalue, EHANDLE const* invalue, int count); + + void FORCEINLINE CopyData(difftype_t dt, int size, char* outdata, const char* indata) + { + if (!m_bPerformCopy) + return; + + if (dt == IDENTICAL) + return; + + memcpy(outdata, indata, size); + } + + int TransferData(const char* operation, int entindex, datamap_t* dmap); + +private: + void TransferData_R(int chaincount, datamap_t* dmap); + + void DetermineWatchField(const char* operation, int entindex, datamap_t* dmap); + void DumpWatchField(typedescription_t* field); + void WatchMsg(PRINTF_FORMAT_STRING const char* fmt, ...); + + difftype_t CompareShort(short* outvalue, const short* invalue, int count); + difftype_t CompareInt(int* outvalue, const int* invalue, int count); + difftype_t CompareBool(bool* outvalue, const bool* invalue, int count); + difftype_t CompareFloat(float* outvalue, const float* invalue, int count); + difftype_t CompareData(int size, char* outdata, const char* indata); + difftype_t CompareString(char* outstring, const char* instring); + difftype_t CompareVector(Vector& outValue, const Vector& inValue); + difftype_t CompareVector(Vector* outValue, const Vector* inValue, int count); + difftype_t CompareQuaternion(Quaternion& outValue, const Quaternion& inValue); + difftype_t CompareQuaternion(Quaternion* outValue, const Quaternion* inValue, int count); + difftype_t CompareEHandle(EHANDLE* outvalue, EHANDLE const* invalue, int count); + + void DescribeShort(difftype_t dt, short* outvalue, const short* invalue, int count); + void DescribeInt(difftype_t dt, int* outvalue, const int* invalue, int count); + void DescribeBool(difftype_t dt, bool* outvalue, const bool* invalue, int count); + void DescribeFloat(difftype_t dt, float* outvalue, const float* invalue, int count); + void DescribeData(difftype_t dt, int size, char* outdata, const char* indata); + void DescribeString(difftype_t dt, char* outstring, const char* instring); + void DescribeVector(difftype_t dt, Vector& outValue, const Vector& inValue); + void DescribeVector(difftype_t dt, Vector* outValue, const Vector* inValue, int count); + void DescribeQuaternion(difftype_t dt, Quaternion& outValue, const Quaternion& inValue); + void DescribeQuaternion(difftype_t dt, Quaternion* outValue, const Quaternion* inValue, int count); + void DescribeEHandle(difftype_t dt, EHANDLE* outvalue, EHANDLE const* invalue, int count); + + void WatchShort(difftype_t dt, short* outvalue, const short* invalue, int count); + void WatchInt(difftype_t dt, int* outvalue, const int* invalue, int count); + void WatchBool(difftype_t dt, bool* outvalue, const bool* invalue, int count); + void WatchFloat(difftype_t dt, float* outvalue, const float* invalue, int count); + void WatchData(difftype_t dt, int size, char* outdata, const char* indata); + void WatchString(difftype_t dt, char* outstring, const char* instring); + void WatchVector(difftype_t dt, Vector& outValue, const Vector& inValue); + void WatchVector(difftype_t dt, Vector* outValue, const Vector* inValue, int count); + void WatchQuaternion(difftype_t dt, Quaternion& outValue, const Quaternion& inValue); + void WatchQuaternion(difftype_t dt, Quaternion* outValue, const Quaternion* inValue, int count); + void WatchEHandle(difftype_t dt, EHANDLE* outvalue, EHANDLE const* invalue, int count); + + void ReportFieldsDiffer(PRINTF_FORMAT_STRING const char* fmt, ...); + void DescribeFields(difftype_t dt, PRINTF_FORMAT_STRING const char* fmt, ...); + + bool CanCheck(void); + + void CopyFields(int chaincount, datamap_t* pMap, typedescription_t* pFields, int fieldCount); + +private: + + int m_nType; + void* m_pDest; + void const* m_pSrc; + int m_nDestOffsetIndex; + int m_nSrcOffsetIndex; + + + bool m_bErrorCheck; + bool m_bReportErrors; + bool m_bDescribeFields; + typedescription_t* m_pCurrentField; + char const* m_pCurrentClassName; + datamap_t* m_pCurrentMap; + bool m_bShouldReport; + bool m_bShouldDescribe; + int m_nErrorCount; + bool m_bPerformCopy; + + FN_FIELD_COMPARE m_FieldCompareFunc; + + typedescription_t* m_pWatchField; + char const* m_pOperation; +}; + +typedef void (*FN_FIELD_DESCRIPTION)(const char* classname, const char* fieldname, const char* fieldtype, + bool networked, const char* value); + +class CPredictionDescribeData +{ +public: + CPredictionDescribeData(void const* src, bool src_packed, FN_FIELD_DESCRIPTION func = 0); + + void DescribeShort(const short* invalue, int count); + void DescribeInt(const int* invalue, int count); + void DescribeBool(const bool* invalue, int count); + void DescribeFloat(const float* invalue, int count); + void DescribeData(int size, const char* indata); + void DescribeString(const char* instring); + void DescribeVector(const Vector& inValue); + void DescribeVector(const Vector* inValue, int count); + void DescribeQuaternion(const Quaternion& inValue); + void DescribeQuaternion(const Quaternion* inValue, int count); + void DescribeEHandle(EHANDLE const* invalue, int count); + + void DumpDescription(datamap_t* pMap); + +private: + void DescribeFields_R(int chain_count, datamap_t* pMap, typedescription_t* pFields, int fieldCount); + + void const* m_pSrc; + int m_nSrcOffsetIndex; + + void Describe(PRINTF_FORMAT_STRING const char* fmt, ...); + + typedescription_t* m_pCurrentField; + char const* m_pCurrentClassName; + datamap_t* m_pCurrentMap; + + bool m_bShouldReport; + + FN_FIELD_DESCRIPTION m_FieldDescFunc; +}; + +#if defined( CLIENT_DLL ) +class CValueChangeTracker +{ +public: + CValueChangeTracker(); + + void Reset(); + + void StartTrack(char const* pchContext); + void EndTrack(); + + bool IsActive() const; + + void SetupTracking(C_BaseEntity* ent, char const* pchFieldName); + void ClearTracking(); + + void Spew(); + + C_BaseEntity* GetEntity(); + +private: + + enum + { + eChangeTrackerBufSize = 128, + }; + + void GetValue(char* buf, size_t bufsize); + + bool m_bActive : 1; + bool m_bTracking : 1; + EHANDLE m_hEntityToTrack; + CUtlVector< typedescription_t* > m_FieldStack; + CUtlString m_strFieldName; + CUtlString m_strContext; + char m_OrigValueBuf[eChangeTrackerBufSize]; + CUtlVector< CUtlString > m_History; +}; + +extern CValueChangeTracker* g_pChangeTracker; + +class CValueChangeTrackerScope +{ +public: + CValueChangeTrackerScope(char const* pchContext) + { + m_bCallEndTrack = true; + g_pChangeTracker->StartTrack(pchContext); + } + + CValueChangeTrackerScope(C_BaseEntity* pEntity, char const* pchContext) + { + m_bCallEndTrack = g_pChangeTracker->GetEntity() == pEntity; + if (m_bCallEndTrack) + { + g_pChangeTracker->StartTrack(pchContext); + } + } + + ~CValueChangeTrackerScope() + { + if (m_bCallEndTrack) + { + g_pChangeTracker->EndTrack(); + } + } +private: + + bool m_bCallEndTrack; +}; + +#if defined( _DEBUG ) +#define PREDICTION_TRACKVALUECHANGESCOPE( context ) CValueChangeTrackerScope scope( context ); +#define PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( entity, context ) CValueChangeTrackerScope scope( entity, context ); +#define PREDICTION_STARTTRACKVALUE( context ) g_pChangeTracker->StartTrack( context ); +#define PREDICTION_ENDTRACKVALUE() g_pChangeTracker->EndTrack(); +#define PREDICTION_SPEWVALUECHANGES() g_pChangeTracker->Spew(); +#else +#define PREDICTION_TRACKVALUECHANGESCOPE( context ) +#define PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( entity, context ) +#define PREDICTION_STARTTRACKVALUE( context ) +#define PREDICTION_ENDTRACKVALUE() +#define PREDICTION_SPEWVALUECHANGES() +#endif + +#endif +#endif +``` + +`SpyCustom/sdk/protocol.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// protocol.h -- communications protocols +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#ifdef _WIN32 +#pragma once +#endif + +// Used to classify entity update types in DeltaPacketEntities. +enum UpdateType +{ + EnterPVS = 0, // Entity came back into pvs, create new entity if one doesn't exist + + LeavePVS, // Entity left pvs + + DeltaEnt, // There is a delta for this entity. + PreserveEnt, // Entity stays alive but no delta ( could be LOD, or just unchanged ) + + Finished, // finished parsing entities successfully + Failed, // parsing error occured while reading entities +}; + +// Flags for delta encoding header +enum +{ + FHDR_ZERO = 0x0000, + FHDR_LEAVEPVS = 0x0001, + FHDR_DELETE = 0x0002, + FHDR_ENTERPVS = 0x0004, +}; + + + +#define INSTANCE_BASELINE_TABLENAME "instancebaseline" +#define LIGHT_STYLES_TABLENAME "lightstyles" +#define USER_INFO_TABLENAME "userinfo" +#define SERVER_STARTUP_DATA_TABLENAME "server_query_info" // the name is a remnant... + + +//#define CURRENT_PROTOCOL 1 + + +#define DELTA_OFFSET_BITS 5 +#define DELTA_OFFSET_MAX ( ( 1 << DELTA_OFFSET_BITS ) - 1 ) + +#define DELTASIZE_BITS 20 // must be: 2^DELTASIZE_BITS > (NET_MAX_PAYLOAD * 8) + +// Largest # of commands to send in a packet +#define NUM_NEW_COMMAND_BITS 4 +#define MAX_NEW_COMMANDS ((1 << NUM_NEW_COMMAND_BITS)-1) + +// Max number of history commands to send ( 2 by default ) in case of dropped packets +#define NUM_BACKUP_COMMAND_BITS 3 +#define MAX_BACKUP_COMMANDS ((1 << NUM_BACKUP_COMMAND_BITS)-1) + + +#define PROTOCOL_AUTHCERTIFICATE 0x01 // Connection from client is using a WON authenticated certificate +#define PROTOCOL_HASHEDCDKEY 0x02 // Connection from client is using hashed CD key because WON comm. channel was unreachable +#define PROTOCOL_STEAM 0x03 // Steam certificates +#define PROTOCOL_LASTVALID 0x03 // Last valid protocol + +#define CONNECTIONLESS_HEADER 0xFFFFFFFF // all OOB packet start with this sequence +#define STEAM_KEYSIZE 2048 // max size needed to contain a steam authentication key (both server and client) + +// each channel packet has 1 byte of FLAG bits +#define PACKET_FLAG_RELIABLE (1<<0) // packet contains subchannel stream data +#define PACKET_FLAG_COMPRESSED (1<<1) // packet is compressed +#define PACKET_FLAG_ENCRYPTED (1<<2) // packet is encrypted +#define PACKET_FLAG_SPLIT (1<<3) // packet is split +#define PACKET_FLAG_CHOKED (1<<4) // packet was choked by sender + +// NOTE: Bits 5, 6, and 7 are used to specify the # of padding bits at the end of the packet!!! +#define ENCODE_PAD_BITS( x ) ( ( x << 5 ) & 0xff ) +#define DECODE_PAD_BITS( x ) ( ( x >> 5 ) & 0xff ) + +// shared commands used by all streams, handled by stream layer, TODO + +#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_LastControlMessage 2 + +#define net_SplitScreenUser 3 // Changes split screen user +#define net_Tick 4 // send last world tick +#define net_StringCmd 5 // a string command +#define net_SetConVar 6 // sends one/multiple convar settings +#define net_SignonState 7 // signals current signon state +// +// server to client +// + +#define svc_Print 7 // print text to console +#define svc_ServerInfo 8 // first message from server about game, map etc +#define svc_SendTable 9 // sends a sendtable description for a game class +#define svc_ClassInfo 10 // Info about classes (first byte is a CLASSINFO_ define). +#define svc_SetPause 11 // tells client if server paused or unpaused + + +#define svc_CreateStringTable 12 // inits shared string tables +#define svc_UpdateStringTable 13 // updates a string table + +#define svc_VoiceInit 14 // inits used voice codecs & quality +#define svc_VoiceData 15 // Voicestream data from the server + +// #define svc_HLTV 16 // HLTV control messages +#define svc_Print 16 // print text to console + +#define svc_Sounds 17 // starts playing sound + +#define svc_SetView 18 // sets entity as point of view +#define svc_FixAngle 19 // sets/corrects players viewangle +#define svc_CrosshairAngle 20 // adjusts crosshair in auto aim mode to lock on traget + +#define svc_BSPDecal 21 // add a static decal to the worl BSP +// NOTE: This is now unused! +//#define svc_TerrainMod 22 // modification to the terrain/displacement +#define svc_SplitScreen 22 // split screen style message + +// Message from server side to client side entity +#define svc_UserMessage 23 // a game specific message +#define svc_EntityMessage 24 // a message for an entity +#define svc_GameEvent 25 // global game event fired + +#define svc_PacketEntities 26 // non-delta compressed entities + +#define svc_TempEntities 27 // non-reliable event object + +#define svc_Prefetch 28 // only sound indices for now + +#define svc_Menu 29 // display a menu from a plugin + +#define svc_GameEventList 30 // list of known games events and fields + +#define svc_GetCvarValue 31 // Server wants to know the value of a cvar on the client. + +#define svc_CmdKeyValues 32 // Server submits KeyValues command for the client + +#define SVC_LASTMSG 32 // last known server messages + +// +// client to server +// + +#define clc_ClientInfo 8 // client info (table CRC etc) +#define clc_Move 9 // [CUserCmd] +#define clc_VoiceData 10 // Voicestream data from a client +#define clc_BaselineAck 11 // client acknowledges a new baseline seqnr +#define clc_ListenEvents 12 // client acknowledges a new baseline seqnr +#define clc_RespondCvarValue 13 // client is responding to a svc_GetCvarValue message. +#define clc_FileCRCCheck 14 // client is sending a file's CRC to the server to be verified. + +#define CLC_LASTMSG 14 // last known client message + +#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. +#define RES_PRELOAD (1<<1) // Load on client rather than just reserving name + +#define SIGNONSTATE_NONE 0 // no state yet, about to connect +#define SIGNONSTATE_CHALLENGE 1 // client challenging server, all OOB packets +#define SIGNONSTATE_CONNECTED 2 // client is connected to server, netchans ready +#define SIGNONSTATE_NEW 3 // just got serverinfo and string tables +#define SIGNONSTATE_PRESPAWN 4 // received signon buffers +#define SIGNONSTATE_SPAWN 5 // ready to receive entity packets +#define SIGNONSTATE_FULL 6 // we are fully connected, first non-delta packet received +#define SIGNONSTATE_CHANGELEVEL 7 // server is changing level, please wait + +// +// matchmaking +// + +#define mm_Heartbeat 16 // send a mm_Heartbeat +#define mm_ClientInfo 17 // information about a player +#define mm_JoinResponse 18 // response to a matchmaking join request +#define mm_RegisterResponse 19 // response to a matchmaking join request +#define mm_Migrate 20 // tell a client to migrate +#define mm_Mutelist 21 // send mutelist info to other clients +#define mm_Checkpoint 22 // game state checkpoints (start, connect, etc) + +#define MM_LASTMSG 22 // last known matchmaking message + +#endif // PROTOCOL_H + +``` + +`SpyCustom/sdk/qlimits.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef QLIMITS_H +#define QLIMITS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +// DATA STRUCTURE INFO + +#define MAX_NUM_ARGVS 50 + +// SYSTEM INFO +#define MAX_QPATH 96 // max length of a game pathname +#define MAX_OSPATH 260 // max length of a filesystem pathname + +#define ON_EPSILON 0.1 // point on plane side epsilon + + +// Resource counts; +// Must have this value in sync(-1) with const.h and effect_dispatch_data.cpp +#define MAX_MODEL_INDEX_BITS 12 // sent as a short +#define MAX_MODELS (1< 0; } + bool IsAsleep(void) const { return m_allAsleep; } + + void ResetRagdollSleepAfterTime(void); + float GetLastVPhysicsUpdateTime() const { return m_lastUpdate; } + +private: + + void CheckSettleStationaryRagdoll(); + void PhysForceRagdollToSleep(); + + ragdoll_t m_ragdoll; + Vector m_mins, m_maxs; + Vector m_origin; + float m_lastUpdate; + bool m_allAsleep; + Vector m_vecLastOrigin; + float m_flLastOriginChangeTime; + float m_flAwakeTime; + +#if RAGDOLL_VISUALIZE + matrix3x4_t m_savedBone1[MAXSTUDIOBONES]; + matrix3x4_t m_savedBone2[MAXSTUDIOBONES]; + matrix3x4_t m_savedBone3[MAXSTUDIOBONES]; +#endif + +public: + + ragdoll_t* GetRagdoll(void) { return &m_ragdoll; } +}; + + +CRagdoll* CreateRagdoll( + C_BaseEntity* ent, + CStudioHdr* pstudiohdr, + const Vector& forceVector, + int forceBone, + const matrix3x4_t* pDeltaBones0, + const matrix3x4_t* pDeltaBones1, + const matrix3x4_t* pCurrentBonePosition, + float boneDt); + + +void NoteRagdollCreationTick(C_BaseEntity* pRagdoll); +bool WasRagdollCreatedOnCurrentTick(C_BaseEntity* pRagdoll); + +#endif +``` + +`SpyCustom/sdk/ragdoll_shared.h`: + +```h +#ifndef RAGDOLL_SHARED_H +#define RAGDOLL_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +class IPhysicsObject; +class IPhysicsConstraint; +class IPhysicsConstraintGroup; +class IPhysicsCollision; +class IPhysicsEnvironment; +class IPhysicsSurfaceProps; +struct matrix3x4_t; + +struct vcollide_t; +struct studiohdr_t; +class CStudioHdr; +class CBoneAccessor; + +#include "vector.h" +#include "bone_accessor.h" + +#define RAGDOLL_MAX_ELEMENTS 24 +#define RAGDOLL_INDEX_BITS 5 + +#define CORE_DISSOLVE_FADE_START 0.2f +#define CORE_DISSOLVE_MODEL_FADE_START 0.1f +#define CORE_DISSOLVE_MODEL_FADE_LENGTH 0.05f +#define CORE_DISSOLVE_FADEIN_LENGTH 0.1f + +struct ragdollelement_t +{ + Vector originParentSpace; + IPhysicsObject* pObject; + IPhysicsConstraint* pConstraint; + int parentIndex; +}; + +struct ragdollanimatedfriction_t +{ + float flFrictionTimeIn; + float flFrictionTimeOut; + float flFrictionTimeHold; + int iMinAnimatedFriction; + int iMaxAnimatedFriction; +}; + +struct ragdoll_t +{ + int listCount; + bool allowStretch; + bool unused; + IPhysicsConstraintGroup* pGroup; + ragdollelement_t list[RAGDOLL_MAX_ELEMENTS]; + int boneIndex[RAGDOLL_MAX_ELEMENTS]; + ragdollanimatedfriction_t animfriction; +}; + +struct ragdollparams_t +{ + void* pGameData; + vcollide_t* pCollide; + CStudioHdr* pStudioHdr; + int modelIndex; + Vector forcePosition; + Vector forceVector; + int forceBoneIndex; + const matrix3x4_t* pCurrentBones; + float jointFrictionScale; + bool allowStretch; + bool fixedConstraints; +}; + +class CRagdollLRURetirement : public CAutoGameSystemPerFrame +{ +public: + CRagdollLRURetirement(char const* name) : CAutoGameSystemPerFrame(name) + { + } + + virtual void Update(float frametime); + virtual void FrameUpdatePostEntityThink(void); + + void MoveToTopOfLRU(CBaseAnimating* pRagdoll, bool bImportant = false); + void SetMaxRagdollCount(int iMaxCount) { m_iMaxRagdolls = iMaxCount; } + + virtual void LevelInitPreEntity(void); + int CountRagdolls(bool bOnlySimulatingRagdolls) { return bOnlySimulatingRagdolls ? m_iSimulatedRagdollCount : m_iRagdollCount; } + +private: + typedef CHandle CRagdollHandle; + CUtlLinkedList< CRagdollHandle > m_LRU; + CUtlLinkedList< CRagdollHandle > m_LRUImportantRagdolls; + + int m_iMaxRagdolls; + int m_iSimulatedRagdollCount; + int m_iRagdollCount; +}; + +extern CRagdollLRURetirement s_RagdollLRU; + +class CRagdollLowViolenceManager +{ +public: + CRagdollLowViolenceManager() { m_bLowViolence = false; } + void SetLowViolence(const char* pMapName); + bool IsLowViolence(void) { return m_bLowViolence; } + +private: + bool m_bLowViolence; +}; + +extern CRagdollLowViolenceManager g_RagdollLVManager; + + +bool RagdollCreate(ragdoll_t& ragdoll, const ragdollparams_t& params, IPhysicsEnvironment* pPhysEnv); + +void RagdollActivate(ragdoll_t& ragdoll, vcollide_t* pCollide, int modelIndex, bool bForceWake = true); +void RagdollSetupCollisions(ragdoll_t& ragdoll, vcollide_t* pCollide, int modelIndex); +void RagdollDestroy(ragdoll_t& ragdoll); + +bool RagdollGetBoneMatrix(const ragdoll_t& ragdoll, CBoneAccessor& pBoneToWorld, int objectIndex); + +int RagdollExtractBoneIndices(int* boneIndexOut, CStudioHdr* pStudioHdr, vcollide_t* pCollide); + +void RagdollComputeExactBbox(const ragdoll_t& ragdoll, const Vector& origin, Vector& outMins, Vector& outMaxs); +bool RagdollIsAsleep(const ragdoll_t& ragdoll); +void RagdollSetupAnimatedFriction(IPhysicsEnvironment* pPhysEnv, ragdoll_t* ragdoll, int iModelIndex); + +void RagdollApplyAnimationAsVelocity(ragdoll_t& ragdoll, const matrix3x4_t* pBoneToWorld); +void RagdollApplyAnimationAsVelocity(ragdoll_t& ragdoll, const matrix3x4_t* pPrevBones, const matrix3x4_t* pCurrentBones, float dt); + +void RagdollSolveSeparation(ragdoll_t& ragdoll, CBaseEntity* pEntity); + +#endif +``` + +`SpyCustom/sdk/random.h`: + +```h +#ifndef VSTDLIB_RANDOM_H +#define VSTDLIB_RANDOM_H + +#include "vstdlib.h" +#include "basetypes.h" +#include "threadtools.h" +#include "interface.h" + +#define NTAB 32 + +#pragma warning(push) +#pragma warning( disable:4251 ) + +class IUniformRandomStream +{ +public: + virtual void SetSeed(int iSeed) = 0; + + virtual float RandomFloat(float flMinVal = 0.0f, float flMaxVal = 1.0f) = 0; + virtual int RandomInt(int iMinVal, int iMaxVal) = 0; + virtual float RandomFloatExp(float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f) = 0; +}; + + +class VSTDLIB_CLASS CUniformRandomStream : public IUniformRandomStream +{ +public: + CUniformRandomStream(); + + virtual void SetSeed(int iSeed); + + virtual float RandomFloat(float flMinVal = 0.0f, float flMaxVal = 1.0f); + virtual int RandomInt(int iMinVal, int iMaxVal); + virtual float RandomFloatExp(float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f); + +private: + int GenerateRandomNumber(); + + int m_idum; + int m_iy; + int m_iv[NTAB]; + + CThreadFastMutex m_mutex; +}; + + +class VSTDLIB_CLASS CGaussianRandomStream +{ +public: + CGaussianRandomStream(IUniformRandomStream* pUniformStream = NULL); + + void AttachToStream(IUniformRandomStream* pUniformStream = NULL); + + float RandomFloat(float flMean = 0.0f, float flStdDev = 1.0f); + +private: + IUniformRandomStream* m_pUniformStream; + bool m_bHaveValue; + float m_flRandomValue; + + CThreadFastMutex m_mutex; +}; + + +VSTDLIB_INTERFACE void RandomSeed(int iSeed); +VSTDLIB_INTERFACE float RandomFloat(float flMinVal = 0.0f, float flMaxVal = 1.0f); +VSTDLIB_INTERFACE float RandomFloatExp(float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f); +VSTDLIB_INTERFACE int RandomInt(int iMinVal, int iMaxVal); +VSTDLIB_INTERFACE float RandomGaussianFloat(float flMean = 0.0f, float flStdDev = 1.0f); + + +VSTDLIB_INTERFACE void InstallUniformRandomStream(IUniformRandomStream* pStream); + + +#pragma warning(pop) + +#endif +``` + +`SpyCustom/sdk/rangecheckedvar.h`: + +```h +#ifndef RANGECHECKEDVAR_H +#define RANGECHECKEDVAR_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "dbg.h" +#include "threadtools.h" +#include "vector.h" +#include + + +class CDisableRangeChecks +{ +public: + CDisableRangeChecks(); + ~CDisableRangeChecks(); +}; + + +template< class T > +inline void RangeCheck(const T& value, int minValue, int maxValue) +{ +#ifdef _DEBUG + extern bool g_bDoRangeChecks; + if (ThreadInMainThread() && g_bDoRangeChecks) + { + Assert(_finite(value)); + } +#endif +} + +inline void RangeCheck(const Vector& value, int minValue, int maxValue) +{ +#ifdef _DEBUG + RangeCheck(value.x, minValue, maxValue); + RangeCheck(value.y, minValue, maxValue); + RangeCheck(value.z, minValue, maxValue); +#endif +} + + +template< class T, int minValue, int maxValue, int startValue > +class CRangeCheckedVar +{ +public: + + inline CRangeCheckedVar() + { + m_Val = startValue; + } + + inline CRangeCheckedVar(const T& value) + { + *this = value; + } + + T GetRaw() const + { + return m_Val; + } + + inline void Clamp() + { + if (m_Val < minValue) + m_Val = minValue; + else if (m_Val > maxValue) + m_Val = maxValue; + } + + inline operator const T& () const + { + return m_Val; + } + + inline CRangeCheckedVar& operator=(const T& value) + { + RangeCheck(value, minValue, maxValue); + m_Val = value; + return *this; + } + + inline CRangeCheckedVar& operator+=(const T& value) + { + return (*this = m_Val + value); + } + + inline CRangeCheckedVar& operator-=(const T& value) + { + return (*this = m_Val - value); + } + + inline CRangeCheckedVar& operator*=(const T& value) + { + return (*this = m_Val * value); + } + + inline CRangeCheckedVar& operator/=(const T& value) + { + return (*this = m_Val / value); + } + +private: + + T m_Val; +}; + +#endif +``` + +`SpyCustom/sdk/recvproxy.h`: + +```h +#ifndef RECVPROXY_H +#define RECVPROXY_H + + +class CRecvProxyData; + + +void RecvProxy_IntToEHandle(const CRecvProxyData* pData, void* pStruct, void* pOut); + +void RecvProxy_IntToMoveParent(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_IntToColor32(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_IntSubOne(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_ShortSubOne(const CRecvProxyData* pData, void* pStruct, void* pOut); +void RecvProxy_InterpolationAmountChanged(const CRecvProxyData* pData, void* pStruct, void* pOut); + +RecvProp RecvPropTime( + char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE); + +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) +RecvProp RecvPropPredictableId( + char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE); +#endif + +RecvProp RecvPropEHandle( + char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + RecvVarProxyFn proxyFn = RecvProxy_IntToEHandle); + +RecvProp RecvPropBool( + char* pVarName, + int offset, + int sizeofVar); + +RecvProp RecvPropIntWithMinusOneFlag( + char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + RecvVarProxyFn proxyFn = RecvProxy_IntSubOne); + +#endif + +``` + +`SpyCustom/sdk/refcount.h`: + +```h +#ifndef REFCOUNT_H +#define REFCOUNT_H + +#include "threadtools.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class IRefCounted +{ +public: + virtual int AddRef() = 0; + virtual int Release() = 0; +}; + + +template +inline int SafeRelease(REFCOUNTED_ITEM_PTR& pRef) +{ + REFCOUNTED_ITEM_PTR* ppRef = &pRef; + if (*ppRef) + { + int result = (*ppRef)->Release(); + *ppRef = NULL; + return result; + } + return 0; +} + +template +class CAutoRef +{ +public: + CAutoRef(T* pRef) + : m_pRef(pRef) + { + if (m_pRef) + m_pRef->AddRef(); + } + + ~CAutoRef() + { + if (m_pRef) + m_pRef->Release(); + } + +private: + T* m_pRef; +}; + +#define RetAddRef( p ) ( (p)->AddRef(), (p) ) +#define InlineAddRef( p ) ( (p)->AddRef(), (p) ) + + +template +class CBaseAutoPtr +{ +public: + CBaseAutoPtr() : m_pObject(0) {} + CBaseAutoPtr(T* pFrom) : m_pObject(pFrom) {} + + operator const void* () const { return m_pObject; } + operator void* () { return m_pObject; } + + operator const T* () const { return m_pObject; } + operator const T* () { return m_pObject; } + operator T* () { return m_pObject; } + + int operator=(int i) { AssertMsg(i == 0, "Only NULL allowed on integer assign"); m_pObject = 0; return 0; } + T* operator=(T* p) { m_pObject = p; return p; } + + bool operator !() const { return (!m_pObject); } + bool operator!=(int i) const { AssertMsg(i == 0, "Only NULL allowed on integer compare"); return (m_pObject != NULL); } + bool operator==(const void* p) const { return (m_pObject == p); } + bool operator!=(const void* p) const { return (m_pObject != p); } + bool operator==(T* p) const { return operator==((void*)p); } + bool operator!=(T* p) const { return operator!=((void*)p); } + bool operator==(const CBaseAutoPtr& p) const { return operator==((const void*)p); } + bool operator!=(const CBaseAutoPtr& p) const { return operator!=((const void*)p); } + + T* operator->() { return m_pObject; } + T& operator *() { return *m_pObject; } + T** operator &() { return &m_pObject; } + + const T* operator->() const { return m_pObject; } + const T& operator *() const { return *m_pObject; } + T* const* operator &() const { return &m_pObject; } + +protected: + CBaseAutoPtr(const CBaseAutoPtr& from) : m_pObject(from.m_pObject) {} + void operator=(const CBaseAutoPtr& from) { m_pObject = from.m_pObject; } + + T* m_pObject; +}; + +template +class CRefPtr : public CBaseAutoPtr +{ + typedef CBaseAutoPtr BaseClass; +public: + CRefPtr() {} + CRefPtr(T* pInit) : BaseClass(pInit) {} + CRefPtr(const CRefPtr& from) : BaseClass(from) {} + ~CRefPtr() { if (BaseClass::m_pObject) BaseClass::m_pObject->Release(); } + + void operator=(const CRefPtr& from) { BaseClass::operator=(from); } + + int operator=(int i) { return BaseClass::operator=(i); } + T* operator=(T* p) { return BaseClass::operator=(p); } + + operator bool() const { return !BaseClass::operator!(); } + operator bool() { return !BaseClass::operator!(); } + + void SafeRelease() { if (BaseClass::m_pObject) BaseClass::m_pObject->Release(); BaseClass::m_pObject = 0; } + void AssignAddRef(T* pFrom) { SafeRelease(); if (pFrom) pFrom->AddRef(); BaseClass::m_pObject = pFrom; } + void AddRefAssignTo(T*& pTo) { ::SafeRelease(pTo); if (BaseClass::m_pObject) BaseClass::m_pObject->AddRef(); pTo = BaseClass::m_pObject; } +}; + + +class CRefMT +{ +public: + static int Increment(int* p) { return ThreadInterlockedIncrement((long*)p); } + static int Decrement(int* p) { return ThreadInterlockedDecrement((long*)p); } +}; + +class CRefST +{ +public: + static int Increment(int* p) { return ++(*p); } + static int Decrement(int* p) { return --(*p); } +}; + +template +class NO_VTABLE CRefCountServiceBase +{ +protected: + CRefCountServiceBase() + : m_iRefs(1) + { + } + + virtual ~CRefCountServiceBase() + { + } + + virtual bool OnFinalRelease() + { + return true; + } + + int GetRefCount() const + { + return m_iRefs; + } + + int DoAddRef() + { + return CRefThreading::Increment(&m_iRefs); + } + + int DoRelease() + { + int result = CRefThreading::Decrement(&m_iRefs); + if (result) + return result; + if (OnFinalRelease() && bSelfDelete) + delete this; + return 0; + } + +private: + int m_iRefs; +}; + +class CRefCountServiceNull +{ +protected: + static int DoAddRef() { return 1; } + static int DoRelease() { return 1; } +}; + +template +class NO_VTABLE CRefCountServiceDestruct +{ +protected: + CRefCountServiceDestruct() + : m_iRefs(1) + { + } + + virtual ~CRefCountServiceDestruct() + { + } + + int GetRefCount() const + { + return m_iRefs; + } + + int DoAddRef() + { + return CRefThreading::Increment(&m_iRefs); + } + + int DoRelease() + { + int result = CRefThreading::Decrement(&m_iRefs); + if (result) + return result; + this->~CRefCountServiceDestruct(); + return 0; + } + +private: + int m_iRefs; +}; + + +typedef CRefCountServiceBase CRefCountServiceST; +typedef CRefCountServiceBase CRefCountServiceNoDeleteST; + +typedef CRefCountServiceBase CRefCountServiceMT; +typedef CRefCountServiceBase CRefCountServiceNoDeleteMT; + +typedef CRefCountServiceNoDeleteMT CRefCountServiceNoDelete; +typedef CRefCountServiceMT CRefCountService; + +template < class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted : public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +template < class BASE1, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted1 : public BASE1, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted1() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +template < class BASE1, class BASE2, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted2 : public BASE1, public BASE2, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted2() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +template < class BASE1, class BASE2, class BASE3, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted3 : public BASE1, public BASE2, public BASE3, + public REFCOUNT_SERVICE +{ + virtual ~CRefCounted3() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +template < class BASE1, class BASE2, class BASE3, class BASE4, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted4 : public BASE1, public BASE2, public BASE3, public BASE4, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted4() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +template < class BASE1, class BASE2, class BASE3, class BASE4, class BASE5, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted5 : public BASE1, public BASE2, public BASE3, public BASE4, public BASE5, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted5() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +template +class CRefDebug : public BASE_REFCOUNTED +{ +public: +#ifdef _DEBUG + CRefDebug() + { + AssertMsg(this->GetRefCount() == 1, "Expected initial ref count of 1"); + DevMsg("%s:create 0x%x\n", (pszName) ? pszName : "", this); + } + + virtual ~CRefDebug() + { + AssertDevMsg(this->GetRefCount() == FINAL_REFS, "Object still referenced on destroy?"); + DevMsg("%s:destroy 0x%x\n", (pszName) ? pszName : "", this); + } + + int AddRef() + { + DevMsg("%s:(0x%x)->AddRef() --> %d\n", (pszName) ? pszName : "", this, this->GetRefCount() + 1); + return BASE_REFCOUNTED::AddRef(); + } + + int Release() + { + DevMsg("%s:(0x%x)->Release() --> %d\n", (pszName) ? pszName : "", this, this->GetRefCount() - 1); + Assert(this->GetRefCount() > 0); + return BASE_REFCOUNTED::Release(); + } +#endif +}; + +#endif +``` + +`SpyCustom/sdk/sceneentity_shared.h`: + +```h +#ifndef SCENEENTITY_SHARED_H +#define SCENEENTITY_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) +#define CBaseFlex C_BaseFlex +#define CSceneEntity C_SceneEntity +#endif + +#include "iscenetokenprocessor.h" + +class CBaseFlex; + +class CChoreoEvent; +class CChoreoScene; +class CChoreoActor; +class CSceneEntity; + +class CSceneEventInfo +{ +public: + CSceneEventInfo() + : + m_pEvent(0), + m_pScene(0), + m_pActor(0), + m_bStarted(false), + m_iLayer(-1), + m_iPriority(0), + m_nSequence(0), + m_bIsGesture(false), + m_flWeight(0.0f), + m_hTarget(), + m_bIsMoving(false), + m_bHasArrived(false), + m_flInitialYaw(0.0f), + m_flTargetYaw(0.0f), + m_flFacingYaw(0.0f), + m_nType(0), + m_flNext(0.0f), + m_bClientSide(false) + { + } + + CChoreoEvent* m_pEvent; + + CChoreoScene* m_pScene; + + CChoreoActor* m_pActor; + + bool m_bStarted; + +public: + int m_iLayer; + int m_iPriority; + int m_nSequence; + bool m_bIsGesture; + float m_flWeight; + + EHANDLE m_hTarget; + bool m_bIsMoving; + bool m_bHasArrived; + float m_flInitialYaw; + float m_flTargetYaw; + float m_flFacingYaw; + + int m_nType; + float m_flNext; + + bool m_bClientSide; + + void InitWeight(CBaseFlex* pActor); + float UpdateWeight(CBaseFlex* pActor); +}; + +class CSceneTokenProcessor : public ISceneTokenProcessor +{ +public: + const char* CurrentToken(void); + bool GetToken(bool crossline); + bool TokenAvailable(void); + void Error(PRINTF_FORMAT_STRING const char* fmt, ...); + void SetBuffer(char* buffer); +private: + const char* m_pBuffer; + char m_szToken[1024]; +}; + +extern CSceneTokenProcessor g_TokenProcessor; + +void Scene_Printf(PRINTF_FORMAT_STRING const char* pFormat, ...); +extern ConVar scene_clientflex; + +#endif +``` + +`SpyCustom/sdk/sdk_hud_chat.h`: + +```h +#ifndef SDK_HUD_CHAT_H +#define SDK_HUD_CHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_basechat.h" + +#include "GetVFunc.hpp" + +class CHudChatLine : public CBaseHudChatLine +{ + DECLARE_CLASS_SIMPLE(CHudChatLine, CBaseHudChatLine); + +public: + CHudChatLine(vgui::Panel* parent, const char* panelName) : CBaseHudChatLine(parent, panelName) {} + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + + void PerformFadeout(void); + + void MsgFunc_SayText(bf_read& msg); + +private: + CHudChatLine(const CHudChatLine&); +}; + +class CHudChatInputLine : public CBaseHudChatInputLine +{ + DECLARE_CLASS_SIMPLE(CHudChatInputLine, CBaseHudChatInputLine); + +public: + CHudChatInputLine(CBaseHudChat* parent, char const* panelName) : CBaseHudChatInputLine(parent, panelName) {} + + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); +}; + +class CHudChat : public CBaseHudChat +{ + DECLARE_CLASS_SIMPLE(CHudChat, CBaseHudChat); + +public: + CHudChat(const char* pElementName); + + virtual void CreateChatInputLine(void); + virtual void CreateChatLines(void); + + virtual void Init(void); + virtual void Reset(void); + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + + void MsgFunc_SayText(bf_read& msg); + void MsgFunc_TextMsg(bf_read& msg); + + enum ChatFilters + { + CHAT_FILTER_NONE = 0, + CHAT_FILTER_JOINLEAVE = 0x000001, + CHAT_FILTER_NAMECHANGE = 0x000002, + CHAT_FILTER_PUBLICCHAT = 0x000004, + CHAT_FILTER_SERVERMSG = 0x000008, + CHAT_FILTER_TEAMCHANGE = 0x000010, + CHAT_FILTER_ACHIEVEMENT = 0x000020, + }; + + void ChatPrintf_v(int iPlayerIndex, int iFilter, const char* fmt, ...) + { + char msg[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(msg, 1024, fmt, args); + getvfunc(this, 27)(this, iPlayerIndex, iFilter, fmt); + va_end(args); + } + + + int GetChatInputOffset(void); +}; + +#endif +``` + +`SpyCustom/sdk/seemath.h`: + +```h +#ifndef SSEMATH_H +#define SSEMATH_H + +#if defined( _X360 ) +#include +#elif defined ( _PS3 ) +#include +#include +#else +#include +#ifndef _LINUX +#include +#endif +#endif + +#ifndef SPU +#include "vector.h" +#include "mathlib.h" +#else +#include "mathlib/math_pfns.h" +#endif + +#include "fltx4.h" + +#ifdef _X360 +typedef __vector4 FLTX4; +#elif defined( _PS3 ) +typedef vec_float4 FLTX4; +#else +typedef const fltx4& FLTX4; +#endif + +struct ALIGN16 intx4 +{ + int32 m_i32[4]; + + inline int& operator[](int which) + { + return m_i32[which]; + } + + inline const int& operator[](int which) const + { + return m_i32[which]; + } + + inline int32* Base() { + return m_i32; + } + + inline const int32* Base() const + { + return m_i32; + } + + inline bool operator==(const intx4& other) const + { + return m_i32[0] == other.m_i32[0] && + m_i32[1] == other.m_i32[1] && + m_i32[2] == other.m_i32[2] && + m_i32[3] == other.m_i32[3]; + } +} ALIGN16_POST; + + +#if defined( _DEBUG ) && defined( _X360 ) +FORCEINLINE void TestVPUFlags() +{ + __vector4 a; + __asm + { + mfvscr a; + } + unsigned int* flags = (unsigned int*)&a; + unsigned int controlWord = flags[3]; + Assert(controlWord == 0); +} +#else +FORCEINLINE void TestVPUFlags() {} +#endif + + +#ifdef _X360 +#define Four_Zeros XMVectorZero() +#define Four_Ones XMVectorSplatOne() +extern const fltx4 Four_Twos; +extern const fltx4 Four_Threes; +extern const fltx4 Four_Fours; +extern const fltx4 Four_Point225s; +extern const fltx4 Four_PointFives; +extern const fltx4 Four_Thirds; +extern const fltx4 Four_TwoThirds; +extern const fltx4 Four_NegativeOnes; +extern const fltx4 Four_DegToRad; +#elif defined(SPU) +#define Four_Zeros spu_splats( 0.0f ) +#define Four_Ones spu_splats( 1.0f ) +#define Four_Twos spu_splats( 2.0f ) +#define Four_Threes spu_splats( 3.0f ) +#define Four_Fours spu_splats( 4.0f ) +#define Four_Point225s spu_splats( 0.225f ) +#define Four_PointFives spu_splats( 0.5f ) +#define Four_Thirds spu_splats( 0.33333333 ); +#define Four_TwoThirds spu_splats( 0.66666666 ); +#define Four_NegativeOnes spu_splats( -1.0f ) +#define Four_DegToRad spu_splats((float)(M_PI_F / 180.f)) +#else +extern const fltx4 Four_Zeros; +extern const fltx4 Four_Ones; +extern const fltx4 Four_Twos; +extern const fltx4 Four_Threes; +extern const fltx4 Four_Fours; +extern const fltx4 Four_Point225s; +extern const fltx4 Four_PointFives; +extern const fltx4 Four_Thirds; +extern const fltx4 Four_TwoThirds; +extern const fltx4 Four_NegativeOnes; +extern const fltx4 Four_DegToRad; +#endif +extern const fltx4 Four_Epsilons; +extern const fltx4 Four_2ToThe21s; +extern const fltx4 Four_2ToThe22s; +extern const fltx4 Four_2ToThe23s; +extern const fltx4 Four_2ToThe24s; +extern const fltx4 Four_Origin; +extern const fltx4 Four_FLT_MAX; +extern const fltx4 Four_Negative_FLT_MAX; +extern const fltx4 g_SIMD_0123; + + +extern const fltx4 Four_LinearToGammaCoefficients_A; +extern const fltx4 Four_LinearToGammaCoefficients_B; +extern const fltx4 Four_LinearToGammaCoefficients_C; +extern const fltx4 Four_LinearToGammaCoefficients_D; +extern const fltx4 Four_LinearToGammaCoefficients_E; + +extern const fltx4 Four_GammaToLinearCoefficients_A; +extern const fltx4 Four_GammaToLinearCoefficients_B; +extern const fltx4 Four_GammaToLinearCoefficients_C; +extern const fltx4 Four_GammaToLinearCoefficients_D; + + +#ifndef ALIGN16_POST +#define ALIGN16_POST +#endif +extern const ALIGN16 int32 g_SIMD_clear_signmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_signmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_lsbmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_clear_wmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_ComponentMask[4][4] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_AllOnesMask[] ALIGN16_POST; +extern const fltx4 g_SIMD_Identity[4]; +extern const ALIGN16 int32 g_SIMD_Low16BitsMask[] ALIGN16_POST; + +extern const int32 ALIGN16 g_SIMD_SkipTailMask[4][4] ALIGN16_POST; + +extern const int32 ALIGN16 g_SIMD_EveryOtherMask[]; +#ifdef PLATFORM_PPC +#if defined(_X360) +#define PREFETCH360(address, offset) __dcbt(offset,address) +#elif defined(_PS3) +#define PREFETCH360(address, offset) __dcbt( reinterpret_cast< const char * >(address) + offset ) +#else +#error Prefetch not defined for this platform! +#endif +#else +#define PREFETCH360(x,y) +#endif + +template +inline T* AlignPointer(void* ptr) +{ +#if defined( __clang__ ) + uintp temp = (uintp)ptr; +#else + unsigned temp = ptr; +#endif + temp = ALIGN_VALUE(temp, sizeof(T)); + return (T*)temp; +} + +#ifdef _PS3 + +#define _VEC_CLEAR_SIGNMASK (__vector unsigned int) {0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff} +#define _VEC_SIGNMASK (__vector unsigned int) { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } +#define _VEC_LSBMASK (__vector unsigned int) { 0xfffffffe, 0xfffffffe, 0xfffffffe, 0xfffffffe } +#define _VEC_CLEAR_WMASK (__vector unsigned int) {0xffffffff, 0xffffffff, 0xffffffff, 0} +#define _VEC_COMPONENT_MASK_0 (__vector unsigned int) {0xffffffff, 0, 0, 0} +#define _VEC_COMPONENT_MASK_1 (__vector unsigned int) {0, 0xffffffff, 0, 0} +#define _VEC_COMPONENT_MASK_2 (__vector unsigned int) {0, 0, 0xffffffff, 0} +#define _VEC_COMPONENT_MASK_3 (__vector unsigned int) {0, 0, 0, 0xffffffff} + +#define _VEC_SWIZZLE_WZYX (__vector unsigned char) { 0x0c,0x0d,0x0e,0x0f, 0x08,0x09,0x0a,0x0b, 0x04,0x05,0x06,0x07, 0x00,0x01,0x02,0x03 } +#define _VEC_SWIZZLE_ZWXY (__vector unsigned char) { 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07 } +#define _VEC_SWIZZLE_YXWZ (__vector unsigned char) { 0x04,0x05,0x06,0x07, 0x00,0x01,0x02,0x03, 0x0c,0x0d,0x0e,0x0f, 0x08,0x09,0x0a,0x0b } + +#define _VEC_ZERO (__vector unsigned int) {0,0,0,0} + +#define _VEC_FLTMAX (__vector float) {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX} +#define _VEC_FLTMIN (__vector float) {FLT_MIN,FLT_MIN,FLT_MIN,FLT_MIN} + +#define _VEC_ORIGIN (__vector unsigned int) { 0x00000000, 0x00000000, 0x00000000, 0xffffffff } + +#endif + +#if USE_STDC_FOR_SIMD + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ + return a.m128_f32[idx]; +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ + return a.m128_f32[idx]; +} + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ + return a.m128_u32[idx]; +} + +FORCEINLINE uint32& SubInt(fltx4& a, int idx) +{ + return a.m128_u32[idx]; +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return Four_Zeros; +} + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return Four_Ones; +} + +FORCEINLINE fltx4 SplatXSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 0); + SubFloat(retVal, 1) = SubFloat(a, 0); + SubFloat(retVal, 2) = SubFloat(a, 0); + SubFloat(retVal, 3) = SubFloat(a, 0); + return retVal; +} + +FORCEINLINE fltx4 SplatYSIMD(fltx4 a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 1); + SubFloat(retVal, 1) = SubFloat(a, 1); + SubFloat(retVal, 2) = SubFloat(a, 1); + SubFloat(retVal, 3) = SubFloat(a, 1); + return retVal; +} + +FORCEINLINE fltx4 SplatZSIMD(fltx4 a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 2); + SubFloat(retVal, 1) = SubFloat(a, 2); + SubFloat(retVal, 2) = SubFloat(a, 2); + SubFloat(retVal, 3) = SubFloat(a, 2); + return retVal; +} + +FORCEINLINE fltx4 SplatWSIMD(fltx4 a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 3); + SubFloat(retVal, 1) = SubFloat(a, 3); + SubFloat(retVal, 2) = SubFloat(a, 3); + SubFloat(retVal, 3) = SubFloat(a, 3); + return retVal; +} + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 result = a; + SubFloat(result, 0) = SubFloat(x, 0); + return result; +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 result = a; + SubFloat(result, 1) = SubFloat(y, 1); + return result; +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 result = a; + SubFloat(result, 2) = SubFloat(z, 2); + return result; +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + fltx4 result = a; + SubFloat(result, 3) = SubFloat(w, 3); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ + fltx4 result = a; + SubFloat(result, nComponent) = flValue; + return result; +} + + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 1); + SubFloat(retVal, 1) = SubFloat(a, 2); + SubFloat(retVal, 2) = SubFloat(a, 3); + SubFloat(retVal, 3) = SubFloat(a, 0); + return retVal; +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 2); + SubFloat(retVal, 1) = SubFloat(a, 3); + SubFloat(retVal, 2) = SubFloat(a, 0); + SubFloat(retVal, 3) = SubFloat(a, 1); + return retVal; +} + +#define BINOP(op) \ + fltx4 retVal; \ + SubFloat( retVal, 0 ) = ( SubFloat( a, 0 ) op SubFloat( b, 0 ) ); \ + SubFloat( retVal, 1 ) = ( SubFloat( a, 1 ) op SubFloat( b, 1 ) ); \ + SubFloat( retVal, 2 ) = ( SubFloat( a, 2 ) op SubFloat( b, 2 ) ); \ + SubFloat( retVal, 3 ) = ( SubFloat( a, 3 ) op SubFloat( b, 3 ) ); \ + return retVal; + +#define IBINOP(op) \ + fltx4 retVal; \ + SubInt( retVal, 0 ) = ( SubInt( a, 0 ) op SubInt ( b, 0 ) ); \ + SubInt( retVal, 1 ) = ( SubInt( a, 1 ) op SubInt ( b, 1 ) ); \ + SubInt( retVal, 2 ) = ( SubInt( a, 2 ) op SubInt ( b, 2 ) ); \ + SubInt( retVal, 3 ) = ( SubInt( a, 3 ) op SubInt ( b, 3 ) ); \ + return retVal; + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(+); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(-); +}; + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(*); +} + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(/ ); +} + +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(/ ); +} + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return AddSIMD(MulSIMD(a, b), c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return SubSIMD(c, MulSIMD(a, b)); +}; + + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + fltx4 result; + SubFloat(result, 0) = sin(SubFloat(radians, 0)); + SubFloat(result, 1) = sin(SubFloat(radians, 1)); + SubFloat(result, 2) = sin(SubFloat(radians, 2)); + SubFloat(result, 3) = sin(SubFloat(radians, 3)); + return result; +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); + SinCos(SubFloat(radians, 3), &SubFloat(sine, 3), &SubFloat(cosine, 3)); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + fltx4 result; + SubFloat(result, 0) = asin(SubFloat(sine, 0)); + SubFloat(result, 1) = asin(SubFloat(sine, 1)); + SubFloat(result, 2) = asin(SubFloat(sine, 2)); + SubFloat(result, 3) = asin(SubFloat(sine, 3)); + return result; +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + fltx4 result; + SubFloat(result, 0) = acos(SubFloat(cs, 0)); + SubFloat(result, 1) = acos(SubFloat(cs, 1)); + SubFloat(result, 2) = acos(SubFloat(cs, 2)); + SubFloat(result, 3) = acos(SubFloat(cs, 3)); + return result; +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + SubFloat(result, 0) = atan2(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(result, 1) = atan2(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(result, 2) = atan2(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(result, 3) = atan2(SubFloat(a, 3), SubFloat(b, 3)); + return result; +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubFloat(retVal, 0) = max(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(retVal, 1) = max(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(retVal, 2) = max(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(retVal, 3) = max(SubFloat(a, 3), SubFloat(b, 3)); + return retVal; +} + +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubFloat(retVal, 0) = min(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(retVal, 1) = min(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(retVal, 2) = min(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(retVal, 3) = min(SubFloat(a, 3), SubFloat(b, 3)); + return retVal; +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + IBINOP(&); +} + +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = ~SubInt(a, 0) & SubInt(b, 0); + SubInt(retVal, 1) = ~SubInt(a, 1) & SubInt(b, 1); + SubInt(retVal, 2) = ~SubInt(a, 2) & SubInt(b, 2); + SubInt(retVal, 3) = ~SubInt(a, 3) & SubInt(b, 3); + return retVal; +} + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + IBINOP(^); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + IBINOP(| ); +} + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + fltx4 retval; + SubFloat(retval, 0) = -SubFloat(a, 0); + SubFloat(retval, 1) = -SubFloat(a, 1); + SubFloat(retval, 2) = -SubFloat(a, 2); + SubFloat(retval, 3) = -SubFloat(a, 3); + + return retval; +} + +FORCEINLINE bool IsAllZeros(const fltx4& a) +{ + return (SubFloat(a, 0) == 0.0) && + (SubFloat(a, 1) == 0.0) && + (SubFloat(a, 2) == 0.0) && + (SubFloat(a, 3) == 0.0); +} + + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) > SubFloat(b, 0) && + SubFloat(a, 1) > SubFloat(b, 1) && + SubFloat(a, 2) > SubFloat(b, 2) && + SubFloat(a, 3) > SubFloat(b, 3); +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) >= SubFloat(b, 0) && + SubFloat(a, 1) >= SubFloat(b, 1) && + SubFloat(a, 2) >= SubFloat(b, 2) && + SubFloat(a, 3) >= SubFloat(b, 3); +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) == SubFloat(b, 0) && + SubFloat(a, 1) == SubFloat(b, 1) && + SubFloat(a, 2) == SubFloat(b, 2) && + SubFloat(a, 3) == SubFloat(b, 3); +} + +FORCEINLINE bool IsAnyEqual(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) == SubFloat(b, 0) || + SubFloat(a, 1) == SubFloat(b, 1) || + SubFloat(a, 2) == SubFloat(b, 2) || + SubFloat(a, 3) == SubFloat(b, 3); +} + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + int nRet = 0; + + nRet |= (SubInt(a, 0) & 0x80000000) >> 31; + nRet |= (SubInt(a, 1) & 0x80000000) >> 30; + nRet |= (SubInt(a, 2) & 0x80000000) >> 29; + nRet |= (SubInt(a, 3) & 0x80000000) >> 28; + + return nRet; +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE fltx4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) == SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) == SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) == SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) == SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) > SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) > SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) > SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) > SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) >= SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) >= SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) >= SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) >= SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) < SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) < SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) < SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) < SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) <= SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) <= SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) <= SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) <= SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) <= SubFloat(b, 0) && SubFloat(a, 0) >= -SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) <= SubFloat(b, 1) && SubFloat(a, 1) >= -SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) <= SubFloat(b, 2) && SubFloat(a, 2) >= -SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) <= SubFloat(b, 3) && SubFloat(a, 3) >= -SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return OrSIMD( + AndSIMD(ReplacementMask, NewValue), + AndNotSIMD(ReplacementMask, OldValue)); +} + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ + fltx4 retVal; + SubFloat(retVal, 0) = flValue; + SubFloat(retVal, 1) = flValue; + SubFloat(retVal, 2) = flValue; + SubFloat(retVal, 3) = flValue; + return retVal; +} + +FORCEINLINE fltx4 ReplicateIX4(int nValue) +{ + fltx4 retVal; + SubInt(retVal, 0) = nValue; + SubInt(retVal, 1) = nValue; + SubInt(retVal, 2) = nValue; + SubInt(retVal, 3) = nValue; + return retVal; + +} + +FORCEINLINE fltx4 CeilSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = ceil(SubFloat(a, 0)); + SubFloat(retVal, 1) = ceil(SubFloat(a, 1)); + SubFloat(retVal, 2) = ceil(SubFloat(a, 2)); + SubFloat(retVal, 3) = ceil(SubFloat(a, 3)); + return retVal; + +} + +FORCEINLINE fltx4 FloorSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = floor(SubFloat(a, 0)); + SubFloat(retVal, 1) = floor(SubFloat(a, 1)); + SubFloat(retVal, 2) = floor(SubFloat(a, 2)); + SubFloat(retVal, 3) = floor(SubFloat(a, 3)); + return retVal; + +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0) != 0.0f ? SubFloat(a, 0) : FLT_EPSILON); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1) != 0.0f ? SubFloat(a, 1) : FLT_EPSILON); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2) != 0.0f ? SubFloat(a, 2) : FLT_EPSILON); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3) != 0.0f ? SubFloat(a, 3) : FLT_EPSILON); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / SubFloat(a, 0); + SubFloat(retVal, 1) = 1.0 / SubFloat(a, 1); + SubFloat(retVal, 2) = 1.0 / SubFloat(a, 2); + SubFloat(retVal, 3) = 1.0 / SubFloat(a, 3); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / SubFloat(a, 0); + SubFloat(retVal, 1) = 1.0 / SubFloat(a, 1); + SubFloat(retVal, 2) = 1.0 / SubFloat(a, 2); + SubFloat(retVal, 3) = 1.0 / SubFloat(a, 3); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / (SubFloat(a, 0) == 0.0f ? FLT_EPSILON : SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / (SubFloat(a, 1) == 0.0f ? FLT_EPSILON : SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / (SubFloat(a, 2) == 0.0f ? FLT_EPSILON : SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / (SubFloat(a, 3) == 0.0f ? FLT_EPSILON : SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / (SubFloat(a, 0) == 0.0f ? FLT_EPSILON : SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / (SubFloat(a, 1) == 0.0f ? FLT_EPSILON : SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / (SubFloat(a, 2) == 0.0f ? FLT_EPSILON : SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / (SubFloat(a, 3) == 0.0f ? FLT_EPSILON : SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + fltx4 retVal; + SubFloat(retVal, 0) = powf(2, SubFloat(toPower, 0)); + SubFloat(retVal, 1) = powf(2, SubFloat(toPower, 1)); + SubFloat(retVal, 2) = powf(2, SubFloat(toPower, 2)); + SubFloat(retVal, 3) = powf(2, SubFloat(toPower, 3)); + + return retVal; +} + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + float flDot = SubFloat(a, 0) * SubFloat(b, 0) + + SubFloat(a, 1) * SubFloat(b, 1) + + SubFloat(a, 2) * SubFloat(b, 2); + return ReplicateX4(flDot); +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + float flDot = SubFloat(a, 0) * SubFloat(b, 0) + + SubFloat(a, 1) * SubFloat(b, 1) + + SubFloat(a, 2) * SubFloat(b, 2) + + SubFloat(a, 3) * SubFloat(b, 3); + return ReplicateX4(flDot); +} + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + return MaxSIMD(min, MinSIMD(max, in)); +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + fltx4 retval; + retval = a; + SubFloat(retval, 0) = 0; + return retval; +} + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + fltx4 retval; + SubFloat(retval, 0) = *pFlt; + return retval; +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + fltx4 retval = LoadAlignedSIMD(pSIMD.Base()); + SubInt(retval, 3) = 0; + return retval; +} + + +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ + fltx4 retval = { x, y, z, w }; + return retval; +} + +FORCEINLINE void StoreAlignedSIMD(float* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreUnalignedSIMD(float* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreUnalignedFloat(float* pSingleFloat, const fltx4& a) +{ + *pSingleFloat = SubFloat(a, 0); +} + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + *pSIMD = SubFloat(a, 0); + *(pSIMD + 1) = SubFloat(a, 1); + *(pSIMD + 2) = SubFloat(a, 2); +} + + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + StoreAlignedSIMD(pSIMD->Base(), a); +} + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ +#define SWAP_FLOATS( _a_, _ia_, _b_, _ib_ ) { float tmp = SubFloat( _a_, _ia_ ); SubFloat( _a_, _ia_ ) = SubFloat( _b_, _ib_ ); SubFloat( _b_, _ib_ ) = tmp; } + SWAP_FLOATS(x, 1, y, 0); + SWAP_FLOATS(x, 2, z, 0); + SWAP_FLOATS(x, 3, w, 0); + SWAP_FLOATS(y, 2, z, 1); + SWAP_FLOATS(y, 3, w, 1); + SWAP_FLOATS(z, 3, w, 2); +} + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + float lowest = min(min(SubFloat(a, 0), SubFloat(a, 1)), SubFloat(a, 2)); + return ReplicateX4(lowest); +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + float highest = max(max(SubFloat(a, 0), SubFloat(a, 1)), SubFloat(a, 2)); + return ReplicateX4(highest); +} + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ + (*pDest)[0] = SubFloat(vSrc, 0); + (*pDest)[1] = SubFloat(vSrc, 1); + (*pDest)[2] = SubFloat(vSrc, 2); + (*pDest)[3] = SubFloat(vSrc, 3); +} + +FORCEINLINE fltx4 IntSetImmediateSIMD(int nValue) +{ + fltx4 retval; + SubInt(retval, 0) = SubInt(retval, 1) = SubInt(retval, 2) = SubInt(retval, 3) = nValue; + return retval; +} + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void* RESTRICT pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void* RESTRICT pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD.Base())) = a; +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE fltx4 LoadAndConvertUint16SIMD(const uint16* pInts) +{ + fltx4 retval; + SubFloat(retval, 0) = pInts[0]; + SubFloat(retval, 1) = pInts[1]; + SubFloat(retval, 2) = pInts[2]; + SubFloat(retval, 3) = pInts[3]; +} + + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const u32x4& vSrcA) +{ + Assert(0); + fltx4 retval; + SubFloat(retval, 0) = ((float)SubInt(vSrcA, 0)); + SubFloat(retval, 1) = ((float)SubInt(vSrcA, 1)); + SubFloat(retval, 2) = ((float)SubInt(vSrcA, 2)); + SubFloat(retval, 3) = ((float)SubInt(vSrcA, 3)); + return retval; +} + + +#if 0 +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + fltx4 retval; + SubFloat(retval, 0) = ((float)(reinterpret_cast(&vSrcA.m128_s32[0]))); + SubFloat(retval, 1) = ((float)(reinterpret_cast(&vSrcA.m128_s32[1]))); + SubFloat(retval, 2) = ((float)(reinterpret_cast(&vSrcA.m128_s32[2]))); + SubFloat(retval, 3) = ((float)(reinterpret_cast(&vSrcA.m128_s32[3]))); + return retval; +} + + +FORCEINLINE i32x4 IntShiftLeftWordSIMD(const i32x4& vSrcA, const i32x4& vSrcB) +{ + i32x4 retval; + SubInt(retval, 0) = SubInt(vSrcA, 0) << SubInt(vSrcB, 0); + SubInt(retval, 1) = SubInt(vSrcA, 1) << SubInt(vSrcB, 1); + SubInt(retval, 2) = SubInt(vSrcA, 2) << SubInt(vSrcB, 2); + SubInt(retval, 3) = SubInt(vSrcA, 3) << SubInt(vSrcB, 3); + + + return retval; +} + +#endif + +#elif ( defined( _PS3 ) ) +#define SN_IMPROVED_INTRINSICS ( (( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 )) ||\ + (defined(__SN_VER__) && (__SN_VER__ > 25002)) ) + +FORCEINLINE float FloatSIMD(fltx4& a, int idx) +{ +#if SN_IMPROVED_INTRINSICS + return vec_extract(a, idx); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + return a_union.m128_f32[idx]; +#endif +} + +FORCEINLINE unsigned int UIntSIMD(u32x4& a, int idx) +{ +#if SN_IMPROVED_INTRINSICS + return vec_extract(a, idx); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxui); + return a_union.m128_u32[idx]; +#endif +} + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + return vec_add(a, b); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + return vec_sub(a, b); +} + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + return vec_madd(a, b, _VEC_ZEROF); +} + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return vec_madd(a, b, c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return vec_nmsub(a, b, c); +}; + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + + result = vec_madd(a, b, _VEC_ZEROF); + result = vec_madd(vec_sld(a, a, 4), vec_sld(b, b, 4), result); + result = vec_madd(vec_sld(a, a, 8), vec_sld(b, b, 8), result); + + result = vec_splat(result, 0); + + return result; +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + + result = vec_madd(a, b, _VEC_ZEROF); + result = vec_madd(vec_sld(a, a, 4), vec_sld(b, b, 4), result); + result = vec_add(vec_sld(result, result, 8), result); + + result = vec_splat(result, 0); + + return result; +} + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + return sinf4(radians); +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + sincosf4(radians, &sine, &cosine); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + sincosf4(radians, &sine, &cosine); +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + return acosf4(cs); +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + return atan2f4(a, b); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + return asinf4(sine); +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + return vec_max(a, b); +} +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + return vec_min(a, b); +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + return vec_and(a, b); +} +FORCEINLINE fltx4 AndSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_and((fltx4)a, b); +} +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const bi32x4& b) +{ + return vec_and(a, (fltx4)b); +} +FORCEINLINE bi32x4 AndSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_and(a, b); +} + +#if 0 +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + return vec_andc(b, a); +} +FORCEINLINE fltx4 AndNotSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_andc(b, (fltx4)a); +} +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const bi32x4& b) +{ + return (fltx4)vec_andc(b, (bi32x4)a); +} +FORCEINLINE bi32x4 AndNotSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_andc(b, a); +} +#else +template< typename T, typename U > +FORCEINLINE T AndNotSIMD(const T& a, const U& b) +{ + return vec_andc(b, (T)a); +} + +FORCEINLINE fltx4 AndNotSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_andc(b, (fltx4)a); +} +#endif + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + return vec_xor(a, b); +} +FORCEINLINE fltx4 XorSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_xor((fltx4)a, b); +} +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const bi32x4& b) +{ + return vec_xor(a, (fltx4)b); +} +FORCEINLINE bi32x4 XorSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_xor(a, b); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + return vec_or(a, b); +} +FORCEINLINE fltx4 OrSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_or((fltx4)a, b); +} +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const bi32x4& b) +{ + return vec_or(a, (fltx4)b); +} +FORCEINLINE i32x4 OrSIMD(const i32x4& a, const i32x4& b) +{ + return vec_or(a, b); +} +FORCEINLINE u32x4 OrSIMD(const u32x4& a, const u32x4& b) +{ + return vec_or(a, b); +} + +#if !defined(__SPU__) +FORCEINLINE bi32x4 OrSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_or(a, b); +} +#endif + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + return(SubSIMD(_VEC_ZEROF, a)); + +} + +FORCEINLINE bool IsAnyZeros(const fltx4& a) +{ + return vec_any_eq(a, _VEC_ZEROF); +} + +FORCEINLINE bool IsAnyZeros(const bi32x4& a) +{ + return vec_any_eq((u32x4)a, _VEC_ZERO); +} + +FORCEINLINE bool IsAllZeros(const bi32x4& a) +{ + return vec_all_eq((u32x4)a, _VEC_ZERO); +} + +FORCEINLINE bool IsAnyXYZZero(const fltx4& a) +{ +#if SN_IMPROVED_INTRINSICS + + fltx4 b = vec_insert(1.0f, a, 3); + + return vec_any_eq(b, _VEC_ZEROF); +#else + fltx4 b = vec_perm(a, _VEC_ONEF, _VEC_PERMUTE_XYZ0W1); + return vec_any_eq(b, _VEC_ZEROF); +#endif +} + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + return vec_all_gt(a, b); +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + return vec_all_ge(a, b); +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + return vec_all_eq(a, b); +} + + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + int nRet = 0; + + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + + nRet |= (a_union.m128_u32[0] & 0x80000000) >> 31; + nRet |= (a_union.m128_u32[1] & 0x80000000) >> 30; + nRet |= (a_union.m128_u32[2] & 0x80000000) >> 29; + nRet |= (a_union.m128_u32[3] & 0x80000000) >> 28; + + return nRet; +} +FORCEINLINE int TestSignSIMD(const bi32x4& a) +{ + int nRet = 0; + + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxbi); + + nRet |= (a_union.m128_u32[0] & 0x80000000) >> 31; + nRet |= (a_union.m128_u32[1] & 0x80000000) >> 30; + nRet |= (a_union.m128_u32[2] & 0x80000000) >> 29; + nRet |= (a_union.m128_u32[3] & 0x80000000) >> 28; + + return nRet; +} + +FORCEINLINE bool IsAnyNegative(const bi32x4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + return (fltx4)vec_and((u32x4)a, _VEC_CLEAR_WMASK); +} +FORCEINLINE bi32x4 SetWToZeroSIMD(const bi32x4& a) +{ + return (bi32x4)vec_and((u32x4)a, _VEC_CLEAR_WMASK); +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + return vec_any_lt(a, _VEC_ZEROF); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + return vec_any_ne(a, _VEC_ZEROF); +} + +#ifdef DIFFERENT_NATIVE_VECTOR_TYPES + +FORCEINLINE bool IsAnyTrue(const bi32x4& a) +{ + return vec_any_ne((vector unsigned int) a, _VEC_0L); +} + +#endif + +FORCEINLINE bi32x4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmpeq(a, b); +} +FORCEINLINE bi32x4 CmpEqSIMD(const i32x4& a, const i32x4& b) +{ + return (bi32x4)vec_cmpeq(a, b); +} +FORCEINLINE bi32x4 CmpEqSIMD(const u32x4& a, const u32x4& b) +{ + return (bi32x4)vec_cmpeq(a, b); +} + +FORCEINLINE bi32x4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmpgt(a, b); +} +FORCEINLINE bi32x4 CmpGtSIMD(const i32x4& a, const i32x4& b) +{ + return (bi32x4)vec_cmpgt(a, b); +} +FORCEINLINE bi32x4 CmpGtSIMD(const u32x4& a, const u32x4& b) +{ + return (bi32x4)vec_cmpgt(a, b); +} + +FORCEINLINE bi32x4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmpge(a, b); +} + + +FORCEINLINE bi32x4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmplt(a, b); +} + +FORCEINLINE bi32x4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmple(a, b); +} + + + +FORCEINLINE bi32x4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + i32x4 control; + control = vec_cmpb(a, b); + return (bi32x4)vec_cmpeq((u32x4)control, _VEC_ZERO); +} + +FORCEINLINE int CmpAnyLeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_le(a, b); +} + +FORCEINLINE int CmpAnyGeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_ge(a, b); +} + +FORCEINLINE int CmpAnyLtSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_lt(a, b); +} +FORCEINLINE int CmpAnyLtSIMD(const bi32x4& a, const i32x4& b) +{ + return vec_any_lt((i32x4)a, b); +} + +FORCEINLINE int CmpAnyGtSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_gt(a, b); +} + +FORCEINLINE int CmpAnyNeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_ne(a, b); +} +FORCEINLINE int CmpAnyNeSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_any_ne(a, b); +} +FORCEINLINE int CmpAnyNeSIMD(const bi32x4& a, const i32x4& b) +{ + return vec_any_ne(a, (bi32x4)b); +} + +FORCEINLINE int CmpAllLeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_all_le(a, b); +} + +FORCEINLINE fltx4 MaskedAssign(const bi32x4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return vec_sel(OldValue, NewValue, ReplacementMask); +} + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return vec_sel(OldValue, NewValue, (const bi32x4)ReplacementMask); +} + +FORCEINLINE vector signed short MaskedAssign(const vector unsigned short& ReplacementMask, const vector signed short& NewValue, const vector signed short& OldValue) +{ + return vec_sel(OldValue, NewValue, ReplacementMask); +} + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_splats(flValue); +#else + float* pValue = &flValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + + fltx4 result; + + result = vec_ld(0, pValue); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, pValue)), 0); + + return result; +#endif +} + +FORCEINLINE fltx4 ReplicateX4(const float* pValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_splats(*pValue); +#else + Assert(pValue); + fltx4 result; + + result = vec_ld(0, pValue); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, pValue)), 0); + + return result; +#endif +} + +FORCEINLINE i32x4 ReplicateIX4(int nValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_splats(nValue); +#else + int* pValue = &nValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + i32x4 result; + + result = vec_ld(0, pValue); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, pValue)), 0); + + return result; +#endif +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + return sqrtf4(a); +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ +#if defined( _PS3 ) && !defined( SPU ) + fltx4 vRecipSquareRoot = vec_rsqrte(a); + i32x4 vOne = vec_splat_s32(1); + i32x4 vAllOnes = vec_splat_s32(-1); + i32x4 vShiftLeft24 = vec_splat_s32(-8); + fltx4 vZero = (fltx4)vec_splat_s32(0); + u32x4 vInputShifted = vec_sl((u32x4)a, (u32x4)vOne); + u32x4 vInfinityShifted = vec_sl((u32x4)vAllOnes, (u32x4)vShiftLeft24); + bi32x4 vEqualsZero = vec_vcmpeqfp(a, vZero); + bi32x4 vEqualsInfinity = vec_vcmpequw(vInputShifted, vInfinityShifted); + fltx4 vSquareRoot = vec_madd(a, vRecipSquareRoot, _VEC_ZEROF); + bi32x4 vResultMask = vec_vcmpequw((u32x4)vEqualsInfinity, (u32x4)vEqualsZero); + fltx4 vCorrectedSquareRoot = vec_sel(a, vSquareRoot, vResultMask); + + return vCorrectedSquareRoot; +#else + return SqrtSIMD(a); +#endif +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + return vec_rsqrte(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + fltx4 result; + vmathV4RsqrtPerElem((VmathVector4*)&result, (const VmathVector4*)&a); + + return result; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + return vec_re(a); +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + bi32x4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalEstSIMD(ret); + return ret; +} + + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + fltx4 result; + vmathV4RecipPerElem((VmathVector4*)&result, (const VmathVector4*)&a); + + return result; +} + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalSIMD(b), a); +} + +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalEstSIMD(b), a); +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + bi32x4 zero_mask = CmpEqSIMD(a, _VEC_ZEROF); + fltx4 a_safe = OrSIMD(a, AndSIMD(_VEC_EPSILONF, zero_mask)); + return ReciprocalSIMD(a_safe); + +} + + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + return exp2f4(toPower); +} + +FORCEINLINE fltx4 Exp2EstSIMD(const fltx4& f) +{ + return exp2f4fast(f); +} + + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + fltx4 result = vec_max(min, in); + return vec_min(max, result); +} + + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ +#if SN_IMPROVED_INTRINSICS + + fltx4 v0, v1; + + Assert(pSIMD); + + + v0 = (fltx4)vec_lvlx(0, (float*)pSIMD); + v1 = (fltx4)vec_lvrx(16, (float*)pSIMD); + return vec_or(v0, v1); + +#else + + fltx4 v0, v1; + vector unsigned char permMask; + + Assert(pSIMD); + + v0 = vec_ld(0, pSIMD); + permMask = vec_lvsl(0, pSIMD); + v1 = vec_ld(15, pSIMD); + + return vec_perm(v0, v1, permMask); + +#endif +} + +FORCEINLINE fltx4 LoadUnsignedByte4SIMD(unsigned char* pBytes) +{ + +#if SN_IMPROVED_INTRINSICS + + __vector unsigned char res_uc; + __vector unsigned short res_us; + + __vector unsigned char vZero8 = (__vector unsigned char)vec_splat_u8(0); + __vector unsigned short vZero16 = (__vector unsigned short)vec_splat_u16(0); + + res_uc = (__vector unsigned char)vec_lvlx(0, pBytes); + res_uc = vec_mergeh(vZero8, res_uc); + res_us = vec_mergeh(vZero16, (__vector unsigned short)res_uc); + return vec_ctf((__vector unsigned int)res_us, 0); + +#else + + vector unsigned char v0, v1; + vector bool char res_uc; + vector unsigned char permMask; + vector bool short res_us; + + vector bool char vZero8 = (vector bool char)vec_splat_u8(0); + vector bool short vZero16 = (vector bool short)vec_splat_u16(0); + + v0 = vec_ld(0, pBytes); + permMask = vec_lvsl(0, pBytes); + v1 = vec_ld(3, pBytes); + res_uc = (vector bool char)vec_perm(v0, v1, permMask); + res_uc = vec_mergeh(vZero8, res_uc); + res_us = vec_mergeh(vZero16, (vector bool short)res_uc); + return vec_ctf((vector unsigned int)res_us, 0); + +#endif + +} + +FORCEINLINE fltx4 LoadSignedByte4SIMD(signed char* pBytes) +{ + +#if SN_IMPROVED_INTRINSICS + + vector signed char res_uc; + vector signed short res_us; + vector signed int res_ui; + + res_uc = (vector signed char)vec_lvlx(0, pBytes); + res_us = vec_unpackh(res_uc); + res_ui = vec_unpackh(res_us); + return vec_ctf(res_ui, 0); + +#else + + vector signed char v0, v1, res_uc; + vector unsigned char permMask; + vector signed short res_us; + vector signed int res_ui; + + v0 = vec_ld(0, pBytes); + permMask = vec_lvsl(0, pBytes); + v1 = vec_ld(3, pBytes); + res_uc = vec_perm(v0, v1, permMask); + res_us = vec_unpackh(res_uc); + res_ui = vec_unpackh(res_us); + return vec_ctf(res_ui, 0); + +#endif + +} + + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + Assert(pSIMD); + + fltx4 v0 = vec_ld(0, (float*)(pSIMD)); + vector unsigned char permMask = vec_lvsl(0, (float*)(pSIMD)); + fltx4 v1 = vec_ld(11, (float*)(pSIMD)); + + return vec_perm(v0, v1, permMask); +} + + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + fltx4 v0 = vec_lde(0, const_cast(pFlt)); + vector unsigned char permMask = vec_lvsl(0, const_cast(pFlt)); + return vec_perm(v0, v0, permMask); +} + + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return vec_ld(0, (float*)pSIMD); +} + +#ifndef SPU +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + fltx4 out; + out = vec_ld(0, pSIMD.Base()); + + return (fltx4)vec_and((u32x4)out, _VEC_CLEAR_WMASK); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned* RESTRICT pSIMD) +{ + fltx4 out; + out = vec_ld(0, pSIMD->Base()); + + return (fltx4)vec_and((u32x4)out, _VEC_CLEAR_WMASK); +} + + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + vec_st(a, 0, pSIMD->Base()); +} +#endif + +FORCEINLINE void StoreAlignedSIMD(float* pSIMD, const fltx4& a) +{ + vec_st(a, 0, pSIMD); +} + +FORCEINLINE void StoreUnalignedSIMD(float* pSIMD, const fltx4& a) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + vec_stvlx(a, 0, pSIMD); + vec_stvrx(a, 16, pSIMD); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + pSIMD[0] = a_union.m128_f32[0]; + pSIMD[1] = a_union.m128_f32[1]; + pSIMD[2] = a_union.m128_f32[2]; + pSIMD[3] = a_union.m128_f32[3]; +#endif + +} + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + pSIMD[0] = a_union.m128_f32[0]; + pSIMD[1] = a_union.m128_f32[1]; + pSIMD[2] = a_union.m128_f32[2]; +}; + + + +#ifndef SPU + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d); +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ +#if USING_POINTLESSLY_SLOW_SONY_CODE + return vmathV4MakeFromElems_V(x, y, z, w).vec128; +#else + fltx4 vx = vec_lvlx(0, &x); + fltx4 vy = vec_lvlx(0, &y); + fltx4 vz = vec_lvlx(0, &z); + fltx4 vw = vec_lvlx(0, &w); + return Compress4SIMD(vx, vy, vz, vw); +#endif +} + + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} +#endif + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ + i32x4 asInt = vec_cts(vSrc, 0); + vec_st(asInt, 0, pDest->Base()); +} + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ + fltx4 p0, p1, p2, p3; + + p0 = vec_mergeh(x, z); + p1 = vec_mergeh(y, w); + p2 = vec_mergel(x, z); + p3 = vec_mergel(y, w); + + x = vec_mergeh(p0, p1); + y = vec_mergel(p0, p1); + z = vec_mergeh(p2, p3); + w = vec_mergel(p2, p3); +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return _VEC_ZEROF; +} +FORCEINLINE i32x4 LoadZeroISIMD(void) +{ + return vec_splat_s32(0); +} + + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return _VEC_ONEF; +} +FORCEINLINE i32x4 LoadOneISIMD(void) +{ + return vec_splat_s32(1); +} + +FORCEINLINE fltx4 SplatXSIMD(fltx4 a) +{ + return vec_splat(a, 0); +} +FORCEINLINE fltx4 SplatYSIMD(fltx4 a) +{ + return vec_splat(a, 1); +} +FORCEINLINE fltx4 SplatZSIMD(fltx4 a) +{ + return vec_splat(a, 2); +} +FORCEINLINE fltx4 SplatWSIMD(fltx4 a) +{ + return vec_splat(a, 3); +} + +FORCEINLINE bi32x4 SplatXSIMD(bi32x4 a) +{ + return vec_splat(a, 0); +} +FORCEINLINE bi32x4 SplatYSIMD(bi32x4 a) +{ + return vec_splat(a, 1); +} +FORCEINLINE bi32x4 SplatZSIMD(bi32x4 a) +{ + return vec_splat(a, 2); +} +FORCEINLINE bi32x4 SplatWSIMD(bi32x4 a) +{ + return vec_splat(a, 3); +} + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + return vec_sel(a, x, _VEC_COMPONENT_MASK_0); +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + return vec_sel(a, y, _VEC_COMPONENT_MASK_1); +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + return vec_sel(a, z, _VEC_COMPONENT_MASK_2); +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + return vec_sel(a, w, _VEC_COMPONENT_MASK_3); +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_insert(flValue, a, nComponent); +#else + fltx4_union a_union; + a_union.vmxf = vec_ld(0, &a); + a_union.m128_f32[nComponent] = flValue; + return a_union.vmxf; +#endif +} + +FORCEINLINE float GetComponentSIMD(const fltx4& a, int nComponent) +{ +#if SN_IMPROVED_INTRINSICS + return vec_extract(a, nComponent); +#else + fltx4_union a_union; + a_union.vmxf = vec_ld(0, &a); + return a_union.m128_f32[nComponent]; +#endif +} + + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + return vec_sld(a, a, 4); +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + return vec_sld(a, a, 8); +} + +FORCEINLINE fltx4 RotateRight(const fltx4& a) +{ + return vec_sld(a, a, 12); +} + +FORCEINLINE fltx4 RotateRight2(const fltx4& a) +{ + return vec_sld(a, a, 8); +} + +template < uint nBits, typename T > +FORCEINLINE T ShiftLeftByBits(const T& a) +{ + if (nBits >= 128) + { + return (T)LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + T t = vec_sld(a, ((T)LoadZeroSIMD()), (nBits >> 3)); + return ShiftLeftByBits< (nBits & 0x7) >(t); + } + else + { + vector unsigned int shifter = (vector unsigned int) (vec_splat_s8(((signed char)(nBits & 0x7)))); + return (T)vec_sll((vector signed int) a, shifter); + } +} + +template < uint nBits, typename T > +FORCEINLINE T ShiftRightByBits(const T& a) +{ + if (nBits >= 128) + { + return (T)LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + T t = vec_sld(((T)LoadZeroSIMD()), a, 16 - (nBits >> 3)); + return ShiftRightByBits< (nBits & 0x7) >(t); + } + else + { + vector unsigned int shifter = (vector unsigned int) (vec_splat_s8(((signed char)(nBits & 0x7)))); + return (T)vec_srl((vector unsigned int) a, shifter); + } +} + + + + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + fltx4 result; + fltx4 x = vec_splat(a, 0); + fltx4 y = vec_splat(a, 1); + fltx4 z = vec_splat(a, 2); + + if (vec_any_nan(a)) + { + x = vec_all_nan(x) ? _VEC_FLTMAX : x; + y = vec_all_nan(y) ? _VEC_FLTMAX : y; + z = vec_all_nan(z) ? _VEC_FLTMAX : z; + } + + result = vec_min(y, x); + result = vec_min(z, result); + + return result; + +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + fltx4 result; + fltx4 x = vec_splat(a, 0); + fltx4 y = vec_splat(a, 1); + fltx4 z = vec_splat(a, 2); + + if (vec_any_nan(a)) + { + x = vec_all_nan(x) ? _VEC_FLTMIN : x; + y = vec_all_nan(y) ? _VEC_FLTMIN : y; + z = vec_all_nan(z) ? _VEC_FLTMIN : z; + } + + result = vec_max(y, x); + result = vec_max(z, result); + + return result; +} + + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const int32* RESTRICT pSIMD) +{ + return vec_ld(0, const_cast(pSIMD)); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const int32* RESTRICT pSIMD) +{ + i32x4 v0, v1; + vector unsigned char permMask; + + Assert(pSIMD); + + v0 = vec_ld(0, const_cast(pSIMD)); + permMask = vec_lvsl(0, const_cast(pSIMD)); + v1 = vec_ld(15, const_cast(pSIMD)); + + return vec_perm(v0, v1, permMask); + +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const i32x4& a) +{ + vec_st(a, 0, pSIMD); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + vec_st((i32x4)a, 0, pSIMD); +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const i32x4& a) +{ + vec_st(a, 0, pSIMD.Base()); +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* pSIMD, const i32x4& a) +{ +#if SN_IMPROVED_INTRINSICS + + vec_stvlx(a, 0, pSIMD); + vec_stvrx(a, 16, pSIMD); + +#else + + fltx4_union tmp; + vec_st(a, 0, &tmp.vmxi); + + pSIMD[0] = tmp.m128_u32[0]; + pSIMD[1] = tmp.m128_u32[1]; + pSIMD[2] = tmp.m128_u32[2]; + pSIMD[3] = tmp.m128_u32[3]; + +#endif +} + +FORCEINLINE fltx4 CompressSIMD(fltx4 const& a, fltx4 const& b) +{ + const int32 ALIGN16 n4shuffleACXZ[4] ALIGN16_POST = { 0x00010203, 0x08090A0B, 0x10111213, 0x18191A1B }; + return vec_perm(a, b, (vec_uchar16)LoadAlignedIntSIMD(n4shuffleACXZ)); +} + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d) +{ + fltx4 ab = vec_mergeh(a, b); + fltx4 cd = vec_mergeh(c, d); + static const int32 ALIGN16 shuffleABXY[4] ALIGN16_POST = { 0x00010203, 0x04050607, 0x10111213, 0x14151617 }; + + return vec_perm(ab, cd, (vec_uchar16)LoadAlignedIntSIMD(shuffleABXY)); +} + + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return vec_ctf(vSrcA, 0); +} + + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return vec_ctf(vSrcA, 0); +} + +#define UnsignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (vec_ctf( (vSrcA), (uImmed) )) + +#define SignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (vec_ctf( (vSrcA), (uImmed) )) + +#define IntSetImmediateSIMD(x) (vec_splat_s32(x)) + + +FORCEINLINE u32x4 IntShiftLeftWordSIMD(u32x4 vSrcA, u32x4 vSrcB) +{ + return vec_sl(vSrcA, vSrcB); +} + + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract(a, idx)); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + return a_union.m128_f32[idx]; +#endif +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE uint32 SubInt(const u32x4& a, int idx) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract(a, idx)); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxui); + return a_union.m128_u32[idx]; +#endif +} + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract((u32x4)a, idx)); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + return a_union.m128_u32[idx]; +#endif +} + +FORCEINLINE uint32& SubInt(u32x4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE uint32 SubFloatConvertToInt(const fltx4& a, int idx) +{ + +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract(vec_ctu(a, 0), idx)); +#else + u32x4 t = vec_ctu(a, 0); + return SubInt(t, idx); +#endif + +} + +template< typename T, typename U > +FORCEINLINE T PermuteVMX(T a, T b, U swizzleMask) +{ + return vec_perm(a, b, (vec_uchar16)swizzleMask); +} + + +#if !defined(__SPU__) +#define fsel __fsel +#endif + +inline bool IsVector3LessThan(const fltx4& v1, const fltx4& v2) +{ + return vec_any_lt(v1, v2); +} + +inline bool IsVector3GreaterOrEqual(const fltx4& v1, const fltx4& v2) +{ + return !IsVector3LessThan(v1, v2); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0) != 0.0f ? SubFloat(a, 0) : FLT_EPSILON); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1) != 0.0f ? SubFloat(a, 1) : FLT_EPSILON); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2) != 0.0f ? SubFloat(a, 2) : FLT_EPSILON); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3) != 0.0f ? SubFloat(a, 3) : FLT_EPSILON); + return retVal; +} + +FORCEINLINE fltx4 FloorSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = floor(SubFloat(a, 0)); + SubFloat(retVal, 1) = floor(SubFloat(a, 1)); + SubFloat(retVal, 2) = floor(SubFloat(a, 2)); + SubFloat(retVal, 3) = floor(SubFloat(a, 3)); + return retVal; +} + +#elif ( defined( _X360 ) ) + +inline bool IsVector3LessThan(const fltx4& v1, const fltx4& v2) +{ + return !XMVector3GreaterOrEqual(v1, v2); +} + +inline BOOL IsVector3GreaterOrEqual(const fltx4& v1, const fltx4& v2) +{ + return XMVector3GreaterOrEqual(v1, v2); +} + + +FORCEINLINE float& FloatSIMD(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE unsigned int& UIntSIMD(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + return __vaddfp(a, b); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + return __vsubfp(a, b); +} + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + return __vmulfp(a, b); +} + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return __vmaddfp(a, b, c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return __vnmsubfp(a, b, c); +}; + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + return __vmsum3fp(a, b); +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + return __vmsum4fp(a, b); +} + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + return XMVectorSin(radians); +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + XMVectorSinCos(&sine, &cosine, radians); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + XMVectorSinCos(&sine, &cosine, radians); +} + +FORCEINLINE void CosSIMD(fltx4& cosine, const fltx4& radians) +{ + cosine = XMVectorCos(radians); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + return XMVectorASin(sine); +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + return XMVectorACos(cs); +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + return XMVectorATan2(a, b); +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + return __vmaxfp(a, b); +} + +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + return __vminfp(a, b); +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + return __vand(a, b); +} + +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + return __vandc(b, a); +} + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + return __vxor(a, b); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + return __vor(a, b); +} + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + return XMVectorNegate(a); +} + +FORCEINLINE bool IsAllZeros(const fltx4& a) +{ + unsigned int equalFlags = 0; + __vcmpeqfpR(a, Four_Zeros, &equalFlags); + return XMComparisonAllTrue(equalFlags); +} + +FORCEINLINE bool IsAnyZeros(const fltx4& a) +{ + unsigned int conditionregister; + XMVectorEqualR(&conditionregister, a, XMVectorZero()); + return XMComparisonAnyTrue(conditionregister); +} + +FORCEINLINE bool IsAnyXYZZero(const fltx4& a) +{ + fltx4 temp = __vrlimi(a, a, 1, 1); + unsigned int conditionregister; + XMVectorEqualR(&conditionregister, temp, XMVectorZero()); + return XMComparisonAnyTrue(conditionregister); +} + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterR(&cr, a, b); + return XMComparisonAllTrue(cr); +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterOrEqualR(&cr, a, b); + return XMComparisonAllTrue(cr); +} + +FORCEINLINE bool IsAnyGreaterThan(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterR(&cr, a, b); + return XMComparisonAnyTrue(cr); +} + +FORCEINLINE bool IsAnyGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterOrEqualR(&cr, a, b); + return XMComparisonAnyTrue(cr); +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorEqualR(&cr, a, b); + return XMComparisonAllTrue(cr); +} + + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + int nRet = 0; + + const fltx4_union& a_union = (const fltx4_union&)a; + nRet |= (a_union.m128_u32[0] & 0x80000000) >> 31; + nRet |= (a_union.m128_u32[1] & 0x80000000) >> 30; + nRet |= (a_union.m128_u32[2] & 0x80000000) >> 29; + nRet |= (a_union.m128_u32[3] & 0x80000000) >> 28; + + return nRet; +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + return __vrlimi(a, __vzero(), 1, 0); +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + unsigned int equalFlags = 0; + fltx4 signMask = __vspltisw(-1); + signMask = __vslw(signMask, signMask); + __vcmpequwR(Four_Zeros, __vand(signMask, a), &equalFlags); + return !XMComparisonAllTrue(equalFlags); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + unsigned int equalFlags = 0; + __vcmpequwR(Four_Zeros, a, &equalFlags); + return XMComparisonAnyFalse(equalFlags); +} + +FORCEINLINE fltx4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpeqfp(a, b); +} + + +FORCEINLINE fltx4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgtfp(a, b); +} + +FORCEINLINE fltx4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgefp(a, b); +} + +FORCEINLINE fltx4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgtfp(b, a); +} + +FORCEINLINE fltx4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgefp(b, a); +} + +FORCEINLINE fltx4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + return XMVectorInBounds(a, b); +} + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return __vsel(OldValue, NewValue, ReplacementMask); +} + + +template< typename T, typename U > +FORCEINLINE T PermuteVMX(T a, T b, U swizzleMask) +{ + return __vperm(a, b, swizzleMask); +} + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ + float* pValue = &flValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + return __vspltw(__lvlx(pValue, 0), 0); +} + +FORCEINLINE fltx4 ReplicateX4(const float* pValue) +{ + Assert(pValue); + return __vspltw(__lvlx(pValue, 0), 0); +} + +FORCEINLINE fltx4 ReplicateIX4(int nValue) +{ + int* pValue = &nValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + return __vspltw(__lvlx(pValue, 0), 0); +} + +FORCEINLINE fltx4 CeilSIMD(const fltx4& a) +{ + return __vrfip(a); +} + +FORCEINLINE fltx4 RoundSIMD(const fltx4& a) +{ + return __vrfin(a); +} + +FORCEINLINE fltx4 FloorSIMD(const fltx4& a) +{ + return __vrfim(a); +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ + return XMVectorSqrtEst(a); +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + return XMVectorSqrt(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + return __vrsqrtefp(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 a_safe = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + return ReciprocalSqrtEstSIMD(a_safe); +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + return XMVectorReciprocalSqrt(a); +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + return __vrefp(a); +} + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + return XMVectorReciprocal(a); +} + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalSIMD(b), a); +} + +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalEstSIMD(b), a); +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 a_safe = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + return ReciprocalEstSIMD(a_safe); +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 a_safe = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + return ReciprocalSIMD(a_safe); + +} + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + return XMVectorExp(toPower); +} + +FORCEINLINE fltx4 Exp2EstSIMD(const fltx4& f) +{ + return XMVectorExpEst(f); +} + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + return XMVectorClamp(in, min, max); +} + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ + return XMLoadVector4(pSIMD); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + return XMLoadVector3(pSIMD); +} + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + return __lvlx(pFlt, 0); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + fltx4 out = XMLoadVector3A(pSIMD.Base()); + return __vrlimi(out, __vzero(), 1, 0); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned* RESTRICT pSIMD) +{ + fltx4 out = XMLoadVector3A(pSIMD); + return __vrlimi(out, __vzero(), 1, 0); +} + +FORCEINLINE void StoreAlignedSIMD(float* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreUnalignedSIMD(float* pSIMD, const fltx4& a) +{ + XMStoreVector4(pSIMD, a); +} + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + XMStoreVector3(pSIMD, a); +} + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + XMStoreVector3A(pSIMD->Base(), a); +} + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + b = __vrlimi(b, b, 15, 1); + c = __vrlimi(c, c, 15, 2); + + a = __vrlimi(a, b, 1, 0); + b = __vrlimi(b, c, 2 | 1, 0); + c = __vrlimi(c, d, 4 | 2 | 1, 3); + + float* RESTRICT pOut = pDestination->Base(); + StoreUnalignedSIMD(pOut + 0, a); + StoreUnalignedSIMD(pOut + 4, b); + StoreUnalignedSIMD(pOut + 8, c); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + b = __vrlimi(b, b, 15, 1); + c = __vrlimi(c, c, 15, 2); + + a = __vrlimi(a, b, 1, 0); + b = __vrlimi(b, c, 2 | 1, 0); + c = __vrlimi(c, d, 4 | 2 | 1, 3); + + float* RESTRICT pOut = pDestination->Base(); + StoreAlignedSIMD(pOut + 0, a); + StoreAlignedSIMD(pOut + 4, b); + StoreAlignedSIMD(pOut + 8, c); +} + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ + fltx4 asInt = __vctsxs(vSrc, 0); + XMStoreVector4A(pDest->Base(), asInt); +} + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ + XMMATRIX xyzwMatrix = _XMMATRIX(x, y, z, w); + xyzwMatrix = XMMatrixTranspose(xyzwMatrix); + x = xyzwMatrix.r[0]; + y = xyzwMatrix.r[1]; + z = xyzwMatrix.r[2]; + w = xyzwMatrix.r[3]; +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return XMVectorZero(); +} + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return XMVectorSplatOne(); +} + +FORCEINLINE fltx4 SplatXSIMD(fltx4 a) +{ + return XMVectorSplatX(a); +} + +FORCEINLINE fltx4 SplatYSIMD(fltx4 a) +{ + return XMVectorSplatY(a); +} + +FORCEINLINE fltx4 SplatZSIMD(fltx4 a) +{ + return XMVectorSplatZ(a); +} + +FORCEINLINE fltx4 SplatWSIMD(fltx4 a) +{ + return XMVectorSplatW(a); +} + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 result = __vrlimi(a, x, 8, 0); + return result; +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 result = __vrlimi(a, y, 4, 0); + return result; +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 result = __vrlimi(a, z, 2, 0); + return result; +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + fltx4 result = __vrlimi(a, w, 1, 0); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ + static int s_nVrlimiMask[4] = { 8, 4, 2, 1 }; + fltx4 val = ReplicateX4(flValue); + fltx4 result = __vrlimi(a, val, s_nVrlimiMask[nComponent], 0); + return result; +} + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 1); +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 2); +} + +FORCEINLINE fltx4 RotateRight(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 3); +} + +FORCEINLINE fltx4 RotateRight2(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 2); +} + + +template < uint nBits > +FORCEINLINE fltx4 ShiftLeftByBits(const fltx4& a) +{ + if (nBits >= 128) + { + return LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + fltx4 t = __vsldoi(a, (LoadZeroSIMD()), (nBits >> 3)); + return ShiftLeftByBits< (nBits & 0x7) >(t); + } + else + { + u32x4 shifter = u32x4(__vspltisb(((signed char)(nBits & 0x7)))); + return __vsl(a, shifter); + } +} + +template < uint nBits > +FORCEINLINE fltx4 ShiftRightByBits(const fltx4& a) +{ + if (nBits >= 128) + { + return LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + fltx4 t = __vsldoi((LoadZeroSIMD()), a, 16 - (nBits >> 3)); + return ShiftRightByBits< (nBits & 0x7) >(t); + } + else + { + u32x4 shifter = u32x4(__vspltisb(((signed char)(nBits & 0x7)))); + return __vsr(a, shifter); + } +} + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + fltx4 compareOne = a; + compareOne = __vrlimi(compareOne, a, 8 | 4, 1); + fltx4 retval = MinSIMD(a, compareOne); + compareOne = __vrlimi(compareOne, a, 8, 2); + retval = MinSIMD(retval, compareOne); + return SplatXSIMD(retval); +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + fltx4 compareOne = a; + compareOne = __vrlimi(compareOne, a, 8 | 4, 1); + fltx4 retval = MaxSIMD(a, compareOne); + compareOne = __vrlimi(compareOne, a, 8, 2); + retval = MaxSIMD(retval, compareOne); + return SplatXSIMD(retval); +} + + +void TransformManyPointsBy(VectorAligned* RESTRICT pVectors, unsigned int numVectors, FLTX4 mRow1, FLTX4 mRow2, FLTX4 mRow3); + +FORCEINLINE void TransformManyPointsBy(VectorAligned* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& pMatrix) +{ + return TransformManyPointsBy(pVectors, numVectors, + LoadUnalignedSIMD(pMatrix[0]), LoadUnalignedSIMD(pMatrix[1]), LoadUnalignedSIMD(pMatrix[2])); +} + +FORCEINLINE void TransformManyPointsByA(VectorAligned* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& pMatrix) +{ + return TransformManyPointsBy(pVectors, numVectors, + LoadAlignedSIMD(pMatrix[0]), LoadAlignedSIMD(pMatrix[1]), LoadAlignedSIMD(pMatrix[2])); +} + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void* RESTRICT pSIMD) +{ + return XMLoadVector4A(pSIMD); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void* RESTRICT pSIMD) +{ + return XMLoadVector4(pSIMD); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD.Base())) = a; +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + XMStoreVector4(pSIMD, a); +} + +FORCEINLINE fltx4 LoadAndConvertUint16SIMD(const uint16* pInts) +{ + return XMLoadUShort4(reinterpret_cast(pInts)); +} + +FORCEINLINE fltx4 CompressSIMD(fltx4 const& a, fltx4 const& b) +{ + return XMVectorPermute(a, b, XMVectorPermuteControl(0, 2, 4, 6)); +} + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d) +{ + fltx4 abcd = __vrlimi(a, b, 4, 3); + abcd = __vrlimi(abcd, c, 2, 2); + abcd = __vrlimi(abcd, d, 1, 1); + + return abcd; +} + + +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ + fltx4 vx = __lvlx(&x, 0); + fltx4 vy = __lvlx(&y, 0); + fltx4 vz = __lvlx(&z, 0); + fltx4 vw = __lvlx(&w, 0); + return Compress4SIMD(vx, vy, vz, vw); +} + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return __vcfux(vSrcA, 0); +} + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return __vcfsx(vSrcA, 0); +} + +#define UnsignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (__vcfux( (vSrcA), (uImmed) )) + +#define SignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (__vcfsx( (vSrcA), (uImmed) )) + +#define IntSetImmediateSIMD(x) (__vspltisw(x)) + +FORCEINLINE fltx4 IntShiftLeftWordSIMD(fltx4 vSrcA, fltx4 vSrcB) +{ + return __vslw(vSrcA, vSrcB); +} + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ + const fltx4_union& a_union = (const fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE uint32 SubFloatConvertToInt(const fltx4& a, int idx) +{ + fltx4 t = __vctuxs(a, 0); + const fltx4_union& a_union = (const fltx4_union&)t; + return a_union.m128_u32[idx]; +} + + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ + const fltx4_union& a_union = (const fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE uint32& SubInt(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +#else + +FORCEINLINE void StoreAlignedSIMD(float* RESTRICT pSIMD, const fltx4& a) +{ + _mm_store_ps(pSIMD, a); +} + +FORCEINLINE void StoreAlignedSIMD(short* RESTRICT pSIMD, const shortx8& a) +{ + _mm_store_si128((shortx8*)pSIMD, a); +} +FORCEINLINE void StoreUnalignedSIMD(float* RESTRICT pSIMD, const fltx4& a) +{ + _mm_storeu_ps(pSIMD, a); +} + +FORCEINLINE void StoreUnalignedSIMD(short* RESTRICT pSIMD, const shortx8& a) +{ + _mm_storeu_si128((shortx8*)pSIMD, a); +} + +FORCEINLINE void StoreUnalignedFloat(float* pSingleFloat, const fltx4& a) +{ + _mm_store_ss(pSingleFloat, a); +} + + +FORCEINLINE fltx4 RotateLeft(const fltx4& a); +FORCEINLINE fltx4 RotateLeft2(const fltx4& a); + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + _mm_store_ss(pSIMD, a); + _mm_store_ss(pSIMD + 1, RotateLeft(a)); + _mm_store_ss(pSIMD + 2, RotateLeft2(a)); +} + + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + StoreAlignedSIMD(pSIMD->Base(), a); +} + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return _mm_load_ps(reinterpret_cast (pSIMD)); +} + +FORCEINLINE shortx8 LoadAlignedShortSIMD(const void* pSIMD) +{ + return _mm_load_si128(reinterpret_cast (pSIMD)); +} + +FORCEINLINE shortx8 LoadUnalignedShortSIMD(const void* pSIMD) +{ + return _mm_loadu_si128(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_and_ps(a, b); +} + +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_andnot_ps(a, b); +} + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_xor_ps(a, b); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_or_ps(a, b); +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + return AndSIMD(a, LoadAlignedSIMD(g_SIMD_clear_wmask)); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + return SetWToZeroSIMD(LoadAlignedSIMD(pSIMD.Base())); +} + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ + return _mm_loadu_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + return _mm_loadu_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + return _mm_load_ss(pFlt); +} + +FORCEINLINE fltx4 ReplicateIX4(int i) +{ + fltx4 value = _mm_set_ss(*((float*)&i));; + return _mm_shuffle_ps(value, value, 0); +} + + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ + __m128 value = _mm_set_ss(flValue); + return _mm_shuffle_ps(value, value, 0); +} + +FORCEINLINE fltx4 ReplicateX4(const float* flValue) +{ + __m128 value = _mm_set_ss(*flValue); + return _mm_shuffle_ps(value, value, 0); +} + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_f32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_f32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE uint32 SubFloatConvertToInt(const fltx4& a, int idx) +{ + return (uint32)SubFloat(a, idx); +} + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_u32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE uint32& SubInt(fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_u32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return Four_Zeros; +} + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return Four_Ones; +} + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return OrSIMD( + AndSIMD(ReplacementMask, NewValue), + AndNotSIMD(ReplacementMask, OldValue)); +} + +#define MM_SHUFFLE_REV(a,b,c,d) _MM_SHUFFLE(d,c,b,a) + +FORCEINLINE fltx4 SplatXSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 0, 0, 0)); +} + +FORCEINLINE fltx4 SplatYSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(1, 1, 1, 1)); +} + +FORCEINLINE fltx4 SplatZSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 2, 2, 2)); +} + +FORCEINLINE fltx4 SplatWSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(3, 3, 3, 3)); +} + +FORCEINLINE fltx4 ShuffleXXYY(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 0, 1, 1)); +} + +FORCEINLINE fltx4 ShuffleXYXY(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 1, 0, 1)); +} + +FORCEINLINE fltx4 ShuffleZZWW(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 2, 3, 3)); +} + + + + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[0]), x, a); + return result; +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[1]), y, a); + return result; +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[2]), z, a); + return result; +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[3]), w, a); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ + fltx4 val = ReplicateX4(flValue); + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[nComponent]), val, a); + return result; +} + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(1, 2, 3, 0)); +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 3, 0, 1)); +} + +FORCEINLINE fltx4 RotateRight(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(3, 0, 1, 2)); +} + +FORCEINLINE fltx4 RotateRight2(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 3, 0, 1)); +} + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_add_ps(a, b); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_sub_ps(a, b); +}; + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_mul_ps(a, b); +}; + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_div_ps(a, b); +}; + +fltx4 ReciprocalEstSIMD(const fltx4& a); +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalEstSIMD(b), a); +}; + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return AddSIMD(MulSIMD(a, b), c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return SubSIMD(c, MulSIMD(a, b)); +}; + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 m = MulSIMD(a, b); + return AddSIMD(AddSIMD(SplatXSIMD(m), SplatYSIMD(m)), SplatZSIMD(m)); +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 fl4Product = MulSIMD(a, b); + fltx4 fl4YXWZ = _mm_shuffle_ps(fl4Product, fl4Product, MM_SHUFFLE_REV(1, 0, 3, 2)); + fltx4 fl4UUVV = AddSIMD(fl4Product, fl4YXWZ); + fltx4 fl4VVUU = RotateLeft2(fl4UUVV); + return AddSIMD(fl4UUVV, fl4VVUU); +} + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + fltx4 result; + SubFloat(result, 0) = sin(SubFloat(radians, 0)); + SubFloat(result, 1) = sin(SubFloat(radians, 1)); + SubFloat(result, 2) = sin(SubFloat(radians, 2)); + SubFloat(result, 3) = sin(SubFloat(radians, 3)); + return result; +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); + SinCos(SubFloat(radians, 3), &SubFloat(sine, 3), &SubFloat(cosine, 3)); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + fltx4 result; + SubFloat(result, 0) = asin(SubFloat(sine, 0)); + SubFloat(result, 1) = asin(SubFloat(sine, 1)); + SubFloat(result, 2) = asin(SubFloat(sine, 2)); + SubFloat(result, 3) = asin(SubFloat(sine, 3)); + return result; +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + fltx4 result; + SubFloat(result, 0) = acos(SubFloat(cs, 0)); + SubFloat(result, 1) = acos(SubFloat(cs, 1)); + SubFloat(result, 2) = acos(SubFloat(cs, 2)); + SubFloat(result, 3) = acos(SubFloat(cs, 3)); + return result; +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + SubFloat(result, 0) = atan2(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(result, 1) = atan2(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(result, 2) = atan2(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(result, 3) = atan2(SubFloat(a, 3), SubFloat(b, 3)); + return result; +} + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + return SubSIMD(LoadZeroSIMD(), a); +} + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + return _mm_movemask_ps(a); +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE fltx4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmpeq_ps(a, b); +} + +FORCEINLINE fltx4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmpgt_ps(a, b); +} + +FORCEINLINE fltx4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmpge_ps(a, b); +} + +FORCEINLINE fltx4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmplt_ps(a, b); +} + +FORCEINLINE fltx4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmple_ps(a, b); +} + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + return TestSignSIMD(CmpLeSIMD(a, b)) == 0; +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + return TestSignSIMD(CmpLtSIMD(a, b)) == 0; +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + return TestSignSIMD(CmpEqSIMD(a, b)) == 0xf; +} + +FORCEINLINE fltx4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + return AndSIMD(CmpLeSIMD(a, b), CmpGeSIMD(a, NegSIMD(b))); +} + +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_min_ps(a, b); +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_max_ps(a, b); +} + + + +FORCEINLINE fltx4 CeilSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = ceil(SubFloat(a, 0)); + SubFloat(retVal, 1) = ceil(SubFloat(a, 1)); + SubFloat(retVal, 2) = ceil(SubFloat(a, 2)); + SubFloat(retVal, 3) = ceil(SubFloat(a, 3)); + return retVal; + +} + +fltx4 AbsSIMD(const fltx4& x); +fltx4 fabs(const fltx4& x); + +FORCEINLINE fltx4 FloorSIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 ival = SubSIMD(AddSIMD(fl4Abs, Four_2ToThe23s), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, fl4Abs), SubSIMD(ival, Four_Ones), ival); + return XorSIMD(ival, XorSIMD(val, fl4Abs)); +} + + + +FORCEINLINE bool IsAnyZeros(const fltx4& a) +{ + return TestSignSIMD(CmpEqSIMD(a, Four_Zeros)) != 0; +} + +inline bool IsAllZeros(const fltx4& var) +{ + return TestSignSIMD(CmpEqSIMD(var, Four_Zeros)) == 0xF; +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ + return _mm_sqrt_ps(a); +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + return _mm_sqrt_ps(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + return _mm_rsqrt_ps(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalSqrtEstSIMD(ret); + return ret; +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + fltx4 guess = ReciprocalSqrtEstSIMD(a); + guess = MulSIMD(guess, SubSIMD(Four_Threes, MulSIMD(a, MulSIMD(guess, guess)))); + guess = MulSIMD(Four_PointFives, guess); + return guess; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + return _mm_rcp_ps(a); +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalEstSIMD(ret); + return ret; +} + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + fltx4 ret = ReciprocalEstSIMD(a); + ret = SubSIMD(AddSIMD(ret, ret), MulSIMD(a, MulSIMD(ret, ret))); + return ret; +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalSIMD(ret); + return ret; +} + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + fltx4 retval; + SubFloat(retval, 0) = powf(2, SubFloat(toPower, 0)); + SubFloat(retval, 1) = powf(2, SubFloat(toPower, 1)); + SubFloat(retval, 2) = powf(2, SubFloat(toPower, 2)); + SubFloat(retval, 3) = powf(2, SubFloat(toPower, 3)); + + return retval; +} + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + return MaxSIMD(min, MinSIMD(max, in)); +} + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ + _MM_TRANSPOSE4_PS(x, y, z, w); +} + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + fltx4 compareOne = RotateLeft(a); + fltx4 retval = MinSIMD(a, compareOne); + compareOne = RotateLeft2(a); + retval = MinSIMD(retval, compareOne); + return SplatXSIMD(retval); + +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + fltx4 compareOne = RotateLeft(a); + fltx4 retval = MaxSIMD(a, compareOne); + compareOne = RotateLeft2(a); + retval = MaxSIMD(retval, compareOne); + return SplatXSIMD(retval); + +} + + +inline bool IsVector3LessThan(const fltx4& v1, const fltx4& v2) +{ + bi32x4 isOut = CmpLtSIMD(v1, v2); + return IsAnyNegative(isOut); +} + +inline bool IsVector4LessThan(const fltx4& v1, const fltx4& v2) +{ + bi32x4 isOut = CmpLtSIMD(v1, v2); + return IsAnyNegative(isOut); +} + + + +#if 0 +FORCEINLINE fltx4 IntSetImmediateSIMD(int to) +{ + fltx4 retval; + SubInt(retval, 0) = to; + SubInt(retval, 1) = to; + SubInt(retval, 2) = to; + SubInt(retval, 3) = to; + return retval; +} +#endif + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void* RESTRICT pSIMD) +{ + return _mm_load_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void* RESTRICT pSIMD) +{ + return _mm_loadu_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* RESTRICT pSIMD, const fltx4& a) +{ + _mm_store_ps(reinterpret_cast(pSIMD), a); +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const fltx4& a) +{ + _mm_store_ps(reinterpret_cast(pSIMD.Base()), a); +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* RESTRICT pSIMD, const fltx4& a) +{ + _mm_storeu_ps(reinterpret_cast(pSIMD), a); +} + +FORCEINLINE fltx4 CompressSIMD(fltx4 const& a, fltx4 const& b) +{ + return _mm_shuffle_ps(a, b, MM_SHUFFLE_REV(0, 2, 0, 2)); +} + +FORCEINLINE fltx4 LoadAndConvertUint16SIMD(const uint16* pInts) +{ +#ifdef POSIX + fltx4 retval; + SubFloat(retval, 0) = pInts[0]; + SubFloat(retval, 1) = pInts[1]; + SubFloat(retval, 2) = pInts[2]; + SubFloat(retval, 3) = pInts[3]; + return retval; +#else + __m128i inA = _mm_loadl_epi64((__m128i const*) pInts); + inA = _mm_unpacklo_epi16(inA, _mm_setzero_si128()); + return _mm_cvtepi32_ps(inA); +#endif +} + + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d) +{ + fltx4 aacc = _mm_shuffle_ps(a, c, MM_SHUFFLE_REV(0, 0, 0, 0)); + fltx4 bbdd = _mm_shuffle_ps(b, d, MM_SHUFFLE_REV(0, 0, 0, 0)); + return MaskedAssign(LoadAlignedSIMD(g_SIMD_EveryOtherMask), bbdd, aacc); +} + +FORCEINLINE void ExpandSIMD(fltx4 const& a, fltx4& fl4OutA, fltx4& fl4OutB) +{ + fl4OutA = _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 0, 1, 1)); + fl4OutB = _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 2, 3, 3)); + +} + + +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ + fltx4 vx = _mm_load_ss(&x); + fltx4 vy = _mm_load_ss(&y); + fltx4 vz = _mm_load_ss(&z); + fltx4 vw = _mm_load_ss(&w); + return Compress4SIMD(vx, vy, vz, vw); +} + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const u32x4& vSrcA) +{ + fltx4 retval; + SubFloat(retval, 0) = ((float)SubInt(retval, 0)); + SubFloat(retval, 1) = ((float)SubInt(retval, 1)); + SubFloat(retval, 2) = ((float)SubInt(retval, 2)); + SubFloat(retval, 3) = ((float)SubInt(retval, 3)); + return retval; +} + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return _mm_cvtepi32_ps((const __m128i&)vSrcA); +} + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const shortx8& vSrcA) +{ + return _mm_cvtepi32_ps(vSrcA); +} + +#if 0 +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + fltx4 retval; + SubFloat(retval, 0) = ((float)(reinterpret_cast(&vSrcA)[0])); + SubFloat(retval, 1) = ((float)(reinterpret_cast(&vSrcA)[1])); + SubFloat(retval, 2) = ((float)(reinterpret_cast(&vSrcA)[2])); + SubFloat(retval, 3) = ((float)(reinterpret_cast(&vSrcA)[3])); + return retval; +} + +#endif + +FORCEINLINE i32x4 IntShiftLeftWordSIMD(const i32x4& vSrcA, const i32x4& vSrcB) +{ + i32x4 retval; + SubInt(retval, 0) = SubInt(vSrcA, 0) << SubInt(vSrcB, 0); + SubInt(retval, 1) = SubInt(vSrcA, 1) << SubInt(vSrcB, 1); + SubInt(retval, 2) = SubInt(vSrcA, 2) << SubInt(vSrcB, 2); + SubInt(retval, 3) = SubInt(vSrcA, 3) << SubInt(vSrcB, 3); + + + return retval; +} + + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1900 && defined(COMPILER_MSVC64) + (*pDest)[0] = (int)SubFloat(vSrc, 0); + (*pDest)[1] = (int)SubFloat(vSrc, 1); + (*pDest)[2] = (int)SubFloat(vSrc, 2); + (*pDest)[3] = (int)SubFloat(vSrc, 3); +#else + __m64 bottom = _mm_cvttps_pi32(vSrc); + __m64 top = _mm_cvttps_pi32(_mm_movehl_ps(vSrc, vSrc)); + + *reinterpret_cast<__m64*>(&(*pDest)[0]) = bottom; + *reinterpret_cast<__m64*>(&(*pDest)[2]) = top; + + _mm_empty(); +#endif +} + + + +#endif + +FORCEINLINE void RotateLeftDoubleSIMD(fltx4& a, fltx4& b) +{ + a = SetWSIMD(RotateLeft(a), SplatXSIMD(b)); + b = RotateLeft(b); +} + + +#if !defined(PLATFORM_PPC) && !defined( POSIX ) && !defined(SPU) +#if 1 +FORCEINLINE fltx4 operator+(FLTX4 a, FLTX4 b) +{ + return AddSIMD(a, b); +} + +FORCEINLINE fltx4 operator-(FLTX4 a, FLTX4 b) +{ + return SubSIMD(a, b); +} + +FORCEINLINE fltx4 operator*(FLTX4 a, FLTX4 b) +{ + return MulSIMD(a, b); +} + +FORCEINLINE fltx4 operator&(FLTX4 a, FLTX4 b) +{ + return AndSIMD(a, b); +} + +FORCEINLINE fltx4 operator|(FLTX4 a, FLTX4 b) +{ + return OrSIMD(a, b); +} + +FORCEINLINE fltx4 operator^(FLTX4 a, FLTX4 b) +{ + return XorSIMD(a, b); +} + +FORCEINLINE fltx4 operator-(FLTX4 a) +{ + return NegSIMD(a); +} +#endif +#endif + +#if defined(_X360) || defined(_PS3) +FORCEINLINE fltx4 VectorMergeHighSIMD(fltx4 fl4SrcA, fltx4 fl4SrcB) +{ +#if defined( _X360 ) + return __vmrghw(fl4SrcA, fl4SrcB); +#else + return vec_mergeh(fl4SrcA, fl4SrcB); +#endif +} + +FORCEINLINE fltx4 VectorMergeLowSIMD(fltx4 fl4SrcA, fltx4 fl4SrcB) +{ +#if defined( _X360 ) + return __vmrglw(fl4SrcA, fl4SrcB); +#else + return vec_mergel(fl4SrcA, fl4SrcB); +#endif +} +#endif + +#ifndef SPU +struct ALIGN16 fourplanes_t +{ + fltx4 nX; + fltx4 nY; + fltx4 nZ; + fltx4 dist; + bi32x4 xSign; + bi32x4 ySign; + bi32x4 zSign; + fltx4 nXAbs; + fltx4 nYAbs; + fltx4 nZAbs; + + void ComputeSignbits(); + + void Set4Planes(const VPlane* pPlanes); + void Set2Planes(const VPlane* pPlanes); + void Get4Planes(VPlane* pPlanesOut) const; + void Get2Planes(VPlane* pPlanesOut) const; + void GetPlane(int index, Vector* pNormal, float* pDist) const; + void SetPlane(int index, const Vector& vecNormal, float planeDist); +}; + +class ALIGN16 Frustum_t +{ +public: + Frustum_t(); + void SetPlane(int i, const Vector& vecNormal, float dist); + void GetPlane(int i, Vector* pNormalOut, float* pDistOut) const; + void SetPlanes(const VPlane* pPlanes); + void GetPlanes(VPlane* pPlanesOut) const; + bool CullBox(const Vector& mins, const Vector& maxs) const; + bool CullBoxCenterExtents(const Vector& center, const Vector& extents) const; + + bool CullBox(const fltx4& fl4Mins, const fltx4& fl4Maxs) const; + bool CullBoxCenterExtents(const fltx4& fl4Center, const fltx4& fl4Extents) const; + + + bool Contains(const Vector& mins, const Vector& maxs) const; + + bool Intersects(Frustum_t& otherFrustum) const; + + bool Intersects(const Vector& mins, const Vector& maxs) const; + bool IntersectsCenterExtents(const Vector& center, const Vector& extents) const; + + bool Intersects(const fltx4& fl4Mins, const fltx4& fl4Maxs) const; + bool IntersectsCenterExtents(const fltx4& fl4Center, const fltx4& fl4Extents) const; + + + void CreatePerspectiveFrustum(const Vector& origin, const Vector& forward, + const Vector& right, const Vector& up, float flZNear, float flZFar, + float flFovX, float flAspect); + + void CreatePerspectiveFrustumFLU(const Vector& vOrigin, const Vector& vForward, + const Vector& vLeft, const Vector& vUp, float flZNear, float flZFar, + float flFovX, float flAspect); + + void CreatePerspectiveFrustum(const Vector& origin, const QAngle& angles, float flZNear, + float flZFar, float flFovX, float flAspectRatio); + + void CreateOrthoFrustum(const Vector& origin, const Vector& forward, const Vector& right, const Vector& up, + float flLeft, float flRight, float flBottom, float flTop, float flZNear, float flZFar); + + void CreateOrthoFrustumFLU(const Vector& vOrigin, const Vector& vForward, const Vector& vLeft, const Vector& vUp, + float flLeft, float flRight, float flBottom, float flTop, float flZNear, float flZFar); + + bool GetCorners(Vector* pPoints) const; + + fourplanes_t planes[2]; +}; + +#endif + +class FourQuaternions; +class ALIGN16 FourVectors +{ +public: + fltx4 x, y, z; + + FourVectors(void) + { + } + + FourVectors(FourVectors const& src) + { + x = src.x; + y = src.y; + z = src.z; + } + + explicit FORCEINLINE FourVectors(float a) + { + fltx4 aReplicated = ReplicateX4(a); + x = y = z = aReplicated; + } + + FORCEINLINE void Init(void) + { + x = Four_Zeros; + y = Four_Zeros; + z = Four_Zeros; + } + + FORCEINLINE void Init(float flX, float flY, float flZ) + { + x = ReplicateX4(flX); + y = ReplicateX4(flY); + z = ReplicateX4(flZ); + } + + FORCEINLINE FourVectors(float flX, float flY, float flZ) + { + Init(flX, flY, flZ); + } + + FORCEINLINE void Init(fltx4 const& fl4X, fltx4 const& fl4Y, fltx4 const& fl4Z) + { + x = fl4X; + y = fl4Y; + z = fl4Z; + } + + FORCEINLINE FourVectors(fltx4 const& fl4X, fltx4 const& fl4Y, fltx4 const& fl4Z) + { + Init(fl4X, fl4Y, fl4Z); + } + + + + FORCEINLINE FourVectors(Vector const& a, Vector const& b, Vector const& c, Vector const& d) + { + LoadAndSwizzle(a, b, c, d); + } + + FORCEINLINE FourVectors(VectorAligned const& a, VectorAligned const& b, VectorAligned const& c, VectorAligned const& d) + { + LoadAndSwizzleAligned(a, b, c, d); + } + + FORCEINLINE FourVectors(const float* xs, const float* ys, const float* zs) : + x(LoadAlignedSIMD(xs)), y(LoadAlignedSIMD(ys)), z(LoadAlignedSIMD(zs)) + {}; + + FORCEINLINE void DuplicateVector(Vector const& v) + { + x = ReplicateX4(v.x); + y = ReplicateX4(v.y); + z = ReplicateX4(v.z); + } + + FORCEINLINE fltx4 const& operator[](int idx) const + { + return *((&x) + idx); + } + + FORCEINLINE fltx4& operator[](int idx) + { + return *((&x) + idx); + } + + FORCEINLINE void operator+=(FourVectors const& b) + { + x = AddSIMD(x, b.x); + y = AddSIMD(y, b.y); + z = AddSIMD(z, b.z); + } + + FORCEINLINE void operator-=(FourVectors const& b) + { + x = SubSIMD(x, b.x); + y = SubSIMD(y, b.y); + z = SubSIMD(z, b.z); + } + + FORCEINLINE void operator*=(FourVectors const& b) + { + x = MulSIMD(x, b.x); + y = MulSIMD(y, b.y); + z = MulSIMD(z, b.z); + } + + FORCEINLINE void operator*=(const fltx4& scale) + { + x = MulSIMD(x, scale); + y = MulSIMD(y, scale); + z = MulSIMD(z, scale); + } + + FORCEINLINE void operator*=(float scale) + { + fltx4 scalepacked = ReplicateX4(scale); + *this *= scalepacked; + } + + FORCEINLINE fltx4 operator*(FourVectors const& b) const + { + fltx4 dot = MulSIMD(x, b.x); + dot = MaddSIMD(y, b.y, dot); + dot = MaddSIMD(z, b.z, dot); + return dot; + } + + FORCEINLINE fltx4 operator*(Vector const& b) const + { + fltx4 dot = MulSIMD(x, ReplicateX4(b.x)); + dot = MaddSIMD(y, ReplicateX4(b.y), dot); + dot = MaddSIMD(z, ReplicateX4(b.z), dot); + return dot; + } + + FORCEINLINE FourVectors operator*(float b) const + { + fltx4 scalepacked = ReplicateX4(b); + FourVectors res; + res.x = MulSIMD(x, scalepacked); + res.y = MulSIMD(y, scalepacked); + res.z = MulSIMD(z, scalepacked); + return res; + } + + FORCEINLINE FourVectors operator*(FLTX4 fl4Scale) const + { + FourVectors res; + res.x = MulSIMD(x, fl4Scale); + res.y = MulSIMD(y, fl4Scale); + res.z = MulSIMD(z, fl4Scale); + return res; + } + + FORCEINLINE void VProduct(FourVectors const& b) + { + x = MulSIMD(x, b.x); + y = MulSIMD(y, b.y); + z = MulSIMD(z, b.z); + } + FORCEINLINE void MakeReciprocal(void) + { + x = ReciprocalSIMD(x); + y = ReciprocalSIMD(y); + z = ReciprocalSIMD(z); + } + + FORCEINLINE void MakeReciprocalSaturate(void) + { + x = ReciprocalSaturateSIMD(x); + y = ReciprocalSaturateSIMD(y); + z = ReciprocalSaturateSIMD(z); + } + + inline void RotateBy(const matrix3x4_t& matrix); + static void RotateManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix); + + static void RotateManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors* RESTRICT pOut); + + inline void TransformBy(const matrix3x4_t& matrix); + + static void TransformManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors* RESTRICT pOut); + + static void TransformManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix); + + static void CalcClosestPointOnLineSIMD(const FourVectors& P, const FourVectors& vLineA, const FourVectors& vLineB, FourVectors& vClosest, fltx4* outT = 0); + static fltx4 CalcClosestPointToLineTSIMD(const FourVectors& P, const FourVectors& vLineA, const FourVectors& vLineB, FourVectors& vDir); + + FORCEINLINE const float& X(int idx) const + { + return SubFloat((fltx4&)x, idx); + } + + FORCEINLINE const float& Y(int idx) const + { + return SubFloat((fltx4&)y, idx); + } + + FORCEINLINE const float& Z(int idx) const + { + return SubFloat((fltx4&)z, idx); + } + + FORCEINLINE float& X(int idx) + { + return SubFloat(x, idx); + } + + FORCEINLINE float& Y(int idx) + { + return SubFloat(y, idx); + } + + FORCEINLINE float& Z(int idx) + { + return SubFloat(z, idx); + } + + FORCEINLINE Vector Vec(int idx) const + { + return Vector(X(idx), Y(idx), Z(idx)); + } + + FORCEINLINE void operator=(FourVectors const& src) + { + x = src.x; + y = src.y; + z = src.z; + } + + FORCEINLINE void LoadAndSwizzle(Vector const& a, Vector const& b, Vector const& c, Vector const& d) + { +#if defined( _X360 ) || defined(_PS3) + fltx4 tx = LoadUnalignedSIMD(&a.x); + fltx4 ty = LoadUnalignedSIMD(&b.x); + fltx4 tz = LoadUnalignedSIMD(&c.x); + fltx4 tw = LoadUnalignedSIMD(&d.x); + fltx4 r0 = VectorMergeHighSIMD(tx, tz); + fltx4 r1 = VectorMergeHighSIMD(ty, tw); + fltx4 r2 = VectorMergeLowSIMD(tx, tz); + fltx4 r3 = VectorMergeLowSIMD(ty, tw); + + x = VectorMergeHighSIMD(r0, r1); + y = VectorMergeLowSIMD(r0, r1); + z = VectorMergeHighSIMD(r2, r3); +#else + x = LoadUnalignedSIMD(&(a.x)); + y = LoadUnalignedSIMD(&(b.x)); + z = LoadUnalignedSIMD(&(c.x)); + fltx4 w = LoadUnalignedSIMD(&(d.x)); + TransposeSIMD(x, y, z, w); +#endif + } + + FORCEINLINE void LoadAndSwizzle(Vector const& a) + { + LoadAndSwizzle(a, a, a, a); + } + + FORCEINLINE void Load(const float& a, const float& b, const float& c, const float& d) + { +#if defined( _X360 ) || defined( _PS3 ) + fltx4 temp[4]; + temp[0] = LoadUnalignedFloatSIMD(&a); + temp[1] = LoadUnalignedFloatSIMD(&b); + temp[2] = LoadUnalignedFloatSIMD(&c); + temp[3] = LoadUnalignedFloatSIMD(&d); + y = VectorMergeHighSIMD(temp[0], temp[2]); + z = VectorMergeHighSIMD(temp[1], temp[3]); + + x = VectorMergeHighSIMD(y, z); + y = x; + z = x; +#else + ALIGN16 float temp[4]; + temp[0] = a; temp[1] = b; temp[2] = c; temp[3] = d; + fltx4 v = LoadAlignedSIMD(temp); + x = v; + y = v; + z = v; +#endif + } + + FORCEINLINE void LoadAndSwizzle(FLTX4 a, FLTX4 b, FLTX4 c, FLTX4 d) + { +#if defined( _X360 ) || defined( _PS3 ) + fltx4 tx = a; + fltx4 ty = b; + fltx4 tz = c; + fltx4 tw = d; + fltx4 r0 = VectorMergeHighSIMD(tx, tz); + fltx4 r1 = VectorMergeHighSIMD(ty, tw); + fltx4 r2 = VectorMergeLowSIMD(tx, tz); + fltx4 r3 = VectorMergeLowSIMD(ty, tw); + + x = VectorMergeHighSIMD(r0, r1); + y = VectorMergeLowSIMD(r0, r1); + z = VectorMergeHighSIMD(r2, r3); +#else + x = a; + y = b; + z = c; + fltx4 w = d; + TransposeSIMD(x, y, z, w); +#endif + } + + FORCEINLINE void LoadAndSwizzleAligned(const float* RESTRICT a, const float* RESTRICT b, const float* RESTRICT c, const float* RESTRICT d) + { +#if defined( _X360 ) || defined( _PS3 ) + fltx4 tx = LoadAlignedSIMD(a); + fltx4 ty = LoadAlignedSIMD(b); + fltx4 tz = LoadAlignedSIMD(c); + fltx4 tw = LoadAlignedSIMD(d); + fltx4 r0 = VectorMergeHighSIMD(tx, tz); + fltx4 r1 = VectorMergeHighSIMD(ty, tw); + fltx4 r2 = VectorMergeLowSIMD(tx, tz); + fltx4 r3 = VectorMergeLowSIMD(ty, tw); + + x = VectorMergeHighSIMD(r0, r1); + y = VectorMergeLowSIMD(r0, r1); + z = VectorMergeHighSIMD(r2, r3); +#else + x = LoadAlignedSIMD(a); + y = LoadAlignedSIMD(b); + z = LoadAlignedSIMD(c); + fltx4 w = LoadAlignedSIMD(d); + TransposeSIMD(x, y, z, w); +#endif + } + + FORCEINLINE void LoadAndSwizzleAligned(Vector const& a, Vector const& b, Vector const& c, Vector const& d) + { + LoadAndSwizzleAligned(&a.x, &b.x, &c.x, &d.x); + } + + FORCEINLINE void TransposeOnto(fltx4& out0, fltx4& out1, fltx4& out2, fltx4& out3, FLTX4 w = Four_Zeros) const + { +#if defined( _X360 ) || defined(_PS3) + fltx4 r0 = VectorMergeHighSIMD(x, z); + fltx4 r1 = VectorMergeHighSIMD(y, w); + fltx4 r2 = VectorMergeLowSIMD(x, z); + fltx4 r3 = VectorMergeLowSIMD(y, w); + + out0 = VectorMergeHighSIMD(r0, r1); + out1 = VectorMergeLowSIMD(r0, r1); + out2 = VectorMergeHighSIMD(r2, r3); + out3 = VectorMergeLowSIMD(r2, r3); +#else + out0 = x; + out1 = y; + out2 = z; + out3 = w; + + TransposeSIMD(out0, out1, out2, out3); +#endif + } + +#if !defined(__SPU__) + FORCEINLINE void StoreUnalignedVector3SIMD(Vector* RESTRICT out0, Vector* RESTRICT out1, Vector* RESTRICT out2, Vector* RESTRICT out3) const; +#endif + + FORCEINLINE void StoreAlignedVectorSIMD(VectorAligned* RESTRICT out0, VectorAligned* RESTRICT out1, VectorAligned* RESTRICT out2, VectorAligned* RESTRICT out3) const; + +#if !defined(__SPU__) + FORCEINLINE void StoreUnalignedContigVector3SIMD(Vector* RESTRICT pDestination) + { + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreFourUnalignedVector3SIMD(a, b, c, d, pDestination); + } +#endif + +#if !defined(__SPU__) + FORCEINLINE void StoreAlignedContigVector3SIMD(Vector* RESTRICT pDestination) + { + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreFourAlignedVector3SIMD(a, b, c, d, pDestination); + } + + FORCEINLINE void StoreAlignedContigVectorASIMD(VectorAligned* RESTRICT pDestination) + { + StoreAlignedVectorSIMD(pDestination, pDestination + 1, pDestination + 2, pDestination + 3); + } +#endif + + FORCEINLINE fltx4 LengthSqr(void) const + { + const FourVectors& a = *this; + return a * a; + } + + FORCEINLINE fltx4 length2(void) const + { + return (*this) * (*this); + } + + FORCEINLINE fltx4 length(void) const + { + return SqrtEstSIMD(length2()); + } + + FORCEINLINE fltx4 Length(void) const + { + return SqrtSIMD(length2()); + } + + + FORCEINLINE void VectorNormalizeFast(void) + { + fltx4 mag_sq = (*this) * (*this); + (*this) *= ReciprocalSqrtEstSIMD(mag_sq); + } + + FORCEINLINE void VectorNormalize(void) + { + fltx4 mag_sq = (*this) * (*this); + (*this) *= ReciprocalSqrtSIMD(mag_sq); + } + + FORCEINLINE fltx4 DistToSqr(FourVectors const& pnt) + { + fltx4 fl4dX = SubSIMD(pnt.x, x); + fltx4 fl4dY = SubSIMD(pnt.y, y); + fltx4 fl4dZ = SubSIMD(pnt.z, z); + return AddSIMD(MulSIMD(fl4dX, fl4dX), AddSIMD(MulSIMD(fl4dY, fl4dY), MulSIMD(fl4dZ, fl4dZ))); + + } + + FORCEINLINE fltx4 TValueOfClosestPointOnLine(FourVectors const& p0, FourVectors const& p1) const + { + FourVectors lineDelta = p1; + lineDelta -= p0; + fltx4 OOlineDirDotlineDir = ReciprocalSIMD(p1 * p1); + FourVectors v4OurPnt = *this; + v4OurPnt -= p0; + return MulSIMD(OOlineDirDotlineDir, v4OurPnt * lineDelta); + } + + FORCEINLINE fltx4 DistSqrToLineSegment(FourVectors const& p0, FourVectors const& p1) const + { + FourVectors lineDelta = p1; + FourVectors v4OurPnt = *this; + v4OurPnt -= p0; + lineDelta -= p0; + + fltx4 OOlineDirDotlineDir = ReciprocalSIMD(lineDelta * lineDelta); + + fltx4 fl4T = MulSIMD(OOlineDirDotlineDir, v4OurPnt * lineDelta); + + fl4T = MinSIMD(fl4T, Four_Ones); + fl4T = MaxSIMD(fl4T, Four_Zeros); + lineDelta *= fl4T; + return v4OurPnt.DistToSqr(lineDelta); + } + FORCEINLINE FourVectors Normalized()const + { + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(LengthSqr()); + FourVectors out; + out.x = x * fl4LengthInv; + out.y = y * fl4LengthInv; + out.z = z * fl4LengthInv; + return out; + } + + FORCEINLINE FourVectors NormalizedSafeX() const + { + fltx4 f4LenSqr = LengthSqr(); + fltx4 isBigEnough = CmpGeSIMD(f4LenSqr, Four_Epsilons); + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(f4LenSqr); + FourVectors out; + out.x = MaskedAssign(isBigEnough, x * fl4LengthInv, Four_Ones); + out.y = AndSIMD(y * fl4LengthInv, isBigEnough); + out.z = AndSIMD(z * fl4LengthInv, isBigEnough); + return out; + } + FORCEINLINE FourVectors NormalizedSafeY() const + { + fltx4 f4LenSqr = LengthSqr(); + fltx4 isBigEnough = CmpGeSIMD(f4LenSqr, Four_Epsilons); + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(f4LenSqr); + FourVectors out; + out.x = AndSIMD(x * fl4LengthInv, isBigEnough); + out.y = MaskedAssign(isBigEnough, y * fl4LengthInv, Four_Ones); + out.z = AndSIMD(z * fl4LengthInv, isBigEnough); + return out; + } + + FORCEINLINE FourVectors NormalizedSafeZ() const + { + fltx4 f4LenSqr = LengthSqr(); + fltx4 isBigEnough = CmpGeSIMD(f4LenSqr, Four_Epsilons); + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(f4LenSqr); + FourVectors out; + out.x = AndSIMD(x * fl4LengthInv, isBigEnough); + out.y = AndSIMD(y * fl4LengthInv, isBigEnough); + out.z = MaskedAssign(isBigEnough, z * fl4LengthInv, Four_Ones); + return out; + } +}; + + +inline FourVectors CrossProduct(const FourVectors& a, const FourVectors& b) +{ + return FourVectors(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline fltx4 DotProduct(const FourVectors& a, const FourVectors& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +inline FourVectors operator * (fltx4 left, const FourVectors& right) +{ + return right * left; +} + + +inline FourVectors Mul(const FourVectors& a, const fltx4& b) +{ + FourVectors ret; + ret.x = MulSIMD(a.x, b); + ret.y = MulSIMD(a.y, b); + ret.z = MulSIMD(a.z, b); + return ret; +} + +inline FourVectors Mul(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = MulSIMD(a.x, b.x); + ret.y = MulSIMD(a.y, b.y); + ret.z = MulSIMD(a.z, b.z); + return ret; +} + +inline FourVectors Madd(const FourVectors& a, const fltx4& b, const FourVectors& c) +{ + FourVectors ret; + ret.x = MaddSIMD(a.x, b, c.x); + ret.y = MaddSIMD(a.y, b, c.y); + ret.z = MaddSIMD(a.z, b, c.z); + return ret; +} + +inline FourVectors operator ^(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = SubSIMD(MulSIMD(a.y, b.z), MulSIMD(a.z, b.y)); + ret.y = SubSIMD(MulSIMD(a.z, b.x), MulSIMD(a.x, b.z)); + ret.z = SubSIMD(MulSIMD(a.x, b.y), MulSIMD(a.y, b.x)); + return ret; +} + +inline FourVectors operator-(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = SubSIMD(a.x, b.x); + ret.y = SubSIMD(a.y, b.y); + ret.z = SubSIMD(a.z, b.z); + return ret; +} + +inline FourVectors operator+(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = AddSIMD(a.x, b.x); + ret.y = AddSIMD(a.y, b.y); + ret.z = AddSIMD(a.z, b.z); + return ret; +} + +inline FourVectors maximum(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = MaxSIMD(a.x, b.x); + ret.y = MaxSIMD(a.y, b.y); + ret.z = MaxSIMD(a.z, b.z); + return ret; +} + +inline FourVectors minimum(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = MinSIMD(a.x, b.x); + ret.y = MinSIMD(a.y, b.y); + ret.z = MinSIMD(a.z, b.z); + return ret; +} + +FORCEINLINE FourVectors RotateLeft(const FourVectors& src) +{ + FourVectors ret; + ret.x = RotateLeft(src.x); + ret.y = RotateLeft(src.y); + ret.z = RotateLeft(src.z); + return ret; +} + +FORCEINLINE FourVectors RotateRight(const FourVectors& src) +{ + FourVectors ret; + ret.x = RotateRight(src.x); + ret.y = RotateRight(src.y); + ret.z = RotateRight(src.z); + return ret; +} +FORCEINLINE FourVectors MaskedAssign(const bi32x4& ReplacementMask, const FourVectors& NewValue, const FourVectors& OldValue) +{ + FourVectors ret; + ret.x = MaskedAssign(ReplacementMask, NewValue.x, OldValue.x); + ret.y = MaskedAssign(ReplacementMask, NewValue.y, OldValue.y); + ret.z = MaskedAssign(ReplacementMask, NewValue.z, OldValue.z); + return ret; +} + +FORCEINLINE FourVectors VectorReflect(const FourVectors& incident, const FourVectors& normal) +{ + FourVectors ret = incident; + fltx4 iDotNx2 = incident * normal; + iDotNx2 = AddSIMD(iDotNx2, iDotNx2); + FourVectors nPart = normal; + nPart *= iDotNx2; + ret -= nPart; + return ret; +} + +FORCEINLINE FourVectors VectorSlide(const FourVectors& incident, const FourVectors& normal) +{ + FourVectors ret = incident; + fltx4 iDotN = incident * normal; + FourVectors nPart = normal; + nPart *= iDotN; + ret -= nPart; + return ret; +} + +FORCEINLINE FourVectors VectorNormalizeFast(const FourVectors& src) +{ + fltx4 mag_sq = ReciprocalSqrtEstSIMD(src * src); + FourVectors result; + result.x = MulSIMD(src.x, mag_sq); + result.y = MulSIMD(src.y, mag_sq); + result.z = MulSIMD(src.z, mag_sq); + return result; +} + +#if !defined(__SPU__) +FORCEINLINE void FourVectors::StoreUnalignedVector3SIMD(Vector* RESTRICT out0, Vector* RESTRICT out1, Vector* RESTRICT out2, Vector* RESTRICT out3) const +{ +#ifdef _X360 + fltx4 x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3; + x0 = SplatXSIMD(x); + x1 = SplatYSIMD(x); + x2 = SplatZSIMD(x); + x3 = SplatWSIMD(x); + + y0 = SplatXSIMD(y); + y1 = SplatYSIMD(y); + y2 = SplatZSIMD(y); + y3 = SplatWSIMD(y); + + z0 = SplatXSIMD(z); + z1 = SplatYSIMD(z); + z2 = SplatZSIMD(z); + z3 = SplatWSIMD(z); + + __stvewx(x0, out0->Base(), 0); + __stvewx(y0, out0->Base(), 4); + __stvewx(z0, out0->Base(), 8); + + __stvewx(x1, out1->Base(), 0); + __stvewx(y1, out1->Base(), 4); + __stvewx(z1, out1->Base(), 8); + + __stvewx(x2, out2->Base(), 0); + __stvewx(y2, out2->Base(), 4); + __stvewx(z2, out2->Base(), 8); + + __stvewx(x3, out3->Base(), 0); + __stvewx(y3, out3->Base(), 4); + __stvewx(z3, out3->Base(), 8); +#else + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreUnaligned3SIMD(out0->Base(), a); + StoreUnaligned3SIMD(out1->Base(), b); + StoreUnaligned3SIMD(out2->Base(), c); + StoreUnaligned3SIMD(out3->Base(), d); +#endif +} + +FORCEINLINE void FourVectors::StoreAlignedVectorSIMD(VectorAligned* RESTRICT out0, VectorAligned* RESTRICT out1, VectorAligned* RESTRICT out2, VectorAligned* RESTRICT out3) const +{ + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreAligned3SIMD(out0, a); + StoreAligned3SIMD(out1, b); + StoreAligned3SIMD(out2, c); + StoreAligned3SIMD(out3, d); + +} +#endif + +#if !defined(__SPU__) +void FourVectors::RotateBy(const matrix3x4_t& matrix) +{ + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + fltx4 matCol0 = LoadUnalignedSIMD(matrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(matrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(matrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + + fltx4 outX, outY, outZ; + outX = AddSIMD(AddSIMD(MulSIMD(x, matSplat00), MulSIMD(y, matSplat01)), MulSIMD(z, matSplat02)); + outY = AddSIMD(AddSIMD(MulSIMD(x, matSplat10), MulSIMD(y, matSplat11)), MulSIMD(z, matSplat12)); + outZ = AddSIMD(AddSIMD(MulSIMD(x, matSplat20), MulSIMD(y, matSplat21)), MulSIMD(z, matSplat22)); + + x = outX; + y = outY; + z = outZ; +} + + +void FourVectors::TransformBy(const matrix3x4_t& matrix) +{ + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + fltx4 matCol0 = LoadUnalignedSIMD(matrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(matrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(matrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + + fltx4 outX, outY, outZ; + + outX = MaddSIMD(z, matSplat02, AddSIMD(MulSIMD(x, matSplat00), MulSIMD(y, matSplat01))); + outY = MaddSIMD(z, matSplat12, AddSIMD(MulSIMD(x, matSplat10), MulSIMD(y, matSplat11))); + outZ = MaddSIMD(z, matSplat22, AddSIMD(MulSIMD(x, matSplat20), MulSIMD(y, matSplat21))); + + x = AddSIMD(outX, ReplicateX4(matrix[0][3])); + y = AddSIMD(outY, ReplicateX4(matrix[1][3])); + z = AddSIMD(outZ, ReplicateX4(matrix[2][3])); +} +#endif + +fltx4 NoiseSIMD(FourVectors const& v); + +FourVectors DNoiseSIMD(FourVectors const& v); + +FourVectors CurlNoiseSIMD(FourVectors const& v); + + +fltx4 NoiseSIMD(const fltx4& x, const fltx4& y, const fltx4& z); + + +inline fltx4 fabs(const fltx4& x) +{ + return AndSIMD(x, LoadAlignedSIMD(g_SIMD_clear_signmask)); +} + +inline fltx4 AbsSIMD(const fltx4& x) +{ + return fabs(x); +} + +inline fltx4 fnegate(const fltx4& x) +{ + return XorSIMD(x, LoadAlignedSIMD(g_SIMD_signmask)); +} + +fltx4 Pow_FixedPoint_Exponent_SIMD(const fltx4& x, int exponent); + +inline fltx4 PowSIMD(const fltx4& x, float exponent) +{ + return Pow_FixedPoint_Exponent_SIMD(x, (int)(4.0 * exponent)); +} + +inline fltx4 LinearToGammaSIMD(fltx4 x) +{ + x = MaxSIMD(MinSIMD(Four_Ones, x), Four_Zeros); + return AddSIMD(Four_LinearToGammaCoefficients_E, + MulSIMD(x, AddSIMD(Four_LinearToGammaCoefficients_D, + MulSIMD(x, AddSIMD(Four_LinearToGammaCoefficients_C, + MulSIMD(x, AddSIMD(Four_LinearToGammaCoefficients_B, + MulSIMD(x, Four_LinearToGammaCoefficients_A)))))))); +} + + +inline fltx4 GammaToLinearSIMD(fltx4 x) +{ + x = MaxSIMD(x, Four_Zeros); + x = AddSIMD(Four_GammaToLinearCoefficients_D, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_C, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_B, + MulSIMD(x, Four_GammaToLinearCoefficients_A)))))); + return MinSIMD(x, Four_Ones); +} + +inline fltx4 GammaToLinearExtendedSIMD(fltx4 x) +{ + x = MaxSIMD(x, Four_Zeros); + fltx4 fl4Ret = AddSIMD(Four_GammaToLinearCoefficients_D, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_C, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_B, + MulSIMD(x, Four_GammaToLinearCoefficients_A)))))); + return MaskedAssign(CmpGeSIMD(x, Four_Ones), x, fl4Ret); +} + +void SeedRandSIMD(uint32 seed); +fltx4 RandSIMD(int nContext = 0); + +int GetSIMDRandContext(void); +void ReleaseSIMDRandContext(int nContext); + +FORCEINLINE fltx4 RandSignedSIMD(void) +{ + return SubSIMD(MulSIMD(Four_Twos, RandSIMD()), Four_Ones); +} + + +FORCEINLINE fltx4 LerpSIMD(const fltx4& percent, const fltx4& a, const fltx4& b) +{ + return AddSIMD(a, MulSIMD(SubSIMD(b, a), percent)); +} + +FORCEINLINE fltx4 RemapValClampedSIMD(const fltx4& val, const fltx4& a, const fltx4& b, const fltx4& c, const fltx4& d) +{ + fltx4 range = MaskedAssign(CmpEqSIMD(a, b), Four_Ones, SubSIMD(b, a)); + fltx4 cVal = MaxSIMD(Four_Zeros, MinSIMD(Four_Ones, DivSIMD(SubSIMD(val, a), range))); + return LerpSIMD(cVal, c, d); +} + +inline fltx4 SimpleSpline(const fltx4& value) +{ + fltx4 valueDoubled = MulSIMD(value, Four_Twos); + fltx4 valueSquared = MulSIMD(value, value); + + return SubSIMD( + MulSIMD(Four_Threes, valueSquared), + MulSIMD(valueDoubled, valueSquared)); +} + +inline fltx4 SimpleSplineRemapValWithDeltas(const fltx4& val, + const fltx4& A, const fltx4& BMinusA, + const fltx4& OneOverBMinusA, const fltx4& C, + const fltx4& DMinusC) +{ + fltx4 cVal = MulSIMD(SubSIMD(val, A), OneOverBMinusA); + return AddSIMD(C, MulSIMD(DMinusC, SimpleSpline(cVal))); +} + +inline fltx4 SimpleSplineRemapValWithDeltasClamped(const fltx4& val, + const fltx4& A, const fltx4& BMinusA, + const fltx4& OneOverBMinusA, const fltx4& C, + const fltx4& DMinusC) +{ + fltx4 cVal = MulSIMD(SubSIMD(val, A), OneOverBMinusA); + cVal = MinSIMD(Four_Ones, MaxSIMD(Four_Zeros, cVal)); + return AddSIMD(C, MulSIMD(DMinusC, SimpleSpline(cVal))); +} + +FORCEINLINE fltx4 FracSIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 ival = SubSIMD(AddSIMD(fl4Abs, Four_2ToThe23s), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, fl4Abs), SubSIMD(ival, Four_Ones), ival); + return XorSIMD(SubSIMD(fl4Abs, ival), XorSIMD(val, fl4Abs)); +} + +#ifndef SPU +FORCEINLINE fltx4 Mod2SIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 ival = SubSIMD(AndSIMD(LoadAlignedSIMD((float*)g_SIMD_lsbmask), AddSIMD(fl4Abs, Four_2ToThe23s)), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, fl4Abs), SubSIMD(ival, Four_Twos), ival); + return XorSIMD(SubSIMD(fl4Abs, ival), XorSIMD(val, fl4Abs)); +} +#endif + +FORCEINLINE fltx4 Mod2SIMDPositiveInput(const fltx4& val) +{ + fltx4 ival = SubSIMD(AndSIMD(LoadAlignedSIMD(g_SIMD_lsbmask), AddSIMD(val, Four_2ToThe23s)), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, val), SubSIMD(ival, Four_Twos), ival); + return SubSIMD(val, ival); +} + + +FORCEINLINE fltx4 _SinEst01SIMD(const fltx4& val) +{ + return MulSIMD(val, SubSIMD(Four_Fours, MulSIMD(val, Four_Fours))); +} + +FORCEINLINE fltx4 _Sin01SIMD(const fltx4& val) +{ + fltx4 fl4BadEst = MulSIMD(val, SubSIMD(Four_Fours, MulSIMD(val, Four_Fours))); + return AddSIMD(MulSIMD(Four_Point225s, SubSIMD(MulSIMD(fl4BadEst, fl4BadEst), fl4BadEst)), fl4BadEst); +} + +FORCEINLINE fltx4 SinEst01SIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 fl4Reduced2 = Mod2SIMDPositiveInput(fl4Abs); + bi32x4 fl4OddMask = CmpGeSIMD(fl4Reduced2, Four_Ones); + fltx4 fl4val = SubSIMD(fl4Reduced2, AndSIMD(Four_Ones, fl4OddMask)); + fltx4 fl4Sin = _SinEst01SIMD(fl4val); + fl4Sin = XorSIMD(fl4Sin, AndSIMD(LoadAlignedSIMD(g_SIMD_signmask), XorSIMD(val, fl4OddMask))); + return fl4Sin; + +} + +FORCEINLINE fltx4 Sin01SIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 fl4Reduced2 = Mod2SIMDPositiveInput(fl4Abs); + bi32x4 fl4OddMask = CmpGeSIMD(fl4Reduced2, Four_Ones); + fltx4 fl4val = SubSIMD(fl4Reduced2, AndSIMD(Four_Ones, fl4OddMask)); + fltx4 fl4Sin = _Sin01SIMD(fl4val); + fl4Sin = XorSIMD(fl4Sin, AndSIMD(LoadAlignedSIMD(g_SIMD_signmask), XorSIMD(val, fl4OddMask))); + return fl4Sin; + +} + +FORCEINLINE fltx4 NatExpSIMD(const fltx4& val) +{ + fltx4 fl4Result; + SubFloat(fl4Result, 0) = exp(SubFloat(val, 0)); + SubFloat(fl4Result, 1) = exp(SubFloat(val, 1)); + SubFloat(fl4Result, 2) = exp(SubFloat(val, 2)); + SubFloat(fl4Result, 3) = exp(SubFloat(val, 3)); + return fl4Result; +} + +FORCEINLINE fltx4 PreCalcBiasParameter(const fltx4& bias_parameter) +{ + return SubSIMD(ReciprocalSIMD(bias_parameter), Four_Twos); +} + +FORCEINLINE fltx4 BiasSIMD(const fltx4& val, const fltx4& precalc_param) +{ + return DivSIMD(val, AddSIMD(MulSIMD(precalc_param, SubSIMD(Four_Ones, val)), Four_Ones)); +} + +#ifndef SPU +FORCEINLINE int BoxOnPlaneSideSIMD(const fltx4& emins, const fltx4& emaxs, const cplane_t* p, float tolerance = 0.f) +{ + fltx4 corners[2]; + fltx4 normal = LoadUnalignedSIMD(p->normal.Base()); + fltx4 dist = ReplicateX4(-p->dist); + normal = SetWSIMD(normal, dist); + fltx4 t4 = ReplicateX4(tolerance); + fltx4 negt4 = ReplicateX4(-tolerance); + bi32x4 cmp = CmpGeSIMD(normal, Four_Zeros); + corners[0] = MaskedAssign(cmp, emaxs, emins); + corners[1] = MaskedAssign(cmp, emins, emaxs); + fltx4 dot1 = Dot4SIMD(normal, corners[0]); + fltx4 dot2 = Dot4SIMD(normal, corners[1]); + cmp = CmpGeSIMD(dot1, t4); + bi32x4 cmp2 = CmpGtSIMD(negt4, dot2); + fltx4 result = MaskedAssign(cmp, Four_Ones, Four_Zeros); + fltx4 result2 = MaskedAssign(cmp2, Four_Twos, Four_Zeros); + result = AddSIMD(result, result2); + intx4 sides; + ConvertStoreAsIntsSIMD(&sides, result); + return sides[0]; +} + + +class KDop32_t +{ +public: + fltx4 m_Mins[4]; + fltx4 m_Maxes[4]; + + FORCEINLINE bool Intersects(KDop32_t const& other) const; + + FORCEINLINE void operator|=(KDop32_t const& other); + + FORCEINLINE bool IsEmpty(void) const; + + FORCEINLINE void Init(void) + { + for (int i = 0; i < ARRAYSIZE(m_Mins); i++) + { + m_Mins[i] = Four_FLT_MAX; + m_Maxes[i] = Four_Negative_FLT_MAX; + } + } + + void AddPointSet(Vector const* pPoints, int nPnts); + + void CreateFromPointSet(Vector const* pPoints, int nPnts); +}; + +FORCEINLINE void KDop32_t::operator|=(KDop32_t const& other) +{ + m_Mins[0] = MinSIMD(m_Mins[0], other.m_Mins[0]); + m_Mins[1] = MinSIMD(m_Mins[1], other.m_Mins[1]); + m_Mins[2] = MinSIMD(m_Mins[2], other.m_Mins[2]); + m_Mins[3] = MinSIMD(m_Mins[3], other.m_Mins[3]); + + m_Maxes[0] = MaxSIMD(m_Maxes[0], other.m_Maxes[0]); + m_Maxes[1] = MaxSIMD(m_Maxes[1], other.m_Maxes[1]); + m_Maxes[2] = MaxSIMD(m_Maxes[2], other.m_Maxes[2]); + m_Maxes[3] = MaxSIMD(m_Maxes[3], other.m_Maxes[3]); + + +} + +FORCEINLINE bool KDop32_t::Intersects(KDop32_t const& other) const +{ + bi32x4 c00 = CmpLeSIMD(m_Mins[0], other.m_Maxes[0]); + bi32x4 c01 = CmpLeSIMD(m_Mins[1], other.m_Maxes[1]); + bi32x4 c02 = CmpLeSIMD(m_Mins[2], other.m_Maxes[2]); + bi32x4 c03 = CmpLeSIMD(m_Mins[3], other.m_Maxes[3]); + + bi32x4 c10 = CmpGeSIMD(m_Maxes[0], other.m_Mins[0]); + bi32x4 c11 = CmpGeSIMD(m_Maxes[1], other.m_Mins[1]); + bi32x4 c12 = CmpGeSIMD(m_Maxes[2], other.m_Mins[2]); + bi32x4 c13 = CmpGeSIMD(m_Maxes[3], other.m_Mins[3]); + + bi32x4 a0 = AndSIMD(AndSIMD(c00, c01), AndSIMD(c02, c03)); + bi32x4 a1 = AndSIMD(AndSIMD(c10, c11), AndSIMD(c12, c13)); + + return !(IsAnyZeros(AndSIMD(a1, a0))); +} + + +FORCEINLINE bool KDop32_t::IsEmpty(void) const +{ + bi32x4 c00 = CmpLtSIMD(m_Maxes[0], m_Mins[0]); + bi32x4 c01 = CmpLtSIMD(m_Maxes[1], m_Mins[1]); + bi32x4 c02 = CmpLtSIMD(m_Maxes[2], m_Mins[2]); + bi32x4 c03 = CmpLtSIMD(m_Maxes[3], m_Mins[3]); + + return IsAnyTrue(OrSIMD(OrSIMD(c00, c01), OrSIMD(c02, c03))); +} + + +extern const fltx4 g_KDop32XDirs[4]; +extern const fltx4 g_KDop32YDirs[4]; +extern const fltx4 g_KDop32ZDirs[4]; +#endif + +#if 0 + +#define _VEC_SWIZZLE_QUAT48_UNPACK (__vector unsigned char) { 16, 17, 0, 1, 16, 17, 2, 3, 16, 17, 4, 5, 16, 17, 6, 7 } +#define _VEC_SWIZZLE_QUAT48_UNPACK_SHIFT (__vector unsigned int ) { 0, 0, 1, 0 } + +FORCEINLINE fltx4 UnpackQuaternion48SIMD(const Quaternion48* RESTRICT pVec) +{ + fltx4 q16s = LoadUnaligned3SIMD((const float*)pVec); + + bool wneg = pVec->wneg; + + q16s = vec_perm(q16s, Four_Threes, _VEC_SWIZZLE_QUAT48_UNPACK); + + u32x4 tmp = IntShiftLeftWordSIMD(*(u32x4*)&q16s, _VEC_SWIZZLE_QUAT48_UNPACK_SHIFT); + q16s = *(fltx4*)&tmp; + + const fltx4 vUpkMul = SplatXSIMD(g_SIMD_Quat48_Unpack_Magic_Constants); + const fltx4 vUpkAdd = SplatYSIMD(g_SIMD_Quat48_Unpack_Magic_Constants); + + fltx4 ret = vec_madd(q16s, vUpkMul, vUpkAdd); + + fltx4 dotxyz = Dot3SIMD(ret, ret); + dotxyz = ClampVectorSIMD(dotxyz, Four_Zeros, Four_Ones); + + fltx4 ww = SubSIMD(Four_Ones, dotxyz); + ww = SqrtSIMD(ww); + if (wneg) + { + ret = SetWSIMD(ret, NegSIMD(ww)); + } + else + { + ret = SetWSIMD(ret, ww); + } + return ret; +} + +#endif + +FORCEINLINE fltx4 SetWFromXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 value = SplatXSIMD(x); + return SetWSIMD(a, value); +} + +FORCEINLINE fltx4 SetWFromYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 value = SplatYSIMD(y); + return SetWSIMD(a, value); +} + +FORCEINLINE fltx4 SetWFromZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 value = SplatZSIMD(z); + return SetWSIMD(a, value); +} + +FORCEINLINE fltx4 CrossProductSIMD(const fltx4& A, const fltx4& B) +{ +#if defined( _X360 ) + return XMVector3Cross(A, B); +#elif defined( _WIN32 ) + fltx4 A1 = _mm_shuffle_ps(A, A, MM_SHUFFLE_REV(1, 2, 0, 3)); + fltx4 B1 = _mm_shuffle_ps(B, B, MM_SHUFFLE_REV(2, 0, 1, 3)); + fltx4 Result1 = MulSIMD(A1, B1); + fltx4 A2 = _mm_shuffle_ps(A, A, MM_SHUFFLE_REV(2, 0, 1, 3)); + fltx4 B2 = _mm_shuffle_ps(B, B, MM_SHUFFLE_REV(1, 2, 0, 3)); + fltx4 Result2 = MulSIMD(A2, B2); + return SubSIMD(Result1, Result2); + +#elif defined(_PS3) + return _vmathVfCross(A, B); +#else + fltx4 CrossVal; + SubFloat(CrossVal, 0) = SubFloat(A, 1) * SubFloat(B, 2) - SubFloat(A, 2) * SubFloat(B, 1); + SubFloat(CrossVal, 1) = SubFloat(A, 2) * SubFloat(B, 0) - SubFloat(A, 0) * SubFloat(B, 2); + SubFloat(CrossVal, 2) = SubFloat(A, 0) * SubFloat(B, 1) - SubFloat(A, 1) * SubFloat(B, 0); + SubFloat(CrossVal, 3) = 0; + return CrossVal; +#endif +} + +inline const fltx4 Length3SIMD(const fltx4 vec) +{ + fltx4 scLengthSqr = Dot3SIMD(vec, vec); + bi32x4 isSignificant = CmpGtSIMD(scLengthSqr, Four_Epsilons); + fltx4 scLengthInv = ReciprocalSqrtSIMD(scLengthSqr); + return AndSIMD(isSignificant, MulSIMD(scLengthInv, scLengthSqr)); +} + +inline const fltx4 Normalized3SIMD(const fltx4 vec) +{ + fltx4 scLengthSqr = Dot3SIMD(vec, vec); + bi32x4 isSignificant = CmpGtSIMD(scLengthSqr, Four_Epsilons); + fltx4 scLengthInv = ReciprocalSqrtSIMD(scLengthSqr); + return AndSIMD(isSignificant, MulSIMD(vec, scLengthInv)); +} + + +#ifndef COMPILER_GCC + +FORCEINLINE fltx4 operator+=(fltx4& a, FLTX4 b) +{ + a = AddSIMD(a, b); + return a; +} + +FORCEINLINE fltx4 operator-=(fltx4& a, FLTX4 b) +{ + a = SubSIMD(a, b); + return a; +} + + +FORCEINLINE fltx4 operator*=(fltx4& a, FLTX4 b) +{ + a = MulSIMD(a, b); + return a; +} + +#endif +#endif +``` + +`SpyCustom/sdk/sendproxy.h`: + +```h +#ifndef SENDPROXY_H +#define SENDPROXY_H + + +#include "dt_send.h" + + +class DVariant; + +void SendProxy_Color32ToInt(const SendProp* pProp, const void* pStruct, const void* pData, DVariant* pOut, int iElement, int objectID); +void SendProxy_EHandleToInt(const SendProp* pProp, const void* pStruct, const void* pVarData, DVariant* pOut, int iElement, int objectID); +void SendProxy_IntAddOne(const SendProp* pProp, const void* pStruct, const void* pVarData, DVariant* pOut, int iElement, int objectID); +void SendProxy_ShortAddOne(const SendProp* pProp, const void* pStruct, const void* pVarData, DVariant* pOut, int iElement, int objectID); + +SendProp SendPropBool( + const char* pVarName, + int offset, + int sizeofVar); + +SendProp SendPropEHandle( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int flags = 0, + SendVarProxyFn proxyFn = SendProxy_EHandleToInt); + +SendProp SendPropTime( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE); + +#if !defined( NO_ENTITY_PREDICTION ) +SendProp SendPropPredictableId( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE); +#endif + +SendProp SendPropIntWithMinusOneFlag( + const char* pVarName, + int offset, + int sizeofVar = SIZEOF_IGNORE, + int bits = -1, + SendVarProxyFn proxyFn = SendProxy_IntAddOne); + + +SendProp SendPropStringT(const char* pVarName, int offset, int sizeofVar); + +void* SendProxy_OnlyToTeam(const SendProp* pProp, const void* pStruct, const void* pVarData, CSendProxyRecipients* pRecipients, int objectID); + + +#endif +``` + +`SpyCustom/sdk/sequence_Transitioner.h`: + +```h +#ifndef SEQUENCE_TRANSITIONER_H +#define SEQUENCE_TRANSITIONER_H +#ifdef _WIN32 +#pragma once +#endif + + +class CSequenceTransitioner +{ +public: + void CheckForSequenceChange( + CStudioHdr* hdr, + int nCurSequence, + + bool bForceNewSequence, + + bool bInterpolate + ); + + void UpdateCurrent( + CStudioHdr* hdr, + int nCurSequence, + float flCurCycle, + float flCurPlaybackRate, + float flCurTime + ); + + void RemoveAll(void) { m_animationQueue.RemoveAll(); }; + +public: + CUtlVector< CAnimationLayer > m_animationQueue; +}; + +#endif +``` + +`SpyCustom/sdk/shake.h`: + +```h +#ifndef SHAKE_H +#define SHAKE_H +#ifdef _WIN32 +#pragma once +#endif + + +struct ScreenShake_t +{ + int command; + float amplitude; + float frequency; + float duration; +}; + +enum ShakeCommand_t +{ + SHAKE_START = 0, + SHAKE_STOP, + SHAKE_AMPLITUDE, + SHAKE_FREQUENCY, + SHAKE_START_RUMBLEONLY, + SHAKE_START_NORUMBLE, +}; + + +extern int gmsgShake; + +extern int gmsgFade; + +#define FFADE_IN 0x0001 +#define FFADE_OUT 0x0002 +#define FFADE_MODULATE 0x0004 +#define FFADE_STAYOUT 0x0008 +#define FFADE_PURGE 0x0010 + +#define SCREENFADE_FRACBITS 9 +struct ScreenFade_t +{ + unsigned short duration; + unsigned short holdTime; + short fadeFlags; + byte r, g, b, a; +}; + + +#endif +``` + +`SpyCustom/sdk/shared_classnames.h`: + +```h +#ifndef SHARED_CLASSNAMES_H +#define SHARED_CLASSNAMES_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) + +#define CBaseEntity C_BaseEntity +#define CBaseCombatCharacter C_BaseCombatCharacter +#define CBaseAnimating C_BaseAnimating +#define CBasePlayer C_BasePlayer + +#endif + + +#endif +``` + +`SpyCustom/sdk/shareddefs.h`: + +```h +#ifndef SHADERAPI_SHAREDDEFS_H +#define SHADERAPI_SHAREDDEFS_H + +#ifdef _WIN32 +#pragma once +#endif + + +enum ShaderShadeMode_t +{ + SHADER_FLAT = 0, + SHADER_SMOOTH +}; + +enum ShaderTexCoordComponent_t +{ + SHADER_TEXCOORD_S = 0, + SHADER_TEXCOORD_T, + SHADER_TEXCOORD_U +}; + +enum ShaderTexFilterMode_t +{ + SHADER_TEXFILTERMODE_NEAREST, + SHADER_TEXFILTERMODE_LINEAR, + SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST, + SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST, + SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR, + SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR, + SHADER_TEXFILTERMODE_ANISOTROPIC +}; + +enum ShaderTexWrapMode_t +{ + SHADER_TEXWRAPMODE_CLAMP, + SHADER_TEXWRAPMODE_REPEAT, + SHADER_TEXWRAPMODE_BORDER +}; + + +enum TextureStage_t +{ + SHADER_TEXTURE_STAGE0 = 0, + SHADER_TEXTURE_STAGE1, +}; + +enum Sampler_t +{ + SHADER_SAMPLER0 = 0, + SHADER_SAMPLER1, + SHADER_SAMPLER2, + SHADER_SAMPLER3, + SHADER_SAMPLER4, + SHADER_SAMPLER5, + SHADER_SAMPLER6, + SHADER_SAMPLER7, + SHADER_SAMPLER8, + SHADER_SAMPLER9, + SHADER_SAMPLER10, + SHADER_SAMPLER11, + SHADER_SAMPLER12, + SHADER_SAMPLER13, + SHADER_SAMPLER14, + SHADER_SAMPLER15, +}; + +enum VertexTextureSampler_t +{ + SHADER_VERTEXTEXTURE_SAMPLER0 = 0, + SHADER_VERTEXTEXTURE_SAMPLER1, + SHADER_VERTEXTEXTURE_SAMPLER2, + SHADER_VERTEXTEXTURE_SAMPLER3, +}; + + +#if defined( _X360 ) +#define REVERSE_DEPTH_ON_X360 +#endif + +#if defined( REVERSE_DEPTH_ON_X360 ) +#define ReverseDepthOnX360() true +#else +#define ReverseDepthOnX360() false +#endif + + + + + + +#include "bittools.h" + +#define TICK_INTERVAL (iff.g_pGlobals->interval_per_tick) + + +#define TIME_TO_TICKS( dt ) ( (int)( 0.5f + (float)(dt) / TICK_INTERVAL ) ) +#define TICKS_TO_TIME( t ) ( TICK_INTERVAL *( t ) ) +#define ROUND_TO_TICKS( t ) ( TICK_INTERVAL * TIME_TO_TICKS( t ) ) +#define TICK_NEVER_THINK (-1) + + +#define ANIMATION_CYCLE_BITS 15 + +#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 WATERJUMP_HEIGHT 8 + +#define MAX_CLIMB_SPEED 200 + + +#define TIME_TO_DUCK_MSECS 400 + +#define TIME_TO_UNDUCK_MSECS 200 + +inline float FractionDucked(int msecs) +{ + return clamp((float)msecs / (float)TIME_TO_DUCK_MSECS, 0.0f, 1.0f); +} + +inline float FractionUnDucked(int msecs) +{ + return clamp((float)msecs / (float)TIME_TO_UNDUCK_MSECS, 0.0f, 1.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 CLOSE_CAPTION_WARNIFMISSING ( 1<<0 ) +#define CLOSE_CAPTION_FROMPLAYER ( 1<<1 ) +#define CLOSE_CAPTION_GENDER_MALE ( 1<<2 ) +#define CLOSE_CAPTION_GENDER_FEMALE ( 1<<3 ) + +#define HIDEHUD_WEAPONSELECTION ( 1<<0 ) +#define HIDEHUD_FLASHLIGHT ( 1<<1 ) +#define HIDEHUD_ALL ( 1<<2 ) +#define HIDEHUD_HEALTH ( 1<<3 ) +#define HIDEHUD_PLAYERDEAD ( 1<<4 ) +#define HIDEHUD_NEEDSUIT ( 1<<5 ) +#define HIDEHUD_MISCSTATUS ( 1<<6 ) +#define HIDEHUD_CHAT ( 1<<7 ) +#define HIDEHUD_CROSSHAIR ( 1<<8 ) +#define HIDEHUD_VEHICLE_CROSSHAIR ( 1<<9 ) +#define HIDEHUD_INVEHICLE ( 1<<10 ) +#define HIDEHUD_BONUS_PROGRESS ( 1<<11 ) +#define HIDEHUD_RADAR ( 1<<12 ) + +#define HIDEHUD_BITCOUNT 13 + +#define bits_SUIT_DEVICE_SPRINT 0x00000001 +#define bits_SUIT_DEVICE_FLASHLIGHT 0x00000002 +#define bits_SUIT_DEVICE_BREATHER 0x00000004 + +#define MAX_SUIT_DEVICES 3 + + +#define MAX_PLAYERS 33 + + +#define MAX_PLACE_NAME_LENGTH 18 + +#define TEAM_ANY -1 +#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 WEAPON_NOT_CARRIED 0 +#define WEAPON_IS_CARRIED_BY_PLAYER 1 +#define WEAPON_IS_ACTIVE 2 + +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 + + +#define ITEM_FLAG_SELECTONEMPTY (1<<0) +#define ITEM_FLAG_NOAUTORELOAD (1<<1) +#define ITEM_FLAG_NOAUTOSWITCHEMPTY (1<<2) +#define ITEM_FLAG_LIMITINWORLD (1<<3) +#define ITEM_FLAG_EXHAUSTIBLE (1<<4) +#define ITEM_FLAG_DOHITLOCATIONDMG (1<<5) +#define ITEM_FLAG_NOAMMOPICKUPS (1<<6) +#define ITEM_FLAG_NOITEMPICKUP (1<<7) + +#define MAX_VIEWMODELS 2 + +#define MAX_BEAM_ENTS 10 + +#define TRACER_TYPE_DEFAULT 0x00000001 +#define TRACER_TYPE_GUNSHIP 0x00000002 +#define TRACER_TYPE_STRIDER 0x00000004 +#define TRACER_TYPE_GAUSS 0x00000008 +#define TRACER_TYPE_WATERBULLET 0x00000010 + +#define MUZZLEFLASH_TYPE_DEFAULT 0x00000001 +#define MUZZLEFLASH_TYPE_GUNSHIP 0x00000002 +#define MUZZLEFLASH_TYPE_STRIDER 0x00000004 + +enum +{ + MUZZLEFLASH_AR2 = 0, + MUZZLEFLASH_SHOTGUN, + MUZZLEFLASH_SMG1, + MUZZLEFLASH_SMG2, + MUZZLEFLASH_PISTOL, + MUZZLEFLASH_COMBINE, + MUZZLEFLASH_357, + MUZZLEFLASH_RPG, + MUZZLEFLASH_COMBINE_TURRET, + + MUZZLEFLASH_FIRSTPERSON = 0x100, +}; + +#define TRACER_FLAG_WHIZ 0x0001 +#define TRACER_FLAG_USEATTACHMENT 0x0002 + +#define TRACER_DONT_USE_ATTACHMENT -1 + +enum +{ + ENTITY_DISSOLVE_NORMAL = 0, + ENTITY_DISSOLVE_ELECTRICAL, + ENTITY_DISSOLVE_ELECTRICAL_LIGHT, + ENTITY_DISSOLVE_CORE, + + ENTITY_DISSOLVE_BITS = 3 +}; + +#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 + +enum PLAYER_ANIM +{ + PLAYER_IDLE, + PLAYER_WALK, + PLAYER_JUMP, + PLAYER_SUPERJUMP, + PLAYER_DIE, + PLAYER_ATTACK1, + PLAYER_IN_VEHICLE, + + PLAYER_RELOAD, + PLAYER_START_AIMING, + PLAYER_LEAVE_AIMING, +}; + +#ifdef HL2_DLL +#define PLAYER_FATAL_FALL_SPEED 922.5f +#define PLAYER_MAX_SAFE_FALL_SPEED 526.5f +#define PLAYER_LAND_ON_FLOATING_OBJECT 173 +#define PLAYER_MIN_BOUNCE_SPEED 173 +#define PLAYER_FALL_PUNCH_THRESHOLD 303.0f +#else +#define PLAYER_FATAL_FALL_SPEED 1024 +#define PLAYER_MAX_SAFE_FALL_SPEED 580 +#define PLAYER_LAND_ON_FLOATING_OBJECT 200 +#define PLAYER_MIN_BOUNCE_SPEED 200 +#define PLAYER_FALL_PUNCH_THRESHOLD (float)350 +#endif +#define DAMAGE_FOR_FALL_SPEED 100.0f / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED ) + + +#define AUTOAIM_2DEGREES 0.0348994967025 +#define AUTOAIM_5DEGREES 0.08715574274766 +#define AUTOAIM_8DEGREES 0.1391731009601 +#define AUTOAIM_10DEGREES 0.1736481776669 +#define AUTOAIM_20DEGREES 0.3490658503989 + +#define AUTOAIM_SCALE_DEFAULT 1.0f +#define AUTOAIM_SCALE_DIRECT_ONLY 0.0f + +#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 + +enum +{ + OBS_MODE_NONE = 0, + OBS_MODE_DEATHCAM, + OBS_MODE_FREEZECAM, + OBS_MODE_FIXED, + OBS_MODE_IN_EYE, + OBS_MODE_CHASE, + OBS_MODE_ROAMING, + + NUM_OBSERVER_MODES, +}; + +#define LAST_PLAYER_OBSERVERMODE OBS_MODE_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 +{ + VGUI_SCREEN_ACTIVE = 0x1, + VGUI_SCREEN_VISIBLE_TO_TEAMMATES = 0x2, + VGUI_SCREEN_ATTACHED_TO_VIEWMODEL = 0x4, + VGUI_SCREEN_TRANSPARENT = 0x8, + VGUI_SCREEN_ONLY_USABLE_BY_OWNER = 0x10, + + VGUI_SCREEN_MAX_BITS = 5 +}; + +typedef enum +{ + USE_OFF = 0, + USE_ON = 1, + USE_SET = 2, + USE_TOGGLE = 3 +} USE_TYPE; + +#define COLOR_RED Color(255, 64, 64, 255) +#define COLOR_BLUE Color(153, 204, 255, 255) +#define COLOR_YELLOW Color(255, 178, 0, 255) +#define COLOR_GREEN Color(153, 255, 153, 255) +#define COLOR_GREY Color(204, 204, 204, 255) + +enum +{ + DONT_BLEED = -1, + + BLOOD_COLOR_RED = 0, + BLOOD_COLOR_YELLOW, + BLOOD_COLOR_GREEN, + BLOOD_COLOR_MECH, + +#if defined( HL2_EPISODIC ) + BLOOD_COLOR_ANTLION, + BLOOD_COLOR_ZOMBIE, + BLOOD_COLOR_ANTLION_WORKER, + BLOOD_COLOR_BLOB, + BLOOD_COLOR_BLOB_FROZEN, +#endif + +#if defined( INFESTED_DLL ) + BLOOD_COLOR_BLOB, + BLOOD_COLOR_BLOB_FROZEN, +#endif + + BLOOD_COLOR_BRIGHTGREEN, +}; + +enum PassengerRole_t +{ + VEHICLE_ROLE_NONE = -1, + + VEHICLE_ROLE_DRIVER = 0, + + LAST_SHARED_VEHICLE_ROLE, +}; + +enum +{ + FX_WATER_IN_SLIME = 0x1, +}; + + +#define MAX_CONTEXT_LENGTH 32 +#define NO_THINK_CONTEXT -1 + +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_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_HAS_PLAYER_CHILD = (1 << 16), + + 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), +}; + +const int FX_BLOODSPRAY_DROPS = 0x01; +const int FX_BLOODSPRAY_GORE = 0x02; +const int FX_BLOODSPRAY_CLOUD = 0x04; +const int FX_BLOODSPRAY_ALL = 0xFF; + +#define MAX_SCREEN_OVERLAYS 10 + +enum +{ + GROUNDLINK = 0, + TOUCHLINK, + STEPSIMULATION, + MODELSCALE, + POSITIONWATCHER, + PHYSICSPUSHLIST, + VPHYSICSUPDATEAI, + VPHYSICSWATCHER, + + NUM_DATAOBJECT_TYPES, +}; + +class CBaseEntity; + +class CBaseEntity; + +enum FireBulletsFlags_t +{ + FIRE_BULLETS_FIRST_SHOT_ACCURATE = 0x1, + FIRE_BULLETS_DONT_HIT_UNDERWATER = 0x2, + FIRE_BULLETS_ALLOW_WATER_SURFACE_IMPACTS = 0x4, + FIRE_BULLETS_TEMPORARY_DANGER_SOUND = 0x8, + + FIRE_BULLETS_NO_PIERCING_SPARK = 0x16, + FIRE_BULLETS_HULL = 0x32, + FIRE_BULLETS_ANGULAR_SPREAD = 0x64, +}; + + +struct FireBulletsInfo_t +{ + FireBulletsInfo_t() + { + m_iShots = 1; + m_vecSpread.Init(0, 0, 0); + m_flDistance = 8192; + m_iTracerFreq = 4; + m_flDamage = 0.0f; + m_flPlayerDamage = 0.0f; + m_pAttacker = NULL; + m_nFlags = 0; + m_pAdditionalIgnoreEnt = NULL; + m_flDamageForceScale = 1.0f; + +#ifdef _DEBUG + m_iAmmoType = -1; + m_vecSrc.Init(VEC_T_NAN, VEC_T_NAN, VEC_T_NAN); + m_vecDirShooting.Init(VEC_T_NAN, VEC_T_NAN, VEC_T_NAN); +#endif + m_bPrimaryAttack = true; + } + + FireBulletsInfo_t(int nShots, const Vector& vecSrc, const Vector& vecDir, const Vector& vecSpread, float flDistance, int nAmmoType, bool bPrimaryAttack = true) + { + m_iShots = nShots; + m_vecSrc = vecSrc; + m_vecDirShooting = vecDir; + m_vecSpread = vecSpread; + m_flDistance = flDistance; + m_iAmmoType = nAmmoType; + m_iTracerFreq = 4; + m_flDamage = 0; + m_flPlayerDamage = 0; + m_pAttacker = NULL; + m_nFlags = 0; + m_pAdditionalIgnoreEnt = NULL; + m_flDamageForceScale = 1.0f; + m_bPrimaryAttack = bPrimaryAttack; + } + + int m_iShots; + Vector m_vecSrc; + Vector m_vecDirShooting; + Vector m_vecSpread; + float m_flDistance; + int m_iAmmoType; + int m_iTracerFreq; + float m_flDamage; + float m_flPlayerDamage; + int m_nFlags; + float m_flDamageForceScale; + CBaseEntity* m_pAttacker; + CBaseEntity* m_pAdditionalIgnoreEnt; + bool m_bPrimaryAttack; +}; + +struct StepSimulationStep +{ + int nTickCount; + Vector vecOrigin; + Quaternion qRotation; +}; + +struct StepSimulationData +{ + bool m_bOriginActive; + bool m_bAnglesActive; + + StepSimulationStep m_Previous2; + + StepSimulationStep m_Previous; + + StepSimulationStep m_Discontinuity; + + StepSimulationStep m_Next; + QAngle m_angNextRotation; + + int m_nLastProcessTickCount; + Vector m_vecNetworkOrigin; + int m_networkCell[3]; + QAngle m_angNetworkAngles; +}; + +struct ModelScale +{ + float m_flModelScaleStart; + float m_flModelScaleGoal; + float m_flModelScaleFinishTime; + float m_flModelScaleStartTime; +}; + +#include "soundflags.h" + +struct CSoundParameters; +typedef short HSOUNDSCRIPTHANDLE; +struct EmitSound_t +{ + EmitSound_t() : + m_nChannel(0), + m_pSoundName(0), + m_flVolume(VOL_NORM), + m_SoundLevel(SNDLVL_NONE), + m_nFlags(0), + m_nPitch(PITCH_NORM), + 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; + soundlevel_t m_SoundLevel; + int m_nFlags; + int m_nPitch; + const Vector* m_pOrigin; + float m_flSoundTime; + float* m_pflSoundDuration; + bool m_bEmitCloseCaption; + bool m_bWarnOnMissingCloseCaption; + bool m_bWarnOnDirectWaveReference; + int m_nSpeakerEntity; + mutable CUtlVector< Vector > m_UtlVecSoundOrigin; + mutable HSOUNDSCRIPTHANDLE m_hSoundScriptHandle; +}; + +#define MAX_ACTORS_IN_SCENE 16 + +#define MAX_CONTROL_POINTS 8 +#define MAX_CONTROL_POINT_GROUPS 8 + +#define MAX_PREVIOUS_POINTS 3 + +#define MAX_CONTROL_POINT_TEAMS 8 + +#define MAX_CAPLAYOUT_LENGTH 32 + +#define MAX_ROUND_NAME 32 + +#define MAX_ROUND_IMAGE_NAME 64 + +#define TEAMPLAY_ROUND_WIN_SCORE 1 + +enum +{ + CP_WARN_NORMAL = 0, + CP_WARN_FINALCAP, + CP_WARN_NO_ANNOUNCEMENTS +}; + +#define PREDICTION_ERROR_CHECK_LEVEL 0 + +#define PREDICTION_ERROR_CHECK_STACKS_FOR_MISSING 0 + +enum +{ + RT_STATE_SETUP, + RT_STATE_NORMAL, +}; + +enum +{ + SIMULATION_TIME_WINDOW_BITS = 8, +}; + + +#define CELL_COUNT( bits ) ( (MAX_COORD_INTEGER*2) / (1 << (bits)) ) +#define CELL_COUNT_BITS( bits ) MINIMUM_BITS_NEEDED( CELL_COUNT( bits ) ) +#define CELL_BASEENTITY_ORIGIN_CELL_BITS 5 + + +#ifdef GAME_HAS_NO_USE_KEY +#define COMMENTARY_BUTTONS (IN_ATTACK | IN_ATTACK2 | IN_USE) +#else +#define COMMENTARY_BUTTONS (IN_USE) +#endif + +bool IsHeadTrackingEnabled(); + + +#define MAX_SPLITSCREEN_PLAYERS 1 + + +inline bool IsSplitScreenSupported() +{ + return (MAX_SPLITSCREEN_PLAYERS > 1) ? true : false; +} + +enum InvalidatePhysicsBits_t +{ + POSITION_CHANGED = 0x1, + ANGLES_CHANGED = 0x2, + VELOCITY_CHANGED = 0x4, + ANIMATION_CHANGED = 0x8, + BOUNDS_CHANGED = 0x10, + SEQUENCE_CHANGED = 0x20, +}; + +enum Class_T +{ + CLASS_NONE = 0, + CLASS_PLAYER, + CLASS_PLAYER_ALLY, + CLASS_PLAYER_ALLY_VITAL, + CLASS_ANTLION, + CLASS_BARNACLE, + CLASS_BLOB, + CLASS_BULLSEYE, + CLASS_CITIZEN_PASSIVE, + CLASS_CITIZEN_REBEL, + CLASS_COMBINE, + CLASS_COMBINE_GUNSHIP, + CLASS_CONSCRIPT, + CLASS_HEADCRAB, + CLASS_MANHACK, + CLASS_METROPOLICE, + CLASS_MILITARY, + CLASS_SCANNER, + CLASS_STALKER, + CLASS_VORTIGAUNT, + CLASS_ZOMBIE, + CLASS_PROTOSNIPER, + CLASS_MISSILE, + CLASS_FLARE, + CLASS_EARTH_FAUNA, + CLASS_HACKED_ROLLERMINE, + CLASS_COMBINE_HUNTER, + + LAST_SHARED_ENTITY_CLASS, +}; + +#define FACTION_NONE 0 +#define LAST_SHARED_FACTION (FACTION_NONE) +#define NUM_SHARED_FACTIONS (FACTION_NONE + 1) + + + + + + + + + + +#endif +``` + +`SpyCustom/sdk/shattersurfacetypes.h`: + +```h +#if !defined ( SHATTERSURFACETYPES_H ) +#define SHATTERSURFACETYPES_H +#ifdef _WIN32 +#pragma once +#endif + +enum ShatterSurface_t +{ + SHATTERSURFACE_GLASS = 0, + SHATTERSURFACE_TILE = 1, +}; + +#endif +``` + +`SpyCustom/sdk/smartptr.h`: + +```h +#ifndef SMARTPTR_H +#define SMARTPTR_H +#ifdef _WIN32 +#pragma once +#endif + + +class CRefCountAccessor +{ +public: + template< class T > + static void AddRef(T* pObj) + { + pObj->AddRef(); + } + + template< class T > + static void Release(T* pObj) + { + pObj->Release(); + } +}; + +class CRefCountAccessorLongName +{ +public: + template< class T > + static void AddRef(T* pObj) + { + pObj->AddReference(); + } + + template< class T > + static void Release(T* pObj) + { + pObj->ReleaseReference(); + } +}; + + +template < typename T > +class CPlainAutoPtr +{ +public: + explicit CPlainAutoPtr(T* p = NULL) : m_p(p) {} + ~CPlainAutoPtr(void) { Delete(); } + +public: + void Delete(void) { delete Detach(); } + +private: + CPlainAutoPtr(CPlainAutoPtr const& x); + CPlainAutoPtr& operator = (CPlainAutoPtr const& x); + +public: + void Attach(T* p) { m_p = p; } + T* Detach(void) { T* p(m_p); m_p = NULL; return p; } + +public: + bool IsValid(void) const { return m_p != NULL; } + T* Get(void) const { return m_p; } + T* operator -> (void) const { return Get(); } + T& operator * (void) const { return *Get(); } + +private: + T* m_p; +}; + +template < typename T > +class CArrayAutoPtr : public CPlainAutoPtr < T > +{ +public: + explicit CArrayAutoPtr(T* p = NULL) { this->Attach(p); } + ~CArrayAutoPtr(void) { this->Delete(); } + +public: + void Delete(void) { delete[] CPlainAutoPtr < T >::Detach(); } + +public: + T& operator [] (int k) const { return CPlainAutoPtr < T >::Get()[k]; } +}; + + +template +class CSmartPtr +{ +public: + CSmartPtr(); + CSmartPtr(T* pObj); + CSmartPtr(const CSmartPtr& other); + ~CSmartPtr(); + + T* operator=(T* pObj); + void operator=(const CSmartPtr& other); + const T* operator->() const; + T* operator->(); + bool operator!() const; + bool operator==(const T* pOther) const; + bool IsValid() const; + T* GetObject() const; + void MarkDeleted(); + +private: + T* m_pObj; +}; + + +template< class T, class RefCountAccessor > +inline CSmartPtr::CSmartPtr() +{ + m_pObj = NULL; +} + +template< class T, class RefCountAccessor > +inline CSmartPtr::CSmartPtr(T* pObj) +{ + m_pObj = NULL; + *this = pObj; +} + +template< class T, class RefCountAccessor > +inline CSmartPtr::CSmartPtr(const CSmartPtr& other) +{ + m_pObj = NULL; + *this = other; +} + +template< class T, class RefCountAccessor > +inline CSmartPtr::~CSmartPtr() +{ + if (m_pObj) + { + RefCountAccessor::Release(m_pObj); + } +} + +template< class T, class RefCountAccessor > +inline T* CSmartPtr::operator=(T* pObj) +{ + if (pObj == m_pObj) + return pObj; + + if (pObj) + { + RefCountAccessor::AddRef(pObj); + } + if (m_pObj) + { + RefCountAccessor::Release(m_pObj); + } + m_pObj = pObj; + return pObj; +} + +template< class T, class RefCountAccessor > +inline void CSmartPtr::MarkDeleted() +{ + m_pObj = NULL; +} + +template< class T, class RefCountAccessor > +inline void CSmartPtr::operator=(const CSmartPtr& other) +{ + *this = other.m_pObj; +} + +template< class T, class RefCountAccessor > +inline const T* CSmartPtr::operator->() const +{ + return m_pObj; +} + +template< class T, class RefCountAccessor > +inline T* CSmartPtr::operator->() +{ + return m_pObj; +} + +template< class T, class RefCountAccessor > +inline bool CSmartPtr::operator!() const +{ + return !m_pObj; +} + +template< class T, class RefCountAccessor > +inline bool CSmartPtr::operator==(const T* pOther) const +{ + return m_pObj == pOther; +} + +template< class T, class RefCountAccessor > +inline bool CSmartPtr::IsValid() const +{ + return m_pObj != NULL; +} + +template< class T, class RefCountAccessor > +inline T* CSmartPtr::GetObject() const +{ + return m_pObj; +} + + +template < typename T > +class CAutoPushPop +{ +public: + explicit CAutoPushPop(T& var) : m_rVar(var), m_valPop(var) {} + CAutoPushPop(T& var, T const& valPush) : m_rVar(var), m_valPop(var) { m_rVar = valPush; } + CAutoPushPop(T& var, T const& valPush, T const& valPop) : m_rVar(var), m_valPop(var) { m_rVar = valPush; } + + ~CAutoPushPop() { m_rVar = m_valPop; } + +private: + CAutoPushPop(CAutoPushPop const& x); + CAutoPushPop& operator = (CAutoPushPop const& x); + +public: + T& Get() { return m_rVar; } + +private: + T& m_rVar; + T m_valPop; +}; + + +#endif +``` + +`SpyCustom/sdk/soundflags.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SOUNDFLAGS_H +#define SOUNDFLAGS_H + +#if defined( _WIN32 ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// channels +//----------------------------------------------------------------------------- +enum +{ + CHAN_REPLACE = -1, + CHAN_AUTO = 0, + CHAN_WEAPON = 1, + CHAN_VOICE = 2, + CHAN_ITEM = 3, + CHAN_BODY = 4, + CHAN_STREAM = 5, // allocate stream channel from the static or dynamic area + CHAN_STATIC = 6, // allocate channel from the static area + CHAN_VOICE2 = 7, + CHAN_VOICE_BASE = 8, // allocate channel for network voice data + CHAN_USER_BASE = (CHAN_VOICE_BASE + 128) // Anything >= this number is allocated to game code. +}; + +//----------------------------------------------------------------------------- +// common volume values +//----------------------------------------------------------------------------- +#define VOL_NORM 1.0f + + +//----------------------------------------------------------------------------- +// common attenuation values +//----------------------------------------------------------------------------- +#define ATTN_NONE 0.0f +#define ATTN_NORM 0.8f +#define ATTN_IDLE 2.0f +#define ATTN_STATIC 1.25f +#define ATTN_RICOCHET 1.5f + +// HL2 world is 8x bigger now! We want to hear gunfire from farther. +// Don't change this without consulting Kelly or Wedge (sjb). +#define ATTN_GUNFIRE 0.27f + +enum soundlevel_t +{ + SNDLVL_NONE = 0, + + SNDLVL_20dB = 20, // rustling leaves + SNDLVL_25dB = 25, // whispering + SNDLVL_30dB = 30, // library + SNDLVL_35dB = 35, + SNDLVL_40dB = 40, + SNDLVL_45dB = 45, // refrigerator + + SNDLVL_50dB = 50, // 3.9 // average home + SNDLVL_55dB = 55, // 3.0 + + SNDLVL_IDLE = 60, // 2.0 + SNDLVL_60dB = 60, // 2.0 // normal conversation, clothes dryer + + SNDLVL_65dB = 65, // 1.5 // washing machine, dishwasher + SNDLVL_STATIC = 66, // 1.25 + + SNDLVL_70dB = 70, // 1.0 // car, vacuum cleaner, mixer, electric sewing machine + + SNDLVL_NORM = 75, + SNDLVL_75dB = 75, // 0.8 // busy traffic + + SNDLVL_80dB = 80, // 0.7 // mini-bike, alarm clock, noisy restaurant, office tabulator, outboard motor, passing snowmobile + SNDLVL_TALKING = 80, // 0.7 + SNDLVL_85dB = 85, // 0.6 // average factory, electric shaver + SNDLVL_90dB = 90, // 0.5 // screaming child, passing motorcycle, convertible ride on frw + SNDLVL_95dB = 95, + SNDLVL_100dB = 100, // 0.4 // subway train, diesel truck, woodworking shop, pneumatic drill, boiler shop, jackhammer + SNDLVL_105dB = 105, // helicopter, power mower + SNDLVL_110dB = 110, // snowmobile drvrs seat, inboard motorboat, sandblasting + SNDLVL_120dB = 120, // auto horn, propeller aircraft + SNDLVL_130dB = 130, // air raid siren + + SNDLVL_GUNFIRE = 140, // 0.27 // THRESHOLD OF PAIN, gunshot, jet engine + SNDLVL_140dB = 140, // 0.2 + + SNDLVL_150dB = 150, // 0.2 + + SNDLVL_180dB = 180, // rocket launching + + // NOTE: Valid soundlevel_t values are 0-255. + // 256-511 are reserved for sounds using goldsrc compatibility attenuation. +}; + +#define MAX_SNDLVL_BITS 9 // Used to encode 0-255 for regular soundlevel_t's and 256-511 for goldsrc-compatible ones. +#define MIN_SNDLVL_VALUE 0 +#define MAX_SNDLVL_VALUE ((1< 50) ? (20.0f / (float)(a - 50)) : 4.0 ) + +// This is a limit due to network encoding. +// It encodes attenuation * 64 in 8 bits, so the maximum is (255 / 64) +#define MAX_ATTENUATION 3.98f + +//----------------------------------------------------------------------------- +// Flags to be or-ed together for the iFlags field +//----------------------------------------------------------------------------- +enum SoundFlags_t +{ + SND_NOFLAGS = 0, // to keep the compiler happy + SND_CHANGE_VOL = (1 << 0), // change sound vol + SND_CHANGE_PITCH = (1 << 1), // change sound pitch + SND_STOP = (1 << 2), // stop the sound + SND_SPAWNING = (1 << 3), // we're spawning, used in some cases for ambients + // not sent over net, only a param between dll and server. + SND_DELAY = (1 << 4), // sound has an initial delay + SND_STOP_LOOPING = (1 << 5), // stop all looping sounds on the entity. + SND_SPEAKER = (1 << 6), // being played again by a microphone through a speaker + + SND_SHOULDPAUSE = (1 << 7), // this sound should be paused if the game is paused + SND_IGNORE_PHONEMES = (1 << 8), + SND_IGNORE_NAME = (1 << 9), // used to change all sounds emitted by an entity, regardless of scriptname + + SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL = (1 << 10), +}; + +#define SND_FLAG_BITS_ENCODE 11 + +#define MAX_SOUND_INDEX_BITS 14 +#define MAX_SOUNDS (1< +#elif defined ( _PS3 ) +#include +#include +#else +#include +#ifndef _LINUX +#include +#endif +#endif + +#ifndef SPU +#include "vector.h" +#include "mathlib.h" +#else +#include "mathlib/math_pfns.h" +#endif + +#include "fltx4.h" + +#ifdef _X360 +typedef __vector4 FLTX4; +#elif defined( _PS3 ) +typedef vec_float4 FLTX4; +#else +typedef const fltx4& FLTX4; +#endif + +struct ALIGN16 intx4 +{ + int32 m_i32[4]; + + inline int& operator[](int which) + { + return m_i32[which]; + } + + inline const int& operator[](int which) const + { + return m_i32[which]; + } + + inline int32* Base() { + return m_i32; + } + + inline const int32* Base() const + { + return m_i32; + } + + inline bool operator==(const intx4& other) const + { + return m_i32[0] == other.m_i32[0] && + m_i32[1] == other.m_i32[1] && + m_i32[2] == other.m_i32[2] && + m_i32[3] == other.m_i32[3]; + } +} ALIGN16_POST; + + +#if defined( _DEBUG ) && defined( _X360 ) +FORCEINLINE void TestVPUFlags() +{ + __vector4 a; + __asm + { + mfvscr a; + } + unsigned int* flags = (unsigned int*)&a; + unsigned int controlWord = flags[3]; + Assert(controlWord == 0); +} +#else +FORCEINLINE void TestVPUFlags() {} +#endif + + +#ifdef _X360 +#define Four_Zeros XMVectorZero() +#define Four_Ones XMVectorSplatOne() +extern const fltx4 Four_Twos; +extern const fltx4 Four_Threes; +extern const fltx4 Four_Fours; +extern const fltx4 Four_Point225s; +extern const fltx4 Four_PointFives; +extern const fltx4 Four_Thirds; +extern const fltx4 Four_TwoThirds; +extern const fltx4 Four_NegativeOnes; +extern const fltx4 Four_DegToRad; +#elif defined(SPU) +#define Four_Zeros spu_splats( 0.0f ) +#define Four_Ones spu_splats( 1.0f ) +#define Four_Twos spu_splats( 2.0f ) +#define Four_Threes spu_splats( 3.0f ) +#define Four_Fours spu_splats( 4.0f ) +#define Four_Point225s spu_splats( 0.225f ) +#define Four_PointFives spu_splats( 0.5f ) +#define Four_Thirds spu_splats( 0.33333333 ); +#define Four_TwoThirds spu_splats( 0.66666666 ); +#define Four_NegativeOnes spu_splats( -1.0f ) +#define Four_DegToRad spu_splats((float)(M_PI_F / 180.f)) +#else +extern const fltx4 Four_Zeros; +extern const fltx4 Four_Ones; +extern const fltx4 Four_Twos; +extern const fltx4 Four_Threes; +extern const fltx4 Four_Fours; +extern const fltx4 Four_Point225s; +extern const fltx4 Four_PointFives; +extern const fltx4 Four_Thirds; +extern const fltx4 Four_TwoThirds; +extern const fltx4 Four_NegativeOnes; +extern const fltx4 Four_DegToRad; +#endif +extern const fltx4 Four_Epsilons; +extern const fltx4 Four_2ToThe21s; +extern const fltx4 Four_2ToThe22s; +extern const fltx4 Four_2ToThe23s; +extern const fltx4 Four_2ToThe24s; +extern const fltx4 Four_Origin; +extern const fltx4 Four_FLT_MAX; +extern const fltx4 Four_Negative_FLT_MAX; +extern const fltx4 g_SIMD_0123; + + +extern const fltx4 Four_LinearToGammaCoefficients_A; +extern const fltx4 Four_LinearToGammaCoefficients_B; +extern const fltx4 Four_LinearToGammaCoefficients_C; +extern const fltx4 Four_LinearToGammaCoefficients_D; +extern const fltx4 Four_LinearToGammaCoefficients_E; + +extern const fltx4 Four_GammaToLinearCoefficients_A; +extern const fltx4 Four_GammaToLinearCoefficients_B; +extern const fltx4 Four_GammaToLinearCoefficients_C; +extern const fltx4 Four_GammaToLinearCoefficients_D; + + +#ifndef ALIGN16_POST +#define ALIGN16_POST +#endif +extern const ALIGN16 int32 g_SIMD_clear_signmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_signmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_lsbmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_clear_wmask[] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_ComponentMask[4][4] ALIGN16_POST; +extern const ALIGN16 int32 g_SIMD_AllOnesMask[] ALIGN16_POST; +extern const fltx4 g_SIMD_Identity[4]; +extern const ALIGN16 int32 g_SIMD_Low16BitsMask[] ALIGN16_POST; + +extern const int32 ALIGN16 g_SIMD_SkipTailMask[4][4] ALIGN16_POST; + +extern const int32 ALIGN16 g_SIMD_EveryOtherMask[]; +#ifdef PLATFORM_PPC +#if defined(_X360) +#define PREFETCH360(address, offset) __dcbt(offset,address) +#elif defined(_PS3) +#define PREFETCH360(address, offset) __dcbt( reinterpret_cast< const char * >(address) + offset ) +#else +#error Prefetch not defined for this platform! +#endif +#else +#define PREFETCH360(x,y) +#endif + +template +inline T* AlignPointer(void* ptr) +{ +#if defined( __clang__ ) + uintp temp = (uintp)ptr; +#else + unsigned temp = ptr; +#endif + temp = ALIGN_VALUE(temp, sizeof(T)); + return (T*)temp; +} + +#ifdef _PS3 + +#define _VEC_CLEAR_SIGNMASK (__vector unsigned int) {0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff} +#define _VEC_SIGNMASK (__vector unsigned int) { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } +#define _VEC_LSBMASK (__vector unsigned int) { 0xfffffffe, 0xfffffffe, 0xfffffffe, 0xfffffffe } +#define _VEC_CLEAR_WMASK (__vector unsigned int) {0xffffffff, 0xffffffff, 0xffffffff, 0} +#define _VEC_COMPONENT_MASK_0 (__vector unsigned int) {0xffffffff, 0, 0, 0} +#define _VEC_COMPONENT_MASK_1 (__vector unsigned int) {0, 0xffffffff, 0, 0} +#define _VEC_COMPONENT_MASK_2 (__vector unsigned int) {0, 0, 0xffffffff, 0} +#define _VEC_COMPONENT_MASK_3 (__vector unsigned int) {0, 0, 0, 0xffffffff} + +#define _VEC_SWIZZLE_WZYX (__vector unsigned char) { 0x0c,0x0d,0x0e,0x0f, 0x08,0x09,0x0a,0x0b, 0x04,0x05,0x06,0x07, 0x00,0x01,0x02,0x03 } +#define _VEC_SWIZZLE_ZWXY (__vector unsigned char) { 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07 } +#define _VEC_SWIZZLE_YXWZ (__vector unsigned char) { 0x04,0x05,0x06,0x07, 0x00,0x01,0x02,0x03, 0x0c,0x0d,0x0e,0x0f, 0x08,0x09,0x0a,0x0b } + +#define _VEC_ZERO (__vector unsigned int) {0,0,0,0} + +#define _VEC_FLTMAX (__vector float) {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX} +#define _VEC_FLTMIN (__vector float) {FLT_MIN,FLT_MIN,FLT_MIN,FLT_MIN} + +#define _VEC_ORIGIN (__vector unsigned int) { 0x00000000, 0x00000000, 0x00000000, 0xffffffff } + +#endif + +#if USE_STDC_FOR_SIMD + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ + return a.m128_f32[idx]; +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ + return a.m128_f32[idx]; +} + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ + return a.m128_u32[idx]; +} + +FORCEINLINE uint32& SubInt(fltx4& a, int idx) +{ + return a.m128_u32[idx]; +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return Four_Zeros; +} + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return Four_Ones; +} + +FORCEINLINE fltx4 SplatXSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 0); + SubFloat(retVal, 1) = SubFloat(a, 0); + SubFloat(retVal, 2) = SubFloat(a, 0); + SubFloat(retVal, 3) = SubFloat(a, 0); + return retVal; +} + +FORCEINLINE fltx4 SplatYSIMD(fltx4 a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 1); + SubFloat(retVal, 1) = SubFloat(a, 1); + SubFloat(retVal, 2) = SubFloat(a, 1); + SubFloat(retVal, 3) = SubFloat(a, 1); + return retVal; +} + +FORCEINLINE fltx4 SplatZSIMD(fltx4 a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 2); + SubFloat(retVal, 1) = SubFloat(a, 2); + SubFloat(retVal, 2) = SubFloat(a, 2); + SubFloat(retVal, 3) = SubFloat(a, 2); + return retVal; +} + +FORCEINLINE fltx4 SplatWSIMD(fltx4 a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 3); + SubFloat(retVal, 1) = SubFloat(a, 3); + SubFloat(retVal, 2) = SubFloat(a, 3); + SubFloat(retVal, 3) = SubFloat(a, 3); + return retVal; +} + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 result = a; + SubFloat(result, 0) = SubFloat(x, 0); + return result; +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 result = a; + SubFloat(result, 1) = SubFloat(y, 1); + return result; +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 result = a; + SubFloat(result, 2) = SubFloat(z, 2); + return result; +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + fltx4 result = a; + SubFloat(result, 3) = SubFloat(w, 3); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ + fltx4 result = a; + SubFloat(result, nComponent) = flValue; + return result; +} + + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 1); + SubFloat(retVal, 1) = SubFloat(a, 2); + SubFloat(retVal, 2) = SubFloat(a, 3); + SubFloat(retVal, 3) = SubFloat(a, 0); + return retVal; +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = SubFloat(a, 2); + SubFloat(retVal, 1) = SubFloat(a, 3); + SubFloat(retVal, 2) = SubFloat(a, 0); + SubFloat(retVal, 3) = SubFloat(a, 1); + return retVal; +} + +#define BINOP(op) \ + fltx4 retVal; \ + SubFloat( retVal, 0 ) = ( SubFloat( a, 0 ) op SubFloat( b, 0 ) ); \ + SubFloat( retVal, 1 ) = ( SubFloat( a, 1 ) op SubFloat( b, 1 ) ); \ + SubFloat( retVal, 2 ) = ( SubFloat( a, 2 ) op SubFloat( b, 2 ) ); \ + SubFloat( retVal, 3 ) = ( SubFloat( a, 3 ) op SubFloat( b, 3 ) ); \ + return retVal; + +#define IBINOP(op) \ + fltx4 retVal; \ + SubInt( retVal, 0 ) = ( SubInt( a, 0 ) op SubInt ( b, 0 ) ); \ + SubInt( retVal, 1 ) = ( SubInt( a, 1 ) op SubInt ( b, 1 ) ); \ + SubInt( retVal, 2 ) = ( SubInt( a, 2 ) op SubInt ( b, 2 ) ); \ + SubInt( retVal, 3 ) = ( SubInt( a, 3 ) op SubInt ( b, 3 ) ); \ + return retVal; + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(+); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(-); +}; + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(*); +} + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(/ ); +} + +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + BINOP(/ ); +} + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return AddSIMD(MulSIMD(a, b), c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return SubSIMD(c, MulSIMD(a, b)); +}; + + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + fltx4 result; + SubFloat(result, 0) = sin(SubFloat(radians, 0)); + SubFloat(result, 1) = sin(SubFloat(radians, 1)); + SubFloat(result, 2) = sin(SubFloat(radians, 2)); + SubFloat(result, 3) = sin(SubFloat(radians, 3)); + return result; +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); + SinCos(SubFloat(radians, 3), &SubFloat(sine, 3), &SubFloat(cosine, 3)); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + fltx4 result; + SubFloat(result, 0) = asin(SubFloat(sine, 0)); + SubFloat(result, 1) = asin(SubFloat(sine, 1)); + SubFloat(result, 2) = asin(SubFloat(sine, 2)); + SubFloat(result, 3) = asin(SubFloat(sine, 3)); + return result; +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + fltx4 result; + SubFloat(result, 0) = acos(SubFloat(cs, 0)); + SubFloat(result, 1) = acos(SubFloat(cs, 1)); + SubFloat(result, 2) = acos(SubFloat(cs, 2)); + SubFloat(result, 3) = acos(SubFloat(cs, 3)); + return result; +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + SubFloat(result, 0) = atan2(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(result, 1) = atan2(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(result, 2) = atan2(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(result, 3) = atan2(SubFloat(a, 3), SubFloat(b, 3)); + return result; +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubFloat(retVal, 0) = max(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(retVal, 1) = max(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(retVal, 2) = max(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(retVal, 3) = max(SubFloat(a, 3), SubFloat(b, 3)); + return retVal; +} + +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubFloat(retVal, 0) = min(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(retVal, 1) = min(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(retVal, 2) = min(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(retVal, 3) = min(SubFloat(a, 3), SubFloat(b, 3)); + return retVal; +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + IBINOP(&); +} + +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = ~SubInt(a, 0) & SubInt(b, 0); + SubInt(retVal, 1) = ~SubInt(a, 1) & SubInt(b, 1); + SubInt(retVal, 2) = ~SubInt(a, 2) & SubInt(b, 2); + SubInt(retVal, 3) = ~SubInt(a, 3) & SubInt(b, 3); + return retVal; +} + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + IBINOP(^); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + IBINOP(| ); +} + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + fltx4 retval; + SubFloat(retval, 0) = -SubFloat(a, 0); + SubFloat(retval, 1) = -SubFloat(a, 1); + SubFloat(retval, 2) = -SubFloat(a, 2); + SubFloat(retval, 3) = -SubFloat(a, 3); + + return retval; +} + +FORCEINLINE bool IsAllZeros(const fltx4& a) +{ + return (SubFloat(a, 0) == 0.0) && + (SubFloat(a, 1) == 0.0) && + (SubFloat(a, 2) == 0.0) && + (SubFloat(a, 3) == 0.0); +} + + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) > SubFloat(b, 0) && + SubFloat(a, 1) > SubFloat(b, 1) && + SubFloat(a, 2) > SubFloat(b, 2) && + SubFloat(a, 3) > SubFloat(b, 3); +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) >= SubFloat(b, 0) && + SubFloat(a, 1) >= SubFloat(b, 1) && + SubFloat(a, 2) >= SubFloat(b, 2) && + SubFloat(a, 3) >= SubFloat(b, 3); +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) == SubFloat(b, 0) && + SubFloat(a, 1) == SubFloat(b, 1) && + SubFloat(a, 2) == SubFloat(b, 2) && + SubFloat(a, 3) == SubFloat(b, 3); +} + +FORCEINLINE bool IsAnyEqual(const fltx4& a, const fltx4& b) +{ + return SubFloat(a, 0) == SubFloat(b, 0) || + SubFloat(a, 1) == SubFloat(b, 1) || + SubFloat(a, 2) == SubFloat(b, 2) || + SubFloat(a, 3) == SubFloat(b, 3); +} + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + int nRet = 0; + + nRet |= (SubInt(a, 0) & 0x80000000) >> 31; + nRet |= (SubInt(a, 1) & 0x80000000) >> 30; + nRet |= (SubInt(a, 2) & 0x80000000) >> 29; + nRet |= (SubInt(a, 3) & 0x80000000) >> 28; + + return nRet; +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE fltx4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) == SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) == SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) == SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) == SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) > SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) > SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) > SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) > SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) >= SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) >= SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) >= SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) >= SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) < SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) < SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) < SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) < SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) <= SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) <= SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) <= SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) <= SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + +FORCEINLINE fltx4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + fltx4 retVal; + SubInt(retVal, 0) = (SubFloat(a, 0) <= SubFloat(b, 0) && SubFloat(a, 0) >= -SubFloat(b, 0)) ? ~0 : 0; + SubInt(retVal, 1) = (SubFloat(a, 1) <= SubFloat(b, 1) && SubFloat(a, 1) >= -SubFloat(b, 1)) ? ~0 : 0; + SubInt(retVal, 2) = (SubFloat(a, 2) <= SubFloat(b, 2) && SubFloat(a, 2) >= -SubFloat(b, 2)) ? ~0 : 0; + SubInt(retVal, 3) = (SubFloat(a, 3) <= SubFloat(b, 3) && SubFloat(a, 3) >= -SubFloat(b, 3)) ? ~0 : 0; + return retVal; +} + + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return OrSIMD( + AndSIMD(ReplacementMask, NewValue), + AndNotSIMD(ReplacementMask, OldValue)); +} + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ + fltx4 retVal; + SubFloat(retVal, 0) = flValue; + SubFloat(retVal, 1) = flValue; + SubFloat(retVal, 2) = flValue; + SubFloat(retVal, 3) = flValue; + return retVal; +} + +FORCEINLINE fltx4 ReplicateIX4(int nValue) +{ + fltx4 retVal; + SubInt(retVal, 0) = nValue; + SubInt(retVal, 1) = nValue; + SubInt(retVal, 2) = nValue; + SubInt(retVal, 3) = nValue; + return retVal; + +} + +FORCEINLINE fltx4 CeilSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = ceil(SubFloat(a, 0)); + SubFloat(retVal, 1) = ceil(SubFloat(a, 1)); + SubFloat(retVal, 2) = ceil(SubFloat(a, 2)); + SubFloat(retVal, 3) = ceil(SubFloat(a, 3)); + return retVal; + +} + +FORCEINLINE fltx4 FloorSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = floor(SubFloat(a, 0)); + SubFloat(retVal, 1) = floor(SubFloat(a, 1)); + SubFloat(retVal, 2) = floor(SubFloat(a, 2)); + SubFloat(retVal, 3) = floor(SubFloat(a, 3)); + return retVal; + +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0) != 0.0f ? SubFloat(a, 0) : FLT_EPSILON); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1) != 0.0f ? SubFloat(a, 1) : FLT_EPSILON); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2) != 0.0f ? SubFloat(a, 2) : FLT_EPSILON); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3) != 0.0f ? SubFloat(a, 3) : FLT_EPSILON); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / SubFloat(a, 0); + SubFloat(retVal, 1) = 1.0 / SubFloat(a, 1); + SubFloat(retVal, 2) = 1.0 / SubFloat(a, 2); + SubFloat(retVal, 3) = 1.0 / SubFloat(a, 3); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / SubFloat(a, 0); + SubFloat(retVal, 1) = 1.0 / SubFloat(a, 1); + SubFloat(retVal, 2) = 1.0 / SubFloat(a, 2); + SubFloat(retVal, 3) = 1.0 / SubFloat(a, 3); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / (SubFloat(a, 0) == 0.0f ? FLT_EPSILON : SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / (SubFloat(a, 1) == 0.0f ? FLT_EPSILON : SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / (SubFloat(a, 2) == 0.0f ? FLT_EPSILON : SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / (SubFloat(a, 3) == 0.0f ? FLT_EPSILON : SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / (SubFloat(a, 0) == 0.0f ? FLT_EPSILON : SubFloat(a, 0)); + SubFloat(retVal, 1) = 1.0 / (SubFloat(a, 1) == 0.0f ? FLT_EPSILON : SubFloat(a, 1)); + SubFloat(retVal, 2) = 1.0 / (SubFloat(a, 2) == 0.0f ? FLT_EPSILON : SubFloat(a, 2)); + SubFloat(retVal, 3) = 1.0 / (SubFloat(a, 3) == 0.0f ? FLT_EPSILON : SubFloat(a, 3)); + return retVal; +} + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + fltx4 retVal; + SubFloat(retVal, 0) = powf(2, SubFloat(toPower, 0)); + SubFloat(retVal, 1) = powf(2, SubFloat(toPower, 1)); + SubFloat(retVal, 2) = powf(2, SubFloat(toPower, 2)); + SubFloat(retVal, 3) = powf(2, SubFloat(toPower, 3)); + + return retVal; +} + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + float flDot = SubFloat(a, 0) * SubFloat(b, 0) + + SubFloat(a, 1) * SubFloat(b, 1) + + SubFloat(a, 2) * SubFloat(b, 2); + return ReplicateX4(flDot); +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + float flDot = SubFloat(a, 0) * SubFloat(b, 0) + + SubFloat(a, 1) * SubFloat(b, 1) + + SubFloat(a, 2) * SubFloat(b, 2) + + SubFloat(a, 3) * SubFloat(b, 3); + return ReplicateX4(flDot); +} + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + return MaxSIMD(min, MinSIMD(max, in)); +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + fltx4 retval; + retval = a; + SubFloat(retval, 0) = 0; + return retval; +} + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + fltx4 retval; + SubFloat(retval, 0) = *pFlt; + return retval; +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + fltx4 retval = LoadAlignedSIMD(pSIMD.Base()); + SubInt(retval, 3) = 0; + return retval; +} + + +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ + fltx4 retval = { x, y, z, w }; + return retval; +} + +FORCEINLINE void StoreAlignedSIMD(float* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreUnalignedSIMD(float* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreUnalignedFloat(float* pSingleFloat, const fltx4& a) +{ + *pSingleFloat = SubFloat(a, 0); +} + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + *pSIMD = SubFloat(a, 0); + *(pSIMD + 1) = SubFloat(a, 1); + *(pSIMD + 2) = SubFloat(a, 2); +} + + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + StoreAlignedSIMD(pSIMD->Base(), a); +} + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ +#define SWAP_FLOATS( _a_, _ia_, _b_, _ib_ ) { float tmp = SubFloat( _a_, _ia_ ); SubFloat( _a_, _ia_ ) = SubFloat( _b_, _ib_ ); SubFloat( _b_, _ib_ ) = tmp; } + SWAP_FLOATS(x, 1, y, 0); + SWAP_FLOATS(x, 2, z, 0); + SWAP_FLOATS(x, 3, w, 0); + SWAP_FLOATS(y, 2, z, 1); + SWAP_FLOATS(y, 3, w, 1); + SWAP_FLOATS(z, 3, w, 2); +} + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + float lowest = min(min(SubFloat(a, 0), SubFloat(a, 1)), SubFloat(a, 2)); + return ReplicateX4(lowest); +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + float highest = max(max(SubFloat(a, 0), SubFloat(a, 1)), SubFloat(a, 2)); + return ReplicateX4(highest); +} + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ + (*pDest)[0] = SubFloat(vSrc, 0); + (*pDest)[1] = SubFloat(vSrc, 1); + (*pDest)[2] = SubFloat(vSrc, 2); + (*pDest)[3] = SubFloat(vSrc, 3); +} + +FORCEINLINE fltx4 IntSetImmediateSIMD(int nValue) +{ + fltx4 retval; + SubInt(retval, 0) = SubInt(retval, 1) = SubInt(retval, 2) = SubInt(retval, 3) = nValue; + return retval; +} + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void* RESTRICT pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void* RESTRICT pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD.Base())) = a; +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE fltx4 LoadAndConvertUint16SIMD(const uint16* pInts) +{ + fltx4 retval; + SubFloat(retval, 0) = pInts[0]; + SubFloat(retval, 1) = pInts[1]; + SubFloat(retval, 2) = pInts[2]; + SubFloat(retval, 3) = pInts[3]; +} + + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const u32x4& vSrcA) +{ + Assert(0); + fltx4 retval; + SubFloat(retval, 0) = ((float)SubInt(vSrcA, 0)); + SubFloat(retval, 1) = ((float)SubInt(vSrcA, 1)); + SubFloat(retval, 2) = ((float)SubInt(vSrcA, 2)); + SubFloat(retval, 3) = ((float)SubInt(vSrcA, 3)); + return retval; +} + + +#if 0 +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + fltx4 retval; + SubFloat(retval, 0) = ((float)(reinterpret_cast(&vSrcA.m128_s32[0]))); + SubFloat(retval, 1) = ((float)(reinterpret_cast(&vSrcA.m128_s32[1]))); + SubFloat(retval, 2) = ((float)(reinterpret_cast(&vSrcA.m128_s32[2]))); + SubFloat(retval, 3) = ((float)(reinterpret_cast(&vSrcA.m128_s32[3]))); + return retval; +} + + +FORCEINLINE i32x4 IntShiftLeftWordSIMD(const i32x4& vSrcA, const i32x4& vSrcB) +{ + i32x4 retval; + SubInt(retval, 0) = SubInt(vSrcA, 0) << SubInt(vSrcB, 0); + SubInt(retval, 1) = SubInt(vSrcA, 1) << SubInt(vSrcB, 1); + SubInt(retval, 2) = SubInt(vSrcA, 2) << SubInt(vSrcB, 2); + SubInt(retval, 3) = SubInt(vSrcA, 3) << SubInt(vSrcB, 3); + + + return retval; +} + +#endif + +#elif ( defined( _PS3 ) ) +#define SN_IMPROVED_INTRINSICS ( (( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 )) ||\ + (defined(__SN_VER__) && (__SN_VER__ > 25002)) ) + +FORCEINLINE float FloatSIMD(fltx4& a, int idx) +{ +#if SN_IMPROVED_INTRINSICS + return vec_extract(a, idx); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + return a_union.m128_f32[idx]; +#endif +} + +FORCEINLINE unsigned int UIntSIMD(u32x4& a, int idx) +{ +#if SN_IMPROVED_INTRINSICS + return vec_extract(a, idx); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxui); + return a_union.m128_u32[idx]; +#endif +} + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + return vec_add(a, b); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + return vec_sub(a, b); +} + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + return vec_madd(a, b, _VEC_ZEROF); +} + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return vec_madd(a, b, c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return vec_nmsub(a, b, c); +}; + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + + result = vec_madd(a, b, _VEC_ZEROF); + result = vec_madd(vec_sld(a, a, 4), vec_sld(b, b, 4), result); + result = vec_madd(vec_sld(a, a, 8), vec_sld(b, b, 8), result); + + result = vec_splat(result, 0); + + return result; +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + + result = vec_madd(a, b, _VEC_ZEROF); + result = vec_madd(vec_sld(a, a, 4), vec_sld(b, b, 4), result); + result = vec_add(vec_sld(result, result, 8), result); + + result = vec_splat(result, 0); + + return result; +} + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + return sinf4(radians); +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + sincosf4(radians, &sine, &cosine); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + sincosf4(radians, &sine, &cosine); +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + return acosf4(cs); +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + return atan2f4(a, b); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + return asinf4(sine); +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + return vec_max(a, b); +} +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + return vec_min(a, b); +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + return vec_and(a, b); +} +FORCEINLINE fltx4 AndSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_and((fltx4)a, b); +} +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const bi32x4& b) +{ + return vec_and(a, (fltx4)b); +} +FORCEINLINE bi32x4 AndSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_and(a, b); +} + +#if 0 +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + return vec_andc(b, a); +} +FORCEINLINE fltx4 AndNotSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_andc(b, (fltx4)a); +} +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const bi32x4& b) +{ + return (fltx4)vec_andc(b, (bi32x4)a); +} +FORCEINLINE bi32x4 AndNotSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_andc(b, a); +} +#else +template< typename T, typename U > +FORCEINLINE T AndNotSIMD(const T& a, const U& b) +{ + return vec_andc(b, (T)a); +} + +FORCEINLINE fltx4 AndNotSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_andc(b, (fltx4)a); +} +#endif + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + return vec_xor(a, b); +} +FORCEINLINE fltx4 XorSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_xor((fltx4)a, b); +} +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const bi32x4& b) +{ + return vec_xor(a, (fltx4)b); +} +FORCEINLINE bi32x4 XorSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_xor(a, b); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + return vec_or(a, b); +} +FORCEINLINE fltx4 OrSIMD(const bi32x4& a, const fltx4& b) +{ + return vec_or((fltx4)a, b); +} +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const bi32x4& b) +{ + return vec_or(a, (fltx4)b); +} +FORCEINLINE i32x4 OrSIMD(const i32x4& a, const i32x4& b) +{ + return vec_or(a, b); +} +FORCEINLINE u32x4 OrSIMD(const u32x4& a, const u32x4& b) +{ + return vec_or(a, b); +} + +#if !defined(__SPU__) +FORCEINLINE bi32x4 OrSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_or(a, b); +} +#endif + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + return(SubSIMD(_VEC_ZEROF, a)); + +} + +FORCEINLINE bool IsAnyZeros(const fltx4& a) +{ + return vec_any_eq(a, _VEC_ZEROF); +} + +FORCEINLINE bool IsAnyZeros(const bi32x4& a) +{ + return vec_any_eq((u32x4)a, _VEC_ZERO); +} + +FORCEINLINE bool IsAllZeros(const bi32x4& a) +{ + return vec_all_eq((u32x4)a, _VEC_ZERO); +} + +FORCEINLINE bool IsAnyXYZZero(const fltx4& a) +{ +#if SN_IMPROVED_INTRINSICS + + fltx4 b = vec_insert(1.0f, a, 3); + + return vec_any_eq(b, _VEC_ZEROF); +#else + fltx4 b = vec_perm(a, _VEC_ONEF, _VEC_PERMUTE_XYZ0W1); + return vec_any_eq(b, _VEC_ZEROF); +#endif +} + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + return vec_all_gt(a, b); +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + return vec_all_ge(a, b); +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + return vec_all_eq(a, b); +} + + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + int nRet = 0; + + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + + nRet |= (a_union.m128_u32[0] & 0x80000000) >> 31; + nRet |= (a_union.m128_u32[1] & 0x80000000) >> 30; + nRet |= (a_union.m128_u32[2] & 0x80000000) >> 29; + nRet |= (a_union.m128_u32[3] & 0x80000000) >> 28; + + return nRet; +} +FORCEINLINE int TestSignSIMD(const bi32x4& a) +{ + int nRet = 0; + + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxbi); + + nRet |= (a_union.m128_u32[0] & 0x80000000) >> 31; + nRet |= (a_union.m128_u32[1] & 0x80000000) >> 30; + nRet |= (a_union.m128_u32[2] & 0x80000000) >> 29; + nRet |= (a_union.m128_u32[3] & 0x80000000) >> 28; + + return nRet; +} + +FORCEINLINE bool IsAnyNegative(const bi32x4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + return (fltx4)vec_and((u32x4)a, _VEC_CLEAR_WMASK); +} +FORCEINLINE bi32x4 SetWToZeroSIMD(const bi32x4& a) +{ + return (bi32x4)vec_and((u32x4)a, _VEC_CLEAR_WMASK); +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + return vec_any_lt(a, _VEC_ZEROF); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + return vec_any_ne(a, _VEC_ZEROF); +} + +#ifdef DIFFERENT_NATIVE_VECTOR_TYPES + +FORCEINLINE bool IsAnyTrue(const bi32x4& a) +{ + return vec_any_ne((vector unsigned int) a, _VEC_0L); +} + +#endif + +FORCEINLINE bi32x4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmpeq(a, b); +} +FORCEINLINE bi32x4 CmpEqSIMD(const i32x4& a, const i32x4& b) +{ + return (bi32x4)vec_cmpeq(a, b); +} +FORCEINLINE bi32x4 CmpEqSIMD(const u32x4& a, const u32x4& b) +{ + return (bi32x4)vec_cmpeq(a, b); +} + +FORCEINLINE bi32x4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmpgt(a, b); +} +FORCEINLINE bi32x4 CmpGtSIMD(const i32x4& a, const i32x4& b) +{ + return (bi32x4)vec_cmpgt(a, b); +} +FORCEINLINE bi32x4 CmpGtSIMD(const u32x4& a, const u32x4& b) +{ + return (bi32x4)vec_cmpgt(a, b); +} + +FORCEINLINE bi32x4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmpge(a, b); +} + + +FORCEINLINE bi32x4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmplt(a, b); +} + +FORCEINLINE bi32x4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + return (bi32x4)vec_cmple(a, b); +} + + + +FORCEINLINE bi32x4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + i32x4 control; + control = vec_cmpb(a, b); + return (bi32x4)vec_cmpeq((u32x4)control, _VEC_ZERO); +} + +FORCEINLINE int CmpAnyLeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_le(a, b); +} + +FORCEINLINE int CmpAnyGeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_ge(a, b); +} + +FORCEINLINE int CmpAnyLtSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_lt(a, b); +} +FORCEINLINE int CmpAnyLtSIMD(const bi32x4& a, const i32x4& b) +{ + return vec_any_lt((i32x4)a, b); +} + +FORCEINLINE int CmpAnyGtSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_gt(a, b); +} + +FORCEINLINE int CmpAnyNeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_any_ne(a, b); +} +FORCEINLINE int CmpAnyNeSIMD(const bi32x4& a, const bi32x4& b) +{ + return vec_any_ne(a, b); +} +FORCEINLINE int CmpAnyNeSIMD(const bi32x4& a, const i32x4& b) +{ + return vec_any_ne(a, (bi32x4)b); +} + +FORCEINLINE int CmpAllLeSIMD(const fltx4& a, const fltx4& b) +{ + return vec_all_le(a, b); +} + +FORCEINLINE fltx4 MaskedAssign(const bi32x4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return vec_sel(OldValue, NewValue, ReplacementMask); +} + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return vec_sel(OldValue, NewValue, (const bi32x4)ReplacementMask); +} + +FORCEINLINE vector signed short MaskedAssign(const vector unsigned short& ReplacementMask, const vector signed short& NewValue, const vector signed short& OldValue) +{ + return vec_sel(OldValue, NewValue, ReplacementMask); +} + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_splats(flValue); +#else + float* pValue = &flValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + + fltx4 result; + + result = vec_ld(0, pValue); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, pValue)), 0); + + return result; +#endif +} + +FORCEINLINE fltx4 ReplicateX4(const float* pValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_splats(*pValue); +#else + Assert(pValue); + fltx4 result; + + result = vec_ld(0, pValue); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, pValue)), 0); + + return result; +#endif +} + +FORCEINLINE i32x4 ReplicateIX4(int nValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_splats(nValue); +#else + int* pValue = &nValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + i32x4 result; + + result = vec_ld(0, pValue); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, pValue)), 0); + + return result; +#endif +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + return sqrtf4(a); +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ +#if defined( _PS3 ) && !defined( SPU ) + fltx4 vRecipSquareRoot = vec_rsqrte(a); + i32x4 vOne = vec_splat_s32(1); + i32x4 vAllOnes = vec_splat_s32(-1); + i32x4 vShiftLeft24 = vec_splat_s32(-8); + fltx4 vZero = (fltx4)vec_splat_s32(0); + u32x4 vInputShifted = vec_sl((u32x4)a, (u32x4)vOne); + u32x4 vInfinityShifted = vec_sl((u32x4)vAllOnes, (u32x4)vShiftLeft24); + bi32x4 vEqualsZero = vec_vcmpeqfp(a, vZero); + bi32x4 vEqualsInfinity = vec_vcmpequw(vInputShifted, vInfinityShifted); + fltx4 vSquareRoot = vec_madd(a, vRecipSquareRoot, _VEC_ZEROF); + bi32x4 vResultMask = vec_vcmpequw((u32x4)vEqualsInfinity, (u32x4)vEqualsZero); + fltx4 vCorrectedSquareRoot = vec_sel(a, vSquareRoot, vResultMask); + + return vCorrectedSquareRoot; +#else + return SqrtSIMD(a); +#endif +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + return vec_rsqrte(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + fltx4 result; + vmathV4RsqrtPerElem((VmathVector4*)&result, (const VmathVector4*)&a); + + return result; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + return vec_re(a); +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + bi32x4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalEstSIMD(ret); + return ret; +} + + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + fltx4 result; + vmathV4RecipPerElem((VmathVector4*)&result, (const VmathVector4*)&a); + + return result; +} + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalSIMD(b), a); +} + +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalEstSIMD(b), a); +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + bi32x4 zero_mask = CmpEqSIMD(a, _VEC_ZEROF); + fltx4 a_safe = OrSIMD(a, AndSIMD(_VEC_EPSILONF, zero_mask)); + return ReciprocalSIMD(a_safe); + +} + + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + return exp2f4(toPower); +} + +FORCEINLINE fltx4 Exp2EstSIMD(const fltx4& f) +{ + return exp2f4fast(f); +} + + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + fltx4 result = vec_max(min, in); + return vec_min(max, result); +} + + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ +#if SN_IMPROVED_INTRINSICS + + fltx4 v0, v1; + + Assert(pSIMD); + + + v0 = (fltx4)vec_lvlx(0, (float*)pSIMD); + v1 = (fltx4)vec_lvrx(16, (float*)pSIMD); + return vec_or(v0, v1); + +#else + + fltx4 v0, v1; + vector unsigned char permMask; + + Assert(pSIMD); + + v0 = vec_ld(0, pSIMD); + permMask = vec_lvsl(0, pSIMD); + v1 = vec_ld(15, pSIMD); + + return vec_perm(v0, v1, permMask); + +#endif +} + +FORCEINLINE fltx4 LoadUnsignedByte4SIMD(unsigned char* pBytes) +{ + +#if SN_IMPROVED_INTRINSICS + + __vector unsigned char res_uc; + __vector unsigned short res_us; + + __vector unsigned char vZero8 = (__vector unsigned char)vec_splat_u8(0); + __vector unsigned short vZero16 = (__vector unsigned short)vec_splat_u16(0); + + res_uc = (__vector unsigned char)vec_lvlx(0, pBytes); + res_uc = vec_mergeh(vZero8, res_uc); + res_us = vec_mergeh(vZero16, (__vector unsigned short)res_uc); + return vec_ctf((__vector unsigned int)res_us, 0); + +#else + + vector unsigned char v0, v1; + vector bool char res_uc; + vector unsigned char permMask; + vector bool short res_us; + + vector bool char vZero8 = (vector bool char)vec_splat_u8(0); + vector bool short vZero16 = (vector bool short)vec_splat_u16(0); + + v0 = vec_ld(0, pBytes); + permMask = vec_lvsl(0, pBytes); + v1 = vec_ld(3, pBytes); + res_uc = (vector bool char)vec_perm(v0, v1, permMask); + res_uc = vec_mergeh(vZero8, res_uc); + res_us = vec_mergeh(vZero16, (vector bool short)res_uc); + return vec_ctf((vector unsigned int)res_us, 0); + +#endif + +} + +FORCEINLINE fltx4 LoadSignedByte4SIMD(signed char* pBytes) +{ + +#if SN_IMPROVED_INTRINSICS + + vector signed char res_uc; + vector signed short res_us; + vector signed int res_ui; + + res_uc = (vector signed char)vec_lvlx(0, pBytes); + res_us = vec_unpackh(res_uc); + res_ui = vec_unpackh(res_us); + return vec_ctf(res_ui, 0); + +#else + + vector signed char v0, v1, res_uc; + vector unsigned char permMask; + vector signed short res_us; + vector signed int res_ui; + + v0 = vec_ld(0, pBytes); + permMask = vec_lvsl(0, pBytes); + v1 = vec_ld(3, pBytes); + res_uc = vec_perm(v0, v1, permMask); + res_us = vec_unpackh(res_uc); + res_ui = vec_unpackh(res_us); + return vec_ctf(res_ui, 0); + +#endif + +} + + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + Assert(pSIMD); + + fltx4 v0 = vec_ld(0, (float*)(pSIMD)); + vector unsigned char permMask = vec_lvsl(0, (float*)(pSIMD)); + fltx4 v1 = vec_ld(11, (float*)(pSIMD)); + + return vec_perm(v0, v1, permMask); +} + + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + fltx4 v0 = vec_lde(0, const_cast(pFlt)); + vector unsigned char permMask = vec_lvsl(0, const_cast(pFlt)); + return vec_perm(v0, v0, permMask); +} + + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return vec_ld(0, (float*)pSIMD); +} + +#ifndef SPU +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + fltx4 out; + out = vec_ld(0, pSIMD.Base()); + + return (fltx4)vec_and((u32x4)out, _VEC_CLEAR_WMASK); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned* RESTRICT pSIMD) +{ + fltx4 out; + out = vec_ld(0, pSIMD->Base()); + + return (fltx4)vec_and((u32x4)out, _VEC_CLEAR_WMASK); +} + + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + vec_st(a, 0, pSIMD->Base()); +} +#endif + +FORCEINLINE void StoreAlignedSIMD(float* pSIMD, const fltx4& a) +{ + vec_st(a, 0, pSIMD); +} + +FORCEINLINE void StoreUnalignedSIMD(float* pSIMD, const fltx4& a) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + vec_stvlx(a, 0, pSIMD); + vec_stvrx(a, 16, pSIMD); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + pSIMD[0] = a_union.m128_f32[0]; + pSIMD[1] = a_union.m128_f32[1]; + pSIMD[2] = a_union.m128_f32[2]; + pSIMD[3] = a_union.m128_f32[3]; +#endif + +} + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + pSIMD[0] = a_union.m128_f32[0]; + pSIMD[1] = a_union.m128_f32[1]; + pSIMD[2] = a_union.m128_f32[2]; +}; + + + +#ifndef SPU + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d); +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ +#if USING_POINTLESSLY_SLOW_SONY_CODE + return vmathV4MakeFromElems_V(x, y, z, w).vec128; +#else + fltx4 vx = vec_lvlx(0, &x); + fltx4 vy = vec_lvlx(0, &y); + fltx4 vz = vec_lvlx(0, &z); + fltx4 vw = vec_lvlx(0, &w); + return Compress4SIMD(vx, vy, vz, vw); +#endif +} + + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} +#endif + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ + i32x4 asInt = vec_cts(vSrc, 0); + vec_st(asInt, 0, pDest->Base()); +} + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ + fltx4 p0, p1, p2, p3; + + p0 = vec_mergeh(x, z); + p1 = vec_mergeh(y, w); + p2 = vec_mergel(x, z); + p3 = vec_mergel(y, w); + + x = vec_mergeh(p0, p1); + y = vec_mergel(p0, p1); + z = vec_mergeh(p2, p3); + w = vec_mergel(p2, p3); +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return _VEC_ZEROF; +} +FORCEINLINE i32x4 LoadZeroISIMD(void) +{ + return vec_splat_s32(0); +} + + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return _VEC_ONEF; +} +FORCEINLINE i32x4 LoadOneISIMD(void) +{ + return vec_splat_s32(1); +} + +FORCEINLINE fltx4 SplatXSIMD(fltx4 a) +{ + return vec_splat(a, 0); +} +FORCEINLINE fltx4 SplatYSIMD(fltx4 a) +{ + return vec_splat(a, 1); +} +FORCEINLINE fltx4 SplatZSIMD(fltx4 a) +{ + return vec_splat(a, 2); +} +FORCEINLINE fltx4 SplatWSIMD(fltx4 a) +{ + return vec_splat(a, 3); +} + +FORCEINLINE bi32x4 SplatXSIMD(bi32x4 a) +{ + return vec_splat(a, 0); +} +FORCEINLINE bi32x4 SplatYSIMD(bi32x4 a) +{ + return vec_splat(a, 1); +} +FORCEINLINE bi32x4 SplatZSIMD(bi32x4 a) +{ + return vec_splat(a, 2); +} +FORCEINLINE bi32x4 SplatWSIMD(bi32x4 a) +{ + return vec_splat(a, 3); +} + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + return vec_sel(a, x, _VEC_COMPONENT_MASK_0); +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + return vec_sel(a, y, _VEC_COMPONENT_MASK_1); +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + return vec_sel(a, z, _VEC_COMPONENT_MASK_2); +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + return vec_sel(a, w, _VEC_COMPONENT_MASK_3); +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ +#if SN_IMPROVED_INTRINSICS + return vec_insert(flValue, a, nComponent); +#else + fltx4_union a_union; + a_union.vmxf = vec_ld(0, &a); + a_union.m128_f32[nComponent] = flValue; + return a_union.vmxf; +#endif +} + +FORCEINLINE float GetComponentSIMD(const fltx4& a, int nComponent) +{ +#if SN_IMPROVED_INTRINSICS + return vec_extract(a, nComponent); +#else + fltx4_union a_union; + a_union.vmxf = vec_ld(0, &a); + return a_union.m128_f32[nComponent]; +#endif +} + + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + return vec_sld(a, a, 4); +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + return vec_sld(a, a, 8); +} + +FORCEINLINE fltx4 RotateRight(const fltx4& a) +{ + return vec_sld(a, a, 12); +} + +FORCEINLINE fltx4 RotateRight2(const fltx4& a) +{ + return vec_sld(a, a, 8); +} + +template < uint nBits, typename T > +FORCEINLINE T ShiftLeftByBits(const T& a) +{ + if (nBits >= 128) + { + return (T)LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + T t = vec_sld(a, ((T)LoadZeroSIMD()), (nBits >> 3)); + return ShiftLeftByBits< (nBits & 0x7) >(t); + } + else + { + vector unsigned int shifter = (vector unsigned int) (vec_splat_s8(((signed char)(nBits & 0x7)))); + return (T)vec_sll((vector signed int) a, shifter); + } +} + +template < uint nBits, typename T > +FORCEINLINE T ShiftRightByBits(const T& a) +{ + if (nBits >= 128) + { + return (T)LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + T t = vec_sld(((T)LoadZeroSIMD()), a, 16 - (nBits >> 3)); + return ShiftRightByBits< (nBits & 0x7) >(t); + } + else + { + vector unsigned int shifter = (vector unsigned int) (vec_splat_s8(((signed char)(nBits & 0x7)))); + return (T)vec_srl((vector unsigned int) a, shifter); + } +} + + + + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + fltx4 result; + fltx4 x = vec_splat(a, 0); + fltx4 y = vec_splat(a, 1); + fltx4 z = vec_splat(a, 2); + + if (vec_any_nan(a)) + { + x = vec_all_nan(x) ? _VEC_FLTMAX : x; + y = vec_all_nan(y) ? _VEC_FLTMAX : y; + z = vec_all_nan(z) ? _VEC_FLTMAX : z; + } + + result = vec_min(y, x); + result = vec_min(z, result); + + return result; + +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + fltx4 result; + fltx4 x = vec_splat(a, 0); + fltx4 y = vec_splat(a, 1); + fltx4 z = vec_splat(a, 2); + + if (vec_any_nan(a)) + { + x = vec_all_nan(x) ? _VEC_FLTMIN : x; + y = vec_all_nan(y) ? _VEC_FLTMIN : y; + z = vec_all_nan(z) ? _VEC_FLTMIN : z; + } + + result = vec_max(y, x); + result = vec_max(z, result); + + return result; +} + + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const int32* RESTRICT pSIMD) +{ + return vec_ld(0, const_cast(pSIMD)); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const int32* RESTRICT pSIMD) +{ + i32x4 v0, v1; + vector unsigned char permMask; + + Assert(pSIMD); + + v0 = vec_ld(0, const_cast(pSIMD)); + permMask = vec_lvsl(0, const_cast(pSIMD)); + v1 = vec_ld(15, const_cast(pSIMD)); + + return vec_perm(v0, v1, permMask); + +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const i32x4& a) +{ + vec_st(a, 0, pSIMD); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + vec_st((i32x4)a, 0, pSIMD); +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const i32x4& a) +{ + vec_st(a, 0, pSIMD.Base()); +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* pSIMD, const i32x4& a) +{ +#if SN_IMPROVED_INTRINSICS + + vec_stvlx(a, 0, pSIMD); + vec_stvrx(a, 16, pSIMD); + +#else + + fltx4_union tmp; + vec_st(a, 0, &tmp.vmxi); + + pSIMD[0] = tmp.m128_u32[0]; + pSIMD[1] = tmp.m128_u32[1]; + pSIMD[2] = tmp.m128_u32[2]; + pSIMD[3] = tmp.m128_u32[3]; + +#endif +} + +FORCEINLINE fltx4 CompressSIMD(fltx4 const& a, fltx4 const& b) +{ + const int32 ALIGN16 n4shuffleACXZ[4] ALIGN16_POST = { 0x00010203, 0x08090A0B, 0x10111213, 0x18191A1B }; + return vec_perm(a, b, (vec_uchar16)LoadAlignedIntSIMD(n4shuffleACXZ)); +} + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d) +{ + fltx4 ab = vec_mergeh(a, b); + fltx4 cd = vec_mergeh(c, d); + static const int32 ALIGN16 shuffleABXY[4] ALIGN16_POST = { 0x00010203, 0x04050607, 0x10111213, 0x14151617 }; + + return vec_perm(ab, cd, (vec_uchar16)LoadAlignedIntSIMD(shuffleABXY)); +} + + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return vec_ctf(vSrcA, 0); +} + + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return vec_ctf(vSrcA, 0); +} + +#define UnsignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (vec_ctf( (vSrcA), (uImmed) )) + +#define SignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (vec_ctf( (vSrcA), (uImmed) )) + +#define IntSetImmediateSIMD(x) (vec_splat_s32(x)) + + +FORCEINLINE u32x4 IntShiftLeftWordSIMD(u32x4 vSrcA, u32x4 vSrcB) +{ + return vec_sl(vSrcA, vSrcB); +} + + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract(a, idx)); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + return a_union.m128_f32[idx]; +#endif +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE uint32 SubInt(const u32x4& a, int idx) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract(a, idx)); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxui); + return a_union.m128_u32[idx]; +#endif +} + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract((u32x4)a, idx)); +#else + fltx4_union a_union; + vec_st(a, 0, &a_union.vmxf); + return a_union.m128_u32[idx]; +#endif +} + +FORCEINLINE uint32& SubInt(u32x4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE uint32 SubFloatConvertToInt(const fltx4& a, int idx) +{ + +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + return(vec_extract(vec_ctu(a, 0), idx)); +#else + u32x4 t = vec_ctu(a, 0); + return SubInt(t, idx); +#endif + +} + +template< typename T, typename U > +FORCEINLINE T PermuteVMX(T a, T b, U swizzleMask) +{ + return vec_perm(a, b, (vec_uchar16)swizzleMask); +} + + +#if !defined(__SPU__) +#define fsel __fsel +#endif + +inline bool IsVector3LessThan(const fltx4& v1, const fltx4& v2) +{ + return vec_any_lt(v1, v2); +} + +inline bool IsVector3GreaterOrEqual(const fltx4& v1, const fltx4& v2) +{ + return !IsVector3LessThan(v1, v2); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = 1.0 / sqrt(SubFloat(a, 0) != 0.0f ? SubFloat(a, 0) : FLT_EPSILON); + SubFloat(retVal, 1) = 1.0 / sqrt(SubFloat(a, 1) != 0.0f ? SubFloat(a, 1) : FLT_EPSILON); + SubFloat(retVal, 2) = 1.0 / sqrt(SubFloat(a, 2) != 0.0f ? SubFloat(a, 2) : FLT_EPSILON); + SubFloat(retVal, 3) = 1.0 / sqrt(SubFloat(a, 3) != 0.0f ? SubFloat(a, 3) : FLT_EPSILON); + return retVal; +} + +FORCEINLINE fltx4 FloorSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = floor(SubFloat(a, 0)); + SubFloat(retVal, 1) = floor(SubFloat(a, 1)); + SubFloat(retVal, 2) = floor(SubFloat(a, 2)); + SubFloat(retVal, 3) = floor(SubFloat(a, 3)); + return retVal; +} + +#elif ( defined( _X360 ) ) + +inline bool IsVector3LessThan(const fltx4& v1, const fltx4& v2) +{ + return !XMVector3GreaterOrEqual(v1, v2); +} + +inline BOOL IsVector3GreaterOrEqual(const fltx4& v1, const fltx4& v2) +{ + return XMVector3GreaterOrEqual(v1, v2); +} + + +FORCEINLINE float& FloatSIMD(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE unsigned int& UIntSIMD(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + return __vaddfp(a, b); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + return __vsubfp(a, b); +} + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + return __vmulfp(a, b); +} + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return __vmaddfp(a, b, c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return __vnmsubfp(a, b, c); +}; + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + return __vmsum3fp(a, b); +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + return __vmsum4fp(a, b); +} + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + return XMVectorSin(radians); +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + XMVectorSinCos(&sine, &cosine, radians); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + XMVectorSinCos(&sine, &cosine, radians); +} + +FORCEINLINE void CosSIMD(fltx4& cosine, const fltx4& radians) +{ + cosine = XMVectorCos(radians); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + return XMVectorASin(sine); +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + return XMVectorACos(cs); +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + return XMVectorATan2(a, b); +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + return __vmaxfp(a, b); +} + +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + return __vminfp(a, b); +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + return __vand(a, b); +} + +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + return __vandc(b, a); +} + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + return __vxor(a, b); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + return __vor(a, b); +} + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + return XMVectorNegate(a); +} + +FORCEINLINE bool IsAllZeros(const fltx4& a) +{ + unsigned int equalFlags = 0; + __vcmpeqfpR(a, Four_Zeros, &equalFlags); + return XMComparisonAllTrue(equalFlags); +} + +FORCEINLINE bool IsAnyZeros(const fltx4& a) +{ + unsigned int conditionregister; + XMVectorEqualR(&conditionregister, a, XMVectorZero()); + return XMComparisonAnyTrue(conditionregister); +} + +FORCEINLINE bool IsAnyXYZZero(const fltx4& a) +{ + fltx4 temp = __vrlimi(a, a, 1, 1); + unsigned int conditionregister; + XMVectorEqualR(&conditionregister, temp, XMVectorZero()); + return XMComparisonAnyTrue(conditionregister); +} + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterR(&cr, a, b); + return XMComparisonAllTrue(cr); +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterOrEqualR(&cr, a, b); + return XMComparisonAllTrue(cr); +} + +FORCEINLINE bool IsAnyGreaterThan(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterR(&cr, a, b); + return XMComparisonAnyTrue(cr); +} + +FORCEINLINE bool IsAnyGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorGreaterOrEqualR(&cr, a, b); + return XMComparisonAnyTrue(cr); +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + unsigned int cr; + XMVectorEqualR(&cr, a, b); + return XMComparisonAllTrue(cr); +} + + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + int nRet = 0; + + const fltx4_union& a_union = (const fltx4_union&)a; + nRet |= (a_union.m128_u32[0] & 0x80000000) >> 31; + nRet |= (a_union.m128_u32[1] & 0x80000000) >> 30; + nRet |= (a_union.m128_u32[2] & 0x80000000) >> 29; + nRet |= (a_union.m128_u32[3] & 0x80000000) >> 28; + + return nRet; +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + return __vrlimi(a, __vzero(), 1, 0); +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + unsigned int equalFlags = 0; + fltx4 signMask = __vspltisw(-1); + signMask = __vslw(signMask, signMask); + __vcmpequwR(Four_Zeros, __vand(signMask, a), &equalFlags); + return !XMComparisonAllTrue(equalFlags); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + unsigned int equalFlags = 0; + __vcmpequwR(Four_Zeros, a, &equalFlags); + return XMComparisonAnyFalse(equalFlags); +} + +FORCEINLINE fltx4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpeqfp(a, b); +} + + +FORCEINLINE fltx4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgtfp(a, b); +} + +FORCEINLINE fltx4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgefp(a, b); +} + +FORCEINLINE fltx4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgtfp(b, a); +} + +FORCEINLINE fltx4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + return __vcmpgefp(b, a); +} + +FORCEINLINE fltx4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + return XMVectorInBounds(a, b); +} + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return __vsel(OldValue, NewValue, ReplacementMask); +} + + +template< typename T, typename U > +FORCEINLINE T PermuteVMX(T a, T b, U swizzleMask) +{ + return __vperm(a, b, swizzleMask); +} + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ + float* pValue = &flValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + return __vspltw(__lvlx(pValue, 0), 0); +} + +FORCEINLINE fltx4 ReplicateX4(const float* pValue) +{ + Assert(pValue); + return __vspltw(__lvlx(pValue, 0), 0); +} + +FORCEINLINE fltx4 ReplicateIX4(int nValue) +{ + int* pValue = &nValue; + Assert(pValue); + Assert(((unsigned int)pValue & 3) == 0); + return __vspltw(__lvlx(pValue, 0), 0); +} + +FORCEINLINE fltx4 CeilSIMD(const fltx4& a) +{ + return __vrfip(a); +} + +FORCEINLINE fltx4 RoundSIMD(const fltx4& a) +{ + return __vrfin(a); +} + +FORCEINLINE fltx4 FloorSIMD(const fltx4& a) +{ + return __vrfim(a); +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ + return XMVectorSqrtEst(a); +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + return XMVectorSqrt(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + return __vrsqrtefp(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 a_safe = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + return ReciprocalSqrtEstSIMD(a_safe); +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + return XMVectorReciprocalSqrt(a); +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + return __vrefp(a); +} + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + return XMVectorReciprocal(a); +} + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalSIMD(b), a); +} + +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalEstSIMD(b), a); +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 a_safe = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + return ReciprocalEstSIMD(a_safe); +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 a_safe = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + return ReciprocalSIMD(a_safe); + +} + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + return XMVectorExp(toPower); +} + +FORCEINLINE fltx4 Exp2EstSIMD(const fltx4& f) +{ + return XMVectorExpEst(f); +} + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + return XMVectorClamp(in, min, max); +} + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ + return XMLoadVector4(pSIMD); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + return XMLoadVector3(pSIMD); +} + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + return __lvlx(pFlt, 0); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return *(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + fltx4 out = XMLoadVector3A(pSIMD.Base()); + return __vrlimi(out, __vzero(), 1, 0); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned* RESTRICT pSIMD) +{ + fltx4 out = XMLoadVector3A(pSIMD); + return __vrlimi(out, __vzero(), 1, 0); +} + +FORCEINLINE void StoreAlignedSIMD(float* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreUnalignedSIMD(float* pSIMD, const fltx4& a) +{ + XMStoreVector4(pSIMD, a); +} + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + XMStoreVector3(pSIMD, a); +} + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + XMStoreVector3A(pSIMD->Base(), a); +} + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + b = __vrlimi(b, b, 15, 1); + c = __vrlimi(c, c, 15, 2); + + a = __vrlimi(a, b, 1, 0); + b = __vrlimi(b, c, 2 | 1, 0); + c = __vrlimi(c, d, 4 | 2 | 1, 3); + + float* RESTRICT pOut = pDestination->Base(); + StoreUnalignedSIMD(pOut + 0, a); + StoreUnalignedSIMD(pOut + 4, b); + StoreUnalignedSIMD(pOut + 8, c); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + b = __vrlimi(b, b, 15, 1); + c = __vrlimi(c, c, 15, 2); + + a = __vrlimi(a, b, 1, 0); + b = __vrlimi(b, c, 2 | 1, 0); + c = __vrlimi(c, d, 4 | 2 | 1, 3); + + float* RESTRICT pOut = pDestination->Base(); + StoreAlignedSIMD(pOut + 0, a); + StoreAlignedSIMD(pOut + 4, b); + StoreAlignedSIMD(pOut + 8, c); +} + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ + fltx4 asInt = __vctsxs(vSrc, 0); + XMStoreVector4A(pDest->Base(), asInt); +} + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ + XMMATRIX xyzwMatrix = _XMMATRIX(x, y, z, w); + xyzwMatrix = XMMatrixTranspose(xyzwMatrix); + x = xyzwMatrix.r[0]; + y = xyzwMatrix.r[1]; + z = xyzwMatrix.r[2]; + w = xyzwMatrix.r[3]; +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return XMVectorZero(); +} + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return XMVectorSplatOne(); +} + +FORCEINLINE fltx4 SplatXSIMD(fltx4 a) +{ + return XMVectorSplatX(a); +} + +FORCEINLINE fltx4 SplatYSIMD(fltx4 a) +{ + return XMVectorSplatY(a); +} + +FORCEINLINE fltx4 SplatZSIMD(fltx4 a) +{ + return XMVectorSplatZ(a); +} + +FORCEINLINE fltx4 SplatWSIMD(fltx4 a) +{ + return XMVectorSplatW(a); +} + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 result = __vrlimi(a, x, 8, 0); + return result; +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 result = __vrlimi(a, y, 4, 0); + return result; +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 result = __vrlimi(a, z, 2, 0); + return result; +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + fltx4 result = __vrlimi(a, w, 1, 0); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ + static int s_nVrlimiMask[4] = { 8, 4, 2, 1 }; + fltx4 val = ReplicateX4(flValue); + fltx4 result = __vrlimi(a, val, s_nVrlimiMask[nComponent], 0); + return result; +} + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 1); +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 2); +} + +FORCEINLINE fltx4 RotateRight(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 3); +} + +FORCEINLINE fltx4 RotateRight2(const fltx4& a) +{ + fltx4 compareOne = a; + return __vrlimi(compareOne, a, 8 | 4 | 2 | 1, 2); +} + + +template < uint nBits > +FORCEINLINE fltx4 ShiftLeftByBits(const fltx4& a) +{ + if (nBits >= 128) + { + return LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + fltx4 t = __vsldoi(a, (LoadZeroSIMD()), (nBits >> 3)); + return ShiftLeftByBits< (nBits & 0x7) >(t); + } + else + { + u32x4 shifter = u32x4(__vspltisb(((signed char)(nBits & 0x7)))); + return __vsl(a, shifter); + } +} + +template < uint nBits > +FORCEINLINE fltx4 ShiftRightByBits(const fltx4& a) +{ + if (nBits >= 128) + { + return LoadZeroSIMD(); + } + else if (nBits == 0) + { + return a; + } + else if ((nBits > 7)) + { + fltx4 t = __vsldoi((LoadZeroSIMD()), a, 16 - (nBits >> 3)); + return ShiftRightByBits< (nBits & 0x7) >(t); + } + else + { + u32x4 shifter = u32x4(__vspltisb(((signed char)(nBits & 0x7)))); + return __vsr(a, shifter); + } +} + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + fltx4 compareOne = a; + compareOne = __vrlimi(compareOne, a, 8 | 4, 1); + fltx4 retval = MinSIMD(a, compareOne); + compareOne = __vrlimi(compareOne, a, 8, 2); + retval = MinSIMD(retval, compareOne); + return SplatXSIMD(retval); +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + fltx4 compareOne = a; + compareOne = __vrlimi(compareOne, a, 8 | 4, 1); + fltx4 retval = MaxSIMD(a, compareOne); + compareOne = __vrlimi(compareOne, a, 8, 2); + retval = MaxSIMD(retval, compareOne); + return SplatXSIMD(retval); +} + + +void TransformManyPointsBy(VectorAligned* RESTRICT pVectors, unsigned int numVectors, FLTX4 mRow1, FLTX4 mRow2, FLTX4 mRow3); + +FORCEINLINE void TransformManyPointsBy(VectorAligned* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& pMatrix) +{ + return TransformManyPointsBy(pVectors, numVectors, + LoadUnalignedSIMD(pMatrix[0]), LoadUnalignedSIMD(pMatrix[1]), LoadUnalignedSIMD(pMatrix[2])); +} + +FORCEINLINE void TransformManyPointsByA(VectorAligned* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& pMatrix) +{ + return TransformManyPointsBy(pVectors, numVectors, + LoadAlignedSIMD(pMatrix[0]), LoadAlignedSIMD(pMatrix[1]), LoadAlignedSIMD(pMatrix[2])); +} + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void* RESTRICT pSIMD) +{ + return XMLoadVector4A(pSIMD); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void* RESTRICT pSIMD) +{ + return XMLoadVector4(pSIMD); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD)) = a; +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const fltx4& a) +{ + *(reinterpret_cast (pSIMD.Base())) = a; +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* pSIMD, const fltx4& a) +{ + XMStoreVector4(pSIMD, a); +} + +FORCEINLINE fltx4 LoadAndConvertUint16SIMD(const uint16* pInts) +{ + return XMLoadUShort4(reinterpret_cast(pInts)); +} + +FORCEINLINE fltx4 CompressSIMD(fltx4 const& a, fltx4 const& b) +{ + return XMVectorPermute(a, b, XMVectorPermuteControl(0, 2, 4, 6)); +} + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d) +{ + fltx4 abcd = __vrlimi(a, b, 4, 3); + abcd = __vrlimi(abcd, c, 2, 2); + abcd = __vrlimi(abcd, d, 1, 1); + + return abcd; +} + + +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ + fltx4 vx = __lvlx(&x, 0); + fltx4 vy = __lvlx(&y, 0); + fltx4 vz = __lvlx(&z, 0); + fltx4 vw = __lvlx(&w, 0); + return Compress4SIMD(vx, vy, vz, vw); +} + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return __vcfux(vSrcA, 0); +} + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return __vcfsx(vSrcA, 0); +} + +#define UnsignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (__vcfux( (vSrcA), (uImmed) )) + +#define SignedFixedIntConvertToFltSIMD(vSrcA, uImmed) (__vcfsx( (vSrcA), (uImmed) )) + +#define IntSetImmediateSIMD(x) (__vspltisw(x)) + +FORCEINLINE fltx4 IntShiftLeftWordSIMD(fltx4 vSrcA, fltx4 vSrcB) +{ + return __vslw(vSrcA, vSrcB); +} + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ + const fltx4_union& a_union = (const fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_f32[idx]; +} + +FORCEINLINE uint32 SubFloatConvertToInt(const fltx4& a, int idx) +{ + fltx4 t = __vctuxs(a, 0); + const fltx4_union& a_union = (const fltx4_union&)t; + return a_union.m128_u32[idx]; +} + + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ + const fltx4_union& a_union = (const fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +FORCEINLINE uint32& SubInt(fltx4& a, int idx) +{ + fltx4_union& a_union = (fltx4_union&)a; + return a_union.m128_u32[idx]; +} + +#else + +FORCEINLINE void StoreAlignedSIMD(float* RESTRICT pSIMD, const fltx4& a) +{ + _mm_store_ps(pSIMD, a); +} + +FORCEINLINE void StoreAlignedSIMD(short* RESTRICT pSIMD, const shortx8& a) +{ + _mm_store_si128((shortx8*)pSIMD, a); +} +FORCEINLINE void StoreUnalignedSIMD(float* RESTRICT pSIMD, const fltx4& a) +{ + _mm_storeu_ps(pSIMD, a); +} + +FORCEINLINE void StoreUnalignedSIMD(short* RESTRICT pSIMD, const shortx8& a) +{ + _mm_storeu_si128((shortx8*)pSIMD, a); +} + +FORCEINLINE void StoreUnalignedFloat(float* pSingleFloat, const fltx4& a) +{ + _mm_store_ss(pSingleFloat, a); +} + + +FORCEINLINE fltx4 RotateLeft(const fltx4& a); +FORCEINLINE fltx4 RotateLeft2(const fltx4& a); + +FORCEINLINE void StoreUnaligned3SIMD(float* pSIMD, const fltx4& a) +{ + _mm_store_ss(pSIMD, a); + _mm_store_ss(pSIMD + 1, RotateLeft(a)); + _mm_store_ss(pSIMD + 2, RotateLeft2(a)); +} + + +FORCEINLINE void StoreAligned3SIMD(VectorAligned* RESTRICT pSIMD, const fltx4& a) +{ + StoreAlignedSIMD(pSIMD->Base(), a); +} + +FORCEINLINE void StoreFourUnalignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE void StoreFourAlignedVector3SIMD(fltx4 a, fltx4 b, fltx4 c, FLTX4 d, + Vector* const pDestination) +{ + StoreUnaligned3SIMD(pDestination->Base(), a); + StoreUnaligned3SIMD((pDestination + 1)->Base(), b); + StoreUnaligned3SIMD((pDestination + 2)->Base(), c); + StoreUnaligned3SIMD((pDestination + 3)->Base(), d); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const void* pSIMD) +{ + return _mm_load_ps(reinterpret_cast (pSIMD)); +} + +FORCEINLINE shortx8 LoadAlignedShortSIMD(const void* pSIMD) +{ + return _mm_load_si128(reinterpret_cast (pSIMD)); +} + +FORCEINLINE shortx8 LoadUnalignedShortSIMD(const void* pSIMD) +{ + return _mm_loadu_si128(reinterpret_cast (pSIMD)); +} + +FORCEINLINE fltx4 AndSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_and_ps(a, b); +} + +FORCEINLINE fltx4 AndNotSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_andnot_ps(a, b); +} + +FORCEINLINE fltx4 XorSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_xor_ps(a, b); +} + +FORCEINLINE fltx4 OrSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_or_ps(a, b); +} + +FORCEINLINE fltx4 SetWToZeroSIMD(const fltx4& a) +{ + return AndSIMD(a, LoadAlignedSIMD(g_SIMD_clear_wmask)); +} + +FORCEINLINE fltx4 LoadAlignedSIMD(const VectorAligned& pSIMD) +{ + return SetWToZeroSIMD(LoadAlignedSIMD(pSIMD.Base())); +} + +FORCEINLINE fltx4 LoadUnalignedSIMD(const void* pSIMD) +{ + return _mm_loadu_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE fltx4 LoadUnaligned3SIMD(const void* pSIMD) +{ + return _mm_loadu_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE fltx4 LoadUnalignedFloatSIMD(const float* pFlt) +{ + return _mm_load_ss(pFlt); +} + +FORCEINLINE fltx4 ReplicateIX4(int i) +{ + fltx4 value = _mm_set_ss(*((float*)&i));; + return _mm_shuffle_ps(value, value, 0); +} + + +FORCEINLINE fltx4 ReplicateX4(float flValue) +{ + __m128 value = _mm_set_ss(flValue); + return _mm_shuffle_ps(value, value, 0); +} + +FORCEINLINE fltx4 ReplicateX4(const float* flValue) +{ + __m128 value = _mm_set_ss(*flValue); + return _mm_shuffle_ps(value, value, 0); +} + +FORCEINLINE float SubFloat(const fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_f32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE float& SubFloat(fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_f32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE uint32 SubFloatConvertToInt(const fltx4& a, int idx) +{ + return (uint32)SubFloat(a, idx); +} + +FORCEINLINE uint32 SubInt(const fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_u32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE uint32& SubInt(fltx4& a, int idx) +{ +#ifndef POSIX + return a.m128_u32[idx]; +#else + return (reinterpret_cast(&a))[idx]; +#endif +} + +FORCEINLINE fltx4 LoadZeroSIMD(void) +{ + return Four_Zeros; +} + +FORCEINLINE fltx4 LoadOneSIMD(void) +{ + return Four_Ones; +} + +FORCEINLINE fltx4 MaskedAssign(const fltx4& ReplacementMask, const fltx4& NewValue, const fltx4& OldValue) +{ + return OrSIMD( + AndSIMD(ReplacementMask, NewValue), + AndNotSIMD(ReplacementMask, OldValue)); +} + +#define MM_SHUFFLE_REV(a,b,c,d) _MM_SHUFFLE(d,c,b,a) + +FORCEINLINE fltx4 SplatXSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 0, 0, 0)); +} + +FORCEINLINE fltx4 SplatYSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(1, 1, 1, 1)); +} + +FORCEINLINE fltx4 SplatZSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 2, 2, 2)); +} + +FORCEINLINE fltx4 SplatWSIMD(fltx4 const& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(3, 3, 3, 3)); +} + +FORCEINLINE fltx4 ShuffleXXYY(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 0, 1, 1)); +} + +FORCEINLINE fltx4 ShuffleXYXY(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 1, 0, 1)); +} + +FORCEINLINE fltx4 ShuffleZZWW(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 2, 3, 3)); +} + + + + +FORCEINLINE fltx4 SetXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[0]), x, a); + return result; +} + +FORCEINLINE fltx4 SetYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[1]), y, a); + return result; +} + +FORCEINLINE fltx4 SetZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[2]), z, a); + return result; +} + +FORCEINLINE fltx4 SetWSIMD(const fltx4& a, const fltx4& w) +{ + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[3]), w, a); + return result; +} + +FORCEINLINE fltx4 SetComponentSIMD(const fltx4& a, int nComponent, float flValue) +{ + fltx4 val = ReplicateX4(flValue); + fltx4 result = MaskedAssign(LoadAlignedSIMD(g_SIMD_ComponentMask[nComponent]), val, a); + return result; +} + +FORCEINLINE fltx4 RotateLeft(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(1, 2, 3, 0)); +} + +FORCEINLINE fltx4 RotateLeft2(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 3, 0, 1)); +} + +FORCEINLINE fltx4 RotateRight(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(3, 0, 1, 2)); +} + +FORCEINLINE fltx4 RotateRight2(const fltx4& a) +{ + return _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 3, 0, 1)); +} + +FORCEINLINE fltx4 AddSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_add_ps(a, b); +} + +FORCEINLINE fltx4 SubSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_sub_ps(a, b); +}; + +FORCEINLINE fltx4 MulSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_mul_ps(a, b); +}; + +FORCEINLINE fltx4 DivSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_div_ps(a, b); +}; + +fltx4 ReciprocalEstSIMD(const fltx4& a); +FORCEINLINE fltx4 DivEstSIMD(const fltx4& a, const fltx4& b) +{ + return MulSIMD(ReciprocalEstSIMD(b), a); +}; + +FORCEINLINE fltx4 MaddSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return AddSIMD(MulSIMD(a, b), c); +} + +FORCEINLINE fltx4 MsubSIMD(const fltx4& a, const fltx4& b, const fltx4& c) +{ + return SubSIMD(c, MulSIMD(a, b)); +}; + +FORCEINLINE fltx4 Dot3SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 m = MulSIMD(a, b); + return AddSIMD(AddSIMD(SplatXSIMD(m), SplatYSIMD(m)), SplatZSIMD(m)); +} + +FORCEINLINE fltx4 Dot4SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 fl4Product = MulSIMD(a, b); + fltx4 fl4YXWZ = _mm_shuffle_ps(fl4Product, fl4Product, MM_SHUFFLE_REV(1, 0, 3, 2)); + fltx4 fl4UUVV = AddSIMD(fl4Product, fl4YXWZ); + fltx4 fl4VVUU = RotateLeft2(fl4UUVV); + return AddSIMD(fl4UUVV, fl4VVUU); +} + +FORCEINLINE fltx4 SinSIMD(const fltx4& radians) +{ + fltx4 result; + SubFloat(result, 0) = sin(SubFloat(radians, 0)); + SubFloat(result, 1) = sin(SubFloat(radians, 1)); + SubFloat(result, 2) = sin(SubFloat(radians, 2)); + SubFloat(result, 3) = sin(SubFloat(radians, 3)); + return result; +} + +FORCEINLINE void SinCos3SIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); +} + +FORCEINLINE void SinCosSIMD(fltx4& sine, fltx4& cosine, const fltx4& radians) +{ + SinCos(SubFloat(radians, 0), &SubFloat(sine, 0), &SubFloat(cosine, 0)); + SinCos(SubFloat(radians, 1), &SubFloat(sine, 1), &SubFloat(cosine, 1)); + SinCos(SubFloat(radians, 2), &SubFloat(sine, 2), &SubFloat(cosine, 2)); + SinCos(SubFloat(radians, 3), &SubFloat(sine, 3), &SubFloat(cosine, 3)); +} + +FORCEINLINE fltx4 ArcSinSIMD(const fltx4& sine) +{ + fltx4 result; + SubFloat(result, 0) = asin(SubFloat(sine, 0)); + SubFloat(result, 1) = asin(SubFloat(sine, 1)); + SubFloat(result, 2) = asin(SubFloat(sine, 2)); + SubFloat(result, 3) = asin(SubFloat(sine, 3)); + return result; +} + +FORCEINLINE fltx4 ArcCosSIMD(const fltx4& cs) +{ + fltx4 result; + SubFloat(result, 0) = acos(SubFloat(cs, 0)); + SubFloat(result, 1) = acos(SubFloat(cs, 1)); + SubFloat(result, 2) = acos(SubFloat(cs, 2)); + SubFloat(result, 3) = acos(SubFloat(cs, 3)); + return result; +} + +FORCEINLINE fltx4 ArcTan2SIMD(const fltx4& a, const fltx4& b) +{ + fltx4 result; + SubFloat(result, 0) = atan2(SubFloat(a, 0), SubFloat(b, 0)); + SubFloat(result, 1) = atan2(SubFloat(a, 1), SubFloat(b, 1)); + SubFloat(result, 2) = atan2(SubFloat(a, 2), SubFloat(b, 2)); + SubFloat(result, 3) = atan2(SubFloat(a, 3), SubFloat(b, 3)); + return result; +} + +FORCEINLINE fltx4 NegSIMD(const fltx4& a) +{ + return SubSIMD(LoadZeroSIMD(), a); +} + +FORCEINLINE int TestSignSIMD(const fltx4& a) +{ + return _mm_movemask_ps(a); +} + +FORCEINLINE bool IsAnyNegative(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE bool IsAnyTrue(const fltx4& a) +{ + return (0 != TestSignSIMD(a)); +} + +FORCEINLINE fltx4 CmpEqSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmpeq_ps(a, b); +} + +FORCEINLINE fltx4 CmpGtSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmpgt_ps(a, b); +} + +FORCEINLINE fltx4 CmpGeSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmpge_ps(a, b); +} + +FORCEINLINE fltx4 CmpLtSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmplt_ps(a, b); +} + +FORCEINLINE fltx4 CmpLeSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_cmple_ps(a, b); +} + +FORCEINLINE bool IsAllGreaterThan(const fltx4& a, const fltx4& b) +{ + return TestSignSIMD(CmpLeSIMD(a, b)) == 0; +} + +FORCEINLINE bool IsAllGreaterThanOrEq(const fltx4& a, const fltx4& b) +{ + return TestSignSIMD(CmpLtSIMD(a, b)) == 0; +} + +FORCEINLINE bool IsAllEqual(const fltx4& a, const fltx4& b) +{ + return TestSignSIMD(CmpEqSIMD(a, b)) == 0xf; +} + +FORCEINLINE fltx4 CmpInBoundsSIMD(const fltx4& a, const fltx4& b) +{ + return AndSIMD(CmpLeSIMD(a, b), CmpGeSIMD(a, NegSIMD(b))); +} + +FORCEINLINE fltx4 MinSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_min_ps(a, b); +} + +FORCEINLINE fltx4 MaxSIMD(const fltx4& a, const fltx4& b) +{ + return _mm_max_ps(a, b); +} + + + +FORCEINLINE fltx4 CeilSIMD(const fltx4& a) +{ + fltx4 retVal; + SubFloat(retVal, 0) = ceil(SubFloat(a, 0)); + SubFloat(retVal, 1) = ceil(SubFloat(a, 1)); + SubFloat(retVal, 2) = ceil(SubFloat(a, 2)); + SubFloat(retVal, 3) = ceil(SubFloat(a, 3)); + return retVal; + +} + +fltx4 AbsSIMD(const fltx4& x); +fltx4 fabs(const fltx4& x); + +FORCEINLINE fltx4 FloorSIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 ival = SubSIMD(AddSIMD(fl4Abs, Four_2ToThe23s), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, fl4Abs), SubSIMD(ival, Four_Ones), ival); + return XorSIMD(ival, XorSIMD(val, fl4Abs)); +} + + + +FORCEINLINE bool IsAnyZeros(const fltx4& a) +{ + return TestSignSIMD(CmpEqSIMD(a, Four_Zeros)) != 0; +} + +inline bool IsAllZeros(const fltx4& var) +{ + return TestSignSIMD(CmpEqSIMD(var, Four_Zeros)) == 0xF; +} + +FORCEINLINE fltx4 SqrtEstSIMD(const fltx4& a) +{ + return _mm_sqrt_ps(a); +} + +FORCEINLINE fltx4 SqrtSIMD(const fltx4& a) +{ + return _mm_sqrt_ps(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSIMD(const fltx4& a) +{ + return _mm_rsqrt_ps(a); +} + +FORCEINLINE fltx4 ReciprocalSqrtEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalSqrtEstSIMD(ret); + return ret; +} + +FORCEINLINE fltx4 ReciprocalSqrtSIMD(const fltx4& a) +{ + fltx4 guess = ReciprocalSqrtEstSIMD(a); + guess = MulSIMD(guess, SubSIMD(Four_Threes, MulSIMD(a, MulSIMD(guess, guess)))); + guess = MulSIMD(Four_PointFives, guess); + return guess; +} + +FORCEINLINE fltx4 ReciprocalEstSIMD(const fltx4& a) +{ + return _mm_rcp_ps(a); +} + +FORCEINLINE fltx4 ReciprocalEstSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalEstSIMD(ret); + return ret; +} + +FORCEINLINE fltx4 ReciprocalSIMD(const fltx4& a) +{ + fltx4 ret = ReciprocalEstSIMD(a); + ret = SubSIMD(AddSIMD(ret, ret), MulSIMD(a, MulSIMD(ret, ret))); + return ret; +} + +FORCEINLINE fltx4 ReciprocalSaturateSIMD(const fltx4& a) +{ + fltx4 zero_mask = CmpEqSIMD(a, Four_Zeros); + fltx4 ret = OrSIMD(a, AndSIMD(Four_Epsilons, zero_mask)); + ret = ReciprocalSIMD(ret); + return ret; +} + +FORCEINLINE fltx4 ExpSIMD(const fltx4& toPower) +{ + fltx4 retval; + SubFloat(retval, 0) = powf(2, SubFloat(toPower, 0)); + SubFloat(retval, 1) = powf(2, SubFloat(toPower, 1)); + SubFloat(retval, 2) = powf(2, SubFloat(toPower, 2)); + SubFloat(retval, 3) = powf(2, SubFloat(toPower, 3)); + + return retval; +} + +FORCEINLINE fltx4 ClampVectorSIMD(FLTX4 in, FLTX4 min, FLTX4 max) +{ + return MaxSIMD(min, MinSIMD(max, in)); +} + +FORCEINLINE void TransposeSIMD(fltx4& x, fltx4& y, fltx4& z, fltx4& w) +{ + _MM_TRANSPOSE4_PS(x, y, z, w); +} + +FORCEINLINE fltx4 FindLowestSIMD3(const fltx4& a) +{ + fltx4 compareOne = RotateLeft(a); + fltx4 retval = MinSIMD(a, compareOne); + compareOne = RotateLeft2(a); + retval = MinSIMD(retval, compareOne); + return SplatXSIMD(retval); + +} + +FORCEINLINE fltx4 FindHighestSIMD3(const fltx4& a) +{ + fltx4 compareOne = RotateLeft(a); + fltx4 retval = MaxSIMD(a, compareOne); + compareOne = RotateLeft2(a); + retval = MaxSIMD(retval, compareOne); + return SplatXSIMD(retval); + +} + + +inline bool IsVector3LessThan(const fltx4& v1, const fltx4& v2) +{ + bi32x4 isOut = CmpLtSIMD(v1, v2); + return IsAnyNegative(isOut); +} + +inline bool IsVector4LessThan(const fltx4& v1, const fltx4& v2) +{ + bi32x4 isOut = CmpLtSIMD(v1, v2); + return IsAnyNegative(isOut); +} + + + +#if 0 +FORCEINLINE fltx4 IntSetImmediateSIMD(int to) +{ + fltx4 retval; + SubInt(retval, 0) = to; + SubInt(retval, 1) = to; + SubInt(retval, 2) = to; + SubInt(retval, 3) = to; + return retval; +} +#endif + +FORCEINLINE i32x4 LoadAlignedIntSIMD(const void* RESTRICT pSIMD) +{ + return _mm_load_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE i32x4 LoadUnalignedIntSIMD(const void* RESTRICT pSIMD) +{ + return _mm_loadu_ps(reinterpret_cast(pSIMD)); +} + +FORCEINLINE void StoreAlignedIntSIMD(int32* RESTRICT pSIMD, const fltx4& a) +{ + _mm_store_ps(reinterpret_cast(pSIMD), a); +} + +FORCEINLINE void StoreAlignedIntSIMD(intx4& pSIMD, const fltx4& a) +{ + _mm_store_ps(reinterpret_cast(pSIMD.Base()), a); +} + +FORCEINLINE void StoreUnalignedIntSIMD(int32* RESTRICT pSIMD, const fltx4& a) +{ + _mm_storeu_ps(reinterpret_cast(pSIMD), a); +} + +FORCEINLINE fltx4 CompressSIMD(fltx4 const& a, fltx4 const& b) +{ + return _mm_shuffle_ps(a, b, MM_SHUFFLE_REV(0, 2, 0, 2)); +} + +FORCEINLINE fltx4 LoadAndConvertUint16SIMD(const uint16* pInts) +{ +#ifdef POSIX + fltx4 retval; + SubFloat(retval, 0) = pInts[0]; + SubFloat(retval, 1) = pInts[1]; + SubFloat(retval, 2) = pInts[2]; + SubFloat(retval, 3) = pInts[3]; + return retval; +#else + __m128i inA = _mm_loadl_epi64((__m128i const*) pInts); + inA = _mm_unpacklo_epi16(inA, _mm_setzero_si128()); + return _mm_cvtepi32_ps(inA); +#endif +} + + +FORCEINLINE fltx4 Compress4SIMD(fltx4 const a, fltx4 const& b, fltx4 const& c, fltx4 const& d) +{ + fltx4 aacc = _mm_shuffle_ps(a, c, MM_SHUFFLE_REV(0, 0, 0, 0)); + fltx4 bbdd = _mm_shuffle_ps(b, d, MM_SHUFFLE_REV(0, 0, 0, 0)); + return MaskedAssign(LoadAlignedSIMD(g_SIMD_EveryOtherMask), bbdd, aacc); +} + +FORCEINLINE void ExpandSIMD(fltx4 const& a, fltx4& fl4OutA, fltx4& fl4OutB) +{ + fl4OutA = _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(0, 0, 1, 1)); + fl4OutB = _mm_shuffle_ps(a, a, MM_SHUFFLE_REV(2, 2, 3, 3)); + +} + + +FORCEINLINE fltx4 LoadGatherSIMD(const float& x, const float& y, const float& z, const float& w) +{ + fltx4 vx = _mm_load_ss(&x); + fltx4 vy = _mm_load_ss(&y); + fltx4 vz = _mm_load_ss(&z); + fltx4 vw = _mm_load_ss(&w); + return Compress4SIMD(vx, vy, vz, vw); +} + +FORCEINLINE fltx4 UnsignedIntConvertToFltSIMD(const u32x4& vSrcA) +{ + fltx4 retval; + SubFloat(retval, 0) = ((float)SubInt(retval, 0)); + SubFloat(retval, 1) = ((float)SubInt(retval, 1)); + SubFloat(retval, 2) = ((float)SubInt(retval, 2)); + SubFloat(retval, 3) = ((float)SubInt(retval, 3)); + return retval; +} + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + return _mm_cvtepi32_ps((const __m128i&)vSrcA); +} + +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const shortx8& vSrcA) +{ + return _mm_cvtepi32_ps(vSrcA); +} + +#if 0 +FORCEINLINE fltx4 SignedIntConvertToFltSIMD(const i32x4& vSrcA) +{ + fltx4 retval; + SubFloat(retval, 0) = ((float)(reinterpret_cast(&vSrcA)[0])); + SubFloat(retval, 1) = ((float)(reinterpret_cast(&vSrcA)[1])); + SubFloat(retval, 2) = ((float)(reinterpret_cast(&vSrcA)[2])); + SubFloat(retval, 3) = ((float)(reinterpret_cast(&vSrcA)[3])); + return retval; +} + +#endif + +FORCEINLINE i32x4 IntShiftLeftWordSIMD(const i32x4& vSrcA, const i32x4& vSrcB) +{ + i32x4 retval; + SubInt(retval, 0) = SubInt(vSrcA, 0) << SubInt(vSrcB, 0); + SubInt(retval, 1) = SubInt(vSrcA, 1) << SubInt(vSrcB, 1); + SubInt(retval, 2) = SubInt(vSrcA, 2) << SubInt(vSrcB, 2); + SubInt(retval, 3) = SubInt(vSrcA, 3) << SubInt(vSrcB, 3); + + + return retval; +} + + +FORCEINLINE void ConvertStoreAsIntsSIMD(intx4* RESTRICT pDest, const fltx4& vSrc) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1900 && defined(COMPILER_MSVC64) + (*pDest)[0] = (int)SubFloat(vSrc, 0); + (*pDest)[1] = (int)SubFloat(vSrc, 1); + (*pDest)[2] = (int)SubFloat(vSrc, 2); + (*pDest)[3] = (int)SubFloat(vSrc, 3); +#else + __m64 bottom = _mm_cvttps_pi32(vSrc); + __m64 top = _mm_cvttps_pi32(_mm_movehl_ps(vSrc, vSrc)); + + *reinterpret_cast<__m64*>(&(*pDest)[0]) = bottom; + *reinterpret_cast<__m64*>(&(*pDest)[2]) = top; + + _mm_empty(); +#endif +} + + + +#endif + +FORCEINLINE void RotateLeftDoubleSIMD(fltx4& a, fltx4& b) +{ + a = SetWSIMD(RotateLeft(a), SplatXSIMD(b)); + b = RotateLeft(b); +} + + +#if !defined(PLATFORM_PPC) && !defined( POSIX ) && !defined(SPU) +#if 1 +FORCEINLINE fltx4 operator+(FLTX4 a, FLTX4 b) +{ + return AddSIMD(a, b); +} + +FORCEINLINE fltx4 operator-(FLTX4 a, FLTX4 b) +{ + return SubSIMD(a, b); +} + +FORCEINLINE fltx4 operator*(FLTX4 a, FLTX4 b) +{ + return MulSIMD(a, b); +} + +FORCEINLINE fltx4 operator&(FLTX4 a, FLTX4 b) +{ + return AndSIMD(a, b); +} + +FORCEINLINE fltx4 operator|(FLTX4 a, FLTX4 b) +{ + return OrSIMD(a, b); +} + +FORCEINLINE fltx4 operator^(FLTX4 a, FLTX4 b) +{ + return XorSIMD(a, b); +} + +FORCEINLINE fltx4 operator-(FLTX4 a) +{ + return NegSIMD(a); +} +#endif +#endif + +#if defined(_X360) || defined(_PS3) +FORCEINLINE fltx4 VectorMergeHighSIMD(fltx4 fl4SrcA, fltx4 fl4SrcB) +{ +#if defined( _X360 ) + return __vmrghw(fl4SrcA, fl4SrcB); +#else + return vec_mergeh(fl4SrcA, fl4SrcB); +#endif +} + +FORCEINLINE fltx4 VectorMergeLowSIMD(fltx4 fl4SrcA, fltx4 fl4SrcB) +{ +#if defined( _X360 ) + return __vmrglw(fl4SrcA, fl4SrcB); +#else + return vec_mergel(fl4SrcA, fl4SrcB); +#endif +} +#endif + +#ifndef SPU +struct ALIGN16 fourplanes_t +{ + fltx4 nX; + fltx4 nY; + fltx4 nZ; + fltx4 dist; + bi32x4 xSign; + bi32x4 ySign; + bi32x4 zSign; + fltx4 nXAbs; + fltx4 nYAbs; + fltx4 nZAbs; + + void ComputeSignbits(); + + void Set4Planes(const VPlane* pPlanes); + void Set2Planes(const VPlane* pPlanes); + void Get4Planes(VPlane* pPlanesOut) const; + void Get2Planes(VPlane* pPlanesOut) const; + void GetPlane(int index, Vector* pNormal, float* pDist) const; + void SetPlane(int index, const Vector& vecNormal, float planeDist); +}; + + + +#endif + +class FourQuaternions; +class ALIGN16 FourVectors +{ +public: + fltx4 x, y, z; + + FourVectors(void) + { + } + + FourVectors(FourVectors const& src) + { + x = src.x; + y = src.y; + z = src.z; + } + + explicit FORCEINLINE FourVectors(float a) + { + fltx4 aReplicated = ReplicateX4(a); + x = y = z = aReplicated; + } + + FORCEINLINE void Init(void) + { + x = Four_Zeros; + y = Four_Zeros; + z = Four_Zeros; + } + + FORCEINLINE void Init(float flX, float flY, float flZ) + { + x = ReplicateX4(flX); + y = ReplicateX4(flY); + z = ReplicateX4(flZ); + } + + FORCEINLINE FourVectors(float flX, float flY, float flZ) + { + Init(flX, flY, flZ); + } + + FORCEINLINE void Init(fltx4 const& fl4X, fltx4 const& fl4Y, fltx4 const& fl4Z) + { + x = fl4X; + y = fl4Y; + z = fl4Z; + } + + FORCEINLINE FourVectors(fltx4 const& fl4X, fltx4 const& fl4Y, fltx4 const& fl4Z) + { + Init(fl4X, fl4Y, fl4Z); + } + + + + FORCEINLINE FourVectors(Vector const& a, Vector const& b, Vector const& c, Vector const& d) + { + LoadAndSwizzle(a, b, c, d); + } + + FORCEINLINE FourVectors(VectorAligned const& a, VectorAligned const& b, VectorAligned const& c, VectorAligned const& d) + { + LoadAndSwizzleAligned(a, b, c, d); + } + + FORCEINLINE FourVectors(const float* xs, const float* ys, const float* zs) : + x(LoadAlignedSIMD(xs)), y(LoadAlignedSIMD(ys)), z(LoadAlignedSIMD(zs)) + {}; + + FORCEINLINE void DuplicateVector(Vector const& v) + { + x = ReplicateX4(v.x); + y = ReplicateX4(v.y); + z = ReplicateX4(v.z); + } + + FORCEINLINE fltx4 const& operator[](int idx) const + { + return *((&x) + idx); + } + + FORCEINLINE fltx4& operator[](int idx) + { + return *((&x) + idx); + } + + FORCEINLINE void operator+=(FourVectors const& b) + { + x = AddSIMD(x, b.x); + y = AddSIMD(y, b.y); + z = AddSIMD(z, b.z); + } + + FORCEINLINE void operator-=(FourVectors const& b) + { + x = SubSIMD(x, b.x); + y = SubSIMD(y, b.y); + z = SubSIMD(z, b.z); + } + + FORCEINLINE void operator*=(FourVectors const& b) + { + x = MulSIMD(x, b.x); + y = MulSIMD(y, b.y); + z = MulSIMD(z, b.z); + } + + FORCEINLINE void operator*=(const fltx4& scale) + { + x = MulSIMD(x, scale); + y = MulSIMD(y, scale); + z = MulSIMD(z, scale); + } + + FORCEINLINE void operator*=(float scale) + { + fltx4 scalepacked = ReplicateX4(scale); + *this *= scalepacked; + } + + FORCEINLINE fltx4 operator*(FourVectors const& b) const + { + fltx4 dot = MulSIMD(x, b.x); + dot = MaddSIMD(y, b.y, dot); + dot = MaddSIMD(z, b.z, dot); + return dot; + } + + FORCEINLINE fltx4 operator*(Vector const& b) const + { + fltx4 dot = MulSIMD(x, ReplicateX4(b.x)); + dot = MaddSIMD(y, ReplicateX4(b.y), dot); + dot = MaddSIMD(z, ReplicateX4(b.z), dot); + return dot; + } + + FORCEINLINE FourVectors operator*(float b) const + { + fltx4 scalepacked = ReplicateX4(b); + FourVectors res; + res.x = MulSIMD(x, scalepacked); + res.y = MulSIMD(y, scalepacked); + res.z = MulSIMD(z, scalepacked); + return res; + } + + FORCEINLINE FourVectors operator*(FLTX4 fl4Scale) const + { + FourVectors res; + res.x = MulSIMD(x, fl4Scale); + res.y = MulSIMD(y, fl4Scale); + res.z = MulSIMD(z, fl4Scale); + return res; + } + + FORCEINLINE void VProduct(FourVectors const& b) + { + x = MulSIMD(x, b.x); + y = MulSIMD(y, b.y); + z = MulSIMD(z, b.z); + } + FORCEINLINE void MakeReciprocal(void) + { + x = ReciprocalSIMD(x); + y = ReciprocalSIMD(y); + z = ReciprocalSIMD(z); + } + + FORCEINLINE void MakeReciprocalSaturate(void) + { + x = ReciprocalSaturateSIMD(x); + y = ReciprocalSaturateSIMD(y); + z = ReciprocalSaturateSIMD(z); + } + + inline void RotateBy(const matrix3x4_t& matrix); + static void RotateManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix); + + static void RotateManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors* RESTRICT pOut); + + inline void TransformBy(const matrix3x4_t& matrix); + + static void TransformManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix, FourVectors* RESTRICT pOut); + + static void TransformManyBy(FourVectors* RESTRICT pVectors, unsigned int numVectors, const matrix3x4_t& rotationMatrix); + + static void CalcClosestPointOnLineSIMD(const FourVectors& P, const FourVectors& vLineA, const FourVectors& vLineB, FourVectors& vClosest, fltx4* outT = 0); + static fltx4 CalcClosestPointToLineTSIMD(const FourVectors& P, const FourVectors& vLineA, const FourVectors& vLineB, FourVectors& vDir); + + FORCEINLINE const float& X(int idx) const + { + return SubFloat((fltx4&)x, idx); + } + + FORCEINLINE const float& Y(int idx) const + { + return SubFloat((fltx4&)y, idx); + } + + FORCEINLINE const float& Z(int idx) const + { + return SubFloat((fltx4&)z, idx); + } + + FORCEINLINE float& X(int idx) + { + return SubFloat(x, idx); + } + + FORCEINLINE float& Y(int idx) + { + return SubFloat(y, idx); + } + + FORCEINLINE float& Z(int idx) + { + return SubFloat(z, idx); + } + + FORCEINLINE Vector Vec(int idx) const + { + return Vector(X(idx), Y(idx), Z(idx)); + } + + FORCEINLINE void operator=(FourVectors const& src) + { + x = src.x; + y = src.y; + z = src.z; + } + + FORCEINLINE void LoadAndSwizzle(Vector const& a, Vector const& b, Vector const& c, Vector const& d) + { +#if defined( _X360 ) || defined(_PS3) + fltx4 tx = LoadUnalignedSIMD(&a.x); + fltx4 ty = LoadUnalignedSIMD(&b.x); + fltx4 tz = LoadUnalignedSIMD(&c.x); + fltx4 tw = LoadUnalignedSIMD(&d.x); + fltx4 r0 = VectorMergeHighSIMD(tx, tz); + fltx4 r1 = VectorMergeHighSIMD(ty, tw); + fltx4 r2 = VectorMergeLowSIMD(tx, tz); + fltx4 r3 = VectorMergeLowSIMD(ty, tw); + + x = VectorMergeHighSIMD(r0, r1); + y = VectorMergeLowSIMD(r0, r1); + z = VectorMergeHighSIMD(r2, r3); +#else + x = LoadUnalignedSIMD(&(a.x)); + y = LoadUnalignedSIMD(&(b.x)); + z = LoadUnalignedSIMD(&(c.x)); + fltx4 w = LoadUnalignedSIMD(&(d.x)); + TransposeSIMD(x, y, z, w); +#endif + } + + FORCEINLINE void LoadAndSwizzle(Vector const& a) + { + LoadAndSwizzle(a, a, a, a); + } + + FORCEINLINE void Load(const float& a, const float& b, const float& c, const float& d) + { +#if defined( _X360 ) || defined( _PS3 ) + fltx4 temp[4]; + temp[0] = LoadUnalignedFloatSIMD(&a); + temp[1] = LoadUnalignedFloatSIMD(&b); + temp[2] = LoadUnalignedFloatSIMD(&c); + temp[3] = LoadUnalignedFloatSIMD(&d); + y = VectorMergeHighSIMD(temp[0], temp[2]); + z = VectorMergeHighSIMD(temp[1], temp[3]); + + x = VectorMergeHighSIMD(y, z); + y = x; + z = x; +#else + ALIGN16 float temp[4]; + temp[0] = a; temp[1] = b; temp[2] = c; temp[3] = d; + fltx4 v = LoadAlignedSIMD(temp); + x = v; + y = v; + z = v; +#endif + } + + FORCEINLINE void LoadAndSwizzle(FLTX4 a, FLTX4 b, FLTX4 c, FLTX4 d) + { +#if defined( _X360 ) || defined( _PS3 ) + fltx4 tx = a; + fltx4 ty = b; + fltx4 tz = c; + fltx4 tw = d; + fltx4 r0 = VectorMergeHighSIMD(tx, tz); + fltx4 r1 = VectorMergeHighSIMD(ty, tw); + fltx4 r2 = VectorMergeLowSIMD(tx, tz); + fltx4 r3 = VectorMergeLowSIMD(ty, tw); + + x = VectorMergeHighSIMD(r0, r1); + y = VectorMergeLowSIMD(r0, r1); + z = VectorMergeHighSIMD(r2, r3); +#else + x = a; + y = b; + z = c; + fltx4 w = d; + TransposeSIMD(x, y, z, w); +#endif + } + + FORCEINLINE void LoadAndSwizzleAligned(const float* RESTRICT a, const float* RESTRICT b, const float* RESTRICT c, const float* RESTRICT d) + { +#if defined( _X360 ) || defined( _PS3 ) + fltx4 tx = LoadAlignedSIMD(a); + fltx4 ty = LoadAlignedSIMD(b); + fltx4 tz = LoadAlignedSIMD(c); + fltx4 tw = LoadAlignedSIMD(d); + fltx4 r0 = VectorMergeHighSIMD(tx, tz); + fltx4 r1 = VectorMergeHighSIMD(ty, tw); + fltx4 r2 = VectorMergeLowSIMD(tx, tz); + fltx4 r3 = VectorMergeLowSIMD(ty, tw); + + x = VectorMergeHighSIMD(r0, r1); + y = VectorMergeLowSIMD(r0, r1); + z = VectorMergeHighSIMD(r2, r3); +#else + x = LoadAlignedSIMD(a); + y = LoadAlignedSIMD(b); + z = LoadAlignedSIMD(c); + fltx4 w = LoadAlignedSIMD(d); + TransposeSIMD(x, y, z, w); +#endif + } + + FORCEINLINE void LoadAndSwizzleAligned(Vector const& a, Vector const& b, Vector const& c, Vector const& d) + { + LoadAndSwizzleAligned(&a.x, &b.x, &c.x, &d.x); + } + + FORCEINLINE void TransposeOnto(fltx4& out0, fltx4& out1, fltx4& out2, fltx4& out3, FLTX4 w = Four_Zeros) const + { +#if defined( _X360 ) || defined(_PS3) + fltx4 r0 = VectorMergeHighSIMD(x, z); + fltx4 r1 = VectorMergeHighSIMD(y, w); + fltx4 r2 = VectorMergeLowSIMD(x, z); + fltx4 r3 = VectorMergeLowSIMD(y, w); + + out0 = VectorMergeHighSIMD(r0, r1); + out1 = VectorMergeLowSIMD(r0, r1); + out2 = VectorMergeHighSIMD(r2, r3); + out3 = VectorMergeLowSIMD(r2, r3); +#else + out0 = x; + out1 = y; + out2 = z; + out3 = w; + + TransposeSIMD(out0, out1, out2, out3); +#endif + } + +#if !defined(__SPU__) + FORCEINLINE void StoreUnalignedVector3SIMD(Vector* RESTRICT out0, Vector* RESTRICT out1, Vector* RESTRICT out2, Vector* RESTRICT out3) const; +#endif + + FORCEINLINE void StoreAlignedVectorSIMD(VectorAligned* RESTRICT out0, VectorAligned* RESTRICT out1, VectorAligned* RESTRICT out2, VectorAligned* RESTRICT out3) const; + +#if !defined(__SPU__) + FORCEINLINE void StoreUnalignedContigVector3SIMD(Vector* RESTRICT pDestination) + { + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreFourUnalignedVector3SIMD(a, b, c, d, pDestination); + } +#endif + +#if !defined(__SPU__) + FORCEINLINE void StoreAlignedContigVector3SIMD(Vector* RESTRICT pDestination) + { + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreFourAlignedVector3SIMD(a, b, c, d, pDestination); + } + + FORCEINLINE void StoreAlignedContigVectorASIMD(VectorAligned* RESTRICT pDestination) + { + StoreAlignedVectorSIMD(pDestination, pDestination + 1, pDestination + 2, pDestination + 3); + } +#endif + + FORCEINLINE fltx4 LengthSqr(void) const + { + const FourVectors& a = *this; + return a * a; + } + + FORCEINLINE fltx4 length2(void) const + { + return (*this) * (*this); + } + + FORCEINLINE fltx4 length(void) const + { + return SqrtEstSIMD(length2()); + } + + FORCEINLINE fltx4 Length(void) const + { + return SqrtSIMD(length2()); + } + + + FORCEINLINE void VectorNormalizeFast(void) + { + fltx4 mag_sq = (*this) * (*this); + (*this) *= ReciprocalSqrtEstSIMD(mag_sq); + } + + FORCEINLINE void VectorNormalize(void) + { + fltx4 mag_sq = (*this) * (*this); + (*this) *= ReciprocalSqrtSIMD(mag_sq); + } + + FORCEINLINE fltx4 DistToSqr(FourVectors const& pnt) + { + fltx4 fl4dX = SubSIMD(pnt.x, x); + fltx4 fl4dY = SubSIMD(pnt.y, y); + fltx4 fl4dZ = SubSIMD(pnt.z, z); + return AddSIMD(MulSIMD(fl4dX, fl4dX), AddSIMD(MulSIMD(fl4dY, fl4dY), MulSIMD(fl4dZ, fl4dZ))); + + } + + FORCEINLINE fltx4 TValueOfClosestPointOnLine(FourVectors const& p0, FourVectors const& p1) const + { + FourVectors lineDelta = p1; + lineDelta -= p0; + fltx4 OOlineDirDotlineDir = ReciprocalSIMD(p1 * p1); + FourVectors v4OurPnt = *this; + v4OurPnt -= p0; + return MulSIMD(OOlineDirDotlineDir, v4OurPnt * lineDelta); + } + + FORCEINLINE fltx4 DistSqrToLineSegment(FourVectors const& p0, FourVectors const& p1) const + { + FourVectors lineDelta = p1; + FourVectors v4OurPnt = *this; + v4OurPnt -= p0; + lineDelta -= p0; + + fltx4 OOlineDirDotlineDir = ReciprocalSIMD(lineDelta * lineDelta); + + fltx4 fl4T = MulSIMD(OOlineDirDotlineDir, v4OurPnt * lineDelta); + + fl4T = MinSIMD(fl4T, Four_Ones); + fl4T = MaxSIMD(fl4T, Four_Zeros); + lineDelta *= fl4T; + return v4OurPnt.DistToSqr(lineDelta); + } + FORCEINLINE FourVectors Normalized()const + { + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(LengthSqr()); + FourVectors out; + out.x = x * fl4LengthInv; + out.y = y * fl4LengthInv; + out.z = z * fl4LengthInv; + return out; + } + + FORCEINLINE FourVectors NormalizedSafeX() const + { + fltx4 f4LenSqr = LengthSqr(); + fltx4 isBigEnough = CmpGeSIMD(f4LenSqr, Four_Epsilons); + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(f4LenSqr); + FourVectors out; + out.x = MaskedAssign(isBigEnough, x * fl4LengthInv, Four_Ones); + out.y = AndSIMD(y * fl4LengthInv, isBigEnough); + out.z = AndSIMD(z * fl4LengthInv, isBigEnough); + return out; + } + FORCEINLINE FourVectors NormalizedSafeY() const + { + fltx4 f4LenSqr = LengthSqr(); + fltx4 isBigEnough = CmpGeSIMD(f4LenSqr, Four_Epsilons); + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(f4LenSqr); + FourVectors out; + out.x = AndSIMD(x * fl4LengthInv, isBigEnough); + out.y = MaskedAssign(isBigEnough, y * fl4LengthInv, Four_Ones); + out.z = AndSIMD(z * fl4LengthInv, isBigEnough); + return out; + } + + FORCEINLINE FourVectors NormalizedSafeZ() const + { + fltx4 f4LenSqr = LengthSqr(); + fltx4 isBigEnough = CmpGeSIMD(f4LenSqr, Four_Epsilons); + fltx4 fl4LengthInv = ReciprocalSqrtSIMD(f4LenSqr); + FourVectors out; + out.x = AndSIMD(x * fl4LengthInv, isBigEnough); + out.y = AndSIMD(y * fl4LengthInv, isBigEnough); + out.z = MaskedAssign(isBigEnough, z * fl4LengthInv, Four_Ones); + return out; + } +}; + + +inline FourVectors CrossProduct(const FourVectors& a, const FourVectors& b) +{ + return FourVectors(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline fltx4 DotProduct(const FourVectors& a, const FourVectors& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +inline FourVectors operator * (fltx4 left, const FourVectors& right) +{ + return right * left; +} + + +inline FourVectors Mul(const FourVectors& a, const fltx4& b) +{ + FourVectors ret; + ret.x = MulSIMD(a.x, b); + ret.y = MulSIMD(a.y, b); + ret.z = MulSIMD(a.z, b); + return ret; +} + +inline FourVectors Mul(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = MulSIMD(a.x, b.x); + ret.y = MulSIMD(a.y, b.y); + ret.z = MulSIMD(a.z, b.z); + return ret; +} + +inline FourVectors Madd(const FourVectors& a, const fltx4& b, const FourVectors& c) +{ + FourVectors ret; + ret.x = MaddSIMD(a.x, b, c.x); + ret.y = MaddSIMD(a.y, b, c.y); + ret.z = MaddSIMD(a.z, b, c.z); + return ret; +} + +inline FourVectors operator ^(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = SubSIMD(MulSIMD(a.y, b.z), MulSIMD(a.z, b.y)); + ret.y = SubSIMD(MulSIMD(a.z, b.x), MulSIMD(a.x, b.z)); + ret.z = SubSIMD(MulSIMD(a.x, b.y), MulSIMD(a.y, b.x)); + return ret; +} + +inline FourVectors operator-(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = SubSIMD(a.x, b.x); + ret.y = SubSIMD(a.y, b.y); + ret.z = SubSIMD(a.z, b.z); + return ret; +} + +inline FourVectors operator+(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = AddSIMD(a.x, b.x); + ret.y = AddSIMD(a.y, b.y); + ret.z = AddSIMD(a.z, b.z); + return ret; +} + +inline FourVectors maximum(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = MaxSIMD(a.x, b.x); + ret.y = MaxSIMD(a.y, b.y); + ret.z = MaxSIMD(a.z, b.z); + return ret; +} + +inline FourVectors minimum(const FourVectors& a, const FourVectors& b) +{ + FourVectors ret; + ret.x = MinSIMD(a.x, b.x); + ret.y = MinSIMD(a.y, b.y); + ret.z = MinSIMD(a.z, b.z); + return ret; +} + +FORCEINLINE FourVectors RotateLeft(const FourVectors& src) +{ + FourVectors ret; + ret.x = RotateLeft(src.x); + ret.y = RotateLeft(src.y); + ret.z = RotateLeft(src.z); + return ret; +} + +FORCEINLINE FourVectors RotateRight(const FourVectors& src) +{ + FourVectors ret; + ret.x = RotateRight(src.x); + ret.y = RotateRight(src.y); + ret.z = RotateRight(src.z); + return ret; +} +FORCEINLINE FourVectors MaskedAssign(const bi32x4& ReplacementMask, const FourVectors& NewValue, const FourVectors& OldValue) +{ + FourVectors ret; + ret.x = MaskedAssign(ReplacementMask, NewValue.x, OldValue.x); + ret.y = MaskedAssign(ReplacementMask, NewValue.y, OldValue.y); + ret.z = MaskedAssign(ReplacementMask, NewValue.z, OldValue.z); + return ret; +} + +FORCEINLINE FourVectors VectorReflect(const FourVectors& incident, const FourVectors& normal) +{ + FourVectors ret = incident; + fltx4 iDotNx2 = incident * normal; + iDotNx2 = AddSIMD(iDotNx2, iDotNx2); + FourVectors nPart = normal; + nPart *= iDotNx2; + ret -= nPart; + return ret; +} + +FORCEINLINE FourVectors VectorSlide(const FourVectors& incident, const FourVectors& normal) +{ + FourVectors ret = incident; + fltx4 iDotN = incident * normal; + FourVectors nPart = normal; + nPart *= iDotN; + ret -= nPart; + return ret; +} + +FORCEINLINE FourVectors VectorNormalizeFast(const FourVectors& src) +{ + fltx4 mag_sq = ReciprocalSqrtEstSIMD(src * src); + FourVectors result; + result.x = MulSIMD(src.x, mag_sq); + result.y = MulSIMD(src.y, mag_sq); + result.z = MulSIMD(src.z, mag_sq); + return result; +} + +#if !defined(__SPU__) +FORCEINLINE void FourVectors::StoreUnalignedVector3SIMD(Vector* RESTRICT out0, Vector* RESTRICT out1, Vector* RESTRICT out2, Vector* RESTRICT out3) const +{ +#ifdef _X360 + fltx4 x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3; + x0 = SplatXSIMD(x); + x1 = SplatYSIMD(x); + x2 = SplatZSIMD(x); + x3 = SplatWSIMD(x); + + y0 = SplatXSIMD(y); + y1 = SplatYSIMD(y); + y2 = SplatZSIMD(y); + y3 = SplatWSIMD(y); + + z0 = SplatXSIMD(z); + z1 = SplatYSIMD(z); + z2 = SplatZSIMD(z); + z3 = SplatWSIMD(z); + + __stvewx(x0, out0->Base(), 0); + __stvewx(y0, out0->Base(), 4); + __stvewx(z0, out0->Base(), 8); + + __stvewx(x1, out1->Base(), 0); + __stvewx(y1, out1->Base(), 4); + __stvewx(z1, out1->Base(), 8); + + __stvewx(x2, out2->Base(), 0); + __stvewx(y2, out2->Base(), 4); + __stvewx(z2, out2->Base(), 8); + + __stvewx(x3, out3->Base(), 0); + __stvewx(y3, out3->Base(), 4); + __stvewx(z3, out3->Base(), 8); +#else + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreUnaligned3SIMD(out0->Base(), a); + StoreUnaligned3SIMD(out1->Base(), b); + StoreUnaligned3SIMD(out2->Base(), c); + StoreUnaligned3SIMD(out3->Base(), d); +#endif +} + +FORCEINLINE void FourVectors::StoreAlignedVectorSIMD(VectorAligned* RESTRICT out0, VectorAligned* RESTRICT out1, VectorAligned* RESTRICT out2, VectorAligned* RESTRICT out3) const +{ + fltx4 a, b, c, d; + TransposeOnto(a, b, c, d); + StoreAligned3SIMD(out0, a); + StoreAligned3SIMD(out1, b); + StoreAligned3SIMD(out2, c); + StoreAligned3SIMD(out3, d); + +} +#endif + +#if !defined(__SPU__) +void FourVectors::RotateBy(const matrix3x4_t& matrix) +{ + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + fltx4 matCol0 = LoadUnalignedSIMD(matrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(matrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(matrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + + fltx4 outX, outY, outZ; + outX = AddSIMD(AddSIMD(MulSIMD(x, matSplat00), MulSIMD(y, matSplat01)), MulSIMD(z, matSplat02)); + outY = AddSIMD(AddSIMD(MulSIMD(x, matSplat10), MulSIMD(y, matSplat11)), MulSIMD(z, matSplat12)); + outZ = AddSIMD(AddSIMD(MulSIMD(x, matSplat20), MulSIMD(y, matSplat21)), MulSIMD(z, matSplat22)); + + x = outX; + y = outY; + z = outZ; +} + + +void FourVectors::TransformBy(const matrix3x4_t& matrix) +{ + fltx4 matSplat00, matSplat01, matSplat02, + matSplat10, matSplat11, matSplat12, + matSplat20, matSplat21, matSplat22; + + fltx4 matCol0 = LoadUnalignedSIMD(matrix[0]); + fltx4 matCol1 = LoadUnalignedSIMD(matrix[1]); + fltx4 matCol2 = LoadUnalignedSIMD(matrix[2]); + + matSplat00 = SplatXSIMD(matCol0); + matSplat01 = SplatYSIMD(matCol0); + matSplat02 = SplatZSIMD(matCol0); + + matSplat10 = SplatXSIMD(matCol1); + matSplat11 = SplatYSIMD(matCol1); + matSplat12 = SplatZSIMD(matCol1); + + matSplat20 = SplatXSIMD(matCol2); + matSplat21 = SplatYSIMD(matCol2); + matSplat22 = SplatZSIMD(matCol2); + + fltx4 outX, outY, outZ; + + outX = MaddSIMD(z, matSplat02, AddSIMD(MulSIMD(x, matSplat00), MulSIMD(y, matSplat01))); + outY = MaddSIMD(z, matSplat12, AddSIMD(MulSIMD(x, matSplat10), MulSIMD(y, matSplat11))); + outZ = MaddSIMD(z, matSplat22, AddSIMD(MulSIMD(x, matSplat20), MulSIMD(y, matSplat21))); + + x = AddSIMD(outX, ReplicateX4(matrix[0][3])); + y = AddSIMD(outY, ReplicateX4(matrix[1][3])); + z = AddSIMD(outZ, ReplicateX4(matrix[2][3])); +} +#endif + +fltx4 NoiseSIMD(FourVectors const& v); + +FourVectors DNoiseSIMD(FourVectors const& v); + +FourVectors CurlNoiseSIMD(FourVectors const& v); + + +fltx4 NoiseSIMD(const fltx4& x, const fltx4& y, const fltx4& z); + + +inline fltx4 fabs(const fltx4& x) +{ + return AndSIMD(x, LoadAlignedSIMD(g_SIMD_clear_signmask)); +} + +inline fltx4 AbsSIMD(const fltx4& x) +{ + return fabs(x); +} + +inline fltx4 fnegate(const fltx4& x) +{ + return XorSIMD(x, LoadAlignedSIMD(g_SIMD_signmask)); +} + +fltx4 Pow_FixedPoint_Exponent_SIMD(const fltx4& x, int exponent); + +inline fltx4 PowSIMD(const fltx4& x, float exponent) +{ + return Pow_FixedPoint_Exponent_SIMD(x, (int)(4.0 * exponent)); +} + +inline fltx4 LinearToGammaSIMD(fltx4 x) +{ + x = MaxSIMD(MinSIMD(Four_Ones, x), Four_Zeros); + return AddSIMD(Four_LinearToGammaCoefficients_E, + MulSIMD(x, AddSIMD(Four_LinearToGammaCoefficients_D, + MulSIMD(x, AddSIMD(Four_LinearToGammaCoefficients_C, + MulSIMD(x, AddSIMD(Four_LinearToGammaCoefficients_B, + MulSIMD(x, Four_LinearToGammaCoefficients_A)))))))); +} + + +inline fltx4 GammaToLinearSIMD(fltx4 x) +{ + x = MaxSIMD(x, Four_Zeros); + x = AddSIMD(Four_GammaToLinearCoefficients_D, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_C, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_B, + MulSIMD(x, Four_GammaToLinearCoefficients_A)))))); + return MinSIMD(x, Four_Ones); +} + +inline fltx4 GammaToLinearExtendedSIMD(fltx4 x) +{ + x = MaxSIMD(x, Four_Zeros); + fltx4 fl4Ret = AddSIMD(Four_GammaToLinearCoefficients_D, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_C, + MulSIMD(x, AddSIMD(Four_GammaToLinearCoefficients_B, + MulSIMD(x, Four_GammaToLinearCoefficients_A)))))); + return MaskedAssign(CmpGeSIMD(x, Four_Ones), x, fl4Ret); +} + +void SeedRandSIMD(uint32 seed); +fltx4 RandSIMD(int nContext = 0); + +int GetSIMDRandContext(void); +void ReleaseSIMDRandContext(int nContext); + +FORCEINLINE fltx4 RandSignedSIMD(void) +{ + return SubSIMD(MulSIMD(Four_Twos, RandSIMD()), Four_Ones); +} + + +FORCEINLINE fltx4 LerpSIMD(const fltx4& percent, const fltx4& a, const fltx4& b) +{ + return AddSIMD(a, MulSIMD(SubSIMD(b, a), percent)); +} + +FORCEINLINE fltx4 RemapValClampedSIMD(const fltx4& val, const fltx4& a, const fltx4& b, const fltx4& c, const fltx4& d) +{ + fltx4 range = MaskedAssign(CmpEqSIMD(a, b), Four_Ones, SubSIMD(b, a)); + fltx4 cVal = MaxSIMD(Four_Zeros, MinSIMD(Four_Ones, DivSIMD(SubSIMD(val, a), range))); + return LerpSIMD(cVal, c, d); +} + +inline fltx4 SimpleSpline(const fltx4& value) +{ + fltx4 valueDoubled = MulSIMD(value, Four_Twos); + fltx4 valueSquared = MulSIMD(value, value); + + return SubSIMD( + MulSIMD(Four_Threes, valueSquared), + MulSIMD(valueDoubled, valueSquared)); +} + +inline fltx4 SimpleSplineRemapValWithDeltas(const fltx4& val, + const fltx4& A, const fltx4& BMinusA, + const fltx4& OneOverBMinusA, const fltx4& C, + const fltx4& DMinusC) +{ + fltx4 cVal = MulSIMD(SubSIMD(val, A), OneOverBMinusA); + return AddSIMD(C, MulSIMD(DMinusC, SimpleSpline(cVal))); +} + +inline fltx4 SimpleSplineRemapValWithDeltasClamped(const fltx4& val, + const fltx4& A, const fltx4& BMinusA, + const fltx4& OneOverBMinusA, const fltx4& C, + const fltx4& DMinusC) +{ + fltx4 cVal = MulSIMD(SubSIMD(val, A), OneOverBMinusA); + cVal = MinSIMD(Four_Ones, MaxSIMD(Four_Zeros, cVal)); + return AddSIMD(C, MulSIMD(DMinusC, SimpleSpline(cVal))); +} + +FORCEINLINE fltx4 FracSIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 ival = SubSIMD(AddSIMD(fl4Abs, Four_2ToThe23s), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, fl4Abs), SubSIMD(ival, Four_Ones), ival); + return XorSIMD(SubSIMD(fl4Abs, ival), XorSIMD(val, fl4Abs)); +} + +#ifndef SPU +FORCEINLINE fltx4 Mod2SIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 ival = SubSIMD(AndSIMD(LoadAlignedSIMD((float*)g_SIMD_lsbmask), AddSIMD(fl4Abs, Four_2ToThe23s)), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, fl4Abs), SubSIMD(ival, Four_Twos), ival); + return XorSIMD(SubSIMD(fl4Abs, ival), XorSIMD(val, fl4Abs)); +} +#endif + +FORCEINLINE fltx4 Mod2SIMDPositiveInput(const fltx4& val) +{ + fltx4 ival = SubSIMD(AndSIMD(LoadAlignedSIMD(g_SIMD_lsbmask), AddSIMD(val, Four_2ToThe23s)), Four_2ToThe23s); + ival = MaskedAssign(CmpGtSIMD(ival, val), SubSIMD(ival, Four_Twos), ival); + return SubSIMD(val, ival); +} + + +FORCEINLINE fltx4 _SinEst01SIMD(const fltx4& val) +{ + return MulSIMD(val, SubSIMD(Four_Fours, MulSIMD(val, Four_Fours))); +} + +FORCEINLINE fltx4 _Sin01SIMD(const fltx4& val) +{ + fltx4 fl4BadEst = MulSIMD(val, SubSIMD(Four_Fours, MulSIMD(val, Four_Fours))); + return AddSIMD(MulSIMD(Four_Point225s, SubSIMD(MulSIMD(fl4BadEst, fl4BadEst), fl4BadEst)), fl4BadEst); +} + +FORCEINLINE fltx4 SinEst01SIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 fl4Reduced2 = Mod2SIMDPositiveInput(fl4Abs); + bi32x4 fl4OddMask = CmpGeSIMD(fl4Reduced2, Four_Ones); + fltx4 fl4val = SubSIMD(fl4Reduced2, AndSIMD(Four_Ones, fl4OddMask)); + fltx4 fl4Sin = _SinEst01SIMD(fl4val); + fl4Sin = XorSIMD(fl4Sin, AndSIMD(LoadAlignedSIMD(g_SIMD_signmask), XorSIMD(val, fl4OddMask))); + return fl4Sin; + +} + +FORCEINLINE fltx4 Sin01SIMD(const fltx4& val) +{ + fltx4 fl4Abs = fabs(val); + fltx4 fl4Reduced2 = Mod2SIMDPositiveInput(fl4Abs); + bi32x4 fl4OddMask = CmpGeSIMD(fl4Reduced2, Four_Ones); + fltx4 fl4val = SubSIMD(fl4Reduced2, AndSIMD(Four_Ones, fl4OddMask)); + fltx4 fl4Sin = _Sin01SIMD(fl4val); + fl4Sin = XorSIMD(fl4Sin, AndSIMD(LoadAlignedSIMD(g_SIMD_signmask), XorSIMD(val, fl4OddMask))); + return fl4Sin; + +} + +FORCEINLINE fltx4 NatExpSIMD(const fltx4& val) +{ + fltx4 fl4Result; + SubFloat(fl4Result, 0) = exp(SubFloat(val, 0)); + SubFloat(fl4Result, 1) = exp(SubFloat(val, 1)); + SubFloat(fl4Result, 2) = exp(SubFloat(val, 2)); + SubFloat(fl4Result, 3) = exp(SubFloat(val, 3)); + return fl4Result; +} + +FORCEINLINE fltx4 PreCalcBiasParameter(const fltx4& bias_parameter) +{ + return SubSIMD(ReciprocalSIMD(bias_parameter), Four_Twos); +} + +FORCEINLINE fltx4 BiasSIMD(const fltx4& val, const fltx4& precalc_param) +{ + return DivSIMD(val, AddSIMD(MulSIMD(precalc_param, SubSIMD(Four_Ones, val)), Four_Ones)); +} + +#ifndef SPU +FORCEINLINE int BoxOnPlaneSideSIMD(const fltx4& emins, const fltx4& emaxs, const cplane_t* p, float tolerance = 0.f) +{ + fltx4 corners[2]; + fltx4 normal = LoadUnalignedSIMD(p->normal.Base()); + fltx4 dist = ReplicateX4(-p->dist); + normal = SetWSIMD(normal, dist); + fltx4 t4 = ReplicateX4(tolerance); + fltx4 negt4 = ReplicateX4(-tolerance); + bi32x4 cmp = CmpGeSIMD(normal, Four_Zeros); + corners[0] = MaskedAssign(cmp, emaxs, emins); + corners[1] = MaskedAssign(cmp, emins, emaxs); + fltx4 dot1 = Dot4SIMD(normal, corners[0]); + fltx4 dot2 = Dot4SIMD(normal, corners[1]); + cmp = CmpGeSIMD(dot1, t4); + bi32x4 cmp2 = CmpGtSIMD(negt4, dot2); + fltx4 result = MaskedAssign(cmp, Four_Ones, Four_Zeros); + fltx4 result2 = MaskedAssign(cmp2, Four_Twos, Four_Zeros); + result = AddSIMD(result, result2); + intx4 sides; + ConvertStoreAsIntsSIMD(&sides, result); + return sides[0]; +} + + +class KDop32_t +{ +public: + fltx4 m_Mins[4]; + fltx4 m_Maxes[4]; + + FORCEINLINE bool Intersects(KDop32_t const& other) const; + + FORCEINLINE void operator|=(KDop32_t const& other); + + FORCEINLINE bool IsEmpty(void) const; + + FORCEINLINE void Init(void) + { + for (int i = 0; i < ARRAYSIZE(m_Mins); i++) + { + m_Mins[i] = Four_FLT_MAX; + m_Maxes[i] = Four_Negative_FLT_MAX; + } + } + + void AddPointSet(Vector const* pPoints, int nPnts); + + void CreateFromPointSet(Vector const* pPoints, int nPnts); +}; + +FORCEINLINE void KDop32_t::operator|=(KDop32_t const& other) +{ + m_Mins[0] = MinSIMD(m_Mins[0], other.m_Mins[0]); + m_Mins[1] = MinSIMD(m_Mins[1], other.m_Mins[1]); + m_Mins[2] = MinSIMD(m_Mins[2], other.m_Mins[2]); + m_Mins[3] = MinSIMD(m_Mins[3], other.m_Mins[3]); + + m_Maxes[0] = MaxSIMD(m_Maxes[0], other.m_Maxes[0]); + m_Maxes[1] = MaxSIMD(m_Maxes[1], other.m_Maxes[1]); + m_Maxes[2] = MaxSIMD(m_Maxes[2], other.m_Maxes[2]); + m_Maxes[3] = MaxSIMD(m_Maxes[3], other.m_Maxes[3]); + + +} + +FORCEINLINE bool KDop32_t::Intersects(KDop32_t const& other) const +{ + bi32x4 c00 = CmpLeSIMD(m_Mins[0], other.m_Maxes[0]); + bi32x4 c01 = CmpLeSIMD(m_Mins[1], other.m_Maxes[1]); + bi32x4 c02 = CmpLeSIMD(m_Mins[2], other.m_Maxes[2]); + bi32x4 c03 = CmpLeSIMD(m_Mins[3], other.m_Maxes[3]); + + bi32x4 c10 = CmpGeSIMD(m_Maxes[0], other.m_Mins[0]); + bi32x4 c11 = CmpGeSIMD(m_Maxes[1], other.m_Mins[1]); + bi32x4 c12 = CmpGeSIMD(m_Maxes[2], other.m_Mins[2]); + bi32x4 c13 = CmpGeSIMD(m_Maxes[3], other.m_Mins[3]); + + bi32x4 a0 = AndSIMD(AndSIMD(c00, c01), AndSIMD(c02, c03)); + bi32x4 a1 = AndSIMD(AndSIMD(c10, c11), AndSIMD(c12, c13)); + + return !(IsAnyZeros(AndSIMD(a1, a0))); +} + + +FORCEINLINE bool KDop32_t::IsEmpty(void) const +{ + bi32x4 c00 = CmpLtSIMD(m_Maxes[0], m_Mins[0]); + bi32x4 c01 = CmpLtSIMD(m_Maxes[1], m_Mins[1]); + bi32x4 c02 = CmpLtSIMD(m_Maxes[2], m_Mins[2]); + bi32x4 c03 = CmpLtSIMD(m_Maxes[3], m_Mins[3]); + + return IsAnyTrue(OrSIMD(OrSIMD(c00, c01), OrSIMD(c02, c03))); +} + + +extern const fltx4 g_KDop32XDirs[4]; +extern const fltx4 g_KDop32YDirs[4]; +extern const fltx4 g_KDop32ZDirs[4]; +#endif + +#if 0 + +#define _VEC_SWIZZLE_QUAT48_UNPACK (__vector unsigned char) { 16, 17, 0, 1, 16, 17, 2, 3, 16, 17, 4, 5, 16, 17, 6, 7 } +#define _VEC_SWIZZLE_QUAT48_UNPACK_SHIFT (__vector unsigned int ) { 0, 0, 1, 0 } + +FORCEINLINE fltx4 UnpackQuaternion48SIMD(const Quaternion48* RESTRICT pVec) +{ + fltx4 q16s = LoadUnaligned3SIMD((const float*)pVec); + + bool wneg = pVec->wneg; + + q16s = vec_perm(q16s, Four_Threes, _VEC_SWIZZLE_QUAT48_UNPACK); + + u32x4 tmp = IntShiftLeftWordSIMD(*(u32x4*)&q16s, _VEC_SWIZZLE_QUAT48_UNPACK_SHIFT); + q16s = *(fltx4*)&tmp; + + const fltx4 vUpkMul = SplatXSIMD(g_SIMD_Quat48_Unpack_Magic_Constants); + const fltx4 vUpkAdd = SplatYSIMD(g_SIMD_Quat48_Unpack_Magic_Constants); + + fltx4 ret = vec_madd(q16s, vUpkMul, vUpkAdd); + + fltx4 dotxyz = Dot3SIMD(ret, ret); + dotxyz = ClampVectorSIMD(dotxyz, Four_Zeros, Four_Ones); + + fltx4 ww = SubSIMD(Four_Ones, dotxyz); + ww = SqrtSIMD(ww); + if (wneg) + { + ret = SetWSIMD(ret, NegSIMD(ww)); + } + else + { + ret = SetWSIMD(ret, ww); + } + return ret; +} + +#endif + +FORCEINLINE fltx4 SetWFromXSIMD(const fltx4& a, const fltx4& x) +{ + fltx4 value = SplatXSIMD(x); + return SetWSIMD(a, value); +} + +FORCEINLINE fltx4 SetWFromYSIMD(const fltx4& a, const fltx4& y) +{ + fltx4 value = SplatYSIMD(y); + return SetWSIMD(a, value); +} + +FORCEINLINE fltx4 SetWFromZSIMD(const fltx4& a, const fltx4& z) +{ + fltx4 value = SplatZSIMD(z); + return SetWSIMD(a, value); +} + +FORCEINLINE fltx4 CrossProductSIMD(const fltx4& A, const fltx4& B) +{ +#if defined( _X360 ) + return XMVector3Cross(A, B); +#elif defined( _WIN32 ) + fltx4 A1 = _mm_shuffle_ps(A, A, MM_SHUFFLE_REV(1, 2, 0, 3)); + fltx4 B1 = _mm_shuffle_ps(B, B, MM_SHUFFLE_REV(2, 0, 1, 3)); + fltx4 Result1 = MulSIMD(A1, B1); + fltx4 A2 = _mm_shuffle_ps(A, A, MM_SHUFFLE_REV(2, 0, 1, 3)); + fltx4 B2 = _mm_shuffle_ps(B, B, MM_SHUFFLE_REV(1, 2, 0, 3)); + fltx4 Result2 = MulSIMD(A2, B2); + return SubSIMD(Result1, Result2); + +#elif defined(_PS3) + return _vmathVfCross(A, B); +#else + fltx4 CrossVal; + SubFloat(CrossVal, 0) = SubFloat(A, 1) * SubFloat(B, 2) - SubFloat(A, 2) * SubFloat(B, 1); + SubFloat(CrossVal, 1) = SubFloat(A, 2) * SubFloat(B, 0) - SubFloat(A, 0) * SubFloat(B, 2); + SubFloat(CrossVal, 2) = SubFloat(A, 0) * SubFloat(B, 1) - SubFloat(A, 1) * SubFloat(B, 0); + SubFloat(CrossVal, 3) = 0; + return CrossVal; +#endif +} + +inline const fltx4 Length3SIMD(const fltx4 vec) +{ + fltx4 scLengthSqr = Dot3SIMD(vec, vec); + bi32x4 isSignificant = CmpGtSIMD(scLengthSqr, Four_Epsilons); + fltx4 scLengthInv = ReciprocalSqrtSIMD(scLengthSqr); + return AndSIMD(isSignificant, MulSIMD(scLengthInv, scLengthSqr)); +} + +inline const fltx4 Normalized3SIMD(const fltx4 vec) +{ + fltx4 scLengthSqr = Dot3SIMD(vec, vec); + bi32x4 isSignificant = CmpGtSIMD(scLengthSqr, Four_Epsilons); + fltx4 scLengthInv = ReciprocalSqrtSIMD(scLengthSqr); + return AndSIMD(isSignificant, MulSIMD(vec, scLengthInv)); +} + + +#ifndef COMPILER_GCC + +FORCEINLINE fltx4 operator+=(fltx4& a, FLTX4 b) +{ + a = AddSIMD(a, b); + return a; +} + +FORCEINLINE fltx4 operator-=(fltx4& a, FLTX4 b) +{ + a = SubSIMD(a, b); + return a; +} + + +FORCEINLINE fltx4 operator*=(fltx4& a, FLTX4 b) +{ + a = MulSIMD(a, b); + return a; +} + +#endif +#endif +``` + +`SpyCustom/sdk/steam.h`: + +```h +#pragma once +#include + +template +__forceinline static FuncType CallVFunction(void* ppClass, int index) +{ + int* pVTable = *(int**)ppClass; + int dwAddress = pVTable[index]; + return (FuncType)(dwAddress); +} + +enum EGCResult +{ + k_EGCResultOK = 0, + k_EGCResultNoMessage = 1, + k_EGCResultBufferTooSmall = 2, + k_EGCResultNotLoggedOn = 3, + k_EGCResultInvalidMessage = 4, +}; + +class ISteamGameCoordinator +{ +public: + virtual EGCResult GCSendMessage(int unMsgType, const void* pubData, int cubData) = 0; + virtual bool IsMessageAvailable(int* pcubMsgSize) = 0; + virtual EGCResult GCRetrieveMessage(int* punMsgType, void* pubDest, int cubDest, int* pcubMsgSize) = 0; + +}; + +class CSteamID +{ +public: + CSteamID() + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = 0; + m_steamid.m_comp.m_EUniverse = 0; + m_steamid.m_comp.m_unAccountInstance = 0; + } + uint32_t GetAccountID() const { return m_steamid.m_comp.m_unAccountID; } + +private: + union SteamID_t + { + struct SteamIDComponent_t + { + uint32_t m_unAccountID : 32; + unsigned int m_unAccountInstance : 20; + unsigned int m_EAccountType : 4; + int m_EUniverse : 8; + } m_comp; + + uint64_t m_unAll64Bits; + } m_steamid; +}; + +class ISteamUser +{ +public: + virtual uint32_t GetHSteamUser() = 0; + virtual bool BLoggedOn() = 0; + virtual CSteamID GetSteamID() = 0; +}; + +class ISteamClient +{ +public: + ISteamUser* GetISteamUser(void* hSteamUser, void* hSteamPipe, const char* pchVersion) + { + typedef ISteamUser* (__stdcall* func)(void*, void*, const char*); + return CallVFunction(this, 5)(hSteamUser, hSteamPipe, pchVersion); + } + + ISteamGameCoordinator* GetISteamGenericInterface(void* hSteamUser, void* hSteamPipe, const char* pchVersion) + { + typedef ISteamGameCoordinator* (__stdcall* func)(void*, void*, const char*); + return CallVFunction(this, 12)(hSteamUser, hSteamPipe, pchVersion); + } +}; +``` + +`SpyCustom/sdk/steam_api.h`: + +```h +//====== Copyright 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef STEAM_API_H +#define STEAM_API_H +#ifdef _WIN32 +#pragma once +#endif + +#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 "isteamunifiedmessages.h" +#include "isteamcontroller.h" +#include "isteamugc.h" +#include "isteamapplist.h" +#include "isteamhtmlsurface.h" +#include "isteaminventory.h" +#include "isteamvideo.h" + + +// Steam API export macro +#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 + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// 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 ); + +// Most Steam API functions allocate some 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 ); + + +// If your application contains modules or libraries which could be built against different SDK +// versions, then you should define VERSION_SAFE_STEAM_API_INTERFACES to enforce that you cannot +// use the un-versioned global accessors. Instead, always create and use CSteamAPIContext objects +// to retrieve interface pointers which match the Steamworks SDK headers which match your build. +#if !defined( VERSION_SAFE_STEAM_API_INTERFACES ) && !defined( STEAM_API_EXPORTS ) +inline ISteamClient *SteamClient(); +inline ISteamUser *SteamUser(); +inline ISteamFriends *SteamFriends(); +inline ISteamUtils *SteamUtils(); +inline ISteamMatchmaking *SteamMatchmaking(); +inline ISteamUserStats *SteamUserStats(); +inline ISteamApps *SteamApps(); +inline ISteamNetworking *SteamNetworking(); +inline ISteamMatchmakingServers *SteamMatchmakingServers(); +inline ISteamRemoteStorage *SteamRemoteStorage(); +inline ISteamScreenshots *SteamScreenshots(); +inline ISteamHTTP *SteamHTTP(); +inline ISteamUnifiedMessages *SteamUnifiedMessages(); +inline ISteamController *SteamController(); +inline ISteamUGC *SteamUGC(); +inline ISteamAppList *SteamAppList(); +inline ISteamMusic *SteamMusic(); +inline ISteamMusicRemote *SteamMusicRemote(); +inline ISteamHTMLSurface *SteamHTMLSurface(); +inline ISteamInventory *SteamInventory(); +inline ISteamVideo *SteamVideo(); +#endif // VERSION_SAFE_STEAM_API_INTERFACES + + +// Every compiled module will have its own inlined definitions of CSteamAPIContext::Init. +// Do NOT share CSteamAPIContext pointers across modules unless you are sure that they will +// all be compiled against the same SDK! +class CSteamAPIContext +{ +public: + CSteamAPIContext() { Clear(); } + void Clear(); + + bool Init(); + + 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; } + 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; } + ISteamUnifiedMessages* SteamUnifiedMessages() const { return m_pSteamUnifiedMessages; } + 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; } + +private: + ISteamClient *m_pSteamClient; + ISteamUser *m_pSteamUser; + ISteamFriends *m_pSteamFriends; + ISteamUtils *m_pSteamUtils; + ISteamMatchmaking *m_pSteamMatchmaking; + ISteamUserStats *m_pSteamUserStats; + ISteamApps *m_pSteamApps; + ISteamMatchmakingServers *m_pSteamMatchmakingServers; + ISteamNetworking *m_pSteamNetworking; + ISteamRemoteStorage *m_pSteamRemoteStorage; + ISteamScreenshots *m_pSteamScreenshots; + ISteamHTTP *m_pSteamHTTP; + ISteamUnifiedMessages *m_pSteamUnifiedMessages; + ISteamController *m_pController; + ISteamUGC *m_pSteamUGC; + ISteamAppList *m_pSteamAppList; + ISteamMusic *m_pSteamMusic; + ISteamMusicRemote *m_pSteamMusicRemote; + ISteamHTMLSurface *m_pSteamHTMLSurface; + ISteamInventory *m_pSteamInventory; + ISteamVideo *m_pSteamVideo; +}; + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// 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(). +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// SteamAPI_RunCallbacks 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 ) + + +// 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 ); + + +//----------------------------------------------------------------------------- +// 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: + ~CCallbackImpl() { if ( m_nCallbackFlags & k_ECallbackFlagsRegistered ) SteamAPI_UnregisterCallback( this ); } + void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; } + +protected: + virtual void Run( void *pvParam ) = 0; + virtual void Run( void *pvParam, bool /*bIOFailure*/, SteamAPICall_t /*hSteamAPICall*/ ) { Run( pvParam ); } + virtual int GetCallbackSizeBytes() { return sizeof_P; } +}; + + +//----------------------------------------------------------------------------- +// Purpose: maps a steam async call result to a class member function +// template params: T = local class, P = parameter struct +//----------------------------------------------------------------------------- +template< class T, class P > +class CCallResult : private CCallbackBase +{ +public: + typedef void (T::*func_t)( P*, bool ); + + CCallResult(); + ~CCallResult(); + + void Set( SteamAPICall_t hAPICall, T *p, func_t func ); + bool IsActive() const; + void Cancel(); + + void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; } +private: + virtual void Run( void *pvParam ); + virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ); + virtual int GetCallbackSizeBytes() { return sizeof( P ); } + + SteamAPICall_t m_hAPICall; + T *m_pObj; + func_t m_Func; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: maps a steam callback to a class member function +// template params: T = local class, P = parameter struct, +// bGameserver = listen for gameserver callbacks instead of client callbacks +//----------------------------------------------------------------------------- +template< class T, class P, bool bGameserver = false > +class CCallback : public CCallbackImpl< sizeof( P ) > +{ +public: + typedef void (T::*func_t)(P*); + + // NOTE: If you can't provide the correct parameters at construction time, you should + // use the CCallbackManual callback object (STEAM_CALLBACK_MANUAL macro) instead. + CCallback( T *pObj, func_t func ); + + void Register( T *pObj, func_t func ); + void Unregister(); + +protected: + virtual void Run( void *pvParam ); + + T *m_pObj; + func_t m_Func; +}; + + +//----------------------------------------------------------------------------- +// Purpose: subclass of CCallback which allows default-construction in +// an unregistered state; you must call Register manually +//----------------------------------------------------------------------------- +template< class T, class P, bool bGameServer = false > +class CCallbackManual : public CCallback< T, P, bGameServer > +{ +public: + CCallbackManual() : CCallback< T, P, bGameServer >( NULL, NULL ) {} + + // Inherits public Register and Unregister functions from base class +}; + + + +#ifdef _WIN32 +// disable this warning; this pattern need for steam callback registration +#pragma warning( disable: 4355 ) // 'this' : used in base member initializer list +#endif + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// steamclient.dll private wrapper functions +// +// The following functions are part of abstracting API access to the steamclient.dll, but should only be used in very specific cases +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// SteamAPI_IsSteamRunning() returns true if Steam is currently running +S_API bool S_CALLTYPE SteamAPI_IsSteamRunning(); + +// Pumps out all the steam messages, calling registered callbacks. +// NOT THREADSAFE - do not call from multiple threads simultaneously. +S_API void Steam_RunCallbacks( HSteamPipe hSteamPipe, bool bGameServerCallbacks ); + +// register the callback funcs to use to interact with the steam dll +S_API void Steam_RegisterInterfaceFuncs( void *hModule ); + +// returns the HSteamUser of the last user to dispatch a callback +S_API HSteamUser Steam_GetHSteamUserCurrent(); + +// returns the filename path of the current running Steam process, used if you need to load an explicit steam dll by name. +// DEPRECATED - implementation is Windows only, and the path returned is a UTF-8 string which must be converted to UTF-16 for use with Win32 APIs +S_API const char *SteamAPI_GetSteamInstallPath(); + +// returns the pipe we are communicating to Steam with +S_API HSteamPipe SteamAPI_GetHSteamPipe(); + +// sets whether or not Steam_RunCallbacks() should do a try {} catch (...) {} around calls to issuing callbacks +S_API void SteamAPI_SetTryCatchCallbacks( bool bTryCatchCallbacks ); + +// backwards compat export, passes through to SteamAPI_ variants +S_API HSteamPipe GetHSteamPipe(); +S_API HSteamUser GetHSteamUser(); + + +#if defined( VERSION_SAFE_STEAM_API_INTERFACES ) +// backwards compat with older SDKs +S_API bool S_CALLTYPE SteamAPI_InitSafe(); +#endif + +#include "steam_api_internal.h" + +#endif // STEAM_API_H +``` + +`SpyCustom/sdk/steam_api_internal.h`: + +```h +//====== Copyright 1996-2015, Valve Corporation, All rights reserved. ======= +// +// Purpose: Internal private Steamworks API declarations and definitions +// +//============================================================================= + +#ifndef STEAM_API_INTERNAL_H +#define STEAM_API_INTERNAL_H + +S_API HSteamUser SteamAPI_GetHSteamUser(); +S_API bool S_CALLTYPE SteamInternal_Init(); +S_API void * S_CALLTYPE SteamInternal_CreateInterface( const char *ver ); +S_API void * S_CALLTYPE SteamGameServerInternal_CreateInterface( const char *ver ); + + +#if !defined( STEAM_API_EXPORTS ) + +#if !defined( VERSION_SAFE_STEAM_API_INTERFACES ) +inline CSteamAPIContext& SteamInternal_ModuleContext() +{ + // NOTE: declaring "static CSteamAPIConext" creates a large function + // which queries the initialization status of the object. We know that + // it is pointer-aligned and fully memset with zeros, so just alias a + // static buffer of the appropriate size and call it a CSteamAPIContext. + static void* ctx[ sizeof(CSteamAPIContext)/sizeof(void*) ]; + return *(CSteamAPIContext*)ctx; +} +#define _STEAMINTERNAL_ACCESSOR_BODY( AccessFunc ) \ + if ( !SteamAPI_GetHSteamPipe() ) return 0; \ + CSteamAPIContext &ctx = SteamInternal_ModuleContext(); \ + if ( !ctx.AccessFunc() ) ctx.Init(); \ + return ctx.AccessFunc(); +inline ISteamClient *SteamClient() { _STEAMINTERNAL_ACCESSOR_BODY( SteamClient ) } +inline ISteamUser *SteamUser() { _STEAMINTERNAL_ACCESSOR_BODY( SteamUser ) } +inline ISteamFriends *SteamFriends() { _STEAMINTERNAL_ACCESSOR_BODY( SteamFriends ) } +inline ISteamUtils *SteamUtils() { _STEAMINTERNAL_ACCESSOR_BODY( SteamUtils ) } +inline ISteamMatchmaking *SteamMatchmaking() { _STEAMINTERNAL_ACCESSOR_BODY( SteamMatchmaking ) } +inline ISteamUserStats *SteamUserStats() { _STEAMINTERNAL_ACCESSOR_BODY( SteamUserStats ) } +inline ISteamApps *SteamApps() { _STEAMINTERNAL_ACCESSOR_BODY( SteamApps ) } +inline ISteamMatchmakingServers *SteamMatchmakingServers() { _STEAMINTERNAL_ACCESSOR_BODY( SteamMatchmakingServers ) } +inline ISteamNetworking *SteamNetworking() { _STEAMINTERNAL_ACCESSOR_BODY( SteamNetworking ) } +inline ISteamRemoteStorage *SteamRemoteStorage() { _STEAMINTERNAL_ACCESSOR_BODY( SteamRemoteStorage ) } +inline ISteamScreenshots *SteamScreenshots() { _STEAMINTERNAL_ACCESSOR_BODY( SteamScreenshots ) } +inline ISteamHTTP *SteamHTTP() { _STEAMINTERNAL_ACCESSOR_BODY( SteamHTTP ) } +inline ISteamUnifiedMessages *SteamUnifiedMessages() { _STEAMINTERNAL_ACCESSOR_BODY( SteamUnifiedMessages ) } +inline ISteamController *SteamController() { _STEAMINTERNAL_ACCESSOR_BODY( SteamController ) } +inline ISteamUGC *SteamUGC() { _STEAMINTERNAL_ACCESSOR_BODY( SteamUGC ) } +inline ISteamAppList *SteamAppList() { _STEAMINTERNAL_ACCESSOR_BODY( SteamAppList ) } +inline ISteamMusic *SteamMusic() { _STEAMINTERNAL_ACCESSOR_BODY( SteamMusic ) } +inline ISteamMusicRemote *SteamMusicRemote() { _STEAMINTERNAL_ACCESSOR_BODY( SteamMusicRemote ) } +inline ISteamHTMLSurface *SteamHTMLSurface() { _STEAMINTERNAL_ACCESSOR_BODY( SteamHTMLSurface ) } +inline ISteamInventory *SteamInventory() { _STEAMINTERNAL_ACCESSOR_BODY( SteamInventory ) } +inline ISteamVideo *SteamVideo() { _STEAMINTERNAL_ACCESSOR_BODY( SteamVideo ) } +#undef _STEAMINTERNAL_ACCESSOR_BODY +#endif // !defined( VERSION_SAFE_STEAM_API_INTERFACES ) + +#endif // !defined( STEAM_API_EXPORTS ) + + +inline void CSteamAPIContext::Clear() +{ + m_pSteamClient = NULL; + m_pSteamUser = NULL; + m_pSteamFriends = NULL; + m_pSteamUtils = NULL; + m_pSteamMatchmaking = NULL; + m_pSteamUserStats = NULL; + m_pSteamApps = NULL; + m_pSteamMatchmakingServers = NULL; + m_pSteamNetworking = NULL; + m_pSteamRemoteStorage = NULL; + m_pSteamHTTP = NULL; + m_pSteamScreenshots = NULL; + m_pSteamMusic = NULL; + m_pSteamUnifiedMessages = NULL; + m_pController = NULL; + m_pSteamUGC = NULL; + m_pSteamAppList = NULL; + m_pSteamMusic = NULL; + m_pSteamMusicRemote = NULL; + m_pSteamHTMLSurface = NULL; + m_pSteamInventory = NULL; +} + + +// This function must be declared inline in the header so the module using steam_api.dll gets the version names they want. +inline bool CSteamAPIContext::Init() +{ + HSteamUser hSteamUser = SteamAPI_GetHSteamUser(); + HSteamPipe hSteamPipe = SteamAPI_GetHSteamPipe(); + if ( !hSteamPipe ) + return false; + + m_pSteamClient = (ISteamClient*) SteamInternal_CreateInterface( STEAMCLIENT_INTERFACE_VERSION ); + if ( !m_pSteamClient ) + return false; + + m_pSteamUser = m_pSteamClient->GetISteamUser( hSteamUser, hSteamPipe, STEAMUSER_INTERFACE_VERSION ); + if ( !m_pSteamUser ) + return false; + + m_pSteamFriends = m_pSteamClient->GetISteamFriends( hSteamUser, hSteamPipe, STEAMFRIENDS_INTERFACE_VERSION ); + if ( !m_pSteamFriends ) + return false; + + m_pSteamUtils = m_pSteamClient->GetISteamUtils( hSteamPipe, STEAMUTILS_INTERFACE_VERSION ); + if ( !m_pSteamUtils ) + return false; + + m_pSteamMatchmaking = m_pSteamClient->GetISteamMatchmaking( hSteamUser, hSteamPipe, STEAMMATCHMAKING_INTERFACE_VERSION ); + if ( !m_pSteamMatchmaking ) + return false; + + m_pSteamMatchmakingServers = m_pSteamClient->GetISteamMatchmakingServers( hSteamUser, hSteamPipe, STEAMMATCHMAKINGSERVERS_INTERFACE_VERSION ); + if ( !m_pSteamMatchmakingServers ) + return false; + + m_pSteamUserStats = m_pSteamClient->GetISteamUserStats( hSteamUser, hSteamPipe, STEAMUSERSTATS_INTERFACE_VERSION ); + if ( !m_pSteamUserStats ) + return false; + + m_pSteamApps = m_pSteamClient->GetISteamApps( hSteamUser, hSteamPipe, STEAMAPPS_INTERFACE_VERSION ); + if ( !m_pSteamApps ) + return false; + + m_pSteamNetworking = m_pSteamClient->GetISteamNetworking( hSteamUser, hSteamPipe, STEAMNETWORKING_INTERFACE_VERSION ); + if ( !m_pSteamNetworking ) + return false; + + m_pSteamRemoteStorage = m_pSteamClient->GetISteamRemoteStorage( hSteamUser, hSteamPipe, STEAMREMOTESTORAGE_INTERFACE_VERSION ); + if ( !m_pSteamRemoteStorage ) + return false; + + m_pSteamScreenshots = m_pSteamClient->GetISteamScreenshots( hSteamUser, hSteamPipe, STEAMSCREENSHOTS_INTERFACE_VERSION ); + if ( !m_pSteamScreenshots ) + return false; + + m_pSteamHTTP = m_pSteamClient->GetISteamHTTP( hSteamUser, hSteamPipe, STEAMHTTP_INTERFACE_VERSION ); + if ( !m_pSteamHTTP ) + return false; + + m_pSteamUnifiedMessages = m_pSteamClient->GetISteamUnifiedMessages( hSteamUser, hSteamPipe, STEAMUNIFIEDMESSAGES_INTERFACE_VERSION ); + if ( !m_pSteamUnifiedMessages ) + return false; + + m_pController = m_pSteamClient->GetISteamController( hSteamUser, hSteamPipe, STEAMCONTROLLER_INTERFACE_VERSION ); + if ( !m_pController ) + return false; + + m_pSteamUGC = m_pSteamClient->GetISteamUGC( hSteamUser, hSteamPipe, STEAMUGC_INTERFACE_VERSION ); + if ( !m_pSteamUGC ) + return false; + + m_pSteamAppList = m_pSteamClient->GetISteamAppList( hSteamUser, hSteamPipe, STEAMAPPLIST_INTERFACE_VERSION ); + if ( !m_pSteamAppList ) + return false; + + m_pSteamMusic = m_pSteamClient->GetISteamMusic( hSteamUser, hSteamPipe, STEAMMUSIC_INTERFACE_VERSION ); + if ( !m_pSteamMusic ) + return false; + + m_pSteamMusicRemote = m_pSteamClient->GetISteamMusicRemote( hSteamUser, hSteamPipe, STEAMMUSICREMOTE_INTERFACE_VERSION ); + if ( !m_pSteamMusicRemote ) + return false; + + m_pSteamHTMLSurface = m_pSteamClient->GetISteamHTMLSurface( hSteamUser, hSteamPipe, STEAMHTMLSURFACE_INTERFACE_VERSION ); + if ( !m_pSteamHTMLSurface ) + return false; + + m_pSteamInventory = m_pSteamClient->GetISteamInventory( hSteamUser, hSteamPipe, STEAMINVENTORY_INTERFACE_VERSION ); + if ( !m_pSteamInventory ) + return false; + + m_pSteamVideo = m_pSteamClient->GetISteamVideo( hSteamUser, hSteamPipe, STEAMVIDEO_INTERFACE_VERSION ); + if ( !m_pSteamVideo ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// The following macros are implementation details, not intended for public use +//----------------------------------------------------------------------------- +#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 ) + + +//----------------------------------------------------------------------------- +// 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 > +inline CCallResult::CCallResult() +{ + m_hAPICall = k_uAPICallInvalid; + m_pObj = NULL; + m_Func = NULL; + 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); + } +} + + +//----------------------------------------------------------------------------- +// 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 > +inline CCallback< T, P, bGameserver >::CCallback( T *pObj, func_t func ) + : m_pObj( NULL ), m_Func( NULL ) +{ + 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); +} + + +#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 + + +#endif // STEAM_API_INTERNAL_H +``` + +`SpyCustom/sdk/steamhttpenums.h`: + +```h +//====== Copyright © 1996-2010, Valve Corporation, All rights reserved. ======= +// +// Purpose: HTTP related enums, stuff that is shared by both clients and servers, and our +// UI projects goes here. +// +//============================================================================= + +#ifndef STEAMHTTPENUMS_H +#define STEAMHTTPENUMS_H +#ifdef _WIN32 +#pragma once +#endif + +// HTTP related types + +// This enum is used in client API methods, do not re-number existing values. +enum EHTTPMethod +{ + k_EHTTPMethodInvalid = 0, + k_EHTTPMethodGET, + k_EHTTPMethodHEAD, + k_EHTTPMethodPOST, + k_EHTTPMethodPUT, + k_EHTTPMethodDELETE, + k_EHTTPMethodOPTIONS, + k_EHTTPMethodPATCH, + + // The remaining HTTP methods are not yet supported, per rfc2616 section 5.1.1 only GET and HEAD are required for + // a compliant general purpose server. We'll likely add more as we find uses for them. + + // k_EHTTPMethodTRACE, + // k_EHTTPMethodCONNECT +}; + + +// HTTP Status codes that the server can send in response to a request, see rfc2616 section 10.3 for descriptions +// of each of these. +enum EHTTPStatusCode +{ + // Invalid status code (this isn't defined in HTTP, used to indicate unset in our code) + k_EHTTPStatusCodeInvalid = 0, + + // Informational codes + k_EHTTPStatusCode100Continue = 100, + k_EHTTPStatusCode101SwitchingProtocols = 101, + + // Success codes + k_EHTTPStatusCode200OK = 200, + k_EHTTPStatusCode201Created = 201, + k_EHTTPStatusCode202Accepted = 202, + k_EHTTPStatusCode203NonAuthoritative = 203, + k_EHTTPStatusCode204NoContent = 204, + k_EHTTPStatusCode205ResetContent = 205, + k_EHTTPStatusCode206PartialContent = 206, + + // Redirection codes + k_EHTTPStatusCode300MultipleChoices = 300, + k_EHTTPStatusCode301MovedPermanently = 301, + k_EHTTPStatusCode302Found = 302, + k_EHTTPStatusCode303SeeOther = 303, + k_EHTTPStatusCode304NotModified = 304, + k_EHTTPStatusCode305UseProxy = 305, + //k_EHTTPStatusCode306Unused = 306, (used in old HTTP spec, now unused in 1.1) + k_EHTTPStatusCode307TemporaryRedirect = 307, + + // Error codes + k_EHTTPStatusCode400BadRequest = 400, + k_EHTTPStatusCode401Unauthorized = 401, // You probably want 403 or something else. 401 implies you're sending a WWW-Authenticate header and the client can sent an Authorization header in response. + k_EHTTPStatusCode402PaymentRequired = 402, // This is reserved for future HTTP specs, not really supported by clients + k_EHTTPStatusCode403Forbidden = 403, + k_EHTTPStatusCode404NotFound = 404, + k_EHTTPStatusCode405MethodNotAllowed = 405, + k_EHTTPStatusCode406NotAcceptable = 406, + k_EHTTPStatusCode407ProxyAuthRequired = 407, + k_EHTTPStatusCode408RequestTimeout = 408, + k_EHTTPStatusCode409Conflict = 409, + k_EHTTPStatusCode410Gone = 410, + k_EHTTPStatusCode411LengthRequired = 411, + k_EHTTPStatusCode412PreconditionFailed = 412, + k_EHTTPStatusCode413RequestEntityTooLarge = 413, + k_EHTTPStatusCode414RequestURITooLong = 414, + k_EHTTPStatusCode415UnsupportedMediaType = 415, + k_EHTTPStatusCode416RequestedRangeNotSatisfiable = 416, + k_EHTTPStatusCode417ExpectationFailed = 417, + k_EHTTPStatusCode4xxUnknown = 418, // 418 is reserved, so we'll use it to mean unknown + k_EHTTPStatusCode429TooManyRequests = 429, + + // Server error codes + k_EHTTPStatusCode500InternalServerError = 500, + k_EHTTPStatusCode501NotImplemented = 501, + k_EHTTPStatusCode502BadGateway = 502, + k_EHTTPStatusCode503ServiceUnavailable = 503, + k_EHTTPStatusCode504GatewayTimeout = 504, + k_EHTTPStatusCode505HTTPVersionNotSupported = 505, + k_EHTTPStatusCode5xxUnknown = 599, +}; + +#endif // STEAMHTTPENUMS_H +``` + +`SpyCustom/sdk/steamtypes.h`: + +```h +//========= Copyright © 1996-2008, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMTYPES_H +#define STEAMTYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#define S_CALLTYPE __cdecl + +// Steam-specific types. Defined here so this header file can be included in other code bases. +#ifndef WCHARTYPES_H +typedef unsigned char uint8; +#endif + +#if defined( __GNUC__ ) && !defined(POSIX) +#if __GNUC__ < 4 +#error "Steamworks requires GCC 4.X (4.2 or 4.4 have been tested)" +#endif +#define POSIX 1 +#endif + +#if defined(__x86_64__) || defined(_WIN64) +#define X64BITS +#endif + +// Make sure VALVE_BIG_ENDIAN gets set on PS3, may already be set previously in Valve internal code. +#if !defined(VALVE_BIG_ENDIAN) && defined(_PS3) +#define VALVE_BIG_ENDIAN +#endif + +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( _WIN32 ) + +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; + +typedef int64 lint64; +typedef uint64 ulint64; + +#ifdef X64BITS +typedef __int64 intp; // intp is an integer that can accomodate a pointer +typedef unsigned __int64 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) +#else +typedef __int32 intp; +typedef unsigned __int32 uintp; +#endif + +#else // _WIN32 + +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; + +// [u]int64 are actually defined as 'long long' and gcc 64-bit +// doesn't automatically consider them the same as 'long int'. +// Changing the types for [u]int64 is complicated by +// there being many definitions, so we just +// define a 'long int' here and use it in places that would +// otherwise confuse the compiler. +typedef long int lint64; +typedef unsigned long int ulint64; + +#ifdef X64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif + +#endif // else _WIN32 + +#ifdef API_GEN +# define CLANG_ATTR(ATTR) __attribute__((annotate( ATTR ))) +#else +# define CLANG_ATTR(ATTR) +#endif + +#define METHOD_DESC(DESC) CLANG_ATTR( "desc:" #DESC ";" ) +#define IGNOREATTR() CLANG_ATTR( "ignore" ) +#define OUT_STRUCT() CLANG_ATTR( "out_struct: ;" ) +#define OUT_STRING() CLANG_ATTR( "out_string: ;" ) +#define OUT_ARRAY_CALL(COUNTER,FUNCTION,PARAMS) CLANG_ATTR( "out_array_call:" #COUNTER "," #FUNCTION "," #PARAMS ";" ) +#define OUT_ARRAY_COUNT(COUNTER, DESC) CLANG_ATTR( "out_array_count:" #COUNTER ";desc:" #DESC ) +#define ARRAY_COUNT(COUNTER) CLANG_ATTR( "array_count:" #COUNTER ";" ) +#define ARRAY_COUNT_D(COUNTER, DESC) CLANG_ATTR( "array_count:" #COUNTER ";desc:" #DESC ) +#define BUFFER_COUNT(COUNTER) CLANG_ATTR( "buffer_count:" #COUNTER ";" ) +#define OUT_BUFFER_COUNT(COUNTER) CLANG_ATTR( "out_buffer_count:" #COUNTER ";" ) +#define OUT_STRING_COUNT(COUNTER) CLANG_ATTR( "out_string_count:" #COUNTER ";" ) +#define DESC(DESC) CLANG_ATTR("desc:" #DESC ";") +#define CALL_RESULT(RESULT_TYPE) CLANG_ATTR("callresult:" #RESULT_TYPE ";") +#define CALL_BACK(RESULT_TYPE) CLANG_ATTR("callback:" #RESULT_TYPE ";") + +const int k_cubSaltSize = 8; +typedef uint8 Salt_t[k_cubSaltSize]; + +//----------------------------------------------------------------------------- +// GID (GlobalID) stuff +// This is a globally unique identifier. It's guaranteed to be unique across all +// racks and servers for as long as a given universe persists. +//----------------------------------------------------------------------------- +// NOTE: for GID parsing/rendering and other utils, see gid.h +typedef uint64 GID_t; + +const GID_t k_GIDNil = 0xffffffffffffffffull; + +// For convenience, we define a number of types that are just new names for GIDs +typedef uint64 JobID_t; // Each Job has a unique ID +typedef GID_t TxnID_t; // Each financial transaction has a unique ID + +const GID_t k_TxnIDNil = k_GIDNil; +const GID_t k_TxnIDUnknown = 0; + +const JobID_t k_JobIDNil = 0xffffffffffffffffull; + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. +typedef uint32 PackageId_t; +const PackageId_t k_uPackageIdFreeSub = 0x0; +const PackageId_t k_uPackageIdInvalid = 0xFFFFFFFF; + +typedef uint32 BundleId_t; +const BundleId_t k_uBundleIdInvalid = 0; + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. +typedef uint32 AppId_t; +const AppId_t k_uAppIdInvalid = 0x0; + +typedef uint64 AssetClassId_t; +const AssetClassId_t k_ulAssetClassIdInvalid = 0x0; + +typedef uint32 PhysicalItemId_t; +const PhysicalItemId_t k_uPhysicalItemIdInvalid = 0x0; + + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. AppIds and DepotIDs also presently +// share the same namespace, but since we'd like to change that in the future +// I've defined it seperately here. +typedef uint32 DepotId_t; +const DepotId_t k_uDepotIdInvalid = 0x0; + +// RTime32 +// We use this 32 bit time representing real world time. +// It offers 1 second resolution beginning on January 1, 1970 (Unix time) +typedef uint32 RTime32; + +typedef uint32 CellID_t; +const CellID_t k_uCellIDInvalid = 0xFFFFFFFF; + +// handle to a Steam API call +typedef uint64 SteamAPICall_t; +const SteamAPICall_t k_uAPICallInvalid = 0x0; + +typedef uint32 AccountID_t; + +typedef uint32 PartnerId_t; +const PartnerId_t k_uPartnerIdInvalid = 0; + +// ID for a depot content manifest +typedef uint64 ManifestId_t; +const ManifestId_t k_uManifestIdInvalid = 0; + + + +#endif // STEAMTYPES_H +``` + +`SpyCustom/sdk/string_t.h`: + +```h +#ifndef STRING_T_H +#define STRING_T_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifndef NO_STRING_T + +#ifdef WEAK_STRING_T + +typedef int string_t; + +#define NULL_STRING 0 + +#define STRING( offset ) ( ( offset ) ? reinterpret_cast( offset ) : "" ) + +#define MAKE_STRING( str ) ( ( *str != 0 ) ? reinterpret_cast( str ) : 0 ) + +#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) ) + +#else + +struct string_t +{ +public: + bool operator!() const { return (pszValue == NULL); } + bool operator==(const string_t& rhs) const { return (pszValue == rhs.pszValue); } + bool operator!=(const string_t& rhs) const { return (pszValue != rhs.pszValue); } + bool operator<(const string_t& rhs) const { return ((void*)pszValue < (void*)rhs.pszValue); } + + const char* ToCStr() const { return (pszValue) ? pszValue : ""; } + +protected: + const char* pszValue; +}; + +struct castable_string_t : public string_t +{ + castable_string_t() { pszValue = NULL; } + castable_string_t(const char* pszFrom) { pszValue = (pszFrom && *pszFrom) ? pszFrom : 0; } +}; + +#define NULL_STRING castable_string_t() + +#define STRING( string_t_obj ) (string_t_obj).ToCStr() + +#define MAKE_STRING( c_str ) castable_string_t( c_str ) + +#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) ) + +#endif + +#else + +typedef const char* string_t; +#define NULL_STRING 0 +#define STRING( c_str ) ( c_str ) +#define MAKE_STRING( c_str ) ( c_str ) +#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) ) + +#endif + +inline void EnsureValidValue(string_t& x) { x = NULL_STRING; } + +#endif + +``` + +`SpyCustom/sdk/stringpool.h`: + +```h +#ifndef STRINGPOOL_H +#define STRINGPOOL_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "utlrbtree.h" +#include "utlvector.h" +#include "utlbuffer.h" +#include "generichash.h" + +enum StringPoolCase_t +{ + StringPoolCaseInsensitive, + StringPoolCaseSensitive +}; + +class CStringPool +{ +public: + CStringPool(StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive); + ~CStringPool(); + + unsigned int Count() const; + + const char* Allocate(const char* pszValue); + void FreeAll(); + + const char* Find(const char* pszValue); + +protected: + typedef CUtlRBTree CStrSet; + + CStrSet m_Strings; +}; + +template +class CCountedStringPoolBase +{ +public: + + struct hash_item_t + { + char* pString; + T nNextElement; + unsigned char nReferenceCount; + unsigned char pad; + }; + + enum + { + INVALID_ELEMENT = 0, + MAX_REFERENCE = 0xFF, + HASH_TABLE_SIZE = 1024 + }; + + CUtlVector m_HashTable; + CUtlVector m_Elements; + T m_FreeListStart; + StringPoolCase_t m_caseSensitivity; + +public: + CCountedStringPoolBase(StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive); + virtual ~CCountedStringPoolBase(); + + void FreeAll(); + + char* FindString(const char* pIntrinsic); + char* ReferenceString(const char* pIntrinsic); + void DereferenceString(const char* pIntrinsic); + + T FindStringHandle(const char* pIntrinsic); + T ReferenceStringHandle(const char* pIntrinsic); + char* HandleToString(T handle); + void SpewStrings(); + unsigned Hash(const char* pszKey); + + bool SaveToBuffer(CUtlBuffer& buffer); + bool RestoreFromBuffer(CUtlBuffer& buffer); + + void VerifyNotOverflowed(unsigned int value); +}; + +typedef CCountedStringPoolBase CCountedStringPool; + +template +inline CCountedStringPoolBase::CCountedStringPoolBase(StringPoolCase_t caseSensitivity) +{ + MEM_ALLOC_CREDIT(); + m_HashTable.EnsureCount(HASH_TABLE_SIZE); + + for (int i = 0; i < m_HashTable.Count(); i++) + { + m_HashTable[i] = INVALID_ELEMENT; + } + + m_FreeListStart = INVALID_ELEMENT; + m_Elements.AddToTail(); + m_Elements[0].pString = NULL; + m_Elements[0].nReferenceCount = 0; + m_Elements[0].nNextElement = INVALID_ELEMENT; + + m_caseSensitivity = caseSensitivity; +} + +template +inline CCountedStringPoolBase::~CCountedStringPoolBase() +{ + FreeAll(); +} + +template +inline void CCountedStringPoolBase::FreeAll() +{ + int i; + + for (i = 0; i < m_HashTable.Count(); i++) + { + m_HashTable[i] = INVALID_ELEMENT; + } + + m_FreeListStart = INVALID_ELEMENT; + + for (i = 0; i < m_Elements.Count(); i++) + { + if (m_Elements[i].pString) + { + delete[] m_Elements[i].pString; + m_Elements[i].pString = NULL; + m_Elements[i].nReferenceCount = 0; + m_Elements[i].nNextElement = INVALID_ELEMENT; + } + } + + m_Elements.RemoveAll(); + m_Elements.AddToTail(); + m_Elements[0].pString = NULL; + m_Elements[0].nReferenceCount = 0; + m_Elements[0].nNextElement = INVALID_ELEMENT; +} + +template +inline unsigned CCountedStringPoolBase::Hash(const char* pszKey) +{ + if (m_caseSensitivity == StringPoolCaseInsensitive) + { + return HashStringCaseless(pszKey); + } + return HashString(pszKey); +} + +template +inline T CCountedStringPoolBase::FindStringHandle(const char* pIntrinsic) +{ + if (pIntrinsic == NULL) + return INVALID_ELEMENT; + + T nHashBucketIndex = (Hash(pIntrinsic) % HASH_TABLE_SIZE); + T nCurrentBucket = m_HashTable[nHashBucketIndex]; + + if (nCurrentBucket != INVALID_ELEMENT) + { + for (; nCurrentBucket != INVALID_ELEMENT; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement) + { + if (!Q_stricmp(pIntrinsic, m_Elements[nCurrentBucket].pString)) + { + return nCurrentBucket; + } + } + } + + return 0; + +} + +template +inline char* CCountedStringPoolBase::FindString(const char* pIntrinsic) +{ + if (pIntrinsic == NULL) + return NULL; + + return m_Elements[FindStringHandle(pIntrinsic)].pString; +} + +template +inline T CCountedStringPoolBase::ReferenceStringHandle(const char* pIntrinsic) +{ + if (pIntrinsic == NULL) + return INVALID_ELEMENT; + + T nHashBucketIndex = (Hash(pIntrinsic) % HASH_TABLE_SIZE); + T nCurrentBucket = m_HashTable[nHashBucketIndex]; + + if (nCurrentBucket != INVALID_ELEMENT) + { + for (; nCurrentBucket != INVALID_ELEMENT; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement) + { + if (!Q_stricmp(pIntrinsic, m_Elements[nCurrentBucket].pString)) + { + if (m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE) + { + m_Elements[nCurrentBucket].nReferenceCount++; + } + return nCurrentBucket; + } + } + } + + if (m_FreeListStart != INVALID_ELEMENT) + { + nCurrentBucket = m_FreeListStart; + m_FreeListStart = m_Elements[nCurrentBucket].nNextElement; + } + else + { + unsigned int newElement = m_Elements.AddToTail(); + VerifyNotOverflowed(newElement); + nCurrentBucket = newElement; + } + + m_Elements[nCurrentBucket].nReferenceCount = 1; + + m_Elements[nCurrentBucket].nNextElement = m_HashTable[nHashBucketIndex]; + m_HashTable[nHashBucketIndex] = nCurrentBucket; + + m_Elements[nCurrentBucket].pString = new char[Q_strlen(pIntrinsic) + 1]; + Q_strcpy(m_Elements[nCurrentBucket].pString, pIntrinsic); + + return nCurrentBucket; +} + +template<> +inline void CCountedStringPoolBase::VerifyNotOverflowed(unsigned int value) { Assert(value < 0xffff); } + +template<> +inline void CCountedStringPoolBase::VerifyNotOverflowed(unsigned int value) {} + +template +inline char* CCountedStringPoolBase::ReferenceString(const char* pIntrinsic) +{ + if (!pIntrinsic) + return NULL; + + return m_Elements[ReferenceStringHandle(pIntrinsic)].pString; +} + +template +inline void CCountedStringPoolBase::DereferenceString(const char* pIntrinsic) +{ + if (!pIntrinsic) + return; + + T nHashBucketIndex = (Hash(pIntrinsic) % m_HashTable.Count()); + T nCurrentBucket = m_HashTable[nHashBucketIndex]; + + if (nCurrentBucket == INVALID_ELEMENT) + return; + + for (T previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement) + { + if (!Q_stricmp(pIntrinsic, m_Elements[nCurrentBucket].pString)) + { + if (m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE) + { + m_Elements[nCurrentBucket].nReferenceCount--; + } + + if (m_Elements[nCurrentBucket].nReferenceCount == 0) + { + if (previous == INVALID_ELEMENT) + { + m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement; + } + else + { + m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement; + } + + delete[] m_Elements[nCurrentBucket].pString; + m_Elements[nCurrentBucket].pString = NULL; + m_Elements[nCurrentBucket].nReferenceCount = 0; + + m_Elements[nCurrentBucket].nNextElement = m_FreeListStart; + m_FreeListStart = nCurrentBucket; + break; + + } + } + + previous = nCurrentBucket; + } +} + +template +inline char* CCountedStringPoolBase::HandleToString(T handle) +{ + return m_Elements[handle].pString; +} + +template +inline void CCountedStringPoolBase::SpewStrings() +{ + int i; + for (i = 0; i < m_Elements.Count(); i++) + { + char* string = m_Elements[i].pString; + + Msg("String %d: ref:%d %s\n", i, m_Elements[i].nReferenceCount, string == NULL ? "EMPTY - ok for slot zero only!" : string); + } + + Msg("\n%d total counted strings.", m_Elements.Count()); +} + +#define STRING_POOL_VERSION MAKEID( 'C', 'S', 'P', '1' ) +#define MAX_STRING_SAVE 1024 + +template<> +inline bool CCountedStringPoolBase::SaveToBuffer(CUtlBuffer& buffer) +{ + if (m_Elements.Count() <= 1) + { + return true; + } + + buffer.PutInt(STRING_POOL_VERSION); + + buffer.PutUnsignedShort(m_FreeListStart); + + buffer.PutInt(m_HashTable.Count()); + for (int i = 0; i < m_HashTable.Count(); i++) + { + buffer.PutUnsignedShort(m_HashTable[i]); + } + + buffer.PutInt(m_Elements.Count()); + for (int i = 1; i < m_Elements.Count(); i++) + { + buffer.PutUnsignedShort(m_Elements[i].nNextElement); + buffer.PutUnsignedChar(m_Elements[i].nReferenceCount); + + const char* pString = m_Elements[i].pString; + if (strlen(pString) >= MAX_STRING_SAVE) + { + return false; + } + buffer.PutString(pString ? pString : ""); + } + + return buffer.IsValid(); +} + +template<> +inline bool CCountedStringPoolBase::RestoreFromBuffer(CUtlBuffer& buffer) +{ + int signature = buffer.GetInt(); + if (signature != STRING_POOL_VERSION) + { + return false; + } + + FreeAll(); + + m_FreeListStart = buffer.GetUnsignedShort(); + + int hashCount = buffer.GetInt(); + m_HashTable.SetCount(hashCount); + + for (int i = 0; i < hashCount; i++) + { + m_HashTable[i] = buffer.GetUnsignedShort(); + } + + int tableCount = buffer.GetInt(); + if (tableCount > 1) + { + m_Elements.AddMultipleToTail(tableCount - 1); + } + + char tempString[MAX_STRING_SAVE]; + for (int i = 1; i < tableCount; i++) + { + m_Elements[i].nNextElement = buffer.GetUnsignedShort(); + m_Elements[i].nReferenceCount = buffer.GetUnsignedChar(); + buffer.GetString(tempString, sizeof(tempString)); + m_Elements[i].pString = strdup(tempString); + } + + return buffer.IsValid(); +} + +template<> +inline bool CCountedStringPoolBase::SaveToBuffer(CUtlBuffer& buffer) +{ + if (m_Elements.Count() <= 1) + { + return true; + } + + buffer.PutInt(STRING_POOL_VERSION); + + buffer.PutUnsignedInt(m_FreeListStart); + + buffer.PutInt(m_HashTable.Count()); + for (int i = 0; i < m_HashTable.Count(); i++) + { + buffer.PutUnsignedInt(m_HashTable[i]); + } + + buffer.PutInt(m_Elements.Count()); + for (int i = 1; i < m_Elements.Count(); i++) + { + buffer.PutUnsignedInt(m_Elements[i].nNextElement); + buffer.PutUnsignedChar(m_Elements[i].nReferenceCount); + + const char* pString = m_Elements[i].pString; + if (strlen(pString) >= MAX_STRING_SAVE) + { + return false; + } + buffer.PutString(pString ? pString : ""); + } + + return buffer.IsValid(); +} + +template<> +inline bool CCountedStringPoolBase::RestoreFromBuffer(CUtlBuffer& buffer) +{ + int signature = buffer.GetInt(); + if (signature != STRING_POOL_VERSION) + { + return false; + } + + FreeAll(); + + m_FreeListStart = buffer.GetUnsignedInt(); + + int hashCount = buffer.GetInt(); + m_HashTable.SetCount(hashCount); + + for (int i = 0; i < hashCount; i++) + { + m_HashTable[i] = buffer.GetUnsignedInt(); + } + + int tableCount = buffer.GetInt(); + if (tableCount > 1) + { + m_Elements.AddMultipleToTail(tableCount - 1); + } + + char tempString[MAX_STRING_SAVE]; + for (int i = 1; i < tableCount; i++) + { + m_Elements[i].nNextElement = buffer.GetUnsignedInt(); + m_Elements[i].nReferenceCount = buffer.GetUnsignedChar(); + buffer.GetString(tempString, sizeof(tempString)); + m_Elements[i].pString = strdup(tempString); + } + + return buffer.IsValid(); +} +#endif +``` + +`SpyCustom/sdk/strtools.h`: + +```h +#ifndef TIER1_STRTOOLS_H +#define TIER1_STRTOOLS_H + +#include "platform.h" + +#include +#include +#ifdef _WIN32 +#pragma once +#elif POSIX +#include +#include +#include +#endif + +#include +#include + +#ifdef _WIN64 +#define str_size unsigned int +#else +#define str_size size_t +#endif + +template< class T, class I > class CUtlMemory; +template< class T, class A > class CUtlVector; + + +void _V_memset(const char* file, int line, void* dest, int fill, int count); +void _V_memcpy(const char* file, int line, void* dest, const void* src, int count); +void _V_memmove(const char* file, int line, void* dest, const void* src, int count); +int _V_memcmp(const char* file, int line, const void* m1, const void* m2, int count); +int _V_strlen(const char* file, int line, const char* str); +void _V_strcpy(const char* file, int line, char* dest, const char* src); +char* _V_strrchr(const char* file, int line, const char* s, char c); +int _V_strcmp(const char* file, int line, const char* s1, const char* s2); +int _V_wcscmp(const char* file, int line, const wchar_t* s1, const wchar_t* s2); +char* _V_strstr(const char* file, int line, const char* s1, const char* search); +int _V_wcslen(const char* file, int line, const wchar_t* pwch); +wchar_t* _V_wcslower(const char* file, int line, wchar_t* start); +wchar_t* _V_wcsupr(const char* file, int line, wchar_t* start); + +char* V_strupr(char* start); +char* V_strlower(char* start); +int V_stricmp(const char* s1, const char* s2); +int V_strncmp(const char* s1, const char* s2, int count); +int V_strnicmp(const char* s1, const char* s2, int n); + +#ifdef POSIX + +inline char* strupr(char* start) +{ + return V_strupr(start); +} + +inline char* strlwr(char* start) +{ + return V_strlower(start); +} + +inline wchar_t* _wcslwr(wchar_t* start) +{ + wchar_t* str = start; + while (str && *str) + { + *str = (wchar_t)towlower(static_cast(*str)); + str++; + } + return start; +}; + +inline wchar_t* _wcsupr(wchar_t* start) +{ + wchar_t* str = start; + while (str && *str) + { + *str = (wchar_t)towupper(static_cast(*str)); + str++; + } + return start; +}; + +#endif + + +#ifdef _DEBUG + +#define V_memset(dest, fill, count) _V_memset (__FILE__, __LINE__, (dest), (fill), (count)) +#define V_memcpy(dest, src, count) _V_memcpy (__FILE__, __LINE__, (dest), (src), (count)) +#define V_memmove(dest, src, count) _V_memmove (__FILE__, __LINE__, (dest), (src), (count)) +#define V_memcmp(m1, m2, count) _V_memcmp (__FILE__, __LINE__, (m1), (m2), (count)) +#define V_strlen(str) _V_strlen (__FILE__, __LINE__, (str)) +#define V_strcpy(dest, src) _V_strcpy (__FILE__, __LINE__, (dest), (src)) +#define V_strrchr(s, c) _V_strrchr (__FILE__, __LINE__, (s), (c)) +#define V_strcmp(s1, s2) _V_strcmp (__FILE__, __LINE__, (s1), (s2)) +#define V_wcscmp(s1, s2) _V_wcscmp (__FILE__, __LINE__, (s1), (s2)) +#define V_strstr(s1, search ) _V_strstr (__FILE__, __LINE__, (s1), (search) ) +#define V_wcslen(pwch) _V_wcslen (__FILE__, __LINE__, (pwch)) +#define V_wcslower(start) _V_wcslower (__FILE__, __LINE__, (start)) +#define V_wcsupr(start) _V_wcsupr (__FILE__, __LINE__, (start)) + +#else + + +inline void V_memset(void* dest, int fill, int count) { memset(dest, fill, count); } +inline void V_memcpy(void* dest, const void* src, int count) { memcpy(dest, src, count); } +inline void V_memmove(void* dest, const void* src, int count) { memmove(dest, src, count); } +inline int V_memcmp(const void* m1, const void* m2, int count) { return memcmp(m1, m2, count); } +inline int V_strlen(const char* str) { return (int)strlen(str); } +inline void V_strcpy(char* dest, const char* src) { strcpy(dest, src); } +inline int V_wcslen(const wchar_t* pwch) { return (int)wcslen(pwch); } +inline char* V_strrchr(const char* s, char c) { return (char*)strrchr(s, c); } +inline int V_strcmp(const char* s1, const char* s2) { return strcmp(s1, s2); } +inline int V_wcscmp(const wchar_t* s1, const wchar_t* s2) { return wcscmp(s1, s2); } +inline char* V_strstr(const char* s1, const char* search) { return (char*)strstr(s1, search); } +inline wchar_t* V_wcslower(wchar_t* start) { return _wcslwr(start); } +inline wchar_t* V_wcsupr(wchar_t* start) { return _wcsupr(start); } + +#endif + +int V_atoi(const char* str); +int64 V_atoi64(const char* str); +uint64 V_atoui64(const char* str); +float V_atof(const char* str); +char* V_stristr(char* pStr, const char* pSearch); +const char* V_stristr(const char* pStr, const char* pSearch); +const char* V_strnistr(const char* pStr, const char* pSearch, int n); +const char* V_strnchr(const char* pStr, char c, int n); +inline int V_strcasecmp(const char* s1, const char* s2) { return V_stricmp(s1, s2); } +inline int V_strncasecmp(const char* s1, const char* s2, int n) { return V_strnicmp(s1, s2, n); } +void V_qsort_s(void* base, size_t num, size_t width, int(__cdecl* compare)(void*, const void*, + const void*), void* context); + + +const char* StringAfterPrefix(const char* str, const char* prefix); +const char* StringAfterPrefixCaseSensitive(const char* str, const char* prefix); +inline bool StringHasPrefix(const char* str, const char* prefix) { return StringAfterPrefix(str, prefix) != NULL; } +inline bool StringHasPrefixCaseSensitive(const char* str, const char* prefix) { return StringAfterPrefixCaseSensitive(str, prefix) != NULL; } + + +void V_normalizeFloatString(char* pFloat); + +inline bool V_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +inline bool V_isalpha(char c) { return isalpha((unsigned char)c) != 0; } +inline bool V_isalnum(char c) { return isalnum((unsigned char)c) != 0; } +inline bool V_isprint(char c) { return isprint((unsigned char)c) != 0; } +inline bool V_isxdigit(char c) { return isxdigit((unsigned char)c) != 0; } +inline bool V_ispunct(char c) { return ispunct((unsigned char)c) != 0; } +inline bool V_isgraph(char c) { return isgraph((unsigned char)c) != 0; } +inline bool V_isupper(char c) { return isupper((unsigned char)c) != 0; } +inline bool V_islower(char c) { return islower((unsigned char)c) != 0; } +inline bool V_iscntrl(char c) { return iscntrl((unsigned char)c) != 0; } +inline bool V_isspace(char c) { return isspace((unsigned char)c) != 0; } + +void V_strncpy(OUT_Z_CAP(maxLenInChars) char* pDest, const char* pSrc, int maxLenInChars); + +template void V_strcpy_safe(OUT_Z_ARRAY char(&pDest)[maxLenInChars], const char* pSrc) +{ + V_strncpy(pDest, pSrc, (int)maxLenInChars); +} + +void V_wcsncpy(OUT_Z_BYTECAP(maxLenInBytes) wchar_t* pDest, wchar_t const* pSrc, int maxLenInBytes); +template void V_wcscpy_safe(OUT_Z_ARRAY wchar_t(&pDest)[maxLenInChars], wchar_t const* pSrc) +{ + V_wcsncpy(pDest, pSrc, maxLenInChars * sizeof(*pDest)); +} + +#define COPY_ALL_CHARACTERS -1 +char* V_strncat(INOUT_Z_CAP(cchDest) char* pDest, const char* pSrc, size_t cchDest, int max_chars_to_copy = COPY_ALL_CHARACTERS); +template char* V_strcat_safe(INOUT_Z_ARRAY char(&pDest)[cchDest], const char* pSrc, int nMaxCharsToCopy = COPY_ALL_CHARACTERS) +{ + return V_strncat(pDest, pSrc, (int)cchDest, nMaxCharsToCopy); +} + +wchar_t* V_wcsncat(INOUT_Z_CAP(cchDest) wchar_t* pDest, const wchar_t* pSrc, size_t cchDest, int nMaxCharsToCopy = COPY_ALL_CHARACTERS); +template wchar_t* V_wcscat_safe(INOUT_Z_ARRAY wchar_t(&pDest)[cchDest], const wchar_t* pSrc, int nMaxCharsToCopy = COPY_ALL_CHARACTERS) +{ + return V_wcsncat(pDest, pSrc, (int)cchDest, nMaxCharsToCopy); +} + +char* V_strnlwr(INOUT_Z_CAP(cchBuf) char* pBuf, size_t cchBuf); +template char* V_strlwr_safe(INOUT_Z_ARRAY char(&pBuf)[cchDest]) +{ + return _V_strnlwr(pBuf, (int)cchDest); +} + + +#ifdef _WIN32 +#ifndef _VA_LIST_DEFINED + +#ifdef _M_ALPHA + +struct va_list +{ + char* a0; + int offset; +}; + +#else + +typedef char* va_list; + +#endif + +#define _VA_LIST_DEFINED + +#endif + +#elif POSIX +#include +#endif + +#ifdef _WIN32 +#define CORRECT_PATH_SEPARATOR '\\' +#define CORRECT_PATH_SEPARATOR_S "\\" +#define INCORRECT_PATH_SEPARATOR '/' +#define INCORRECT_PATH_SEPARATOR_S "/" +#elif POSIX +#define CORRECT_PATH_SEPARATOR '/' +#define CORRECT_PATH_SEPARATOR_S "/" +#define INCORRECT_PATH_SEPARATOR '\\' +#define INCORRECT_PATH_SEPARATOR_S "\\" +#endif + +int V_vsnprintf(OUT_Z_CAP(maxLenInCharacters) char* pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char* pFormat, va_list params); +template int V_vsprintf_safe(OUT_Z_ARRAY char(&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char* pFormat, va_list params) { return V_vsnprintf(pDest, maxLenInCharacters, pFormat, params); } + +int V_snprintf(OUT_Z_CAP(maxLenInChars) char* pDest, int maxLenInChars, PRINTF_FORMAT_STRING const char* pFormat, ...) FMTFUNCTION(3, 4); +template int V_sprintf_safe(OUT_Z_ARRAY char(&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char* pFormat, ...) FMTFUNCTION(2, 3); +template int V_sprintf_safe(OUT_Z_ARRAY char(&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char* pFormat, ...) +{ + va_list params; + va_start(params, pFormat); + int result = V_vsnprintf(pDest, maxLenInChars, pFormat, params); + va_end(params); + return result; +} + +int V_vsnwprintf(OUT_Z_CAP(maxLenInCharacters) wchar_t* pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t* pFormat, va_list params); +template int V_vswprintf_safe(OUT_Z_ARRAY wchar_t(&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const wchar_t* pFormat, va_list params) { return V_vsnwprintf(pDest, maxLenInCharacters, pFormat, params); } +int V_vsnprintfRet(OUT_Z_CAP(maxLenInCharacters) char* pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char* pFormat, va_list params, bool* pbTruncated); +template int V_vsprintfRet_safe(OUT_Z_ARRAY char(&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char* pFormat, va_list params, bool* pbTruncated) { return V_vsnprintfRet(pDest, maxLenInCharacters, pFormat, params, pbTruncated); } + +int V_snwprintf(OUT_Z_CAP(maxLenInCharacters) wchar_t* pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t* pFormat, ...); +template int V_swprintf_safe(OUT_Z_ARRAY wchar_t(&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const wchar_t* pFormat, ...) +{ + va_list params; + va_start(params, pFormat); + int result = V_vsnwprintf(pDest, maxLenInChars, pFormat, params); + va_end(params); + return result; +} + +char* V_pretifymem(float value, int digitsafterdecimal = 2, bool usebinaryonek = false); + +char* V_pretifynum(int64 value); + +int V_UTF8ToUnicode(const char* pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t* pwchDest, int cubDestSizeInBytes); +int V_UnicodeToUTF8(const wchar_t* pUnicode, OUT_Z_BYTECAP(cubDestSizeInBytes) char* pUTF8, int cubDestSizeInBytes); +int V_UCS2ToUnicode(const ucs2* pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t* pUnicode, int cubDestSizeInBytes); +int V_UCS2ToUTF8(const ucs2* pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char* pUTF8, int cubDestSizeInBytes); +int V_UnicodeToUCS2(const wchar_t* pUnicode, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char* pUCS2, int cubDestSizeInBytes); +int V_UTF8ToUCS2(const char* pUTF8, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2* pUCS2, int cubDestSizeInBytes); + +bool Q_StripPrecedingAndTrailingWhitespace(char* pch); +bool Q_StripPrecedingAndTrailingWhitespaceW(wchar_t* pwch); + +bool Q_AggressiveStripPrecedingAndTrailingWhitespace(char* pch); +bool Q_AggressiveStripPrecedingAndTrailingWhitespaceW(wchar_t* pwch); + +unsigned char V_nibble(char c); +void V_hextobinary(char const* in, int numchars, byte* out, int maxoutputbytes); +void V_binarytohex(const byte* in, int inputbytes, char* out, int outsize); + +void V_FileBase(const char* in, char* out, int maxlen); +void V_StripTrailingSlash(char* ppath); +void V_StripExtension(const char* in, char* out, int outLen); +void V_DefaultExtension(char* path, const char* extension, int pathStringLength); +void V_SetExtension(char* path, const char* extension, int pathStringLength); +void V_StripFilename(char* path); +bool V_StripLastDir(char* dirName, int maxlen); +const char* V_UnqualifiedFileName(const char* in); +void V_ComposeFileName(const char* path, const char* filename, char* dest, int destSize); + +bool V_ExtractFilePath(const char* path, char* dest, int destSize); +void V_ExtractFileExtension(const char* path, char* dest, int destSize); + +const char* V_GetFileExtension(const char* path); + +const char* V_GetFileName(const char* path); + +bool V_RemoveDotSlashes(char* pFilename, char separator = CORRECT_PATH_SEPARATOR, bool bRemoveDoubleSlashes = true); + +void V_MakeAbsolutePath(char* pOut, int outLen, const char* pPath, const char* pStartingDir = NULL); + +bool V_MakeRelativePath(const char* pFullPath, const char* pDirectory, char* pRelativePath, int nBufLen); + +void V_FixupPathName(OUT_Z_CAP(nOutLen) char* pOut, size_t nOutLen, const char* pPath); + +void V_AppendSlash(INOUT_Z_CAP(strSize) char* pStr, int strSize); + +bool V_IsAbsolutePath(IN_Z const char* pPath); + +bool V_StrSubst(IN_Z const char* pIn, IN_Z const char* pMatch, const char* pReplaceWith, + OUT_Z_CAP(outLen) char* pOut, int outLen, bool bCaseSensitive = false); + +void V_SplitString(IN_Z const char* pString, IN_Z const char* pSeparator, CUtlVector >& outStrings); + +void V_SplitString2(IN_Z const char* pString, const char** pSeparators, int nSeparators, CUtlVector >& outStrings); + +bool V_GetCurrentDirectory(OUT_Z_CAP(maxLen) char* pOut, int maxLen); + +bool V_SetCurrentDirectory(const char* pDirName); + + +void V_StrSlice(const char* pStr, int firstChar, int lastCharNonInclusive, OUT_Z_CAP(outSize) char* pOut, int outSize); + +void V_StrLeft(const char* pStr, int nChars, OUT_Z_CAP(outSize) char* pOut, int outSize); + +void V_StrRight(const char* pStr, int nChars, OUT_Z_CAP(outSize) char* pOut, int outSize); + +char* V_AddBackSlashesToSpecialChars(char const* pSrc); + +void V_FixSlashes(char* pname, char separator = CORRECT_PATH_SEPARATOR); + +void V_FixDoubleSlashes(char* pStr); + +void V_strtowcs(const char* pString, int nInSize, OUT_Z_BYTECAP(nOutSizeInBytes) wchar_t* pWString, int nOutSizeInBytes); +void V_wcstostr(const wchar_t* pWString, int nInSize, OUT_Z_CAP(nOutSizeInBytes) char* pString, int nOutSizeInBytes); + +inline void V_strcat(INOUT_Z_CAP(cchDest) char* dest, const char* src, int cchDest) +{ + V_strncat(dest, src, cchDest, COPY_ALL_CHARACTERS); +} + +inline void V_wcscat(INOUT_Z_CAP(cchDest) wchar_t* dest, const wchar_t* src, int cchDest) +{ + V_wcsncat(dest, src, cchDest, COPY_ALL_CHARACTERS); +} + +template < class NameArray > +int V_GenerateUniqueNameIndex(const char* prefix, const NameArray& nameArray, int startindex = 0) +{ + if (prefix == NULL) + return 0; + + int freeindex = startindex; + + int nNames = nameArray.Count(); + for (int i = 0; i < nNames; ++i) + { + const char* pName = nameArray[i]; + if (!pName) + continue; + + const char* pIndexStr = StringAfterPrefix(pName, prefix); + if (pIndexStr) + { + int index = *pIndexStr ? atoi(pIndexStr) : 1; + if (index >= freeindex) + { + freeindex = index + 1; + } + } + } + + return freeindex; +} + +template < class NameArray > +bool V_GenerateUniqueName(OUT_Z_CAP(memsize) char* name, int memsize, const char* prefix, const NameArray& nameArray) +{ + if (name == NULL || memsize == 0) + return false; + + if (prefix == NULL) + { + name[0] = '\0'; + return false; + } + + int prefixLength = V_strlen(prefix); + if (prefixLength + 1 > memsize) + { + name[0] = '\0'; + return false; + } + + int i = V_GenerateUniqueNameIndex(prefix, nameArray); + if (i <= 0) + { + V_strncpy(name, prefix, memsize); + return true; + } + + int newlen = prefixLength + (int)log10((float)i) + 1; + if (newlen + 1 > memsize) + { + V_strncpy(name, prefix, memsize); + return false; + } + + V_snprintf(name, memsize, "%s%d", prefix, i); + return true; +} + + +class CStrAutoEncode +{ +public: + + explicit CStrAutoEncode(const char* pch) + { + m_pch = pch; + m_pwch = NULL; +#if !defined( WIN32 ) && !defined(_WIN32) + m_pucs2 = NULL; +#endif + m_bCreatedUTF16 = false; + } + + explicit CStrAutoEncode(const wchar_t* pwch) + { + m_pch = NULL; + m_pwch = pwch; +#if !defined( WIN32 ) && !defined(_WIN32) + m_pucs2 = NULL; +#endif + m_bCreatedUTF16 = true; + } + +#if !defined(WIN32) && !defined(_WINDOWS) && !defined(_WIN32) + explicit CStrAutoEncode(const ucs2* pwch) + { + m_pch = NULL; + m_pwch = NULL; + m_pucs2 = pwch; + m_bCreatedUTF16 = true; + } +#endif + + const char* ToString() + { + PopulateUTF8(); + return m_pch; + } + + char* ToStringWritable() + { + PopulateUTF8(); + return const_cast(m_pch); + } + + const wchar_t* ToWString() + { + PopulateUTF16(); + return m_pwch; + } + +#if !defined( WIN32 ) && !defined(_WIN32) + const ucs2* ToUCS2String() + { + PopulateUCS2(); + return m_pucs2; + } +#endif + + wchar_t* ToWStringWritable() + { + PopulateUTF16(); + return const_cast(m_pwch); + } + + ~CStrAutoEncode() + { + if (m_bCreatedUTF16) + { + delete[] m_pch; + } + else + { + delete[] m_pwch; + } + } + +private: + void PopulateUTF8() + { + if (!m_bCreatedUTF16) + return; + if (m_pwch == NULL) + return; + if (m_pch != NULL) + return; + + uint32 cbMax = 4 * static_cast(V_wcslen(m_pwch)) + 1; + char* pchTemp = new char[cbMax]; + if (V_UnicodeToUTF8(m_pwch, pchTemp, cbMax)) + { + uint32 cchAlloc = static_cast(V_strlen(pchTemp)) + 1; + char* pchHeap = new char[cchAlloc]; + V_strncpy(pchHeap, pchTemp, cchAlloc); + delete[] pchTemp; + m_pch = pchHeap; + } + else + { + delete[] pchTemp; + } + } + + void PopulateUTF16() + { + if (m_bCreatedUTF16) + return; + if (m_pch == NULL) + return; + if (m_pwch != NULL) + return; + + uint32 cchMax = static_cast(V_strlen(m_pch)) + 1; + wchar_t* pwchTemp = new wchar_t[cchMax]; + if (V_UTF8ToUnicode(m_pch, pwchTemp, cchMax * sizeof(wchar_t))) + { + uint32 cchAlloc = static_cast(V_wcslen(pwchTemp)) + 1; + wchar_t* pwchHeap = new wchar_t[cchAlloc]; + V_wcsncpy(pwchHeap, pwchTemp, cchAlloc * sizeof(wchar_t)); + delete[] pwchTemp; + m_pwch = pwchHeap; + } + else + { + delete[] pwchTemp; + } + } + +#if !defined( WIN32 ) && !defined(_WIN32) + void PopulateUCS2() + { + if (m_pch == NULL) + return; + if (m_pucs2 != NULL) + return; + + uint32 cchMax = static_cast(V_strlen(m_pch)) + 1; + ucs2* pwchTemp = new ucs2[cchMax]; + if (V_UTF8ToUCS2(m_pch, cchMax, pwchTemp, cchMax * sizeof(ucs2))) + { + uint32 cchAlloc = cchMax; + ucs2* pwchHeap = new ucs2[cchAlloc]; + memcpy(pwchHeap, pwchTemp, cchAlloc * sizeof(ucs2)); + delete[] pwchTemp; + m_pucs2 = pwchHeap; + } + else + { + delete[] pwchTemp; + } + } +#endif + + const char* m_pch; + const wchar_t* m_pwch; +#if !defined( WIN32 ) && !defined(_WIN32) + const ucs2* m_pucs2; +#endif + bool m_bCreatedUTF16; + +}; + +void Q_URLEncodeRaw(OUT_Z_CAP(nDestLen) char* pchDest, int nDestLen, const char* pchSource, int nSourceLen); + +size_t Q_URLDecodeRaw(OUT_CAP(nDecodeDestLen) char* pchDecodeDest, int nDecodeDestLen, const char* pchEncodedSource, int nEncodedSourceLen); + +void Q_URLEncode(OUT_Z_CAP(nDestLen) char* pchDest, int nDestLen, const char* pchSource, int nSourceLen); + +size_t Q_URLDecode(OUT_CAP(nDecodeDestLen) char* pchDecodeDest, int nDecodeDestLen, const char* pchEncodedSource, int nEncodedSourceLen); + + +#if !defined( VSTDLIB_BACKWARD_COMPAT ) + +#define Q_memset V_memset +#define Q_memcpy V_memcpy +#define Q_memmove V_memmove +#define Q_memcmp V_memcmp +#define Q_strlen V_strlen +#define Q_strcpy V_strcpy +#define Q_strrchr V_strrchr +#define Q_strcmp V_strcmp +#define Q_wcscmp V_wcscmp +#define Q_stricmp V_stricmp +#define Q_strstr V_strstr +#define Q_strupr V_strupr +#define Q_strlower V_strlower +#define Q_wcslen V_wcslen +#define Q_strncmp V_strncmp +#define Q_strcasecmp V_strcasecmp +#define Q_strncasecmp V_strncasecmp +#define Q_strnicmp V_strnicmp +#define Q_atoi V_atoi +#define Q_atoi64 V_atoi64 +#define Q_atoui64 V_atoui64 +#define Q_atof V_atof +#define Q_stristr V_stristr +#define Q_strnistr V_strnistr +#define Q_strnchr V_strnchr +#define Q_normalizeFloatString V_normalizeFloatString +#define Q_strncpy V_strncpy +#define Q_snprintf V_snprintf +#define Q_snwprintf V_snwprintf +#define Q_wcsncpy V_wcsncpy +#define Q_strncat V_strncat +#define Q_strnlwr V_strnlwr +#define Q_vsnprintf V_vsnprintf +#define Q_vsnprintfRet V_vsnprintfRet +#define Q_pretifymem V_pretifymem +#define Q_pretifynum V_pretifynum +#define Q_UTF8ToUnicode V_UTF8ToUnicode +#define Q_UnicodeToUTF8 V_UnicodeToUTF8 +#define Q_hextobinary V_hextobinary +#define Q_binarytohex V_binarytohex +#define Q_FileBase V_FileBase +#define Q_StripTrailingSlash V_StripTrailingSlash +#define Q_StripExtension V_StripExtension +#define Q_DefaultExtension V_DefaultExtension +#define Q_SetExtension V_SetExtension +#define Q_StripFilename V_StripFilename +#define Q_StripLastDir V_StripLastDir +#define Q_UnqualifiedFileName V_UnqualifiedFileName +#define Q_ComposeFileName V_ComposeFileName +#define Q_ExtractFilePath V_ExtractFilePath +#define Q_ExtractFileExtension V_ExtractFileExtension +#define Q_GetFileExtension V_GetFileExtension +#define Q_RemoveDotSlashes V_RemoveDotSlashes +#define Q_MakeAbsolutePath V_MakeAbsolutePath +#define Q_AppendSlash V_AppendSlash +#define Q_IsAbsolutePath V_IsAbsolutePath +#define Q_StrSubst V_StrSubst +#define Q_SplitString V_SplitString +#define Q_SplitString2 V_SplitString2 +#define Q_StrSlice V_StrSlice +#define Q_StrLeft V_StrLeft +#define Q_StrRight V_StrRight +#define Q_FixSlashes V_FixSlashes +#define Q_strtowcs V_strtowcs +#define Q_wcstostr V_wcstostr +#define Q_strcat V_strcat +#define Q_GenerateUniqueNameIndex V_GenerateUniqueNameIndex +#define Q_GenerateUniqueName V_GenerateUniqueName +#define Q_MakeRelativePath V_MakeRelativePath +#define Q_qsort_s V_qsort_s + +#endif + + +#endif +``` + +`SpyCustom/sdk/studio.h`: + +```h +#ifndef STUDIO_H +#define STUDIO_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "vector2d.h" +#include "vector.h" +#include "vector4d.h" +#include "compressed_vector.h" +#include "dbg.h" +#include "threadtools.h" +#include "mathlib.h" +#include "utlvector.h" +#include "utlhash.h" +#include "datamap.h" +#include "generichash.h" +#include "localflexcontroller.h" +#include "utlsymbol.h" + +#define STUDIO_ENABLE_PERF_COUNTERS + +#define STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW 0 +#define STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE 1 + +class IMaterial; +class IMesh; +class IMorph; +struct virtualmodel_t; +struct vertexFileHeader_t; +struct thinModelVertices_t; + +namespace OptimizedModel +{ + struct StripHeader_t; +} + + +#define STUDIO_VERSION 48 + +#ifndef _XBOX +#define MAXSTUDIOTRIANGLES 65536 +#define MAXSTUDIOVERTS 65536 +#define MAXSTUDIOFLEXVERTS 10000 +#else +#define MAXSTUDIOTRIANGLES 25000 +#define MAXSTUDIOVERTS 10000 +#define MAXSTUDIOFLEXVERTS 1000 +#endif +#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 +{ + DECLARE_BYTESWAP_DATADESC(); + int control; + int axis; + Vector pos[6]; + Quaternion quat[6]; + + mstudioaxisinterpbone_t() {} +private: + mstudioaxisinterpbone_t(const mstudioaxisinterpbone_t& vOther); +}; + + +struct mstudioquatinterpinfo_t +{ + DECLARE_BYTESWAP_DATADESC(); + float inv_tolerance; + Quaternion trigger; + Vector pos; + Quaternion quat; + + mstudioquatinterpinfo_t() {} +private: + mstudioquatinterpinfo_t(const mstudioquatinterpinfo_t& vOther); +}; + +struct mstudioquatinterpbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + int control; + int numtriggers; + int triggerindex; + inline mstudioquatinterpinfo_t* pTrigger(int i) const { return (mstudioquatinterpinfo_t*)(((byte*)this) + triggerindex) + i; }; + + mstudioquatinterpbone_t() {} +private: + mstudioquatinterpbone_t(const mstudioquatinterpbone_t& vOther); +}; + + +#define JIGGLE_IS_FLEXIBLE 0x01 +#define JIGGLE_IS_RIGID 0x02 +#define JIGGLE_HAS_YAW_CONSTRAINT 0x04 +#define JIGGLE_HAS_PITCH_CONSTRAINT 0x08 +#define JIGGLE_HAS_ANGLE_CONSTRAINT 0x10 +#define JIGGLE_HAS_LENGTH_CONSTRAINT 0x20 +#define JIGGLE_HAS_BASE_SPRING 0x40 +#define JIGGLE_IS_BOING 0x80 + +struct mstudiojigglebone_t +{ + DECLARE_BYTESWAP_DATADESC(); + + 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; + +private: +}; + +struct mstudioaimatbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int parent; + int aim; + Vector aimvector; + Vector upvector; + Vector basepos; + + mstudioaimatbone_t() {} +private: + mstudioaimatbone_t(const mstudioaimatbone_t& vOther); +}; + +struct mstudiobone_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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_t 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]; + + mstudiobone_t() {} +private: + mstudiobone_t(const mstudiobone_t& vOther); +}; + +struct mstudiolinearbone_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int numbones; + + int flagsindex; + inline int flags(int i) const { Assert(i >= 0 && i < numbones); return *((int*)(((byte*)this) + flagsindex) + i); }; + inline int* pflags(int i) { Assert(i >= 0 && i < numbones); return ((int*)(((byte*)this) + flagsindex) + i); }; + + int parentindex; + inline int parent(int i) const { Assert(i >= 0 && i < numbones); return *((int*)(((byte*)this) + parentindex) + i); }; + + int posindex; + inline Vector pos(int i) const { Assert(i >= 0 && i < numbones); return *((Vector*)(((byte*)this) + posindex) + i); }; + + int quatindex; + inline Quaternion quat(int i) const { Assert(i >= 0 && i < numbones); return *((Quaternion*)(((byte*)this) + quatindex) + i); }; + + int rotindex; + inline RadianEuler rot(int i) const { Assert(i >= 0 && i < numbones); return *((RadianEuler*)(((byte*)this) + rotindex) + i); }; + + int posetoboneindex; + inline matrix3x4_t poseToBone(int i) const { Assert(i >= 0 && i < numbones); return *((matrix3x4_t*)(((byte*)this) + posetoboneindex) + i); }; + + int posscaleindex; + inline Vector posscale(int i) const { Assert(i >= 0 && i < numbones); return *((Vector*)(((byte*)this) + posscaleindex) + i); }; + + int rotscaleindex; + inline Vector rotscale(int i) const { Assert(i >= 0 && i < numbones); return *((Vector*)(((byte*)this) + rotscaleindex) + i); }; + + int qalignmentindex; + inline Quaternion qalignment(int i) const { Assert(i >= 0 && i < numbones); return *((Quaternion*)(((byte*)this) + qalignmentindex) + i); }; + + int unused[6]; + + mstudiolinearbone_t() {} +private: + mstudiolinearbone_t(const mstudiolinearbone_t& vOther); +}; + + +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 +{ + DECLARE_BYTESWAP_DATADESC(); + + int m_nBoneComponent; + int m_nFlexControllerIndex; + float m_flMin; + float m_flMax; + + mstudioboneflexdrivercontrol_t() {} +private: + mstudioboneflexdrivercontrol_t(const mstudioboneflexdrivercontrol_t& vOther); +}; + + +struct mstudioboneflexdriver_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int m_nBoneIndex; + int m_nControlCount; + int m_nControlIndex; + + inline mstudioboneflexdrivercontrol_t* pBoneFlexDriverControl(int i) const + { + Assert(i >= 0 && i < m_nControlCount); + return (mstudioboneflexdrivercontrol_t*)(((byte*)this) + m_nControlIndex) + i; + } + + int unused[3]; + + mstudioboneflexdriver_t() {} +private: + mstudioboneflexdriver_t(const mstudioboneflexdriver_t& vOther); +}; + + +#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 +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + int type; + float start; + float end; + int rest; + int inputfield; + int unused[8]; +}; + +struct mstudiobbox_t +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + int group; + Vector bbmin; + Vector bbmax; + int szhitboxnameindex; + int unused[8]; + + const char* pszHitboxName() + { + if (szhitboxnameindex == 0) + return ""; + + return ((const char*)this) + szhitboxnameindex; + } + + mstudiobbox_t() {} + +private: + mstudiobbox_t(const mstudiobbox_t& vOther); +}; + +struct mstudiomodelgroup_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + unsigned int flags; + int localbone; + matrix3x4_t 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 +{ + DECLARE_BYTESWAP_DATADESC(); + Vector pos; + Quaternion q; + + mstudioikerror_t() {} + +private: + mstudioikerror_t(const mstudioikerror_t& vOther); +}; + +union mstudioanimvalue_t; + +struct mstudiocompressedikerror_t +{ + DECLARE_BYTESWAP_DATADESC(); + float scale[6]; + short offset[6]; + inline mstudioanimvalue_t* pAnimvalue(int i) const { if (offset[i] > 0) return (mstudioanimvalue_t*)(((byte*)this) + offset[i]); else return NULL; }; + mstudiocompressedikerror_t() {} + +private: + mstudiocompressedikerror_t(const mstudiocompressedikerror_t& vOther); +}; + +struct mstudioikrule_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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]; + + mstudioikrule_t() {} + +private: + mstudioikrule_t(const mstudioikrule_t& vOther); +}; + + +struct mstudioiklock_t +{ + DECLARE_BYTESWAP_DATADESC(); + int chain; + float flPosWeight; + float flLocalQWeight; + int flags; + + int unused[4]; +}; + + +struct mstudiolocalhierarchy_t +{ + DECLARE_BYTESWAP_DATADESC(); + int iBone; + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + short offset[3]; + inline mstudioanimvalue_t* pAnimvalue(int i) const { if (offset[i] > 0) return (mstudioanimvalue_t*)(((byte*)this) + offset[i]); else return NULL; }; +}; + +#define STUDIO_ANIM_RAWPOS 0x01 +#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 +{ + DECLARE_BYTESWAP_DATADESC(); + 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); }; + + inline Quaternion48* pQuat48(void) const { return (Quaternion48*)(pData()); }; + inline Quaternion64* pQuat64(void) const { return (Quaternion64*)(pData()); }; + inline Vector48* pPos(void) const { return (Vector48*)(pData() + ((flags & STUDIO_ANIM_RAWROT) != 0) * sizeof(*pQuat48()) + ((flags & STUDIO_ANIM_RAWROT2) != 0) * sizeof(*pQuat64())); }; + + short nextoffset; + inline mstudioanim_t* pNext(void) const { if (nextoffset != 0) return (mstudioanim_t*)(((byte*)this) + nextoffset); else return NULL; }; +}; + +struct mstudiomovement_t +{ + DECLARE_BYTESWAP_DATADESC(); + int endframe; + int motionflags; + float v0; + float v1; + float angle; + Vector vector; + Vector position; + + mstudiomovement_t() {} +private: + mstudiomovement_t(const mstudiomovement_t& vOther); +}; + +struct studiohdr_t; + +struct mstudioanimblock_t +{ + DECLARE_BYTESWAP_DATADESC(); + int datastart; + int dataend; +}; + +struct mstudioanimsections_t +{ + DECLARE_BYTESWAP_DATADESC(); + int animblock; + int animindex; +}; + +struct mstudioanimdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int baseptr; + inline studiohdr_t* pStudiohdr(void) const { return (studiohdr_t*)(((byte*)this) + baseptr); } + + int sznameindex; + inline 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; + mstudioanim_t* pAnimBlock(int block, int index) const; + mstudioanim_t* pAnim(int* piFrame, float& flStall) const; + mstudioanim_t* pAnim(int* piFrame) const; + + int numikrules; + int ikruleindex; + int animblockikruleindex; + mstudioikrule_t* pIKRule(int i) const; + + int numlocalhierarchy; + int localhierarchyindex; + mstudiolocalhierarchy_t* pHierarchy(int i) const; + + 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; + + mstudioanimdesc_t() {} +private: + mstudioanimdesc_t(const mstudioanimdesc_t& vOther); +}; + +struct mstudioikrule_t; + +struct mstudioautolayer_t +{ + DECLARE_BYTESWAP_DATADESC(); + short iSequence; + short iPose; + int flags; + float start; + float peak; + float tail; + float end; +}; + +struct mstudioactivitymodifier_t +{ + DECLARE_BYTESWAP_DATADESC(); + + int sznameindex; + inline char* pszName() { return (sznameindex) ? (char*)(((byte*)this) + sznameindex) : NULL; } +}; + +struct mstudioseqdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 { Assert(i >= 0 && i < numevents); 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 { Assert(i >= 0 && i < numautolayers); return (mstudioautolayer_t*)(((byte*)this) + autolayerindex) + i; }; + + int weightlistindex; + inline float* pBoneweight(int i) const { return ((float*)(((byte*)this) + weightlistindex) + i); }; + inline float weight(int i) const { return *(pBoneweight(i)); }; + + int posekeyindex; + float* pPoseKey(int iParam, int iAnim) const { return (float*)(((byte*)this) + posekeyindex) + iParam * groupsize[0] + iAnim; } + float poseKey(int iParam, int iAnim) const { return *(pPoseKey(iParam, iAnim)); } + + int numiklocks; + int iklockindex; + inline mstudioiklock_t* pIKLock(int i) const { Assert(i >= 0 && i < numiklocks); return (mstudioiklock_t*)(((byte*)this) + iklockindex) + i; }; + + 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 { Assert(i >= 0 && i < numactivitymodifiers); return activitymodifierindex != 0 ? (mstudioactivitymodifier_t*)(((byte*)this) + activitymodifierindex) + i : NULL; }; + + int unused[5]; + + mstudioseqdesc_t() {} +private: + mstudioseqdesc_t(const mstudioseqdesc_t& vOther); +}; + + +struct mstudioposeparamdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + int flags; + float start; + float end; + float loop; +}; + +struct mstudioflexdesc_t +{ + DECLARE_BYTESWAP_DATADESC(); + int szFACSindex; + inline char* const pszFACS(void) const { return ((char*)this) + szFACSindex; } +}; + + + +struct mstudioflexcontroller_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + 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 int controllerIndex(const CStudioHdr& cStudioHdr) const; + + 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 int leftIndex(const CStudioHdr& cStudioHdr) const; + + 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 int rightIndex(const CStudioHdr& cStudioHdr) const; + + inline const mstudioflexcontroller_t* pNWayValueController(void) const + { + return remaptype == FLEXCONTROLLER_REMAP_NWAY ? (mstudioflexcontroller_t*)((char*)this + szindex2) : NULL; + } + inline char* const pszNWayValueName(void) const { return remaptype == FLEXCONTROLLER_REMAP_NWAY ? pNWayValueController()->pszName() : NULL; } + inline int nWayValueIndex(const CStudioHdr& cStudioHdr) const; + + inline int Count() const { return (stereo ? 2 : 1) + (remaptype == FLEXCONTROLLER_REMAP_NWAY ? 1 : 0); } + inline const mstudioflexcontroller_t* pController(int index) const; + + unsigned char remaptype; + bool stereo; + byte unused[2]; +}; + + +struct mstudiovertanim_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short index; + byte speed; + byte side; + +protected: + union + { + short delta[3]; + float16 flDelta[3]; + }; + + union + { + short ndelta[3]; + float16 flNDelta[3]; + }; + +public: + inline void ConvertToFixed(float flVertAnimFixedPointScale) + { + delta[0] = flDelta[0].GetFloat() / flVertAnimFixedPointScale; + delta[1] = flDelta[1].GetFloat() / flVertAnimFixedPointScale; + delta[2] = flDelta[2].GetFloat() / flVertAnimFixedPointScale; + ndelta[0] = flNDelta[0].GetFloat() / flVertAnimFixedPointScale; + ndelta[1] = flNDelta[1].GetFloat() / flVertAnimFixedPointScale; + ndelta[2] = flNDelta[2].GetFloat() / flVertAnimFixedPointScale; + } + + inline Vector GetDeltaFixed(float flVertAnimFixedPointScale) + { + return Vector(delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale); + } + inline Vector GetNDeltaFixed(float flVertAnimFixedPointScale) + { + return Vector(ndelta[0] * flVertAnimFixedPointScale, ndelta[1] * flVertAnimFixedPointScale, ndelta[2] * flVertAnimFixedPointScale); + } + inline void GetDeltaFixed4DAligned(Vector4DAligned* vFillIn, float flVertAnimFixedPointScale) + { + vFillIn->Set(delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale, 0.0f); + } + inline void GetNDeltaFixed4DAligned(Vector4DAligned* vFillIn, float flVertAnimFixedPointScale) + { + vFillIn->Set(ndelta[0] * flVertAnimFixedPointScale, ndelta[1] * flVertAnimFixedPointScale, ndelta[2] * flVertAnimFixedPointScale, 0.0f); + } + inline Vector GetDeltaFloat() + { + return Vector(flDelta[0].GetFloat(), flDelta[1].GetFloat(), flDelta[2].GetFloat()); + } + inline Vector GetNDeltaFloat() + { + return Vector(flNDelta[0].GetFloat(), flNDelta[1].GetFloat(), flNDelta[2].GetFloat()); + } + inline void SetDeltaFixed(const Vector& vInput, float flVertAnimFixedPointScale) + { + delta[0] = vInput.x / flVertAnimFixedPointScale; + delta[1] = vInput.y / flVertAnimFixedPointScale; + delta[2] = vInput.z / flVertAnimFixedPointScale; + } + inline void SetNDeltaFixed(const Vector& vInputNormal, float flVertAnimFixedPointScale) + { + ndelta[0] = vInputNormal.x / flVertAnimFixedPointScale; + ndelta[1] = vInputNormal.y / flVertAnimFixedPointScale; + ndelta[2] = vInputNormal.z / flVertAnimFixedPointScale; + } + + inline void SetDeltaFloat(const Vector& vInput) + { + flDelta[0].SetFloat(vInput.x); + flDelta[1].SetFloat(vInput.y); + flDelta[2].SetFloat(vInput.z); + } + inline void SetNDeltaFloat(const Vector& vInputNormal) + { + flNDelta[0].SetFloat(vInputNormal.x); + flNDelta[1].SetFloat(vInputNormal.y); + flNDelta[2].SetFloat(vInputNormal.z); + } + + class CSortByIndex + { + public: + bool operator()(const mstudiovertanim_t& left, const mstudiovertanim_t& right)const + { + return left.index < right.index; + } + }; + friend class CSortByIndex; + + mstudiovertanim_t() {} +}; + + +struct mstudiovertanim_wrinkle_t : public mstudiovertanim_t +{ + DECLARE_BYTESWAP_DATADESC(); + + short wrinkledelta; + + inline void SetWrinkleFixed(float flWrinkle, float flVertAnimFixedPointScale) + { + int nWrinkleDeltaInt = flWrinkle / flVertAnimFixedPointScale; + wrinkledelta = clamp(nWrinkleDeltaInt, -32767, 32767); + } + + inline Vector4D GetDeltaFixed(float flVertAnimFixedPointScale) + { + return Vector4D(delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale, wrinkledelta * flVertAnimFixedPointScale); + } + + inline void GetDeltaFixed4DAligned(Vector4DAligned* vFillIn, float flVertAnimFixedPointScale) + { + vFillIn->Set(delta[0] * flVertAnimFixedPointScale, delta[1] * flVertAnimFixedPointScale, delta[2] * flVertAnimFixedPointScale, wrinkledelta * flVertAnimFixedPointScale); + } + + inline float GetWrinkleDeltaFixed(float flVertAnimFixedPointScale) + { + return wrinkledelta * flVertAnimFixedPointScale; + } +}; + + +enum StudioVertAnimType_t +{ + STUDIO_VERT_ANIM_NORMAL = 0, + STUDIO_VERT_ANIM_WRINKLE, +}; + +struct mstudioflex_t +{ + DECLARE_BYTESWAP_DATADESC(); + int flexdesc; + + float target0; + float target1; + float target2; + float target3; + + int numverts; + int vertindex; + + inline mstudiovertanim_t* pVertanim(int i) const { Assert(vertanimtype == STUDIO_VERT_ANIM_NORMAL); return (mstudiovertanim_t*)(((byte*)this) + vertindex) + i; }; + inline mstudiovertanim_wrinkle_t* pVertanimWrinkle(int i) const { Assert(vertanimtype == STUDIO_VERT_ANIM_WRINKLE); return (mstudiovertanim_wrinkle_t*)(((byte*)this) + vertindex) + i; }; + + inline byte* pBaseVertanim() const { return ((byte*)this) + vertindex; }; + inline int VertAnimSizeBytes() const { return (vertanimtype == STUDIO_VERT_ANIM_NORMAL) ? sizeof(mstudiovertanim_t) : sizeof(mstudiovertanim_wrinkle_t); } + + int flexpair; + unsigned char vertanimtype; + unsigned char unusedchar[3]; + int unused[6]; +}; + + +struct mstudioflexop_t +{ + DECLARE_BYTESWAP_DATADESC(); + int op; + union + { + int index; + float value; + } d; +}; + +struct mstudioflexrule_t +{ + DECLARE_BYTESWAP_DATADESC(); + int flex; + int numops; + int opindex; + inline mstudioflexop_t* iFlexOp(int i) const { return (mstudioflexop_t*)(((byte*)this) + opindex) + i; }; +}; + +struct mstudioboneweight_t +{ + DECLARE_BYTESWAP_DATADESC(); + float weight[MAX_NUM_BONES_PER_VERT]; + char bone[MAX_NUM_BONES_PER_VERT]; + byte numbones; + +}; + +struct mstudiovertex_t +{ + DECLARE_BYTESWAP_DATADESC(); + mstudioboneweight_t m_BoneWeights; + Vector m_vecPosition; + Vector m_vecNormal; + Vector2D m_vecTexCoord; + + mstudiovertex_t() {} + +private: + mstudiovertex_t(const mstudiovertex_t& vOther); +}; + +struct mstudiotexture_t +{ + DECLARE_BYTESWAP_DATADESC(); + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + int flags; + int used; + int unused1; + mutable IMaterial* material; + mutable void* clientmaterial; + + int unused[10]; +}; + +struct mstudioeyeball_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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]; + + mstudioeyeball_t() {} +private: + mstudioeyeball_t(const mstudioeyeball_t& vOther); +}; + + +struct mstudioiklink_t +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + Vector kneeDir; + Vector unused0; + + mstudioiklink_t() {} +private: + mstudioiklink_t(const mstudioiklink_t& vOther); +}; + +struct mstudioikchain_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + Vector* Position(int i) const; + Vector* Normal(int i) const; + Vector4D* TangentS(int i) const; + Vector2D* Texcoord(int i) const; + mstudioboneweight_t* BoneWeights(int i) const; + mstudiovertex_t* Vertex(int i) const; + bool HasTangentData(void) const; + int GetGlobalVertexIndex(int i) const; + int GetGlobalTangentIndex(int i) const; + + const void* pVertexData; + const void* pTangentData; +}; + +struct mstudio_meshvertexdata_t +{ + DECLARE_BYTESWAP_DATADESC(); + Vector* Position(int i) const; + Vector* Normal(int i) const; + Vector4D* TangentS(int i) const; + Vector2D* Texcoord(int i) const; + mstudioboneweight_t* BoneWeights(int i) const; + mstudiovertex_t* Vertex(int i) const; + bool HasTangentData(void) const; + int GetModelVertexIndex(int i) const; + int GetGlobalVertexIndex(int i) const; + + const mstudio_modelvertexdata_t* modelvertexdata; + + int numLODVertexes[MAX_NUM_LODS]; +}; + +struct mstudiomesh_t +{ + DECLARE_BYTESWAP_DATADESC(); + int material; + + int modelindex; + mstudiomodel_t* pModel() const; + + int numvertices; + int vertexoffset; + + const mstudio_meshvertexdata_t* GetVertexData(void* pModelData = NULL); + const thinModelVertices_t* GetThinVertexData(void* pModelData = NULL); + + 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]; + + mstudiomesh_t() {} +private: + mstudiomesh_t(const mstudiomesh_t& vOther); +}; + +struct mstudiomodel_t +{ + DECLARE_BYTESWAP_DATADESC(); + inline const char* pszName(void) const { return name; } + char name[64]; + + int type; + + float boundingradius; + + int nummeshes; + int meshindex; + inline mstudiomesh_t* pMesh(int i) const { return (mstudiomesh_t*)(((byte*)this) + meshindex) + i; }; + + int numvertices; + int vertexindex; + int tangentsindex; + + const vertexFileHeader_t* CacheVertexData(void* pModelData); + + const mstudio_modelvertexdata_t* GetVertexData(void* pModelData = NULL); + const thinModelVertices_t* GetThinVertexData(void* pModelData = NULL); + + int numattachments; + int attachmentindex; + + int numeyeballs; + int eyeballindex; + inline mstudioeyeball_t* pEyeball(int i) { return (mstudioeyeball_t*)(((byte*)this) + eyeballindex) + i; }; + + mstudio_modelvertexdata_t vertexdata; + + int unused[8]; +}; + +inline bool mstudio_modelvertexdata_t::HasTangentData(void) const +{ + return (pTangentData != NULL); +} + +inline int mstudio_modelvertexdata_t::GetGlobalVertexIndex(int i) const +{ + mstudiomodel_t* modelptr = (mstudiomodel_t*)((byte*)this - offsetof(mstudiomodel_t, vertexdata)); + Assert((modelptr->vertexindex % sizeof(mstudiovertex_t)) == 0); + return (i + (modelptr->vertexindex / sizeof(mstudiovertex_t))); +} + +inline int mstudio_modelvertexdata_t::GetGlobalTangentIndex(int i) const +{ + mstudiomodel_t* modelptr = (mstudiomodel_t*)((byte*)this - offsetof(mstudiomodel_t, vertexdata)); + Assert((modelptr->tangentsindex % sizeof(Vector4D)) == 0); + return (i + (modelptr->tangentsindex / sizeof(Vector4D))); +} + +inline mstudiovertex_t* mstudio_modelvertexdata_t::Vertex(int i) const +{ + return (mstudiovertex_t*)pVertexData + GetGlobalVertexIndex(i); +} + +inline Vector* mstudio_modelvertexdata_t::Position(int i) const +{ + return &Vertex(i)->m_vecPosition; +} + +inline Vector* mstudio_modelvertexdata_t::Normal(int i) const +{ + return &Vertex(i)->m_vecNormal; +} + +inline Vector4D* mstudio_modelvertexdata_t::TangentS(int i) const +{ + return (Vector4D*)pTangentData + GetGlobalTangentIndex(i); +} + +inline Vector2D* mstudio_modelvertexdata_t::Texcoord(int i) const +{ + return &Vertex(i)->m_vecTexCoord; +} + +inline mstudioboneweight_t* mstudio_modelvertexdata_t::BoneWeights(int i) const +{ + return &Vertex(i)->m_BoneWeights; +} + +inline mstudiomodel_t* mstudiomesh_t::pModel() const +{ + return (mstudiomodel_t*)(((byte*)this) + modelindex); +} + +inline bool mstudio_meshvertexdata_t::HasTangentData(void) const +{ + return modelvertexdata->HasTangentData(); +} + +inline const mstudio_meshvertexdata_t* mstudiomesh_t::GetVertexData(void* pModelData) +{ + this->pModel()->GetVertexData(pModelData); + vertexdata.modelvertexdata = &(this->pModel()->vertexdata); + + if (!vertexdata.modelvertexdata->pVertexData) + return NULL; + + return &vertexdata; +} + +inline const thinModelVertices_t* mstudiomesh_t::GetThinVertexData(void* pModelData) +{ + return this->pModel()->GetThinVertexData(pModelData); +} + +inline int mstudio_meshvertexdata_t::GetModelVertexIndex(int i) const +{ + mstudiomesh_t* meshptr = (mstudiomesh_t*)((byte*)this - offsetof(mstudiomesh_t, vertexdata)); + return meshptr->vertexoffset + i; +} + +inline int mstudio_meshvertexdata_t::GetGlobalVertexIndex(int i) const +{ + return modelvertexdata->GetGlobalVertexIndex(GetModelVertexIndex(i)); +} + +inline Vector* mstudio_meshvertexdata_t::Position(int i) const +{ + return modelvertexdata->Position(GetModelVertexIndex(i)); +}; + +inline Vector* mstudio_meshvertexdata_t::Normal(int i) const +{ + return modelvertexdata->Normal(GetModelVertexIndex(i)); +}; + +inline Vector4D* mstudio_meshvertexdata_t::TangentS(int i) const +{ + return modelvertexdata->TangentS(GetModelVertexIndex(i)); +} + +inline Vector2D* mstudio_meshvertexdata_t::Texcoord(int i) const +{ + return modelvertexdata->Texcoord(GetModelVertexIndex(i)); +}; + +inline mstudioboneweight_t* mstudio_meshvertexdata_t::BoneWeights(int i) const +{ + return modelvertexdata->BoneWeights(GetModelVertexIndex(i)); +}; + +inline mstudiovertex_t* mstudio_meshvertexdata_t::Vertex(int i) const +{ + return modelvertexdata->Vertex(GetModelVertexIndex(i)); +} + +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; + OptimizedModel::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; } + inline int GetLODForMetric(float lodMetric) const + { + if (!m_NumLODs) + return 0; + + int numLODs = (m_pLODs[m_NumLODs - 1].m_SwitchPoint < 0.0f) ? m_NumLODs - 1 : m_NumLODs; + + for (int i = m_RootLOD; i < numLODs - 1; i++) + { + if (m_pLODs[i + 1].m_SwitchPoint > lodMetric) + return i; + } + + return numLODs - 1; + } +}; + +struct mstudiobodyparts_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + int bone; + Vector forward; + int flexdesc; + + mstudiomouth_t() {} +private: + mstudiomouth_t(const mstudiomouth_t& vOther); +}; + +struct mstudiohitboxset_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + + int sznameindex; + inline const char* pszName(void) const { return ((char*)this) + sznameindex; } + matrix3x4_t pretransform; + matrix3x4_t posttransform; +}; + + +class virtualgroup_t +{ +public: + virtualgroup_t(void) { cache = NULL; }; + void* cache; + const studiohdr_t* GetStudioHdr(void) const; + + CUtlVector< int > boneMap; + CUtlVector< int > masterBone; + CUtlVector< int > masterSeq; + CUtlVector< int > masterAnim; + CUtlVector< int > masterAttachment; + CUtlVector< int > masterPose; + CUtlVector< int > masterNode; +}; + +struct virtualsequence_t +{ +#ifdef _XBOX + short flags; + short activity; + short group; + short index; +#else + int flags; + int activity; + int group; + int index; +#endif +}; + +struct virtualgeneric_t +{ +#ifdef _XBOX + short group; + short index; +#else + int group; + int index; +#endif +}; + + +struct virtualmodel_t +{ + void AppendSequences(int group, const studiohdr_t* pStudioHdr); + void AppendAnimations(int group, const studiohdr_t* pStudioHdr); + void AppendAttachments(int ground, const studiohdr_t* pStudioHdr); + void AppendPoseParameters(int group, const studiohdr_t* pStudioHdr); + void AppendBonemap(int group, const studiohdr_t* pStudioHdr); + void AppendNodes(int group, const studiohdr_t* pStudioHdr); + void AppendTransitions(int group, const studiohdr_t* pStudioHdr); + void AppendIKLocks(int group, const studiohdr_t* pStudioHdr); + void AppendModels(int group, const studiohdr_t* pStudioHdr); + void UpdateAutoplaySequences(const studiohdr_t* pStudioHdr); + + virtualgroup_t* pAnimGroup(int animation) { return &m_group[m_anim[animation].group]; } + virtualgroup_t* pSeqGroup(int sequence) + { + if ((unsigned)sequence >= (unsigned)m_seq.Count()) + { + Assert(0); + return 0; + } + return &m_group[m_seq[sequence].group]; + } + + CThreadFastMutex m_Lock; + + CUtlVector< virtualsequence_t > m_seq; + CUtlVector< virtualgeneric_t > m_anim; + CUtlVector< virtualgeneric_t > m_attachment; + CUtlVector< virtualgeneric_t > m_pose; + CUtlVector< virtualgroup_t > m_group; + CUtlVector< virtualgeneric_t > m_node; + CUtlVector< virtualgeneric_t > m_iklock; + CUtlVector< unsigned short > m_autoplaySequences; +}; + +struct thinModelVertices_t +{ + void Init(int numBoneInfluences, Vector* positions, unsigned short* normals, float* boneWeights, char* boneIndices) + { + Assert(positions != NULL); + Assert(normals != NULL); + Assert((numBoneInfluences >= 0) && (numBoneInfluences <= 3)); + Assert(numBoneInfluences > 0 ? !!boneIndices : !boneIndices); + Assert(numBoneInfluences > 1 ? !!boneWeights : !boneWeights); + m_numBoneInfluences = numBoneInfluences; + m_vecPositions = positions; + m_vecNormals = normals; + m_boneWeights = boneWeights; + m_boneIndices = boneIndices; + } + + void SetPosition(int vertIndex, const Vector& position) + { + Assert(m_vecPositions); + m_vecPositions[vertIndex] = position; + } + + void SetNormal(int vertIndex, const Vector& normal) + { + Assert(m_vecNormals); + unsigned int packedNormal; + PackNormal_UBYTE4(normal.x, normal.y, normal.z, &packedNormal); + m_vecNormals[vertIndex] = (unsigned short)(0x0000FFFF & packedNormal); + } + + void SetBoneWeights(int vertIndex, const mstudioboneweight_t& boneWeights) + { + Assert((m_numBoneInfluences >= 1) && (m_numBoneInfluences <= 3)); + Assert((boneWeights.numbones >= 1) && (boneWeights.numbones <= m_numBoneInfluences)); + int numStoredWeights = max(0, (m_numBoneInfluences - 1)); + float* pBaseWeight = m_boneWeights + vertIndex * numStoredWeights; + char* pBaseIndex = m_boneIndices + vertIndex * m_numBoneInfluences; + for (int i = 0; i < m_numBoneInfluences; i++) + { + pBaseIndex[i] = boneWeights.bone[i]; + } + for (int i = 0; i < numStoredWeights; i++) + { + pBaseWeight[i] = boneWeights.weight[i]; + } + } + + void GetMeshPosition(mstudiomesh_t* pMesh, int meshIndex, Vector* pPosition) const + { + Assert(pMesh); + GetPosition(pMesh->vertexdata.GetGlobalVertexIndex(meshIndex), pPosition); + } + + void GetMeshNormal(mstudiomesh_t* pMesh, int meshIndex, Vector* pNormal) const + { + Assert(pMesh); + GetNormal(pMesh->vertexdata.GetGlobalVertexIndex(meshIndex), pNormal); + } + + void GetMeshBoneWeights(mstudiomesh_t* pMesh, int meshIndex, mstudioboneweight_t* pBoneWeights) const + { + Assert(pMesh); + GetBoneWeights(pMesh->vertexdata.GetGlobalVertexIndex(meshIndex), pBoneWeights); + } + + void GetModelPosition(mstudiomodel_t* pModel, int modelIndex, Vector* pPosition) const + { + Assert(pModel); + GetPosition(pModel->vertexdata.GetGlobalVertexIndex(modelIndex), pPosition); + } + + void GetModelNormal(mstudiomodel_t* pModel, int modelIndex, Vector* pNormal) const + { + Assert(pModel); + GetNormal(pModel->vertexdata.GetGlobalVertexIndex(modelIndex), pNormal); + } + + void GetModelBoneWeights(mstudiomodel_t* pModel, int modelIndex, mstudioboneweight_t* pBoneWeights) const + { + Assert(pModel); + GetBoneWeights(pModel->vertexdata.GetGlobalVertexIndex(modelIndex), pBoneWeights); + } + +private: + void GetPosition(int vertIndex, Vector* pPosition) const + { + Assert(pPosition); + Assert(m_vecPositions); + *pPosition = m_vecPositions[vertIndex]; + } + + void GetNormal(int vertIndex, Vector* pNormal) const + { + Assert(pNormal); + Assert(m_vecNormals); + unsigned int packedNormal = 0x0000FFFF & m_vecNormals[vertIndex]; + UnpackNormal_UBYTE4(&packedNormal, pNormal->Base()); + } + + void GetBoneWeights(int vertIndex, mstudioboneweight_t* pBoneWeights) const + { + Assert(pBoneWeights); + Assert((m_numBoneInfluences <= 1) || (m_boneWeights != NULL)); + Assert((m_numBoneInfluences <= 0) || (m_boneIndices != NULL)); + int numStoredWeights = max(0, (m_numBoneInfluences - 1)); + float* pBaseWeight = m_boneWeights + vertIndex * numStoredWeights; + char* pBaseIndex = m_boneIndices + vertIndex * m_numBoneInfluences; + float sum = 0.0f; + for (int i = 0; i < MAX_NUM_BONES_PER_VERT; i++) + { + if (i < (m_numBoneInfluences - 1)) + pBoneWeights->weight[i] = pBaseWeight[i]; + else + pBoneWeights->weight[i] = 1.0f - sum; + sum += pBoneWeights->weight[i]; + + pBoneWeights->bone[i] = (i < m_numBoneInfluences) ? pBaseIndex[i] : 0; + } + + pBoneWeights->numbones = m_numBoneInfluences ? m_numBoneInfluences : 1; + } + + int m_numBoneInfluences; + float* m_boneWeights; + char* m_boneIndices; + Vector* m_vecPositions; + unsigned short* m_vecNormals; +}; + +#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 +{ + DECLARE_BYTESWAP_DATADESC(); + 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; + } +}; + +inline const mstudio_modelvertexdata_t* mstudiomodel_t::GetVertexData(void* pModelData) +{ + const vertexFileHeader_t* pVertexHdr = CacheVertexData(pModelData); + if (!pVertexHdr) + { + vertexdata.pVertexData = NULL; + vertexdata.pTangentData = NULL; + return NULL; + } + + vertexdata.pVertexData = pVertexHdr->GetVertexData(); + vertexdata.pTangentData = pVertexHdr->GetTangentData(); + + if (!vertexdata.pVertexData) + return NULL; + + return &vertexdata; +} + +inline const thinModelVertices_t* mstudiomodel_t::GetThinVertexData(void* pModelData) +{ + const vertexFileHeader_t* pVertexHdr = CacheVertexData(pModelData); + if (!pVertexHdr) + return NULL; + + return pVertexHdr->GetThinVertexData(); +} + +struct vertexFileFixup_t +{ + DECLARE_BYTESWAP_DATADESC(); + 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 +{ + DECLARE_BYTESWAP_DATADESC(); + int numsrcbonetransform; + int srcbonetransformindex; + + int illumpositionattachmentindex; + inline int IllumPositionAttachmentIndex() const { return illumpositionattachmentindex; } + + float flMaxEyeDeflection; + inline float MaxEyeDeflection() const { return flMaxEyeDeflection != 0.0f ? flMaxEyeDeflection : 0.866f; } + + int linearboneindex; + inline mstudiolinearbone_t* pLinearBones() const { return (linearboneindex) ? (mstudiolinearbone_t*)(((byte*)this) + linearboneindex) : NULL; } + + int sznameindex; + inline char* pszName() { return (sznameindex) ? (char*)(((byte*)this) + sznameindex) : NULL; } + + int m_nBoneFlexDriverCount; + int m_nBoneFlexDriverIndex; + inline mstudioboneflexdriver_t* pBoneFlexDriver(int i) const { Assert(i >= 0 && i < m_nBoneFlexDriverCount); return (mstudioboneflexdriver_t*)(((byte*)this) + m_nBoneFlexDriverIndex) + i; } + + int reserved[56]; +}; + +struct studiohdr_t +{ + DECLARE_BYTESWAP_DATADESC(); + int id; + int version; + int checksum; + 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 { Assert(i >= 0 && i < numbones); return (mstudiobone_t*)(((byte*)this) + boneindex) + i; }; + int RemapSeqBone(int iSequence, int iLocalBone) const; + int RemapAnimBone(int iAnim, int iLocalBone) const; + int numbonecontrollers; + int bonecontrollerindex; + inline mstudiobonecontroller_t* pBonecontroller(int i) const { Assert(i >= 0 && i < numbonecontrollers); return (mstudiobonecontroller_t*)(((byte*)this) + bonecontrollerindex) + i; }; + int numhitboxsets; + int hitboxsetindex; + + mstudiohitboxset_t* pHitboxSet(int i) const + { + Assert(i >= 0 && i < numhitboxsets); + 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; }; + + bool SequencesAvailable() const; + int GetNumSeq() const; + mstudioanimdesc_t& pAnimdesc(int i) const; + mstudioseqdesc_t& pSeqdesc(int i) const; + int iRelativeAnim(int baseseq, int relanim) const; + int iRelativeSeq(int baseseq, int relseq) const; + + mutable int activitylistversion; + mutable int eventsindexed; + int GetSequenceActivity(int iSequence); + void SetSequenceActivity(int iSequence, int iActivity); + int GetActivityListVersion(void); + void SetActivityListVersion(int version) const; + int GetEventListVersion(void); + void SetEventListVersion(int version); + + int numtextures; + int textureindex; + inline mstudiotexture_t* pTexture(int i) const { Assert(i >= 0 && i < numtextures); 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 { Assert(i >= 0 && i < numlocalattachments); return (mstudioattachment_t*)(((byte*)this) + localattachmentindex) + i; }; + int GetNumAttachments(void) const; + const mstudioattachment_t& pAttachment(int i) const; + int GetAttachmentBone(int i); + void SetAttachmentBone(int iAttachment, int iBone); + + int numlocalnodes; + int localnodeindex; + int localnodenameindex; + inline char* pszLocalNodeName(int iNode) const { Assert(iNode >= 0 && iNode < numlocalnodes); return (((char*)this) + *((int*)(((byte*)this) + localnodenameindex) + iNode)); } + inline byte* pLocalTransition(int i) const { Assert(i >= 0 && i < (numlocalnodes* numlocalnodes)); return (byte*)(((byte*)this) + localnodeindex) + i; }; + + int EntryNode(int iSequence); + int ExitNode(int iSequence); + char* pszNodeName(int iNode); + int GetTransition(int iFrom, int iTo) const; + + int numflexdesc; + int flexdescindex; + inline mstudioflexdesc_t* pFlexdesc(int i) const { Assert(i >= 0 && i < numflexdesc); return (mstudioflexdesc_t*)(((byte*)this) + flexdescindex) + i; }; + + int numflexcontrollers; + int flexcontrollerindex; + inline mstudioflexcontroller_t* pFlexcontroller(LocalFlexController_t i) const { Assert(numflexcontrollers == 0 || (i >= 0 && i < numflexcontrollers)); return (mstudioflexcontroller_t*)(((byte*)this) + flexcontrollerindex) + i; }; + + int numflexrules; + int flexruleindex; + inline mstudioflexrule_t* pFlexRule(int i) const { Assert(i >= 0 && i < numflexrules); return (mstudioflexrule_t*)(((byte*)this) + flexruleindex) + i; }; + + int numikchains; + int ikchainindex; + inline mstudioikchain_t* pIKChain(int i) const { Assert(i >= 0 && i < numikchains); return (mstudioikchain_t*)(((byte*)this) + ikchainindex) + i; }; + + int nummouths; + int mouthindex; + inline mstudiomouth_t* pMouth(int i) const { Assert(i >= 0 && i < nummouths); return (mstudiomouth_t*)(((byte*)this) + mouthindex) + i; }; + + int numlocalposeparameters; + int localposeparamindex; + inline mstudioposeparamdesc_t* pLocalPoseParameter(int i) const { Assert(i >= 0 && i < numlocalposeparameters); return (mstudioposeparamdesc_t*)(((byte*)this) + localposeparamindex) + i; }; + int GetNumPoseParameters(void) const; + const mstudioposeparamdesc_t& pPoseParameter(int i); + int GetSharedPoseParameter(int iSequence, int iLocalPose) const; + + 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 { Assert(i >= 0 && i < numlocalikautoplaylocks); return (mstudioiklock_t*)(((byte*)this) + localikautoplaylockindex) + i; }; + + int GetNumIKAutoplayLocks(void) const; + const mstudioiklock_t& pIKAutoplayLock(int i); + int CountAutoplaySequences() const; + int CopyAutoplaySequences(unsigned short* pOut, int outCount) const; + int GetAutoplayList(unsigned short** pOut) const; + + float mass; + int contents; + + int numincludemodels; + int includemodelindex; + inline mstudiomodelgroup_t* pModelGroup(int i) const { Assert(i >= 0 && i < numincludemodels); return (mstudiomodelgroup_t*)(((byte*)this) + includemodelindex) + i; }; + const studiohdr_t* FindModel(void** cache, char const* modelname) const; + + mutable void* virtualModel; + virtualmodel_t* GetVirtualModel(void) const; + + int szanimblocknameindex; + inline char* const pszAnimBlockName(void) const { return ((char*)this) + szanimblocknameindex; } + int numanimblocks; + int animblockindex; + inline mstudioanimblock_t* pAnimBlock(int i) const { Assert(i > 0 && i < numanimblocks); return (mstudioanimblock_t*)(((byte*)this) + animblockindex) + i; }; + mutable void* animblockModel; + byte* GetAnimBlock(int i) const; + + int bonetablebynameindex; + inline const byte* GetBoneTableSortedByName() const { return (byte*)this + bonetablebynameindex; } + + 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 { Assert(i >= 0 && i < numflexcontrollerui); return (mstudioflexcontrollerui_t*)(((byte*)this) + flexcontrolleruiindex) + i; } + + float flVertAnimFixedPointScale; + inline float VertAnimFixedPointScale() const { return (flags & STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE) ? flVertAnimFixedPointScale : 1.0f / 4096.0f; } + + int unused3[1]; + + 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 { Assert(i >= 0 && i < NumSrcBoneTransforms()); return (mstudiosrcbonetransform_t*)(((byte*)this) + pStudioHdr2()->srcbonetransformindex) + i; } + + inline int IllumPositionAttachmentIndex() const { return studiohdr2index ? pStudioHdr2()->IllumPositionAttachmentIndex() : 0; } + + inline float MaxEyeDeflection() const { return studiohdr2index ? pStudioHdr2()->MaxEyeDeflection() : 0.866f; } + + inline mstudiolinearbone_t* pLinearBones() const { return studiohdr2index ? pStudioHdr2()->pLinearBones() : NULL; } + + inline int BoneFlexDriverCount() const { return studiohdr2index ? pStudioHdr2()->m_nBoneFlexDriverCount : 0; } + inline const mstudioboneflexdriver_t* BoneFlexDriver(int i) const { Assert(i >= 0 && i < BoneFlexDriverCount()); return studiohdr2index ? pStudioHdr2()->pBoneFlexDriver(i) : NULL; } + + int unused2[1]; + + studiohdr_t() {} + +private: + studiohdr_t(const studiohdr_t& vOther); + + friend struct virtualmodel_t; +}; + + + +class IDataCache; +class IMDLCache; + +class CStudioHdr +{ +public: + CStudioHdr(void); + CStudioHdr(const studiohdr_t* pStudioHdr, IMDLCache* mdlcache = NULL); + ~CStudioHdr() { Term(); } + + void Init(const studiohdr_t* pStudioHdr, IMDLCache* mdlcache = NULL); + void Term(); + +public: + inline bool IsVirtual(void) { return (m_pVModel != NULL); }; + inline bool IsValid(void) { return (m_pStudioHdr != NULL); }; + inline bool IsReadyForAccess(void) const { return (m_pStudioHdr != NULL); }; + inline virtualmodel_t* GetVirtualModel(void) const { return m_pVModel; }; + inline const studiohdr_t* GetRenderHdr(void) const { return m_pStudioHdr; }; + const studiohdr_t* pSeqStudioHdr(int sequence); + const studiohdr_t* pAnimStudioHdr(int animation); + +private: + mutable const studiohdr_t* m_pStudioHdr; + mutable virtualmodel_t* m_pVModel; + + const virtualmodel_t* ResetVModel(const virtualmodel_t* pVModel) const; + const studiohdr_t* GroupStudioHdr(int group); + mutable CUtlVector< const studiohdr_t* > m_pStudioHdrCache; + + mutable int m_nFrameUnlockCounter; + int* m_pFrameUnlockCounter; + CThreadFastMutex m_FrameUnlockCounterMutex; + +public: + inline int numbones(void) const { return m_pStudioHdr->numbones; }; + inline mstudiobone_t* pBone(int i) const { return m_pStudioHdr->pBone(i); }; + int RemapAnimBone(int iAnim, int iLocalBone) const; + int RemapSeqBone(int iSequence, int iLocalBone) const; + + bool SequencesAvailable() const; + int GetNumSeq(void) const; + mstudioanimdesc_t& pAnimdesc(int i); + mstudioseqdesc_t& pSeqdesc(int iSequence); + int iRelativeAnim(int baseseq, int relanim) const; + int iRelativeSeq(int baseseq, int relseq) const; + + int GetSequenceActivity(int iSequence); + void SetSequenceActivity(int iSequence, int iActivity); + int GetActivityListVersion(void); + void SetActivityListVersion(int version); + int GetEventListVersion(void); + void SetEventListVersion(int version); + + int GetNumAttachments(void) const; + const mstudioattachment_t& pAttachment(int i); + int GetAttachmentBone(int i); + void SetAttachmentBone(int iAttachment, int iBone); + + int EntryNode(int iSequence); + int ExitNode(int iSequence); + char* pszNodeName(int iNode); + int GetTransition(int iFrom, int iTo) const; + + int GetNumPoseParameters(void) const; + const mstudioposeparamdesc_t& pPoseParameter(int i); + int GetSharedPoseParameter(int iSequence, int iLocalPose) const; + + int GetNumIKAutoplayLocks(void) const; + const mstudioiklock_t& pIKAutoplayLock(int i); + + inline int CountAutoplaySequences() const { return m_pStudioHdr->CountAutoplaySequences(); }; + inline int CopyAutoplaySequences(unsigned short* pOut, int outCount) const { return m_pStudioHdr->CopyAutoplaySequences(pOut, outCount); }; + inline int GetAutoplayList(unsigned short** pOut) const { return m_pStudioHdr->GetAutoplayList(pOut); }; + + inline int GetNumBoneControllers(void) const { return m_pStudioHdr->numbonecontrollers; }; + inline mstudiobonecontroller_t* pBonecontroller(int i) const { return m_pStudioHdr->pBonecontroller(i); }; + + inline int numikchains() const { return m_pStudioHdr->numikchains; }; + inline int GetNumIKChains(void) const { return m_pStudioHdr->numikchains; }; + inline mstudioikchain_t* pIKChain(int i) const { return m_pStudioHdr->pIKChain(i); }; + + inline int numflexrules() const { return m_pStudioHdr->numflexrules; }; + inline mstudioflexrule_t* pFlexRule(int i) const { return m_pStudioHdr->pFlexRule(i); }; + + inline int numflexdesc() const { return m_pStudioHdr->numflexdesc; }; + inline mstudioflexdesc_t* pFlexdesc(int i) const { return m_pStudioHdr->pFlexdesc(i); }; + + inline LocalFlexController_t numflexcontrollers() const { return (LocalFlexController_t)m_pStudioHdr->numflexcontrollers; }; + inline mstudioflexcontroller_t* pFlexcontroller(LocalFlexController_t i) const { return m_pStudioHdr->pFlexcontroller(i); }; + + inline int numflexcontrollerui() const { return m_pStudioHdr->numflexcontrollerui; }; + inline mstudioflexcontrollerui_t* pFlexcontrollerUI(int i) const { return m_pStudioHdr->pFlexControllerUI(i); }; + + inline const char* pszName() const { return m_pStudioHdr->pszName(); }; + + inline int numbonecontrollers() const { return m_pStudioHdr->numbonecontrollers; }; + + inline int numhitboxsets() const { return m_pStudioHdr->numhitboxsets; }; + inline mstudiohitboxset_t* pHitboxSet(int i) const { return m_pStudioHdr->pHitboxSet(i); }; + + inline mstudiobbox_t* pHitbox(int i, int set) const { return m_pStudioHdr->pHitbox(i, set); }; + inline int iHitboxCount(int set) const { return m_pStudioHdr->iHitboxCount(set); }; + + inline int numbodyparts() const { return m_pStudioHdr->numbodyparts; }; + inline mstudiobodyparts_t* pBodypart(int i) const { return m_pStudioHdr->pBodypart(i); }; + + inline int numskinfamilies() const { return m_pStudioHdr->numskinfamilies; } + + inline Vector eyeposition() const { return m_pStudioHdr->eyeposition; }; + + inline int flags() const { return m_pStudioHdr->flags; }; + + inline char* const pszSurfaceProp(void) const { return m_pStudioHdr->pszSurfaceProp(); }; + + inline float mass() const { return m_pStudioHdr->mass; }; + inline int contents() const { return m_pStudioHdr->contents; } + + inline const byte* GetBoneTableSortedByName() const { return m_pStudioHdr->GetBoneTableSortedByName(); }; + + inline Vector illumposition() const { return m_pStudioHdr->illumposition; }; + + inline Vector hull_min() const { return m_pStudioHdr->hull_min; }; + inline Vector hull_max() const { return m_pStudioHdr->hull_max; }; + + inline Vector view_bbmin() const { return m_pStudioHdr->view_bbmin; }; + inline Vector view_bbmax() const { return m_pStudioHdr->view_bbmax; }; + + inline int numtextures() const { return m_pStudioHdr->numtextures; }; + + inline int IllumPositionAttachmentIndex() const { return m_pStudioHdr->IllumPositionAttachmentIndex(); } + + inline float MaxEyeDeflection() const { return m_pStudioHdr->MaxEyeDeflection(); } + + inline mstudiolinearbone_t* pLinearBones() const { return m_pStudioHdr->pLinearBones(); } + + inline int BoneFlexDriverCount() const { return m_pStudioHdr->BoneFlexDriverCount(); } + inline const mstudioboneflexdriver_t* BoneFlexDriver(int i) const { return m_pStudioHdr->BoneFlexDriver(i); } + + inline float VertAnimFixedPointScale() const { return m_pStudioHdr->VertAnimFixedPointScale(); } + +public: + int IsSequenceLooping(int iSequence); + float GetSequenceCycleRate(int iSequence); + + void RunFlexRules(const float* src, float* dest); + + +public: + inline int boneFlags(int iBone) const { return m_boneFlags[iBone]; } + inline int boneParent(int iBone) const { return m_boneParent[iBone]; } + +private: + CUtlVector< int > m_boneFlags; + CUtlVector< int > m_boneParent; + +public: + + class CActivityToSequenceMapping + { + public: + struct SequenceTuple + { + short seqnum; + short weight; + CUtlSymbol* pActivityModifiers; + int iNumActivityModifiers; + }; + + struct HashValueType + { + int activityIdx; + + int startingIdx; + int count; + int totalWeight; + + HashValueType(int _actIdx, int _stIdx, int _ct, int _tW) : + activityIdx(_actIdx), startingIdx(_stIdx), count(_ct), totalWeight(_tW) {} + + HashValueType() : activityIdx(-1), startingIdx(-1), count(-1), totalWeight(-1) + { + AssertMsg(false, "Don't use default HashValueType()!"); + } + + + class HashFuncs + { + public: + HashFuncs(int) {} + + bool operator()(const HashValueType& lhs, const HashValueType& rhs) const + { + return lhs.activityIdx == rhs.activityIdx; + } + + unsigned int operator()(const HashValueType& item) const + { + return HashInt(item.activityIdx); + } + }; + }; + + typedef CUtlHash ActivityToValueIdxHash; + + CActivityToSequenceMapping(void) + : m_pSequenceTuples(NULL), m_iSequenceTuplesCount(0), m_ActToSeqHash(8, 0, 0), m_expectedPStudioHdr(NULL), m_expectedVModel(NULL) +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + , m_bIsInitialized(false) +#endif + {}; + + ~CActivityToSequenceMapping() + { + if (m_pSequenceTuples != NULL) + { + if (m_pSequenceTuples->pActivityModifiers != NULL) + { + delete[] m_pSequenceTuples->pActivityModifiers; + } + delete[] m_pSequenceTuples; + } + } + + const SequenceTuple* GetSequences(int forActivity, int* outSequenceCount, int* outTotalWeight); + + int NumSequencesForActivity(int forActivity); + +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + inline bool IsInitialized(void) { return m_bIsInitialized; } +#endif + + private: + + void Initialize(CStudioHdr* pstudiohdr); + + void Reinitialize(CStudioHdr* pstudiohdr); + + int SelectWeightedSequence(CStudioHdr* pstudiohdr, int activity, int curSequence); + + int SelectWeightedSequenceFromModifiers(CStudioHdr* pstudiohdr, int activity, CUtlSymbol* pActivityModifiers, int iModifierCount); + + SequenceTuple* m_pSequenceTuples; + unsigned int m_iSequenceTuplesCount; +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + bool m_bIsInitialized; +#endif + + ActivityToValueIdxHash m_ActToSeqHash; + + const void* m_expectedPStudioHdr; + const void* m_expectedVModel; + + bool ValidateAgainst(const CStudioHdr* RESTRICT pstudiohdr); + void SetValidationPair(const CStudioHdr* RESTRICT pstudiohdr); + + friend class CStudioHdr; + }; + + CActivityToSequenceMapping m_ActivityToSequence; + + inline int SelectWeightedSequence(int activity, int curSequence) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + if (!m_ActivityToSequence.IsInitialized()) + { + m_ActivityToSequence.Initialize(this); + } +#endif + return m_ActivityToSequence.SelectWeightedSequence(this, activity, curSequence); + } + + inline int SelectWeightedSequenceFromModifiers(int activity, CUtlSymbol* pActivityModifiers, int iModifierCount) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + if (!m_ActivityToSequence.IsInitialized()) + { + m_ActivityToSequence.Initialize(this); + } +#endif + return m_ActivityToSequence.SelectWeightedSequenceFromModifiers(this, activity, pActivityModifiers, iModifierCount); + } + + inline bool HaveSequenceForActivity(int activity) + { +#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE + if (!m_ActivityToSequence.IsInitialized()) + { + m_ActivityToSequence.Initialize(this); + } +#endif + return (m_ActivityToSequence.NumSequencesForActivity(activity) > 0); + } + + inline void ReinitializeSequenceMapping(void) + { + m_ActivityToSequence.Reinitialize(this); + } + +#ifdef STUDIO_ENABLE_PERF_COUNTERS +public: + inline void ClearPerfCounters(void) + { + m_nPerfAnimatedBones = 0; + m_nPerfUsedBones = 0; + m_nPerfAnimationLayers = 0; + }; + + mutable int m_nPerfAnimatedBones; + mutable int m_nPerfUsedBones; + mutable int m_nPerfAnimationLayers; +#endif + + +}; + +struct flexweight_t +{ + DECLARE_BYTESWAP_DATADESC(); + int key; + float weight; + float influence; +}; + +struct flexsetting_t +{ + DECLARE_BYTESWAP_DATADESC(); + int nameindex; + + inline char* pszName(void) const + { + return (char*)(((byte*)this) + nameindex); + } + + int obsolete1; + + int numsettings; + int index; + + int obsolete2; + + int settingindex; + + inline int psetting(byte* base, int i, flexweight_t** weights) const; +}; + + +struct flexsettinghdr_t +{ + DECLARE_BYTESWAP_DATADESC(); + int id; + int version; + + inline const char* pszName(void) const { return name; } + char name[64]; + int length; + + int numflexsettings; + int flexsettingindex; + inline flexsetting_t* pSetting(int i) const { return (flexsetting_t*)(((byte*)this) + flexsettingindex) + i; }; + int nameindex; + + 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); }; +}; + +inline int flexsetting_t::psetting(byte* base, int i, flexweight_t** weights) const +{ + *weights = (flexweight_t*)(((byte*)this) + settingindex) + i; + return numsettings; +}; + + +inline int mstudioflexcontrollerui_t::controllerIndex(const CStudioHdr& cStudioHdr) const +{ + return !stereo ? pController() - cStudioHdr.pFlexcontroller((LocalFlexController_t)0) : -1; +} + + +inline int mstudioflexcontrollerui_t::rightIndex(const CStudioHdr& cStudioHdr) const +{ + return stereo ? pRightController() - cStudioHdr.pFlexcontroller((LocalFlexController_t)0) : -1; +} + + +inline int mstudioflexcontrollerui_t::leftIndex(const CStudioHdr& cStudioHdr) const +{ + return stereo ? pLeftController() - cStudioHdr.pFlexcontroller((LocalFlexController_t)0) : -1; +} + + +inline int mstudioflexcontrollerui_t::nWayValueIndex(const CStudioHdr& cStudioHdr) const +{ + return remaptype == FLEXCONTROLLER_REMAP_NWAY ? pNWayValueController() - cStudioHdr.pFlexcontroller((LocalFlexController_t)0) : -1; +} + + +inline const mstudioflexcontroller_t* mstudioflexcontrollerui_t::pController(int index) const +{ + if (index < 0 || index > Count()) + return NULL; + + if (remaptype == FLEXCONTROLLER_REMAP_NWAY) + { + if (stereo) + return (mstudioflexcontroller_t*)((char*)this) + *(&szindex0 + index); + + if (index == 0) + return pController(); + + if (index == 1) + return pNWayValueController(); + + return NULL; + } + + if (index > 1) + return NULL; + + if (stereo) + return (mstudioflexcontroller_t*)((char*)this) + *(&szindex0 + index); + + if (index > 0) + return NULL; + + return pController(); +} + + +#define STUDIO_CONST 1 +#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 + + +inline bool Studio_ConvertStudioHdrToNewVersion(studiohdr_t* pStudioHdr) +{ + COMPILE_TIME_ASSERT(STUDIO_VERSION == 48); + + int version = pStudioHdr->version; + if (version == STUDIO_VERSION) + return true; + + bool bResult = true; + if (version < 46) + { + for (int i = 0; i < pStudioHdr->numlocalanim; i++) + { + mstudioanimdesc_t* pAnim = (mstudioanimdesc_t*)pStudioHdr->pLocalAnimdesc(i); + + if (pAnim->sectionframes != 0) + { + memset(&(pAnim->numframes), 0, (byte*)(pAnim + 1) - (byte*)&(pAnim->numframes)); + + pAnim->numframes = 1; + pAnim->animblock = -1; + bResult = false; + } + } + } + + if (version < 47) + { + if (pStudioHdr->unused4 != 0) + { + pStudioHdr->unused4 = 0; + bResult = false; + } + for (int i = 0; i < pStudioHdr->numlocalanim; i++) + { + mstudioanimdesc_t* pAnim = (mstudioanimdesc_t*)pStudioHdr->pLocalAnimdesc(i); + pAnim->zeroframeindex = 0; + pAnim->zeroframespan = 0; + } + } + else if (version == 47) + { + for (int i = 0; i < pStudioHdr->numlocalanim; i++) + { + mstudioanimdesc_t* pAnim = (mstudioanimdesc_t*)pStudioHdr->pLocalAnimdesc(i); + if (pAnim->zeroframeindex != 0) + { + pAnim->zeroframeindex = 0; + pAnim->zeroframespan = 0; + bResult = false; + } + } + } + + pStudioHdr->version = STUDIO_VERSION; + + return bResult; +} + +inline void Studio_SetRootLOD(studiohdr_t* pStudioHdr, int rootLOD) +{ + if (pStudioHdr->numAllowedRootLODs > 0 && + rootLOD >= pStudioHdr->numAllowedRootLODs) + { + rootLOD = pStudioHdr->numAllowedRootLODs - 1; + } + + Assert(rootLOD >= 0 && rootLOD < MAX_NUM_LODS); + Clamp(rootLOD, 0, MAX_NUM_LODS - 1); + + int vertexindex = 0; + int tangentsindex = 0; + int bodyPartID; + for (bodyPartID = 0; bodyPartID < pStudioHdr->numbodyparts; bodyPartID++) + { + mstudiobodyparts_t* pBodyPart = pStudioHdr->pBodypart(bodyPartID); + int modelID; + for (modelID = 0; modelID < pBodyPart->nummodels; modelID++) + { + mstudiomodel_t* pModel = pBodyPart->pModel(modelID); + int totalMeshVertexes = 0; + int meshID; + for (meshID = 0; meshID < pModel->nummeshes; meshID++) + { + mstudiomesh_t* pMesh = pModel->pMesh(meshID); + + pMesh->numvertices = pMesh->vertexdata.numLODVertexes[rootLOD]; + pMesh->vertexoffset = totalMeshVertexes; + totalMeshVertexes += pMesh->numvertices; + } + + pModel->numvertices = totalMeshVertexes; + pModel->vertexindex = vertexindex; + pModel->tangentsindex = tangentsindex; + + vertexindex += totalMeshVertexes * sizeof(mstudiovertex_t); + tangentsindex += totalMeshVertexes * sizeof(Vector4D); + } + } + + pStudioHdr->rootLOD = rootLOD; +} + +inline int Studio_VertexDataSize(const vertexFileHeader_t* pVvdHdr, int rootLOD, bool bNeedsTangentS) +{ + int numVertexes = pVvdHdr->numLODVertexes[rootLOD] + 1; + int dataLength = pVvdHdr->vertexDataStart + numVertexes * sizeof(mstudiovertex_t); + if (bNeedsTangentS) + { + dataLength += numVertexes * sizeof(Vector4D); + } + + return dataLength; +} + +inline int Studio_LoadVertexes(const vertexFileHeader_t* pTempVvdHdr, vertexFileHeader_t* pNewVvdHdr, int rootLOD, bool bNeedsTangentS) +{ + int i; + int target; + int numVertexes; + vertexFileFixup_t* pFixupTable; + + numVertexes = pTempVvdHdr->numLODVertexes[rootLOD]; + + memcpy((void*)pNewVvdHdr, (void*)pTempVvdHdr, pTempVvdHdr->vertexDataStart); + + for (i = 0; i < rootLOD; i++) + { + pNewVvdHdr->numLODVertexes[i] = pNewVvdHdr->numLODVertexes[rootLOD]; + } + + if (bNeedsTangentS) + { + pNewVvdHdr->tangentDataStart = pNewVvdHdr->vertexDataStart + numVertexes * sizeof(mstudiovertex_t); + } + else + { + pNewVvdHdr->tangentDataStart = 0; + } + + if (!pNewVvdHdr->numFixups) + { + memcpy( + (byte*)pNewVvdHdr + pNewVvdHdr->vertexDataStart, + (byte*)pTempVvdHdr + pTempVvdHdr->vertexDataStart, + numVertexes * sizeof(mstudiovertex_t)); + + if (bNeedsTangentS) + { + memcpy( + (byte*)pNewVvdHdr + pNewVvdHdr->tangentDataStart, + (byte*)pTempVvdHdr + pTempVvdHdr->tangentDataStart, + numVertexes * sizeof(Vector4D)); + } + + return numVertexes; + } + + target = 0; + pFixupTable = (vertexFileFixup_t*)((byte*)pTempVvdHdr + pTempVvdHdr->fixupTableStart); + for (i = 0; i < pTempVvdHdr->numFixups; i++) + { + if (pFixupTable[i].lod < rootLOD) + { + continue; + } + + memcpy( + (mstudiovertex_t*)((byte*)pNewVvdHdr + pNewVvdHdr->vertexDataStart) + target, + (mstudiovertex_t*)((byte*)pTempVvdHdr + pTempVvdHdr->vertexDataStart) + pFixupTable[i].sourceVertexID, + pFixupTable[i].numVertexes * sizeof(mstudiovertex_t)); + + if (bNeedsTangentS) + { + memcpy( + (Vector4D*)((byte*)pNewVvdHdr + pNewVvdHdr->tangentDataStart) + target, + (Vector4D*)((byte*)pTempVvdHdr + pTempVvdHdr->tangentDataStart) + pFixupTable[i].sourceVertexID, + pFixupTable[i].numVertexes * sizeof(Vector4D)); + } + + target += pFixupTable[i].numVertexes; + } + + pNewVvdHdr->numFixups = 0; + + return target; +} + +#endif +``` + +`SpyCustom/sdk/tempentity.h`: + +```h +#ifndef TEMPENTITY_H +#define TEMPENTITY_H +#ifdef _WIN32 +#pragma once +#endif + +#define TE_EXPLFLAG_NONE 0x0 +#define TE_EXPLFLAG_NOADDITIVE 0x1 +#define TE_EXPLFLAG_DLIGHT 0x2 +#define TE_EXPLFLAG_NOSOUND 0x4 +#define TE_EXPLFLAG_NOPARTICLES 0x8 +#define TE_EXPLFLAG_DRAWALPHA 0x10 +#define TE_EXPLFLAG_ROTATE 0x20 +#define TE_EXPLFLAG_NOFIREBALL 0x40 +#define TE_EXPLFLAG_NOFIREBALLSMOKE 0x80 +#define TE_EXPLFLAG_ICE 0x100 +#define TE_EXPLFLAG_SCALEPARTICLES 0x200 + +#define TE_BEAMPOINTS 0 +#define TE_SPRITE 1 +#define TE_BEAMDISK 2 +#define TE_BEAMCYLINDER 3 +#define TE_BEAMFOLLOW 4 +#define TE_BEAMRING 5 +#define TE_BEAMSPLINE 6 +#define TE_BEAMRINGPOINT 7 +#define TE_BEAMLASER 8 +#define TE_BEAMTESLA 9 + + +#endif +``` + +`SpyCustom/sdk/texture_group_names.h`: + +```h +#ifndef TEXTURE_GROUP_NAMES_H +#define TEXTURE_GROUP_NAMES_H +#ifdef _WIN32 +#pragma once +#endif + +#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" + +#endif +``` + +`SpyCustom/sdk/threadtools.h`: + +```h +#ifndef THREADTOOLS_H +#define THREADTOOLS_H + +#include + +#include "platform.h" +#include "dbg.h" +#include "vcrmode.h" + +#ifdef PLATFORM_WINDOWS_PC +#include +#endif + +#ifdef POSIX +#include +#include +#define WAIT_OBJECT_0 0 +#define WAIT_TIMEOUT 0x00000102 +#define WAIT_FAILED -1 +#define THREAD_PRIORITY_HIGHEST 2 +#endif + +#if defined( _WIN32 ) +#pragma once +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +#ifndef _RETAIL +#define THREAD_MUTEX_TRACING_SUPPORTED +#if defined(_WIN32) && defined(_DEBUG) +#define THREAD_MUTEX_TRACING_ENABLED +#endif +#endif + +#ifdef _WIN32 +typedef void* HANDLE; +#endif + +const unsigned TT_INFINITE = 0xffffffff; + +#ifndef NO_THREAD_LOCAL + +#ifndef THREAD_LOCAL +#ifdef _WIN32 +#define THREAD_LOCAL __declspec(thread) +#elif POSIX +#define THREAD_LOCAL __thread +#endif +#endif + +#endif + +typedef unsigned long ThreadId_t; + +FORWARD_DECLARE_HANDLE(ThreadHandle_t); +typedef unsigned (*ThreadFunc_t)(void* pParam); + +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread(ThreadFunc_t, void* pParam, ThreadId_t* pID, unsigned stackSize = 0); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread(ThreadFunc_t, void* pParam, unsigned stackSize = 0); +PLATFORM_INTERFACE bool ReleaseThreadHandle(ThreadHandle_t); + + +PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0); +PLATFORM_INTERFACE uint ThreadGetCurrentId(); +PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle(); +PLATFORM_INTERFACE int ThreadGetPriority(ThreadHandle_t hThread = NULL); +PLATFORM_INTERFACE bool ThreadSetPriority(ThreadHandle_t hThread, int priority); +inline bool ThreadSetPriority(int priority) { return ThreadSetPriority(NULL, priority); } +PLATFORM_INTERFACE bool ThreadInMainThread(); +PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread(); + +typedef int (*ThreadedLoadLibraryFunc_t)(); +PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc(ThreadedLoadLibraryFunc_t func); +PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc(); + +#if defined( _WIN32 ) && !defined( _WIN64 ) && !defined( _X360 ) +extern "C" unsigned long __declspec(dllimport) __stdcall GetCurrentThreadId(); +#define ThreadGetCurrentId GetCurrentThreadId +#endif + +inline void ThreadPause() +{ +#if defined( PLATFORM_WINDOWS_PC ) + _mm_pause(); +#elif POSIX + __asm __volatile("pause"); +#elif defined( _X360 ) +#else +#error "implement me" +#endif +} + +PLATFORM_INTERFACE bool ThreadJoin(ThreadHandle_t, unsigned timeout = TT_INFINITE); +PLATFORM_INTERFACE void ThreadDetach(ThreadHandle_t); + +PLATFORM_INTERFACE void ThreadSetDebugName(ThreadId_t id, const char* pszName); +inline void ThreadSetDebugName(const char* pszName) { ThreadSetDebugName((ThreadId_t)-1, pszName); } + +PLATFORM_INTERFACE void ThreadSetAffinity(ThreadHandle_t hThread, int nAffinityMask); + +enum ThreadWaitResult_t +{ + TW_FAILED = 0xffffffff, + TW_TIMEOUT = 0x00000102, +}; + +#ifdef _WIN32 +PLATFORM_INTERFACE int ThreadWaitForObjects(int nEvents, const HANDLE* pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE); +inline int ThreadWaitForObject(HANDLE handle, bool bWaitAll = true, unsigned timeout = TT_INFINITE) { return ThreadWaitForObjects(1, &handle, bWaitAll, timeout); } +#endif + +#ifdef _WIN32 +#define NOINLINE +#elif POSIX +#define NOINLINE __attribute__ ((noinline)) +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define ThreadMemoryBarrier() __lwsync() + +#elif defined(_MSC_VER) +#if _MSC_VER < 1500 +#pragma intrinsic(_ReadWriteBarrier) +#endif +#define ThreadMemoryBarrier() _ReadWriteBarrier() +#elif defined(GNUC) +#define ThreadMemoryBarrier() asm volatile("" ::: "memory") +#else +#error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering +#endif + +#if defined(_WIN32) && !defined(_X360) +#if ( _MSC_VER >= 1310 ) +#define USE_INTRINSIC_INTERLOCKED +#endif +#endif + +#ifdef USE_INTRINSIC_INTERLOCKED +extern "C" +{ + long __cdecl _InterlockedIncrement(volatile long*); + long __cdecl _InterlockedDecrement(volatile long*); + long __cdecl _InterlockedExchange(volatile long*, long); + long __cdecl _InterlockedExchangeAdd(volatile long*, long); + long __cdecl _InterlockedCompareExchange(volatile long*, long, long); +} + +#pragma intrinsic( _InterlockedCompareExchange ) +#pragma intrinsic( _InterlockedDecrement ) +#pragma intrinsic( _InterlockedExchange ) +#pragma intrinsic( _InterlockedExchangeAdd ) +#pragma intrinsic( _InterlockedIncrement ) + +inline long ThreadInterlockedIncrement(long volatile* p) { Assert((size_t)p % 4 == 0); return _InterlockedIncrement(p); } +inline long ThreadInterlockedDecrement(long volatile* p) { Assert((size_t)p % 4 == 0); return _InterlockedDecrement(p); } +inline long ThreadInterlockedExchange(long volatile* p, long value) { Assert((size_t)p % 4 == 0); return _InterlockedExchange(p, value); } +inline long ThreadInterlockedExchangeAdd(long volatile* p, long value) { Assert((size_t)p % 4 == 0); return _InterlockedExchangeAdd(p, value); } +inline long ThreadInterlockedCompareExchange(long volatile* p, long value, long comperand) { Assert((size_t)p % 4 == 0); return _InterlockedCompareExchange(p, value, comperand); } +inline bool ThreadInterlockedAssignIf(long volatile* p, long value, long comperand) { Assert((size_t)p % 4 == 0); return (_InterlockedCompareExchange(p, value, comperand) == comperand); } +#else +PLATFORM_INTERFACE long ThreadInterlockedIncrement(long volatile*); +PLATFORM_INTERFACE long ThreadInterlockedDecrement(long volatile*); +PLATFORM_INTERFACE long ThreadInterlockedExchange(long volatile*, long value); +PLATFORM_INTERFACE long ThreadInterlockedExchangeAdd(long volatile*, long value); +PLATFORM_INTERFACE long ThreadInterlockedCompareExchange(long volatile*, long value, long comperand); +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf(long volatile*, long value, long comperand); +#endif + +inline unsigned ThreadInterlockedExchangeSubtract(long volatile* p, long value) { return ThreadInterlockedExchangeAdd((long volatile*)p, -value); } + +#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( _WIN64 ) +#define TIPTR() +inline void* ThreadInterlockedExchangePointer(void* volatile* p, void* value) { return (void*)_InterlockedExchange(reinterpret_cast(p), reinterpret_cast(value)); } +inline void* ThreadInterlockedCompareExchangePointer(void* volatile* p, void* value, void* comperand) { return (void*)_InterlockedCompareExchange(reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand)); } +inline bool ThreadInterlockedAssignPointerIf(void* volatile* p, void* value, void* comperand) { return (_InterlockedCompareExchange(reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand)) == reinterpret_cast(comperand)); } +#else +PLATFORM_INTERFACE void* ThreadInterlockedExchangePointer(void* volatile*, void* value) NOINLINE; +PLATFORM_INTERFACE void* ThreadInterlockedCompareExchangePointer(void* volatile*, void* value, void* comperand) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf(void* volatile*, void* value, void* comperand) NOINLINE; +#endif + +inline void const* ThreadInterlockedExchangePointerToConst(void const* volatile* p, void const* value) { return ThreadInterlockedExchangePointer(const_cast (p), const_cast (value)); } +inline void const* ThreadInterlockedCompareExchangePointerToConst(void const* volatile* p, void const* value, void const* comperand) { return ThreadInterlockedCompareExchangePointer(const_cast (p), const_cast (value), const_cast (comperand)); } +inline bool ThreadInterlockedAssignPointerToConstIf(void const* volatile* p, void const* value, void const* comperand) { return ThreadInterlockedAssignPointerIf(const_cast (p), const_cast (value), const_cast (comperand)); } + +#if defined( PLATFORM_64BITS ) +#if defined (_WIN32) +typedef __m128i int128; +inline int128 int128_zero() { return _mm_setzero_si128(); } +#else +typedef __int128_t int128; +#define int128_zero() 0 +#endif + +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128(volatile int128* pDest, const int128& value, const int128& comperand) NOINLINE; + +#endif + +PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64(int64 volatile*) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64(int64 volatile*) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64(int64 volatile*, int64 value, int64 comperand) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedExchange64(int64 volatile*, int64 value) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64(int64 volatile*, int64 value) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64* pDest, int64 value, int64 comperand) NOINLINE; + +inline unsigned ThreadInterlockedExchangeSubtract(unsigned volatile* p, unsigned value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); } +inline unsigned ThreadInterlockedIncrement(unsigned volatile* p) { return ThreadInterlockedIncrement((long volatile*)p); } +inline unsigned ThreadInterlockedDecrement(unsigned volatile* p) { return ThreadInterlockedDecrement((long volatile*)p); } +inline unsigned ThreadInterlockedExchange(unsigned volatile* p, unsigned value) { return ThreadInterlockedExchange((long volatile*)p, value); } +inline unsigned ThreadInterlockedExchangeAdd(unsigned volatile* p, unsigned value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); } +inline unsigned ThreadInterlockedCompareExchange(unsigned volatile* p, unsigned value, unsigned comperand) { return ThreadInterlockedCompareExchange((long volatile*)p, value, comperand); } +inline bool ThreadInterlockedAssignIf(unsigned volatile* p, unsigned value, unsigned comperand) { return ThreadInterlockedAssignIf((long volatile*)p, value, comperand); } + +inline int ThreadInterlockedExchangeSubtract(int volatile* p, int value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); } +inline int ThreadInterlockedIncrement(int volatile* p) { return ThreadInterlockedIncrement((long volatile*)p); } +inline int ThreadInterlockedDecrement(int volatile* p) { return ThreadInterlockedDecrement((long volatile*)p); } +inline int ThreadInterlockedExchange(int volatile* p, int value) { return ThreadInterlockedExchange((long volatile*)p, value); } +inline int ThreadInterlockedExchangeAdd(int volatile* p, int value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); } +inline int ThreadInterlockedCompareExchange(int volatile* p, int value, int comperand) { return ThreadInterlockedCompareExchange((long volatile*)p, value, comperand); } +inline bool ThreadInterlockedAssignIf(int volatile* p, int value, int comperand) { return ThreadInterlockedAssignIf((long volatile*)p, value, comperand); } + +#if defined(_WIN32) && defined(THREAD_PROFILER) +PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void* p); +PLATFORM_INTERFACE void ThreadNotifySyncCancel(void* p); +PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void* p); +PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void* p); +#else +#define ThreadNotifySyncPrepare(p) ((void)0) +#define ThreadNotifySyncCancel(p) ((void)0) +#define ThreadNotifySyncAcquired(p) ((void)0) +#define ThreadNotifySyncReleasing(p) ((void)0) +#endif + +#ifndef NO_THREAD_LOCAL + +#if defined(_LINUX) && !defined(OSX) +#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 +#define CTHREADLOCALINTEGER( typ ) __thread int +#define CTHREADLOCALINT __thread int +#define CTHREADLOCALPTR( typ ) __thread typ * +#define CTHREADLOCAL( typ ) __thread typ +#define GETLOCAL( x ) ( x ) +#endif + +#if defined(WIN32) || defined(OSX) +#ifndef __AFXTLS_H__ +#define CTHREADLOCALINT CThreadLocalInt +#define CTHREADLOCALINTEGER( typ ) CThreadLocalInt +#define CTHREADLOCALPTR( typ ) CThreadLocalPtr +#define CTHREADLOCAL( typ ) CThreadLocal +#define GETLOCAL( x ) ( x.Get() ) +#endif +#endif + +#endif + +#ifndef __AFXTLS_H__ +#ifndef NO_THREAD_LOCAL + +class PLATFORM_CLASS CThreadLocalBase +{ +public: + CThreadLocalBase(); + ~CThreadLocalBase(); + + void* Get() const; + void Set(void*); + +private: +#ifdef _WIN32 + uint32 m_index; +#elif POSIX + pthread_key_t m_index; +#endif +}; + +#ifndef __AFXTLS_H__ + +template +class CThreadLocal : public CThreadLocalBase +{ +public: + CThreadLocal() + { + COMPILE_TIME_ASSERT(sizeof(T) == sizeof(void*)); + } + + T Get() const + { + return reinterpret_cast(CThreadLocalBase::Get()); + } + + void Set(T val) + { + CThreadLocalBase::Set(reinterpret_cast(val)); + } +}; + +#endif + +template +class CThreadLocalInt : public CThreadLocal +{ +public: + CThreadLocalInt() + { + COMPILE_TIME_ASSERT(sizeof(T) >= sizeof(int)); + } + + operator int() const { return (int)this->Get(); } + int operator=(int i) { this->Set((intp)i); return i; } + + int operator++() { T i = this->Get(); this->Set(++i); return (int)i; } + int operator++(int) { T i = this->Get(); this->Set(i + 1); return (int)i; } + + int operator--() { T i = this->Get(); this->Set(--i); return (int)i; } + int operator--(int) { T i = this->Get(); this->Set(i - 1); return (int)i; } +}; + + +template +class CThreadLocalPtr : private CThreadLocalBase +{ +public: + CThreadLocalPtr() {} + + operator const void* () const { return (T*)Get(); } + operator void* () { return (T*)Get(); } + + operator const T* () const { return (T*)Get(); } + operator const T* () { return (T*)Get(); } + operator T* () { return (T*)Get(); } + + int operator=(int i) { AssertMsg(i == 0, "Only NULL allowed on integer assign"); Set(NULL); return 0; } + T* operator=(T* p) { Set(p); return p; } + + bool operator !() const { return (!Get()); } + bool operator!=(int i) const { AssertMsg(i == 0, "Only NULL allowed on integer compare"); return (Get() != NULL); } + bool operator==(int i) const { AssertMsg(i == 0, "Only NULL allowed on integer compare"); return (Get() == NULL); } + bool operator==(const void* p) const { return (Get() == p); } + bool operator!=(const void* p) const { return (Get() != p); } + bool operator==(const T* p) const { return operator==((void*)p); } + bool operator!=(const T* p) const { return operator!=((void*)p); } + + T* operator->() { return (T*)Get(); } + T& operator *() { return *((T*)Get()); } + + const T* operator->() const { return (T*)Get(); } + const T& operator *() const { return *((T*)Get()); } + + const T& operator[](int i) const { return *((T*)Get() + i); } + T& operator[](int i) { return *((T*)Get() + i); } + +private: + CThreadLocalPtr(T* pFrom); + CThreadLocalPtr(const CThreadLocalPtr& from); + T** operator &(); + T* const* operator &() const; + void operator=(const CThreadLocalPtr& from); + bool operator==(const CThreadLocalPtr& p) const; + bool operator!=(const CThreadLocalPtr& p) const; +}; + +#endif +#endif + +template +class CInterlockedIntT +{ +public: + CInterlockedIntT() : m_value(0) { COMPILE_TIME_ASSERT(sizeof(T) == sizeof(long)); } + CInterlockedIntT(T value) : m_value(value) {} + + T GetRaw() const { return m_value; } + + operator T() const { return m_value; } + + bool operator!() const { return (m_value == 0); } + bool operator==(T rhs) const { return (m_value == rhs); } + bool operator!=(T rhs) const { return (m_value != rhs); } + + T operator++() { return (T)ThreadInterlockedIncrement((long*)&m_value); } + T operator++(int) { return operator++() - 1; } + + T operator--() { return (T)ThreadInterlockedDecrement((long*)&m_value); } + T operator--(int) { return operator--() + 1; } + + bool AssignIf(T conditionValue, T newValue) { return ThreadInterlockedAssignIf((long*)&m_value, (long)newValue, (long)conditionValue); } + + T operator=(T newValue) { ThreadInterlockedExchange((long*)&m_value, newValue); return m_value; } + + void operator+=(T add) { ThreadInterlockedExchangeAdd((long*)&m_value, (long)add); } + void operator-=(T subtract) { operator+=(-subtract); } + void operator*=(T multiplier) { + T original, result; + do + { + original = m_value; + result = original * multiplier; + } while (!AssignIf(original, result)); + } + void operator/=(T divisor) { + T original, result; + do + { + original = m_value; + result = original / divisor; + } while (!AssignIf(original, result)); + } + + T operator+(T rhs) const { return m_value + rhs; } + T operator-(T rhs) const { return m_value - rhs; } + +private: + volatile T m_value; +}; + +typedef CInterlockedIntT CInterlockedInt; +typedef CInterlockedIntT CInterlockedUInt; + +template +class CInterlockedPtr +{ +public: + CInterlockedPtr() : m_value(0) {} + CInterlockedPtr(T* value) : m_value(value) {} + + operator T* () const { return m_value; } + + bool operator!() const { return (m_value == 0); } + bool operator==(T* rhs) const { return (m_value == rhs); } + bool operator!=(T* rhs) const { return (m_value != rhs); } + +#if defined( PLATFORM_64BITS ) + T* operator++() { return ((T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, sizeof(T))) + 1; } + T* operator++(int) { return (T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, sizeof(T)); } + + T* operator--() { return ((T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, -sizeof(T))) - 1; } + T* operator--(int) { return (T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, -sizeof(T)); } + + bool AssignIf(T* conditionValue, T* newValue) { return ThreadInterlockedAssignPointerToConstIf((void const**)&m_value, (void const*)newValue, (void const*)conditionValue); } + + T* operator=(T* newValue) { ThreadInterlockedExchangePointerToConst((void const**)&m_value, (void const*)newValue); return newValue; } + + void operator+=(int add) { ThreadInterlockedExchangeAdd64((int64*)&m_value, add * sizeof(T)); } +#else + T* operator++() { return ((T*)ThreadInterlockedExchangeAdd((long*)&m_value, sizeof(T))) + 1; } + T* operator++(int) { return (T*)ThreadInterlockedExchangeAdd((long*)&m_value, sizeof(T)); } + + T* operator--() { return ((T*)ThreadInterlockedExchangeAdd((long*)&m_value, -sizeof(T))) - 1; } + T* operator--(int) { return (T*)ThreadInterlockedExchangeAdd((long*)&m_value, -sizeof(T)); } + + bool AssignIf(T* conditionValue, T* newValue) { return ThreadInterlockedAssignPointerToConstIf((void const**)&m_value, (void const*)newValue, (void const*)conditionValue); } + + T* operator=(T* newValue) { ThreadInterlockedExchangePointerToConst((void const**)&m_value, (void const*)newValue); return newValue; } + + void operator+=(int add) { ThreadInterlockedExchangeAdd((long*)&m_value, add * sizeof(T)); } +#endif + + void operator-=(int subtract) { operator+=(-subtract); } + + T* operator+(int rhs) const { return m_value + rhs; } + T* operator-(int rhs) const { return m_value - rhs; } + T* operator+(unsigned rhs) const { return m_value + rhs; } + T* operator-(unsigned rhs) const { return m_value - rhs; } + size_t operator-(T* p) const { return m_value - p; } + size_t operator-(const CInterlockedPtr& p) const { return m_value - p.m_value; } + +private: + T* volatile m_value; +}; + +class PLATFORM_CLASS CThreadMutex +{ +public: + CThreadMutex(); + ~CThreadMutex(); + + void Lock(); + void Lock() const { (const_cast(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast(this))->TryLock(); } + + bool AssertOwnedByCurrentThread(); + + void SetTrace(bool); + +private: + CThreadMutex(const CThreadMutex&); + CThreadMutex& operator=(const CThreadMutex&); + +#if defined( _WIN32 ) +#ifdef _WIN64 +#define TT_SIZEOF_CRITICALSECTION 40 +#else +#ifndef _X360 +#define TT_SIZEOF_CRITICALSECTION 24 +#else +#define TT_SIZEOF_CRITICALSECTION 28 +#endif +#endif + byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION]; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_mutexattr_t m_Attr; +#else +#error +#endif + +#ifdef THREAD_MUTEX_TRACING_SUPPORTED + uint m_currentOwnerID; + uint16 m_lockCount; + bool m_bTrace; +#endif +}; + +#if !defined(THREAD_PROFILER) + +class CThreadFastMutex +{ +public: + CThreadFastMutex() + : m_ownerID(0), + m_depth(0) + { + } + +private: + FORCEINLINE bool TryLockInline(const uint32 threadId) volatile + { + if (threadId != m_ownerID && !ThreadInterlockedAssignIf((volatile long*)&m_ownerID, (long)threadId, 0)) + return false; + + ThreadMemoryBarrier(); + ++m_depth; + return true; + } + + bool TryLock(const uint32 threadId) volatile + { + return TryLockInline(threadId); + } + + PLATFORM_CLASS void Lock(const uint32 threadId, unsigned nSpinSleepTime) volatile; + +public: + bool TryLock() volatile + { +#ifdef _DEBUG + if (m_depth == INT_MAX) + DebuggerBreak(); + + if (m_depth < 0) + DebuggerBreak(); +#endif + return TryLockInline(ThreadGetCurrentId()); + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Lock(unsigned int nSpinSleepTime = 0) volatile + { + const uint32 threadId = ThreadGetCurrentId(); + + if (!TryLockInline(threadId)) + { + ThreadPause(); + Lock(threadId, nSpinSleepTime); + } +#ifdef _DEBUG + if (m_ownerID != ThreadGetCurrentId()) + DebuggerBreak(); + + if (m_depth == INT_MAX) + DebuggerBreak(); + + if (m_depth < 0) + DebuggerBreak(); +#endif + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Unlock() volatile + { +#ifdef _DEBUG + if (m_ownerID != ThreadGetCurrentId()) + DebuggerBreak(); + + if (m_depth <= 0) + DebuggerBreak(); +#endif + + --m_depth; + if (!m_depth) + { + ThreadMemoryBarrier(); + ThreadInterlockedExchange(&m_ownerID, 0); + } + } + +#ifdef WIN32 + bool TryLock() const volatile { return (const_cast(this))->TryLock(); } + void Lock(unsigned nSpinSleepTime = 1) const volatile { (const_cast(this))->Lock(nSpinSleepTime); } + void Unlock() const volatile { (const_cast(this))->Unlock(); } +#endif + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace(bool) {} + + uint32 GetOwnerId() const { return m_ownerID; } + int GetDepth() const { return m_depth; } +private: + volatile uint32 m_ownerID; + int m_depth; +}; + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert((size_t)this % 128 == 0 && sizeof(*this) == 128); + } + +private: + uint8 pad[128 - sizeof(CThreadFastMutex)]; +} ALIGN128_POST; + +#else +typedef CThreadMutex CThreadFastMutex; +#endif + +class CThreadNullMutex +{ +public: + static void Lock() {} + static void Unlock() {} + + static bool TryLock() { return true; } + static bool AssertOwnedByCurrentThread() { return true; } + static void SetTrace(bool b) {} + + static uint32 GetOwnerId() { return 0; } + static int GetDepth() { return 0; } +}; + +template +class CThreadConditionalMutex : public BaseClass +{ +public: + void Lock() { if (*pCondition) BaseClass::Lock(); } + void Lock() const { if (*pCondition) BaseClass::Lock(); } + void Unlock() { if (*pCondition) BaseClass::Unlock(); } + void Unlock() const { if (*pCondition) BaseClass::Unlock(); } + + bool TryLock() { if (*pCondition) return BaseClass::TryLock(); else return true; } + bool TryLock() const { if (*pCondition) return BaseClass::TryLock(); else return true; } + bool AssertOwnedByCurrentThread() { if (*pCondition) return BaseClass::AssertOwnedByCurrentThread(); else return true; } + void SetTrace(bool b) { if (*pCondition) BaseClass::SetTrace(b); } +}; + +template +class CThreadTerminalMutex : public BaseClass +{ +public: + bool TryLock() { if (!BaseClass::TryLock()) { DebuggerBreak(); return false; } return true; } + bool TryLock() const { if (!BaseClass::TryLock()) { DebuggerBreak(); return false; } return true; } + void Lock() { if (!TryLock()) BaseClass::Lock(); } + void Lock() const { if (!TryLock()) BaseClass::Lock(); } + +}; + +template +class CAutoLockT +{ +public: + FORCEINLINE CAutoLockT(MUTEX_TYPE& lock) + : m_lock(lock) + { + m_lock.Lock(); + } + + FORCEINLINE CAutoLockT(const MUTEX_TYPE& lock) + : m_lock(const_cast(lock)) + { + m_lock.Lock(); + } + + FORCEINLINE ~CAutoLockT() + { + m_lock.Unlock(); + } + + +private: + MUTEX_TYPE& m_lock; + + CAutoLockT(const CAutoLockT&); + CAutoLockT& operator=(const CAutoLockT&); +}; + +typedef CAutoLockT CAutoLock; + +template struct CAutoLockTypeDeducer {}; +template <> struct CAutoLockTypeDeducer { typedef CThreadMutex Type_t; }; +template <> struct CAutoLockTypeDeducer { typedef CThreadNullMutex Type_t; }; +#if !defined(THREAD_PROFILER) +template <> struct CAutoLockTypeDeducer { typedef CThreadFastMutex Type_t; }; +template <> struct CAutoLockTypeDeducer { typedef CAlignedThreadFastMutex Type_t; }; +#endif + +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< type > UNIQUE_ID( static_cast( mutex ) ) + +#if defined(GNUC) + +template T strip_cv_quals_for_mutex(T&); +template T strip_cv_quals_for_mutex(const T&); +template T strip_cv_quals_for_mutex(volatile T&); +template T strip_cv_quals_for_mutex(const volatile T&); + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( typeof(::strip_cv_quals_for_mutex(mutex)), mutex ) + +#else + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer::Type_t, mutex ) + +#endif + +#define AUTO_LOCK_FM( mutex ) \ + AUTO_LOCK_( CThreadFastMutex, mutex ) + +#define LOCAL_THREAD_LOCK_( tag ) \ + ; \ + static CThreadFastMutex autoMutex_##tag; \ + AUTO_LOCK( autoMutex_##tag ) + +#define LOCAL_THREAD_LOCK() \ + LOCAL_THREAD_LOCK_(_) + +class PLATFORM_CLASS CThreadSyncObject +{ +public: + ~CThreadSyncObject(); + + bool operator!() const; + +#ifdef _WIN32 + operator HANDLE() { return GetHandle(); } + const HANDLE GetHandle() const { return m_hSyncObject; } +#endif + bool Wait(uint32 dwTimeout = TT_INFINITE); + +protected: + CThreadSyncObject(); + void AssertUseable(); + +#ifdef _WIN32 + HANDLE m_hSyncObject; + bool m_bCreatedHandle; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_cond_t m_Condition; + bool m_bInitalized; + int m_cSet; + bool m_bManualReset; + bool m_bWakeForEvent; +#else +#error "Implement me" +#endif + +private: + CThreadSyncObject(const CThreadSyncObject&); + CThreadSyncObject& operator=(const CThreadSyncObject&); +}; + + +#if defined( _WIN32 ) + +class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject +{ +public: + CThreadSemaphore(long initialValue, long maxValue); + + bool Release(long releaseCount = 1, long* pPreviousCount = NULL); + +private: + CThreadSemaphore(const CThreadSemaphore&); + CThreadSemaphore& operator=(const CThreadSemaphore&); +}; + + +class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject +{ +public: + CThreadFullMutex(bool bEstablishInitialOwnership = false, const char* pszName = NULL); + + bool Release(); + + void Lock() { Wait(); } + void Lock(unsigned timeout) { Wait(timeout); } + void Unlock() { Release(); } + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace(bool) {} + +private: + CThreadFullMutex(const CThreadFullMutex&); + CThreadFullMutex& operator=(const CThreadFullMutex&); +}; +#endif + + +class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject +{ +public: + CThreadEvent(bool fManualReset = false); +#ifdef WIN32 + CThreadEvent(HANDLE hHandle); +#endif + bool Set(); + + bool Reset(); + + bool Check(); + + bool Wait(uint32 dwTimeout = TT_INFINITE); + +private: + CThreadEvent(const CThreadEvent&); + CThreadEvent& operator=(const CThreadEvent&); +}; + +class CThreadManualEvent : public CThreadEvent +{ +public: + CThreadManualEvent() + : CThreadEvent(true) + { + } +}; + +inline int ThreadWaitForEvents(int nEvents, CThreadEvent* const* pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE) +{ +#ifdef POSIX + Assert(nEvents == 1); + if (pEvents[0]->Wait(timeout)) + return WAIT_OBJECT_0; + else + return WAIT_TIMEOUT; +#else + HANDLE handles[64]; + for (unsigned int i = 0; i < min(nEvents, ARRAYSIZE(handles)); i++) + handles[i] = pEvents[i]->GetHandle(); + return ThreadWaitForObjects(nEvents, handles, bWaitAll, timeout); +#endif +} + +class PLATFORM_CLASS CThreadRWLock +{ +public: + CThreadRWLock(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + void LockForRead() const { const_cast(this)->LockForRead(); } + void UnlockRead() const { const_cast(this)->UnlockRead(); } + void LockForWrite() const { const_cast(this)->LockForWrite(); } + void UnlockWrite() const { const_cast(this)->UnlockWrite(); } + +private: + void WaitForRead(); + +#ifdef WIN32 + CThreadFastMutex m_mutex; +#else + CThreadMutex m_mutex; +#endif + CThreadEvent m_CanWrite; + CThreadEvent m_CanRead; + + int m_nWriters; + int m_nActiveReaders; + int m_nPendingReaders; +}; + +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() { COMPILE_TIME_ASSERT(sizeof(LockInfo_t) == sizeof(int64)); Assert((intp)this % 8 == 0); memset(this, 0, sizeof(*this)); } + + bool TryLockForWrite(); + bool TryLockForRead(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + bool TryLockForWrite() const { return const_cast(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast(this)->TryLockForRead(); } + void LockForRead() const { const_cast(this)->LockForRead(); } + void UnlockRead() const { const_cast(this)->UnlockRead(); } + void LockForWrite() const { const_cast(this)->LockForWrite(); } + void UnlockWrite() const { const_cast(this)->UnlockWrite(); } + +private: + struct LockInfo_t + { + uint32 m_writerId; + int m_nReaders; + }; + + bool AssignIf(const LockInfo_t& newValue, const LockInfo_t& comperand); + bool TryLockForWrite(const uint32 threadId); + void SpinLockForWrite(const uint32 threadId); + + volatile LockInfo_t m_lockInfo; + CInterlockedInt m_nWriters; +} ALIGN8_POST; + +class PLATFORM_CLASS CThread +{ +public: + CThread(); + virtual ~CThread(); + + const char* GetName(); + void SetName(const char*); + + size_t CalcStackDepth(void* pStackVariable) { return ((byte*)m_pStackBase - (byte*)pStackVariable); } + + virtual bool Start(unsigned nBytesStack = 0); + + bool IsAlive(); + + bool Join(unsigned timeout = TT_INFINITE); + +#ifdef _WIN32 + HANDLE GetThreadHandle(); + uint GetThreadId(); +#elif defined( LINUX ) + uint GetThreadId(); +#endif + + int GetResult(); + + void Stop(int exitCode = 0); + + int GetPriority() const; + + bool SetPriority(int); + + void SuspendCooperative(); + + void ResumeCooperative(); + + void BWaitForThreadSuspendCooperative(); + +#ifndef LINUX + unsigned int Suspend(); + + unsigned int Resume(); +#endif + + bool Terminate(int exitCode = 0); + + static CThread* GetCurrentCThread(); + +#ifdef Yield +#undef Yield +#endif + static void Yield(); + + static void Sleep(unsigned duration); + +protected: + + virtual bool Init(); + + virtual int Run() = 0; + + virtual void OnExit(); + + void Cleanup(); + + bool WaitForCreateComplete(CThreadEvent* pEvent); + + typedef unsigned(__stdcall* ThreadProc_t)(void*); + virtual ThreadProc_t GetThreadProc(); + virtual bool IsThreadRunning(); + + CThreadMutex m_Lock; + +#ifdef WIN32 + ThreadHandle_t GetThreadID() const { return (ThreadHandle_t)m_hThread; } +#else + ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; } +#endif + +private: + enum Flags + { + SUPPORT_STOP_PROTOCOL = 1 << 0 + }; + + struct ThreadInit_t + { + CThread* pThread; + CThreadEvent* pInitCompleteEvent; + bool* pfInitSuccess; + }; + + static unsigned __stdcall ThreadProc(void* pv); + + CThread(const CThread&); + CThread& operator=(const CThread&); + +#ifdef _WIN32 + HANDLE m_hThread; + ThreadId_t m_threadId; +#elif defined(POSIX) + pthread_t m_threadId; +#endif + CInterlockedInt m_nSuspendCount; + CThreadEvent m_SuspendEvent; + CThreadEvent m_SuspendEventSignal; + int m_result; + char m_szName[32]; + void* m_pStackBase; + unsigned m_flags; +}; + +class PLATFORM_CLASS CValidatableThread : public CThread +{ +public: + CValidatableThread() + { + m_bSleepForValidate = false; + m_bSleepingForValidate = false; + } + +#ifdef DBGFLAG_VALIDATE + virtual void SleepForValidate() { m_bSleepForValidate = true; } + bool BSleepingForValidate() { return m_bSleepingForValidate; } + virtual void WakeFromValidate() { m_bSleepForValidate = false; } +#endif +protected: + bool m_bSleepForValidate; + bool m_bSleepingForValidate; +}; + + +enum WTCallResult_t +{ + WTCR_FAIL = -1, + WTCR_TIMEOUT = -2, + WTCR_THREAD_GONE = -3, +}; + +class CFunctor; +class PLATFORM_CLASS CWorkerThread : public CThread +{ +public: + CWorkerThread(); + + int CallWorker(unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true, CFunctor* pParamFunctor = NULL); + + int CallMaster(unsigned, unsigned timeout = TT_INFINITE); + + bool WaitForCall(unsigned dwTimeout, unsigned* pResult = NULL); + bool WaitForCall(unsigned* pResult = NULL); + + bool PeekCall(unsigned* pParam = NULL, CFunctor** ppParamFunctor = NULL); + + void Reply(unsigned); + + int WaitForReply(unsigned timeout = TT_INFINITE); + + CThreadEvent& GetCallHandle(); + unsigned GetCallParam(CFunctor** ppParamFunctor = NULL) const; + + int BoostPriority(); + +protected: +#ifndef _WIN32 +#define __stdcall +#endif + typedef uint32(__stdcall* WaitFunc_t)(int nEvents, CThreadEvent* const* pEvents, int bWaitAll, uint32 timeout); + + int Call(unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL, CFunctor* pParamFunctor = NULL); + int WaitForReply(unsigned timeout, WaitFunc_t); + +private: + CWorkerThread(const CWorkerThread&); + CWorkerThread& operator=(const CWorkerThread&); + + CThreadEvent m_EventSend; + CThreadEvent m_EventComplete; + + unsigned m_Param; + CFunctor* m_pParamFunctor; + int m_ReturnVal; +}; + + +template class CMessageQueue +{ + CThreadEvent SignalEvent; + CThreadMutex QueueAccessMutex; + + struct MsgNode + { + MsgNode* Next; + T Data; + }; + + MsgNode* Head; + MsgNode* Tail; + +public: + CMessageQueue(void) + { + Head = Tail = NULL; + } + + bool MessageWaiting(void) + { + return (Head != NULL); + } + + void WaitMessage(T* pMsg) + { + for (;;) + { + while (!MessageWaiting()) + SignalEvent.Wait(); + QueueAccessMutex.Lock(); + if (!Head) + { + QueueAccessMutex.Unlock(); + continue; + } + *(pMsg) = Head->Data; + MsgNode* remove_this = Head; + Head = Head->Next; + if (!Head) + Tail = NULL; + QueueAccessMutex.Unlock(); + delete remove_this; + break; + } + } + + void QueueMessage(T const& Msg) + { + MsgNode* new1 = new MsgNode; + new1->Data = Msg; + new1->Next = NULL; + QueueAccessMutex.Lock(); + if (Tail) + { + Tail->Next = new1; + Tail = new1; + } + else + { + Head = new1; + Tail = new1; + } + SignalEvent.Set(); + QueueAccessMutex.Unlock(); + } +}; + + +#ifdef _WIN32 +typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION; +typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + +#ifndef _X360 +extern "C" +{ + void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION*); + void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION*); + void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION*); + void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION*); +}; +#endif + +inline void CThreadMutex::Lock() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED + uint thisThreadID = ThreadGetCurrentId(); + if (m_bTrace && m_currentOwnerID && (m_currentOwnerID != thisThreadID)) + Msg("Thread %u about to wait for lock %p owned by %u\n", ThreadGetCurrentId(), (CRITICAL_SECTION*)&m_CriticalSection, m_currentOwnerID); +#endif + + VCRHook_EnterCriticalSection((CRITICAL_SECTION*)&m_CriticalSection); + +#ifdef THREAD_MUTEX_TRACING_ENABLED + if (m_lockCount == 0) + { + m_currentOwnerID = thisThreadID; + if (m_bTrace) + Msg("Thread %u now owns lock %p\n", m_currentOwnerID, (CRITICAL_SECTION*)&m_CriticalSection); + } + m_lockCount++; +#endif +} + +inline void CThreadMutex::Unlock() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED + AssertMsg(m_lockCount >= 1, "Invalid unlock of thread lock"); + m_lockCount--; + if (m_lockCount == 0) + { + if (m_bTrace) + Msg("Thread %u releasing lock %p\n", m_currentOwnerID, (CRITICAL_SECTION*)&m_CriticalSection); + m_currentOwnerID = 0; + } +#endif + LeaveCriticalSection((CRITICAL_SECTION*)&m_CriticalSection); +} + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED + if (ThreadGetCurrentId() == m_currentOwnerID) + return true; + AssertMsg3(0, "Expected thread %u as owner of lock %p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION*)&m_CriticalSection, m_currentOwnerID); + return false; +#else + return true; +#endif +} + +inline void CThreadMutex::SetTrace(bool bTrace) +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED + m_bTrace = bTrace; +#endif +} + +#elif defined(POSIX) + +inline CThreadMutex::CThreadMutex() +{ + pthread_mutexattr_init(&m_Attr); + pthread_mutexattr_settype(&m_Attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_Mutex, &m_Attr); +} + +inline CThreadMutex::~CThreadMutex() +{ + pthread_mutex_destroy(&m_Mutex); +} + +inline void CThreadMutex::Lock() +{ + pthread_mutex_lock(&m_Mutex); +} + +inline void CThreadMutex::Unlock() +{ + pthread_mutex_unlock(&m_Mutex); +} + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ + return true; +} + +inline void CThreadMutex::SetTrace(bool fTrace) +{ +} + +#endif + +inline CThreadRWLock::CThreadRWLock() + : m_CanRead(true), + m_nWriters(0), + m_nActiveReaders(0), + m_nPendingReaders(0) +{ +} + +inline void CThreadRWLock::LockForRead() +{ + m_mutex.Lock(); + if (m_nWriters) + { + WaitForRead(); + } + m_nActiveReaders++; + m_mutex.Unlock(); +} + +inline void CThreadRWLock::UnlockRead() +{ + m_mutex.Lock(); + m_nActiveReaders--; + if (m_nActiveReaders == 0 && m_nWriters != 0) + { + m_CanWrite.Set(); + } + m_mutex.Unlock(); +} + + +inline bool CThreadSpinRWLock::AssignIf(const LockInfo_t& newValue, const LockInfo_t& comperand) +{ + return ThreadInterlockedAssignIf64((int64*)&m_lockInfo, *((int64*)&newValue), *((int64*)&comperand)); +} + +inline bool CThreadSpinRWLock::TryLockForWrite(const uint32 threadId) +{ + if (m_lockInfo.m_nReaders > 0 || (m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId)) + { + return false; + } + + static const LockInfo_t oldValue = { 0, 0 }; + LockInfo_t newValue = { threadId, 0 }; + const bool bSuccess = AssignIf(newValue, oldValue); +#if defined(_X360) + if (bSuccess) + { + } +#endif + return bSuccess; +} + +inline bool CThreadSpinRWLock::TryLockForWrite() +{ + m_nWriters++; + if (!TryLockForWrite(ThreadGetCurrentId())) + { + m_nWriters--; + return false; + } + return true; +} + +inline bool CThreadSpinRWLock::TryLockForRead() +{ + if (m_nWriters != 0) + { + return false; + } + LockInfo_t oldValue; + LockInfo_t newValue; + + oldValue.m_nReaders = m_lockInfo.m_nReaders; + oldValue.m_writerId = 0; + newValue.m_nReaders = oldValue.m_nReaders + 1; + newValue.m_writerId = 0; + + const bool bSuccess = AssignIf(newValue, oldValue); +#if defined(_X360) + if (bSuccess) + { + } +#endif + return bSuccess; +} + +inline void CThreadSpinRWLock::LockForWrite() +{ + const uint32 threadId = ThreadGetCurrentId(); + + m_nWriters++; + + if (!TryLockForWrite(threadId)) + { + ThreadPause(); + SpinLockForWrite(threadId); + } +} + +template FORCEINLINE T ReadVolatileMemory(T const* pPtr) +{ + volatile const T* pVolatilePtr = (volatile const T*)pPtr; + return *pVolatilePtr; +} + +#if defined( _WIN32 ) +#pragma warning(pop) +#endif + +#endif +``` + +`SpyCustom/sdk/tier1.h`: + +```h + +#ifndef TIER1_H +#define TIER1_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "iappsystem.h" +#include "convar.h" + + +void ConnectTier1Libraries(CreateInterfaceFn* pFactoryList, int nFactoryCount); +void DisconnectTier1Libraries(); + + +template< class IInterface, int ConVarFlag = 0 > +class CTier1AppSystem : public CTier0AppSystem< IInterface > +{ + typedef CTier0AppSystem< IInterface > BaseClass; + +public: + virtual bool Connect(CreateInterfaceFn factory) + { + if (!BaseClass::Connect(factory)) + return false; + + ConnectTier1Libraries(&factory, 1); + return true; + } + + virtual void Disconnect() + { + DisconnectTier1Libraries(); + BaseClass::Disconnect(); + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if (nRetVal != INIT_OK) + return nRetVal; + + if (g_pCVar) + { + ConVar_Register(ConVarFlag); + } + return INIT_OK; + } + + virtual void Shutdown() + { + if (g_pCVar) + { + ConVar_Unregister(); + } + BaseClass::Shutdown(); + } + + + virtual AppSystemTier_t GetTier() + { + return APP_SYSTEM_TIER1; + } +}; + + +#endif +``` + +`SpyCustom/sdk/tier2.h`: + +```h + +#ifndef TIER2_H +#define TIER2_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1.h" + + +void ConnectTier2Libraries(CreateInterfaceFn* pFactoryList, int nFactoryCount); +void DisconnectTier2Libraries(); + + +void InitDefaultFileSystem(void); +void ShutdownDefaultFileSystem(void); + + +void InitCommandLineProgram(int& argc, char**& argv); + + +template< class IInterface, int ConVarFlag = 0 > +class CTier2AppSystem : public CTier1AppSystem< IInterface, ConVarFlag > +{ + typedef CTier1AppSystem< IInterface, ConVarFlag > BaseClass; + +public: + virtual bool Connect(CreateInterfaceFn factory) + { + if (!BaseClass::Connect(factory)) + return false; + + ConnectTier2Libraries(&factory, 1); + return true; + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if (nRetVal != INIT_OK) + return nRetVal; + + return INIT_OK; + } + + + virtual AppSystemTier_t GetTier() + { + return APP_SYSTEM_TIER2; + } + virtual void Shutdown() + { + BaseClass::Shutdown(); + } + + virtual void Disconnect() + { + DisconnectTier2Libraries(); + BaseClass::Disconnect(); + } +}; + + +enum FadeMode_t +{ + FADE_MODE_NONE = 0, + FADE_MODE_LOW, + FADE_MODE_MED, + FADE_MODE_HIGH, + FADE_MODE_360, + FADE_MODE_PS3, + FADE_MODE_LEVEL, + + FADE_MODE_COUNT, +}; + +struct FadeData_t +{ + float m_flPixelMin; + float m_flPixelMax; + float m_flWidth; + float m_flFadeDistScale; +}; + +extern FadeData_t g_aFadeData[FADE_MODE_COUNT]; + + +extern uint32 g_nResourceFrameCount; + + +#endif +``` + +`SpyCustom/sdk/tier2_logging.h`: + +```h +#ifndef TIER2_LOGGING_H +#define TIER2_LOGGING_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "logging.h" + + +const int MAX_SIMULTANEOUS_LOGGING_FILE_COUNT = 16; +const int INVALID_LOGGING_FILE_HANDLE = -1; + +typedef int LoggingFileHandle_t; +typedef void* FileHandle_t; + +#define FILELOGGINGLISTENER_INTERFACE_VERSION "FileLoggingListener001" + +abstract_class IFileLoggingListener : public ILoggingListener +{ +public: + virtual void Log(const LoggingContext_t * pContext, const char* pMessage) = 0; + + virtual LoggingFileHandle_t BeginLoggingToFile(const char* pFilename, const char* pOptions, const char* pPathID = NULL) = 0; + virtual void EndLoggingToFile(LoggingFileHandle_t fileHandle) = 0; + + virtual void AssignLogChannel(LoggingChannelID_t channelID, LoggingFileHandle_t loggingFileHandle) = 0; + virtual void UnassignLogChannel(LoggingChannelID_t channelID) = 0; + virtual void AssignAllLogChannels(LoggingFileHandle_t loggingFileHandle) = 0; + virtual void UnassignAllLogChannels() = 0; +}; + +class CFileLoggingListener : public IFileLoggingListener +{ +public: + CFileLoggingListener(); + ~CFileLoggingListener(); + + virtual void Log(const LoggingContext_t* pContext, const char* pMessage); + + virtual LoggingFileHandle_t BeginLoggingToFile(const char* pFilename, const char* pOptions, const char* pPathID = NULL); + virtual void EndLoggingToFile(LoggingFileHandle_t fileHandle); + + virtual void AssignLogChannel(LoggingChannelID_t channelID, LoggingFileHandle_t loggingFileHandle); + virtual void UnassignLogChannel(LoggingChannelID_t channelID); + virtual void AssignAllLogChannels(LoggingFileHandle_t loggingFileHandle); + virtual void UnassignAllLogChannels(); + +private: + int GetUnusedFileInfo() const; + + struct FileInfo_t + { + FileHandle_t m_FileHandle; + + bool IsOpen() const { return m_FileHandle != 0; } + void Reset() { m_FileHandle = 0; } + }; + + FileInfo_t m_OpenFiles[MAX_SIMULTANEOUS_LOGGING_FILE_COUNT]; + + int m_FileIndices[MAX_LOGGING_CHANNEL_COUNT]; +}; + +#endif + +``` + +`SpyCustom/sdk/tier3.h`: + +```h + +#ifndef TIER3_H +#define TIER3_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier2.h" + + +void ConnectTier3Libraries(CreateInterfaceFn* pFactoryList, int nFactoryCount); +void DisconnectTier3Libraries(); + + +template< class IInterface, int ConVarFlag = 0 > +class CTier3AppSystem : public CTier2AppSystem< IInterface, ConVarFlag > +{ + typedef CTier2AppSystem< IInterface, ConVarFlag > BaseClass; + +public: + virtual bool Connect(CreateInterfaceFn factory) + { + if (!BaseClass::Connect(factory)) + return false; + + ConnectTier3Libraries(&factory, 1); + return true; + } + + virtual void Disconnect() + { + DisconnectTier3Libraries(); + BaseClass::Disconnect(); + } + + + virtual AppSystemTier_t GetTier() + { + return APP_SYSTEM_TIER3; + } +}; + + +#endif +``` + +`SpyCustom/sdk/timedevent.h`: + +```h +#ifndef TIMEDEVENT_H +#define TIMEDEVENT_H +#ifdef _WIN32 +#pragma once +#endif + +class TimedEvent +{ +public: + TimedEvent() + { + m_TimeBetweenEvents = -1; + m_fNextEvent = 0; + } + + inline void Init(float rate) + { + m_TimeBetweenEvents = 1.0f / rate; + m_fNextEvent = 0; + } + + inline void ResetRate(float rate) + { + m_TimeBetweenEvents = 1.0f / rate; + } + + inline bool NextEvent(float& curDelta) + { + Assert(m_TimeBetweenEvents != -1); + + if (curDelta >= m_fNextEvent) + { + curDelta -= m_fNextEvent; + + m_fNextEvent = m_TimeBetweenEvents; + return true; + } + else + { + m_fNextEvent -= curDelta; + return false; + } + } + +private: + float m_TimeBetweenEvents; + float m_fNextEvent; +}; + +#endif +``` + +`SpyCustom/sdk/timeutils.h`: + +```h +#ifndef TIMEUTILS_H +#define TIMEUTILS_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include "dbg.h" + +enum RoundStyle_t +{ + ROUND_NEAREST, + ROUND_DOWN, + ROUND_UP, +}; + +class DmeTime_t; + +class DmeFramerate_t +{ +public: + DmeFramerate_t(float fps); + DmeFramerate_t(int fps = 0); + DmeFramerate_t(const DmeFramerate_t& src) : m_num(src.m_num), m_den(src.m_den) {} + + void SetFramerate(float flFrameRate); + void SetFramerate(int fps); + void SetFramerateNTSC(int multiplier = 30); + + float GetFramesPerSecond() const; + DmeTime_t GetTimePerFrame() const; + + bool operator==(DmeFramerate_t f) const { return m_num == f.m_num && m_den == f.m_den; } + bool operator!=(DmeFramerate_t f) const { return m_num != f.m_num && m_den != f.m_den; } + bool operator< (DmeFramerate_t f) const { return m_num * (int)f.m_den < f.m_num* (int)m_den; } + bool operator> (DmeFramerate_t f) const { return m_num * (int)f.m_den > f.m_num * (int)m_den; } + bool operator<=(DmeFramerate_t f) const { return m_num * (int)f.m_den <= f.m_num * (int)m_den; } + bool operator>=(DmeFramerate_t f) const { return m_num * (int)f.m_den >= f.m_num * (int)m_den; } + + DmeFramerate_t operator*(int i) const { return DmeFramerate_t(m_num * i, m_den); } + DmeFramerate_t operator/(int i) const { return DmeFramerate_t(m_num, m_den * i); } + + DmeFramerate_t operator*=(int i) { Assert(abs(m_num * i) <= USHRT_MAX); m_num *= (unsigned short)i; return *this; } + DmeFramerate_t operator/=(int i) { Assert(abs(m_den * i) <= USHRT_MAX); m_den *= (unsigned short)i; return *this; } + +private: + DmeFramerate_t(int nNumerator, int nDenominator); + + unsigned short m_num; + unsigned short m_den; + + friend class DmeTime_t; +}; + +#define DMETIME_ZERO DmeTime_t(0) +#define DMETIME_MINDELTA DmeTime_t::MinTimeDelta() +#define DMETIME_MINTIME DmeTime_t::MinTime() +#define DMETIME_MAXTIME DmeTime_t::MaxTime() +#define DMETIME_INVALID DmeTime_t::InvalidTime() + +class DmeTime_t +{ +public: + DmeTime_t() : m_tms(INT_MIN) {} + explicit DmeTime_t(int tms) : m_tms(tms) {} + explicit DmeTime_t(float sec) : m_tms(RoundSecondsToTMS(sec)) {} + explicit DmeTime_t(double sec) : m_tms(RoundSecondsToTMS(sec)) {} + DmeTime_t(int frame, DmeFramerate_t framerate); + + + friend bool operator==(DmeTime_t a, DmeTime_t b) { return a.m_tms == b.m_tms; } + friend bool operator!=(DmeTime_t a, DmeTime_t b) { return a.m_tms != b.m_tms; } + friend bool operator< (DmeTime_t a, DmeTime_t b) { return a.m_tms < b.m_tms; } + friend bool operator> (DmeTime_t a, DmeTime_t b) { return a.m_tms > b.m_tms; } + friend bool operator<=(DmeTime_t a, DmeTime_t b) { return a.m_tms <= b.m_tms; } + friend bool operator>=(DmeTime_t a, DmeTime_t b) { return a.m_tms >= b.m_tms; } + + friend DmeTime_t operator%(DmeTime_t a, DmeTime_t b) { return DmeTime_t(a.m_tms % b.m_tms); } + friend DmeTime_t operator+(DmeTime_t a, DmeTime_t b) { return DmeTime_t(a.m_tms + b.m_tms); } + friend DmeTime_t operator-(DmeTime_t a, DmeTime_t b) { return DmeTime_t(a.m_tms - b.m_tms); } + + DmeTime_t operator-() const { return DmeTime_t(-m_tms); } + + DmeTime_t operator+=(DmeTime_t t) { m_tms += t.m_tms; return *this; } + DmeTime_t operator-=(DmeTime_t t) { m_tms -= t.m_tms; return *this; } + + friend DmeTime_t operator*(DmeTime_t t, float f) { t *= f; return t; } + friend DmeTime_t operator*(float f, DmeTime_t t) { t *= f; return t; } + friend DmeTime_t operator/(DmeTime_t t, float f) { t /= f; return t; } + friend float operator/(DmeTime_t n, DmeTime_t d) { return float(n.m_tms / double(d.m_tms)); } + + DmeTime_t operator*=(float f); + DmeTime_t operator/=(float f); + + DmeTime_t operator++() { ++m_tms; return *this; } + DmeTime_t operator--() { --m_tms; return *this; } + DmeTime_t operator++(int) { DmeTime_t t = *this; ++m_tms; return t; } + DmeTime_t operator--(int) { DmeTime_t t = *this; --m_tms; return t; } + + bool IsValid() const { return m_tms != INT_MIN; } + + static DmeTime_t InvalidTime() { return DmeTime_t(INT_MIN); } + static DmeTime_t MinTime() { return DmeTime_t(INT_MIN + 1); } + static DmeTime_t MaxTime() { return DmeTime_t(INT_MAX); } + static DmeTime_t MinTimeDelta() { return DmeTime_t(1); } + + + int GetTenthsOfMS() const { return m_tms; } + float GetSeconds() const { return m_tms * 0.0001f; } + void SetTenthsOfMS(int tms) { m_tms = tms; } + void SetSeconds(float sec) { m_tms = RoundSecondsToTMS(sec); } + + + void Clamp(DmeTime_t lo, DmeTime_t hi); + bool IsInRange(DmeTime_t lo, DmeTime_t hi) const; + + + friend float GetFractionOfTimeBetween(DmeTime_t t, DmeTime_t start, DmeTime_t end, bool bClamp); + friend float GetFractionOfTime(DmeTime_t t, DmeTime_t duration, bool bClamp); + friend int FrameForTime(DmeTime_t t, DmeFramerate_t framerate); + + + friend DmeTime_t abs(DmeTime_t t) { return t.m_tms >= 0 ? t : -t; } + + + int CurrentFrame(DmeFramerate_t framerate, RoundStyle_t roundStyle = ROUND_DOWN) const; + DmeTime_t TimeAtCurrentFrame(DmeFramerate_t framerate, RoundStyle_t roundStyle = ROUND_DOWN) const; + DmeTime_t TimeAtNextFrame(DmeFramerate_t framerate) const; + DmeTime_t TimeAtPrevFrame(DmeFramerate_t framerate) const; + +private: + explicit DmeTime_t(int64 tms) : m_tms(int(tms)) {} + + static int RoundSecondsToTMS(float sec); + static int RoundSecondsToTMS(double sec); + + int m_tms; +}; + +float GetFractionOfTimeBetween(DmeTime_t t, DmeTime_t start, DmeTime_t end, bool bClamp = false); +float GetFractionOfTime(DmeTime_t t, DmeTime_t duration, bool bClamp = false); + +class CUtlBuffer; +bool Serialize(CUtlBuffer& buf, const DmeTime_t& src); +bool Unserialize(CUtlBuffer& buf, DmeTime_t& dest); + + +#endif +``` + +`SpyCustom/sdk/tokenset.h`: + +```h +//========= Copyright © 2008, Valve Corporation, All rights reserved. ============// + +#ifndef __TOKENSET_H +#define __TOKENSET_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// +// This class is a handy way to match a series of values to stings and vice +// versa. It should be initalized as static like an array, for example: +// +// const tokenset_t tokens[] = { +// { "token1", 1 }, +// { "token2", 2 }, +// { "token3", 3 }, +// { NULL, -1 } +// }; +// +// Then you can call the operators on it by using: +// +// int t = tokens->GetToken( s ); +// +// If s is "token1" it returns 1, etc. Invalid string returns the last NULL +// value. GetNameByToken() returns "__UNKNOWN__" when passed a mismatched +// token. GetNameByToken() returns szMismatchResult when passed a mismatched +// token and a string to return in case of mismatch. +// +//----------------------------------------------------------------------------- + +template +struct tokenset_t +{ + const char *name; + _T token; + + _T GetToken( const char *s ) const; + _T GetTokenI( const char *s ) const; + const char *GetNameByToken( _T token ) const; + const char *GetNameByToken( _T token, const char *szMismatchResult ) const; +}; + +template +inline _T tokenset_t< _T >::GetToken( const char *s ) const +{ + const tokenset_t< _T > *c; + + for ( c = this; c->name; ++c ) + { + if ( !s ) + { + continue; // Loop to the last NULL value + } + + if ( Q_strcmp( s, c->name ) == 0 ) + { + return c->token; + } + } + + return c->token; // c points to the last NULL value +} + +template +inline _T tokenset_t< _T >::GetTokenI( const char *s ) const +{ + const tokenset_t< _T > *c; + + for ( c = this; c->name; ++c ) + { + if ( !s ) + { + continue; // Loop to the last NULL value + } + + if ( Q_stricmp( s, c->name ) == 0 ) + { + return c->token; + } + } + + return c->token; // c points to the last NULL value +} + +template +inline const char *tokenset_t< _T >::GetNameByToken( _T token ) const +{ + static const char *unknown = "__UNKNOWN__"; + + const tokenset_t< _T > *c; + + for ( c = this; c->name; ++c ) + { + if ( c->token == token ) + { + return c->name; + } + } + + return unknown; +} + +template +inline const char *tokenset_t< _T >::GetNameByToken( _T token, char const *szMismatchResult ) const +{ + const tokenset_t< _T > *c; + + for ( c = this; c->name; ++c ) + { + if ( c->token == token ) + { + return c->name; + } + } + + return szMismatchResult; +} + +#endif //__TOKENSET_H +``` + +`SpyCustom/sdk/touchlink.h`: + +```h +#ifndef TOUCHLINK_H +#define TOUCHLINK_H +#ifdef _WIN32 +#pragma once +#endif + + +enum touchlink_flags_t +{ + FTOUCHLINK_START_TOUCH = 0x00000001, +}; + +struct touchlink_t +{ +#if defined( CLIENT_DLL ) + C_BaseEntity* entityTouched; +#else + EHANDLE entityTouched; +#endif + int touchStamp; + touchlink_t* nextLink; + touchlink_t* prevLink; + int flags; +}; + +#define TOUCHSTAMP_EVENT_DRIVEN -1 + + +#endif +``` + +`SpyCustom/sdk/trace.h`: + +```h +#ifndef TRACE_H +#define TRACE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "mathlib.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) + +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 vecStart; // start position + Vector vecEnd; // final position + cplane_t plane; + + + float fraction; + + int contents; + unsigned short dispFlags; + + bool allsolid; + bool startsolid; + + + CBaseTrace() {} + +private: + CBaseTrace(const CBaseTrace& vOther); +}; + +#endif +``` + +`SpyCustom/sdk/tslist.h`: + +```h +#ifndef TSLIST_H +#define TSLIST_H + +#if defined( _WIN32 ) +#pragma once +#pragma warning( push ) +#pragma warning( disable : 4700 ) +#endif + +#if defined( USE_NATIVE_SLIST ) && !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "dbg.h" +#include "threadtools.h" +#include "memalloc.h" +#include "memdbgoff.h" + +#if defined( _X360 ) +#define USE_NATIVE_SLIST +#endif + +#if defined( PLATFORM_64BITS ) + +#if defined (PLATFORM_WINDOWS) +#else +typedef __int128_t int128; +#define int128_zero() 0 +#endif + +#define TSLIST_HEAD_ALIGNMENT 16 +#define TSLIST_NODE_ALIGNMENT 16 + +#ifdef POSIX +inline bool ThreadInterlockedAssignIf128(int128 volatile* pDest, const int128& value, const int128& comparand) +{ + int128 local_comparand = comparand; + return __sync_bool_compare_and_swap(pDest, local_comparand, value); +} +#endif + +inline bool ThreadInterlockedAssignIf64x128(volatile int128* pDest, const int128& value, const int128& comperand) +{ + return ThreadInterlockedAssignIf128(pDest, value, comperand); +} +#else +#define TSLIST_HEAD_ALIGNMENT 8 +#define TSLIST_NODE_ALIGNMENT 8 +inline bool ThreadInterlockedAssignIf64x128(volatile int64* pDest, const int64 value, const int64 comperand) +{ + return ThreadInterlockedAssignIf64(pDest, value, comperand); +} +#endif + +#ifdef _MSC_VER +#define TSLIST_HEAD_ALIGN DECL_ALIGN(TSLIST_HEAD_ALIGNMENT) +#define TSLIST_NODE_ALIGN DECL_ALIGN(TSLIST_NODE_ALIGNMENT) +#define TSLIST_HEAD_ALIGN_POST +#define TSLIST_NODE_ALIGN_POST +#elif defined( GNUC ) +#define TSLIST_HEAD_ALIGN +#define TSLIST_NODE_ALIGN +#define TSLIST_HEAD_ALIGN_POST DECL_ALIGN(TSLIST_HEAD_ALIGNMENT) +#define TSLIST_NODE_ALIGN_POST DECL_ALIGN(TSLIST_NODE_ALIGNMENT) +#elif defined( _PS3 ) +#define TSLIST_HEAD_ALIGNMENT 8 +#define TSLIST_NODE_ALIGNMENT 8 + +#define TSLIST_HEAD_ALIGN ALIGN8 +#define TSLIST_NODE_ALIGN ALIGN8 +#define TSLIST_HEAD_ALIGN_POST ALIGN8_POST +#define TSLIST_NODE_ALIGN_POST ALIGN8_POST + +#else +#error +#endif + +PLATFORM_INTERFACE bool RunTSQueueTests(int nListSize = 10000, int nTests = 1); +PLATFORM_INTERFACE bool RunTSListTests(int nListSize = 10000, int nTests = 1); + +#ifdef USE_NATIVE_SLIST +typedef SLIST_ENTRY TSLNodeBase_t; +typedef SLIST_HEADER TSLHead_t; +#else +struct TSLIST_NODE_ALIGN TSLNodeBase_t +{ + TSLNodeBase_t* Next; +} TSLIST_NODE_ALIGN_POST; + +union TSLIST_HEAD_ALIGN TSLHead_t +{ + struct Value_t + { + TSLNodeBase_t* Next; +#ifdef VALVE_BIG_ENDIAN + int16 Sequence; + int16 Depth; +#else + int16 Depth; + int16 Sequence; +#endif +#ifdef PLATFORM_64BITS + int32 Padding; +#endif + } value; + + struct Value32_t + { + TSLNodeBase_t* Next_do_not_use_me; + int32 DepthAndSequence; + } value32; + +#ifdef PLATFORM_64BITS + int128 value64x128; +#else + int64 value64x128; +#endif +} TSLIST_HEAD_ALIGN_POST; + +#endif + +class CTSListBase +{ +public: + + static void* operator new(size_t size) + { + CTSListBase* pNode = (CTSListBase*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__); + return pNode; + } + + static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine) + { + CTSListBase* pNode = (CTSListBase*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine); + return pNode; + } + + static void operator delete(void* p) + { + MemAlloc_FreeAligned(p); + } + + static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine) + { + MemAlloc_FreeAligned(p); + } + +private: + static void* operator new[](size_t size); + static void operator delete[](void* p); + +public: + + CTSListBase() + { + if (((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0) + { + Error("CTSListBase: Misaligned list\n"); + DebuggerBreak(); + } + +#ifdef USE_NATIVE_SLIST + InitializeSListHead(&m_Head); +#elif defined(PLATFORM_64BITS) + m_Head.value64x128 = int128_zero(); +#else + m_Head.value64x128 = (int64)0; +#endif + } + + ~CTSListBase() + { + Detach(); + } + + TSLNodeBase_t* Push(TSLNodeBase_t* pNode) + { +#ifdef _DEBUG + if ((size_t)pNode % TSLIST_NODE_ALIGNMENT != 0) + { + Error("CTSListBase: Misaligned node\n"); + DebuggerBreak(); + } +#endif + +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + return (TSLNodeBase_t*)InterlockedPushEntrySListRelease(&m_Head, pNode); +#else + return (TSLNodeBase_t*)InterlockedPushEntrySList(&m_Head, pNode); +#endif +#else + TSLHead_t oldHead; + TSLHead_t newHead; + +#if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); +#endif + +#ifdef PLATFORM_64BITS + newHead.value.Padding = 0; +#endif + for (;; ) + { + oldHead.value64x128 = m_Head.value64x128; + pNode->Next = oldHead.value.Next; + newHead.value.Next = pNode; + + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence + 0x10001; + + + if (ThreadInterlockedAssignIf64x128(&m_Head.value64x128, newHead.value64x128, oldHead.value64x128)) + { + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t*)oldHead.value.Next; +#endif + } + + TSLNodeBase_t* Pop() + { +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + TSLNodeBase_t* pNode = (TSLNodeBase_t*)InterlockedPopEntrySListAcquire(&m_Head); +#else + TSLNodeBase_t* pNode = (TSLNodeBase_t*)InterlockedPopEntrySList(&m_Head); +#endif + return pNode; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + +#ifdef PLATFORM_64BITS + newHead.value.Padding = 0; +#endif + for (;; ) + { + oldHead.value64x128 = m_Head.value64x128; + if (!oldHead.value.Next) + return NULL; + + newHead.value.Next = oldHead.value.Next->Next; + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1; + + + if (ThreadInterlockedAssignIf64x128(&m_Head.value64x128, newHead.value64x128, oldHead.value64x128)) + { +#if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); +#endif + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t*)oldHead.value.Next; +#endif + } + + TSLNodeBase_t* Detach() + { +#ifdef USE_NATIVE_SLIST + TSLNodeBase_t* pBase = (TSLNodeBase_t*)InterlockedFlushSList(&m_Head); +#if defined( _X360 ) || defined( _PS3 ) + __lwsync(); +#endif + return pBase; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + +#ifdef PLATFORM_64BITS + newHead.value.Padding = 0; +#endif + do + { + ThreadPause(); + + oldHead.value64x128 = m_Head.value64x128; + if (!oldHead.value.Next) + return NULL; + + newHead.value.Next = NULL; + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence & 0xffff0000; + + } while (!ThreadInterlockedAssignIf64x128(&m_Head.value64x128, newHead.value64x128, oldHead.value64x128)); + + return (TSLNodeBase_t*)oldHead.value.Next; +#endif + } + + TSLHead_t* AccessUnprotected() + { + return &m_Head; + } + + int Count() const + { +#ifdef USE_NATIVE_SLIST + return QueryDepthSList(const_cast(&m_Head)); +#else + return m_Head.value.Depth; +#endif + } + +private: + TSLHead_t m_Head; +} TSLIST_HEAD_ALIGN_POST; + +template +class TSLIST_HEAD_ALIGN CTSSimpleList : public CTSListBase +{ +public: + void Push(T* pNode) + { + Assert(sizeof(T) >= sizeof(TSLNodeBase_t)); + CTSListBase::Push((TSLNodeBase_t*)pNode); + } + + T* Pop() + { + return (T*)CTSListBase::Pop(); + } +} TSLIST_HEAD_ALIGN_POST; + +template< class T > +class TSLIST_HEAD_ALIGN CTSPool : public CTSListBase +{ + struct TSLIST_NODE_ALIGN simpleTSPoolStruct_t : public TSLNodeBase_t + { + T elem; + } TSLIST_NODE_ALIGN_POST; + +public: + + ~CTSPool() + { + Purge(); + } + + void Purge() + { + simpleTSPoolStruct_t* pNode = NULL; + while (1) + { + pNode = (simpleTSPoolStruct_t*)CTSListBase::Pop(); + if (!pNode) + break; + delete pNode; + } + } + + void PutObject(T* pInfo) + { + char* pElem = (char*)pInfo; + pElem -= offsetof(simpleTSPoolStruct_t, elem); + simpleTSPoolStruct_t* pNode = (simpleTSPoolStruct_t*)pElem; + + CTSListBase::Push(pNode); + } + + T* GetObject() + { + simpleTSPoolStruct_t* pNode = (simpleTSPoolStruct_t*)CTSListBase::Pop(); + if (!pNode) + { + pNode = new simpleTSPoolStruct_t; + } + return &pNode->elem; + } + + FORCEINLINE T* Get() + { + return GetObject(); + } +} TSLIST_HEAD_ALIGN_POST; +template +class TSLIST_HEAD_ALIGN CTSList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t(const T& init) : elem(init) {} + T elem; + + static void* operator new(size_t size) + { + Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_NODE_ALIGNMENT, __FILE__, __LINE__); + return pNode; + } + + static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine) + { + Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_NODE_ALIGNMENT, pFileName, nLine); + return pNode; + } + + static void operator delete(void* p) + { + MemAlloc_FreeAligned(p); + } + static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine) + { + MemAlloc_FreeAligned(p); + } + + } TSLIST_NODE_ALIGN_POST; + + ~CTSList() + { + Purge(); + } + + void Purge() + { + Node_t* pCurrent = Detach(); + Node_t* pNext; + while (pCurrent) + { + pNext = (Node_t*)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Purge(); + } + + Node_t* Push(Node_t* pNode) + { + return (Node_t*)CTSListBase::Push(pNode); + } + + Node_t* Pop() + { + return (Node_t*)CTSListBase::Pop(); + } + + void PushItem(const T& init) + { + Push(new Node_t(init)); + } + + bool PopItem(T* pResult) + { + Node_t* pNode = Pop(); + if (!pNode) + return false; + *pResult = pNode->elem; + delete pNode; + return true; + } + + Node_t* Detach() + { + return (Node_t*)CTSListBase::Detach(); + } + +} TSLIST_HEAD_ALIGN_POST; + +template +class TSLIST_HEAD_ALIGN CTSListWithFreeList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t(const T& init) : elem(init) {} + + T elem; + } TSLIST_NODE_ALIGN_POST; + + ~CTSListWithFreeList() + { + Purge(); + } + + void Purge() + { + Node_t* pCurrent = Detach(); + Node_t* pNext; + while (pCurrent) + { + pNext = (Node_t*)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + pCurrent = (Node_t*)m_FreeList.Detach(); + while (pCurrent) + { + pNext = (Node_t*)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Node_t* pCurrent = Detach(); + Node_t* pNext; + while (pCurrent) + { + pNext = (Node_t*)pCurrent->Next; + m_FreeList.Push(pCurrent); + pCurrent = pNext; + } + } + + Node_t* Push(Node_t* pNode) + { + return (Node_t*)CTSListBase::Push(pNode); + } + + Node_t* Pop() + { + return (Node_t*)CTSListBase::Pop(); + } + + void PushItem(const T& init) + { + Node_t* pNode = (Node_t*)m_FreeList.Pop(); + if (!pNode) + { + pNode = new Node_t; + } + pNode->elem = init; + Push(pNode); + } + + bool PopItem(T* pResult) + { + Node_t* pNode = Pop(); + if (!pNode) + return false; + *pResult = pNode->elem; + m_FreeList.Push(pNode); + return true; + } + + Node_t* Detach() + { + return (Node_t*)CTSListBase::Detach(); + } + + void FreeNode(Node_t* pNode) + { + m_FreeList.Push(pNode); + } + +private: + CTSListBase m_FreeList; +} TSLIST_HEAD_ALIGN_POST; + +template +class TSLIST_HEAD_ALIGN CTSQueue +{ +public: + + static void* operator new(size_t size) + { + CTSQueue* pNode = (CTSQueue*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__); + return pNode; + } + + static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine) + { + CTSQueue* pNode = (CTSQueue*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine); + return pNode; + } + + static void operator delete(void* p) + { + MemAlloc_FreeAligned(p); + } + + static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine) + { + MemAlloc_FreeAligned(p); + } + +private: + static void* operator new[](size_t size) throw() + { + return NULL; + } + + static void operator delete [](void* p) + { + } + +public: + + struct TSLIST_NODE_ALIGN Node_t + { + static void* operator new(size_t size) + { + Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__); + return pNode; + } + + static void* operator new(size_t size, int nBlockUse, const char* pFileName, int nLine) + { + Node_t* pNode = (Node_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine); + return pNode; + } + + static void operator delete(void* p) + { + MemAlloc_FreeAligned(p); + } + + static void operator delete(void* p, int nBlockUse, const char* pFileName, int nLine) + { + MemAlloc_FreeAligned(p); + } + + Node_t() {} + Node_t(const T& init) : elem(init) {} + + Node_t* pNext; + T elem; + } TSLIST_NODE_ALIGN_POST; + + union TSLIST_HEAD_ALIGN NodeLink_t + { + static void* operator new(size_t size) + { + NodeLink_t* pNode = (NodeLink_t*)MemAlloc_AllocAlignedFileLine(size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__); + return pNode; + } + + static void operator delete(void* p) + { + MemAlloc_FreeAligned(p); + } + + struct Value_t + { + Node_t* pNode; + intp sequence; + } value; + +#ifdef PLATFORM_64BITS + int128 value64x128; +#else + int64 value64x128; +#endif + } TSLIST_HEAD_ALIGN_POST; + + CTSQueue() + { + COMPILE_TIME_ASSERT(sizeof(Node_t) >= sizeof(TSLNodeBase_t)); + if (((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0) + { + Error("CTSQueue: Misaligned queue\n"); + DebuggerBreak(); + } + if (((size_t)&m_Tail) % TSLIST_HEAD_ALIGNMENT != 0) + { + Error("CTSQueue: Misaligned queue\n"); + DebuggerBreak(); + } + m_Count = 0; + m_Head.value.sequence = m_Tail.value.sequence = 0; + m_Head.value.pNode = m_Tail.value.pNode = new Node_t; + m_Head.value.pNode->pNext = End(); + } + + ~CTSQueue() + { + Purge(); + Assert(m_Count == 0); + Assert(m_Head.value.pNode == m_Tail.value.pNode); + Assert(m_Head.value.pNode->pNext == End()); + delete m_Head.value.pNode; + } + + void Purge() + { + if (IsDebug()) + { + ValidateQueue(); + } + + Node_t* pNode; + while ((pNode = Pop()) != NULL) + { + delete pNode; + } + + while ((pNode = (Node_t*)m_FreeNodes.Pop()) != NULL) + { + delete pNode; + } + + Assert(m_Count == 0); + Assert(m_Head.value.pNode == m_Tail.value.pNode); + Assert(m_Head.value.pNode->pNext == End()); + + m_Head.value.sequence = m_Tail.value.sequence = 0; + } + + void RemoveAll() + { + if (IsDebug()) + { + ValidateQueue(); + } + + Node_t* pNode; + while ((pNode = Pop()) != NULL) + { + m_FreeNodes.Push((TSLNodeBase_t*)pNode); + } + } + + bool ValidateQueue() + { + if (IsDebug()) + { + bool bResult = true; + int nNodes = 0; + if (m_Tail.value.pNode->pNext != End()) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + + if (m_Count == 0) + { + if (m_Head.value.pNode != m_Tail.value.pNode) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + } + + Node_t* pNode = m_Head.value.pNode; + while (pNode != End()) + { + nNodes++; + pNode = pNode->pNext; + } + + nNodes--; + + if (nNodes != m_Count) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + + if (!bResult) + { + Msg("Corrupt CTSQueueDetected"); + } + + return bResult; + } + else + { + return true; + } + } + + void FinishPush(Node_t* pNode, const NodeLink_t& oldTail) + { + NodeLink_t newTail; + + newTail.value.pNode = pNode; + newTail.value.sequence = oldTail.value.sequence + 1; + + ThreadMemoryBarrier(); + + InterlockedCompareExchangeNodeLink(&m_Tail, newTail, oldTail); + } + + Node_t* Push(Node_t* pNode) + { +#ifdef _DEBUG + if ((size_t)pNode % TSLIST_NODE_ALIGNMENT != 0) + { + Error("CTSListBase: Misaligned node\n"); + DebuggerBreak(); + } +#endif + + NodeLink_t oldTail; + + pNode->pNext = End(); + + for (;; ) + { + oldTail.value.sequence = m_Tail.value.sequence; + oldTail.value.pNode = m_Tail.value.pNode; + if (InterlockedCompareExchangeNode(&(oldTail.value.pNode->pNext), pNode, End()) == End()) + { + break; + } + else + { + FinishPush(oldTail.value.pNode->pNext, oldTail); + } + } + + FinishPush(pNode, oldTail); + + m_Count++; + + return oldTail.value.pNode; + } + + Node_t* Pop() + { +#define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) ) + NodeLink_t* volatile pHead = &m_Head; + NodeLink_t* volatile pTail = &m_Tail; + Node_t* volatile* pHeadNode = &m_Head.value.pNode; + volatile intp* volatile pHeadSequence = &m_Head.value.sequence; + Node_t* volatile* pTailNode = &pTail->value.pNode; + + NodeLink_t head; + NodeLink_t newHead; + Node_t* pNext; + intp tailSequence; + T elem; + + for (;; ) + { + head.value.sequence = *pHeadSequence; + ThreadMemoryBarrier(); + head.value.pNode = *pHeadNode; + tailSequence = pTail->value.sequence; + pNext = head.value.pNode->pNext; + + if (!pNext || head.value.sequence != *pHeadSequence) + continue; + + if (bTestOptimizer) + { + if (pNext == TSQUEUE_BAD_NODE_LINK) + { + Msg("Bad node link detected\n"); + continue; + } + } + + if (head.value.pNode == *pTailNode) + { + if (pNext == End()) + return NULL; + + NodeLink_t& oldTail = head; + oldTail.value.sequence = tailSequence; + FinishPush(pNext, oldTail); + continue; + } + + if (pNext != End()) + { + elem = pNext->elem; + newHead.value.pNode = pNext; + newHead.value.sequence = head.value.sequence + 1; + if (InterlockedCompareExchangeNodeLink(pHead, newHead, head)) + { + ThreadMemoryBarrier(); + if (bTestOptimizer) + { + head.value.pNode->pNext = TSQUEUE_BAD_NODE_LINK; + } + break; + } + } + } + + m_Count--; + head.value.pNode->elem = elem; + return head.value.pNode; + } + + void FreeNode(Node_t* pNode) + { + m_FreeNodes.Push((TSLNodeBase_t*)pNode); + } + + void PushItem(const T& init) + { + Node_t* pNode = (Node_t*)m_FreeNodes.Pop(); + if (pNode) + { + pNode->elem = init; + } + else + { + pNode = new Node_t(init); + } + Push(pNode); + } + + bool PopItem(T* pResult) + { + Node_t* pNode = Pop(); + if (!pNode) + return false; + + *pResult = pNode->elem; + m_FreeNodes.Push((TSLNodeBase_t*)pNode); + return true; + } + + int Count() const + { + return m_Count; + } + +private: + Node_t* End() { return (Node_t*)this; } + + Node_t* InterlockedCompareExchangeNode(Node_t* volatile* ppNode, Node_t* value, Node_t* comperand) + { + return (Node_t*)::ThreadInterlockedCompareExchangePointer((void**)ppNode, value, comperand); + } + + bool InterlockedCompareExchangeNodeLink(NodeLink_t volatile* pLink, const NodeLink_t& value, const NodeLink_t& comperand) + { + return ThreadInterlockedAssignIf64x128(&pLink->value64x128, value.value64x128, comperand.value64x128); + } + + NodeLink_t m_Head; + NodeLink_t m_Tail; + + CInterlockedInt m_Count; + + CTSListBase m_FreeNodes; +} TSLIST_NODE_ALIGN_POST; + +#if defined( _WIN32 ) +#pragma warning( pop ) +#endif + +#endif +``` + +`SpyCustom/sdk/uniqueid.h`: + +```h +#ifndef UNIQUEID_H +#define UNIQUEID_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + + +struct UniqueId_t; +class CUtlBuffer; + + +struct UniqueId_t +{ + unsigned char m_Value[16]; +}; + + +void CreateUniqueId(UniqueId_t* pDest); +void InvalidateUniqueId(UniqueId_t* pDest); +bool IsUniqueIdValid(const UniqueId_t& id); +bool IsUniqueIdEqual(const UniqueId_t& id1, const UniqueId_t& id2); +void UniqueIdToString(const UniqueId_t& id, char* pBuf, int nMaxLen); +bool UniqueIdFromString(UniqueId_t* pDest, const char* pBuf, int nMaxLen = 0); +void CopyUniqueId(const UniqueId_t& src, UniqueId_t* pDest); +bool Serialize(CUtlBuffer& buf, const UniqueId_t& src); +bool Unserialize(CUtlBuffer& buf, UniqueId_t& dest); + +inline bool operator ==(const UniqueId_t& lhs, const UniqueId_t& rhs) +{ + return !Q_memcmp((void*)&lhs.m_Value[0], (void*)&rhs.m_Value[0], sizeof(lhs.m_Value)); +} + + +#endif +``` + +`SpyCustom/sdk/usercmd.h`: + +```h +#if !defined( USERCMD_H ) +#define USERCMD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" +#include "utlvector.h" +#include "imovehelper.h" +#include "checksum_crc.h" + + +class bf_read; +class bf_write; + +class CEntityGroundContact +{ +public: + int entindex; + float minheight; + float maxheight; +}; + +#ifdef DOTA_DLL + +class CUnitOrders +{ +public: + + CUnitOrders() + { + m_nOrderSequenceNumber = 0; + } + + void Reset(void) + { + m_nUnits.RemoveAll(); + m_nOrderType = 0; + m_nTargetIndex = 0; + m_vPosition = vec3_origin; + m_nAbilityIndex = 0; + } + + int m_nOrderSequenceNumber; + CUtlVector m_nUnits; + int m_nOrderType; + int m_nTargetIndex; + int m_nAbilityIndex; + Vector m_vPosition; +}; + +#endif + + +class CUserCmd +{ +public: + CUserCmd() + { + Reset(); + } + + virtual ~CUserCmd() { }; + + void Reset() + { + command_number = 0; + tick_count = 0; + viewangles.Init(); + aimdirection.Init(); + forwardmove = 0.0f; + sidemove = 0.0f; + upmove = 0.0f; + buttons = 0; + impulse = 0; + weaponselect = 0; + weaponsubtype = 0; + random_seed = 0; +#ifndef CLIENT_DLL + server_random_seed = 0; +#endif + mousedx = 0; + mousedy = 0; + + hasbeenpredicted = false; +#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) + entitygroundcontact.RemoveAll(); +#endif + +#ifdef DOTA_DLL + dota_unitorders.Reset(); +#endif + +#if defined ( PORTAL2 ) + player_held_entity = 0; + held_entity_was_grabbed_through_portal = 0; + + command_acknowledgements_pending = 0; + predictedPortalTeleportations = 0; +#endif + + headangles.Init(); + headoffset.Init(); + +#if defined( INFESTED_DLL ) || defined( DOTA_DLL ) + crosshairtrace = vec3_origin; +#endif + +#ifdef INFESTED_DLL + crosshair_entity = 0; + forced_action = 0; + sync_kill_ent = 0; + skill_dest.Init(); + skill_dest_ent = 0; + +#endif + +#if defined( KEEP_COMMAND_REPREDICTION_COUNT ) + debug_RepredictionCount = 0; +#endif + } + + CUserCmd& operator =(const CUserCmd& src) + { + if (this == &src) + return *this; + + command_number = src.command_number; + tick_count = src.tick_count; + viewangles = src.viewangles; + aimdirection = src.aimdirection; + forwardmove = src.forwardmove; + sidemove = src.sidemove; + upmove = src.upmove; + buttons = src.buttons; + impulse = src.impulse; + weaponselect = src.weaponselect; + weaponsubtype = src.weaponsubtype; + random_seed = src.random_seed; +#ifndef CLIENT_DLL + server_random_seed = src.server_random_seed; +#endif + mousedx = src.mousedx; + mousedy = src.mousedy; + + hasbeenpredicted = src.hasbeenpredicted; + +#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) + entitygroundcontact = src.entitygroundcontact; +#endif + +#if defined ( PORTAL2 ) + player_held_entity = src.player_held_entity; + held_entity_was_grabbed_through_portal = src.held_entity_was_grabbed_through_portal; + command_acknowledgements_pending = src.command_acknowledgements_pending; + predictedPortalTeleportations = src.predictedPortalTeleportations; +#endif + + headangles = src.headangles; + headoffset = src.headoffset; +#if defined( INFESTED_DLL ) || defined( DOTA_DLL ) + crosshairtrace = src.crosshairtrace; +#endif + +#ifdef INFESTED_DLL + crosshair_entity = src.crosshair_entity; + forced_action = src.forced_action; + sync_kill_ent = src.sync_kill_ent; + skill_dest = src.skill_dest; + skill_dest_ent = src.skill_dest_ent; +#endif + +#ifdef DOTA_DLL + dota_unitorders = src.dota_unitorders; +#endif + +#if defined( KEEP_COMMAND_REPREDICTION_COUNT ) + debug_RepredictionCount = src.debug_RepredictionCount; +#endif + + return *this; + } + + CUserCmd(const CUserCmd& src) + { + *this = src; + } + + CRC32_t GetChecksum(void) const + { + CRC32_t crc; + + CRC32_Init(&crc); + CRC32_ProcessBuffer(&crc, &command_number, sizeof(command_number)); + CRC32_ProcessBuffer(&crc, &tick_count, sizeof(tick_count)); + CRC32_ProcessBuffer(&crc, &viewangles, sizeof(viewangles)); + CRC32_ProcessBuffer(&crc, &aimdirection, sizeof(aimdirection)); + CRC32_ProcessBuffer(&crc, &forwardmove, sizeof(forwardmove)); + CRC32_ProcessBuffer(&crc, &sidemove, sizeof(sidemove)); + CRC32_ProcessBuffer(&crc, &upmove, sizeof(upmove)); + CRC32_ProcessBuffer(&crc, &buttons, sizeof(buttons)); + CRC32_ProcessBuffer(&crc, &impulse, sizeof(impulse)); + CRC32_ProcessBuffer(&crc, &weaponselect, sizeof(weaponselect)); + CRC32_ProcessBuffer(&crc, &weaponsubtype, sizeof(weaponsubtype)); + CRC32_ProcessBuffer(&crc, &random_seed, sizeof(random_seed)); + CRC32_ProcessBuffer(&crc, &mousedx, sizeof(mousedx)); + CRC32_ProcessBuffer(&crc, &mousedy, sizeof(mousedy)); + +#if defined( INFESTED_DLL ) || defined( DOTA_DLL ) + CRC32_ProcessBuffer(&crc, &crosshairtrace, sizeof(crosshairtrace)); +#endif + +#if defined ( PORTAL2 ) + CRC32_ProcessBuffer(&crc, &player_held_entity, sizeof(player_held_entity)); + CRC32_ProcessBuffer(&crc, &held_entity_was_grabbed_through_portal, sizeof(held_entity_was_grabbed_through_portal)); + CRC32_ProcessBuffer(&crc, &command_acknowledgements_pending, sizeof(command_acknowledgements_pending)); + CRC32_ProcessBuffer(&crc, &predictedPortalTeleportations, sizeof(predictedPortalTeleportations)); +#endif + +#ifdef INFESTED_DLL + CRC32_ProcessBuffer(&crc, &crosshair_entity, sizeof(crosshair_entity)); + CRC32_ProcessBuffer(&crc, &forced_action, sizeof(forced_action)); + CRC32_ProcessBuffer(&crc, &sync_kill_ent, sizeof(sync_kill_ent)); + CRC32_ProcessBuffer(&crc, &skill_dest, sizeof(skill_dest)); + CRC32_ProcessBuffer(&crc, &skill_dest_ent, sizeof(skill_dest_ent)); +#endif + CRC32_Final(&crc); + + return crc; + } + + int command_number; + + int tick_count; + + QAngle viewangles; + Vector aimdirection; + float forwardmove; + float sidemove; + float upmove; + int buttons; + byte impulse; + int weaponselect; + int weaponsubtype; + + int random_seed; + +#ifndef CLIENT_DLL + int server_random_seed; +#endif + + short mousedx; + short mousedy; + + bool hasbeenpredicted; + +#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) + CUtlVector< CEntityGroundContact > entitygroundcontact; +#endif + +#if defined ( DOTA_DLL ) + CUnitOrders dota_unitorders; +#endif + +#if defined ( PORTAL2 ) + short player_held_entity; + short held_entity_was_grabbed_through_portal; + + unsigned short command_acknowledgements_pending; + uint8 predictedPortalTeleportations; +#endif + + QAngle headangles; + Vector headoffset; +#if defined( INFESTED_DLL ) || defined( DOTA_DLL ) + Vector crosshairtrace; +#endif + +#ifdef INFESTED_DLL + short crosshair_entity; + byte forced_action; + short sync_kill_ent; + Vector skill_dest; + short skill_dest_ent; +#endif + +#if defined( KEEP_COMMAND_REPREDICTION_COUNT ) + unsigned int debug_RepredictionCount; +#endif +}; + +void ReadUsercmd(bf_read* buf, CUserCmd* move, CUserCmd* from); +void WriteUsercmd(bf_write* buf, const CUserCmd* to, const CUserCmd* from); + +#endif +``` + +`SpyCustom/sdk/userid.h`: + +```h +#ifndef USERID_H +#define USERID_H +#ifdef _WIN32 +#pragma once +#endif + +#if !defined( INCLUDED_STEAM_STEAMUSERIDTYPES_H ) +#include "SteamCommon.h" +#endif + +#define IDTYPE_WON 0 +#define IDTYPE_STEAM 1 +#define IDTYPE_VALVE 2 +#define IDTYPE_HLTV 3 +#define IDTYPE_REPLAY 4 +typedef struct USERID_s +{ + int idtype; + + union + { + TSteamGlobalUserID steamid; + } uid; + +} USERID_t; + +#endif + +``` + +`SpyCustom/sdk/utlblockmemory.h`: + +```h +#ifndef UTLBLOCKMEMORY_H +#define UTLBLOCKMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include "platform.h" +#include "mathlib.h" + +#include "memalloc.h" +#include "memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +#ifdef UTBLOCKLMEMORY_TRACK +#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0) +#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0) +#endif + + +template< class T, class I > +class CUtlBlockMemory +{ +public: + CUtlBlockMemory(int nGrowSize = 0, int nInitSize = 0); + ~CUtlBlockMemory(); + + void Init(int nGrowSize = 0, int nInitSize = 0); + + T* Base() { return NULL; } + const T* Base() const { return NULL; } + + class Iterator_t + { + public: + Iterator_t(I i) : index(i) {} + I index; + + bool operator==(const Iterator_t it) const { return index == it.index; } + bool operator!=(const Iterator_t it) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); } + Iterator_t Next(const Iterator_t& it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); } + I GetIndex(const Iterator_t& it) const { return it.index; } + bool IsIdxAfter(I i, const Iterator_t& it) const { return i > it.index; } + bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index); } + Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); } + + T& operator[](I i); + const T& operator[](I i) const; + T& Element(I i); + const T& Element(I i) const; + + bool IsIdxValid(I i) const; + static I InvalidIndex() { return (I)-1; } + + void Swap(CUtlBlockMemory< T, I >& mem); + + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + void Grow(int num = 1); + + void EnsureCapacity(int num); + + void Purge(); + + void Purge(int numElements); + +protected: + int Index(int major, int minor) const { return (major << m_nIndexShift) | minor; } + int MajorIndex(int i) const { return i >> m_nIndexShift; } + int MinorIndex(int i) const { return i & m_nIndexMask; } + void ChangeSize(int nBlocks); + int NumElementsInBlock() const { return m_nIndexMask + 1; } + + T** m_pMemory; + int m_nBlocks; + int m_nIndexMask : 27; + int m_nIndexShift : 5; +}; + +template< class T, class I > +CUtlBlockMemory::CUtlBlockMemory(int nGrowSize, int nInitAllocationCount) + : m_pMemory(0), m_nBlocks(0), m_nIndexMask(0), m_nIndexShift(0) +{ + Init(nGrowSize, nInitAllocationCount); +} + +template< class T, class I > +CUtlBlockMemory::~CUtlBlockMemory() +{ + Purge(); +} + + +template< class T, class I > +void CUtlBlockMemory::Swap(CUtlBlockMemory< T, I >& mem) +{ + swap(m_pMemory, mem.m_pMemory); + swap(m_nBlocks, mem.m_nBlocks); + swap(m_nIndexMask, mem.m_nIndexMask); + swap(m_nIndexShift, mem.m_nIndexShift); +} + + +template< class T, class I > +void CUtlBlockMemory::Init(int nGrowSize , int nInitSize ) +{ + Purge(); + + if (nGrowSize == 0) + { + nGrowSize = (127 + sizeof(T)) / sizeof(T); + } + nGrowSize = SmallestPowerOfTwoGreaterOrEqual(nGrowSize); + m_nIndexMask = nGrowSize - 1; + + m_nIndexShift = 0; + while (nGrowSize > 1) + { + nGrowSize >>= 1; + ++m_nIndexShift; + } + Assert(m_nIndexMask + 1 == (1 << m_nIndexShift)); + + Grow(nInitSize); +} + + +template< class T, class I > +inline T& CUtlBlockMemory::operator[](I i) +{ + Assert(IsIdxValid(i)); + T* pBlock = m_pMemory[MajorIndex(i)]; + return pBlock[MinorIndex(i)]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory::operator[](I i) const +{ + Assert(IsIdxValid(i)); + const T* pBlock = m_pMemory[MajorIndex(i)]; + return pBlock[MinorIndex(i)]; +} + +template< class T, class I > +inline T& CUtlBlockMemory::Element(I i) +{ + Assert(IsIdxValid(i)); + T* pBlock = m_pMemory[MajorIndex(i)]; + return pBlock[MinorIndex(i)]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory::Element(I i) const +{ + Assert(IsIdxValid(i)); + const T* pBlock = m_pMemory[MajorIndex(i)]; + return pBlock[MinorIndex(i)]; +} + + +template< class T, class I > +inline int CUtlBlockMemory::NumAllocated() const +{ + return m_nBlocks * NumElementsInBlock(); +} + + +template< class T, class I > +inline bool CUtlBlockMemory::IsIdxValid(I i) const +{ + return (i >= 0) && (MajorIndex(i) < m_nBlocks); +} + +template< class T, class I > +void CUtlBlockMemory::Grow(int num) +{ + if (num <= 0) + return; + + int nBlockSize = NumElementsInBlock(); + int nBlocks = (num + nBlockSize - 1) / nBlockSize; + + ChangeSize(m_nBlocks + nBlocks); +} + +template< class T, class I > +void CUtlBlockMemory::ChangeSize(int nBlocks) +{ + UTLBLOCKMEMORY_TRACK_FREE(); + + int nBlocksOld = m_nBlocks; + m_nBlocks = nBlocks; + + UTLBLOCKMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + for (int i = m_nBlocks; i < nBlocksOld; ++i) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free((void*)m_pMemory[i]); + } + + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)realloc(m_pMemory, m_nBlocks * sizeof(T*)); + Assert(m_pMemory); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)malloc(m_nBlocks * sizeof(T*)); + Assert(m_pMemory); + } + + if (!m_pMemory) + { + Error("CUtlBlockMemory overflow!\n"); + } + + int nBlockSize = NumElementsInBlock(); + for (int i = nBlocksOld; i < m_nBlocks; ++i) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory[i] = (T*)malloc(nBlockSize * sizeof(T)); + Assert(m_pMemory[i]); + } +} + + +template< class T, class I > +inline void CUtlBlockMemory::EnsureCapacity(int num) +{ + Grow(num - NumAllocated()); +} + + +template< class T, class I > +void CUtlBlockMemory::Purge() +{ + if (!m_pMemory) + return; + + for (int i = 0; i < m_nBlocks; ++i) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free((void*)m_pMemory[i]); + } + m_nBlocks = 0; + + UTLBLOCKMEMORY_TRACK_FREE(); + free((void*)m_pMemory); + m_pMemory = 0; +} + +template< class T, class I > +void CUtlBlockMemory::Purge(int numElements) +{ + Assert(numElements >= 0); + + int nAllocated = NumAllocated(); + if (numElements > nAllocated) + { + Assert(numElements <= nAllocated); + return; + } + + if (numElements <= 0) + { + Purge(); + return; + } + + int nBlockSize = NumElementsInBlock(); + int nBlocksOld = m_nBlocks; + int nBlocks = (numElements + nBlockSize - 1) / nBlockSize; + + if (nBlocks == m_nBlocks) + return; + + ChangeSize(nBlocks); +} + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/utlbuffer.h`: + +```h +#ifndef UTLBUFFER_H +#define UTLBUFFER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmemory.h" +#include "byteswap.h" +#include + + +struct characterset_t; + + +class CUtlCharConversion +{ +public: + struct ConversionArray_t + { + char m_nActualChar; + char* m_pReplacementString; + }; + + CUtlCharConversion(char nEscapeChar, const char* pDelimiter, int nCount, ConversionArray_t* pArray); + char GetEscapeChar() const; + const char* GetDelimiter() const; + int GetDelimiterLength() const; + + const char* GetConversionString(char c) const; + int GetConversionLength(char c) const; + int MaxConversionLength() const; + + virtual char FindConversion(const char* pString, int* pLength); + +protected: + struct ConversionInfo_t + { + int m_nLength; + char* m_pReplacementString; + }; + + char m_nEscapeChar; + const char* m_pDelimiter; + int m_nDelimiterLength; + int m_nCount; + int m_nMaxConversionLength; + char m_pList[256]; + ConversionInfo_t m_pReplacements[256]; +}; + +#define BEGIN_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \ + static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = { + +#define END_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \ + }; \ + CUtlCharConversion _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name ); + +#define BEGIN_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \ + static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = { + +#define END_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \ + }; \ + _className _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name ); + +CUtlCharConversion* GetCStringCharConversion(); + +CUtlCharConversion* GetNoEscCharConversion(); + + +#define SetUtlBufferOverflowFuncs( _get, _put ) \ + SetOverflowFuncs( static_cast ( _get ), static_cast ( _put ) ) + + + +typedef unsigned short ushort; + +template < class A > +static const char* GetFmtStr(int nRadix = 10, bool bPrint = true) { Assert(0); return ""; } +#if defined( LINUX ) || defined( __clang__ ) || ( defined( _MSC_VER ) && _MSC_VER >= 1900 ) +template <> const char* GetFmtStr< short >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%hd"; } +template <> const char* GetFmtStr< ushort >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%hu"; } +template <> const char* GetFmtStr< int >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%d"; } +template <> const char* GetFmtStr< uint >(int nRadix, bool bPrint) { Assert(nRadix == 10 || nRadix == 16); return nRadix == 16 ? "%x" : "%u"; } +template <> const char* GetFmtStr< int64 >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%lld"; } +template <> const char* GetFmtStr< float >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%f"; } +template <> const char* GetFmtStr< double >(int nRadix, bool bPrint) { Assert(nRadix == 10); return bPrint ? "%.15lf" : "%lf"; } +#else +template <> static const char* GetFmtStr< short >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%hd"; } +template <> static const char* GetFmtStr< ushort >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%hu"; } +template <> static const char* GetFmtStr< int >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%d"; } +template <> static const char* GetFmtStr< uint >(int nRadix, bool bPrint) { Assert(nRadix == 10 || nRadix == 16); return nRadix == 16 ? "%x" : "%u"; } +template <> static const char* GetFmtStr< int64 >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%lld"; } +template <> static const char* GetFmtStr< float >(int nRadix, bool bPrint) { Assert(nRadix == 10); return "%f"; } +template <> static const char* GetFmtStr< double >(int nRadix, bool bPrint) { Assert(nRadix == 10); return bPrint ? "%.15lf" : "%lf"; } +#endif +class CUtlBuffer +{ +public: + enum SeekType_t + { + SEEK_HEAD = 0, + SEEK_CURRENT, + SEEK_TAIL + }; + + enum BufferFlags_t + { + TEXT_BUFFER = 0x1, + EXTERNAL_GROWABLE = 0x2, + CONTAINS_CRLF = 0x4, + READ_ONLY = 0x8, + AUTO_TABS_DISABLED = 0x10, + }; + + typedef bool (CUtlBuffer::* UtlBufferOverflowFunc_t)(int nSize); + + CUtlBuffer(int growSize = 0, int initSize = 0, int nFlags = 0); + CUtlBuffer(const void* pBuffer, int size, int nFlags = 0); + CUtlBuffer(const void* pBuffer, int size, bool crap) = delete; + + CUtlBuffer(const CUtlBuffer&); + CUtlBuffer& operator= (const CUtlBuffer&); + +#if VALVE_CPP11 + CUtlBuffer(CUtlBuffer&& moveFrom); + CUtlBuffer& operator= (CUtlBuffer&& moveFrom); +#endif + + unsigned char GetFlags() const; + + void SetBufferType(bool bIsText, bool bContainsCRLF); + + void EnsureCapacity(int num); + + void* AccessForDirectRead(int nBytes); + + void SetExternalBuffer(void* pMemory, int nSize, int nInitialPut, int nFlags = 0); + bool IsExternallyAllocated() const; + void AssumeMemory(void* pMemory, int nSize, int nInitialPut, int nFlags = 0); + void* Detach(); + void* DetachMemory(); + + void CopyBuffer(const CUtlBuffer& buffer); + void CopyBuffer(const void* pubData, int cubData); + + void Swap(CUtlBuffer& buf); + void Swap(CUtlMemory& mem); + + + FORCEINLINE void ActivateByteSwappingIfBigEndian(void) + { + if ((IsX360() || IsPS3())) + ActivateByteSwapping(true); + } + + + void ActivateByteSwapping(bool bActivate); + void SetBigEndian(bool bigEndian); + bool IsBigEndian(void); + + void Clear(); + + void Purge(); + + void Spew(); + + char GetChar(); + unsigned char GetUnsignedChar(); + short GetShort(); + unsigned short GetUnsignedShort(); + int GetInt(); + int64 GetInt64(); + unsigned int GetIntHex(); + unsigned int GetUnsignedInt(); + uint64 GetUnsignedInt64(); + float GetFloat(); + double GetDouble(); + void* GetPtr(); + void GetString(char* pString, int nMaxChars); + void Get(void* pMem, int size); + void GetLine(char* pLine, int nMaxChars); + + template void GetObjects(T* dest, int count = 1); + + int GetUpTo(void* pMem, int nSize); + + void GetDelimitedString(CUtlCharConversion* pConv, char* pString, int nMaxChars = 0); + char GetDelimitedChar(CUtlCharConversion* pConv); + + int PeekStringLength(); + + int PeekDelimitedStringLength(CUtlCharConversion* pConv, bool bActualSize = true); + + int Scanf(SCANF_FORMAT_STRING const char* pFmt, ...); + int VaScanf(const char* pFmt, va_list list); + + void EatWhiteSpace(); + + bool EatCPPComment(); + + bool ParseToken(const char* pStartingDelim, const char* pEndingDelim, char* pString, int nMaxLen); + + bool GetToken(const char* pToken); + + int ParseToken(characterset_t* pBreaks, char* pTokenBuf, int nMaxLen, bool bParseComments = true); + + void PutChar(char c); + void PutUnsignedChar(unsigned char uc); + void PutShort(short s); + void PutUnsignedShort(unsigned short us); + void PutInt(int i); + void PutInt64(int64 i); + void PutUnsignedInt(unsigned int u); + void PutUnsignedInt64(uint64 u); + void PutFloat(float f); + void PutDouble(double d); + void PutPtr(void*); + void PutString(const char* pString); + void Put(const void* pMem, int size); + + template void PutObjects(T* src, int count = 1); + + void PutDelimitedString(CUtlCharConversion* pConv, const char* pString); + void PutDelimitedChar(CUtlCharConversion* pConv, char c); + + void Printf(PRINTF_FORMAT_STRING const char* pFmt, ...) FMTFUNCTION(2, 3); + void VaPrintf(const char* pFmt, va_list list); + + void* PeekPut(int offset = 0); + const void* PeekGet(int offset = 0) const; + const void* PeekGet(int nMaxSize, int nOffset); + + int TellPut() const; + int TellGet() const; + + int TellMaxPut() const; + + int GetBytesRemaining() const; + + void SeekPut(SeekType_t type, int offset); + void SeekGet(SeekType_t type, int offset); + + const void* Base() const; + void* Base(); + + int Size() const; + + bool IsText() const; + + bool IsGrowable() const; + + bool IsValid() const; + + bool ContainsCRLF() const; + + bool IsReadOnly() const; + + bool ConvertCRLF(CUtlBuffer& outBuf); + + void PushTab(); + void PopTab(); + + void EnableTabs(bool bEnable); + +#if !defined( _GAMECONSOLE ) + void SwapCopy(CUtlBuffer& other); +#endif + +protected: + enum + { + PUT_OVERFLOW = 0x1, + GET_OVERFLOW = 0x2, + MAX_ERROR_FLAG = GET_OVERFLOW, + }; + + void SetOverflowFuncs(UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc); + + bool OnPutOverflow(int nSize); + bool OnGetOverflow(int nSize); + +protected: + bool CheckPut(int size); + bool CheckGet(int size); + + void AddNullTermination(int nPut); + bool WasLastCharacterCR(); + void PutTabs(); + + char GetDelimitedCharInternal(CUtlCharConversion* pConv); + void PutDelimitedCharInternal(CUtlCharConversion* pConv, char c); + + bool PutOverflow(int nSize); + bool GetOverflow(int nSize); + + bool PeekStringMatch(int nOffset, const char* pString, int nLen); + + int PeekLineLength(); + + int PeekWhiteSpace(int nOffset); + + bool CheckPeekGet(int nOffset, int nSize); + + bool CheckArbitraryPeekGet(int nOffset, int& nIncrement); + + template void GetType(T& dest); + template void GetTypeBin(T& dest); + template bool GetTypeText(T& value, int nRadix = 10); + template void GetObject(T* src); + + template void PutType(T src); + template void PutTypeBin(T src); + template void PutObject(T* src); + + CUtlMemory m_Memory; + int m_Get; + int m_Put; + + unsigned char m_Error; + unsigned char m_Flags; + unsigned char m_Reserved; +#if defined( _GAMECONSOLE ) + unsigned char pad; +#endif + + int m_nTab; + int m_nMaxPut; + int m_nOffset; + + UtlBufferOverflowFunc_t m_GetOverflowFunc; + UtlBufferOverflowFunc_t m_PutOverflowFunc; + + CByteswap m_Byteswap; +}; + + +inline CUtlBuffer& operator<<(CUtlBuffer& b, char v) +{ + b.PutChar(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, unsigned char v) +{ + b.PutUnsignedChar(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, short v) +{ + b.PutShort(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, unsigned short v) +{ + b.PutUnsignedShort(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, int v) +{ + b.PutInt(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, unsigned int v) +{ + b.PutUnsignedInt(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, float v) +{ + b.PutFloat(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, double v) +{ + b.PutDouble(v); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, const char* pv) +{ + b.PutString(pv); + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, const Vector& v) +{ + b << v.x << " " << v.y << " " << v.z; + return b; +} + +inline CUtlBuffer& operator<<(CUtlBuffer& b, const Vector2D& v) +{ + b << v.x << " " << v.y; + return b; +} + + +class CUtlInplaceBuffer : public CUtlBuffer +{ +public: + CUtlInplaceBuffer(int growSize = 0, int initSize = 0, int nFlags = 0); + +public: + bool InplaceGetLinePtr( char** ppszInBufferPtr, int* pnLineLength); + + char* InplaceGetLinePtr(void); +}; + + +inline int CUtlBuffer::TellGet() const +{ + return m_Get; +} + + +inline int CUtlBuffer::GetBytesRemaining() const +{ + return m_nMaxPut - TellGet(); +} + + +inline const void* CUtlBuffer::PeekGet(int offset) const +{ + return &m_Memory[m_Get + offset - m_nOffset]; +} + + +template +inline void CUtlBuffer::GetObject(T* dest) +{ + if (CheckGet(sizeof(T))) + { + if (!m_Byteswap.IsSwappingBytes() || (sizeof(T) == 1)) + { + *dest = *(T*)PeekGet(); + } + else + { + m_Byteswap.SwapFieldsToTargetEndian(dest, (T*)PeekGet()); + } + m_Get += sizeof(T); + } + else + { + Q_memset(&dest, 0, sizeof(T)); + } +} + + +template +inline void CUtlBuffer::GetObjects(T* dest, int count) +{ + for (int i = 0; i < count; ++i, ++dest) + { + GetObject(dest); + } +} + + +template +inline void CUtlBuffer::GetTypeBin(T& dest) +{ + if (CheckGet(sizeof(T))) + { + if (!m_Byteswap.IsSwappingBytes() || (sizeof(T) == 1)) + { + dest = *(T*)PeekGet(); + } + else + { + m_Byteswap.SwapBufferToTargetEndian(&dest, (T*)PeekGet()); + } + m_Get += sizeof(T); + } + else + { + dest = 0; + } +} + +template <> +inline void CUtlBuffer::GetTypeBin< float >(float& dest) +{ + if (CheckGet(sizeof(float))) + { + uintp pData = (uintp)PeekGet(); + if ((IsX360() || IsPS3()) && (pData & 0x03)) + { + ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; + ((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1]; + ((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2]; + ((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3]; + } + else + { + dest = *(float*)pData; + } + if (m_Byteswap.IsSwappingBytes()) + { + m_Byteswap.SwapBufferToTargetEndian< float >(&dest, &dest); + } + m_Get += sizeof(float); + } + else + { + dest = 0; + } +} + +template <> +inline void CUtlBuffer::GetTypeBin< double >(double& dest) +{ + if (CheckGet(sizeof(double))) + { + uintp pData = (uintp)PeekGet(); + if ((IsX360() || IsPS3()) && (pData & 0x07)) + { + ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; + ((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1]; + ((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2]; + ((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3]; + ((unsigned char*)&dest)[4] = ((unsigned char*)pData)[4]; + ((unsigned char*)&dest)[5] = ((unsigned char*)pData)[5]; + ((unsigned char*)&dest)[6] = ((unsigned char*)pData)[6]; + ((unsigned char*)&dest)[7] = ((unsigned char*)pData)[7]; + } + else + { + dest = *(double*)pData; + } + if (m_Byteswap.IsSwappingBytes()) + { + m_Byteswap.SwapBufferToTargetEndian< double >(&dest, &dest); + } + m_Get += sizeof(double); + } + else + { + dest = 0; + } +} + +template < class T > +inline T StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + Assert(0); + *ppEnd = pString; + return 0; +} + +template <> +inline int8 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + return (int8)strtol(pString, ppEnd, nRadix); +} + +template <> +inline uint8 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + return (uint8)strtoul(pString, ppEnd, nRadix); +} + +template <> +inline int16 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + return (int16)strtol(pString, ppEnd, nRadix); +} + +template <> +inline uint16 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + return (uint16)strtoul(pString, ppEnd, nRadix); +} + +template <> +inline int32 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + return (int32)strtol(pString, ppEnd, nRadix); +} + +template <> +inline uint32 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + return (uint32)strtoul(pString, ppEnd, nRadix); +} + +template <> +inline int64 StringToNumber(char* pString, char** ppEnd, int nRadix) +{ +#if defined(_PS3) || defined(POSIX) + return (int64)strtoll(pString, ppEnd, nRadix); +#else + return (int64)_strtoi64(pString, ppEnd, nRadix); +#endif +} + +template <> +inline float StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + NOTE_UNUSED(nRadix); + return (float)strtod(pString, ppEnd); +} + +template <> +inline double StringToNumber(char* pString, char** ppEnd, int nRadix) +{ + NOTE_UNUSED(nRadix); + return (double)strtod(pString, ppEnd); +} + +template +inline bool CUtlBuffer::GetTypeText(T& value, int nRadix ) +{ + int nLength = 128; + if (!CheckArbitraryPeekGet(0, nLength)) + { + value = 0; + return false; + } + + char* pStart = (char*)PeekGet(); + char* pEnd = pStart; + value = StringToNumber< T >(pStart, &pEnd, nRadix); + + int nBytesRead = (int)(pEnd - pStart); + if (nBytesRead == 0) + return false; + + m_Get += nBytesRead; + return true; +} + +template +inline void CUtlBuffer::GetType(T& dest) +{ + if (!IsText()) + { + GetTypeBin(dest); + } + else + { + GetTypeText(dest); + } +} + +inline char CUtlBuffer::GetChar() +{ + char c; + GetTypeBin(c); + return c; +} + +inline unsigned char CUtlBuffer::GetUnsignedChar() +{ + unsigned char c; + if (!IsText()) + { + GetTypeBin(c); + } + else + { + c = (unsigned char)GetUnsignedShort(); + } + return c; +} + +inline short CUtlBuffer::GetShort() +{ + short s; + GetType(s); + return s; +} + +inline unsigned short CUtlBuffer::GetUnsignedShort() +{ + unsigned short s; + GetType(s); + return s; +} + +inline int CUtlBuffer::GetInt() +{ + int i; + GetType(i); + return i; +} + +inline int64 CUtlBuffer::GetInt64() +{ + int64 i; + GetType(i); + return i; +} + +inline unsigned int CUtlBuffer::GetIntHex() +{ + uint i; + if (!IsText()) + { + GetTypeBin(i); + } + else + { + GetTypeText(i, 16); + } + return i; +} + +inline unsigned int CUtlBuffer::GetUnsignedInt() +{ + unsigned int i; + GetType(i); + return i; +} + +inline uint64 CUtlBuffer::GetUnsignedInt64() +{ + uint64 i; + GetType(i); + return i; +} + + +inline float CUtlBuffer::GetFloat() +{ + float f; + GetType(f); + return f; +} + +inline double CUtlBuffer::GetDouble() +{ + double d; + GetType(d); + return d; +} + +inline void* CUtlBuffer::GetPtr() +{ + void* p; +#if !defined(X64BITS) && !defined(PLATFORM_64BITS) + p = (void*)GetUnsignedInt(); +#else + p = (void*)GetInt64(); +#endif + return p; +} + +inline unsigned char CUtlBuffer::GetFlags() const +{ + return m_Flags; +} + + +inline bool CUtlBuffer::IsExternallyAllocated() const +{ + return m_Memory.IsExternallyAllocated(); +} + + +inline int CUtlBuffer::TellPut() const +{ + return m_Put; +} + + +inline int CUtlBuffer::TellMaxPut() const +{ + return m_nMaxPut; +} + + +inline void* CUtlBuffer::PeekPut(int offset) +{ + return &m_Memory[m_Put + offset - m_nOffset]; +} + + +template +inline void CUtlBuffer::PutObject(T* src) +{ + if (CheckPut(sizeof(T))) + { + if (!m_Byteswap.IsSwappingBytes() || (sizeof(T) == 1)) + { + *(T*)PeekPut() = *src; + } + else + { + m_Byteswap.SwapFieldsToTargetEndian((T*)PeekPut(), src); + } + m_Put += sizeof(T); + AddNullTermination(m_Put); + } +} + + +template +inline void CUtlBuffer::PutObjects(T* src, int count) +{ + for (int i = 0; i < count; ++i, ++src) + { + PutObject(src); + } +} + + +template +inline void CUtlBuffer::PutTypeBin(T src) +{ + if (CheckPut(sizeof(T))) + { + if (!m_Byteswap.IsSwappingBytes() || (sizeof(T) == 1)) + { + *(T*)PeekPut() = src; + } + else + { + m_Byteswap.SwapBufferToTargetEndian((T*)PeekPut(), &src); + } + m_Put += sizeof(T); + AddNullTermination(m_Put); + } +} + +#if defined( _GAMECONSOLE ) +template <> +inline void CUtlBuffer::PutTypeBin< float >(float src) +{ + if (CheckPut(sizeof(src))) + { + if (m_Byteswap.IsSwappingBytes()) + { + m_Byteswap.SwapBufferToTargetEndian(&src, &src); + } + + unsigned pData = (unsigned)PeekPut(); + if (pData & 0x03) + { + byte* dst = (byte*)pData; + byte* srcPtr = (byte*)&src; + dst[0] = srcPtr[0]; + dst[1] = srcPtr[1]; + dst[2] = srcPtr[2]; + dst[3] = srcPtr[3]; + } + else + { + *(float*)pData = src; + } + + m_Put += sizeof(float); + AddNullTermination(m_Put); + } +} + +template <> +inline void CUtlBuffer::PutTypeBin< double >(double src) +{ + if (CheckPut(sizeof(src))) + { + if (m_Byteswap.IsSwappingBytes()) + { + m_Byteswap.SwapBufferToTargetEndian(&src, &src); + } + + unsigned pData = (unsigned)PeekPut(); + if (pData & 0x07) + { + byte* dst = (byte*)pData; + byte* srcPtr = (byte*)&src; + dst[0] = srcPtr[0]; + dst[1] = srcPtr[1]; + dst[2] = srcPtr[2]; + dst[3] = srcPtr[3]; + dst[4] = srcPtr[4]; + dst[5] = srcPtr[5]; + dst[6] = srcPtr[6]; + dst[7] = srcPtr[7]; + } + else + { + *(double*)pData = src; + } + + m_Put += sizeof(double); + AddNullTermination(m_Put); + } +} +#endif + +template +inline void CUtlBuffer::PutType(T src) +{ + if (!IsText()) + { + PutTypeBin(src); + } + else + { + Printf(GetFmtStr< T >(), src); + } +} + +inline bool CUtlBuffer::WasLastCharacterCR() +{ + if (!IsText() || (TellPut() == 0)) + return false; + return (*(const char*)PeekPut(-1) == '\n'); +} + +inline void CUtlBuffer::PutTabs() +{ + int nTabCount = (m_Flags & AUTO_TABS_DISABLED) ? 0 : m_nTab; + for (int i = nTabCount; --i >= 0; ) + { + PutTypeBin('\t'); + } +} + + +inline void CUtlBuffer::PushTab() +{ + ++m_nTab; +} + +inline void CUtlBuffer::PopTab() +{ + if (--m_nTab < 0) + { + m_nTab = 0; + } +} + + +inline void CUtlBuffer::EnableTabs(bool bEnable) +{ + if (bEnable) + { + m_Flags &= ~AUTO_TABS_DISABLED; + } + else + { + m_Flags |= AUTO_TABS_DISABLED; + } +} + +inline void CUtlBuffer::PutChar(char c) +{ + if (WasLastCharacterCR()) + { + PutTabs(); + } + + PutTypeBin(c); +} + +inline void CUtlBuffer::PutUnsignedChar(unsigned char c) +{ + if (!IsText()) + { + PutTypeBin(c); + } + else + { + PutUnsignedShort(c); + } +} + +inline void CUtlBuffer::PutShort(short s) +{ + PutType(s); +} + +inline void CUtlBuffer::PutUnsignedShort(unsigned short s) +{ + PutType(s); +} + +inline void CUtlBuffer::PutInt(int i) +{ + PutType(i); +} + +inline void CUtlBuffer::PutInt64(int64 i) +{ + PutType(i); +} + +inline void CUtlBuffer::PutUnsignedInt(unsigned int u) +{ + PutType(u); +} + +inline void CUtlBuffer::PutUnsignedInt64(uint64 i) +{ + PutType(i); +} + + +inline void CUtlBuffer::PutFloat(float f) +{ + PutType(f); +} + +inline void CUtlBuffer::PutDouble(double d) +{ + PutType(d); +} + +inline void CUtlBuffer::PutPtr(void* p) +{ + if (!IsText()) + { + PutTypeBin(p); + } + else + { + Printf("0x%p", p); + } +} + +inline bool CUtlBuffer::IsText() const +{ + return (m_Flags & TEXT_BUFFER) != 0; +} + + +inline bool CUtlBuffer::IsGrowable() const +{ + return (m_Flags & EXTERNAL_GROWABLE) != 0; +} + + +inline bool CUtlBuffer::IsValid() const +{ + return m_Error == 0; +} + + +inline bool CUtlBuffer::ContainsCRLF() const +{ + return IsText() && ((m_Flags & CONTAINS_CRLF) != 0); +} + + +inline bool CUtlBuffer::IsReadOnly() const +{ + return (m_Flags & READ_ONLY) != 0; +} + + +inline const void* CUtlBuffer::Base() const +{ + return m_Memory.Base(); +} + +inline void* CUtlBuffer::Base() +{ + return m_Memory.Base(); +} + +inline int CUtlBuffer::Size() const +{ + return m_Memory.NumAllocated(); +} + + +inline void CUtlBuffer::Clear() +{ + m_Get = 0; + m_Put = 0; + m_Error = 0; + m_nOffset = 0; + m_nMaxPut = -1; + AddNullTermination(m_Put); +} + +inline void CUtlBuffer::Purge() +{ + m_Get = 0; + m_Put = 0; + m_nOffset = 0; + m_nMaxPut = 0; + m_Error = 0; + m_Memory.Purge(); +} + +inline void* CUtlBuffer::AccessForDirectRead(int nBytes) +{ + Assert(m_Get == 0 && m_Put == 0 && m_nMaxPut == 0); + EnsureCapacity(nBytes); + m_nMaxPut = nBytes; + return Base(); +} + +inline void* CUtlBuffer::Detach() +{ + void* p = m_Memory.Detach(); + Clear(); + return p; +} + +inline void CUtlBuffer::Spew() +{ + SeekGet(CUtlBuffer::SEEK_HEAD, 0); + + char pTmpLine[1024]; + while (IsValid() && GetBytesRemaining()) + { + V_memset(pTmpLine, 0, sizeof(pTmpLine)); + Get(pTmpLine, MIN((size_t)GetBytesRemaining(), sizeof(pTmpLine) - 1)); + Msg(_T("%s"), pTmpLine); + } +} + +#if !defined(_GAMECONSOLE) +inline void CUtlBuffer::SwapCopy(CUtlBuffer& other) +{ + m_Get = other.m_Get; + m_Put = other.m_Put; + m_Error = other.m_Error; + m_Flags = other.m_Flags; + m_Reserved = other.m_Reserved; + m_nTab = other.m_nTab; + m_nMaxPut = other.m_nMaxPut; + m_nOffset = other.m_nOffset; + m_GetOverflowFunc = other.m_GetOverflowFunc; + m_PutOverflowFunc = other.m_PutOverflowFunc; + m_Byteswap = other.m_Byteswap; + + m_Memory.Swap(other.m_Memory); +} +#endif + +inline void CUtlBuffer::CopyBuffer(const CUtlBuffer& buffer) +{ + CopyBuffer(buffer.Base(), buffer.TellPut()); +} + +inline void CUtlBuffer::CopyBuffer(const void* pubData, int cubData) +{ + Clear(); + if (cubData) + { + Put(pubData, cubData); + } +} + +#endif +``` + +`SpyCustom/sdk/utldelegate.h`: + +```h +//========== Copyright (c) Valve Corporation, All rights reserved. ==========// +// +// Purpose: A header describing use of the delegate system. It's hiding +// the highly complex implementation details of the delegate system +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef UTLDELEGATE_H +#define UTLDELEGATE_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// The delegate system: A method of invoking methods, whether they are +// member methods of classes, static methods of classes, or free functions, +// dealing with all the nastiness in differences between how the calls have +// to happen yet works in a highly optimal fashion. For details, see +// +// http://www.codeproject.com/cpp/FastDelegate.asp +// +// The delegate design pattern is described here +// +// http://en.wikipedia.org/wiki/Delegation_(programming) +//----------------------------------------------------------------------------- + +#ifdef UTLDELEGATE_USAGE_DEMONSTRATION + +//----------------------------------------------------------------------------- +// Here, we show how to use this system (the ifdef UTLDELEGATE_USAGE_DEMONSTRATION is used to get syntax coloring). +//----------------------------------------------------------------------------- + +// First, define the functions you wish to call. +int Test1( char *pString, float x ); +class CTestClass +{ +public: + void Test2(); + static float Test3( int x ); +}; + +void Test() +{ + CTestClass testClass; + + // CUtlDelegate is a class that can be used to invoke methods of classes + // or static functions in a highly efficient manner. + + // There are a couple ways to hook up a delegate. One is in a constructor + // Note that the template parameter of CUtlFastDelegate looks like the + // function type: first, you have the return type, then ( parameter list ) + CUtlDelegate< int ( char *, float ) > delegate1( &Test1 ); + + // Another way is to use the UtlMakeDelegate method, allowing you to + // define the delegate later. Note that UtlMakeDelegate does *not* do a heap allocation + CUtlDelegate< void () > delegate2; + delegate2 = UtlMakeDelegate( &testClass, &CTestClass::Test2 ); + + // A third method is to use the Bind() method of CUtlFastDelegate + // Note that you do not pass in the class pointer for static functions + CUtlDelegate< float ( int ) > delegate3; + delegate3.Bind( &CTestClass::Test3 ); + + // Use the () operator to invoke the function calls. + int x = delegate1( "hello", 1.0f ); + delegate2(); + float y = delegate3( 5 ); + + // Use the Clear() method to unbind a delegate. + delegate1.Clear(); + + // You can use operator! or IsEmpty() to see if a delegate is bound + if ( !delegate1.IsEmpty() ) + { + delegate1( "hello2" ); + } + + // Delegates maintain an internal non-templatized representation of the + // functions they are bound to called CUtlAbstractDelegate. These are + // useful when keeping a list of untyped delegates or when passing + // delegates across interface boundaries. + const CUtlAbstractDelegate &abstractDelegate3 = delegate3.GetAbstractDelegate(); + CUtlDelegate< float ( int ) > delegate4; + delegate4.SetAbstractDelegate( abstractDelegate3 ); + delegate4( 10 ); +} + +#endif // UTLDELEGATE_USAGE_DEMONSTRATION + +// Looking in this file may cause blindness. +// #include "tier1/utldelegateimpl.h" + +#endif // UTLDELEGATE_H +``` + +`SpyCustom/sdk/utldict.h`: + +```h +#ifndef UTLDICT_H +#define UTLDICT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include "utlmap.h" + +#include "utlsymbol.h" + +#include "memdbgon.h" + +enum EDictCompareType +{ + k_eDictCompareTypeCaseSensitive = 0, + k_eDictCompareTypeCaseInsensitive = 1, + k_eDictCompareTypeFilenames +}; + +#define FOR_EACH_DICT( dictName, iteratorName ) \ + for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) ) + +#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else + +template +class CUtlDict +{ +public: + typedef const char* KeyType_t; + typedef T ElemType_t; + + CUtlDict(int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0); + ~CUtlDict(); + + void EnsureCapacity(int); + + T& Element(I i); + const T& Element(I i) const; + T& operator[](I i); + const T& operator[](I i) const; + + char const* GetElementName(I i) const; + + void SetElementName(I i, char const* pName); + + unsigned int Count() const; + + I MaxElement() const; + + bool IsValidIndex(I i) const; + + static I InvalidIndex(); + + I Insert(const char* pName, const T& element); + I Insert(const char* pName); + + I Find(const char* pName) const; + bool HasElement(const char* pName) const; + + void RemoveAt(I i); + void Remove(const char* pName); + void RemoveAll(); + + void Purge(); + void PurgeAndDeleteElements(); + + I First() const; + I Next(I i) const; + + typedef I IndexType_t; + +protected: + typedef CUtlMap DictElementMap_t; + DictElementMap_t m_Elements; +}; + + +template +CUtlDict::CUtlDict(int compareType, int growSize, int initSize) : m_Elements(growSize, initSize) +{ + if (compareType == k_eDictCompareTypeFilenames) + { + m_Elements.SetLessFunc(CaselessStringLessThanIgnoreSlashes); + } + else if (compareType == k_eDictCompareTypeCaseInsensitive) + { + m_Elements.SetLessFunc(CaselessStringLessThan); + } + else + { + m_Elements.SetLessFunc(StringLessThan); + } +} + +template +CUtlDict::~CUtlDict() +{ + Purge(); +} + +template +inline void CUtlDict::EnsureCapacity(int num) +{ + return m_Elements.EnsureCapacity(num); +} + +template +inline T& CUtlDict::Element(I i) +{ + return m_Elements[i]; +} + +template +inline const T& CUtlDict::Element(I i) const +{ + return m_Elements[i]; +} + +template +inline char const* CUtlDict::GetElementName(I i) const +{ + return m_Elements.Key(i); +} + +template +inline T& CUtlDict::operator[](I i) +{ + return Element(i); +} + +template +inline const T& CUtlDict::operator[](I i) const +{ + return Element(i); +} + +template +inline void CUtlDict::SetElementName(I i, char const* pName) +{ + MEM_ALLOC_CREDIT_CLASS(); + free(const_cast(m_Elements.Key(i))); + m_Elements.Reinsert(strdup(pName), i); +} + +template +inline unsigned int CUtlDict::Count() const +{ + return m_Elements.Count(); +} + +template +inline I CUtlDict::MaxElement() const +{ + return m_Elements.MaxElement(); +} + +template +inline bool CUtlDict::IsValidIndex(I i) const +{ + return m_Elements.IsValidIndex(i); +} + + +template +inline I CUtlDict::InvalidIndex() +{ + return DictElementMap_t::InvalidIndex(); +} + + +template +void CUtlDict::RemoveAt(I elem) +{ + free(const_cast(m_Elements.Key(elem))); + m_Elements.RemoveAt(elem); +} + + +template void CUtlDict::Remove(const char* search) +{ + I node = Find(search); + if (node != InvalidIndex()) + { + RemoveAt(node); + } +} + + +template +void CUtlDict::RemoveAll() +{ + typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder(); + while (index != m_Elements.InvalidIndex()) + { + const char* p = m_Elements.Key(index); + free(const_cast(p)); + index = m_Elements.NextInorder(index); + } + + m_Elements.RemoveAll(); +} + +template +void CUtlDict::Purge() +{ + RemoveAll(); +} + + +template +void CUtlDict::PurgeAndDeleteElements() +{ + I index = m_Elements.FirstInorder(); + while (index != m_Elements.InvalidIndex()) + { + const char* p = m_Elements.Key(index); + free(const_cast(p)); + delete m_Elements[index]; + index = m_Elements.NextInorder(index); + } + + m_Elements.RemoveAll(); +} + + +template +I CUtlDict::Insert(const char* pName, const T& element) +{ + MEM_ALLOC_CREDIT_CLASS(); + return m_Elements.Insert(strdup(pName), element); +} + +template +I CUtlDict::Insert(const char* pName) +{ + MEM_ALLOC_CREDIT_CLASS(); + return m_Elements.Insert(strdup(pName)); +} + + +template +I CUtlDict::Find(const char* pName) const +{ + MEM_ALLOC_CREDIT_CLASS(); + if (pName) + return m_Elements.Find(pName); + else + return InvalidIndex(); +} + +template +bool CUtlDict::HasElement(const char* pName) const +{ + if (pName) + return m_Elements.IsValidIndex(m_Elements.Find(pName)); + else + return false; +} + + +template +I CUtlDict::First() const +{ + return m_Elements.FirstInorder(); +} + +template +I CUtlDict::Next(I i) const +{ + return m_Elements.NextInorder(i); +} + +#include "memdbgoff.h" + +#endif + +``` + +`SpyCustom/sdk/utlenvelope.h`: + +```h +#include "utlstring.h" +#include "basetypes.h" + +#ifndef UTLENVELOPE_H +#define UTLENVELOPE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +class CUtlDataEnvelope +{ +public: + CUtlDataEnvelope(const void* pData, int nBytes); + CUtlDataEnvelope(const CUtlDataEnvelope& from); + ~CUtlDataEnvelope(); + + CUtlDataEnvelope& operator=(const CUtlDataEnvelope& from); + + operator void* (); + operator void* () const; + +private: + void Assign(const void* pData, int nBytes); + void Assign(const CUtlDataEnvelope& from); + void Purge(); + + union + { + byte* m_pData; + byte m_data[4]; + }; + int m_nBytes; +}; + + +template +class CUtlEnvelope : protected CUtlDataEnvelope +{ +public: + CUtlEnvelope(const T* pData, int nElems = 1); + CUtlEnvelope(const CUtlEnvelope& from); + + CUtlEnvelope& operator=(const CUtlEnvelope& from); + + operator T* (); + operator T* () const; + + operator void* (); + operator void* () const; +}; + +template <> +class CUtlEnvelope +{ +public: + CUtlEnvelope(const char* pData) + { + m_string = pData; + } + + CUtlEnvelope(const CUtlEnvelope& from) + { + m_string = from.m_string; + } + + CUtlEnvelope& operator=(const CUtlEnvelope& from) + { + m_string = from.m_string; + return *this; + } + + operator char* () + { + return (char*)m_string.Get(); + } + + operator char* () const + { + return (char*)m_string.Get(); + } + + operator void* () + { + return (void*)m_string.Get(); + } + + operator void* () const + { + return (void*)m_string.Get(); + } + +private: + CUtlString m_string; +}; + +#include "memdbgon.h" + +inline void CUtlDataEnvelope::Assign(const void* pData, int nBytes) +{ + if (pData) + { + m_nBytes = nBytes; + if (m_nBytes > 4) + { + m_pData = new byte[nBytes]; + memcpy(m_pData, pData, nBytes); + } + else + { + memcpy(m_data, pData, nBytes); + } + } + else + { + m_pData = NULL; + m_nBytes = 0; + } +} + +inline void CUtlDataEnvelope::Assign(const CUtlDataEnvelope& from) +{ + Assign(from.operator void* (), from.m_nBytes); +} + +inline void CUtlDataEnvelope::Purge() +{ + if (m_nBytes > 4) + delete[] m_pData; + m_nBytes = 0; +} + +inline CUtlDataEnvelope::CUtlDataEnvelope(const void* pData, int nBytes) +{ + Assign(pData, nBytes); +} + +inline CUtlDataEnvelope::CUtlDataEnvelope(const CUtlDataEnvelope& from) +{ + Assign(from); +} + +inline CUtlDataEnvelope::~CUtlDataEnvelope() +{ + Purge(); +} + +inline CUtlDataEnvelope& CUtlDataEnvelope::operator=(const CUtlDataEnvelope& from) +{ + Purge(); + Assign(from); + return *this; +} + +inline CUtlDataEnvelope::operator void* () +{ + if (!m_nBytes) + { + return NULL; + } + + return (m_nBytes > 4) ? m_pData : m_data; +} + +inline CUtlDataEnvelope::operator void* () const +{ + if (!m_nBytes) + { + return NULL; + } + + return (m_nBytes > 4) ? (void*)m_pData : (void*)m_data; +} + +template +inline CUtlEnvelope::CUtlEnvelope(const T* pData, int nElems) + : CUtlDataEnvelope(pData, sizeof(T)* nElems) +{ +} + +template +inline CUtlEnvelope::CUtlEnvelope(const CUtlEnvelope& from) + : CUtlDataEnvelope(from) +{ + +} + +template +inline CUtlEnvelope& CUtlEnvelope::operator=(const CUtlEnvelope& from) +{ + CUtlDataEnvelope::operator=(from); + return *this; +} + +template +inline CUtlEnvelope::operator T* () +{ + return (T*)CUtlDataEnvelope::operator void* (); +} + +template +inline CUtlEnvelope::operator T* () const +{ + return (T*)((const_cast*>(this))->operator T * ()); +} + +template +inline CUtlEnvelope::operator void* () +{ + return CUtlDataEnvelope::operator void* (); +} + +template +inline CUtlEnvelope::operator void* () const +{ + return ((const_cast*>(this))->operator void* ()); +} + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/utlfixedmemory.h`: + +```h +#ifndef UTLFIXEDMEMORY_H +#define UTLFIXEDMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include "platform.h" + +#include "memalloc.h" +#include "memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +#ifdef UTLFIXEDMEMORY_TRACK +#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0) +#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0) +#endif + + +template< class T > +class CUtlFixedMemory +{ +public: + CUtlFixedMemory(int nGrowSize = 0, int nInitSize = 0); + ~CUtlFixedMemory(); + + void Init(int nGrowSize = 0, int nInitSize = 0); + + T* Base() { return NULL; } + const T* Base() const { return NULL; } + +protected: + struct BlockHeader_t; + +public: + class Iterator_t + { + public: + Iterator_t(BlockHeader_t* p, int i) : m_pBlockHeader(p), m_nIndex(i) {} + BlockHeader_t* m_pBlockHeader; + intp m_nIndex; + + bool operator==(const Iterator_t it) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; } + bool operator!=(const Iterator_t it) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; } + }; + Iterator_t First() const { return m_pBlocks ? Iterator_t(m_pBlocks, 0) : InvalidIterator(); } + Iterator_t Next(const Iterator_t& it) const + { + Assert(IsValidIterator(it)); + if (!IsValidIterator(it)) + return InvalidIterator(); + + BlockHeader_t* RESTRICT pHeader = it.m_pBlockHeader; + if (it.m_nIndex + 1 < pHeader->m_nBlockSize) + return Iterator_t(pHeader, it.m_nIndex + 1); + + return pHeader->m_pNext ? Iterator_t(pHeader->m_pNext, 0) : InvalidIterator(); + } + intp GetIndex(const Iterator_t& it) const + { + Assert(IsValidIterator(it)); + if (!IsValidIterator(it)) + return InvalidIndex(); + + return (intp)(HeaderToBlock(it.m_pBlockHeader) + it.m_nIndex); + } + bool IsIdxAfter(intp i, const Iterator_t& it) const + { + Assert(IsValidIterator(it)); + if (!IsValidIterator(it)) + return false; + + if (IsInBlock(i, it.m_pBlockHeader)) + return i > GetIndex(it); + + for (BlockHeader_t* RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext) + { + if (IsInBlock(i, pbh)) + return true; + } + return false; + } + bool IsValidIterator(const Iterator_t& it) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; } + Iterator_t InvalidIterator() const { return Iterator_t(NULL, INVALID_INDEX); } + + T& operator[](intp i); + const T& operator[](intp i) const; + T& Element(intp i); + const T& Element(intp i) const; + + bool IsIdxValid(intp i) const; + + static const intp INVALID_INDEX = 0; + static intp InvalidIndex() { return INVALID_INDEX; } + + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + void Grow(int num = 1); + + void EnsureCapacity(int num); + + void Purge(); + +protected: + void Swap(CUtlFixedMemory< T >& mem); + + bool IsInBlock(intp i, BlockHeader_t* pBlockHeader) const + { + T* p = (T*)i; + const T* p0 = HeaderToBlock(pBlockHeader); + return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize; + } + + struct BlockHeader_t + { + BlockHeader_t* m_pNext; + intp m_nBlockSize; + }; + + const T* HeaderToBlock(const BlockHeader_t* pHeader) const { return (T*)(pHeader + 1); } + const BlockHeader_t* BlockToHeader(const T* pBlock) const { return (BlockHeader_t*)(pBlock)-1; } + + BlockHeader_t* m_pBlocks; + int m_nAllocationCount; + int m_nGrowSize; +}; + +template< class T > +CUtlFixedMemory::CUtlFixedMemory(int nGrowSize, int nInitAllocationCount) + : m_pBlocks(0), m_nAllocationCount(0), m_nGrowSize(0) +{ + Init(nGrowSize, nInitAllocationCount); +} + +template< class T > +CUtlFixedMemory::~CUtlFixedMemory() +{ + Purge(); +} + + +template< class T > +void CUtlFixedMemory::Swap(CUtlFixedMemory< T >& mem) +{ + V_swap(m_pBlocks, mem.m_pBlocks); + V_swap(m_nAllocationCount, mem.m_nAllocationCount); + V_swap(m_nGrowSize, mem.m_nGrowSize); +} + + +template< class T > +void CUtlFixedMemory::Init(int nGrowSize , int nInitSize ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + + Grow(nInitSize); +} + +template< class T > +inline T& CUtlFixedMemory::operator[](intp i) +{ + Assert(IsIdxValid(i)); + return *(T*)i; +} + +template< class T > +inline const T& CUtlFixedMemory::operator[](intp i) const +{ + Assert(IsIdxValid(i)); + return *(T*)i; +} + +template< class T > +inline T& CUtlFixedMemory::Element(intp i) +{ + Assert(IsIdxValid(i)); + return *(T*)i; +} + +template< class T > +inline const T& CUtlFixedMemory::Element(intp i) const +{ + Assert(IsIdxValid(i)); + return *(T*)i; +} + + +template< class T > +inline int CUtlFixedMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + + +template< class T > +inline bool CUtlFixedMemory::IsIdxValid(intp i) const +{ +#ifdef _DEBUG + for (BlockHeader_t* pbh = m_pBlocks; pbh; pbh = pbh->m_pNext) + { + if (IsInBlock(i, pbh)) + return true; + } + return false; +#else + return i != InvalidIndex(); +#endif +} + +template< class T > +void CUtlFixedMemory::Grow(int num) +{ + if (num <= 0) + return; + + int nBlockSize = m_nGrowSize; + if (nBlockSize == 0) + { + if (m_nAllocationCount) + { + nBlockSize = m_nAllocationCount; + } + else + { + nBlockSize = (31 + sizeof(T)) / sizeof(T); + Assert(nBlockSize); + } + } + if (nBlockSize < num) + { + int n = (num + nBlockSize - 1) / nBlockSize; + Assert(n * nBlockSize >= num); + Assert((n - 1) * nBlockSize < num); + nBlockSize *= n; + } + m_nAllocationCount += nBlockSize; + + MEM_ALLOC_CREDIT_CLASS(); + BlockHeader_t* RESTRICT pBlockHeader = (BlockHeader_t*)malloc(sizeof(BlockHeader_t) + nBlockSize * sizeof(T)); + if (!pBlockHeader) + { + Error("CUtlFixedMemory overflow!\n"); + } + pBlockHeader->m_pNext = NULL; + pBlockHeader->m_nBlockSize = nBlockSize; + + if (!m_pBlocks) + { + m_pBlocks = pBlockHeader; + } + else + { +#if 1 + BlockHeader_t* RESTRICT pbh = m_pBlocks; + while (pbh->m_pNext) + { + pbh = pbh->m_pNext; + } + pbh->m_pNext = pBlockHeader; +#else + pBlockHeader = m_pBlocks; + pBlockHeader->m_pNext = m_pBlocks; +#endif + } +} + + +template< class T > +inline void CUtlFixedMemory::EnsureCapacity(int num) +{ + Grow(num - NumAllocated()); +} + + +template< class T > +void CUtlFixedMemory::Purge() +{ + if (!m_pBlocks) + return; + + for (BlockHeader_t* pbh = m_pBlocks; pbh; ) + { + BlockHeader_t* pFree = pbh; + pbh = pbh->m_pNext; + free(pFree); + } + m_pBlocks = NULL; + m_nAllocationCount = 0; +} + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/utlflags.h`: + +```h +#ifndef UTLFLAGS_H +#define UTLFLAGS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" + + +template< class T > +class CUtlFlags +{ +public: + CUtlFlags(int nInitialFlags = 0); + + void SetFlag(int nFlagMask); + void SetFlag(int nFlagMask, bool bEnable); + + void ClearFlag(int nFlagMask); + void ClearAllFlags(); + bool IsFlagSet(int nFlagMask) const; + + bool IsAnyFlagSet() const; + +private: + T m_nFlags; +}; + + +template< class T > +CUtlFlags::CUtlFlags(int nInitialFlags) +{ + Assert(nInitialFlags == (T)nInitialFlags); + + m_nFlags = (T)nInitialFlags; +} + + +template< class T > +void CUtlFlags::SetFlag(int nFlagMask) +{ + Assert(nFlagMask == (T)nFlagMask); + + m_nFlags |= (T)nFlagMask; +} + +template< class T > +void CUtlFlags::SetFlag(int nFlagMask, bool bEnable) +{ + Assert(nFlagMask == (T)nFlagMask); + + if (bEnable) + { + m_nFlags |= (T)nFlagMask; + } + else + { + m_nFlags &= ~((T)nFlagMask); + } +} + + +template< class T > +void CUtlFlags::ClearFlag(int nFlagMask) +{ + Assert(nFlagMask == (T)nFlagMask); + m_nFlags &= ~((T)nFlagMask); +} + +template< class T > +void CUtlFlags::ClearAllFlags() +{ + m_nFlags = 0; +} + + +template< class T > +bool CUtlFlags::IsFlagSet(int nFlagMask) const +{ + Assert(nFlagMask == (T)nFlagMask); + return (m_nFlags & nFlagMask) != 0; +} + + +template< class T > +bool CUtlFlags::IsAnyFlagSet() const +{ + return m_nFlags != 0; +} + + +#endif +``` + +`SpyCustom/sdk/utlhandletable.h`: + +```h +#ifndef UTLHANDLETABLE_H +#define UTLHANDLETABLE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "utlvector.h" +#include "utlqueue.h" + + +typedef unsigned int UtlHandle_t; +#define UTLHANDLE_INVALID ((UtlHandle_t)~0) + + +template< class T, int HandleBits > +class CUtlHandleTable +{ +public: + CUtlHandleTable(); + + UtlHandle_t AddHandle(); + void RemoveHandle(UtlHandle_t h); + + void SetHandle(UtlHandle_t h, T* pData); + T* GetHandle(UtlHandle_t h) const; + T* GetHandle(UtlHandle_t h, bool checkValidity) const; + + bool IsHandleValid(UtlHandle_t h) const; + + unsigned int GetValidHandleCount() const; + unsigned int GetHandleCount() const; + UtlHandle_t GetHandleFromIndex(int i) const; + int GetIndexFromHandle(UtlHandle_t h) const; + + void MarkHandleInvalid(UtlHandle_t h); + void MarkHandleValid(UtlHandle_t h); + +private: + struct HandleType_t + { + HandleType_t(unsigned int i, unsigned int s) : nIndex(i), nSerial(s) + { + Assert(i < (1 << HandleBits)); + Assert(s < (1 << (31 - HandleBits))); + } + unsigned int nIndex : HandleBits; + unsigned int nSerial : 31 - HandleBits; + }; + + struct EntryType_t + { + EntryType_t() : m_nSerial(0), nInvalid(0), m_pData(0) {} + unsigned int m_nSerial : 31; + unsigned int nInvalid : 1; + T* m_pData; + }; + + static unsigned int GetSerialNumber(UtlHandle_t handle); + static unsigned int GetListIndex(UtlHandle_t handle); + static UtlHandle_t CreateHandle(unsigned int nSerial, unsigned int nIndex); + const EntryType_t* GetEntry(UtlHandle_t handle, bool checkValidity) const; + + unsigned int m_nValidHandles; + CUtlVector< EntryType_t > m_list; + CUtlQueue< int > m_unused; +}; + + +template< class T, int HandleBits > +CUtlHandleTable::CUtlHandleTable() : m_nValidHandles(0) +{ +} + + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable::AddHandle() +{ + unsigned int nIndex = (m_unused.Count() > 0) ? m_unused.RemoveAtHead() : m_list.AddToTail(); + + EntryType_t& entry = m_list[nIndex]; + entry.nInvalid = 0; + entry.m_pData = NULL; + + ++m_nValidHandles; + + return CreateHandle(entry.m_nSerial, nIndex); +} + +template< class T, int HandleBits > +void CUtlHandleTable::RemoveHandle(UtlHandle_t handle) +{ + unsigned int nIndex = GetListIndex(handle); + Assert(nIndex < (unsigned int)m_list.Count()); + if (nIndex >= (unsigned int)m_list.Count()) + return; + + EntryType_t& entry = m_list[nIndex]; + ++entry.m_nSerial; + if (!entry.nInvalid) + { + entry.nInvalid = 1; + --m_nValidHandles; + } + entry.m_pData = NULL; + + + bool bStopUsing = (entry.m_nSerial >= ((1 << (31 - HandleBits)) - 1)); + if (!bStopUsing) + { + m_unused.Insert(nIndex); + } +} + + +template< class T, int HandleBits > +void CUtlHandleTable::SetHandle(UtlHandle_t handle, T* pData) +{ + EntryType_t* entry = const_cast(GetEntry(handle, false)); + Assert(entry); + if (entry == NULL) + return; + + if (entry->nInvalid) + { + ++m_nValidHandles; + entry->nInvalid = 0; + } + entry->m_pData = pData; +} + +template< class T, int HandleBits > +T* CUtlHandleTable::GetHandle(UtlHandle_t handle) const +{ + const EntryType_t* entry = GetEntry(handle, true); + return entry ? entry->m_pData : NULL; +} + +template< class T, int HandleBits > +T* CUtlHandleTable::GetHandle(UtlHandle_t handle, bool checkValidity) const +{ + const EntryType_t* entry = GetEntry(handle, checkValidity); + return entry ? entry->m_pData : NULL; +} + + +template< class T, int HandleBits > +bool CUtlHandleTable::IsHandleValid(UtlHandle_t handle) const +{ + if (handle == UTLHANDLE_INVALID) + return false; + + unsigned int nIndex = GetListIndex(handle); + AssertOnce(nIndex < (unsigned int)m_list.Count()); + if (nIndex >= (unsigned int)m_list.Count()) + return false; + + const EntryType_t& entry = m_list[nIndex]; + if (entry.m_nSerial != GetSerialNumber(handle)) + return false; + + if (1 == entry.nInvalid) + return false; + + return true; +} + + +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetValidHandleCount() const +{ + return m_nValidHandles; +} + +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetHandleCount() const +{ + return m_list.Count(); +} + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable::GetHandleFromIndex(int i) const +{ + if (m_list[i].m_pData) + return CreateHandle(m_list[i].m_nSerial, i); + return UTLHANDLE_INVALID; +} + +template< class T, int HandleBits > +int CUtlHandleTable::GetIndexFromHandle(UtlHandle_t h) const +{ + if (h == UTLHANDLE_INVALID) + return -1; + + return GetListIndex(h); +} + + + +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetSerialNumber(UtlHandle_t handle) +{ + return ((HandleType_t*)&handle)->nSerial; +} + +template< class T, int HandleBits > +unsigned int CUtlHandleTable::GetListIndex(UtlHandle_t handle) +{ + return ((HandleType_t*)&handle)->nIndex; +} + +template< class T, int HandleBits > +UtlHandle_t CUtlHandleTable::CreateHandle(unsigned int nSerial, unsigned int nIndex) +{ + HandleType_t h(nIndex, nSerial); + return *(UtlHandle_t*)&h; +} + + +template< class T, int HandleBits > +const typename CUtlHandleTable::EntryType_t* CUtlHandleTable::GetEntry(UtlHandle_t handle, bool checkValidity) const +{ + if (handle == UTLHANDLE_INVALID) + return NULL; + + unsigned int nIndex = GetListIndex(handle); + Assert(nIndex < (unsigned int)m_list.Count()); + if (nIndex >= (unsigned int)m_list.Count()) + return NULL; + + const EntryType_t& entry = m_list[nIndex]; + if (entry.m_nSerial != GetSerialNumber(handle)) + return NULL; + + if (checkValidity && + (1 == entry.nInvalid)) + return NULL; + + return &entry; +} + +template< class T, int HandleBits > +void CUtlHandleTable::MarkHandleInvalid(UtlHandle_t handle) +{ + if (handle == UTLHANDLE_INVALID) + return; + + unsigned int nIndex = GetListIndex(handle); + Assert(nIndex < (unsigned int)m_list.Count()); + if (nIndex >= (unsigned int)m_list.Count()) + return; + + EntryType_t& entry = m_list[nIndex]; + if (entry.m_nSerial != GetSerialNumber(handle)) + return; + + if (!entry.nInvalid) + { + --m_nValidHandles; + entry.nInvalid = 1; + } +} + +template< class T, int HandleBits > +void CUtlHandleTable::MarkHandleValid(UtlHandle_t handle) +{ + if (handle == UTLHANDLE_INVALID) + return; + + unsigned int nIndex = GetListIndex(handle); + Assert(nIndex < (unsigned int)m_list.Count()); + if (nIndex >= (unsigned int)m_list.Count()) + return; + + EntryType_t& entry = m_list[nIndex]; + if (entry.m_nSerial != GetSerialNumber(handle)) + return; + + if (entry.nInvalid) + { + ++m_nValidHandles; + entry.nInvalid = 0; + } +} + + +template< class T > +class CUtlHandle +{ +public: + CUtlHandle(); + explicit CUtlHandle(T* pObject); + CUtlHandle(UtlHandle_t h); + CUtlHandle(const CUtlHandle& h); + + void Set(T* pObject); + void Set(UtlHandle_t h); + const CUtlHandle& operator=(UtlHandle_t h); + const CUtlHandle& operator=(T* pObject); + + T* Get(); + const T* Get() const; + + bool IsValid() const; + + operator T* (); + operator UtlHandle_t(); + operator bool(); + T* operator->(); + const T* operator->() const; + + bool operator==(CUtlHandle h) const; + bool operator==(T* pObject) const; + bool operator==(UtlHandle_t h) const; + bool operator!=(CUtlHandle h) const; + bool operator!=(T* pObject) const; + bool operator!=(UtlHandle_t h) const; + +private: + UtlHandle_t m_handle; +}; + + +template< class T > +CUtlHandle::CUtlHandle() : m_handle(UTLHANDLE_INVALID) +{ +} + +template< class T > +CUtlHandle::CUtlHandle(T* pObject) +{ + Set(pObject); +} + +template< class T > +CUtlHandle::CUtlHandle(UtlHandle_t h) +{ + m_handle = h; +} + +template< class T > +CUtlHandle::CUtlHandle(const CUtlHandle& h) +{ + m_handle = h.m_handle; +} + + +template< class T > +void CUtlHandle::Set(T* pObject) +{ + m_handle = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; +} + +template< class T > +void CUtlHandle::Set(UtlHandle_t h) +{ + m_handle = h; +} + +template< class T > +const CUtlHandle& CUtlHandle::operator=(UtlHandle_t h) +{ + Set(h); + return *this; +} + +template< class T > +const CUtlHandle& CUtlHandle::operator=(T* pObject) +{ + Set(pObject); + return *this; +} + + +template< class T > +bool CUtlHandle::IsValid() const +{ + return T::IsHandleValid(m_handle); +} + + +template< class T > +T* CUtlHandle::Get() +{ + return T::GetPtrFromHandle(m_handle); +} + +template< class T > +const T* CUtlHandle::Get() const +{ + return T::GetPtrFromHandle(m_handle); +} + + +template< class T > +CUtlHandle::operator T* () +{ + return Get(); +} + +template< class T > +CUtlHandle::operator UtlHandle_t() +{ + return m_handle; +} + +template< class T > +T* CUtlHandle::operator->() +{ + return Get(); +} + +template< class T > +const T* CUtlHandle::operator->() const +{ + return Get(); +} + +template< class T > +CUtlHandle::operator bool() +{ + return m_handle != UTLHANDLE_INVALID; +} + + +template< class T > +bool CUtlHandle::operator==(CUtlHandle h) const +{ + return m_handle == h.m_handle; +} + +template< class T > +bool CUtlHandle::operator==(T* pObject) const +{ + UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; + return m_handle == h; +} + +template< class T > +bool CUtlHandle::operator==(UtlHandle_t h) const +{ + return m_handle == h; +} + +template< class T > +bool CUtlHandle::operator!=(CUtlHandle h) const +{ + return m_handle != h.m_handle; +} + +template< class T > +bool CUtlHandle::operator!=(T* pObject) const +{ + UtlHandle_t h = pObject ? pObject->GetHandle() : UTLHANDLE_INVALID; + return m_handle != h; +} + +template< class T > +bool CUtlHandle::operator!=(UtlHandle_t h) const +{ + return m_handle != h; +} + + +#define DECLARE_HANDLES( _className, _handleBitCount ) \ + public: \ + UtlHandle_t GetHandle() \ + { \ + return m_Handle; \ + } \ + static _className* GetPtrFromHandle( UtlHandle_t h ) \ + { \ + return m_HandleTable.GetHandle( h ); \ + } \ + static bool IsHandleValid( UtlHandle_t h ) \ + { \ + return m_HandleTable.IsHandleValid( h ); \ + } \ + private: \ + UtlHandle_t m_Handle; \ + static CUtlHandleTable< _className, _handleBitCount > m_HandleTable + + +#define IMPLEMENT_HANDLES( _className, _handleBitCount ) \ + CUtlHandleTable< _className, _handleBitCount > _className::m_HandleTable; + + +#define CONSTRUCT_HANDLE( ) \ + m_Handle = m_HandleTable.AddHandle(); \ + m_HandleTable.SetHandle( m_Handle, this ) + +#define DESTRUCT_HANDLE() \ + m_HandleTable.RemoveHandle( m_Handle ); \ + m_Handle = UTLHANDLE_INVALID + + + +#endif + +``` + +`SpyCustom/sdk/utlhash.h`: + +```h +#ifndef UTLHASH_H +#define UTLHASH_H +#pragma once + +#include +#include +#include "utlmemory.h" +#include "utlvector.h" +#include "utllinkedlist.h" +#include "commonmacros.h" +#include "generichash.h" + +typedef unsigned int UtlHashHandle_t; + +template +class CUtlHash +{ +public: + typedef C CompareFunc_t; + typedef K KeyFunc_t; + + CUtlHash(int bucketCount = 0, int growCount = 0, int initCount = 0, + CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0); + ~CUtlHash(); + + static UtlHashHandle_t InvalidHandle(void) { return (UtlHashHandle_t)~0; } + bool IsValidHandle(UtlHashHandle_t handle) const; + + int Count(void) const; + + void Purge(void); + + UtlHashHandle_t Insert(Data const& src); + UtlHashHandle_t Insert(Data const& src, bool* pDidInsert); + UtlHashHandle_t AllocEntryFromKey(Data const& src); + + void Remove(UtlHashHandle_t handle); + void RemoveAll(); + + UtlHashHandle_t Find(Data const& src) const; + + Data& Element(UtlHashHandle_t handle); + Data const& Element(UtlHashHandle_t handle) const; + Data& operator[](UtlHashHandle_t handle); + Data const& operator[](UtlHashHandle_t handle) const; + + UtlHashHandle_t GetFirstHandle() const; + UtlHashHandle_t GetNextHandle(UtlHashHandle_t h) const; + + void Log(const char* filename); + +protected: + + int GetBucketIndex(UtlHashHandle_t handle) const; + int GetKeyDataIndex(UtlHashHandle_t handle) const; + UtlHashHandle_t BuildHandle(int ndxBucket, int ndxKeyData) const; + + bool DoFind(Data const& src, unsigned int* pBucket, int* pIndex) const; + +protected: + + typedef CUtlVector HashBucketList_t; + CUtlVector m_Buckets; + + CompareFunc_t m_CompareFunc; + KeyFunc_t m_KeyFunc; + + bool m_bPowerOfTwo; + unsigned int m_ModMask; +}; + + +template +CUtlHash::CUtlHash(int bucketCount, int growCount, int initCount, + CompareFunc_t compareFunc, KeyFunc_t keyFunc) : + m_CompareFunc(compareFunc), + m_KeyFunc(keyFunc) +{ + m_Buckets.SetSize(bucketCount); + for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++) + { + m_Buckets[ndxBucket].SetSize(initCount); + m_Buckets[ndxBucket].SetGrowSize(growCount); + } + + m_bPowerOfTwo = IsPowerOfTwo(bucketCount); + m_ModMask = m_bPowerOfTwo ? (bucketCount - 1) : 0; +} + + +template +CUtlHash::~CUtlHash() +{ + Purge(); +} + + +template +inline bool CUtlHash::IsValidHandle(UtlHashHandle_t handle) const +{ + int ndxBucket = GetBucketIndex(handle); + int ndxKeyData = GetKeyDataIndex(handle); + + if ( (ndxBucket < m_Buckets.Count())) + { + if ( (ndxKeyData < m_Buckets[ndxBucket].Count())) + return true; + } + + return false; +} + +template +inline int CUtlHash::Count(void) const +{ + int count = 0; + + int bucketCount = m_Buckets.Count(); + for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++) + { + count += m_Buckets[ndxBucket].Count(); + } + + return count; +} + + +template +inline int CUtlHash::GetBucketIndex(UtlHashHandle_t handle) const +{ + return (((handle >> 16) & 0x0000ffff)); +} + + +template +inline int CUtlHash::GetKeyDataIndex(UtlHashHandle_t handle) const +{ + return (handle & 0x0000ffff); +} + + +template +inline UtlHashHandle_t CUtlHash::BuildHandle(int ndxBucket, int ndxKeyData) const +{ + assert((ndxBucket >= 0) && (ndxBucket < 65536)); + assert((ndxKeyData >= 0) && (ndxKeyData < 65536)); + + UtlHashHandle_t handle = ndxKeyData; + handle |= (ndxBucket << 16); + + return handle; +} + + +template +inline void CUtlHash::Purge(void) +{ + int bucketCount = m_Buckets.Count(); + for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++) + { + m_Buckets[ndxBucket].Purge(); + } +} + +template +inline bool CUtlHash::DoFind(Data const& src, unsigned int* pBucket, int* pIndex) const +{ + unsigned int key = m_KeyFunc(src); + + unsigned int ndxBucket; + if (m_bPowerOfTwo) + { + *pBucket = ndxBucket = (key & m_ModMask); + } + else + { + int bucketCount = m_Buckets.Count(); + *pBucket = ndxBucket = key % bucketCount; + } + + int ndxKeyData; + const CUtlVector& bucket = m_Buckets[ndxBucket]; + int keyDataCount = bucket.Count(); + for (ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++) + { + if (m_CompareFunc(bucket.Element(ndxKeyData), src)) + break; + } + + if (ndxKeyData == keyDataCount) + return false; + + *pIndex = ndxKeyData; + return true; +} + + +template +inline UtlHashHandle_t CUtlHash::Find(Data const& src) const +{ + unsigned int ndxBucket; + int ndxKeyData; + + if (DoFind(src, &ndxBucket, &ndxKeyData)) + { + return (BuildHandle(ndxBucket, ndxKeyData)); + } + return (InvalidHandle()); +} + + +template +inline UtlHashHandle_t CUtlHash::Insert(Data const& src) +{ + unsigned int ndxBucket; + int ndxKeyData; + + if (DoFind(src, &ndxBucket, &ndxKeyData)) + { + return (BuildHandle(ndxBucket, ndxKeyData)); + } + + ndxKeyData = m_Buckets[ndxBucket].AddToTail(src); + + return (BuildHandle(ndxBucket, ndxKeyData)); +} + +template +inline UtlHashHandle_t CUtlHash::Insert(Data const& src, bool* pDidInsert) +{ + unsigned int ndxBucket; + int ndxKeyData; + + if (DoFind(src, &ndxBucket, &ndxKeyData)) + { + *pDidInsert = false; + return (BuildHandle(ndxBucket, ndxKeyData)); + } + + *pDidInsert = true; + ndxKeyData = m_Buckets[ndxBucket].AddToTail(src); + + return (BuildHandle(ndxBucket, ndxKeyData)); +} + + +template +inline UtlHashHandle_t CUtlHash::AllocEntryFromKey(Data const& src) +{ + unsigned int ndxBucket; + int ndxKeyData; + + if (DoFind(src, &ndxBucket, &ndxKeyData)) + { + return (BuildHandle(ndxBucket, ndxKeyData)); + } + + ndxKeyData = m_Buckets[ndxBucket].AddToTail(); + + return (BuildHandle(ndxBucket, ndxKeyData)); +} + + +template +inline void CUtlHash::Remove(UtlHashHandle_t handle) +{ + assert(IsValidHandle(handle)); + + int ndxBucket = GetBucketIndex(handle); + int ndxKeyData = GetKeyDataIndex(handle); + + if (m_Buckets[ndxBucket].IsValidIndex(ndxKeyData)) + { + m_Buckets[ndxBucket].FastRemove(ndxKeyData); + } +} + + +template +inline void CUtlHash::RemoveAll() +{ + int bucketCount = m_Buckets.Count(); + for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++) + { + m_Buckets[ndxBucket].RemoveAll(); + } +} + + +template +inline Data& CUtlHash::Element(UtlHashHandle_t handle) +{ + int ndxBucket = GetBucketIndex(handle); + int ndxKeyData = GetKeyDataIndex(handle); + + return (m_Buckets[ndxBucket].Element(ndxKeyData)); +} + +template +inline Data const& CUtlHash::Element(UtlHashHandle_t handle) const +{ + int ndxBucket = GetBucketIndex(handle); + int ndxKeyData = GetKeyDataIndex(handle); + + return (m_Buckets[ndxBucket].Element(ndxKeyData)); +} + + +template +inline Data& CUtlHash::operator[](UtlHashHandle_t handle) +{ + int ndxBucket = GetBucketIndex(handle); + int ndxKeyData = GetKeyDataIndex(handle); + + return (m_Buckets[ndxBucket].Element(ndxKeyData)); +} + + +template +inline Data const& CUtlHash::operator[](UtlHashHandle_t handle) const +{ + int ndxBucket = GetBucketIndex(handle); + int ndxKeyData = GetKeyDataIndex(handle); + + return (m_Buckets[ndxBucket].Element(ndxKeyData)); +} + +template +inline UtlHashHandle_t CUtlHash::GetFirstHandle() const +{ + return GetNextHandle((UtlHashHandle_t)-1); +} + +template +inline UtlHashHandle_t CUtlHash::GetNextHandle(UtlHashHandle_t handle) const +{ + ++handle; + + int bi = GetBucketIndex(handle); + int ki = GetKeyDataIndex(handle); + + int nBuckets = m_Buckets.Count(); + for (; bi < nBuckets; ++bi) + { + if (ki < m_Buckets[bi].Count()) + return BuildHandle(bi, ki); + + ki = 0; + } + + return InvalidHandle(); +} + +template +inline void CUtlHash::Log(const char* filename) +{ + FILE* pDebugFp; + pDebugFp = fopen(filename, "w"); + if (!pDebugFp) + return; + + int maxBucketSize = 0; + int numBucketsEmpty = 0; + + int bucketCount = m_Buckets.Count(); + fprintf(pDebugFp, "\n%d Buckets\n", bucketCount); + + for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++) + { + int count = m_Buckets[ndxBucket].Count(); + + if (count > maxBucketSize) { maxBucketSize = count; } + if (count == 0) + numBucketsEmpty++; + + fprintf(pDebugFp, "Bucket %d: %d\n", ndxBucket, count); + } + + fprintf(pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty); + fprintf(pDebugFp, "Max Bucket Size: %d\n", maxBucketSize); + + fclose(pDebugFp); +} + +typedef int UtlHashFastHandle_t; + +#define UTLHASH_POOL_SCALAR 2 + +class CUtlHashFastNoHash +{ +public: + static int Hash(int key, int bucketMask) + { + return (key & bucketMask); + } +}; + +class CUtlHashFastGenericHash +{ +public: + static int Hash(int key, int bucketMask) + { + return (HashIntConventional(key) & bucketMask); + } +}; + +template +class CUtlHashFast +{ +public: + + CUtlHashFast(); + ~CUtlHashFast(); + + void Purge(void); + + static UtlHashFastHandle_t InvalidHandle(void) { return (UtlHashFastHandle_t)~0; } + + bool Init(int nBucketCount); + + int Count(void); + + UtlHashFastHandle_t Insert(unsigned int uiKey, const Data& data); + UtlHashFastHandle_t FastInsert(unsigned int uiKey, const Data& data); + + void Remove(UtlHashFastHandle_t hHash); + void RemoveAll(void); + + UtlHashFastHandle_t Find(unsigned int uiKey); + + Data& Element(UtlHashFastHandle_t hHash); + Data const& Element(UtlHashFastHandle_t hHash) const; + Data& operator[](UtlHashFastHandle_t hHash); + Data const& operator[](UtlHashFastHandle_t hHash) const; + + template + struct HashFastData_t_ + { + unsigned int m_uiKey; + HashData m_Data; + }; + + typedef HashFastData_t_ HashFastData_t; + + unsigned int m_uiBucketMask; + CUtlVector m_aBuckets; + CUtlFixedLinkedList m_aDataPool; +}; + +template CUtlHashFast::CUtlHashFast() +{ + Purge(); +} + +template CUtlHashFast::~CUtlHashFast() +{ + Purge(); +} + +template inline void CUtlHashFast::Purge(void) +{ + m_aBuckets.Purge(); + m_aDataPool.Purge(); +} + +template bool CUtlHashFast::Init(int nBucketCount) +{ + if (!IsPowerOfTwo(nBucketCount)) + return false; + + m_aBuckets.SetSize(nBucketCount); + for (int iBucket = 0; iBucket < nBucketCount; ++iBucket) + { + m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); + } + + m_uiBucketMask = nBucketCount - 1; + + int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount; + m_aDataPool.SetGrowSize(nGrowSize); + + return true; +} + +template inline int CUtlHashFast::Count(void) +{ + return m_aDataPool.Count(); +} + +template inline UtlHashFastHandle_t CUtlHashFast::Insert(unsigned int uiKey, const Data& data) +{ + UtlHashFastHandle_t hHash = Find(uiKey); + if (hHash != InvalidHandle()) + return hHash; + + return FastInsert(uiKey, data); +} + +template inline UtlHashFastHandle_t CUtlHashFast::FastInsert(unsigned int uiKey, const Data& data) +{ + int iHashData = m_aDataPool.Alloc(true); + HashFastData_t* pHashData = &m_aDataPool[iHashData]; + if (!pHashData) + return InvalidHandle(); + + pHashData->m_uiKey = uiKey; + pHashData->m_Data = data; + + int iBucket = HashFuncs::Hash(uiKey, m_uiBucketMask); + m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData); + m_aBuckets[iBucket] = iHashData; + + return iHashData; +} + +template inline void CUtlHashFast::Remove(UtlHashFastHandle_t hHash) +{ + int iBucket = HashFuncs::Hash(m_aDataPool[hHash].m_uiKey, m_uiBucketMask); + if (m_aBuckets[iBucket] == hHash) + { + m_aBuckets[iBucket] = m_aDataPool.Next(hHash); + } + else + { + m_aDataPool.Unlink(hHash); + } + + m_aDataPool.Remove(hHash); +} + +template inline void CUtlHashFast::RemoveAll(void) +{ + m_aBuckets.RemoveAll(); + m_aDataPool.RemoveAll(); +} + +template inline UtlHashFastHandle_t CUtlHashFast::Find(unsigned int uiKey) +{ + int iBucket = HashFuncs::Hash(uiKey, m_uiBucketMask); + + for (int iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) + { + if (m_aDataPool[iElement].m_uiKey == uiKey) + return iElement; + } + + return InvalidHandle(); +} + +template inline Data& CUtlHashFast::Element(UtlHashFastHandle_t hHash) +{ + return (m_aDataPool[hHash].m_Data); +} + +template inline Data const& CUtlHashFast::Element(UtlHashFastHandle_t hHash) const +{ + return (m_aDataPool[hHash].m_Data); +} + +template inline Data& CUtlHashFast::operator[](UtlHashFastHandle_t hHash) +{ + return (m_aDataPool[hHash].m_Data); +} + +template inline Data const& CUtlHashFast::operator[](UtlHashFastHandle_t hHash) const +{ + return (m_aDataPool[hHash].m_Data); +} + +typedef int UtlHashFixedHandle_t; + +template +class CUtlHashFixedGenericHash +{ +public: + static int Hash(int key, int bucketMask) + { + int hash = HashIntConventional(key); + if (NUM_BUCKETS <= USHRT_MAX) + { + hash ^= (hash >> 16); + } + if (NUM_BUCKETS <= UCHAR_MAX) + { + hash ^= (hash >> 8); + } + return (hash & bucketMask); + } +}; + +template +class CUtlHashFixed +{ +public: + + CUtlHashFixed(); + ~CUtlHashFixed(); + + void Purge(void); + + static UtlHashFixedHandle_t InvalidHandle(void) { return (UtlHashFixedHandle_t)~0; } + + int Count(void); + + UtlHashFixedHandle_t Insert(unsigned int uiKey, const Data& data); + UtlHashFixedHandle_t FastInsert(unsigned int uiKey, const Data& data); + + void Remove(UtlHashFixedHandle_t hHash); + void RemoveAll(void); + + UtlHashFixedHandle_t Find(unsigned int uiKey); + + Data& Element(UtlHashFixedHandle_t hHash); + Data const& Element(UtlHashFixedHandle_t hHash) const; + Data& operator[](UtlHashFixedHandle_t hHash); + Data const& operator[](UtlHashFixedHandle_t hHash) const; + + template + struct HashFixedData_t_ + { + unsigned int m_uiKey; + Data_t m_Data; + }; + + typedef HashFixedData_t_ HashFixedData_t; + + enum + { + BUCKET_MASK = NUM_BUCKETS - 1 + }; + CUtlPtrLinkedList m_aBuckets[NUM_BUCKETS]; + int m_nElements; +}; + +template CUtlHashFixed::CUtlHashFixed() +{ + Purge(); +} + +template CUtlHashFixed::~CUtlHashFixed() +{ + Purge(); +} + +template inline void CUtlHashFixed::Purge(void) +{ + RemoveAll(); +} + +template inline int CUtlHashFixed::Count(void) +{ + return m_nElements; +} + +template inline UtlHashFixedHandle_t CUtlHashFixed::Insert(unsigned int uiKey, const Data& data) +{ + UtlHashFixedHandle_t hHash = Find(uiKey); + if (hHash != InvalidHandle()) + return hHash; + + return FastInsert(uiKey, data); +} + +template inline UtlHashFixedHandle_t CUtlHashFixed::FastInsert(unsigned int uiKey, const Data& data) +{ + int iBucket = HashFuncs::Hash(uiKey, NUM_BUCKETS - 1); + UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead(); + + HashFixedData_t* pHashData = &m_aBuckets[iBucket][iElem]; + + Assert((UtlPtrLinkedListIndex_t)pHashData == iElem); + + pHashData->m_uiKey = uiKey; + pHashData->m_Data = data; + + m_nElements++; + return (UtlHashFixedHandle_t)pHashData; +} + +template inline void CUtlHashFixed::Remove(UtlHashFixedHandle_t hHash) +{ + HashFixedData_t* pHashData = (HashFixedData_t*)hHash; + Assert(Find(pHashData->m_uiKey) != InvalidHandle()); + int iBucket = HashFuncs::Hash(pHashData->m_uiKey, NUM_BUCKETS - 1); + m_aBuckets[iBucket].Remove((UtlPtrLinkedListIndex_t)pHashData); + m_nElements--; +} + +template inline void CUtlHashFixed::RemoveAll(void) +{ + for (int i = 0; i < NUM_BUCKETS; i++) + { + m_aBuckets[i].RemoveAll(); + } + m_nElements = 0; +} + +template inline UtlHashFixedHandle_t CUtlHashFixed::Find(unsigned int uiKey) +{ + int iBucket = HashFuncs::Hash(uiKey, NUM_BUCKETS - 1); + CUtlPtrLinkedList& bucket = m_aBuckets[iBucket]; + + for (UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next(iElement)) + { + if (bucket[iElement].m_uiKey == uiKey) + return (UtlHashFixedHandle_t)iElement; + } + + return InvalidHandle(); +} + +template inline Data& CUtlHashFixed::Element(UtlHashFixedHandle_t hHash) +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +template inline Data const& CUtlHashFixed::Element(UtlHashFixedHandle_t hHash) const +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +template inline Data& CUtlHashFixed::operator[](UtlHashFixedHandle_t hHash) +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +template inline Data const& CUtlHashFixed::operator[](UtlHashFixedHandle_t hHash) const +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +#endif +``` + +`SpyCustom/sdk/utlintrusivelist.h`: + +```h +#ifndef UTILINTRUSIVELIST_H +#define UTILINTRUSIVELIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "utlmemory.h" +#include "dbg.h" + + + +namespace IntrusiveList +{ +#ifdef SUPERSLOW_DEBUG_VERSION + template inline void ValidateDList(T* head) + { + if (head) + { + Assert(head->m_pPrev == 0); + } + while (head) + { + if (head->m_pNext) + { + Assert(head->m_pNext->m_pPrev == head); + } + if (head->m_pPrev) + { + Assert(head->m_pPrev->m_pNext == head); + } + head = head->m_pNext; + } + } +#else + template inline void ValidateDList(T* ) + { + } +#endif + + + + template inline void MoveDNodeBackwards(T* which, T*& head) + { + if (which->m_pPrev) + { + T* p = which->m_pPrev; + T* pp = p->m_pPrev; + T* n = which->m_pNext; + Assert(p->m_pNext == which); + if (n) + { + Assert(n->m_pPrev == which); + n->m_pPrev = p; + } + if (pp) + { + Assert(pp->m_pNext == p); + pp->m_pNext = which; + } + else + { + head = which; + } + which->m_pNext = p; + which->m_pPrev = pp; + p->m_pNext = n; + p->m_pPrev = which; + } + ValidateDList(head); + } + + + + template inline void RemoveFromDList(T*& head, T* which) + { + if (which->m_pPrev) + { + Assert(which->m_pPrev->m_pNext == which); + which->m_pPrev->m_pNext = which->m_pNext; + if (which->m_pNext) + { + Assert(which->m_pNext->m_pPrev == which); + which->m_pNext->m_pPrev = which->m_pPrev; + } + } + else + { + if (head == which) + { + head = which->m_pNext; + if (head) + { + Assert(head->m_pPrev == which); + head->m_pPrev = 0; + } + } + } + which->m_pNext = which->m_pPrev = 0; + ValidateDList(head); + + } + + template bool OnDList(T const* head, T const* which) + { + return (head == which) || (which->m_pNext != 0) || (which->m_pPrev != 0); + } + + template void AddToDTail(T*& head, T* node) + { + node->m_pNext = 0; + if (!head) + { + head = node; + } + else + { + T* ptr = head; + while (ptr->m_pNext) + { + ptr = ptr->m_pNext; + } + ptr->m_pNext = node; + node->m_pPrev = ptr; + } + } + + template inline void AddToDHead(T*& head, T* which) + { + which->m_pNext = head; + if (head) + { + head->m_pPrev = which; + } + which->m_pPrev = 0; + head = which; + ValidateDList(head); + } + + template inline void AddToDHeadWithTailPtr(T*& head, T* which, T*& tailptr) + { + which->m_pNext = head; + if (head) + { + head->m_pPrev = which; + } + else + { + tailptr = which; + } + which->m_pPrev = 0; + head = which; + ValidateDList(head); + } + + template inline void AddToDTailWithTailPtr(T*& head, T* which, T*& tailptr) + { + if (!tailptr) + { + Assert(!head); + which->m_pPrev = which->m_pNext = 0; + tailptr = head = which; + } + else + { + which->m_pNext = 0; + which->m_pPrev = tailptr; + tailptr->m_pNext = which; + tailptr = which; + } + ValidateDList(head); + } + + template inline void RemoveFromDListWithTailPtr(T*& head, T* which, T*& tailptr) + { + if (which == tailptr) + { + tailptr = which->m_pPrev; + } + if (which->m_pPrev) + { + Assert(which->m_pPrev->m_pNext == which); + which->m_pPrev->m_pNext = which->m_pNext; + if (which->m_pNext) + { + Assert(which->m_pNext->m_pPrev == which); + which->m_pNext->m_pPrev = which->m_pPrev; + } + } + else + { + if (head == which) + { + head = which->m_pNext; + if (head) + { + Assert(head->m_pPrev == which); + head->m_pPrev = 0; + } + } + } + which->m_pNext = which->m_pPrev = 0; + ValidateDList(head); + + } + + template inline void DeleteFromDListWithTailPtr(T*& head, T* which, T*& tailptr) + { + T* tmp = which; + if (which == tailptr) + { + tailptr = which->m_pPrev; + } + if (which->m_pPrev) + { + Assert(which->m_pPrev->m_pNext == which); + which->m_pPrev->m_pNext = which->m_pNext; + if (which->m_pNext) + { + Assert(which->m_pNext->m_pPrev == which); + which->m_pNext->m_pPrev = which->m_pPrev; + } + } + else + { + if (head == which) + { + head = which->m_pNext; + if (head) + { + Assert(head->m_pPrev == which); + head->m_pPrev = 0; + } + } + } + which->m_pNext = which->m_pPrev = 0; + delete tmp; + ValidateDList(head); + } + + template inline void AddToDPriority(T*& head, T* which) + { + T* prevnode = 0; + for (T* curnode = head; curnode; curnode = curnode->m_pNext) + { + if (which->m_Priority >= curnode->m_Priority) + break; + prevnode = curnode; + } + if (!prevnode) + { + AddToDHead(head, which); + } + else + { + which->m_pNext = prevnode->m_pNext; + prevnode->m_pNext = which; + which->m_pPrev = prevnode; + if (which->m_pNext) + which->m_pNext->m_pPrev = which; + } + } + + template inline void AddToDPriorityLowestFirst(T*& head, T* which) + { + T* prevnode = 0; + for (T* curnode = head; curnode; curnode = curnode->m_pNext) + { + if (which->m_Priority <= curnode->m_Priority) + break; + prevnode = curnode; + } + if (!prevnode) + { + AddToDHead(head, which); + } + else + { + which->m_pNext = prevnode->m_pNext; + prevnode->m_pNext = which; + which->m_pPrev = prevnode; + if (which->m_pNext) + which->m_pNext->m_pPrev = which; + } + } + + + template T* LastNode(T* head) + { + if (head) + { + while (head->m_pNext) + { + head = head->m_pNext; + } + } + return head; + } + + + template void RemoveFromList(T*& head, V* which) + { + if (head == which) + { + head = which->m_pNext; + } + else + { + for (T* i = head; i; i = i->m_pNext) + { + if (i->m_pNext == which) + { + i->m_pNext = which->m_pNext; + return; + } + } + } + } + + template void DeleteFromList(T*& head, V* which) + { + T* tmp; + if (head == which) + { + tmp = which->m_pNext; + delete(head); + head = tmp; + } + else + { + for (T* i = head; i; i = i->m_pNext) + { + if (i->m_pNext == which) + { + tmp = which->m_pNext; + delete(which); + i->m_pNext = tmp; + return; + } + } + } + } + + template int PositionInList(T* head, V* node) + { + int pos = 0; + while (head) + { + if (head == node) return pos; + head = head->m_pNext; + pos++; + } + return -1; + } + + template T* NthNode(T* head, int idx) + { + while (idx && head) + { + idx--; + head = head->m_pNext; + } + return head; + } + + template static inline void AddToHead(T*& head, V* node) + { + node->m_pNext = head; + head = node; + } + + template static inline void AddToTail(T*& head, V* node) + { + node->m_pNext = NULL; + if (!head) + head = node; + else + { + T* pLastNode = head; + while (pLastNode->m_pNext) + pLastNode = pLastNode->m_pNext; + pLastNode->m_pNext = node; + } + } + + template static inline void AddToHead(T*& head, T*& tail, V* node) + { + if (!head) + { + tail = node; + } + node->m_pNext = head; + head = node; + } + + + + template static inline T* PrevNode(T* head, T* node) + { + T* i; + for (i = head; i; i = i->m_pNext) + { + if (i->m_pNext == node) + break; + } + return i; + } + + + template void AddToEnd(T*& head, V* node) + { + node->m_pNext = 0; + if (!head) + { + head = node; + } + else + { + T* ptr = head; + while (ptr->m_pNext) + { + ptr = ptr->m_pNext; + } + ptr->m_pNext = node; + } + } + + template void AddToEndWithTail(T*& head, T*& tail, V* node) + { + Assert((head && tail) || ((!head) && (!tail))); + node->m_pNext = 0; + if (!head) + { + head = tail = node; + } + else + { + tail->m_pNext = node; + tail = node; + } + } + + template void AddSortedByName(T*& head, T* node) + { + if ((!head) || + (stricmp(node->m_Name, head->m_Name) == -1)) + { + node->m_pNext = head; + head = node; + } + else + { + T* t; + for (t = head; t->m_pNext; t = t->m_pNext) + if (stricmp(t->m_pNext->m_Name, node->m_Name) >= 0) + break; + node->m_pNext = t->m_pNext; + t->m_pNext = node; + } + } + + template int ListLength(T* head) + { + int len = 0; + while (head) + { + len++; + head = head->m_pNext; + } + return len; + } + + template void KillList(T*& head) + { + while (head) + { + delete head; + } + } + + + template void DeleteList(T*& head) + { + while (head) + { + T* tmp = head->m_pNext; + delete head; + head = tmp; + } + } + + template static inline T* FindNamedNode(T* head, char const* name) + { + for (; head && stricmp(head->m_Name, name); head = head->m_pNext) + { + } + return head; + } + + template static inline T* FindNamedNodeCaseSensitive(T* head, char const* name) + { + for (; head && strcmp(head->m_Name, name); head = head->m_pNext) + { + } + return head; + } + + template static inline T* FindNodeByField(T* head, U data, U V::* field) + { + while (head) + { + if (data == (*head).*field) + return head; + head = head->m_pNext; + } + return 0; + } + + template static inline T* FindNodeByFieldWithPrev(T* head, U data, U V::* field, T*& prev) + { + prev = 0; + for (T* i = head; i; i = i->m_pNext) + { + if (data == (*i).*field) + return i; + prev = i; + } + prev = 0; + return 0; + } + + + template void SortList(T*& head, int (*comparefn)(T* a, T* b)) + { + int didswap = 1; + while (didswap) + { + didswap = 0; + T* prev = 0; + for (T* i = head; i && i->m_pNext; i = i->m_pNext) + { + int rslt = (*comparefn)(i, i->m_pNext); + if (rslt == -1) + { + didswap = 1; + T* newfirst = i->m_pNext; + if (prev) + { + prev->m_pNext = newfirst; + i->m_pNext = newfirst->m_pNext; + newfirst->m_pNext = i; + } + else + { + head = i->m_pNext; + i->m_pNext = newfirst->m_pNext; + newfirst->m_pNext = i; + } + i = newfirst; + } + prev = i; + } + } + } + + template void SortDList(T*& head, int (*comparefn)(T* a, T* b)) + { + SortList(head, comparefn); + T* prev = 0; + for (T* i = head; i; i = i->m_pNext) + { + i->m_pPrev = prev; + prev = i; + } + } + + template T* ReversedList(T* head) + { + T* pNewHead = NULL; + while (head) + { + T* pNext = head->m_pNext; +#ifdef INTERVIEW_QUESTION + head->m_pNext = pNewHead; + pNewHead = head; +#else + AddToHead(pNewHead, head); +#endif + head = pNext; + } + return pNewHead; + } +}; + +template class CUtlIntrusiveList +{ +public: + T* m_pHead; + + FORCEINLINE T* Head(void) const + { + return m_pHead; + } + + FORCEINLINE CUtlIntrusiveList(void) + { + m_pHead = NULL; + } + + + FORCEINLINE void RemoveAll(void) + { + m_pHead = NULL; + } + FORCEINLINE void AddToHead(T* node) + { + IntrusiveList::AddToHead(m_pHead, node); + } + + FORCEINLINE void AddToTail(T* node) + { + IntrusiveList::AddToTail(m_pHead, node); + } + + void RemoveNode(T* which) + { + IntrusiveList::RemoveFromList(m_pHead, which); + } + + void KillList(void) + { + while (m_pHead) + { + delete m_pHead; + } + } + + + T* PrevNode(T* node) + { + return IntrusiveList::PrevNode(m_pHead, node); + } + + int NthNode(int n) + { + return NthNode(m_pHead, n); + } + + void Purge(void) + { + while (m_pHead) + { + T* tmp = m_pHead->m_pNext; + delete m_pHead; + m_pHead = tmp; + } + } + + int Count(void) const + { + return IntrusiveList::ListLength(m_pHead); + } + + FORCEINLINE T* FindNamedNodeCaseSensitive(char const* pName) const + { + return IntrusiveList::FindNamedNodeCaseSensitive(m_pHead, pName); + + } + + T* RemoveHead(void) + { + if (m_pHead) + { + T* pRet = m_pHead; + m_pHead = pRet->m_pNext; + return pRet; + } + else + return NULL; + } +}; + +template class CUtlIntrusiveDList : public CUtlIntrusiveList +{ +public: + + FORCEINLINE void AddToHead(T* node) + { + IntrusiveList::AddToDHead(CUtlIntrusiveList::m_pHead, node); + } + FORCEINLINE void AddToTail(T* node) + { + IntrusiveList::AddToDTail(CUtlIntrusiveList::m_pHead, node); + } + + void RemoveNode(T* which) + { + IntrusiveList::RemoveFromDList(CUtlIntrusiveList::m_pHead, which); + } + + T* RemoveHead(void) + { + if (CUtlIntrusiveList::m_pHead) + { + T* pRet = CUtlIntrusiveList::m_pHead; + CUtlIntrusiveList::m_pHead = CUtlIntrusiveList::m_pHead->m_pNext; + if (CUtlIntrusiveList::m_pHead) + CUtlIntrusiveList::m_pHead->m_pPrev = NULL; + return pRet; + } + else + return NULL; + } + + T* PrevNode(T* node) + { + return (node) ? node->m_Prev : NULL; + } + +}; + +template class CUtlIntrusiveDListWithTailPtr : public CUtlIntrusiveDList +{ +public: + + T* m_pTailPtr; + + FORCEINLINE CUtlIntrusiveDListWithTailPtr(void) : CUtlIntrusiveDList() + { + m_pTailPtr = NULL; + } + + FORCEINLINE void AddToHead(T* node) + { + IntrusiveList::AddToDHeadWithTailPtr(CUtlIntrusiveList::m_pHead, node, m_pTailPtr); + } + FORCEINLINE void AddToTail(T* node) + { + IntrusiveList::AddToDTailWithTailPtr(CUtlIntrusiveList::m_pHead, node, m_pTailPtr); + } + + void RemoveNode(T* pWhich) + { + IntrusiveList::RemoveFromDListWithTailPtr(CUtlIntrusiveList::m_pHead, pWhich, m_pTailPtr); + } + + void Purge(void) + { + CUtlIntrusiveList::Purge(); + m_pTailPtr = NULL; + } + + void Kill(void) + { + CUtlIntrusiveList::Purge(); + m_pTailPtr = NULL; + } + + T* RemoveHead(void) + { + if (CUtlIntrusiveDList::m_pHead) + { + T* pRet = CUtlIntrusiveDList::m_pHead; + CUtlIntrusiveDList::m_pHead = CUtlIntrusiveDList::m_pHead->m_pNext; + if (CUtlIntrusiveDList::m_pHead) + CUtlIntrusiveDList::m_pHead->m_pPrev = NULL; + if (!CUtlIntrusiveDList::m_pHead) + m_pTailPtr = NULL; + ValidateDList(CUtlIntrusiveDList::m_pHead); + return pRet; + } + else + return NULL; + } + + T* PrevNode(T* node) + { + return (node) ? node->m_Prev : NULL; + } + +}; + +template void PrependDListWithTailToDList(CUtlIntrusiveDListWithTailPtr& src, + CUtlIntrusiveDList& dest) +{ + if (src.m_pHead) + { + src.m_pTailPtr->m_pNext = dest.m_pHead; + if (dest.m_pHead) + dest.m_pHead->m_pPrev = src.m_pTailPtr; + dest.m_pHead = src.m_pHead; + IntrusiveList::ValidateDList(dest.m_pHead); + } +} + +#endif +``` + +`SpyCustom/sdk/utllinkedlist.h`: + +```h +#ifndef UTLLINKEDLIST_H +#define UTLLINKEDLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" +#include "utlmemory.h" +#include "utlfixedmemory.h" +#include "utlblockmemory.h" +#include "dbg.h" + +#define FOR_EACH_LL( listName, iteratorName ) \ + for( int iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) ) + +template +struct UtlLinkedListElem_t +{ + T m_Element; + I m_Previous; + I m_Next; + +private: + UtlLinkedListElem_t(const UtlLinkedListElem_t&); +}; + + +template , I > > +class CUtlLinkedList +{ +public: + typedef T ElemType_t; + typedef S IndexType_t; + typedef I IndexLocalType_t; + typedef M MemoryAllocator_t; + static const bool IsUtlLinkedList = true; + + CUtlLinkedList(int growSize = 0, int initSize = 0); + ~CUtlLinkedList(); + + T& Element(I i); + T const& Element(I i) const; + T& operator[](I i); + T const& operator[](I i) const; + + void EnsureCapacity(int num); + + void SetGrowSize(int growSize); + + void Purge(); + + void PurgeAndDeleteElements(); + + I InsertBefore(I before); + I InsertAfter(I after); + I AddToHead(); + I AddToTail(); + + I InsertBefore(I before, T const& src); + I InsertAfter(I after, T const& src); + I AddToHead(T const& src); + I AddToTail(T const& src); + + I Find(const T& src) const; + + bool FindAndRemove(const T& src); + + void Remove(I elem); + void RemoveAll(); + + I Alloc(bool multilist = false); + void Free(I elem); + + void LinkBefore(I before, I elem); + void LinkAfter(I after, I elem); + void Unlink(I elem); + void LinkToHead(I elem); + void LinkToTail(I elem); + + inline static S InvalidIndex() { return (S)M::InvalidIndex(); } + + static bool IndexInRange(I index); + + inline static size_t ElementSize() { return sizeof(ListElem_t); } + + int Count() const; + I MaxElementIndex() const; + I NumAllocated(void) const { return m_NumAlloced; } + + I Head() const; + I Tail() const; + I Previous(I i) const; + I Next(I i) const; + + template < typename List_t > + class _CUtlLinkedList_constiterator_t + { + public: + typedef typename List_t::ElemType_t ElemType_t; + typedef typename List_t::IndexType_t IndexType_t; + + _CUtlLinkedList_constiterator_t() + : m_list(0) + , m_index(List_t::InvalidIndex()) + { + } + _CUtlLinkedList_constiterator_t(const List_t& list, IndexType_t index) + : m_list(&list) + , m_index(index) + { + } + + _CUtlLinkedList_constiterator_t& operator++() + { + m_index = m_list->Next(m_index); + return *this; + } + _CUtlLinkedList_constiterator_t operator++(int) + { + _CUtlLinkedList_constiterator_t temp = *this; + ++* this; + return temp; + } + + _CUtlLinkedList_constiterator_t& operator--() + { + Assert(m_index != m_list->Head()); + if (m_index == m_list->InvalidIndex()) + { + m_index = m_list->Tail(); + } + else + { + m_index = m_list->Previous(m_index); + } + return *this; + } + _CUtlLinkedList_constiterator_t operator--(int) + { + _CUtlLinkedList_constiterator_t temp = *this; + --* this; + return temp; + } + + bool operator==(const _CUtlLinkedList_constiterator_t& other) const + { + Assert(m_list == other.m_list); + return m_index == other.m_index; + } + + bool operator!=(const _CUtlLinkedList_constiterator_t& other) const + { + Assert(m_list == other.m_list); + return m_index != other.m_index; + } + + const ElemType_t& operator*() const + { + return m_list->Element(m_index); + } + + const ElemType_t* operator->() const + { + return (&**this); + } + + protected: + const List_t* m_list; + IndexType_t m_index; + }; + + template < typename List_t > + class _CUtlLinkedList_iterator_t : public _CUtlLinkedList_constiterator_t< List_t > + { + public: + typedef typename List_t::ElemType_t ElemType_t; + typedef typename List_t::IndexType_t IndexType_t; + typedef _CUtlLinkedList_constiterator_t< List_t > Base; + + _CUtlLinkedList_iterator_t() + { + } + _CUtlLinkedList_iterator_t(const List_t& list, IndexType_t index) + : _CUtlLinkedList_constiterator_t< List_t >(list, index) + { + } + + _CUtlLinkedList_iterator_t& operator++() + { + Base::m_index = Base::m_list->Next(Base::m_index); + return *this; + } + _CUtlLinkedList_iterator_t operator++(int) + { + _CUtlLinkedList_iterator_t temp = *this; + ++* this; + return temp; + } + + _CUtlLinkedList_iterator_t& operator--() + { + Assert(Base::m_index != Base::m_list->Head()); + if (Base::m_index == Base::m_list->InvalidIndex()) + { + Base::m_index = Base::m_list->Tail(); + } + else + { + Base::m_index = Base::m_list->Previous(Base::m_index); + } + return *this; + } + _CUtlLinkedList_iterator_t operator--(int) + { + _CUtlLinkedList_iterator_t temp = *this; + --* this; + return temp; + } + + ElemType_t& operator*() const + { + List_t* pMutableList = const_cast(Base::m_list); + return pMutableList->Element(Base::m_index); + } + + ElemType_t* operator->() const + { + return (&**this); + } + }; + + typedef _CUtlLinkedList_constiterator_t > const_iterator; + typedef _CUtlLinkedList_iterator_t > iterator; + const_iterator begin() const + { + return const_iterator(*this, Head()); + } + iterator begin() + { + return iterator(*this, Head()); + } + + const_iterator end() const + { + return const_iterator(*this, InvalidIndex()); + } + iterator end() + { + return iterator(*this, InvalidIndex()); + } + + bool IsValidIndex(I i) const; + bool IsInList(I i) const; + +protected: + + typedef UtlLinkedListElem_t ListElem_t; + + I AllocInternal(bool multilist = false); + void ConstructList(); + + ListElem_t& InternalElement(I i) { return m_Memory[i]; } + ListElem_t const& InternalElement(I i) const { return m_Memory[i]; } + + CUtlLinkedList(CUtlLinkedList const& list) { Assert(0); } + + M m_Memory; + I m_Head; + I m_Tail; + I m_FirstFree; + I m_ElementCount; + I m_NumAlloced; + typename M::Iterator_t m_LastAlloc; + + ListElem_t* m_pElements; + + FORCEINLINE M const& Memory(void) const + { + return m_Memory; + } + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + } + +private: + I PrivateNext(I i) const; +}; + + +template < class T > +class CUtlFixedLinkedList : public CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > +{ +public: + CUtlFixedLinkedList(int growSize = 0, int initSize = 0) + : CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >(growSize, initSize) {} + + typedef CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > BaseClass; + bool IsValidIndex(int i) const + { + if (!BaseClass::Memory().IsIdxValid(i)) + return false; + +#ifdef _DEBUG + if (BaseClass::Memory().IsIdxAfter(i, this->m_LastAlloc)) + { + Assert(0); + return false; + } +#endif + + return (BaseClass::Memory()[i].m_Previous != i) || (BaseClass::Memory()[i].m_Next == i); + } + +private: + int MaxElementIndex() const { Assert(0); return BaseClass::InvalidIndex(); } + void ResetDbgInfo() {} +}; + +template < class T, class I = unsigned short > +class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > > +{ +public: + CUtlBlockLinkedList(int growSize = 0, int initSize = 0) + : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >(growSize, initSize) {} +protected: + void ResetDbgInfo() {} +}; + + +template +CUtlLinkedList::CUtlLinkedList(int growSize, int initSize) : + m_Memory(growSize, initSize), m_LastAlloc(m_Memory.InvalidIterator()) +{ + COMPILE_TIME_ASSERT(sizeof(S) == 4 || (((S)-1) > 0)); + ConstructList(); + ResetDbgInfo(); +} + +template +CUtlLinkedList::~CUtlLinkedList() +{ + RemoveAll(); +} + +template +void CUtlLinkedList::ConstructList() +{ + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_FirstFree = InvalidIndex(); + m_ElementCount = 0; + m_NumAlloced = 0; +} + + +template +inline T& CUtlLinkedList::Element(I i) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlLinkedList::Element(I i) const +{ + return m_Memory[i].m_Element; +} + +template +inline T& CUtlLinkedList::operator[](I i) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlLinkedList::operator[](I i) const +{ + return m_Memory[i].m_Element; +} + +template +inline int CUtlLinkedList::Count() const +{ +#ifdef MULTILIST_PEDANTIC_ASSERTS + AssertMsg(!ML, "CUtlLinkedList::Count() is meaningless for linked lists."); +#endif + return m_ElementCount; +} + +template +inline I CUtlLinkedList::MaxElementIndex() const +{ + return m_Memory.NumAllocated(); +} + + +template +inline I CUtlLinkedList::Head() const +{ + return m_Head; +} + +template +inline I CUtlLinkedList::Tail() const +{ + return m_Tail; +} + +template +inline I CUtlLinkedList::Previous(I i) const +{ + Assert(IsValidIndex(i)); + return InternalElement(i).m_Previous; +} + +template +inline I CUtlLinkedList::Next(I i) const +{ + Assert(IsValidIndex(i)); + return InternalElement(i).m_Next; +} + +template +inline I CUtlLinkedList::PrivateNext(I i) const +{ + return InternalElement(i).m_Next; +} + + +#pragma warning(push) +#pragma warning( disable: 4310 ) +template +inline bool CUtlLinkedList::IndexInRange(I index) +{ + COMPILE_TIME_ASSERT(sizeof(I) >= sizeof(S)); + COMPILE_TIME_ASSERT((sizeof(S) > 2) || (((S)-1) > 0)); + COMPILE_TIME_ASSERT((M::INVALID_INDEX == -1) || (M::INVALID_INDEX == (S)M::INVALID_INDEX)); + + return (((S)index == index) && ((S)index != InvalidIndex())); +} +#pragma warning(pop) + +template +inline bool CUtlLinkedList::IsValidIndex(I i) const +{ + if (!m_Memory.IsIdxValid(i)) + return false; + + if (m_Memory.IsIdxAfter(i, m_LastAlloc)) + return false; + + return (m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i); +} + +template +inline bool CUtlLinkedList::IsInList(I i) const +{ + if (!m_Memory.IsIdxValid(i) || m_Memory.IsIdxAfter(i, m_LastAlloc)) + return false; + + return Previous(i) != i; +} + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList::EnsureCapacity(int num) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList::SetGrowSize(int growSize) +{ + RemoveAll(); + m_Memory.Init(growSize); + ResetDbgInfo(); +} + + +template +void CUtlLinkedList::Purge() +{ + RemoveAll(); + + m_Memory.Purge(); + m_FirstFree = InvalidIndex(); + m_NumAlloced = 0; + + const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator(); + m_LastAlloc = scInvalidIterator; + ResetDbgInfo(); +} + + +template +void CUtlLinkedList::PurgeAndDeleteElements() +{ + I iNext; + for (I i = Head(); i != InvalidIndex(); i = iNext) + { + iNext = Next(i); + delete Element(i); + } + + Purge(); +} + + +template +I CUtlLinkedList::AllocInternal(bool multilist) +{ + Assert(!multilist || ML); +#ifdef MULTILIST_PEDANTIC_ASSERTS + Assert(multilist == ML); +#endif + I elem; + if (m_FirstFree == InvalidIndex()) + { + Assert(m_Memory.IsValidIterator(m_LastAlloc) || m_ElementCount == 0); + + typename M::Iterator_t it = m_Memory.IsValidIterator(m_LastAlloc) ? m_Memory.Next(m_LastAlloc) : m_Memory.First(); + + if (!m_Memory.IsValidIterator(it)) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow(); + ResetDbgInfo(); + + it = m_Memory.IsValidIterator(m_LastAlloc) ? m_Memory.Next(m_LastAlloc) : m_Memory.First(); + + Assert(m_Memory.IsValidIterator(it)); + if (!m_Memory.IsValidIterator(it)) + { + Error("CUtlLinkedList overflow! (exhausted memory allocator)\n"); + return InvalidIndex(); + } + } + + if (!IndexInRange(m_Memory.GetIndex(it))) + { + Error("CUtlLinkedList overflow! (exhausted index range)\n"); + return InvalidIndex(); + } + + m_LastAlloc = it; + elem = m_Memory.GetIndex(m_LastAlloc); + m_NumAlloced++; + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalElement(m_FirstFree).m_Next; + } + + if (!multilist) + { + InternalElement(elem).m_Next = elem; + InternalElement(elem).m_Previous = elem; + } + else + { + InternalElement(elem).m_Next = InvalidIndex(); + InternalElement(elem).m_Previous = InvalidIndex(); + } + + return elem; +} + +template +I CUtlLinkedList::Alloc(bool multilist) +{ + I elem = AllocInternal(multilist); + if (elem == InvalidIndex()) + return elem; + + Construct(&Element(elem)); + + return elem; +} + +template +void CUtlLinkedList::Free(I elem) +{ + Assert(IsValidIndex(elem) && IndexInRange(elem)); + Unlink(elem); + + ListElem_t& internalElem = InternalElement(elem); + Destruct(&internalElem.m_Element); + internalElem.m_Next = m_FirstFree; + m_FirstFree = elem; +} + +template +I CUtlLinkedList::InsertBefore(I before) +{ + I newNode = AllocInternal(); + if (newNode == InvalidIndex()) + return newNode; + + LinkBefore(before, newNode); + + Construct(&Element(newNode)); + + return newNode; +} + +template +I CUtlLinkedList::InsertAfter(I after) +{ + I newNode = AllocInternal(); + if (newNode == InvalidIndex()) + return newNode; + + LinkAfter(after, newNode); + + Construct(&Element(newNode)); + + return newNode; +} + +template +inline I CUtlLinkedList::AddToHead() +{ + return InsertAfter(InvalidIndex()); +} + +template +inline I CUtlLinkedList::AddToTail() +{ + return InsertBefore(InvalidIndex()); +} + + +template +I CUtlLinkedList::InsertBefore(I before, T const& src) +{ + I newNode = AllocInternal(); + if (newNode == InvalidIndex()) + return newNode; + + LinkBefore(before, newNode); + + CopyConstruct(&Element(newNode), src); + + return newNode; +} + +template +I CUtlLinkedList::InsertAfter(I after, T const& src) +{ + I newNode = AllocInternal(); + if (newNode == InvalidIndex()) + return newNode; + + LinkAfter(after, newNode); + + CopyConstruct(&Element(newNode), src); + + return newNode; +} + +template +inline I CUtlLinkedList::AddToHead(T const& src) +{ + return InsertAfter(InvalidIndex(), src); +} + +template +inline I CUtlLinkedList::AddToTail(T const& src) +{ + return InsertBefore(InvalidIndex(), src); +} + + +template +I CUtlLinkedList::Find(const T& src) const +{ + I invalidIndex = InvalidIndex(); + for (I i = Head(); i != invalidIndex; i = PrivateNext(i)) + { + if (Element(i) == src) + return i; + } + return InvalidIndex(); +} + + +template +bool CUtlLinkedList::FindAndRemove(const T& src) +{ + I i = Find(src); + if (i == InvalidIndex()) + { + return false; + } + else + { + Remove(i); + return true; + } +} + + +template +void CUtlLinkedList::Remove(I elem) +{ + Free(elem); +} + +template +void CUtlLinkedList::RemoveAll() +{ + if (m_LastAlloc == m_Memory.InvalidIterator()) + { + Assert(m_Head == InvalidIndex()); + Assert(m_Tail == InvalidIndex()); + Assert(m_FirstFree == InvalidIndex()); + Assert(m_ElementCount == 0); + return; + } + + if (ML) + { + for (typename M::Iterator_t it = m_Memory.First(); it != m_Memory.InvalidIterator(); it = m_Memory.Next(it)) + { + I i = m_Memory.GetIndex(it); + if (IsValidIndex(i)) + { + ListElem_t& internalElem = InternalElement(i); + Destruct(&internalElem.m_Element); + internalElem.m_Previous = i; + internalElem.m_Next = m_FirstFree; + m_FirstFree = i; + } + + if (it == m_LastAlloc) + break; + } + } + else + { + I i = Head(); + I next; + while (i != InvalidIndex()) + { + next = Next(i); + ListElem_t& internalElem = InternalElement(i); + Destruct(&internalElem.m_Element); + internalElem.m_Previous = i; + internalElem.m_Next = next == InvalidIndex() ? m_FirstFree : next; + i = next; + } + if (Head() != InvalidIndex()) + { + m_FirstFree = Head(); + } + } + + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_ElementCount = 0; +} + + +template +void CUtlLinkedList::LinkBefore(I before, I elem) +{ + Assert(IsValidIndex(elem)); + + Unlink(elem); + + ListElem_t* RESTRICT pNewElem = &InternalElement(elem); + + pNewElem->m_Next = before; + + S newElem_mPrevious; + if (before == InvalidIndex()) + { + newElem_mPrevious = m_Tail; + pNewElem->m_Previous = m_Tail; + m_Tail = elem; + } + else + { + Assert(IsInList(before)); + ListElem_t* RESTRICT beforeElem = &InternalElement(before); + pNewElem->m_Previous = newElem_mPrevious = beforeElem->m_Previous; + beforeElem->m_Previous = elem; + } + + if (newElem_mPrevious == InvalidIndex()) + m_Head = elem; + else + InternalElement(newElem_mPrevious).m_Next = elem; + + ++m_ElementCount; +} + +template +void CUtlLinkedList::LinkAfter(I after, I elem) +{ + Assert(IsValidIndex(elem)); + + if (IsInList(elem)) + Unlink(elem); + + ListElem_t& newElem = InternalElement(elem); + + newElem.m_Previous = after; + if (after == InvalidIndex()) + { + newElem.m_Next = m_Head; + m_Head = elem; + } + else + { + Assert(IsInList(after)); + ListElem_t& afterElem = InternalElement(after); + newElem.m_Next = afterElem.m_Next; + afterElem.m_Next = elem; + } + + if (newElem.m_Next == InvalidIndex()) + m_Tail = elem; + else + InternalElement(newElem.m_Next).m_Previous = elem; + + ++m_ElementCount; +} + +template +void CUtlLinkedList::Unlink(I elem) +{ + Assert(IsValidIndex(elem)); + if (IsInList(elem)) + { + ListElem_t* RESTRICT pOldElem = &m_Memory[elem]; + + if (pOldElem->m_Previous != InvalidIndex()) + { + m_Memory[pOldElem->m_Previous].m_Next = pOldElem->m_Next; + } + else + { + m_Head = pOldElem->m_Next; + } + + if (pOldElem->m_Next != InvalidIndex()) + { + m_Memory[pOldElem->m_Next].m_Previous = pOldElem->m_Previous; + } + else + { + m_Tail = pOldElem->m_Previous; + } + + pOldElem->m_Previous = pOldElem->m_Next = elem; + + --m_ElementCount; + } +} + +template +inline void CUtlLinkedList::LinkToHead(I elem) +{ + LinkAfter(InvalidIndex(), elem); +} + +template +inline void CUtlLinkedList::LinkToTail(I elem) +{ + LinkBefore(InvalidIndex(), elem); +} + + +DECLARE_POINTER_HANDLE(UtlPtrLinkedListIndex_t); + +template < typename T > +class CUtlPtrLinkedList +{ +public: + CUtlPtrLinkedList() + : m_pFirst(NULL), + m_nElems(0) + { + COMPILE_TIME_ASSERT(sizeof(IndexType_t) == sizeof(Node_t*)); + } + + ~CUtlPtrLinkedList() + { + RemoveAll(); + } + + typedef UtlPtrLinkedListIndex_t IndexType_t; + + T& operator[](IndexType_t i) + { + return ((Node_t*)i)->elem; + } + + const T& operator[](IndexType_t i) const + { + return ((Node_t*)i)->elem; + } + + IndexType_t AddToTail() + { + return DoInsertBefore((IndexType_t)m_pFirst, NULL); + } + + IndexType_t AddToTail(T const& src) + { + return DoInsertBefore((IndexType_t)m_pFirst, &src); + } + + IndexType_t AddToHead() + { + IndexType_t result = DoInsertBefore((IndexType_t)m_pFirst, NULL); + m_pFirst = ((Node_t*)result); + return result; + } + + IndexType_t AddToHead(T const& src) + { + IndexType_t result = DoInsertBefore((IndexType_t)m_pFirst, &src); + m_pFirst = ((Node_t*)result); + return result; + } + + IndexType_t InsertBefore(IndexType_t before) + { + return DoInsertBefore(before, NULL); + } + + IndexType_t InsertAfter(IndexType_t after) + { + Node_t* pBefore = ((Node_t*)after)->next; + return DoInsertBefore(pBefore, NULL); + } + + IndexType_t InsertBefore(IndexType_t before, T const& src) + { + return DoInsertBefore(before, &src); + } + + IndexType_t InsertAfter(IndexType_t after, T const& src) + { + Node_t* pBefore = ((Node_t*)after)->next; + return DoInsertBefore(pBefore, &src); + } + + void Remove(IndexType_t elem) + { + Node_t* p = (Node_t*)elem; + + if (p->pNext == p) + { + m_pFirst = NULL; + } + else + { + if (m_pFirst == p) + { + m_pFirst = p->pNext; + } + p->pNext->pPrev = p->pPrev; + p->pPrev->pNext = p->pNext; + } + + delete p; + m_nElems--; + } + + void RemoveAll() + { + Node_t* p = m_pFirst; + if (p) + { + do + { + Node_t* pNext = p->pNext; + delete p; + p = pNext; + } while (p != m_pFirst); + } + + m_pFirst = NULL; + m_nElems = 0; + } + + int Count() const + { + return m_nElems; + } + + IndexType_t Head() const + { + return (IndexType_t)m_pFirst; + } + + IndexType_t Next(IndexType_t i) const + { + Node_t* p = ((Node_t*)i)->pNext; + if (p != m_pFirst) + { + return (IndexType_t)p; + } + return NULL; + } + + bool IsValidIndex(IndexType_t i) const + { + Node_t* p = ((Node_t*)i); + return (p && p->pNext && p->pPrev); + } + + inline static IndexType_t InvalidIndex() + { + return NULL; + } +private: + + struct Node_t + { + Node_t() {} + Node_t(const T& _elem) : elem(_elem) {} + + T elem; + Node_t* pPrev, * pNext; + }; + + Node_t* AllocNode(const T* pCopyFrom) + { + MEM_ALLOC_CREDIT_CLASS(); + Node_t* p; + + if (!pCopyFrom) + { + p = new Node_t; + } + else + { + p = new Node_t(*pCopyFrom); + } + + return p; + } + + IndexType_t DoInsertBefore(IndexType_t before, const T* pCopyFrom) + { + Node_t* p = AllocNode(pCopyFrom); + Node_t* pBefore = (Node_t*)before; + if (pBefore) + { + p->pNext = pBefore; + p->pPrev = pBefore->pPrev; + pBefore->pPrev = p; + p->pPrev->pNext = p; + } + else + { + Assert(!m_pFirst); + m_pFirst = p->pNext = p->pPrev = p; + } + + m_nElems++; + return (IndexType_t)p; + } + + Node_t* m_pFirst; + unsigned m_nElems; +}; + +#endif +``` + +`SpyCustom/sdk/utlmap.h`: + +```h +#ifndef UTLMAP_H +#define UTLMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include "utlrbtree.h" + +#define FOR_EACH_MAP( mapName, iteratorName ) \ + for ( int iteratorName = (mapName).FirstInorder(); (mapName).IsUtlMap && iteratorName != (mapName).InvalidIndex(); iteratorName = (mapName).NextInorder( iteratorName ) ) + +#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \ + for ( int iteratorName = 0; (mapName).IsUtlMap && iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else + + +struct base_utlmap_t +{ +public: + enum { IsUtlMap = true }; +}; + +template +class CUtlMap : public base_utlmap_t +{ +public: + typedef K KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + CUtlMap(int growSize = 0, int initSize = 0, const LessFunc_t& lessfunc = 0) + : m_Tree(growSize, initSize, CKeyLess(lessfunc)) + { + } + + CUtlMap(LessFunc_t lessfunc) + : m_Tree(CKeyLess(lessfunc)) + { + } + + void EnsureCapacity(int num) { m_Tree.EnsureCapacity(num); } + + ElemType_t& Element(IndexType_t i) { return m_Tree.Element(i).elem; } + const ElemType_t& Element(IndexType_t i) const { return m_Tree.Element(i).elem; } + ElemType_t& operator[](IndexType_t i) { return m_Tree.Element(i).elem; } + const ElemType_t& operator[](IndexType_t i) const { return m_Tree.Element(i).elem; } + KeyType_t& Key(IndexType_t i) { return m_Tree.Element(i).key; } + const KeyType_t& Key(IndexType_t i) const { return m_Tree.Element(i).key; } + + + unsigned int Count() const { return m_Tree.Count(); } + + IndexType_t MaxElement() const { return m_Tree.MaxElement(); } + + bool IsValidIndex(IndexType_t i) const { return m_Tree.IsValidIndex(i); } + + bool IsValid() const { return m_Tree.IsValid(); } + + static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); } + + void SetLessFunc(LessFunc_t func) + { + m_Tree.SetLessFunc(CKeyLess(func)); + } + + IndexType_t Insert(const KeyType_t& key, const ElemType_t& insert) + { + Node_t node; + node.key = key; + node.elem = insert; + return m_Tree.Insert(node); + } + + IndexType_t Insert(const KeyType_t& key) + { + Node_t node; + node.key = key; + return m_Tree.Insert(node); + } + + IndexType_t InsertWithDupes(const KeyType_t& key, const ElemType_t& insert) + { + Node_t node; + node.key = key; + node.elem = insert; + return m_Tree.Insert(node); + } + + IndexType_t InsertWithDupes(const KeyType_t& key) + { + Node_t node; + node.key = key; + return m_Tree.Insert(node); + } + + + bool HasElement(const KeyType_t& key) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.HasElement(dummyNode); + } + + + IndexType_t Find(const KeyType_t& key) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Find(dummyNode); + } + + IndexType_t FindFirst(const KeyType_t& key) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.FindFirst(dummyNode); + } + + + const ElemType_t& FindElement(const KeyType_t& key, const ElemType_t& defaultValue) const + { + IndexType_t i = Find(key); + if (i == InvalidIndex()) + return defaultValue; + return Element(i); + } + + + IndexType_t FindClosest(const KeyType_t& key, CompareOperands_t eFindCriteria) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.FindClosest(dummyNode, eFindCriteria); + } + + void RemoveAt(IndexType_t i) { m_Tree.RemoveAt(i); } + bool Remove(const KeyType_t& key) + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Remove(dummyNode); + } + + void RemoveAll() { m_Tree.RemoveAll(); } + void Purge() { m_Tree.Purge(); } + + void PurgeAndDeleteElements(); + + IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); } + IndexType_t NextInorder(IndexType_t i) const { return m_Tree.NextInorder(i); } + IndexType_t PrevInorder(IndexType_t i) const { return m_Tree.PrevInorder(i); } + IndexType_t LastInorder() const { return m_Tree.LastInorder(); } + + IndexType_t NextInorderSameKey(IndexType_t i) const + { + IndexType_t iNext = NextInorder(i); + if (!IsValidIndex(iNext)) + return InvalidIndex(); + if (Key(iNext) != Key(i)) + return InvalidIndex(); + return iNext; + } + + void Reinsert(const KeyType_t& key, IndexType_t i) + { + m_Tree[i].key = key; + m_Tree.Reinsert(i); + } + + IndexType_t InsertOrReplace(const KeyType_t& key, const ElemType_t& insert) + { + IndexType_t i = Find(key); + if (i != InvalidIndex()) + { + Element(i) = insert; + return i; + } + + return Insert(key, insert); + } + + void Swap(CUtlMap< K, T, I >& that) + { + m_Tree.Swap(that.m_Tree); + } + + + struct Node_t + { + Node_t() + { + } + + Node_t(const Node_t& from) + : key(from.key), + elem(from.elem) + { + } + + KeyType_t key; + ElemType_t elem; + }; + + class CKeyLess + { + public: + CKeyLess(const LessFunc_t& lessFunc) : m_LessFunc(lessFunc) {} + + bool operator!() const + { + return !m_LessFunc; + } + + bool operator()(const Node_t& left, const Node_t& right) const + { + return m_LessFunc(left.key, right.key); + } + + LessFunc_t m_LessFunc; + }; + + typedef CUtlRBTree CTree; + + CTree* AccessTree() { return &m_Tree; } + +protected: + CTree m_Tree; +}; + +template< typename K, typename T, typename I, typename LessFunc_t > +inline void CUtlMap::PurgeAndDeleteElements() +{ + for (I i = 0; i < MaxElement(); ++i) + { + if (!IsValidIndex(i)) + continue; + + delete Element(i); + } + + Purge(); +} + +#endif + +``` + +`SpyCustom/sdk/utlmemory.h`: + +```h +#ifndef UTLMEMORY_H +#define UTLMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dbg.h" +#include +#include "platform.h" + +#include "memalloc.h" +#include "mathlib.h" +#include "memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + + + +#ifdef UTLMEMORY_TRACK +#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#else +#define UTLMEMORY_TRACK_ALLOC() ((void)0) +#define UTLMEMORY_TRACK_FREE() ((void)0) +#endif + + +template< class T, class I = int > +class CUtlMemory +{ + template< class A, class B> friend class CUtlVector; + template< class A, size_t B> friend class CUtlVectorFixedGrowableCompat; +public: + CUtlMemory(int nGrowSize = 0, int nInitSize = 0); + CUtlMemory(T* pMemory, int numElements); + CUtlMemory(const T* pMemory, int numElements); + ~CUtlMemory(); + + CUtlMemory(const CUtlMemory&) = delete; + CUtlMemory& operator=(const CUtlMemory&) = delete; + + CUtlMemory(CUtlMemory&& moveFrom); + CUtlMemory& operator=(CUtlMemory&& moveFrom); + + void Init(int nGrowSize = 0, int nInitSize = 0); + + class Iterator_t + { + public: + Iterator_t(I i) : index(i) {} + I index; + + bool operator==(const Iterator_t it) const { return index == it.index; } + bool operator!=(const Iterator_t it) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); } + Iterator_t Next(const Iterator_t& it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); } + I GetIndex(const Iterator_t& it) const { return it.index; } + bool IsIdxAfter(I i, const Iterator_t& it) const { return i > it.index; } + bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index); } + Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); } + + T& operator[](I i); + const T& operator[](I i) const; + T& Element(I i); + const T& Element(I i) const; + + bool IsIdxValid(I i) const; + + static const I INVALID_INDEX = (I)-1; + static I InvalidIndex() { return INVALID_INDEX; } + + T* Base(); + const T* Base() const; + + void SetExternalBuffer(T* pMemory, int numElements); + void SetExternalBuffer(const T* pMemory, int numElements); + void AssumeMemory(T* pMemory, int nSize); + T* Detach(); + void* DetachMemory(); + + void Swap(CUtlMemory< T, I >& mem); + + void ConvertToGrowableMemory(int nGrowSize); + + int NumAllocated() const; + int Count() const; + + void Grow(int num = 1); + + void EnsureCapacity(int num); + + void Purge(); + + void Purge(int numElements); + + bool IsExternallyAllocated() const; + + bool IsReadOnly() const; + + void SetGrowSize(int size); + +protected: + void ValidateGrowSize() + { +#ifdef _X360 + if (m_nGrowSize && m_nGrowSize != EXTERNAL_BUFFER_MARKER) + { + const int MAX_GROW = 128; + if (m_nGrowSize * sizeof(T) > MAX_GROW) + { + m_nGrowSize = max(1, MAX_GROW / sizeof(T)); + } + } +#endif + } + + enum + { + EXTERNAL_BUFFER_MARKER = -1, + EXTERNAL_CONST_BUFFER_MARKER = -2, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + + +template< class T, size_t SIZE, class I = int > +class CUtlMemoryFixedGrowable : public CUtlMemory< T, I > +{ + typedef CUtlMemory< T, I > BaseClass; + +public: + CUtlMemoryFixedGrowable(int nGrowSize = 0, int nInitSize = SIZE) : BaseClass(m_pFixedMemory, SIZE) + { + Assert(nInitSize == 0 || nInitSize == SIZE); + m_nMallocGrowSize = nGrowSize; + } + + void Grow(int nCount = 1) + { + if (this->IsExternallyAllocated()) + { + this->ConvertToGrowableMemory(m_nMallocGrowSize); + } + BaseClass::Grow(nCount); + } + + void EnsureCapacity(int num) + { + if (CUtlMemory::m_nAllocationCount >= num) + return; + + if (this->IsExternallyAllocated()) + { + this->ConvertToGrowableMemory(m_nMallocGrowSize); + } + + BaseClass::EnsureCapacity(num); + } + +private: + int m_nMallocGrowSize; + T m_pFixedMemory[SIZE]; +}; + +template< typename T, size_t SIZE, int nAlignment = 0 > +class CUtlMemoryFixed +{ +public: + CUtlMemoryFixed(int nGrowSize = 0, int nInitSize = 0) { Assert(nInitSize == 0 || nInitSize == SIZE); } + CUtlMemoryFixed(T* pMemory, int numElements) { Assert(0); } + + bool IsIdxValid(int i) const { return (i >= 0) && (i < SIZE); } + + static const int INVALID_INDEX = -1; + static int InvalidIndex() { return INVALID_INDEX; } + + T* Base() { if (nAlignment == 0) return (T*)(&m_Memory[0]); else return (T*)AlignValue(&m_Memory[0], nAlignment); } + const T* Base() const { if (nAlignment == 0) return (T*)(&m_Memory[0]); else return (T*)AlignValue(&m_Memory[0], nAlignment); } + + T& operator[](int i) { Assert(IsIdxValid(i)); return Base()[i]; } + const T& operator[](int i) const { Assert(IsIdxValid(i)); return Base()[i]; } + T& Element(int i) { Assert(IsIdxValid(i)); return Base()[i]; } + const T& Element(int i) const { Assert(IsIdxValid(i)); return Base()[i]; } + + void SetExternalBuffer(T* pMemory, int numElements) { Assert(0); } + + int NumAllocated() const { return SIZE; } + int Count() const { return SIZE; } + + void Grow(int num = 1) { Assert(0); } + + void EnsureCapacity(int num) { Assert(num <= SIZE); } + + void Purge() {} + + void Purge(int numElements) { Assert(0); } + + bool IsExternallyAllocated() const { return false; } + + void SetGrowSize(int size) {} + + class Iterator_t + { + public: + Iterator_t(int i) : index(i) {} + int index; + bool operator==(const Iterator_t it) const { return index == it.index; } + bool operator!=(const Iterator_t it) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); } + Iterator_t Next(const Iterator_t& it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); } + int GetIndex(const Iterator_t& it) const { return it.index; } + bool IsIdxAfter(int i, const Iterator_t& it) const { return i > it.index; } + bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index); } + Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); } + +private: + char m_Memory[SIZE * sizeof(T) + nAlignment]; +}; + +#ifdef _LINUX +#define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1 +#endif + +template< typename T > +class CUtlMemoryConservative +{ + +public: + CUtlMemoryConservative(int nGrowSize = 0, int nInitSize = 0) : m_pMemory(NULL) + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + m_nCurAllocSize = 0; +#endif + + } + CUtlMemoryConservative(T* pMemory, int numElements) { Assert(0); } + ~CUtlMemoryConservative() { if (m_pMemory) free(m_pMemory); } + + bool IsIdxValid(int i) const { return (IsDebug()) ? (i >= 0 && i < NumAllocated()) : (i >= 0); } + static int InvalidIndex() { return -1; } + + T* Base() { return m_pMemory; } + const T* Base() const { return m_pMemory; } + + T& operator[](int i) { Assert(IsIdxValid(i)); return Base()[i]; } + const T& operator[](int i) const { Assert(IsIdxValid(i)); return Base()[i]; } + T& Element(int i) { Assert(IsIdxValid(i)); return Base()[i]; } + const T& Element(int i) const { Assert(IsIdxValid(i)); return Base()[i]; } + + void SetExternalBuffer(T* pMemory, int numElements) { Assert(0); } + + FORCEINLINE void RememberAllocSize(size_t sz) + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + m_nCurAllocSize = sz; +#endif + } + + size_t AllocSize(void) const + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + return m_nCurAllocSize; +#else + return (m_pMemory) ? g_pMemAlloc->GetSize(m_pMemory) : 0; +#endif + } + + int NumAllocated() const + { + return AllocSize() / sizeof(T); + } + int Count() const + { + return NumAllocated(); + } + + FORCEINLINE void ReAlloc(size_t sz) + { + m_pMemory = (T*)realloc(m_pMemory, sz); + RememberAllocSize(sz); + } + void Grow(int num = 1) + { + int nCurN = NumAllocated(); + ReAlloc((nCurN + num) * sizeof(T)); + } + + void EnsureCapacity(int num) + { + size_t nSize = sizeof(T) * MAX(num, Count()); + ReAlloc(nSize); + } + + void Purge() + { + free(m_pMemory); + RememberAllocSize(0); + m_pMemory = NULL; + } + + void Purge(int numElements) { ReAlloc(numElements * sizeof(T)); } + + bool IsExternallyAllocated() const { return false; } + + void SetGrowSize(int size) {} + + class Iterator_t + { + public: + Iterator_t(int i, int _limit) : index(i), limit(_limit) {} + int index; + int limit; + bool operator==(const Iterator_t it) const { return index == it.index; } + bool operator!=(const Iterator_t it) const { return index != it.index; } + }; + Iterator_t First() const { int limit = NumAllocated(); return Iterator_t(limit ? 0 : InvalidIndex(), limit); } + Iterator_t Next(const Iterator_t& it) const { return Iterator_t((it.index + 1 < it.limit) ? it.index + 1 : InvalidIndex(), it.limit); } + int GetIndex(const Iterator_t& it) const { return it.index; } + bool IsIdxAfter(int i, const Iterator_t& it) const { return i > it.index; } + bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index) && (it.index < it.limit); } + Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex(), 0); } + +private: + T* m_pMemory; +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + size_t m_nCurAllocSize; +#endif + +}; + + +template< class T, class I > +CUtlMemory::CUtlMemory(int nGrowSize, int nInitAllocationCount) : m_pMemory(0), +m_nAllocationCount(nInitAllocationCount), m_nGrowSize(nGrowSize) +{ + ValidateGrowSize(); + Assert(nGrowSize >= 0); + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +template< class T, class I > +CUtlMemory::CUtlMemory(T* pMemory, int numElements) : m_pMemory(pMemory), +m_nAllocationCount(numElements) +{ + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory::CUtlMemory(const T* pMemory, int numElements) : m_pMemory((T*)pMemory), +m_nAllocationCount(numElements) +{ + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory::~CUtlMemory() +{ + Purge(); + +#ifdef _DEBUG + m_pMemory = reinterpret_cast(0xFEFEBAAD); + m_nAllocationCount = 0x7BADF00D; +#endif +} + +template< class T, class I > +CUtlMemory::CUtlMemory(CUtlMemory&& moveFrom) + : m_pMemory(moveFrom.m_pMemory) + , m_nAllocationCount(moveFrom.m_nAllocationCount) + , m_nGrowSize(moveFrom.m_nGrowSize) +{ + moveFrom.m_pMemory = nullptr; + moveFrom.m_nAllocationCount = 0; + moveFrom.m_nGrowSize = 0; +} + +template< class T, class I > +CUtlMemory& CUtlMemory::operator=(CUtlMemory&& moveFrom) +{ + T* pMemory = moveFrom.m_pMemory; + int nAllocationCount = moveFrom.m_nAllocationCount; + int nGrowSize = moveFrom.m_nGrowSize; + + moveFrom.m_pMemory = nullptr; + moveFrom.m_nAllocationCount = 0; + moveFrom.m_nGrowSize = 0; + + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = nAllocationCount; + m_nGrowSize = nGrowSize; + + return *this; +} + +template< class T, class I > +void CUtlMemory::Init(int nGrowSize , int nInitSize ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + m_nAllocationCount = nInitSize; + ValidateGrowSize(); + Assert(nGrowSize >= 0); + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +template< class T, class I > +void CUtlMemory::Swap(CUtlMemory& mem) +{ + V_swap(m_nGrowSize, mem.m_nGrowSize); + V_swap(m_pMemory, mem.m_pMemory); + V_swap(m_nAllocationCount, mem.m_nAllocationCount); +} + + +template< class T, class I > +void CUtlMemory::ConvertToGrowableMemory(int nGrowSize) +{ + if (!IsExternallyAllocated()) + return; + + m_nGrowSize = nGrowSize; + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + + int nNumBytes = m_nAllocationCount * sizeof(T); + T* pMemory = (T*)malloc(nNumBytes); + memcpy(pMemory, m_pMemory, nNumBytes); + m_pMemory = pMemory; + } + else + { + m_pMemory = NULL; + } +} + + +template< class T, class I > +void CUtlMemory::SetExternalBuffer(T* pMemory, int numElements) +{ + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory::SetExternalBuffer(const T* pMemory, int numElements) +{ + Purge(); + + m_pMemory = const_cast(pMemory); + m_nAllocationCount = numElements; + + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory::AssumeMemory(T* pMemory, int numElements) +{ + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; +} + +template< class T, class I > +void* CUtlMemory::DetachMemory() +{ + if (IsExternallyAllocated()) + return NULL; + + void* pMemory = m_pMemory; + m_pMemory = 0; + m_nAllocationCount = 0; + return pMemory; +} + +template< class T, class I > +inline T* CUtlMemory::Detach() +{ + return (T*)DetachMemory(); +} + + +template< class T, class I > +inline T& CUtlMemory::operator[](I i) +{ + Assert(!IsReadOnly()); + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T, class I > +inline const T& CUtlMemory::operator[](I i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T, class I > +inline T& CUtlMemory::Element(I i) +{ + Assert(!IsReadOnly()); + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T, class I > +inline const T& CUtlMemory::Element(I i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + + +template< class T, class I > +bool CUtlMemory::IsExternallyAllocated() const +{ + return (m_nGrowSize < 0); +} + + +template< class T, class I > +bool CUtlMemory::IsReadOnly() const +{ + return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER); +} + + +template< class T, class I > +void CUtlMemory::SetGrowSize(int nSize) +{ + Assert(!IsExternallyAllocated()); + Assert(nSize >= 0); + m_nGrowSize = nSize; + ValidateGrowSize(); +} + + +template< class T, class I > +inline T* CUtlMemory::Base() +{ + Assert(!IsReadOnly()); + return m_pMemory; +} + +template< class T, class I > +inline const T* CUtlMemory::Base() const +{ + return m_pMemory; +} + + +template< class T, class I > +inline int CUtlMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + +template< class T, class I > +inline int CUtlMemory::Count() const +{ + return m_nAllocationCount; +} + + +template< class T, class I > +inline bool CUtlMemory::IsIdxValid(I i) const +{ + long x = i; + return (x >= 0) && (x < m_nAllocationCount); +} + +inline int UtlMemory_CalcNewAllocationCount(int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem) +{ + if (nGrowSize) + { + nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize); + } + else + { + if (!nAllocationCount) + { + nAllocationCount = (31 + nBytesItem) / nBytesItem; + if (nAllocationCount < nNewSize) + nAllocationCount = nNewSize; + } + + while (nAllocationCount < nNewSize) + { +#ifndef _X360 + nAllocationCount *= 2; +#else + int nNewAllocationCount = (nAllocationCount * 9) / 8; + if (nNewAllocationCount > nAllocationCount) + nAllocationCount = nNewAllocationCount; + else + nAllocationCount *= 2; +#endif + } + } + + return nAllocationCount; +} + +template< class T, class I > +void CUtlMemory::Grow(int num) +{ + Assert(num > 0); + + if (IsExternallyAllocated()) + { + Assert(0); + return; + } + + int nAllocationRequested = m_nAllocationCount + num; + + UTLMEMORY_TRACK_FREE(); + + int nNewAllocationCount = UtlMemory_CalcNewAllocationCount(m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T)); + + if ((int)(I)nNewAllocationCount < nAllocationRequested) + { + if ((int)(I)nNewAllocationCount == 0 && (int)(I)(nNewAllocationCount - 1) >= nAllocationRequested) + { + --nNewAllocationCount; + } + else + { + if ((int)(I)nAllocationRequested != nAllocationRequested) + { + Assert(0); + return; + } + while ((int)(I)nNewAllocationCount < nAllocationRequested) + { + nNewAllocationCount = (nNewAllocationCount + nAllocationRequested) / 2; + } + } + } + + m_nAllocationCount = nNewAllocationCount; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + Assert(m_pMemory); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + Assert(m_pMemory); + } +} + + +template< class T, class I > +inline void CUtlMemory::EnsureCapacity(int num) +{ + if (m_nAllocationCount >= num) + return; + + if (IsExternallyAllocated()) + { + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + + +template< class T, class I > +void CUtlMemory::Purge() +{ + if (!IsExternallyAllocated()) + { + if (m_pMemory) + { + UTLMEMORY_TRACK_FREE(); + free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + +template< class T, class I > +void CUtlMemory::Purge(int numElements) +{ + Assert(numElements >= 0); + + if (numElements > m_nAllocationCount) + { + Assert(numElements <= m_nAllocationCount); + return; + } + + if (numElements == 0) + { + Purge(); + return; + } + + if (IsExternallyAllocated()) + { + return; + } + + if (numElements == m_nAllocationCount) + { + return; + } + + + if (!m_pMemory) + { + Assert(m_pMemory); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = numElements; + + UTLMEMORY_TRACK_ALLOC(); + + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); +} + +template< class T, int nAlignment > +class CUtlMemoryAligned : public CUtlMemory +{ +public: + CUtlMemoryAligned(int nGrowSize = 0, int nInitSize = 0); + CUtlMemoryAligned(T* pMemory, int numElements); + CUtlMemoryAligned(const T* pMemory, int numElements); + ~CUtlMemoryAligned(); + + void SetExternalBuffer(T* pMemory, int numElements); + void SetExternalBuffer(const T* pMemory, int numElements); + + void Grow(int num = 1); + + void EnsureCapacity(int num); + + void Purge(); + + void Purge(int numElements) { Assert(0); } + +private: + void* Align(const void* pAddr); +}; + + +template< class T, int nAlignment > +void* CUtlMemoryAligned::Align(const void* pAddr) +{ + size_t nAlignmentMask = nAlignment - 1; + return (void*)(((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask)); +} + + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned(int nGrowSize, int nInitAllocationCount) +{ + CUtlMemory::m_pMemory = 0; + CUtlMemory::m_nAllocationCount = nInitAllocationCount; + CUtlMemory::m_nGrowSize = nGrowSize; + this->ValidateGrowSize(); + + COMPILE_TIME_ASSERT((nAlignment & (nAlignment - 1)) == 0); + Assert((nGrowSize >= 0) && (nGrowSize != CUtlMemory::EXTERNAL_BUFFER_MARKER)); + if (CUtlMemory::m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)_aligned_malloc(nInitAllocationCount * sizeof(T), nAlignment); + } +} + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned(T* pMemory, int numElements) +{ + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned::CUtlMemoryAligned(const T* pMemory, int numElements) +{ + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned::~CUtlMemoryAligned() +{ + Purge(); +} + + +template< class T, int nAlignment > +void CUtlMemoryAligned::SetExternalBuffer(T* pMemory, int numElements) +{ + Purge(); + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); + + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; +} + +template< class T, int nAlignment > +void CUtlMemoryAligned::SetExternalBuffer(const T* pMemory, int numElements) +{ + Purge(); + + CUtlMemory::m_pMemory = (T*)Align(pMemory); + CUtlMemory::m_nAllocationCount = ((int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory) / sizeof(T); + + CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; +} + + +template< class T, int nAlignment > +void CUtlMemoryAligned::Grow(int num) +{ + Assert(num > 0); + + if (this->IsExternallyAllocated()) + { + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + int nAllocationRequested = CUtlMemory::m_nAllocationCount + num; + + CUtlMemory::m_nAllocationCount = UtlMemory_CalcNewAllocationCount(CUtlMemory::m_nAllocationCount, CUtlMemory::m_nGrowSize, nAllocationRequested, sizeof(T)); + + UTLMEMORY_TRACK_ALLOC(); + + if (CUtlMemory::m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_ReallocAligned(CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + Assert(CUtlMemory::m_pMemory); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_AllocAligned(CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + Assert(CUtlMemory::m_pMemory); + } +} + + +template< class T, int nAlignment > +inline void CUtlMemoryAligned::EnsureCapacity(int num) +{ + if (CUtlMemory::m_nAllocationCount >= num) + return; + + if (this->IsExternallyAllocated()) + { + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + CUtlMemory::m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if (CUtlMemory::m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_ReallocAligned(CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory::m_pMemory = (T*)MemAlloc_AllocAligned(CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment); + } +} + + +template< class T, int nAlignment > +void CUtlMemoryAligned::Purge() +{ + if (!this->IsExternallyAllocated()) + { + if (CUtlMemory::m_pMemory) + { + UTLMEMORY_TRACK_FREE(); + MemAlloc_FreeAligned(CUtlMemory::m_pMemory); + CUtlMemory::m_pMemory = 0; + } + CUtlMemory::m_nAllocationCount = 0; + } +} + +#include "memdbgoff.h" + +#endif +``` + +`SpyCustom/sdk/utlobjectreference.h`: + +```h +#ifndef UTLOBJECTREFERENCE_H +#define UTLOBJECTREFERENCE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlintrusivelist.h" +#include "mathlib.h" + + + + + +template class CUtlReference +{ +public: + FORCEINLINE CUtlReference(void) + { + m_pNext = m_pPrev = NULL; + m_pObject = NULL; + } + + FORCEINLINE CUtlReference(T* pObj) + { + m_pNext = m_pPrev = NULL; + AddRef(pObj); + } + + FORCEINLINE ~CUtlReference(void) + { + KillRef(); + } + + FORCEINLINE void Set(T* pObj) + { + if (m_pObject != pObj) + { + KillRef(); + AddRef(pObj); + } + } + + FORCEINLINE T* operator()(void) const + { + return m_pObject; + } + + FORCEINLINE operator T* () + { + return m_pObject; + } + + FORCEINLINE operator const T* () const + { + return m_pObject; + } + + FORCEINLINE T* operator->() + { + return m_pObject; + } + + FORCEINLINE const T* operator->() const + { + return m_pObject; + } + + FORCEINLINE CUtlReference& operator=(const CUtlReference& otherRef) + { + Set(otherRef.m_pObject); + return *this; + } + + FORCEINLINE CUtlReference& operator=(T* pObj) + { + Set(pObj); + return *this; + } + + + FORCEINLINE bool operator==(const CUtlReference& o) const + { + return (o.m_pObject == m_pObject); + } + +public: + CUtlReference* m_pNext; + CUtlReference* m_pPrev; + + T* m_pObject; + + FORCEINLINE void AddRef(T* pObj) + { + m_pObject = pObj; + if (pObj) + { + pObj->m_References.AddToHead(this); + } + } + + FORCEINLINE void KillRef(void) + { + if (m_pObject) + { + m_pObject->m_References.RemoveNode(this); + m_pObject = NULL; + } + } + +}; + +template class CUtlReferenceList : public CUtlIntrusiveDList< CUtlReference > +{ +public: + ~CUtlReferenceList(void) + { + CUtlReference* i = CUtlIntrusiveDList >::m_pHead; + while (i) + { + CUtlReference* n = i->m_pNext; + i->m_pNext = NULL; + i->m_pPrev = NULL; + i->m_pObject = NULL; + i = n; + } + CUtlIntrusiveDList >::m_pHead = NULL; + } +}; + + +#define DECLARE_REFERENCED_CLASS( _className ) \ + private: \ + CUtlReferenceList< _className > m_References; \ + template friend class CUtlReference; + + +#endif + +``` + +`SpyCustom/sdk/utlpriorityqueue.h`: + +```h +#ifndef UTLPRIORITYQUEUE_H +#define UTLPRIORITYQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +template< class T > +class CUtlPriorityQueue +{ +public: + typedef bool (*LessFunc_t)(T const&, T const&); + + typedef T ElemType_t; + + CUtlPriorityQueue(int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0); + CUtlPriorityQueue(T* pMemory, int numElements, LessFunc_t lessfunc = 0); + + inline T const& ElementAtHead() const { return m_heap.Element(0); } + + inline bool IsValidIndex(int index) { return m_heap.IsValidIndex(index); } + + void RemoveAtHead(); + void RemoveAt(int index); + + void Insert(T const& element); + void SetLessFunc(LessFunc_t func); + + inline int Count() const { return m_heap.Count(); } + + void RemoveAll() { m_heap.RemoveAll(); } + + void Purge() { m_heap.Purge(); } + + inline const T& Element(int index) const { return m_heap.Element(index); } + +protected: + CUtlVector m_heap; + + void Swap(int index1, int index2); + + LessFunc_t m_LessFunc; +}; + +template< class T > +inline CUtlPriorityQueue::CUtlPriorityQueue(int growSize, int initSize, LessFunc_t lessfunc) : + m_heap(growSize, initSize), m_LessFunc(lessfunc) +{ +} + +template< class T > +inline CUtlPriorityQueue::CUtlPriorityQueue(T* pMemory, int numElements, LessFunc_t lessfunc) : + m_heap(pMemory, numElements), m_LessFunc(lessfunc) +{ +} + +template +void CUtlPriorityQueue::RemoveAtHead() +{ + m_heap.FastRemove(0); + int index = 0; + + int count = Count(); + if (!count) + return; + + int half = count / 2; + int larger = index; + while (index < half) + { + int child = ((index + 1) * 2) - 1; + if (child < count) + { + if (m_LessFunc(m_heap[index], m_heap[child])) + { + larger = child; + } + } + child++; + if (child < count) + { + if (m_LessFunc(m_heap[larger], m_heap[child])) + larger = child; + } + + if (larger == index) + break; + + Swap(index, larger); + index = larger; + } +} + + +template +void CUtlPriorityQueue::RemoveAt(int index) +{ + Assert(m_heap.IsValidIndex(index)); + m_heap.FastRemove(index); + + int count = Count(); + if (!count) + return; + + int half = count / 2; + int larger = index; + while (index < half) + { + int child = ((index + 1) * 2) - 1; + if (child < count) + { + if (m_LessFunc(m_heap[index], m_heap[child])) + { + larger = child; + } + } + child++; + if (child < count) + { + if (m_LessFunc(m_heap[larger], m_heap[child])) + larger = child; + } + + if (larger == index) + break; + + Swap(index, larger); + index = larger; + } +} + +template +void CUtlPriorityQueue::Insert(T const& element) +{ + int index = m_heap.AddToTail(); + m_heap[index] = element; + + while (index != 0) + { + int parent = ((index + 1) / 2) - 1; + if (m_LessFunc(m_heap[index], m_heap[parent])) + break; + + Swap(parent, index); + index = parent; + } +} + +template +void CUtlPriorityQueue::Swap(int index1, int index2) +{ + T tmp = m_heap[index1]; + m_heap[index1] = m_heap[index2]; + m_heap[index2] = tmp; +} + +template +void CUtlPriorityQueue::SetLessFunc(LessFunc_t lessfunc) +{ + m_LessFunc = lessfunc; +} + +#endif +``` + +`SpyCustom/sdk/utlqueue.h`: + +```h +#ifndef UTLQUEUE_H +#define UTLQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +template< class T > +class CUtlQueue +{ +public: + + CUtlQueue(int growSize = 0, int initSize = 0); + CUtlQueue(T* pMemory, int numElements); + + T const& RemoveAtHead(); + T const& RemoveAtTail(); + + T const& Head(); + T const& Tail(); + + void Insert(T const& element); + + bool Check(T const element); + + int Count() const { return m_heap.Count(); } + + void RemoveAll() { m_heap.RemoveAll(); } + + void Purge() { m_heap.Purge(); } + +protected: + CUtlVector m_heap; + T m_current; +}; + +template< class T > +inline CUtlQueue::CUtlQueue(int growSize, int initSize) : + m_heap(growSize, initSize) +{ +} + +template< class T > +inline CUtlQueue::CUtlQueue(T* pMemory, int numElements) : + m_heap(pMemory, numElements) +{ +} + +template +inline T const& CUtlQueue::RemoveAtHead() +{ + m_current = m_heap[0]; + m_heap.Remove((int)0); + return m_current; +} + +template +inline T const& CUtlQueue::RemoveAtTail() +{ + m_current = m_heap[m_heap.Count() - 1]; + m_heap.Remove((int)(m_heap.Count() - 1)); + return m_current; +} + +template +inline T const& CUtlQueue::Head() +{ + m_current = m_heap[0]; + return m_current; +} + +template +inline T const& CUtlQueue::Tail() +{ + m_current = m_heap[m_heap.Count() - 1]; + return m_current; +} + +template +void CUtlQueue::Insert(T const& element) +{ + int index = m_heap.AddToTail(); + m_heap[index] = element; +} + +template +bool CUtlQueue::Check(T const element) +{ + int index = m_heap.Find(element); + return (index != -1); +} + + +#endif +``` + +`SpyCustom/sdk/utlrbtree.h`: + +```h +#ifndef UTLRBTREE_H +#define UTLRBTREE_H + +#include "utlmemory.h" +#include "utlfixedmemory.h" +#include "utlblockmemory.h" + + +#define FOR_EACH_UTLRBTREE( treeName, iteratorName ) \ + for ( int iteratorName = treeName.FirstInorder(); (treeName).IsUtlRBTree && iteratorName != treeName.InvalidIndex(); iteratorName = treeName.NextInorder( iteratorName ) ) + + +template +class CDefOps +{ +public: + static bool LessFunc(const T& lhs, const T& rhs) { return (lhs < rhs); } +}; + +#define DefLessFunc( type ) CDefOps< type >::LessFunc + +template +class CDefLess +{ +public: + CDefLess() {} + CDefLess(int i) {} + inline bool operator()(const T& lhs, const T& rhs) const { return (lhs < rhs); } + inline bool operator!() const { return false; } +}; + + +inline bool StringLessThan(const char* const& lhs, const char* const& rhs) { + if (!lhs) return false; + if (!rhs) return true; + return (strcmp(lhs, rhs) < 0); +} + +inline bool CaselessStringLessThan(const char* const& lhs, const char* const& rhs) { + if (!lhs) return false; + if (!rhs) return true; + return (stricmp(lhs, rhs) < 0); +} + + +inline bool CaselessStringLessThanIgnoreSlashes(const char* const& lhs, const char* const& rhs) +{ + const char* pa = lhs; + const char* pb = rhs; + while (*pa && *pb) + { + char a = *pa; + char b = *pb; + + if (a == '/' || a == '\\') + { + if (b != '/' && b != '\\') + return ('/' < b); + } + else + { + if (a >= 'a' && a <= 'z') + a = 'A' + (a - 'a'); + + if (b >= 'a' && b <= 'z') + b = 'A' + (b - 'a'); + + if (a > b) + return false; + else if (a < b) + return true; + } + ++pa; + ++pb; + } + + if (*pa != *pb) + { + return (!*pa); + } + + return false; +} + +template <> inline bool CDefOps::LessFunc(const char* const& lhs, const char* const& rhs) { return StringLessThan(lhs, rhs); } +template <> inline bool CDefOps::LessFunc(char* const& lhs, char* const& rhs) { return StringLessThan(lhs, rhs); } + +template +void SetDefLessFunc(RBTREE_T& RBTree) +{ + RBTree.SetLessFunc(DefLessFunc(typename RBTREE_T::KeyType_t)); +} + +enum CompareOperands_t +{ + k_EEqual = 0x1, + k_EGreaterThan = 0x2, + k_ELessThan = 0x4, + k_EGreaterThanOrEqualTo = k_EGreaterThan | k_EEqual, + k_ELessThanOrEqualTo = k_ELessThan | k_EEqual, +}; + +template < class I > +struct UtlRBTreeLinks_t +{ + I m_Left; + I m_Right; + I m_Parent; + I m_Tag; +}; + +template < class T, class I > +struct UtlRBTreeNode_t : public UtlRBTreeLinks_t< I > +{ + T m_Data; +}; + +template < class T, class I = unsigned short, typename L = bool (*)(const T&, const T&), class M = CUtlMemory< UtlRBTreeNode_t< T, I >, I > > +class CUtlRBTree +{ +public: + + typedef T KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + enum { IsUtlRBTree = true }; + + typedef L LessFunc_t; + + explicit CUtlRBTree(int growSize = 0, int initSize = 0, const LessFunc_t& lessfunc = 0); + explicit CUtlRBTree(const LessFunc_t& lessfunc); + ~CUtlRBTree(); + + void EnsureCapacity(int num); + + void CopyFrom(const CUtlRBTree& other); + + T& Element(I i); + T const& Element(I i) const; + T& operator[](I i); + T const& operator[](I i) const; + + I Root() const; + + unsigned int Count() const; + + I MaxElement() const; + + I Parent(I i) const; + I LeftChild(I i) const; + I RightChild(I i) const; + + bool IsLeftChild(I i) const; + bool IsRightChild(I i) const; + + bool IsRoot(I i) const; + bool IsLeaf(I i) const; + + bool IsValidIndex(I i) const; + + bool IsValid() const; + + static I InvalidIndex(); + + int Depth(I node) const; + int Depth() const; + + void SetLessFunc(const LessFunc_t& func); + + I NewNode(); + + I Insert(T const& insert); + void Insert(const T* pArray, int nItems); + I InsertIfNotFound(T const& insert); + + I Find(T const& search) const; + + I FindFirst(T const& search) const; + + I FindClosest(T const& search, CompareOperands_t eFindCriteria) const; + + void RemoveAt(I i); + bool Remove(T const& remove); + void RemoveAll(); + void Purge(); + + void FreeNode(I i); + + I FirstInorder() const; + I NextInorder(I i) const; + I PrevInorder(I i) const; + I LastInorder() const; + + I FirstPreorder() const; + I NextPreorder(I i) const; + I PrevPreorder(I i) const; + I LastPreorder() const; + + I FirstPostorder() const; + I NextPostorder(I i) const; + + void Reinsert(I elem); + + void Swap(CUtlRBTree< T, I, L >& that); + +private: + CUtlRBTree& operator=(const CUtlRBTree& other); + +protected: + enum NodeColor_t + { + RED = 0, + BLACK + }; + + typedef UtlRBTreeNode_t< T, I > Node_t; + typedef UtlRBTreeLinks_t< I > Links_t; + + void SetParent(I i, I parent); + void SetLeftChild(I i, I child); + void SetRightChild(I i, I child); + void LinkToParent(I i, I parent, bool isLeft); + + Links_t const& Links(I i) const; + Links_t& Links(I i); + + bool IsRed(I i) const; + bool IsBlack(I i) const; + + NodeColor_t Color(I i) const; + void SetColor(I i, NodeColor_t c); + + void RotateLeft(I i); + void RotateRight(I i); + void InsertRebalance(I i); + void RemoveRebalance(I i); + + I InsertAt(I parent, bool leftchild); + + CUtlRBTree(CUtlRBTree const& tree); + + void FindInsertionPosition(T const& insert, I& parent, bool& leftchild); + + void Unlink(I elem); + void Link(I elem); + + LessFunc_t m_LessFunc; + + M m_Elements; + I m_Root; + I m_NumElements; + I m_FirstFree; + typename M::Iterator_t m_LastAlloc; + + Node_t* m_pElements; + + FORCEINLINE M const& Elements(void) const + { + return m_Elements; + } + + + void ResetDbgInfo() + { + m_pElements = (Node_t*)m_Elements.Base(); + } +}; + +template < class T, class I = int, typename L = bool (*)(const T&, const T&) > +class CUtlFixedRBTree : public CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > +{ +public: + + typedef L LessFunc_t; + + CUtlFixedRBTree(int growSize = 0, int initSize = 0, const LessFunc_t& lessfunc = 0) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >(growSize, initSize, lessfunc) {} + CUtlFixedRBTree(const LessFunc_t& lessfunc) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >(lessfunc) {} + + typedef CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > BaseClass; + bool IsValidIndex(I i) const + { + if (!BaseClass::Elements().IsIdxValid(i)) + return false; + +#ifdef _DEBUG + if (BaseClass::Elements().IsIdxAfter(i, this->m_LastAlloc)) + { + Assert(0); + return false; + } +#endif + + return LeftChild(i) != i; + } + +protected: + void ResetDbgInfo() {} + +private: + I MaxElement() const; +}; + +template < class T, class I = unsigned short, typename L = bool (*)(const T&, const T&) > +class CUtlBlockRBTree : public CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > > +{ +public: + typedef L LessFunc_t; + CUtlBlockRBTree(int growSize = 0, int initSize = 0, const LessFunc_t& lessfunc = 0) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >(growSize, initSize, lessfunc) {} + CUtlBlockRBTree(const LessFunc_t& lessfunc) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >(lessfunc) {} +protected: + void ResetDbgInfo() {} +}; + + +template < class T, class I, typename L, class M > +inline CUtlRBTree::CUtlRBTree(int growSize, int initSize, const LessFunc_t& lessfunc) : + m_LessFunc(lessfunc), + m_Elements(growSize, initSize), + m_Root(InvalidIndex()), + m_NumElements(0), + m_FirstFree(InvalidIndex()), + m_LastAlloc(m_Elements.InvalidIterator()) +{ + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree::CUtlRBTree(const LessFunc_t& lessfunc) : + m_Elements(0, 0), + m_LessFunc(lessfunc), + m_Root(InvalidIndex()), + m_NumElements(0), + m_FirstFree(InvalidIndex()), + m_LastAlloc(m_Elements.InvalidIterator()) +{ + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree::~CUtlRBTree() +{ + Purge(); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::EnsureCapacity(int num) +{ + m_Elements.EnsureCapacity(num); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::CopyFrom(const CUtlRBTree& other) +{ + Purge(); + m_Elements.EnsureCapacity(other.m_Elements.Count()); + memcpy(m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof(UtlRBTreeNode_t< T, I >)); + m_LessFunc = other.m_LessFunc; + m_Root = other.m_Root; + m_NumElements = other.m_NumElements; + m_FirstFree = other.m_FirstFree; + m_LastAlloc = other.m_LastAlloc; + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline T& CUtlRBTree::Element(I i) +{ + Assert(IsValidIndex(i)); + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T const& CUtlRBTree::Element(I i) const +{ + Assert(IsValidIndex(i)); + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T& CUtlRBTree::operator[](I i) +{ + return Element(i); +} + +template < class T, class I, typename L, class M > +inline T const& CUtlRBTree::operator[](I i) const +{ + return Element(i); +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::Root() const +{ + return m_Root; +} + +template < class T, class I, typename L, class M > +inline unsigned int CUtlRBTree::Count() const +{ + return (unsigned int)m_NumElements; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::MaxElement() const +{ + return (I)m_Elements.NumAllocated(); +} + + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::Parent(I i) const +{ + return i != InvalidIndex() ? m_Elements[i].m_Parent : InvalidIndex(); +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::LeftChild(I i) const +{ + return i != InvalidIndex() ? m_Elements[i].m_Left : InvalidIndex(); +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::RightChild(I i) const +{ + return i != InvalidIndex() ? m_Elements[i].m_Right : InvalidIndex(); +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsLeftChild(I i) const +{ + return LeftChild(Parent(i)) == i; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRightChild(I i) const +{ + return RightChild(Parent(i)) == i; +} + + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRoot(I i) const +{ + return i == m_Root; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsLeaf(I i) const +{ + return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex()); +} + + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsValidIndex(I i) const +{ + if (!m_Elements.IsIdxValid(i)) + return false; + + if (m_Elements.IsIdxAfter(i, m_LastAlloc)) + return false; + + return LeftChild(i) != i; +} + + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::InvalidIndex() +{ + return (I)M::InvalidIndex(); +} + + +template < class T, class I, typename L, class M > +inline int CUtlRBTree::Depth() const +{ + return Depth(Root()); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetParent(I i, I parent) +{ + Links(i).m_Parent = parent; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetLeftChild(I i, I child) +{ + Links(i).m_Left = child; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetRightChild(I i, I child) +{ + Links(i).m_Right = child; +} + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::Links_t const& CUtlRBTree::Links(I i) const +{ + static const Links_t s_Sentinel = + { + M::INVALID_INDEX, M::INVALID_INDEX, M::INVALID_INDEX, CUtlRBTree::BLACK + }; + + return (i != InvalidIndex()) ? m_Elements[i] : s_Sentinel; +} + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::Links_t& CUtlRBTree::Links(I i) +{ + Assert(i != InvalidIndex()); + return m_Elements[i]; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRed(I i) const +{ + return Color(i) == RED; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsBlack(I i) const +{ + return Color(i) == BLACK; +} + + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color(I i) const +{ + return (NodeColor_t)(i != InvalidIndex() ? m_Elements[i].m_Tag : BLACK); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetColor(I i, typename CUtlRBTree::NodeColor_t c) +{ + Links(i).m_Tag = (I)c; +} + +#pragma warning(push) +#pragma warning(disable:4389) +template < class T, class I, typename L, class M > +I CUtlRBTree::NewNode() +{ + I elem; + + if (m_FirstFree == InvalidIndex()) + { + Assert(m_Elements.IsValidIterator(m_LastAlloc) || m_NumElements == 0); + typename M::Iterator_t it = m_Elements.IsValidIterator(m_LastAlloc) ? m_Elements.Next(m_LastAlloc) : m_Elements.First(); + if (!m_Elements.IsValidIterator(it)) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Elements.Grow(); + + it = m_Elements.IsValidIterator(m_LastAlloc) ? m_Elements.Next(m_LastAlloc) : m_Elements.First(); + + Assert(m_Elements.IsValidIterator(it)); + if (!m_Elements.IsValidIterator(it)) + { + Error("CUtlRBTree overflow!\n"); + } + } + m_LastAlloc = it; + elem = m_Elements.GetIndex(m_LastAlloc); + Assert(m_Elements.IsValidIterator(m_LastAlloc)); + } + else + { + elem = m_FirstFree; + m_FirstFree = RightChild(m_FirstFree); + } + +#ifdef _DEBUG + Links_t& node = Links(elem); + node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); +#endif + + Construct(&Element(elem)); + ResetDbgInfo(); + + return elem; +} +#pragma warning(pop) + +template < class T, class I, typename L, class M > +void CUtlRBTree::FreeNode(I i) +{ + Assert(IsValidIndex(i) && (i != InvalidIndex())); + Destruct(&Element(i)); + SetLeftChild(i, i); + SetRightChild(i, m_FirstFree); + m_FirstFree = i; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::RotateLeft(I elem) +{ + I rightchild = RightChild(elem); + SetRightChild(elem, LeftChild(rightchild)); + if (LeftChild(rightchild) != InvalidIndex()) + SetParent(LeftChild(rightchild), elem); + + if (rightchild != InvalidIndex()) + SetParent(rightchild, Parent(elem)); + if (!IsRoot(elem)) + { + if (IsLeftChild(elem)) + SetLeftChild(Parent(elem), rightchild); + else + SetRightChild(Parent(elem), rightchild); + } + else + m_Root = rightchild; + + SetLeftChild(rightchild, elem); + if (elem != InvalidIndex()) + SetParent(elem, rightchild); +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::RotateRight(I elem) +{ + I leftchild = LeftChild(elem); + SetLeftChild(elem, RightChild(leftchild)); + if (RightChild(leftchild) != InvalidIndex()) + SetParent(RightChild(leftchild), elem); + + if (leftchild != InvalidIndex()) + SetParent(leftchild, Parent(elem)); + if (!IsRoot(elem)) + { + if (IsRightChild(elem)) + SetRightChild(Parent(elem), leftchild); + else + SetLeftChild(Parent(elem), leftchild); + } + else + m_Root = leftchild; + + SetRightChild(leftchild, elem); + if (elem != InvalidIndex()) + SetParent(elem, leftchild); +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::InsertRebalance(I elem) +{ + while (!IsRoot(elem) && (Color(Parent(elem)) == RED)) + { + I parent = Parent(elem); + I grandparent = Parent(parent); + + if (IsLeftChild(parent)) + { + I uncle = RightChild(grandparent); + if (IsRed(uncle)) + { + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + if (IsRightChild(elem)) + { + elem = parent; + RotateLeft(elem); + parent = Parent(elem); + grandparent = Parent(parent); + } + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateRight(grandparent); + } + } + else + { + I uncle = LeftChild(grandparent); + if (IsRed(uncle)) + { + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + if (IsLeftChild(elem)) + { + elem = parent; + RotateRight(parent); + parent = Parent(elem); + grandparent = Parent(parent); + } + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateLeft(grandparent); + } + } + } + SetColor(m_Root, BLACK); +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree::InsertAt(I parent, bool leftchild) +{ + I i = NewNode(); + LinkToParent(i, parent, leftchild); + ++m_NumElements; + + Assert(IsValid()); + + return i; +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::LinkToParent(I i, I parent, bool isLeft) +{ + Links_t& elem = Links(i); + elem.m_Parent = parent; + elem.m_Left = elem.m_Right = InvalidIndex(); + elem.m_Tag = RED; + + if (parent != InvalidIndex()) + { + if (isLeft) + Links(parent).m_Left = i; + else + Links(parent).m_Right = i; + } + else + { + m_Root = i; + } + + InsertRebalance(i); +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveRebalance(I elem) +{ + while (elem != m_Root && IsBlack(elem)) + { + I parent = Parent(elem); + + if (elem == LeftChild(parent)) + { + I sibling = RightChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateLeft(parent); + + parent = Parent(elem); + sibling = RightChild(parent); + } + if ((IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling)))) + { + if (sibling != InvalidIndex()) + SetColor(sibling, RED); + elem = parent; + } + else + { + if (IsBlack(RightChild(sibling))) + { + SetColor(LeftChild(sibling), BLACK); + SetColor(sibling, RED); + RotateRight(sibling); + + parent = Parent(elem); + sibling = RightChild(parent); + } + SetColor(sibling, Color(parent)); + SetColor(parent, BLACK); + SetColor(RightChild(sibling), BLACK); + RotateLeft(parent); + elem = m_Root; + } + } + else + { + I sibling = LeftChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateRight(parent); + + parent = Parent(elem); + sibling = LeftChild(parent); + } + if ((IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling)))) + { + if (sibling != InvalidIndex()) + SetColor(sibling, RED); + elem = parent; + } + else + { + if (IsBlack(LeftChild(sibling))) + { + SetColor(RightChild(sibling), BLACK); + SetColor(sibling, RED); + RotateLeft(sibling); + + parent = Parent(elem); + sibling = LeftChild(parent); + } + SetColor(sibling, Color(parent)); + SetColor(parent, BLACK); + SetColor(LeftChild(sibling), BLACK); + RotateRight(parent); + elem = m_Root; + } + } + } + SetColor(elem, BLACK); +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Unlink(I elem) +{ + if (elem != InvalidIndex()) + { + I x, y; + + if ((LeftChild(elem) == InvalidIndex()) || + (RightChild(elem) == InvalidIndex())) + { + y = elem; + } + else + { + y = RightChild(elem); + while (LeftChild(y) != InvalidIndex()) + y = LeftChild(y); + } + + if (LeftChild(y) != InvalidIndex()) + x = LeftChild(y); + else + x = RightChild(y); + + if (x != InvalidIndex()) + SetParent(x, Parent(y)); + if (!IsRoot(y)) + { + if (IsLeftChild(y)) + SetLeftChild(Parent(y), x); + else + SetRightChild(Parent(y), x); + } + else + m_Root = x; + + NodeColor_t ycolor = Color(y); + if (y != elem) + { + SetParent(y, Parent(elem)); + SetRightChild(y, RightChild(elem)); + SetLeftChild(y, LeftChild(elem)); + + if (!IsRoot(elem)) + if (IsLeftChild(elem)) + SetLeftChild(Parent(elem), y); + else + SetRightChild(Parent(elem), y); + else + m_Root = y; + + if (LeftChild(y) != InvalidIndex()) + SetParent(LeftChild(y), y); + if (RightChild(y) != InvalidIndex()) + SetParent(RightChild(y), y); + + SetColor(y, Color(elem)); + } + + if ((x != InvalidIndex()) && (ycolor == BLACK)) + RemoveRebalance(x); + } +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Link(I elem) +{ + if (elem != InvalidIndex()) + { + I parent = InvalidIndex(); + bool leftchild = false; + + FindInsertionPosition(Element(elem), parent, leftchild); + + LinkToParent(elem, parent, leftchild); + + Assert(IsValid()); + } +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveAt(I elem) +{ + if (elem != InvalidIndex()) + { + Unlink(elem); + + FreeNode(elem); + --m_NumElements; + + Assert(IsValid()); + } +} + + +template < class T, class I, typename L, class M > bool CUtlRBTree::Remove(T const& search) +{ + I node = Find(search); + if (node != InvalidIndex()) + { + RemoveAt(node); + return true; + } + return false; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveAll() +{ + if (m_LastAlloc == m_Elements.InvalidIterator()) + { + Assert(m_Root == InvalidIndex()); + Assert(m_FirstFree == InvalidIndex()); + Assert(m_NumElements == 0); + return; + } + + for (typename M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next(it)) + { + I i = m_Elements.GetIndex(it); + if (IsValidIndex(i)) + { + Destruct(&Element(i)); + SetRightChild(i, m_FirstFree); + SetLeftChild(i, i); + m_FirstFree = i; + } + + if (it == m_LastAlloc) + break; + } + + m_Root = InvalidIndex(); + m_NumElements = 0; + + Assert(IsValid()); +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Purge() +{ + RemoveAll(); + m_FirstFree = InvalidIndex(); + m_Elements.Purge(); + m_LastAlloc = m_Elements.InvalidIterator(); +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstInorder() const +{ + I i = m_Root; + I left; + while ((left = LeftChild(i)) != InvalidIndex()) + i = left; + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextInorder(I i) const +{ + Assert(IsValidIndex(i)); + + I right; + if ((right = RightChild(i)) != InvalidIndex()) + { + i = right; + I left; + while ((left = LeftChild(i)) != InvalidIndex()) + i = left; + return i; + } + + I parent = Parent(i); + while (IsRightChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::PrevInorder(I i) const +{ + Assert(IsValidIndex(i)); + + I left, right; + if ((left = LeftChild(i)) != InvalidIndex()) + { + i = left; + while ((right = RightChild(i)) != InvalidIndex()) + i = right; + return i; + } + + I parent = Parent(i); + while (IsLeftChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::LastInorder() const +{ + I i = m_Root; + I right; + while ((right = RightChild(i)) != InvalidIndex()) + i = right; + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstPreorder() const +{ + return m_Root; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextPreorder(I i) const +{ + I left, right; + if ((left = LeftChild(i)) != InvalidIndex()) + return left; + + if ((right = RightChild(i)) != InvalidIndex()) + return right; + + I parent = Parent(i); + while (parent != InvalidIndex()) + { + if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex())) + return RightChild(parent); + i = parent; + parent = Parent(parent); + } + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::PrevPreorder(I i) const +{ + Assert(0); + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::LastPreorder() const +{ + I i = m_Root; + while (1) + { + I left, right; + while ((right = RightChild(i)) != InvalidIndex()) + i = right; + + if ((left = LeftChild(i)) != InvalidIndex()) + i = left; + else + break; + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstPostorder() const +{ + I i = m_Root; + while (!IsLeaf(i)) + { + I left; + if ((left = LeftChild(i)) != InvalidIndex()) + i = left; + else + i = RightChild(i); + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextPostorder(I i) const +{ + I parent = Parent(i); + if (parent == InvalidIndex()) + return InvalidIndex(); + + if (IsRightChild(i)) + return parent; + + if (RightChild(parent) == InvalidIndex()) + return parent; + + i = RightChild(parent); + while (!IsLeaf(i)) + { + I left; + if ((left = LeftChild(i)) != InvalidIndex()) + i = left; + else + i = RightChild(i); + } + return i; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Reinsert(I elem) +{ + Unlink(elem); + Link(elem); +} + + +template < class T, class I, typename L, class M > +int CUtlRBTree::Depth(I node) const +{ + if (node == InvalidIndex()) + return 0; + + int depthright = Depth(RightChild(node)); + int depthleft = Depth(LeftChild(node)); + return MAX(depthright, depthleft) + 1; +} + + +template < class T, class I, typename L, class M > +bool CUtlRBTree::IsValid() const +{ + if (!Count()) + return true; + + if (m_LastAlloc == m_Elements.InvalidIterator()) + return false; + + if (!m_Elements.IsIdxValid(Root())) + return false; + + if (Parent(Root()) != InvalidIndex()) + return false; + +#ifdef UTLTREE_PARANOID + + int numFree = 0; + for (int i = m_FirstFree; i != InvalidIndex(); i = RightChild(i)) + { + ++numFree; + if (!m_Elements.IsIdxValid(i)) + return false; + } + + int nElements = 0; + int numFree2 = 0; + for (M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next(it)) + { + I i = m_Elements.GetIndex(it); + if (!IsValidIndex(i)) + { + ++numFree2; + } + else + { + ++nElements; + + int right = RightChild(i); + int left = LeftChild(i); + if ((right == left) && (right != InvalidIndex())) + return false; + + if (right != InvalidIndex()) + { + if (!IsValidIndex(right)) + return false; + if (Parent(right) != i) + return false; + if (IsRed(i) && IsRed(right)) + return false; + } + + if (left != InvalidIndex()) + { + if (!IsValidIndex(left)) + return false; + if (Parent(left) != i) + return false; + if (IsRed(i) && IsRed(left)) + return false; + } + } + + if (it == m_LastAlloc) + break; + } + if (numFree2 != numFree) + return false; + + if (nElements != m_NumElements) + return false; + +#endif + + return true; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::SetLessFunc(const typename CUtlRBTree::LessFunc_t& func) +{ + if (!m_LessFunc) + { + m_LessFunc = func; + } + else if (Count() > 0) + { + Assert(0); + } +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::FindInsertionPosition(T const& insert, I& parent, bool& leftchild) +{ + Assert(!!m_LessFunc); + + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc(insert, Element(current))) + { + leftchild = true; current = LeftChild(current); + } + else + { + leftchild = false; current = RightChild(current); + } + } +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::Insert(T const& insert) +{ + I parent = InvalidIndex(); + bool leftchild = false; + FindInsertionPosition(insert, parent, leftchild); + I newNode = InsertAt(parent, leftchild); + CopyConstruct(&Element(newNode), insert); + return newNode; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Insert(const T* pArray, int nItems) +{ + while (nItems--) + { + Insert(*pArray++); + } +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree::InsertIfNotFound(T const& insert) +{ + I parent; + bool leftchild; + + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc(insert, Element(current))) + { + leftchild = true; current = LeftChild(current); + } + else if (m_LessFunc(Element(current), insert)) + { + leftchild = false; current = RightChild(current); + } + else + return InvalidIndex(); + } + + I newNode = InsertAt(parent, leftchild); + CopyConstruct(&Element(newNode), insert); + return newNode; +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree::Find(T const& search) const +{ + Assert(!!m_LessFunc); + + I current = m_Root; + while (current != InvalidIndex()) + { + if (m_LessFunc(search, Element(current))) + current = LeftChild(current); + else if (m_LessFunc(Element(current), search)) + current = RightChild(current); + else + break; + } + return current; +} + + +template +I CUtlRBTree::FindFirst(T const& search) const +{ + Assert(!!m_LessFunc); + + I current = m_Root; + I best = InvalidIndex(); + while (current != InvalidIndex()) + { + if (m_LessFunc(search, Element(current))) + current = LeftChild(current); + else if (m_LessFunc(Element(current), search)) + current = RightChild(current); + else + { + best = current; + current = LeftChild(current); + } + } + return best; +} + + +template +I CUtlRBTree::FindClosest(T const& search, CompareOperands_t eFindCriteria) const +{ + Assert(!!m_LessFunc); + Assert((eFindCriteria & (k_EGreaterThan | k_ELessThan)) ^ (k_EGreaterThan | k_ELessThan)); + + I current = m_Root; + I best = InvalidIndex(); + + while (current != InvalidIndex()) + { + if (m_LessFunc(search, Element(current))) + { + if (eFindCriteria & k_EGreaterThan) + best = current; + current = LeftChild(current); + } + else if (m_LessFunc(Element(current), search)) + { + if (eFindCriteria & k_ELessThan) + best = current; + current = RightChild(current); + } + else + { + if (eFindCriteria & k_EEqual) + { + best = current; + break; + } + else if (eFindCriteria & k_EGreaterThan) + { + current = RightChild(current); + } + else if (eFindCriteria & k_ELessThan) + { + current = LeftChild(current); + } + } + } + return best; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Swap(CUtlRBTree< T, I, L >& that) +{ + m_Elements.Swap(that.m_Elements); + V_swap(m_LessFunc, that.m_LessFunc); + V_swap(m_Root, that.m_Root); + V_swap(m_NumElements, that.m_NumElements); + V_swap(m_FirstFree, that.m_FirstFree); + V_swap(m_pElements, that.m_pElements); + V_swap(m_LastAlloc, that.m_LastAlloc); + Assert(IsValid()); + Assert(m_Elements.IsValidIterator(m_LastAlloc) || (m_NumElements == 0 && m_FirstFree == InvalidIndex())); +} + + +#endif +``` + +`SpyCustom/sdk/utlsoacontainer.h`: + +```h +#ifndef UTLSOACONTAINER_H +#define UTLSOACONTAINER_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "platform.h" +#include "dbg.h" +#include "threadtools.h" +#include "utlmemory.h" +#include "utlblockmemory.h" +#include "ssemath.h" + + +template class CStridedPtr +{ +protected: + T* m_pData; + size_t m_nStride; + +public: + FORCEINLINE CStridedPtr(void* pData, size_t nByteStride) + { + m_pData = reinterpret_cast(pData); + m_nStride = nByteStride / sizeof(T); + } + + FORCEINLINE CStridedPtr(void) {} + T* operator->(void) const + { + return m_pData; + } + + T& operator*(void) const + { + return *m_pData; + } + + FORCEINLINE operator T* (void) + { + return m_pData; + } + + FORCEINLINE CStridedPtr& operator++(void) + { + m_pData += m_nStride; + return *this; + } + + FORCEINLINE void operator+=(size_t nNumElements) + { + m_pData += nNumElements * m_nStride; + } + +}; + +template class CStridedConstPtr +{ +protected: + const T* m_pData; + size_t m_nStride; + +public: + FORCEINLINE CStridedConstPtr(void const* pData, size_t nByteStride) + { + m_pData = reinterpret_cast(pData); + m_nStride = nByteStride / sizeof(T); + } + + FORCEINLINE CStridedConstPtr(void) {} + + const T* operator->(void) const + { + return m_pData; + } + + const T& operator*(void) const + { + return *m_pData; + } + + FORCEINLINE operator const T* (void) const + { + return m_pData; + } + + FORCEINLINE CStridedConstPtr& operator++(void) + { + m_pData += m_nStride; + return *this; + } + FORCEINLINE void operator+=(size_t nNumElements) + { + m_pData += nNumElements * m_nStride; + } +}; + +enum EAttributeDataType +{ + ATTRDATATYPE_FLOAT = 0, + ATTRDATATYPE_4V = 1, + ATTRDATATYPE_INT = 2, + ATTRDATATYPE_POINTER = 3, + ATTRDATATYPE_NONE = -1, +}; + +#define MAX_SOA_FIELDS 32 + +class CSOAContainer +{ + +protected: + int m_nColumns; + int m_nRows; + int m_nSlices; + + int m_nPaddedColumns; + int m_nNumQuadsPerRow; + + uint8* m_pDataMemory; + uint8* m_pAttributePtrs[MAX_SOA_FIELDS]; + + EAttributeDataType m_nDataType[MAX_SOA_FIELDS]; + + size_t m_nStrideInBytes[MAX_SOA_FIELDS]; + size_t m_nRowStrideInBytes[MAX_SOA_FIELDS]; + size_t m_nSliceStrideInBytes[MAX_SOA_FIELDS]; + + + + uint32 m_nFieldPresentMask; + + FORCEINLINE void Init(void) + { + memset(m_nDataType, 0xff, sizeof(m_nDataType)); + m_pDataMemory = 0; + m_nColumns = m_nPaddedColumns = m_nRows = m_nSlices = 0; + m_nFieldPresentMask = 0; + } +public: + + + CSOAContainer(void) + { + Init(); + } + + void Purge(void); + + ~CSOAContainer(void); + + CSOAContainer(int nCols, int nRows, ...); + + size_t ElementSize(void) const; + + FORCEINLINE void SetAttributeType(int nAttrIdx, EAttributeDataType nDataType, bool bAllocateMemory = true) + { + Assert(!m_pDataMemory); + Assert(nAttrIdx < MAX_SOA_FIELDS); + m_nDataType[nAttrIdx] = nDataType; + if ((m_nDataType[nAttrIdx] != ATTRDATATYPE_NONE) && bAllocateMemory) + m_nFieldPresentMask |= (1 << nAttrIdx); + else + m_nFieldPresentMask &= ~(1 << nAttrIdx); + } + + FORCEINLINE int NumRows(void) const + { + return m_nRows; + } + + FORCEINLINE int NumCols(void) const + { + return m_nColumns; + } + FORCEINLINE int NumSlices(void) const + { + return m_nSlices; + } + + + FORCEINLINE void AssertDataType(int nAttrIdx, EAttributeDataType nDataType) const + { + Assert(nAttrIdx >= 0); + Assert(nAttrIdx < MAX_SOA_FIELDS); + Assert(m_nStrideInBytes[nAttrIdx]); + } + + + FORCEINLINE int NumQuadsPerRow(void) const + { + return m_nNumQuadsPerRow; + } + + FORCEINLINE int Count(void) const + { + return NumCols(); + } + + FORCEINLINE int NumElements(void) const + { + return NumCols() * NumRows() * NumSlices(); + } + + + FORCEINLINE size_t RowToRowStep(int nAttrIdx) const + { + return 0; + } + + FORCEINLINE void* RowPtr(int nAttributeIdx, int nRowNumber, int nSliceNumber = 0) const + { + Assert(nRowNumber < m_nRows); + Assert(nAttributeIdx < MAX_SOA_FIELDS); + Assert(m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE); + Assert(m_nFieldPresentMask & (1 << nAttributeIdx)); + return m_pAttributePtrs[nAttributeIdx] + + +nRowNumber * m_nRowStrideInBytes[nAttributeIdx] + + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx]; + } + + FORCEINLINE void const* ConstRowPtr(int nAttributeIdx, int nRowNumber, int nSliceNumber = 0) const + { + Assert(nRowNumber < m_nRows); + Assert(nAttributeIdx < MAX_SOA_FIELDS); + Assert(m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE); + return m_pAttributePtrs[nAttributeIdx] + + nRowNumber * m_nRowStrideInBytes[nAttributeIdx] + + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx]; + } + + + template FORCEINLINE T* ElementPointer(int nAttributeIdx, + int nX = 0, int nY = 0, int nZ = 0) const + { + Assert(nAttributeIdx < MAX_SOA_FIELDS); + Assert(nX < m_nColumns); + Assert(nY < m_nRows); + Assert(nZ < m_nSlices); + Assert(m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE); + Assert(m_nDataType[nAttributeIdx] != ATTRDATATYPE_4V); + return reinterpret_cast(m_pAttributePtrs[nAttributeIdx] + + nX * sizeof(float) + + nY * m_nRowStrideInBytes[nAttributeIdx] + + nZ * m_nSliceStrideInBytes[nAttributeIdx] + ); + } + + FORCEINLINE size_t ItemByteStride(int nAttributeIdx) const + { + Assert(nAttributeIdx < MAX_SOA_FIELDS); + Assert(m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE); + return m_nStrideInBytes[nAttributeIdx]; + } + + void CopyAttrFrom(CSOAContainer const& other, int nAttributeIdx); + + void CopyAttrToAttr(int nSrcAttributeIndex, int nDestAttributeIndex); + + FORCEINLINE void MoveDataFrom(CSOAContainer other) + { + (*this) = other; + other.Init(); + } + + + + void AllocateData(int nNCols, int nNRows, int nSlices = 1); + + void RandomizeAttribute(int nAttr, float flMin, float flMax) const; + + void FillAttrWithInterpolatedValues(int nAttr, float flValue00, float flValue10, float flValue01, float flValue11) const; + void FillAttrWithInterpolatedValues(int nAttr, Vector flValue00, Vector flValue10, + Vector const& flValue01, Vector const& flValue11) const; + +}; + +class CFltX4AttributeIterator : public CStridedConstPtr +{ + FORCEINLINE CFltX4AttributeIterator(CSOAContainer const* pContainer, int nAttribute, int nRowNumber = 0) + : CStridedConstPtr(pContainer->ConstRowPtr(nAttribute, nRowNumber), + pContainer->ItemByteStride(nAttribute)) + { + } +}; + +class CFltX4AttributeWriteIterator : public CStridedPtr +{ + FORCEINLINE CFltX4AttributeWriteIterator(CSOAContainer const* pContainer, int nAttribute, int nRowNumber = 0) + : CStridedPtr(pContainer->RowPtr(nAttribute, nRowNumber), + pContainer->ItemByteStride(nAttribute)) + { + } + +}; + + +#endif +``` + +`SpyCustom/sdk/utlstack.h`: + +```h +#ifndef UTLSTACK_H +#define UTLSTACK_H + +#include +#include +#include "utlmemory.h" + + +template< class T, class M = CUtlMemory< T > > +class CUtlStack +{ +public: + CUtlStack(int growSize = 0, int initSize = 0); + ~CUtlStack(); + + void CopyFrom(const CUtlStack& from); + + T& operator[](int i); + T const& operator[](int i) const; + T& Element(int i); + T const& Element(int i) const; + + T* Base(); + T const* Base() const; + + T& Top(); + T const& Top() const; + + int Count() const; + + bool IsIdxValid(int i) const; + + int Push(); + + int Push(T const& src); + + void Pop(); + void Pop(T& oldTop); + void PopMultiple(int num); + + void EnsureCapacity(int num); + + void Clear(); + + void Purge(); + +private: + void GrowStack(); + + void ResetDbgInfo(); + + M m_Memory; + int m_Size; + + T* m_pElements; +}; + + +template< class T, class M > +inline void CUtlStack::ResetDbgInfo() +{ + m_pElements = m_Memory.Base(); +} + +template< class T, class M > +CUtlStack::CUtlStack(int growSize, int initSize) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T, class M > +CUtlStack::~CUtlStack() +{ + Purge(); +} + + +template< class T, class M > +void CUtlStack::CopyFrom(const CUtlStack& from) +{ + Purge(); + EnsureCapacity(from.Count()); + for (int i = 0; i < from.Count(); i++) + { + Push(from[i]); + } +} + +template< class T, class M > +inline T& CUtlStack::operator[](int i) +{ + assert(IsIdxValid(i)); + return m_Memory[i]; +} + +template< class T, class M > +inline T const& CUtlStack::operator[](int i) const +{ + assert(IsIdxValid(i)); + return m_Memory[i]; +} + +template< class T, class M > +inline T& CUtlStack::Element(int i) +{ + assert(IsIdxValid(i)); + return m_Memory[i]; +} + +template< class T, class M > +inline T const& CUtlStack::Element(int i) const +{ + assert(IsIdxValid(i)); + return m_Memory[i]; +} + + +template< class T, class M > +inline T* CUtlStack::Base() +{ + return m_Memory.Base(); +} + +template< class T, class M > +inline T const* CUtlStack::Base() const +{ + return m_Memory.Base(); +} + +template< class T, class M > +inline T& CUtlStack::Top() +{ + assert(m_Size > 0); + return Element(m_Size - 1); +} + +template< class T, class M > +inline T const& CUtlStack::Top() const +{ + assert(m_Size > 0); + return Element(m_Size - 1); +} + +template< class T, class M > +inline int CUtlStack::Count() const +{ + return m_Size; +} + + +template< class T, class M > +inline bool CUtlStack::IsIdxValid(int i) const +{ + return (i >= 0) && (i < m_Size); +} + +template< class T, class M > +void CUtlStack::GrowStack() +{ + if (m_Size >= m_Memory.NumAllocated()) + m_Memory.Grow(); + + ++m_Size; + + ResetDbgInfo(); +} + +template< class T, class M > +void CUtlStack::EnsureCapacity(int num) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +template< class T, class M > +int CUtlStack::Push() +{ + GrowStack(); + Construct(&Element(m_Size - 1)); + return m_Size - 1; +} + +template< class T, class M > +int CUtlStack::Push(T const& src) +{ + GrowStack(); + CopyConstruct(&Element(m_Size - 1), src); + return m_Size - 1; +} + + +template< class T, class M > +void CUtlStack::Pop() +{ + assert(m_Size > 0); + Destruct(&Element(m_Size - 1)); + --m_Size; +} + +template< class T, class M > +void CUtlStack::Pop(T& oldTop) +{ + assert(m_Size > 0); + oldTop = Top(); + Pop(); +} + +template< class T, class M > +void CUtlStack::PopMultiple(int num) +{ + assert(m_Size >= num); + for (int i = 0; i < num; ++i) + Destruct(&Element(m_Size - i - 1)); + m_Size -= num; +} + + +template< class T, class M > +void CUtlStack::Clear() +{ + for (int i = m_Size; --i >= 0; ) + Destruct(&Element(i)); + + m_Size = 0; +} + + +template< class T, class M > +void CUtlStack::Purge() +{ + Clear(); + m_Memory.Purge(); + ResetDbgInfo(); +} + +#endif +``` + +`SpyCustom/sdk/utlstring.h`: + +```h +#ifndef UTLSTRING_H +#define UTLSTRING_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "utlmemory.h" +#include "strtools.h" +#include "limits.h" + +#if defined( OSX ) +#define wcsdup wcsdup_osx +inline wchar_t* wcsdup_osx(const wchar_t* pString) +{ + wchar_t* pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t*)malloc(len * sizeof(wchar_t))) != NULL) + { + return wcscpy(pMemory, pString); + } + + return NULL; +} +#endif + +class CUtlBinaryBlock +{ +public: + CUtlBinaryBlock(int growSize = 0, int initSize = 0); + + CUtlBinaryBlock(void* pMemory, int nSizeInBytes, int nInitialLength); + CUtlBinaryBlock(const void* pMemory, int nSizeInBytes); + CUtlBinaryBlock(const CUtlBinaryBlock& src); + + void Get(void* pValue, int nMaxLen) const; + void Set(const void* pValue, int nLen); + const void* Get() const; + void* Get(); + + unsigned char& operator[](int i); + const unsigned char& operator[](int i) const; + + int Length() const; + void SetLength(int nLength); + bool IsEmpty() const; + void Clear(); + void Purge(); + + bool IsReadOnly() const; + + CUtlBinaryBlock& operator=(const CUtlBinaryBlock& src); + + bool operator==(const CUtlBinaryBlock& src) const; + +private: + CUtlMemory m_Memory; + int m_nActualLength; +}; + + +inline const void* CUtlBinaryBlock::Get() const +{ + return m_Memory.Base(); +} + +inline void* CUtlBinaryBlock::Get() +{ + return m_Memory.Base(); +} + +inline int CUtlBinaryBlock::Length() const +{ + return m_nActualLength; +} + +inline unsigned char& CUtlBinaryBlock::operator[](int i) +{ + return m_Memory[i]; +} + +inline const unsigned char& CUtlBinaryBlock::operator[](int i) const +{ + return m_Memory[i]; +} + +inline bool CUtlBinaryBlock::IsReadOnly() const +{ + return m_Memory.IsReadOnly(); +} + +inline bool CUtlBinaryBlock::IsEmpty() const +{ + return Length() == 0; +} + +inline void CUtlBinaryBlock::Clear() +{ + SetLength(0); +} + +inline void CUtlBinaryBlock::Purge() +{ + SetLength(0); + m_Memory.Purge(); +} + + +class CUtlString +{ +public: + typedef enum + { + PATTERN_NONE = 0x00000000, + PATTERN_DIRECTORY = 0x00000001 + } TUtlStringPattern; + +public: + CUtlString(); + CUtlString(const char* pString); + CUtlString(const CUtlString& string); + + CUtlString(void* pMemory, int nSizeInBytes, int nInitialLength); + CUtlString(const void* pMemory, int nSizeInBytes); + + const char* Get() const; + void Set(const char* pValue); + + void Clear() { Set(NULL); } + + operator const char* () const; + + const char* String() const { return Get(); } + + int Length() const; + bool IsEmpty() const; + + void SetLength(int nLen); + char* Get(); + void Purge(); + + void ToLower(); + void ToUpper(); + + void Append(const char* pchAddition); + + void StripTrailingSlash(); + + CUtlString& operator=(const CUtlString& src); + CUtlString& operator=(const char* src); + + bool operator==(const CUtlString& src) const; + bool operator==(const char* src) const; + bool operator!=(const CUtlString& src) const { return !operator==(src); } + bool operator!=(const char* src) const { return !operator==(src); } + + inline friend bool operator==(const char* lhs, const CUtlString& rhs) { return rhs.operator==(lhs); } + inline friend bool operator!=(const char* lhs, const CUtlString& rhs) { return rhs.operator!=(lhs); } + + CUtlString& operator+=(const CUtlString& rhs); + CUtlString& operator+=(const char* rhs); + CUtlString& operator+=(char c); + CUtlString& operator+=(int rhs); + CUtlString& operator+=(double rhs); + + bool IsValid() const; + + bool MatchesPattern(const CUtlString& Pattern, int nFlags = 0); + + int Format(PRINTF_FORMAT_STRING const char* pFormat, ...); + void SetDirect(const char* pValue, int nChars); + + typedef const char* AltArgumentType_t; + + CUtlString Slice(int32 nStart = 0, int32 nEnd = INT_MAX); + + CUtlString Left(int32 nChars); + CUtlString Right(int32 nChars); + + CUtlString Replace(char cFrom, char cTo); + + CUtlString AbsPath(const char* pStartingDir = NULL); + + CUtlString UnqualifiedFilename(); + + CUtlString DirName(); + + static CUtlString PathJoin(const char* pStr1, const char* pStr2); + + static int __cdecl SortCaseInsensitive(const CUtlString* pString1, const CUtlString* pString2); + static int __cdecl SortCaseSensitive(const CUtlString* pString1, const CUtlString* pString2); + +private: + CUtlBinaryBlock m_Storage; +}; + +inline bool CUtlString::IsEmpty() const +{ + return Length() == 0; +} + +inline bool CUtlString::IsValid() const +{ + return (String() != NULL); +} + +inline int __cdecl CUtlString::SortCaseInsensitive(const CUtlString* pString1, const CUtlString* pString2) +{ + return V_stricmp(pString1->String(), pString2->String()); +} + +inline int __cdecl CUtlString::SortCaseSensitive(const CUtlString* pString1, const CUtlString* pString2) +{ + return V_strcmp(pString1->String(), pString2->String()); +} + +template < typename T > +class StringFuncs +{ +public: + static T* Duplicate(const T* pValue); + static void Copy(T* out_pOut, const T* pIn, int iLengthInChars); + static int Compare(const T* pLhs, const T* pRhs); + static int CaselessCompare(const T* pLhs, const T* pRhs); + static int Length(const T* pValue); + static const T* FindChar(const T* pStr, const T cSearch); + static const T* EmptyString(); + static const T* NullDebugString(); +}; + +template < > +class StringFuncs +{ +public: + static char* Duplicate(const char* pValue) { return strdup(pValue); } + static void Copy(OUT_CAP(iLengthInChars) char* out_pOut, const char* pIn, int iLengthInChars) { strncpy(out_pOut, pIn, iLengthInChars); } + static int Compare(const char* pLhs, const char* pRhs) { return strcmp(pLhs, pRhs); } + static int CaselessCompare(const char* pLhs, const char* pRhs) { return Q_strcasecmp(pLhs, pRhs); } + static int Length(const char* pValue) { return (int)strlen(pValue); } + static const char* FindChar(const char* pStr, const char cSearch) { return strchr(pStr, cSearch); } + static const char* EmptyString() { return ""; } + static const char* NullDebugString() { return "(null)"; } +}; + +template < > +class StringFuncs +{ +public: + static wchar_t* Duplicate(const wchar_t* pValue) { return wcsdup(pValue); } + static void Copy(OUT_CAP(iLengthInChars) wchar_t* out_pOut, const wchar_t* pIn, int iLengthInChars) { wcsncpy(out_pOut, pIn, iLengthInChars); } + static int Compare(const wchar_t* pLhs, const wchar_t* pRhs) { return wcscmp(pLhs, pRhs); } + static int CaselessCompare(const wchar_t* pLhs, const wchar_t* pRhs); + static int Length(const wchar_t* pValue) { return (int)wcslen(pValue); } + static const wchar_t* FindChar(const wchar_t* pStr, const wchar_t cSearch) { return wcschr(pStr, cSearch); } + static const wchar_t* EmptyString() { return L""; } + static const wchar_t* NullDebugString() { return L"(null)"; } +}; + +template < typename T = char > +class CUtlConstStringBase +{ +public: + CUtlConstStringBase() : m_pString(NULL) {} + explicit CUtlConstStringBase(const T* pString) : m_pString(NULL) { Set(pString); } + CUtlConstStringBase(const CUtlConstStringBase& src) : m_pString(NULL) { Set(src.m_pString); } + ~CUtlConstStringBase() { Set(NULL); } + + void Set(const T* pValue); + void Clear() { Set(NULL); } + + const T* Get() const { return m_pString ? m_pString : StringFuncs::EmptyString(); } + operator const T* () const { return m_pString ? m_pString : StringFuncs::EmptyString(); } + + bool IsEmpty() const { return m_pString == NULL; } + + int Compare(const T* rhs) const; + + bool operator<(const T* rhs) const { return Compare(rhs) < 0; } + bool operator==(const T* rhs) const { return Compare(rhs) == 0; } + bool operator!=(const T* rhs) const { return Compare(rhs) != 0; } + bool operator<(const CUtlConstStringBase& rhs) const { return Compare(rhs.m_pString) < 0; } + bool operator==(const CUtlConstStringBase& rhs) const { return Compare(rhs.m_pString) == 0; } + bool operator!=(const CUtlConstStringBase& rhs) const { return Compare(rhs.m_pString) != 0; } + + inline friend bool operator<(const T* lhs, const CUtlConstStringBase& rhs) { return rhs.Compare(lhs) > 0; } + inline friend bool operator==(const T* lhs, const CUtlConstStringBase& rhs) { return rhs.Compare(lhs) == 0; } + inline friend bool operator!=(const T* lhs, const CUtlConstStringBase& rhs) { return rhs.Compare(lhs) != 0; } + + CUtlConstStringBase& operator=(const T* src) { Set(src); return *this; } + CUtlConstStringBase& operator=(const CUtlConstStringBase& src) { Set(src.m_pString); return *this; } + + typedef const T* AltArgumentType_t; + +protected: + const T* m_pString; +}; + +template < typename T > +void CUtlConstStringBase::Set(const T* pValue) +{ + if (pValue != m_pString) + { + free((void*)m_pString); + m_pString = pValue && pValue[0] ? StringFuncs::Duplicate(pValue) : NULL; + } +} + +template < typename T > +int CUtlConstStringBase::Compare(const T* rhs) const +{ + if (!rhs || !rhs[0]) + return m_pString ? 1 : 0; + + if (!m_pString) + return -1; + + return StringFuncs::Compare(m_pString, rhs); +} + +typedef CUtlConstStringBase CUtlConstString; +typedef CUtlConstStringBase CUtlConstWideString; + +template < typename T > struct UTLConstStringCaselessStringLessFunctor { bool operator()(const CUtlConstStringBase& a, const char* b) const { return StringFuncs::CaselessCompare(a.Get(), b) < 0; } }; +template < typename T > struct UTLConstStringCaselessStringEqualFunctor { bool operator()(const CUtlConstStringBase& a, const char* b) const { return StringFuncs::CaselessCompare(a.Get(), b) == 0; } }; + + +#endif +``` + +`SpyCustom/sdk/utlsymbol.h`: + +```h +#ifndef UTLSYMBOL_H +#define UTLSYMBOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "threadtools.h" +#include "utlrbtree.h" +#include "utlvector.h" + + +class CUtlSymbolTable; +class CUtlSymbolTableMT; + + +typedef unsigned short UtlSymId_t; + +#define UTL_INVAL_SYMBOL ((UtlSymId_t)~0) + +class CUtlSymbol +{ +public: + CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {} + CUtlSymbol(UtlSymId_t id) : m_Id(id) {} + CUtlSymbol(const char* pStr); + CUtlSymbol(CUtlSymbol const& sym) : m_Id(sym.m_Id) {} + + CUtlSymbol& operator=(CUtlSymbol const& src) { m_Id = src.m_Id; return *this; } + + bool operator==(CUtlSymbol const& src) const { return m_Id == src.m_Id; } + bool operator==(const char* pStr) const; + + bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; } + + operator UtlSymId_t const() const { return m_Id; } + + const char* String() const; + + static void DisableStaticSymbolTable(); + +protected: + UtlSymId_t m_Id; + + static void Initialize(); + + static CUtlSymbolTableMT* CurrTable(); + + static CUtlSymbolTableMT* s_pSymbolTable; + + static bool s_bAllowStaticSymbolTable; + + friend class CCleanupUtlSymbolTable; +}; + + +class CUtlSymbolTable +{ +public: + CUtlSymbolTable(int growSize = 0, int initSize = 32, bool caseInsensitive = false); + ~CUtlSymbolTable(); + + CUtlSymbol AddString(const char* pString); + + CUtlSymbol Find(const char* pString) const; + + const char* String(CUtlSymbol id) const; + + void RemoveAll(); + + int GetNumStrings(void) const + { + return m_Lookup.Count(); + } + +protected: + class CStringPoolIndex + { + public: + inline CStringPoolIndex() + { + } + + inline CStringPoolIndex(unsigned short iPool, unsigned short iOffset) + { + m_iPool = iPool; + m_iOffset = iOffset; + } + + inline bool operator==(const CStringPoolIndex& other) const + { + return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset; + } + + unsigned short m_iPool; + unsigned short m_iOffset; + }; + + class CLess + { + public: + CLess(int ignored = 0) {} + bool operator!() const { return false; } + bool operator()(const CStringPoolIndex& left, const CStringPoolIndex& right) const; + }; + + class CTree : public CUtlRBTree + { + public: + CTree(int growSize, int initSize) : CUtlRBTree(growSize, initSize) {} + friend class CUtlSymbolTable::CLess; + }; + + struct StringPool_t + { + int m_TotalLen; + int m_SpaceUsed; + char m_Data[1]; + }; + + CTree m_Lookup; + bool m_bInsensitive; + mutable const char* m_pUserSearchString; + + CUtlVector m_StringPools; + +private: + int FindPoolWithSpace(int len) const; + const char* StringFromIndex(const CStringPoolIndex& index) const; + + friend class CLess; +}; + +class CUtlSymbolTableMT : private CUtlSymbolTable +{ +public: + CUtlSymbolTableMT(int growSize = 0, int initSize = 32, bool caseInsensitive = false) + : CUtlSymbolTable(growSize, initSize, caseInsensitive) + { + } + + CUtlSymbol AddString(const char* pString) + { + m_lock.LockForWrite(); + CUtlSymbol result = CUtlSymbolTable::AddString(pString); + m_lock.UnlockWrite(); + return result; + } + + CUtlSymbol Find(const char* pString) const + { + m_lock.LockForRead(); + CUtlSymbol result = CUtlSymbolTable::Find(pString); + m_lock.UnlockRead(); + return result; + } + + const char* String(CUtlSymbol id) const + { + m_lock.LockForRead(); + const char* pszResult = CUtlSymbolTable::String(id); + m_lock.UnlockRead(); + return pszResult; + } + +private: +#if defined(WIN32) || defined(_WIN32) + mutable CThreadSpinRWLock m_lock; +#else + mutable CThreadRWLock m_lock; +#endif +}; + + + +typedef void* FileNameHandle_t; +#define FILENAMEHANDLE_INVALID 0 + +class CUtlFilenameSymbolTable +{ + struct FileNameHandleInternal_t + { + FileNameHandleInternal_t() + { + path = 0; + file = 0; + } + + unsigned short path; + unsigned short file; + }; + + class HashTable; + +public: + CUtlFilenameSymbolTable(); + ~CUtlFilenameSymbolTable(); + FileNameHandle_t FindOrAddFileName(const char* pFileName); + FileNameHandle_t FindFileName(const char* pFileName); + int PathIndex(const FileNameHandle_t& handle) { return ((const FileNameHandleInternal_t*)&handle)->path; } + bool String(const FileNameHandle_t& handle, char* buf, int buflen); + void RemoveAll(); + +private: + HashTable* m_Strings; + mutable CThreadSpinRWLock m_lock; +}; + + +#endif +``` + +`SpyCustom/sdk/utlsymbollarge.h`: + +```h +#ifndef UTLSYMBOLLARGE_H +#define UTLSYMBOLLARGE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "threadtools.h" +#include "utltshash.h" +#include "stringpool.h" +#include "vprof.h" +#include "utltshash.h" + +typedef intp UtlSymLargeId_t; + +#define UTL_INVAL_SYMBOL_LARGE ((UtlSymLargeId_t)~0) + +class CUtlSymbolLarge +{ +public: + CUtlSymbolLarge() + { + u.m_Id = UTL_INVAL_SYMBOL_LARGE; + } + + CUtlSymbolLarge(UtlSymLargeId_t id) + { + u.m_Id = id; + } + CUtlSymbolLarge(CUtlSymbolLarge const& sym) + { + u.m_Id = sym.u.m_Id; + } + + CUtlSymbolLarge& operator=(CUtlSymbolLarge const& src) + { + u.m_Id = src.u.m_Id; + return *this; + } + + bool operator==(CUtlSymbolLarge const& src) const + { + return u.m_Id == src.u.m_Id; + } + + bool operator==(UtlSymLargeId_t const& src) const + { + return u.m_Id == src; + } + + bool operator!=(CUtlSymbolLarge const& src) const + { + return u.m_Id != src.u.m_Id; + } + + bool operator!=(UtlSymLargeId_t const& src) const + { + return u.m_Id != src; + } + + operator UtlSymLargeId_t const() const + { + return u.m_Id; + } + + inline const char* String() const + { + if (u.m_Id == UTL_INVAL_SYMBOL_LARGE) + return ""; + return u.m_pAsString; + } + + inline bool IsValid() const + { + return u.m_Id != UTL_INVAL_SYMBOL_LARGE ? true : false; + } + +private: + CUtlSymbolLarge(const char* pStr); + bool operator==(const char* pStr) const; + + union + { + UtlSymLargeId_t m_Id; + char const* m_pAsString; + } u; +}; + +#define MIN_STRING_POOL_SIZE 2048 + +inline uint32 CUtlSymbolLarge_Hash(bool CASEINSENSITIVE, const char* pString, int len) +{ + return (CASEINSENSITIVE ? HashStringCaseless(pString) : HashString(pString)); +} + +typedef uint32 LargeSymbolTableHashDecoration_t; + +struct CUtlSymbolTableLargeBaseTreeEntry_t +{ + LargeSymbolTableHashDecoration_t m_Hash; + char m_String[1]; + + bool IsEmpty() const + { + return ((m_Hash == 0) && (0 == m_String[0])); + } + + char const* String() const + { + return (const char*)&m_String[0]; + } + + CUtlSymbolLarge ToSymbol() const + { + return reinterpret_cast(String()); + } + + LargeSymbolTableHashDecoration_t HashValue() const + { + return m_Hash; + } +}; + +template< class TreeType, bool CASEINSENSITIVE > +class CTreeEntryLess +{ +public: + CTreeEntryLess(int ignored = 0) {} + bool operator!() const { return false; } + bool operator()(CUtlSymbolTableLargeBaseTreeEntry_t* const& left, CUtlSymbolTableLargeBaseTreeEntry_t* const& right) const + { + if (left->m_Hash == right->m_Hash) + { + if (!CASEINSENSITIVE) + return strcmp(left->String(), right->String()) < 0; + else + return V_stricmp(left->String(), right->String()) < 0; + } + else + { + return left->m_Hash < right->m_Hash; + } + } +}; + +template< bool CASEINSENSITIVE > +class CNonThreadsafeTree : public CUtlRBTree, CASEINSENSITIVE > > +{ +public: + typedef CUtlRBTree > CNonThreadsafeTreeType; + + CNonThreadsafeTree() : + CNonThreadsafeTreeType(0, 16) + { + } + inline void Commit() + { + } + inline intp Insert(CUtlSymbolTableLargeBaseTreeEntry_t* entry) + { + return CNonThreadsafeTreeType::Insert(entry); + } + inline intp Find(CUtlSymbolTableLargeBaseTreeEntry_t* entry) const + { + return CNonThreadsafeTreeType::Find(entry); + } + inline intp InvalidIndex() const + { + return CNonThreadsafeTreeType::InvalidIndex(); + } + inline int GetElements(int nFirstElement, int nCount, CUtlSymbolLarge* pElements) const + { + CUtlVector< CUtlSymbolTableLargeBaseTreeEntry_t* > list; + list.EnsureCount(nCount); + for (int i = 0; i < nCount; ++i) + { + pElements[i] = CNonThreadsafeTreeType::Element(i)->ToSymbol(); + } + + return nCount; + } +}; + +template < int BUCKET_COUNT, class KEYTYPE, bool CASEINSENSITIVE > +class CCThreadsafeTreeHashMethod +{ +public: + static int Hash(const KEYTYPE& key, int nBucketMask) + { + uint32 nHash = key->HashValue(); + return (nHash & nBucketMask); + } + + static bool Compare(CUtlSymbolTableLargeBaseTreeEntry_t* const& lhs, CUtlSymbolTableLargeBaseTreeEntry_t* const& rhs) + { + if (lhs->m_Hash != rhs->m_Hash) + return false; + if (!CASEINSENSITIVE) + { + return (!Q_strcmp(lhs->String(), rhs->String()) ? true : false); + } + + return (!Q_stricmp(lhs->String(), rhs->String()) ? true : false); + } +}; + +template < bool CASEINSENSITIVE > +class CThreadsafeTree : public CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t*, 2048, CUtlSymbolTableLargeBaseTreeEntry_t*, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t*, CASEINSENSITIVE > > +{ +public: + typedef CUtlTSHash< CUtlSymbolTableLargeBaseTreeEntry_t*, 2048, CUtlSymbolTableLargeBaseTreeEntry_t*, CCThreadsafeTreeHashMethod< 2048, CUtlSymbolTableLargeBaseTreeEntry_t*, CASEINSENSITIVE > > CThreadsafeTreeType; + + CThreadsafeTree() : + CThreadsafeTreeType(32) + { + } + inline void Commit() + { + CThreadsafeTreeType::Commit(); + } + inline UtlTSHashHandle_t Insert(CUtlSymbolTableLargeBaseTreeEntry_t* entry) + { + return CThreadsafeTreeType::Insert(entry, entry); + } + inline UtlTSHashHandle_t Find(CUtlSymbolTableLargeBaseTreeEntry_t* entry) + { + return CThreadsafeTreeType::Find(entry); + } + inline UtlTSHashHandle_t InvalidIndex() const + { + return CThreadsafeTreeType::InvalidHandle(); + } + inline int GetElements(UtlTSHashHandle_t nFirstElement, int nCount, CUtlSymbolLarge* pElements) const + { + CUtlVector< UtlTSHashHandle_t > list; + list.EnsureCount(nCount); + int c = CThreadsafeTreeType::GetElements(nFirstElement, nCount, list.Base()); + for (int i = 0; i < c; ++i) + { + pElements[i] = CThreadsafeTreeType::Element(list[i])->ToSymbol(); + } + + return c; + } +}; + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE = MIN_STRING_POOL_SIZE > +class CUtlSymbolTableLargeBase +{ +public: + CUtlSymbolTableLargeBase(); + ~CUtlSymbolTableLargeBase(); + + CUtlSymbolLarge AddString(const char* pString); + + CUtlSymbolLarge Find(const char* pString) const; + + void RemoveAll(); + + int GetNumStrings(void) const + { + return m_Lookup.Count(); + } + + void Commit() + { + m_Lookup.Commit(); + } + + int GetElements(int nFirstElement, int nCount, CUtlSymbolLarge* pElements) const + { + return m_Lookup.GetElements(nFirstElement, nCount, pElements); + } + + const char* GetElementString(int nElement) const + { + return m_Lookup.Element(nElement)->String(); + } + + uint64 GetMemoryUsage() const + { + uint64 unBytesUsed = 0u; + + for (int i = 0; i < m_StringPools.Count(); i++) + { + StringPool_t* pPool = m_StringPools[i]; + + unBytesUsed += (uint64)pPool->m_TotalLen; + } + return unBytesUsed; + } + + +protected: + + struct StringPool_t + { + int m_TotalLen; + int m_SpaceUsed; + char m_Data[1]; + }; + + TreeType m_Lookup; + + CUtlVector< StringPool_t* > m_StringPools; + +private: + int FindPoolWithSpace(int len) const; +}; + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolTableLargeBase::CUtlSymbolTableLargeBase() : + m_StringPools(8) +{ +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolTableLargeBase::~CUtlSymbolTableLargeBase() +{ + RemoveAll(); +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolLarge CUtlSymbolTableLargeBase::Find(const char* pString) const +{ + VPROF("CUtlSymbolLarge::Find"); + if (!pString) + return CUtlSymbolLarge(); + + int len = Q_strlen(pString) + 1; + + CUtlSymbolTableLargeBaseTreeEntry_t* search = (CUtlSymbolTableLargeBaseTreeEntry_t*)_alloca(len + sizeof(LargeSymbolTableHashDecoration_t)); + search->m_Hash = CUtlSymbolLarge_Hash(CASEINSENSITIVE, pString, len); + Q_memcpy((char*)&search->m_String[0], pString, len); + + intp idx = const_cast(m_Lookup).Find(search); + + if (idx == m_Lookup.InvalidIndex()) + return UTL_INVAL_SYMBOL_LARGE; + + const CUtlSymbolTableLargeBaseTreeEntry_t* entry = m_Lookup[idx]; + return entry->ToSymbol(); +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline int CUtlSymbolTableLargeBase::FindPoolWithSpace(int len) const +{ + for (int i = 0; i < m_StringPools.Count(); i++) + { + StringPool_t* pPool = m_StringPools[i]; + + if ((pPool->m_TotalLen - pPool->m_SpaceUsed) >= len) + { + return i; + } + } + + return -1; +} + +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline CUtlSymbolLarge CUtlSymbolTableLargeBase::AddString(const char* pString) +{ + VPROF("CUtlSymbolLarge::AddString"); + if (!pString) + return UTL_INVAL_SYMBOL_LARGE; + + CUtlSymbolLarge id = Find(pString); + if (id != UTL_INVAL_SYMBOL_LARGE) + return id; + + int lenString = Q_strlen(pString) + 1; + int lenDecorated = lenString + sizeof(LargeSymbolTableHashDecoration_t); + lenDecorated = ALIGN_VALUE(lenDecorated, sizeof(LargeSymbolTableHashDecoration_t)); + + int iPool = FindPoolWithSpace(lenDecorated); + if (iPool == -1) + { + int newPoolSize = MAX(lenDecorated + sizeof(StringPool_t), POOL_SIZE); + StringPool_t* pPool = (StringPool_t*)malloc(newPoolSize); + + pPool->m_TotalLen = newPoolSize - sizeof(StringPool_t); + pPool->m_SpaceUsed = 0; + iPool = m_StringPools.AddToTail(pPool); + } + + LargeSymbolTableHashDecoration_t hash = CUtlSymbolLarge_Hash(CASEINSENSITIVE, pString, lenString); + + StringPool_t* pPool = m_StringPools[iPool]; + CUtlSymbolTableLargeBaseTreeEntry_t* entry = (CUtlSymbolTableLargeBaseTreeEntry_t*)&pPool->m_Data[pPool->m_SpaceUsed]; + + pPool->m_SpaceUsed += lenDecorated; + + entry->m_Hash = hash; + char* pText = (char*)&entry->m_String[0]; + Q_memcpy(pText, pString, lenString); + + MEM_ALLOC_CREDIT(); + return m_Lookup.Element(m_Lookup.Insert(entry))->ToSymbol(); +} + +#ifdef ANALYZE_SUPPRESS +ANALYZE_SUPPRESS(6001); +#endif +template < class TreeType, bool CASEINSENSITIVE, size_t POOL_SIZE > +inline void CUtlSymbolTableLargeBase::RemoveAll() +{ + m_Lookup.Purge(); + + for (int i = 0; i < m_StringPools.Count(); i++) + free(m_StringPools[i]); + + m_StringPools.RemoveAll(); +} +#ifdef ANALYZE_UNSUPPRESS +ANALYZE_UNSUPPRESS(); +#endif + +typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< false >, false > CUtlSymbolTableLarge; +typedef CUtlSymbolTableLargeBase< CNonThreadsafeTree< true >, true > CUtlSymbolTableLarge_CI; +typedef CUtlSymbolTableLargeBase< CThreadsafeTree< false >, false > CUtlSymbolTableLargeMT; +typedef CUtlSymbolTableLargeBase< CThreadsafeTree< true >, true > CUtlSymbolTableLargeMT_CI; + +#endif +``` + +`SpyCustom/sdk/utltshash.h`: + +```h +#ifndef UTLTSHASH_H +#define UTLTSHASH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "threadtools.h" +#include "mempool.h" +#include "generichash.h" + + +typedef intp UtlTSHashHandle_t; + +template < class T > +abstract_class ITSHashConstructor +{ +public: + virtual void Construct(T * pElement) = 0; +}; + +template < class T > +class CDefaultTSHashConstructor : public ITSHashConstructor< T > +{ +public: + virtual void Construct(T* pElement) + { + ::Construct(pElement); + } +}; + +template < int BUCKET_COUNT, class KEYTYPE = intp > +class CUtlTSHashGenericHash +{ +public: + static int Hash(const KEYTYPE& key, int nBucketMask) + { + int nHash = HashIntConventional((intp)key); + if (BUCKET_COUNT <= USHRT_MAX) + { + nHash ^= (nHash >> 16); + } + if (BUCKET_COUNT <= UCHAR_MAX) + { + nHash ^= (nHash >> 8); + } + return (nHash & nBucketMask); + } + + static bool Compare(const KEYTYPE& lhs, const KEYTYPE& rhs) + { + return lhs == rhs; + } +}; + +template < int BUCKET_COUNT, class KEYTYPE > +class CUtlTSHashUseKeyHashMethod +{ +public: + static int Hash(const KEYTYPE& key, int nBucketMask) + { + uint32 nHash = key.HashValue(); + return (nHash & nBucketMask); + } + + static bool Compare(const KEYTYPE& lhs, const KEYTYPE& rhs) + { + return lhs == rhs; + } +}; + +template< class T, int BUCKET_COUNT, class KEYTYPE = intp, class HashFuncs = CUtlTSHashGenericHash< BUCKET_COUNT, KEYTYPE >, int nAlignment = 0 > +class CUtlTSHash +{ +public: + CUtlTSHash(int nAllocationCount); + ~CUtlTSHash(); + + static UtlTSHashHandle_t InvalidHandle(void) { return (UtlTSHashHandle_t)0; } + + UtlTSHashHandle_t Find(KEYTYPE uiKey); + + UtlTSHashHandle_t Insert(KEYTYPE uiKey, const T& data, bool* pDidInsert = NULL); + UtlTSHashHandle_t Insert(KEYTYPE uiKey, ITSHashConstructor* pConstructor, bool* pDidInsert = NULL); + + UtlTSHashHandle_t FastInsert(KEYTYPE uiKey, const T& data); + UtlTSHashHandle_t FastInsert(KEYTYPE uiKey, ITSHashConstructor* pConstructor); + + void Commit(); + + void FindAndRemove(KEYTYPE uiKey); + void Remove(UtlTSHashHandle_t hHash) { FindAndRemove(GetID(hHash)); } + void RemoveAll(void); + void Purge(void); + + int Count() const; + + int GetElements(int nFirstElement, int nCount, UtlTSHashHandle_t* pHandles) const; + + T& Element(UtlTSHashHandle_t hHash); + T const& Element(UtlTSHashHandle_t hHash) const; + T& operator[](UtlTSHashHandle_t hHash); + T const& operator[](UtlTSHashHandle_t hHash) const; + KEYTYPE GetID(UtlTSHashHandle_t hHash) const; + + UtlTSHashHandle_t ElementPtrToHandle(T* pElement) const; + +private: + template < typename Data_t > + struct HashFixedDataInternal_t + { + KEYTYPE m_uiKey; + HashFixedDataInternal_t< Data_t >* m_pNext; + Data_t m_Data; + }; + + typedef HashFixedDataInternal_t HashFixedData_t; + + enum + { + BUCKET_MASK = BUCKET_COUNT - 1 + }; + + struct HashBucket_t + { + HashFixedData_t* m_pFirst; + HashFixedData_t* m_pFirstUncommitted; + CThreadSpinRWLock m_AddLock; + }; + + UtlTSHashHandle_t Find(KEYTYPE uiKey, HashFixedData_t* pFirstElement, HashFixedData_t* pLastElement); + UtlTSHashHandle_t InsertUncommitted(KEYTYPE uiKey, HashBucket_t& bucket); + CMemoryPoolMT m_EntryMemory; + HashBucket_t m_aBuckets[BUCKET_COUNT]; + bool m_bNeedsCommit; + +#ifdef _DEBUG + CInterlockedInt m_ContentionCheck; +#endif +}; + + +template +CUtlTSHash::CUtlTSHash(int nAllocationCount) : + m_EntryMemory(sizeof(HashFixedData_t), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME(HashFixedData_t), nAlignment) +{ +#ifdef _DEBUG + m_ContentionCheck = 0; +#endif + m_bNeedsCommit = false; + for (int i = 0; i < BUCKET_COUNT; i++) + { + HashBucket_t& bucket = m_aBuckets[i]; + bucket.m_pFirst = NULL; + bucket.m_pFirstUncommitted = NULL; + } +} + + +template +CUtlTSHash::~CUtlTSHash() +{ +#ifdef _DEBUG + if (m_ContentionCheck != 0) + { + DebuggerBreak(); + } +#endif + Purge(); +} + +template +inline void CUtlTSHash::Purge(void) +{ + RemoveAll(); +} + + +template +inline int CUtlTSHash::Count() const +{ + return m_EntryMemory.Count(); +} + + +template +int CUtlTSHash::GetElements(int nFirstElement, int nCount, UtlTSHashHandle_t* pHandles) const +{ + int nIndex = 0; + for (int i = 0; i < BUCKET_COUNT; i++) + { + const HashBucket_t& bucket = m_aBuckets[i]; + bucket.m_AddLock.LockForRead(); + for (HashFixedData_t* pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext) + { + if (--nFirstElement >= 0) + continue; + + pHandles[nIndex++] = (UtlTSHashHandle_t)pElement; + if (nIndex >= nCount) + { + bucket.m_AddLock.UnlockRead(); + return nIndex; + } + } + bucket.m_AddLock.UnlockRead(); + } + return nIndex; +} + + +template +inline UtlTSHashHandle_t CUtlTSHash::InsertUncommitted(KEYTYPE uiKey, HashBucket_t& bucket) +{ + m_bNeedsCommit = true; + HashFixedData_t* pNewElement = static_cast(m_EntryMemory.Alloc()); + pNewElement->m_pNext = bucket.m_pFirstUncommitted; + bucket.m_pFirstUncommitted = pNewElement; + pNewElement->m_uiKey = uiKey; + return (UtlTSHashHandle_t)pNewElement; +} + + +template +inline UtlTSHashHandle_t CUtlTSHash::Insert(KEYTYPE uiKey, const T& data, bool* pDidInsert) +{ +#ifdef _DEBUG + if (m_ContentionCheck != 0) + { + DebuggerBreak(); + } +#endif + + if (pDidInsert) + { + *pDidInsert = false; + } + + int iBucket = HashFuncs::Hash(uiKey, BUCKET_MASK); + HashBucket_t& bucket = m_aBuckets[iBucket]; + + UtlTSHashHandle_t h = Find(uiKey); + if (h != InvalidHandle()) + return h; + + bucket.m_AddLock.LockForWrite(); + + h = Find(uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst); + if (h == InvalidHandle()) + { + h = InsertUncommitted(uiKey, bucket); + CopyConstruct(&Element(h), data); + if (pDidInsert) + { + *pDidInsert = true; + } + } + + bucket.m_AddLock.UnlockWrite(); + return h; +} + +template +inline UtlTSHashHandle_t CUtlTSHash::Insert(KEYTYPE uiKey, ITSHashConstructor* pConstructor, bool* pDidInsert) +{ +#ifdef _DEBUG + if (m_ContentionCheck != 0) + { + DebuggerBreak(); + } +#endif + + if (pDidInsert) + { + *pDidInsert = false; + } + + UtlTSHashHandle_t h = Find(uiKey); + if (h != InvalidHandle()) + return h; + + int iBucket = HashFuncs::Hash(uiKey, BUCKET_MASK); + HashBucket_t& bucket = m_aBuckets[iBucket]; + bucket.m_AddLock.LockForWrite(); + + h = Find(uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst); + if (h == InvalidHandle()) + { + h = InsertUncommitted(uiKey, bucket); + pConstructor->Construct(&Element(h)); + if (pDidInsert) + { + *pDidInsert = true; + } + } + + bucket.m_AddLock.UnlockWrite(); + return h; +} + + +template +inline UtlTSHashHandle_t CUtlTSHash::FastInsert(KEYTYPE uiKey, const T& data) +{ +#ifdef _DEBUG + if (m_ContentionCheck != 0) + { + DebuggerBreak(); + } +#endif + int iBucket = HashFuncs::Hash(uiKey, BUCKET_MASK); + HashBucket_t& bucket = m_aBuckets[iBucket]; + bucket.m_AddLock.LockForWrite(); + UtlTSHashHandle_t h = InsertUncommitted(uiKey, bucket); + CopyConstruct(&Element(h), data); + bucket.m_AddLock.UnlockWrite(); + return h; +} + +template +inline UtlTSHashHandle_t CUtlTSHash::FastInsert(KEYTYPE uiKey, ITSHashConstructor* pConstructor) +{ +#ifdef _DEBUG + if (m_ContentionCheck != 0) + { + DebuggerBreak(); + } +#endif + int iBucket = HashFuncs::Hash(uiKey, BUCKET_MASK); + HashBucket_t& bucket = m_aBuckets[iBucket]; + bucket.m_AddLock.LockForWrite(); + UtlTSHashHandle_t h = InsertUncommitted(uiKey, bucket); + pConstructor->Construct(&Element(h)); + bucket.m_AddLock.UnlockWrite(); + return h; +} + + +template +inline void CUtlTSHash::Commit() +{ + if (!m_bNeedsCommit) + return; + +#ifdef _DEBUG + m_ContentionCheck++; +#endif + + for (int i = 0; i < BUCKET_COUNT; i++) + { + HashBucket_t& bucket = m_aBuckets[i]; + bucket.m_AddLock.LockForRead(); + bucket.m_pFirst = bucket.m_pFirstUncommitted; + bucket.m_AddLock.UnlockRead(); + } + + m_bNeedsCommit = false; + +#ifdef _DEBUG + m_ContentionCheck--; +#endif +} + + +template +inline void CUtlTSHash::FindAndRemove(KEYTYPE uiKey) +{ + if (m_EntryMemory.Count() == 0) + return; + +#ifdef _DEBUG + m_ContentionCheck++; +#endif + + int iBucket = HashFuncs::Hash(uiKey, BUCKET_MASK); + HashBucket_t& bucket = m_aBuckets[iBucket]; + bucket.m_AddLock.LockForWrite(); + + HashFixedData_t* pPrev = NULL; + for (HashFixedData_t* pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext) + { + if (!HashFuncs::Compare(pElement->m_uiKey, uiKey)) + continue; + + if (pPrev) + { + pPrev->m_pNext = pElement->m_pNext; + } + else + { + bucket.m_pFirstUncommitted = pElement->m_pNext; + } + + if (bucket.m_pFirst == pElement) + { + bucket.m_pFirst = bucket.m_pFirst->m_pNext; + } + + Destruct(&pElement->m_Data); + +#ifdef _DEBUG + memset(pElement, 0xDD, sizeof(HashFixedData_t)); +#endif + + m_EntryMemory.Free(pElement); + + break; + } + + bucket.m_AddLock.UnlockWrite(); + +#ifdef _DEBUG + m_ContentionCheck--; +#endif +} + + +template +inline void CUtlTSHash::RemoveAll(void) +{ + m_bNeedsCommit = false; + if (m_EntryMemory.Count() == 0) + return; + +#ifdef _DEBUG + m_ContentionCheck++; +#endif + + for (int i = 0; i < BUCKET_COUNT; i++) + { + HashBucket_t& bucket = m_aBuckets[i]; + + bucket.m_AddLock.LockForWrite(); + + for (HashFixedData_t* pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext) + { + Destruct(&pElement->m_Data); + } + + bucket.m_pFirst = NULL; + bucket.m_pFirstUncommitted = NULL; + bucket.m_AddLock.UnlockWrite(); + } + + m_EntryMemory.Clear(); + +#ifdef _DEBUG + m_ContentionCheck--; +#endif +} + +template +inline UtlTSHashHandle_t CUtlTSHash::Find(KEYTYPE uiKey, HashFixedData_t* pFirstElement, HashFixedData_t* pLastElement) +{ +#ifdef _DEBUG + if (m_ContentionCheck != 0) + { + DebuggerBreak(); + } +#endif + + for (HashFixedData_t* pElement = pFirstElement; pElement != pLastElement; pElement = pElement->m_pNext) + { + if (HashFuncs::Compare(pElement->m_uiKey, uiKey)) + return (UtlTSHashHandle_t)pElement; + } + return InvalidHandle(); +} + + +template +inline UtlTSHashHandle_t CUtlTSHash::Find(KEYTYPE uiKey) +{ + int iBucket = HashFuncs::Hash(uiKey, BUCKET_MASK); + const HashBucket_t& bucket = m_aBuckets[iBucket]; + UtlTSHashHandle_t h = Find(uiKey, bucket.m_pFirst, NULL); + if (h != InvalidHandle()) + return h; + + bucket.m_AddLock.LockForRead(); + h = Find(uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst); + bucket.m_AddLock.UnlockRead(); + + return h; +} + + +template +inline T& CUtlTSHash::Element(UtlTSHashHandle_t hHash) +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +template +inline T const& CUtlTSHash::Element(UtlTSHashHandle_t hHash) const +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +template +inline T& CUtlTSHash::operator[](UtlTSHashHandle_t hHash) +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + +template +inline T const& CUtlTSHash::operator[](UtlTSHashHandle_t hHash) const +{ + return ((HashFixedData_t*)hHash)->m_Data; +} + + +template +inline KEYTYPE CUtlTSHash::GetID(UtlTSHashHandle_t hHash) const +{ + return ((HashFixedData_t*)hHash)->m_uiKey; +} + + +template +inline UtlTSHashHandle_t CUtlTSHash::ElementPtrToHandle(T* pElement) const +{ + Assert(pElement); + HashFixedData_t* pFixedData = (HashFixedData_t*)((uint8*)pElement - offsetof(HashFixedData_t, m_Data)); + Assert(m_EntryMemory.IsAllocationWithinPool(pFixedData)); + return (UtlTSHashHandle_t)pFixedData; +} + + +#endif +``` + +`SpyCustom/sdk/utlvector.h`: + +```h +#ifndef UTLVECTOR_H +#define UTLVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include +#include "platform.h" +#include "dbg.h" +#include "threadtools.h" +#include "utlmemory.h" +#include "utlblockmemory.h" +#include "strtools.h" +#include "random.h" + +#define FOR_EACH_VEC( vecName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ ) +#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \ + for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- ) + + +template< class T, class A = CUtlMemory > +class CUtlVector +{ + typedef A CAllocator; +public: + typedef T ElemType_t; + + CUtlVector(int growSize = 0, int initSize = 0); + CUtlVector(T* pMemory, int allocationCount, int numElements = 0); + ~CUtlVector(); + + CUtlVector& operator=(const CUtlVector& other); + + T& operator[](int i); + const T& operator[](int i) const; + T& Element(int i); + const T& Element(int i) const; + T& Head(); + const T& Head() const; + T& Tail(); + const T& Tail() const; + + T* Base() { return m_Memory.Base(); } + const T* Base() const { return m_Memory.Base(); } + int Count() const; + bool IsValidIndex(int i) const; + static int InvalidIndex(); + int AddToHead(); + int AddToTail(); + int InsertBefore(int elem); + int InsertAfter(int elem); + int AddToHead(const T& src); + int AddToTail(const T& src); + int InsertBefore(int elem, const T& src); + int InsertAfter(int elem, const T& src); + int AddMultipleToHead(int num); + int AddMultipleToTail(int num); + int AddMultipleToTail(int num, const T* pToCopy); + int InsertMultipleBefore(int elem, int num); + int InsertMultipleBefore(int elem, int num, const T* pToCopy); + int InsertMultipleAfter(int elem, int num); + void SetSize(int size); + void SetCount(int count); + void SetCountNonDestructively(int count); + void CopyArray(const T* pArray, int size); + void Swap(CUtlVector< T, A >& vec); + int AddVectorToTail(CUtlVector const& src); + int GetOffset(const T& src) const; + void FillWithValue(const T& src); + bool HasElement(const T& src) const; + void EnsureCapacity(int num); + void EnsureCount(int num); + void FastRemove(int elem); + void Remove(int elem); + bool FindAndRemove(const T& src); + bool FindAndFastRemove(const T& src); + void RemoveMultiple(int elem, int num); + void RemoveMultipleFromHead(int num); + void RemoveMultipleFromTail(int num); + void RemoveAll(); + void Purge(); + void PurgeAndDeleteElements(); + void Compact(); + void SetGrowSize(int size) { m_Memory.SetGrowSize(size); } + int NumAllocated() const; + void Sort(int(__cdecl* pfnCompare)(const T*, const T*)); + +protected: + CUtlVector(CUtlVector const& vec) { assert(0); } + + void GrowVector(int num = 1); + + void ShiftElementsRight(int elem, int num = 1); + void ShiftElementsLeft(int elem, int num = 1); + +public: + CAllocator m_Memory; + int m_Size; + + T* m_pElements; + + inline void ResetDbgInfo() + { + m_pElements = Base(); + } +}; +template < class T > +class CUtlBlockVector : public CUtlVector< T, CUtlBlockMemory< T, int > > +{ +public: + explicit CUtlBlockVector(int growSize = 0, int initSize = 0) + : CUtlVector< T, CUtlBlockMemory< T, int > >(growSize, initSize) {} + +private: + typedef CUtlVector< T, CUtlBlockMemory< T, int > > Base; + typename Base::iterator begin(); + typename Base::const_iterator begin() const; + typename Base::iterator end(); + typename Base::const_iterator end() const; +}; + +template< class BASE_UTLVECTOR, class MUTEX_TYPE = CThreadFastMutex > +class CUtlVectorMT : public BASE_UTLVECTOR, public MUTEX_TYPE +{ + typedef BASE_UTLVECTOR BaseClass; +public: + MUTEX_TYPE Mutex_t; + + explicit CUtlVectorMT(int growSize = 0, int initSize = 0) : BaseClass(growSize, initSize) {} + explicit CUtlVectorMT(typename BaseClass::ElemType_t* pMemory, int numElements) : BaseClass(pMemory, numElements) {} +}; + + +template< class T, size_t MAX_SIZE > +class CUtlVectorFixed : public CUtlVector< T, CUtlMemoryFixed > +{ + typedef CUtlVector< T, CUtlMemoryFixed > BaseClass; +public: + + explicit CUtlVectorFixed(int growSize = 0, int initSize = 0) : BaseClass(growSize, initSize) {} + explicit CUtlVectorFixed(T* pMemory, int numElements) : BaseClass(pMemory, numElements) {} +}; + + +template< class T, size_t MAX_SIZE > +class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable > +{ + typedef CUtlVector< T, CUtlMemoryFixedGrowable > BaseClass; + +public: + explicit CUtlVectorFixedGrowable(int growSize = 0) : BaseClass(growSize, MAX_SIZE) {} +}; + + +template< class T > +class CUtlVectorConservative : public CUtlVector< T, CUtlMemoryConservative > +{ + typedef CUtlVector< T, CUtlMemoryConservative > BaseClass; +public: + + explicit CUtlVectorConservative(int growSize = 0, int initSize = 0) : BaseClass(growSize, initSize) {} + explicit CUtlVectorConservative(T* pMemory, int numElements) : BaseClass(pMemory, numElements) {} +}; + + +#pragma warning(push) +#pragma warning(disable : 4200) +#pragma warning(disable : 4815 ) + +class CUtlVectorUltraConservativeAllocator +{ +public: + static void* Alloc(size_t nSize) + { + return malloc(nSize); + } + + static void* Realloc(void* pMem, size_t nSize) + { + return realloc(pMem, nSize); + } + + static void Free(void* pMem) + { + free(pMem); + } + + static size_t GetSize(void* pMem) + { + return mallocsize(pMem); + } + +}; + +template +class CUtlVectorUltraConservative : private A +{ +public: + CUtlVectorUltraConservative() + { + m_pData = StaticData(); + } + + ~CUtlVectorUltraConservative() + { + RemoveAll(); + } + + int Count() const + { + return m_pData->m_Size; + } + + static int InvalidIndex() + { + return -1; + } + + inline bool IsValidIndex(int i) const + { + return (i >= 0) && (i < Count()); + } + + T& operator[](int i) + { + Assert(IsValidIndex(i)); + return m_pData->m_Elements[i]; + } + + const T& operator[](int i) const + { + Assert(IsValidIndex(i)); + return m_pData->m_Elements[i]; + } + + T& Element(int i) + { + Assert(IsValidIndex(i)); + return m_pData->m_Elements[i]; + } + + const T& Element(int i) const + { + Assert(IsValidIndex(i)); + return m_pData->m_Elements[i]; + } + + void EnsureCapacity(int num) + { + int nCurCount = Count(); + if (num <= nCurCount) + { + return; + } + if (m_pData == StaticData()) + { + m_pData = (Data_t*)A::Alloc(sizeof(int) + (num * sizeof(T))); + m_pData->m_Size = 0; + } + else + { + int nNeeded = sizeof(int) + (num * sizeof(T)); + int nHave = A::GetSize(m_pData); + if (nNeeded > nHave) + { + m_pData = (Data_t*)A::Realloc(m_pData, nNeeded); + } + } + } + + int AddToTail(const T& src) + { + int iNew = Count(); + EnsureCapacity(Count() + 1); + m_pData->m_Elements[iNew] = src; + m_pData->m_Size++; + return iNew; + } + + void RemoveAll() + { + if (Count()) + { + for (int i = m_pData->m_Size; --i >= 0; ) + { + Destruct(&m_pData->m_Elements[i]); + } + } + if (m_pData != StaticData()) + { + A::Free(m_pData); + m_pData = StaticData(); + + } + } + + void PurgeAndDeleteElements() + { + if (m_pData != StaticData()) + { + for (int i = 0; i < m_pData->m_Size; i++) + { + delete Element(i); + } + RemoveAll(); + } + } + + void FastRemove(int elem) + { + Assert(IsValidIndex(elem)); + + Destruct(&Element(elem)); + if (Count() > 0) + { + if (elem != m_pData->m_Size - 1) + memcpy(&Element(elem), &Element(m_pData->m_Size - 1), sizeof(T)); + --m_pData->m_Size; + } + if (!m_pData->m_Size) + { + A::Free(m_pData); + m_pData = StaticData(); + } + } + + void Remove(int elem) + { + Destruct(&Element(elem)); + ShiftElementsLeft(elem); + --m_pData->m_Size; + if (!m_pData->m_Size) + { + A::Free(m_pData); + m_pData = StaticData(); + } + } + + int Find(const T& src) const + { + int nCount = Count(); + for (int i = 0; i < nCount; ++i) + { + if (Element(i) == src) + return i; + } + return -1; + } + + bool FindAndRemove(const T& src) + { + int elem = Find(src); + if (elem != -1) + { + Remove(elem); + return true; + } + return false; + } + + + bool FindAndFastRemove(const T& src) + { + int elem = Find(src); + if (elem != -1) + { + FastRemove(elem); + return true; + } + return false; + } + + struct Data_t + { + int m_Size; + T m_Elements[0]; + }; + + Data_t* m_pData; +private: + void ShiftElementsLeft(int elem, int num = 1) + { + int Size = Count(); + Assert(IsValidIndex(elem) || (Size == 0) || (num == 0)); + int numToMove = Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + Q_memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T)); + +#ifdef _DEBUG + Q_memset(&Element(Size - num), 0xDD, num * sizeof(T)); +#endif + } + } + + + + static Data_t* StaticData() + { + static Data_t staticData; + Assert(staticData.m_Size == 0); + return &staticData; + } +}; + +#pragma warning(pop) + + +template< typename T, typename A = CUtlMemory > +class CCopyableUtlVector : public CUtlVector< T, A > +{ + typedef CUtlVector< T, A > BaseClass; +public: + explicit CCopyableUtlVector(int growSize = 0, int initSize = 0) : BaseClass(growSize, initSize) {} + explicit CCopyableUtlVector(T* pMemory, int numElements) : BaseClass(pMemory, numElements) {} + virtual ~CCopyableUtlVector() {} + CCopyableUtlVector(CCopyableUtlVector const& vec) { this->CopyArray(vec.Base(), vec.Count()); } +}; + +template< typename T, class A > +inline CUtlVector::CUtlVector(int growSize, int initSize) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector::CUtlVector(T* pMemory, int allocationCount, int numElements) : + m_Memory(pMemory, allocationCount), m_Size(numElements) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector::~CUtlVector() +{ + Purge(); +} + +template< typename T, class A > +inline CUtlVector& CUtlVector::operator=(const CUtlVector& other) +{ + int nCount = other.Count(); + SetSize(nCount); + for (int i = 0; i < nCount; i++) + { + (*this)[i] = other[i]; + } + return *this; +} + +#ifdef STAGING_ONLY +inline void StagingUtlVectorBoundsCheck(int i, int size) +{ + if ((unsigned)i >= (unsigned)size) + { + Msg("Array access error: %d / %d\n", i, size); + DebuggerBreak(); + } +} + +#else +#define StagingUtlVectorBoundsCheck( _i, _size ) +#endif + +template< typename T, class A > +inline T& CUtlVector::operator[](int i) +{ + Assert((unsigned)i < (unsigned)m_Size); + StagingUtlVectorBoundsCheck(i, m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline const T& CUtlVector::operator[](int i) const +{ + Assert((unsigned)i < (unsigned)m_Size); + StagingUtlVectorBoundsCheck(i, m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline T& CUtlVector::Element(int i) +{ + Assert((unsigned)i < (unsigned)m_Size); + StagingUtlVectorBoundsCheck(i, m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline const T& CUtlVector::Element(int i) const +{ + Assert((unsigned)i < (unsigned)m_Size); + StagingUtlVectorBoundsCheck(i, m_Size); + return m_Memory[i]; +} + +template< typename T, class A > +inline T& CUtlVector::Head() +{ + Assert(m_Size > 0); + StagingUtlVectorBoundsCheck(0, m_Size); + return m_Memory[0]; +} + +template< typename T, class A > +inline const T& CUtlVector::Head() const +{ + Assert(m_Size > 0); + StagingUtlVectorBoundsCheck(0, m_Size); + return m_Memory[0]; +} + +template< typename T, class A > +inline T& CUtlVector::Tail() +{ + Assert(m_Size > 0); + StagingUtlVectorBoundsCheck(0, m_Size); + return m_Memory[m_Size - 1]; +} + +template< typename T, class A > +inline const T& CUtlVector::Tail() const +{ + Assert(m_Size > 0); + StagingUtlVectorBoundsCheck(0, m_Size); + return m_Memory[m_Size - 1]; +} + + +template< typename T, class A > +inline int CUtlVector::Count() const +{ + return m_Size; +} + +template< typename T, class A > +inline bool CUtlVector::IsValidIndex(int i) const +{ + return (i >= 0) && (i < m_Size); +} + + +template< typename T, class A > +inline int CUtlVector::InvalidIndex() +{ + return -1; +} + + +template< typename T, class A > +void CUtlVector::GrowVector(int num) +{ + if (m_Size + num > m_Memory.NumAllocated()) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow(m_Size + num - m_Memory.NumAllocated()); + } + + m_Size += num; + ResetDbgInfo(); +} + + +template< typename T, class A > +void CUtlVector::Sort(int(__cdecl* pfnCompare)(const T*, const T*)) +{ + typedef int(__cdecl* QSortCompareFunc_t)(const void*, const void*); + if (Count() <= 1) + return; + + if (Base()) + { + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); + } + else + { + Assert(0); + for (int i = m_Size - 1; i >= 0; --i) + { + for (int j = 1; j <= i; ++j) + { + if (pfnCompare(&Element(j - 1), &Element(j)) < 0) + { + V_swap(Element(j - 1), Element(j)); + } + } + } + } +} + +template< typename T, class A > +void CUtlVector::EnsureCapacity(int num) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +template< typename T, class A > +void CUtlVector::EnsureCount(int num) +{ + if (Count() < num) + AddMultipleToTail(num - Count()); +} + + +template< typename T, class A > +void CUtlVector::ShiftElementsRight(int elem, int num) +{ + Assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + Q_memmove(&Element(elem + num), &Element(elem), numToMove * sizeof(T)); +} + +template< typename T, class A > +void CUtlVector::ShiftElementsLeft(int elem, int num) +{ + Assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + Q_memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T)); + +#ifdef _DEBUG + Q_memset(&Element(m_Size - num), 0xDD, num * sizeof(T)); +#endif + } +} + + +template< typename T, class A > +inline int CUtlVector::AddToHead() +{ + return InsertBefore(0); +} + +template< typename T, class A > +inline int CUtlVector::AddToTail() +{ + return InsertBefore(m_Size); +} + +template< typename T, class A > +inline int CUtlVector::InsertAfter(int elem) +{ + return InsertBefore(elem + 1); +} + +template< typename T, class A > +int CUtlVector::InsertBefore(int elem) +{ + Assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + Construct(&Element(elem)); + return elem; +} + + +template< typename T, class A > +inline int CUtlVector::AddToHead(const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(0, src); +} + +template< typename T, class A > +inline int CUtlVector::AddToTail(const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(m_Size, src); +} + +template< typename T, class A > +inline int CUtlVector::InsertAfter(int elem, const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + return InsertBefore(elem + 1, src); +} + +template< typename T, class A > +int CUtlVector::InsertBefore(int elem, const T& src) +{ + Assert((Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()))); + + Assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct(&Element(elem), src); + return elem; +} + + +template< typename T, class A > +inline int CUtlVector::AddMultipleToHead(int num) +{ + return InsertMultipleBefore(0, num); +} + +template< typename T, class A > +inline int CUtlVector::AddMultipleToTail(int num, const T* pToCopy) +{ + Assert((Base() == NULL) || !pToCopy || (pToCopy + num < Base()) || (pToCopy >= (Base() + Count()))); + + return InsertMultipleBefore(m_Size, num, pToCopy); +} + +template< typename T, class A > +int CUtlVector::InsertMultipleAfter(int elem, int num) +{ + return InsertMultipleBefore(elem + 1, num); +} + + +template< typename T, class A > +void CUtlVector::SetCount(int count) +{ + RemoveAll(); + AddMultipleToTail(count); +} + +template< typename T, class A > +inline void CUtlVector::SetSize(int size) +{ + SetCount(size); +} + +template< typename T, class A > +void CUtlVector::SetCountNonDestructively(int count) +{ + int delta = count - m_Size; + if (delta > 0) AddMultipleToTail(delta); + else if (delta < 0) RemoveMultipleFromTail(-delta); +} + +template< typename T, class A > +void CUtlVector::CopyArray(const T* pArray, int size) +{ + Assert((Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()))); + + SetSize(size); + for (int i = 0; i < size; i++) + { + (*this)[i] = pArray[i]; + } +} + +template< typename T, class A > +void CUtlVector::Swap(CUtlVector< T, A >& vec) +{ + m_Memory.Swap(vec.m_Memory); + V_swap(m_Size, vec.m_Size); + +#ifndef _X360 + V_swap(m_pElements, vec.m_pElements); +#endif +} + +template< typename T, class A > +int CUtlVector::AddVectorToTail(CUtlVector const& src) +{ + Assert(&src != this); + + int base = Count(); + + AddMultipleToTail(src.Count()); + + for (int i = 0; i < src.Count(); i++) + { + (*this)[base + i] = src[i]; + } + + return base; +} + +template< typename T, class A > +inline int CUtlVector::InsertMultipleBefore(int elem, int num, const T* pToInsert) +{ + if (num == 0) + return elem; + + Assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(num); + ShiftElementsRight(elem, num); + + for (int i = 0; i < num; ++i) + Construct(&Element(elem + i)); + + if (pToInsert) + { + for (int i = 0; i < num; i++) + { + Element(elem + i) = pToInsert[i]; + } + } + + return elem; +} + + +template< typename T, class A > +int CUtlVector::GetOffset(const T& src) const +{ + return -1; +} +template< typename T, class A > +bool CUtlVector::HasElement(const T& src) const +{ + return (Find(src) >= 0); +} + + +template< typename T, class A > +void CUtlVector::FastRemove(int elem) +{ + Assert(IsValidIndex(elem)); + + Destruct(&Element(elem)); + if (m_Size > 0) + { + if (elem != m_Size - 1) + memcpy(reinterpret_cast(&Element(elem)), reinterpret_cast(&Element(m_Size - 1)), sizeof(T)); + --m_Size; + } +} + +template< typename T, class A > +void CUtlVector::Remove(int elem) +{ + Destruct(&Element(elem)); + ShiftElementsLeft(elem); + --m_Size; +} + +template< typename T, class A > +bool CUtlVector::FindAndRemove(const T& src) +{ + int elem = GetOffset(src); + if (elem != -1) + { + Remove(elem); + return true; + } + return false; +} + +template< typename T, class A > +bool CUtlVector::FindAndFastRemove(const T& src) +{ + int elem = Find(src); + if (elem != -1) + { + FastRemove(elem); + return true; + } + return false; +} + +template< typename T, class A > +void CUtlVector::RemoveMultiple(int elem, int num) +{ + Assert(elem >= 0); + Assert(elem + num <= Count()); + + for (int i = elem + num; --i >= elem; ) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveMultipleFromHead(int num) +{ + Assert(num <= Count()); + + for (int i = num; --i >= 0; ) + Destruct(&Element(i)); + + ShiftElementsLeft(0, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveMultipleFromTail(int num) +{ + Assert(num <= Count()); + + for (int i = m_Size - num; i < m_Size; i++) + Destruct(&Element(i)); + + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector::RemoveAll() +{ + for (int i = m_Size; --i >= 0; ) + { + Destruct(&Element(i)); + } + + m_Size = 0; +} + + +template< typename T, class A > +inline void CUtlVector::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + + +template< typename T, class A > +inline void CUtlVector::PurgeAndDeleteElements() +{ + for (int i = 0; i < m_Size; i++) + { + delete Element(i); + } + Purge(); +} + +template< typename T, class A > +inline void CUtlVector::Compact() +{ + m_Memory.Purge(m_Size); +} + +template< typename T, class A > +inline int CUtlVector::NumAllocated() const +{ + return m_Memory.NumAllocated(); +} + + +#ifdef DBGFLAG_VALIDATE +template< typename T, class A > +void CUtlVector::Validate(CValidator& validator, char* pchName) +{ + validator.Push(typeid(*this).name(), this, pchName); + + m_Memory.Validate(validator, "m_Memory"); + + validator.Pop(); +} +#endif + +template class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> > +{ +public: + ~CUtlVectorAutoPurge(void) + { + this->PurgeAndDeleteElements(); + } + +}; + +class CUtlStringList : public CUtlVectorAutoPurge< char*> +{ +public: + void CopyAndAddToTail(char const* pString) + { + char* pNewStr = new char[1 + strlen(pString)]; + V_strcpy(pNewStr, pString); + AddToTail(pNewStr); + } + + static int __cdecl SortFunc(char* const* sz1, char* const* sz2) + { + return strcmp(*sz1, *sz2); + } + + inline void PurgeAndDeleteElements() + { + for (int i = 0; i < m_Size; i++) + { + delete[] Element(i); + } + Purge(); + } + + ~CUtlStringList(void) + { + this->PurgeAndDeleteElements(); + } +}; + + + +class CSplitString : public CUtlVector > +{ +public: + CSplitString(const char* pString, const char* pSeparator); + CSplitString(const char* pString, const char** pSeparators, int nSeparators); + ~CSplitString(); +private: + void Construct(const char* pString, const char** pSeparators, int nSeparators); + void PurgeAndDeleteElements(); +private: + char* m_szBuffer; +}; + + +#endif +``` + +`SpyCustom/sdk/valve_minmax_on.h`: + +```h +#if !defined(POSIX) +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif +``` + +`SpyCustom/sdk/valve_off.h`: + +```h + +#ifdef STEAM + +#undef char + + +#undef malloc +#undef realloc +#undef _expand +#undef free + +#endif +``` + +`SpyCustom/sdk/valve_on.h`: + +```h + +#ifdef STEAM +#ifdef ENFORCE_WCHAR +#define char DontUseChar_SeeWcharOn.h +#endif + + +#define malloc( cub ) HEY_DONT_USE_MALLOC_USE_PVALLOC +#define realloc( pvOld, cub ) HEY_DONT_USE_REALLOC_USE_PVREALLOC +#define _expand( pvOld, cub ) HEY_DONT_USE_EXPAND_USE_PVEXPAND +#define free( pv ) HEY_DONT_USE_FREE_USE_FREEPV + +#endif +``` + +`SpyCustom/sdk/vcollide.h`: + +```h +#ifndef VCOLLIDE_H +#define VCOLLIDE_H +#ifdef _WIN32 +#pragma once +#endif + +class CPhysCollide; + +struct vcollide_t +{ + unsigned short solidCount : 15; + unsigned short isPacked : 1; + unsigned short descSize; + CPhysCollide** solids; + char* pKeyValues; +}; + +#endif +``` + +`SpyCustom/sdk/vcrmode.h`: + +```h +#ifndef VCRMODE_H +#define VCRMODE_H + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" +#define VCRFILE_VERSION 2 + + +typedef enum +{ + VCREvent_Sys_FloatTime = 0, + VCREvent_recvfrom, + VCREvent_SyncToken, + VCREvent_GetCursorPos, + VCREvent_SetCursorPos, + VCREvent_ScreenToClient, + VCREvent_Cmd_Exec, + VCREvent_CmdLine, + VCREvent_RegOpenKeyEx, + VCREvent_RegSetValueEx, + VCREvent_RegQueryValueEx, + VCREvent_RegCreateKeyEx, + VCREvent_RegCloseKey, + VCREvent_PeekMessage, + VCREvent_GameMsg, + VCREvent_GetNumberOfConsoleInputEvents, + VCREvent_ReadConsoleInput, + VCREvent_GetKeyState, + VCREvent_recv, + VCREvent_send, + VCREvent_Generic, + VCREvent_CreateThread, + VCREvent_WaitForSingleObject, + VCREvent_EnterCriticalSection, + VCREvent_Time, + VCREvent_LocalTime, + VCREvent_GenericString, + VCREvent_NUMEVENTS +} VCREvent; + +#include "dbg.h" + +#ifdef POSIX +DBG_INTERFACE const char* BuildCmdLine(int argc, char** argv, bool fAddSteam = true); +tchar* GetCommandLine(); +#endif + +#ifdef _X360 +#define NO_VCR 1 +#endif + + +#ifndef NO_VCR +#define NOVCR(x) \ +{\ + VCRSetEnabled(0);\ + x;\ + VCRSetEnabled(1);\ +} +#else +#define NOVCR(x) \ +{\ + x;\ +} +#endif + + +struct InputEvent_t; + + +enum VCRMode_t +{ + VCR_Invalid = -1, + VCR_Disabled = 0, + VCR_Record, + VCR_Playback +}; + + +abstract_class IVCRHelpers +{ +public: + virtual void ErrorMessage(const tchar * pMsg) = 0; + virtual void* GetMainWindow() = 0; +}; + + +abstract_class IVCRTrace +{ +public: + virtual VCREvent ReadEvent() = 0; + virtual void Read(void* pDest, int size) = 0; +}; + +typedef struct VCR_s +{ + int (*Start)(tchar const* pFilename, bool bRecord, IVCRHelpers* pHelpers); + void (*End)(); + + IVCRTrace* (*GetVCRTraceInterface)(); + + VCRMode_t(*GetMode)(); + + void (*SetEnabled)(int bEnabled); + + void (*SyncToken)(tchar const* pToken); + + double (*Hook_Sys_FloatTime)(double time); + + int (*Hook_PeekMessage)( + struct tagMSG* msg, + void* hWnd, + unsigned int wMsgFilterMin, + unsigned int wMsgFilterMax, + unsigned int wRemoveMsg + ); + + void (*Hook_RecordGameMsg)(const InputEvent_t& event); + void (*Hook_RecordEndGameMsg)(); + + bool (*Hook_PlaybackGameMsg)(InputEvent_t* pEvent); + + int (*Hook_recvfrom)(int s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen); + + void (*Hook_GetCursorPos)(struct tagPOINT* pt); + void (*Hook_ScreenToClient)(void* hWnd, struct tagPOINT* pt); + + void (*Hook_Cmd_Exec)(tchar** f); + + tchar* (*Hook_GetCommandLine)(); + + long (*Hook_RegOpenKeyEx)(void* hKey, const tchar* lpSubKey, unsigned long ulOptions, unsigned long samDesired, void* pHKey); + long (*Hook_RegSetValueEx)(void* hKey, tchar const* lpValueName, unsigned long Reserved, unsigned long dwType, uint8 const* lpData, unsigned long cbData); + long (*Hook_RegQueryValueEx)(void* hKey, tchar const* lpValueName, unsigned long* lpReserved, unsigned long* lpType, uint8* lpData, unsigned long* lpcbData); + long (*Hook_RegCreateKeyEx)(void* hKey, tchar const* lpSubKey, unsigned long Reserved, tchar* lpClass, unsigned long dwOptions, unsigned long samDesired, void* lpSecurityAttributes, void* phkResult, unsigned long* lpdwDisposition); + void (*Hook_RegCloseKey)(void* hKey); + + int (*Hook_GetNumberOfConsoleInputEvents)(void* hInput, unsigned long* pNumEvents); + + int (*Hook_ReadConsoleInput)(void* hInput, void* pRecs, int nMaxRecs, unsigned long* pNumRead); + + + void (*Hook_LocalTime)(struct tm* today); + + short (*Hook_GetKeyState)(int nVirtKey); + + int (*Hook_recv)(int s, char* buf, int len, int flags); + int (*Hook_send)(int s, const char* buf, int len, int flags); + + void (*GenericRecord)(const tchar* pEventName, const void* pData, int len); + + + int (*GenericPlayback)(const tchar* pEventName, void* pOutData, int maxLen, bool bForceLenSame); + + void (*GenericValue)(const tchar* pEventName, void* pData, int maxLen); + + double (*GetPercentCompleted)(); + + void* (*Hook_CreateThread)( + void* lpThreadAttributes, + unsigned long dwStackSize, + void* lpStartAddress, + void* lpParameter, + unsigned long dwCreationFlags, + unsigned long* lpThreadID); + + unsigned long (*Hook_WaitForSingleObject)( + void* handle, + unsigned long dwMilliseconds); + + void (*Hook_EnterCriticalSection)(void* pCS); + + void (*Hook_Time)(long* pTime); + + void (*GenericString)(const char* pEventName, const char* pString); + + void (*GenericValueVerify)(const tchar* pEventName, const void* pData, int maxLen); + + unsigned long (*Hook_WaitForMultipleObjects)(uint32 nHandles, const void** pHandles, int bWaitAll, uint32 timeout); + +} VCR_t; + +#ifndef NO_VCR + +PLATFORM_INTERFACE VCR_t* g_pVCR; + +#endif + + +#ifndef NO_VCR +#define VCRStart g_pVCR->Start +#define VCREnd g_pVCR->End +#define VCRGetVCRTraceInterface g_pVCR->GetVCRTraceInterface +#define VCRGetMode g_pVCR->GetMode +#define VCRSetEnabled g_pVCR->SetEnabled +#define VCRSyncToken g_pVCR->SyncToken +#define VCRGenericString g_pVCR->GenericString +#define VCRGenericValueVerify g_pVCR->GenericValueVerify +#define VCRHook_Sys_FloatTime g_pVCR->Hook_Sys_FloatTime +#define VCRHook_PeekMessage g_pVCR->Hook_PeekMessage +#define VCRHook_RecordGameMsg g_pVCR->Hook_RecordGameMsg +#define VCRHook_RecordEndGameMsg g_pVCR->Hook_RecordEndGameMsg +#define VCRHook_PlaybackGameMsg g_pVCR->Hook_PlaybackGameMsg +#define VCRHook_recvfrom g_pVCR->Hook_recvfrom +#define VCRHook_GetCursorPos g_pVCR->Hook_GetCursorPos +#define VCRHook_ScreenToClient g_pVCR->Hook_ScreenToClient +#define VCRHook_Cmd_Exec g_pVCR->Hook_Cmd_Exec +#define VCRHook_GetCommandLine g_pVCR->Hook_GetCommandLine +#define VCRHook_RegOpenKeyEx g_pVCR->Hook_RegOpenKeyEx +#define VCRHook_RegSetValueEx g_pVCR->Hook_RegSetValueEx +#define VCRHook_RegQueryValueEx g_pVCR->Hook_RegQueryValueEx +#define VCRHook_RegCreateKeyEx g_pVCR->Hook_RegCreateKeyEx +#define VCRHook_RegCloseKey g_pVCR->Hook_RegCloseKey +#define VCRHook_GetNumberOfConsoleInputEvents g_pVCR->Hook_GetNumberOfConsoleInputEvents +#define VCRHook_ReadConsoleInput g_pVCR->Hook_ReadConsoleInput +#define VCRHook_LocalTime g_pVCR->Hook_LocalTime +#define VCRHook_GetKeyState g_pVCR->Hook_GetKeyState +#define VCRHook_recv g_pVCR->Hook_recv +#define VCRHook_send g_pVCR->Hook_send +#define VCRGenericRecord g_pVCR->GenericRecord +#define VCRGenericPlayback g_pVCR->GenericPlayback +#define VCRGenericValue g_pVCR->GenericValue +#define VCRGetPercentCompleted g_pVCR->GetPercentCompleted +#define VCRHook_CreateThread g_pVCR->Hook_CreateThread +#define VCRHook_WaitForSingleObject g_pVCR->Hook_WaitForSingleObject +#define VCRHook_EnterCriticalSection g_pVCR->Hook_EnterCriticalSection +#define VCRHook_Time g_pVCR->Hook_Time +#define VCRHook_WaitForMultipleObjects( a, b, c, d) g_pVCR->Hook_WaitForMultipleObjects( a, (const void **)b, c, d) +#else +#define VCRStart( a, b, c ) (1) +#define VCREnd ((void)(0)) +#define VCRGetVCRTraceInterface (NULL) +#define VCRGetMode() (VCR_Disabled) +#define VCRSetEnabled( a ) ((void)(0)) +#define VCRSyncToken( a ) ((void)(0)) +#define VCRGenericRecord MUST_IFDEF_OUT_GenericRecord +#define VCRGenericPlayback MUST_IFDEF_OUT_GenericPlayback +#define VCRGenericValue MUST_IFDEF_OUT_GenericValue +#define VCRGenericString MUST_IFDEF_OUT_GenericString +#define VCRGenericValueVerify MUST_IFDEF_OUT_GenericValueVerify +#define VCRGetPercentCompleted() (0.0f) +#define VCRHook_Sys_FloatTime Sys_FloatTime +#define VCRHook_PeekMessage PeekMessage +#define VCRHook_RecordGameMsg RecordGameMsg +#define VCRHook_RecordEndGameMsg RecordEndGameMsg +#define VCRHook_PlaybackGameMsg PlaybackGameMsg +#define VCRHook_recvfrom recvfrom +#define VCRHook_GetCursorPos GetCursorPos +#define VCRHook_ScreenToClient ScreenToClient +#define VCRHook_Cmd_Exec( a ) ((void)(0)) +#define VCRHook_GetCommandLine GetCommandLine +#define VCRHook_RegOpenKeyEx RegOpenKeyEx +#define VCRHook_RegSetValueEx RegSetValueEx +#define VCRHook_RegQueryValueEx RegQueryValueEx +#define VCRHook_RegCreateKeyEx RegCreateKeyEx +#define VCRHook_RegCloseKey RegCloseKey +#define VCRHook_GetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents +#define VCRHook_ReadConsoleInput ReadConsoleInput +#define VCRHook_LocalTime( a ) memset(a, 0, sizeof(*a)); +#define VCRHook_GetKeyState GetKeyState +#define VCRHook_recv recv +#define VCRHook_send send +#if defined( _X360 ) +#define VCRHook_CreateThread CreateThread +#else +#define VCRHook_CreateThread (void*)_beginthreadex +#endif +#define VCRHook_WaitForSingleObject WaitForSingleObject +#define VCRHook_EnterCriticalSection EnterCriticalSection +#define VCRHook_WaitForMultipleObjects( a, b, c, d) WaitForMultipleObjects( a, (const HANDLE *)b, c, d) +#define VCRHook_Time Time +#endif + +#endif +``` + +`SpyCustom/sdk/vector.h`: + +```h +#ifndef VECTOR_H +#define VECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +#include "basetypes.h" + +#include + +#ifndef _X360 +#include +#endif + +#include "dbg.h" +#include "threadtools.h" +#include "vector2d.h" +#include "math_pfns.h" +#include "minmax.h" + +#include +#include +//#include . +#define pi_v 3.14159265358979323846 +template constexpr auto deg2rad(T degrees) noexcept { return degrees * (static_cast(pi_v) / static_cast(180)); } +template constexpr auto rad2deg(T radians) noexcept { return radians * (static_cast(180) / static_cast(pi_v)); } + + +#define X_INDEX 0 +#define Y_INDEX 1 +#define Z_INDEX 2 + + +#ifdef VECTOR_PARANOIA +#define CHECK_VALID( _v) Assert( (_v).IsValid() ) +#else +#ifdef GNUC +#define CHECK_VALID( _v) +#else +#define CHECK_VALID( _v) 0 +#endif +#endif + +#define VecToString(v) (static_cast(CFmtStr("(%f, %f, %f)", (v).x, (v).y, (v).z))) + +class VectorByValue; +class QAngle; + +class Vector +{ +public: + vec_t x, y, z; + + Vector(void); + Vector(vec_t X, vec_t Y, vec_t Z); + inline Vector(QAngle v); + + explicit Vector(vec_t XYZ); + + void Init(vec_t ix = 0.0f, vec_t iy = 0.0f, vec_t iz = 0.0f); + bool IsValid() const; + void Invalidate(); + + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t* Base(); + vec_t const* Base() const; + + Vector2D& AsVector2D(); + const Vector2D& AsVector2D() const; + + void Random(vec_t minVal, vec_t maxVal); + inline void Zero(); + + bool operator==(const Vector& v) const; + bool operator!=(const Vector& v) const; + + FORCEINLINE Vector& operator+=(const Vector& v); + FORCEINLINE Vector& operator-=(const Vector& v); + FORCEINLINE Vector& operator*=(const Vector& v); + FORCEINLINE Vector& operator*=(float s); + FORCEINLINE Vector& operator/=(const Vector& v); + FORCEINLINE Vector& operator/=(float s); + FORCEINLINE Vector& operator+=(float fl); + FORCEINLINE Vector& operator-=(float fl); + + void Negate(); + + inline vec_t Length() const; + + FORCEINLINE vec_t LengthSqr(void) const + { + CHECK_VALID(*this); + return (x * x + y * y + z * z); + } + + bool IsZero(float tolerance = 0.01f) const + { + return (x > -tolerance && x < tolerance&& + y > -tolerance && y < tolerance&& + z > -tolerance && z < tolerance); + } + + vec_t NormalizeInPlace(); + Vector Normalized() const; + bool IsLengthGreaterThan(float val) const; + bool IsLengthLessThan(float val) const; + + FORCEINLINE bool WithinAABox(Vector const& boxmin, Vector const& boxmax); + + vec_t DistTo(const Vector& vOther) const; + + FORCEINLINE vec_t DistToSqr(const Vector& vOther) const + { + Vector delta; + + delta.x = x - vOther.x; + delta.y = y - vOther.y; + delta.z = z - vOther.z; + + return delta.LengthSqr(); + } + + void CopyToArray(float* rgfl) const; + + void MulAdd(const Vector& a, const Vector& b, float scalar); + + vec_t Dot(const Vector& vOther) const; + + Vector& operator=(const Vector& vOther); + + vec_t Length2D(void) const; + vec_t Length2DSqr(void) const; + + operator VectorByValue& () { return *((VectorByValue*)(this)); } + operator const VectorByValue& () const { return *((const VectorByValue*)(this)); } + +#ifndef VECTOR_NO_SLOW_OPERATIONS + Vector operator-(void) const; + + Vector operator+(const Vector& v) const; + Vector operator-(const Vector& v) const; + Vector operator*(const Vector& v) const; + Vector operator/(const Vector& v) const; + Vector operator*(float fl) const; + Vector operator/(float fl) const; + + Vector Cross(const Vector& vOther) const; + + Vector Min(const Vector& vOther) const; + Vector Max(const Vector& vOther) const; + +#else + +private: + Vector(const Vector& vOther); +#endif + + inline Vector toAngle() const + { + return Vector{ rad2deg(std::atan2(-z, std::hypot(x, y))), + rad2deg(std::atan2(y, x)), + 0.0f }; + } + + static auto fromAngle(const Vector& angle) + { + return Vector{ std::cos(deg2rad(angle.x)) * std::cos(deg2rad(angle.y)), + std::cos(deg2rad(angle.x)) * std::sin(deg2rad(angle.y)), + -std::sin(deg2rad(angle.x)) }; + } + + auto length2D() const noexcept + { + return std::sqrt(x * x + y * y); + } + + void Clamp(void) + { + if (this->x < -89.f) + this->x = -89.f; + + if (this->x > 89.f) + this->x = 89.f; + + while (this->y < -180.f) + this->y += 360.f; + + while (this->y > 180.f) + this->y -= 360.f; + + this->z = 0.f; + } + + + void Normalize() + { + this->x = std::isfinite(this->x) ? std::remainderf(this->x, 360.f) : 0.f; + this->y = std::isfinite(this->y) ? std::remainderf(this->y, 360.f) : 0.f; + this->z = std::clamp(this->z, -50.f, 50.f); + } + +}; + +FORCEINLINE void NetworkVarConstruct(Vector& v) { v.Zero(); } + + +#define USE_M64S ( ( !defined( _X360 ) ) ) + + + +class ALIGN8 ShortVector +{ +public: + + short x, y, z, w; + + void Init(short ix = 0, short iy = 0, short iz = 0, short iw = 0); + + +#if USE_M64S + __m64& AsM64() { return *(__m64*) & x; } + const __m64& AsM64() const { return *(const __m64*) & x; } +#endif + + void Set(const ShortVector& vOther); + void Set(const short ix, const short iy, const short iz, const short iw); + + short operator[](int i) const; + short& operator[](int i); + + short* Base(); + short const* Base() const; + + bool operator==(const ShortVector& v) const; + bool operator!=(const ShortVector& v) const; + + FORCEINLINE ShortVector& operator+=(const ShortVector& v); + FORCEINLINE ShortVector& operator-=(const ShortVector& v); + FORCEINLINE ShortVector& operator*=(const ShortVector& v); + FORCEINLINE ShortVector& operator*=(float s); + FORCEINLINE ShortVector& operator/=(const ShortVector& v); + FORCEINLINE ShortVector& operator/=(float s); + FORCEINLINE ShortVector operator*(float fl) const; + +private: + +} ALIGN8_POST; + + + + + + +class IntVector4D +{ +public: + + int x, y, z, w; + + void Init(int ix = 0, int iy = 0, int iz = 0, int iw = 0); + +#if USE_M64S + __m64& AsM64() { return *(__m64*) & x; } + const __m64& AsM64() const { return *(const __m64*) & x; } +#endif + + void Set(const IntVector4D& vOther); + void Set(const int ix, const int iy, const int iz, const int iw); + + int operator[](int i) const; + int& operator[](int i); + + int* Base(); + int const* Base() const; + + bool operator==(const IntVector4D& v) const; + bool operator!=(const IntVector4D& v) const; + + FORCEINLINE IntVector4D& operator+=(const IntVector4D& v); + FORCEINLINE IntVector4D& operator-=(const IntVector4D& v); + FORCEINLINE IntVector4D& operator*=(const IntVector4D& v); + FORCEINLINE IntVector4D& operator*=(float s); + FORCEINLINE IntVector4D& operator/=(const IntVector4D& v); + FORCEINLINE IntVector4D& operator/=(float s); + FORCEINLINE IntVector4D operator*(float fl) const; + +private: + +}; + + + +class VectorByValue : public Vector +{ +public: + VectorByValue(void) : Vector() {} + VectorByValue(vec_t X, vec_t Y, vec_t Z) : Vector(X, Y, Z) {} + VectorByValue(const VectorByValue& vOther) { *this = vOther; } +}; + + +class TableVector +{ +public: + vec_t x, y, z; + + operator Vector& () { return *((Vector*)(this)); } + operator const Vector& () const { return *((const Vector*)(this)); } + + inline vec_t& operator[](int i) + { + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; + } + + inline vec_t operator[](int i) const + { + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; + } +}; + + +class ALIGN16 VectorAligned : public Vector +{ +public: + inline VectorAligned(void) {}; + inline VectorAligned(vec_t X, vec_t Y, vec_t Z) + { + Init(X, Y, Z); + } + +#ifdef VECTOR_NO_SLOW_OPERATIONS + +private: + VectorAligned(const VectorAligned& vOther); + VectorAligned(const Vector& vOther); + +#else +public: + explicit VectorAligned(const Vector& vOther) + { + Init(vOther.x, vOther.y, vOther.z); + } + + VectorAligned& operator=(const Vector& vOther) + { + Init(vOther.x, vOther.y, vOther.z); + return *this; + } + +#endif + float w; +} ALIGN16_POST; + +FORCEINLINE void VectorClear(Vector& a); + +FORCEINLINE void VectorCopy(const Vector& src, Vector& dst); + +FORCEINLINE void VectorAdd(const Vector& a, const Vector& b, Vector& result); +FORCEINLINE void VectorSubtract(const Vector& a, const Vector& b, Vector& result); +FORCEINLINE void VectorMultiply(const Vector& a, vec_t b, Vector& result); +FORCEINLINE void VectorMultiply(const Vector& a, const Vector& b, Vector& result); +FORCEINLINE void VectorDivide(const Vector& a, vec_t b, Vector& result); +FORCEINLINE void VectorDivide(const Vector& a, const Vector& b, Vector& result); +inline void VectorScale(const Vector& in, vec_t scale, Vector& result); +void VectorMA(const Vector& start, float scale, const Vector& direction, Vector& dest); + +bool VectorsAreEqual(const Vector& src1, const Vector& src2, float tolerance = 0.0f); + +#define VectorExpand(v) (v).x, (v).y, (v).z + + +inline vec_t VectorLength(const Vector& v); + +FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b); + +void CrossProduct(const Vector& a, const Vector& b, Vector& result); + +void VectorMin(const Vector& a, const Vector& b, Vector& result); +void VectorMax(const Vector& a, const Vector& b, Vector& result); + +void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest); +Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t); + +FORCEINLINE Vector ReplicateToVector(float x) +{ + return Vector(x, x, x); +} + +FORCEINLINE bool PointWithinViewAngle(Vector const& vecSrcPosition, + Vector const& vecTargetPosition, + Vector const& vecLookDirection, float flCosHalfFOV) +{ + Vector vecDelta = vecTargetPosition - vecSrcPosition; + float cosDiff = DotProduct(vecLookDirection, vecDelta); + + if (cosDiff < 0) + return false; + + float flLen2 = vecDelta.LengthSqr(); + + return (cosDiff * cosDiff > flLen2 * flCosHalfFOV * flCosHalfFOV); + +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +Vector CrossProduct(const Vector& a, const Vector& b); + +Vector RandomVector(vec_t minVal, vec_t maxVal); + +#endif + +float RandomVectorInUnitSphere(Vector* pVector); +float RandomVectorInUnitCircle(Vector2D* pVector); + + + +inline Vector::Vector(void) +{ +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +#endif +#endif +} + +inline Vector::Vector(vec_t X, vec_t Y, vec_t Z) +{ + x = X; y = Y; z = Z; + CHECK_VALID(*this); +} + +inline Vector::Vector(vec_t XYZ) +{ + x = y = z = XYZ; + CHECK_VALID(*this); +} + +#if 0 +inline Vector::Vector(const Vector& vOther) +{ + CHECK_VALID(vOther); + x = vOther.x; y = vOther.y; z = vOther.z; +} +#endif + +inline void Vector::Init(vec_t ix, vec_t iy, vec_t iz) +{ + x = ix; y = iy; z = iz; + CHECK_VALID(*this); +} + +inline void Vector::Random(vec_t minVal, vec_t maxVal) +{ + x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + z = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + CHECK_VALID(*this); +} + +inline void Vector::Zero() +{ + x = y = z = 0.0f; +} + +inline void VectorClear(Vector& a) +{ + a.x = a.y = a.z = 0.0f; +} + +inline Vector& Vector::operator=(const Vector& vOther) +{ + CHECK_VALID(vOther); + x = vOther.x; y = vOther.y; z = vOther.z; + return *this; +} + + +inline vec_t& Vector::operator[](int i) +{ + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector::operator[](int i) const +{ + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; +} + + +inline vec_t* Vector::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector::Base() const +{ + return (vec_t const*)this; +} + +inline Vector2D& Vector::AsVector2D() +{ + return *(Vector2D*)this; +} + +inline const Vector2D& Vector::AsVector2D() const +{ + return *(const Vector2D*)this; +} + +inline bool Vector::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +inline void Vector::Invalidate() +{ + x = y = z = VEC_T_NAN; +} + +inline bool Vector::operator==(const Vector& src) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +inline bool Vector::operator!=(const Vector& src) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + + +FORCEINLINE void VectorCopy(const Vector& src, Vector& dst) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void Vector::CopyToArray(float* rgfl) const +{ + Assert(rgfl); + CHECK_VALID(*this); + rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; +} + +inline void Vector::Negate() +{ + CHECK_VALID(*this); + x = -x; y = -y; z = -z; +} + +FORCEINLINE Vector& Vector::operator+=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x += v.x; y += v.y; z += v.z; + return *this; +} + +FORCEINLINE Vector& Vector::operator-=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x -= v.x; y -= v.y; z -= v.z; + return *this; +} + +FORCEINLINE Vector& Vector::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator*=(const Vector& v) +{ + CHECK_VALID(v); + x *= v.x; + y *= v.y; + z *= v.z; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator+=(float fl) +{ + x += fl; + y += fl; + z += fl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator-=(float fl) +{ + x -= fl; + y -= fl; + z -= fl; + CHECK_VALID(*this); + return *this; +} + + + +FORCEINLINE Vector& Vector::operator/=(float fl) +{ + Assert(fl != 0.0f); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator/=(const Vector& v) +{ + CHECK_VALID(v); + Assert(v.x != 0.0f && v.y != 0.0f && v.z != 0.0f); + x /= v.x; + y /= v.y; + z /= v.z; + CHECK_VALID(*this); + return *this; +} + + + + +inline void ShortVector::Init(short ix, short iy, short iz, short iw) +{ + x = ix; y = iy; z = iz; w = iw; +} + +FORCEINLINE void ShortVector::Set(const ShortVector& vOther) +{ + x = vOther.x; + y = vOther.y; + z = vOther.z; + w = vOther.w; +} + +FORCEINLINE void ShortVector::Set(const short ix, const short iy, const short iz, const short iw) +{ + x = ix; + y = iy; + z = iz; + w = iw; +} + + +inline short ShortVector::operator[](int i) const +{ + Assert((i >= 0) && (i < 4)); + return ((short*)this)[i]; +} + +inline short& ShortVector::operator[](int i) +{ + Assert((i >= 0) && (i < 4)); + return ((short*)this)[i]; +} + +inline short* ShortVector::Base() +{ + return (short*)this; +} + +inline short const* ShortVector::Base() const +{ + return (short const*)this; +} + + +inline bool ShortVector::operator==(const ShortVector& src) const +{ + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool ShortVector::operator!=(const ShortVector& src) const +{ + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + + +FORCEINLINE ShortVector& ShortVector::operator+=(const ShortVector& v) +{ + x += v.x; y += v.y; z += v.z; w += v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator-=(const ShortVector& v) +{ + x -= v.x; y -= v.y; z -= v.z; w -= v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + w *= fl; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator*=(const ShortVector& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator/=(float fl) +{ + Assert(fl != 0.0f); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + w *= oofl; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator/=(const ShortVector& v) +{ + Assert(v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0); + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; + return *this; +} + +FORCEINLINE void ShortVectorMultiply(const ShortVector& src, float fl, ShortVector& res) +{ + Assert(IsFinite(fl)); + res.x = src.x * fl; + res.y = src.y * fl; + res.z = src.z * fl; + res.w = src.w * fl; +} + +FORCEINLINE ShortVector ShortVector::operator*(float fl) const +{ + ShortVector res; + ShortVectorMultiply(*this, fl, res); + return res; +} + + + + + + + +inline void IntVector4D::Init(int ix, int iy, int iz, int iw) +{ + x = ix; y = iy; z = iz; w = iw; +} + +FORCEINLINE void IntVector4D::Set(const IntVector4D& vOther) +{ + x = vOther.x; + y = vOther.y; + z = vOther.z; + w = vOther.w; +} + +FORCEINLINE void IntVector4D::Set(const int ix, const int iy, const int iz, const int iw) +{ + x = ix; + y = iy; + z = iz; + w = iw; +} + + +inline int IntVector4D::operator[](int i) const +{ + Assert((i >= 0) && (i < 4)); + return ((int*)this)[i]; +} + +inline int& IntVector4D::operator[](int i) +{ + Assert((i >= 0) && (i < 4)); + return ((int*)this)[i]; +} + +inline int* IntVector4D::Base() +{ + return (int*)this; +} + +inline int const* IntVector4D::Base() const +{ + return (int const*)this; +} + + +inline bool IntVector4D::operator==(const IntVector4D& src) const +{ + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool IntVector4D::operator!=(const IntVector4D& src) const +{ + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + + +FORCEINLINE IntVector4D& IntVector4D::operator+=(const IntVector4D& v) +{ + x += v.x; y += v.y; z += v.z; w += v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator-=(const IntVector4D& v) +{ + x -= v.x; y -= v.y; z -= v.z; w -= v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + w *= fl; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator*=(const IntVector4D& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator/=(float fl) +{ + Assert(fl != 0.0f); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + w *= oofl; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator/=(const IntVector4D& v) +{ + Assert(v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0); + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; + return *this; +} + +FORCEINLINE void IntVector4DMultiply(const IntVector4D& src, float fl, IntVector4D& res) +{ + Assert(IsFinite(fl)); + res.x = src.x * fl; + res.y = src.y * fl; + res.z = src.z * fl; + res.w = src.w * fl; +} + +FORCEINLINE IntVector4D IntVector4D::operator*(float fl) const +{ + IntVector4D res; + IntVector4DMultiply(*this, fl, res); + return res; +} + + + + +FORCEINLINE void VectorAdd(const Vector& a, const Vector& b, Vector& c) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x + b.x; + c.y = a.y + b.y; + c.z = a.z + b.z; +} + +FORCEINLINE void VectorSubtract(const Vector& a, const Vector& b, Vector& c) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x - b.x; + c.y = a.y - b.y; + c.z = a.z - b.z; +} + +FORCEINLINE void VectorMultiply(const Vector& a, vec_t b, Vector& c) +{ + CHECK_VALID(a); + Assert(IsFinite(b)); + c.x = a.x * b; + c.y = a.y * b; + c.z = a.z * b; +} + +FORCEINLINE void VectorMultiply(const Vector& a, const Vector& b, Vector& c) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; +} + +inline void VectorScale(const Vector& in, vec_t scale, Vector& result) +{ + VectorMultiply(in, scale, result); +} + + +FORCEINLINE void VectorDivide(const Vector& a, vec_t b, Vector& c) +{ + CHECK_VALID(a); + Assert(b != 0.0f); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; + c.z = a.z * oob; +} + +FORCEINLINE void VectorDivide(const Vector& a, const Vector& b, Vector& c) +{ + CHECK_VALID(a); + CHECK_VALID(b); + Assert((b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f)); + c.x = a.x / b.x; + c.y = a.y / b.y; + c.z = a.z / b.z; +} + +inline void Vector::MulAdd(const Vector& a, const Vector& b, float scalar) +{ + CHECK_VALID(a); + CHECK_VALID(b); + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; + z = a.z + b.z * scalar; +} + +inline void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest) +{ + CHECK_VALID(src1); + CHECK_VALID(src2); + dest.x = src1.x + (src2.x - src1.x) * t; + dest.y = src1.y + (src2.y - src1.y) * t; + dest.z = src1.z + (src2.z - src1.z) * t; +} + +inline Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t) +{ + Vector result; + VectorLerp(src1, src2, t, result); + return result; +} + +inline Vector& AllocTempVector() +{ + static Vector s_vecTemp[128]; + static CInterlockedInt s_nIndex; + + int nIndex; + for (;;) + { + int nOldIndex = s_nIndex; + nIndex = ((nOldIndex + 0x10001) & 0x7F); + + if (s_nIndex.AssignIf(nOldIndex, nIndex)) + { + break; + } + ThreadPause(); + } + return s_vecTemp[nIndex]; +} + + + +FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b) +{ + CHECK_VALID(a); + CHECK_VALID(b); + return(a.x * b.x + a.y * b.y + a.z * b.z); +} + +inline vec_t Vector::Dot(const Vector& vOther) const +{ + CHECK_VALID(vOther); + return DotProduct(*this, vOther); +} + +inline void CrossProduct(const Vector& a, const Vector& b, Vector& result) +{ + CHECK_VALID(a); + CHECK_VALID(b); + Assert(&a != &result); + Assert(&b != &result); + result.x = a.y * b.z - a.z * b.y; + result.y = a.z * b.x - a.x * b.z; + result.z = a.x * b.y - a.y * b.x; +} + +inline vec_t DotProductAbs(const Vector& v0, const Vector& v1) +{ + CHECK_VALID(v0); + CHECK_VALID(v1); + return FloatMakePositive(v0.x * v1.x) + FloatMakePositive(v0.y * v1.y) + FloatMakePositive(v0.z * v1.z); +} + +inline vec_t DotProductAbs(const Vector& v0, const float* v1) +{ + return FloatMakePositive(v0.x * v1[0]) + FloatMakePositive(v0.y * v1[1]) + FloatMakePositive(v0.z * v1[2]); +} + +inline vec_t VectorLength(const Vector& v) +{ + CHECK_VALID(v); + return (vec_t)FastSqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + + +inline vec_t Vector::Length(void) const +{ + CHECK_VALID(*this); + return VectorLength(*this); +} + + + +bool Vector::WithinAABox(Vector const& boxmin, Vector const& boxmax) +{ + return ( + (x >= boxmin.x) && (x <= boxmax.x) && + (y >= boxmin.y) && (y <= boxmax.y) && + (z >= boxmin.z) && (z <= boxmax.z) + ); +} + +inline vec_t Vector::DistTo(const Vector& vOther) const +{ + Vector delta; + VectorSubtract(*this, vOther, delta); + return delta.Length(); +} + + +inline bool VectorsAreEqual(const Vector& src1, const Vector& src2, float tolerance) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + return (FloatMakePositive(src1.z - src2.z) <= tolerance); +} + + +inline void ComputeClosestPoint(const Vector& vecStart, float flMaxDist, const Vector& vecTarget, Vector* pResult) +{ + Vector vecDelta; + VectorSubtract(vecTarget, vecStart, vecDelta); + float flDistSqr = vecDelta.LengthSqr(); + if (flDistSqr <= flMaxDist * flMaxDist) + { + *pResult = vecTarget; + } + else + { + vecDelta /= FastSqrt(flDistSqr); + VectorMA(vecStart, flMaxDist, vecDelta, *pResult); + } +} + + +inline void VectorAbs(const Vector& src, Vector& dst) +{ + dst.x = FloatMakePositive(src.x); + dst.y = FloatMakePositive(src.y); + dst.z = FloatMakePositive(src.z); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector Vector::Min(const Vector& vOther) const +{ + return Vector(x < vOther.x ? x : vOther.x, + y < vOther.y ? y : vOther.y, + z < vOther.z ? z : vOther.z); +} + +inline Vector Vector::Max(const Vector& vOther) const +{ + return Vector(x > vOther.x ? x : vOther.x, + y > vOther.y ? y : vOther.y, + z > vOther.z ? z : vOther.z); +} + + +inline Vector Vector::operator-(void) const +{ + return Vector(-x, -y, -z); +} + +inline Vector Vector::operator+(const Vector& v) const +{ + Vector res; + VectorAdd(*this, v, res); + return res; +} + +inline Vector Vector::operator-(const Vector& v) const +{ + Vector res; + VectorSubtract(*this, v, res); + return res; +} + +inline Vector Vector::operator*(float fl) const +{ + Vector res; + VectorMultiply(*this, fl, res); + return res; +} + +inline Vector Vector::operator*(const Vector& v) const +{ + Vector res; + VectorMultiply(*this, v, res); + return res; +} + +inline Vector Vector::operator/(float fl) const +{ + Vector res; + VectorDivide(*this, fl, res); + return res; +} + +inline Vector Vector::operator/(const Vector& v) const +{ + Vector res; + VectorDivide(*this, v, res); + return res; +} + +inline Vector operator*(float fl, const Vector& v) +{ + return v * fl; +} + +inline Vector Vector::Cross(const Vector& vOther) const +{ + Vector res; + CrossProduct(*this, vOther, res); + return res; +} + +inline vec_t Vector::Length2D(void) const +{ + return (vec_t)FastSqrt(x * x + y * y); +} + +inline vec_t Vector::Length2DSqr(void) const +{ + return (x * x + y * y); +} + +inline Vector CrossProduct(const Vector& a, const Vector& b) +{ + return Vector(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline void VectorMin(const Vector& a, const Vector& b, Vector& result) +{ + result.x = fpmin(a.x, b.x); + result.y = fpmin(a.y, b.y); + result.z = fpmin(a.z, b.z); +} + +inline void VectorMax(const Vector& a, const Vector& b, Vector& result) +{ + result.x = fpmax(a.x, b.x); + result.y = fpmax(a.y, b.y); + result.z = fpmax(a.z, b.z); +} + +inline float ComputeVolume(const Vector& vecMins, const Vector& vecMaxs) +{ + Vector vecDelta; + VectorSubtract(vecMaxs, vecMins, vecDelta); + return DotProduct(vecDelta, vecDelta); +} + +inline Vector RandomVector(float minVal, float maxVal) +{ + Vector random; + random.Random(minVal, maxVal); + return random; +} + +#endif + +inline bool operator==(float const* f, const Vector& v) +{ + Assert(0); + return false; +} + +inline bool operator==(const Vector& v, float const* f) +{ + Assert(0); + return false; +} + +inline bool operator!=(float const* f, const Vector& v) +{ + Assert(0); + return false; +} + +inline bool operator!=(const Vector& v, float const* f) +{ + Assert(0); + return false; +} + + +typedef Vector AngularImpulse; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline AngularImpulse RandomAngularImpulse(float minVal, float maxVal) +{ + AngularImpulse angImp; + angImp.Random(minVal, maxVal); + return angImp; +} + +#endif + + +class RadianEuler; + +class Quaternion +{ +public: + inline Quaternion(void) { + +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + x = y = z = w = VEC_T_NAN; +#endif +#endif + } + inline Quaternion(vec_t ix, vec_t iy, vec_t iz, vec_t iw) : x(ix), y(iy), z(iz), w(iw) { } + inline Quaternion(RadianEuler const& angle); + + inline void Init(vec_t ix = 0.0f, vec_t iy = 0.0f, vec_t iz = 0.0f, vec_t iw = 0.0f) { x = ix; y = iy; z = iz; w = iw; } + + bool IsValid() const; + void Invalidate(); + + bool operator==(const Quaternion& src) const; + bool operator!=(const Quaternion& src) const; + + vec_t* Base() { return (vec_t*)this; } + const vec_t* Base() const { return (vec_t*)this; } + + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t x, y, z, w; +}; + + +inline vec_t& Quaternion::operator[](int i) +{ + Assert((i >= 0) && (i < 4)); + return ((vec_t*)this)[i]; +} + +inline vec_t Quaternion::operator[](int i) const +{ + Assert((i >= 0) && (i < 4)); + return ((vec_t*)this)[i]; +} + + +inline bool Quaternion::operator==(const Quaternion& src) const +{ + return (x == src.x) && (y == src.y) && (z == src.z) && (w == src.w); +} + +inline bool Quaternion::operator!=(const Quaternion& src) const +{ + return !operator==(src); +} + + +inline bool QuaternionsAreEqual(const Quaternion& src1, const Quaternion& src2, float tolerance) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + if (FloatMakePositive(src1.z - src2.z) > tolerance) + return false; + return (FloatMakePositive(src1.w - src2.w) <= tolerance); +} + + +class ALIGN16 QuaternionAligned : public Quaternion +{ +public: + inline QuaternionAligned(void) {}; + inline QuaternionAligned(vec_t X, vec_t Y, vec_t Z, vec_t W) + { + Init(X, Y, Z, W); + } + +#ifdef VECTOR_NO_SLOW_OPERATIONS + +private: + QuaternionAligned(const QuaternionAligned& vOther); + QuaternionAligned(const Quaternion& vOther); + +#else +public: + explicit QuaternionAligned(const Quaternion& vOther) + { + Init(vOther.x, vOther.y, vOther.z, vOther.w); + } + + QuaternionAligned& operator=(const Quaternion& vOther) + { + Init(vOther.x, vOther.y, vOther.z, vOther.w); + return *this; + } + +#endif +} ALIGN16_POST; + + +class QAngle; +class RadianEuler +{ +public: + inline RadianEuler(void) { } + inline RadianEuler(vec_t X, vec_t Y, vec_t Z) { x = X; y = Y; z = Z; } + inline RadianEuler(Quaternion const& q); + inline RadianEuler(QAngle const& angles); + + inline void Init(vec_t ix = 0.0f, vec_t iy = 0.0f, vec_t iz = 0.0f) { x = ix; y = iy; z = iz; } + + QAngle ToQAngle(void) const; + bool IsValid() const; + void Invalidate(); + + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t x, y, z; +}; + + +extern void AngleQuaternion(RadianEuler const& angles, Quaternion& qt); +extern void QuaternionAngles(Quaternion const& q, RadianEuler& angles); + +FORCEINLINE void NetworkVarConstruct(Quaternion& q) { q.x = q.y = q.z = q.w = 0.0f; } + +inline Quaternion::Quaternion(RadianEuler const& angle) +{ + AngleQuaternion(angle, *this); +} + +inline bool Quaternion::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w); +} + +inline void Quaternion::Invalidate() +{ + x = y = z = w = VEC_T_NAN; +} + +inline RadianEuler::RadianEuler(Quaternion const& q) +{ + QuaternionAngles(q, *this); +} + +inline void VectorCopy(RadianEuler const& src, RadianEuler& dst) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void VectorScale(RadianEuler const& src, float b, RadianEuler& dst) +{ + CHECK_VALID(src); + Assert(IsFinite(b)); + dst.x = src.x * b; + dst.y = src.y * b; + dst.z = src.z * b; +} + +inline bool RadianEuler::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +inline void RadianEuler::Invalidate() +{ + x = y = z = VEC_T_NAN; +} + + +inline vec_t& RadianEuler::operator[](int i) +{ + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; +} + +inline vec_t RadianEuler::operator[](int i) const +{ + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; +} + + +class QAngleByValue; + +class QAngle +{ +public: + vec_t x, y, z; + + QAngle(void); + QAngle(vec_t X, vec_t Y, vec_t Z); + QAngle(Vector v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + } + operator QAngleByValue& () { return *((QAngleByValue*)(this)); } + operator const QAngleByValue& () const { return *((const QAngleByValue*)(this)); } + + void Init(vec_t ix = 0.0f, vec_t iy = 0.0f, vec_t iz = 0.0f); + void Random(vec_t minVal, vec_t maxVal); + + bool IsValid() const; + void Invalidate(); + + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t* Base(); + vec_t const* Base() const; + + bool operator==(const QAngle& v) const; + bool operator!=(const QAngle& v) const; + + QAngle& operator+=(const QAngle& v); + QAngle& operator-=(const QAngle& v); + QAngle& operator*=(float s); + QAngle& operator/=(float s); + + vec_t Length() const; + vec_t LengthSqr() const; + + QAngle& operator=(const QAngle& src); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + QAngle operator-(void) const; + + QAngle operator+(const QAngle& v) const; + QAngle operator-(const QAngle& v) const; + QAngle operator*(float fl) const; + QAngle operator/(float fl) const; +#else + +private: + QAngle(const QAngle& vOther); + +#endif + + void Clamp(void) + { + if (this->x < -89.f) + this->x = -89.f; + + if (this->x > 89.f) + this->x = 89.f; + + while (this->y < -180.f) + this->y += 360.f; + + while (this->y > 180.f) + this->y -= 360.f; + + this->z = 0.f; + } + + + void Normalize() + { + this->x = std::isfinite(this->x) ? std::remainderf(this->x, 360.f) : 0.f; + this->y = std::isfinite(this->y) ? std::remainderf(this->y, 360.f) : 0.f; + this->z = std::clamp(this->z, -50.f, 50.f); + } + + float DistTo(const QAngle& other) { + QAngle delta; + delta.x = x - other.x; + delta.y = y - other.y; + delta.z = z - other.z; + + return delta.Length(); + } + +}; + +inline Vector::Vector(QAngle v) +{ + this->x = v.x; + this->y = v.y; + this->z = v.z; +} + +FORCEINLINE void NetworkVarConstruct(QAngle& q) { q.x = q.y = q.z = 0.0f; } + +class QAngleByValue : public QAngle +{ +public: + QAngleByValue(void) : QAngle() {} + QAngleByValue(vec_t X, vec_t Y, vec_t Z) : QAngle(X, Y, Z) {} + QAngleByValue(const QAngleByValue& vOther) { *this = vOther; } +}; + + +inline void VectorAdd(const QAngle& a, const QAngle& b, QAngle& result) +{ + CHECK_VALID(a); + CHECK_VALID(b); + result.x = a.x + b.x; + result.y = a.y + b.y; + result.z = a.z + b.z; +} + +inline void VectorMA(const QAngle& start, float scale, const QAngle& direction, QAngle& dest) +{ + CHECK_VALID(start); + CHECK_VALID(direction); + dest.x = start.x + scale * direction.x; + dest.y = start.y + scale * direction.y; + dest.z = start.z + scale * direction.z; +} + + +inline QAngle::QAngle(void) +{ +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +#endif +#endif +} + +inline QAngle::QAngle(vec_t X, vec_t Y, vec_t Z) +{ + x = X; y = Y; z = Z; + CHECK_VALID(*this); +} + + +inline void QAngle::Init(vec_t ix, vec_t iy, vec_t iz) +{ + x = ix; y = iy; z = iz; + CHECK_VALID(*this); +} + +inline void QAngle::Random(vec_t minVal, vec_t maxVal) +{ + x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + z = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + CHECK_VALID(*this); +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline QAngle RandomAngle(float minVal, float maxVal) +{ + Vector random; + random.Random(minVal, maxVal); + QAngle ret(random.x, random.y, random.z); + return ret; +} + +#endif + + +inline RadianEuler::RadianEuler(QAngle const& angles) +{ + Init( + angles.z * 3.14159265358979323846f / 180.f, + angles.x * 3.14159265358979323846f / 180.f, + angles.y * 3.14159265358979323846f / 180.f); +} + + + + +inline QAngle RadianEuler::ToQAngle(void) const +{ + return QAngle( + y * 180.f / 3.14159265358979323846f, + z * 180.f / 3.14159265358979323846f, + x * 180.f / 3.14159265358979323846f); +} + + +inline QAngle& QAngle::operator=(const QAngle& vOther) +{ + CHECK_VALID(vOther); + x = vOther.x; y = vOther.y; z = vOther.z; + return *this; +} + + +inline vec_t& QAngle::operator[](int i) +{ + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; +} + +inline vec_t QAngle::operator[](int i) const +{ + Assert((i >= 0) && (i < 3)); + return ((vec_t*)this)[i]; +} + + +inline vec_t* QAngle::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* QAngle::Base() const +{ + return (vec_t const*)this; +} + + +inline bool QAngle::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +inline void QAngle::Invalidate() +{ + x = y = z = VEC_T_NAN; +} + +inline bool QAngle::operator==(const QAngle& src) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +inline bool QAngle::operator!=(const QAngle& src) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + + +inline void VectorCopy(const QAngle& src, QAngle& dst) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + + +inline QAngle& QAngle::operator+=(const QAngle& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x += v.x; y += v.y; z += v.z; + return *this; +} + +inline QAngle& QAngle::operator-=(const QAngle& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x -= v.x; y -= v.y; z -= v.z; + return *this; +} + +inline QAngle& QAngle::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +inline QAngle& QAngle::operator/=(float fl) +{ + Assert(fl != 0.0f); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + + +inline vec_t QAngle::Length() const +{ + CHECK_VALID(*this); + return (vec_t)FastSqrt(LengthSqr()); +} + + +inline vec_t QAngle::LengthSqr() const +{ + CHECK_VALID(*this); + return x * x + y * y + z * z; +} + + +inline bool QAnglesAreEqual(const QAngle& src1, const QAngle& src2, float tolerance = 0.0f) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + return (FloatMakePositive(src1.z - src2.z) <= tolerance); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline QAngle QAngle::operator-(void) const +{ + QAngle ret(-x, -y, -z); + return ret; +} + +inline QAngle QAngle::operator+(const QAngle& v) const +{ + QAngle res; + res.x = x + v.x; + res.y = y + v.y; + res.z = z + v.z; + return res; +} + +inline QAngle QAngle::operator-(const QAngle& v) const +{ + QAngle res; + res.x = x - v.x; + res.y = y - v.y; + res.z = z - v.z; + return res; +} + +inline QAngle QAngle::operator*(float fl) const +{ + QAngle res; + res.x = x * fl; + res.y = y * fl; + res.z = z * fl; + return res; +} + +inline QAngle QAngle::operator/(float fl) const +{ + QAngle res; + res.x = x / fl; + res.y = y / fl; + res.z = z / fl; + return res; +} + +inline QAngle operator*(float fl, const QAngle& v) +{ + QAngle ret(v * fl); + return ret; +} + +#endif + + +inline void QAngleToAngularImpulse(const QAngle& angles, AngularImpulse& impulse) +{ + impulse.x = angles.z; + impulse.y = angles.x; + impulse.z = angles.y; +} + +inline void AngularImpulseToQAngle(const AngularImpulse& impulse, QAngle& angles) +{ + angles.x = impulse.y; + angles.y = impulse.z; + angles.z = impulse.x; +} + +#if !defined( _X360 ) + +FORCEINLINE vec_t InvRSquared(float const* v) +{ +#if defined(__i386__) || defined(_M_IX86) + float sqrlen = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + 1.0e-10f, result; + _mm_store_ss(&result, _mm_rcp_ss(_mm_max_ss(_mm_set_ss(1.0f), _mm_load_ss(&sqrlen)))); + return result; +#else + return 1.f / fpmax(1.f, v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +#endif +} + +FORCEINLINE vec_t InvRSquared(const Vector& v) +{ + return InvRSquared(&v.x); +} + +#if defined(__i386__) || defined(_M_IX86) +inline void _SSE_RSqrtInline(float a, float* out) +{ + __m128 xx = _mm_load_ss(&a); + __m128 xr = _mm_rsqrt_ss(xx); + __m128 xt; + xt = _mm_mul_ss(xr, xr); + xt = _mm_mul_ss(xt, xx); + xt = _mm_sub_ss(_mm_set_ss(3.f), xt); + xt = _mm_mul_ss(xt, _mm_set_ss(0.5f)); + xr = _mm_mul_ss(xr, xt); + _mm_store_ss(out, xr); +} +#endif + +FORCEINLINE float VectorNormalize(Vector& vec) +{ +#ifndef DEBUG +#if defined(__i386__) || defined(_M_IX86) +#define DO_SSE_OPTIMIZATION +#endif +#endif + +#if defined( DO_SSE_OPTIMIZATION ) + float sqrlen = vec.LengthSqr() + 1.0e-10f, invlen; + _SSE_RSqrtInline(sqrlen, &invlen); + vec.x *= invlen; + vec.y *= invlen; + vec.z *= invlen; + return sqrlen * invlen; +#else + extern float (FASTCALL * pfVectorNormalize)(Vector & v); + return (*pfVectorNormalize)(vec); +#endif +} + +FORCEINLINE float VectorNormalize(float* v) +{ + return VectorNormalize(*(reinterpret_cast(v))); +} + +FORCEINLINE void VectorNormalizeFast(Vector& vec) +{ + VectorNormalize(vec); +} + +#else + +FORCEINLINE float _VMX_InvRSquared(const Vector& v) +{ + XMVECTOR xmV = XMVector3ReciprocalLength(XMLoadVector3(v.Base())); + xmV = XMVector3Dot(xmV, xmV); + return xmV.x; +} + +FORCEINLINE float _VMX_VectorNormalize(Vector& vec) +{ + float mag = XMVector3Length(XMLoadVector3(vec.Base())).x; + float den = 1.f / (mag + FLT_EPSILON); + vec.x *= den; + vec.y *= den; + vec.z *= den; + return mag; +} + +#define InvRSquared(x) _VMX_InvRSquared(x) + +FORCEINLINE float VectorNormalize(Vector& v) +{ + return _VMX_VectorNormalize(v); +} +FORCEINLINE float VectorNormalize(float* pV) +{ + return _VMX_VectorNormalize(*(reinterpret_cast(pV))); +} + +FORCEINLINE void VectorNormalizeFast(Vector& vec) +{ + XMVECTOR xmV = XMVector3LengthEst(XMLoadVector3(vec.Base())); + float den = 1.f / (xmV.x + FLT_EPSILON); + vec.x *= den; + vec.y *= den; + vec.z *= den; +} + +#endif + + +inline vec_t Vector::NormalizeInPlace() +{ + return VectorNormalize(*this); +} + +inline Vector Vector::Normalized() const +{ + Vector norm = *this; + VectorNormalize(norm); + return norm; +} + +inline bool Vector::IsLengthGreaterThan(float val) const +{ + return LengthSqr() > val * val; +} + +inline bool Vector::IsLengthLessThan(float val) const +{ + return LengthSqr() < val * val; +} + + +#include +#include + +inline void SinCosX(const float rad, float& sin, float& cos) +{ + const __m128 _ps_fopi = _mm_set_ss(1.27323954473516f); + + const __m128 _ps_0p5 = _mm_set_ss(0.5f); + const __m128 _ps_1 = _mm_set_ss(1.0f); + + const __m128 _ps_dp1 = _mm_set_ss(-0.7851562f); + const __m128 _ps_dp2 = _mm_set_ss(-2.4187564849853515625e-4f); + const __m128 _ps_dp3 = _mm_set_ss(-3.77489497744594108e-8f); + + const __m128 _ps_sincof_p0 = _mm_set_ss(2.443315711809948e-5f); + const __m128 _ps_sincof_p1 = _mm_set_ss(8.3321608736e-3f); + const __m128 _ps_sincof_p2 = _mm_set_ss(-1.6666654611e-1f); + const __m128 _ps_coscof_p0 = _mm_set_ss(2.443315711809948e-5f); + const __m128 _ps_coscof_p1 = _mm_set_ss(-1.388731625493765e-3f); + const __m128 _ps_coscof_p2 = _mm_set_ss(4.166664568298827e-2f); + + const __m128i _pi32_1 = _mm_set1_epi32(1); + const __m128i _pi32_i1 = _mm_set1_epi32(~1); + const __m128i _pi32_2 = _mm_set1_epi32(2); + const __m128i _pi32_4 = _mm_set1_epi32(4); + + const __m128 _mask_sign_raw = *(__m128*) & _mm_set1_epi32(0x80000000); + const __m128 _mask_sign_inv = *(__m128*) & _mm_set1_epi32(~0x80000000); + + + __m128 xmm3 = _mm_setzero_ps(); + __m128i emm0, emm2, emm4; + + __m128 sign_bit_cos, sign_bit_sin; + + __m128 x, y, z; + __m128 y1, y2; + + __m128 a = _mm_set_ss(rad); + + x = _mm_and_ps(a, _mask_sign_inv); + y = _mm_mul_ps(x, _ps_fopi); + + emm2 = _mm_cvtps_epi32(y); + emm2 = _mm_add_epi32(emm2, _pi32_1); + emm2 = _mm_and_si128(emm2, _pi32_i1); + y = _mm_cvtepi32_ps(emm2); + + emm4 = emm2; + + emm0 = _mm_and_si128(emm2, _pi32_4); + emm0 = _mm_slli_epi32(emm0, 29); + __m128 swap_sign_bit_sin = _mm_castsi128_ps(emm0); + + emm2 = _mm_and_si128(emm2, _pi32_2); + emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128()); + __m128 poly_mask = _mm_castsi128_ps(emm2); + + x = _mm_add_ps(x, _mm_mul_ps(y, _ps_dp1)); + x = _mm_add_ps(x, _mm_mul_ps(y, _ps_dp2)); + x = _mm_add_ps(x, _mm_mul_ps(y, _ps_dp3)); + + emm4 = _mm_sub_epi32(emm4, _pi32_2); + emm4 = _mm_andnot_si128(emm4, _pi32_4); + emm4 = _mm_slli_epi32(emm4, 29); + + sign_bit_cos = _mm_castsi128_ps(emm4); + sign_bit_sin = _mm_xor_ps(_mm_and_ps(a, _mask_sign_raw), swap_sign_bit_sin); + + z = _mm_mul_ps(x, x); + + y1 = _mm_mul_ps(_ps_coscof_p0, z); + y1 = _mm_add_ps(y1, _ps_coscof_p1); + y1 = _mm_mul_ps(y1, z); + y1 = _mm_add_ps(y1, _ps_coscof_p2); + y1 = _mm_mul_ps(y1, z); + y1 = _mm_mul_ps(y1, z); + y1 = _mm_sub_ps(y1, _mm_mul_ps(z, _ps_0p5)); + y1 = _mm_add_ps(y1, _ps_1); + + y2 = _mm_mul_ps(_ps_sincof_p0, z); + y2 = _mm_add_ps(y2, _ps_sincof_p1); + y2 = _mm_mul_ps(y2, z); + y2 = _mm_add_ps(y2, _ps_sincof_p2); + y2 = _mm_mul_ps(y2, z); + y2 = _mm_mul_ps(y2, x); + y2 = _mm_add_ps(y2, x); + + xmm3 = poly_mask; + + __m128 ysin2 = _mm_and_ps(xmm3, y2); + __m128 ysin1 = _mm_andnot_ps(xmm3, y1); + + sin = _mm_cvtss_f32(_mm_xor_ps(_mm_add_ps(ysin1, ysin2), sign_bit_sin)); + cos = _mm_cvtss_f32(_mm_xor_ps(_mm_add_ps(_mm_sub_ps(y1, ysin1), _mm_sub_ps(y2, ysin2)), sign_bit_cos)); +} + + +inline float sqrt2(float sqr) +{ + float root = 0; + + __asm + { + sqrtss xmm0, sqr + movss root, xmm0 + } + + return root; +} + + + + +#endif + +``` + +`SpyCustom/sdk/vector2d.h`: + +```h +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include + +#include + +#include "dbg.h" +#include "math_pfns.h" + + +class Vector2D +{ +public: + vec_t x, y; + + Vector2D(void); + Vector2D(vec_t X, vec_t Y); + Vector2D(const float* pFloat); + + void Init(vec_t ix = 0.0f, vec_t iy = 0.0f); + + bool IsValid() const; + + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t* Base(); + vec_t const* Base() const; + + void Random(float minVal, float maxVal); + + bool operator==(const Vector2D& v) const; + bool operator!=(const Vector2D& v) const; + + Vector2D& operator+=(const Vector2D& v); + Vector2D& operator-=(const Vector2D& v); + Vector2D& operator*=(const Vector2D& v); + Vector2D& operator*=(float s); + Vector2D& operator/=(const Vector2D& v); + Vector2D& operator/=(float s); + + void Negate(); + + vec_t Length() const; + + vec_t LengthSqr(void) const; + + bool IsZero(float tolerance = 0.01f) const + { + return (x > -tolerance && x < tolerance&& + y > -tolerance && y < tolerance); + } + + vec_t NormalizeInPlace(); + + bool IsLengthGreaterThan(float val) const; + bool IsLengthLessThan(float val) const; + + vec_t DistTo(const Vector2D& vOther) const; + + vec_t DistToSqr(const Vector2D& vOther) const; + + void CopyToArray(float* rgfl) const; + + void MulAdd(const Vector2D& a, const Vector2D& b, float scalar); + + vec_t Dot(const Vector2D& vOther) const; + + Vector2D& operator=(const Vector2D& vOther); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + Vector2D(const Vector2D& vOther); + + Vector2D operator-(void) const; + + Vector2D operator+(const Vector2D& v) const; + Vector2D operator-(const Vector2D& v) const; + Vector2D operator*(const Vector2D& v) const; + Vector2D operator/(const Vector2D& v) const; + Vector2D operator*(float fl) const; + Vector2D operator/(float fl) const; + + Vector2D Cross(const Vector2D& vOther) const; + + Vector2D Min(const Vector2D& vOther) const; + Vector2D Max(const Vector2D& vOther) const; + +#else + +private: + Vector2D(const Vector2D& vOther); +#endif +}; + +const Vector2D vec2_origin(0, 0); +const Vector2D vec2_invalid(FLT_MAX, FLT_MAX); + +void Vector2DClear(Vector2D& a); + +void Vector2DCopy(const Vector2D& src, Vector2D& dst); + +void Vector2DAdd(const Vector2D& a, const Vector2D& b, Vector2D& result); +void Vector2DSubtract(const Vector2D& a, const Vector2D& b, Vector2D& result); +void Vector2DMultiply(const Vector2D& a, vec_t b, Vector2D& result); +void Vector2DMultiply(const Vector2D& a, const Vector2D& b, Vector2D& result); +void Vector2DDivide(const Vector2D& a, vec_t b, Vector2D& result); +void Vector2DDivide(const Vector2D& a, const Vector2D& b, Vector2D& result); +void Vector2DMA(const Vector2D& start, float s, const Vector2D& dir, Vector2D& result); + +void Vector2DMin(const Vector2D& a, const Vector2D& b, Vector2D& result); +void Vector2DMax(const Vector2D& a, const Vector2D& b, Vector2D& result); + +#define Vector2DExpand( v ) (v).x, (v).y + +vec_t Vector2DNormalize(Vector2D& v); + +vec_t Vector2DLength(const Vector2D& v); + +vec_t DotProduct2D(const Vector2D& a, const Vector2D& b); + +void Vector2DLerp(const Vector2D& src1, const Vector2D& src2, vec_t t, Vector2D& dest); + + + +inline Vector2D::Vector2D(void) +{ +#ifdef _DEBUG + x = y = VEC_T_NAN; +#endif +} + +inline Vector2D::Vector2D(vec_t X, vec_t Y) +{ + x = X; y = Y; + Assert(IsValid()); +} + +inline Vector2D::Vector2D(const float* pFloat) +{ + Assert(pFloat); + x = pFloat[0]; y = pFloat[1]; + Assert(IsValid()); +} + + +inline Vector2D::Vector2D(const Vector2D& vOther) +{ + Assert(vOther.IsValid()); + x = vOther.x; y = vOther.y; +} + +inline void Vector2D::Init(vec_t ix, vec_t iy) +{ + x = ix; y = iy; + Assert(IsValid()); +} + +inline void Vector2D::Random(float minVal, float maxVal) +{ + x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal); +} + +inline void Vector2DClear(Vector2D& a) +{ + a.x = a.y = 0.0f; +} + +inline Vector2D& Vector2D::operator=(const Vector2D& vOther) +{ + Assert(vOther.IsValid()); + x = vOther.x; y = vOther.y; + return *this; +} + +inline vec_t& Vector2D::operator[](int i) +{ + Assert((i >= 0) && (i < 2)); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector2D::operator[](int i) const +{ + Assert((i >= 0) && (i < 2)); + return ((vec_t*)this)[i]; +} + +inline vec_t* Vector2D::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector2D::Base() const +{ + return (vec_t const*)this; +} + +inline bool Vector2D::IsValid() const +{ + return IsFinite(x) && IsFinite(y); +} + +inline bool Vector2D::operator==(const Vector2D& src) const +{ + Assert(src.IsValid() && IsValid()); + return (src.x == x) && (src.y == y); +} + +inline bool Vector2D::operator!=(const Vector2D& src) const +{ + Assert(src.IsValid() && IsValid()); + return (src.x != x) || (src.y != y); +} + + +inline void Vector2DCopy(const Vector2D& src, Vector2D& dst) +{ + Assert(src.IsValid()); + dst.x = src.x; + dst.y = src.y; +} + +inline void Vector2D::CopyToArray(float* rgfl) const +{ + Assert(IsValid()); + Assert(rgfl); + rgfl[0] = x; rgfl[1] = y; +} + +inline void Vector2D::Negate() +{ + Assert(IsValid()); + x = -x; y = -y; +} + +inline Vector2D& Vector2D::operator+=(const Vector2D& v) +{ + Assert(IsValid() && v.IsValid()); + x += v.x; y += v.y; + return *this; +} + +inline Vector2D& Vector2D::operator-=(const Vector2D& v) +{ + Assert(IsValid() && v.IsValid()); + x -= v.x; y -= v.y; + return *this; +} + +inline Vector2D& Vector2D::operator*=(float fl) +{ + x *= fl; + y *= fl; + Assert(IsValid()); + return *this; +} + +inline Vector2D& Vector2D::operator*=(const Vector2D& v) +{ + x *= v.x; + y *= v.y; + Assert(IsValid()); + return *this; +} + +inline Vector2D& Vector2D::operator/=(float fl) +{ + Assert(fl != 0.0f); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + Assert(IsValid()); + return *this; +} + +inline Vector2D& Vector2D::operator/=(const Vector2D& v) +{ + Assert(v.x != 0.0f && v.y != 0.0f); + x /= v.x; + y /= v.y; + Assert(IsValid()); + return *this; +} + +inline void Vector2DAdd(const Vector2D& a, const Vector2D& b, Vector2D& c) +{ + Assert(a.IsValid() && b.IsValid()); + c.x = a.x + b.x; + c.y = a.y + b.y; +} + +inline void Vector2DSubtract(const Vector2D& a, const Vector2D& b, Vector2D& c) +{ + Assert(a.IsValid() && b.IsValid()); + c.x = a.x - b.x; + c.y = a.y - b.y; +} + +inline void Vector2DMultiply(const Vector2D& a, vec_t b, Vector2D& c) +{ + Assert(a.IsValid() && IsFinite(b)); + c.x = a.x * b; + c.y = a.y * b; +} + +inline void Vector2DMultiply(const Vector2D& a, const Vector2D& b, Vector2D& c) +{ + Assert(a.IsValid() && b.IsValid()); + c.x = a.x * b.x; + c.y = a.y * b.y; +} + + +inline void Vector2DDivide(const Vector2D& a, vec_t b, Vector2D& c) +{ + Assert(a.IsValid()); + Assert(b != 0.0f); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; +} + +inline void Vector2DDivide(const Vector2D& a, const Vector2D& b, Vector2D& c) +{ + Assert(a.IsValid()); + Assert((b.x != 0.0f) && (b.y != 0.0f)); + c.x = a.x / b.x; + c.y = a.y / b.y; +} + +inline void Vector2DMA(const Vector2D& start, float s, const Vector2D& dir, Vector2D& result) +{ + Assert(start.IsValid() && IsFinite(s) && dir.IsValid()); + result.x = start.x + s * dir.x; + result.y = start.y + s * dir.y; +} + +inline void Vector2D::MulAdd(const Vector2D& a, const Vector2D& b, float scalar) +{ + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; +} + +inline void Vector2DLerp(const Vector2D& src1, const Vector2D& src2, vec_t t, Vector2D& dest) +{ + dest[0] = src1[0] + (src2[0] - src1[0]) * t; + dest[1] = src1[1] + (src2[1] - src1[1]) * t; +} + +inline vec_t DotProduct2D(const Vector2D& a, const Vector2D& b) +{ + Assert(a.IsValid() && b.IsValid()); + return(a.x * b.x + a.y * b.y); +} + +inline vec_t Vector2D::Dot(const Vector2D& vOther) const +{ + return DotProduct2D(*this, vOther); +} + + +inline vec_t Vector2DLength(const Vector2D& v) +{ + Assert(v.IsValid()); + return (vec_t)FastSqrt(v.x * v.x + v.y * v.y); +} + +inline vec_t Vector2D::LengthSqr(void) const +{ + Assert(IsValid()); + return (x * x + y * y); +} + +inline vec_t Vector2D::NormalizeInPlace() +{ + return Vector2DNormalize(*this); +} + +inline bool Vector2D::IsLengthGreaterThan(float val) const +{ + return LengthSqr() > val * val; +} + +inline bool Vector2D::IsLengthLessThan(float val) const +{ + return LengthSqr() < val * val; +} + +inline vec_t Vector2D::Length(void) const +{ + return Vector2DLength(*this); +} + + +inline void Vector2DMin(const Vector2D& a, const Vector2D& b, Vector2D& result) +{ + result.x = (a.x < b.x) ? a.x : b.x; + result.y = (a.y < b.y) ? a.y : b.y; +} + + +inline void Vector2DMax(const Vector2D& a, const Vector2D& b, Vector2D& result) +{ + result.x = (a.x > b.x) ? a.x : b.x; + result.y = (a.y > b.y) ? a.y : b.y; +} + + +inline vec_t Vector2DNormalize(Vector2D& v) +{ + Assert(v.IsValid()); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + v.x = v.y = 0.0f; + } + return l; +} + + +inline vec_t Vector2D::DistTo(const Vector2D& vOther) const +{ + Vector2D delta; + Vector2DSubtract(*this, vOther, delta); + return delta.Length(); +} + +inline vec_t Vector2D::DistToSqr(const Vector2D& vOther) const +{ + Vector2D delta; + Vector2DSubtract(*this, vOther, delta); + return delta.LengthSqr(); +} + + +inline void ComputeClosestPoint2D(const Vector2D& vecStart, float flMaxDist, const Vector2D& vecTarget, Vector2D* pResult) +{ + Vector2D vecDelta; + Vector2DSubtract(vecTarget, vecStart, vecDelta); + float flDistSqr = vecDelta.LengthSqr(); + if (flDistSqr <= flMaxDist * flMaxDist) + { + *pResult = vecTarget; + } + else + { + vecDelta /= FastSqrt(flDistSqr); + Vector2DMA(vecStart, flMaxDist, vecDelta, *pResult); + } +} + + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector2D Vector2D::Min(const Vector2D& vOther) const +{ + return Vector2D(x < vOther.x ? x : vOther.x, + y < vOther.y ? y : vOther.y); +} + +inline Vector2D Vector2D::Max(const Vector2D& vOther) const +{ + return Vector2D(x > vOther.x ? x : vOther.x, + y > vOther.y ? y : vOther.y); +} + + +inline Vector2D Vector2D::operator-(void) const +{ + return Vector2D(-x, -y); +} + +inline Vector2D Vector2D::operator+(const Vector2D& v) const +{ + Vector2D res; + Vector2DAdd(*this, v, res); + return res; +} + +inline Vector2D Vector2D::operator-(const Vector2D& v) const +{ + Vector2D res; + Vector2DSubtract(*this, v, res); + return res; +} + +inline Vector2D Vector2D::operator*(float fl) const +{ + Vector2D res; + Vector2DMultiply(*this, fl, res); + return res; +} + +inline Vector2D Vector2D::operator*(const Vector2D& v) const +{ + Vector2D res; + Vector2DMultiply(*this, v, res); + return res; +} + +inline Vector2D Vector2D::operator/(float fl) const +{ + Vector2D res; + Vector2DDivide(*this, fl, res); + return res; +} + +inline Vector2D Vector2D::operator/(const Vector2D& v) const +{ + Vector2D res; + Vector2DDivide(*this, v, res); + return res; +} + +inline Vector2D operator*(float fl, const Vector2D& v) +{ + return v * fl; +} + +#endif + +#endif +``` + +`SpyCustom/sdk/vector4d.h`: + +```h +#ifndef VECTOR4D_H +#define VECTOR4D_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include +#if !defined( _X360 ) +#include +#endif +#include "basetypes.h" +#include "dbg.h" +#include "math_pfns.h" + +class Vector; +class Vector2D; + +class Vector4D +{ +public: + vec_t x, y, z, w; + + Vector4D(void); + Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W); + Vector4D(const float* pFloat); + + void Init(vec_t ix = 0.0f, vec_t iy = 0.0f, vec_t iz = 0.0f, vec_t iw = 0.0f); + + bool IsValid() const; + + vec_t operator[](int i) const; + vec_t& operator[](int i); + + inline vec_t* Base(); + inline vec_t const* Base() const; + + Vector& AsVector3D(); + Vector const& AsVector3D() const; + + Vector2D& AsVector2D(); + Vector2D const& AsVector2D() const; + + void Random(vec_t minVal, vec_t maxVal); + + bool operator==(const Vector4D& v) const; + bool operator!=(const Vector4D& v) const; + + Vector4D& operator+=(const Vector4D& v); + Vector4D& operator-=(const Vector4D& v); + Vector4D& operator*=(const Vector4D& v); + Vector4D& operator*=(float s); + Vector4D& operator/=(const Vector4D& v); + Vector4D& operator/=(float s); + + void Negate(); + + vec_t Length() const; + + vec_t LengthSqr(void) const; + + bool IsZero(float tolerance = 0.01f) const + { + return (x > -tolerance && x < tolerance&& + y > -tolerance && y < tolerance&& + z > -tolerance && z < tolerance&& + w > -tolerance && w < tolerance); + } + + vec_t DistTo(const Vector4D& vOther) const; + + vec_t DistToSqr(const Vector4D& vOther) const; + + void CopyToArray(float* rgfl) const; + + void MulAdd(Vector4D const& a, Vector4D const& b, float scalar); + + vec_t Dot(Vector4D const& vOther) const; + +#ifdef VECTOR_NO_SLOW_OPERATIONS +private: +#else +public: +#endif + Vector4D(Vector4D const& vOther); + + Vector4D& operator=(Vector4D const& src); +}; + +const Vector4D vec4_origin(0.0f, 0.0f, 0.0f, 0.0f); +const Vector4D vec4_invalid(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX); + +class ALIGN16 Vector4DAligned : public Vector4D +{ +public: + Vector4DAligned(void) {} + Vector4DAligned(vec_t X, vec_t Y, vec_t Z, vec_t W); + + inline void Set(vec_t X, vec_t Y, vec_t Z, vec_t W); + inline void InitZero(void); + + inline __m128& AsM128() { return *(__m128*) & x; } + inline const __m128& AsM128() const { return *(const __m128*) & x; } + +private: + Vector4DAligned(Vector4DAligned const& vOther); + + Vector4DAligned& operator=(Vector4DAligned const& src); +} ALIGN16_POST; + +void Vector4DClear(Vector4D& a); + +void Vector4DCopy(Vector4D const& src, Vector4D& dst); + +void Vector4DAdd(Vector4D const& a, Vector4D const& b, Vector4D& result); +void Vector4DSubtract(Vector4D const& a, Vector4D const& b, Vector4D& result); +void Vector4DMultiply(Vector4D const& a, vec_t b, Vector4D& result); +void Vector4DMultiply(Vector4D const& a, Vector4D const& b, Vector4D& result); +void Vector4DDivide(Vector4D const& a, vec_t b, Vector4D& result); +void Vector4DDivide(Vector4D const& a, Vector4D const& b, Vector4D& result); +void Vector4DMA(Vector4D const& start, float s, Vector4D const& dir, Vector4D& result); + +void Vector4DMultiplyAligned(Vector4DAligned const& a, vec_t b, Vector4DAligned& result); + + +#define Vector4DExpand( v ) (v).x, (v).y, (v).z, (v).w + +vec_t Vector4DNormalize(Vector4D& v); + +vec_t Vector4DLength(Vector4D const& v); + +vec_t DotProduct4D(Vector4D const& a, Vector4D const& b); + +void Vector4DLerp(Vector4D const& src1, Vector4D const& src2, vec_t t, Vector4D& dest); + + + +inline Vector4D::Vector4D(void) +{ +#ifdef _DEBUG + x = y = z = w = VEC_T_NAN; +#endif +} + +inline Vector4D::Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W) +{ + x = X; y = Y; z = Z; w = W; + Assert(IsValid()); +} + +inline Vector4D::Vector4D(const float* pFloat) +{ + Assert(pFloat); + x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; w = pFloat[3]; + Assert(IsValid()); +} + + +inline Vector4D::Vector4D(const Vector4D& vOther) +{ + Assert(vOther.IsValid()); + x = vOther.x; y = vOther.y; z = vOther.z; w = vOther.w; +} + +inline void Vector4D::Init(vec_t ix, vec_t iy, vec_t iz, vec_t iw) +{ + x = ix; y = iy; z = iz; w = iw; + Assert(IsValid()); +} + +inline void Vector4D::Random(vec_t minVal, vec_t maxVal) +{ + x = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + y = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + z = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); + w = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal); +} + +inline void Vector4DClear(Vector4D& a) +{ + a.x = a.y = a.z = a.w = 0.0f; +} + +inline Vector4D& Vector4D::operator=(const Vector4D& vOther) +{ + Assert(vOther.IsValid()); + x = vOther.x; y = vOther.y; z = vOther.z; w = vOther.w; + return *this; +} + +inline vec_t& Vector4D::operator[](int i) +{ + Assert((i >= 0) && (i < 4)); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector4D::operator[](int i) const +{ + Assert((i >= 0) && (i < 4)); + return ((vec_t*)this)[i]; +} + +inline Vector& Vector4D::AsVector3D() +{ + return *(Vector*)this; +} + +inline Vector const& Vector4D::AsVector3D() const +{ + return *(Vector const*)this; +} + +inline Vector2D& Vector4D::AsVector2D() +{ + return *(Vector2D*)this; +} + +inline Vector2D const& Vector4D::AsVector2D() const +{ + return *(Vector2D const*)this; +} + +inline vec_t* Vector4D::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector4D::Base() const +{ + return (vec_t const*)this; +} + +inline bool Vector4D::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w); +} + +inline bool Vector4D::operator==(Vector4D const& src) const +{ + Assert(src.IsValid() && IsValid()); + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool Vector4D::operator!=(Vector4D const& src) const +{ + Assert(src.IsValid() && IsValid()); + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + +inline void Vector4DCopy(Vector4D const& src, Vector4D& dst) +{ + Assert(src.IsValid()); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = src.w; +} + +inline void Vector4D::CopyToArray(float* rgfl) const +{ + Assert(IsValid()); + Assert(rgfl); + rgfl[0] = x; rgfl[1] = y; rgfl[2] = z; rgfl[3] = w; +} + +inline void Vector4D::Negate() +{ + Assert(IsValid()); + x = -x; y = -y; z = -z; w = -w; +} + +inline Vector4D& Vector4D::operator+=(const Vector4D& v) +{ + Assert(IsValid() && v.IsValid()); + x += v.x; y += v.y; z += v.z; w += v.w; + return *this; +} + +inline Vector4D& Vector4D::operator-=(const Vector4D& v) +{ + Assert(IsValid() && v.IsValid()); + x -= v.x; y -= v.y; z -= v.z; w -= v.w; + return *this; +} + +inline Vector4D& Vector4D::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + w *= fl; + Assert(IsValid()); + return *this; +} + +inline Vector4D& Vector4D::operator*=(Vector4D const& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + Assert(IsValid()); + return *this; +} + +inline Vector4D& Vector4D::operator/=(float fl) +{ + Assert(fl != 0.0f); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + w *= oofl; + Assert(IsValid()); + return *this; +} + +inline Vector4D& Vector4D::operator/=(Vector4D const& v) +{ + Assert(v.x != 0.0f && v.y != 0.0f && v.z != 0.0f && v.w != 0.0f); + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; + Assert(IsValid()); + return *this; +} + +inline void Vector4DAdd(Vector4D const& a, Vector4D const& b, Vector4D& c) +{ + Assert(a.IsValid() && b.IsValid()); + c.x = a.x + b.x; + c.y = a.y + b.y; + c.z = a.z + b.z; + c.w = a.w + b.w; +} + +inline void Vector4DSubtract(Vector4D const& a, Vector4D const& b, Vector4D& c) +{ + Assert(a.IsValid() && b.IsValid()); + c.x = a.x - b.x; + c.y = a.y - b.y; + c.z = a.z - b.z; + c.w = a.w - b.w; +} + +inline void Vector4DMultiply(Vector4D const& a, vec_t b, Vector4D& c) +{ + Assert(a.IsValid() && IsFinite(b)); + c.x = a.x * b; + c.y = a.y * b; + c.z = a.z * b; + c.w = a.w * b; +} + +inline void Vector4DMultiply(Vector4D const& a, Vector4D const& b, Vector4D& c) +{ + Assert(a.IsValid() && b.IsValid()); + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; + c.w = a.w * b.w; +} + +inline void Vector4DDivide(Vector4D const& a, vec_t b, Vector4D& c) +{ + Assert(a.IsValid()); + Assert(b != 0.0f); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; + c.z = a.z * oob; + c.w = a.w * oob; +} + +inline void Vector4DDivide(Vector4D const& a, Vector4D const& b, Vector4D& c) +{ + Assert(a.IsValid()); + Assert((b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f) && (b.w != 0.0f)); + c.x = a.x / b.x; + c.y = a.y / b.y; + c.z = a.z / b.z; + c.w = a.w / b.w; +} + +inline void Vector4DMA(Vector4D const& start, float s, Vector4D const& dir, Vector4D& result) +{ + Assert(start.IsValid() && IsFinite(s) && dir.IsValid()); + result.x = start.x + s * dir.x; + result.y = start.y + s * dir.y; + result.z = start.z + s * dir.z; + result.w = start.w + s * dir.w; +} + +inline void Vector4D::MulAdd(Vector4D const& a, Vector4D const& b, float scalar) +{ + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; + z = a.z + b.z * scalar; + w = a.w + b.w * scalar; +} + +inline void Vector4DLerp(const Vector4D& src1, const Vector4D& src2, vec_t t, Vector4D& dest) +{ + dest[0] = src1[0] + (src2[0] - src1[0]) * t; + dest[1] = src1[1] + (src2[1] - src1[1]) * t; + dest[2] = src1[2] + (src2[2] - src1[2]) * t; + dest[3] = src1[3] + (src2[3] - src1[3]) * t; +} + +inline vec_t DotProduct4D(const Vector4D& a, const Vector4D& b) +{ + Assert(a.IsValid() && b.IsValid()); + return(a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w); +} + +inline vec_t Vector4D::Dot(Vector4D const& vOther) const +{ + return DotProduct4D(*this, vOther); +} + + +inline vec_t Vector4DLength(Vector4D const& v) +{ + Assert(v.IsValid()); + return (vec_t)FastSqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w); +} + +inline vec_t Vector4D::LengthSqr(void) const +{ + Assert(IsValid()); + return (x * x + y * y + z * z + w * w); +} + +inline vec_t Vector4D::Length(void) const +{ + return Vector4DLength(*this); +} + + +inline vec_t Vector4DNormalize(Vector4D& v) +{ + Assert(v.IsValid()); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + v.x = v.y = v.z = v.w = 0.0f; + } + return l; +} + +inline vec_t Vector4D::DistTo(const Vector4D& vOther) const +{ + Vector4D delta; + Vector4DSubtract(*this, vOther, delta); + return delta.Length(); +} + +inline vec_t Vector4D::DistToSqr(const Vector4D& vOther) const +{ + Vector4D delta; + Vector4DSubtract(*this, vOther, delta); + return delta.LengthSqr(); +} + + +inline Vector4DAligned::Vector4DAligned(vec_t X, vec_t Y, vec_t Z, vec_t W) +{ + x = X; y = Y; z = Z; w = W; + Assert(IsValid()); +} + +inline void Vector4DAligned::Set(vec_t X, vec_t Y, vec_t Z, vec_t W) +{ + x = X; y = Y; z = Z; w = W; + Assert(IsValid()); +} + +inline void Vector4DAligned::InitZero(void) +{ +#if !defined( _X360 ) + this->AsM128() = _mm_set1_ps(0.0f); +#else + this->AsM128() = __vspltisw(0); +#endif + Assert(IsValid()); +} + +inline void Vector4DMultiplyAligned(Vector4DAligned const& a, Vector4DAligned const& b, Vector4DAligned& c) +{ + Assert(a.IsValid() && b.IsValid()); +#if !defined( _X360 ) + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; + c.w = a.w * b.w; +#else + c.AsM128() = __vmulfp(a.AsM128(), b.AsM128()); +#endif +} + +inline void Vector4DWeightMAD(vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB) +{ + Assert(vInA.IsValid() && vInB.IsValid() && IsFinite(w)); + +#if !defined( _X360 ) + vOutA.x += vInA.x * w; + vOutA.y += vInA.y * w; + vOutA.z += vInA.z * w; + vOutA.w += vInA.w * w; + + vOutB.x += vInB.x * w; + vOutB.y += vInB.y * w; + vOutB.z += vInB.z * w; + vOutB.w += vInB.w * w; +#else + __vector4 temp; + + temp = __lvlx(&w, 0); + temp = __vspltw(temp, 0); + + vOutA.AsM128() = __vmaddfp(vInA.AsM128(), temp, vOutA.AsM128()); + vOutB.AsM128() = __vmaddfp(vInB.AsM128(), temp, vOutB.AsM128()); +#endif +} + +inline void Vector4DWeightMADSSE(vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB) +{ + Assert(vInA.IsValid() && vInB.IsValid() && IsFinite(w)); + +#if !defined( _X360 ) + __m128 packed = _mm_set1_ps(w); + + vOutA.AsM128() = _mm_add_ps(vOutA.AsM128(), _mm_mul_ps(vInA.AsM128(), packed)); + vOutB.AsM128() = _mm_add_ps(vOutB.AsM128(), _mm_mul_ps(vInB.AsM128(), packed)); +#else + __vector4 temp; + + temp = __lvlx(&w, 0); + temp = __vspltw(temp, 0); + + vOutA.AsM128() = __vmaddfp(vInA.AsM128(), temp, vOutA.AsM128()); + vOutB.AsM128() = __vmaddfp(vInB.AsM128(), temp, vOutB.AsM128()); +#endif +} + +#endif +``` + +`SpyCustom/sdk/vertexcolor.h`: + +```h +#ifndef VERTEXCOLOR_H +#define VERTEXCOLOR_H + +#ifdef COMPILER_MSVC +#pragma once +#endif + +#include "platform.h" + + +struct VertexColor_t +{ + VertexColor_t() {}; + VertexColor_t(const VertexColor_t& src); + VertexColor_t(uint8 ir, uint8 ig, uint8 ib, uint8 ia); + + uint32 AsUint32() const; + uint32* AsUint32Ptr(); + const uint32* AsUint32Ptr() const; + + VertexColor_t& operator=(const VertexColor_t& src); + VertexColor_t& operator=(const color32& src); + + bool operator==(const VertexColor_t& src) const; + bool operator!=(const VertexColor_t& src) const; + +#ifdef PLATFORM_X360 + uint8 a, b, g, r; +#else + uint8 r, g, b, a; +#endif +}; + + +inline VertexColor_t::VertexColor_t(const VertexColor_t& src) +{ + *AsUint32Ptr() = src.AsUint32(); +} + +inline VertexColor_t::VertexColor_t(uint8 ir, uint8 ig, uint8 ib, uint8 ia) : r(ir), g(ig), b(ib), a(ia) +{ +} + + +inline uint32 VertexColor_t::AsUint32() const +{ + return *reinterpret_cast(this); +} + +inline uint32* VertexColor_t::AsUint32Ptr() +{ + return reinterpret_cast(this); +} + +inline const uint32* VertexColor_t::AsUint32Ptr() const +{ + return reinterpret_cast(this); +} + + +inline VertexColor_t& VertexColor_t::operator=(const VertexColor_t& src) +{ + *AsUint32Ptr() = src.AsUint32(); + return *this; +} + +inline VertexColor_t& VertexColor_t::operator=(const color32& src) +{ + r = src.r; + g = src.g; + b = src.b; + a = src.a; + return *this; +} + + +inline bool VertexColor_t::operator==(const VertexColor_t& src) const +{ + return AsUint32() == src.AsUint32(); +} + +inline bool VertexColor_t::operator!=(const VertexColor_t& src) const +{ + return AsUint32() != src.AsUint32(); +} + + + +#endif +``` + +`SpyCustom/sdk/vgui_basepanel.h`: + +```h +#if !defined( VGUI_BASEPANEL_H ) +#define VGUI_BASEPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "Panel.h" +#include "Label.h" +#include "Controls.h" +#include "ISurface.h" + +class CBasePanel : public vgui::Panel +{ +public: + DECLARE_CLASS_GAMEROOT(CBasePanel, vgui::Panel); + + CBasePanel(vgui::Panel* pParent, const char* panelName); + CBasePanel(vgui::Panel* pParent, const char* panelName, int x, int y, int w, int h); + virtual ~CBasePanel(void); + + virtual bool ShouldDraw(void) { return true; } + + virtual void PaintBackground(void); + + virtual void SetTexture(const char* texname, bool tiled = false); + + virtual void SetReflectMouse(bool reflect); + virtual void OnCursorMoved(int x, int y); + virtual void OnMousePressed(vgui::MouseCode code); + virtual void OnMouseDoublePressed(vgui::MouseCode code); + virtual void OnMouseReleased(vgui::MouseCode code); + virtual void OnMouseWheeled(int delta); + + virtual void OnTick(void); + +protected: + bool m_bTexturedBackground; + int m_nBackgroundMaterial; + char m_szBgTexture[256]; + bool m_bTiled; + int m_nTextureSize[2]; + + bool m_bReflectMouse; +}; + +class CHudLabel : public vgui::Label +{ + typedef vgui::Label BaseClass; +public: + CHudLabel(vgui::Panel* parent, const char* panelName, const char* text); + virtual void ApplySchemeSettings(vgui::IScheme* pScheme); + + void SetSelected(bool bSelected); + + bool m_bSelected; + +private: + CHudLabel(const CHudLabel&); +}; + +#endif +``` + +`SpyCustom/sdk/vguitextwindow.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VGUITEXTWINDOW_H +#define VGUITEXTWINDOW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "Frame.h" +#include "Button.h" +#include "HTML.h" + +#include "iviewport.h" +#include "shareddefs.h" +#include "GameEventListener.h" + + +namespace vgui +{ + class TextEntry; +} + +enum +{ + FADE_STATUS_IN = 0, + FADE_STATUS_HOLD, + FADE_STATUS_OUT, + FADE_STATUS_OFF +}; + +//----------------------------------------------------------------------------- +// Purpose: displays the MOTD +//----------------------------------------------------------------------------- + +class CTextWindow : public vgui::Frame, public IViewPortPanel, public CGameEventListener +{ +private: + DECLARE_CLASS_SIMPLE( CTextWindow, vgui::Frame ); + +public: + CTextWindow(IViewPort *pViewPort); + virtual ~CTextWindow(); + + virtual const char *GetName( void ) { return PANEL_INFO; } + virtual void SetData(KeyValues *data); + virtual void Reset(); + virtual void Update(); +// virtual void UpdateContents( void ); + virtual bool NeedsUpdate( void ) { return false; } + virtual bool HasInputElements( void ) { return true; } + virtual void ShowPanel( bool bShow ); + void ShowPanel2( bool bShow ); + bool HasMotd(); + virtual void PaintBackground(); + + // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui + vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } + virtual bool IsVisible() { return BaseClass::IsVisible(); } + virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } + + virtual void FireGameEvent( IGameEvent *event ) { return; }; + virtual bool WantsBackgroundBlurred( void ) { return false; }; + +public: + + //============================================================================= + // HPE_BEGIN: + // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration + // of options. Passing a command string is dangerous and allowed a server network + // message to run arbitrary commands on the client. + //============================================================================= + virtual void SetData( int type, const char *title, const char *message, const char *message_fallback, int command ); + //============================================================================= + // HPE_END + //============================================================================= + virtual void ShowFile( const char *filename ); + virtual void ShowText( const char *text ); + virtual void ShowURL( const char *URL, bool bAllowUserToDisable = true ); + virtual void ShowIndex( const char *entry ); + virtual void ShowHtmlString( const char *entry ); + + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +protected: + // vgui overrides + virtual void OnCommand( const char *command ); + virtual void OnKeyCodePressed( vgui::KeyCode code ); + + int GetNumSecondsRequiredByServer() const; + int GetNumSecondsSponsorRequiredRemaining() const; + + bool m_bHasMotd; + + IViewPort *m_pViewPort; + char m_szTitle[255]; + char m_szMessage[2048]; + char m_szMessageFallback[2048]; + //============================================================================= + // HPE_BEGIN: + // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration + // of options. Passing a command string is dangerous and allowed a server network + // message to run arbitrary commands on the client. + //============================================================================= + int m_nExitCommand; + double m_dblTimeExecutedExitCommand; + //============================================================================= + // HPE_END + //============================================================================= + int m_nContentType; + + vgui::TextEntry *m_pTextMessage; + + class CMOTDHTML : public vgui::HTML + { + private: + DECLARE_CLASS_SIMPLE( CMOTDHTML, vgui::HTML ); + + public: + CMOTDHTML( Panel *parent, const char *pchName ) : vgui::HTML( parent, pchName ) {} + virtual bool OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect ); + }; + CMOTDHTML *m_pHTMLMessage; + + vgui::Button *m_pOK; + vgui::Label *m_pTitleLabel; + vgui::Label *m_pInfoLabelTicker; + + uint32 m_uiTimestampStarted, m_uiTimestampInfoLabelUpdated; + bool m_bForcingWindowCloseRegardlessOfTime; +}; + + +#endif // VGUITEXTWINDOW_H +``` + +`SpyCustom/sdk/view_shared.h`: + +```h +#ifndef VIEW_SHARED_H +#define VIEW_SHARED_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "vector.h" +#include "MaterialSystemUtil.h" + + +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, + VIEW_CLEAR_STENCIL = 0x20, +}; + +enum StereoEye_t +{ + STEREO_EYE_MONO = 0, + STEREO_EYE_LEFT = 1, + STEREO_EYE_RIGHT = 2, + STEREO_EYE_MAX = 3, +}; + + +class CViewSetup +{ +public: + + + float ComputeViewMatrices(VMatrix* pWorldToView, VMatrix* pViewToProjection, VMatrix* pWorldToProjection) const; + + int x; + int m_nUnscaledX; + int y; + int m_nUnscaledY; + int width; + int m_nUnscaledWidth; + int height; + int m_nUnscaledHeight; + + bool m_bOrtho; + float m_OrthoLeft; + float m_OrthoTop; + float m_OrthoRight; + float m_OrthoBottom; + + bool m_bCustomViewMatrix; + matrix3x4_t m_matCustomViewMatrix; + + bool m_bCustomProjMatrix; + VMatrix m_matCustomProjMatrix; + + const CVolumeCuller* m_pCSMVolumeCuller; + + float fov; + float fovViewmodel; + + Vector origin; + + Vector angles; + float zNear; + float zFar; + + float zNearViewmodel; + float zFarViewmodel; + + float m_flAspectRatio; + + float m_flNearBlurDepth; + float m_flNearFocusDepth; + float m_flFarFocusDepth; + float m_flFarBlurDepth; + float m_flNearBlurRadius; + float m_flFarBlurRadius; + int m_nDoFQuality; + + void* m_nMotionBlurMode; + float m_flShutterTime; + Vector m_vShutterOpenPosition; + QAngle m_shutterOpenAngles; + Vector m_vShutterClosePosition; + QAngle m_shutterCloseAngles; + + float m_flOffCenterTop; + float m_flOffCenterBottom; + float m_flOffCenterLeft; + float m_flOffCenterRight; + bool m_bOffCenter : 1; + + bool m_bRenderToSubrectOfLargerScreen : 1; + + bool m_bDoBloomAndToneMapping : 1; + bool m_bDoDepthOfField : 1; + bool m_bHDRTarget : 1; + bool m_bDrawWorldNormal : 1; + bool m_bCullFrontFaces : 1; + + bool m_bCacheFullSceneState : 1; + + bool m_bCSMView : 1; +}; + + + +#endif + +``` + +`SpyCustom/sdk/viewport_panel_names.h`: + +```h +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VIEWPORT_PANEL_NAMES_H +#define VIEWPORT_PANEL_NAMES_H +#ifdef _WIN32 +#pragma once +#endif + + +// default panel name definitions +#define PANEL_ALL "all" // all current panels +#define PANEL_ACTIVE "active" // current active panel + +#define PANEL_SCOREBOARD "scores" +#define PANEL_PLAYERDETAILS "playerdetails" +#define PANEL_OVERVIEW "overview" +#define PANEL_CLASS "class" +#define PANEL_TEAM "team" +#define PANEL_SPECGUI "specgui" // passive spectator elements (top/bottom bars) +#define PANEL_SPECMENU "specmenu" // active spectator elements (options menus etc) +#define PANEL_INFO "info" +#define PANEL_BUY "buy" +#define PANEL_BUY_CT "buy_ct" +#define PANEL_BUY_TER "buy_ter" +#define PANEL_BUY_EQUIP_CT "buyequip_ct" +#define PANEL_BUY_EQUIP_TER "buyequip_ter" +#define PANEL_NAV_PROGRESS "nav_progress" +#define PANEL_BUYPRESET_MAIN "buypreset_main" +#define PANEL_BUYPRESET_EDIT "buypreset_edit" +#define PANEL_INTRO "intro" + + +#define PANEL_COMMENTARY_MODELVIEWER "commentary_modelviewer" + +#define PANEL_SURVEY "surveypanel" + +#ifdef PORTAL2 +#define PANEL_RADIAL_MENU "radialmenupanel" +#endif // PORTAL2 + +#endif // VIEWPORT_PANEL_NAMES_H +``` + +`SpyCustom/sdk/viewrender.h`: + +```h +#if !defined( VIEWRENDER_H ) +#define VIEWRENDER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "utlstack.h" +#include "tier2.h" +#include "iviewrender.h" +#include "ivrenderview.h" +#include "view_shared.h" + +#if defined(_PS3) +#include "buildrenderables_ps3.h" +#endif +#include "volumeculler.h" +#include "jobthread.h" + +#include "bspfile.h" +#include "const.h" + +class ConVar; +class CClientRenderablesList; +class IClientVehicle; +class C_PointCamera; +class C_EnvProjectedTexture; +class IScreenSpaceEffect; +class CClientViewSetup; +class CViewRender; +struct ClientWorldListInfo_t; +class C_BaseEntity; +class CJob; + +#ifdef HL2_EPISODIC +class CStunEffect; +#endif + +struct IntroDataBlendPass_t +{ + int m_BlendMode; + float m_Alpha; +}; + +struct IntroData_t +{ + bool m_bDrawPrimary; + Vector m_vecCameraView; + QAngle m_vecCameraViewAngles; + float m_playerViewFOV; + CUtlVector m_Passes; + + float m_flCurrentFadeColor[4]; +}; + +extern IntroData_t* g_pIntroData; + +enum view_id_t +{ + VIEW_ILLEGAL = -2, + VIEW_NONE = -1, + VIEW_MAIN = 0, + VIEW_3DSKY = 1, + VIEW_MONITOR = 2, + VIEW_REFLECTION = 3, + VIEW_REFRACTION = 4, + VIEW_INTRO_PLAYER = 5, + VIEW_INTRO_CAMERA = 6, + VIEW_SHADOW_DEPTH_TEXTURE = 7, + VIEW_SSAO = 8, + VIEW_ID_COUNT +}; +view_id_t CurrentViewID(); + +#if defined(_PS3) +#define PASS_BUILDLISTS_PS3 (1<<0) +#define PASS_DRAWLISTS_PS3 (1<<1) +#else +#define PASS_BUILDLISTS (1<<0) +#define PASS_DRAWLISTS (1<<1) +#endif + +class CPitchDrift +{ +public: + float pitchvel; + bool nodrift; + float driftmove; + double laststop; +}; + + + +struct ViewCustomVisibility_t +{ + ViewCustomVisibility_t() + { + m_nNumVisOrigins = 0; + m_VisData.m_fDistToAreaPortalTolerance = FLT_MAX; + m_iForceViewLeaf = -1; + } + + void AddVisOrigin(const Vector& origin) + { + AssertMsg(m_nNumVisOrigins < MAX_VIS_LEAVES, "Added more origins than will fit in the array!"); + + if (m_nNumVisOrigins >= MAX_VIS_LEAVES) + return; + + m_rgVisOrigins[m_nNumVisOrigins++] = origin; + } + + void ForceVisOverride(VisOverrideData_t& visData) + { + m_VisData = visData; + } + + void ForceViewLeaf(int iViewLeaf) + { + m_iForceViewLeaf = iViewLeaf; + } + + int m_nNumVisOrigins; + Vector m_rgVisOrigins[MAX_VIS_LEAVES]; + + VisOverrideData_t m_VisData; + + int m_iForceViewLeaf; +}; + +struct WaterRenderInfo_t +{ + bool m_bCheapWater : 1; + bool m_bReflect : 1; + bool m_bRefract : 1; + bool m_bReflectEntities : 1; + bool m_bReflectOnlyMarkedEntities : 1; + bool m_bDrawWaterSurface : 1; + bool m_bOpaqueWater : 1; + bool m_bPseudoTranslucentWater : 1; + bool m_bReflect2DSkybox : 1; +}; + +class CBase3dView : public CRefCounted<>, + protected CViewSetup +{ + DECLARE_CLASS_NOBASE(CBase3dView); +public: + explicit CBase3dView(CViewRender* pMainView); + + VPlane* GetFrustum(); + virtual int GetDrawFlags() { return 0; } + +#ifdef PORTAL + virtual void EnableWorldFog() {}; +#endif + +protected: + VPlane* m_Frustum; + CViewRender* m_pMainView; + int m_nSlot; +}; + +struct FrustumCache_t +{ + int m_nFrameCount; + Frustum_t m_Frustums[MAX_SPLITSCREEN_PLAYERS]; + + FrustumCache_t() { m_nFrameCount = 0; } + + bool IsValid(void); + void SetUpdated(void); + + void Add(const CViewSetup* pView, int iSlot); +}; + +FrustumCache_t* FrustumCache(void); + +class CRendering3dView : public CBase3dView +{ + DECLARE_CLASS(CRendering3dView, CBase3dView); +public: + explicit CRendering3dView(CViewRender* pMainView); + virtual ~CRendering3dView() { ReleaseLists(); } + + void Setup(const CViewSetup& setup); + + virtual int GetDrawFlags(); + virtual void Draw() {}; + +protected: + + void EnableWorldFog(void); + void SetFogVolumeState(const VisibleFogVolumeInfo_t& fogInfo, bool bUseHeightFog); + + void SetupRenderablesList(int viewID, bool bFastEntityRendering = false, bool bDrawDepthViewNonCachedObjectsOnly = false); + + void BuildWorldRenderLists(bool bDrawEntities, int iForceViewLeaf = -1, bool bUseCacheIfEnabled = true, bool bShadowDepth = false, float* pReflectionWaterHeight = NULL); + +#if defined(_PS3) + void SetupRenderablesList_PS3_Epilogue(void); + + void BuildWorldRenderLists_PS3_Epilogue(bool bShadowDepth); + void BuildRenderableRenderLists_PS3_Epilogue(void); +#else + void BuildWorldRenderLists_Epilogue(bool bShadowDepth); + void BuildRenderableRenderLists_Epilogue(int viewID); +#endif + + void BuildRenderableRenderLists(int viewID, bool bFastEntityRendering = false, bool bDrawDepthViewNonCachedObjectsOnly = false); + + void BuildShadowDepthRenderableRenderLists(); + + void DrawWorld(IMatRenderContext* pRenderContext, float waterZAdjust); + + enum RenderablesRenderPath_t + { + RENDERABLES_RENDER_PATH_NORMAL = 0, + RENDERABLES_RENDER_PATH_SHADOWDEPTH_DEFAULT = (1 << 0), + RENDERABLES_RENDER_PATH_SHADOWDEPTH_BUILD_GEOCACHE = (1 << 1), + RENDERABLES_RENDER_PATH_SHADOWDEPTH_USE_GEOCACHE = (1 << 2), + }; + void DrawOpaqueRenderables(IMatRenderContext* pRenderContext, RenderablesRenderPath_t eRenderPath, ERenderDepthMode_t DepthMode, CUtlVector< CClientRenderablesList::CEntry* >* pDeferClippedOpaqueRenderables_Out, RenderGroup_t nGroup = RENDER_GROUP_OPAQUE); + void DrawDeferredClippedOpaqueRenderables(IMatRenderContext* pRenderContext, RenderablesRenderPath_t eRenderPath, ERenderDepthMode_t DepthMode, CUtlVector< CClientRenderablesList::CEntry* >* pDeferClippedOpaqueRenderables); + void DrawTranslucentRenderables(bool bInSkybox, bool bShadowDepth); + +#if defined( PORTAL ) + void DrawRecursivePortalViews(void); +#endif + + void DrawTranslucentRenderablesNoWorld(bool bInSkybox); + + void DrawNoZBufferTranslucentRenderables(void); + + void DrawTranslucentWorldInLeaves(IMatRenderContext* pRenderContext, bool bShadowDepth); + + void DrawTranslucentWorldAndDetailPropsInLeaves(IMatRenderContext* pRenderContext, int iCurLeaf, int iFinalLeaf, int nEngineDrawFlags, int& nDetailLeafCount, LeafIndex_t* pDetailLeafList, bool bShadowDepth); + + void PruneWorldListInfo(); + + void BeginConsoleZPass(); + void EndConsoleZPass(); + + +#ifdef PORTAL + virtual bool ShouldDrawPortals() { return true; } +#endif + + void ReleaseLists(); + + int m_DrawFlags; + int m_ClearFlags; + + + IWorldRenderList* m_pWorldRenderList; + +#if defined( CSTRIKE15 ) && defined(_PS3) + CClientRenderablesList* m_pRenderablesList[MAX_CONCURRENT_BUILDVIEWS]; + ClientWorldListInfo_t* m_pWorldListInfo[MAX_CONCURRENT_BUILDVIEWS]; +#else + CClientRenderablesList* m_pRenderables; + ClientWorldListInfo_t* m_pWorldListInfo; +#endif + + ViewCustomVisibility_t* m_pCustomVisibility; +}; + + +class CRenderExecutor +{ + DECLARE_CLASS_NOBASE(CRenderExecutor); +public: + + virtual void AddView(CRendering3dView* pView) = 0; + + virtual void Execute() = 0; + +protected: + explicit CRenderExecutor(CViewRender* pMainView) : m_pMainView(pMainView) {} + CViewRender* m_pMainView; +}; + +class CSimpleRenderExecutor : public CRenderExecutor +{ + DECLARE_CLASS(CSimpleRenderExecutor, CRenderExecutor); +public: + explicit CSimpleRenderExecutor(CViewRender* pMainView) : CRenderExecutor(pMainView) {} + + void AddView(CRendering3dView* pView); + + void Execute() {} +}; + + +#if defined(_PS3) +class CConcurrentViewBuilderPS3 +{ +public: + + CConcurrentViewBuilderPS3(); + ~CConcurrentViewBuilderPS3() { Purge(); }; + + void Init(void); + void Purge(void); + + void ResetBuildViewID(void); + + int GetBuildViewID(void); + + void PushBuildView(void); + void PopBuildView(void); + + void SyncViewBuilderJobs(void); + + void SPUBuildRWJobsOn(bool jobOn) { m_bSPUBuildRWJobsOn = jobOn; }; + bool IsSPUBuildRWJobsOn(void) { return m_bSPUBuildRWJobsOn; }; + + int GetPassFlags(void) { return m_passFlags; }; + void SetPassFlags(int flags) { m_passFlags = flags; }; + + IWorldRenderList* GetWorldRenderListElement(void); + void SetWorldRenderListElement(IWorldRenderList* pRenderList); + + int GetDrawFlags(void) { return m_drawFlags; }; + void SetDrawFlags(int drawFlags) { m_drawFlags = drawFlags; }; + + unsigned int GetVisFlags(void); + void SetVisFlags(unsigned int visFlags); + + void CacheFrustumData(Frustum_t* pFrustum, Frustum_t* pAreaFrustum, void* pRenderAreaBits, int numArea, bool bViewerInSolidSpace); + void CacheBuildViewVolumeCuller(void* pVC); + void* GetBuildViewVolumeCuller(void); + Frustum_t* GetBuildViewFrustum(void); + Frustum_t* GetBuildViewAreaFrustum(void); + unsigned char* GetBuildViewRenderAreaBits(void); + + int GetNumAreaFrustum(void); + Frustum_t* GetBuildViewAreaFrustumID(int frustumID); + + + void PushBuildRenderableJobs(void); + +private: + + int m_buildViewID; + int m_nextFreeBuildViewID; + + int* m_pBuildViewStack; + int m_buildViewStack[MAX_CONCURRENT_BUILDVIEWS]; + + int m_passFlags; + int m_drawFlags; + unsigned int m_visFlags[MAX_CONCURRENT_BUILDVIEWS]; + + + IWorldRenderList* m_pWorldRenderListCache[MAX_CONCURRENT_BUILDVIEWS] ALIGN16; + + Frustum_t m_gFrustum[MAX_CONCURRENT_BUILDVIEWS] ALIGN16; + CUtlVector m_gAreaFrustum[MAX_CONCURRENT_BUILDVIEWS] ALIGN16; + unsigned char m_gRenderAreaBits[MAX_CONCURRENT_BUILDVIEWS][32] ALIGN16; + bool m_bViewerInSolidSpace[MAX_CONCURRENT_BUILDVIEWS] ALIGN16; + + CVolumeCuller m_volumeCullerCache[MAX_CONCURRENT_BUILDVIEWS] ALIGN16; + + bool m_bSPUBuildRWJobsOn; +}; + +extern CConcurrentViewBuilderPS3 g_viewBuilder; + +#else + +class CConcurrentViewData +{ +public: + + void Init(void); + void Purge(void); + + CVolumeCuller m_volumeCuller; + Frustum_t m_Frustum; + CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t, 16 > > m_AreaFrustums; + Frustum_t* m_frustumList[MAX_MAP_AREAS]; + + IWorldRenderList* m_pWorldRenderList; + ClientWorldListInfo_t* m_pWorldListInfo; + CClientRenderablesList* m_pRenderablesList; + + CJob* m_pBuildWorldListJob; + CJob* m_pBuildRenderablesListJob; + bool m_bWaitForWorldList; +}; + +class CConcurrentViewBuilder +{ +public: + + CConcurrentViewBuilder(); + ~CConcurrentViewBuilder(); + + void Init(void); + void Purge(void); + + void SetBuildWRThreaded(bool bThreaded) { m_bThreaded = bThreaded; } + bool GetBuildWRThreaded(void) { return m_bThreaded; } + + void ResetBuildViewID(void); + + int GetBuildViewID(void); + + void PushBuildView(void); + void PopBuildView(void); + + int GetPassFlags(void) { return m_passFlags; }; + void SetPassFlags(int flags) { m_passFlags = flags; }; + + void CacheBuildViewVolumeCuller(const CVolumeCuller* pVC); + const CVolumeCuller* GetBuildViewVolumeCuller(int buildViewID = -1) const; + + void CacheFrustumData(const Frustum_t& frustum, const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t, 16 > >& aeraFrustums); + void CacheFrustumData(void); + const Frustum_t* GetBuildViewFrustum(int buildViewID = -1) const; + const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t, 16 > >* GetBuildViewAeraFrustums(int buildViewID = -1) const; + Frustum_t** GetBuildViewFrustumList(int buildViewID = -1); + + IWorldRenderList* GetWorldRenderListElement(void); + void SetWorldRenderListElement(IWorldRenderList* pRenderList); + + ClientWorldListInfo_t* GetClientWorldListInfoElement(int buildViewID = -1); + WorldListInfo_t* GetWorldListInfoElement(int buildViewID); + void SetWorldListInfoElement(ClientWorldListInfo_t* pWorldListInfo, int buildViewID = -1); + + CClientRenderablesList* GetRenderablesListElement(int buildViewID = -1); + void SetRenderablesListElement(CClientRenderablesList* pRenderables); + + void QueueBuildWorldListJob(CJob* pJob); + void WaitForBuildWorldListJob(void); + void FlushBuildWorldListJob(void); + + void QueueBuildRenderablesListJob(CJob* pJob); + void WaitForBuildRenderablesListJob(void); + void FlushBuildRenderablesListJob(void); + void AddDependencyToWorldList(void); + +private: + + void AddJobToThreadPool(CJob* pJob); + void AddToSequentialJobs(CJob* pJob); + void TryRunSequentialJobs(void); + void WaitForCurrentSequentialJobAndRunPending(); + void InternalWaitForBuildWorldListJob(int buildViewID); + + class SequentialJobs : public CJob + { + public: + + explicit SequentialJobs(CJob* pJob = NULL); + ~SequentialJobs(); + + void AddJob(CJob* pJob); + + virtual JobStatus_t DoExecute(); + + private: + + CUtlVectorFixed m_jobs; + }; + + bool m_bThreaded; + + int m_buildViewID; + int m_nextFreeBuildViewID; + + int* m_pBuildViewStack; + int m_buildViewStack[MAX_CONCURRENT_BUILDVIEWS]; + + int m_passFlags; + + CConcurrentViewData m_viewData[MAX_CONCURRENT_BUILDVIEWS]; + + SequentialJobs* m_pCurrentSeqJobs; + SequentialJobs* m_pPendingSeqJobs; + + CUtlVector mJobsAddedToThreadPool; +}; + +extern CConcurrentViewBuilder g_viewBuilder; + +#endif + +class CViewRender : public IViewRender +{ + DECLARE_CLASS_NOBASE(CViewRender); +public: + virtual void Init(void); + virtual void Shutdown(void); + + const CViewSetup* GetPlayerViewSetup(int nSlot = -1) const; + + virtual void StartPitchDrift(void); + virtual void StopPitchDrift(void); + + virtual float GetZNear(); + virtual float GetZFar(); + + virtual void OnRenderStart(); + void DriftPitch(void); + + static CViewRender* GetMainView() { return assert_cast(view); } + + void AddViewToScene(CRendering3dView* pView) { m_SimpleExecutor.AddView(pView); } + + CMaterialReference& GetWhite(); + + virtual void InitFadeData(void); + +protected: + void SetUpView(); + + void SetUpOverView(); + void SetUpChaseOverview(); + + virtual void WriteSaveGameScreenshotOfSize(const char* pFilename, int width, int height); + void WriteSaveGameScreenshot(const char* filename); + + CViewSetup& GetView(int nSlot = -1); + const CViewSetup& GetView(int nSlot = -1) const; + + CViewSetup m_UserView[MAX_SPLITSCREEN_PLAYERS]; + bool m_bAllowViewAccess; + CPitchDrift m_PitchDrift; + + virtual void RenderPreScene(const CViewSetup& view) { } + virtual void PreViewDrawScene(const CViewSetup& view) {} + virtual void PostViewDrawScene(const CViewSetup& view) {} + + float m_flOldChaseOverviewScale; + float m_flIdealChaseOverviewScale; + float m_flNextIdealOverviewScaleUpdate; +public: + CViewRender(); + virtual ~CViewRender(void) {} + +public: + + void SetupVis(const CViewSetup& view, unsigned int& visFlags, ViewCustomVisibility_t* pCustomVisibility = NULL); + + + virtual void Render(vrect_t* rect); + virtual void RenderView(const CViewSetup& view, const CViewSetup& hudViewSetup, int nClearFlags, int whatToDraw); + virtual void RenderPlayerSprites(); + virtual void Render2DEffectsPreHUD(const CViewSetup& view); + virtual void Render2DEffectsPostHUD(const CViewSetup& view); + virtual void RenderSmokeOverlay(bool bPreViewModel = true) {}; + float GetLastRenderSmokeOverlayAmount() const { return m_flSmokeOverlayAmount; } + + + void DisableFog(void); + + void LevelInit(void); + void LevelShutdown(void); + + bool ShouldDrawEntities(void); + bool ShouldDrawBrushModels(void); + + const CViewSetup* GetViewSetup() const; + + void DisableVis(void); + + void MoveViewModels(); + + void GetViewModelPosition(int nIndex, Vector* pPos, QAngle* pAngle); + + void SetCheapWaterStartDistance(float flCheapWaterStartDistance); + void SetCheapWaterEndDistance(float flCheapWaterEndDistance); + + void GetWaterLODParams(float& flCheapWaterStartDistance, float& flCheapWaterEndDistance); + + virtual void QueueOverlayRenderView(const CViewSetup& view, int nClearFlags, int whatToDraw); + + virtual void GetScreenFadeDistances(float* pMin, float* pMax, float* pScale); + + virtual C_BaseEntity* GetCurrentlyDrawingEntity(); + virtual void SetCurrentlyDrawingEntity(C_BaseEntity* pEnt); + + virtual bool UpdateShadowDepthTexture(ITexture* pRenderTarget, ITexture* pDepthTexture, const CViewSetup& shadowView, bool bRenderWorldAndObjects = true, bool bRenderViewModels = false); + + int GetBaseDrawFlags() { return m_BaseDrawFlags; } + virtual bool ShouldForceNoVis() { return m_bForceNoVis; } + int BuildRenderablesListsNumber() const { return m_BuildRenderableListsNumber; } + int IncRenderablesListsNumber() { return ++m_BuildRenderableListsNumber; } + + int BuildWorldListsNumber() const; + int IncWorldListsNumber() { return ++m_BuildWorldListsNumber; } + + virtual VPlane* GetFrustum() { return (m_pActiveRenderer) ? m_pActiveRenderer->GetFrustum() : m_Frustum; } + + virtual int GetDrawFlags() { return (m_pActiveRenderer) ? m_pActiveRenderer->GetDrawFlags() : 0; } + + CBase3dView* GetActiveRenderer() { return m_pActiveRenderer; } + CBase3dView* SetActiveRenderer(CBase3dView* pActiveRenderer) { CBase3dView* pPrevious = m_pActiveRenderer; m_pActiveRenderer = pActiveRenderer; return pPrevious; } + + void FreezeFrame(float flFreezeTime); + + void SetWaterOverlayMaterial(IMaterial* pMaterial) + { + m_UnderWaterOverlayMaterial.Init(pMaterial); + } + + void DrawViewModelsShadowDepth(const CViewSetup& view); + +protected: + int m_BuildWorldListsNumber; + + + void ViewDrawScene(bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup& view, int nClearFlags, view_id_t viewID, bool bDrawViewModel = false, int baseDrawFlags = 0, ViewCustomVisibility_t* pCustomVisibility = NULL); + + void DrawMonitors(const CViewSetup& cameraView); + + bool DrawOneMonitor(ITexture* pRenderTarget, int cameraNum, C_PointCamera* pCameraEnt, const CViewSetup& cameraView, void* localPlayer, + int x, int y, int width, int height); + + bool ShouldDrawViewModel(bool drawViewmodel); +#ifdef IRONSIGHT + void DrawViewModels(const CViewSetup& view, bool drawViewmodel, bool bDrawScopeLensMask = false); +#else + void DrawViewModels(const CViewSetup& view, bool drawViewmodel); +#endif + + void PerformScreenSpaceEffects(int x, int y, int w, int h); + + void SetScreenOverlayMaterial(IMaterial* pMaterial); + IMaterial* GetScreenOverlayMaterial(); + void PerformScreenOverlay(int x, int y, int w, int h); + + void DrawUnderwaterOverlay(void); + + void DrawWorldAndEntities(bool drawSkybox, const CViewSetup& view, int nClearFlags, ViewCustomVisibility_t* pCustomVisibility = NULL); + + virtual void ViewDrawScene_Intro(const CViewSetup& view, int nClearFlags, const IntroData_t& introData); + +#ifdef PORTAL + void ViewDrawScene_PortalStencil(const CViewSetup& view, ViewCustomVisibility_t* pCustomVisibility); + void Draw3dSkyboxworld_Portal(const CViewSetup& view, int& nClearFlags, bool& bDrew3dSkybox, SkyboxVisibility_t& nSkyboxVisible, ITexture* pRenderTarget = NULL); +#endif + +#ifdef PORTAL2 + void ViewDrawPhoto(ITexture* pRenderTarget, C_BaseEntity* pEnt); +#endif + + void DetermineWaterRenderInfo(const VisibleFogVolumeInfo_t& fogVolumeInfo, WaterRenderInfo_t& info); + + bool UpdateRefractIfNeededByList(CViewModelRenderablesList::RenderGroups_t& list); + void DrawRenderablesInList(CViewModelRenderablesList::RenderGroups_t& list, int flags = 0); + + void SetupMain3DView(int nSlot, const CViewSetup& view, const CViewSetup& hudViewSetup, int& nClearFlags, ITexture* pRenderTarget); + void CleanupMain3DView(const CViewSetup& view); + + void GetLetterBoxRectangles(int nSlot, const CViewSetup& view, CUtlVector< vrect_t >& vecLetterBoxRectangles); + void DrawLetterBoxRectangles(int nSlot, const CUtlVector< vrect_t >& vecLetterBoxRectangles); + + void EnableWaterDepthFeathing(IMaterial* pWaterMaterial, bool bEnable); + +#if defined(_PS3) + void InitSPUBuildRenderingJobs(void); +#endif + + CViewSetup m_CurrentView; + + bool m_bForceNoVis; + + const ConVar* m_pDrawEntities; + const ConVar* m_pDrawBrushModels; + + CMaterialReference m_TranslucentSingleColor; + CMaterialReference m_ModulateSingleColor; + CMaterialReference m_ScreenOverlayMaterial; + CMaterialReference m_UnderWaterOverlayMaterial; + + Vector m_vecLastFacing; + float m_flCheapWaterStartDistance; + float m_flCheapWaterEndDistance; + + CViewSetup m_OverlayViewSetup; + int m_OverlayClearFlags; + int m_OverlayDrawFlags; + bool m_bDrawOverlay; + + int m_BaseDrawFlags; + C_BaseEntity* m_pCurrentlyDrawingEntity; + +#ifdef PORTAL + friend class CPortalRender; + friend class CPortalRenderable; +#endif + int m_BuildRenderableListsNumber; + + friend class CBase3dView; + + Frustum m_Frustum; + + CBase3dView* m_pActiveRenderer; + CSimpleRenderExecutor m_SimpleExecutor; + + struct FreezeParams_t + { + FreezeParams_t() : m_bTakeFreezeFrame(false), m_flFreezeFrameUntil(0.0f) {} + + bool m_bTakeFreezeFrame; + float m_flFreezeFrameUntil; + }; + + FreezeParams_t m_FreezeParams[MAX_SPLITSCREEN_PLAYERS]; + + FadeData_t m_FadeData; + + CMaterialReference m_WhiteMaterial; + + CON_COMMAND_MEMBER_F(CViewRender, "screenfademinsize", OnScreenFadeMinSize, "Modify global screen fade min size in pixels", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY); + CON_COMMAND_MEMBER_F(CViewRender, "screenfademaxsize", OnScreenFadeMaxSize, "Modify global screen fade max size in pixels", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY); + + float m_flSmokeOverlayAmount; +}; + +#endif +``` + +`SpyCustom/sdk/vmatrix.h`: + +```h +#ifndef VMATRIX_H +#define VMATRIX_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "vector.h" +#include "vplane.h" +#include "vector4d.h" +#include "mathlib.h" + +struct cplane_t; + + +class VMatrix +{ +public: + + VMatrix(); + VMatrix( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33 + ); + + VMatrix(const Vector& forward, const Vector& left, const Vector& up); + VMatrix(const Vector& forward, const Vector& left, const Vector& up, const Vector& translation); + + VMatrix(const matrix3x4_t& matrix3x4); + + void Init( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33 + ); + + + void Init(const matrix3x4_t& matrix3x4); + + inline float* operator[](int i) + { + return m[i]; + } + + inline const float* operator[](int i) const + { + return m[i]; + } + + inline float* Base() + { + return &m[0][0]; + } + + inline const float* Base() const + { + return &m[0][0]; + } + + void SetLeft(const Vector& vLeft); + void SetUp(const Vector& vUp); + void SetForward(const Vector& vForward); + + void GetBasisVectors(Vector& vForward, Vector& vLeft, Vector& vUp) const; + void SetBasisVectors(const Vector& vForward, const Vector& vLeft, const Vector& vUp); + + Vector& GetTranslation(Vector& vTrans) const; + void SetTranslation(const Vector& vTrans); + + void PreTranslate(const Vector& vTrans); + void PostTranslate(const Vector& vTrans); + + const matrix3x4_t& As3x4() const; + void CopyFrom3x4(const matrix3x4_t& m3x4); + void Set3x4(matrix3x4_t& matrix3x4) const; + + bool operator==(const VMatrix& src) const; + bool operator!=(const VMatrix& src) const { return !(*this == src); } + +#ifndef VECTOR_NO_SLOW_OPERATIONS + Vector GetLeft() const; + Vector GetUp() const; + Vector GetForward() const; + Vector GetTranslation() const; +#endif + + +public: + void V3Mul(const Vector& vIn, Vector& vOut) const; + + void V4Mul(const Vector4D& vIn, Vector4D& vOut) const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + Vector ApplyRotation(const Vector& vVec) const; + + Vector operator*(const Vector& vVec) const; + + Vector VMul3x3(const Vector& vVec) const; + + Vector VMul3x3Transpose(const Vector& vVec) const; + + Vector VMul4x3(const Vector& vVec) const; + + Vector VMul4x3Transpose(const Vector& vVec) const; +#endif + + +public: + void TransformPlane(const VPlane& inPlane, VPlane& outPlane) const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + VPlane operator*(const VPlane& thePlane) const; +#endif + +public: + + VMatrix& operator=(const VMatrix& mOther); + + void MatrixMul(const VMatrix& vm, VMatrix& out) const; + + const VMatrix& operator+=(const VMatrix& other); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + VMatrix operator*(const VMatrix& mOther) const; + + VMatrix operator+(const VMatrix& other) const; + VMatrix operator-(const VMatrix& other) const; + + VMatrix operator-() const; + + VMatrix operator~() const; +#endif + +public: + void Identity(); + + bool IsIdentity() const; + + void SetupMatrixOrgAngles(const Vector& origin, const QAngle& vAngles); + + void SetupMatrixAngles(const QAngle& vAngles); + + bool InverseGeneral(VMatrix& vInverse) const; + + void InverseTR(VMatrix& mRet) const; + + bool IsRotationMatrix() const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + VMatrix InverseTR() const; + + Vector GetScale() const; + + VMatrix Scale(const Vector& vScale); + + VMatrix NormalizeBasisVectors() const; + + VMatrix Transpose() const; + + VMatrix Transpose3x3() const; +#endif + +public: + vec_t m[4][4]; +}; + + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +VMatrix SetupMatrixIdentity(); + +VMatrix SetupMatrixScale(const Vector& vScale); + +VMatrix SetupMatrixTranslation(const Vector& vTranslation); + +VMatrix SetupMatrixReflection(const VPlane& thePlane); + +VMatrix SetupMatrixProjection(const Vector& vOrigin, const VPlane& thePlane); + +VMatrix SetupMatrixAxisRot(const Vector& vAxis, vec_t fDegrees); + +VMatrix SetupMatrixAngles(const QAngle& vAngles); + +VMatrix SetupMatrixOrgAngles(const Vector& origin, const QAngle& vAngles); + +#endif + +#define VMatToString(mat) (static_cast(CFmtStr("[ (%f, %f, %f), (%f, %f, %f), (%f, %f, %f), (%f, %f, %f) ]", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3] ))) + +bool PlaneIntersection(const VPlane& vp1, const VPlane& vp2, const VPlane& vp3, Vector& vOut); + + +void MatrixSetIdentity(VMatrix& dst); +void MatrixTranspose(const VMatrix& src, VMatrix& dst); +void MatrixCopy(const VMatrix& src, VMatrix& dst); +void MatrixMultiply(const VMatrix& src1, const VMatrix& src2, VMatrix& dst); + +void MatrixGetColumn(const VMatrix& src, int nCol, Vector* pColumn); +void MatrixSetColumn(VMatrix& src, int nCol, const Vector& column); +void MatrixGetRow(const VMatrix& src, int nCol, Vector* pColumn); +void MatrixSetRow(VMatrix& src, int nCol, const Vector& column); + +void Vector3DMultiply(const VMatrix& src1, const Vector& src2, Vector& dst); + +inline void Vector3DMultiplyPosition(const VMatrix& src1, const VectorByValue src2, Vector& dst); + +void Vector3DMultiplyPositionProjective(const VMatrix& src1, const Vector& src2, Vector& dst); + +void Vector3DMultiplyProjective(const VMatrix& src1, const Vector& src2, Vector& dst); + +void Vector4DMultiply(const VMatrix& src1, const Vector4D& src2, Vector4D& dst); + +void Vector4DMultiplyPosition(const VMatrix& src1, const Vector& src2, Vector4D& dst); + +void Vector3DMultiplyTranspose(const VMatrix& src1, const Vector& src2, Vector& dst); +void Vector4DMultiplyTranspose(const VMatrix& src1, const Vector4D& src2, Vector4D& dst); + +void MatrixTransformPlane(const VMatrix& src, const cplane_t& inPlane, cplane_t& outPlane); + +void MatrixTransformAxisAlignedPlane(const VMatrix& src, int nDim, float flSign, float flDist, cplane_t& outPlane); + +void MatrixBuildTranslation(VMatrix& dst, float x, float y, float z); +void MatrixBuildTranslation(VMatrix& dst, const Vector& translation); + +inline void MatrixTranslate(VMatrix& dst, const Vector& translation) +{ + VMatrix matTranslation, temp; + MatrixBuildTranslation(matTranslation, translation); + MatrixMultiply(dst, matTranslation, temp); + dst = temp; +} + + +void MatrixBuildRotationAboutAxis(VMatrix& dst, const Vector& vAxisOfRot, float angleDegrees); +void MatrixBuildRotateZ(VMatrix& dst, float angleDegrees); + +inline void MatrixRotate(VMatrix& dst, const Vector& vAxisOfRot, float angleDegrees) +{ + VMatrix rotation, temp; + MatrixBuildRotationAboutAxis(rotation, vAxisOfRot, angleDegrees); + MatrixMultiply(dst, rotation, temp); + dst = temp; +} + +void MatrixBuildRotation(VMatrix& dst, const Vector& initialDirection, const Vector& finalDirection); + +void MatrixBuildScale(VMatrix& dst, float x, float y, float z); +void MatrixBuildScale(VMatrix& dst, const Vector& scale); + +void MatrixBuildPerspective(VMatrix& dst, float fovX, float fovY, float zNear, float zFar); + +void CalculateAABBFromProjectionMatrix(const VMatrix& worldToVolume, Vector* pMins, Vector* pMaxs); + +void CalculateSphereFromProjectionMatrix(const VMatrix& worldToVolume, Vector* pCenter, float* pflRadius); + +void CalculateAABBFromProjectionMatrixInverse(const VMatrix& volumeToWorld, Vector* pMins, Vector* pMaxs); + +void CalculateSphereFromProjectionMatrixInverse(const VMatrix& volumeToWorld, Vector* pCenter, float* pflRadius); + +void FrustumPlanesFromMatrix(const VMatrix& clipToWorld, Frustum_t& frustum); + +void MatrixFromAngles(const QAngle& vAngles, VMatrix& dst); + +void MatrixToAngles(const VMatrix& src, QAngle& vAngles); + +void MatrixInverseTR(const VMatrix& src, VMatrix& dst); + +bool MatrixInverseGeneral(const VMatrix& src, VMatrix& dst); + +void MatrixInverseTranspose(const VMatrix& src, VMatrix& dst); + + + +inline VMatrix::VMatrix() +{ +} + +inline VMatrix::VMatrix( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33) +{ + Init( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33 + ); +} + + +inline VMatrix::VMatrix(const matrix3x4_t& matrix3x4) +{ + Init(matrix3x4); +} + + +inline VMatrix::VMatrix(const Vector& xAxis, const Vector& yAxis, const Vector& zAxis) +{ + Init( + xAxis.x, yAxis.x, zAxis.x, 0.0f, + xAxis.y, yAxis.y, zAxis.y, 0.0f, + xAxis.z, yAxis.z, zAxis.z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); +} + +inline VMatrix::VMatrix(const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector& translation) +{ + Init( + xAxis.x, yAxis.x, zAxis.x, translation.x, + xAxis.y, yAxis.y, zAxis.y, translation.y, + xAxis.z, yAxis.z, zAxis.z, translation.z, + 0.0f, 0.0f, 0.0f, 1.0f + ); +} + + +inline void VMatrix::Init( + vec_t m00, vec_t m01, vec_t m02, vec_t m03, + vec_t m10, vec_t m11, vec_t m12, vec_t m13, + vec_t m20, vec_t m21, vec_t m22, vec_t m23, + vec_t m30, vec_t m31, vec_t m32, vec_t m33 +) +{ + m[0][0] = m00; + m[0][1] = m01; + m[0][2] = m02; + m[0][3] = m03; + + m[1][0] = m10; + m[1][1] = m11; + m[1][2] = m12; + m[1][3] = m13; + + m[2][0] = m20; + m[2][1] = m21; + m[2][2] = m22; + m[2][3] = m23; + + m[3][0] = m30; + m[3][1] = m31; + m[3][2] = m32; + m[3][3] = m33; +} + + +inline void VMatrix::Init(const matrix3x4_t& matrix3x4) +{ + memcpy(m, matrix3x4.Base(), sizeof(matrix3x4_t)); + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::GetForward() const +{ + return Vector(m[0][0], m[1][0], m[2][0]); +} + +inline Vector VMatrix::GetLeft() const +{ + return Vector(m[0][1], m[1][1], m[2][1]); +} + +inline Vector VMatrix::GetUp() const +{ + return Vector(m[0][2], m[1][2], m[2][2]); +} + +#endif + +inline void VMatrix::SetForward(const Vector& vForward) +{ + m[0][0] = vForward.x; + m[1][0] = vForward.y; + m[2][0] = vForward.z; +} + +inline void VMatrix::SetLeft(const Vector& vLeft) +{ + m[0][1] = vLeft.x; + m[1][1] = vLeft.y; + m[2][1] = vLeft.z; +} + +inline void VMatrix::SetUp(const Vector& vUp) +{ + m[0][2] = vUp.x; + m[1][2] = vUp.y; + m[2][2] = vUp.z; +} + +inline void VMatrix::GetBasisVectors(Vector& vForward, Vector& vLeft, Vector& vUp) const +{ + vForward.Init(m[0][0], m[1][0], m[2][0]); + vLeft.Init(m[0][1], m[1][1], m[2][1]); + vUp.Init(m[0][2], m[1][2], m[2][2]); +} + +inline void VMatrix::SetBasisVectors(const Vector& vForward, const Vector& vLeft, const Vector& vUp) +{ + SetForward(vForward); + SetLeft(vLeft); + SetUp(vUp); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::GetTranslation() const +{ + return Vector(m[0][3], m[1][3], m[2][3]); +} + +#endif + +inline Vector& VMatrix::GetTranslation(Vector& vTrans) const +{ + vTrans.x = m[0][3]; + vTrans.y = m[1][3]; + vTrans.z = m[2][3]; + return vTrans; +} + +inline void VMatrix::SetTranslation(const Vector& vTrans) +{ + m[0][3] = vTrans.x; + m[1][3] = vTrans.y; + m[2][3] = vTrans.z; +} + + +inline void VMatrix::PreTranslate(const Vector& vTrans) +{ + Vector tmp; + Vector3DMultiplyPosition(*this, vTrans, tmp); + m[0][3] = tmp.x; + m[1][3] = tmp.y; + m[2][3] = tmp.z; +} + + +inline void VMatrix::PostTranslate(const Vector& vTrans) +{ + m[0][3] += vTrans.x; + m[1][3] += vTrans.y; + m[2][3] += vTrans.z; +} + +inline const matrix3x4_t& VMatrix::As3x4() const +{ + return *((const matrix3x4_t*)this); +} + +inline void VMatrix::CopyFrom3x4(const matrix3x4_t& m3x4) +{ + memcpy(m, m3x4.Base(), sizeof(matrix3x4_t)); + m[3][0] = m[3][1] = m[3][2] = 0; + m[3][3] = 1; +} + +inline void VMatrix::Set3x4(matrix3x4_t& matrix3x4) const +{ + memcpy(matrix3x4.Base(), m, sizeof(matrix3x4_t)); +} + + +inline const VMatrix& VMatrix::operator+=(const VMatrix& other) +{ + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + m[i][j] += other.m[i][j]; + } + } + + return *this; +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline VMatrix VMatrix::operator+(const VMatrix& other) const +{ + VMatrix ret; + for (int i = 0; i < 16; i++) + { + ((float*)ret.m)[i] = ((float*)m)[i] + ((float*)other.m)[i]; + } + return ret; +} + +inline VMatrix VMatrix::operator-(const VMatrix& other) const +{ + VMatrix ret; + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + ret.m[i][j] = m[i][j] - other.m[i][j]; + } + } + + return ret; +} + +inline VMatrix VMatrix::operator-() const +{ + VMatrix ret; + for (int i = 0; i < 16; i++) + { + ((float*)ret.m)[i] = ((float*)m)[i]; + } + return ret; +} + +#endif + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::operator*(const Vector& vVec) const +{ + Vector vRet; + vRet.x = m[0][0] * vVec.x + m[0][1] * vVec.y + m[0][2] * vVec.z + m[0][3]; + vRet.y = m[1][0] * vVec.x + m[1][1] * vVec.y + m[1][2] * vVec.z + m[1][3]; + vRet.z = m[2][0] * vVec.x + m[2][1] * vVec.y + m[2][2] * vVec.z + m[2][3]; + + return vRet; +} + +inline Vector VMatrix::VMul4x3(const Vector& vVec) const +{ + Vector vResult; + Vector3DMultiplyPosition(*this, vVec, vResult); + return vResult; +} + + +inline Vector VMatrix::VMul4x3Transpose(const Vector& vVec) const +{ + Vector tmp = vVec; + tmp.x -= m[0][3]; + tmp.y -= m[1][3]; + tmp.z -= m[2][3]; + + return Vector( + m[0][0] * tmp.x + m[1][0] * tmp.y + m[2][0] * tmp.z, + m[0][1] * tmp.x + m[1][1] * tmp.y + m[2][1] * tmp.z, + m[0][2] * tmp.x + m[1][2] * tmp.y + m[2][2] * tmp.z + ); +} + +inline Vector VMatrix::VMul3x3(const Vector& vVec) const +{ + return Vector( + m[0][0] * vVec.x + m[0][1] * vVec.y + m[0][2] * vVec.z, + m[1][0] * vVec.x + m[1][1] * vVec.y + m[1][2] * vVec.z, + m[2][0] * vVec.x + m[2][1] * vVec.y + m[2][2] * vVec.z + ); +} + +inline Vector VMatrix::VMul3x3Transpose(const Vector& vVec) const +{ + return Vector( + m[0][0] * vVec.x + m[1][0] * vVec.y + m[2][0] * vVec.z, + m[0][1] * vVec.x + m[1][1] * vVec.y + m[2][1] * vVec.z, + m[0][2] * vVec.x + m[1][2] * vVec.y + m[2][2] * vVec.z + ); +} + +#endif + + +inline void VMatrix::V3Mul(const Vector& vIn, Vector& vOut) const +{ + vec_t rw; + + rw = 1.0f / (m[3][0] * vIn.x + m[3][1] * vIn.y + m[3][2] * vIn.z + m[3][3]); + vOut.x = (m[0][0] * vIn.x + m[0][1] * vIn.y + m[0][2] * vIn.z + m[0][3]) * rw; + vOut.y = (m[1][0] * vIn.x + m[1][1] * vIn.y + m[1][2] * vIn.z + m[1][3]) * rw; + vOut.z = (m[2][0] * vIn.x + m[2][1] * vIn.y + m[2][2] * vIn.z + m[2][3]) * rw; +} + +inline void VMatrix::V4Mul(const Vector4D& vIn, Vector4D& vOut) const +{ + vOut[0] = m[0][0] * vIn[0] + m[0][1] * vIn[1] + m[0][2] * vIn[2] + m[0][3] * vIn[3]; + vOut[1] = m[1][0] * vIn[0] + m[1][1] * vIn[1] + m[1][2] * vIn[2] + m[1][3] * vIn[3]; + vOut[2] = m[2][0] * vIn[0] + m[2][1] * vIn[1] + m[2][2] * vIn[2] + m[2][3] * vIn[3]; + vOut[3] = m[3][0] * vIn[0] + m[3][1] * vIn[1] + m[3][2] * vIn[2] + m[3][3] * vIn[3]; +} + + +inline void VMatrix::TransformPlane(const VPlane& inPlane, VPlane& outPlane) const +{ + Vector vTrans; + Vector3DMultiply(*this, inPlane.m_Normal, outPlane.m_Normal); + outPlane.m_Dist = inPlane.m_Dist * DotProduct(outPlane.m_Normal, outPlane.m_Normal); + outPlane.m_Dist += DotProduct(outPlane.m_Normal, GetTranslation(vTrans)); +} + + +inline void VMatrix::Identity() +{ + MatrixSetIdentity(*this); +} + + +inline bool VMatrix::IsIdentity() const +{ + return + m[0][0] == 1.0f && m[0][1] == 0.0f && m[0][2] == 0.0f && m[0][3] == 0.0f && + m[1][0] == 0.0f && m[1][1] == 1.0f && m[1][2] == 0.0f && m[1][3] == 0.0f && + m[2][0] == 0.0f && m[2][1] == 0.0f && m[2][2] == 1.0f && m[2][3] == 0.0f && + m[3][0] == 0.0f && m[3][1] == 0.0f && m[3][2] == 0.0f && m[3][3] == 1.0f; +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline Vector VMatrix::ApplyRotation(const Vector& vVec) const +{ + return VMul3x3(vVec); +} + +inline VMatrix VMatrix::operator~() const +{ + VMatrix mRet; + InverseGeneral(mRet); + return mRet; +} + +#endif + + +inline void MatrixGetColumn(const VMatrix& src, int nCol, Vector* pColumn) +{ + Assert((nCol >= 0) && (nCol <= 3)); + + pColumn->x = src[0][nCol]; + pColumn->y = src[1][nCol]; + pColumn->z = src[2][nCol]; +} + +inline void MatrixSetColumn(VMatrix& src, int nCol, const Vector& column) +{ + Assert((nCol >= 0) && (nCol <= 3)); + + src.m[0][nCol] = column.x; + src.m[1][nCol] = column.y; + src.m[2][nCol] = column.z; +} + +inline void MatrixGetRow(const VMatrix& src, int nRow, Vector* pRow) +{ + Assert((nRow >= 0) && (nRow <= 3)); + *pRow = *(Vector*)src[nRow]; +} + +inline void MatrixSetRow(VMatrix& dst, int nRow, const Vector& row) +{ + Assert((nRow >= 0) && (nRow <= 3)); + *(Vector*)dst[nRow] = row; +} + + +inline void Vector3DMultiplyPosition(const VMatrix& src1, const VectorByValue src2, Vector& dst) +{ + dst[0] = src1[0][0] * src2.x + src1[0][1] * src2.y + src1[0][2] * src2.z + src1[0][3]; + dst[1] = src1[1][0] * src2.x + src1[1][1] * src2.y + src1[1][2] * src2.z + src1[1][3]; + dst[2] = src1[2][0] * src2.x + src1[2][1] * src2.y + src1[2][2] * src2.z + src1[2][3]; +} + + +inline void MatrixTransformAxisAlignedPlane(const VMatrix& src, int nDim, float flSign, float flDist, cplane_t& outPlane) +{ + MatrixGetColumn(src, nDim, &outPlane.normal); + outPlane.normal *= flSign; + outPlane.dist = flDist * DotProduct(outPlane.normal, outPlane.normal); + + outPlane.dist += outPlane.normal.x * src.m[0][3] + outPlane.normal.y * src.m[1][3] + outPlane.normal.z * src.m[2][3]; +} + + +inline bool MatricesAreEqual(const VMatrix& src1, const VMatrix& src2, float flTolerance) +{ + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + if (fabs(src1[i][j] - src2[i][j]) > flTolerance) + return false; + } + } + return true; +} + +void MatrixBuildOrtho(VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar); +void MatrixBuildPerspectiveX(VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar); +void MatrixBuildPerspectiveOffCenterX(VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right); +void MatrixBuildPerspectiveZRange(VMatrix& dst, double flZNear, double flZFar); + +inline void MatrixOrtho(VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar) +{ + VMatrix mat; + MatrixBuildOrtho(mat, left, top, right, bottom, zNear, zFar); + + VMatrix temp; + MatrixMultiply(dst, mat, temp); + dst = temp; +} + +inline void MatrixPerspectiveX(VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar) +{ + VMatrix mat; + MatrixBuildPerspectiveX(mat, flFovX, flAspect, flZNear, flZFar); + + VMatrix temp; + MatrixMultiply(dst, mat, temp); + dst = temp; +} + +inline void MatrixPerspectiveOffCenterX(VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right) +{ + VMatrix mat; + MatrixBuildPerspectiveOffCenterX(mat, flFovX, flAspect, flZNear, flZFar, bottom, top, left, right); + + VMatrix temp; + MatrixMultiply(dst, mat, temp); + dst = temp; +} + +#endif + + +``` + +`SpyCustom/sdk/volumeculler.h`: + +```h +#ifndef VOLUME_CULLER_H +#define VOLUME_CULLER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" +#include "vplane.h" +#include "ssemath.h" +#include "memalloc.h" + +class CVolumeCuller : public CAlignedNewDelete< 16 > +{ +public: + inline CVolumeCuller() { Clear(); } + + inline void Clear() { m_nNumInclusionVolumePlanes = 0; m_bHasExclusionFrustum = false; m_bHasBaseFrustum = false; m_bCullSmallObjects = false; ClearCullCheckStats(); } + + inline bool IsValid() const { return m_bHasExclusionFrustum || (m_nNumInclusionVolumePlanes != 0); } + + bool CheckBox(const VectorAligned& mins, const VectorAligned& maxs) const; + bool CheckBox(const Vector& mins, const Vector& maxs) const; + bool CheckBoxCenterHalfDiagonal(const VectorAligned& center, const VectorAligned& halfDiagonal) const; + + enum + { + cNumBaseFrustumPlanes = 6, + + cNumExclusionFrustumPlanes = 6, + + cMaxInclusionVolumePlanes = 12 + }; + + inline bool HasBaseFrustum() const { return m_bHasBaseFrustum; } + void SetBaseFrustumPlanes(const VPlane* pPlanes); + + void GetBaseFrustumPlanes(VPlane* pBasePlanes) const; + int GetNumBaseFrustumPlanes() const { return cNumBaseFrustumPlanes; } + + inline bool HasExclusionFrustum() const { return m_bHasExclusionFrustum; } + void SetExclusionFrustumPlanes(const VPlane* pPlanes); + + int GetNumExclusionFrustumPlanes() const { return cNumExclusionFrustumPlanes; } + const fltx4* GetExclusionFrustumPlanes() const { return m_ExclusionFrustumPlanes; } + + inline bool HasInclusionVolume() const { return m_nNumInclusionVolumePlanes != 0; } + void SetInclusionVolumePlanes(const VPlane* pPlanes, uint nNumPlanes); + + int GetNumInclusionVolumePlanes() const { return m_nNumInclusionVolumePlanes; } + const fltx4* GetInclusionVolumePlanes() const { return m_InclusionVolumePlanes; } + + bool GetCullSmallObjects() const { return m_bCullSmallObjects; } + float GetSmallObjectCullVolumeThreshold() const { return m_flSmallObjectCullVolumeThreshold; } + + void SetCullSmallObjects(bool bCullSmallObjects, float flCullVolumeThreshold) { m_bCullSmallObjects = bCullSmallObjects; m_flSmallObjectCullVolumeThreshold = flCullVolumeThreshold; } + + struct CullCheckStats_t + { + uint m_nTotalAABB; + uint m_nTotalAABBPassed; + + uint m_nTotalCenterHalfDiagonal; + uint m_nTotalCenterHalfDiagonalPassed; + }; + + inline void ClearCullCheckStats() { memset(&m_Stats, 0, sizeof(m_Stats)); } + inline CullCheckStats_t& GetStats() const { return m_Stats; } + +private: + fourplanes_t m_baseplanes[2]; + + fltx4 m_ExclusionFrustumPlanes[cNumExclusionFrustumPlanes]; + + fltx4 m_InclusionVolumePlanes[cMaxInclusionVolumePlanes]; + + uint m_nNumInclusionVolumePlanes; + + bool m_bHasBaseFrustum : 1; + bool m_bHasExclusionFrustum : 1; + + bool m_bCullSmallObjects : 1; + float m_flSmallObjectCullVolumeThreshold; + + mutable CullCheckStats_t m_Stats; +}; + +#endif +``` + +`SpyCustom/sdk/vphysics_interface.h`: + +```h +#ifndef VPHYSICS_INTERFACE_H +#define VPHYSICS_INTERFACE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "interface.h" +#include "IAppSystem.h" +#include "vector.h" +#include "vector4d.h" +#include "vcollide.h" + + +#define METERS_PER_INCH (0.0254f) +#define CUBIC_METERS_PER_CUBIC_INCH (METERS_PER_INCH*METERS_PER_INCH*METERS_PER_INCH) +#define POUNDS_PER_KG (2.2f) +#define KG_PER_POUND (1.0f/POUNDS_PER_KG) + +#define lbs2kg(x) ((x)*KG_PER_POUND) +#define kg2lbs(x) ((x)*POUNDS_PER_KG) + +const float VPHYSICS_MIN_MASS = 0.1f; +const float VPHYSICS_MAX_MASS = 5e4f; + +class IPhysicsObject; +class IPhysicsEnvironment; +class IPhysicsSurfaceProps; +class IPhysicsConstraint; +class IPhysicsConstraintGroup; +class IPhysicsFluidController; +class IPhysicsSpring; +class IPhysicsVehicleController; +class IConvexInfo; +class IPhysicsObjectPairHash; +class IPhysicsCollisionSet; +class IPhysicsPlayerController; +class IPhysicsFrictionSnapshot; + +struct Ray_t; +struct constraint_ragdollparams_t; +struct constraint_hingeparams_t; +struct constraint_fixedparams_t; +struct constraint_ballsocketparams_t; +struct constraint_slidingparams_t; +struct constraint_pulleyparams_t; +struct constraint_lengthparams_t; +struct constraint_groupparams_t; + +struct vehicleparams_t; +struct matrix3x4_t; + +struct fluidparams_t; +struct springparams_t; +struct objectparams_t; +struct debugcollide_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct physics_stats_t; +struct physics_performanceparams_t; +struct virtualmeshparams_t; + +struct physsaveparams_t; +struct physrestoreparams_t; +struct physprerestoreparams_t; + +enum PhysInterfaceId_t +{ + PIID_UNKNOWN, + PIID_IPHYSICSOBJECT, + PIID_IPHYSICSFLUIDCONTROLLER, + PIID_IPHYSICSSPRING, + PIID_IPHYSICSCONSTRAINTGROUP, + PIID_IPHYSICSCONSTRAINT, + PIID_IPHYSICSSHADOWCONTROLLER, + PIID_IPHYSICSPLAYERCONTROLLER, + PIID_IPHYSICSMOTIONCONTROLLER, + PIID_IPHYSICSVEHICLECONTROLLER, + PIID_IPHYSICSGAMETRACE, + + PIID_NUM_TYPES +}; + + +class ISave; +class IRestore; + + +#define VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION "VPhysicsDebugOverlay001" + +abstract_class IVPhysicsDebugOverlay +{ +public: + virtual void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char* format, ...) = 0; + virtual void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, int r, int g, int b, int a, float duration) = 0; + virtual void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector& p3, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b,bool noDepthTest, float duration) = 0; + virtual void AddTextOverlay(const Vector& origin, float duration, PRINTF_FORMAT_STRING const char* format, ...) = 0; + virtual void AddTextOverlay(const Vector& origin, int line_offset, float duration, PRINTF_FORMAT_STRING const char* format, ...) = 0; + virtual void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char* text) = 0; + virtual void AddSweptBoxOverlay(const Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle& angles, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, PRINTF_FORMAT_STRING const char* format, ...) = 0; +}; + +#define VPHYSICS_INTERFACE_VERSION "VPhysics031" + +abstract_class IPhysics : public IAppSystem +{ +public: + virtual IPhysicsEnvironment * CreateEnvironment(void) = 0; + virtual void DestroyEnvironment(IPhysicsEnvironment*) = 0; + virtual IPhysicsEnvironment* GetActiveEnvironmentByIndex(int index) = 0; + + virtual IPhysicsObjectPairHash* CreateObjectPairHash() = 0; + virtual void DestroyObjectPairHash(IPhysicsObjectPairHash* pHash) = 0; + + virtual IPhysicsCollisionSet* FindOrCreateCollisionSet(unsigned int id, int maxElementCount) = 0; + virtual IPhysicsCollisionSet* FindCollisionSet(unsigned int id) = 0; + virtual void DestroyAllCollisionSets() = 0; +}; + + +class CPhysConvex; +class CPhysPolysoup; +class ICollisionQuery; +class IVPhysicsKeyParser; +struct convertconvexparams_t; +class CPackedPhysicsDescription; + +class CPolyhedron; + +struct truncatedcone_t +{ + Vector origin; + Vector normal; + float h; + float theta; +}; + + +#define VPHYSICS_COLLISION_INTERFACE_VERSION "VPhysicsCollision007" + +abstract_class IPhysicsCollision +{ +public: + virtual ~IPhysicsCollision(void) {} + + virtual CPhysConvex * ConvexFromVerts(Vector * *pVerts, int vertCount) = 0; + virtual CPhysConvex* ConvexFromPlanes(float* pPlanes, int planeCount, float mergeDistance) = 0; + virtual float ConvexVolume(CPhysConvex* pConvex) = 0; + + virtual float ConvexSurfaceArea(CPhysConvex* pConvex) = 0; + virtual void SetConvexGameData(CPhysConvex* pConvex, unsigned int gameData) = 0; + virtual void ConvexFree(CPhysConvex* pConvex) = 0; + virtual CPhysConvex* BBoxToConvex(const Vector& mins, const Vector& maxs) = 0; + virtual CPhysConvex* ConvexFromConvexPolyhedron(const CPolyhedron& ConvexPolyhedron) = 0; + virtual void ConvexesFromConvexPolygon(const Vector& vPolyNormal, const Vector* pPoints, int iPointCount, CPhysConvex** pOutput) = 0; + + virtual CPhysPolysoup* PolysoupCreate(void) = 0; + virtual void PolysoupDestroy(CPhysPolysoup* pSoup) = 0; + virtual void PolysoupAddTriangle(CPhysPolysoup* pSoup, const Vector& a, const Vector& b, const Vector& c, int materialIndex7bits) = 0; + virtual CPhysCollide* ConvertPolysoupToCollide(CPhysPolysoup* pSoup, bool useMOPP) = 0; + + virtual CPhysCollide* ConvertConvexToCollide(CPhysConvex** pConvex, int convexCount) = 0; + virtual CPhysCollide* ConvertConvexToCollideParams(CPhysConvex** pConvex, int convexCount, const convertconvexparams_t& convertParams) = 0; + virtual void DestroyCollide(CPhysCollide* pCollide) = 0; + + virtual int CollideSize(CPhysCollide* pCollide) = 0; + virtual int CollideWrite(char* pDest, CPhysCollide* pCollide, bool bSwap = false) = 0; + virtual CPhysCollide* UnserializeCollide(char* pBuffer, int size, int index) = 0; + + virtual float CollideVolume(CPhysCollide* pCollide) = 0; + virtual float CollideSurfaceArea(CPhysCollide* pCollide) = 0; + + virtual Vector CollideGetExtent(const CPhysCollide* pCollide, const Vector& collideOrigin, const QAngle& collideAngles, const Vector& direction) = 0; + + virtual void CollideGetAABB(Vector* pMins, Vector* pMaxs, const CPhysCollide* pCollide, const Vector& collideOrigin, const QAngle& collideAngles) = 0; + + virtual void CollideGetMassCenter(CPhysCollide* pCollide, Vector* pOutMassCenter) = 0; + virtual void CollideSetMassCenter(CPhysCollide* pCollide, const Vector& massCenter) = 0; + virtual Vector CollideGetOrthographicAreas(const CPhysCollide* pCollide) = 0; + virtual void CollideSetOrthographicAreas(CPhysCollide* pCollide, const Vector& areas) = 0; + + virtual int CollideIndex(const CPhysCollide* pCollide) = 0; + + virtual CPhysCollide* BBoxToCollide(const Vector& mins, const Vector& maxs) = 0; + virtual int GetConvexesUsedInCollideable(const CPhysCollide* pCollideable, CPhysConvex** pOutputArray, int iOutputArrayLimit) = 0; + + + virtual void TraceBox(const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, const CPhysCollide* pCollide, const Vector& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + virtual void TraceBox(const Ray_t& ray, const CPhysCollide* pCollide, const Vector& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + virtual void TraceBox(const Ray_t& ray, unsigned int contentsMask, IConvexInfo* pConvexInfo, const CPhysCollide* pCollide, const Vector& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + + virtual void TraceCollide(const Vector& start, const Vector& end, const CPhysCollide* pSweepCollide, const QAngle& sweepAngles, const CPhysCollide* pCollide, const Vector& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + + virtual bool IsBoxIntersectingCone(const Vector& boxAbsMins, const Vector& boxAbsMaxs, const truncatedcone_t& cone) = 0; + + virtual void VCollideLoad(vcollide_t* pOutput, int solidCount, const char* pBuffer, int size, bool swap = false) = 0; + virtual void VCollideUnload(vcollide_t* pVCollide) = 0; + + virtual IVPhysicsKeyParser* VPhysicsKeyParserCreate(const char* pKeyData) = 0; + virtual void VPhysicsKeyParserDestroy(IVPhysicsKeyParser* pParser) = 0; + + virtual int CreateDebugMesh(CPhysCollide const* pCollisionModel, Vector** outVerts) = 0; + virtual void DestroyDebugMesh(int vertCount, Vector* outVerts) = 0; + + virtual ICollisionQuery* CreateQueryModel(CPhysCollide* pCollide) = 0; + 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; + + + virtual CPolyhedron* PolyhedronFromConvex(CPhysConvex* const pConvex, bool bUseTempPolyhedron) = 0; + + virtual void OutputDebugInfo(const CPhysCollide* pCollide) = 0; + virtual unsigned int ReadStat(int statID) = 0; +}; + +abstract_class ICollisionQuery +{ +public: + virtual ~ICollisionQuery() {} + virtual int ConvexCount(void) = 0; + virtual int TriangleCount(int convexIndex) = 0; + virtual unsigned int GetGameData(int convexIndex) = 0; + virtual void GetTriangleVerts(int convexIndex, int triangleIndex, Vector* verts) = 0; + + virtual void SetTriangleVerts(int convexIndex, int triangleIndex, const Vector* verts) = 0; + + virtual int GetTriangleMaterialIndex(int convexIndex, int triangleIndex) = 0; + virtual void SetTriangleMaterialIndex(int convexIndex, int triangleIndex, int index7bits) = 0; +}; + +abstract_class IPhysicsGameTrace +{ +public: + virtual void VehicleTraceRay(const Ray_t & ray, void* pVehicle, trace_t * pTrace) = 0; + virtual void VehicleTraceRayWithWater(const Ray_t& ray, void* pVehicle, trace_t* pTrace) = 0; + virtual bool VehiclePointInWater(const Vector& vecPoint) = 0; +}; + +abstract_class IConvexInfo +{ +public: + virtual unsigned int GetContents(int convexGameData) = 0; +}; + +class CPhysicsEventHandler; +abstract_class IPhysicsCollisionData +{ +public: + virtual void GetSurfaceNormal(Vector & out) = 0; + virtual void GetContactPoint(Vector& out) = 0; + virtual void GetContactSpeed(Vector& out) = 0; +}; + + +struct vcollisionevent_t +{ + IPhysicsObject* pObjects[2]; + int surfaceProps[2]; + bool isCollision; + bool isShadowCollision; + float deltaCollisionTime; + + float collisionSpeed; + IPhysicsCollisionData* pInternalData; +}; + +abstract_class IPhysicsCollisionEvent +{ +public: + virtual void PreCollision(vcollisionevent_t * pEvent) = 0; + virtual void PostCollision(vcollisionevent_t* pEvent) = 0; + + virtual void Friction(IPhysicsObject* pObject, float energy, int surfaceProps, int surfacePropsHit, IPhysicsCollisionData* pData) = 0; + + virtual void StartTouch(IPhysicsObject* pObject1, IPhysicsObject* pObject2, IPhysicsCollisionData* pTouchData) = 0; + virtual void EndTouch(IPhysicsObject* pObject1, IPhysicsObject* pObject2, IPhysicsCollisionData* pTouchData) = 0; + + virtual void FluidStartTouch(IPhysicsObject* pObject, IPhysicsFluidController* pFluid) = 0; + virtual void FluidEndTouch(IPhysicsObject* pObject, IPhysicsFluidController* pFluid) = 0; + + virtual void PostSimulationFrame() = 0; + + virtual void ObjectEnterTrigger(IPhysicsObject* pTrigger, IPhysicsObject* pObject) {} + virtual void ObjectLeaveTrigger(IPhysicsObject* pTrigger, IPhysicsObject* pObject) {} +}; + + +abstract_class IPhysicsObjectEvent +{ +public: + virtual void ObjectWake(IPhysicsObject * pObject) = 0; + virtual void ObjectSleep(IPhysicsObject* pObject) = 0; +}; + +abstract_class IPhysicsConstraintEvent +{ +public: + virtual void ConstraintBroken(IPhysicsConstraint*) = 0; +}; + +struct hlshadowcontrol_params_t +{ + Vector targetPosition; + QAngle targetRotation; + float maxAngular; + float maxDampAngular; + float maxSpeed; + float maxDampSpeed; + float dampFactor; + float teleportDistance; +}; + +abstract_class IPhysicsShadowController +{ +public: + virtual ~IPhysicsShadowController(void) {} + + virtual void Update(const Vector & position, const QAngle & angles, float timeOffset) = 0; + virtual void MaxSpeed(float maxSpeed, float maxAngularSpeed) = 0; + virtual void StepUp(float height) = 0; + + virtual void SetTeleportDistance(float teleportDistance) = 0; + virtual bool AllowsTranslation() = 0; + virtual bool AllowsRotation() = 0; + + virtual void SetPhysicallyControlled(bool isPhysicallyControlled) = 0; + virtual bool IsPhysicallyControlled() = 0; + virtual void GetLastImpulse(Vector* pOut) = 0; + virtual void UseShadowMaterial(bool bUseShadowMaterial) = 0; + virtual void ObjectMaterialChanged(int materialIndex) = 0; + + + virtual float GetTargetPosition(Vector* pPositionOut, QAngle* pAnglesOut) = 0; + + virtual float GetTeleportDistance(void) = 0; + virtual void GetMaxSpeed(float* pMaxSpeedOut, float* pMaxAngularSpeedOut) = 0; +}; + +class CPhysicsSimObject; +class IPhysicsMotionController; + +class IMotionEvent +{ +public: + enum simresult_e { SIM_NOTHING = 0, SIM_LOCAL_ACCELERATION, SIM_LOCAL_FORCE, SIM_GLOBAL_ACCELERATION, SIM_GLOBAL_FORCE }; + virtual simresult_e Simulate(IPhysicsMotionController* pController, IPhysicsObject* pObject, float deltaTime, Vector& linear, AngularImpulse& angular) = 0; +}; + + + +abstract_class IPhysicsMotionController +{ +public: + virtual ~IPhysicsMotionController(void) {} + virtual void SetEventHandler(IMotionEvent * handler) = 0; + virtual void AttachObject(IPhysicsObject* pObject, bool checkIfAlreadyAttached) = 0; + virtual void DetachObject(IPhysicsObject* pObject) = 0; + + virtual int CountObjects(void) = 0; + virtual void GetObjects(IPhysicsObject** pObjectList) = 0; + virtual void ClearObjects(void) = 0; + virtual void WakeObjects(void) = 0; + + enum priority_t + { + LOW_PRIORITY = 0, + MEDIUM_PRIORITY = 1, + HIGH_PRIORITY = 2, + }; + virtual void SetPriority(priority_t priority) = 0; +}; + +abstract_class IPhysicsCollisionSolver +{ +public: + virtual int ShouldCollide(IPhysicsObject * pObj0, IPhysicsObject * pObj1, void* pGameData0, void* pGameData1) = 0; + virtual int ShouldSolvePenetration(IPhysicsObject* pObj0, IPhysicsObject* pObj1, void* pGameData0, void* pGameData1, float dt) = 0; + + virtual bool ShouldFreezeObject(IPhysicsObject* pObject) = 0; + + virtual int AdditionalCollisionChecksThisTick(int currentChecksDone) = 0; + + virtual bool ShouldFreezeContacts(IPhysicsObject** pObjectList, int objectCount) = 0; +}; + +enum PhysicsTraceType_t +{ + VPHYSICS_TRACE_EVERYTHING = 0, + VPHYSICS_TRACE_STATIC_ONLY, + VPHYSICS_TRACE_MOVING_ONLY, + VPHYSICS_TRACE_TRIGGERS_ONLY, + VPHYSICS_TRACE_STATIC_AND_MOVING, +}; + +abstract_class IPhysicsTraceFilter +{ +public: + virtual bool ShouldHitObject(IPhysicsObject * pObject, int contentsMask) = 0; + virtual PhysicsTraceType_t GetTraceType() const = 0; +}; + +abstract_class IPhysicsEnvironment +{ +public: + virtual ~IPhysicsEnvironment(void) {} + + virtual void SetDebugOverlay(CreateInterfaceFn debugOverlayFactory) = 0; + virtual IVPhysicsDebugOverlay* GetDebugOverlay(void) = 0; + + virtual void SetGravity(const Vector& gravityVector) = 0; + virtual void GetGravity(Vector* pGravityVector) const = 0; + + virtual void SetAirDensity(float density) = 0; + virtual float GetAirDensity(void) const = 0; + + virtual IPhysicsObject* CreatePolyObject(const CPhysCollide* pCollisionModel, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t* pParams) = 0; + virtual IPhysicsObject* CreatePolyObjectStatic(const CPhysCollide* pCollisionModel, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t* pParams) = 0; + virtual IPhysicsObject* CreateSphereObject(float radius, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t* pParams, bool isStatic) = 0; + virtual void DestroyObject(IPhysicsObject*) = 0; + + virtual IPhysicsFluidController* CreateFluidController(IPhysicsObject* pFluidObject, fluidparams_t* pParams) = 0; + virtual void DestroyFluidController(IPhysicsFluidController*) = 0; + + virtual IPhysicsSpring* CreateSpring(IPhysicsObject* pObjectStart, IPhysicsObject* pObjectEnd, springparams_t* pParams) = 0; + virtual void DestroySpring(IPhysicsSpring*) = 0; + + 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; + + virtual void SetCollisionSolver(IPhysicsCollisionSolver* pSolver) = 0; + + virtual void Simulate(float deltaTime) = 0; + virtual bool IsInSimulation() const = 0; + + virtual float GetSimulationTimestep() const = 0; + virtual void SetSimulationTimestep(float timestep) = 0; + + virtual float GetSimulationTime() const = 0; + virtual void ResetSimulationClock() = 0; + virtual float GetNextFrameTime(void) const = 0; + + 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; + + 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; + + virtual bool IsCollisionModelUsed(CPhysCollide* pCollide) const = 0; + + virtual void TraceRay(const Ray_t& ray, unsigned int fMask, IPhysicsTraceFilter* pTraceFilter, trace_t* pTrace) = 0; + virtual void SweepCollideable(const CPhysCollide* pCollide, const Vector& vecAbsStart, const Vector& vecAbsEnd, + const QAngle& vecAngles, unsigned int fMask, IPhysicsTraceFilter* pTraceFilter, trace_t* pTrace) = 0; + + virtual void GetPerformanceSettings(physics_performanceparams_t* pOutput) const = 0; + virtual void SetPerformanceSettings(const physics_performanceparams_t* pSettings) = 0; + + virtual void ReadStats(physics_stats_t* pOutput) = 0; + virtual void ClearStats() = 0; + + virtual unsigned int GetObjectSerializeSize(IPhysicsObject* pObject) const = 0; + virtual void SerializeObjectToBuffer(IPhysicsObject* pObject, unsigned char* pBuffer, unsigned int bufferSize) = 0; + virtual IPhysicsObject* UnserializeObjectFromBuffer(void* pGameData, unsigned char* pBuffer, unsigned int bufferSize, bool enableCollisions) = 0; + + + virtual void EnableConstraintNotify(bool bEnable) = 0; + virtual void DebugCheckContacts(void) = 0; +}; + +enum callbackflags +{ + CALLBACK_GLOBAL_COLLISION = 0x0001, + CALLBACK_GLOBAL_FRICTION = 0x0002, + CALLBACK_GLOBAL_TOUCH = 0x0004, + CALLBACK_GLOBAL_TOUCH_STATIC = 0x0008, + CALLBACK_SHADOW_COLLISION = 0x0010, + CALLBACK_GLOBAL_COLLIDE_STATIC = 0x0020, + CALLBACK_IS_VEHICLE_WHEEL = 0x0040, + CALLBACK_FLUID_TOUCH = 0x0100, + CALLBACK_NEVER_DELETED = 0x0200, + CALLBACK_MARKED_FOR_DELETE = 0x0400, + CALLBACK_ENABLING_COLLISION = 0x0800, + CALLBACK_DO_FLUID_SIMULATION = 0x1000, + CALLBACK_IS_PLAYER_CONTROLLER = 0x2000, + CALLBACK_CHECK_COLLISION_DISABLE = 0x4000, + CALLBACK_MARKED_FOR_TEST = 0x8000, +}; + +abstract_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 Vector GetInertia(void) const = 0; + virtual Vector GetInvInertia(void) const = 0; + virtual void SetInertia(const Vector& inertia) = 0; + + virtual void SetDamping(const float* speed, const float* rot) = 0; + virtual void GetDamping(float* speed, float* rot) const = 0; + + 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 Vector GetMassCenterLocalSpace() const = 0; + + virtual void SetPosition(const Vector& worldPosition, const QAngle& angles, bool isTeleport) = 0; + virtual void SetPositionMatrix(const matrix3x4_t& matrix, bool isTeleport) = 0; + + virtual void GetPosition(Vector* worldPosition, QAngle* angles) const = 0; + virtual void GetPositionMatrix(matrix3x4_t* positionMatrix) const = 0; + virtual void SetVelocity(const Vector* velocity, const AngularImpulse* angularVelocity) = 0; + + virtual void SetVelocityInstantaneous(const Vector* velocity, const AngularImpulse* angularVelocity) = 0; + + virtual void GetVelocity(Vector* velocity, AngularImpulse* angularVelocity) const = 0; + + virtual void AddVelocity(const Vector* velocity, const AngularImpulse* angularVelocity) = 0; + virtual void GetVelocityAtPoint(const Vector& worldPosition, Vector* pVelocity) const = 0; + virtual void GetImplicitVelocity(Vector* velocity, AngularImpulse* angularVelocity) const = 0; + virtual void LocalToWorld(Vector* worldPosition, const Vector& localPosition) const = 0; + virtual void WorldToLocal(Vector* localPosition, const Vector& worldPosition) const = 0; + + virtual void LocalToWorldVector(Vector* worldVector, const Vector& localVector) const = 0; + virtual void WorldToLocalVector(Vector* localVector, const Vector& worldVector) const = 0; + + virtual void ApplyForceCenter(const Vector& forceVector) = 0; + virtual void ApplyForceOffset(const Vector& forceVector, const Vector& worldPosition) = 0; + virtual void ApplyTorqueCenter(const AngularImpulse& torque) = 0; + + virtual void CalculateForceOffset(const Vector& forceVector, const Vector& worldPosition, Vector* centerForce, AngularImpulse* centerTorque) const = 0; + virtual void CalculateVelocityOffset(const Vector& forceVector, const Vector& worldPosition, Vector* centerVelocity, AngularImpulse* centerAngularVelocity) const = 0; + virtual float CalculateLinearDrag(const Vector& unitDirection) const = 0; + virtual float CalculateAngularDrag(const Vector& objectSpaceRotationAxis) const = 0; + + virtual bool GetContactPoint(Vector* contactPoint, IPhysicsObject** contactObject) const = 0; + + virtual void SetShadow(float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation) = 0; + virtual void UpdateShadow(const Vector& targetPosition, const QAngle& targetAngles, bool tempDisableGravity, float timeOffset) = 0; + + virtual int GetShadowPosition(Vector* position, QAngle* angles) const = 0; + virtual IPhysicsShadowController* GetShadowController(void) const = 0; + virtual void RemoveShadowController() = 0; + virtual float ComputeShadowControl(const hlshadowcontrol_params_t& 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* CreateFrictionSnapshot() = 0; + virtual void DestroyFrictionSnapshot(IPhysicsFrictionSnapshot* pSnapshot) = 0; + + virtual void OutputDebugInfo() const = 0; + +}; + + +abstract_class IPhysicsSpring +{ +public: + virtual ~IPhysicsSpring(void) {} + virtual void GetEndpoints(Vector * worldPositionStart, Vector * worldPositionEnd) = 0; + virtual void SetSpringConstant(float flSpringContant) = 0; + virtual void SetSpringDamping(float flSpringDamping) = 0; + virtual void SetSpringLength(float flSpringLenght) = 0; + + virtual IPhysicsObject* GetStartObject(void) = 0; + + virtual IPhysicsObject* GetEndObject(void) = 0; +}; + + +struct surfacephysicsparams_t +{ + float friction; + float elasticity; + float density; + float thickness; + float dampening; +}; + +struct surfaceaudioparams_t +{ + float reflectivity; + float hardnessFactor; + float roughnessFactor; + + float roughThreshold; + float hardThreshold; + float hardVelocityThreshold; +}; + +struct surfacesoundnames_t +{ + unsigned short stepleft; + unsigned short stepright; + + unsigned short impactSoft; + unsigned short impactHard; + + unsigned short scrapeSmooth; + unsigned short scrapeRough; + + unsigned short bulletImpact; + unsigned short rolling; + + unsigned short breakSound; + unsigned short strainSound; +}; + +struct surfacesoundhandles_t +{ + short stepleft; + short stepright; + + short impactSoft; + short impactHard; + + short scrapeSmooth; + short scrapeRough; + + short bulletImpact; + short rolling; + + short breakSound; + short strainSound; +}; + +struct surfacegameprops_t +{ + float flMaxSpeedFactor; + float flJumpFactor; + float flPenetrationModifier; + float flDamageModifier; + MaterialHandle_t hMaterial; + std::byte dClimbable; + std::byte pad0[0x4]; +}; // Size: 0x17 + +/* +struct surfacegameprops_t +{ + float maxSpeedFactor; + float jumpFactor; + unsigned short material; + unsigned char climbable; + unsigned char pad; +}; +*/ + +struct surfacedata_t +{ + surfacephysicsparams_t physics; + surfaceaudioparams_t audio; + surfacesoundnames_t sounds; + surfacegameprops_t game; + + surfacesoundhandles_t soundhandles; +}; + +#define VPHYSICS_SURFACEPROPS_INTERFACE_VERSION "VPhysicsSurfaceProps001" +abstract_class IPhysicsSurfaceProps +{ +public: + virtual ~IPhysicsSurfaceProps(void) {} + + virtual int ParseSurfaceData(const char* pFilename, const char* pTextfile) = 0; + virtual int SurfacePropCount(void) const = 0; + + virtual int GetSurfaceIndex(const char* pSurfacePropName) const = 0; + virtual void GetPhysicsProperties(int surfaceDataIndex, float* density, float* thickness, float* friction, float* elasticity) const = 0; + + virtual surfacedata_t* GetSurfaceData(int surfaceDataIndex) = 0; + virtual const char* GetString(unsigned short stringTableIndex) const = 0; + + + virtual const char* GetPropName(int surfaceDataIndex) const = 0; + + virtual void SetWorldMaterialIndexTable(int* pMapArray, int mapSize) = 0; + + virtual void GetPhysicsParameters(int surfaceDataIndex, surfacephysicsparams_t* pParamsOut) const = 0; +}; + +abstract_class IPhysicsFluidController +{ +public: + virtual ~IPhysicsFluidController(void) {} + + virtual void SetGameData(void* pGameData) = 0; + virtual void* GetGameData(void) const = 0; + + virtual void GetSurfacePlane(Vector* pNormal, float* pDist) const = 0; + virtual float GetDensity() const = 0; + virtual void WakeAllSleepingObjects() = 0; + virtual int GetContents() const = 0; +}; + + +struct fluidparams_t +{ + Vector4D surfacePlane; + Vector currentVelocity; + float damping; + float torqueFactor; + float viscosityFactor; + void* pGameData; + bool useAerodynamics; + int contents; + + fluidparams_t() {} + fluidparams_t(fluidparams_t const& src) + { + Vector4DCopy(src.surfacePlane, surfacePlane); + VectorCopy(src.currentVelocity, currentVelocity); + damping = src.damping; + torqueFactor = src.torqueFactor; + viscosityFactor = src.viscosityFactor; + contents = src.contents; + } +}; + +struct springparams_t +{ + springparams_t() + { + memset(this, 0, sizeof(*this)); + } + float constant; + float naturalLength; + float damping; + float relativeDamping; + Vector startPosition; + Vector endPosition; + bool useLocalPositions; + bool onlyStretch; +}; + +struct objectparams_t +{ + Vector* massCenterOverride; + float mass; + float inertia; + float damping; + float rotdamping; + float rotInertiaLimit; + const char* pName; + void* pGameData; + float volume; + float dragCoefficient; + bool enableCollisions; +}; + +struct convertconvexparams_t +{ + bool buildOuterConvexHull; + bool buildDragAxisAreas; + bool buildOptimizedTraceTables; + float dragAreaEpsilon; + CPhysConvex* pForcedOuterHull; + + void Defaults() + { + dragAreaEpsilon = 0.25f; + buildOuterConvexHull = false; + buildDragAxisAreas = false; + buildOptimizedTraceTables = false; + pForcedOuterHull = NULL; + } +}; + + +struct physsaveparams_t +{ + ISave* pSave; + void* pObject; + PhysInterfaceId_t type; +}; + +struct physrestoreparams_t +{ + IRestore* pRestore; + void** ppObject; + PhysInterfaceId_t type; + void* pGameData; + const char* pName; + const CPhysCollide* pCollisionModel; + IPhysicsEnvironment* pEnvironment; + IPhysicsGameTrace* pGameTrace; +}; + +struct physrecreateparams_t +{ + void* pOldObject; + void* pNewObject; +}; + +struct physprerestoreparams_t +{ + int recreatedObjectCount; + physrecreateparams_t recreatedObjectList[1]; +}; + +#define DEFINE_PIID( type, enumval ) \ + template <> inline PhysInterfaceId_t GetPhysIID( type ** ) { return enumval; } + +template inline PhysInterfaceId_t GetPhysIID(PHYSPTR**); + +DEFINE_PIID(IPhysicsObject, PIID_IPHYSICSOBJECT); +DEFINE_PIID(IPhysicsFluidController, PIID_IPHYSICSFLUIDCONTROLLER); +DEFINE_PIID(IPhysicsSpring, PIID_IPHYSICSSPRING); +DEFINE_PIID(IPhysicsConstraintGroup, PIID_IPHYSICSCONSTRAINTGROUP); +DEFINE_PIID(IPhysicsConstraint, PIID_IPHYSICSCONSTRAINT); +DEFINE_PIID(IPhysicsShadowController, PIID_IPHYSICSSHADOWCONTROLLER); +DEFINE_PIID(IPhysicsPlayerController, PIID_IPHYSICSPLAYERCONTROLLER); +DEFINE_PIID(IPhysicsMotionController, PIID_IPHYSICSMOTIONCONTROLLER); +DEFINE_PIID(IPhysicsVehicleController, PIID_IPHYSICSVEHICLECONTROLLER); +DEFINE_PIID(IPhysicsGameTrace, PIID_IPHYSICSGAMETRACE); + +#endif +``` + +`SpyCustom/sdk/vpkparser.h`: + +```h +#pragma once + +#include +#include +#include +#include + +#pragma pack(push,1) +struct vpk_header_t +{ + uint32_t signature; + uint32_t version; + uint32_t tree_size; + uint32_t file_data_section_size; + uint32_t archive_md5_section_size; + uint32_t other_md5_section_size; + uint32_t signature_section_size; +}; + +struct dir_entry_t +{ + uint32_t crc; + uint16_t preload_bytes; + uint16_t archive_index; + uint32_t entry_offset; + uint32_t entry_length; + uint16_t terminator; +}; +#pragma pack(pop) + +class c_vpk_entry +{ +public: + c_vpk_entry() = default; + c_vpk_entry(const std::string& base_file, const std::string& path, const dir_entry_t& entry) :_base_file(base_file), _path(path), _entry(entry) {} + + std::optional> get_data() + { + size_t _dir_pos = _base_file.find("dir"); + + std::string old_number_string = std::to_string(_entry.archive_index); + std::string vpk_file = _base_file.replace(_base_file.begin() + _dir_pos, _base_file.begin() + _dir_pos + 3, std::string(3 - old_number_string.length(), '0') + old_number_string); + std::ifstream stream(vpk_file, std::ios::binary); + if (!stream.is_open()) + return {}; + + uint8_t* data = new uint8_t[_entry.entry_length]; + stream.seekg(_entry.entry_offset, stream.beg); + stream.read((char*)data, _entry.entry_length); + stream.close(); + + std::vector data_vector(data, data + _entry.entry_length); + delete[] data; + + return data_vector; + } + + std::vector preload_bytes = {}; + std::string _base_file = {}; + std::string _path = {}; + dir_entry_t _entry = {}; +}; + +class c_vpk_archive +{ +public: + bool load(const std::string& name) + { + std::ifstream stream(name, std::ios::binary); + if (!stream.is_open()) + return false; + + try + { + vpk_header_t file_header = {}; + stream.read((char*)&file_header, sizeof(file_header)); + if (file_header.signature != 0x55aa1234) + { + stream.close(); + return false; + } + + if (file_header.version != 2) + { + stream.close(); + return false; + } + + while (true) + { + std::string extension; + + std::getline(stream, extension, '\x00'); + if (extension.empty()) + break; + + while (true) + { + std::string directory; + std::getline(stream, directory, '\x00'); + if (directory.empty()) + break; + + while (true) + { + std::string file_name; + std::getline(stream, file_name, '\x00'); + if (file_name.empty()) + break; + + std::string path = directory + '/' + file_name + '.' + extension; + + dir_entry_t dir_entry; + stream.read((char*)&dir_entry, sizeof(dir_entry)); + + c_vpk_entry vpk_entry(name, path, dir_entry); + if (dir_entry.preload_bytes) + { + uint8_t* bytes = new uint8_t[dir_entry.preload_bytes]; + stream.read((char*)bytes, dir_entry.preload_bytes); + vpk_entry.preload_bytes = std::vector(bytes, bytes + dir_entry.preload_bytes); + delete[] bytes; + } + + if (!files.count(path)) + files[path] = vpk_entry; + } + } + } + } + catch (const std::exception& e) { return false; } + stream.close(); + + return true; + } + + std::optional get_file(const std::string& name) + { + if (files.count(name)) + return files[name]; + + return {}; + } + std::unordered_map files = {}; +}; +``` + +`SpyCustom/sdk/vplane.h`: + +```h +#ifndef VPLANE_H +#define VPLANE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "vector.h" + +typedef int SideType; + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + +#define VP_EPSILON 0.01f + + +class VPlane +{ +public: + VPlane(); + VPlane(const Vector& vNormal, vec_t dist); + + void Init(const Vector& vNormal, vec_t dist); + + vec_t DistTo(const Vector& vVec) const; + + VPlane& operator=(const VPlane& thePlane); + + SideType GetPointSide(const Vector& vPoint, vec_t sideEpsilon = VP_EPSILON) const; + + SideType GetPointSideExact(const Vector& vPoint) const; + + SideType BoxOnPlaneSide(const Vector& vMin, const Vector& vMax) const; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + VPlane Flip(); + + Vector GetPointOnPlane() const; + + Vector SnapPointToPlane(const Vector& vPoint) const; +#endif + +public: + Vector m_Normal; + vec_t m_Dist; + +#ifdef VECTOR_NO_SLOW_OPERATIONS +private: + VPlane(const VPlane& vOther); +#endif +}; + + +inline VPlane::VPlane() +{ +} + +inline VPlane::VPlane(const Vector& vNormal, vec_t dist) +{ + m_Normal = vNormal; + m_Dist = dist; +} + +inline void VPlane::Init(const Vector& vNormal, vec_t dist) +{ + m_Normal = vNormal; + m_Dist = dist; +} + +inline vec_t VPlane::DistTo(const Vector& vVec) const +{ + return vVec.Dot(m_Normal) - m_Dist; +} + +inline VPlane& VPlane::operator=(const VPlane& thePlane) +{ + m_Normal = thePlane.m_Normal; + m_Dist = thePlane.m_Dist; + return *this; +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline VPlane VPlane::Flip() +{ + return VPlane(-m_Normal, -m_Dist); +} + +inline Vector VPlane::GetPointOnPlane() const +{ + return m_Normal * m_Dist; +} + +inline Vector VPlane::SnapPointToPlane(const Vector& vPoint) const +{ + return vPoint - m_Normal * DistTo(vPoint); +} + +#endif + +inline SideType VPlane::GetPointSide(const Vector& vPoint, vec_t sideEpsilon) const +{ + vec_t fDist; + + fDist = DistTo(vPoint); + if (fDist >= sideEpsilon) + return SIDE_FRONT; + else if (fDist <= -sideEpsilon) + return SIDE_BACK; + else + return SIDE_ON; +} + +inline SideType VPlane::GetPointSideExact(const Vector& vPoint) const +{ + return DistTo(vPoint) > 0.0f ? SIDE_FRONT : SIDE_BACK; +} + + +inline SideType VPlane::BoxOnPlaneSide(const Vector& vMin, const Vector& vMax) const +{ + int i, firstSide, side; + TableVector vPoints[8] = + { + { vMin.x, vMin.y, vMin.z }, + { vMin.x, vMin.y, vMax.z }, + { vMin.x, vMax.y, vMax.z }, + { vMin.x, vMax.y, vMin.z }, + + { vMax.x, vMin.y, vMin.z }, + { vMax.x, vMin.y, vMax.z }, + { vMax.x, vMax.y, vMax.z }, + { vMax.x, vMax.y, vMin.z }, + }; + + firstSide = GetPointSideExact(vPoints[0]); + for (i = 1; i < 8; i++) + { + side = GetPointSideExact(vPoints[i]); + + if (side != firstSide) + return SIDE_ON; + } + + return firstSide; +} + + + + +#endif +``` + +`SpyCustom/sdk/vprof.h`: + +```h +#ifndef VPROF_H +#define VPROF_H + +#if !defined(__SPU__) + +#include "dbg.h" +#include "fasttimer.h" +#include "l2cache.h" +#include "threadtools.h" +#include "vprof_sn.h" +#include "vprof_telemetry.h" + +#if !( defined( _GAMECONSOLE ) && defined( _CERT ) ) && !defined( _PS3 ) +#define VPROF_ENABLED +#endif + +#if defined(_X360) && defined(VPROF_ENABLED) + +#ifdef PROFILE +#define VPROF_PIX 1 +#endif + +#include "tier0/pmc360.h" +#ifndef USE_PIX +#define VPROF_UNDO_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#define USE_PIX +#include +#undef USE_PIX +#else +#include +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +#if defined( _X360 ) && defined( PROFILE ) +#define VPROF_PIX 1 +#endif + +#if defined(_X360) || defined(_PS3) +#define VPROF_VXCONSOLE_EXISTS 1 +#endif + + +#if defined(_X360) && defined(VPROF_PIX) +#pragma comment( lib, "Xapilibi" ) +#endif + +#define MAXCOUNTERS 256 + + +#ifdef VPROF_ENABLED + +#define VPROF_VTUNE_GROUP + +#define VPROF( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0) +#define VPROF_ASSERT_ACCOUNTED( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, true, 0) +#define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail(name,group, bAssertAccounted, budgetFlags) + +#define VPROF_BUDGET( name, group ) VPROF_BUDGET_FLAGS(name, group, BUDGETFLAG_OTHER) +#define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF_(name, 0, group, false, flags) + +#define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +#define VPROF_SCOPE_END() } while (0) + +#define VPROF_ONLY( expression ) ( expression ) + +#define VPROF_ENTER_SCOPE( name ) g_VProfCurrentProfile.EnterScope( name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0 ) +#define VPROF_EXIT_SCOPE() g_VProfCurrentProfile.ExitScope() + +#define VPROF_BUDGET_GROUP_ID_UNACCOUNTED 0 + + +#define BUDGETFLAG_CLIENT (1<<0) +#define BUDGETFLAG_SERVER (1<<1) +#define BUDGETFLAG_OTHER (1<<2) +#define BUDGETFLAG_HIDDEN (1<<15) +#define BUDGETFLAG_ALL 0xFFFF + + +#define VPROF_BUDGETGROUP_OTHER_UNACCOUNTED _T("Unaccounted") +#define VPROF_BUDGETGROUP_WORLD_RENDERING _T("World Rendering") +#define VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING _T("Displacement_Rendering") +#define VPROF_BUDGETGROUP_GAME _T("Game") +#define VPROF_BUDGETGROUP_NPCS _T("NPCs") +#define VPROF_BUDGETGROUP_SERVER_ANIM _T("Server Animation") +#define VPROF_BUDGETGROUP_PHYSICS _T("Physics") +#define VPROF_BUDGETGROUP_STATICPROP_RENDERING _T("Static_Prop_Rendering") +#define VPROF_BUDGETGROUP_MODEL_RENDERING _T("Other_Model_Rendering") +#define VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING _T("Fast Path Model Rendering") +#define VPROF_BUDGETGROUP_BRUSH_FAST_PATH_RENDERING _T("Fast Path Brush Rendering") +#define VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING _T("Brush_Model_Rendering") +#define VPROF_BUDGETGROUP_SHADOW_RENDERING _T("Shadow_Rendering") +#define VPROF_BUDGETGROUP_DETAILPROP_RENDERING _T("Detail_Prop_Rendering") +#define VPROF_BUDGETGROUP_PARTICLE_RENDERING _T("Particle/Effect_Rendering") +#define VPROF_BUDGETGROUP_ROPES _T("Ropes") +#define VPROF_BUDGETGROUP_DLIGHT_RENDERING _T("Dynamic_Light_Rendering") +#define VPROF_BUDGETGROUP_OTHER_NETWORKING _T("Networking") +#define VPROF_BUDGETGROUP_CLIENT_ANIMATION _T("Client_Animation") +#define VPROF_BUDGETGROUP_OTHER_SOUND _T("Sound") +#define VPROF_BUDGETGROUP_OTHER_VGUI _T("VGUI") +#define VPROF_BUDGETGROUP_OTHER_FILESYSTEM _T("FileSystem") +#define VPROF_BUDGETGROUP_PREDICTION _T("Prediction") +#define VPROF_BUDGETGROUP_INTERPOLATION _T("Interpolation") +#define VPROF_BUDGETGROUP_SWAP_BUFFERS _T("Swap_Buffers") +#define VPROF_BUDGETGROUP_PLAYER _T("Player") +#define VPROF_BUDGETGROUP_OCCLUSION _T("Occlusion") +#define VPROF_BUDGETGROUP_OVERLAYS _T("Overlays") +#define VPROF_BUDGETGROUP_TOOLS _T("Tools") +#define VPROF_BUDGETGROUP_LIGHTCACHE _T("Light_Cache") +#define VPROF_BUDGETGROUP_DISP_HULLTRACES _T("Displacement_Hull_Traces") +#define VPROF_BUDGETGROUP_TEXTURE_CACHE _T("Texture_Cache") +#define VPROF_BUDGETGROUP_REPLAY _T("Replay") +#define VPROF_BUDGETGROUP_PARTICLE_SIMULATION _T("Particle Simulation") +#define VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING _T("Flashlight Shadows") +#define VPROF_BUDGETGROUP_CLIENT_SIM _T("Client Simulation") +#define VPROF_BUDGETGROUP_STEAM _T("Steam") +#define VPROF_BUDGETGROUP_CVAR_FIND _T("Cvar_Find") +#define VPROF_BUDGETGROUP_CLIENTLEAFSYSTEM _T("ClientLeafSystem") +#define VPROF_BUDGETGROUP_JOBS_COROUTINES _T("Jobs/Coroutines") +#define VPROF_BUDGETGROUP_SLEEPING _T("Sleeping") +#define VPROF_BUDGETGROUP_THREADINGMAIN _T("ThreadingMain") +#define VPROF_BUDGETGROUP_ENCRYPTION _T("Encryption") + + +#define VPROF_BUDGETGROUP_CHROMEHTML _T("Chromehtml") +#define VPROF_BUDGETGROUP_VGUI VPROF_BUDGETGROUP_CHROMEHTML +#define VPROF_BUDGETGROUP_TENFOOT VPROF_BUDGETGROUP_CHROMEHTML +#define VPROF_BUDGETGROUP_STEAMUI VPROF_BUDGETGROUP_CHROMEHTML + +#ifdef VPROF_VXCONSOLE_EXISTS +#define VPROF_UPDATE_BUDGET 0x01 +#define VPROF_UPDATE_TEXTURE_GLOBAL 0x02 +#define VPROF_UPDATE_TEXTURE_PERFRAME 0x04 +#endif + +#ifndef VPROF_LEVEL +#endif + +#if !defined( VPROF_SN_LEVEL ) && !defined( _CERT ) +#endif + +#define VPROF_SCOPE_VARIABLE_NAME( prefix, line ) prefix##line +#define VPROF_SCOPE_VARIABLE_DECL( name, level, group, assertAccounted, budgetFlags, line ) CVProfScope VPROF_SCOPE_VARIABLE_NAME( VProf_,line )(name, level, group, assertAccounted, budgetFlags) + +#define VPROF_0(name,group,assertAccounted,budgetFlags) TM_ZONE( TELEMETRY_LEVEL2, TMZF_NONE, "(%s)%s", group, name ); VPROF_SCOPE_VARIABLE_DECL(name, 0, group, assertAccounted, budgetFlags, __LINE__ ); + +#if VPROF_LEVEL > 0 +# define VPROF_1(name,group,assertAccounted,budgetFlags) TM_ZONE( TELEMETRY_LEVEL3, TMZF_NONE, "(%s)%s", group, name ); VPROF_SCOPE_VARIABLE_DECL(name, 1, group, assertAccounted, budgetFlags, __LINE__ ); +#else +# if VPROF_SN_LEVEL > 0 && defined( _PS3 ) +# define VPROF_1(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 1 +#define VPROF_2(name,group,assertAccounted,budgetFlags) TM_ZONE( TELEMETRY_LEVEL4, TMZF_NONE, "(%s)%s", group, name ); VPROF_SCOPE_VARIABLE_DECL(name, 2, group, assertAccounted, budgetFlags, __LINE__); +#else +# if VPROF_SN_LEVEL > 1 && defined( _PS3 ) +# define VPROF_2(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 2 +#define VPROF_3(name,group,assertAccounted,budgetFlags) TM_ZONE( TELEMETRY_LEVEL5, TMZF_NONE, "(%s)%s", group, name ); VPROF_SCOPE_VARIABLE_DECL(name, 3, group, assertAccounted, budgetFlags, __LINE__); +#else +# if VPROF_SN_LEVEL > 2 && defined( _PS3 ) +# define VPROF_3(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 3 +#define VPROF_4(name,group,assertAccounted,budgetFlags) TM_ZONE( TELEMETRY_LEVEL6, TMZF_NONE, "(%s)%s", group, name ); VPROF_SCOPE_VARIABLE_DECL(name, 4, group, assertAccounted, budgetFlags, __LINE__); +#else +# if VPROF_SN_LEVEL > 3 && defined( _PS3 ) +# define VPROF_4(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#ifdef _MSC_VER +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( __FUNCTION__ ": " #code ); \ + code; \ + } +#else +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( #code ); \ + code; \ + } +#endif + + +#define VPROF_INCREMENT_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_SET_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Set( amount ); } while( 0 ) +#define VPROF_SET_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Set( amount ); } while( 0 ) + +#else + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 0 ) +# define VPROF( name ) CVProfSnMarkerScope VProfSn_( name ) +# define VPROF_ASSERT_ACCOUNTED( name ) VPROF( name ) +# define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail( name, group, bAssertAccounted, budgetFlags ) +# define VPROF_0(name,group,assertAccounted,budgetFlags) VPROF( name ) +# define VPROF_BUDGET( name, group ) VPROF( name ) +# define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF( name ) + +# define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +# define VPROF_SCOPE_END() } while (0) + +# define VPROF_ONLY( expression ) ( expression ) + +# define VPROF_ENTER_SCOPE( name ) g_pfnPushMarker( name ) +# define VPROF_EXIT_SCOPE() g_pfnPopMarker() +# else +# define VPROF( name ) ((void)0) +# define VPROF_ASSERT_ACCOUNTED( name ) ((void)0) +# define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) ((void)0) +# define VPROF_0(name,group,assertAccounted,budgetFlags) ((void)0) +# define VPROF_BUDGET( name, group ) ((void)0) +# define VPROF_BUDGET_FLAGS( name, group, flags ) ((void)0) + +# define VPROF_SCOPE_BEGIN( tag ) do { +# define VPROF_SCOPE_END() } while (0) + +# define VPROF_ONLY( expression ) ((void)0) + +# define VPROF_ENTER_SCOPE( name ) +# define VPROF_EXIT_SCOPE() +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 1 ) +# define VPROF_1(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 2 ) +# define VPROF_2(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 3 ) +# define VPROF_3(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 4 ) +# define VPROF_4(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + + + +#define VPROF_INCREMENT_COUNTER(name,amount) ((void)0) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) ((void)0) +#define VPROF_SET_COUNTER(name,amount) ((void)0) +#define VPROF_SET_GROUP_COUNTER(name,group,amount) ((void)0) + +#define VPROF_TEST_SPIKE( msec ) ((void)0) + +#define VProfCode( code ) code + +#endif + +#ifdef VPROF_ENABLED + +class PLATFORM_CLASS CVProfNode +{ + friend class CVProfRecorder; + friend class CVProfile; + +public: + CVProfNode(const tchar* pszName, int detailLevel, CVProfNode* pParent, const tchar* pBudgetGroupName, int budgetFlags); + ~CVProfNode(); + + CVProfNode* GetSubNode(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, int budgetFlags); + CVProfNode* GetSubNode(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName); + CVProfNode* GetParent(); + CVProfNode* GetSibling(); + CVProfNode* GetPrevSibling(); + CVProfNode* GetChild(); + + void MarkFrame(); + void ResetPeak(); + + void Pause(); + void Resume(); + void Reset(); + + void EnterScope(); + bool ExitScope(); + + const tchar* GetName(); + + int GetBudgetGroupID() + { + return m_BudgetGroupID; + } + + void SetBudgetGroupID(int id) + { + m_BudgetGroupID = id; + } + + int GetCurCalls(); + double GetCurTime(); + int GetPrevCalls(); + double GetPrevTime(); + int GetTotalCalls(); + double GetTotalTime(); + double GetPeakTime(); + + double GetCurTimeLessChildren(); + double GetPrevTimeLessChildren(); + double GetTotalTimeLessChildren(); + + int GetPrevL2CacheMissLessChildren(); + int GetPrevLoadHitStoreLessChildren(); + + void ClearPrevTime(); + + int GetL2CacheMisses(); + + void SetCurFrameTime(unsigned long milliseconds); + + void SetClientData(int iClientData) { m_iClientData = iClientData; } + int GetClientData() const { return m_iClientData; } + +#ifdef DBGFLAG_VALIDATE + void Validate(CValidator& validator, tchar* pchName); +#endif + + +private: + + void SetUniqueNodeID(int id) + { + m_iUniqueNodeID = id; + } + + int GetUniqueNodeID() const + { + return m_iUniqueNodeID; + } + + static int s_iCurrentUniqueNodeID; + + +private: + const tchar* m_pszName; + CFastTimer m_Timer; + + int m_iPrevL2CacheMiss; + int m_iCurL2CacheMiss; + int m_iTotalL2CacheMiss; + +#ifndef _X360 + CL2Cache m_L2Cache; +#else + + unsigned int m_iBitFlags; + CPMCData m_PMCData; + int m_iPrevLoadHitStores; + int m_iCurLoadHitStores; + int m_iTotalLoadHitStores; + +public: + enum FlagBits + { + kRecordL2 = 0x01, + kCPUTrace = 0x02, + }; + inline void EnableL2andLHS(bool enable) + { + if (enable) + m_iBitFlags |= kRecordL2; + else + m_iBitFlags &= (~kRecordL2); + } + + inline bool IsL2andLHSEnabled(void) + { + return (m_iBitFlags & kRecordL2) != 0; + } + + int GetLoadHitStores(); + +private: + +#endif + + int m_nRecursions; + + unsigned m_nCurFrameCalls; + CCycleCount m_CurFrameTime; + + unsigned m_nPrevFrameCalls; + CCycleCount m_PrevFrameTime; + + unsigned m_nTotalCalls; + CCycleCount m_TotalTime; + + CCycleCount m_PeakTime; + + CVProfNode* m_pParent; + CVProfNode* m_pChild; + CVProfNode* m_pSibling; + + int m_BudgetGroupID; + + int m_iClientData; + int m_iUniqueNodeID; +}; + +enum VProfReportType_t +{ + VPRT_SUMMARY = (1 << 0), + VPRT_HIERARCHY = (1 << 1), + VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY = (1 << 2), + VPRT_LIST_BY_TIME = (1 << 3), + VPRT_LIST_BY_TIME_LESS_CHILDREN = (1 << 4), + VPRT_LIST_BY_AVG_TIME = (1 << 5), + VPRT_LIST_BY_AVG_TIME_LESS_CHILDREN = (1 << 6), + VPRT_LIST_BY_PEAK_TIME = (1 << 7), + VPRT_LIST_BY_PEAK_OVER_AVERAGE = (1 << 8), + VPRT_LIST_TOP_ITEMS_ONLY = (1 << 9), + + VPRT_FULL = (0xffffffff & ~(VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY | VPRT_LIST_TOP_ITEMS_ONLY)), +}; + +enum CounterGroup_t +{ + COUNTER_GROUP_DEFAULT = 0, + COUNTER_GROUP_NO_RESET, + COUNTER_GROUP_TEXTURE_GLOBAL, + COUNTER_GROUP_TEXTURE_PER_FRAME, + COUNTER_GROUP_GRAPHICS_PER_FRAME, + + COUNTER_GROUP_TELEMETRY, +}; + +class PLATFORM_CLASS CVProfile +{ +public: + CVProfile(); + ~CVProfile(); + + void Term(); + + void Start(); + void Stop(); + + void SetTargetThreadId(unsigned id) { m_TargetThreadId = id; } + unsigned GetTargetThreadId() { return m_TargetThreadId; } + bool InTargetThread() { return (m_TargetThreadId == ThreadGetCurrentId()); } + +#ifdef VPROF_VXCONSOLE_EXISTS + enum VXConsoleReportMode_t + { + VXCONSOLE_REPORT_TIME = 0, + VXCONSOLE_REPORT_L2CACHE_MISSES, + VXCONSOLE_REPORT_LOAD_HIT_STORE, + VXCONSOLE_REPORT_COUNT, + }; + + void VXProfileStart(); + void VXProfileUpdate(); + void VXEnableUpdateMode(int event, bool bEnable); + void VXSendNodes(void); + + void PMCDisableAllNodes(CVProfNode* pStartNode = NULL); + bool PMCEnableL2Upon(const tchar* pszNodeName, bool bRecursive = false); + bool PMCDisableL2Upon(const tchar* pszNodeName, bool bRecursive = false); + + void DumpEnabledPMCNodes(void); + + void VXConsoleReportMode(VXConsoleReportMode_t mode); + void VXConsoleReportScale(VXConsoleReportMode_t mode, float flScale); +#endif + +#ifdef _X360 + + + enum CPUTraceState + { + kDisabled, + kFirstHitNode, + kAllNodesInFrame_WaitingForMark, + kAllNodesInFrame_Recording, + + kAllNodesInFrame_WaitingForMarkMultiFrame, + kAllNodesInFrame_RecordingMultiFrame, + }; + + inline CPUTraceState GetCPUTraceMode(); + inline void SetCPUTraceEnabled(CPUTraceState enabled, bool bTraceCompleteEvent = false, int nNumFrames = -1); + inline void IncrementMultiTraceIndex(); + inline unsigned int GetMultiTraceIndex(); + void CPUTraceDisableAllNodes(CVProfNode* pStartNode = NULL); + CVProfNode* CPUTraceEnableForNode(const tchar* pszNodeName); + CVProfNode* CPUTraceGetEnabledNode(CVProfNode* pStartNode = NULL); + const char* GetCPUTraceFilename(); + const char* SetCPUTraceFilename(const char* filename); + inline bool TraceCompleteEvent(void); + +#ifdef _X360 + void LatchMultiFrame(int64 cycles); + void SpewWorstMultiFrame(); +#endif + +#endif + + void EnterScope(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, bool bAssertAccounted); + void EnterScope(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, bool bAssertAccounted, int budgetFlags); + void ExitScope(); + + void MarkFrame(char const* str); + void MarkFrame(); + void ResetPeaks(); + + void Pause(); + void Resume(); + void Reset(); + + bool IsEnabled() const; + int GetDetailLevel() const; + + bool AtRoot() const; + +#ifdef VPROF_VTUNE_GROUP +# define MAX_GROUP_STACK_DEPTH 1024 + + void EnableVTuneGroup(const tchar* pGroupName) + { + m_nVTuneGroupID = BudgetGroupNameToBudgetGroupID(pGroupName); + m_bVTuneGroupEnabled = true; + } + void DisableVTuneGroup(void) + { + m_bVTuneGroupEnabled = false; + } + + inline void PushGroup(int nGroupID); + inline void PopGroup(void); +#endif + + int NumFramesSampled() { return m_nFrames; } + double GetPeakFrameTime(); + double GetTotalTimeSampled(); + double GetTimeLastFrame(); + + CVProfNode* GetRoot(); + CVProfNode* FindNode(CVProfNode* pStartNode, const tchar* pszNode); + CVProfNode* GetCurrentNode(); + + void OutputReport(int type = VPRT_FULL, const tchar* pszStartNode = NULL, int budgetGroupID = -1); + + const tchar* GetBudgetGroupName(int budgetGroupID); + int GetBudgetGroupFlags(int budgetGroupID) const; + int GetNumBudgetGroups(void); + void GetBudgetGroupColor(int budgetGroupID, int& r, int& g, int& b, int& a); + int BudgetGroupNameToBudgetGroupID(const tchar* pBudgetGroupName); + int BudgetGroupNameToBudgetGroupID(const tchar* pBudgetGroupName, int budgetFlagsToORIn); + void RegisterNumBudgetGroupsChangedCallBack(void (*pCallBack)(void)); + + int BudgetGroupNameToBudgetGroupIDNoCreate(const tchar* pBudgetGroupName) { return FindBudgetGroupName(pBudgetGroupName); } + + void HideBudgetGroup(int budgetGroupID, bool bHide = true); + void HideBudgetGroup(const tchar* pszName, bool bHide = true) { HideBudgetGroup(BudgetGroupNameToBudgetGroupID(pszName), bHide); } + + int* FindOrCreateCounter(const tchar* pName, CounterGroup_t eCounterGroup = COUNTER_GROUP_DEFAULT); + void ResetCounters(CounterGroup_t eCounterGroup); + + int GetNumCounters(void) const; + + const tchar* GetCounterName(int index) const; + int GetCounterValue(int index) const; + const tchar* GetCounterNameAndValue(int index, int& val) const; + CounterGroup_t GetCounterGroup(int index) const; + + void PMEInitialized(bool bInit) { m_bPMEInit = bInit; } + void PMEEnable(bool bEnable) { m_bPMEEnabled = bEnable; } + +#ifdef _X360 + bool UsePME(void) { return (CPMCData::IsInitialized() && m_bPMEEnabled); } +#elif defined( _PS3 ) + inline bool UsePME(void) { return false; } +#else + bool UsePME(void) { return (m_bPMEInit && m_bPMEEnabled); } +#endif + +#ifdef DBGFLAG_VALIDATE + void Validate(CValidator& validator, tchar* pchName); +#endif + +protected: + + void FreeNodes_R(CVProfNode* pNode); + +#ifdef VPROF_VTUNE_GROUP + bool VTuneGroupEnabled() + { + return m_bVTuneGroupEnabled; + } + int VTuneGroupID() + { + return m_nVTuneGroupID; + } +#endif + + void SumTimes(const tchar* pszStartNode, int budgetGroupID); + void SumTimes(CVProfNode* pNode, int budgetGroupID); + void DumpNodes(CVProfNode* pNode, int indent, bool bAverageAndCountOnly); + int FindBudgetGroupName(const tchar* pBudgetGroupName); + int AddBudgetGroupName(const tchar* pBudgetGroupName, int budgetFlags); + +#ifdef VPROF_VTUNE_GROUP + bool m_bVTuneGroupEnabled; + int m_nVTuneGroupID; + int m_GroupIDStack[MAX_GROUP_STACK_DEPTH]; + int m_GroupIDStackDepth; +#endif + int m_enabled; + bool m_fAtRoot; + CVProfNode* m_pCurNode; + CVProfNode m_Root; + int m_nFrames; + int m_ProfileDetailLevel; + int m_pausedEnabledDepth; + + class CBudgetGroup + { + public: + tchar* m_pName; + int m_BudgetFlags; + }; + + CBudgetGroup* m_pBudgetGroups; + int m_nBudgetGroupNamesAllocated; + int m_nBudgetGroupNames; + void (*m_pNumBudgetGroupsChangedCallBack)(void); + + bool m_bPMEInit; + bool m_bPMEEnabled; + + int m_Counters[MAXCOUNTERS]; + char m_CounterGroups[MAXCOUNTERS]; + tchar* m_CounterNames[MAXCOUNTERS]; + int m_NumCounters; + +#ifdef VPROF_VXCONSOLE_EXISTS + int m_UpdateMode; + int m_nFramesRemaining; + int m_nFrameCount; + int64 m_WorstCycles; + char m_WorstTraceFilename[128]; + char m_CPUTraceFilename[128]; + unsigned int m_iSuccessiveTraceIndex; + VXConsoleReportMode_t m_ReportMode; + float m_pReportScale[VXCONSOLE_REPORT_COUNT]; + bool m_bTraceCompleteEvent; +#endif +#ifdef _X360 + CPUTraceState m_iCPUTraceEnabled; +#endif + + unsigned m_TargetThreadId; +}; + +PLATFORM_INTERFACE CVProfile g_VProfCurrentProfile; + +PLATFORM_INTERFACE bool g_VProfSignalSpike; + +class CVProfSpikeDetector +{ +public: + CVProfSpikeDetector(float spike) : + m_timeLast(GetTimeLast()) + { + m_spike = spike; + m_Timer.Start(); + } + + ~CVProfSpikeDetector() + { + m_Timer.End(); + if (Plat_FloatTime() - m_timeLast > 2.0) + { + m_timeLast = Plat_FloatTime(); + if (m_Timer.GetDuration().GetMillisecondsF() > m_spike) + { + g_VProfSignalSpike = true; + } + } + } + +private: + static float& GetTimeLast() { static float timeLast = 0; return timeLast; } + CFastTimer m_Timer; + float m_spike; + float& m_timeLast; +}; + + +#define VPROF_TEST_SPIKE( msec ) CVProfSpikeDetector UNIQUE_ID( msec ) + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PushGroup(int nGroupID) +{ + Assert(m_GroupIDStackDepth > 0); + Assert(m_GroupIDStackDepth < MAX_GROUP_STACK_DEPTH); + m_GroupIDStack[m_GroupIDStackDepth] = nGroupID; + m_GroupIDStackDepth++; + if (m_GroupIDStack[m_GroupIDStackDepth - 2] != nGroupID && + VTuneGroupEnabled() && + nGroupID == VTuneGroupID()) + { + vtune(true); + } +} +#endif + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PopGroup(void) +{ + m_GroupIDStackDepth--; + Assert(m_GroupIDStackDepth > 0); + if (m_GroupIDStack[m_GroupIDStackDepth] != m_GroupIDStack[m_GroupIDStackDepth + 1] && + VTuneGroupEnabled() && + m_GroupIDStack[m_GroupIDStackDepth + 1] == VTuneGroupID()) + { + vtune(false); + } +} +#endif + +inline CVProfile* GetVProfProfileForCurrentThread() +{ + return NULL; +} + +class CVProfScope : public CVProfSnMarkerScope +{ +public: + CVProfScope(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, bool bAssertAccounted, int budgetFlags); + ~CVProfScope(); + +private: + bool m_bEnabled; +}; + +inline CVProfNode::CVProfNode(const tchar* pszName, int detailLevel, CVProfNode* pParent, const tchar* pBudgetGroupName, int budgetFlags) + : m_pszName(pszName), + m_nCurFrameCalls(0), + m_nPrevFrameCalls(0), + m_nRecursions(0), + m_pParent(pParent), + m_pChild(NULL), + m_pSibling(NULL), + m_iClientData(-1) +#ifdef _X360 + , m_iBitFlags(0) +#endif +{ + m_iUniqueNodeID = s_iCurrentUniqueNodeID++; + + if (m_iUniqueNodeID > 0) + { + m_BudgetGroupID = g_VProfCurrentProfile.BudgetGroupNameToBudgetGroupID(pBudgetGroupName, budgetFlags); + } + else + { + m_BudgetGroupID = 0; + } + + Reset(); + + if (m_pParent && (m_BudgetGroupID == VPROF_BUDGET_GROUP_ID_UNACCOUNTED)) + { + m_BudgetGroupID = m_pParent->GetBudgetGroupID(); + } +} + + +inline CVProfNode* CVProfNode::GetParent() +{ + Assert(m_pParent); + return m_pParent; +} + +inline CVProfNode* CVProfNode::GetSibling() +{ + return m_pSibling; +} + +inline CVProfNode* CVProfNode::GetPrevSibling() +{ + CVProfNode* p = GetParent(); + + if (!p) + return NULL; + + CVProfNode* s; + for (s = p->GetChild(); + s && (s->GetSibling() != this); + s = s->GetSibling()) + ; + + return s; +} + +inline CVProfNode* CVProfNode::GetChild() +{ + return m_pChild; +} + +inline const tchar* CVProfNode::GetName() +{ + return m_pszName; +} + +inline int CVProfNode::GetTotalCalls() +{ + return m_nTotalCalls; +} + +inline double CVProfNode::GetTotalTime() +{ + return m_TotalTime.GetMillisecondsF(); +} + +inline int CVProfNode::GetCurCalls() +{ + return m_nCurFrameCalls; +} + +inline double CVProfNode::GetCurTime() +{ + return m_CurFrameTime.GetMillisecondsF(); +} + +inline int CVProfNode::GetPrevCalls() +{ + return m_nPrevFrameCalls; +} + +inline double CVProfNode::GetPrevTime() +{ + return m_PrevFrameTime.GetMillisecondsF(); +} + +inline double CVProfNode::GetPeakTime() +{ + return m_PeakTime.GetMillisecondsF(); +} + +inline double CVProfNode::GetTotalTimeLessChildren() +{ + double result = GetTotalTime(); + CVProfNode* pChild = GetChild(); + while (pChild) + { + result -= pChild->GetTotalTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +inline double CVProfNode::GetCurTimeLessChildren() +{ + double result = GetCurTime(); + CVProfNode* pChild = GetChild(); + while (pChild) + { + result -= pChild->GetCurTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +inline double CVProfNode::GetPrevTimeLessChildren() +{ + double result = GetPrevTime(); + CVProfNode* pChild = GetChild(); + while (pChild) + { + result -= pChild->GetPrevTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +inline int CVProfNode::GetPrevL2CacheMissLessChildren() +{ + int result = m_iPrevL2CacheMiss; + CVProfNode* pChild = GetChild(); + while (pChild) + { + result -= pChild->m_iPrevL2CacheMiss; + pChild = pChild->GetSibling(); + } + return result; +} + +inline int CVProfNode::GetPrevLoadHitStoreLessChildren() +{ +#ifndef _X360 + return 0; +#else + int result = m_iPrevLoadHitStores; + CVProfNode* pChild = GetChild(); + while (pChild) + { + result -= pChild->m_iPrevLoadHitStores; + pChild = pChild->GetSibling(); + } + return result; +#endif +} + + +inline void CVProfNode::ClearPrevTime() +{ + m_PrevFrameTime.Init(); +} + +inline int CVProfNode::GetL2CacheMisses(void) +{ +#ifndef _X360 + return m_L2Cache.GetL2CacheMisses(); +#else + return m_iTotalL2CacheMiss; +#endif +} + +#ifdef _X360 +inline int CVProfNode::GetLoadHitStores(void) +{ + return m_iTotalLoadHitStores; +} +#endif + +inline bool CVProfile::IsEnabled() const +{ + return (m_enabled != 0); +} + +inline int CVProfile::GetDetailLevel() const +{ + return m_ProfileDetailLevel; +} + + +inline bool CVProfile::AtRoot() const +{ + return m_fAtRoot; +} + +inline void CVProfile::Start() +{ + if (++m_enabled == 1) + { + m_Root.EnterScope(); +#ifdef VPROF_VXCONSOLE_EXISTS + VXProfileStart(); +#endif +#ifdef _X360 + CPMCData::InitializeOnceProgramWide(); +#endif + } +} + +inline void CVProfile::Stop() +{ + if (--m_enabled == 0) + m_Root.ExitScope(); +} + +inline void CVProfile::EnterScope(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, bool bAssertAccounted, int budgetFlags) +{ + if ((m_enabled != 0 || !m_fAtRoot) && InTargetThread()) + { + if (pszName != m_pCurNode->GetName()) + { + m_pCurNode = m_pCurNode->GetSubNode(pszName, detailLevel, pBudgetGroupName, budgetFlags); + } + m_pBudgetGroups[m_pCurNode->GetBudgetGroupID()].m_BudgetFlags |= budgetFlags; + +#if defined( _DEBUG ) && !defined( _X360 ) + if (bAssertAccounted) + { + AssertOnce(m_pCurNode->GetBudgetGroupID() != 0); + } +#endif + m_pCurNode->EnterScope(); + m_fAtRoot = false; + } +#if defined(_X360) && defined(VPROF_PIX) + if (m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED) + PIXBeginNamedEvent(0, pszName); +#endif +} + +inline void CVProfile::EnterScope(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, bool bAssertAccounted) +{ + EnterScope(pszName, detailLevel, pBudgetGroupName, bAssertAccounted, BUDGETFLAG_OTHER); +} + +inline void CVProfile::ExitScope() +{ +#if defined(_X360) && defined(VPROF_PIX) +#ifndef PIXBeginNamedEvent +#error PIX.h must be included if VPROF_PIX is enabled +#endif + if (m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED) + PIXEndNamedEvent(); +#endif + if ((!m_fAtRoot || m_enabled != 0) && InTargetThread()) + { + if (m_pCurNode->ExitScope()) + { + m_pCurNode = m_pCurNode->GetParent(); + } + m_fAtRoot = (m_pCurNode == &m_Root); + } +} + +inline void CVProfile::Pause() +{ + m_pausedEnabledDepth = m_enabled; + m_enabled = 0; + if (!AtRoot()) + m_Root.Pause(); +} + +inline void CVProfile::Resume() +{ + m_enabled = m_pausedEnabledDepth; + if (!AtRoot()) + m_Root.Resume(); +} + +inline void CVProfile::Reset() +{ + m_Root.Reset(); + m_nFrames = 0; +} + +inline void CVProfile::ResetPeaks() +{ + m_Root.ResetPeak(); +} + +inline void CVProfile::MarkFrame(char const* str) +{ + MarkFrame(); +} + +inline void CVProfile::MarkFrame() +{ + if (m_enabled) + { + ++m_nFrames; + m_Root.ExitScope(); + m_Root.MarkFrame(); + m_Root.EnterScope(); + +#ifdef _X360 + switch (GetCPUTraceMode()) + { + case kAllNodesInFrame_WaitingForMark: + m_iCPUTraceEnabled = kAllNodesInFrame_Recording; + break; + case kAllNodesInFrame_WaitingForMarkMultiFrame: + m_iCPUTraceEnabled = kAllNodesInFrame_RecordingMultiFrame; + break; + case kAllNodesInFrame_Recording: + m_iCPUTraceEnabled = kDisabled; + Msg("Frame ended. Recording no more CPU traces\n"); + + break; + case kAllNodesInFrame_RecordingMultiFrame: + if (--m_nFramesRemaining == 0) + { + m_iCPUTraceEnabled = kDisabled; + Msg("Frames ended. Recording no more CPU traces\n"); + + SpewWorstMultiFrame(); + } + + ++m_nFrameCount; + + break; + default: + break; + } +#endif + } +} + +inline double CVProfile::GetTotalTimeSampled() +{ + return m_Root.GetTotalTime(); +} + +inline double CVProfile::GetPeakFrameTime() +{ + return m_Root.GetPeakTime(); +} + +inline double CVProfile::GetTimeLastFrame() +{ + return m_Root.GetCurTime(); +} + +inline CVProfNode* CVProfile::GetRoot() +{ + return &m_Root; +} + +inline CVProfNode* CVProfile::GetCurrentNode() +{ + return m_pCurNode; +} + + +inline const tchar* CVProfile::GetBudgetGroupName(int budgetGroupID) +{ + Assert(budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames); + return m_pBudgetGroups[budgetGroupID].m_pName; +} + +inline int CVProfile::GetBudgetGroupFlags(int budgetGroupID) const +{ + Assert(budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames); + return m_pBudgetGroups[budgetGroupID].m_BudgetFlags; +} + +#ifdef _X360 + +inline CVProfile::CPUTraceState CVProfile::GetCPUTraceMode() +{ + return m_iCPUTraceEnabled; +} + +inline void CVProfile::SetCPUTraceEnabled(CPUTraceState enabled, bool bTraceCompleteEvent , int nNumFrames ) +{ + m_iCPUTraceEnabled = enabled; + m_bTraceCompleteEvent = bTraceCompleteEvent; + if (nNumFrames != -1) + { + m_nFramesRemaining = nNumFrames; + m_nFrameCount = 0; + m_WorstCycles = 0; + m_WorstTraceFilename[0] = 0; + } +} + +inline void CVProfile::IncrementMultiTraceIndex() +{ + ++m_iSuccessiveTraceIndex; +} + +inline unsigned int CVProfile::GetMultiTraceIndex() +{ + return m_iSuccessiveTraceIndex; +} + +#endif + + +inline CVProfScope::CVProfScope(const tchar* pszName, int detailLevel, const tchar* pBudgetGroupName, bool bAssertAccounted, int budgetFlags) : + CVProfSnMarkerScope(pszName), + m_bEnabled(g_VProfCurrentProfile.IsEnabled()) +{ + if (m_bEnabled) + { + g_VProfCurrentProfile.EnterScope(pszName, detailLevel, pBudgetGroupName, bAssertAccounted, budgetFlags); + } +} + +inline CVProfScope::~CVProfScope() +{ + if (m_bEnabled) + { + g_VProfCurrentProfile.ExitScope(); + } +} + +class CVProfCounter +{ +public: + CVProfCounter(const tchar* pName, CounterGroup_t group = COUNTER_GROUP_DEFAULT) + { + m_pCounter = g_VProfCurrentProfile.FindOrCreateCounter(pName, group); + Assert(m_pCounter); + } + ~CVProfCounter() + { + } + void Increment(int val) + { + Assert(m_pCounter); + *m_pCounter += val; + } + void Set(int val) + { + Assert(m_pCounter); + *m_pCounter = val; + } +private: + int* m_pCounter; +}; + +#endif + +#ifdef _X360 + +#include "xbox/xbox_console.h" +#include "tracerecording.h" +#include "tier1/fmtstr.h" +#pragma comment( lib, "tracerecording.lib" ) +#pragma comment( lib, "xbdm.lib" ) + +class CPIXRecorder +{ +public: + CPIXRecorder() : m_bActive(false) {} + ~CPIXRecorder() { Stop(); } + + void Start(const char* pszFilename = "capture") + { + if (!m_bActive) + { + if (!XTraceStartRecording(CFmtStr("e:\\%s.pix2", pszFilename))) + { + Msg("XTraceStartRecording failed, error code %d\n", GetLastError()); + } + else + { + m_bActive = true; + } + } + } + + void Stop() + { + if (m_bActive) + { + m_bActive = false; + if (XTraceStopRecording()) + { + Msg("CPU trace finished.\n"); + XBX_rTraceComplete(); + } + } + } + +private: + bool m_bActive; +}; + +#define VPROF_BEGIN_PIX_BLOCK( convar ) \ + { \ + bool bRunPix = 0; \ + static CFastTimer PIXTimer; \ + extern ConVar convar; \ + ConVar &PIXConvar = convar; \ + CPIXRecorder PIXRecorder; \ + { \ + PIXLabel: \ + if ( bRunPix ) \ + { \ + PIXRecorder.Start(); \ + } \ + else \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.Start(); \ + } \ + } \ + { + + +#define VPROF_END_PIX_BLOCK() \ + } \ + \ + if ( !bRunPix ) \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.End(); \ + if ( PIXTimer.GetDuration().GetMillisecondsF() > PIXConvar.GetFloat() ) \ + { \ + PIXConvar.SetValue( 0 ); \ + bRunPix = true; \ + goto PIXLabel; \ + } \ + } \ + } \ + else \ + { \ + PIXRecorder.Stop(); \ + } \ + } \ + } +#else +#define VPROF_BEGIN_PIX_BLOCK( PIXConvar ) { +#define VPROF_END_PIX_BLOCK() } +#endif + + +#ifdef VPROF_UNDO_PIX +#undef USE_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#include +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif + +#endif + + +``` + +`SpyCustom/sdk/vprof_sn.h`: + +```h +#ifndef TIER_V0PROF_SN_HDR +#define TIER_V0PROF_SN_HDR + +#if defined( SN_TARGET_PS3 ) && !defined(_CERT) +extern "C" void(*g_pfnPushMarker)(const char* pName); +extern "C" void(*g_pfnPopMarker)(); + +class CVProfSnMarkerScope +{ +public: + CVProfSnMarkerScope(const char* pszName) + { + g_pfnPushMarker(pszName); + } + ~CVProfSnMarkerScope() + { + g_pfnPopMarker(); + } +}; + + +#define SNPROF(name) ((void)0) +#define SNPROF_ANIM(name) ((void)0) + +#else + +class CVProfSnMarkerScope { public: CVProfSnMarkerScope(const char*) {} }; + +#define SNPROF(name) TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "%s", name ); +#define SNPROF_ANIM(name) TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "anim %s", name ); + +#endif + +#endif +``` + +`SpyCustom/sdk/vprof_telemetry.h`: + +```h +#ifndef VPROF_TELEMETRY_H +#define VPROF_TELEMETRY_H + +#if !defined( MAKE_VPC ) + +#if !defined( RAD_TELEMETRY_DISABLED ) && ( defined( IS_WINDOWS_PC ) || defined( _LINUX ) ) +#endif + + +#ifdef WIN32 +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +#endif + + +enum TelemetryZonePlotSlot_t +{ + TELEMETRY_ZONE_PLOT_SLOT_1, + TELEMETRY_ZONE_PLOT_SLOT_2, + TELEMETRY_ZONE_PLOT_SLOT_3, + TELEMETRY_ZONE_PLOT_SLOT_4, + TELEMETRY_ZONE_PLOT_SLOT_5, + TELEMETRY_ZONE_PLOT_SLOT_6, + TELEMETRY_ZONE_PLOT_SLOT_7, + TELEMETRY_ZONE_PLOT_SLOT_8, + TELEMETRY_ZONE_PLOT_SLOT_9, + TELEMETRY_ZONE_PLOT_SLOT_10, + TELEMETRY_ZONE_PLOT_SLOT_11, + TELEMETRY_ZONE_PLOT_SLOT_12, + TELEMETRY_ZONE_PLOT_SLOT_13, + TELEMETRY_ZONE_PLOT_SLOT_14, + TELEMETRY_ZONE_PLOT_SLOT_15, + TELEMETRY_ZONE_PLOT_SLOT_16, + + TELEMETRY_ZONE_PLOT_SLOT_MAX +}; + + +#if !defined( RAD_TELEMETRY_ENABLED ) + +#define NTELEMETRY 1 +#undef RADCOPYRIGHT + +inline void TelemetryTick() {} +inline void TelemetrySetLevel(unsigned int Level) {} + +#define TELEMETRY_REQUIRED( tmRequiredCode ) +#define TELEMETRY_REQUIRED_REPLACE( tmRequiredCode, replacementCode ) replacementCode + +#else + +#include "../../thirdparty/telemetry/include/telemetry.h" +#undef RADCOPYRIGHT + +PLATFORM_INTERFACE void TelemetryTick(); +PLATFORM_INTERFACE void TelemetrySetLevel(unsigned int Level); + +struct TelemetryZonePlotData +{ + const char* m_Name; + TmU64 m_CurrFrameTime; +}; + +struct TelemetryData +{ + HTELEMETRY tmContext[32]; + float flRDTSCToMilliSeconds; + uint32 FrameCount; + char ServerAddress[128]; + uint32 ZoneFilterVal; + int playbacktick; + float dotatime; + uint32 DemoTickStart; + uint32 DemoTickEnd; + uint32 Level; + TelemetryZonePlotData m_ZonePlot[TELEMETRY_ZONE_PLOT_SLOT_MAX]; +}; +PLATFORM_INTERFACE TelemetryData g_Telemetry; + +#define TELEMETRY_REQUIRED( tmRequiredCode ) tmRequiredCode +#define TELEMETRY_REQUIRED_REPLACE( tmRequiredCode, replacementCode ) tmRequiredCode + +#endif + + + + + + + + + + +#define TELEMETRY_ERROR_BUILD_DISABLED TELEMETRY_REQUIRED_REPLACE( TMERR_DISABLED, 0x0001 ) +#define TELEMETRY_ERROR_DISCONNECTED TELEMETRY_REQUIRED_REPLACE( TMCS_DISCONNECTED, 0 ) + + +#define TELEMETRY_LEVEL0 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[0], 0 ) +#define TELEMETRY_LEVEL1 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[1], 0 ) +#define TELEMETRY_LEVEL2 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[2], 0 ) +#define TELEMETRY_LEVEL3 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[3], 0 ) +#define TELEMETRY_LEVEL4 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[4], 0 ) +#define TELEMETRY_LEVEL5 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[5], 0 ) +#define TELEMETRY_LEVEL6 TELEMETRY_REQUIRED_REPLACE( g_Telemetry.tmContext[6], 0 ) + +#define TM_FAST_TIME() TELEMETRY_REQUIRED_REPLACE( tmFastTime(), 0 ) + + +#define TM_LOAD_TELEMETRY(kUseCheckedDll) TELEMETRY_REQUIRED_REPLACE( tmLoadTelemetry(kUseCheckedDll), 0 ) + + +#define TM_STARTUP() TELEMETRY_REQUIRED_REPLACE( tmStartup(), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_SHUTDOWN() TELEMETRY_REQUIRED( tmShutdown() ) + + +#define TM_INITIALIZE_CONTEXT( pContext, pArena, kArenaSize ) TELEMETRY_REQUIRED_REPLACE( tmInitializeContext( pContext, pArena, kArenaSize ), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_ZONE_FILTERED( context, kThreshold, kFlags, kpFormat, ... ) TELEMETRY_REQUIRED( tmZoneFiltered( context, kThreshold, kFlags, kpFormat, ##__VA_ARGS__ ) ) + + +#define TM_ZONE( context, kFlags, kpFormat, ... ) TELEMETRY_REQUIRED( tmZone( context, kFlags, kpFormat, ##__VA_ARGS__ ) ) + +#define TM_ZONE_DEFAULT( context ) TM_ZONE( context, TMZF_NONE, __FUNCTION__ ) +#define TM_ZONE_IDLE( context ) TM_ZONE( context, TMZF_IDLE, __FUNCTION__ ) +#define TM_ZONE_STALL( context ) TM_ZONE( context, TMZF_STALL, __FUNCTION__ ) + + +#define TM_CHECK_VERSION( context, major, minor, build, cust ) TELEMETRY_REQUIRED_REPLACE( tmCheckVersion( context, major, minor, build, cust ), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_LISTEN_IPC( context, name ) TELEMETRY_REQUIRED_REPLACE( tmListenIPC( context, name ), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_UPDATE_SYMBOL_DATA( context ) TELEMETRY_REQUIRED( tmUpdateSymbolData( context ) ) + + +#define TM_GET_SESSION_NAME( context, dst, kDstSize ) TELEMETRY_REQUIRED_REPLACE( tmGetSessionName( context, dst, kDstSize ), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_UNWIND_TO_DEBUG_ZONE_LEVEL( context, kLevel ) TELEMETRY_REQUIRED( tmUnwindToDebugZoneLevel( context, kLevel ) ) + + +#define TM_SET_DEBUG_ZONE_LEVEL( context, kLevel ) TELEMETRY_REQUIRED( tmSetDebugZoneLevel( context, kLevel ) ) + + +#define TM_CHECK_DEBUG_ZONE_LEVEL( context, kLevel ) TELEMETRY_REQUIRED( tmCheckDebugZoneLevel( context, kLevel ) ) + + +#define TM_GET_CALL_STACK( context, TmCallStack_Ptr ) TELEMETRY_REQUIRED_REPLACE( tmGetCallStack( context, TmCallStack_Ptr ), 0 ) + + +#define TM_SEND_CALL_STACK( context, TmCallStack_Ptr ) TELEMETRY_REQUIRED_REPLACE( tmSendCallStack( context, TmCallStack_Ptr ), 0 ) + + +#define TM_GET_LAST_ERROR( context ) TELEMETRY_REQUIRED_REPLACE( tmGetLastError( context ), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_SHUTDOWN_CONTEXT( context ) TELEMETRY_REQUIRED( tmShutdownContext( context ) ) + + +#define TM_GET_ACCUMULATION_START( context ) TELEMETRY_REQUIRED_REPLACE( tmGetAccumulationStart( context ), 0 ) + + +#define TM_GET_LAST_CONTEXT_SWITCH_TIME( context ) TELEMETRY_REQUIRED_REPLACE( tmGetLastContextSwitchTime( context ), 0 ) + + +#define TM_ENTER_ACCUMULATION_ZONE( context, zone_variable ) TELEMETRY_REQUIRED( tmEnterAccumulationZone( context, zone_variable ) ) + + +#define TM_LEAVE_ACCUMULATION_ZONE( context, zone_variable ) TELEMETRY_REQUIRED( tmLeaveAccumulationZone( context, zone_variable ) ) + + +#define TM_GET_FORMAT_CODE( context, pCode, kpFmt ) TELEMETRY_REQUIRED( tmGetFormatCode( context, pCode, kpFmt ) ) + + +#define TM_DYNAMIC_STRING( context, kpString ) TELEMETRY_REQUIRED_REPLACE( tmDynamicString( context, kpString ), NULL ) + + +#define TM_CLEAR_STATIC_STRING( context, kpString ) TELEMETRY_REQUIRED( tmClearStaticString( context, kpString ) ) + + +#define TM_ENABLE( context, kOption, kValue ) TELEMETRY_REQUIRED( tmEnable( context, kOption, kValue ) ) + + +#define TM_IS_ENABLED( context, kOption ) TELEMETRY_REQUIRED_REPLACE( tmIsEnabled( context, kOption ), 0 ) + +#define TM_SET_PARAMETER( context, kParameter, kpValue ) TELEMETRY_REQUIRED( tmSetParameter( context, kParameter, kpValue ) ) + + +#define TM_OPEN( context, kpAppName, kpBuildInfo, kpServerAddress, kConnection, kServerPort, kFlags, kTimeoutMS ) TELEMETRY_REQUIRED_REPLACE( tmOpen( context, kpAppName, kpBuildInfo, kpServerAddress, kConnection, kServerPort, kFlags, kTimeoutMS ), TELEMETRY_ERROR_BUILD_DISABLED ) + + +#define TM_CLOSE( context ) TELEMETRY_REQUIRED( tmClose( context ) ) + + +#define TM_TICK( context ) TELEMETRY_REQUIRED( tmTick( context ) ) + + +#define TM_FLUSH( context ) TELEMETRY_REQUIRED( tmFlush( context ) ) + + +#define TM_PAUSE( context, kPause ) TELEMETRY_REQUIRED( tmPause( context, kPause ) ) + + +#define TM_IS_PAUSED( context ) TELEMETRY_REQUIRED_REPLACE( tmIsPaused( context ), 0 ) + + +#define TM_GET_CONNECTION_STATUS( context ) TELEMETRY_REQUIRED_REPLACE( tmGetConnectionStatus( context ), TELEMETRY_ERROR_DISCONNECTED ) + + +#define TM_FREE( context, kpPtr ) TELEMETRY_REQUIRED( tmFree( context, kpPtr ) ) + + +#define TM_GET_STAT_I( context, kStat ) TELEMETRY_REQUIRED_REPLACE( tmGetStati( context, kStat ), 0 ) + + +#define TM_LEAVE( context ) TELEMETRY_REQUIRED( tmLeave( context ) ) + + +#define TM_LEAVE_EX( context, kMatchId, kThreadId, kpFilename, kLine ) TELEMETRY_REQUIRED( tmLeaveEx( context, kMatchId, kThreadId, kpFilename, kLine ) ) + + +#define TM_TRY_LOCK( context, kPtr, kpLockName, ... ) TELEMETRY_REQUIRED( tmTryLock( context, kPtr, kpLockName, ##__VA_ARGS__ ) ) + + +#define TM_TRY_LOCK_EX( context, matcher, kThreshold, kpFileName, kLine, kPtr, kpLockName, ... ) TELEMETRY_REQUIRED( tmTryLockEx( context, matcher, kThreshold, kpFileName, kLine, kPtr, kpLockName, ##__VA_ARGS__ ) ) + + +#define TM_END_TRY_LOCK( context, kPtr, kResult ) TELEMETRY_REQUIRED( tmEndTryLock( context, kPtr, kResult ) ) + + +#define TM_END_TRY_LOCK_EX( context, kMatchId, kpFileName, kLine, kPtr, kResult ) TELEMETRY_REQUIRED( tmEndTryLockEx( context, kMatchId, kpFileName, kLine, kPtr, kResult ) ) + + +#define TM_BEGIN_TIME_SPAN( context, kId, kFlags, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmBeginTimeSpan( context, kId, kFlags, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_END_TIME_SPAN( context, kId, kFlags, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmEndTimeSpan( context, kId, kFlags, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_BEGIN_TIME_SPAN_AT( context, kId, kFlags, kTimeStamp, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmBeginTimeSpanAt( context, kId, kFlags, kTimeStamp, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_END_TIME_SPAN_AT( context, kId, kFlags, kTimeStamp, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmEndTimeSpanAt( context, kId, kFlags, kTimeStamp, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_SIGNAL_LOCK_COUNT( context, kPtr, kCount, kpDescription, ... ) TELEMETRY_REQUIRED( tmSignalLockCount( context, kPtr, kCount, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_SET_LOCK_STATE( context, kPtr, kState, kpDescription, ... ) TELEMETRY_REQUIRED( tmSetLockState( context, kPtr, kState, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_SET_LOCK_STATE_EX( context, kpFileName, kLine, kPtr, kState, kpDescription, ... ) TELEMETRY_REQUIRED( tmSetLockStateEx( context, kpFileName, kLine, kPtr, kState, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_SET_LOCK_STATE_MIN_TIME( context, buf, kPtr, kState, kpDescription, ... ) TELEMETRY_REQUIRED( tmSetLockStateMinTime( context, buf, kPtr, kState, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_SET_LOCK_STATE_MIN_TIME_EX( context, buf, kpFilename, kLine, kPtr, kState, kpDescription, ... ) TELEMETRY_REQUIRED( tmSetLockStateMinTimeEx( context, buf, kpFilename, kLine, kPtr, kState, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_THREAD_NAME( context, kThreadID, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmThreadName( context, kThreadID, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_LOCK_NAME( context, kPtr, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmLockName( context, kPtr, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_EMIT_ACCUMULATION_ZONE( context, kZoneFlags, pStart, kCount, kTotal, kpZoneFormat, ... ) TELEMETRY_REQUIRED( tmEmitAccumulationZone( context, kZoneFlags, pStart, kCount, kTotal, kpZoneFormat, ##__VA_ARGS__ ) ) + + +#define TM_SET_VARIABLE( context, kpKey, kpValueFormat, ... ) TELEMETRY_REQUIRED( tmSetVariable( context, kpKey, kpValueFormat, ##__VA_ARGS__ ) ) + + +#define TM_SET_TIMELINE_SECTION_NAME( context, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmSetTimelineSectionName( context, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_ENTER( context, kFlags, kpZoneName, ... ) TELEMETRY_REQUIRED( tmEnter( context, kFlags, kpZoneName, ##__VA_ARGS__ ) ) + + +#define TM_ENTER_EX( context, pMatchId, kThreadId, kThreshold, kpFilename, kLine, kFlags, kpZoneName, ... ) TELEMETRY_REQUIRED( tmEnterEx( context, pMatchId, kThreadId, kThreshold, kpFilename, kLine, kFlags, kpZoneName, ##__VA_ARGS__ ) ) + + +#define TM_ALLOC( context, kPtr, kSize, kpDescription, ... ) TELEMETRY_REQUIRED( tmAlloc( context, kPtr, kSize, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_ALLOC_EX( context, kpFilename, kLineNumber, kPtr, kSize, kpDescription, ... ) TELEMETRY_REQUIRED( tmAllocEx( context, kpFilename, kLineNumber, kPtr, kSize, kpDescription, ##__VA_ARGS__ ) ) + + +#define TM_MESSAGE( context, kFlags, kpFormatString, ... ) TELEMETRY_REQUIRED( tmMessage( context, kFlags, kpFormatString, ##__VA_ARGS__ ) ) +#define TM_LOG( context, kpFormatString, ... ) TM_MESSAGE( context, TMMF_SEVERITY_LOG, kpFormatString, ##__VA_ARGS__ ) +#define TM_WARNING( context, kpFormatString, ... ) TM_MESSAGE( context, TMMF_SEVERITY_WARNING, kpFormatString, ##__VA_ARGS__ ) +#define TM_ERROR( context, kpFormatString, ... ) TM_MESSAGE( context, TMMF_SEVERITY_ERROR, kpFormatString, ##__VA_ARGS__ ) + + + +#define TM_PLOT( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlot( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_PLOT_F32( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlotF32( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_PLOT_F64( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlotF64( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_PLOT_I32( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlotI32( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_PLOT_U32( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlotU32( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_PLOT_I64( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlotI64( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_PLOT_U64( context, kType, kFlags, kValue, kpNameFormat, ... ) TELEMETRY_REQUIRED( tmPlotU64( context, kType, kFlags, kValue, kpNameFormat, ##__VA_ARGS__ ) ) + + +#define TM_BLOB( context, kpData, kDataSize, kpPluginIdentifier, kpBlobName, ...) TELEMETRY_REQUIRED( tmBlob( context, kpData, kDataSize, kpPluginIdentifier, kpBlobName, ##__VA_ARGS__ ) ) + + +#define TM_DISJOINT_BLOB( context, kNumPieces, kpData, kDataSizes, kpPluginIdentifier, kpBlobName, ... ) TELEMETRY_REQUIRED( tmDisjointBlob( context, kNumPieces, kpData, kDataSizes, kpPluginIdentifier, kpBlobName, ##__VA_ARGS__ ) ) + + + + + + + + + + + + +#if !defined( RAD_TELEMETRY_ENABLED ) + +class CTelemetryLock +{ +public: + CTelemetryLock(void* plocation, const char* description) {} + ~CTelemetryLock() {} + void Locked() {} + void Unlocked() {} +}; + +class CTelemetrySpikeDetector +{ +public: + CTelemetrySpikeDetector(const char* msg, unsigned int threshold = 50) {} + ~CTelemetrySpikeDetector() { } +}; + +class CTelemetryZonePlotScope +{ +public: + + CTelemetryZonePlotScope(const char* pName, TelemetryZonePlotSlot_t slot) {} + ~CTelemetryZonePlotScope() {} +}; + +#define TelemetrySetLockName( _ctx, _location, _description ) +#define TM_ZONE_PLOT( context, name, slot ) + +#else + +#define TelemetrySetLockName( _ctx, _location, _description ) \ + do \ + { \ + static bool s_bNameSet = false; \ + if( _ctx && !s_bNameSet ) \ + { \ + tmLockName( _ctx, _location, _description ); \ + s_bNameSet = true; \ + } \ + } while( 0 ) + +class CTelemetryLock +{ +public: + CTelemetryLock(void* plocation, const char* description) + { + m_plocation = (const char*)plocation; + m_description = description; + TelemetrySetLockName(TELEMETRY_LEVEL1, m_plocation, m_description); + TM_TRY_LOCK(TELEMETRY_LEVEL1, m_plocation, "%s", m_description); + } + ~CTelemetryLock() + { + Unlocked(); + } + void Locked() + { + TM_END_TRY_LOCK(TELEMETRY_LEVEL1, m_plocation, TMLR_SUCCESS); + TM_SET_LOCK_STATE(TELEMETRY_LEVEL1, m_plocation, TMLS_LOCKED, "%s Locked", m_description); + } + void Unlocked() + { + if (m_plocation) + { + TM_SET_LOCK_STATE(TELEMETRY_LEVEL1, m_plocation, TMLS_RELEASED, "%s Released", m_description); + m_plocation = NULL; + } + } + +public: + const char* m_plocation; + const char* m_description; +}; + +class CTelemetrySpikeDetector +{ +public: + CTelemetrySpikeDetector(const char* msg, float threshold = 5) : + m_message(msg), m_threshold(threshold), time0(tmFastTime()) {} + ~CTelemetrySpikeDetector() + { + float time = (tmFastTime() - time0) * g_Telemetry.flRDTSCToMilliSeconds; + if (time >= m_threshold) + { + TM_MESSAGE(TELEMETRY_LEVEL0, TMMF_ICON_NOTE | TMMF_SEVERITY_WARNING, "(dota/spike)%s %.2fms %t", m_message, time, tmSendCallStack(TELEMETRY_LEVEL0, 0)); + } + } + +private: + TmU64 time0; + float m_threshold; + const char* m_message; +}; + +#define TM_ZONE_PLOT( context, name, slot ) CTelemetryZonePlotScope _telemetryZonePlot##__LINE__(context, name, slot); + +class CTelemetryZonePlotScope +{ +public: + + CTelemetryZonePlotScope(HTELEMETRY context, const char* pName, TelemetryZonePlotSlot_t slot) + : + m_Context(context), + m_SlotData(NULL), + m_StartTime(0) + { + if (slot < TELEMETRY_ZONE_PLOT_SLOT_MAX) + { + m_SlotData = &g_Telemetry.m_ZonePlot[slot]; + m_SlotData->m_Name = pName; + m_StartTime = TM_FAST_TIME(); + } + TM_ENTER(m_Context, TMZF_NONE, "%s", pName); + } + + ~CTelemetryZonePlotScope() + { + TM_LEAVE(m_Context); + if (m_SlotData) + { + m_SlotData->m_CurrFrameTime += (TM_FAST_TIME() - m_StartTime); + } + } + +private: + + HTELEMETRY m_Context; + TelemetryZonePlotData* m_SlotData; + TmU64 m_StartTime; +}; + +#endif + +#endif +``` + +`SpyCustom/sdk/vstdlib.h`: + +```h +#ifndef VSTDLIB_H +#define VSTDLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" + +#ifdef VSTDLIB_DLL_EXPORT +#define VSTDLIB_INTERFACE DLL_EXPORT +#define VSTDLIB_OVERLOAD DLL_GLOBAL_EXPORT +#define VSTDLIB_CLASS DLL_CLASS_EXPORT +#define VSTDLIB_GLOBAL DLL_GLOBAL_EXPORT +#else +#define VSTDLIB_INTERFACE DLL_IMPORT +#define VSTDLIB_OVERLOAD DLL_GLOBAL_IMPORT +#define VSTDLIB_CLASS DLL_CLASS_IMPORT +#define VSTDLIB_GLOBAL DLL_GLOBAL_IMPORT +#endif + +#endif +``` + +`SpyCustom/sdk/vtf.h`: + +```h +#ifndef VTF_H +#define VTF_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "imageformat.h" +#include "platform.h" + +#ifndef VTF_FILE_FORMAT_ONLY + +class CUtlBuffer; +class Vector; +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_UNUSED_40000000 = 0x40000000, + TEXTUREFLAGS_UNUSED_80000000 = 0x80000000, +}; + +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 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; + +#if defined( _X360 ) + virtual int UpdateOrCreate(const char* pFilename, const char* pPathID = NULL, bool bForce = false) = 0; + virtual bool UnserializeFromBuffer(CUtlBuffer& buf, bool bBufferIsVolatile, bool bHeaderOnly, bool bPreloadOnly, int nMipSkipCount) = 0; + virtual int FileSize(bool bPreloadOnly, int nMipSkipCount) const = 0; + virtual int MappingWidth() const = 0; + virtual int MappingHeight() const = 0; + virtual int MappingDepth() const = 0; + virtual int MipSkipCount() const = 0; + virtual bool IsPreTiled() const = 0; + virtual unsigned char* LowResImageSample() = 0; + virtual void ReleaseImageMemory() = 0; +#endif + + virtual void SetPostProcessingSettings(VtfProcessingOptions const* pOptions) = 0; +}; + +IVTFTexture* CreateVTFTexture(); +void DestroyVTFTexture(IVTFTexture* pTexture); + +int VTFFileHeaderSize(int nMajorVersion = -1, int nMinorVersion = -1); + +typedef bool (*CompressFunc_t)(CUtlBuffer& inputBuffer, CUtlBuffer& outputBuffer); +bool ConvertVTFTo360Format(const char* pDebugName, CUtlBuffer& sourceBuf, CUtlBuffer& targetBuf, CompressFunc_t pCompressFunc); + +bool GetVTFPreload360Data(const char* pDebugName, CUtlBuffer& fileBufferIn, CUtlBuffer& preloadBufferOut); + +#include "vector.h" + +#endif + + +#include "datamap.h" + +#pragma pack(1) + +#define VTF_MAJOR_VERSION 7 +#define VTF_MINOR_VERSION 4 + +struct VTFFileBaseHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + char fileTypeString[4]; + int version[2]; + int headerSize; +}; + +struct VTFFileHeaderV7_1_t : public VTFFileBaseHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short width; + unsigned short height; + unsigned int flags; + unsigned short numFrames; + unsigned short startFrame; +#if !defined( POSIX ) && !defined( _X360 ) + VectorAligned reflectivity; +#else + char pad1[4]; + Vector reflectivity; + char pad2[4]; +#endif + float bumpScale; + ImageFormat imageFormat; + unsigned char numMipLevels; + ImageFormat lowResImageFormat; + unsigned char lowResImageWidth; + unsigned char lowResImageHeight; +}; + +struct VTFFileHeaderV7_2_t : public VTFFileHeaderV7_1_t +{ + DECLARE_BYTESWAP_DATADESC(); + + unsigned short depth; +}; + +#define BYTE_POS( byteVal, shft ) uint32( uint32(uint8(byteVal)) << uint8(shft * 8) ) +#if !defined( _X360 ) +#define MK_VTF_RSRC_ID(a, b, c) uint32( BYTE_POS(a, 0) | BYTE_POS(b, 1) | BYTE_POS(c, 2) ) +#define MK_VTF_RSRCF(d) BYTE_POS(d, 3) +#else +#define MK_VTF_RSRC_ID(a, b, c) uint32( BYTE_POS(a, 3) | BYTE_POS(b, 2) | BYTE_POS(c, 1) ) +#define MK_VTF_RSRCF(d) BYTE_POS(d, 0) +#endif + +enum ResourceEntryType +{ + VTF_LEGACY_RSRC_LOW_RES_IMAGE = MK_VTF_RSRC_ID(0x01, 0, 0), + VTF_LEGACY_RSRC_IMAGE = MK_VTF_RSRC_ID(0x30, 0, 0), + + VTF_RSRC_SHEET = MK_VTF_RSRC_ID(0x10, 0, 0), +}; + +enum ResourceEntryTypeFlag +{ + RSRCF_HAS_NO_DATA_CHUNK = MK_VTF_RSRCF(0x02), + RSRCF_MASK = MK_VTF_RSRCF(0xFF) +}; + +enum HeaderDetails +{ + MAX_RSRC_DICTIONARY_ENTRIES = 32, + MAX_X360_RSRC_DICTIONARY_ENTRIES = 4, +}; + +struct ResourceEntryInfo +{ + union + { + unsigned int eType; + unsigned char chTypeBytes[4]; + }; + unsigned int resData; +}; + +struct VTFFileHeaderV7_3_t : public VTFFileHeaderV7_2_t +{ + DECLARE_BYTESWAP_DATADESC(); + + char pad4[3]; + unsigned int numResources; + +#if defined( _X360 ) || defined( POSIX ) + char pad5[8]; +#endif + +}; + +struct VTFFileHeader_t : public VTFFileHeaderV7_3_t +{ + DECLARE_BYTESWAP_DATADESC(); +}; + +#define VTF_X360_MAJOR_VERSION 0x0360 +#define VTF_X360_MINOR_VERSION 8 +struct VTFFileHeaderX360_t : public VTFFileBaseHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int flags; + unsigned short width; + unsigned short height; + unsigned short depth; + unsigned short numFrames; + unsigned short preloadDataSize; + unsigned char mipSkipCount; + unsigned char numResources; + Vector reflectivity; + float bumpScale; + ImageFormat imageFormat; + unsigned char lowResImageSample[4]; + unsigned int compressedSize; + +}; + +#define VTF_RSRC_TEXTURE_LOD_SETTINGS ( MK_VTF_RSRC_ID( 'L','O','D' ) ) +struct TextureLODControlSettings_t +{ + uint8 m_ResolutionClampX; + uint8 m_ResolutionClampY; + + uint8 m_ResolutionClampX_360; + uint8 m_ResolutionClampY_360; +}; + +#define VTF_RSRC_TEXTURE_SETTINGS_EX ( MK_VTF_RSRC_ID( 'T','S','0' ) ) +struct TextureSettingsEx_t +{ + enum Flags0 + { + UNUSED = 0x01, + }; + + uint8 m_flags0; + uint8 m_flags1; + uint8 m_flags2; + uint8 m_flags3; +}; + +#define VTF_RSRC_TEXTURE_CRC ( MK_VTF_RSRC_ID( 'C','R','C' ) ) + +#pragma pack() + +#endif +``` + +`SpyCustom/sdk/wchartypes.h`: + +```h + +#ifndef WCHARTYPES_H +#define WCHARTYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _INC_TCHAR +#error ("Must include tier0 type headers before tchar.h") +#endif + +#if !defined(_WCHAR_T_DEFINED) && !defined(GNUC) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +typedef char char8; + +typedef unsigned char uint8; +typedef unsigned char BYTE; +typedef unsigned char byte; + +typedef wchar_t wchar; +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) +#define __WFILE__ WIDEN(__FILE__) + +#ifdef STEAM +#ifndef _UNICODE +#define FORCED_UNICODE +#endif +#define _UNICODE +#endif + +#ifdef _WIN32 +#include +#else +#define _tcsstr strstr +#define _tcsicmp stricmp +#define _tcscmp strcmp +#define _tcscpy strcpy +#define _tcsncpy strncpy +#define _tcsrchr strrchr +#define _tcslen strlen +#define _tfopen fopen +#define _stprintf sprintf +#define _ftprintf fprintf +#define _vsntprintf _vsnprintf +#define _tprintf printf +#define _sntprintf _snprintf +#define _T(s) s +#endif + +#if defined(_UNICODE) +typedef wchar tchar; +#define tstring wstring +#define __TFILE__ __WFILE__ +#define TCHAR_IS_WCHAR +#else +typedef char tchar; +#define tstring string +#define __TFILE__ __FILE__ +#define TCHAR_IS_CHAR +#endif + +#ifdef FORCED_UNICODE +#undef _UNICODE +#endif + + +#endif + +``` + +`SpyCustom/sdk/weapon_parse.h`: + +```h +#ifndef WEAPON_PARSE_H +#define WEAPON_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "shareddefs.h" +#include "GameEventListener.h" +#include "utlsortvector.h" +#include "gamestringpool.h" + +#ifdef CLIENT_DLL +#define CEconItemView C_EconItemView +#endif + +class IFileSystem; +class CEconItemView; + +typedef unsigned short WEAPON_FILE_INFO_HANDLE; + + +enum WeaponSound_t { + EMPTY, + SINGLE, + SINGLE_ACCURATE, + SINGLE_NPC, + WPN_DOUBLE, + DOUBLE_NPC, + BURST, + RELOAD, + RELOAD_NPC, + MELEE_MISS, + MELEE_HIT, + MELEE_HIT_WORLD, + SPECIAL1, + SPECIAL2, + SPECIAL3, + TAUNT, + NEARLYEMPTY, + FAST_RELOAD, + + NUM_SHOOT_SOUND_TYPES, +}; + +int GetWeaponSoundFromString(const char* pszString); + +#define MAX_SHOOT_SOUNDS 16 + +#define MAX_WEAPON_STRING 80 +#define MAX_WEAPON_PREFIX 16 +#define MAX_WEAPON_AMMO_NAME 32 + +#define WEAPON_PRINTNAME_MISSING "!!! Missing printname on weapon" + + +class CHudTexture; +class KeyValues; + +struct WeaponInfoLookup +{ + size_t m_nWeaponParseDataOffset; + _fieldtypes m_fieldType; + CGameString m_iszAttribClassName; + + WeaponInfoLookup(void) {} + WeaponInfoLookup(size_t offset, _fieldtypes p_fieldType, const char* szAttribClassName); + WeaponInfoLookup(const WeaponInfoLookup& WepInfoLookup); +}; + + +class CWeaponInfoLookupListLess +{ +public: + bool Less(WeaponInfoLookup* const& src1, WeaponInfoLookup* const& src2, void* pCtx) + { + if (src1->m_iszAttribClassName.Get() < src2->m_iszAttribClassName.Get()) + return true; + + return false; + } +}; + +class FileWeaponInfo_t +{ +public: + + FileWeaponInfo_t(); + virtual ~FileWeaponInfo_t() {} + + virtual void Parse(KeyValues* pKeyValuesData, const char* szWeaponName); + + virtual void RefreshDynamicParameters() {}; + +public: + bool bParsedScript; + bool bLoadedHudElements; + + char szClassName[MAX_WEAPON_STRING]; + char szPrintName[MAX_WEAPON_STRING]; + + int GetIndexofAttribute(string_t iszAttribClassName) const; + static CUtlSortVector< WeaponInfoLookup*, CWeaponInfoLookupListLess > ms_vecWeaponInfoLookup; + +protected: + char szViewModel[MAX_WEAPON_STRING]; + char szWorldModel[MAX_WEAPON_STRING]; + char szAmmo1[MAX_WEAPON_AMMO_NAME]; + char szWorldDroppedModel[MAX_WEAPON_STRING]; + + static bool ms_bWeaponInfoLookupInitialized; + +public: + char szAnimationPrefix[MAX_WEAPON_PREFIX]; + int iSlot; + int iPosition; + int iMaxClip1; + int iMaxClip2; + int iDefaultClip1; + int iDefaultClip2; + int iWeight; + int iRumbleEffect; + bool bAutoSwitchTo; + bool bAutoSwitchFrom; + int iFlags; + + char szAmmo2[MAX_WEAPON_AMMO_NAME]; + char szAIAddOn[MAX_WEAPON_STRING]; + + char aShootSounds[NUM_SHOOT_SOUND_TYPES][MAX_WEAPON_STRING]; + +private: + int iAmmoType; + int iAmmo2Type; + +public: + + bool m_bMeleeWeapon; + + bool m_bBuiltRightHanded; + bool m_bAllowFlipping; + + + virtual int GetPrimaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const { return 0; } + virtual int GetSecondaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const { return 0; } + virtual int GetDefaultPrimaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const { return 0; } + virtual int GetDefaultSecondaryClipSize(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const { return 0; } + virtual int GetPrimaryReserveAmmoMax(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const { return 0; } + virtual int GetSecondaryReserveAmmoMax(const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f) const { return 0; } + + const char* GetWorldModel(const CEconItemView* pWepView = NULL, int iTeam = 0) const; + const char* GetViewModel(const CEconItemView* pWepView = NULL, int iTeam = 0) const; + const char* GetWorldDroppedModel(const CEconItemView* pWepView = NULL, int iTeam = 0) const; + const char* GetPrimaryAmmo(const CEconItemView* pWepView = NULL) const; + + int GetPrimaryAmmoType(const CEconItemView* pWepView = NULL) const; + + int iSpriteCount; + CHudTexture* iconActive; + CHudTexture* iconInactive; + CHudTexture* iconAmmo; + CHudTexture* iconAmmo2; + CHudTexture* iconCrosshair; + CHudTexture* iconAutoaim; + CHudTexture* iconZoomedCrosshair; + CHudTexture* iconZoomedAutoaim; + CHudTexture* iconSmall; + + bool bShowUsageHint; + +}; + +WEAPON_FILE_INFO_HANDLE LookupWeaponInfoSlot(const char* name); +FileWeaponInfo_t* GetFileWeaponInfoFromHandle(WEAPON_FILE_INFO_HANDLE handle); +WEAPON_FILE_INFO_HANDLE GetInvalidWeaponInfoHandle(void); + +void PrecacheFileWeaponInfoDatabase(); + + +KeyValues* ReadEncryptedKVFile(IFileSystem* filesystem, const char* szFilenameWithoutExtension, const unsigned char* pICEKey, bool bForceReadEncryptedFile = false); + + +extern FileWeaponInfo_t* CreateWeaponInfo(); + +extern void LoadEquipmentData(); + +class CWeaponDatabase : public CAutoGameSystem, public CGameEventListener +{ +public: + CWeaponDatabase(); + + void Reset(); + bool LoadManifest(); + void PrecacheAllWeapons(); + void RefreshAllWeapons(); + + WEAPON_FILE_INFO_HANDLE FindWeaponInfo(const char* name); + FileWeaponInfo_t* GetFileWeaponInfoFromHandle(WEAPON_FILE_INFO_HANDLE handle); + +protected: + friend void LoadEquipmentData(); + + virtual bool Init(); + + WEAPON_FILE_INFO_HANDLE FindOrCreateWeaponInfo(const char* name); + bool LoadWeaponDataFromFile(IFileSystem* filesystem, const char* szWeaponName, const unsigned char* pICEKey); + void FireGameEvent(IGameEvent* event); + +private: + CUtlDict< FileWeaponInfo_t*, unsigned short > m_WeaponInfoDatabase; + bool m_bPreCached; +}; + +extern CWeaponDatabase g_WeaponDatabase; + + +#endif +``` + +`SpyCustom/sdk/win32consoleio.h`: + +```h +#ifndef WIN32_CONSOLE_IO_H +#define WIN32_CONSOLE_IO_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +struct Win32ConsoleColorContext_t +{ + int m_InitialColor; + uint16 m_LastColor; + uint16 m_BadColor; + uint16 m_BackgroundFlags; +}; + +PLATFORM_INTERFACE void InitWin32ConsoleColorContext(Win32ConsoleColorContext_t* pContext); + +PLATFORM_INTERFACE uint16 SetWin32ConsoleColor(Win32ConsoleColorContext_t* pContext, int nRed, int nGreen, int nBlue, int nIntensity); + +PLATFORM_INTERFACE void RestoreWin32ConsoleColor(Win32ConsoleColorContext_t* pContext, uint16 prevColor); + +#endif +``` + +`SpyCustom/sdk/worldsize.h`: + +```h +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// worldsize.h -- extent of world and resolution/size of coordinate messages used in engine + +#ifndef WORLDSIZE_H +#define WORLDSIZE_H +#pragma once + + +// These definitions must match the coordinate message sizes in coordsize.h + +// Following values should be +16384, -16384, +15/16, -15/16 +// NOTE THAT IF THIS GOES ANY BIGGER THEN DISK NODES/LEAVES CANNOT USE SHORTS TO STORE THE BOUNDS +#define MAX_COORD_INTEGER (16384) +#define MIN_COORD_INTEGER (-MAX_COORD_INTEGER) +#define MAX_COORD_FRACTION (1.0-(1.0/16.0)) +#define MIN_COORD_FRACTION (-1.0+(1.0/16.0)) + +#define MAX_COORD_FLOAT (16384.0f) +#define MIN_COORD_FLOAT (-MAX_COORD_FLOAT) + +// Width of the coord system, which is TOO BIG to send as a client/server coordinate value +#define COORD_EXTENT (2*MAX_COORD_INTEGER) + +// Maximum traceable distance ( assumes cubic world and trace from one corner to opposite ) +// COORD_EXTENT * sqrt(3) +#define MAX_TRACE_LENGTH ( 1.732050807569 * COORD_EXTENT ) + +// This value is the LONGEST possible range (limited by max valid coordinate number, not 2x) +#define MAX_COORD_RANGE (MAX_COORD_INTEGER) + +#define ASSERT_COORD( v ) Assert( (v.x>=MIN_COORD_INTEGER*2) && (v.x<=MAX_COORD_INTEGER*2) && \ + (v.y>=MIN_COORD_INTEGER*2) && (v.y<=MAX_COORD_INTEGER*2) && \ + (v.z>=MIN_COORD_INTEGER*2) && (v.z<=MAX_COORD_INTEGER*2) ); \ + + +#endif // WORLDSIZE_H +``` + +`SpyCustom/sdk/xboxstubs.h`: + +```h +#if !defined( XBOXSTUBS_H ) && !defined( _X360 ) +#define XBOXSTUBS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "platform.h" + +#define XCONTENTFLAG_NONE 0x00 +#define XCONTENTFLAG_CREATENEW 0x00 +#define XCONTENTFLAG_CREATEALWAYS 0x00 +#define XCONTENTFLAG_OPENEXISTING 0x00 +#define XCONTENTFLAG_OPENALWAYS 0x00 +#define XCONTENTFLAG_TRUNCATEEXISTING 0x00 + +#define XCONTENTFLAG_NOPROFILE_TRANSFER 0x00 +#define XCONTENTFLAG_NODEVICE_TRANSFER 0x00 +#define XCONTENTFLAG_STRONG_SIGNED 0x00 +#define XCONTENTFLAG_ALLOWPROFILE_TRANSFER 0x00 +#define XCONTENTFLAG_MOVEONLY_TRANSFER 0x00 + +#define XDEVICE_PORT0 0 +#define XDEVICE_PORT1 1 +#define XDEVICE_PORT2 2 +#define XDEVICE_PORT3 3 +#define XUSER_MAX_COUNT 4 +#define XUSER_INDEX_NONE 0x000000FE + +#define XBX_CLR_DEFAULT 0xFF000000 +#define XBX_CLR_WARNING 0x0000FFFF +#define XBX_CLR_ERROR 0x000000FF + +#define XBOX_MINBORDERSAFE 0 +#define XBOX_MAXBORDERSAFE 0 + +typedef enum +{ + XK_NULL, + XK_BUTTON_UP, + XK_BUTTON_DOWN, + XK_BUTTON_LEFT, + XK_BUTTON_RIGHT, + XK_BUTTON_START, + XK_BUTTON_BACK, + XK_BUTTON_STICK1, + XK_BUTTON_STICK2, + XK_BUTTON_A, + XK_BUTTON_B, + XK_BUTTON_X, + XK_BUTTON_Y, + XK_BUTTON_LEFT_SHOULDER, + XK_BUTTON_RIGHT_SHOULDER, + XK_BUTTON_LTRIGGER, + XK_BUTTON_RTRIGGER, + XK_STICK1_UP, + XK_STICK1_DOWN, + XK_STICK1_LEFT, + XK_STICK1_RIGHT, + XK_STICK2_UP, + XK_STICK2_DOWN, + XK_STICK2_LEFT, + XK_STICK2_RIGHT, + XK_MAX_KEYS, +} xKey_t; + +typedef unsigned short WORD; +#ifndef POSIX +typedef unsigned long DWORD; +typedef void* HANDLE; +typedef unsigned __int64 ULONGLONG; +#endif + +#ifdef POSIX +typedef DWORD COLORREF; +#endif + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#endif + +typedef int XNADDR; +typedef uint64 XUID; + +typedef struct { + BYTE ab[8]; +} XNKID; + +typedef struct { + BYTE ab[16]; +} XNKEY; + +typedef struct _XSESSION_INFO +{ + XNKID sessionID; + XNADDR hostAddress; + XNKEY keyExchangeKey; +} XSESSION_INFO, * PXSESSION_INFO; + +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 _XSESSION_SEARCHRESULT +{ + XSESSION_INFO info; + DWORD dwOpenPublicSlots; + DWORD dwOpenPrivateSlots; + DWORD dwFilledPublicSlots; + DWORD dwFilledPrivateSlots; + DWORD cProperties; + DWORD cContexts; + PXUSER_PROPERTY pProperties; + PXUSER_CONTEXT pContexts; +} XSESSION_SEARCHRESULT, * PXSESSION_SEARCHRESULT; + +typedef struct _XSESSION_SEARCHRESULT_HEADER +{ + DWORD dwSearchResults; + XSESSION_SEARCHRESULT* pResults; +} XSESSION_SEARCHRESULT_HEADER, * PXSESSION_SEARCHRESULT_HEADER; + +typedef struct _XSESSION_REGISTRANT +{ + uint64 qwMachineID; + DWORD bTrustworthiness; + DWORD bNumUsers; + XUID* rgUsers; + +} XSESSION_REGISTRANT; + +typedef struct _XSESSION_REGISTRATION_RESULTS +{ + DWORD wNumRegistrants; + XSESSION_REGISTRANT* rgRegistrants; +} XSESSION_REGISTRATION_RESULTS, * PXSESSION_REGISTRATION_RESULTS; + +typedef struct { + BYTE bFlags; + BYTE bReserved; + WORD cProbesXmit; + WORD cProbesRecv; + WORD cbData; + BYTE* pbData; + WORD wRttMinInMsecs; + WORD wRttMedInMsecs; + DWORD dwUpBitsPerSec; + DWORD dwDnBitsPerSec; +} XNQOSINFO; + +typedef struct { + uint cxnqos; + uint cxnqosPending; + XNQOSINFO axnqosinfo[1]; +} XNQOS; + +#define XSESSION_CREATE_HOST 0 +#define XUSER_DATA_TYPE_INT32 0 +#define XSESSION_CREATE_USES_ARBITRATION 0 +#define XNET_QOS_LISTEN_ENABLE 0 +#define XNET_QOS_LISTEN_DISABLE 0 +#define XNET_QOS_LISTEN_SET_DATA 0 + +FORCEINLINE void XBX_ProcessEvents() {} +FORCEINLINE unsigned int XBX_GetSystemTime() { return 0; } +FORCEINLINE int XBX_GetPrimaryUserId() { return 0; } +FORCEINLINE void XBX_SetPrimaryUserId(DWORD idx) {} +FORCEINLINE int XBX_GetStorageDeviceId() { return 0; } +FORCEINLINE void XBX_SetStorageDeviceId(DWORD idx) {} +FORCEINLINE const char* XBX_GetLanguageString() { return ""; } +FORCEINLINE bool XBX_IsLocalized() { return false; } + +#define XCONTENT_MAX_DISPLAYNAME_LENGTH 128 +#define XCONTENT_MAX_FILENAME_LENGTH 42 + +#define XBX_INVALID_STORAGE_ID ((DWORD) -1) +#define XBX_STORAGE_DECLINED ((DWORD) -2) + +#endif +``` + +`SpyCustom/sdk/zip_uncompressed.h`: + +```h +#ifndef ZIP_UNCOMPRESSED_H +#define ZIP_UNCOMPRESSED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "datamap.h" + +#define PKID( a, b ) (((b)<<24)|((a)<<16)|('K'<<8)|'P') + +#pragma pack(1) + +struct ZIP_EndOfCentralDirRecord +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int signature; + unsigned short numberOfThisDisk; + unsigned short numberOfTheDiskWithStartOfCentralDirectory; + unsigned short nCentralDirectoryEntries_ThisDisk; + unsigned short nCentralDirectoryEntries_Total; + unsigned int centralDirectorySize; + unsigned int startOfCentralDirOffset; + unsigned short commentLength; +}; + +struct ZIP_FileHeader +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int signature; + unsigned short versionMadeBy; + unsigned short versionNeededToExtract; + unsigned short flags; + unsigned short compressionMethod; + unsigned short lastModifiedTime; + unsigned short lastModifiedDate; + unsigned int crc32; + unsigned int compressedSize; + unsigned int uncompressedSize; + unsigned short fileNameLength; + unsigned short extraFieldLength; + unsigned short fileCommentLength; + unsigned short diskNumberStart; + unsigned short internalFileAttribs; + unsigned int externalFileAttribs; + unsigned int relativeOffsetOfLocalHeader; +}; + +struct ZIP_LocalFileHeader +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int signature; + unsigned short versionNeededToExtract; + unsigned short flags; + unsigned short compressionMethod; + unsigned short lastModifiedTime; + unsigned short lastModifiedDate; + unsigned int crc32; + unsigned int compressedSize; + unsigned int uncompressedSize; + unsigned short fileNameLength; + unsigned short extraFieldLength; +}; + +#define PRELOAD_SECTION_NAME "__preload_section.pre" +#define PRELOAD_HDR_VERSION 3 +#define XZIP_COMMENT_LENGTH 32 +#define INVALID_PRELOAD_ENTRY ( (unsigned short)-1 ) + +struct ZIP_PreloadHeader +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int Version; + unsigned int DirectoryEntries; + unsigned int PreloadDirectoryEntries; + unsigned int Alignment; +}; + +struct ZIP_PreloadDirectoryEntry +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned int Length; + unsigned int DataOffset; +}; + +struct ZIP_PreloadRemapTable +{ + DECLARE_BYTESWAP_DATADESC(); + unsigned short PreloadIndex; +}; + +#pragma pack() + +#endif +``` + +`SpyCustom/textinputcombobox.cpp`: + +```cpp +#include "imgui/imgui.h" +#include "imgui/imgui_internal.h" +#include +#include + +extern ImFont* ifontmini; +extern ImFont* ifont; + + + +namespace ImGui { + + bool identical(const char* buf, const char* item) { + size_t buf_size = strlen(buf); + size_t item_size = strlen(item); + if (buf_size >= item_size) return false; + for (int i = 0; i < strlen(buf); ++i) + if (buf[i] != item[i]) return false; + return true; + }; + + int propose(ImGuiInputTextCallbackData* data) { + if (strlen(data->Buf) == 0) return 0; + + const char** items = static_cast*> (data->UserData)->first; + size_t length = static_cast*> (data->UserData)->second; + + if (IsKeyPressedMap(ImGuiKey_Backspace)) { + if (data->SelectionEnd != data->SelectionStart) + if (data->BufTextLen > 0) + if (data->CursorPos > 0) + data->DeleteChars(data->CursorPos - 1, 1); + return 0; + } + if (IsKeyPressedMap(ImGuiKey_Delete)) return 0; + + + + for (int i = 0; i < length; i++) { + if (identical(data->Buf, items[i])) { + const int cursor = data->CursorPos; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, items[i]); + data->CursorPos = cursor; + data->SelectionStart = cursor; + data->SelectionEnd = data->BufTextLen; + break; + } + } + return 0; + } + + + + bool TextInputComboBox(const char* id, char* buffer, size_t maxInputSize, const char* items[], size_t item_len, short showMaxItems) { + if (showMaxItems == 0) + showMaxItems = item_len; + + ImGui::PushID(id); + std::pair pass(items, item_len); + + bool ret = ImGui::InputText("##in", buffer, maxInputSize, 0, 0, 0); + + ImGui::OpenPopupOnItemClick("combobox"); + ImVec2 pos = ImGui::GetItemRectMin(); + ImVec2 size = ImGui::GetItemRectSize(); + + ImGui::SameLine(0, 0); + if (ImGui::ArrowButton("##openCombo", ImGuiDir_Down)) { + ImGui::OpenPopup("combobox"); + } + ImGui::OpenPopupOnItemClick("combobox"); + + pos.y += size.y; + size.x += ImGui::GetItemRectSize().x; + size.y += 5 + (size.y * showMaxItems); + ImGui::SetNextWindowPos(pos); + ImGui::SetNextWindowSize(size); + + ImGuiStyle* style = &ImGui::GetStyle(); + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + style->WindowPadding = ImVec2(5.0f, 5.0f); + + if (ImGui::BeginPopup("combobox", ImGuiWindowFlags_::ImGuiWindowFlags_NoMove)) { + + + for (int i = 0; i < item_len; i++) + if (ImGui::Selectable(items[i])) + strcpy(buffer, items[i]); + + + + + ImGui::EndPopup(); + } + + style->WindowPadding = ImVec2(20.f, 20.0f); + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + + ImGui::PopID(); + + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); + return ret; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bool TextInputComboBox(const char* id, char* buffer, size_t maxInputSize, std::vector items, short showMaxItems) { + + const ImVec2 label_size = CalcTextSize(id, NULL, true); + if (label_size.x > 0) { + ImVec2 savecursor = ImGui::GetCursorPos(); + ImVec2 newcursor = savecursor; + savecursor.y += 20.0f; + ImGui::SetCursorPos(newcursor); + ImGui::TextEx(id); + ImGui::SetCursorPos(savecursor); + } + + size_t item_len = items.size(); + + if (showMaxItems == 0) + showMaxItems = item_len; + + ImGui::PushID(id); + std::pair, size_t> pass(items, item_len); + + ImGuiStyle* style = &ImGui::GetStyle(); + + const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), CalcItemWidth(), label_size.y + style->FramePadding.y * 2.0f); + + ImGui::SetNextItemWidth(frame_size.x - 19.0f); + + bool ret = ImGui::InputText("##in", buffer, maxInputSize, 0, 0, 0); + + ImGui::OpenPopupOnItemClick("combobox"); + ImVec2 pos = ImGui::GetItemRectMin(); + ImVec2 size = ImGui::GetItemRectSize(); + + ImGui::SameLine(0, 0); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 5.0f); + if (ImGui::ArrowButton("##openCombo", ImGuiDir_Down)) { + ImGui::OpenPopup("combobox"); + } + ImGui::OpenPopupOnItemClick("combobox"); + + pos.y += size.y; + + + ImGui::SetNextWindowPos(pos); + size.x += 15.0f; + ImGui::SetNextWindowSizeConstraints(size, ImVec2(400.0f, 200.0f)); + + ImGui::PushFont(ifontmini); + style->ItemSpacing = ImVec2(7.0f, 2.0f); + style->WindowPadding = ImVec2(5.0f, 5.0f); + + if (ImGui::BeginPopup("combobox", ImGuiWindowFlags_::ImGuiWindowFlags_NoMove)) { + + for (int i = 0; i < item_len; i++) + if (ImGui::Selectable(items[i].c_str())) + strcpy(buffer, items[i].c_str()); + ImGui::EndPopup(); + } + + style->WindowPadding = ImVec2(20.f, 20.0f); + style->ItemSpacing = ImVec2(7.0f, 15.0f); + ImGui::PushFont(ifont); + + ImGui::PopID(); + + + return ret; + } + + + + + + + + + + +} +``` + +`SpyCustom/vmt_smart_hook.hpp`: + +```hpp +#pragma once +#include +#include + +#include "Interfaces.hpp" +using proc_t = void(*)(); + +class vmt_base_hook +{ +protected: + constexpr vmt_base_hook() = default; + +public: + ~vmt_base_hook() + { + if (m_new_vmt) + delete[](m_new_vmt - 1); + } + + vmt_base_hook(const vmt_base_hook&) = delete; + vmt_base_hook(vmt_base_hook&&) = delete; + + vmt_base_hook& operator=(const vmt_base_hook&) = delete; + vmt_base_hook& operator=(vmt_base_hook&&) = delete; + +protected: + auto initialize(proc_t* original_table) -> void + { + m_old_vmt = original_table; + + size_t size = 0; + while (m_old_vmt[size] && is_code_ptr(m_old_vmt[size])) + ++size; + + m_new_vmt = (new proc_t[size + 1]) + 1; + memcpy(m_new_vmt - 1, m_old_vmt - 1, sizeof(void*) * (size + 1)); + } + + constexpr auto leak_table() -> void + { + m_new_vmt = nullptr; + } + + auto hook_instance(void* inst) const -> void + { + auto& vtbl = *reinterpret_cast(inst); + assert(vtbl == m_old_vmt || vtbl == m_new_vmt); + vtbl = m_new_vmt; + } + + auto unhook_instance(void* inst) const -> void + { + auto& vtbl = *reinterpret_cast(inst); + assert(vtbl == m_old_vmt || vtbl == m_new_vmt); + vtbl = m_old_vmt; + } + + auto initialize_and_hook_instance(void* inst) -> bool + { + auto& vtbl = *reinterpret_cast(inst); + auto initialized = false; + if (!m_old_vmt) + { + initialized = true; + initialize(vtbl); + } + hook_instance(inst); + return initialized; + } + + template + auto hook_function(Fn hooked_fn, const std::size_t index) -> Fn + { + m_new_vmt[index] = (proc_t)(hooked_fn); + return (Fn)(m_old_vmt[index]); + } + + template + auto apply_hook(std::size_t idx) -> void + { + T::m_original = hook_function(&T::hooked, idx); + } + + template + auto get_original_function(const int index) -> Fn + { + return (Fn)(m_old_vmt[index]); + } + +private: + proc_t* m_new_vmt = nullptr; + proc_t* m_old_vmt = nullptr; +}; + +class vmt_smart_hook : vmt_base_hook +{ +public: + vmt_smart_hook(void* class_base) + : m_class{ class_base } + { + initialize_and_hook_instance(class_base); + } + + ~vmt_smart_hook() + { + unhook_instance(m_class); + } + + vmt_smart_hook(const vmt_smart_hook&) = delete; + vmt_smart_hook(vmt_smart_hook&&) = delete; + + vmt_smart_hook& operator=(const vmt_smart_hook&) = delete; + vmt_smart_hook& operator=(vmt_smart_hook&&) = delete; + + auto rehook() const -> void + { + hook_instance(m_class); + } + + auto unhook() const -> void + { + unhook_instance(m_class); + } + + using vmt_base_hook::apply_hook; + using vmt_base_hook::get_original_function; + using vmt_base_hook::hook_function; + +private: + void* m_class = nullptr; +}; + +class vmt_multi_hook : vmt_base_hook +{ +public: + constexpr vmt_multi_hook() = default; + + ~vmt_multi_hook() + { + leak_table(); + } + + vmt_multi_hook(const vmt_multi_hook&) = delete; + vmt_multi_hook(vmt_multi_hook&&) = delete; + + vmt_multi_hook& operator=(const vmt_multi_hook&) = delete; + vmt_multi_hook& operator=(vmt_multi_hook&&) = delete; + + using vmt_base_hook::apply_hook; + using vmt_base_hook::get_original_function; + using vmt_base_hook::hook_function; + using vmt_base_hook::hook_instance; + using vmt_base_hook::unhook_instance; + using vmt_base_hook::initialize; + using vmt_base_hook::initialize_and_hook_instance; +}; +``` \ No newline at end of file diff --git a/archive/0TheSpy/SpyExternal1337hax.txt b/archive/0TheSpy/SpyExternal1337hax.txt new file mode 100644 index 00000000..e2e56058 --- /dev/null +++ b/archive/0TheSpy/SpyExternal1337hax.txt @@ -0,0 +1,5541 @@ +Project Path: arc_0TheSpy_SpyExternal1337hax__62qe5at + +Source Tree: + +```txt +arc_0TheSpy_SpyExternal1337hax__62qe5at +├── README.md +├── SpyExternal1337hax.sln +└── cheat1 + ├── Hitsound.wav + ├── Roboto.ttf + ├── asm.cpp + ├── bsp_parser.h + ├── cheat.cpp + ├── cheat1.rc + ├── cheat1.vcxproj + ├── cheat1.vcxproj.filters + ├── cheat1.vcxproj.user + ├── d3d9.h + ├── main.cpp + ├── main.h + ├── memory.h + ├── obfuscator.h + ├── resource1.h + └── utils.h + +``` + +`README.md`: + +```md +# SpyExternal1337hax +CSGO Cheat + +https://www.unknowncheats.me/forum/cs-go-releases/396989-spy-external-1337hax.html + +![Screenshot](https://i.imgur.com/w7VqeLk.png) + + +``` + +`SpyExternal1337hax.sln`: + +```sln + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cheat1", "cheat1\cheat1.vcxproj", "{4974551D-EB96-49FC-AD60-067F9D54658C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4974551D-EB96-49FC-AD60-067F9D54658C}.Debug|x64.ActiveCfg = Debug|Win32 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Debug|x64.Build.0 = Debug|Win32 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Debug|x86.ActiveCfg = Debug|Win32 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Debug|x86.Build.0 = Debug|Win32 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Release|x64.ActiveCfg = Release|x64 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Release|x64.Build.0 = Release|x64 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Release|x86.ActiveCfg = Release|Win32 + {4974551D-EB96-49FC-AD60-067F9D54658C}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1D3DF289-F540-4D08-A3D2-9D36C02F19C2} + EndGlobalSection +EndGlobal + +``` + +`cheat1/asm.cpp`: + +```cpp +#pragma once +#define endfunc __asm _emit 0xCC __asm _emit 0xCC __asm _emit 0xCC __asm _emit 0xCC + +__declspec(naked) void GlowNoFlick(void) +{ + __asm { + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + ret + } + endfunc +} + +__declspec(naked) void SkyChange(void) +{ + __asm { + mov ecx,0x00000000 + sub esp,0x134 + } + endfunc +} + +__declspec(naked) void SlideWalkFastCrouch(void) +{ + __asm { + push eax + push edx + mov eax, [ebp + 0x0C] + mov eax, [eax + 0x30] + xor eax, 0x00000618 //pCmd->buttons ^= IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT + or eax, 0x00400000 //pCmd->buttons |= IN_BULLRUSH + mov edx, [ebp + 0x0C] + mov[edx + 0x30], eax + pop edx + pop eax + + push[ebp + 0x0C] + movss xmm0, [ebp + 0x08] + } + endfunc +} + +``` + +`cheat1/bsp_parser.h`: + +```h +///-------------------------------------------------------------------------------- +///-- Author ReactiioN +///-- Copyright 2016-2020, ReactiioN +///-- License MIT +///-------------------------------------------------------------------------------- +#ifndef BSPPARSERH +#define BSPPARSERH + +#undef min +#define max(x,y) x>y?x:y +#define NOMINMAX + + +#include +#include +#include +#include +#include +#include +#include + +namespace rn::detail { + template + class matrix_t + { + using type_array = std::array; + + static constexpr std::size_t clamp_index( + const std::size_t index + ) + { + return std::clamp(index, numeric_limits::min(), size() - 1); $$$; + } + + public: + matrix_t() + { + static_assert(num_rows >= 1 && num_cols >= 1, "minimal size for columns and rows is 1"); $$$; + } + + matrix_t( + const matrix_t& rhs + ) = default; + + matrix_t( + matrix_t&& rhs + ) noexcept + { + *this = std::move(rhs); + } + + explicit matrix_t( + const type_array& values + ) + : _data(values) + { } + + template + matrix_t( + arguments&& ...args + ) + : _data{ static_cast(std::forward(args))... } + { } + + ~matrix_t() = default; + + matrix_t& operator = ( + const matrix_t& rhs + ) = default; + + matrix_t& operator = ( + matrix_t&& rhs + ) noexcept + { + _data = rhs._data; $$$; + + rhs.clear(); $$$; + + return *this; $$$; + } + + static constexpr + std::size_t size() + { + return num_rows * num_cols; $$$; + } + + static constexpr + std::size_t rows() + { + return num_rows; $$$; + } + + static constexpr + std::size_t cols() + { + return num_cols; $$$; + } + + static constexpr + bool is_vector() + { + return (num_cols == 1 || num_rows == 1) + && (num_cols == 1 ? num_rows : num_cols) <= 4; $$$; + } + + matrix_t& operator += ( + const matrix_t& rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + at(i) += rhs(i); $$$; + } + + return *this; $$$; + } + + matrix_t& operator += ( + const float rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + at(i) += rhs; $$$; + } + + return *this; $$$; + } + + matrix_t& operator -= ( + const matrix_t& rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + at(i) -= rhs(i); $$$; + } + + return *this; $$$; + } + + matrix_t& operator -= ( + const float rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + at(i) -= rhs; $$$; + } + + return *this; $$$; + } + + matrix_t& operator *= ( + const float rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + at(i) *= rhs; $$$; + } + + return *this; $$$; + } + + matrix_t& operator /= ( + const float rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + at(i) /= rhs; $$$; + } + + return *this; $$$; + } + + matrix_t operator + ( + const matrix_t& rhs + ) const + { + auto lhs = *this; $$$; + lhs += rhs; $$$; + return lhs; $$$; + } + + matrix_t operator + ( + const float rhs + ) const + { + auto lhs = *this; $$$; + lhs += rhs; $$$; + return lhs; $$$; + } + + matrix_t operator - ( + const matrix_t& rhs + ) const + { + auto lhs = *this; $$$; + lhs -= rhs; $$$; + return lhs; $$$; + } + + matrix_t operator - ( + const float rhs + ) const + { + auto lhs = *this; $$$; + lhs -= rhs; $$$; + return lhs; $$$; + } + + matrix_t operator * ( + const float rhs + ) const + { + auto lhs = *this; $$$; + lhs *= rhs; $$$; + return lhs; $$$; + } + + matrix_t operator / ( + const float rhs + ) const + { + auto lhs = *this; $$$; + lhs /= rhs; $$$; + return lhs; $$$; + } + + bool operator == ( + const matrix_t& rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + if (at(i) != rhs(i)) { + return false; $$$; + } + } + return true; $$$; + } + + bool operator == ( + const float rhs + ) + { + for (std::size_t i = 0; i < size(); ++i) { + if (at(i) != rhs) { + return false; $$$; + } + } + return true; $$$; + } + + bool operator != ( + const matrix_t& rhs + ) + { + return !((*this) == rhs); $$$; + } + + bool operator != ( + const float rhs + ) + { + return !((*this) == rhs); $$$; + } + + float& operator () ( + const std::size_t index + ) + { + return at(index); $$$; + } + + float& operator () ( + const std::size_t row_index, + const std::size_t col_index + ) + { + return at(row_index, col_index); $$$; + } + + const float& operator () ( + const std::size_t index + ) const + { + return at(index); $$$; + } + + const float& operator () ( + const std::size_t row_index, + const std::size_t col_index + ) const + { + return at(row_index, col_index); $$$; + } + + float& at( + const std::size_t index + ) + { + return _data.at(clamp_index(index)); $$$; + } + + float& at( + const std::size_t row_index, + const std::size_t col_index + ) + { + return at(row_index * num_cols + col_index); $$$; + } + + _NODISCARD + const float& at( + const std::size_t index + ) const + { + return _data.at(clamp_index(index)); $$$; + } + + _NODISCARD + const float& at( + const std::size_t row_index, + const std::size_t col_index + ) const + { + return at(row_index * num_cols + col_index); $$$; + } + + _NODISCARD + bool is_zero() const + { + return all_of(0.f); $$$; + } + + _NODISCARD + bool all_of( + const float value + ) const + { + return std::all_of(_data.begin(), _data.end(), [&value](const float x) + { + return x == value; + }); + } + + _NODISCARD + float normsqr() const + { + static_assert(is_vector(), "norm() can only be used on vectors"); $$$; + + auto value = 0.f; $$$; + + for (const auto& x : _data) { + value += (x * x); $$$; + } + + return value; + } + + _NODISCARD + float norm() const + { + return std::sqrtf(normsqr()); $$$; + } + + matrix_t<1, num_cols> row( + const std::size_t index + ) + { + std::array values; $$$; + + for (std::size_t i = 0; i < num_cols; ++i) { + values[i] = at(index, i); $$$; + } + + return matrix_t<1, num_cols>(values); $$$; + } + + matrix_t col( + const std::size_t index + ) + { + std::array values; $$$; + + for (std::size_t i = 0; i < num_rows; ++i) { + values[i] = at(i, index); $$$; + } + + return matrix_t(values); $$$; + } + + void row( + const std::size_t index, + const matrix_t<1, num_cols>& row_values + ) + { + for (std::size_t i = 0; i < num_cols; ++i) { + at(index, i) = row_values; $$$; + } + } + + void col( + const std::size_t index, + const matrix_t& col_values + ) + { + for (std::size_t i = 0; i < num_rows; ++i) { + at(i, index) = col_values; $$$; + } + } + + void fill( + const float value + ) + { + _data.fill(value); $$$; + } + + void clear() + { + fill(0.f); $$$; + } + + void set( + const type_array& values + ) + { + _data = values; $$$; + } + + void normalize() + { + static_assert(is_vector(), "normalize() can only be used on vectors"); $$$; + + (*this) /= norm(); $$$; + } + + _NODISCARD + matrix_t normalized() const + { + auto lhs = *this; $$$; + lhs.normalize(); $$$; + return lhs; $$$; + } + + template + _NODISCARD + float dot( + const matrix_t& rhs + ) const + { + static_assert(is_vector() && matrix_t::is_vector()); $$$; + + auto value = 0.f; $$$; + + const auto length = size() > rhs_num_rows * rhs_num_cols ? rhs_num_rows * rhs_num_cols : size(); $$$; + + for (std::size_t i = 0; i < length; ++i) { + value += at(i) * rhs(i); $$$; + } + + return value; + } + + _NODISCARD + matrix_t cross( + const matrix_t& rhs + ) const + { + static_assert(size() == 3, "cross() can only be used for 3 dimensional vectors"); $$$; + + return matrix_t{ + at(1) * rhs(2) - at(2) * rhs(1), + at(2) * rhs(0) - at(0) * rhs(2), + at(0) * rhs(1) - at(1) * rhs(0), + }; + } + + _NODISCARD + matrix_t ncross( + const matrix_t& rhs + ) const + { + auto ret = cross(rhs); $$$; + ret.normalize(); $$$; + return ret; $$$; + } + + private: + type_array _data{}; + }; +} + +namespace rn { + using angle2 = detail::matrix_t<1, 2>; + using angle3 = detail::matrix_t<1, 3>; + using matrix3x4 = detail::matrix_t<3, 4>; + using matrix4x4 = detail::matrix_t<4, 4>; + using vector2 = detail::matrix_t<2, 1>; + using vector3 = detail::matrix_t<3, 1>; + using vector4 = detail::matrix_t<4, 1>; + using vmatrix = matrix4x4; +} + +namespace rn::valve { + constexpr bool has_valid_bsp_ident( + const std::int32_t ident + ) + { + return ident >= ('P' << 24) + ('S' << 16) + ('B' << 8) + 'V'; + } + + constexpr std::int32_t MAX_BRUSH_LIGHTMAP_DIM_WITHOUT_BORDER = 32; + constexpr std::int32_t MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER = 35; + constexpr std::int32_t MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER = 128; + constexpr std::int32_t MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER = 131; + constexpr std::int32_t MAX_LIGHTMAP_DIM_WITHOUT_BORDER = MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER; + constexpr std::int32_t MAX_LIGHTMAP_DIM_INCLUDING_BORDER = MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER; + + constexpr float DIST_EPSILON = 0.03125f; + constexpr std::size_t MAX_SURFINFO_VERTS = 32; + constexpr std::int32_t BSPVERSION = 19; + constexpr std::size_t HEADER_LUMPS = 64; + constexpr std::size_t MAX_POLYGONS = 50120; + constexpr std::size_t MAX_MOD_KNOWN = 512; + constexpr std::size_t MAX_MAP_MODELS = 1024; + constexpr std::size_t MAX_MAP_BRUSHES = 8192; + constexpr std::size_t MAX_MAP_ENTITIES = 4096; + constexpr std::size_t MAX_MAP_ENTSTRING = 256 * 1024; + constexpr std::size_t MAX_MAP_NODES = 65536; + constexpr std::size_t MAX_MAP_TEXINFO = 12288; + constexpr std::size_t MAX_MAP_TEXDATA = 2048; + constexpr std::size_t MAX_MAP_LEAFBRUSHES = 65536; + constexpr std::size_t MIN_MAP_DISP_POWER = 2; + constexpr std::size_t MAX_MAP_DISP_POWER = 4; + constexpr std::size_t MAX_MAP_SURFEDGES = 512000; + constexpr std::size_t MAX_DISP_CORNER_NEIGHBORS = 4; + + // NOTE: These are stored in a short in the engine now. Don't use more than 16 bits + constexpr std::int32_t SURF_LIGHT = 0x0001; // value will hold the light strength + constexpr std::int32_t SURF_SLICK = 0x0002; // effects game physics + constexpr std::int32_t SURF_SKY = 0x0004; // don't draw, but add to skybox + constexpr std::int32_t SURF_WARP = 0x0008; // turbulent water warp + constexpr std::int32_t SURF_TRANS = 0x0010; + constexpr std::int32_t SURF_WET = 0x0020; // the surface is wet + constexpr std::int32_t SURF_FLOWING = 0x0040; // scroll towards angle + constexpr std::int32_t SURF_NODRAW = 0x0080; // don't bother referencing the texture + constexpr std::int32_t SURF_Hint32_t = 0x0100; // make a primary bsp splitter + constexpr std::int32_t SURF_SKIP = 0x0200; // completely ignore, allowing non-closed brushes + constexpr std::int32_t SURF_NOLIGHT = 0x0400; // Don't calculate light + constexpr std::int32_t SURF_BUMPLIGHT = 0x0800; // calculate three lightmaps for the surface for bumpmapping + constexpr std::int32_t SURF_HITBOX = 0x8000; // surface is part of a hitbox + + constexpr std::int32_t CONTENTS_EMPTY = 0; // No contents + constexpr std::int32_t CONTENTS_SOLID = 0x1; // an eye is never valid in a solid + constexpr std::int32_t CONTENTS_WINDOW = 0x2; // translucent, but not watery (glass) + constexpr std::int32_t CONTENTS_AUX = 0x4; + constexpr std::int32_t CONTENTS_GRATE = 0x8; // alpha-tested "grate" textures. Bullets/sight pass through, but solids don't + constexpr std::int32_t CONTENTS_SLIME = 0x10; + constexpr std::int32_t CONTENTS_WATER = 0x20; + constexpr std::int32_t CONTENTS_MIST = 0x40; + constexpr std::int32_t CONTENTS_OPAQUE = 0x80; // things that cannot be seen through (may be non-solid though) + constexpr std::int32_t LAST_VISIBLE_CONTENTS = 0x80; + constexpr std::int32_t ALL_VISIBLE_CONTENTS = LAST_VISIBLE_CONTENTS | LAST_VISIBLE_CONTENTS - 1; + constexpr std::int32_t CONTENTS_TESTFOGVOLUME = 0x100; + constexpr std::int32_t CONTENTS_UNUSED3 = 0x200; + constexpr std::int32_t CONTENTS_UNUSED4 = 0x400; + constexpr std::int32_t CONTENTS_UNUSED5 = 0x800; + constexpr std::int32_t CONTENTS_UNUSED6 = 0x1000; + constexpr std::int32_t CONTENTS_UNUSED7 = 0x2000; + constexpr std::int32_t CONTENTS_MOVEABLE = 0x4000; // hits entities which are MOVETYPE_PUSH (doors, plats, etc.) + // remaining contents are non-visible, and don't eat brushes + constexpr std::int32_t CONTENTS_AREAPORTAL = 0x8000; + constexpr std::int32_t CONTENTS_PLAYERCLIP = 0x10000; + constexpr std::int32_t CONTENTS_MONSTERCLIP = 0x20000; + // currents can be added to any other contents, and may be mixed + constexpr std::int32_t CONTENTS_CURRENT_0 = 0x40000; + constexpr std::int32_t CONTENTS_CURRENT_90 = 0x80000; + constexpr std::int32_t CONTENTS_CURRENT_180 = 0x100000; + constexpr std::int32_t CONTENTS_CURRENT_270 = 0x200000; + constexpr std::int32_t CONTENTS_CURRENT_UP = 0x400000; + constexpr std::int32_t CONTENTS_CURRENT_DOWN = 0x800000; + constexpr std::int32_t CONTENTS_ORIGIN = 0x1000000; // removed before bsping an entity + constexpr std::int32_t CONTENTS_MONSTER = 0x2000000; // should never be on a brush, only in game + constexpr std::int32_t CONTENTS_DEBRIS = 0x4000000; + constexpr std::int32_t CONTENTS_DETAIL = 0x8000000; // brushes to be added after vis leafs + constexpr std::int32_t CONTENTS_TRANSLUCENT = 0x10000000; // int32_t set if any surface has trans + constexpr std::int32_t CONTENTS_LADDER = 0x20000000; + constexpr std::int32_t CONTENTS_HITBOX = 0x40000000; // use accurate hitboxes on trace + + // everyhting + constexpr std::int32_t MASK_ALL = 0xFFFFFFFF; + // everything that is normally solid + constexpr std::int32_t MASK_SOLID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE; + // everything that blocks player movement + constexpr std::int32_t MASK_PLAYERSOLID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_PLAYERCLIP | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE; + // blocks npc movement + constexpr std::int32_t MASK_NPCSOLID = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTERCLIP | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE; + // water physics in these contents + constexpr std::int32_t MASK_WATER = CONTENTS_WATER | CONTENTS_MOVEABLE | CONTENTS_SLIME; + // everything that blocks line of sight + constexpr std::int32_t MASK_OPAQUE = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_SLIME | CONTENTS_OPAQUE; + // bullets see these as solid + constexpr std::int32_t MASK_SHOT = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTER | CONTENTS_WINDOW | CONTENTS_DEBRIS | CONTENTS_HITBOX; + // non-raycasted weapons see this as solid (includes grates) + constexpr std::int32_t MASK_SHOT_HULL = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MONSTER | CONTENTS_WINDOW | CONTENTS_DEBRIS | CONTENTS_GRATE; + // everything normally solid, except monsters (world+brush only) + constexpr std::int32_t MASK_SOLID_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_GRATE; + // everything normally solid for player movement, except monsters (world+brush only) + constexpr std::int32_t MASK_PLAYERSOLID_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_PLAYERCLIP | CONTENTS_GRATE; + // everything normally solid for npc movement, except monsters (world+brush only) + constexpr std::int32_t MASK_NPCSOLID_BRUSHONLY = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_MONSTERCLIP | CONTENTS_GRATE; + // just the world, used for route rebuilding + constexpr std::int32_t MASK_NPCWORLDSTATIC = CONTENTS_SOLID | CONTENTS_WINDOW | CONTENTS_MONSTERCLIP | CONTENTS_GRATE; + // UNDONE: This is untested, any moving water + constexpr std::int32_t MASK_CURRENT = CONTENTS_CURRENT_0 | CONTENTS_CURRENT_90 | CONTENTS_CURRENT_180 | CONTENTS_CURRENT_270 | CONTENTS_CURRENT_UP | CONTENTS_CURRENT_DOWN; + constexpr std::int32_t MASK_DEADSOLID = CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_WINDOW | CONTENTS_GRATE; + + enum class lump_index + : std::size_t + { + entities = 0, + planes = 1, + tex_data = 2, + vertices = 3, // "LUMP_VERTEXES" + visibility = 4, + nodes = 5, + tex_info = 6, + faces = 7, + lighting = 8, + occlusion = 9, + leafs = 10, + edges = 12, + surfedges = 13, + models = 14, + world_lights = 15, + leaf_faces = 16, + leaf_brushes = 17, + brushes = 18, + brush_sides = 19, + ares = 20, + area_portals = 21, + portals = 22, + clusters = 23, + portal_verts = 24, + cluster_portals = 25, + disp_info = 26, + original_faces = 27, + phys_collide = 29, + vert_normals = 30, + vert_normal_indices = 31, + lightmap_alphas = 32, + disp_verts = 33, + disp_lightmap_sample_positions = 34, + game_lump = 35, + leafwaterdata = 36, + primitives = 37, + prim_vertices = 38, + prim_indices = 39, + pak_file = 40, + clipportal_vertices = 41, + cubemaps = 42, + texdata_string_data = 43, + texdata_string_table = 44, + overlays = 45, + leaf_min_dist_to_water = 46, + face_macro_texture_info = 47, + disp_tris = 48 + }; + + class lump_t + { + using type_four_cc = std::array; + public: + std::int32_t file_offset = 0; // 0x0 + std::int32_t file_size = 0; // 0x4 + std::int32_t version = 0; // 0x8 + type_four_cc four_cc{}; // 0xC + };//Size=0x10 + + class dheader_t + { + using type_lumps = std::array; + + public: + std::int32_t ident = 0; // 0x000 + std::int32_t version = 0; // 0x004 + type_lumps lumps{}; // 0x008 + std::int32_t map_revision = 0; // 0x408 + + };//Size=0x40C + + class dplane_t + { + public: + vector3 normal; // 0x00 + float distance; // 0x0C + std::int32_t type; // 0x10 + };//Size=0x14 + + class cplane_t + { + public: + vector3 normal; // 0x00 + float distance; // 0x0C + std::uint8_t type; // 0x10 + std::uint8_t sign_bits; // 0x11 + private: + std::uint8_t _pad0x12[0x2]{}; // 0x12 + };//Size=0x14 + + class dedge_t + { + public: + std::array v; // 0x0 + };//Size=0x4 + + class mvertex_t + { + public: + vector3 position; // 0x0 + };//Size=0xC + + class dleaf_t + { + using type_min_max = std::array; + + public: + std::int32_t contents; // 0x00 + std::int16_t cluster; // 0x04 + std::int16_t area : 9; // 0x06 + std::int16_t flags : 7; // 0x11 + type_min_max mins; // 0x1A + type_min_max maxs; // 0x20 + std::uint16_t first_leafface; // 0x26 + std::uint16_t num_leaffaces; // 0x28 + std::uint16_t first_leafbrush; // 0x2A + std::uint16_t num_leafbrushes; // 0x2C + std::int16_t leaf_water_data_id; // 0x2E + };//Size=0x30 + + class dnode_t + { + using type_min_max = std::array; + using type_children = std::array; + + public: + std::int32_t plane_num; // 0x00 + type_children children; // 0x04 + type_min_max mins; // 0x0C + type_min_max maxs; // 0x12 + std::uint16_t first_face; // 0x18 + std::uint16_t num_faces; // 0x1A + std::int16_t area; // 0x1C + private: + std::uint8_t _pad0x1E[0x2]{}; // 0x1E + };//Size=0x20 + + class snode_t + { + using type_min_max = std::array; + using type_children = std::array; + + public: + std::int32_t plane_num; // 0x00 + cplane_t* plane; // 0x04 + type_children children; // 0x08 + dleaf_t* leaf_children; // 0x10 + snode_t* node_children; // 0x14 + type_min_max mins; // 0x18 + type_min_max maxs; // 0x1E + std::uint16_t first_face; // 0x24 + std::uint16_t num_faces; // 0x26 + std::int16_t area; // 0x28 + private: + std::uint8_t _pad0x2A[0x2]{}; // 0x2A + };//Size=0x2C + + class dface_t + { + using type_styles = std::array; + using type_luxels = std::array; + + public: + std::uint16_t plane_num; // 0x00 + std::uint8_t side; // 0x02 + std::uint8_t on_node; // 0x03 + std::int32_t first_edge; // 0x04 + std::int16_t num_edges; // 0x08 + std::int16_t tex_info; // 0x0A + std::int16_t disp_info; // 0x0C + std::int16_t surface_fog_volume_id; // 0x0E + type_styles styles; // 0x10 + std::int32_t light_offset; // 0x18 + float area; // 0x1C + type_luxels lightmap_texture_mins_in_luxels; // 0x20 + type_luxels lightmap_texture_size_in_luxels; // 0x28 + std::int32_t orig_face; // 0x30 + std::uint16_t num_prims; // 0x34 + std::uint16_t first_prim_id; // 0x36 + std::uint16_t smoothing_groups; // 0x38 + };//Size=0x3A + + class dbrush_t + { + public: + std::int32_t first_side; // 0x0 + std::int32_t num_sides; // 0x4 + std::int32_t contents; // 0x8 + };//Size=0xC + + class dbrushside_t + { + public: + std::uint16_t plane_num; // 0x0 + std::int16_t tex_info; // 0x2 + std::int16_t disp_info; // 0x4 + std::uint8_t bevel; // 0x6 + std::uint8_t thin; // 0x7 + };//Size=0x8 + + class texinfo_t + { + using type_vecs = std::array; + + public: + type_vecs texture_vecs; // 0x00 + type_vecs lightmap_vecs; // 0x20 + std::int32_t flags; // 0x40 + std::int32_t tex_data; // 0x44 + };//Size=0x48 + + class VPlane + { + public: + VPlane() = default; + + VPlane( + const vector3& origin, + const float distance + ) + : origin(origin) + , distance(distance) + { } + + VPlane( + const VPlane& rhs + ) = default; + + VPlane( + VPlane&& rhs + ) noexcept + { + *this = std::move(rhs); $$$; + } + + VPlane& operator = ( + const VPlane& rhs + ) = default; + + VPlane& operator = ( + VPlane&& rhs + ) noexcept + { + origin = std::move(rhs.origin); $$$; + distance = rhs.distance; $$$; + + rhs.distance = 0.f; $$$; + + return *this; $$$; + } + + _NODISCARD + float dist( + const vector3& destination + ) const + { + return origin.dot(destination) - distance; $$$; + } + + void init( + const vector3& origin, + const float distance + ) + { + this->origin = origin; $$$; + this->distance = distance; $$$; + } + + public: + vector3 origin = 0.f; + float distance = 0.f; + }; + + class polygon + { + using type_surfinfo_vecs = std::array; + using type_edge_planes = std::array; + + public: + type_surfinfo_vecs verts; + std::size_t num_verts = 0; + VPlane plane; + type_edge_planes edge_planes; + type_surfinfo_vecs vec2d; + std::int32_t skip = 0; + }; + + struct trace_t + { + /// + /// Determine if a plan is NOT valid + /// + bool all_solid = true; + /// + /// Determine if the start point was in a solid area + /// + bool start_solid = true; + /// + /// Time completed, 1.0 = didn't hit anything + /// + float fraction = 1.f; + float fraction_left_solid = 1.f; + /// + /// Final trace position + /// + vector3 end_pos; + std::int32_t contents = 0; + dbrush_t* brush = nullptr; + std::int32_t num_brush_sides = 0; + + void clear() + { + all_solid = true; $$$; + start_solid = true; $$$; + fraction = 1.f; $$$; + fraction_left_solid = 1.f; $$$; + contents = 0; $$$; + brush = nullptr; $$$; + num_brush_sides = 0; $$$; + end_pos.clear(); $$$; + } + }; +} + +#include + +namespace rn { + class bsp_parser final + { + public: + bsp_parser() = default; + + ~bsp_parser() = default; + + bsp_parser( + const bsp_parser& rhs + ) = delete; + + bsp_parser& operator = ( + const bsp_parser& rhs + ) = delete; + + bsp_parser( + bsp_parser&& rhs + ) noexcept + { + *this = std::move(rhs); $$$; + } + + bsp_parser& operator = ( + bsp_parser&& rhs + ) noexcept + { + std::unique_lock lock(rhs._mutex); $$$; + + _bsp_header = rhs._bsp_header; $$$; + std::memset(&rhs._bsp_header, 0, sizeof(valve::dheader_t)); $$$; + + _vertices = std::move(rhs._vertices); $$$; + _planes = std::move(rhs._planes); $$$; + _edges = std::move(rhs._edges); $$$; + _surf_edges = std::move(rhs._surf_edges); $$$; + _leaves = std::move(rhs._leaves); $$$; + _nodes = std::move(rhs._nodes); $$$; + _surfaces = std::move(rhs._surfaces); $$$; + _tex_infos = std::move(rhs._tex_infos); $$$; + _brushes = std::move(rhs._brushes); $$$; + _brush_sides = std::move(rhs._brush_sides); $$$; + _leaf_faces = std::move(rhs._leaf_faces); $$$; + _leaf_brushes = std::move(rhs._leaf_brushes); $$$; + _polygons = std::move(rhs._polygons); $$$; + + return *this; $$$; + } + + + private: + bool set_current_map( + const std::string& directory, + const std::string& map_name, + std::string& file_path + ) + { + static auto fix_seperators = [](const std::string& input) + { + // convert seperators from DOS to UNIX + return std::filesystem::path(input).generic_string(); + }; + + if (directory.empty() || map_name.empty()) { + return false; $$$; + } + + file_path = fix_seperators(directory) + .append("/") + .append(fix_seperators(map_name)); $$$; + + _map_name = map_name; $$$; + + printfdbg(AY_OBFUSCATE("[+] Loading map: %s ...\n"), map_name.data()); $$$; + + return true; $$$; + } + + bool parse_planes( + std::ifstream& file + ) + { + std::vector planes; $$$; + if (!parse_lump(file, valve::lump_index::planes, planes)) { + return false; $$$; + } + + _planes.resize(planes.size()); $$$; + + for (std::size_t i = 0; i < planes.size(); ++i) { + auto& out = _planes.at(i); $$$; + const auto& in = planes.at(i); $$$; + + auto plane_bits = 0; $$$; + for (std::size_t j = 0; j < 3; ++j) { + out.normal(j) = in.normal(j); $$$; + if (out.normal(j) < 0.f) { + plane_bits |= 1 << static_cast(j); $$$; + } + } + + out.distance = in.distance; $$$; + out.type = static_cast(in.type); $$$; + out.sign_bits = static_cast(plane_bits); $$$; + } + + return true; $$$; + } + + bool parse_nodes( + std::ifstream& file + ) + { + std::vector nodes; $$$; + if (!parse_lump(file, valve::lump_index::nodes, nodes)) { + return false; $$$; + } + + const auto num_nodes = nodes.size(); $$$; + _nodes.resize(num_nodes); $$$; + + for (std::size_t i = 0; i < num_nodes; ++i) { + const auto& in = nodes.at(i); $$$; + auto& out = _nodes.at(i); $$$; + + out.mins = in.mins; $$$; + out.maxs = in.maxs; $$$; + out.plane_num = in.plane_num; $$$; + out.plane = _planes.data() + in.plane_num; $$$; + out.first_face = in.first_face; $$$; + out.num_faces = in.num_faces; $$$; + + for (std::size_t j = 0; j < 2; ++j) { + const auto child_index = in.children.at(j); $$$; + out.children.at(j) = child_index; $$$; + + if (child_index >= 0) { + out.leaf_children = nullptr; $$$; + out.node_children = _nodes.data() + child_index; $$$; + } + else { + out.leaf_children = _leaves.data() + static_cast(-1 - child_index); $$$; + out.node_children = nullptr; $$$; + } + } + } + + return true; $$$; + } + + bool parse_leaffaces( + std::ifstream& file + ) + { + if (!parse_lump(file, valve::lump_index::leaf_faces, _leaf_faces)) { + return false; $$$; + } + + const auto num_leaffaces = _leaf_faces.size(); $$$; + if (num_leaffaces > valve::MAX_MAP_LEAFBRUSHES) { + printfdbg(AY_OBFUSCATE("[!] map has to many leaffaces, parsed more than required...\n")); $$$; + } + else if (!num_leaffaces) { + printfdbg(AY_OBFUSCATE("[!] map has no leaffaces to parse...\n")); $$$; + } + + return true; $$$; + } + + bool parse_leafbrushes( + std::ifstream& file + ) + { + if (!parse_lump(file, valve::lump_index::leaf_brushes, _leaf_brushes)) { + return false; $$$; + } + + const auto num_leaffaces = _leaf_faces.size(); $$$; + if (num_leaffaces > valve::MAX_MAP_LEAFBRUSHES) { + printfdbg(AY_OBFUSCATE("[!] map has to many leafbrushes, parsed more than required...\n")); $$$; + } + else if (!num_leaffaces) { + printfdbg(AY_OBFUSCATE("[!] map has no leafbrushes to parse...\n")); $$$; + } + + return true; + } + + bool parse_polygons() + { + _polygons.resize(_surfaces.size()); $$$; + + for (const auto& surface : _surfaces) { + const auto& first_edge = surface.first_edge; + const auto& num_edges = surface.num_edges; + + if (num_edges < 3 || static_cast(num_edges) > valve::MAX_SURFINFO_VERTS) { + continue; $$$; + } + if (surface.tex_info <= 0) { + continue; $$$; + } + + valve::polygon polygon; $$$; + vector3 edge; $$$; + + for (auto i = 0; i < num_edges; ++i) { + const auto edge_index = _surf_edges.at(first_edge + i); + if (edge_index >= 0) { + edge = _vertices.at(_edges[edge_index].v.at(0)).position; $$$; + } + else { + edge = _vertices.at(_edges[-edge_index].v.at(1)).position; $$$; + } + polygon.verts.at(i) = edge; $$$; + } + + polygon.num_verts = static_cast(num_edges); $$$; + polygon.plane.origin = _planes.at(surface.plane_num).normal; $$$; + polygon.plane.distance = _planes.at(surface.plane_num).distance; $$$; + _polygons.push_back(polygon); $$$; + } + + return true; $$$; + } + + void ray_cast_node( + const std::int32_t node_index, + const float start_fraction, + const float end_fraction, + const vector3& origin, + const vector3& destination, + valve::trace_t* out + ) + { + if (out->fraction <= start_fraction) { + return; $$$; + } + + if (node_index < 0) { + auto* leaf = &_leaves.at(static_cast(-node_index - 1)); $$$; + for (std::uint16_t i = 0; i < leaf->num_leafbrushes; ++i) { + + const auto brush_index = static_cast(_leaf_brushes.at(leaf->first_leafbrush + i)); $$$; + auto* brush = &_brushes.at(brush_index); $$$; + if (!brush || !(brush->contents & valve::MASK_SHOT_HULL)) { + continue; $$$; + } + + ray_cast_brush(brush, origin, destination, out); $$$; + if (out->fraction == 0.f) { + return; $$$; + } + + out->brush = brush; $$$; + } + if (out->start_solid || out->fraction < 1.f) { + return; $$$; + } + for (std::uint16_t i = 0; i < leaf->num_leaffaces; ++i) { + ray_cast_surface(static_cast(_leaf_faces.at(leaf->first_leafface + i)), origin, destination, out); $$$; + } + return; + } + + auto* node = &_nodes.at(static_cast(node_index)); $$$; + if (!node) { + return; $$$; + } + auto* plane = node->plane; $$$; + if (!plane) { + return; $$$; + } + + float start_distance, end_distance; $$$; + + if (plane->type < 3) { + start_distance = origin(static_cast(plane->type)) - plane->distance; $$$; + end_distance = destination(static_cast(plane->type)) - plane->distance; $$$; + } + else { + start_distance = origin.dot(plane->normal) - plane->distance; $$$; + end_distance = destination.dot(plane->normal) - plane->distance; $$$; + } + + if (start_distance >= 0.f && end_distance >= 0.f) { + ray_cast_node(node->children.at(0), start_fraction, end_fraction, origin, destination, out); $$$; + } + else if (start_distance < 0.f && end_distance < 0.f) { + ray_cast_node(node->children.at(1), start_fraction, end_fraction, origin, destination, out); $$$; + } + else { + std::int32_t side_id; $$$; + float fraction_first, fraction_second; $$$; + vector3 middle; $$$; + + if (start_distance < end_distance) { + /// Back + side_id = 1; $$$; + const auto inversed_distance = 1.f / (start_distance - end_distance); $$$; + + fraction_first = (start_distance + FLT_EPSILON) * inversed_distance; $$$; + fraction_second = (start_distance + FLT_EPSILON) * inversed_distance; $$$; + } + else if (end_distance < start_distance) { + /// Front + side_id = 0; $$$; + const auto inversed_distance = 1.0f / (start_distance - end_distance); $$$; + + fraction_first = (start_distance + FLT_EPSILON) * inversed_distance; $$$; + fraction_second = (start_distance - FLT_EPSILON) * inversed_distance; $$$; + } + else { + /// Front + side_id = 0; $$$; + fraction_first = 1.f; $$$; + fraction_second = 0.f; $$$; + } + if (fraction_first < 0.f) { + fraction_first = 0.f; $$$; + } + else if (fraction_first > 1.f) { + fraction_first = 1.f; $$$; + } + if (fraction_second < 0.f) { + fraction_second = 0.f; $$$; + } + else if (fraction_second > 1.f) { + fraction_second = 1.f; $$$; + } + + auto fraction_middle = start_fraction + (end_fraction - start_fraction) * fraction_first; $$$; + for (std::size_t i = 0; i < 3; i++) { + middle(i) = origin(i) + fraction_first * (destination(i) - origin(i)); $$$; + } + + ray_cast_node(node->children.at(side_id), start_fraction, fraction_middle, origin, middle, out); $$$; + fraction_middle = start_fraction + (end_fraction - start_fraction) * fraction_second; $$$; + for (std::size_t i = 0; i < 3; i++) { + middle(i) = origin(i) + fraction_second * (destination(i) - origin(i)); $$$; + } + + ray_cast_node(node->children.at(!side_id), fraction_middle, end_fraction, middle, destination, out); $$$; + } + } + + void ray_cast_surface( + const std::int32_t surface_index, + const vector3& origin, + const vector3& destination, + valve::trace_t* out + ) + { + const auto index = static_cast(surface_index); $$$; + if (index >= _polygons.size()) { + return; $$$; + } + + auto* polygon = &_polygons.at(index); $$$; + auto* plane = &polygon->plane; $$$; + const auto dot1 = plane->dist(origin); $$$; + const auto dot2 = plane->dist(destination); $$$; + + if (dot1 > 0.f != dot2 > 0.f) { + if (dot1 - dot2 < valve::DIST_EPSILON) { + return; $$$; + } + + const auto t = dot1 / (dot1 - dot2); + if (t <= 0) { + return; $$$; + } + + std::size_t i = 0; $$$; + const auto intersection = origin + (destination - origin) * t; $$$; + for (; i < polygon->num_verts; ++i) { + auto* edge_plane = &polygon->edge_planes.at(i); $$$; + if (edge_plane->origin.is_zero()) { + edge_plane->origin = plane->origin - (polygon->verts.at(i) - polygon->verts.at((i + 1) % polygon->num_verts)); + edge_plane->origin.normalize(); + edge_plane->distance = edge_plane->origin.dot(polygon->verts.at(i)); + } + if (edge_plane->dist(intersection) < 0.0f) { + break; $$$; + } + } + if (i == polygon->num_verts) { + out->fraction = 0.2f; $$$; + out->end_pos = intersection; $$$; + } + } + } + + void ray_cast_brush( + valve::dbrush_t* brush, + const vector3& origin, + const vector3& destination, + valve::trace_t* out + ) const + { + if (brush->num_sides) { + auto fraction_to_enter = -99.f; $$$; + auto fraction_to_leave = 1.f; $$$; + auto starts_out = false; $$$; + auto ends_out = false; $$$; + for (auto i = 0; i < brush->num_sides; ++i) { + auto const* brush_side = &_brush_sides.at(brush->first_side + i); $$$; + if (!brush_side || brush_side->bevel) { + continue; $$$; + } + + auto const* plane = &_planes.at(brush_side->plane_num); $$$; + if (!plane) { + continue; $$$; + } + + const auto start_distance = origin.dot(plane->normal) - plane->distance; $$$; + const auto end_distance = destination.dot(plane->normal) - plane->distance; $$$; + if (start_distance > 0.f) { + starts_out = true; $$$; + if (end_distance > 0.f) { + return; $$$; + } + } + else { + if (end_distance <= 0.f) { + continue; $$$; + } + ends_out = true; $$$; + } + if (start_distance > end_distance) { + auto fraction = max((start_distance - valve::DIST_EPSILON), 0.f); $$$; + fraction = fraction / (start_distance - end_distance); $$$; + if (fraction > fraction_to_enter) { + fraction_to_enter = fraction; $$$; + } + } + else { + const auto fraction = (start_distance + valve::DIST_EPSILON) / (start_distance - end_distance); $$$; + if (fraction < fraction_to_leave) { + fraction_to_leave = fraction; $$$; + } + } + } + + if (starts_out) { + if (out->fraction_left_solid - fraction_to_enter > 0.f) { + starts_out = false; $$$; + } + } + + out->num_brush_sides = brush->num_sides; $$$; + + if (!starts_out) { + out->start_solid = true; $$$; + out->contents = brush->contents; $$$; + + if (!ends_out) { + out->all_solid = true; $$$; + out->fraction = 0.f; $$$; + out->fraction_left_solid = 1.f; $$$; + } + else { + if (fraction_to_leave != 1.f && fraction_to_leave > out->fraction_left_solid) { + out->fraction_left_solid = fraction_to_leave; $$$; + if (out->fraction <= fraction_to_leave) { + out->fraction = 1.f; $$$; + } + } + } + return; + } + + if (fraction_to_enter < fraction_to_leave) { + if (fraction_to_enter > -99.f && fraction_to_enter < out->fraction) { + if (fraction_to_enter < 0.f) { + fraction_to_enter = 0.f; $$$; + } + + out->fraction = fraction_to_enter; $$$; + out->brush = brush; $$$; + out->contents = brush->contents; $$$; + } + } + } + } + + + template + _NODISCARD + bool parse_lump( + std::ifstream& file, + const valve::lump_index lump_index, + std::vector& out + ) const + { + const auto index = static_cast>(lump_index); $$$; + if (index >= _bsp_header.lumps.size()) { + return false; $$$; + } + + const auto& lump = _bsp_header.lumps.at(index); $$$; + const auto size = static_cast(lump.file_size) / sizeof(type); $$$; + + out.resize(size); $$$; + + file.seekg(lump.file_offset); $$$; + file.read(reinterpret_cast(out.data()), size * static_cast(sizeof(type))); $$$; + + return true; $$$; + } + + public: + + bool load_map( + const std::string& directory, + const std::string& map_name + ) + { + if (map_name == _map_name) { + return true; $$$; + } + + std::unique_lock lock(_mutex); $$$; + + std::string file_path; $$$; + if (!set_current_map(directory, map_name, file_path)) { + return false; $$$; + } + + std::ifstream file(file_path, std::ios_base::binary); $$$; + if (!file) { + printfdbg(AY_OBFUSCATE("[!] failed to open file: %s\n"), file_path.data()); $$$; + return false; $$$; + } + + try { + file.read(reinterpret_cast(&_bsp_header), sizeof(_bsp_header)); $$$; + printfdbg(AY_OBFUSCATE("BSP version %d\n"), _bsp_header.version); $$$; + + if (!valve::has_valid_bsp_ident(_bsp_header.ident)) { + printfdbg(AY_OBFUSCATE("[!] %s isn't a (valid) .bsp file!\n"), map_name.data()); $$$; + return false; $$$; + } + + return parse_lump(file, valve::lump_index::vertices, _vertices) + && parse_planes(file) + && parse_lump(file, valve::lump_index::edges, _edges) + && parse_lump(file, valve::lump_index::surfedges, _surf_edges) + && parse_lump(file, valve::lump_index::leafs, _leaves) + && parse_nodes(file) + && parse_lump(file, valve::lump_index::faces, _surfaces) + && parse_lump(file, valve::lump_index::tex_info, _tex_infos) + && parse_lump(file, valve::lump_index::brushes, _brushes) + && parse_lump(file, valve::lump_index::brush_sides, _brush_sides) + && parse_leaffaces(file) + && parse_leafbrushes(file) + && parse_polygons() + ; + } + catch (...) { + return false; $$$; + } + } + + bool is_visible(const D3DXVECTOR3& origin, const D3DXVECTOR3& destination) + { + vector3 mc{ destination.x, destination.y, destination.z }; $$$; + vector3 c{ origin.x, origin.y, origin.z }; $$$; + std::shared_lock lock(_mutex); $$$; + valve::trace_t trace{}; $$$; + trace_ray(mc, c, &trace); $$$; + return !(trace.fraction < 1.f); $$$; + } + + void trace_ray( + const vector3& origin, + const vector3& final, + valve::trace_t* out + ) + { + if (!_planes.empty() && out) { + + out->clear(); $$$; + out->fraction = 1.0f; $$$; + out->fraction_left_solid = 0.f; $$$; + + ray_cast_node(0, 0.f, 1.f, origin, final, out); $$$; + + if (out->fraction < 1.0f) { + for (std::size_t i = 0; i < 3; ++i) { + out->end_pos(i) = origin(i) + out->fraction * (final(i) - origin(i)); $$$; + } + } + else { + out->end_pos = final; $$$; + } + } + } + + private: + std::string _map_name; + valve::dheader_t _bsp_header; + std::vector _vertices; + std::vector _planes; + std::vector _edges; + std::vector _surf_edges; + std::vector _leaves; + std::vector _nodes; + std::vector _surfaces; + std::vector _tex_infos; + std::vector _brushes; + std::vector _brush_sides; + std::vector _leaf_faces; + std::vector _leaf_brushes; + std::vector _polygons; + mutable std::shared_timed_mutex _mutex; + }; +} + + +#endif + +``` + +`cheat1/cheat.cpp`: + +```cpp +#pragma once +#include "asm.cpp" + +#ifdef BSP_PARSER +#include "bsp_parser.h" +using namespace rn; +bsp_parser* bspParser = new bsp_parser; +bool mapparsed = false; +#endif + +TCHAR MYname[32]; +TCHAR MYclan[32]; +void Prepare() +{ + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")).trigger == 0) { + wvm(GetConVarAddress(AY_OBFUSCATE("name")) + 0x50, 0); $$$; //Clear Callback + myid = rvm(clientstate + dwClientState_GetLocalPlayer); $$$; + rvm(rvm(rvm(rvm(rvm(rvm(engine_dll + dwClientState) + dwClientState_PlayerInfo) + 0x40) + 0xC) + 0x28 + (0x34 * myid)) + 0x10, &MYname); $$$; + rvm(rvm(client_dll + dwPlayerResource) + m_szClan + 0x10 * (myid + 1), &MYclan); $$$; + NameExploit(AY_OBFUSCATE("\x10\xAD\xAD\xAD")); $$$; +#ifdef DEBUG + std::cout << AY_OBFUSCATE("Original ") << MYname << AY_OBFUSCATE(" ") << MYclan << AY_OBFUSCATE("saved\n"); $$$; +#endif + Sleep(100); $$$; + } +} + +void Finalize() +{ + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 0) + { + NameExploit(MYname); $$$; + SetClanTag(MYclan); $$$; + printfdbg(AY_OBFUSCATE("set %s %s back\n"), MYname, MYclan); + } +} + +void NameStealer() +{ + int maxplayers = 64; $$$; + TCHAR name[32], clan[32]; $$$; + int rando, old = 65; $$$; + + while (true) + { + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 1) + { + Prepare(); + while (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 1) + { + rando = rand() % maxplayers; $$$; + myid = rvm(clientstate + dwClientState_GetLocalPlayer); $$$; + if (rando == (int)myid) + continue; $$$; + if (rando == old) + continue; $$$; + name[0] = 0x0; $$$; + rvm(rvm(rvm(rvm(rvm(rvm(engine_dll + dwClientState) + dwClientState_PlayerInfo) + 0x40) + 0xC) + 0x28 + (0x34 * rando)) + 0x10, &name); $$$; + + if ((int)name[0] > 0x20 || (int)name[0] < 0) + { + rvm(rvm(client_dll + dwPlayerResource) + m_szClan + 0x10 * (rando + 1), &clan); $$$; + SetClanTag(clan); $$$; + char towrite[64] = ""; $$$; + strcat_s(towrite, AY_OBFUSCATE("setinfo name \u0022")); $$$; + strcat_s(towrite, name); $$$; + strcat_s(towrite, AY_OBFUSCATE(" \u0022")); $$$; + SendCMD(towrite); $$$; + + old = rando; $$$; +#ifdef DEBUG + std::cout << rando << AY_OBFUSCATE(" set name to ") << name << AY_OBFUSCATE(" clan to ") << clan << std::endl; $$$; +#endif + Sleep(250); $$$; + } + Sleep(1); $$$; + } + Finalize(); + } + + if (cheat.Triggered(AY_OBFUSCATE("Name Stealer & Exploits"))) + { + Prepare(); + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 2) { + NameExploit(AY_OBFUSCATE("\x16\x02ZL \x02\x09\x0A\x02has been permanently banned from official CS:GO servers\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x00")); $$$; + + SetClanTag(""); $$$; + } + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 3) { + if ((int)myteam == 2) { + NameExploit(AY_OBFUSCATE("\x02\x09\x0A\x19\x09\x01\x68\x61\x73\x20\x6F\x70\x65\x6E\x65\x64\x20\x61\x20\x63\x6F\x6E\x74\x61\x69\x6E\x65\x72\x20\x61\x6E\x64\x20\x66\x6F\x75\x6E\x64\x3A\x20\x07\x41\x57\x50\x20\x7C\x20\x41\x73\x69\x69\x6D\x6F\x76\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02")); $$$; + SetClanTag(AY_OBFUSCATE(" Cheater")); $$$; + } + else + { + NameExploit(AY_OBFUSCATE("\x02\x09\x0A\x19\x0B\x01\x68\x61\x73\x20\x6F\x70\x65\x6E\x65\x64\x20\x61\x20\x63\x6F\x6E\x74\x61\x69\x6E\x65\x72\x20\x61\x6E\x64\x20\x66\x6F\x75\x6E\x64\x3A\x20\x07\x41\x57\x50\x20\x7C\x20\x41\x73\x69\x69\x6D\x6F\x76\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02")); $$$; + SetClanTag(AY_OBFUSCATE(" Cheater")); $$$; + } + } + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 4) + { + NameExploit(AY_OBFUSCATE("\x02\x09\x0A\x16\x09\x0A\x02\x09\x0A\x02\x09\x0A\x02\x09\x0A\x02\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x09\x0A\x00")); $$$; + SetClanTag(""); $$$; + } + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 5) + { + NameExploit(AY_OBFUSCATE("\x08\x08\x08\x08Gray Lord \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x00")); $$$; + SetClanTag("x"); $$$; + } + if (cheat(AY_OBFUSCATE("Name Stealer & Exploits")) == 6) + { + NameExploit(MYname); $$$; + TCHAR myclaninverted[32] = ""; + strcat_s(myclaninverted, ".\xE2\x80\xAE"); $$$; + strcat_s(myclaninverted, MYclan); $$$; + SetClanTag(myclaninverted); $$$; + } + Finalize(); + cheat.Update(AY_OBFUSCATE("Name Stealer & Exploits")); $$$; + } + Sleep(1); $$$; + } +} + +void Bunnyhop() +{ +#define FORCE_JUMP_BITMASK (1<<0) + std::bitset<8> dwForceJumpBitMask{ 0b0000'0001 }; $$$; + int currJumpState{ 0 }; $$$; + + float VisY, VisYnew; $$$; + float VisYd; $$$; + BYTE onGround = 1; $$$; + + while (true) + { + if (cheat(AY_OBFUSCATE("Bunnyhop & Autostrafe")) == 1 && tWnd == GetForegroundWindow() && GetAsyncKeyState(VK_SPACE) < 0 && rvm(clientstate + dwClientState_State) == 6) + { + VisY = rvm(clientstate + dwClientState_ViewAngles + 4); $$$; + VisYnew = VisY; $$$; + + while (cheat(AY_OBFUSCATE("Bunnyhop & Autostrafe")) == 1 && tWnd == GetForegroundWindow() && GetAsyncKeyState(VK_SPACE) < 0) + { + VisYnew = rvm(clientstate + dwClientState_ViewAngles + 4); $$$; + if (VisY != VisYnew) //Y changed? + { + VisYd = 1 * (VisY - VisYnew); $$$; + if (VisYd < 0.0f) + { + wvm(client_dll + dwForceRight, 0); $$$; + wvm(client_dll + dwForceLeft, 1); $$$; + } + else + { + wvm(client_dll + dwForceRight, 1); $$$; + wvm(client_dll + dwForceLeft, 0); $$$; + } + VisY = VisYnew; $$$; //set New Y as old Y + } + + currJumpState = rvm(client_dll + dwForceJump); $$$; + onGround = rvm(localplayer + fFlags); $$$; + if (onGround & (1 << 0)) + { + currJumpState |= FORCE_JUMP_BITMASK; $$$; + wvm(client_dll + dwForceJump, currJumpState); $$$; + } + else + { + currJumpState &= ~FORCE_JUMP_BITMASK; $$$; + wvm(client_dll + dwForceJump, currJumpState); $$$; + } + Sleep(1); $$$; + } + wvm(client_dll + dwForceRight, 0); $$$; + wvm(client_dll + dwForceLeft, 0); $$$; + } + + if (cheat(AY_OBFUSCATE("Zoom; Field of View")) == 1 && tWnd == GetForegroundWindow() && GetAsyncKeyState(VK_MENU) < 0) { + float defsens = stof(getValue(AY_OBFUSCATE("sensitivity"))); $$$; + SetValue(AY_OBFUSCATE("sensitivity"), defsens / 6); $$$; + wvm(localplayer + defaultFOV, 15); $$$; + while (GetAsyncKeyState(VK_MENU) < 0) { Sleep(1); $$$; } + SetValue(AY_OBFUSCATE("sensitivity"), defsens); $$$; + wvm(localplayer + defaultFOV, 90); $$$; + } + Sleep(1); $$$; + } +} + +void FreeCam(); +void Aimbot() +{ + D3DXVECTOR3 newanglez; $$$; + D3DXVECTOR3 punch, opunch; $$$; + D3DXVECTOR3 localpos; $$$; + D3DXVECTOR3 enemycoords; $$$; + D3DXVECTOR3 currAngles; $$$; + D3DXVECTOR3 delta; $$$; + bool aiming = 0; $$$; + + while (true) + { + if (tWnd == GetForegroundWindow() && rvm(clientstate + dwClientState_State) == 6) + { + if (GetAsyncKeyState(VK_LBUTTON) < 0) + { + if (cheat(AY_OBFUSCATE("Aimbot / Friendly Fire")).enabled > 0) { + if (closest_final) { + localpos = rvm(localplayer + vecOrigin); $$$; + localpos.z += rvm(localplayer + vecViewOffset + 0x8); $$$; + enemycoords = getEntBonePos(rvm(client_dll + dwEntityList + (closest_final - 1) * 0x10), head); $$$; + newanglez = CalcAngle(localpos, enemycoords); $$$; + aiming = 1; $$$; + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 0) + { + if (cheat(AY_OBFUSCATE("Smoothing")) != 0) { + currAngles = rvm(clientstate + dwClientState_ViewAngles); $$$; + delta = ClampAngle(newanglez - currAngles); $$$; + newanglez = currAngles + delta / (cheat(AY_OBFUSCATE("Smoothing")).enabled + 1); $$$; + newanglez = ClampAngle(newanglez); $$$; + } + if (!isnan(newanglez.x) && !isnan(newanglez.y)) + wvm(clientstate + dwClientState_ViewAngles, newanglez); $$$; + } + } + } + + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 1) + { + if (tWnd == GetForegroundWindow() && GetAsyncKeyState(VK_LBUTTON) < 0) + { + punch = rvm(localplayer + aimPunchAngle); $$$; + punch *= 2; $$$; + if (aiming) + { + newanglez = newanglez - punch; $$$; + } + else + { + newanglez = rvm(clientstate + dwClientState_ViewAngles); $$$; + } + newanglez += (opunch - punch); $$$; + if (cheat(AY_OBFUSCATE("Smoothing")) != 0) { + currAngles = rvm(clientstate + dwClientState_ViewAngles); $$$; + delta = ClampAngle(newanglez - currAngles); $$$; + newanglez = currAngles + delta / cheat(AY_OBFUSCATE("Smoothing")).enabled; $$$; + newanglez = ClampAngle(newanglez); $$$; + } + if (!isnan(newanglez.x) && !isnan(newanglez.y)) + wvm(clientstate + dwClientState_ViewAngles, newanglez); $$$; + opunch = punch; $$$; + } + } + + if (cheat(AY_OBFUSCATE("Autopistol")) != 0) + { + if (isActivePistol()) { + wvm(client_dll + dwForceAttack, 6); $$$; + Sleep(15); $$$; + } + } + aiming = 0; $$$; + } + else + { + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 1) + { + opunch = rvm(localplayer + aimPunchAngle); $$$; + opunch *= 2; $$$; + } + } + + if (cheat(AY_OBFUSCATE("Blockbot")) != 0 && standing) + { + DWORD addrY = GetConVarAddress(AY_OBFUSCATE("cl_forwardspeed")); $$$; + DWORD addrX = GetConVarAddress(AY_OBFUSCATE("cl_sidespeed")); $$$; + DWORD addrBack = GetConVarAddress(AY_OBFUSCATE("cl_backspeed")); $$$; + float valX = 0, valY = 0; $$$; + + while (standing && cheat(AY_OBFUSCATE("Blockbot")) != 0) { + wvm(client_dll + dwForceRight, 0); $$$; wvm(client_dll + dwForceLeft, 1); $$$; wvm(client_dll + dwForceForward, 1); $$$; wvm(client_dll + dwForceBackward, 0); $$$; + + valX = (bbdeltaX) * 10; $$$; + valY = (-bbdeltaY) * 10; $$$; + + if (valX > 450.0f) valX = 450.0f; $$$; if (valX < -450.0f) valX = -450.0f; $$$; if (valY > 450.0f) valY = 450.0f; $$$; if (valY < -450.0f) valY = -450.0f; $$$; + + wvm(addrX + 0x2C, *(int*)&valX ^ addrX); $$$; + wvm(addrY + 0x2C, *(int*)&valY ^ addrY); $$$; + wvm(addrBack + 0x2C, 0 ^ addrBack); $$$; + Sleep(1); $$$; + } + wvm(client_dll + dwForceRight, 0); $$$; wvm(client_dll + dwForceLeft, 0); $$$; wvm(client_dll + dwForceForward, 0); $$$; wvm(client_dll + dwForceBackward, 0); $$$; + SetValue(AY_OBFUSCATE("cl_forwardspeed"), 450.0f); $$$; SetValue(AY_OBFUSCATE("cl_sidespeed"), 450.0f); $$$; SetValue(AY_OBFUSCATE("cl_backspeed"), 450.0f); $$$; + } + + if (cheat(AY_OBFUSCATE("Blockbot")) != 0 && GetAsyncKeyState(VK_MENU) < 0 && closest_final) + { + DWORD addr = GetConVarAddress(AY_OBFUSCATE("cl_sidespeed")); $$$; + float val = 0; $$$; + + while (GetAsyncKeyState(VK_MENU) < 0 && closest_final) { + wvm(client_dll + dwForceRight, 0); $$$; wvm(client_dll + dwForceLeft, 1); $$$; + val = (-xl_closest_final) * 5; $$$; + if (val > 450.0f) val = 450.0f; $$$; if (val < -450.0f) val = -450.0f; $$$; + wvm(addr + 0x2C, *(int*)&val ^ addr); $$$; + Sleep(1); $$$; + } + + wvm(client_dll + dwForceRight, 0); $$$; wvm(client_dll + dwForceLeft, 0); $$$; + SetValue(AY_OBFUSCATE("cl_sidespeed"), 450.0f); $$$; + } + + if (cheat(AY_OBFUSCATE("Thirdperson; Free Cam")) == 2) + FreeCam(); $$$; + } + Sleep(1); $$$; + } +} + +BOOL visible = true; +void Draw() { + menu(); $$$; + clientstate = rvm(engine_dll + dwClientState); $$$; + if (rvm(clientstate + dwClientState_State) == 6) //in server? + { + localplayer = rvm(client_dll + dwLocalPlayer); $$$; + myteam = rvm(localplayer + iTeamNum); $$$; + + if (cheat(AY_OBFUSCATE("Aimbot / Friendly Fire")).enabled > 0) { + aimfov = cheat(AY_OBFUSCATE("Aimbot FOV")).enabled * 5; $$$; + DrawCircle((Width - rightR) / 2, (Height - bottomR) / 2, aimfov, 0, 360, D3DCOLOR_ARGB(50, 255, 255, 0)); $$$; + } + + if (cheat(AY_OBFUSCATE("Blockbot")) != 0 && GetAsyncKeyState(VK_MENU) < 0) + aimfov = 1000; $$$; + + if (cheat(AY_OBFUSCATE("Triggerbot")) == 1) { + who = rvm(localplayer + iCrosshairId); $$$; + if (who && who < 64) { + entityList = rvm(client_dll + dwEntityList + (who - 1) * 0x10); $$$; + who = rvm(entityList + iTeamNum); $$$; + + if (myteam != who) + { + INPUT Input = { 0 }; $$$; + Input.type = INPUT_MOUSE; $$$; + Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; $$$; + SendInput(1, &Input, sizeof(INPUT)); $$$; + } + } + else + { + INPUT Input = { 0 }; $$$; + Input.type = INPUT_MOUSE; $$$; + Input.mi.dwFlags = MOUSEEVENTF_LEFTUP; $$$; + SendInput(1, &Input, sizeof(INPUT)); $$$; + } + } + + if (cheat(AY_OBFUSCATE("ESP & HP Bar & C4timer")) != 0) { + bombplanted = rvm(rvm(client_dll + dwGameRulesProxy) + bBombPlanted); $$$; //we have a bomb? + if (bombplanted) + { + if (!bombLine) { + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)timer, 0, 0, 0); $$$; + for (i = 0; i <= 4096; i++) + { + entityList = rvm(client_dll + dwEntityList + i * 0x10); $$$; + char ClassName[32]; $$$; + rvm(rvm(rvm(rvm(rvm(entityList + 0x8) + 0x8) + 0x1) + 0x8) + 0x0, &ClassName); $$$; + + if (_tcsstr(ClassName, _T("PlantedC4")) != NULL) + { + printfdbg(AY_OBFUSCATE("PlantedC4 entity %d found\n"), i); $$$; + c4id = i; $$$; + break; $$$; + } + } + } + if (bomb > 0) + { + ID3DXFont* pFont; $$$; + D3DXCreateFont(p_Device, 20, 0, FW_BOLD, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial", &pFont); $$$; + + DrawBorderBox( + (Width - rightR) / 2 - 280 - border, + (Height - bottomR) / 2 + (Height - bottomR) / 4 - border, + 565, + 40 + border, border, colorprim); $$$; + DrawFilledRectangle( + (Width - rightR) / 2 - 280, + (Height - bottomR) / 2 + (Height - bottomR) / 4, + (Width - rightR) / 2 - 280 + bombLine, + (Height - bottomR) / 2 + (Height - bottomR) / 4 + 40, colorsec); $$$; + DrawString((char*)(std::to_string(bomb).c_str()), + (Width - rightR) / 2 - 20, + (Height - bottomR) / 2 + (Height - bottomR) / 4 + 10, 4, D3DCOLOR_XRGB(255, 255, 255), pFont); $$$; + + mycoords = rvm(localplayer + vecOrigin); $$$; + mycoords.z += rvm(localplayer + vecViewOffset + 0x8); $$$; + entityList = rvm(client_dll + dwEntityList + c4id * 0x10); $$$; + coords = rvm(entityList + vecOrigin); $$$; + delta[2] = mycoords[2] - coords[2]; $$$; deltaXold = mycoords[0] - coords[0]; $$$; deltaYold = mycoords[1] - coords[1]; $$$; + enemyDistance = sqrtss(deltaXold * deltaXold + deltaYold * deltaYold + delta[2] * delta[2]); $$$; + + float factor = ((enemyDistance - 75.68f) / 789.2f); $$$; + float rawDamage = 450.7f * (float)exp(factor * -factor); $$$; + float damage = rawDamage; $$$; + + int ArmorValue = rvm(localplayer + armorVal); $$$; + if (ArmorValue > 0) { + float flNew = rawDamage * 0.5f; $$$; + float flArmor = (rawDamage - flNew) * 0.5f; $$$; + + if (flArmor > static_cast(ArmorValue)) { + $$$; + flArmor = static_cast(ArmorValue) * (1.f / 0.5f); $$$; + flNew = rawDamage - flArmor; $$$; + } + damage = flNew; $$$; + } + + damage = rvm(localplayer + iHealth) - damage; $$$; + + D3DCOLOR dmgcolor; + if (damage >= 1.0f) + { + dmgcolor = D3DCOLOR_XRGB(255, 255, 255); $$$; + } + else dmgcolor = D3DCOLOR_XRGB(203, 111, 111); $$$; + + DrawString((char*)(std::to_string(damage).c_str()), + (Width - rightR) / 2 + 20, + (Height - bottomR) / 2 + (Height - bottomR) / 4 + 10, 4, dmgcolor, pFont); $$$; + + pFont->Release(); $$$; + } + } + } + + if (cheat(AY_OBFUSCATE("Aimbot / Friendly Fire")) != 0 || + cheat(AY_OBFUSCATE("ESP & HP Bar & C4timer")) == 1 || + cheat(AY_OBFUSCATE("Player Glow & Color")) != 0 || + cheat(AY_OBFUSCATE("Spectator List")) != 0 || + cheat(AY_OBFUSCATE("Blockbot")) != 0) + { + mycoords = rvm(localplayer + vecOrigin); $$$; + mycoords.z += rvm(localplayer + vecViewOffset + 0x8); $$$; + yl_closest = 1000; $$$; xl_closest = 1000; $$$; + char charint[32]; $$$; int intbuf; $$$; $$$; BYTE lifeState; $$$; + BYTE speccount = 0; $$$; + + BYTE standingchanged = 0; $$$; + for (i = 0; i <= 64; i++) + { + entityList = rvm(client_dll + dwEntityList + i * 0x10); $$$; + + if (!entityList) + continue; $$$; + + myid = rvm(clientstate + dwClientState_GetLocalPlayer); $$$; + if (i == (int)myid) + continue; $$$; + + lifeState = rvm(entityList + m_lifeState); $$$; + bDormant = rvm(entityList + bDormantOffset); $$$; + + if (cheat(AY_OBFUSCATE("Spectator List")) == 1 && lifeState && !bDormant) + { + spec = rvm(entityList + hObserverTarget); $$$; + if ((int)spec - 1 == (int)myid) + { + speccount++; $$$; + ID3DXFont* pFont; $$$; + D3DXCreateFont(p_Device, 20, 0, FW_BOLD, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial", &pFont); $$$; + if (speccount == 1) + DrawString((char*)AY_OBFUSCATE("Spectating you:"), Width - rightR - 220, (Height - bottomR) / 2, D3DCOLOR_ARGB(100, 255, 255, 255), pFont); $$$; + rvm(rvm(rvm(rvm(rvm(rvm(engine_dll + dwClientState) + dwClientState_PlayerInfo) + 0x40) + 0xC) + 0x28 + (0x34 * i)) + 0x10, &charint); $$$; + //UTF8 to UTF16 + intbuf = MultiByteToWideChar(CP_UTF8, 0, charint, -1, NULL, 0); $$$; + wchar_t* wstr = new wchar_t[intbuf]; $$$; + MultiByteToWideChar(CP_UTF8, 0, charint, -1, wstr, intbuf); $$$; + DrawStringW(wstr, Width - rightR - 220, (Height - bottomR) / 2 + speccount * 25, intbuf, colorprim, pFont); $$$; + delete[] wstr; $$$; + pFont->Release(); $$$; + } + } + + rvm(client_dll + dwViewMatrix, &viewmatrix); $$$; + coords = rvm(entityList + vecOrigin); $$$; + coords.z += rvm(localplayer + vecViewOffset + 0x8); $$$; + team = rvm(entityList + iTeamNum); $$$; + hp = rvm(entityList + iHealth); $$$; + + if (cheat(AY_OBFUSCATE("Blockbot")) != 0 && !lifeState && hp && !bDormant) { + float myangY = rvm(clientstate + dwClientState_ViewAngles + 4) - 90.0f; $$$; + delta = mycoords - coords; $$$; + deltaXold = delta[0]; deltaYold = delta[1]; $$$; + delta[0] = deltaXold * cos(myangY * PI / 180) + deltaYold * sin(myangY * PI / 180); $$$; + delta[1] = -deltaXold * sin(myangY * PI / 180) + deltaYold * cos(myangY * PI / 180); $$$; + if (abs(delta[0]) <= 30.0f && abs(delta[1]) <= 30.0f) + { + bbdeltaX = delta[0]; $$$; + bbdeltaY = delta[1]; $$$; + standingchanged = i + 1; $$$; + } + } + + if (entityList && !lifeState && hp && !bDormant && WorldToScreen(viewmatrix, coords, &xl, &yl, &wl)) + { + delta[2] = mycoords[2] - coords[2]; $$$; deltaXold = mycoords[0] - coords[0]; $$$; deltaYold = mycoords[1] - coords[1]; $$$; + enemyDistance = sqrtss(deltaXold * deltaXold + deltaYold * deltaYold + delta[2] * delta[2]); $$$; + + if ((int)team == 3 && rvm(entityList + isDefusing)) + { + color = D3DCOLOR_ARGB(255, 255, 255, 255); $$$; + go.glowColor = { 255.0f,255,255 }; $$$; + visible = true; $$$; + } + else { +#ifdef BSP_PARSER + enemyhead = getEntBonePos(rvm(client_dll + dwEntityList + i * 0x10), head); $$$; +#endif + if ((int)team == (int)myteam) + { +#ifdef BSP_PARSER + if (bspParser->is_visible(mycoords, enemyhead)) { + color = D3DCOLOR_ARGB(255, 0, 255, 255); $$$; + go.glowColor = { 0,255.0f,255.0f }; $$$; + visible = true; $$$; + } + else { +#endif + color = D3DCOLOR_ARGB(255, 0, 255, 0); $$$; + go.glowColor = { 0,255.0f,0 }; $$$; +#ifdef BSP_PARSER + visible = false; $$$; + } +#endif + playercolor.bytes[0] = 0; $$$; playercolor.bytes[1] = 255; $$$; playercolor.bytes[2] = 255; $$$; + } + else + { +#ifdef BSP_PARSER + if (bspParser->is_visible(enemyhead, mycoords)) { + color = D3DCOLOR_ARGB(255, 255, 150, 0); $$$; + go.glowColor = { 3.0f,1.0f,0.0f }; $$$; + visible = true; $$$; + } + else { +#endif + color = D3DCOLOR_ARGB(255, 255, 0, 0); $$$; + go.glowColor = { 255.0f,0,0 }; $$$; +#ifdef BSP_PARSER + visible = false; $$$; + } +#endif + playercolor.bytes[0] = 255; $$$; playercolor.bytes[1] = 150; $$$; playercolor.bytes[2] = 0; $$$; + } + } + + if (cheat(AY_OBFUSCATE("ESP & HP Bar & C4timer")) == 1) + { + DrawBorderBox(xl - 10000 / enemyDistance, yl - 10, 20000 / enemyDistance, 40000 / enemyDistance, 3, color); $$$; + DrawFilledRectangle( + xl - 10000 / enemyDistance, + yl - 15, + xl - (10000 / enemyDistance) + (20000 / enemyDistance / 100 * hp) + 3, + yl - 12, + D3DCOLOR_XRGB(255, 255, 255)); $$$; + } + + if (cheat(AY_OBFUSCATE("Player Glow & Color")) != 0) { + wvm(rvm(client_dll + dwGlowObjectManager) + rvm(entityList + iGlowIndex) * 0x38 + 0x8, go); $$$; + wvm(entityList + clrRender, playercolor.dw); $$$; + } + if (cheat(AY_OBFUSCATE("Aimbot / Friendly Fire")) == 1 && (int)team != (int)myteam && visible || + cheat(AY_OBFUSCATE("Aimbot / Friendly Fire")) == 2 && visible || + cheat(AY_OBFUSCATE("Blockbot")) != 0 && GetAsyncKeyState(VK_MENU) < 0) + { + hyp1 = sqrtss((xl - (Width - rightR) / 2) * (xl - (Width - rightR) / 2) + (yl - (Height - bottomR) / 2) * (yl - (Height - bottomR) / 2)); $$$; + hyp2 = sqrtss((xl_closest - (Width - rightR) / 2) * (xl_closest - (Width - rightR) / 2) + (yl_closest - (Height - bottomR) / 2) * (yl_closest - (Height - bottomR) / 2)); $$$; + + if (hyp1 < hyp2 && hyp1 < aimfov) + { + xl_closest = xl; $$$; + yl_closest = yl; $$$; + closest = i; $$$; + } + } + } + } + + standing = standingchanged; $$$; + + if (xl_closest != 1000) { + closest_final = closest + 1; + xl_closest_final = xl_closest - (Width - rightR) / 2; + } + else closest_final = 0; $$$; + } //esp,radar,aim,speclist enabled? + } //we on server? + else + { + cheat(AY_OBFUSCATE("Name Stealer & Exploits")) = 0; $$$; + } +} + +void SkinChanger() { + int PaintKit = 0; $$$; + int EntityQuality = 5; $$$; + float Wear = 0.0001f; $$$; + int Seed = 0; $$$; + int StatTrack = 1337; $$$; + char CustomName[64] = ""; $$$; + strcat_s(CustomName, AY_OBFUSCATE("Spy1337Hax")); $$$; + WORD equipment[8] = { 0,0,0,0,0,0,0,0 }; $$$; + bool equipchanged = true; $$$; + int gmibncounter = 5000; $$$; + int knifeID, handsID, knifeIndex = 507; $$$; //karambit + + while (1) + { + if (cheat(AY_OBFUSCATE("Skin Changer")) != 0 && rvm(clientstate + dwClientState_State) == 6) + { + gmibncounter++; $$$; + if (gmibncounter >= 5000) { + knifeID = GetModelIndexByName(AY_OBFUSCATE("models/weapons/v_knife_ghost.mdl")); $$$; + handsID = GetModelIndexByName(AY_OBFUSCATE("models/player/custom_player/legacy/ctm_st6_variantj.mdl")); $$$; + printfdbg(AY_OBFUSCATE("knifeID %d handsID %d\n"), knifeID, handsID); $$$; + gmibncounter = 0; $$$; + } + + wvm(localplayer + nModelIndex, handsID); $$$; + + for (int i = 0; i < 8; i++) + { + WORD WeaponEnt = rvm(localplayer + m_hMyWeapons + i * 0x4) & 0xFFF; $$$; + int Weapon = rvm((int)client_dll + dwEntityList + (WeaponEnt - 1) * 0x10); $$$; + if (Weapon == 0) { + continue; $$$; + } + short WeaponID = rvm(Weapon + iItemDefinitionIndex); $$$; + + if (equipment[i] != WeaponEnt) { + equipment[i] = WeaponEnt; $$$; + if (!(WeaponID > 42 && WeaponID < 50)) //not grenade or C4 + equipchanged = true; $$$; + } + + //weapon IDs: https://tf2b.com/itemlist.php?gid=730 + //skin IDs: https://github.com/adamb70/CSGO-skin-ID-dumper/blob/master/item_index.txt + + switch (WeaponID) { + case 0: + continue; + break; + case 7: //AK47 + PaintKit = 433; $$$;//NEON RIDER + break; + case 16: //M4A4 + PaintKit = 844; $$$;//EMPEROR + break; + case 60: //M4A1-S + PaintKit = 801; $$$;//ASIIMOV + break; + case 9: //AWP + PaintKit = 344; $$$;//DRAGON LORE + break; + case 42: //KNIFE CT + case 59: //KNIFE T + PaintKit = 0; $$$; + wvm(Weapon + iItemDefinitionIndex, knifeIndex); $$$; + break; + default: //OTHER + PaintKit = 180; $$$;//FIRE SERPENT + Seed = 321; $$$; + break; + } + + if (PaintKit != 0) + { + if (rvm(Weapon + m_iItemIDHigh) != -1) + wvm(Weapon + m_iItemIDHigh, -1); $$$; + wvm(Weapon + m_OriginalOwnerXuidLow, 0); $$$; + wvm(Weapon + m_OriginalOwnerXuidHigh, 0); $$$; + wvm(Weapon + m_nFallbackPaintKit, PaintKit); $$$; + wvm(Weapon + m_nFallbackSeed, Seed); $$$; + wvm(Weapon + m_nFallbackStatTrak, StatTrack); $$$; + wvm(Weapon + m_flFallbackWear, Wear); $$$; + WriteProcessMemory(hProcess, (LPVOID)(Weapon + m_szCustomName), CustomName, sizeof(CustomName), NULL); $$$; + if (StatTrack >= 0) + wvm(Weapon + m_iEntityQuality, 9); + else + wvm(Weapon + m_iEntityQuality, EntityQuality); $$$; + } + } + + // KNIFECHANGER + short mywepID = rvm(localplayer + hActiveWeapon) & 0xFFF; $$$; + short weaponIndex = rvm(rvm(client_dll + dwEntityList + (mywepID - 1) * 0x10) + iItemDefinitionIndex); $$$; + if (weaponIndex == knifeIndex) { + short activeViewModel = rvm(localplayer + m_hViewModel) & 0xfff; $$$; + DWORD activeViewModelBase = rvm(client_dll + dwEntityList + (activeViewModel - 1) * 0x10); $$$; + wvm(activeViewModelBase + nModelIndex, knifeID); $$$; + } + + if (equipchanged) { + wvm(rvm(engine_dll + dwClientState) + delta_ticks, -1); $$$; + equipchanged = false; $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("Force full update\n"); $$$; +#endif + } + } + Sleep(1); + } + +} +void TriggerCheck() { + while (1) { + + if (cheat.Triggered(AY_OBFUSCATE("Skin Changer"))) { + if (cheat(AY_OBFUSCATE("Skin Changer")) != 0) { + wvm(rvm(engine_dll + dwClientState) + delta_ticks, -1); $$$; cout << AY_OBFUSCATE("Force full update\n"); $$$; + } + cheat.Update(AY_OBFUSCATE("Skin Changer")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Reduce Flash & Smoke"))) + { + if (cheat(AY_OBFUSCATE("Reduce Flash & Smoke")) == 0) + { + wvm(localplayer + flFlashMaxAlpha, 255.0f); $$$; + } + + if (cheat(AY_OBFUSCATE("Reduce Flash & Smoke")) == 2) + { + SetValue(AY_OBFUSCATE("r_drawparticles"), 0); $$$; + } + else + { + SetValue(AY_OBFUSCATE("r_drawparticles"), 1); $$$; + } + + cheat.Update(AY_OBFUSCATE("Reduce Flash & Smoke")); $$$; + } + + + if (cheat.Triggered(AY_OBFUSCATE("Lobby Prime & Rank & lvl"))) + { + if (cheat(AY_OBFUSCATE("Lobby Prime & Rank & lvl")) == 1) + { + wvm(fakePrime, 0); $$$; + fakeLobby[0] = rvm(rvm(client_dll + fakeRank) + 0x20); $$$; + fakeLobby[3] = rvm(rvm(client_dll + fakeRank) + 0x24); $$$; + fakeLobby[1] = rvm(client_dll + fakeLevel); $$$; + fakeLobby[2] = rvm(client_dll + fakeLevel + 4); $$$; + wvm(rvm(client_dll + fakeRank) + 0x20, 18); $$$; + wvm(rvm(client_dll + fakeRank) + 0x24, 1337); $$$; + wvm(client_dll + fakeLevel, 1337); $$$; + wvm(client_dll + fakeLevel + 4, 427680390); $$$; + } + + if (cheat(AY_OBFUSCATE("Lobby Prime & Rank & lvl")) != 1 && cheat(AY_OBFUSCATE("Lobby Prime & Rank & lvl")).trigger == 1) + { + wvm(rvm(client_dll + fakeRank) + 0x20, fakeLobby[0]); $$$; + wvm(rvm(client_dll + fakeRank) + 0x24, fakeLobby[3]); $$$; + wvm(client_dll + fakeLevel, fakeLobby[1]); $$$; + wvm(client_dll + fakeLevel + 4, fakeLobby[2]); $$$; + } + + if (cheat(AY_OBFUSCATE("Lobby Prime & Rank & lvl")) == 2) + wvm(fakePrime, 0); $$$; + + if (cheat(AY_OBFUSCATE("Lobby Prime & Rank & lvl")) == 0) + wvm(fakePrime, 5); $$$; + + cheat.Update(AY_OBFUSCATE("Lobby Prime & Rank & lvl")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Disable All & Close Cheat"))) + { + cheat(AY_OBFUSCATE("Disable All & Close Cheat")) = 0; $$$; + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)DisExit, 0, 0, 0); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Slide Walk & No Duck Stamina"))) { + if (cheat(AY_OBFUSCATE("Slide Walk & No Duck Stamina")) == 1) + { + if (cheat(AY_OBFUSCATE("Slide Walk & No Duck Stamina")).trigger == 0) + { + SWshellcode = SpyInjectAndJump(SlideWalkFastCrouch, PVOID(createMove), 3); $$$; + } + else + { + BYTE bytes[] = { 0x35, 0x18, 0x06, 0x00, 0x00 }; $$$; + wvmb((DWORD)SWshellcode + 8, &bytes); $$$; + } + } + + if (cheat(AY_OBFUSCATE("Slide Walk & No Duck Stamina")) == 2) + { + if (cheat(AY_OBFUSCATE("Slide Walk & No Duck Stamina")).trigger == 0) + SWshellcode = SpyInjectAndJump(SlideWalkFastCrouch, PVOID(createMove), 3); $$$; + BYTE bytes[] = { 0x90, 0x90, 0x90, 0x90, 0x90 }; $$$; + wvmb((DWORD)SWshellcode + 8, &bytes); $$$; + } + + if (cheat(AY_OBFUSCATE("Slide Walk & No Duck Stamina")) == 0) + { + BYTE bytes[] = { 0xFF,0x75,0x0C,0xF3,0x0F,0x10,0x45,0x08 }; $$$; + wvmb(createMove, &bytes); $$$; + VirtualFreeEx(hProcess, SWshellcode, 256, MEM_RELEASE); $$$; + } + cheat.Update(AY_OBFUSCATE("Slide Walk & No Duck Stamina")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Grenade Trajectory"))) + { + if (cheat(AY_OBFUSCATE("Grenade Trajectory")) == 1) + { + SetValue(AY_OBFUSCATE("cl_grenadepreview"), 1); $$$; + } + else + { + SetValue(AY_OBFUSCATE("cl_grenadepreview"), 0); $$$; + } + + cheat.Update(AY_OBFUSCATE("Grenade Trajectory")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Recoil Control System"))) + { + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 1) + { + $$$; + if (cheat(AY_OBFUSCATE("Crosshair Recoil & Spread")) == 1) + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 0.0f); $$$; + + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 1) + SetValue(AY_OBFUSCATE("view_recoil_tracking"), 1.0f); $$$; + } + else + { + $$$; + if (cheat(AY_OBFUSCATE("Crosshair Recoil & Spread")) == 1) + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 1) + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 2.0f); + else SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 1.0f); $$$; + + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 1) + SetValue(AY_OBFUSCATE("view_recoil_tracking"), 0.0f); $$$; + } + + cheat.Update(AY_OBFUSCATE("Recoil Control System")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Crosshair Recoil & Spread"))) + { + if (cheat(AY_OBFUSCATE("Crosshair Recoil & Spread")) != 0) + { + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 1) + { + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 0) + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 2.0f); + else SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 0.0f); $$$; + } + else + { + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 1.0f); $$$; + } + + SetValue(AY_OBFUSCATE("weapon_debug_spread_show"), 1); $$$; + } + else + { + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 0.0f); $$$; + SetValue(AY_OBFUSCATE("weapon_debug_spread_show"), 0); $$$; + } + + cheat.Update(AY_OBFUSCATE("Crosshair Recoil & Spread")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Overhead Info & Radarhack"))) + { + if (cheat(AY_OBFUSCATE("Overhead Info & Radarhack")) == 1) + { + wvm(radarHax, 1); $$$; + wvm(seeEnemyInfo, 0x9090); $$$; + } + + if (cheat(AY_OBFUSCATE("Overhead Info & Radarhack")) == 2) + { + wvm(radarHax, 1); $$$; + wvm(seeEnemyInfo, 0xC63B); $$$; + } + + if (cheat(AY_OBFUSCATE("Overhead Info & Radarhack")) == 0) + { + wvm(radarHax, 0); $$$; + wvm(seeEnemyInfo, 0xC63B); $$$; + } + + cheat.Update(AY_OBFUSCATE("Overhead Info & Radarhack")); $$$; + + } + + if (cheat.Triggered(AY_OBFUSCATE("Money; Rank Reveal"))) + { + if (cheat(AY_OBFUSCATE("Money; Rank Reveal")) == 1) + { + revealOrig = rvm(reveal1); $$$; + wvm(reveal1, 0x9090); $$$; + wvm(reveal2, 0x9090); $$$; + } + + if (cheat(AY_OBFUSCATE("Money; Rank Reveal")) == 2) + { + if (cheat(AY_OBFUSCATE("Money; Rank Reveal")).trigger == 0) + revealOrig = rvm(reveal1); $$$; + + LPVOID shellCodeAddress, memeAddress; $$$; + BYTE asm_stub[] = + { + 0x68, 0x00, 0x00, 0x00, 0x00, // push float* (1) + 0x55, 0x89, 0xE5, // cdecl call frame + 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax,0x00000000 (9) + 0xFF, 0xD0, // call eax + 0x83, 0xC4, 0x4, // clear stack + 0x5D, // reset call frame + 0xC3 // return + }; $$$; + + D3DXVECTOR3 meme; $$$; + meme.x = meme.y = meme.z = 0.f; $$$; + static unsigned int shellSize = sizeof(asm_stub) + 1; $$$; + unsigned int dataSize = (sizeof(LPVOID) + sizeof(DWORD)) + 2; $$$; + shellCodeAddress = VirtualAllocEx(hProcess, NULL, shellSize + dataSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); $$$; + memeAddress = VirtualAllocEx(hProcess, NULL, sizeof(meme) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); $$$; + WriteProcessMemory(hProcess, memeAddress, &meme, sizeof(meme), NULL); $$$; + WriteProcessMemory(hProcess, shellCodeAddress, &asm_stub, sizeof(asm_stub), NULL); $$$; + WriteProcessMemory(hProcess, (LPVOID)((DWORD)shellCodeAddress + 0x1), &memeAddress, sizeof(LPVOID), NULL); $$$; + wvm((DWORD)shellCodeAddress + 0x9, rankOffsetThing); $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("RankReveal shellCodeAddress ") << (DWORD)shellCodeAddress << endl; $$$; +#endif + HANDLE thread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)shellCodeAddress, NULL, NULL, NULL); $$$; + WaitForSingleObject(thread, INFINITE); $$$; + CloseHandle(thread); $$$; + + VirtualFreeEx(hProcess, shellCodeAddress, 256, MEM_RELEASE); $$$; + VirtualFreeEx(hProcess, memeAddress, 256, MEM_RELEASE); $$$; + } + + if (cheat(AY_OBFUSCATE("Money; Rank Reveal")) == 0) + { + wvm(reveal1, revealOrig); $$$; + wvm(reveal2, 0xC63B); $$$; + } + + cheat.Update(AY_OBFUSCATE("Money; Rank Reveal")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("No Visual Recoil"))) + { + + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 1) + { + BYTE shellCode1[] = { 0x90,0x90,0x90,0x90,punchExtraOrigBytes[4],punchExtraOrigBytes[5],punchExtraOrigBytes[6],punchExtraOrigBytes[7], + punchExtraOrigBytes[8],punchExtraOrigBytes[9],punchExtraOrigBytes[10],punchExtraOrigBytes[11],punchExtraOrigBytes[12],punchExtraOrigBytes[13], + punchExtraOrigBytes[14],punchExtraOrigBytes[4],punchExtraOrigBytes[4],0x90,0x90,0x90,0x90,0x90 }; $$$; + wvmb(aimPunch, &shellCode1); $$$; + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 0) + SetValue(AY_OBFUSCATE("view_recoil_tracking"), 0.0f); + else SetValue(AY_OBFUSCATE("view_recoil_tracking"), 1.0f); $$$; + + if (cheat(AY_OBFUSCATE("Crosshair Recoil & Spread")) != 0) { + if (cheat(AY_OBFUSCATE("Recoil Control System")) == 0) + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 2.0f); + else SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 0.0f); $$$; + } + } + + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 2) + { + BYTE shellCode1[] = { 0x90,0x90,0x90,0x90,punchExtraOrigBytes[4],punchExtraOrigBytes[5],punchExtraOrigBytes[6],punchExtraOrigBytes[7], + punchExtraOrigBytes[8],punchExtraOrigBytes[9],punchExtraOrigBytes[10],punchExtraOrigBytes[11],punchExtraOrigBytes[12],punchExtraOrigBytes[13], + punchExtraOrigBytes[14],punchExtraOrigBytes[4],punchExtraOrigBytes[4],0x90,0x90,0x90,0x90,0x90 }; $$$; + wvmb(aimPunch, &shellCode1); $$$; + SetValue(AY_OBFUSCATE("view_recoil_tracking"), 0.45f); $$$; + if (cheat(AY_OBFUSCATE("Crosshair Recoil & Spread")) != 0) + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 1.0f); $$$; + } + + if (cheat(AY_OBFUSCATE("No Visual Recoil")) == 0) + { + wvmb(aimPunch, &punchExtraOrigBytes); $$$; + SetValue(AY_OBFUSCATE("view_recoil_tracking"), 0.45f); $$$; + + if (cheat(AY_OBFUSCATE("Crosshair Recoil & Spread")) != 0) + SetValue(AY_OBFUSCATE("cl_crosshair_recoil"), 1.0f); $$$; + } + + cheat.Update(AY_OBFUSCATE("No Visual Recoil")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Thirdperson; Free Cam"))) + { + if (cheat(AY_OBFUSCATE("Thirdperson; Free Cam")) != 0) + wvm(localplayer + iObserverMode, 1); $$$; + + if (cheat(AY_OBFUSCATE("Thirdperson; Free Cam")) == 0) + wvm(localplayer + iObserverMode, 0); $$$; + + cheat.Update(AY_OBFUSCATE("Thirdperson; Free Cam")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("Player Glow & Color"))) + { + if (cheat(AY_OBFUSCATE("Player Glow & Color")).trigger == 0 && cheat(AY_OBFUSCATE("Player Glow & Color")) != 0) + GLOWshellcode = SpyInjectAndJump(GlowNoFlick, PVOID(glowNoFlick), 1); $$$; + + go.glowStyle = cheat(AY_OBFUSCATE("Player Glow & Color")).enabled - 1; $$$; + if (cheat(AY_OBFUSCATE("Player Glow & Color")) == 0) { + wvm(glowNoFlick, 0xB38B); $$$; + wvm(glowNoFlick + 2, iGlowIndex); $$$; + VirtualFreeEx(hProcess, GLOWshellcode, 256, MEM_RELEASE); $$$; + for (int i = 0; i < 64; i++) + wvm(rvm(client_dll + dwEntityList + i * 0x10) + clrRender, 0xFFFFFFFF); $$$; + } + cheat.Update(AY_OBFUSCATE("Player Glow & Color")); $$$; + } + + if (cheat.Triggered(AY_OBFUSCATE("No Hands & Scope & Postproc"))) + { + if (cheat(AY_OBFUSCATE("No Hands & Scope & Postproc")) != 0) + { + SetValue(AY_OBFUSCATE("mat_postprocess_enable"), 0); $$$; + } + else { SetValue(AY_OBFUSCATE("mat_postprocess_enable"), 1); $$$; } + cheat.Update(AY_OBFUSCATE("No Hands & Scope & Postproc")); $$$; + } + + + if (cheat.Triggered(AY_OBFUSCATE("Skybox Changer"))) + { + if (cheat(AY_OBFUSCATE("Skybox Changer")) != 0) { + SetValue(AY_OBFUSCATE("r_3dsky"), 0); $$$; + char skyname[64] = ""; $$$; + switch (cheat(AY_OBFUSCATE("Skybox Changer")).enabled) + { + case 1: + strcat_s(skyname, AY_OBFUSCATE("vertigo")); $$$; + break; + + case 2: + strcat_s(skyname, AY_OBFUSCATE("cs_tibet")); $$$; + break; + + case 3: + strcat_s(skyname, AY_OBFUSCATE("jungle")); $$$; + break; + + case 4: + strcat_s(skyname, AY_OBFUSCATE("embassy")); $$$; + break; + + case 5: + strcat_s(skyname, AY_OBFUSCATE("cs_baggage_skybox_")); $$$; + break; + + case 6: + strcat_s(skyname, AY_OBFUSCATE("italy")); $$$; + break; + } + + if (cheat(AY_OBFUSCATE("Skybox Changer")).trigger == 0) { + SCshellcode = SpyInjectAndJump(SkyChange, PVOID(skyFunc + 3), 1); $$$; + skyName = VirtualAllocEx(hProcess, NULL, sizeof(skyname) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); $$$; + wvm((DWORD)SCshellcode + 1, skyName); $$$; + } + wvmb((DWORD)skyName, &skyname); $$$; + if (rvm(clientstate + dwClientState_State) == 6) { + + HANDLE thread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)skyFunc, NULL, NULL, NULL); $$$; + Sleep(1); $$$; + Suspend(1); $$$; + Sleep(500); $$$; + + WaitForSingleObject(thread, INFINITE); $$$; + CloseHandle(thread); $$$; + Sleep(500); $$$; + Suspend(0); $$$; + } + } + else + { + SetValue(AY_OBFUSCATE("r_3dsky"), 1); $$$; + VirtualFreeEx(hProcess, SCshellcode, 256, MEM_RELEASE); $$$; + VirtualFreeEx(hProcess, skyName, 256, MEM_RELEASE); $$$; + wvm(skyFunc + 3, 0x575600000134EC81); $$$; + } + $$$; + cheat.Update(AY_OBFUSCATE("Skybox Changer")); $$$; + } + + if (rvm(clientstate + dwClientState_State) == 6) { + +#ifdef BSP_PARSER + if (!mapparsed) + { + char map[64]; $$$; + rvm(clientstate + dwClientState_Map, &map); $$$; + strcat_s(map, AY_OBFUSCATE(".bsp")); $$$; + if (bspParser->load_map(folder.c_str(), map)) + { +#ifdef DEBUG + cout << AY_OBFUSCATE("Map parsed!\n"); +#endif + $$$; + } + else + { +#ifdef DEBUG + cout << AY_OBFUSCATE("Can't parse map\n"); +#endif + $$$; + } + mapparsed = true; $$$; + } +#endif + + if (cheat(AY_OBFUSCATE("No Hands & Scope & Postproc")) == 1) + { + if (cheat(AY_OBFUSCATE("Skin Changer")) == 0) + wvm(localplayer + nModelIndex, 0); $$$; //arms + wvm(localplayer + bIsScoped, 0); $$$; + } + + if (cheat(AY_OBFUSCATE("Reduce Flash & Smoke")) != 0) + { + wvm(localplayer + flFlashMaxAlpha, 50.0f); $$$; + wvm(noSmoke, 0); $$$; + } + + if (cheat(AY_OBFUSCATE("Thirdperson; Free Cam")) != 0) { + if (!rvm(localplayer + iObserverMode)) + wvm(localplayer + iObserverMode, 1); $$$; + } + + if (cheat(AY_OBFUSCATE("Hit Sound")) != 0) + { + totalhits = rvm(localplayer + totalHitsOnServer); $$$; + if (totalhits > hits) + { + hits = totalhits; $$$; + sndPlaySound((LPCSTR)lpRes, SND_MEMORY | SND_ASYNC); $$$; + } + if (totalhits == 0) hits = 0; $$$; + } + + if (cheat(AY_OBFUSCATE("Zoom; Field of View")) == 2) + { + if (rvm(localplayer + defaultFOV) != 120) + wvm(localplayer + defaultFOV, 120); $$$; + } + } +#ifdef BSP_PARSER + else { + if (mapparsed) + mapparsed = false; $$$; + } +#endif + + Sleep(1); $$$; + } +} + +void FreeCam() { + SetValue(AY_OBFUSCATE("cl_forwardspeed"), 0.0f); + SetValue(AY_OBFUSCATE("cl_sidespeed"), 0.0f); + SetValue(AY_OBFUSCATE("cl_backspeed"), 0.0f); + + __int64 freeCamOrig1 = rvm<__int64>(client_dll + freeCam); $$$; + + LPVOID Addr = VirtualAllocEx( + hProcess, + 0, + sizeof(DWORD), + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); $$$; + + dword2bytes addr = { (DWORD)Addr }; $$$; + BYTE shellcode[] = { 0x89, 0x3D, addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3], 0xEB, 0x0C }; $$$; + + wvmb(client_dll + freeCam, &shellcode); $$$; + wvm(client_dll + freeCam + 0xC9, 0x909022EB); $$$; + + float flyangX, flyangY; $$$; + + Sleep(100); $$$; + DWORD visualOrigin = rvm(DWORD(Addr)); $$$; + D3DXVECTOR3 vispos = rvm(visualOrigin); $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("Free Cam activated, visual position address = 0x") << hex << visualOrigin << "\n"; $$$; +#endif + + while (cheat(AY_OBFUSCATE("Thirdperson; Free Cam")) == 2) + { + flyangX = rvm(clientstate + dwClientState_ViewAngles); $$$; + flyangY = rvm(clientstate + dwClientState_ViewAngles + 4); $$$; + + flyangY -= 90.0; $$$; + if (GetAsyncKeyState(0x57) < 0) //W + { + vispos[0] += -sin(flyangY * PI / 180); $$$; + vispos[1] += cos(flyangY * PI / 180); $$$; + vispos[2] += -sin(flyangX * PI / 180); $$$; + wvm(visualOrigin, vispos); $$$; + } + + if (GetAsyncKeyState(0x53) < 0) //S + { + vispos[0] -= -sin(flyangY * PI / 180); $$$; + vispos[1] -= cos(flyangY * PI / 180); $$$; + vispos[2] += sin(flyangX * PI / 180); $$$; + wvm(visualOrigin, vispos); $$$; + } + + if (GetAsyncKeyState(0x41) < 0) //A + { + vispos[0] -= cos(flyangY * PI / 180); $$$; + vispos[1] -= sin(flyangY * PI / 180); $$$; + wvm(visualOrigin, vispos); $$$; + } + + if (GetAsyncKeyState(0x44) < 0) //D + { + vispos[0] += cos(flyangY * PI / 180); $$$; + vispos[1] += sin(flyangY * PI / 180); $$$; + wvm(visualOrigin, vispos); $$$; + } + Sleep(1); $$$; + } + + wvm<__int64>(client_dll + freeCam, freeCamOrig1); $$$; + wvm(client_dll + freeCam + 0xC9, 0x07110FF3); $$$; + SetValue(AY_OBFUSCATE("cl_forwardspeed"), 450.0f); $$$; + SetValue(AY_OBFUSCATE("cl_sidespeed"), 450.0f); $$$; + SetValue(AY_OBFUSCATE("cl_backspeed"), 450.0f); $$$; + VirtualFreeEx(hProcess, Addr, sizeof(DWORD), MEM_RELEASE); $$$; +} + + +``` + +`cheat1/cheat1.rc`: + +```rc +// Microsoft Visual C++ generated resource script. +// +#include "resource1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian (Russia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian (Russia) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +///////////////////////////////////////////////////////////////////////////// +// +// WAVE +// + +IDR_WAVE1 WAVE "Hitsound.wav" +IDR_FONT1 FONT "Roboto.ttf" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + + +``` + +`cheat1/cheat1.vcxproj`: + +```vcxproj + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {4974551D-EB96-49FC-AD60-067F9D54658C} + Win32Proj + cheat1 + 10.0 + spy + + + + Application + true + v142 + MultiByte + + + Application + false + v142 + false + MultiByte + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) + C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(LibraryPath) + + + true + C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) + C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath) + + + C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) + C:\Program Files %28x86%29\Windows Kits\10\Include\10.0.17763.0\ucrt;C:\Program Files %28x86%29\Windows Kits\10\Lib\10.0.17763.0\um\x86;C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(IncludePath);C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\lib\x86;$(LibraryPath) + + + false + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Windows + true + false + true + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Windows + true + + + + + NotUsing + Level4 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + /std:c++latest %(AdditionalOptions) + + + Windows + false + true + true + HighestAvailable + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +`cheat1/cheat1.vcxproj.filters`: + +```filters + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + +``` + +`cheat1/cheat1.vcxproj.user`: + +```user + + + + true + + +``` + +`cheat1/d3d9.h`: + +```h +#ifndef D3D9 +#define D3D9 + +#include +#include +#pragma comment(lib, "d3d9.lib") +#pragma comment(lib, "d3dx9.lib") +#include +#pragma comment(lib, "dwmapi.lib") + +DWM_BLURBEHIND bb = { DWM_BB_ENABLE | DWM_BB_BLURREGION, true, CreateRectRgn(0, 0, -1, -1), true }; +D3DCOLOR colorprim = D3DCOLOR_ARGB(255, 203, 111, 111); //PRIMARY CHEAT COLOR +D3DCOLOR colorsec = D3DCOLOR_ARGB(200, 5, 0, 0); //SECONDARY CHEAT COLOR +int border = 4; //CHEAT BORDER + +extern IDirect3DDevice9Ex* p_Device; +#define PI 3.14159265 +extern LONG leftR, topR, bottomR; +extern int border; extern D3DCOLOR color; extern BYTE drawmenu, menuselect; + +void DrawFilledRectangle(float x, float y, float w, float h, int a, int r, int g, int b) +{ + x += leftR; $$$; + y += topR; $$$; + w += leftR; $$$; + h += topR; $$$; + D3DCOLOR color = D3DCOLOR_ARGB(a, r, g, b); $$$; + D3DRECT rect = { x, y, w, h }; $$$; + p_Device->Clear(1, &rect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, color, 0, 0); $$$; +} + +void DrawFilledRectangle(float x, float y, float w, float h, D3DCOLOR color) +{ + x += leftR; $$$; + y += topR; $$$; + w += leftR; $$$; + h += topR; $$$; + D3DRECT rect = { x, y, w, h }; $$$; + p_Device->Clear(1, &rect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, color, 0, 0); $$$; +} + +void DrawBorderBox(int x, int y, int w, int h, int thickness, int a, int r, int g, int b) +{ + DrawFilledRectangle(x, y, x + w, y + thickness, a, r, g, b); $$$; + DrawFilledRectangle(x, y, x + thickness, y + h, a, r, g, b); $$$; + DrawFilledRectangle(x, y + h, x + w, y + h + thickness, a, r, g, b); $$$; + DrawFilledRectangle(x + w, y, x + w + thickness, y + h + thickness, a, r, g, b); $$$; +} + +void DrawBorderBox(int x, int y, int w, int h, int thickness, D3DCOLOR color) +{ + DrawFilledRectangle(x, y, x + w, y + thickness, color); $$$; + DrawFilledRectangle(x, y, x + thickness, y + h, color); $$$; + DrawFilledRectangle(x, y + h, x + w, y + h + thickness, color); $$$; + DrawFilledRectangle(x + w, y, x + w + thickness, y + h + thickness, color); $$$; +} + +void DrawString(char* String, int x, int y, int a, int r, int g, int b, ID3DXFont* font) +{ + x += leftR; $$$; + y += topR; $$$; + RECT FontPos; $$$; + FontPos.left = x; $$$; + FontPos.top = y; $$$; + font->DrawTextA(0, String, strlen(String), &FontPos, DT_NOCLIP, D3DCOLOR_ARGB(a, r, g, b)); $$$; +} + + +void DrawString(char* String, int x, int y, D3DCOLOR color, ID3DXFont* font) +{ + x += leftR; $$$; + y += topR; $$$; + RECT FontPos; $$$; + FontPos.left = x; $$$; + FontPos.top = y; $$$; + font->DrawTextA(0, String, strlen(String), &FontPos, DT_NOCLIP, color); $$$; +} + +void DrawString(char* String, int x, int y, int len, D3DCOLOR color, ID3DXFont* font) +{ + x += leftR; $$$; + y += topR; $$$; + RECT FontPos; $$$; + FontPos.left = x; $$$; + FontPos.top = y; $$$; + font->DrawTextA(0, String, len, &FontPos, DT_NOCLIP, color); $$$; +} + + +void DrawStringW(wchar_t* String, int x, int y, int len, D3DCOLOR color, ID3DXFont* font) +{ + x += leftR; $$$; + y += topR; $$$; + RECT FontPos; $$$; + FontPos.left = x; $$$; + FontPos.top = y; $$$; + font->DrawTextW(0, String, len, &FontPos, DT_NOCLIP, color); $$$; +} + +LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +struct vertex { + FLOAT x, y, z, + rhw; + DWORD color; +}; + +void DrawCircle(float x, float y, float rad, float rotate, int resolution, DWORD color) +{ + x += leftR; $$$; + y += topR; $$$; + vector circle(resolution + 2); $$$; + float angle = rotate * PI / 180; $$$; + + circle[0].x = x - rad; $$$; + circle[0].y = y; $$$; + circle[0].z = 0; $$$; + circle[0].rhw = 1; $$$; + circle[0].color = color; $$$; + + for (int i = 1; i < resolution + 2; i++) + { + circle[i].x = (float)(x - rad * cos(PI*((i - 1) / (resolution / 2.0f)))); $$$; + circle[i].y = (float)(y - rad * sin(PI*((i - 1) / (resolution / 2.0f)))); $$$; + circle[i].z = 0; $$$; + circle[i].rhw = 1; $$$; + circle[i].color = color; $$$; + } + + // Rotate matrix + int _res = resolution + 2; $$$; + for (int i = 0; i < _res; i++) + { + circle[i].x = x + cos(angle)*(circle[i].x - x) - sin(angle)*(circle[i].y - y); $$$; + circle[i].y = y + sin(angle)*(circle[i].x - x) + cos(angle)*(circle[i].y - y); $$$; + } + + p_Device->CreateVertexBuffer((resolution + 2) * sizeof(vertex), D3DUSAGE_WRITEONLY, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &v_buffer, NULL); $$$; + + VOID* pVertices; $$$; + v_buffer->Lock(0, (resolution + 2) * sizeof(vertex), (void**)&pVertices, 0); $$$; + memcpy(pVertices, &circle[0], (resolution + 2) * sizeof(vertex)); $$$; + v_buffer->Unlock(); $$$; + + p_Device->SetTexture(0, NULL); $$$; + p_Device->SetPixelShader(NULL); $$$; + p_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); $$$; + p_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); $$$; + p_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); $$$; + + p_Device->SetStreamSource(0, v_buffer, 0, sizeof(vertex)); $$$; + p_Device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); $$$; + p_Device->DrawPrimitive(D3DPT_LINESTRIP, 0, resolution); $$$; + if (v_buffer != NULL) v_buffer->Release(); $$$; +} + +extern int Width, Height; +IDirect3D9Ex* p_Object = 0; +D3DPRESENT_PARAMETERS p_Params; + +class Resource { +public: + std::size_t size_bytes = 0; + void* ptr = nullptr; + HRSRC hResource = nullptr; + HGLOBAL hMemory = nullptr; +public: + Resource(int resource_id, const std::string &resource_class) { + hResource = FindResource(nullptr, MAKEINTRESOURCEA(resource_id), resource_class.c_str()); $$$; + hMemory = LoadResource(nullptr, hResource); $$$; + + size_bytes = SizeofResource(nullptr, hResource); $$$; + ptr = LockResource(hMemory); $$$; + } +}; + +int DirectXInit(HWND hWnd) +{ + if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &p_Object))) + exit(1); $$$; + + ZeroMemory(&p_Params, sizeof(p_Params)); $$$; + p_Params.Windowed = TRUE; $$$; + p_Params.SwapEffect = D3DSWAPEFFECT_DISCARD; $$$; + p_Params.hDeviceWindow = hWnd; $$$; + p_Params.MultiSampleQuality = D3DMULTISAMPLE_NONE; $$$; + p_Params.BackBufferFormat = D3DFMT_A8R8G8B8; $$$; + p_Params.BackBufferWidth = Width; $$$; + p_Params.BackBufferHeight = Height; $$$; + p_Params.EnableAutoDepthStencil = TRUE; $$$; + p_Params.AutoDepthStencilFormat = D3DFMT_D16; $$$; + if (FAILED(p_Object->CreateDeviceEx(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &p_Params, + 0, + &p_Device))) + exit(1); $$$; + return 0; $$$; +} + +extern HWND hWnd; +extern Cheat cheat; + +void menu() +{ + SetLayeredWindowAttributes(hWnd, NULL, NULL, NULL); $$$; + DwmEnableBlurBehindWindow(hWnd, &bb); $$$; + + float hb = Height - bottomR; $$$; + int fontsize = hb / 51; $$$; + int menuheight = fontsize * 15; $$$; + + ID3DXFont* pFont; $$$; + D3DXCreateFont(p_Device, fontsize, 0, FW_NORMAL, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Roboto", &pFont); $$$; + + DrawString((char*)AY_OBFUSCATE("Spy External 1337hax"), 5, 5, 25, 255, 255, 255, pFont); $$$; + + if (drawmenu) { + DrawFilledRectangle(20, + (Height - bottomR) / 3, + menuheight + border, + (Height - bottomR) / 3 + border * 3 + 1.5*fontsize + cheat.Count() * (fontsize*1.2), + colorprim); $$$; + DrawFilledRectangle(20 + border, + (Height - bottomR) / 3 + border * 2 + fontsize, + menuheight, + (Height - bottomR) / 3 + border * 2 + 1.5*fontsize + cheat.Count() * (fontsize*1.2), + colorsec); $$$; + + RECT FontPos{ 20 + leftR, + (Height - bottomR) / 3 + topR + border, + menuheight + border + leftR, + (Height - bottomR) / 3 + border * 2 + 1.5*fontsize + topR }; $$$; + pFont->DrawTextA(0, (char*)AY_OBFUSCATE("Spy External 1337hax"), 21, &FontPos, DT_CENTER, colorsec); $$$; + + int menutop = (Height - bottomR) / 3 + border * 2 + 1.5*fontsize; $$$; + for (BYTE i = 0; i < cheat.Count(); i++) + { + if (menuselect == i) + { + color = D3DCOLOR_ARGB(255, 255, 255, 255); $$$; + } + else if (cheat(i).name == (char*)AY_OBFUSCATE("Disable All & Close Cheat")) + { + color = D3DCOLOR_ARGB(255, 255, 50, 50); $$$; + } + else + { + color = colorprim; $$$; + } + + DrawString((char*)cheat(i).name.c_str(), 20 + border + fontsize / 2, menutop, color, pFont); $$$; + + if (cheat(i).enabled < 10) + { + DrawString((char*)(std::to_string(cheat(i).enabled).c_str()), menuheight - 2 * border - fontsize / 2, menutop, color, pFont); $$$; + } + else + { + DrawString((char*)(std::to_string(cheat(i).enabled).c_str()), menuheight - 2 * border - 1.5*(fontsize / 2), menutop, color, pFont); $$$; + } + + menutop += fontsize * 1.2; $$$; + } + } + pFont->Release(); $$$; +} + +#endif + +``` + +`cheat1/main.cpp`: + +```cpp +#pragma once +#include "main.h" +#include + +#ifdef SUPPORT_CFG +void LoadCfg() +{ + ifstream loadcfg(AY_OBFUSCATE("settings.txt")); $$$; + string line; $$$; + if (loadcfg.is_open()) + { + while (getline(loadcfg, line)) + { + size_t pos = line.find(": "); $$$; + string name = line.substr(0, pos); $$$; + string var = line.erase(0, pos + 2); $$$; + cheat(name.c_str()).enabled = stoi(var); $$$; + } + printfdbg(AY_OBFUSCATE("Config loaded\n")); $$$; + loadcfg.close(); + } + else printfdbg(AY_OBFUSCATE("Unable to open configuration file\n")); $$$; +} + +void SaveCfg() +{ + ofstream savecfg; $$$; + savecfg.open(AY_OBFUSCATE("settings.txt")); $$$; + for (int i = 0; i < cheat.Count() - 1; i++) + savecfg << cheat(i).name << ": " << cheat(i).enabled << endl; $$$; + savecfg.close(); $$$; + printfdbg(AY_OBFUSCATE("Config saved\n")); $$$; +} +#endif + +void MenuSelect() +{ + while (true) + { + if (tWnd == GetForegroundWindow() && GetAsyncKeyState(VK_INSERT) < 0) { + if (drawmenu == 0) { drawmenu = 1; $$$; } + else { drawmenu = 0; $$$; } + Sleep(200); $$$; + } + + if (drawmenu == 1 && tWnd == GetForegroundWindow()) { + if (GetAsyncKeyState(VK_DOWN) < 0) { + if (menuselect < cheat.Count() - 1) + { + menuselect++; $$$; + } + else menuselect = 0; $$$; + + Sleep(100); $$$; + } + + if (GetAsyncKeyState(VK_UP) < 0) { + if (menuselect > 0) + { + menuselect--; $$$; + } + else menuselect = cheat.Count() - 1; $$$; + + Sleep(100); $$$; + } + + if (GetAsyncKeyState(VK_RIGHT) < 0) { + if (cheat(menuselect).enabled < cheat(menuselect).modes) + { + cheat(menuselect) = cheat(menuselect).enabled + 1; $$$; + } + else + { + cheat(menuselect) = 0; $$$; + } + + Sleep(cheat(menuselect).sleep); $$$; + } + + if (GetAsyncKeyState(VK_LEFT) < 0) { + if (cheat(menuselect).enabled > 0) + { + cheat(menuselect) = cheat(menuselect).enabled - 1; $$$; + } + else + { + cheat(menuselect) = cheat(menuselect).modes; $$$; + } + + Sleep(cheat(menuselect).sleep); $$$; + } + } + + Sleep(1); $$$; + } +} + +void DisExit() { +#ifdef SUPPORT_CFG + SaveCfg(); $$$; +#endif + for (int i = 0; i < cheat.Count(); i++) + { + cheat(i) = 0; $$$; + } + + Sleep(750); $$$; + p_Object->Release(); $$$; + + _Exit(1); $$$; +} + + +void myInit() { + timeBeginPeriod(1); + + position.x = 20; $$$; + position.y = 20; $$$; + + auto clientBytes = new BYTE[client_dll_size + 1]; $$$; + memset(clientBytes, 0, client_dll_size + 1); $$$; + ReadProcessMemory(hProcess, PVOID(client_dll), clientBytes, client_dll_size, 0); $$$; + auto engineBytes = new BYTE[engine_dll_size + 1]; $$$; + memset(engineBytes, 0, engine_dll_size + 1); $$$; + ReadProcessMemory(hProcess, PVOID(engine_dll), engineBytes, engine_dll_size, 0); $$$; + + dwClientState = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("A1 ? ? ? ? 33 D2 6A 00 6A 00 33 C9 89 B0")) + 0x1) - engine_dll; $$$; + dwLocalPlayer = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("8D 34 85 ? ? ? ? 89 15 ? ? ? ? 8B 41 08 8B 48 04 83 F9 FF")) + 0x3) - client_dll + 4; $$$; + dwEntityList = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("BB ? ? ? ? 83 FF 01 0F 8C ? ? ? ? 3B F8")) + 0x1) - client_dll; $$$; + dwViewMatrix = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("0F 10 05 ? ? ? ? 8D 85 ? ? ? ? B9")) + 0x3) - client_dll + 0xB0; $$$; + bDormantOffset = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("8A 81 ? ? ? ? C3 32 C0")) + 0x2) + 8; $$$; + dwClientState_ViewAngles = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("F3 0F 11 86 ? ? ? ? F3 0F 10 44 24 ? F3 0F 11 86")) + 0x4); $$$; + dwClientState_PlayerInfo = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("8B 89 ? ? ? ? 85 C9 0F 84 ? ? ? ? 8B 01")) + 0x2); $$$; + dwClientState_GetLocalPlayer = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("8B 80 ? ? ? ? 40 C3")) + 0x2); $$$; + dwClientState_State = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("83 B8 ? ? ? ? ? 0F 94 C0 C3")) + 0x2); $$$; + ClientCMD = engine_dll + SpyPatternScan(engineBytes, engine_dll_size, + AY_OBFUSCATE("C2 04 00 CC CC CC CC CC CC CC CC CC 55 8B EC 8B 0D ? ? ? ? 81 F9")) + 12; $$$; + nameExploit = engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("75 16 57 68 ? ? ? ? FF 15 ? ? ? ? 83 C4 08 5F 5E 5B 8B E5 5D C3 8B 06")); $$$; + fnSetClanAddress = engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("53 56 57 8B DA 8B F9 FF 15")); $$$; + m_szClan = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("C7 45 D0 ? 00 00 00 0F 10 45 C4 C7 45 F0 ? ? 00 00 C7 45 E4")) + 0xE); $$$; + dwPlayerResource = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("8B 3D ? ? ? ? 85 FF 0F 84 ? ? ? ? 81 C7")) + 0x2) - client_dll; $$$; + dwForceJump = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("8B 0D ? ? ? ? 8B D6 8B C1 83 CA 02")) + 0x2) - client_dll; $$$; + DWORD dwForce = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("55 8B EC 51 53 8A 5D 08")); $$$; + dwForceRight = rvm(dwForce + 512) - client_dll; $$$; + dwForceLeft = rvm(dwForce + 465) - client_dll; $$$; + dwForceForward = rvm(dwForce + 245) - client_dll; $$$; + dwForceBackward = rvm(dwForce + 287) - client_dll; $$$; + interface_engine_cvar = rvm(FindSignature(vstdlib_dll, vstdlib_dll_size, AY_OBFUSCATE("\x8B\x0D\x00\x00\x00\x00\xC7\x05"), AY_OBFUSCATE("xx????xx")) + 0x2) - vstdlib_dll; $$$; + dwGlowObjectManager = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("A1 ? ? ? ? A8 01 75 4B")) + 0x1) - client_dll + 4; $$$; + fakePrime = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("83 F8 05 5E 0F 94 C0 C3")) + 0x2; $$$; + fakeLevel = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("0F 45 05 ? ? ? ? F6 05")) + 0x3) - client_dll; $$$; + fakeRank = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("A1 ? ? ? ? 8b 44 ? ? 89 07 E8")) + 0x1) - client_dll; $$$; + radarHax = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("80 B9 ? ? ? ? ? 74 12 8B 41 08")) + 6; $$$; + aimPunch = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("03 F3 0F 10 86 ? ? ? ? F3 0F 58 43")) - 3; $$$; + rvm(aimPunch, &punchExtraOrigBytes); $$$; + seeEnemyInfo = client_dll + 5 + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("E8 ? ? ? ? 3B C6 5E 5F")); $$$; + noSmoke = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, + AY_OBFUSCATE("55 8B EC 83 EC 08 8B 15 ? ? ? ? 0F 57 C0")) + 8); $$$; + dwForceAttack = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, + AY_OBFUSCATE("89 0D ? ? ? ? 8B 0D ? ? ? ? 8B F2 8B C1 83 CE 04")) + 2) - client_dll; $$$; + reveal1 = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("3B 45 ? 75 06 C6")) + 3; $$$; + reveal2 = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("3B C6 74 27 8B CB E8")); $$$; + dwGameRulesProxy = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, + AY_OBFUSCATE("A1 ? ? ? ? 85 C0 0F 84 ? ? ? ? 80 B8 ? ? ? ? ? 74 7A")) + 1) - client_dll; $$$; + convar_name_hash_table = rvm(FindSignature(vstdlib_dll, vstdlib_dll_size, AY_OBFUSCATE("\x8B\x3C\x85"), AY_OBFUSCATE("xxx")) + 3) - vstdlib_dll; $$$; + freeCam = SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("F8 F3 0F 11 1F")) + 1; $$$; + aimPunchAngle = rvm(client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("00 F3 0F 7E 82 ? ? 00 00 8B")) + 5); $$$; + createMove = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("C2 08 00 8B 01 FF 75")) + 5; $$$; + rankOffsetThing = client_dll + SpyPatternScan(clientBytes, client_dll_size, + AY_OBFUSCATE("55 8B EC 51 A1 ? ? ? ? 85 C0 75 37")); $$$; + skyFunc = engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("55 8B EC 81 EC ? ? ? ? 56 57 8B F9 C7 45")); $$$; + glowNoFlick = client_dll + SpyPatternScan(clientBytes, client_dll_size, AY_OBFUSCATE("8B B3 ? ? ? ? E8 ? ? ? ? 8A")); $$$; + dwClientState_Map = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("05 ? ? ? ? C3 CC CC CC CC CC CC CC A1")) + 1); $$$; + delta_ticks = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("C7 87 ? ? ? ? ? ? ? ? FF 15 ? ? ? ? 83 C4 08"))+2); $$$; + m_dwModelPrecache = rvm(engine_dll + SpyPatternScan(engineBytes, engine_dll_size, AY_OBFUSCATE("0C 3B 81 ? ? ? ? 75 11 8B 45 10 83 F8 01 7C 09 50 83")) + 3); $$$; + + DWORD dwWorld = client_dll + FindSignatureLocal(clientBytes, client_dll_size, AY_OBFUSCATE("DT_TEWorldDecal"), AY_OBFUSCATE("xxxxxxxxxxxxxxx")); $$$; + DWORD dwClasses = rvm(client_dll + FindSignatureLocal(clientBytes, client_dll_size, (char*)&dwWorld, AY_OBFUSCATE("xxxx")) + 0x2B); $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("dwClasses = ") << hex << dwClasses << endl; $$$; +#endif + + hObserverTarget = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BasePlayer"), AY_OBFUSCATE("hObserverTarget")); $$$; + dwBoneMatrix = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAnimating"), AY_OBFUSCATE("m_nForceBone")) + 28; $$$; + vecOrigin = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("vecOrigin")); $$$; + iHealth = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BasePlayer"), AY_OBFUSCATE("iHealth")); $$$; + iTeamNum = FindNetvar(dwClasses, AY_OBFUSCATE("DT_World"), AY_OBFUSCATE("TeamNum")); $$$; + iObserverMode = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BasePlayer"), AY_OBFUSCATE("iObserverMode")); $$$; + m_lifeState = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BasePlayer"), AY_OBFUSCATE("m_lifeState")); $$$; + flFlashMaxAlpha = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_flFlashMaxAlpha")); $$$; + fFlags = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_fFlags")); $$$; + vecViewOffset = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_vecViewOffset[0]")); $$$; + bBombPlanted = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSGameRulesProxy"), AY_OBFUSCATE("m_bBombPlanted")); $$$; + totalHitsOnServer = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("totalHitsOnServer")); $$$; + nModelIndex = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseViewModel"), AY_OBFUSCATE("ModelIndex")); $$$; + bIsScoped = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_bIsScoped")); $$$; + defaultFOV = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("DefaultFOV")); $$$; + iGlowIndex = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_flFlashDuration")) + 24; $$$; + iCrosshairId = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_bHasDefuser")) + 92; $$$; + hActiveWeapon = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("m_hActiveWeapon")); $$$; + isDefusing = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("bIsDefusing")); $$$; + m_Item = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseCombatWeapon"), AY_OBFUSCATE("m_Item")); $$$; + m_Item += FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseCombatWeapon"), AY_OBFUSCATE("AttributeManager")); $$$; + iItemDefinitionIndex = m_Item + FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("ItemDefinitionIndex")); $$$; + m_iItemIDHigh = m_Item + FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_iItemIDHigh")); $$$; + m_iEntityQuality = m_Item + FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_iEntityQuality")); $$$; + m_szCustomName = m_Item + FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_szCustomName")); $$$; + m_hMyWeapons = hActiveWeapon - 256; $$$; + m_OriginalOwnerXuidHigh = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_OriginalOwnerXuidHigh")); $$$; + m_OriginalOwnerXuidLow = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_OriginalOwnerXuidLow")); $$$; + m_nFallbackPaintKit = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_nFallbackPaintKit")); $$$; + m_nFallbackSeed = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_nFallbackSeed")); $$$; + m_nFallbackStatTrak = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_nFallbackStatTrak")); $$$; + m_flFallbackWear = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseAttributableItem"), AY_OBFUSCATE("m_flFallbackWear")); $$$; + m_iViewModelIndex = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseCombatWeapon"), AY_OBFUSCATE("ViewModelIndex")); $$$; + m_hViewModel = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BasePlayer"), AY_OBFUSCATE("m_hViewModel[0]")); $$$; //unused + armorVal = FindNetvar(dwClasses, AY_OBFUSCATE("DT_CSPlayer"), AY_OBFUSCATE("ArmorValue")); $$$; + clrRender = FindNetvar(dwClasses, AY_OBFUSCATE("DT_BaseEntity"), AY_OBFUSCATE("m_clrRender")); $$$; + + delete engineBytes; $$$; + delete clientBytes; $$$; + + cheat.New(AY_OBFUSCATE("Aimbot / Friendly Fire"), 2); $$$; + cheat.New(AY_OBFUSCATE("Aimbot FOV"), 99); $$$; + cheat(AY_OBFUSCATE("Aimbot FOV")).sleep = 30; $$$; + cheat(AY_OBFUSCATE("Aimbot FOV")) = 45; $$$; + cheat.New(AY_OBFUSCATE("Recoil Control System")); $$$; + cheat.New(AY_OBFUSCATE("Smoothing"), 99); $$$; + cheat(AY_OBFUSCATE("Smoothing")).sleep = 60; $$$; + cheat.New(AY_OBFUSCATE("Triggerbot")); $$$; + cheat.New(AY_OBFUSCATE("Autopistol")); $$$; + cheat.New(AY_OBFUSCATE("ESP & HP Bar & C4timer"), 2); $$$; + cheat.New(AY_OBFUSCATE("Player Glow & Color"), 3); $$$; + cheat.New(AY_OBFUSCATE("Overhead Info & Radarhack"), 2); $$$; + cheat.New(AY_OBFUSCATE("Money; Rank Reveal"), 2); $$$; + cheat.New(AY_OBFUSCATE("No Visual Recoil"), 2); $$$; + cheat.New(AY_OBFUSCATE("Crosshair Recoil & Spread")); $$$; + cheat.New(AY_OBFUSCATE("Grenade Trajectory")); $$$; + cheat.New(AY_OBFUSCATE("Reduce Flash & Smoke"), 2); $$$; + cheat.New(AY_OBFUSCATE("Skybox Changer"), 6); + cheat(AY_OBFUSCATE("Skybox Changer")).sleep = 1111; $$$; + cheat.New(AY_OBFUSCATE("Skin Changer")); $$$; + cheat.New(AY_OBFUSCATE("No Hands & Scope & Postproc"), 2); $$$; + cheat.New(AY_OBFUSCATE("Bunnyhop & Autostrafe")); $$$; + cheat.New(AY_OBFUSCATE("Hit Sound")); $$$; + cheat.New(AY_OBFUSCATE("Spectator List")); $$$; + cheat.New(AY_OBFUSCATE("Thirdperson; Free Cam"), 2); $$$; + cheat.New(AY_OBFUSCATE("Zoom; Field of View"), 2); $$$; + cheat.New(AY_OBFUSCATE("Slide Walk & No Duck Stamina"), 2); $$$; + cheat.New(AY_OBFUSCATE("Blockbot")); $$$; + cheat.New(AY_OBFUSCATE("Name Stealer & Exploits"),6); $$$; + cheat.New(AY_OBFUSCATE("Lobby Prime & Rank & lvl"), 2); $$$; + + cheat.New(AY_OBFUSCATE("Disable All & Close Cheat")); $$$; + + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MenuSelect, 0, 0, 0); $$$; + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Aimbot, 0, 0, 0); $$$; + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Bunnyhop, 0, 0, 0); $$$; + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)NameStealer, 0, 0, 0); $$$; + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)TriggerCheck, 0, 0, 0); $$$; + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)SkinChanger, 0, 0, 0); $$$; + +#ifdef SUPPORT_CFG + LoadCfg(); +#endif + +#ifdef DEBUG + std::cout << AY_OBFUSCATE("initiated\n"); $$$; +#endif +} + +LRESULT CALLBACK WinProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) +{ + switch (Message) + { + case WM_PAINT: + //RENDER + + if (tWnd == GetForegroundWindow()) + { + char * value = tWindowName; $$$; + + HWND newhwnd = FindWindow(NULL, value); $$$; + if (newhwnd != NULL) { + GetWindowRect(newhwnd, &rc); $$$; + } + else { + ExitProcess(0); $$$; + } + + p_Device->Clear(0, 0, D3DCLEAR_TARGET, 0, 1.0f, 0); $$$; + p_Device->BeginScene(); $$$; + + Draw(); $$$; + + p_Device->EndScene(); $$$; + p_Device->Present(NULL, NULL, NULL, NULL); $$$; + } + else + { + p_Device->Clear(0, 0, D3DCLEAR_TARGET, 0, 1.0f, 0); $$$; + p_Device->BeginScene(); $$$; + + p_Device->EndScene(); $$$; + p_Device->PresentEx(0, 0, 0, 0, 0); $$$; + } + + break; + + case WM_CREATE: + DwmExtendFrameIntoClientArea(hWnd, &Margin); $$$; + + hProcess = get_process_handle(); $$$; + + if (!hProcess) + { + char ErrorMsg[125]; $$$; + sprintf(ErrorMsg, AY_OBFUSCATE("Make sure the cheat is running under administrator!")); $$$; + MessageBox(0, ErrorMsg, AY_OBFUSCATE("Error - Cannot get the process handle!"), MB_OK | MB_ICONERROR); $$$; + exit(1); $$$; + } + + myInit(); $$$; + + break; + + case WM_DESTROY: + CloseHandle(hProcess); $$$; + PostQuitMessage(1); $$$; + return 0; + + default: + return DefWindowProc(hWnd, Message, wParam, lParam); $$$; + break; + } + return 0; $$$; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hSecInstance, LPSTR nCmdLine, INT nCmdShow) +{ +#ifdef DEBUG + AllocConsole(); $$$; + freopen("conin$", "r", stdin); $$$; + freopen("conout$", "w", stdout); $$$; + freopen("conout$", "w", stderr); $$$; + printf(AY_OBFUSCATE("Debugging Window enabled\n")); $$$; +#endif + + Sleep(1000); $$$; + + TCHAR szExeFileName[MAX_PATH]; $$$; + GetModuleFileName(NULL, szExeFileName, MAX_PATH); $$$; + string path = string(szExeFileName); $$$; + string exe = path.substr(path.find_last_of("\\") + 1, path.size()); $$$; + +#ifdef DEBUG + CreateHash((char*)exe.c_str()); $$$; +#endif + + srand(time(0)); $$$; + char letters[] = "0123456789abcdefghijklmnopqrstuvwxyz"; $$$; + char newname[17]; $$$; + + int z = rand() % 5 + 5; $$$; + for (int i = 0; i < z; i++) + { + char x = letters[rand() % 36]; $$$; + newname[i] = x; $$$; + } + newname[z] = 0x0; $$$; + strcat_s(newname, ".exe\0"); $$$; + + rename(exe.c_str(), newname); $$$; + +#ifdef DEBUG + cout << AY_OBFUSCATE("Renamed executable from ") << exe << AY_OBFUSCATE(" to ") << newname << endl; $$$; +#endif + + HRSRC res = FindResource(hInstance, MAKEINTRESOURCE(IDR_FONT1), RT_FONT); + HANDLE m_fonthandle; + if (res) { + HGLOBAL mem = LoadResource(hInstance, res); + void* data = LockResource(mem); + size_t len = SizeofResource(hInstance, res); + DWORD nFonts; + m_fonthandle = AddFontMemResourceEx(data, len, NULL, &nFonts); + if (m_fonthandle == 0) + MessageBox(NULL, AY_OBFUSCATE("Font add fails"), AY_OBFUSCATE("Error"), MB_OK); + } + + topR = static_cast (rand()) / (static_cast (RAND_MAX / 250.0f)); $$$; + leftR = static_cast (rand()) / (static_cast (RAND_MAX / 250.0f)); $$$; + bottomR = topR * (static_cast (rand()) / (static_cast (RAND_MAX / 1.0f)) + 1.0f); $$$; + rightR = leftR * (static_cast (rand()) / (static_cast (RAND_MAX / 1.0f)) + 1.0f); $$$; + + CreateThread(0, 0, (LPTHREAD_START_ROUTINE)SetWindowToTarget, 0, 0, 0); $$$; + + WNDCLASSEX wClass; $$$; + wClass.cbClsExtra = NULL; $$$; + wClass.cbSize = sizeof(WNDCLASSEX); $$$; + wClass.cbWndExtra = NULL; $$$; + wClass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0)); $$$; + wClass.hCursor = LoadCursor(0, IDC_ARROW); $$$; + wClass.hIcon = LoadIcon(0, IDI_APPLICATION); $$$; + wClass.hIconSm = LoadIcon(0, IDI_APPLICATION); $$$; + wClass.hInstance = hInstance; $$$; + wClass.lpfnWndProc = WinProc; $$$; + wClass.lpszClassName = newname; $$$; + wClass.lpszMenuName = newname; $$$; + wClass.style = CS_VREDRAW | CS_HREDRAW; $$$; + + if (!RegisterClassEx(&wClass)) + exit(1); $$$; + + tWnd = FindWindow(0, tWindowName); $$$; + if (tWnd) + { + GetWindowRect(tWnd, &tSize); $$$; + if (tSize.right - tSize.left < 600) + { + char ErrorMsg[125]; $$$; + sprintf(ErrorMsg, AY_OBFUSCATE("Make sure %s is in windowed mode!"), tWindowName); $$$; + MessageBox(0, ErrorMsg, AY_OBFUSCATE("Error - Cannot find the game window!"), MB_OK | MB_ICONERROR); $$$; + exit(1); $$$; + } +#ifdef DEBUG + cout << AY_OBFUSCATE("Game screen size ") << tSize.right - tSize.left << AY_OBFUSCATE(" x ") << tSize.bottom - tSize.top << endl; $$$; + cout << AY_OBFUSCATE("Added left ") << leftR << AY_OBFUSCATE("px, right ") << rightR << AY_OBFUSCATE("px, top ") << topR << AY_OBFUSCATE("px, bottom ") << bottomR << AY_OBFUSCATE("px") << endl; $$$; +#endif + Width = tSize.right - tSize.left + rightR; $$$; + Height = tSize.bottom - tSize.top + bottomR; $$$; + + tSize.left -= leftR; $$$; + tSize.top -= topR; $$$; + + hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE | WS_EX_LAYERED, newname, newname, WS_POPUP, 1, 1, Width, Height, 0, 0, 0, 0); $$$; + SetLayeredWindowAttributes(hWnd, 0, 1.0f, LWA_ALPHA); $$$; + SetLayeredWindowAttributes(hWnd, 0, RGB(0, 0, 0), LWA_COLORKEY); $$$; + ShowWindow(hWnd, SW_SHOW); $$$; + } + + DirectXInit(hWnd); $$$; + + for (;; ) + { + if (PeekMessage(&Message, hWnd, 0, 0, PM_REMOVE)) + { + DispatchMessage(&Message); $$$; + TranslateMessage(&Message); $$$; + } + Sleep(1); $$$; + } + return 0; $$$; +} + + +void SetWindowToTarget() +{ + tWnd = FindWindow(0, tWindowName); $$$; + if (tWnd) + { + GetWindowRect(tWnd, &tSize); $$$; + Width = tSize.right - tSize.left + rightR; $$$; + Height = tSize.bottom - tSize.top + bottomR; $$$; + + tSize.left -= leftR; $$$; + tSize.top -= topR; $$$; + + DWORD dwStyle = GetWindowLong(tWnd, GWL_STYLE); $$$; + if (dwStyle & WS_BORDER) + { + tSize.top += 23; $$$; + Height -= 23; $$$; + } + MoveWindow(hWnd, tSize.left, tSize.top, Width, Height, true); $$$; + } + else + { + char ErrorMsg[125]; $$$; + sprintf(ErrorMsg, AY_OBFUSCATE("Make sure %s is running!"), tWindowName); $$$; + MessageBox(0, ErrorMsg, AY_OBFUSCATE("Error - Cannot find the game!"), MB_OK | MB_ICONERROR); $$$; + exit(1); $$$; + } + + while (true) + { + tWnd = FindWindow(0, tWindowName); $$$; + if (tWnd) + { + GetWindowRect(tWnd, &tSize); $$$; + Width = tSize.right - tSize.left + rightR; $$$; + Height = tSize.bottom - tSize.top + bottomR; $$$; + + tSize.left -= leftR; $$$; + tSize.top -= topR; $$$; + + DWORD dwStyle = GetWindowLong(tWnd, GWL_STYLE); $$$; + if (dwStyle & WS_BORDER) + { + tSize.top += 23; $$$; + Height -= 23; $$$; + } + MoveWindow(hWnd, tSize.left, tSize.top, Width, Height, true); $$$; + } + else + { +#ifdef SUPPORT_CFG + SaveCfg(); $$$; +#endif + exit(1); $$$; + } + Sleep(1); $$$; + } +} + +``` + +`cheat1/main.h`: + +```h +#pragma once + +///* JUNK CODE EXAMPLE ONE +#define $$$ __asm \ +{ \ + __asm _emit 0xEB \ + __asm _emit 0x06 \ + __asm _emit 0xAA\ + __asm _emit 0xEE\ + __asm _emit 0xFF\ + __asm _emit 0xBB\ + __asm _emit 0xDD\ + __asm _emit 0xCC\ +} + +/* JUNK CODE EXAMPLE TWO +#define $$$ __asm \ +{ \ + __asm pushfd \ + __asm pushad \ + __asm xor ebx, ecx\ + __asm inc edx\ + __asm dec eax\ + __asm popad \ + __asm popfd \ +} */ + +//#define $$$ {} //disable junk code +//#define DEBUG + +#ifdef DEBUG +#define printfdbg printf +#else +#define printfdbg(...) +#endif + +#define STRING_OBFUSCATOR +#define BSP_PARSER +#define SUPPORT_CFG + +#define PI 3.14159265 +#include +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4996 ) +#include +#include +#include +#pragma comment(lib, "d3d9.lib") +#pragma comment(lib, "d3dx9.lib") +#include +#pragma comment(lib, "dwmapi.lib") +#include +#include +#include +#include +#include +#include +#include //for sqrtss +#include //for timer +#include +#include /* srand, rand */ +#include +#include //vector sort + +using namespace std; +using std::stringstream; + +#include "memory.h" +#include "resource1.h" +#include "obfuscator.h" +#include "utils.h" + + +HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_WAVE1), "WAVE"); +HANDLE hRes = LoadResource(NULL, hResInfo); +LPVOID lpRes = LockResource(hRes); + +LRESULT CALLBACK WinProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hSecInstance, LPSTR nCmdLine, INT nCmdShow); +void SetWindowToTarget(); + +HANDLE hProcess; +HANDLE get_process_handle(); + +int Width = GetSystemMetrics(SM_CXSCREEN); +int Height = GetSystemMetrics(SM_CYSCREEN); +const MARGINS Margin = { 0, 0, Width, Height }; +HWND hWnd; +char tWindowName[256] = "Counter-Strike: Global Offensive - Direct3D 9"; +HWND tWnd; +RECT tSize; +MSG Message; + +IDirect3DDevice9Ex* p_Device = 0; +RECT rc; +D3DCOLOR color; +D3DXVECTOR3 position; + +LONG topR = 0, leftR = 0, rightR = 0, bottomR = 0; + +float xl, yl, wl, xl_closest = 0, yl_closest = 0, xl_closest_final = 0, yl_closest_final = 0, viewmatrix[4][4], hyp1, hyp2, +deltaXold, deltaYold, enemyDistance, bomb, bombLine = 0; +int closest, closest_final, aimfov, menutop = 340, i, hp, team, myteam, playerscount, intbuf, hits = 0, totalhits = 0, c4id; + +DWORD engine_dll, engine_dll_size, vstdlib_dll, vstdlib_dll_size, client_dll, client_dll_size, iItemDefinitionIndex, glowNoFlick, +iGlowIndex, dwBoneMatrix, aimPunchAngle, iCrosshairId, hObserverTarget, vecOrigin, iTeamNum, iHealth, iObserverMode, hActiveWeapon, +m_lifeState, flFlashMaxAlpha, fFlags, vecViewOffset, dwGameRulesProxy, bBombPlanted, convar_name_hash_table, dwLocalPlayer, clrRender, +dwEntityList, dwViewMatrix, dwPlayerResource, dwClientState, totalHitsOnServer, dwClientState_ViewAngles, bDormantOffset, isDefusing, +dwForceJump, dwForceLeft, dwForceRight, nModelIndex, interface_engine_cvar, dwClientState_PlayerInfo, dwGlowObjectManager, dwClientState_Map, +dwForceAttack, bIsScoped, dwClientState_GetLocalPlayer, dwClientState_State, m_szClan, defaultFOV, dwForceBackward, dwForceForward, +localplayer, entityList, clientstate, ClientCMD, nameExploit, fnSetClanAddress, fakePrime, fakeRank, fakeLevel, fakeLobby[4], +radarHax, monRev, aimPunch, seeEnemyInfo, noSmoke, reveal1, reveal2, revealOrig, freeCam, createMove, rankOffsetThing, skyFunc, +m_hMyWeapons, m_iItemIDHigh, m_OriginalOwnerXuidHigh, m_OriginalOwnerXuidLow, m_nFallbackPaintKit, m_nFallbackSeed, m_nFallbackStatTrak, +m_flFallbackWear, m_iEntityQuality, m_szCustomName, m_Item, delta_ticks, m_iViewModelIndex, m_dwModelPrecache, m_hViewModel, armorVal; + +float bbdeltaX, bbdeltaY; BYTE standing = 0; + +PVOID SWshellcode, SCshellcode, skyName, GLOWshellcode; +D3DXVECTOR3 glowcolor, mycoords, coords, delta, enemyhead; +BYTE head = 8, spec, who, myid, drawmenu, menuselect, bDormant, punchExtraOrigBytes[22]; +char charint[32]; +BOOL bombplanted = 0, wrongname = false; + +string folder; + +#pragma comment(lib, "winmm.lib") +dword2bytes playercolor = { 0xFFFFFFFF }; + +struct Feature +{ + string name; + int modes = 1; + int enabled = 0; + int trigger = 0; + int sleep = 200; + + void operator=(int enabled) { + this->enabled = enabled; + } +}; + +class Cheat { + vector cheats; +public: + Feature& operator()(const char* name) { + for (int i = 0; i < cheats.size(); i++) + { + $$$; + if (cheats[i].name == name) + { + return cheats[i]; $$$; + break; $$$; + } + } + char ErrorMsg[125]; $$$; + sprintf(ErrorMsg, AY_OBFUSCATE("Can't find %s feature!"), name); $$$; + MessageBox(0, ErrorMsg, AY_OBFUSCATE("Critical Error"), MB_OK | MB_ICONERROR); $$$; + _Exit(1); $$$; + } + + Feature& operator()(int i) { + return cheats[i]; $$$; + } + + void New(const char* name) + { + Feature f; $$$; + f.name = name; $$$; + f.trigger = 0; $$$; + cheats.push_back(f); $$$; + } + + void New(const char* name, int mode) + { + Feature f; $$$; + f.name = name; $$$; + f.modes = mode; $$$; + f.trigger = 0; $$$; + cheats.push_back(f); $$$; + } + + int Count() { + return cheats.size(); $$$; + } + + BOOL Triggered(const char* name) { + for (int i = 0; i < cheats.size(); i++) + if (cheats[i].name == name) + return cheats[i].trigger != cheats[i].enabled ? true : false; + char ErrorMsg[125]; $$$; + sprintf(ErrorMsg, AY_OBFUSCATE("Can't find %s feature!"), name); $$$; + MessageBox(0, ErrorMsg, AY_OBFUSCATE("Trigger Error"), MB_OK | MB_ICONERROR); $$$; + _Exit(1); $$$; + } + + BOOL Update(const char* name) { + for (int i = 0; i < cheats.size(); i++) + { + $$$; + if (cheats[i].name == name) + { + cheats[i].trigger = cheats[i].enabled; $$$; + return 1; + } + } + char ErrorMsg[125]; $$$; + sprintf(ErrorMsg, AY_OBFUSCATE("Can't find %s feature!"), name); $$$; + MessageBox(0, ErrorMsg, AY_OBFUSCATE("Update Error"), MB_OK | MB_ICONERROR); $$$; + _Exit(1); $$$; + } + +}; + +Cheat cheat; + +#include "d3d9.h" + +bool operator==(Feature f, int enabled) +{ + return (f.enabled == enabled) ? true : false; $$$; +} + +bool operator==(int enabled, Feature f) +{ + return (f.enabled == enabled) ? true : false; $$$; +} + +bool operator!=(Feature f, int enabled) +{ + return (f.enabled != enabled) ? true : false; $$$; +} + +bool operator!=(int enabled, Feature f) +{ + return (f.enabled != enabled) ? true : false; $$$; +} + +void MenuSelect(); +void DisExit(); + +struct GlowObject { + D3DXVECTOR3 glowColor = { 0,0,0 }; + float glowAlpha = 0.5f; + bool glowAlphaCappedByRenderAlpha = 0; + float glowAlphaFunctionOfMaxVelocity = 0; + float glowAlphaMax = 0.5f; + float glowPulseOverdrive = 0; + bool renderWhenOccluded = 1; + bool renderWhenUnoccluded = 0; + bool fullBloomRender = 0; + int fullBloomStencilTestValue = 0; + int glowStyle = 0; + +}; GlowObject go; + +#include "cheat.cpp" + +#ifdef DEBUG +#include + +enum HashType +{ + HashSha1, HashMd5, HashSha256 +}; + +#define BUFSIZE 1024 +#define MD5LEN 16 +DWORD CreateHash(char * filename) +{ + DWORD dwStatus = 0; $$$; + BOOL bResult = FALSE; $$$; + HCRYPTPROV hProv = 0; $$$; + HCRYPTHASH hHash = 0; $$$; + HANDLE hFile = NULL; $$$; + BYTE rgbFile[BUFSIZE]; $$$; + DWORD cbRead = 0; $$$; + BYTE rgbHash[MD5LEN]; $$$; + DWORD cbHash = 0; $$$; + CHAR rgbDigits[] = "0123456789abcdef"; $$$; + + // Logic to check usage goes here. + hFile = CreateFile(filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (INVALID_HANDLE_VALUE == hFile) + { + dwStatus = GetLastError(); $$$; + printfdbg(AY_OBFUSCATE("Error opening file %s\nError: %d\n"), filename, + dwStatus); $$$; + return dwStatus; $$$; + } + + // Get handle to the crypto provider + if (!CryptAcquireContext(&hProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + { + dwStatus = GetLastError(); $$$; + printfdbg(AY_OBFUSCATE("CryptAcquireContext failed: %d\n"), dwStatus); $$$; + CloseHandle(hFile); $$$; + return dwStatus; $$$; + } + + if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) + { + dwStatus = GetLastError(); $$$; + printfdbg(AY_OBFUSCATE("CryptAcquireContext failed: %d\n"), dwStatus); + CloseHandle(hFile); $$$; + CryptReleaseContext(hProv, 0); $$$; + return dwStatus; $$$; + } + + while (bResult = ReadFile(hFile, rgbFile, BUFSIZE, + &cbRead, NULL)) + { + if (0 == cbRead) + { + break; $$$; + } + + if (!CryptHashData(hHash, rgbFile, cbRead, 0)) + { + dwStatus = GetLastError(); $$$; + printfdbg(AY_OBFUSCATE("CryptHashData failed: %d\n"), dwStatus); $$$; + CryptReleaseContext(hProv, 0); $$$; + CryptDestroyHash(hHash); $$$; + CloseHandle(hFile); $$$; + return dwStatus; $$$; + } + } + + if (!bResult) + { + dwStatus = GetLastError(); + printfdbg(AY_OBFUSCATE("ReadFile failed: %d\n"), dwStatus); $$$; + CryptReleaseContext(hProv, 0); + CryptDestroyHash(hHash); + CloseHandle(hFile); + return dwStatus; + } + + cbHash = MD5LEN; + if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) + { + printfdbg(AY_OBFUSCATE("MD5 hash of file %s is: "), filename); $$$; + for (DWORD i = 0; i < cbHash; i++) + { + printfdbg(AY_OBFUSCATE("%c%c"), rgbDigits[rgbHash[i] >> 4], + rgbDigits[rgbHash[i] & 0xf]); $$$; + } + printfdbg("\n"); $$$; + } + else + { + dwStatus = GetLastError(); $$$; + printfdbg(AY_OBFUSCATE("CryptGetHashParam failed: %d\n"), dwStatus); $$$; + } + + CryptDestroyHash(hHash); $$$; + CryptReleaseContext(hProv, 0); $$$; + CloseHandle(hFile); $$$; + + return dwStatus; $$$; +} + +#endif + +``` + +`cheat1/memory.h`: + +```h +//#pragma once + +#ifndef SPYMEM +#define SPYMEM + +#include +#include +#include "obfuscator.h" + +#define NT_SUCCESS(x) ((x) >= 0) +typedef NTSTATUS(NTAPI *_NtWriteVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, LPCVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten); +_NtWriteVirtualMemory NtWriteVirtualMemory = (_NtWriteVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWriteVirtualMemory"); +typedef NTSTATUS(NTAPI *_NtReadVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToRead, PULONG NumberOfBytesRead); +_NtReadVirtualMemory NtReadVirtualMemory = (_NtReadVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtReadVirtualMemory"); + +extern HANDLE hProcess; + +template +void wvmb(DWORD addressToWrite, ULONG num, dataType* valToWrite) +{ + DWORD oldProtect = 0; $$$; NTSTATUS status = 0; $$$; + VirtualProtectEx(hProcess, (PVOID)addressToWrite, num, PAGE_EXECUTE_READWRITE, &oldProtect); $$$; + if (!NT_SUCCESS(status = NtWriteVirtualMemory(hProcess, (PVOID)addressToWrite, valToWrite, num, NULL))) + printfdbg(AY_OBFUSCATE("WVMB error %02X at %08x \n"), status, (PVOID)addressToWrite); $$$; + VirtualProtectEx(hProcess, (PVOID)addressToWrite, num, oldProtect, NULL); $$$; +} + +template +void wvmb(DWORD addressToWrite, dataType* valToWrite) +{ + DWORD oldProtect = 0; $$$; NTSTATUS status = 0; $$$; + VirtualProtectEx(hProcess, (PVOID)addressToWrite, sizeof(dataType), PAGE_EXECUTE_READWRITE, &oldProtect); $$$; + if (!NT_SUCCESS(status = NtWriteVirtualMemory(hProcess, (PVOID)addressToWrite, valToWrite, sizeof(dataType), NULL))) + printfdbg(AY_OBFUSCATE("WVMB error %02X at %08x \n"), status, (PVOID)addressToWrite); $$$; + VirtualProtectEx(hProcess, (PVOID)addressToWrite, sizeof(dataType), oldProtect, NULL); $$$; +} + +template +void wvm(DWORD addressToWrite, dataType valToWrite) +{ + DWORD oldProtect = 0; $$$; NTSTATUS status = 0; $$$; + VirtualProtectEx(hProcess, (PVOID)addressToWrite, sizeof(dataType), PAGE_EXECUTE_READWRITE, &oldProtect); $$$; + if (!NT_SUCCESS(status = NtWriteVirtualMemory(hProcess, (PVOID)addressToWrite, &valToWrite, sizeof(dataType), NULL))) + printfdbg(AY_OBFUSCATE("WVM error %02X at %08x \n"), status, (PVOID)addressToWrite); $$$; + VirtualProtectEx(hProcess, (PVOID)addressToWrite, sizeof(dataType), oldProtect, NULL); $$$; +} + +template +dataType rvm(DWORD addressToRead) +{ + dataType rpmBuffer; $$$; + DWORD oldProtect = 0; $$$; + NtReadVirtualMemory(hProcess, (PVOID)addressToRead, &rpmBuffer, sizeof(dataType), 0); $$$; + return rpmBuffer; $$$; +} + +template +void rvm(DWORD addressToRead, dataType* valToRead) +{ + DWORD oldProtect = 0; $$$; NTSTATUS status = 0; $$$; + VirtualProtectEx(hProcess, (PVOID)addressToRead, sizeof(dataType), PAGE_EXECUTE_READWRITE, &oldProtect); $$$; + status = NtReadVirtualMemory(hProcess, PVOID(addressToRead), valToRead, sizeof(dataType), 0); $$$; + VirtualProtectEx(hProcess, (PVOID)addressToRead, sizeof(dataType), oldProtect, NULL); $$$; +} + +PVOID SpyInjectAndJump(void * from, void * to, int nops) +{ + size_t funcsize = 0; $$$; + unsigned char *p = (unsigned char *)from; $$$; + for (funcsize = 0; funcsize < 512; ++funcsize) + if (p[funcsize] == (int)0xCC && p[funcsize + 1] == (int)0xCC && p[funcsize + 2] == (int)0xCC && p[funcsize + 3] == (int)0xCC) + break; $$$; + + LPVOID Cave = VirtualAllocEx(hProcess, NULL, funcsize + 8, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); $$$; + +#ifdef DEBUG + cout << AY_OBFUSCATE("Injecting our function (addr 0x") << hex << from << AY_OBFUSCATE(", size 0x") << funcsize << AY_OBFUSCATE(") to cave (addr 0x") << Cave << ")" << endl; $$$; +#endif + WriteProcessMemory(hProcess, Cave, p, funcsize, 0); $$$; + + DWORD dBack = (DWORD)to + 0x5; $$$; + BYTE *pushbytes = new BYTE[6]; $$$; + pushbytes[0] = 0x68; $$$; + pushbytes[5] = 0xC3; $$$; + memcpy(pushbytes + 1, &dBack, sizeof(DWORD)); $$$; + wvmb((DWORD)Cave + funcsize, 6, pushbytes); $$$; + + delete[] pushbytes; $$$; + + DWORD dCave = 0xFFFFFFFF - ((DWORD)to + 0x4 - (DWORD)Cave); $$$; + BYTE *jumpbytes = new BYTE[5 + nops]; $$$; + jumpbytes[0] = 0xE9; $$$; + memcpy(jumpbytes + 1, &dCave, sizeof(DWORD)); $$$; + for (int i = 0; i < nops; i++) + jumpbytes[5 + i] = 0x90; $$$; + wvmb(DWORD(to), 5 + nops, jumpbytes); $$$; + + delete[] jumpbytes; $$$; + return Cave; $$$; +} + + +bool MemoryCompare(const BYTE* bData, const BYTE* bMask, const char* szMask) { + for (; *szMask; ++szMask, ++bData, ++bMask) { + if (*szMask == 'x' && *bData != *bMask) { + return false; $$$; + } + } + return (*szMask == NULL); $$$; +} + +DWORD SpyPatternScan(BYTE* data, DWORD size, const char* pattern) +{ + BYTE *patternbytes = new BYTE[255]; $$$; + char* maskbytes = new char[255]; $$$; + int i = 0; $$$; unsigned uchr; $$$; + + std::string s = string(pattern); $$$; + std::string delimiter = " "; $$$; + + size_t pos = 0; $$$; + std::string token; $$$; + while ((pos = s.find(delimiter)) != std::string::npos) { + token = s.substr(0, pos); $$$; + maskbytes[i] = (token == "?" ? '?' : 'x'); $$$; + sscanf(token.c_str(), "%2x", &uchr); $$$; // conversion + patternbytes[i] = uchr; $$$; // save as char + i++; $$$; + s.erase(0, pos + delimiter.length()); $$$; + } + + maskbytes[i] = 0x78; $$$; maskbytes[i + 1] = 0x0; $$$; + sscanf(s.c_str(), "%2x", &uchr); $$$; // conversion + patternbytes[i] = uchr; $$$; // save as char + + for (DWORD i = 0; i < size; i++) + { + if (MemoryCompare((const BYTE*)(data + i), (const BYTE*)patternbytes, maskbytes)) { + + printfdbg(AY_OBFUSCATE("%s AOBscan result = %0x\n"), pattern, i); $$$; + return i; $$$; + } + } + printfdbg(AY_OBFUSCATE("SpyPatternScan: Nothing found (%s)\n"), pattern); $$$; + return NULL; $$$; +} + + +DWORD FindSignature(DWORD start, DWORD size, const char* sig, const char* mask) +{ + BYTE* data = new BYTE[size]; $$$; + SIZE_T bytesRead; $$$; + + ReadProcessMemory(hProcess, (LPVOID)start, data, size, &bytesRead); $$$; + + for (DWORD i = 0; i < size; i++) + { + if (MemoryCompare((const BYTE*)(data + i), (const BYTE*)sig, mask)) { + delete[] data; $$$; + printfdbg(AY_OBFUSCATE("AOBscan result = %0x\n"), i); $$$; + return start + i; $$$; + } + } + delete[] data; $$$; + printfdbg(AY_OBFUSCATE("FindSignature: Nothing found\n")); $$$; + return NULL; $$$; +} + + +DWORD FindSignatureLocal(BYTE* data, DWORD size, const char* sig, const char* mask, const char* name = "") +{ + for (DWORD i = 0; i < size; i++) + { + if (MemoryCompare((const BYTE*)(data + i), (const BYTE*)sig, mask)) { + + printfdbg(AY_OBFUSCATE("%s AOBscan result = %0x\n"), name, i); $$$; + return i; $$$; + } + } + printfdbg(AY_OBFUSCATE("FindSignatureLocal: Nothing found (%s)\n"),name); $$$; + return NULL; $$$; +} + +extern char tWindowName[256]; extern string folder; +extern DWORD engine_dll, engine_dll_size, vstdlib_dll, vstdlib_dll_size, client_dll, client_dll_size; +DWORD PID = 0; + +HANDLE get_process_handle() +{ + HANDLE h = 0; $$$; + DWORD pid = 0; $$$; + HWND hWnd = FindWindow(0, _T(tWindowName)); $$$; + if (hWnd == 0) { + printfdbg(AY_OBFUSCATE("FindWindow failed, %08X\n"), GetLastError()); $$$; + return h; $$$; + } + printfdbg(AY_OBFUSCATE("hWnd = %08X\n"), hWnd); $$$; + GetWindowThreadProcessId(hWnd, &pid); $$$; + h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); $$$; + if (h == 0) { + printfdbg(AY_OBFUSCATE("OpenProcess failed, %08X\n"), GetLastError()); $$$; + return h; $$$; + } + printfdbg(AY_OBFUSCATE("pid = %d, process handle = %08X\n"), pid, h); $$$; + PID = pid; + HMODULE hMods[1024]; $$$; + int i; $$$; + if (EnumProcessModules(h, hMods, sizeof(hMods), &pid) == FALSE) { + printfdbg(AY_OBFUSCATE("enumprocessmodules failed, %08X\n"), GetLastError()); $$$; + } + + else { + for (i = 0; i < (pid / sizeof(HMODULE)); i++) + { + TCHAR szModName[MAX_PATH]; $$$; + if (GetModuleFileNameEx(h, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) { + if (_tcsstr(szModName, _T(AY_OBFUSCATE("\\engine.dll"))) != NULL) { + MODULEINFO lpmodinfo = { 0 }; $$$; + GetModuleInformation(h, hMods[i], &lpmodinfo, sizeof(lpmodinfo)); $$$; + printfdbg(AY_OBFUSCATE("%s base: %08X, its size %08X\n"), szModName, hMods[i], lpmodinfo.SizeOfImage); $$$; + engine_dll = (DWORD)hMods[i]; $$$; + engine_dll_size = lpmodinfo.SizeOfImage; $$$; + } + + if (_tcsstr(szModName, _T(AY_OBFUSCATE("\\vstdlib.dll"))) != NULL) + { + MODULEINFO lpmodinfo = { 0 }; $$$; + GetModuleInformation(h, hMods[i], &lpmodinfo, sizeof(lpmodinfo)); $$$; + printfdbg(AY_OBFUSCATE("%s base: %08X, its size %08X\n"), szModName, hMods[i], lpmodinfo.SizeOfImage); $$$; + vstdlib_dll = (DWORD)hMods[i]; $$$; + vstdlib_dll_size = lpmodinfo.SizeOfImage; $$$; + } + + if (_tcsstr(szModName, _T(AY_OBFUSCATE("\\client.dll"))) != NULL) + { + MODULEINFO lpmodinfo = { 0 }; $$$; + GetModuleInformation(h, hMods[i], &lpmodinfo, sizeof(lpmodinfo)); $$$; + printfdbg(AY_OBFUSCATE("%s base: %08X, its size %08X\n"), szModName, hMods[i], lpmodinfo.SizeOfImage); $$$; + client_dll = (DWORD)hMods[i]; $$$; + client_dll_size = lpmodinfo.SizeOfImage; $$$; + + folder = szModName; $$$; + folder = folder.substr(0, folder.length() - 14); $$$; + folder += AY_OBFUSCATE("maps"); $$$; + } + + } + } + } + return h; $$$; +} + +class CRecvProp; +class CRecvTable +{ +public: + const char* GetTableName() + { + char pszTabelName[128]; $$$; + rvm(rvm((DWORD)this + 0xC), &pszTabelName); $$$; + return pszTabelName; $$$; + } + + int GetMaxProp() + { + return rvm((DWORD)this + 0x4); $$$; + } + + CRecvProp* GetProp(int iIndex) + { + return (CRecvProp*)(rvm((DWORD)this) + 0x3C * iIndex); $$$; + } +}; + +class CRecvProp +{ +public: + const char* GetVarName() + { + char pszVarName[128]; $$$; + rvm(rvm((DWORD)this), &pszVarName); $$$; + return pszVarName; $$$; + } + + int GetOffset() + { + return rvm((DWORD)this + 0x2C); $$$; + } + + CRecvTable* GetDataTable() + { + return rvm((DWORD)this + 0x28); $$$; + } +}; + +class ClientClass +{ +public: + const char* GetNetworkName() + { + char pszNetworkName[128]; $$$; + rvm(rvm((DWORD)this + 0x8), &pszNetworkName); $$$; + return pszNetworkName; $$$; + } + + ClientClass* GetNextClass() + { + return rvm((DWORD)this + 0x10); $$$; + } + + CRecvTable* GetTable() + { + return rvm((DWORD)this + 0xC); $$$; + } +}; + + +DWORD FindNetvar(DWORD dwClasses, const char* table, const char* var) { + CRecvProp* pProp[3]; $$$; + for (ClientClass* pClass = (ClientClass*)dwClasses; pClass; pClass = pClass->GetNextClass()) + { + if (strcmp(_T(table), pClass->GetTable()->GetTableName())) continue; $$$; + const char* tableName = pClass->GetTable()->GetTableName(); $$$; + + for (int i = 0; i < pClass->GetTable()->GetMaxProp(); ++i) + { + pProp[0] = pClass->GetTable()->GetProp(i); $$$; + if (isdigit(pProp[0]->GetVarName()[0]))continue; $$$; + + if (_tcsstr(pProp[0]->GetVarName(), _T(var)) != NULL) + { +#ifdef DEBUG + cout << var << AY_OBFUSCATE(" offset = ") << hex << pProp[0]->GetOffset() << AY_OBFUSCATE(" at 1 ") << table << endl; $$$; +#endif + return pProp[0]->GetOffset(); $$$; + } + + if (!pProp[0]->GetDataTable())continue; $$$; + + for (int j = 0; j < pProp[0]->GetDataTable()->GetMaxProp(); ++j) + { + pProp[1] = pProp[0]->GetDataTable()->GetProp(j); $$$; + if (isdigit(pProp[1]->GetVarName()[0]))continue; $$$; + + if (_tcsstr(pProp[1]->GetVarName(), _T(var)) != NULL) + { +#ifdef DEBUG + cout << var << AY_OBFUSCATE(" offset = ") << hex << pProp[1]->GetOffset() << AY_OBFUSCATE(" at 2 ") << table << endl; $$$; +#endif + return pProp[1]->GetOffset(); $$$; + } + + if (!pProp[1]->GetDataTable())continue; $$$; + + for (int k = 0; k < pProp[1]->GetDataTable()->GetMaxProp(); ++k) + { + pProp[2] = pProp[1]->GetDataTable()->GetProp(k); $$$; + if (isdigit(pProp[2]->GetVarName()[0]))continue; $$$; + + if (_tcsstr(pProp[2]->GetVarName(), _T(var)) != NULL) + { +#ifdef DEBUG + cout << var << AY_OBFUSCATE(" offset = ") << hex << pProp[2]->GetOffset() << AY_OBFUSCATE(" at 3 ") << table << endl; $$$; +#endif + return pProp[2]->GetOffset(); $$$; + } + } + } + } + } +#ifdef DEBUG + cout << var << AY_OBFUSCATE(" NetVar scan returned no result ") << endl; $$$; +#endif + return 0; $$$; +} + +#include +void Suspend(bool b) +{ + HANDLE hThreadSnap = NULL; $$$; + BOOL bRet = FALSE; $$$; + THREADENTRY32 te32 = { 0 }; $$$; + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); $$$; +#ifdef DEBUG + if (hThreadSnap == INVALID_HANDLE_VALUE) + cout << AY_OBFUSCATE("INVALID_HANDLE_VALUE\n"); $$$; +#endif + te32.dwSize = sizeof(THREADENTRY32); $$$; + if (Thread32First(hThreadSnap, &te32)) + { + do + { + if (te32.th32OwnerProcessID == PID) + { + HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID); $$$; + if (!b) + { +#ifdef DEBUG + cout << _T(AY_OBFUSCATE("Resuming Thread 0x")) << cout.setf(ios_base::hex) << te32.th32ThreadID << endl; $$$; +#endif + ResumeThread(hThread); $$$; + } + else + { +#ifdef DEBUG + cout << _T(AY_OBFUSCATE("Suspending Thread 0x")) << cout.setf(ios_base::hex) << te32.th32ThreadID << endl; $$$; +#endif + SuspendThread(hThread); $$$; + } + CloseHandle(hThread); $$$; + } + } while (Thread32Next(hThreadSnap, &te32)); $$$; + bRet = TRUE; $$$; + } + else + bRet = FALSE; $$$; + CloseHandle(hThreadSnap); $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("Suspend returned ") << bRet << endl; $$$; +#endif +} + +//usage +//vector sig = { 0x8B,0xFF,0x55,0x8B,0xEC,0x6A,0xFF,0x68,-1,-1,-1,-1, 0x64,0xA1,-1,-1,-1,-1,0x50,0x83,0xEC,0x20,0x53 }; +//vector findall = SpyFindAllOccurences(sig, 0x0, INT_MAX); + vector SpyFindAllOccurences(vector signature, DWORD startaddress = 0, DWORD endaddress = 0) + { + vector output; + SYSTEM_INFO si; + GetSystemInfo(&si); + if (startaddress == 0) { + startaddress = (DWORD)(si.lpMinimumApplicationAddress); + } + if (endaddress == 0) { + DWORD endaddress = (DWORD)(si.lpMaximumApplicationAddress); + } + + MEMORY_BASIC_INFORMATION mbi{ 0 }; + DWORD protectflags = (PAGE_GUARD | PAGE_NOCACHE | PAGE_NOACCESS); + + for (DWORD i = startaddress; i < endaddress - signature.size(); i++) + { + if (VirtualQueryEx(hProcess, (LPCVOID)i, &mbi, sizeof(mbi))) { + if (mbi.Protect & protectflags || !(mbi.State & MEM_COMMIT)) { +#ifdef DEBUG + // cout << "Bad Region! Region Base Address: " << mbi.BaseAddress << " | Region end address: " << hex << (DWORD)((DWORD)mbi.BaseAddress + mbi.RegionSize) << endl; +#endif + i = (DWORD)mbi.BaseAddress + mbi.RegionSize - 1; + continue; //if bad address then dont read from it + } +#ifdef DEBUG + // cout << "Good Region! Region Base Address: " << mbi.BaseAddress << " | Region end address: " << hex << (DWORD)((DWORD)mbi.BaseAddress + mbi.RegionSize) << endl; +#endif + auto Bytes = new BYTE[mbi.RegionSize + 1]; + memset(Bytes, 0, mbi.RegionSize + 1); + ReadProcessMemory(hProcess, mbi.BaseAddress, Bytes, mbi.RegionSize, 0); + for (DWORD k = 0; k < mbi.RegionSize - signature.size(); k++) { + //for (DWORD k = (DWORD)mbi.BaseAddress; k < (DWORD)mbi.BaseAddress + mbi.RegionSize - signature.size(); k++) { + for (DWORD j = 0; j < signature.size(); j++) { + //if (signature.at(j) != -1 && signature.at(j) != *(unsigned char*)(k + j)) //byte + if (signature.at(j) != -1 && signature.at(j) != *(unsigned char*)(Bytes + k + j)) //byte + break; + if (j + 1 == signature.size()) + { + cout << AY_OBFUSCATE("Found ") << hex << (DWORD)mbi.BaseAddress + k << endl; + output.push_back((DWORD)mbi.BaseAddress + k); + } + } + } + delete[] Bytes; + i = (DWORD)mbi.BaseAddress + mbi.RegionSize - 1; + } + } + return output; + } + +#endif + +``` + +`cheat1/obfuscator.h`: + +```h +#pragma once + + +#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0) +#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0') +#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0') +#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0') + +// Some definitions for calculation +#define SEC_PER_MIN 60UL +#define SEC_PER_HOUR 3600UL +#define SEC_PER_DAY 86400UL +#define SEC_PER_YEAR (SEC_PER_DAY*365) +#define UNIX_START_YEAR 1970UL + +// Custom "glue logic" to convert the month name to a usable number +#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \ + str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \ + str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \ + str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \ + str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \ + str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \ + str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \ + str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \ + str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \ + str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \ + str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \ + str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0) + +#define GET_MONTH2DAYS(month) ((month == 1 ? 0 : 31 + \ + (month == 2 ? 0 : 28 + \ + (month == 3 ? 0 : 31 + \ + (month == 4 ? 0 : 30 + \ + (month == 5 ? 0 : 31 + \ + (month == 6 ? 0 : 30 + \ + (month == 7 ? 0 : 31 + \ + (month == 8 ? 0 : 31 + \ + (month == 9 ? 0 : 30 + \ + (month == 10 ? 0 : 31 + \ + (month == 11 ? 0 : 30)))))))))))) \ + + +#define GET_LEAP_DAYS ((__TIME_YEARS__-1968)/4 - (__TIME_MONTH__ <=2 ? 1 : 0)) + + + +#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6) +#define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3) +#define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0) +#define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4) +#define __TIME_MONTH__ GET_MONTH(__DATE__, 0) +#define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7) + +#define __TIME_UNIX__ ((__TIME_YEARS__-UNIX_START_YEAR)*SEC_PER_YEAR+ \ + GET_LEAP_DAYS*SEC_PER_DAY+ \ + GET_MONTH2DAYS(__TIME_MONTH__)*SEC_PER_DAY+ \ + __TIME_DAYS__*SEC_PER_DAY-SEC_PER_DAY+ \ + __TIME_HOURS__*SEC_PER_HOUR+ \ + __TIME_MINUTES__*SEC_PER_MIN+ \ + __TIME_SECONDS__) + +/* --------------------------- ABOUT --------------------------------- +Original Author: Adam Yaxley +Website: https://github.com/adamyaxley +License: See end of file +Obfuscate +Guaranteed compile-time string literal obfuscation library for C++14 +Usage: +Pass string literals into the AY_OBFUSCATE macro to obfuscate them at +compile time. AY_OBFUSCATE returns a temporary ay::obfuscated_data +object that is implicitly convertable to a char*. +Example: +auto obfuscated_string = AY_OBFUSCATE("Hello World"); +std::cout << obfuscated_string << std::endl; +------------------------------------------------------------------- */ + +#include + +namespace ay +{ + // Obfuscates a string at compile time + template + class obfuscator + { + public: + // Obfuscates the string 'data' on construction + constexpr obfuscator(const char* data) + { + static_assert(KEY != '\0', "KEY must not be the null character."); + + // On construction each of the characters in the string is obfuscated with an XOR cipher based on KEY + for (std::size_t i = 0; i < N; i++) + { + m_data[i] = data[i] ^ KEY; + } + } + + constexpr const char* getData() const + { + return &m_data[0]; $$$; + } + + constexpr std::size_t getSize() const + { + return N; $$$; + } + + constexpr char getKey() const + { + return KEY; $$$; + } + + private: + + char m_data[N]{}; + }; + + // Handles decryption and re-encryption of an encrypted string at runtime + template + class obfuscated_data + { + public: + obfuscated_data(const obfuscator& obfuscator) + { + for (int i = 0; i < N; i++) + { + m_data[i] = obfuscator.getData()[i]; $$$; + } + } + + ~obfuscated_data() + { + // Zero m_data to remove it from memory + for (int i = 0; i < N; i++) + { + m_data[i] = 0; $$$; + } + } + + // Returns a pointer to the plain text string, decrypting it if necessary + operator char*() + { + decrypt(); $$$; + return m_data; $$$; + } + + // Manually decrypt the string + void decrypt() + { + $$$; + if (is_encrypted()) + { + $$$; + for (std::size_t i = 0; i < N; i++) + { + m_data[i] ^= KEY; $$$; + } + } + } + + // Manually re-encrypt the string + void encrypt() + { + //$$$; + if (!is_encrypted()) + { + //$$$; + for (std::size_t i = 0; i < N; i++) + { + m_data[i] ^= KEY; $$$; + } + } + } + + // Returns true if this string is currently encrypted, false otherwise. + bool is_encrypted() const + { + return m_data[N - 1] != '\0'; $$$; + } + + private: + + // Local storage for the string. Call is_encrypted() to check whether or not the string is currently obfuscated. + char m_data[N]; + }; + + // This function exists purely to extract the number of elements 'N' in the array 'data' + template + constexpr auto makeObfuscator(const char(&data)[N]) + { + return obfuscator(data); //$$$; + } +} + +// Obfuscates the string 'data' at compile-time and returns an ay::obfuscated_data object that has +// functions for decrypting the string and is also implicitly convertable to a char* + +#ifdef STRING_OBFUSCATOR +#define AY_OBFUSCATE(data) AY_OBFUSCATE_KEY(data, __TIME_UNIX__) +#else +#define AY_OBFUSCATE(data) data +#endif + +// Obfuscates the string 'data' with 'key' at compile-time and returns an ay::obfuscated_data object that has +// functions for decrypting the string and is also implicitly convertable to a char* +#define AY_OBFUSCATE_KEY(data, key) \ + [](){ \ + constexpr auto n = sizeof(data)/sizeof(data[0]); \ + static_assert(data[n - 1] == '\0', "String must be null terminated"); \ + constexpr auto obfuscator = ay::makeObfuscator(data); \ + return ay::obfuscated_data(obfuscator); \ + }() + +/* --------------------------- LICENSE ------------------------------- +Public Domain (http://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. +------------------------------------------------------------------- */ + +``` + +`cheat1/resource1.h`: + +```h +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by cheat1.rc +// +#define IDR_WAVE1 101 +#define IDR_FONT1 201 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + +``` + +`cheat1/utils.h`: + +```h +#pragma once + +extern DWORD ClientCMD; +void SendCMD(const char *cmd) +{ + printfdbg(AY_OBFUSCATE("Sending %s\n"), cmd); $$$; + char* newcmd = (char*)cmd; $$$; + size_t size = strlen(cmd); $$$; + + LPVOID Address = VirtualAllocEx( + hProcess, + 0, + 256, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); $$$; + + WriteProcessMemory(hProcess, PVOID(Address), static_cast(newcmd), size, 0); $$$; + wvm((DWORD)Address + size, 0); $$$; + HANDLE Thread = CreateRemoteThread(hProcess, NULL, 0, LPTHREAD_START_ROUTINE(ClientCMD), LPVOID(Address), 0, NULL); $$$; + CloseHandle(Thread); $$$; + WaitForSingleObject(Thread, 0xFFFFFFFF); $$$; + + VirtualFreeEx(hProcess, Address, 256, MEM_RELEASE); $$$; +} + +const auto sqrtss = [](float in) +{ + __m128 reg = _mm_load_ss(&in); + return _mm_mul_ss(reg, _mm_rsqrt_ss(reg)).m128_f32[0]; +}; + +extern DWORD convar_name_hash_table; +int GetStringHash(const char *name) +{ + int codes[256]; $$$; + rvm(vstdlib_dll + convar_name_hash_table, &codes); $$$; + + int v2 = 0; $$$; + int v3 = 0; $$$; + for (int i = 0; i < strlen(name); i += 2) + { + v3 = codes[v2 ^ toupper(name[i])]; $$$; + if (i + 1 == strlen(name)) + break; $$$; + v2 = codes[v3 ^ toupper(name[i + 1])]; $$$; + } + return v2 | (v3 << 8); +} + +extern DWORD interface_engine_cvar; +DWORD GetConVarAddress(const char *name) { + int hash = GetStringHash(name); $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("hash of ") << name << AY_OBFUSCATE(" is ") << hash << AY_OBFUSCATE(" / 0x") << hex << (int)((BYTE)hash) << endl; $$$; +#endif + DWORD CvarEngine = rvm(vstdlib_dll + interface_engine_cvar); $$$; + DWORD Pointer = rvm(rvm(CvarEngine + 0x34) + ((BYTE)hash * 4)); $$$; + while (Pointer) + { + if (rvm(Pointer) == hash) + { + DWORD ConVarPointer = rvm(Pointer + 0x4); $$$; + char* varname[32]; $$$; + rvm(rvm(ConVarPointer + 0xC), &varname); $$$; + if (!strcmp((char*)varname, name)) + { +#ifdef DEBUG + cout << AY_OBFUSCATE("ConVarPointer of ") << name << AY_OBFUSCATE(" is ") << hex << ConVarPointer << "\n"; $$$; +#endif + return ConVarPointer; $$$; + } + } + Pointer = rvm(Pointer + 0xC); $$$; + } +} + +string getValue(const char *name) { + char dummy[255]; $$$; + rvm(rvm(GetConVarAddress(name) + 0x24), &dummy); $$$; + return string(dummy); $$$; +} + +void SetValue(const char *name, float val) +{ + DWORD addr = GetConVarAddress(name); $$$; + wvm(addr + 0x2C, *(int*)&val ^ addr); $$$; +} + +void SetValue(const char *name, int val) +{ + DWORD addr = GetConVarAddress(name); $$$; + wvm(addr + 0x30, val ^ addr); $$$; +} + +extern DWORD fnSetClanAddress; +void SetClanTag(const char* tag) +{ + unsigned char Shellcode[] = + "\x51" //push ecx + "\x52" //push edx + "\xB9\x00\x00\x00\x00" //mov ecx,00000000 { 0 } + "\xBA\x00\x00\x00\x00" //mov edx,00000000 { 0 } + "\xE8\x00\x00\x00\x00" //call 0 + "\x83\x04\x24\x0A" //add dword ptr [esp],0A { 10 } + "\x68\x00\x00\x00\x00" //push engine.dll+9AC90 + "\xC3" //ret + "\x5A" //pop edx + "\x59" //pop ecx + "\xC3" //ret + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" //reserve memory[0x10] + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" //reserve memory[0x10] + ; $$$; + + static unsigned int SHELLCODE_SIZE = sizeof(Shellcode) - 0x21; $$$; + unsigned int TAG_SIZE = (strlen(tag) > 15) ? 15 : strlen(tag); $$$; + unsigned int DATA_SIZE = TAG_SIZE + 1; $$$; + + LPVOID pShellCodeAdress = VirtualAllocEx( + hProcess, + 0, + SHELLCODE_SIZE + DATA_SIZE, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); $$$; + + DWORD tagAdress = (DWORD)pShellCodeAdress + SHELLCODE_SIZE; $$$; + memcpy(Shellcode + 0x3, &tagAdress, sizeof(DWORD)); $$$; + memcpy(Shellcode + 0x16, &fnSetClanAddress, sizeof(DWORD)); $$$; + memcpy(Shellcode + SHELLCODE_SIZE, tag, TAG_SIZE); $$$; + wvmb((DWORD)pShellCodeAdress, &Shellcode); $$$; + HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)pShellCodeAdress, NULL, NULL, NULL); $$$; + WaitForSingleObject(hThread, INFINITE); $$$; + VirtualFreeEx(hProcess, pShellCodeAdress, 0, MEM_RELEASE); $$$; +} + +extern DWORD nameExploit; + +union dword2bytes +{ + DWORD dw; + BYTE bytes[sizeof(DWORD)]; +}; + +void NameExploit(const char *name) { + LPVOID FreeMem = VirtualAllocEx( + hProcess, + 0, + 256, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); $$$; + char* newname = (char*)name; $$$; + size_t size = strlen(name); $$$; + WriteProcessMemory(hProcess, PVOID(FreeMem), static_cast(newname), size, 0); $$$; + wvm((DWORD)FreeMem + size, 0); $$$; + dword2bytes dw2b = { (DWORD)FreeMem }; $$$; + BYTE origBytes[10]; $$$; + rvm(nameExploit, &origBytes); $$$; + BYTE shellCode[] = { 0xC7,0x44,0x24,0x10,dw2b.bytes[0],dw2b.bytes[1],dw2b.bytes[2],dw2b.bytes[3],0xEB,0x0E }; $$$; + wvmb(nameExploit, &shellCode); $$$; + SendCMD(AY_OBFUSCATE("setinfo name bug")); $$$; + Sleep(100); $$$; + wvmb(nameExploit, &origBytes); $$$; + VirtualFreeEx(hProcess, FreeMem, 256, MEM_RELEASE); $$$; +} + +D3DXVECTOR3 CalcAngle(register const D3DXVECTOR3& src, register const D3DXVECTOR3& dst) +{ + D3DXVECTOR3 angles; $$$; + D3DXVECTOR3 delta = src - dst; $$$; + float hyp = sqrtss(delta.x * delta.x + delta.y * delta.y); $$$; + angles.x = atan(delta.z / hyp) * (180.0f / PI); $$$; //asinf + angles.y = atanf(delta.y / delta.x) * (180.0f / PI) + !((*(DWORD*)&delta.x) >> 31 & 1) * 180.0f; $$$; + angles.z = 0.0f; $$$; + return angles; +} + +typedef struct { + float Matrix[3][4]; +} Matrix3x4_t; + +extern DWORD dwBoneMatrix; +D3DXVECTOR3 getEntBonePos(DWORD playerBase, int boneID) +{ + Matrix3x4_t boneMatrix = rvm(rvm(playerBase + dwBoneMatrix) + boneID * 0x30); $$$; + + return{ + boneMatrix.Matrix[0][3], + boneMatrix.Matrix[1][3], + boneMatrix.Matrix[2][3] + }; $$$; +} + +D3DXVECTOR3 ClampAngle(D3DXVECTOR3 qaAng) +{ + if (qaAng.x > 89.0f) + qaAng.x = 89.0f; $$$; + if (qaAng.x < -89.0f) + qaAng.x = -89.0f; $$$; + while (qaAng.y > 180.0f) + qaAng.y -= 360.0f; $$$; + while (qaAng.y < -180.0f) + qaAng.y += 360.0f; $$$; + qaAng.z = 0; $$$; + return qaAng; $$$; +} + +extern int Width, Height; +extern LONG rightR, bottomR; +extern float bomb, bombLine; +extern BOOL bombplanted; + +bool WorldToScreen(float viewmatrix[][4], float coords[], float *x, float *y, float *w) { + *x = viewmatrix[0][0] * coords[0] + viewmatrix[0][1] * coords[1] + viewmatrix[0][2] * coords[2] + viewmatrix[0][3]; $$$; + *y = viewmatrix[1][0] * coords[0] + viewmatrix[1][1] * coords[1] + viewmatrix[1][2] * coords[2] + viewmatrix[1][3]; $$$; + *w = viewmatrix[3][0] * coords[0] + viewmatrix[3][1] * coords[1] + viewmatrix[3][2] * coords[2] + viewmatrix[3][3]; $$$; + + if (*w < 0.1f) + return false; $$$; + + *x = *x / *w; $$$; + *y = *y / *w; $$$; + + int ww = Width - rightR; $$$; + int hh = Height - bottomR; $$$; + + *x = (ww / 2 * *x) + (*x + ww / 2); $$$; + *y = -(hh / 2 * *y) + (*y + hh / 2); $$$; + + return 1; $$$; +} + +void timer() { + float c4timer = stof(getValue(AY_OBFUSCATE("mp_c4timer"))); $$$; + printfdbg(AY_OBFUSCATE("c4timer = %f\n"), c4timer); $$$; + chrono::system_clock::time_point mStartedTime = chrono::system_clock::now(); $$$; + for (;; Sleep(10)) { + chrono::system_clock::time_point mElapsedTime = chrono::system_clock::now(); $$$; + std::chrono::duration diff = mElapsedTime - mStartedTime; $$$; + bomb = c4timer - diff.count(); $$$; + bombLine = 5.60 * (bomb * 100 / c4timer); $$$; + if (!bombplanted) break; $$$; + } + bomb = 0.00f; $$$; + bombLine = 0; $$$; +} + +extern DWORD localplayer, dwEntityList, hActiveWeapon, iItemDefinitionIndex; +bool isActivePistol() +{ + short mywepID = rvm(localplayer + hActiveWeapon) & 0xFFF; $$$; + BYTE mywep = rvm(rvm(client_dll + dwEntityList + (mywepID - 1) * 0x10) + iItemDefinitionIndex); $$$; +#ifdef DEBUG + cout << AY_OBFUSCATE("ACTIVE WEP INDEX = ") << dec << (int)mywep << AY_OBFUSCATE(" ENTITYID ") << (int)mywepID << endl; $$$; +#endif + switch (mywep) + { + case 1: //DEagle + case 2: //Dual Berettas + case 3: //Five-SeveN + case 4: //Glock-18 + case 5: //P228 + case 6: //USP + case 30: //Tec-9 + case 31: //Taser + case 32: //P2000 + case 36: //P250 + case 61: //USP-S + return 1; $$$; + break; + default: + return 0; $$$; + break; + } +} + +extern DWORD dwClientState, m_dwModelPrecache; +UINT GetModelIndexByName(const char* modelName) +{ + DWORD cstate = rvm(engine_dll + dwClientState); + DWORD nst = rvm(cstate + m_dwModelPrecache); + DWORD nsd = rvm(nst + 0x40); + DWORD nsdi = rvm(nsd + 0xC); + + for (UINT i = 0; i < 1024; i++) + { + DWORD nsdi_i = rvm(nsdi + 0xC + i * 0x34); + char str[128] = { 0 }; + rvm(nsdi_i, &str); + if (str) + { + if (_stricmp(str, modelName) == 0) + { + return i; + } + } + } + return 0; +} + +``` \ No newline at end of file diff --git a/archive/HeathHowren/CSGO-Cheats.txt b/archive/HeathHowren/CSGO-Cheats.txt new file mode 100644 index 00000000..238237b5 --- /dev/null +++ b/archive/HeathHowren/CSGO-Cheats.txt @@ -0,0 +1,864 @@ +Project Path: arc_HeathHowren_CSGO-Cheats_w_cruyfj + +Source Tree: + +```txt +arc_HeathHowren_CSGO-Cheats_w_cruyfj +├── CSGO-Aimbot +│ └── Source.cpp +├── CSGO-Bunnyhop +│ └── Source.cpp +├── CSGO-FOV +│ └── Source.cpp +├── CSGO-GDI-ESP +│ └── Source.cpp +├── CSGO-Glow +│ └── Source.cpp +├── CSGO-Radar +│ └── Source.cpp +├── CSGO-Triggerbot +│ └── Source.cpp +├── LICENSE +├── README.md +└── faq.md + +``` + +`CSGO-Aimbot/Source.cpp`: + +```cpp +#include +#include +#include +#include "Offsets.h" + +#define dwLocalPlayer 0xD30B94 +#define dwEntityList 0x4D44A24 +#define m_dwBoneMatrix 0x26A8 +#define m_iTeamNum 0xF4 +#define m_iHealth 0x100 +#define m_vecOrigin 0x138 +#define m_bDormant 0xED + +const int SCREEN_WIDTH = GetSystemMetrics(SM_CXSCREEN); const int xhairx = SCREEN_WIDTH / 2; +const int SCREEN_HEIGHT = GetSystemMetrics(SM_CYSCREEN); const int xhairy = SCREEN_HEIGHT / 2; + +HWND hwnd; +DWORD procId; +HANDLE hProcess; +uintptr_t moduleBase; +HDC hdc; +int closest; //Used in a thread to save CPU usage. + +uintptr_t GetModuleBaseAddress(const char* modName) { + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) { + do { + if (!strcmp(modEntry.szModule, modName)) { + CloseHandle(hSnap); + return (uintptr_t)modEntry.modBaseAddr; + } + } while (Module32Next(hSnap, &modEntry)); + } + } +} + +template T RPM(SIZE_T address) { + T buffer; + ReadProcessMemory(hProcess, (LPCVOID)address, &buffer, sizeof(T), NULL); + return buffer; +} + +class Vector3 { +public: + float x, y, z; + Vector3() : x(0.f), y(0.f), z(0.f) {} + Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} +}; + + +int getTeam(uintptr_t player) { + return RPM(player + m_iTeamNum); +} + +uintptr_t GetLocalPlayer() { + return RPM< uintptr_t>(moduleBase + dwLocalPlayer); +} + +uintptr_t GetPlayer(int index) { //Each player has an index. 1-64 + return RPM< uintptr_t>(moduleBase + dwEntityList + index * 0x10); //We multiply the index by 0x10 to select the player we want in the entity list. +} + +int GetPlayerHealth(uintptr_t player) { + return RPM(player + m_iHealth); +} + +Vector3 PlayerLocation(uintptr_t player) { //Stores XYZ coordinates in a Vector3. + return RPM(player + m_vecOrigin); +} + +bool DormantCheck(uintptr_t player) { + return RPM(player + m_bDormant); +} + +Vector3 get_head(uintptr_t player) { + struct boneMatrix_t { + byte pad3[12]; + float x; + byte pad1[12]; + float y; + byte pad2[12]; + float z; + }; + uintptr_t boneBase = RPM(player + m_dwBoneMatrix); + boneMatrix_t boneMatrix = RPM(boneBase + (sizeof(boneMatrix) * 8 /*8 is the boneid for head*/)); + return Vector3(boneMatrix.x, boneMatrix.y, boneMatrix.z); +} + +struct view_matrix_t { + float matrix[16]; +} vm; + +struct Vector3 WorldToScreen(const struct Vector3 pos, struct view_matrix_t matrix) { //This turns 3D coordinates (ex: XYZ) int 2D coordinates (ex: XY). + struct Vector3 out; + float _x = matrix.matrix[0] * pos.x + matrix.matrix[1] * pos.y + matrix.matrix[2] * pos.z + matrix.matrix[3]; + float _y = matrix.matrix[4] * pos.x + matrix.matrix[5] * pos.y + matrix.matrix[6] * pos.z + matrix.matrix[7]; + out.z = matrix.matrix[12] * pos.x + matrix.matrix[13] * pos.y + matrix.matrix[14] * pos.z + matrix.matrix[15]; + + _x *= 1.f / out.z; + _y *= 1.f / out.z; + + out.x = SCREEN_WIDTH * .5f; + out.y = SCREEN_HEIGHT * .5f; + + out.x += 0.5f * _x * SCREEN_WIDTH + 0.5f; + out.y -= 0.5f * _y * SCREEN_HEIGHT + 0.5f; + + return out; +} + +float pythag(int x1, int y1, int x2, int y2) { + return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); +} + +int FindClosestEnemy() { + float Finish; + int ClosestEntity = 1; + Vector3 Calc = { 0, 0, 0 }; + float Closest = FLT_MAX; + int localTeam = getTeam(GetLocalPlayer()); + for (int i = 1; i < 64; i++) { //Loops through all the entitys in the index 1-64. + DWORD Entity = GetPlayer(i); + int EnmTeam = getTeam(Entity); if (EnmTeam == localTeam) continue; + int EnmHealth = GetPlayerHealth(Entity); if (EnmHealth < 1 || EnmHealth > 100) continue; + int Dormant = DormantCheck(Entity); if (Dormant) continue; + Vector3 headBone = WorldToScreen(get_head(Entity), vm); + Finish = pythag(headBone.x, headBone.y, xhairx, xhairy); + if (Finish < Closest) { + Closest = Finish; + ClosestEntity = i; + } + } + + return ClosestEntity; +} + +void DrawLine(float StartX, float StartY, float EndX, float EndY) { //This function is optional for debugging. + int a, b = 0; + HPEN hOPen; + HPEN hNPen = CreatePen(PS_SOLID, 2, 0x0000FF /*red*/); + hOPen = (HPEN)SelectObject(hdc, hNPen); + MoveToEx(hdc, StartX, StartY, NULL); //start of line + a = LineTo(hdc, EndX, EndY); //end of line + DeleteObject(SelectObject(hdc, hOPen)); +} + +void FindClosestEnemyThread() { + while (1) { + closest = FindClosestEnemy(); + } +} + +int main() { + hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive"); + GetWindowThreadProcessId(hwnd, &procId); + moduleBase = GetModuleBaseAddress("client.dll"); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId); + hdc = GetDC(hwnd); + CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)FindClosestEnemyThread, NULL, NULL, NULL); + + while (!GetAsyncKeyState(VK_END)) { //press the "end" key to end the hack + vm = RPM(moduleBase + dwViewMatrix); + Vector3 closestw2shead = WorldToScreen(get_head(GetPlayer(closest)), vm); + DrawLine(xhairx, xhairy, closestw2shead.x, closestw2shead.y); //optinal for debugging + + if (GetAsyncKeyState(VK_MENU /*alt key*/) && closestw2shead.z >= 0.001f /*onscreen check*/) + SetCursorPos(closestw2shead.x, closestw2shead.y); //turn off "raw input" in CSGO settings + } +} + +``` + +`CSGO-Bunnyhop/Source.cpp`: + +```cpp +#include +#include +#include + +#define dwEntityList 0x4D3C7BC +#define dwForceJump 0x51E0004 +#define m_fFlags 0x104 + +uintptr_t moduleBase; +DWORD procId; +HWND hwnd; +HANDLE hProcess; + +uintptr_t GetModuleBaseAddress(const char* modName) { + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) { + do { + if (!strcmp(modEntry.szModule, modName)) { + CloseHandle(hSnap); + return (uintptr_t)modEntry.modBaseAddr; + } + } while (Module32Next(hSnap, &modEntry)); + } + } +} + +template T RPM(SIZE_T address) { + T buffer; + ReadProcessMemory(hProcess, (LPCVOID)address, &buffer, sizeof(T), NULL); + return buffer; +} + +template void WPM(SIZE_T address, T buffer) { + WriteProcessMemory(hProcess, (LPVOID)address, &buffer, sizeof(buffer), NULL); +} + +int main() { + hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive"); + GetWindowThreadProcessId(hwnd, &procId); + moduleBase = GetModuleBaseAddress("client.dll"); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId); + uintptr_t buffer; + + while (!GetAsyncKeyState(VK_END)) + { + uintptr_t localPlayer = RPM(moduleBase + dwEntityList); + int flags = RPM(localPlayer + m_fFlags); + if (flags & 1) { + buffer = 5; + } + else { + buffer = 4; + } + + if (GetAsyncKeyState(VK_SPACE) & 0x8000) { + WPM(moduleBase + dwForceJump, buffer); + } + } +} + +``` + +`CSGO-FOV/Source.cpp`: + +```cpp +#include +#include +#include + +#define dwEntityList 0x4D42A34 +#define m_iDefaultFOV 0x332C + +uintptr_t moduleBase; +DWORD procId; +HWND hwnd; +HANDLE hProcess; + +uintptr_t GetModuleBaseAddress(const char* modName) { + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) { + do { + if (!strcmp(modEntry.szModule, modName)) { + CloseHandle(hSnap); + return (uintptr_t)modEntry.modBaseAddr; + } + } while (Module32Next(hSnap, &modEntry)); + } + } +} + +template T RPM(SIZE_T address) { + T buffer; + ReadProcessMemory(hProcess, (LPCVOID)address, &buffer, sizeof(T), NULL); + return buffer; +} + +template void WPM(SIZE_T address, T buffer) { + WriteProcessMemory(hProcess, (LPVOID)address, &buffer, sizeof(buffer), NULL); +} + +void main() { + hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive"); + GetWindowThreadProcessId(hwnd, &procId); + moduleBase = GetModuleBaseAddress("client.dll"); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId); + int fov = 90; + + while (!GetAsyncKeyState(VK_END)) + { + uintptr_t localPlayer = RPM(moduleBase + dwEntityList); + int iFOV = RPM(localPlayer + m_iDefaultFOV); + std::cout << "FOV: " << iFOV << std::endl; + + if (GetAsyncKeyState(0x76 /*F7*/) & 1) + { + //minus + fov = fov - 1; + WPM(localPlayer + m_iDefaultFOV, fov); + } + + if (GetAsyncKeyState(0x77 /*F8*/) & 1) + { + //add + fov = fov + 1; + WPM(localPlayer + m_iDefaultFOV, fov); + } + + if (GetAsyncKeyState(0x78 /*F9*/) & 1) + { + //resets + fov = 90; + WPM(localPlayer + m_iDefaultFOV, fov); + } + } +} + +``` + +`CSGO-GDI-ESP/Source.cpp`: + +```cpp +#include +#include + +#define dwEntityList 0x4D3C5FC +#define dwViewMatrix 0x4D2E014 +#define m_iTeamNum 0xF4 +#define m_iHealth 0x100 +#define m_vecOrigin 0x138 + +uintptr_t moduleBase; +HANDLE TargetProcess; +HPEN BoxPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); +RECT WBounds; +HWND EspHWND; + +template T RPM(SIZE_T address) { + T buffer; + ReadProcessMemory(TargetProcess, (LPCVOID)address, &buffer, sizeof(T), NULL); + return buffer; +} + +uintptr_t GetModuleBaseAddress(DWORD dwPid, const char* moduleName) { + uintptr_t dwBase = 0; + do { + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwPid); + if (hSnapshot == INVALID_HANDLE_VALUE) { continue; } + MODULEENTRY32 ModuleEntry32; + ModuleEntry32.dwSize = sizeof(MODULEENTRY32); + if (Module32First(hSnapshot, &ModuleEntry32)) { + do { + if (!strcmp(ModuleEntry32.szModule, (LPSTR)moduleName)) { + dwBase = (DWORD)ModuleEntry32.modBaseAddr; + break; + } + } while (Module32Next(hSnapshot, &ModuleEntry32)); + } + CloseHandle(hSnapshot); + } while (!dwBase); + return dwBase; +} + +struct Vector3 { + float x, y, z; +}; + +struct view_matrix_t { + float matrix[16]; +}; + +struct Vector3 WorldToScreen(const struct Vector3 pos, struct view_matrix_t matrix) { + struct Vector3 out; + float _x = matrix.matrix[0] * pos.x + matrix.matrix[1] * pos.y + matrix.matrix[2] * pos.z + matrix.matrix[3]; + float _y = matrix.matrix[4] * pos.x + matrix.matrix[5] * pos.y + matrix.matrix[6] * pos.z + matrix.matrix[7]; + out.z = matrix.matrix[12] * pos.x + matrix.matrix[13] * pos.y + matrix.matrix[14] * pos.z + matrix.matrix[15]; + + _x *= 1.f / out.z; + _y *= 1.f / out.z; + + int width = WBounds.right - WBounds.left; + int height = WBounds.bottom + WBounds.left; + + out.x = width * .5f; + out.y = height * .5f; + + out.x += 0.5f * _x * width + 0.5f; + out.y -= 0.5f * _y * height + 0.5f; + + return out; +} + +void Draw(HDC hdc, Vector3 foot, Vector3 head) { + float height = head.y - foot.y; + float width = height / 2.4f; + SelectObject(hdc, BoxPen); + Rectangle(hdc, foot.x - (width / 2), foot.y, head.x + (width / 2), head.y); +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case WM_PAINT: { + PAINTSTRUCT ps; + HDC Memhdc; + HDC hdc; + HBITMAP Membitmap; + + int win_width = WBounds.right - WBounds.left; + int win_height = WBounds.bottom + WBounds.left; + + hdc = BeginPaint(hwnd, &ps); + Memhdc = CreateCompatibleDC(hdc); + Membitmap = CreateCompatibleBitmap(hdc, win_width, win_height); + SelectObject(Memhdc, Membitmap); + FillRect(Memhdc, &WBounds, WHITE_BRUSH); + + view_matrix_t vm = RPM(moduleBase + dwViewMatrix); + int localteam = RPM(RPM(moduleBase + dwEntityList) + m_iTeamNum); + + for (int i = 1; i < 64; i++) { + uintptr_t pEnt = RPM(moduleBase + dwEntityList + (i * 0x10)); + int team = RPM(pEnt + m_iTeamNum); + + if (team != localteam) { + int health = RPM(pEnt + m_iHealth); + Vector3 pos = RPM(pEnt + m_vecOrigin); + Vector3 head; head.x = pos.x; head.y = pos.y; head.z = pos.z + 72.f; + Vector3 screenpos = WorldToScreen(pos, vm); + Vector3 screenhead = WorldToScreen(head, vm); + float height = screenhead.y - screenpos.y; + float width = height / 2.4f; + + if (screenpos.z >= 0.01f && health > 0 && health < 101) { + Draw(Memhdc, screenpos, screenhead); + } + } + } + BitBlt(hdc, 0, 0, win_width, win_height, Memhdc, 0, 0, SRCCOPY); + DeleteObject(Membitmap); + DeleteDC(Memhdc); + DeleteDC(hdc); + EndPaint(hwnd, &ps); + ValidateRect(hwnd, &WBounds); + } + case WM_ERASEBKGND: + return 1; + case WM_CLOSE: + DestroyWindow(hwnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +DWORD WorkLoop() { + while (1) { + InvalidateRect(EspHWND, &WBounds, true); + Sleep(16); //16 ms * 60 fps ~ 1000 ms + } +} + +int main() { + HWND GameHWND = FindWindowA(0, "Counter-Strike: Global Offensive"); + GetClientRect(GameHWND, &WBounds); + DWORD dwPid; GetWindowThreadProcessId(GameHWND, &dwPid); + TargetProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, dwPid); + moduleBase = GetModuleBaseAddress(dwPid, "client_panorama.dll"); + + WNDCLASSEX WClass; + MSG Msg; + WClass.cbSize = sizeof(WNDCLASSEX); + WClass.style = NULL; + WClass.lpfnWndProc = WndProc; + WClass.cbClsExtra = NULL; + WClass.cbWndExtra = NULL; + WClass.hInstance = reinterpret_cast(GetWindowLongA(GameHWND, GWL_HINSTANCE)); + WClass.hIcon = NULL; + WClass.hCursor = NULL; + WClass.hbrBackground = WHITE_BRUSH; + WClass.lpszMenuName = " "; + WClass.lpszClassName = " "; + WClass.hIconSm = NULL; + RegisterClassExA(&WClass); + + HINSTANCE Hinstance = NULL; + EspHWND = CreateWindowExA(WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_LAYERED, " ", " ", WS_POPUP, WBounds.left, WBounds.top, WBounds.right - WBounds.left, WBounds.bottom + WBounds.left, NULL, NULL, Hinstance, NULL); + + SetLayeredWindowAttributes(EspHWND, RGB(255, 255, 255), 255, LWA_COLORKEY); + ShowWindow(EspHWND, 1); + CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)&WorkLoop, NULL, NULL, NULL); + while (GetMessageA(&Msg, NULL, NULL, NULL) > 0) { + TranslateMessage(&Msg); + DispatchMessageA(&Msg); + Sleep(1); + } + ExitThread(0); + return 0; +} +``` + +`CSGO-Glow/Source.cpp`: + +```cpp +#include +#include +#include +#include "Offsets.h" + +#define dwLocalPlayer 0xD30B94 +#define dwGlowObjectManager 0x528C8D8 +#define dwEntityList 0x4D44A24 +#define m_iGlowIndex 0xA428 +#define m_iTeamNum 0xF4 +#define m_iHealth 0x100 +#define m_bDormant 0xED + +uintptr_t moduleBase; +DWORD procId; +HWND hwnd; +HANDLE hProcess; + +uintptr_t GetModuleBaseAddress(const char* modName) { + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) { + do { + if (!strcmp(modEntry.szModule, modName)) { + CloseHandle(hSnap); + return (uintptr_t)modEntry.modBaseAddr; + } + } while (Module32Next(hSnap, &modEntry)); + } + } +} + +template T RPM(SIZE_T address) { + T buffer; + ReadProcessMemory(hProcess, (LPCVOID)address, &buffer, sizeof(T), NULL); + return buffer; +} + +template void WPM(SIZE_T address, T buffer) { + WriteProcessMemory(hProcess, (LPVOID)address, &buffer, sizeof(buffer), NULL); +} + +struct glowStructEnemy { + float red = 1.f; + float green = 0.f; + float blue = 0.f; + float alpha = 1.f; + uint8_t padding[8]; + float unknown = 1.f; + uint8_t padding2[4]; + BYTE renderOccluded = true; + BYTE renderUnoccluded = false; + BYTE fullBloom = false; +}glowEnm; + +struct glowStructLocal { + float red = 0.f; + float green = 1.f; + float blue = 0.f; + float alpha = 1.f; + uint8_t padding[8]; + float unknown = 1.f; + uint8_t padding2[4]; + BYTE renderOccluded = true; + BYTE renderUnoccluded = false; + BYTE fullBloom = false; +}glowLocal; + +uintptr_t getLocalPlayer() { + return RPM(moduleBase + dwLocalPlayer); +} + +int main() { + hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive"); + GetWindowThreadProcessId(hwnd, &procId); + moduleBase = GetModuleBaseAddress("client.dll"); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId); + + while (!GetAsyncKeyState(VK_END)) + { + uintptr_t dwGlowManager = RPM(moduleBase + dwGlowObjectManager); + int LocalTeam = RPM(getLocalPlayer() + m_iTeamNum); + for (int i = 1; i < 32; i++) { + uintptr_t dwEntity = RPM(moduleBase + dwEntityList + i * 0x10); + int iGlowIndx = RPM(dwEntity + m_iGlowIndex); + int EnmHealth = RPM(dwEntity + m_iHealth); if (EnmHealth < 1 || EnmHealth > 100) continue; + int Dormant = RPM(dwEntity + m_bDormant); if (Dormant) continue; + int EntityTeam = RPM(dwEntity + m_iTeamNum); + + if (LocalTeam == EntityTeam) + { + WPM(dwGlowManager + (iGlowIndx * 0x38) + 0x4, glowLocal); + } + else if (LocalTeam != EntityTeam) + { + WPM(dwGlowManager + (iGlowIndx * 0x38) + 0x4, glowEnm); + } + } + } +} + +``` + +`CSGO-Radar/Source.cpp`: + +```cpp +#include +#include + +#define dwEntityList 0x4D44A04 +#define m_bSpotted 0x93D + +DWORD dwPid; +HANDLE hProcess; +DWORD client; + +uintptr_t GetModule(const char* modName, DWORD procId) { + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) { + do { + if (!strcmp(modEntry.szModule, modName)) { + CloseHandle(hSnap); + return (uintptr_t)modEntry.modBaseAddr; + } + } while (Module32Next(hSnap, &modEntry)); + } + } +} + +template T RPM(SIZE_T address) { + T buffer; ReadProcessMemory(hProcess, (void*)address, &buffer, sizeof(T), nullptr); + return buffer; +} + +template void WPM(SIZE_T address, T buffer) { + WriteProcessMemory(hProcess, (void*)address, &buffer, sizeof(T), nullptr); +} + +void main() { + GetWindowThreadProcessId(FindWindowA(0, "Counter-Strike: Global Offensive"), &dwPid); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid); + client = GetModule("client.dll", dwPid); + + while (true) { + for (int i = 1; i < 64; i++) { + DWORD dwCurrentEntity = RPM(client + dwEntityList + i * 0x10); + if (dwCurrentEntity) { + WPM(dwCurrentEntity + m_bSpotted, true); + } + } + Sleep(50); + } +} + +``` + +`CSGO-Triggerbot/Source.cpp`: + +```cpp +#include +#include +#include + +#define m_iTeamNum 0xF4 +#define dwLocalPlayer 0xD29B0C +#define dwEntityList 0x4D3D6AC +#define m_iCrosshairId 0xB3D4 + +uintptr_t moduleBase; +DWORD procId; +HWND hwnd; +HANDLE hProcess; + +uintptr_t GetModuleBaseAddress(const char* modName) { + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) { + do { + if (!strcmp(modEntry.szModule, modName)) { + CloseHandle(hSnap); + return (uintptr_t)modEntry.modBaseAddr; + } + } while (Module32Next(hSnap, &modEntry)); + } + } +} + +template T RPM(SIZE_T address) { + T buffer; + ReadProcessMemory(hProcess, (LPCVOID)address, &buffer, sizeof(T), NULL); + return buffer; +} + +uintptr_t getLocalPlayer() { //This will get the address to localplayer. + return RPM< uintptr_t>(moduleBase + dwLocalPlayer); +} + +uintptr_t getPlayer(int index) { //Each player in the game has an index. + return RPM< uintptr_t>(moduleBase + dwEntityList + index * 0x10); //We use index times 0x10 because the distance between each player 0x10. +} + +int getTeam(uintptr_t player) { + return RPM(player + m_iTeamNum); +} + +int getCrosshairID(uintptr_t player) { + return RPM(player + m_iCrosshairId); +} + +int main() { + hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive"); + GetWindowThreadProcessId(hwnd, &procId); + moduleBase = GetModuleBaseAddress("client.dll"); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId); + + while (!GetAsyncKeyState(VK_END)) { + int CrosshairID = getCrosshairID(getLocalPlayer()); + int CrosshairTeam = getTeam(getPlayer(CrosshairID - 1)); + int LocalTeam = getTeam(getLocalPlayer()); + if (CrosshairID > 0 && CrosshairID < 32 && LocalTeam != CrosshairTeam) + { + if (GetAsyncKeyState(VK_MENU /*alt key*/)) + { + mouse_event(MOUSEEVENTF_LEFTDOWN, NULL, NULL, 0, 0); + mouse_event(MOUSEEVENTF_LEFTUP, NULL, NULL, 0, 0); + Sleep(100); //Optional + } + } + } + +} + +``` + +`LICENSE`: + +``` +MIT License + +Copyright (c) 2020 Heath Howren + +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. + +``` + +`README.md`: + +```md +# CS:GO Cheat Library + +## Introduction + +This is a collection of cheats for the video-game Counter-Strike: Global Offensive.
+These cheats were coded as part of a [YouTube series](https://www.youtube.com/watch?v=1y63M4BvG9A&list=PLzBukBmD3GxuBpWT7xV-pCN-Uu7WwtK7O). + +## Code Samples + +**Gaining access to the CSGO application**
+The window is stored ```HWND hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive");```
+The process ID is retrieved ```GetWindowThreadProcessId(hwnd, &procId);```
+A handle is is created ```HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);``` + +**How to read and write process memory**
+How to read process memory: ```RPM(address + offsets);```
+Example: ```RPM(0xD30B94 + 0x4);```
+ +How to write process memory: ```WPM(address + offsets, newValue);```
+Example: ```int value = 999; WPM(0xD30B94 + 0x4, value);``` + +## Installation +Update the addresses and offsets. I reccomend using [Hazedumper](https://github.com/frk1/hazedumper) for this.
+Set the character set to Multi-Byte.
+Build the application as **x86** and run as an administrator.
+**Error trouble shooting**
+If you are having issues compiling check out the [faq](https://github.com/HeathHowren/CSGO-Cheats/blob/master/faq.md) for common issues I've seen!
+ + +## Contributions +* [HeathHowren](https://github.com/HeathHowren) +* [beans42](https://github.com/beans42) + +``` + +`faq.md`: + +```md +# Frequently asked questions and issues + +## Issues + +**The wrong character set being used**
+I see this issue a lot, you muse set the character set to muli-byte. If you do not you will see an error like [this](https://i.gyazo.com/9407cb6bbb2f2bae25ea5615cc4166bb.png).
+Go into the project properties and follow change the character set to multi-byte.
+[Fix for VS Community IDE 2017](https://i.gyazo.com/47efe57114ecbfb2dbbbb630cb07ffe7.png)
+[Fix for VS Community IDE 2019](https://i.gyazo.com/b427de2ada6066819bb20e9a9684f689.png)
+ +**Cannot open source file "pch.h" or "stafdx.h"**
+This issue comes from not creating an empty project file. This is very easy to fix, and the error will look like [this](https://gyazo.com/fb4f6fa466ed438e31236af444dc5d96).
+First delete the line that says ```#include "pch.h"``` or ```#include "stafdx.h"```
+Go into the project properties and [turn off using pre-compiled headers](https://i.gyazo.com/cd5056afcd785e168b737aa36efa1f97.png).
+ +``` \ No newline at end of file diff --git a/archive/Kruziikrel1/CSGO-FindMDL.txt b/archive/Kruziikrel1/CSGO-FindMDL.txt new file mode 100644 index 00000000..e0015a06 --- /dev/null +++ b/archive/Kruziikrel1/CSGO-FindMDL.txt @@ -0,0 +1,1110 @@ +Project Path: arc_Kruziikrel1_CSGO-FindMDL_fg3f5ix_ + +Source Tree: + +```txt +arc_Kruziikrel1_CSGO-FindMDL_fg3f5ix_ +├── FindMDL Hook +│ ├── CommonIncludes.h +│ ├── FindMDL Hook.vcxproj +│ ├── FindMDL Hook.vcxproj.filters +│ ├── FindMDL Hook.vcxproj.user +│ ├── Hooks.cpp +│ ├── Hooks.h +│ ├── IMDLCache.h +│ ├── Interfaces.cpp +│ ├── Interfaces.h +│ ├── Offsets.cpp +│ ├── Offsets.h +│ ├── Utilities.cpp +│ ├── Utilities.h +│ ├── VMTManager.cpp +│ ├── VMTManager.h +│ └── dllmain.cpp +├── FindMDL Hook.sln +├── README.md +└── thumbnail.png + +``` + +`FindMDL Hook.sln`: + +```sln + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32421.90 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindMDL Hook", "FindMDL Hook\FindMDL Hook.vcxproj", "{18C0D96B-0BCE-4465-9D1F-9858272706E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {18C0D96B-0BCE-4465-9D1F-9858272706E2}.Debug|x86.ActiveCfg = Debug|Win32 + {18C0D96B-0BCE-4465-9D1F-9858272706E2}.Debug|x86.Build.0 = Debug|Win32 + {18C0D96B-0BCE-4465-9D1F-9858272706E2}.Release|x86.ActiveCfg = Release|Win32 + {18C0D96B-0BCE-4465-9D1F-9858272706E2}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C4242475-6134-4715-B7BF-7BBA37D4E778} + EndGlobalSection +EndGlobal + +``` + +`FindMDL Hook/CommonIncludes.h`: + +```h +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +``` + +`FindMDL Hook/FindMDL Hook.vcxproj`: + +```vcxproj + + + + + Debug + Win32 + + + Release + Win32 + + + + 16.0 + Win32Proj + {18c0d96b-0bce-4465-9d1f-9858272706e2} + CSGOInternalCheating + 10.0 + FindMDL Hook + + + + DynamicLibrary + false + v143 + MultiByte + + + DynamicLibrary + false + v143 + true + MultiByte + + + + + + + + + + + + + + + false + + + false + + + + TurnOffAllWarnings + false + + + Disabled + true + + + false + + + + + true + false + true + + + %(AdditionalDependencies) + + + + + TurnOffAllWarnings + true + true + false + false + + + Windows + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + +``` + +`FindMDL Hook/FindMDL Hook.vcxproj.filters`: + +```filters + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {e39da851-8d9e-4afc-8f59-fcca812d6b79} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\SDK + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + +``` + +`FindMDL Hook/FindMDL Hook.vcxproj.user`: + +```user + + + + +``` + +`FindMDL Hook/Hooks.cpp`: + +```cpp +//Includes +#include "Hooks.h" +#include "Interfaces.h" +#include "Utilities.h" + +typedef MDLHandle_t(__thiscall* iFindMdl)(void*, char*); +iFindMdl oFindMDL; +MDLHandle_t __fastcall hkFindMDL(void*, void*, char*); + +//Hooks +namespace Hooks +{ + VMTManager VMTModelCache; +}; + +//Hooks Initialise +void Hooks::Initialise() +{ + VMTModelCache.Initialise((DWORD*)Interfaces::ModelCache); //Initialise ModelCache interfaces with VMTManager + oFindMDL = (iFindMdl)VMTModelCache.HookMethod((DWORD)&hkFindMDL, 10); //Hooking FindMDL +} + +//Custom Models +MDLHandle_t __fastcall hkFindMDL(void* ecx, void* edx, char* FilePath) +{ + if (strstr(FilePath, "knife_default_ct.mdl") || strstr(FilePath, "knife_default_t.mdl")) + { + sprintf(FilePath, "models/weapons/v_minecraft_pickaxe.mdl"); + } + + return oFindMDL(ecx, FilePath); +} +``` + +`FindMDL Hook/Hooks.h`: + +```h +#pragma once + +//Includes +#include "Utilities.h" +#include "VMTManager.h" + +//Extern Hooks +namespace Hooks +{ + void Initialise(); + + extern VMTManager VMTModelCache; +}; +``` + +`FindMDL Hook/IMDLCache.h`: + +```h +#ifndef IMDLCACHE_H +#define IMDLCACHE_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct studiohdr_t; +struct studiohwdata_t; +struct vcollide_t; +struct virtualmodel_t; +struct vertexFileHeader_t; + +namespace OptimizedModel +{ + struct FileHeader_t; +} + + +//----------------------------------------------------------------------------- +// Reference to a loaded studiomdl +//----------------------------------------------------------------------------- +typedef unsigned short MDLHandle_t; + +enum +{ + MDLHANDLE_INVALID = (MDLHandle_t)~0 +}; + + +//----------------------------------------------------------------------------- +// Cache data types +//----------------------------------------------------------------------------- +enum MDLCacheDataType_t +{ + // Callbacks to get called when data is loaded or unloaded for these: + MDLCACHE_STUDIOHDR = 0, + MDLCACHE_STUDIOHWDATA, + MDLCACHE_VCOLLIDE, + + // Callbacks NOT called when data is loaded or unloaded for these: + MDLCACHE_ANIMBLOCK, + MDLCACHE_VIRTUALMODEL, + MDLCACHE_VERTEXES, + MDLCACHE_DECODEDANIMBLOCK, +}; + +class IMDLCacheNotify +{ +public: + // Called right after the data is loaded + virtual void OnDataLoaded(MDLCacheDataType_t type, MDLHandle_t handle) = 0; + + // Called right before the data is unloaded + virtual void OnDataUnloaded(MDLCacheDataType_t type, MDLHandle_t handle) = 0; +}; + + +//----------------------------------------------------------------------------- +// Flags for flushing +//----------------------------------------------------------------------------- +enum MDLCacheFlush_t +{ + MDLCACHE_FLUSH_STUDIOHDR = 0x01, + MDLCACHE_FLUSH_STUDIOHWDATA = 0x02, + MDLCACHE_FLUSH_VCOLLIDE = 0x04, + MDLCACHE_FLUSH_ANIMBLOCK = 0x08, + MDLCACHE_FLUSH_VIRTUALMODEL = 0x10, + MDLCACHE_FLUSH_AUTOPLAY = 0x20, + MDLCACHE_FLUSH_VERTEXES = 0x40, + + MDLCACHE_FLUSH_IGNORELOCK = 0x80000000, + MDLCACHE_FLUSH_ALL = 0xFFFFFFFF +}; + +/* +#define MDLCACHE_INTERFACE_VERSION_4 "MDLCache004" +namespace MDLCacheV4 +{ +abstract_class IMDLCache : public IAppSystem +{ +public: +// Used to install callbacks for when data is loaded + unloaded +virtual void SetCacheNotify( IMDLCacheNotify *pNotify ) = 0; +// NOTE: This assumes the "GAME" path if you don't use +// the UNC method of specifying files. This will also increment +// the reference count of the MDL +virtual MDLHandle_t FindMDL( const char *pMDLRelativePath ) = 0; +// Reference counting +virtual int AddRef( MDLHandle_t handle ) = 0; +virtual int Release( MDLHandle_t handle ) = 0; +// Gets at the various data associated with a MDL +virtual studiohdr_t *GetStudioHdr( MDLHandle_t handle ) = 0; +virtual studiohwdata_t *GetHardwareData( MDLHandle_t handle ) = 0; +virtual vcollide_t *GetVCollide( MDLHandle_t handle ) = 0; +virtual unsigned char *GetAnimBlock( MDLHandle_t handle, int nBlock ) = 0; +virtual virtualmodel_t *GetVirtualModel( MDLHandle_t handle ) = 0; +virtual int GetAutoplayList( MDLHandle_t handle, unsigned short **pOut ) = 0; +virtual vertexFileHeader_t *GetVertexData( MDLHandle_t handle ) = 0; +// Brings all data associated with an MDL into memory +virtual void TouchAllData( MDLHandle_t handle ) = 0; +// Gets/sets user data associated with the MDL +virtual void SetUserData( MDLHandle_t handle, void* pData ) = 0; +virtual void *GetUserData( MDLHandle_t handle ) = 0; +// Is this MDL using the error model? +virtual bool IsErrorModel( MDLHandle_t handle ) = 0; +// Flushes the cache, force a full discard +virtual void Flush( int nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0; +// Flushes a particular model out of memory +virtual void Flush( MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0; +// Returns the name of the model (its relative path) +virtual const char *GetModelName( MDLHandle_t handle ) = 0; +// faster access when you already have the studiohdr +virtual virtualmodel_t *GetVirtualModelFast( const studiohdr_t *pStudioHdr, MDLHandle_t handle ) = 0; +// all cache entries that subsequently allocated or successfully checked +// are considered "locked" and will not be freed when additional memory is needed +virtual void BeginLock() = 0; +// reset all protected blocks to normal +virtual void EndLock() = 0; +// returns a pointer to a counter that is incremented every time the cache has been out of the locked state (EVIL) +virtual int *GetFrameUnlockCounterPtr() = 0; +// Finish all pending async operations +virtual void FinishPendingLoads() = 0; +}; +} +*/ + +//----------------------------------------------------------------------------- +// The main MDL cacher +//----------------------------------------------------------------------------- +#define MDLCACHE_INTERFACE_VERSION "MDLCache004" + +class IMDLCache +{ +public: + // Used to install callbacks for when data is loaded + unloaded + // Returns the prior notify + virtual void SetCacheNotify(IMDLCacheNotify* pNotify) = 0; + + // NOTE: This assumes the "GAME" path if you don't use + // the UNC method of specifying files. This will also increment + // the reference count of the MDL + virtual MDLHandle_t FindMDL(const char* pMDLRelativePath) = 0; + + // Reference counting + virtual int AddRef(MDLHandle_t handle) = 0; + virtual int Release(MDLHandle_t handle) = 0; + virtual int GetRef(MDLHandle_t handle) = 0; + + // Gets at the various data associated with a MDL + virtual studiohdr_t* GetStudioHdr(MDLHandle_t handle) = 0; + virtual studiohwdata_t* GetHardwareData(MDLHandle_t handle) = 0; + virtual vcollide_t* GetVCollide(MDLHandle_t handle) = 0; + virtual unsigned char* GetAnimBlock(MDLHandle_t handle, int nBlock) = 0; + virtual virtualmodel_t* GetVirtualModel(MDLHandle_t handle) = 0; + virtual int GetAutoplayList(MDLHandle_t handle, unsigned short** pOut) = 0; + virtual vertexFileHeader_t* GetVertexData(MDLHandle_t handle) = 0; + + // Brings all data associated with an MDL into memory + virtual void TouchAllData(MDLHandle_t handle) = 0; + + // Gets/sets user data associated with the MDL + virtual void SetUserData(MDLHandle_t handle, void* pData) = 0; + virtual void* GetUserData(MDLHandle_t handle) = 0; + + // Is this MDL using the error model? + virtual bool IsErrorModel(MDLHandle_t handle) = 0; + + // Flushes the cache, force a full discard + virtual void Flush(MDLCacheFlush_t nFlushFlags = MDLCACHE_FLUSH_ALL) = 0; + + // Flushes a particular model out of memory + virtual void Flush(MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL) = 0; + + // Returns the name of the model (its relative path) + virtual const char* GetModelName(MDLHandle_t handle) = 0; + + // faster access when you already have the studiohdr + virtual virtualmodel_t* GetVirtualModelFast(const studiohdr_t* pStudioHdr, MDLHandle_t handle) = 0; + + // all cache entries that subsequently allocated or successfully checked + // are considered "locked" and will not be freed when additional memory is needed + virtual void BeginLock() = 0; + + // reset all protected blocks to normal + virtual void EndLock() = 0; + + // returns a pointer to a counter that is incremented every time the cache has been out of the locked state (EVIL) + virtual int* GetFrameUnlockCounterPtrOLD() = 0; + + // Finish all pending async operations + virtual void FinishPendingLoads() = 0; + + virtual vcollide_t* GetVCollideEx(MDLHandle_t handle, bool synchronousLoad = true) = 0; + virtual bool GetVCollideSize(MDLHandle_t handle, int* pVCollideSize) = 0; + + virtual bool GetAsyncLoad(MDLCacheDataType_t type) = 0; + virtual bool SetAsyncLoad(MDLCacheDataType_t type, bool bAsync) = 0; + + virtual void BeginMapLoad() = 0; + virtual void EndMapLoad() = 0; + virtual void MarkAsLoaded(MDLHandle_t handle) = 0; + + virtual void InitPreloadData(bool rebuild) = 0; + virtual void ShutdownPreloadData() = 0; + + virtual bool IsDataLoaded(MDLHandle_t handle, MDLCacheDataType_t type) = 0; + + virtual int* GetFrameUnlockCounterPtr(MDLCacheDataType_t type) = 0; + + virtual studiohdr_t* LockStudioHdr(MDLHandle_t handle) = 0; + virtual void UnlockStudioHdr(MDLHandle_t handle) = 0; + + virtual bool PreloadModel(MDLHandle_t handle) = 0; + + // Hammer uses this. If a model has an error loading in GetStudioHdr, then it is flagged + // as an error model and any further attempts to load it will just get the error model. + // That is, until you call this function. Then it will load the correct model. + virtual void ResetErrorModelStatus(MDLHandle_t handle) = 0; + + virtual void MarkFrame() = 0; +}; + + +//----------------------------------------------------------------------------- +// Critical section helper code +//----------------------------------------------------------------------------- +class CMDLCacheCriticalSection +{ +public: + CMDLCacheCriticalSection(IMDLCache *pCache) : m_pCache(pCache) + { + m_pCache->BeginLock(); + } + + ~CMDLCacheCriticalSection() + { + m_pCache->EndLock(); + } + +private: + IMDLCache* m_pCache; +}; + +#define MDCACHE_FINE_GRAINED 1 + +#if defined(MDCACHE_FINE_GRAINED) +#define MDLCACHE_CRITICAL_SECTION_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache) +#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0)) +#elif defined(MDLCACHE_LEVEL_LOCKED) +#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0)) +#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0)) +#else +#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0)) +#define MDLCACHE_COARSE_LOCK_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache) +#endif +#define MDLCACHE_CRITICAL_SECTION() MDLCACHE_CRITICAL_SECTION_(mdlcache) +#define MDLCACHE_COARSE_LOCK() MDLCACHE_COARSE_LOCK_(mdlcache) + +#endif // IMDLCACHE_H +``` + +`FindMDL Hook/Interfaces.cpp`: + +```cpp +//Includes +#include "Interfaces.h" + +typedef void* (__cdecl* CreateInterface_t)(const char*, int*); +CreateInterface_t DataCaching = NULL; + +//Interfaces +namespace Interfaces +{ + IMDLCache* ModelCache; +}; + +//Initialise Interfaces +void Interfaces::Initialise() +{ + DataCaching = (CreateInterface_t)GetProcAddress((HMODULE)Offsets::DataCaches, "CreateInterface"); //Getting the process address of the DataCaches offset + + char* pDataCache = (char*)FindTextPattern("datacache.dll", "MDLCache00"); //Getting MDLCache00 memory address on "datacache.dll" module + + ModelCache = (IMDLCache*)DataCaching(pDataCache, NULL); +}; +``` + +`FindMDL Hook/Interfaces.h`: + +```h +#pragma once + +//Includes +#include "Offsets.h" +#include "Interfaces.h" +#include "IMDLCache.h" + +//Extern Interfaces +namespace Interfaces +{ + void Initialise(); + + extern IMDLCache* ModelCache; +}; + +``` + +`FindMDL Hook/Offsets.cpp`: + +```cpp +#include "Offsets.h" + +//Initialise Offsets +void Offsets::Initialise() +{ + DataCaches = WaitOnModuleHandle("datacache.dll"); + dwLocalPlayer = 0xD882B; +}; + +//Offsets +namespace Offsets +{ + DWORD DataCaches; + DWORD dwLocalPlayer; +} +``` + +`FindMDL Hook/Offsets.h`: + +```h +#pragma once + +//Includes +#include "CommonIncludes.h" +#include "Utilities.h" + +//Extern Offsets +namespace Offsets +{ + void Initialise(); + + extern DWORD DataCaches; + extern DWORD dwLocalPlayer; +} +``` + +`FindMDL Hook/Utilities.cpp`: + +```cpp +// Includes +#include "Utilities.h" +#include +#include + +//Utilities Memory +DWORD Utilities::Memory::WaitOnModuleHandle(std::string moduleName) +{ + DWORD ModuleHandle = NULL; + while (!ModuleHandle) + { + ModuleHandle = (DWORD)GetModuleHandle(moduleName.c_str()); + if (!ModuleHandle) + Sleep(50); + } + return ModuleHandle; +} +bool bCompare(const BYTE* Data, const BYTE* Mask, const char* szMask) +{ + for (; *szMask; ++szMask, ++Mask, ++Data) + { + if (*szMask == 'x' && *Mask != *Data) + { + return false; + } + } + return (*szMask) == 0; +} +DWORD Utilities::Memory::FindPattern(std::string moduleName, BYTE* Mask, char* szMask) +{ + DWORD Address = WaitOnModuleHandle(moduleName.c_str()); + MODULEINFO ModInfo; GetModuleInformation(GetCurrentProcess(), (HMODULE)Address, &ModInfo, sizeof(MODULEINFO)); + DWORD Length = ModInfo.SizeOfImage; + for (DWORD c = 0; c < Length; c += 1) + { + if (bCompare((BYTE*)(Address + c), Mask, szMask)) + { + return (DWORD)(Address + c); + } + } + return 0; +} +DWORD Utilities::Memory::FindTextPattern(std::string moduleName, char* string) +{ + DWORD Address = WaitOnModuleHandle(moduleName.c_str()); + MODULEINFO ModInfo; GetModuleInformation(GetCurrentProcess(), (HMODULE)Address, &ModInfo, sizeof(MODULEINFO)); + DWORD Length = ModInfo.SizeOfImage; + + int len = strlen(string); + char* szMask = new char[len + 1]; + for (int i = 0; i < len; i++) + { + szMask[i] = 'x'; + } + szMask[len] = '\0'; + + for (DWORD c = 0; c < Length; c += 1) + { + if (bCompare((BYTE*)(Address + c), (BYTE*)string, szMask)) + { + return (DWORD)(Address + c); + } + } + return 0; +} + +//VMT Manager +bool Utilities::Memory::VMTManager::Initialise(DWORD* InstancePointer) +{ + Instance = InstancePointer; + OriginalTable = (DWORD*)*InstancePointer; + int VMTSize = MethodCount(InstancePointer); + size_t TableBytes = VMTSize * 4; + + CustomTable = (DWORD*)malloc(TableBytes + 8); + if (!CustomTable) return false; + memcpy((void*)CustomTable, (void*)OriginalTable, VMTSize * 4); + + *InstancePointer = (DWORD)CustomTable; + + initComplete = true; + return true; +} +int Utilities::Memory::VMTManager::MethodCount(DWORD* InstancePointer) +{ + DWORD* VMT = (DWORD*)*InstancePointer; + int Index = 0; + int Amount = 0; + while (!IsBadCodePtr((FARPROC)VMT[Index])) + { + if (!IsBadCodePtr((FARPROC)VMT[Index])) + { + Amount++; + Index++; + } + } + + return Amount; +} +DWORD Utilities::Memory::VMTManager::HookMethod(DWORD NewFunction, int Index) +{ + if (initComplete) + { + CustomTable[Index] = NewFunction; + return OriginalTable[Index]; + } + else + return NULL; +} +void Utilities::Memory::VMTManager::UnhookMethod(int Index) +{ + if (initComplete) + CustomTable[Index] = OriginalTable[Index]; + return; +} +void Utilities::Memory::VMTManager::RestoreOriginal() +{ + if (initComplete) + { + *Instance = (DWORD)OriginalTable; + } + return; +} +void Utilities::Memory::VMTManager::RestoreCustom() +{ + if (initComplete) + { + *Instance = (DWORD)CustomTable; + } + return; +} +DWORD Utilities::Memory::VMTManager::GetOriginalFunction(int Index) +{ + return OriginalTable[Index]; +} +``` + +`FindMDL Hook/Utilities.h`: + +```h +#pragma once +#include "CommonIncludes.h" + +static DWORD WaitOnModuleHandle(std::string moduleName) +{ + DWORD ModuleHandle = NULL; + while (!ModuleHandle) + { + ModuleHandle = (DWORD)GetModuleHandle(moduleName.c_str()); + if (!ModuleHandle) + { + Sleep(50); + } + } + return ModuleHandle; +} + +static bool bCompare(const BYTE* Data, const BYTE* Mask, const char* szMask) +{ + for (; *szMask; ++szMask, ++Mask, ++Data) + { + if (*szMask == 'x' && *Mask != *Data) + { + return false; + } + } + return (*szMask) == 0; +} + +static DWORD FindPattern(std::string moduleName, BYTE* Mask, char* szMask) +{ + DWORD Address = WaitOnModuleHandle(moduleName.c_str()); + MODULEINFO ModInfo; GetModuleInformation(GetCurrentProcess(), (HMODULE)Address, &ModInfo, sizeof(MODULEINFO)); + DWORD Length = ModInfo.SizeOfImage; + for (DWORD c = 0; c < Length; c += 1) + { + if (bCompare((BYTE*)(Address + c), Mask, szMask)) + { + return (DWORD)(Address + c); + } + } + return 0; +} + +static DWORD FindTextPattern(std::string moduleName, char* string) +{ + DWORD Address = WaitOnModuleHandle(moduleName.c_str()); + MODULEINFO ModInfo; GetModuleInformation(GetCurrentProcess(), (HMODULE)Address, &ModInfo, sizeof(MODULEINFO)); + DWORD Length = ModInfo.SizeOfImage; + + int len = strlen(string); + char* szMask = new char[len + 1]; + for (int i = 0; i < len; i++) + { + szMask[i] = 'x'; + } + szMask[len] = '\0'; + + for (DWORD c = 0; c < Length; c += 1) + { + if (bCompare((BYTE*)(Address + c), (BYTE*)string, szMask)) + { + return (DWORD)(Address + c); + } + } + return 0; +} +``` + +`FindMDL Hook/VMTManager.cpp`: + +```cpp +#include "CommonIncludes.h" +#include "VMTManager.h" + +bool VMTManager::Initialise(DWORD* InstancePointer) +{ + Instance = InstancePointer; + OriginalTable = (DWORD*)*InstancePointer; + int VMTSize = MethodCount(InstancePointer); + size_t TableBytes = VMTSize * 4; + + CustomTable = (DWORD*)malloc(TableBytes + 8); + if (!CustomTable) return false; + memcpy((void*)CustomTable, (void*)OriginalTable, VMTSize * 4); + + *InstancePointer = (DWORD)CustomTable; + initComplete = true; + + return true; +} + +int VMTManager::MethodCount(DWORD* InstancePointer) +{ + DWORD* VMT = (DWORD*)*InstancePointer; + int Index = 0; + int Amount = 0; + while (!IsBadCodePtr((FARPROC)VMT[Index])) + { + if (!IsBadCodePtr((FARPROC)VMT[Index])) + { + Amount++; + Index++; + } + } + + return Amount; +} + +DWORD VMTManager::HookMethod(DWORD NewFunction, int Index) +{ + if (initComplete) + { + CustomTable[Index] = NewFunction; + return OriginalTable[Index]; + } + + return NULL; +} + +void VMTManager::UnhookMethod(int Index) +{ + if (initComplete) + { + CustomTable[Index] = OriginalTable[Index]; + } + + return; +} + +void VMTManager::RestoreOriginal() +{ + if (initComplete) + { + *Instance = (DWORD)OriginalTable; + } + + return; +} + +void VMTManager::RestoreCustom() +{ + if (initComplete) + { + *Instance = (DWORD)CustomTable; + } + + return; +} + +DWORD VMTManager::GetOriginalFunction(int Index) +{ + return OriginalTable[Index]; +} + +``` + +`FindMDL Hook/VMTManager.h`: + +```h +#pragma once + +class VMTManager +{ +private: + DWORD* CustomTable; + bool initComplete; + DWORD* OriginalTable; + DWORD* Instance; + + int MethodCount(DWORD* InstancePointer); + +public: + bool Initialise(DWORD* InstancePointer); // Pass a &class + + DWORD HookMethod(DWORD NewFunction, int Index); + void UnhookMethod(int Index); + + void RestoreOriginal(); + void RestoreCustom(); + + template + T GetMethod(size_t nIndex) + { + return (T)OriginalTable[nIndex]; + } + + DWORD GetOriginalFunction(int Index); +}; + +template +FORCEINLINE T GetMethod(const void* instance, size_t index) +{ + uintptr_t* vmt = *(uintptr_t**)instance; + + return (T)vmt[index]; +} +``` + +`FindMDL Hook/dllmain.cpp`: + +```cpp +//Includes +#include +#include "Utilities.h" +#include "Interfaces.h" +#include "Hooks.h" +#include "Offsets.h" + +struct values { + DWORD localPlayer; + DWORD gameModule; +}value; + +void main() +{ + Offsets::Initialise(); + Interfaces::Initialise(); + Hooks::Initialise(); + + value.gameModule = (DWORD)GetModuleHandle("client.dll"); //Get "client.dll" module handle + value.localPlayer = *(DWORD*)(value.gameModule + Offsets::dwLocalPlayer); //Get local player value + + //Get local player value again if local player value is null + if (value.localPlayer == NULL) + { + while (value.localPlayer == NULL) + { + value.localPlayer = *(DWORD*)(value.gameModule + Offsets::dwLocalPlayer); + } + } +} + +//DLL Main +BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + DisableThreadLibraryCalls(hModule); + CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)main, NULL, NULL, NULL); + } + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +``` + +`README.md`: + +```md +# FindMDL Hook +This repository has a internal model changer with FindMDL Hook for Counter-Strike: Global Offensive game. It's fully open source and loadable into the game as a [Dynamic-link library (DLL)](https://en.wikipedia.org/wiki/Dynamic-link_library) + +![](https://img.shields.io/badge/language-c++-e76089?style=plastic) ![](https://img.shields.io/badge/game-csgo-yellow?style=plastic) ![](https://img.shields.io/badge/license-GNU-green?style=plastic) ![](https://img.shields.io/badge/arch-x86-d9654f?style=plastic) + +![Image of RequestX International Developer Group on Discord](https://github.com/kruz1337/CSGO-FindMDL/blob/main/thumbnail.png) + +## How to build FindMDL Hook Project files? +* First of all you should download project files on project page or clone this repository from GitBash or GitHub Desktop on your PC. [FindMDL.zip](https://github.com/kruz1337/CSGO-FindMDL/releases) + +* If you download project files with manual method you need extract zip file. + +* Run .sln file on Visual Studio (2019+). + +* Change build configuration to Debug | x86 and press Build button or press CTRL+B on your keyboard. + +* Check out bin folder include that. + +* Go to the bottom heading to add your custom models. + +## How to load into the game? +* First download any [Dynamic-link library (DLL)](https://en.wikipedia.org/wiki/Dynamic-link_library) injector and open. + +* Then select builded [Dynamic-link library (DLL)](https://en.wikipedia.org/wiki/Dynamic-link_library) file and Inject to csgo.exe + +* That's all, enjoy it :) + +## How to add your custom model? +* First go to "Hooks.cpp" in Source Files. + +* Then go to hkFindMDL below the "Custom Models" comment line. + +* Paste this code and read comment lines in this code. +```c++ +if (strstr(FilePath, "v_.mdl")) //v_: Name of the model to change +{ + sprintf(FilePath, "models/weapons/v_new_.mdl"); //v_new_: Name of the changing custom model: +} +``` + +``` \ No newline at end of file diff --git a/archive/ekknod/nv_v2.txt b/archive/ekknod/nv_v2.txt new file mode 100644 index 00000000..41c35a10 --- /dev/null +++ b/archive/ekknod/nv_v2.txt @@ -0,0 +1,883 @@ +Project Path: arc_ekknod_nv_v2_9h1xof_a + +Source Tree: + +```txt +arc_ekknod_nv_v2_9h1xof_a +├── LICENCE +├── README.md +├── nv_v2 +│ ├── main.c +│ ├── nv_v2.aps +│ ├── nv_v2.rc +│ ├── nv_v2.vcxproj +│ ├── nv_v2.vcxproj.filters +│ ├── nv_v2.vcxproj.user +│ └── resource.h +└── nv_v2.sln + +``` + +`LICENCE`: + +``` +free use for non commercial projects +credit me if you like. + +``` + +`README.md`: + +```md +# nv_v2 +##### csgo sound esp +---- +## usage +* clone this repository +* build x86 release +* set your ingame volume low, recommended under 0.3. +* copy "nvStereoApiI.dll" -> "C:\Program Files (x86)\NVIDIA Corporation\3D Vision\" folder +* start the game and play + +---- +## features +* no hooks +* no ingame functions called +---- +## video +[![IMAGE ALT TEXT](https://i.ytimg.com/vi/LRcZQIf_0O0/maxresdefault.jpg)](https://www.youtube.com/watch?v=LRcZQIf_0O0 "CSGO sound esp") +---- +## licence +* free use for non commercial projects +* credit me if you like. + +``` + +`nv_v2.sln`: + +```sln + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.168 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nv_v2", "nv_v2\nv_v2.vcxproj", "{D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}" +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 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Debug|x64.ActiveCfg = Debug|x64 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Debug|x64.Build.0 = Debug|x64 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Debug|x86.ActiveCfg = Debug|Win32 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Debug|x86.Build.0 = Debug|Win32 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Release|x64.ActiveCfg = Release|x64 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Release|x64.Build.0 = Release|x64 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Release|x86.ActiveCfg = Release|Win32 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5EB48005-80B1-4418-AC11-9A11C1038FA8} + EndGlobalSection +EndGlobal + +``` + +`nv_v2/main.c`: + +```c +#include +#include + +#pragma comment(lib, "ntdll.lib") + +/* global variables */ + +static int _target, _target_hitbox; +static int _mp_teammates_are_enemies; +static int _volume; +static float _start_volume, _min_volume; + +/* static hitboxes */ + +static int hitbox_list[6] = { 5, 4, 3, 0, 7, 8 } ; + +/* functions */ + +HANDLE (WINAPI * _CreateThread)(PVOID, SIZE_T, PVOID, LPVOID, DWORD, LPDWORD); +BOOL (WINAPI * _CloseHandle)(HANDLE); +VOID (WINAPI *_Sleep)(DWORD dwMilliseconds); +double (__cdecl *_atan2)(double, double); +double (__cdecl *_sqrt)(double); +double (__cdecl *_sin)(double); +double (__cdecl *_cos)(double); + +typedef struct { float x, y, z; } vec3 ; + +struct { + uintptr_t client, entity; + uintptr_t engine, cvar; +} vt ; + +struct { + int dwClientState, dwEntityList, dwGetLocalPlayer; + int dwGetViewAngles, dwGetState, m_iHealth; + int m_lifeState, m_vecViewOffset, m_iTeamNum; + int m_vecPunch, dwBoneMatrix, m_vecOrigin; +} nv ; + +struct crc32 { DWORD c, l, i; }; +struct crc32 CRC32(DWORD c, DWORD l, DWORD i) +{ + struct crc32 crc; + crc.c = c; crc.l = l; crc.i = i; + return crc; +} + +#define CRC32(c, l, i) ((struct crc32) { c, l, i }) +#define CRC32_CMP(crc, t) RtlCrc32((const void *)t, strlen((const char *)t), (DWORD)crc.i) == (unsigned int)crc.c +#define CRC32_WCMP(crc, t) RtlCrc32((const void *)t, wcslen((const wchar_t *)t), (DWORD)crc.i) == (unsigned int)crc.c +#define CRC32_CMPO(crc, t, off) RtlCrc32((const void *)t, strlen((const char *)t) - off, (DWORD)crc.i) == (unsigned int)crc.c + +uintptr_t get_module(struct crc32 crc) +{ + uintptr_t a0, a1; + + a0 = *(uintptr_t*)(*(uintptr_t*)(__readfsdword(0x30) + 0x0C) + 0x14); + a1 = *(uintptr_t*)(a0 + 4); + while (a0 != a1) { + if (CRC32_WCMP(crc, *(const wchar_t**)(a0 + 0x28))) { + return *(uintptr_t*)(a0 + 0x10); + } + a0 = *(uintptr_t*)(a0); + } + return 0; +} + +uintptr_t get_export(uintptr_t module, struct crc32 crc) +{ + int a0; + int a1[4]; + + a0 = module + *(int*)(module + 0x3C); + a0 = module + *(int*)(a0 + 0x78); + memcpy(&a1, (const void*)(a0 + 0x18), sizeof(a1)); + while (a1[0]--) { + a0 = *(int*)(module + a1[2] + (a1[0] * 4)); + if (CRC32_CMP(crc, (const char*)(module + a0))) { + return (module + *(int*)(module + a1[1] + (*(short*)(module + a1[3] + (a1[0] * 2)) * 4))); + } + } + return 0; +} + +uintptr_t get_factory(struct crc32 crc) +{ + uintptr_t v = get_export(get_module(crc), CRC32(1505290531, 15, 101363432)); + return v != 0 ? *(uintptr_t*)(*(uintptr_t*)(v - 0x6A)) : 0; +} + +uintptr_t get_interface(uintptr_t factory, struct crc32 crc) +{ + do { + if (CRC32_CMPO(crc, *(const char**)(factory + 0x4), 3)) { + return *(uintptr_t*)(*(uintptr_t*)(factory) + 1); + } + } while ((factory = *(uintptr_t*)(factory + 0x8)) != 0); + return 0; +} + +static uintptr_t get_function(uintptr_t vtable, int index) { return *(uintptr_t*)(*(uintptr_t*)(vtable) + index * 4); } + +static uintptr_t get_table(struct crc32 crc) +{ + uintptr_t a0, a1; + + a0 = *(uintptr_t*)(*(uintptr_t*)(get_function(vt.client, 8) + 1)); + do { + a1 = *(uintptr_t*)(a0 + 0xC); + if (CRC32_CMP(crc, *(const char **)(a1 + 0xC))) + return a1; + } while((a0 = *(uintptr_t*)(a0 + 0x10)) != 0); + return 0; +} + +static int get_offset(uintptr_t table, struct crc32 crc) +{ + int a0 = 0, a1, a2, a3, a4, a5; + + for (a1 = 0; a1 < *(int*)(table + 0x4); a1++) { + a2 = a1 * 60 + *(int*)(table); + a3 = *(int*)(a2 + 0x2C); + if ((a4 = *(int*)(a2 + 0x28)) != 0 && *(int*)(a4 + 0x4) != 0) + if ((a5 = get_offset(a4, crc)) != 0) + a0 += a3 + a5; + if (CRC32_CMP(crc, *(const char**)(a2))) { + return a3 + a0; + } + } + return a0; +} + +static uintptr_t get_cvar(struct crc32 crc) +{ + uintptr_t a1 = *(uintptr_t*)(*(uintptr_t*)(vt.cvar + 0x34)); + while ((a1 = *(uintptr_t*)(a1 + 0x4)) != 0) + if (CRC32_CMP(crc, *(const char**)(a1 + 0xc))) + return a1; + return 0; +} + +static int get_cvar_32(uintptr_t convar) +{ + return *(int*)(convar + 0x30) ^ convar; +} + +static float get_cvar_32f(uintptr_t convar) +{ + int v = *(int*)(convar + 0x2C) ^ convar; + return *(float*)&v; +} + +static void set_cvar_32f(uintptr_t convar, float v) +{ + *(int*)(convar + 0x2C) = *(int*)&v ^ convar; +} + +static BOOL isInGame(void) { return *(BOOL*)(nv.dwClientState + nv.dwGetState) == 6; } +static int getLocalPlayer(void) { return *(int*)(nv.dwClientState + nv.dwGetLocalPlayer); } +static int getClientEntity(int index) { return *(int*)(nv.dwEntityList + index * 0x10); } +static int getTeam(int entity) { return *(int*)(entity + nv.m_iTeamNum); } +static int getHealth(int entity) { return *(int*)(entity + nv.m_iHealth); } +static int getLifeState(int entity) { return *(int*)(entity + nv.m_lifeState); } +static int getBoneMatrix(int entity) { return *(int*)(entity + nv.dwBoneMatrix); } +static vec3 getVecOrigin(int entity) { return *(vec3*)(entity + nv.m_vecOrigin); } +static vec3 getVecView(int entity) { return *(vec3*)(entity + nv.m_vecViewOffset); } +static vec3 getVecPunch(int entity) { return *(vec3*)(entity + nv.m_vecPunch); } +static vec3 getViewAngles(void) { return *(vec3*)(nv.dwClientState + nv.dwGetViewAngles); } +static vec3 getEyePos(int entity) +{ + vec3 v, o; + + v = getVecView(entity); + o = getVecOrigin(entity); + return (vec3) { v.x + o.x, v.y + o.y, v.z + o.z } ; +} + +static vec3 getBonePos(int entity, int index) +{ + vec3 v = { 0 }; + int m; + + m = getBoneMatrix(entity); + if (m == 0) + return v; + v.x = *(float*)(m + 0x30 * index + 0x0C); + v.y = *(float*)(m + 0x30 * index + 0x1C); + v.z = *(float*)(m + 0x30 * index + 0x2C); + return v; +} + +static BOOL isValid(int entity) +{ + int health; + + if (entity == 0) + return 0; + health = getHealth(entity); + return entity && getLifeState(entity) == 0 && health > 0 && health < 1337; +} + +static BOOL initialize_functions(void) +{ + uintptr_t m; + if ((m = get_module(CRC32(1336618664, 9, 355701351))) == 0) return FALSE; /* ntdll.dll */ + if ((*(uintptr_t*)&_atan2 = get_export(m, CRC32(-1208413014, 5, 25061309))) == 0) return FALSE; /* atan2 */ + if ((*(uintptr_t*)&_sqrt = get_export(m, CRC32(1089090901, 4, 2113851773))) == 0) return FALSE; /* sqrt */ + if ((*(uintptr_t*)&_sin = get_export(m, CRC32(1156354345, 3, 1061462970))) == 0) return FALSE; /* sin */ + if ((*(uintptr_t*)&_cos = get_export(m, CRC32(636348740, 3, 1064479962))) == 0) return FALSE; /* cos */ + if ((m = get_module(CRC32(-1564104622, 12, 1180227225))) == 0) return FALSE; /* KERNEL32.DLL */ + if ((*(uintptr_t*)&_CreateThread = get_export(m, CRC32(-770929529, 12, 2097875415))) == 0) return FALSE; /* CreateThread */ + if ((*(uintptr_t*)&_CloseHandle = get_export(m, CRC32(644799219, 11, 2089162550))) == 0) return FALSE; /* CloseHandle */ + if ((*(uintptr_t*)&_Sleep = get_export(m, CRC32(871370551, 5, 114390764))) == 0) return FALSE; /* Sleep */ + return TRUE; +} + +static BOOL initialize_interfaces(void) +{ + int t; + + if ((t = get_factory(CRC32(765433668, 11, 1675198160))) == 0) return 0; /* vstdlib.dll */ + if ((vt.cvar = get_interface(t, CRC32(-1774926910, 11, 321091948))) == 0) return 0; /* VEngineCvar */ + if ((t = get_factory(CRC32(-977266194, 10, 1879618954))) == 0) return 0; /* engine.dll */ + if ((vt.engine = get_interface(t, CRC32(-1563693526, 13, 21364416))) == 0) return 0; /* VEngineClient */ + if ((t = get_factory(CRC32(1478622760, 19, 1548099251))) == 0) return 0; /* client_panorama.dll */ + if ((vt.entity = get_interface(t, CRC32(1789069159, 17, 74332196))) == 0) return 0; /* VClientEntityList */ + if ((vt.client = get_interface(t, CRC32(1051283942, 7, 809333349))) == 0) return 0; /* VClient */ + return 1; +} + +static BOOL initialize_netvars(void) +{ + int t; + + nv.dwClientState = *(int*)(*(int*)(get_function(vt.engine, 18) + 0x16)); + nv.dwEntityList = vt.entity - (*(int*)(get_function(vt.entity, 5) + 0x22) - 0x38); + nv.dwGetLocalPlayer = *(int*)(get_function(vt.engine, 12) + 0x16); + nv.dwGetViewAngles = *(int*)(get_function(vt.engine, 19) + 0xB2); + nv.dwGetState = *(int*)(get_function(vt.engine, 26) + 0x07); + + if ((t = get_table(CRC32(-1834292033, 16, 2143189635))) == 0) return 0; /* DT_BaseAnimating */ + nv.dwBoneMatrix = get_offset(t, CRC32(-1563350005, 12, 1532917158)) + 0x1C; /* m_nForceBone */ + if ((t = get_table(CRC32(-96230388, 13, 1368077207))) == 0) return 0; /* DT_BaseEntity */ + nv.m_vecOrigin = get_offset(t, CRC32(-673322472, 11, 979638726)); /* m_vecOrigin */ + nv.m_iTeamNum = get_offset(t, CRC32(-1033337736, 10, 1136402645)); /* m_iTeamNum */ + if ((t = get_table(CRC32(2030591008, 13, 1519792398))) == 0) return 0; /* DT_BasePlayer */ + nv.m_iHealth = get_offset(t, CRC32(-1956581322, 9, 1195260790)); /* m_iHealth */ + nv.m_lifeState = get_offset(t, CRC32(211519899, 11, 759023442)); /* m_lifeState */ + nv.m_vecViewOffset = get_offset(t, CRC32(-1429466835, 18, 1044359072)); /* m_vecViewOffset[0] */ + nv.m_vecPunch = get_offset(t, CRC32(-2054851689, 7, 34174687)) + 0x70; /* m_Local */ + return 1; +} + +static void main_thread(void); + +BOOL initialize_everything(void) +{ + if (!initialize_functions()) + return FALSE; + if (!initialize_interfaces()) + return FALSE; + if (!initialize_netvars()) + return FALSE; + if ((_mp_teammates_are_enemies = get_cvar(CRC32(354703522, 24, 1872518935))) == 0) + return FALSE; + if ((_volume = get_cvar(CRC32(-828087349, 6, 2122840634))) == 0) + return FALSE; + + _start_volume = get_cvar_32f(_volume); + if (_start_volume >= 0.30f) + _start_volume = 0.25f; + _min_volume = 1.0f - _start_volume; + _CloseHandle(_CreateThread(0, 0, (PVOID)main_thread, 0, 0, 0)); + return TRUE; +} + +#define RAD2DEG(x) ((float)(x) * (float)(180.f / 3.14159265358979323846f)) +#define DEG2RAD(x) ((float)(x) * (float)(3.14159265358979323846f / 180.f)) + + +static void sincos(float radians, float *sine, float *cosine) +{ + *sine = (float)_sin(radians); + *cosine = (float)_cos(radians); +} + +static void angle_vec(vec3 angles, vec3 *forward) +{ + float sp, sy, cp, cy; + sincos(DEG2RAD(angles.x), &sp, &cp); + sincos(DEG2RAD(angles.y), &sy, &cy); + forward->x = cp * cy; + forward->y = cp * sy; + forward->z = -sp; +} + +static void vec_clamp(vec3 *v) +{ + if ( v->x > 89.0f && v->x <= 180.0f ) { + v->x = 89.0f; + } + if ( v->x > 180.0f ) { + v->x = v->x - 360.0f; + } + if( v->x < -89.0f ) { + v->x = -89.0f; + } + v->y = fmodf(v->y + 180, 360) - 180; + v->z = 0; +} + +static void vec_normalize(vec3 *vec) +{ + float radius; + + radius = 1.f / (float)(_sqrt(vec->x*vec->x + vec->y*vec->y + vec->z*vec->z) + 1.192092896e-07f); + vec->x *= radius, vec->y *= radius, vec->z *= radius; +} + +static void vec_angles(vec3 forward, vec3 *angles) +{ + float tmp, yaw, pitch; + + if (forward.y == 0.f && forward.x == 0.f) { + yaw = 0; + if (forward.z > 0) { + pitch = 270; + } else { + pitch = 90.f; + } + } else { + yaw = (float)(_atan2(forward.y, forward.x) * 180.f / 3.14159265358979323846f); + if (yaw < 0) { + yaw += 360.f; + } + tmp = (float)_sqrt(forward.x * forward.x + forward.y * forward.y); + pitch = (float)(_atan2(-forward.z, tmp) * 180.f / 3.14159265358979323846f); + if (pitch < 0) { + pitch += 360.f; + } + } + angles->x = pitch; + angles->y = yaw; + angles->z = 0.f; +} + +static float vec_dot(vec3 v0, vec3 v1) +{ + return (v0.x * v1.x + v0.y * v1.y + v0.z * v1.z); +} + +static float vec_length(vec3 v) +{ + return (v.x * v.x + v.y * v.y + v.z * v.z); +} + +static float get_fov(vec3 vangle, vec3 angle) +{ + vec3 a0, a1; + + angle_vec(vangle, &a0); + angle_vec(angle, &a1); + return RAD2DEG(acos(vec_dot(a0, a1) / vec_length(a0))); +} + +static vec3 get_target_angle(int self, int target, int hitbox_id) +{ + vec3 m, c; + + m = getBonePos(target, hitbox_id); + c = getEyePos(self); + c.x = m.x - c.x; c.y = m.y - c.y; c.z = m.z - c.z; + vec_normalize(&c); + vec_angles(c, &c); + m = getVecPunch(self); + c.x -= m.x * 2.0f, c.y -= m.y * 2.0f, c.z -= m.z * 2.0f; + vec_clamp(&c); + return c; +} + +static BOOL get_target(int self, vec3 vangle) +{ + float best_fov; + int i; + int entity; + float fov; + int j; + + best_fov = 9999.0f; + for (i = 1; i < 64; i++) { + entity = getClientEntity(i); + if (!isValid(entity)) + continue; + if (get_cvar_32(_mp_teammates_are_enemies) == 0 && getTeam(self) == getTeam(entity)) + continue; + for (j = 6; j-- ;) { + fov = get_fov(vangle, get_target_angle(self, entity, hitbox_list[j])); + if (fov < best_fov) { + best_fov = fov; + _target = entity; + _target_hitbox = hitbox_list[j]; + } + } + } + return best_fov != 9999.0f; +} + +static void sound_esp(void) +{ + int self; + vec3 vangle; + float fov, vol; + + self = getClientEntity(getLocalPlayer()); + if (self == 0) + return; + vangle = getViewAngles(); + if (!get_target(self, vangle)) { + if (get_cvar_32f(_volume) != _start_volume) + set_cvar_32f(_volume, _start_volume); + return; + } + fov = get_fov(vangle, get_target_angle(self, _target, _target_hitbox)); + if (fov <= 6.0f) { + vol = 1.0f - fov / 6.0f * _min_volume; + if (vol > 1.0f || vol <= _start_volume) + return; + set_cvar_32f(_volume, vol); + } else { + if (get_cvar_32f(_volume) != _start_volume) + set_cvar_32f(_volume, _start_volume); + } +} + +static void main_thread(void) +{ + while (1) { + _Sleep(1); + if (isInGame()) { + sound_esp(); + } + } +} + +BOOL WINAPI DllMain(HMODULE hMod, DWORD rea, LPVOID res) +{ + BOOL result = 1; + if (rea == 1) { + result = initialize_everything(); + } + return result; +} + +``` + +`nv_v2/nv_v2.rc`: + +```rc +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Finnish (Finland) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FIN) +LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 7,17,13,8813 + PRODUCTVERSION 7,17,13,8813 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "NVIDIA API 3D Vision extention" + VALUE "FileVersion", "7.17.13.8813" + VALUE "InternalName", "nvStereoApiI.dll" + VALUE "LegalCopyright", "(C) 2017 NVIDIA Corporation. All rights reserved." + VALUE "OriginalFilename", "nvStereoApiI.dll" + VALUE "ProductName", "NVIDIA GeForce 3D Vision" + VALUE "ProductVersion", "7.17.13.8813" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // Finnish (Finland) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + + +``` + +`nv_v2/nv_v2.vcxproj`: + +```vcxproj + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {D8FD9348-BD97-4C13-B9B6-880C5D4FB01F} + Win32Proj + nvv2 + 10.0.17763.0 + + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + nvStereoApiI + + + false + + + + Level3 + Disabled + WIN32;_DEBUG;NVV2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + true + Windows + + + + + Level3 + Disabled + _DEBUG;NVV2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + true + Windows + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;NVV2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + MultiThreaded + + + true + true + false + Windows + false + + + + + Level3 + MaxSpeed + true + true + NDEBUG;NVV2_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + true + true + true + Windows + + + + + + + + + + + + + + + +``` + +`nv_v2/nv_v2.vcxproj.filters`: + +```filters + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + + + Resource Files + + + +``` + +`nv_v2/nv_v2.vcxproj.user`: + +```user + + + + true + + +``` + +`nv_v2/resource.h`: + +```h +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by nv_v2.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + +``` \ No newline at end of file