Custom loading screen: Difference between revisions
MaestroFenix (talk | contribs) (Created page with "File:Custom loading screen test.jpg|thumb|600px|Showing the final results, in this case, loading a custom screen upon detecting a defined map. Note: The RES file for the loa...") |
GamerDude27 (talk | contribs) m (Removed div style from code blocks and grammar corrections,) |
||
Line 1: | Line 1: | ||
[[File:Custom loading screen test.jpg|thumb|600px|Showing the final results, in this case, loading a custom screen upon detecting a defined map. Note: The RES file for the loading pop-up was edited in order to remove borders so the background isn't "cut-off". ]] | [[File:Custom loading screen test.jpg|thumb|600px|Showing the final results, in this case, loading a custom screen upon detecting a defined map. Note: The RES file for the loading pop-up was edited in order to remove borders so the background isn't "cut-off". ]] | ||
The following code allows to have custom loading screens when loading maps, either unique ones depending on the map name, or a default one. The final aspect will make it look like in No More Room In Hell, or Obsidian Conflict. | The following code allows us to have custom loading screens when loading maps, either unique ones depending on the map name, or a default one. The final aspect will make it look like in No More Room In Hell, or Obsidian Conflict. | ||
This method overrides GameUI as seen in [https://developer.valvesoftware.com/wiki/Override_GameUI here] and based on what it was hinted on [https://www.mail-archive.com/hlcoders@list.valvesoftware.com/msg26845.html this email from HLCoders]. | This method overrides GameUI as seen in [https://developer.valvesoftware.com/wiki/Override_GameUI here] and based on what it was hinted on [https://www.mail-archive.com/hlcoders@list.valvesoftware.com/msg26845.html this email from HLCoders]. | ||
Line 19: | Line 19: | ||
=== mapload_background.h === | === mapload_background.h === | ||
<source lang=cpp> | <source lang=cpp> | ||
//======= Maestra Fenix, 2017 ==================================================// | //======= Maestra Fenix, 2017 ==================================================// | ||
Line 62: | Line 61: | ||
#endif // !MAPLOAD_BACKGROUND_H | #endif // !MAPLOAD_BACKGROUND_H | ||
</source> | </source> | ||
=== mapload_background.cpp === | === mapload_background.cpp === | ||
<source lang=cpp> | <source lang=cpp> | ||
//======= Maestra Fenix, 2017 ==================================================// | //======= Maestra Fenix, 2017 ==================================================// | ||
Line 126: | Line 123: | ||
} | } | ||
</source> | </source> | ||
Line 132: | Line 128: | ||
Go to <code>clientmode_share.cpp</code> and add the following between lines 42 and 44 ( after <code>#if defined( _X360 )</code> and before <code>#if defined( REPLAY_ENABLED )</code> ): | Go to <code>clientmode_share.cpp</code> and add the following between lines 42 and 44 ( after <code>#if defined( _X360 )</code> and before <code>#if defined( REPLAY_ENABLED )</code> ): | ||
<source lang=cpp> | <source lang=cpp> | ||
//Fenix: Needed for the custom background loading screens | //Fenix: Needed for the custom background loading screens | ||
Line 138: | Line 133: | ||
#include "mapload_background.h" | #include "mapload_background.h" | ||
</source> | </source> | ||
Add this following snippet between lines 77 and 79 ( after <code>static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT;</code> and before <code>ConVar cl_drawhud</code> ): | Add this following snippet between lines 77 and 79 ( after <code>static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT;</code> and before <code>ConVar cl_drawhud</code> ): | ||
<source lang=cpp> | <source lang=cpp> | ||
//Fenix: Needed for the custom background loading screens | //Fenix: Needed for the custom background loading screens | ||
Line 149: | Line 142: | ||
static CDllDemandLoader g_GameUI( "GameUI" ); | static CDllDemandLoader g_GameUI( "GameUI" ); | ||
</source> | </source> | ||
Lines 87 and 89 ( after <code>extern bool IsInCommentaryMode( void );</code> and before <code>#ifdef VOICE_VOX_ENABLE</code> ): | Lines 87 and 89 ( after <code>extern bool IsInCommentaryMode( void );</code> and before <code>#ifdef VOICE_VOX_ENABLE</code> ): | ||
<source lang=cpp> | <source lang=cpp> | ||
//Fenix: Needed for the custom background loading screens | //Fenix: Needed for the custom background loading screens | ||
Line 159: | Line 150: | ||
IMaterial *pMatMapBg; | IMaterial *pMatMapBg; | ||
</source> | </source> | ||
In <code>ClientModeShared()</code>, add the following after line 278 ( <code>m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1;</code> ): | In <code>ClientModeShared()</code>, add the following after line 278 ( <code>m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1;</code> ): | ||
<source lang=cpp> | <source lang=cpp> | ||
//Fenix: Needed for the custom background loading screens | //Fenix: Needed for the custom background loading screens | ||
Line 169: | Line 158: | ||
pMatMapBg = NULL; | pMatMapBg = NULL; | ||
</source> | </source> | ||
At <code>Init()</code>, after line 368 ( <code>HOOK_MESSAGE( Rumble );</code> ): | At <code>Init()</code>, after line 368 ( <code>HOOK_MESSAGE( Rumble );</code> ): | ||
<source lang=cpp> | <source lang=cpp> | ||
//Fenix: Custom background loading screens - Injects the custom panel at the loading screen | //Fenix: Custom background loading screens - Injects the custom panel at the loading screen | ||
Line 191: | Line 178: | ||
} | } | ||
</source> | </source> | ||
To end this, add the following in <code>LevelInit( const char *newmap )</code> at line 832 ( after <code>enginesound->SetPlayerDSP( filter, 0, true );</code> ): | To end this, add the following in <code>LevelInit( const char *newmap )</code> at line 832 ( after <code>enginesound->SetPlayerDSP( filter, 0, true );</code> ): | ||
<source lang=cpp> | <source lang=cpp> | ||
//Fenix: Custom background loading screens - decides if use a loading screen for a map or a default one | //Fenix: Custom background loading screens - decides if use a loading screen for a map or a default one | ||
Line 220: | Line 205: | ||
} | } | ||
</source> | </source> | ||
Line 231: | Line 215: | ||
Create this RES file at the <code>resource</code> folder present on the main mod folder: | Create this RES file at the <code>resource</code> folder present on the main mod folder: | ||
<source lang=cpp> | <source lang=cpp> | ||
"Resource/loadingdialogbackground.res" | "Resource/loadingdialogbackground.res" | ||
Line 254: | Line 237: | ||
} | } | ||
</source> | </source> | ||
Line 260: | Line 242: | ||
Head to <code>materials/vgui/</code> and create a new folder called <code>loading</code>. In there, create a VMT called <code>default</code> with the following code: | Head to <code>materials/vgui/</code> and create a new folder called <code>loading</code>. In there, create a VMT called <code>default</code> with the following code: | ||
<source lang=cpp> | <source lang=cpp> | ||
"UnlitGeneric" | "UnlitGeneric" | ||
Line 272: | Line 253: | ||
} | } | ||
</source> | </source> | ||
You are free to create a VTF texture with the same name of any size, although I recommend being 2048 x 1024 big, with <code>No Mipmap</code>, <code>No Level of Detail</code> and <code>No Minimum Mipmap</code> flags checked. | You are free to create a VTF texture with the same name of any size, although I recommend being 2048 x 1024 big, with <code>No Mipmap</code>, <code>No Level of Detail</code> and <code>No Minimum Mipmap</code> flags checked. | ||
Line 285: | Line 265: | ||
== Notes == | == Notes == | ||
* This code was made with having as a reference the | * This code was made with having as a reference the emails at HLCoders present above and looking at how NMRIH loading screens appear. Aside from that, all was guesswork and trial & error. Likely there can be better methods out there, but couldn't find other ways. Those teams who did refuse to share their secrets. | ||
* As seen in NMRIH and OC, the checks about if a map has a present custom loading screen aren't made until late in the load. Other mods apparently were able to do it instantly, but IDK how they did that without engine access. | * As seen in NMRIH and OC, the checks about if a map has a present custom loading screen aren't made until late in the load. Other mods apparently were able to do it instantly, but IDK how they did that without engine access. |
Revision as of 14:53, 2 June 2020
The following code allows us to have custom loading screens when loading maps, either unique ones depending on the map name, or a default one. The final aspect will make it look like in No More Room In Hell, or Obsidian Conflict.
This method overrides GameUI as seen in here and based on what it was hinted on this email from HLCoders.
Credit me ( Maestra Fénix ) if you want to use this, that's the sole condition.
Requirements
- A mod running on Source SDK 2013
- Knowledge of C++, RES, and VMT / VTF files.
Code
Place the following two files somewhere in client
( if possible, in a subfolder in order to keep it tidy ):
mapload_background.h
//======= Maestra Fenix, 2017 ==================================================//
//
// Purpose: Map load background panel
//
//==============================================================================//
#ifndef MAPLOAD_BACKGROUND_H
#define MAPLOAD_BACKGROUND_H
#ifdef _WIN32
#pragma once
#endif
#include "vgui\ISurface.h"
#include <vgui_controls/EditablePanel.h>
#include <vgui_controls\ImagePanel.h>
#include "ienginevgui.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CMapLoadBG : public vgui::EditablePanel
{
DECLARE_CLASS_SIMPLE( CMapLoadBG, vgui::EditablePanel);
public:
// Construction
CMapLoadBG( char const *panelName );
~CMapLoadBG();
void SetNewBackgroundImage( char const *imageName );
protected:
void ApplySchemeSettings( vgui::IScheme *pScheme );
private:
vgui::ImagePanel *m_pBackground;
};
#endif // !MAPLOAD_BACKGROUND_H
mapload_background.cpp
//======= Maestra Fenix, 2017 ==================================================//
//
// Purpose: Map load background panel
//
//==============================================================================//
#include "cbase.h"
#include "mapload_background.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMapLoadBG::CMapLoadBG( char const *panelName ) : EditablePanel( NULL, panelName )
{
VPANEL toolParent = enginevgui->GetPanel( PANEL_GAMEUIDLL );
SetParent( toolParent );
//Fenix: We load a RES file rather than create the element here for taking advantage of the "F" parameter for wide and tall
//Is the sole thing that makes fill the background to the entire screen regardless of the texture size
//Congratulations to Valve for once again give options to only one side and not both
LoadControlSettings( "resource/loadingdialogbackground.res" );
m_pBackground = FindControl<ImagePanel>( "LoadingImage", true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMapLoadBG::~CMapLoadBG()
{
// None
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapLoadBG::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
int iWide, iTall;
surface()->GetScreenSize( iWide, iTall );
SetSize( iWide, iTall );
}
//-----------------------------------------------------------------------------
// Purpose: Sets a new background on demand
//-----------------------------------------------------------------------------
void CMapLoadBG::SetNewBackgroundImage( char const *imageName )
{
m_pBackground->SetImage( imageName );
}
Go to clientmode_share.cpp
and add the following between lines 42 and 44 ( after #if defined( _X360 )
and before #if defined( REPLAY_ENABLED )
):
//Fenix: Needed for the custom background loading screens
#include "GameUI/IGameUI.h"
#include "mapload_background.h"
Add this following snippet between lines 77 and 79 ( after static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT;
and before ConVar cl_drawhud
):
//Fenix: Needed for the custom background loading screens
// See interface.h/.cpp for specifics: basically this ensures that we actually Sys_UnloadModule the dll and that we don't call Sys_LoadModule
// over and over again.
static CDllDemandLoader g_GameUI( "GameUI" );
Lines 87 and 89 ( after extern bool IsInCommentaryMode( void );
and before #ifdef VOICE_VOX_ENABLE
):
//Fenix: Needed for the custom background loading screens
CMapLoadBG *pPanelBg;
IMaterial *pMatMapBg;
In ClientModeShared()
, add the following after line 278 ( m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1;
):
//Fenix: Needed for the custom background loading screens
pPanelBg = NULL;
pMatMapBg = NULL;
At Init()
, after line 368 ( HOOK_MESSAGE( Rumble );
):
//Fenix: Custom background loading screens - Injects the custom panel at the loading screen
CreateInterfaceFn gameUIFactory = g_GameUI.GetFactory();
if ( gameUIFactory )
{
IGameUI *pGameUI = ( IGameUI * )gameUIFactory( GAMEUI_INTERFACE_VERSION, NULL );
if ( pGameUI )
{
// insert custom loading panel for the loading dialog
pPanelBg = new CMapLoadBG( "Background" );
pPanelBg->InvalidateLayout( false, true );
pPanelBg->SetVisible(false);
pPanelBg->MakePopup( false );
pGameUI->SetLoadingBackgroundDialog( pPanelBg->GetVPanel() );
}
}
To end this, add the following in LevelInit( const char *newmap )
at line 832 ( after enginesound->SetPlayerDSP( filter, 0, true );
):
//Fenix: Custom background loading screens - decides if use a loading screen for a map or a default one
#ifdef _WIN32
char szMapBgName[MAX_PATH];
#else // !_WIN32
char szMapBgName[PATH_MAX];
#endif // _WIN32
Q_snprintf( szMapBgName, sizeof( szMapBgName ), "vgui/loading/maps/%s", newmap );
pMatMapBg = materials->FindMaterial( szMapBgName, TEXTURE_GROUP_OTHER );
if ( !pMatMapBg->IsErrorMaterial() )
{
Q_snprintf( szMapBgName, sizeof( szMapBgName ), "loading/maps/%s", newmap );
pPanelBg->SetNewBackgroundImage( szMapBgName );
}
else
{
pPanelBg->SetNewBackgroundImage( "loading/default" );
}
Here ends all the work at the code. Time to create the RES file and the VMT and VTF files.
RES and VMT / VTF
loadingdialogbackground.res
Create this RES file at the resource
folder present on the main mod folder:
"Resource/loadingdialogbackground.res"
{
"LoadingImage"
{
"ControlName" "ImagePanel"
"fieldName" "LoadingImage"
"xpos" "0"
"ypos" "0"
"wide" "f-1"
"tall" "f-1"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"border" "1"
"image" "loading/default" //Leaving it empty will make appear a grey background the first time on map load
"scaleImage" "1"
}
}
VMT & VTF
Head to materials/vgui/
and create a new folder called loading
. In there, create a VMT called default
with the following code:
"UnlitGeneric"
{
"$basetexture" "vgui/loading/default"
"$vertexcolor" 1
"$vertexalpha" 1
"$ignorez" 1
"$no_fullbright" "1"
"$nolod" "1"
}
You are free to create a VTF texture with the same name of any size, although I recommend being 2048 x 1024 big, with No Mipmap
, No Level of Detail
and No Minimum Mipmap
flags checked.
This will be used as the default loading screen in case no defined loading screen for a map is found.
Create now a subfolder called maps
, in there you can place the VMTs and VTFs with the name of the maps desired ( example: ep2_outland_03
).
After this step, the feature is ready to be tested.
Notes
- This code was made with having as a reference the emails at HLCoders present above and looking at how NMRIH loading screens appear. Aside from that, all was guesswork and trial & error. Likely there can be better methods out there, but couldn't find other ways. Those teams who did refuse to share their secrets.
- As seen in NMRIH and OC, the checks about if a map has a present custom loading screen aren't made until late in the load. Other mods apparently were able to do it instantly, but IDK how they did that without engine access.
- This is an obvious one, but this code was very old and can be improved, like having different default loading screens, or avoiding throwing an error in console ( visible with
Developer 2
) if it can't find one.