Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NeoUI - Custom loading screen, wrapped text #677

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions mp/src/game/client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,8 @@ target_sources_grouped(
neo/ui/neo_root_serverbrowser.h
neo/ui/neo_root_settings.cpp
neo/ui/neo_root_settings.h
neo/ui/neo_loading.cpp
neo/ui/neo_loading.h
neo/ui/neo_ui.cpp
neo/ui/neo_ui.h
neo/ui/IOverrideInterface.h
Expand Down
6 changes: 6 additions & 0 deletions mp/src/game/client/cdll_client_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ extern vgui::IInputInternal *g_InputInternal;
#ifdef NEO
#include "neo_version.h"
#include "neo_mount_original.h"
#include "ui/neo_loading.h"
extern bool NeoRootCaptureESC();
extern CNeoLoading *g_pNeoLoading;

#ifdef LINUX
#include "neo_fixup_glshaders.h"
Expand Down Expand Up @@ -1769,6 +1771,10 @@ void CHLClient::LevelInitPostEntity( )
IGameSystem::LevelInitPostEntityAllSystems();
C_PhysPropClientside::RecreateAll();
internalCenterPrint->Clear();

#ifdef NEO
g_pNeoLoading->m_wszLoadingMap[0] = L'\0';
#endif
}

//-----------------------------------------------------------------------------
Expand Down
33 changes: 33 additions & 0 deletions mp/src/game/client/clientmode_shared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ extern ConVar replay_rendersetting_renderglow;

#ifdef NEO
#include "c_neo_player.h"
#include <GameUI/IGameUI.h>
#include "ui/neo_loading.h"
#endif

// memdbgon must be the last include file in a .cpp file!!!
Expand All @@ -78,6 +80,10 @@ class CHudWeaponSelection;
class CHudChat;
class CHudVote;

#ifdef NEO
static CDllDemandLoader g_gameUI("GameUI");
#endif

static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT;

ConVar cl_drawhud( "cl_drawhud", "1", FCVAR_CHEAT, "Enable the rendering of the hud" );
Expand All @@ -96,6 +102,10 @@ CON_COMMAND( cl_reload_localization_files, "Reloads all localization files" )
g_pVGuiLocalize->ReloadLocalizationFiles();
}

#ifdef NEO
CNeoLoading *g_pNeoLoading;
#endif

#ifdef VOICE_VOX_ENABLE
void VoxCallback( IConVar *var, const char *oldString, float oldFloat )
{
Expand Down Expand Up @@ -287,6 +297,10 @@ ClientModeShared::ClientModeShared()
m_pWeaponSelection = NULL;
m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1;

#ifdef NEO
g_pNeoLoading = nullptr;
#endif

#if defined( REPLAY_ENABLED )
m_pReplayReminderPanel = NULL;
m_flReplayStartRecordTime = 0.0f;
Expand Down Expand Up @@ -385,6 +399,17 @@ void ClientModeShared::Init()

HOOK_MESSAGE( VGUIMenu );
HOOK_MESSAGE( Rumble );

#ifdef NEO
if (CreateInterfaceFn gameUIFactory = g_gameUI.GetFactory())
{
if (IGameUI *pGameUI = reinterpret_cast<IGameUI *>(gameUIFactory(GAMEUI_INTERFACE_VERSION, nullptr)))
{
g_pNeoLoading = new CNeoLoading;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should g_pNeoLoading be deleted and the value of the pointer reset in ~ClientModeShared()

pGameUI->SetLoadingBackgroundDialog(g_pNeoLoading->GetVPanel());
}
}
#endif
}


Expand Down Expand Up @@ -874,6 +899,10 @@ void ClientModeShared::LevelInit( const char *newmap )
// Reset any player explosion/shock effects
CLocalPlayerFilter filter;
enginesound->SetPlayerDSP( filter, 0, true );

#ifdef NEO
g_pVGuiLocalize->ConvertANSIToUnicode(newmap, g_pNeoLoading->m_wszLoadingMap, sizeof(g_pNeoLoading->m_wszLoadingMap));
#endif
}

//-----------------------------------------------------------------------------
Expand All @@ -897,6 +926,10 @@ void ClientModeShared::LevelShutdown( void )
// Reset any player explosion/shock effects
CLocalPlayerFilter filter;
enginesound->SetPlayerDSP( filter, 0, true );

#ifdef NEO
g_pNeoLoading->m_wszLoadingMap[0] = L'\0';
#endif
}


Expand Down
214 changes: 214 additions & 0 deletions mp/src/game/client/neo/ui/neo_loading.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#include "neo_loading.h"

#include "cbase.h"
#include "ienginevgui.h"
#include "ui/neo_root.h"
#include "vgui/ISurface.h"
#include "vgui_controls/ProgressBar.h"
#include "vgui_controls/Label.h"
#include "vgui_controls/TextImage.h"
#include "vgui_controls/Frame.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

CNeoLoading::CNeoLoading()
: vgui::EditablePanel(nullptr, "NeoLoadingPanel")
{
SetParent(enginevgui->GetPanel(PANEL_GAMEUIDLL));
InvalidateLayout(false, true);
SetVisible(false);
MakePopup(false);

vgui::HScheme neoscheme = vgui::scheme()->LoadSchemeFromFileEx(
enginevgui->GetPanel(PANEL_CLIENTDLL), "resource/ClientScheme.res", "ClientScheme");
SetScheme(neoscheme);

SetMouseInputEnabled(true);
// NEO TODO (nullsystem): Don't need to handle KB input since ESC already does that
// Unless console controller the concern?
//SetKeyBoardInputEnabled(true);

vgui::IScheme *pScheme = vgui::scheme()->GetIScheme(neoscheme);
ApplySchemeSettings(pScheme);
}

void CNeoLoading::ApplySchemeSettings(vgui::IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);

int wide, tall;
vgui::surface()->GetScreenSize(wide, tall);
SetSize(wide, tall);
SetFgColor(COLOR_TRANSPARENT);
SetBgColor(COLOR_TRANSPARENT);

static constexpr const char *FONT_NAMES[NeoUI::FONT__TOTAL] = {
"NeoUINormal", "NHudOCR", "NHudOCRSmallNoAdditive", "ClientTitleFont",
"NeoUILarge"
};
for (int i = 0; i < NeoUI::FONT__TOTAL; ++i)
{
m_uiCtx.fonts[i].hdl = pScheme->GetFont(FONT_NAMES[i], true);
}

// In 1080p, g_uiCtx.iRowTall == 40, g_uiCtx.iMarginX = 10, g_iAvatar = 64,
// other resolution scales up/down from it
m_uiCtx.iRowTall = tall / 27;
m_iRowsInScreen = (tall * 0.85f) / m_uiCtx.iRowTall;
m_uiCtx.iMarginX = wide / 192;
m_uiCtx.iMarginY = tall / 108;
m_uiCtx.selectBgColor = COLOR_NEOPANELACCENTBG;
const float flWide = static_cast<float>(wide);
float flWideAs43 = static_cast<float>(tall) * (4.0f / 3.0f);
if (flWideAs43 > flWide) flWideAs43 = flWide;
m_iRootSubPanelWide = static_cast<int>(flWideAs43 * 0.9f);
}

void CNeoLoading::OnMessage(const KeyValues *params, vgui::VPANEL fromPanel)
{
BaseClass::OnMessage(params, fromPanel);
const char *pSzMsgName = params->GetName();
if (V_strcmp(pSzMsgName, "Activate") == 0)
{
FetchGameUIPanels();
g_pNeoRoot->m_bOnLoadingScreen = true;
}
else if (V_strcmp(pSzMsgName, "deactivate") == 0)
{
g_pNeoRoot->m_bOnLoadingScreen = false;
}
}

void CNeoLoading::FetchGameUIPanels()
{
m_bValidGameUIPanels = false;
vgui::VPANEL basePanel = vgui::INVALID_PANEL;
vgui::VPANEL rootPanel = enginevgui->GetPanel(PANEL_GAMEUIDLL);
const int iRootChildren = vgui::ipanel()->GetChildCount(rootPanel);
for (int i = 0; i < iRootChildren; ++i)
{
const vgui::VPANEL curBasePanel = vgui::ipanel()->GetChild(rootPanel, i);
const char *curBasePanelName = vgui::ipanel()->GetName(curBasePanel);
if (V_strcmp(curBasePanelName, "BaseGameUIPanel") == 0)
{
basePanel = curBasePanel;
break;
}
}
if (basePanel == vgui::INVALID_PANEL)
{
return;
}

vgui::VPANEL loadingPanel = vgui::INVALID_PANEL;
const int iBaseChildren = vgui::ipanel()->GetChildCount(basePanel);
for (int i = 0; i < iBaseChildren; ++i)
{
const vgui::VPANEL curLoadingPanel = vgui::ipanel()->GetChild(basePanel, i);
const char *curLoadingPanelName = vgui::ipanel()->GetName(curLoadingPanel);
if (V_strcmp(curLoadingPanelName, "LoadingDialog") == 0)
{
loadingPanel = curLoadingPanel;
break;
}
}
if (loadingPanel == vgui::INVALID_PANEL)
{
return;
}

m_pLoadingPanel = static_cast<vgui::Frame *>(vgui::ipanel()->GetPanel(loadingPanel, "GAMEUI"));

m_aStrIdxMap[LOADINGSTATE_LOADING] = g_pVGuiLocalize->FindIndex("GameUI_Loading");
m_aStrIdxMap[LOADINGSTATE_DISCONNECTED] = g_pVGuiLocalize->FindIndex("GameUI_Disconnected");

// Hide loading panel
vgui::ipanel()->SetParent(loadingPanel, 0);
m_bValidGameUIPanels = true;
const int iLoadingChildren = vgui::ipanel()->GetChildCount(loadingPanel);
for (int i = 0; i < iLoadingChildren; ++i)
{
const vgui::VPANEL curLoadChPanel = vgui::ipanel()->GetChild(loadingPanel, i);
const char *curLoadChPanelName = vgui::ipanel()->GetName(curLoadChPanel);
const char *curLoadChPanelClass = vgui::ipanel()->GetClassName(curLoadChPanel);
Panel *pPanel = vgui::ipanel()->GetPanel(curLoadChPanel, "GAMEUI");
if (!pPanel)
{
continue;
}
if (V_strcmp(curLoadChPanelName, "Progress") == 0)
{
Assert(V_strcmp(curLoadChPanelClass, "ProgressBar") == 0);
m_pProgressBarMain = static_cast<vgui::ProgressBar *>(pPanel);
}
else if (V_strcmp(curLoadChPanelName, "InfoLabel") == 0)
{
Assert(V_strcmp(curLoadChPanelClass, "Label") == 0);
m_pLabelInfo = static_cast<vgui::Label *>(pPanel);
}
// NEO NOTE (nullsystem): Unused panels:
// "Progress2" - Don't seem utilized
// "TimeRemainingLabel" - Don't seem utilized
// "CancelButton" - Can't do mouse input proper/workaround doesn't work well
}
}

void CNeoLoading::Paint()
{
OnMainLoop(NeoUI::MODE_PAINT);
}

void CNeoLoading::OnMainLoop(const NeoUI::Mode eMode)
{
static constexpr int BOTTOM_ROWS = 3;

int wide, tall;
GetSize(wide, tall);
m_uiCtx.dPanel.x = (wide / 2) - (m_iRootSubPanelWide / 2);
m_uiCtx.dPanel.wide = m_iRootSubPanelWide;
m_uiCtx.dPanel.tall = (m_iRowsInScreen - BOTTOM_ROWS) * m_uiCtx.iRowTall;
m_uiCtx.dPanel.y = (tall / 2) - ((m_iRowsInScreen * m_uiCtx.iRowTall) / 2);
m_uiCtx.bgColor = COLOR_TRANSPARENT;

// NEO JANK (nullsystem): Since we don't have proper access to loading internals,
// determining by localization text index should be good enough to differ between
// loading and disconnect state.
vgui::TextImage *pTITitle = m_pLoadingPanel ? m_pLoadingPanel->TITitlePtr() : nullptr;
const StringIndex_t iStrIdx = pTITitle ? pTITitle->GetUnlocalizedTextSymbol() : INVALID_LOCALIZE_STRING_INDEX;
NeoUI::BeginContext(&m_uiCtx, eMode, pTITitle ? pTITitle->GetUText() : L"Loading...", "NeoLoadingMainCtx");
if (iStrIdx == m_aStrIdxMap[LOADINGSTATE_LOADING])
{
NeoUI::BeginSection();
{
m_uiCtx.eFont = NeoUI::FONT_NTLARGE;
NeoUI::Label(m_wszLoadingMap);
m_uiCtx.eFont = NeoUI::FONT_NTNORMAL;
}
NeoUI::EndSection();
m_uiCtx.dPanel.y += m_uiCtx.dPanel.tall;
m_uiCtx.dPanel.tall = BOTTOM_ROWS * m_uiCtx.iRowTall;
m_uiCtx.bgColor = COLOR_NEOPANELFRAMEBG;
NeoUI::BeginSection(true);
{
NeoUI::Label(L"Press ESC to cancel");
if (m_pLabelInfo) NeoUI::Label(m_pLabelInfo->GetTextImage()->GetUText());
if (m_pProgressBarMain) NeoUI::Progress(m_pProgressBarMain->GetProgress(), 0.0f, 1.0f);
}
NeoUI::EndSection();
}
else if (iStrIdx == m_aStrIdxMap[LOADINGSTATE_DISCONNECTED])
{
m_uiCtx.dPanel.tall = (m_iRowsInScreen / 2) * m_uiCtx.iRowTall;
m_uiCtx.dPanel.y = (tall / 2) - (m_uiCtx.dPanel.tall / 2);
m_uiCtx.bgColor = COLOR_NEOPANELFRAMEBG;
NeoUI::BeginSection(true);
{
if (m_pLabelInfo) NeoUI::LabelWrap(m_pLabelInfo->GetTextImage()->GetUText());
NeoUI::Pad();
NeoUI::Label(L"Press ESC to go back");
}
NeoUI::EndSection();
}
NeoUI::EndContext();
}
44 changes: 44 additions & 0 deletions mp/src/game/client/neo/ui/neo_loading.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include "ui/neo_ui.h"
#include <vgui_controls/EditablePanel.h>

/*
* Override loading screen
*
* Based on: https://developer.valvesoftware.com/wiki/Custom_loading_screen by Maestra Fenix
* Although goes beyond and tries to re-route text and progress into NeoUI
*/

class CNeoLoading : public vgui::EditablePanel
{
DECLARE_CLASS_SIMPLE(CNeoLoading, vgui::EditablePanel);
public:
CNeoLoading();
wchar_t m_wszLoadingMap[256] = {};

void ApplySchemeSettings(vgui::IScheme *pScheme) final;
void OnMessage(const KeyValues *params, vgui::VPANEL fromPanel) final;
void FetchGameUIPanels();

void Paint() final;
void OnMainLoop(const NeoUI::Mode eMode);

NeoUI::Context m_uiCtx;
int m_iRowsInScreen = 0;
int m_iRootSubPanelWide = 0;

bool m_bValidGameUIPanels = false;
vgui::Frame *m_pLoadingPanel = nullptr;
vgui::ProgressBar *m_pProgressBarMain = nullptr;
vgui::Label *m_pLabelInfo = nullptr;

enum ELoadingState
{
LOADINGSTATE_LOADING = 0,
LOADINGSTATE_DISCONNECTED,

LOADINGSTATE__TOTAL,
};
unsigned long m_aStrIdxMap[LOADINGSTATE__TOTAL] = {};
};
Loading