Models on VGUI Panels: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
Basic code dump for model render in vgui panel : | Basic code dump for model render in vgui panel : | ||
[[Image:Vguimodelrender.jpg|frame|Player model rendered in VGUI panel]] This article shows how to render a player model to a custom VGUI image panel, the player model can be shown with a weapon and any animation. | |||
It involves editing ''clientmode.cpp'', ''teammenu.cpp'' and ''teammenu.h'' (or as appropriate for your mod). The basic premise is to generate a global list of the custom image panel, checking if any of the panel's is visible and then drawing the contents. | |||
Possible expansions to this feature are to allow specification of the weapon model and animations required in the .res file entry. | |||
'''sdk_clientmode.cpp''' | '''sdk_clientmode.cpp''' | ||
Revision as of 21:25, 11 March 2006
Basic code dump for model render in vgui panel :
This article shows how to render a player model to a custom VGUI image panel, the player model can be shown with a weapon and any animation.
It involves editing clientmode.cpp, teammenu.cpp and teammenu.h (or as appropriate for your mod). The basic premise is to generate a global list of the custom image panel, checking if any of the panel's is visible and then drawing the contents.
Possible expansions to this feature are to allow specification of the weapon model and animations required in the .res file entry.
sdk_clientmode.cpp
void UpdateClassImageEntity( const char *pModelName, int x, int y, int width, int height );
CHandle<C_BaseAnimatingOverlay> g_ClassImagePlayer; // player CHandle<C_BaseAnimating> g_ClassImageWeapon; // weapon
// Utility to determine if the vgui panel is visible
bool WillPanelBeVisible( vgui::VPANEL hPanel )
{
while ( hPanel )
{
if ( !vgui::ipanel()->IsVisible( hPanel ) )
return false;
hPanel = vgui::ipanel()->GetParent( hPanel );
}
return true;
}
// Called to see if we should be creating or recreating the model instances
bool ShouldRecreateClassImageEntity( C_BaseAnimating *pEnt, const char *pNewModelName )
{
if ( !pNewModelName || !pNewModelName[0] )
return false;
if ( !pEnt )
return true;
const model_t *pModel = pEnt->GetModel();
if ( !pModel )
return true;
const char *pName = modelinfo->GetModelName( pModel );
if ( !pName )
return true;
// reload only if names are different
return( Q_stricmp( pName, pNewModelName ) != 0 );
}
void ClientModeSDKNormal::PostRenderVGui()
{
// If the team menu is up, then we will render the model of the character that is currently selected.
for ( int i=0; i < g_ClassImagePanels.Count(); i++ )
{
CClassImagePanel *pPanel = g_ClassImagePanels[i];
if ( WillPanelBeVisible( pPanel->GetVPanel() ) )
{
// Ok, we have a visible class image panel.
int x, y, w, h;
pPanel->GetBounds( x, y, w, h );
pPanel->LocalToScreen( x, y );
// Allow for the border.
x += 3;
y += 5;
w -= 2;
h -= 10;
UpdateClassImageEntity( g_ClassImagePanels[i]->m_ModelName, x, y, w, h );
return;
}
}
}
void UpdateClassImageEntity(
const char *pModelName,
int x, int y, int width, int height )
{
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
const char *pWeaponName = "models/weapons/f2000/w_f2000.mdl";
const char *pWeaponSequence = "Idle_Upper_Aug";
C_BaseAnimatingOverlay *pPlayerModel = g_ClassImagePlayer.Get();
// Does the entity even exist yet?
bool recreatePlayer = ShouldRecreateClassImageEntity( pPlayerModel, pModelName );
if ( recreatePlayer )
{
if ( pPlayerModel )
pPlayerModel->Remove();
pPlayerModel = new C_BaseAnimatingOverlay;
pPlayerModel->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY );
pPlayerModel->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
// have the player stand idle
pPlayerModel->SetSequence( pPlayerModel->LookupSequence( "Idle_lower" ) );
pPlayerModel->SetPoseParameter( 0, 0.0f ); // move_yaw
pPlayerModel->SetPoseParameter( 1, 10.0f ); // body_pitch, look down a bit
pPlayerModel->SetPoseParameter( 2, 0.0f ); // body_yaw
pPlayerModel->SetPoseParameter( 3, 0.0f ); // move_y
pPlayerModel->SetPoseParameter( 4, 0.0f ); // move_x, walk forward
g_ClassImagePlayer = pPlayerModel;
}
C_BaseAnimating *pWeaponModel = g_ClassImageWeapon.Get();
// Does the entity even exist yet?
if ( recreatePlayer || ShouldRecreateClassImageEntity( pWeaponModel, pWeaponName ) )
{
if ( pWeaponModel )
pWeaponModel->Remove();
pWeaponModel = new C_BaseAnimating;
pWeaponModel->InitializeAsClientEntity( pWeaponName, RENDER_GROUP_OPAQUE_ENTITY );
pWeaponModel->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
pWeaponModel->FollowEntity( pPlayerModel ); // attach to player model
g_ClassImageWeapon = pWeaponModel;
}
Vector origin = pLocalPlayer->EyePosition();
Vector lightOrigin = origin;
// find a spot inside the world for the dlight's origin, or it won't illuminate the model
Vector testPos( origin.x - 100, origin.y, origin.z + 100 );
trace_t tr;
UTIL_TraceLine( origin, testPos, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction == 1.0f )
{
lightOrigin = tr.endpos;
}
else
{
// Now move the model away so we get the correct illumination
lightOrigin = tr.endpos + Vector( 1, 0, -1 ); // pull out from the solid
Vector start = lightOrigin;
Vector end = lightOrigin + Vector( 100, 0, -100 );
UTIL_TraceLine( start, end, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
origin = tr.endpos;
}
float ambient = engine->GetLightForPoint( origin, true ).Length();
// Make a light so the model is well lit.
// use a non-zero number so we cannibalize ourselves next frame
dlight_t *dl = effects->CL_AllocDlight( LIGHT_INDEX_TE_DYNAMIC+1 );
dl->flags = DLIGHT_NO_WORLD_ILLUMINATION;
dl->origin = lightOrigin;
// Go away immediately so it doesn't light the world
dl->die = gpGlobals->curtime + 0.1f; too.
dl->color.r = dl->color.g = dl->color.b = 250;
if ( ambient < 1.0f )
{
dl->color.exponent = 1 + (1 - ambient) * 2;
}
dl->radius = 400;
// move player model in front of our view
pPlayerModel->SetAbsOrigin( origin );
pPlayerModel->SetAbsAngles( QAngle( 0, 210, 0 ) );
// set upper body animation
pPlayerModel->m_SequenceTransitioner.Update(
pPlayerModel->GetModelPtr(),
pPlayerModel->LookupSequence( "walk_lower" ),
pPlayerModel->GetCycle(),
pPlayerModel->GetPlaybackRate(),
gpGlobals->realtime,
false,
true
);
// Now, blend the lower and upper (aim) anims together
pPlayerModel->SetNumAnimOverlays( 2 );
int numOverlays = pPlayerModel->GetNumAnimOverlays();
for ( int i=0; i < numOverlays; ++i )
{
C_AnimationLayer *layer = pPlayerModel->GetAnimOverlay( i );
layer->flCycle = pPlayerModel->GetCycle();
if ( i )
layer->nSequence = pPlayerModel->LookupSequence( pWeaponSequence );
else
layer->nSequence = pPlayerModel->LookupSequence( "walk_lower" );
layer->flPlaybackrate = 1.0;
layer->flWeight = 1.0f;
layer->SetOrder( i );
}
pPlayerModel->FrameAdvance( gpGlobals->frametime );
// Now draw it.
CViewSetup view;
view.x = x;
view.y = y;
view.width = width;
view.height = height;
view.m_bOrtho = false;
view.fov = 54;
view.origin = origin + Vector( -110, -5, -5 );
Vector vMins, vMaxs;
pPlayerModel->C_BaseAnimating::GetRenderBounds( vMins, vMaxs );
view.origin.z += ( vMins.z + vMaxs.z ) * 0.55f;
view.angles.Init();
view.m_vUnreflectedOrigin = view.origin;
view.zNear = VIEW_NEARZ;
view.zFar = 1000;
view.m_bForceAspectRatio1To1 = false;
Frustum dummyFrustum;
render->ViewSetup3D( &view, dummyFrustum );
pPlayerModel->DrawModel( STUDIO_RENDER );
if ( pWeaponModel )
{
pWeaponModel->DrawModel( STUDIO_RENDER );
}
}
teammenu.h
class CClassImagePanel : public vgui::ImagePanel
{
public:
typedef vgui::ImagePanel BaseClass;
CClassImagePanel( vgui::Panel *pParent, const char *pName );
virtual ~CClassImagePanel();
virtual void ApplySettings( KeyValues *inResourceData );
virtual void Paint();
public:
char m_ModelName[128];
};
extern CUtlVector<CClassImagePanel*> g_ClassImagePanels;
teammenu.cpp
CUtlVector<CClassImagePanel*> g_ClassImagePanels;
CClassImagePanel::CClassImagePanel( vgui::Panel *pParent, const char *pName ) : vgui::ImagePanel( pParent, pName ) { g_ClassImagePanels.AddToTail( this ); m_ModelName[0] = 0; }
CClassImagePanel::~CClassImagePanel() { g_ClassImagePanels.FindAndRemove( this ); }
void CClassImagePanel::ApplySettings( KeyValues *inResourceData ) { const char *pName = inResourceData->GetString( "3DModel" ); if ( pName ) { Q_strncpy( m_ModelName, pName, sizeof( m_ModelName ) ); }
BaseClass::ApplySettings( inResourceData ); }
void CClassImagePanel::Paint() { BaseClass::Paint(); }
Panel *TeamMenu::CreateControlByName(const char *controlName) { if ( Q_stricmp( controlName, "ClassImagePanel" ) == 0 ) { return new CClassImagePanel( NULL, controlName ); }
return BaseClass::CreateControlByName( controlName ); }
teammenu.res
"classimage"
{
"ControlName" "ClassImagePanel"
"fieldName" "classimage"
"xpos" "270"
"ypos" "170"
"wide" "512"
"tall" "384"
"autoResize" "0"
"pinCorner" "0"
"visible" "1"
"enabled" "1"
"textAlignment" "west"
"3DModel" "models/player/iris.mdl"
"scaleImage" "1"
"zpos" "1"
}
