summaryrefslogtreecommitdiff
path: root/utils/hlmv/controlpanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hlmv/controlpanel.cpp')
-rw-r--r--utils/hlmv/controlpanel.cpp3989
1 files changed, 3989 insertions, 0 deletions
diff --git a/utils/hlmv/controlpanel.cpp b/utils/hlmv/controlpanel.cpp
new file mode 100644
index 0000000..e4c5da5
--- /dev/null
+++ b/utils/hlmv/controlpanel.cpp
@@ -0,0 +1,3989 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+//
+// Half-Life Model Viewer (c) 1999 by Mete Ciragan
+//
+// file: ControlPanel.cpp
+// last modified: May 29 1999, Mete Ciragan
+// copyright: The programs and associated files contained in this
+// distribution were developed by Mete Ciragan. The programs
+// are not in the public domain, but they are freely
+// distributable without licensing fees. These programs are
+// provided without guarantee or warrantee expressed or
+// implied.
+//
+// version: 1.2
+//
+// web: http://www.swissquake.ch/chumbalum-soft/
+//
+#include "ControlPanel.h"
+#include "ViewerSettings.h"
+#include "StudioModel.h"
+#include "IStudioRender.h"
+#include "MatSysWin.h"
+#include "vphysics/constraints.h"
+#include "physmesh.h"
+#include "sys.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mxtk/mx.h>
+#include <mxtk/mxBmp.h>
+#include "vphysics_interface.h"
+#include "utlvector.h"
+#include "utlsymbol.h"
+#include "UtlBuffer.h"
+#include "attachments_window.h"
+#include "istudiorender.h"
+#include "studio_render.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "tier1/KeyValues.h"
+#include "tier0/icommandline.h"
+#include "valve_ipc_win32.h"
+#include "mdlviewer.h"
+
+extern char g_appTitle[];
+extern IPhysicsSurfaceProps *physprop;
+extern bool LoadPhysicsProperties( void );
+extern ISoundEmitterSystemBase *g_pSoundEmitterBase;
+extern CValveIpcClientUtl g_HlmvIpcClient;
+extern bool g_bHlmvMaster;
+
+
+//-----------------------------------------------------------------------------
+// Reads all of the physics materials from surface property file
+//-----------------------------------------------------------------------------
+
+static void ReadPhysicsMaterials( mxChoice *plist )
+{
+ LoadPhysicsProperties();
+ plist->removeAll();
+
+ if ( !physprop || !physprop->SurfacePropCount() )
+ {
+ plist->add("default");
+ plist->select(0);
+ return;
+ }
+
+ for ( int i = 0; i < physprop->SurfacePropCount(); i++ )
+ {
+ plist->add(physprop->GetPropName( i ) );
+ }
+ plist->select(0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates a control with all the physics bones
+//-----------------------------------------------------------------------------
+
+static bool PopulatePhysicsBoneList( mxChoice* pChoice )
+{
+ pChoice->removeAll();
+
+ if ( g_pStudioModel->Physics_GetBoneCount() )
+ {
+ for ( int i = 0; i < g_pStudioModel->Physics_GetBoneCount(); i++ )
+ {
+ pChoice->add (g_pStudioModel->Physics_GetBoneName( i ) );
+ }
+ }
+ else
+ {
+ pChoice->add( "None" );
+ pChoice->select (0);
+ return false;
+ }
+
+ pChoice->select (0);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Populates a control with all the sound names
+//-----------------------------------------------------------------------------
+
+static void PopulateSoundNameList( mxListBox *pListBox )
+{
+ pListBox->removeAll();
+
+ if ( g_pSoundEmitterBase )
+ {
+ for ( int i = g_pSoundEmitterBase->First(); i != g_pSoundEmitterBase->InvalidIndex(); i = g_pSoundEmitterBase->Next( i ) )
+ {
+ pListBox->add( g_pSoundEmitterBase->GetSoundName( i ) );
+ }
+ }
+
+ pListBox->select( 0 );
+ pListBox->deselect( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Populates a control with all the physics bones
+//-----------------------------------------------------------------------------
+
+bool PopulateBoneList( mxChoice* pChoice, bool bAlwaysAddNone = false )
+{
+ pChoice->removeAll();
+
+ if ( bAlwaysAddNone )
+ {
+ pChoice->add( "(None)" );
+ }
+
+ if ( g_pStudioModel )
+ {
+ CStudioHdr *pHdr = g_pStudioModel->GetStudioHdr();
+ if ( pHdr && pHdr->numbones() > 0 )
+ {
+ for ( int i = 0; i < pHdr->numbones(); i++ )
+ {
+ pChoice->add ( pHdr->pBone(i)->pszName() );
+ }
+
+ pChoice->select(0);
+ return true;
+ }
+ }
+
+ if ( !bAlwaysAddNone )
+ {
+ pChoice->add( "(None)" );
+ }
+
+ pChoice->select(0);
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Populates a control with all the attachments
+//-----------------------------------------------------------------------------
+
+void PopulateAttachmentsList( mxChoice *pChoice )
+{
+ pChoice->removeAll();
+
+ pChoice->add( "(none)" );
+
+ if ( g_pStudioModel )
+ {
+ CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
+ if ( pHdr && pHdr->GetNumAttachments() > 0 )
+ {
+ for ( int i = 0; i < pHdr->GetNumAttachments(); i++ )
+ {
+ pChoice->add( pHdr->pAttachment(i).pszName() );
+ }
+ }
+ }
+
+ pChoice->select(0);
+}
+
+//-----------------------------------------------------------------------------
+// Sets the text of a lineedit to the current frame
+//-----------------------------------------------------------------------------
+void SetFrameString( mxLineEdit2 *pLineEdit, int iLayer )
+{
+ float flFrame = g_pStudioModel->GetFrame( iLayer );
+ int nFrame = int( flFrame + 0.5f );
+
+ char msg[ 16 ];
+ sprintf( msg, "%d", nFrame );
+ pLineEdit->setText( msg );
+}
+
+//-----------------------------------------------------------------------------
+// Finds the index of a surface prop
+//-----------------------------------------------------------------------------
+
+static int FindSurfaceProp( const char* pSurfaceProp )
+{
+ for (int i = 0; i < physprop->SurfacePropCount(); ++i)
+ {
+ if (!stricmp( physprop->GetPropName( i ), pSurfaceProp ))
+ return i;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// The tab associated with bone control
+//-----------------------------------------------------------------------------
+
+class CBoneControlWindow : public mxWindow
+{
+public:
+ CBoneControlWindow( ControlPanel* pParent );
+
+ void Init( );
+
+ // This gets called when the model is loaded and unloaded
+ void OnLoadModel();
+ void OnUnloadModel();
+
+ // Handles various events
+ int handleEvent (mxEvent *event);
+
+ // Called when we're selected
+ void OnTabSelected();
+
+ int GetHitboxSet( void );
+private:
+ // Called when the bone is selected
+ void OnBoneSelected( int boneIndex );
+ void OnBoneHighlighted( bool isChecked );
+ void OnHitboxHighlighted( bool isChecked );
+ void OnShowDefaultPose( bool isChecked );
+ void OnHitboxSelected( int hitbox );
+ void OnHitboxGroupChanged( );
+ void OnHitboxChanged( );
+ void OnHitboxSetChanged( void );
+ void OnAddHitbox( );
+ void OnDeleteHitbox( );
+ void OnGenerateQC( );
+ void OnAutogenerateHitboxes( bool isChecked );
+
+ // Writes out qc-style text to a utlbuffer
+ bool SerializeQC( CUtlBuffer& buf );
+
+ // Sets the surface property
+ void OnSurfaceProp( int propIndex );
+
+ // Duplictes the surface property to all children
+ void OnSurfacePropApplyToChildren( );
+
+ void RefreshHitbox( );
+ void ComputeHitboxList( );
+
+ void ComputeHitboxSetList( void );
+ void OnHitboxAddSet( void );
+ void OnHitboxDeleteSet( void );
+ void OnHitboxSetChangeName( void );
+
+ // Generates a list of all hitboxes per bone
+ void PopulateHitboxLists();
+
+ // Applies a surface property to all children
+ void OnSurfacePropApplyToChildren_R( int bone, CUtlSymbol prop );
+
+ // Selects the bone
+ mxChoice* m_cBone;
+
+ mxChoice* m_cHitboxSet;
+
+ mxLineEdit *m_eHitboxSetName;
+ mxButton *m_bHitboxSetUpdateName;
+ mxButton *m_bAddHitboxSet;
+ mxButton *m_bDeleteHitboxSet;
+
+ // Selects a hitbox associated with a bone
+ mxChoice* m_cHitbox;
+
+ // The materials to assign to the bone
+ mxChoice* m_cSurfaceProp;
+
+ // Are we highlighting bones?
+ mxCheckBox* m_cBoneHighlight;
+
+ // Are we highlighting hitboxes?
+ mxCheckBox* m_cHitboxHighlight;
+
+ // Should we show the default pose?
+ mxCheckBox* m_cShowDefaultPose;
+
+ // Should hitboxes be autogenerated?
+ mxCheckBox* m_cAutoHitbox;
+
+ // The control panel to which we're attached
+ ControlPanel* m_pControlPanel;
+
+ // Hitbox group
+ mxLineEdit* m_eHitboxGroup;
+
+ // Hitbox name
+ mxLineEdit* m_eHitboxName;
+
+
+ // Hitbox origin
+ mxLineEdit* m_eOriginX;
+ mxLineEdit* m_eOriginY;
+ mxLineEdit* m_eOriginZ;
+
+ // Hitbox size
+ mxLineEdit* m_eSizeX;
+ mxLineEdit* m_eSizeY;
+ mxLineEdit* m_eSizeZ;
+
+ // Hitbox buttons
+ mxButton* m_bUpdateHitbox;
+ mxButton* m_bAddHitbox;
+ mxButton* m_bDeleteHitbox;
+
+ // The list of hitboxes per bone...
+ typedef CUtlVector< int > BoneHitboxList_t;
+ typedef CUtlVector< BoneHitboxList_t > BoneHitboxes_t;
+
+ CUtlVector< BoneHitboxes_t > m_SetBoneHitBoxes;
+
+ // Currently selected hitbox + bone
+ int m_Bone;
+ int m_Hitbox;
+ int m_nHitboxSet;
+};
+
+
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+
+CBoneControlWindow::CBoneControlWindow( ControlPanel* pParent ) : mxWindow( pParent, 0, 0, 0, 0 )
+{
+ m_pControlPanel = pParent;
+
+ m_nHitboxSet = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Sets up all the controls in the window
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::Init( )
+{
+ int left, top;
+ left = 5;
+ top = 0;
+
+ // Bone selection list
+ new mxLabel (this, left + 3, top + 4, 30, 18, "Bone");
+ m_cBone = new mxChoice (this, left, top + 20, 260, 22, IDC_BONE_BONELIST);
+ m_cBone->add ("None");
+ m_cBone->select (0);
+ mxToolTip::add (m_cBone, "Select a bone to modify");
+
+ // Show bone checkbox
+ m_cBoneHighlight = new mxCheckBox (this, left, top + 45, 140, 20, "Highlight Bone", IDC_BONE_HIGHLIGHT_BONE);
+ mxToolTip::add (m_cBoneHighlight, "Toggle display of the bone being modified");
+
+ // Bone surface property selection
+ new mxLabel (this, left + 3, top + 68, 100, 18, "Bone Surface Prop");
+ m_cSurfaceProp = new mxChoice( this, left, top + 85, 140, 22, IDC_BONE_SURFACEPROP );
+ mxToolTip::add (m_cSurfaceProp, "Select a surface property to apply to the bone");
+
+ // FIXME: We can't read the surface props yet because the vphysics path isn't known!!!
+ // This will only add 'default' to the list
+ ReadPhysicsMaterials( m_cSurfaceProp );
+
+ // This button will apply the surface prop to all children
+ mxButton *btnApplyChild = new mxButton( this, left, top + 115, 140, 20, "Apply to Children", IDC_BONE_APPLY_TO_CHILDREN );
+ mxToolTip::add (btnApplyChild, "Apply the surface property to all child bones");
+
+ // Use autogenerated hitboxes
+ m_cAutoHitbox = new mxCheckBox (this, left, top + 140, 140, 20, "Autogenerate Hitboxes", IDC_BONE_USE_AUTOGENERATED_HITBOXES);
+ mxToolTip::add (m_cAutoHitbox, "When this is checked, studiomdl will automatically generate hitboxes");
+
+ m_cShowDefaultPose = new mxCheckBox (this, left, top + 160, 140, 20, "Show Default Pose", IDC_BONE_SHOW_DEFAULT_POSE);
+ mxToolTip::add (m_cShowDefaultPose, "Toggles display of the default physics pose");
+
+ left = 160;
+
+ new mxLabel( this, left + 3, top + 50, 80, 18, "Hitbox Set" );
+ m_cHitboxSet = new mxChoice (this, left, top + 66, 100, 22, IDC_BONE_HITBOXSET);
+ m_cHitboxSet->add ("unnamed");
+ m_cHitboxSet->select (0);
+ mxToolTip::add (m_cHitboxSet, "Change hitbox set");
+
+ m_eHitboxSetName = new mxLineEdit(this, left, top + 96, 100, 18, "", IDC_BONE_HITBOXSETNAME_EDIT);
+ mxToolTip::add (m_eHitboxSetName, "Type in a name and hit the set button");
+
+ m_bHitboxSetUpdateName = new mxButton( this, left, top + 116, 100, 16, "Set Name", IDC_BONE_HITBOXSETNAME );
+ mxToolTip::add (m_bHitboxSetUpdateName, "Press to set hitbox set name from above text field");
+
+ m_bAddHitboxSet = new mxButton( this, left, top + 140, 100, 20, "Add set", IDC_BONE_HITBOXADDSET );
+ mxToolTip::add (m_bAddHitboxSet, "Add a hitbox set");
+ m_bDeleteHitboxSet= new mxButton( this, left, top + 162, 100, 20, "Delete set", IDC_BONE_HITBOXDELETESET );
+ mxToolTip::add (m_bDeleteHitboxSet, "Remove a hitbox set");
+
+ left += 120;
+
+ // Hitbox selection list
+ new mxLabel (this, left + 3, top + 4, 30, 18, "Hitbox");
+ m_cHitbox = new mxChoice (this, left, top + 20, 100, 22, IDC_BONE_HITBOXLIST);
+ m_cHitbox->add ("None");
+ m_cHitbox->select (0);
+ mxToolTip::add (m_cHitbox, "Select a hitbox to modify");
+
+ // Show hitbox checkbox
+ m_cHitboxHighlight = new mxCheckBox (this, left + 3, top + 45, 100, 20, "Highlight Hitbox", IDC_BONE_HIGHLIGHT_HITBOX);
+ mxToolTip::add (m_cHitboxHighlight, "Toggle display of the hitbox being modified");
+
+ // Hitbox group
+ new mxLabel (this, left + 3, top + 80, 80, 18, "Hitbox Group");
+ m_eHitboxGroup = new mxLineEdit(this, left + 80, top + 75, 50, 22, "", IDC_BONE_HITBOX_GROUP);
+ mxToolTip::add (m_eHitboxGroup, "The group of the current hitbox");
+
+ // Hitbox name
+ new mxLabel (this, left + 133, top + 80, 80, 18, "Hitbox Name");
+ m_eHitboxName = new mxLineEdit(this, left + 133+80, top + 75, 50, 22, "", IDC_BONE_HITBOX_NAME);
+ m_eHitboxName->setEnabled(false);
+ mxToolTip::add (m_eHitboxName, "The name of the current hitbox");
+
+ // Hitbox origin
+ new mxLabel (this, left + 3, top + 110, 80, 18, "Hitbox Origin");
+ new mxLabel (this, left + 133, top + 110, 10, 18, "X");
+ new mxLabel (this, left + 198, top + 110, 10, 18, "Y");
+ new mxLabel (this, left + 263, top + 110, 10, 18, "Z");
+ m_eOriginX = new mxLineEdit(this, left + 80, top + 105, 50, 22, "", IDC_BONE_HITBOX_ORIGINX);
+ m_eOriginY = new mxLineEdit(this, left + 145, top + 105, 50, 22, "", IDC_BONE_HITBOX_ORIGINY);
+ m_eOriginZ = new mxLineEdit(this, left + 210, top + 105, 50, 22, "", IDC_BONE_HITBOX_ORIGINZ);
+
+ // Hitbox size
+ new mxLabel (this, left + 3, top + 140, 80, 18, "Hitbox Size");
+ new mxLabel (this, left + 133, top + 140, 10, 18, "X");
+ new mxLabel (this, left + 198, top + 140, 10, 18, "Y");
+ new mxLabel (this, left + 263, top + 140, 10, 18, "Z");
+ m_eSizeX = new mxLineEdit(this, left + 80, top + 135, 50, 22, "", IDC_BONE_HITBOX_SIZEX);
+ m_eSizeY = new mxLineEdit(this, left + 145, top + 135, 50, 22, "", IDC_BONE_HITBOX_SIZEY);
+ m_eSizeZ = new mxLineEdit(this, left + 210, top + 135, 50, 22, "", IDC_BONE_HITBOX_SIZEZ);
+
+ // Update hitboxes here
+ m_bUpdateHitbox = new mxButton( this, left, top + 163, 100, 20, "Update Hitbox", IDC_BONE_UPDATE_HITBOX );
+ mxToolTip::add (m_bUpdateHitbox, "Apply hitbox group, origin, and size to the hitbox");
+
+ left += 160;
+
+ // Generate a QC file
+ mxButton* btnGenerateQC = new mxButton (this, left, top + 10, 100, 20, "Generate QC", IDC_BONE_GENERATEQC );
+ mxToolTip::add (btnGenerateQC, "Copy a .qc file snippet to the clipboard");
+
+ // Add, remove hitboxes here
+ m_bAddHitbox = new mxButton( this, left, top + 30, 100, 20, "Add Hitbox", IDC_BONE_ADD_HITBOX );
+ m_bDeleteHitbox = new mxButton( this, left, top + 50, 100, 20, "Delete Hitbox", IDC_BONE_DELETE_HITBOX );
+ mxToolTip::add (m_bAddHitbox, "Create a new hitbox attached to the current bone");
+ mxToolTip::add (m_bDeleteHitbox, "Delete the currently selected hitbox");
+
+ OnAutogenerateHitboxes( false );
+}
+
+//-----------------------------------------------------------------------------
+// Generates a list of all hitboxes per bone
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::PopulateHitboxLists()
+{
+ // Find the surface prop associated with this bone
+ if (!g_pStudioModel)
+ return;
+
+ m_SetBoneHitBoxes.RemoveAll();
+ for (int set = 0; set < g_pStudioModel->m_HitboxSets.Count(); set++ )
+ {
+ m_SetBoneHitBoxes.AddToTail();
+
+ HitboxList_t &list = g_pStudioModel->m_HitboxSets[ set ].m_Hitboxes;
+ for ( unsigned short i = list.Head(); i != list.InvalidIndex(); i = list.Next(i) )
+ {
+ mstudiobbox_t* pHitbox = &list[i].m_BBox;
+ m_SetBoneHitBoxes[ set ].EnsureCount( pHitbox->bone + 1 );
+ m_SetBoneHitBoxes[ set ][ pHitbox->bone ].AddToTail( i );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// This gets called when the model is loaded and unloaded
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnLoadModel()
+{
+ // Now that the vphysics path is known, we can load the surface props
+ ReadPhysicsMaterials( m_cSurfaceProp );
+
+ CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
+ m_cAutoHitbox->setChecked( (pHdr->flags() & STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX) != 0 );
+ OnAutogenerateHitboxes( m_cAutoHitbox->isChecked() );
+
+ // Determine all bones for this model
+ PopulateBoneList( m_cBone );
+
+ ComputeHitboxSetList();
+ PopulateHitboxLists();
+
+ OnBoneSelected( 0 );
+ g_bDrawModelInfoValid = false;
+}
+
+void CBoneControlWindow::OnUnloadModel()
+{
+ m_cBone->removeAll();
+ m_cBone->add ("None");
+ m_cBone->select (0);
+
+ m_cAutoHitbox->setChecked( false );
+}
+
+//-----------------------------------------------------------------------------
+// Called when we're selected
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnTabSelected()
+{
+ // Make the selected bone and highlight state match
+ OnBoneSelected( m_cBone->getSelectedIndex() );
+ OnBoneHighlighted( m_cBoneHighlight->isChecked() );
+ OnHitboxHighlighted( m_cHitboxHighlight->isChecked() );
+ OnShowDefaultPose( m_cShowDefaultPose->isChecked() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBoneControlWindow::GetHitboxSet( void )
+{
+ return m_nHitboxSet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::ComputeHitboxSetList( void )
+{
+ m_cHitboxSet->removeAll();
+
+ for ( int i = 0 ; i < g_pStudioModel->m_HitboxSets.Count(); i++ )
+ {
+ const char *name = g_pStudioModel->m_HitboxSets[ i ].m_Name;
+ m_cHitboxSet->add( name );
+ }
+ m_cHitboxSet->select( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Recomputes the hitbox list
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::ComputeHitboxList( )
+{
+ // Reset the hitbox list
+ m_cHitbox->removeAll();
+ int count = 0;
+ if ( m_SetBoneHitBoxes.Count() > 0 )
+ {
+ if (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() > m_Bone)
+ count = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count();
+ if (count > 0)
+ {
+ for (int i = 0; i < count; ++i )
+ {
+ char buf[32];
+ sprintf( buf, "%d", m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][i] );
+ m_cHitbox->add( buf );
+ }
+ }
+ else
+ {
+ m_cHitbox->add ("None");
+ }
+ }
+ else
+ {
+ m_cHitbox->add ("None");
+ }
+
+ OnHitboxSelected(0);
+}
+
+//-----------------------------------------------------------------------------
+// Here's what we do when a new bone is selected
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnBoneSelected( int boneIndex )
+{
+ // Reset the surface prop
+ if (!g_pStudioModel)
+ return;
+
+ if ( physprop && g_pStudioModel->m_SurfaceProps.Count() )
+ {
+ // Find the surface prop associated with this bone
+ const char* pSurfaceProp = g_pStudioModel->m_SurfaceProps[boneIndex].String();
+ int idx = FindSurfaceProp( pSurfaceProp );
+
+ // Can't find it? Then apply the default one
+ if (idx < 0)
+ idx = FindSurfaceProp( "default" );
+ if (idx < 0)
+ idx = 0;
+ m_cSurfaceProp->select(idx);
+ }
+ else
+ {
+ m_cSurfaceProp->select(0);
+ }
+
+ // Store off the bone
+ m_Bone = boneIndex;
+ if (m_cBoneHighlight->isChecked())
+ g_viewerSettings.highlightBone = m_Bone;
+
+ ComputeHitboxList();
+
+ // select the render/highlight bone
+ m_pControlPanel->redraw();
+}
+
+
+//-----------------------------------------------------------------------------
+// When the bone is highlighted or not
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnShowDefaultPose( bool isChecked )
+{
+ g_viewerSettings.showPhysicsPreview = isChecked;
+}
+
+//-----------------------------------------------------------------------------
+// When the bone is highlighted or not
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnBoneHighlighted( bool isChecked )
+{
+ g_viewerSettings.highlightBone = isChecked ? m_Bone : -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// When the hitbox is highlighted or not
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnHitboxHighlighted( bool isChecked )
+{
+ g_viewerSettings.highlightHitbox = isChecked ? m_Hitbox : -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Refreshes the hitbox size
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::RefreshHitbox( )
+{
+ if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
+ {
+ m_nHitboxSet = 0;
+ }
+
+ if ( m_Hitbox >= 0 && g_pStudioModel->m_HitboxSets.Count() > 0 )
+ {
+ // Set the hitbox size + origin + group
+ mstudiobbox_t* pHitbox = &g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[ m_Hitbox ].m_BBox;
+
+ Vector origin, size;
+ VectorSubtract( pHitbox->bbmax, pHitbox->bbmin, size );
+ VectorAdd( pHitbox->bbmax, pHitbox->bbmin, origin );
+ origin *= 0.5f;
+
+ m_eHitboxGroup->setLabel( "%i", pHitbox->group );
+ const char *hitboxname = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[ m_Hitbox ].m_Name;
+ m_eHitboxName->setLabel( hitboxname );
+
+ m_eOriginX->setLabel("%.3f", origin.x );
+ m_eOriginY->setLabel("%.3f", origin.y );
+ m_eOriginZ->setLabel("%.3f", origin.z );
+ m_eSizeX->setLabel("%.3f", size.x );
+ m_eSizeY->setLabel("%.3f", size.y );
+ m_eSizeZ->setLabel("%.3f", size.z );
+ }
+ else
+ {
+ m_eHitboxGroup->setLabel( "" );
+ m_eHitboxName->setLabel( "" );
+ m_eOriginX->setLabel("");
+ m_eOriginY->setLabel("");
+ m_eOriginZ->setLabel("");
+ m_eSizeX->setLabel("");
+ m_eSizeY->setLabel("");
+ m_eSizeZ->setLabel("");
+ }
+}
+
+//-----------------------------------------------------------------------------
+// When a hitbox is selected
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnHitboxSelected( int hitbox )
+{
+ if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Size() )
+ {
+ m_nHitboxSet = 0;
+ }
+
+ m_cHitbox->select(hitbox);
+
+ if ( m_SetBoneHitBoxes.Count() == 0 ||
+ (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() <= m_Bone) ||
+ (m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() <= hitbox))
+ {
+ m_Hitbox = -1;
+ CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
+
+ // This'll cause no boxes to be drawn
+ if (m_cHitboxHighlight->isChecked())
+ g_viewerSettings.highlightHitbox = pHdr ? pHdr->numbones() + 1 : 1;
+ }
+ else
+ {
+ m_Hitbox = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][hitbox];
+ if (m_cHitboxHighlight->isChecked())
+ g_viewerSettings.highlightHitbox = m_Hitbox;
+ }
+
+ RefreshHitbox();
+}
+
+
+//-----------------------------------------------------------------------------
+// Hitbox size/origin changed
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnAutogenerateHitboxes( bool isChecked )
+{
+ m_eHitboxGroup->setEnabled( !isChecked );
+ m_eHitboxName->setEnabled( !isChecked );
+ m_eOriginX->setEnabled( !isChecked );
+ m_eOriginY->setEnabled( !isChecked );
+ m_eOriginZ->setEnabled( !isChecked );
+ m_eSizeX->setEnabled( !isChecked );
+ m_eSizeY->setEnabled( !isChecked );
+ m_eSizeZ->setEnabled( !isChecked );
+ m_bUpdateHitbox->setEnabled( !isChecked );
+ m_bAddHitbox->setEnabled( !isChecked );
+ m_bDeleteHitbox->setEnabled( !isChecked );
+
+ m_cHitboxSet->setEnabled( !isChecked );
+ m_eHitboxSetName->setEnabled( !isChecked );
+ m_bHitboxSetUpdateName->setEnabled( !isChecked );
+ m_bAddHitboxSet->setEnabled( !isChecked );
+ m_bDeleteHitboxSet->setEnabled( !isChecked );
+}
+
+//-----------------------------------------------------------------------------
+// Hitbox size/origin changed
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnHitboxChanged( )
+{
+ if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
+ {
+ m_nHitboxSet = 0;
+ }
+
+ if ( m_Hitbox < 0 || g_pStudioModel->m_HitboxSets.Count() <= 0 )
+ {
+ // Blat out the hitbox size + origin + group
+ RefreshHitbox();
+ return;
+ }
+
+ Vector size, origin;
+ mstudiobbox_t* pHitbox;
+ const char *pGroup;
+
+ // Gotta do it this way since getLabel whacks the previous return result to getLable
+ const char* pLabel = m_eOriginX->getLabel();
+ if (!pLabel)
+ goto errOut;
+ origin.x = atof( pLabel );
+
+ pLabel = m_eOriginY->getLabel();
+ if (!pLabel)
+ goto errOut;
+ origin.y = atof( pLabel );
+
+ pLabel = m_eOriginZ->getLabel();
+ if (!pLabel)
+ goto errOut;
+ origin.z = atof( pLabel );
+
+ pLabel = m_eSizeX->getLabel();
+ if (!pLabel)
+ goto errOut;
+ size.x = atof( pLabel );
+
+ pLabel = m_eSizeY->getLabel();
+ if (!pLabel)
+ goto errOut;
+ size.y = atof( pLabel );
+
+ pLabel = m_eSizeZ->getLabel();
+ if (!pLabel)
+ goto errOut;
+ size.z = atof( pLabel );
+
+ pHitbox = &g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[m_Hitbox].m_BBox;
+
+ // Recompute the hitbox from the new data
+ VectorMA( origin, -0.5f, size, pHitbox->bbmin );
+ VectorMA( origin, 0.5f, size, pHitbox->bbmax );
+
+ pGroup = m_eHitboxGroup->getLabel();
+ if (pGroup)
+ {
+ pHitbox->group = atol( pGroup );
+ }
+
+ // Store off the hitbox name
+ g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[m_Hitbox].m_Name = m_eHitboxName->getLabel();
+
+errOut:
+ RefreshHitbox();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hitbox set changed
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnHitboxSetChanged( void )
+{
+ m_Hitbox = 0;
+ m_nHitboxSet = m_cHitboxSet->getSelectedIndex();
+
+ PopulateHitboxLists();
+
+ // Repopulate other controls
+ ComputeHitboxList();
+ RefreshHitbox();
+ //OnHitboxGroupChanged( ); // Refresh hitbox will update the group label from the hitbox's group. No need to turn that back into a group #
+}
+
+
+//-----------------------------------------------------------------------------
+// Hitbox size/origin changed
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnHitboxGroupChanged( )
+{
+ if ( m_Hitbox >= 0 && g_pStudioModel->m_HitboxSets.Count() > 0 )
+ {
+ const char *pGroup = m_eHitboxGroup->getLabel();
+ HitboxList_t &list = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes;
+ if ( pGroup && list.IsInList( m_Hitbox ) )
+ {
+ mstudiobbox_t* pHitbox = &list[m_Hitbox].m_BBox;
+ pHitbox->group = atol( pGroup );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Add, remove hitboxes
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnAddHitbox( )
+{
+ if (!g_pStudioModel)
+ return;
+
+ // Remove the 'none' entry
+ if (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() > 0 &&
+ m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() == 0)
+ {
+ m_cHitbox->removeAll();
+ }
+
+ int i = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes.AddToTail();
+ HitboxInfo_t &hitbox = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[i];
+ hitbox.m_BBox.bone = m_Bone;
+ hitbox.m_BBox.group = 0;
+ hitbox.m_BBox.bbmin.Init( -8, -8, -8 );
+ hitbox.m_BBox.bbmax.Init( 8, 8, 8 );
+ hitbox.m_BBox.szhitboxnameindex = 0;
+
+ m_SetBoneHitBoxes[ m_nHitboxSet ].EnsureCount( m_Bone + 1 );
+ m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].AddToTail(i);
+
+ char buf[32];
+ sprintf(buf, "%d", i );
+ m_cHitbox->add ( buf );
+ OnHitboxSelected(m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() - 1);
+}
+
+void CBoneControlWindow::OnDeleteHitbox( )
+{
+ if ( !g_pStudioModel || ( m_Hitbox < 0 ) )
+ return;
+
+ g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes.Remove(m_Hitbox);
+ for (int i = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count(); --i >= 0; )
+ {
+ if (m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][i] == m_Hitbox)
+ {
+ m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Remove(i);
+ break;
+ }
+ }
+
+ // Recompute the list of hitboxes
+ ComputeHitboxList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the surface property
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnSurfaceProp( int propIndex )
+{
+ if (g_pStudioModel->IsModelLoaded())
+ {
+ // Store off the new surface prop symbol
+ CUtlSymbol prop( physprop->GetPropName( propIndex ) );
+ g_pStudioModel->m_SurfaceProps[m_Bone] = prop;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Duplictes the surface property to all children
+//-----------------------------------------------------------------------------
+
+void CBoneControlWindow::OnSurfacePropApplyToChildren_R( int bone, CUtlSymbol prop )
+{
+ g_pStudioModel->m_SurfaceProps[bone] = prop;
+
+ CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
+ for ( int i = 0; i < pHdr->numbones(); i++ )
+ {
+ mstudiobone_t* pBone = pHdr->pBone(i);
+ if (pBone->parent == bone)
+ {
+ OnSurfacePropApplyToChildren_R( i, prop );
+ }
+ }
+}
+
+void CBoneControlWindow::OnSurfacePropApplyToChildren( )
+{
+ if (!g_pStudioModel)
+ return;
+
+ CUtlSymbol prop = g_pStudioModel->m_SurfaceProps[m_Bone];
+ OnSurfacePropApplyToChildren_R( m_Bone, prop );
+}
+
+//-----------------------------------------------------------------------------
+// Writes out qc-style text to a utlbuffer
+//-----------------------------------------------------------------------------
+
+bool CBoneControlWindow::SerializeQC( CUtlBuffer& buf )
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (!hdr)
+ return false;
+
+ buf.Printf("// .qc block generated by HLMV begins.\n\n");
+
+ // Print out the surface props
+ buf.Printf( "$surfaceprop \"%s\"\n", g_pStudioModel->m_SurfaceProps[0].String() );
+ Assert( g_pStudioModel->m_SurfaceProps.Count() == hdr->numbones() );
+
+ int i;
+ for ( i = 1; i < g_pStudioModel->m_SurfaceProps.Count(); ++i)
+ {
+ mstudiobone_t* pBone = hdr->pBone(i);
+
+ // Don't bother printing out the name if it's got the same
+ // surface prop as the parent does
+ if (pBone->parent >= 0)
+ {
+ if (!stricmp( g_pStudioModel->m_SurfaceProps[i].String(),
+ g_pStudioModel->m_SurfaceProps[pBone->parent].String() ))
+ continue;
+ }
+
+ buf.Printf( "$jointsurfaceprop \"%s\"\t \"%s\"\n", pBone->pszName(),
+ g_pStudioModel->m_SurfaceProps[i].String() );
+ }
+
+ if (!m_cAutoHitbox->isChecked())
+ {
+ buf.Printf("\n");
+
+ for ( i = 0 ; i < g_pStudioModel->m_HitboxSets.Count(); i++ )
+ {
+ buf.Printf( "\n$hboxset \"%s\"\n\n", g_pStudioModel->m_HitboxSets[ i ].m_Name.Get() );
+
+ HitboxList_t &list = g_pStudioModel->m_HitboxSets[ i ].m_Hitboxes;
+ for ( unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
+ {
+ mstudiobbox_t &hitbox = list[j].m_BBox;
+ mstudiobone_t* pBone = hdr->pBone( hitbox.bone );
+ buf.Printf( "$hbox %d \"%s\"\t %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f",
+ hitbox.group, pBone->pszName(),
+ hitbox.bbmin.x, hitbox.bbmin.y, hitbox.bbmin.z,
+ hitbox.bbmax.x, hitbox.bbmax.y, hitbox.bbmax.z );
+ if ( !list[j].m_Name.IsEmpty() )
+ {
+ buf.Printf( " \"%s\"", list[j].m_Name.Get() );
+ }
+ buf.Printf( "\n" );
+ }
+ }
+ }
+
+ buf.Printf("\n// .qc block generated by HLMV ends.\n\n");
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Generates the QC file and copies it to the clipboard
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnGenerateQC( )
+{
+ CUtlBuffer outbuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ SerializeQC( outbuf );
+ if ( outbuf.TellPut() )
+ {
+ // Null-terminate the string so CopyString works...
+ outbuf.PutChar('\0');
+ Sys_CopyStringToClipboard( (const char*)outbuf.Base() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnHitboxAddSet( void )
+{
+ char sz[ 32 ];
+ sprintf( sz, "set%02i", g_pStudioModel->m_HitboxSets.Count() + 1 );
+
+ int newsetnumber = g_pStudioModel->m_HitboxSets.AddToTail();
+ g_pStudioModel->m_HitboxSets[ newsetnumber ].m_Name = sz;
+
+ ComputeHitboxSetList();
+
+ m_cHitboxSet->select( newsetnumber );
+
+ OnHitboxSetChanged();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnHitboxDeleteSet( void )
+{
+ // Can't remove last element
+ if ( m_nHitboxSet == 0 )
+ {
+ return;
+ }
+
+ g_pStudioModel->m_HitboxSets.Remove( m_nHitboxSet );
+
+ ComputeHitboxSetList();
+
+ m_cHitboxSet->select( 0 );
+
+ OnHitboxSetChanged();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBoneControlWindow::OnHitboxSetChangeName( void )
+{
+ if ( g_pStudioModel->m_HitboxSets.Count() <= 0 )
+ return;
+
+ char newname[ 512 ];
+
+ strcpy( newname, m_eHitboxSetName->getLabel() );
+ if ( !newname[ 0 ] )
+ return;
+
+ g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Name = newname;
+
+ int oldsel = m_nHitboxSet;
+
+ ComputeHitboxSetList();
+
+ m_cHitboxSet->select( oldsel );
+
+ OnHitboxSetChanged();
+}
+
+//-----------------------------------------------------------------------------
+// Responds to events on controls in the window
+//-----------------------------------------------------------------------------
+
+int CBoneControlWindow::handleEvent (mxEvent *event)
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ if ( event->event == mxEvent::KeyDown )
+ {
+ // FIXME: calling this forces the edit box to lose position
+ // OnHitboxChanged( );
+ return 1;
+ }
+
+ switch( event->action )
+ {
+ case IDC_BONE_BONELIST:
+ if (g_pStudioModel->IsModelLoaded())
+ {
+ OnHitboxGroupChanged( );
+ OnBoneSelected( m_cBone->getSelectedIndex() );
+ }
+ break;
+
+ case IDC_BONE_HIGHLIGHT_BONE:
+ OnBoneHighlighted( ((mxCheckBox *) event->widget)->isChecked() );
+ break;
+
+ case IDC_BONE_HIGHLIGHT_HITBOX:
+ OnHitboxHighlighted( ((mxCheckBox *) event->widget)->isChecked() );
+ break;
+
+ case IDC_BONE_SHOW_DEFAULT_POSE:
+ OnShowDefaultPose( ((mxCheckBox *) event->widget)->isChecked() );
+ break;
+
+ case IDC_BONE_HITBOXLIST:
+ OnHitboxGroupChanged( );
+ OnHitboxSelected( m_cHitbox->getSelectedIndex() );
+ break;
+
+ case IDC_BONE_HITBOXSET:
+ OnHitboxSetChanged();
+ break;
+
+ case IDC_BONE_HITBOXADDSET:
+ OnHitboxAddSet();
+ break;
+ case IDC_BONE_HITBOXDELETESET:
+ OnHitboxDeleteSet();
+ break;
+ case IDC_BONE_HITBOXSETNAME:
+ OnHitboxSetChangeName();
+ break;
+
+ case IDC_BONE_UPDATE_HITBOX:
+ OnHitboxChanged( );
+ break;
+
+ case IDC_BONE_ADD_HITBOX:
+ OnHitboxGroupChanged( );
+ OnAddHitbox( );
+ break;
+
+ case IDC_BONE_DELETE_HITBOX:
+ OnDeleteHitbox( );
+ break;
+
+ case IDC_BONE_USE_AUTOGENERATED_HITBOXES:
+ if (g_pStudioModel->IsModelLoaded())
+ OnAutogenerateHitboxes( m_cAutoHitbox->isChecked() );
+ break;
+
+ case IDC_BONE_SURFACEPROP:
+ OnSurfaceProp( m_cSurfaceProp->getSelectedIndex() );
+ break;
+
+ case IDC_BONE_APPLY_TO_CHILDREN:
+ if (g_pStudioModel->IsModelLoaded())
+ OnSurfacePropApplyToChildren( );
+ break;
+
+ case IDC_BONE_GENERATEQC:
+ if (g_pStudioModel->IsModelLoaded())
+ {
+ OnHitboxGroupChanged( );
+ OnGenerateQC( );
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton instance
+//-----------------------------------------------------------------------------
+
+ControlPanel *g_ControlPanel = 0;
+
+
+
+ControlPanel::ControlPanel( mxWindow *parent )
+: mxWindow( parent, 0, 0, 0, 0, "Control Panel", mxWindow::Normal )
+{
+ InitViewerSettings ( "hlmv" );
+
+ // frame slider
+ new mxLabel( this, 5, 220, 50, 18, "Frame" );
+ slForceFrame = new mxSlider( this, 55, 220, 450, 18, IDC_FORCEFRAME );
+ slForceFrame->setRange( 0, 1.0 );
+ slForceFrame->setValue( 0.0 );
+ slForceFrame->setSteps( 1, 1 );
+ mxToolTip::add( slForceFrame, "Force To Frame" );
+ lForcedFrame = new mxLabel( this, 505, 220, 30, 18, "0" );
+
+ // create tabcontrol with subdialog windows
+ tab = new mxTab( this, 0, 20, 0, 0, IDC_TAB );
+#ifdef WIN32
+ SetWindowLong( ( HWND )tab->getHandle(), GWL_EXSTYLE, WS_EX_CLIENTEDGE );
+#endif
+
+ SetupRenderWindow( tab );
+ SetupSequenceWindow( tab );
+ SetupBodyWindow( tab );
+ SetupFlexWindow( tab );
+ SetupPhysicsWindow( tab );
+ SetupBoneControlWindow( tab );
+ SetupAttachmentsWindow( tab );
+ SetupIKRuleWindow( tab );
+ SetupEventWindow( tab );
+
+ g_ControlPanel = this;
+
+ iSelectionToSequence = NULL;
+ iSequenceToSelection = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with render control
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupRenderWindow( mxTab* pTab )
+{
+ wRender = new mxWindow (this, 0, 0, 0, 0);
+ tab->add (wRender, "Render");
+ cRenderMode = new mxChoice (wRender, 5, 2, 100, 22, IDC_RENDERMODE);
+ cRenderMode->add ("Wireframe");
+// cRenderMode->add ("Flatshaded");
+ cRenderMode->add ("Smoothshaded");
+ cRenderMode->add ("Textured");
+ cRenderMode->add ("BoneWeights");
+ cRenderMode->add ("BadVertexData");
+ cRenderMode->add ("UV Chart");
+ cRenderMode->select (2);
+ mxToolTip::add (cRenderMode, "Select Render Mode");
+ cbGround = new mxCheckBox (wRender, 125, 5, 150, 20, "Ground (Ctrl-G)", IDC_GROUND);
+ cbGround->setEnabled( true );
+ cbMovement = new mxCheckBox (wRender, 125, 25, 150, 20, "Movement (Ctrl-M)", IDC_MOVEMENT);
+ cbMovement->setEnabled( true );
+ cbBackground = new mxCheckBox (wRender, 125, 45, 150, 20, "Background (Ctrl-B)", IDC_BACKGROUND);
+ cbBackground->setEnabled( true );
+ cbHitBoxes = new mxCheckBox (wRender, 125, 65, 150, 20, "Hit Boxes (Ctrl-H)", IDC_HITBOXES);
+ cbSequenceBoxes = new mxCheckBox (wRender, 125, 85, 150, 20, "Seq. Boxes", IDC_SEQUENCEBOXES);
+ cbShadow = new mxCheckBox (wRender, 125, 105, 150, 20, "Shadow (Ctrl-S)", IDC_SHADOW);
+ cbSoftwareSkin = new mxCheckBox (wRender, 125, 125, 150, 20, "Software Skin", IDC_SOFTWARESKIN);
+ cbSoftwareSkin->setEnabled( true );
+ cbOverbright2 = new mxCheckBox (wRender, 125, 145, 150, 20, "Enable Overbrightening", IDC_OVERBRIGHT2);
+ cbOverbright2->setEnabled( true );
+ cbOverbright2->setChecked( true );
+ setOverbright( true );
+
+ cbAttachments = new mxCheckBox (wRender, 5, 45, 120, 20, "Attachments (Ctrl-A)", IDC_ATTACHMENTS);
+ cbAttachments->setEnabled( true );
+
+ cbBones = new mxCheckBox (wRender, 5, 65, 120, 20, "Bones (Ctrl-O)", IDC_BONES);
+
+ cbNormals = new mxCheckBox (wRender, 5, 85, 120, 20, "Normals (Ctrl-N)", IDC_NORMALS);
+ cbNormals->setEnabled( true );
+ cbNormals->setChecked( false );
+
+ cbTangentFrame = new mxCheckBox( wRender, 5, 105, 120, 20, "Tangents (Ctrl-T)", IDC_TANGENTFRAME );
+ cbTangentFrame->setEnabled( true );
+ cbTangentFrame->setChecked( false );
+
+ cbOverlayWireframe = new mxCheckBox (wRender, 5, 125, 120, 20, "Wireframe (Ctrl-W)", IDC_OVERLAY_WIREFRAME);
+ cbOverlayWireframe->setEnabled( true );
+ cbOverlayWireframe->setChecked( false );
+
+// cbParallaxMap = new mxCheckBox (wRender, 5, 125, 100, 20, "Parallax Mapping", IDC_PARALLAXMAP);
+// cbParallaxMap->setEnabled( true );
+// cbParallaxMap->setChecked( true );
+
+ cbSpecular = new mxCheckBox (wRender, 5, 145, 120, 20, "Specular", IDC_SPECULAR);
+ cbSpecular->setEnabled( true );
+ cbSpecular->setChecked( true );
+
+ cbNormalMap = new mxCheckBox (wRender, 5, 25, 100, 20, "Normal Mapping", IDC_NORMALMAP);
+ cbNormalMap->setEnabled( true );
+ cbNormalMap->setChecked( true );
+
+ cbRunIK = new mxCheckBox (wRender, 275, 65, 150, 20, "Enable IK", IDC_RUNIK);
+ cbEnableHead = new mxCheckBox (wRender, 275, 85, 150, 20, "Head Turn", IDC_HEADTURN);
+
+ cbIllumPosition = new mxCheckBox (wRender, 275, 105, 150, 20, "Illum. Position", IDC_ILLUMPOSITION);
+
+ cbPlaySounds = new mxCheckBox (wRender, 275, 125, 150, 20, "Play Sounds", IDC_PLAYSOUNDS);
+
+ cbShowOriginAxis = new mxCheckBox (wRender, 275, 145, 150, 20, "Show Origin Axis", IDC_SHOWORIGINAXIS);
+
+ new mxLabel (wRender, 275, 170, 45, 18, "Axis Len:");
+ leOriginAxisLength = new mxSlider(wRender, 320, 165, 105, 22, IDC_ORIGINAXISLENGTH);
+ leOriginAxisLength->setRange( 1, 100 );
+ leOriginAxisLength->setValue( 10 );
+
+ new mxCheckBox (wRender, 275, 5, 150, 20, "Physics Model", IDC_PHYSICSMODEL);
+ cHighlightBone = new mxChoice (wRender, 275, 25, 150, 22, IDC_PHYSICSHIGHLIGHT);
+ cHighlightBone->add ("None");
+ cHighlightBone->select (0);
+ mxToolTip::add (cHighlightBone, "Select Physics Bone to highlight");
+
+ new mxLabel (wRender, 5, 170, 30, 18, "FOV:");
+ leFOV = new mxLineEdit(wRender, 35, 165, 30, 22, "65", IDC_RENDER_FOV);
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with sequence control
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupSequenceWindow( mxTab* pTab )
+{
+ mxWindow *wSequence = new mxWindow (this, 0, 0, 0, 0);
+ tab->add (wSequence, "Sequence");
+
+ for ( int i = 0; i < MAX_SEQUENCES; i++ )
+ {
+ cSequence[i] = new mxChoice (wSequence, 5, 5 + i * 22, 200, 22, IDC_SEQUENCE0+i);
+ mxToolTip::add (cSequence[i], "Select Sequence");
+ slSequence[i] = new mxSlider (wSequence, 208, 5 + i * 22, 80, 18, IDC_SEQUENCESCALE0+i);
+ slSequence[i]->setRange (0, 1.0, 100);
+ slSequence[i]->setValue (0.0);
+
+ rbFrameSelection[i] = new mxRadioButton (wSequence, 300, 5 + i * 22, 35, 22, "", IDC_FRAMESELECTION0+i, i == 0);
+ }
+ slSequence[0]->setVisible( false );
+
+ laGroundSpeed = new mxLabel( wSequence, 208, 5, 80, 18, "" );
+
+ for ( int i = 0; i < NUM_POSEPARAMETERS; i++ )
+ {
+ int x, y;
+ x = 334;
+ y = 2 + (i % 8) * 17;
+
+ cPoseParameter[i] = new mxChoice (wSequence, 520, y, 96, 22, IDC_POSEPARAMETER+i);
+ cPoseParameter[i]->setVisible( false );
+
+ slPoseParameter[i] = new mxSlider (wSequence, x, y, 140, 16, IDC_POSEPARAMETER_SCALE+i);
+ slPoseParameter[i]->setRange (0.0, 1.0, 1000);
+ mxToolTip::add (slPoseParameter[i], "Parameter");
+ slPoseParameter[i]->setVisible( false );
+
+ lePoseParameter[i] = new mxLineEdit ( wSequence, x + 146, y, 40, 16, "X", IDC_POSEPARAMETER_VALUE+i );
+ lePoseParameter[i]->setVisible( false );
+ }
+
+ slSpeedScale = new mxSlider (wSequence, 5, 115, 200, 18, IDC_SPEEDSCALE);
+ slSpeedScale->setRange (0, 1.0, 100);
+ slSpeedScale->setValue (1.0);
+ mxToolTip::add (slSpeedScale, "Speed Scale");
+ laFPS = new mxLabel (wSequence, 208, 115, 128, 22, "" );
+
+ new mxCheckBox (wSequence, 5, 142, 150, 20, "Blend Sequence Changes", IDC_BLENDSEQUENCECHANGES);
+ new mxButton( wSequence, 155, 142, 80, 20, "Blend Now", IDC_BLENDNOW );
+ laBlendAmount = new mxLabel( wSequence, 240, 142, 60, 20, "" );
+
+ slBlendTime = new mxSlider( wSequence, 308, 142, 200, 18, IDC_BLENDTIME );
+ slBlendTime->setRange( 0, 1.0, 100 );
+ slBlendTime->setValue( DEFAULT_BLEND_TIME );
+ laBlendTime = new mxLabel( wSequence, 540, 142, 80, 22, "" );
+
+ new mxLabel (wSequence, 5, 170, 90, 18, "Activity modifiers:");
+ cActivityModifiers = new mxChoice (wSequence, 105, 166, 350, 22, IDC_ACTIVITY_MODIFIERS);
+
+ new mxCheckBox (wSequence, 460, 166, 350, 22, "Animate weapons", IDC_ANIMATEWEAPONS);
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with body control
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupBodyWindow( mxTab* pTab )
+{
+ mxWindow *wBody = new mxWindow (this, 0, 0, 0, 0);
+ pTab->add (wBody, "Model");
+ cBodypart = new mxChoice (wBody, 5, 5, 100, 22, IDC_BODYPART);
+ mxToolTip::add (cBodypart, "Choose a bodypart");
+ cSubmodel = new mxChoice (wBody, 110, 5, 100, 22, IDC_SUBMODEL);
+ mxToolTip::add (cSubmodel, "Choose a submodel of current bodypart");
+ cController = new mxChoice (wBody, 5, 30, 100, 22, IDC_CONTROLLER);
+ mxToolTip::add (cController, "Choose a bone controller");
+ slController = new mxSlider (wBody, 105, 32, 100, 18, IDC_CONTROLLERVALUE);
+ slController->setRange (0, 255);
+ mxToolTip::add (slController, "Change current bone controller value");
+ lModelInfo1 = new mxLabel (wBody, 220, 5, 120, 80, "No Model.");
+ lModelInfo2 = new mxLabel (wBody, 340, 5, 120, 130, "");
+ cSkin = new mxChoice (wBody, 5, 55, 100, 22, IDC_SKINS);
+ mxToolTip::add (cSkin, "Choose a skin family");
+ new mxLabel (wBody, 5, 170, 90, 18, "Materials used:");
+ cMaterials = new mxChoice (wBody, 105, 166, 350, 22, IDC_MATERIALS);
+ mxToolTip::add (cMaterials, "Select material for UV Chart view");
+
+ lModelInfo3 = new mxLabel (wBody, 220, 100, 220, 18, "");
+ lModelInfo4 = new mxLabel (wBody, 220, 118, 260, 18, "");
+ lModelInfo5 = new mxLabel (wBody, 220, 136, 120, 18, "");
+ setTransparent( false );
+
+ cbAutoLOD = new mxCheckBox (wBody, 5, 80, 100, 20, "Auto LOD", IDC_AUTOLOD);
+ cbAutoLOD->setEnabled( true );
+ cLODChoice = new mxChoice( wBody, 5, 101, 100, 22, IDC_LODCHOICE);
+ mxToolTip::add (cLODChoice, "Select model LOD to render");
+ new mxLabel (wBody, 5, 126, 60, 18, "LOD Switch:");
+ leLODSwitch = new mxLineEdit(wBody, 70, 126, 35, 22, "", IDC_LODSWITCH);
+ new mxLabel (wBody, 5, 151, 60, 18, "LOD Metric:" );
+ lLODMetric = new mxLabel( wBody, 70, 151, 35, 22, "" );
+
+ new mxLabel( wBody, 505, 5, 100, 18, "VMTs Loaded:" );
+ cMessageList = new mxListBox( wBody, 500, 25, 540, 160, IDC_MESSAGES );
+ cMessageList->add ("None");
+ cMessageList->select (1);
+ mxToolTip::add (cMessageList, "Materials (VMT files) this model has loaded");
+
+ new mxLabel( wBody, 785, 5, 100, 18, "Shader:" );
+ cShaderUsed = new mxListBox( wBody, 830, 3, 210, 28, IDC_SHADERS );
+ cShaderUsed->add ("Select material to show shader");
+ cShaderUsed->select (0);
+ mxToolTip::add (cShaderUsed, "Shader Used");
+
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with flexes
+//-----------------------------------------------------------------------------
+
+#define FLEX_DROPDOWN_WIDTH 90
+#define FLEX_SLIDER_WIDTH 100
+#define FLEX_ROWS_OF_SLIDERS 8
+
+void ControlPanel::SetupFlexWindow( mxTab* pTab )
+{
+ mxWindow *wFlex = new mxWindow (this, 0, 0, 0, 0);
+ pTab->add (wFlex, "Flex");
+ for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
+ {
+ int w = (i / FLEX_ROWS_OF_SLIDERS) * (FLEX_SLIDER_WIDTH + FLEX_DROPDOWN_WIDTH + 4) + 5;
+ int h = (i % FLEX_ROWS_OF_SLIDERS) * 20 + 5;
+
+ cFlex[i] = new mxChoice (wFlex, w, h, FLEX_DROPDOWN_WIDTH, 22, IDC_FLEX + i);
+ mxToolTip::add (cFlex[i], "Select Flex");
+ slFlexScale[i] = new mxSlider (wFlex, w + FLEX_DROPDOWN_WIDTH, h, FLEX_SLIDER_WIDTH, 18, IDC_FLEXSCALE + i);
+ slFlexScale[i]->setRange (0, 1.0);
+ slFlexScale[i]->setValue (0);
+ mxToolTip::add (slFlexScale[i], "Flex Scale");
+ }
+
+ {
+ int h = FLEX_ROWS_OF_SLIDERS * 20 + 5;
+ new mxButton( wFlex, 5, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Reset", IDC_FLEXDEFAULTS );
+
+ int w = ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
+ new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Random", IDC_FLEXRANDOM );
+
+ w += ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
+ new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Zero", IDC_FLEXZERO );
+
+ w += ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
+ new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "One", IDC_FLEXONE );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with physics
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupPhysicsWindow( mxTab* pTab )
+{
+ // Physics Window
+ mxWindow *wPhysics = new mxWindow (this, 0, 0, 0, 0);
+ pTab->add (wPhysics, "Physics");
+
+ new mxLabel (wPhysics, 5, 33, 30, 18, "Mass");
+ leMass = new mxLineEdit(wPhysics, 35, 30, 70, 22, "", IDC_PHYS_MASS);
+
+ cPhysicsBone = new mxChoice (wPhysics, 5, 5, 345, 22, IDC_PHYS_BONE);
+ cPhysicsBone->add ("None");
+ cPhysicsBone->select (0);
+
+ new mxCheckBox (wPhysics, 5, 55, 100, 20, "Highlight", IDC_PHYSICSMODEL);
+ int x = 5;
+ int y = 80;
+
+ rbConstraintAxis[0] = new mxRadioButton (wPhysics, x, y, 35, 22, "X", IDC_PHYS_CON_AXIS_X, true);
+ rbConstraintAxis[1] = new mxRadioButton (wPhysics, x+35, y, 35, 22, "Y", IDC_PHYS_CON_AXIS_Y);
+ rbConstraintAxis[2] = new mxRadioButton (wPhysics, x+70, y, 35, 22, "Z", IDC_PHYS_CON_AXIS_Z);
+ setPhysicsAxis( 0 );
+ y += 25;
+
+ new mxLabel (wPhysics, x, y, 45, 18, "Friction");
+ slPhysicsFriction = new mxSlider (wPhysics, x+50, y, 180, 18, IDC_PHYS_CON_FRICTION);
+ slPhysicsFriction->setRange (0, 1000.0, 1000);
+ slPhysicsFriction->setValue (0);
+ slPhysicsFriction->setSteps( 1, 1 );
+ lPhysicsFriction = new mxLabel (wPhysics, x+230, y, 30, 18, "0");
+
+ x = 135;
+ y = 30;
+
+ new mxLabel (wPhysics, 115, y, 30, 18, "Min");
+ slPhysicsConMin = new mxSlider (wPhysics, x, y, 180, 18, IDC_PHYS_CON_MIN);
+ slPhysicsConMin->setRange (-180, 180.0, 360);
+ slPhysicsConMin->setValue (-90);
+ slPhysicsConMin->setSteps( 1, 1 );
+ lPhysicsConMin = new mxLabel (wPhysics, x+180, y, 30, 18, "-90");
+ y += 25;
+
+ new mxLabel (wPhysics, 115, y, 30, 18, "Max");
+ slPhysicsConMax = new mxSlider (wPhysics, x, y, 180, 18, IDC_PHYS_CON_MAX);
+ slPhysicsConMax->setRange (-180.0, 180.0, 360);
+ slPhysicsConMax->setValue (90.0);
+ slPhysicsConMax->setSteps( 1, 1 );
+ lPhysicsConMax = new mxLabel (wPhysics, x+180, y, 30, 18, "90");
+ y += 25;
+
+ new mxLabel (wPhysics, 115, y, 30, 18, "Test");
+ slPhysicsConTest = new mxSlider (wPhysics, x, y, 55, 18, IDC_PHYS_CON_TEST);
+ slPhysicsConTest->setRange (0, 1.0, 100);
+ slPhysicsConTest->setValue (0);
+
+ cbLinked = new mxCheckBox (wPhysics, 200, y, 50, 20, "Link", IDC_PHYS_CON_LINK_LIMITS);
+ mxToolTip::add (cbLinked, "Link mins/maxs to be symmetric");
+ new mxButton (wPhysics, 250, y, 80, 22, "Generate QC", IDC_PHYS_QCFILE);
+
+ x += 220;
+ y = 5;
+ new mxLabel (wPhysics, x, y, 55, 18, "Mass Bias");
+ new mxLabel (wPhysics, x, y+25, 55, 18, "Inertia");
+ new mxLabel (wPhysics, x, y+50, 55, 18, "Damping");
+ new mxLabel (wPhysics, x, y+75, 55, 18, "Rot Damp");
+ new mxLabel (wPhysics, x, y+100+3, 55, 18, "Material");
+ x += 55;
+
+ slPhysicsParamMassBias = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_MASSBIAS );
+ slPhysicsParamMassBias->setRange (0, 10.0, 100);
+ slPhysicsParamMassBias->setValue (1.0);
+ slPhysicsParamMassBias->setSteps( 1, 1 );
+ lPhysicsParamMassBias = new mxLabel (wPhysics, x+80, y, 30, 18, "1.0");
+ y += 25;
+
+ slPhysicsParamInertia = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_INERTIA );
+ slPhysicsParamInertia->setRange (0, 10.0, 100);
+ slPhysicsParamInertia->setValue (1.0);
+ slPhysicsParamInertia->setSteps( 1, 1 );
+ lPhysicsParamInertia = new mxLabel (wPhysics, x+80, y, 30, 18, "1.0");
+ y += 25;
+
+ slPhysicsParamDamping = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_DAMPING );
+ slPhysicsParamDamping->setRange (0, 1.0, 100);
+ slPhysicsParamDamping->setValue (0.01);
+ slPhysicsParamDamping->setSteps( 1, 1 );
+ lPhysicsParamDamping = new mxLabel (wPhysics, x+80, y, 30, 18, "0.5");
+ y += 25;
+
+ slPhysicsParamRotDamping = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_ROT_DAMPING );
+ slPhysicsParamRotDamping->setRange (0, 10.0, 200);
+ slPhysicsParamRotDamping->setValue (0.2);
+ slPhysicsParamRotDamping->setSteps( 1, 1 );
+ lPhysicsParamRotDamping = new mxLabel (wPhysics, x+80, y, 30, 18, "0.2");
+ y += 25;
+
+ lPhysicsMaterial = new mxLabel( wPhysics, x, y+3, 110, 18, "default" );
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with ik rules
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupIKRuleWindow( mxTab *pTab )
+{
+ mxWindow *wIKRule = new mxWindow( this, 0, 0, 0, 0 );
+ pTab->add( wIKRule, "IKRule" );
+
+ new mxLabel( wIKRule, 5, 5, 80, 20, "Chain:" );
+ cIKChain = new mxChoice( wIKRule, 90, 5, 50, 20, IDC_IKRULE_CHAIN );
+ cIKChain->add( "lfoot" );
+ cIKChain->add( "rfoot" );
+ cIKChain->add( "lhand" );
+ cIKChain->add( "rhand" );
+ cIKChain->select( 0 );
+ mxToolTip::add( cIKChain, "Select IK Chain" );
+
+ new mxLabel( wIKRule, 145, 5, 80, 20, "Type:" );
+ cIKType = new mxChoice( wIKRule, 230, 5, 80, 20, IDC_IKRULE_CHOICE );
+ cIKType->add( "footstep" );
+ cIKType->add( "touch" );
+ cIKType->add( "release" );
+ cIKType->add( "attachment" );
+ cIKType->add( "unlatch" );
+ cIKType->select( 0 );
+ mxToolTip::add( cIKType, "Select IK Type" );
+
+ lIKTouch = new mxLabel( wIKRule, 315, 5, 80, 20, "Bone:" );
+ cIKTouch = new mxChoice( wIKRule, 400, 5, 200, 20, IDC_IKRULE_TOUCH );
+ PopulateBoneList( cIKTouch );
+ mxToolTip::add( cIKTouch, "Select Touched Bone" );
+
+ lIKAttachment = new mxLabel( wIKRule, 315, 5, 80, 20, "Attachment:" );
+ leIKAttachment = new mxLineEdit( wIKRule, 400, 5, 80, 20, "", IDC_IKRULE_ATTACHMENT );
+
+ cbIKRangeToggle = new mxCheckBox( wIKRule, 5, 30, 80, 20, "Range", IDC_IKRULE_RANGE_TOGGLE );
+ mxToolTip::add( cbIKRangeToggle, "Toggle range option" );
+ new mxButton( wIKRule, 90, 30, 30, 20, "start", IDC_IKRULE_RANGE_START_NOW );
+ leIKRangeStart = new mxLineEdit2( wIKRule, 120, 30, 35, 20, "..", IDC_IKRULE_RANGE_START );
+ new mxButton( wIKRule, 160, 30, 30, 20, "peak", IDC_IKRULE_RANGE_PEAK_NOW );
+ leIKRangePeak = new mxLineEdit2( wIKRule, 190, 30, 35, 20, "..", IDC_IKRULE_RANGE_PEAK );
+ new mxButton( wIKRule, 230, 30, 30, 20, "tail", IDC_IKRULE_RANGE_TAIL_NOW );
+ leIKRangeTail = new mxLineEdit2( wIKRule, 260, 30, 35, 20, "..", IDC_IKRULE_RANGE_TAIL );
+ new mxButton( wIKRule, 300, 30, 30, 20, "end", IDC_IKRULE_RANGE_END_NOW );
+ leIKRangeEnd = new mxLineEdit2( wIKRule, 330, 30, 35, 20, "..", IDC_IKRULE_RANGE_END );
+
+ cbIKContactToggle = new mxCheckBox( wIKRule, 5, 55, 80, 20, "Contact", IDC_IKRULE_CONTACT_TOGGLE );
+ mxToolTip::add( cbIKContactToggle, "Toggle contact option" );
+ new mxButton( wIKRule, 90, 55, 30, 20, "frame", IDC_IKRULE_CONTACT_FRAME_NOW );
+ leIKContactFrame = new mxLineEdit2( wIKRule, 120, 55, 35, 20, "", IDC_IKRULE_CONTACT_FRAME );
+
+ new mxLabel( wIKRule, 5, 80, 80, 20, "Transform using:" );
+ cIKUsing = new mxChoice( wIKRule, 90, 80, 80, 20, IDC_IKRULE_USING );
+ cIKUsing->add( "neither" );
+ cIKUsing->add( "source" );
+ cIKUsing->add( "sequence" );
+ cIKUsing->select( 0 );
+ mxToolTip::add( cIKUsing, "Choose Transform To Use" );
+
+ new mxLabel( wIKRule, 5, 105, 80, 20, "QC String:" );
+ leIKQCString = new mxLineEdit2( wIKRule, 90, 105, 500, 20, "", IDC_IKRULE_QC_STRING );
+ UpdateIKRuleWindow();
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with events
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupEventWindow( mxTab *pTab )
+{
+ mxWindow *wEvents = new mxWindow( this, 0, 0, 0, 0 );
+ pTab->add( wEvents, "Events" );
+
+ new mxLabel( wEvents, 5, 5, 80, 20, "Sound:" );
+ mxButton *bSoundFrameNow = new mxButton( wEvents, 90, 5, 30, 20, "frame", IDC_EVENT_SOUND_FRAME_NOW );
+ mxToolTip::add( bSoundFrameNow, "Set sound start at the current frame" );
+ leEventSoundFrame = new mxLineEdit2( wEvents, 120, 5, 35, 20, "0", IDC_EVENT_SOUND_FRAME );
+ lbEventSoundName = new mxListBox( wEvents, 160, 5, 300, 170, IDC_EVENT_SOUND_NAME );
+ PopulateSoundNameList( lbEventSoundName );
+ mxToolTip::add( lbEventSoundName, "Select Sound Name" );
+
+ new mxLabel( wEvents, 5, 170, 80, 20, "QC String:" );
+ leEventQCString = new mxLineEdit2( wEvents, 90, 170, 450, 20, "", IDC_EVENT_QC_STRING );
+ BuildEventQCString();
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the window dealing with bone control
+//-----------------------------------------------------------------------------
+
+void ControlPanel::SetupBoneControlWindow( mxTab* pTab )
+{
+ m_pBoneWindow = new CBoneControlWindow(this);
+ pTab->add (m_pBoneWindow, "Bones");
+ m_pBoneWindow->Init();
+}
+
+
+void ControlPanel::SetupAttachmentsWindow( mxTab *pTab )
+{
+ m_pAttachmentsWindow = new CAttachmentsWindow(this);
+ pTab->add( m_pAttachmentsWindow, "Attachments" );
+ m_pAttachmentsWindow->Init();
+}
+
+
+int ControlPanel::GetCurrentHitboxSet( void )
+{
+ return m_pBoneWindow ? m_pBoneWindow->GetHitboxSet() : 0;
+}
+
+ControlPanel::~ControlPanel()
+{
+ g_ControlPanel = NULL;
+}
+
+void ControlPanel::OnDelete()
+{
+ // for some reason, the destructor only gets called from mx when breakpoints are set,
+ // so to be safe, clear the pointer (possibly twice)
+ g_ControlPanel = NULL;
+}
+
+void ControlPanel::BuildEventQCString()
+{
+ if ( g_ControlPanel == NULL )
+ return;
+
+ char qcstr[ 256 ];
+ Q_strcpy( qcstr, "{ event AE_CL_PLAYSOUND " );
+ Q_strcat( qcstr, leEventSoundFrame->getLabel(), sizeof(qcstr) );
+ Q_strcat( qcstr, " \"", sizeof(qcstr) );
+ int i = lbEventSoundName->getSelectedIndex();
+ Q_strcat( qcstr, lbEventSoundName->getItemText( i ), sizeof(qcstr) );
+ Q_strcat( qcstr, "\" }", sizeof(qcstr) );
+
+ leEventQCString->setText( qcstr );
+}
+
+void ControlPanel::BuildIKRuleQCString()
+{
+ if ( g_ControlPanel == NULL )
+ return;
+
+ char qcstr[ 256 ];
+ Q_strcpy( qcstr, "ikrule " );
+ Q_strcat( qcstr, cIKChain->getLabel(), sizeof(qcstr) );
+ Q_strcat( qcstr, " ", sizeof(qcstr) );
+ const char *pType = cIKType->getLabel();
+ Q_strcat( qcstr, pType, sizeof(qcstr) );
+
+ if ( Q_strcmp( pType, "touch" ) == 0 )
+ {
+ Q_strcat( qcstr, " \"", sizeof(qcstr) );
+ if ( cIKTouch->getSelectedIndex() > 0 )
+ {
+ Q_strcat( qcstr, cIKTouch->getLabel(), sizeof(qcstr) );
+ }
+ Q_strcat( qcstr, "\"", sizeof(qcstr) );
+ }
+ else if ( Q_strcmp( pType, "attachment" ) == 0 )
+ {
+ Q_strcat( qcstr, " \"", sizeof(qcstr) );
+ Q_strcat( qcstr, leIKAttachment->getLabel(), sizeof(qcstr) );
+ Q_strcat( qcstr, "\"", sizeof(qcstr) );
+ }
+
+ if ( cbIKRangeToggle->isChecked() )
+ {
+ Q_strcat( qcstr, " range ", sizeof(qcstr) );
+
+ char str[ 20 ];
+ leIKRangeStart->getText( str, sizeof( str ) );
+ Q_strcat( qcstr, str, sizeof(qcstr) );
+ Q_strcat( qcstr, " ", sizeof(qcstr) );
+ leIKRangePeak->getText( str, sizeof( str ) );
+ Q_strcat( qcstr, str, sizeof(qcstr) );
+ Q_strcat( qcstr, " ", sizeof(qcstr) );
+ leIKRangeTail->getText( str, sizeof( str ) );
+ Q_strcat( qcstr, str, sizeof(qcstr) );
+ Q_strcat( qcstr, " ", sizeof(qcstr) );
+ leIKRangeEnd->getText( str, sizeof( str ) );
+ Q_strcat( qcstr, str, sizeof(qcstr) );
+ }
+
+ if ( cbIKContactToggle->isChecked() )
+ {
+ Q_strcat( qcstr, " contact ", sizeof(qcstr) );
+
+ char str[ 20 ];
+ leIKContactFrame->getText( str, sizeof( str ) );
+ Q_strcat( qcstr, str, sizeof(qcstr) );
+ }
+
+ int nUsing = cIKUsing->getSelectedIndex();
+ if ( nUsing > 0 )
+ {
+ if ( nUsing == 1 ) // source
+ {
+ Q_strcat( qcstr, " usesource", sizeof(qcstr) );
+ }
+ else if ( nUsing == 2 ) // sequence
+ {
+ Q_strcat( qcstr, " usesequence", sizeof(qcstr) );
+ }
+ }
+
+ leIKQCString->setText( qcstr );
+}
+
+void ControlPanel::UpdateIKRuleWindow()
+{
+ const char *pIKType = cIKType->getLabel();
+ bool bIsTouch = Q_strcmp( pIKType, "touch" ) == 0;
+ bool bIsAttachment = Q_strcmp( pIKType, "attachment" ) == 0;
+
+ lIKTouch->setVisible( bIsTouch );
+ cIKTouch->setVisible( bIsTouch );
+ lIKAttachment->setVisible( bIsAttachment );
+ leIKAttachment->setVisible( bIsAttachment );
+
+ BuildIKRuleQCString();
+}
+
+int
+ControlPanel::handleEvent (mxEvent *event)
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ if ( !g_ControlPanel )
+ return 1;
+
+ if ( event->event == mxEvent::Size )
+ {
+ tab->setBounds( 0, 0, event->width, max( 0, event->height - 20 ) );
+ return 1;
+ }
+
+ if ( event->event == mxEvent::KeyDown )
+ {
+ if ( tab->getSelectedIndex() == 4 )
+ {
+ handlePhysicsKey( event );
+ }
+
+ if (event->action >= IDC_POSEPARAMETER_VALUE && event->action < IDC_POSEPARAMETER_VALUE + NUM_POSEPARAMETERS)
+ {
+ int index = event->action - IDC_POSEPARAMETER_VALUE;
+ int poseparam = cPoseParameter[index]->getSelectedIndex();
+
+ float value = atof( lePoseParameter[index]->getLabel() );
+ setBlend( poseparam, value );
+ slPoseParameter[index]->setValue( g_pStudioModel->GetPoseParameter( poseparam ) );
+ return 1;
+ }
+
+ switch (event->key)
+ {
+ case 27:
+ if (!getParent ()) // fullscreen mode ?
+ mx::quit ();
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ g_viewerSettings.renderMode = event->key - '1';
+ break;
+
+ case '-':
+ g_viewerSettings.speedScale -= 0.1f;
+ if (g_viewerSettings.speedScale < 0.0f)
+ g_viewerSettings.speedScale = 0.0f;
+ break;
+
+ case '+':
+ g_viewerSettings.speedScale += 0.1f;
+ if (g_viewerSettings.speedScale > 5.0f)
+ g_viewerSettings.speedScale = 5.0f;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+ }
+
+ switch (event->action)
+ {
+ case IDC_TAB:
+ {
+ int tabIndex = tab->getSelectedIndex();
+
+ // g_viewerSettings.highlightBone = -1;
+ g_viewerSettings.highlightHitbox = -1;
+ g_viewerSettings.showTexture = (tabIndex == 3) ? true : false;
+ g_viewerSettings.showPhysicsPreview = (tabIndex == 4) ? true : false;
+ setHighlightBone(cHighlightBone->getSelectedIndex());
+
+ if (tabIndex == 4)
+ {
+ setupPhysicsBone(cPhysicsBone->getSelectedIndex());
+ }
+
+ if (tabIndex == 5)
+ {
+ m_pBoneWindow->OnTabSelected();
+ }
+
+ if ( tabIndex == 6 )
+ {
+ m_pAttachmentsWindow->OnTabSelected();
+ }
+ else
+ {
+ m_pAttachmentsWindow->OnTabUnselected();
+ }
+ }
+ break;
+
+ case IDC_RENDERMODE:
+ {
+ int index = cRenderMode->getSelectedIndex();
+ if (index >= 0)
+ {
+ setRenderMode (index);
+ }
+ }
+ break;
+
+ case IDC_PHYSICSHIGHLIGHT:
+ {
+ int index = cHighlightBone->getSelectedIndex();
+ setHighlightBone(index);
+ }
+ break;
+
+ case IDC_RENDER_FOV:
+ {
+ mxLineEdit *pLineEdit = ((mxLineEdit *) event->widget);
+ const char *pText = pLineEdit->getLabel();
+ float val = atof( pText );
+ g_viewerSettings.fov = val;
+ break;
+ }
+
+ case IDC_ORIGINAXISLENGTH:
+ {
+ g_viewerSettings.originAxisLength = reinterpret_cast< mxSlider * >( event->widget )->getValue();
+ break;
+ }
+
+ case IDC_LODCHOICE:
+ {
+ int index = cLODChoice->getSelectedIndex();
+ if( index >= 0 )
+ {
+ setLOD( index, false, false );
+ }
+ break;
+ }
+
+ case IDC_LODSWITCH:
+ {
+ mxLineEdit *pLineEdit = ((mxLineEdit *) event->widget);
+ const char *pText = pLineEdit->getLabel();
+ float val = atof( pText );
+ g_pStudioModel->SetLODSwitchValue( g_viewerSettings.lod, val );
+ break;
+ }
+
+ case IDC_AUTOLOD:
+ setAutoLOD (((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_SOFTWARESKIN:
+ setSoftwareSkin(((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_OVERBRIGHT2:
+ setOverbright(((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_GROUND:
+ setShowGround (((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_MOVEMENT:
+ setShowMovement (((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_BACKGROUND:
+ setShowBackground (((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_HITBOXES:
+ g_viewerSettings.showHitBoxes = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_SEQUENCEBOXES:
+ g_viewerSettings.showSequenceBoxes = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_SHADOW:
+ g_viewerSettings.showShadow = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_ILLUMPOSITION:
+ g_viewerSettings.showIllumPosition = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_RUNIK:
+ g_viewerSettings.enableIK = ((mxCheckBox *) event->widget)->isChecked();
+ g_viewerSettings.enableTargetIK = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_HEADTURN:
+ g_pStudioModel->SetSolveHeadTurn( ((mxCheckBox *) event->widget)->isChecked() ? 1 : 0 );
+ break;
+
+ case IDC_PHYSICSMODEL:
+ g_viewerSettings.showPhysicsModel = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_BONES:
+ g_viewerSettings.showBones = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_PLAYSOUNDS:
+ g_viewerSettings.playSounds = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_NORMALMAP:
+ g_viewerSettings.enableNormalMapping = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+// case IDC_PARALLAXMAP:
+// g_viewerSettings.enableParallaxMapping = ((mxCheckBox *) event->widget)->isChecked();
+// break;
+
+ case IDC_SPECULAR:
+ g_viewerSettings.enableSpecular = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_NORMALS:
+ g_viewerSettings.showNormals = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_TANGENTFRAME:
+ g_viewerSettings.showTangentFrame = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_OVERLAY_WIREFRAME:
+ g_viewerSettings.overlayWireframe = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_ATTACHMENTS:
+ g_viewerSettings.showAttachments = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+
+ case IDC_SHOWORIGINAXIS:
+ setShowOriginAxis (((mxCheckBox *) event->widget)->isChecked());
+ break;
+
+ case IDC_MESSAGES:
+ {
+ int index = cMessageList->getSelectedIndex();
+ if (index >= 0)
+ {
+ studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
+ if ( pStudioR )
+ {
+ IMaterial *pMaterials[128];
+ g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
+
+ cShaderUsed->removeAll();
+ if ( pMaterials[index]->IsErrorMaterial() )
+ {
+ cShaderUsed->add( "*** ERROR *** Can't load VMT");
+ }
+ else
+ {
+ cShaderUsed->add( pMaterials[index]->GetShaderName() );
+ }
+ }
+ }
+ }
+ break;
+
+ case IDC_SEQUENCE0:
+ case IDC_SEQUENCE1:
+ case IDC_SEQUENCE2:
+ case IDC_SEQUENCE3:
+ case IDC_SEQUENCE4:
+ {
+ int i = event->action - IDC_SEQUENCE0;
+ int index = ((mxChoice *) event->widget)->getSelectedIndex();
+ if (index >= 0)
+ {
+ index = iSelectionToSequence[index];
+ if (i == 0)
+ {
+ setSequence (index);
+ showActivityModifiers( index );
+ }
+ else
+ {
+ setOverlaySequence( i, index, slSequence[i]->getValue() );
+ }
+ }
+ }
+ break;
+
+ case IDC_SEQUENCESCALE0:
+ case IDC_SEQUENCESCALE1:
+ case IDC_SEQUENCESCALE2:
+ case IDC_SEQUENCESCALE3:
+ case IDC_SEQUENCESCALE4:
+ {
+ int i = event->action - IDC_SEQUENCESCALE0;
+ int index = cSequence[i]->getSelectedIndex();
+ if (index >= 0)
+ {
+ index = iSelectionToSequence[index];
+ if (i == 0)
+ {
+ setSequence (index);
+ showActivityModifiers( index );
+ }
+ else
+ {
+ setOverlaySequence( i, index, (float)((mxSlider *) event->widget)->getValue() );
+ }
+ }
+ }
+ break;
+
+ case IDC_FRAMESELECTION0:
+ case IDC_FRAMESELECTION1:
+ case IDC_FRAMESELECTION2:
+ case IDC_FRAMESELECTION3:
+ case IDC_FRAMESELECTION4:
+ {
+ updateFrameSelection();
+ }
+ break;
+
+ case IDC_BLENDTIME:
+ {
+ char sz[ 256 ];
+ sprintf( sz, "%.2f s", (float)((mxSlider *) event->widget)->getValue() );
+
+ g_pStudioModel->SetBlendTime( ((mxSlider *) event->widget)->getValue() );
+ laBlendTime->setLabel( sz );
+ }
+ break;
+ case IDC_BLENDSEQUENCECHANGES:
+ g_viewerSettings.blendSequenceChanges = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+ case IDC_ANIMATEWEAPONS:
+ g_viewerSettings.animateWeapons = ((mxCheckBox *) event->widget)->isChecked();
+ break;
+ case IDC_BLENDNOW:
+ startBlending();
+ break;
+ case IDC_SPEEDSCALE:
+ {
+ setSpeedScale( ((mxSlider *) event->widget)->getValue() );
+ }
+ break;
+
+ case IDC_FORCEFRAME:
+ {
+ setFrame( ((mxSlider *) event->widget)->getValue() );
+
+ // stop the animation
+ setSpeedScale( 0 );
+
+ if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
+ {
+ CUtlBuffer cmd;
+ CUtlBuffer res;
+ cmd.Printf( "%s %f", "hlmvForceFrame", reinterpret_cast< mxSlider * >( event->widget )->getValue() );
+ g_HlmvIpcClient.ExecuteCommand( cmd, res );
+ g_HlmvIpcClient.Disconnect();
+ }
+ }
+ break;
+
+ case IDC_BODYPART:
+ {
+ int index = cBodypart->getSelectedIndex();
+ if (index >= 0)
+ {
+ g_pStudioModel->SetBodygroup( cBodypart->getSelectedIndex() );
+ setBodypart (index);
+ }
+ }
+ break;
+
+ case IDC_SUBMODEL:
+ {
+ int index = cSubmodel->getSelectedIndex();
+ if (index >= 0)
+ {
+ setSubmodel (index);
+ }
+ }
+ break;
+
+ case IDC_CONTROLLER:
+ {
+ int index = cController->getSelectedIndex();
+ if (index >= 0)
+ setBoneController (index);
+ }
+ break;
+
+ case IDC_CONTROLLERVALUE:
+ {
+ int index = cController->getSelectedIndex();
+ if (index >= 0)
+ {
+ float flValue = slController->getValue();
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
+ if (pbonecontroller->end < pbonecontroller->start)
+ {
+ flValue *= -1.0f;
+ }
+ setBoneControllerValue(index, flValue);
+ }
+ }
+ break;
+
+ case IDC_SKINS:
+ {
+ int index = cSkin->getSelectedIndex();
+ if (index >= 0)
+ {
+ g_pStudioModel->SetSkin (index);
+ g_viewerSettings.skin = index;
+ d_MatSysWindow->redraw();
+ }
+ }
+ break;
+
+ case IDC_MATERIALS:
+ {
+ int index = cMaterials->getSelectedIndex();
+ if (index >= 0)
+ {
+ g_viewerSettings.materialIndex = index;
+ }
+ }
+ break;
+
+ case IDC_IKRULE_CHAIN:
+ case IDC_IKRULE_CHOICE:
+ case IDC_IKRULE_RANGE_TOGGLE:
+ case IDC_IKRULE_RANGE_START:
+ case IDC_IKRULE_RANGE_PEAK:
+ case IDC_IKRULE_RANGE_TAIL:
+ case IDC_IKRULE_RANGE_END:
+ case IDC_IKRULE_CONTACT_TOGGLE:
+ case IDC_IKRULE_CONTACT_FRAME:
+ case IDC_IKRULE_USING:
+ UpdateIKRuleWindow();
+ break;
+
+ case IDC_IKRULE_TOUCH:
+ case IDC_IKRULE_ATTACHMENT:
+ BuildIKRuleQCString();
+ break;
+
+ case IDC_IKRULE_RANGE_START_NOW:
+ SetFrameString( leIKRangeStart, getFrameSelection() );
+ break;
+
+ case IDC_IKRULE_RANGE_PEAK_NOW:
+ SetFrameString( leIKRangePeak, getFrameSelection() );
+ break;
+
+ case IDC_IKRULE_RANGE_TAIL_NOW:
+ SetFrameString( leIKRangeTail, getFrameSelection() );
+ break;
+
+ case IDC_IKRULE_RANGE_END_NOW:
+ SetFrameString( leIKRangeEnd, getFrameSelection() );
+ break;
+
+ case IDC_IKRULE_CONTACT_FRAME_NOW:
+ SetFrameString( leIKContactFrame, getFrameSelection() );
+ break;
+
+ case IDC_IKRULE_QC_STRING:
+ // ignore edits to the qc text box
+ break;
+
+ case IDC_EVENT_SOUND_FRAME:
+ case IDC_EVENT_SOUND_NAME:
+ BuildEventQCString();
+ break;
+
+ case IDC_EVENT_SOUND_FRAME_NOW:
+ SetFrameString( leEventSoundFrame, getFrameSelection() );
+ break;
+
+ case IDC_EVENT_QC_STRING:
+ // ignore edits to the qc text box
+ break;
+
+ default:
+ {
+ if ( event->action == IDC_FLEXDEFAULTS )
+ {
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ g_pStudioModel->SetFlexController( i, 0 );
+ }
+ for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
+ {
+ LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
+ slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
+ }
+ }
+ else if ( event->action == IDC_FLEXRANDOM )
+ {
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ float r = rand() / float( VALVE_RAND_MAX );
+ g_pStudioModel->SetFlexController( i, r );
+ }
+
+ for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
+ {
+ LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
+ slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
+ }
+ }
+ else if ( event->action == IDC_FLEXZERO )
+ {
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ g_pStudioModel->SetFlexController( i, 0 );
+ }
+
+ for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
+ {
+ LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
+ slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
+ }
+ }
+ else if ( event->action == IDC_FLEXONE )
+ {
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ g_pStudioModel->SetFlexController( i, 1 );
+ }
+
+ for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
+ {
+ LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
+ slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
+ }
+ }
+ else if (event->action >= IDC_FLEX && event->action < IDC_FLEX + NUM_FLEX_SLIDERS)
+ {
+ int flex = (event->action - IDC_FLEX);
+ LocalFlexController_t index = (LocalFlexController_t)cFlex[flex]->getSelectedIndex();
+
+ if (index >= 0)
+ {
+ slFlexScale[flex]->setValue(g_pStudioModel->GetFlexControllerRaw(index));
+ }
+ }
+ else if (event->action >= IDC_FLEXSCALE && event->action < IDC_FLEXSCALE + NUM_FLEX_SLIDERS)
+ {
+ int flex = (event->action - IDC_FLEXSCALE);
+ LocalFlexController_t index = (LocalFlexController_t)cFlex[flex]->getSelectedIndex();
+
+ g_pStudioModel->SetFlexControllerRaw( index, ((mxSlider *) event->widget)->getValue() );
+ }
+ else if ( event->action >= IDC_PHYS_FIRST && event->action <= IDC_PHYS_LAST )
+ {
+ return handlePhysicsEvent( event );
+ }
+ else if (event->action >= IDC_POSEPARAMETER && event->action < IDC_POSEPARAMETER + NUM_POSEPARAMETERS)
+ {
+ int index = event->action - IDC_POSEPARAMETER;
+ int poseparam = cPoseParameter[index]->getSelectedIndex();
+
+ float flMin, flMax;
+ if (g_pStudioModel->GetPoseParameterRange( poseparam, &flMin, &flMax ))
+ {
+ slPoseParameter[index]->setRange( flMin, flMax, 1000 );
+ slPoseParameter[index]->setValue( g_pStudioModel->GetPoseParameter( poseparam ) );
+ lePoseParameter[index]->setLabel( "%.1f", g_pStudioModel->GetPoseParameter( poseparam ) );
+ }
+ }
+ else if (event->action >= IDC_POSEPARAMETER_SCALE && event->action < IDC_POSEPARAMETER_SCALE + NUM_POSEPARAMETERS)
+ {
+ int index = event->action - IDC_POSEPARAMETER_SCALE;
+ int poseparam = cPoseParameter[index]->getSelectedIndex();
+
+ setBlend( poseparam, ((mxSlider *) event->widget)->getValue() );
+ lePoseParameter[index]->setLabel( "%.1f", ((mxSlider *) event->widget)->getValue() );
+ }
+ }
+ break;
+ }
+
+ return 1;
+}
+
+
+
+void
+ControlPanel::dumpModelInfo()
+{
+#if 0
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ DeleteFile ("midump.txt");
+ FILE *file = fopen ("midump.txt", "wt");
+ if (file)
+ {
+ byte *phdr = (byte *) hdr;
+ int i;
+
+ fprintf (file, "id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]);
+ fprintf (file, "version: %d\n", hdr->version);
+ fprintf (file, "name: \"%s\"\n", hdr->name);
+ fprintf (file, "length: %d\n\n", hdr->length);
+
+ fprintf (file, "eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]);
+ fprintf (file, "min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]);
+ fprintf (file, "max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]);
+ fprintf (file, "bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]);
+ fprintf (file, "bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]);
+
+ fprintf (file, "flags: %d\n\n", hdr->flags);
+
+ fprintf (file, "numbones: %d\n", hdr->numbones);
+ for (i = 0; i < hdr->numbones; i++)
+ {
+ mstudiobone_t *pbones = (mstudiobone_t *) (phdr + hdr->boneindex);
+ fprintf (file, "\nbone %d.name: \"%s\"\n", i + 1, pbones[i].name);
+ fprintf (file, "bone %d.parent: %d\n", i + 1, pbones[i].parent);
+ fprintf (file, "bone %d.flags: %d\n", i + 1, pbones[i].flags);
+ fprintf (file, "bone %d.bonecontroller: %d %d %d %d %d %d\n", i + 1, pbones[i].bonecontroller[0], pbones[i].bonecontroller[1], pbones[i].bonecontroller[2], pbones[i].bonecontroller[3], pbones[i].bonecontroller[4], pbones[i].bonecontroller[5]);
+ fprintf (file, "bone %d.value: %f %f %f %f %f %f\n", i + 1, pbones[i].value[0], pbones[i].value[1], pbones[i].value[2], pbones[i].value[3], pbones[i].value[4], pbones[i].value[5]);
+ fprintf (file, "bone %d.scale: %f %f %f %f %f %f\n", i + 1, pbones[i].scale[0], pbones[i].scale[1], pbones[i].scale[2], pbones[i].scale[3], pbones[i].scale[4], pbones[i].scale[5]);
+ }
+
+ fprintf (file, "\nnumbonecontrollers: %d\n", hdr->numbonecontrollers);
+ for (i = 0; i < hdr->numbonecontrollers; i++)
+ {
+ mstudiobonecontroller_t *pbonecontrollers = (mstudiobonecontroller_t *) (phdr + hdr->bonecontrollerindex);
+ fprintf (file, "\nbonecontroller %d.bone: %d\n", i + 1, pbonecontrollers[i].bone);
+ fprintf (file, "bonecontroller %d.type: %d\n", i + 1, pbonecontrollers[i].type);
+ fprintf (file, "bonecontroller %d.start: %f\n", i + 1, pbonecontrollers[i].start);
+ fprintf (file, "bonecontroller %d.end: %f\n", i + 1, pbonecontrollers[i].end);
+ fprintf (file, "bonecontroller %d.rest: %d\n", i + 1, pbonecontrollers[i].rest);
+ fprintf (file, "bonecontroller %d.index: %d\n", i + 1, pbonecontrollers[i].index);
+ }
+
+ fprintf (file, "\nnumhitboxes: %d\n", hdr->numhitboxes);
+ for (i = 0; i < hdr->numhitboxes; i++)
+ {
+ mstudiobbox_t *pbboxes = (mstudiobbox_t *) (phdr + hdr->hitboxindex);
+ fprintf (file, "\nhitbox %d.bone: %d\n", i + 1, pbboxes[i].bone);
+ fprintf (file, "hitbox %d.group: %d\n", i + 1, pbboxes[i].group);
+ fprintf (file, "hitbox %d.bbmin: %f %f %f\n", i + 1, pbboxes[i].bbmin[0], pbboxes[i].bbmin[1], pbboxes[i].bbmin[2]);
+ fprintf (file, "hitbox %d.bbmax: %f %f %f\n", i + 1, pbboxes[i].bbmax[0], pbboxes[i].bbmax[1], pbboxes[i].bbmax[2]);
+ }
+
+ fprintf (file, "\nnumseq: %d\n", hdr->GetNumSeq());
+ for (i = 0; i < hdr->GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t *pseqdescs = (mstudioseqdesc_t *) (phdr + hdr->seqindex);
+ fprintf (file, "\nseqdesc %d.label: \"%s\"\n", i + 1, pseqdescs[i].label);
+ fprintf (file, "seqdesc %d.fps: %f\n", i + 1, pseqdescs[i].fps);
+ fprintf (file, "seqdesc %d.flags: %d\n", i + 1, pseqdescs[i].flags);
+ fprintf (file, "<...>\n");
+ }
+/*
+ fprintf (file, "\nnumseqgroups: %d\n", hdr->GetNumSeq()groups);
+ for (i = 0; i < hdr->GetNumSeq()groups; i++)
+ {
+ mstudioseqgroup_t *pseqgroups = (mstudioseqgroup_t *) (phdr + hdr->seqgroupindex);
+ fprintf (file, "\nseqgroup %d.label: \"%s\"\n", i + 1, pseqgroups[i].label);
+ fprintf (file, "\nseqgroup %d.namel: \"%s\"\n", i + 1, pseqgroups[i].name);
+ fprintf (file, "\nseqgroup %d.data: %d\n", i + 1, pseqgroups[i].data);
+ }
+*/
+ hdr = g_pStudioModel->getTextureHeader();
+ fprintf (file, "\nnumtextures: %d\n", hdr->numtextures);
+ fprintf (file, "textureindex: %d\n", hdr->textureindex);
+ fprintf (file, "texturedataindex: %d\n", hdr->texturedataindex);
+ for (i = 0; i < hdr->numtextures; i++)
+ {
+ mstudiotexture_t *ptextures = (mstudiotexture_t *) ((byte *) hdr + hdr->textureindex);
+ fprintf (file, "\ntexture %d.name: \"%s\"\n", i + 1, ptextures[i].name);
+ fprintf (file, "texture %d.flags: %d\n", i + 1, ptextures[i].flags);
+ fprintf (file, "texture %d.width: %d\n", i + 1, ptextures[i].width);
+ fprintf (file, "texture %d.height: %d\n", i + 1, ptextures[i].height);
+ fprintf (file, "texture %d.index: %d\n", i + 1, ptextures[i].index);
+ }
+
+ hdr = g_pStudioModel->GetStudioHdr();
+ fprintf (file, "\nnumskinref: %d\n", hdr->numskinref);
+ fprintf (file, "numskinfamilies: %d\n", hdr->numskinfamilies);
+
+ fprintf (file, "\nnumbodyparts: %d\n", hdr->numbodyparts);
+ for (i = 0; i < hdr->numbodyparts; i++)
+ {
+ mstudiobodyparts_t *pbodyparts = (mstudiobodyparts_t *) ((byte *) hdr + hdr->bodypartindex);
+ fprintf (file, "\nbodypart %d.name: \"%s\"\n", i + 1, pbodyparts[i].name);
+ fprintf (file, "bodypart %d.nummodels: %d\n", i + 1, pbodyparts[i].nummodels);
+ fprintf (file, "bodypart %d.base: %d\n", i + 1, pbodyparts[i].base);
+ fprintf (file, "bodypart %d.modelindex: %d\n", i + 1, pbodyparts[i].modelindex);
+ }
+
+ fprintf (file, "\nnumattachments: %d\n", hdr->numattachments);
+ for (i = 0; i < hdr->numattachments; i++)
+ {
+ mstudioattachment_t *pattachments = (mstudioattachment_t *) ((byte *) hdr + hdr->attachmentindex);
+ fprintf (file, "attachment %d.name: \"%s\"\n", i + 1, pattachments[i].name);
+ }
+
+ fclose (file);
+
+ ShellExecute ((HWND) getHandle(), "open", "midump.txt", 0, 0, SW_SHOW);
+ }
+ }
+#endif
+}
+
+
+LoadModelResult_t ControlPanel::loadModel(const char *filename)
+{
+ SaveViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
+
+ g_pStudioModel->FreeModel( false );
+
+ if (!g_pStudioModel->LoadModel( filename ))
+ {
+ return LoadModel_LoadFail;
+ }
+
+ if (!g_pStudioModel->PostLoadModel( filename ))
+ {
+ return LoadModel_PostLoadFail;
+ }
+
+ if (!g_pStudioModel->HasModel())
+ {
+ return LoadModel_NoModel;
+ }
+
+ OnLoadModel( );
+
+ return LoadModel_Success;
+}
+
+void ControlPanel::OnLoadModel( void )
+{
+ int i;
+ m_bVMTInfoLoaded = false;
+
+ if (!g_pStudioModel->HasModel())
+ return;
+
+ initSequenceChoices();
+ initBodypartChoices();
+ initBoneControllers();
+ initSkinChoices();
+ initMaterialChoices();
+ initPhysicsBones();
+ initLODs();
+ initFlexes();
+
+ setModelInfo();
+
+ UnloadAllMergedModels();
+
+ const bool bNoModelSettings = LoadViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
+ if ( !bNoModelSettings )
+ {
+ InitViewerSettings( "hlmv" );
+ setSequence( 0 );
+ showActivityModifiers( 0 );
+ setSpeedScale( 1.0 );
+ }
+
+ resetControlPanel();
+
+ /*!!
+ for (i = 0; i < 32; i++)
+ g_viewerSettings.submodels[i] = 0;
+ for (i = 0; i < 8; i++)
+ g_viewerSettings.controllers[i] = 0;
+ */
+
+ setupPhysics();
+ m_pBoneWindow->OnLoadModel();
+ m_pAttachmentsWindow->OnLoadModel();
+
+ PopulateBoneList( cIKTouch, true );
+
+ mx_setcwd (mx_getpath (g_pStudioModel->GetFileName()));
+
+ for ( i = 0; i < HLMV_MAX_MERGED_MODELS; ++i )
+ {
+ if ( strlen( g_viewerSettings.mergeModelFile[i] ) != 0 )
+ {
+ loadModel( g_viewerSettings.mergeModelFile[i], i );
+ }
+ }
+
+ // Center the model if we don't have last view position data in the registry
+ if ( !bNoModelSettings )
+ {
+ // Need to call this twice for some reason. Really - I don't have OCD!
+ centerView();
+ centerView();
+ }
+}
+
+
+LoadModelResult_t ControlPanel::loadModel(const char *filename, int slot )
+{
+ if (slot == -1)
+ {
+ return loadModel( filename );
+ }
+
+ if (g_pStudioExtraModel[slot] == NULL)
+ {
+ g_pStudioExtraModel[slot] = new StudioModel;
+ }
+ else
+ {
+ g_pStudioExtraModel[slot]->FreeModel( false );
+ }
+
+ if (g_pStudioExtraModel[slot]->LoadModel( filename ))
+ {
+ if (g_pStudioExtraModel[slot]->PostLoadModel( filename ))
+ {
+ connectFlexes( g_pStudioExtraModel[slot]->GetStudioHdr() );
+ if ( g_MDLViewer && g_MDLViewer->getMenuBar() )
+ {
+ g_MDLViewer->getMenuBar()->modify (IDC_FILE_UNLOADMERGEDMODEL1 + slot, IDC_FILE_UNLOADMERGEDMODEL1 + slot, filename);
+ g_MDLViewer->getMenuBar()->setEnabled (IDC_FILE_UNLOADMERGEDMODEL1 + slot, true);
+ }
+ return LoadModel_Success;
+ }
+ else
+ {
+ return LoadModel_PostLoadFail;
+ }
+ }
+
+ return LoadModel_LoadFail;
+}
+
+
+void
+ControlPanel::resetControlPanel( void )
+{
+ setSequence( g_pStudioModel->GetSequence() );
+ showActivityModifiers( g_pStudioModel->GetSequence() );
+ setOverlaySequence( 1, g_pStudioModel->GetOverlaySequence( 0 ), g_pStudioModel->GetOverlaySequenceWeight( 0 ) );
+ setOverlaySequence( 2, g_pStudioModel->GetOverlaySequence( 1 ), g_pStudioModel->GetOverlaySequenceWeight( 1 ) );
+ setOverlaySequence( 3, g_pStudioModel->GetOverlaySequence( 2 ), g_pStudioModel->GetOverlaySequenceWeight( 2 ) );
+ setOverlaySequence( 4, g_pStudioModel->GetOverlaySequence( 3 ), g_pStudioModel->GetOverlaySequenceWeight( 3 ) );
+
+ setSpeedScale( g_viewerSettings.speedScale );
+
+ cbGround->setChecked( g_viewerSettings.showGround );
+ cbMovement->setChecked( g_viewerSettings.showMovement );
+ cbShadow->setChecked( g_viewerSettings.showShadow );
+ cbNormalMap->setChecked( g_viewerSettings.enableNormalMapping );
+ cbIllumPosition->setChecked( g_viewerSettings.showIllumPosition );
+
+ cbHitBoxes->setChecked( g_viewerSettings.showHitBoxes );
+ cbBones->setChecked( g_viewerSettings.showBones );
+ cbPlaySounds->setChecked( g_viewerSettings.playSounds );
+ cbSequenceBoxes->setChecked( g_viewerSettings.showSequenceBoxes );
+ cbRunIK->setChecked( g_viewerSettings.enableIK );
+
+ cbBackground->setChecked( g_viewerSettings.showBackground );
+ cbSoftwareSkin->setChecked( g_viewerSettings.softwareSkin );
+ cbOverbright2->setChecked( g_viewerSettings.overbright );
+ cbAttachments->setChecked( g_viewerSettings.showAttachments );
+ cbNormals->setChecked( g_viewerSettings.showNormals );
+ cbEnableHead->setChecked( g_pStudioModel->GetSolveHeadTurn() ? 1 : 0 );
+
+ cbShowOriginAxis->setChecked( g_viewerSettings.showOriginAxis );
+ setOriginAxisLength( g_viewerSettings.originAxisLength );
+}
+
+
+void
+ControlPanel::setRenderMode (int mode)
+{
+ g_viewerSettings.renderMode = mode;
+ d_MatSysWindow->redraw();
+}
+
+
+void
+ControlPanel::setHighlightBone( int index )
+{
+ if ( index >= 0 )
+ {
+ g_viewerSettings.highlightPhysicsBone = index;
+ }
+}
+
+void
+ControlPanel::setLOD( int index, bool setLODchoice, bool force )
+{
+#if 1
+ if( !force && ( g_viewerSettings.lod == index ) )
+ {
+ return;
+ }
+#endif
+ g_viewerSettings.lod = index;
+ float lodSwitch = g_pStudioModel->GetLODSwitchValue( index );
+ char tmp[128];
+ sprintf( tmp, "%0.0f", lodSwitch );
+ leLODSwitch->setLabel( tmp );
+ HWND wnd = ( HWND )leLODSwitch->getHandle();
+ if( setLODchoice )
+ {
+ cLODChoice->select( index );
+ }
+ setModelInfo();
+ InvalidateRect( wnd, NULL, TRUE );
+ UpdateWindow( wnd );
+}
+
+void
+ControlPanel::setLODMetric( float metric )
+{
+ static int saveMetric = -10;
+ int intMetric = ( int )metric;
+ if( intMetric == saveMetric )
+ {
+ return;
+ }
+ saveMetric = intMetric;
+ char tmp[128];
+ sprintf( tmp, "%d", intMetric );
+ lLODMetric->setLabel( tmp );
+}
+
+void
+ControlPanel::setPolycount( int polycount )
+{
+ static int savePolycount = -10;
+ if( polycount == savePolycount )
+ {
+ return;
+ }
+ savePolycount = polycount;
+ char tmp[128];
+ sprintf( tmp, "Shader Draw Count: %d", polycount );
+ lModelInfo3->setLabel( tmp );
+}
+
+void ControlPanel::setModelInfo( int nVertCount, int nIndexCount, int nTriCount )
+{
+ static int nSaveVertCount = -10;
+ static int nSaveIndexCount = -10;
+ static int nSaveTriCount = -10;
+
+ if ( nVertCount == nSaveVertCount && nIndexCount == nSaveIndexCount && nTriCount == nSaveTriCount )
+ {
+ return;
+ }
+
+ nSaveVertCount = nVertCount;
+ nSaveIndexCount = nIndexCount;
+ nSaveTriCount = nTriCount;
+
+ char tmp[ 128 ];
+ sprintf( tmp, "Verts: %d Indexes: %d Triangles: %d", nVertCount, nIndexCount, nTriCount );
+ lModelInfo4->setLabel( tmp );
+}
+
+void
+ControlPanel::setTransparent( bool isTransparent )
+{
+ static int saveTransparent = -1;
+ if( (int)isTransparent == saveTransparent )
+ return;
+
+ saveTransparent = isTransparent;
+ char tmp[128];
+ sprintf( tmp, "Model is: %s", isTransparent ? "transparent" : "opaque" );
+ lModelInfo5->setLabel( tmp );
+}
+
+void
+ControlPanel::updatePoseParameters( )
+{
+ for (int i = 0; i < NUM_POSEPARAMETERS; i++)
+ {
+ if (slPoseParameter[i]->isEnabled())
+ {
+ int j = cPoseParameter[i]->getSelectedIndex();
+ float value = g_pStudioModel->GetPoseParameter( j );
+
+ float temp = atof( lePoseParameter[i]->getLabel( ) );
+
+ if (fabs( temp - value ) > 0.1)
+ {
+ slPoseParameter[i]->setValue( value );
+ lePoseParameter[i]->setLabel( "%.1f", value );
+ }
+ }
+ }
+}
+
+void
+ControlPanel::setShowGround (bool b)
+{
+ g_viewerSettings.showGround = b;
+ cbGround->setChecked (b);
+}
+
+void
+ControlPanel::setAutoLOD( bool b )
+{
+ g_viewerSettings.autoLOD = b;
+ cbAutoLOD->setChecked( b );
+}
+
+void
+ControlPanel::setSoftwareSkin( bool b )
+{
+ g_viewerSettings.softwareSkin = b;
+ cbSoftwareSkin->setChecked( b );
+}
+
+void
+ControlPanel::setOverbright( bool b )
+{
+ g_viewerSettings.overbright = b;
+ cbOverbright2->setChecked( b );
+}
+
+void
+ControlPanel::setShowMovement (bool b)
+{
+ g_viewerSettings.showMovement = b;
+ cbMovement->setChecked (b);
+}
+
+void
+ControlPanel::setShowBackground (bool b)
+{
+ g_viewerSettings.showBackground = b;
+ cbBackground->setChecked (b);
+}
+
+void
+ControlPanel::setShowNormals (bool b)
+{
+ g_viewerSettings.showNormals = b;
+ cbNormals->setChecked (b);
+}
+
+void
+ControlPanel::setShowTangentFrame (bool b)
+{
+ g_viewerSettings.showTangentFrame = b;
+ cbTangentFrame->setChecked (b);
+}
+
+void
+ControlPanel::setOverlayWireframe (bool b)
+{
+ g_viewerSettings.overlayWireframe = b;
+ cbOverlayWireframe->setChecked (b);
+}
+
+void
+ControlPanel::setShowShadow (bool b)
+{
+ g_viewerSettings.showShadow = b;
+ cbShadow->setChecked (b);
+}
+
+void
+ControlPanel::setShowHitBoxes (bool b)
+{
+ g_viewerSettings.showHitBoxes = b;
+ cbHitBoxes->setChecked (b);
+}
+
+void
+ControlPanel::setShowBones (bool b)
+{
+ g_viewerSettings.showBones = b;
+ cbBones->setChecked (b);
+}
+
+void
+ControlPanel::setShowAttachments (bool b)
+{
+ g_viewerSettings.showAttachments = b;
+ cbAttachments->setChecked (b);
+}
+
+
+void
+ControlPanel::setPlaySounds (bool b)
+{
+ g_viewerSettings.playSounds = b;
+ cbPlaySounds->setChecked (b);
+}
+
+void
+ControlPanel::setShowOriginAxis (bool b)
+{
+ g_viewerSettings.showOriginAxis = b;
+ cbShowOriginAxis->setChecked (b);
+}
+
+struct SortInfo_t
+{
+ int m_nSequence;
+ const char *m_pName;
+ int m_nType;
+};
+
+int SortSequenceFunc( const void *p1, const void *p2 )
+{
+ const SortInfo_t* pSort1 = (const SortInfo_t*)p1;
+ const SortInfo_t* pSort2 = (const SortInfo_t*)p2;
+ if ( pSort1->m_nType < pSort2->m_nType )
+ return -10000;
+ if ( pSort1->m_nType > pSort2->m_nType )
+ return 10000;
+ return Q_stricmp( pSort1->m_pName, pSort2->m_pName );
+}
+
+void ControlPanel::CreateSortedSequenceList( CStudioHdr* hdr, int *pSequence )
+{
+ int nSequenceCount = hdr->GetNumSeq();
+ SortInfo_t *pSort = (SortInfo_t*)_alloca( nSequenceCount * sizeof(SortInfo_t) );
+
+ // Set up sort info
+ for ( int j = 0; j < nSequenceCount; j++ )
+ {
+ pSort[j].m_nSequence = j;
+ if ( g_viewerSettings.showActivities )
+ {
+ pSort[j].m_pName = hdr->pSeqdesc(j).pszActivityName();
+ }
+ else
+ {
+ pSort[j].m_pName = hdr->pSeqdesc(j).pszLabel();
+ }
+
+ pSort[j].m_nType = 0;
+
+ const char *pKeyValuesText = Studio_GetKeyValueText( hdr, j );
+ if ( !pKeyValuesText )
+ continue;
+
+ KeyValues *pKeyValues = new KeyValues( "sort" );
+
+ if ( pKeyValues->LoadFromBuffer( "mdl", pKeyValuesText ) )
+ {
+ KeyValues *pFacePoserKeys = pKeyValues->FindKey( "faceposer" );
+ if ( pFacePoserKeys )
+ {
+ const char *pType = pFacePoserKeys->GetString( "type", "" );
+ if ( !Q_stricmp( pType, "posture" ) )
+ {
+ pSort[j].m_nType = 2;
+ }
+ else if ( !Q_stricmp( pType, "gesture" ) )
+ {
+ pSort[j].m_nType = 1;
+ }
+ }
+ }
+ pKeyValues->deleteThis();
+ }
+
+ if ( !CommandLine()->CheckParm( "-nosort" ) )
+ {
+ qsort( pSort, nSequenceCount, sizeof(SortInfo_t), SortSequenceFunc );
+ }
+
+ for ( int i = 0; i < nSequenceCount; ++i )
+ {
+ pSequence[i] = pSort[i].m_nSequence;
+ }
+}
+
+void ControlPanel::initSequenceChoices()
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ int nSequenceCount = hdr->GetNumSeq();
+ int *pSequence = (int*)_alloca( nSequenceCount * sizeof(int) );
+ CreateSortedSequenceList( hdr, pSequence );
+
+ if (iSelectionToSequence)
+ {
+ free( iSelectionToSequence );
+ }
+ iSelectionToSequence = (int*)malloc( nSequenceCount * sizeof(int) );
+
+ if (iSequenceToSelection)
+ {
+ free( iSequenceToSelection );
+ }
+ iSequenceToSelection = (int*)malloc( nSequenceCount * sizeof(int) );
+
+ for (int i = 0; i < MAX_SEQUENCES; i++)
+ {
+ cSequence[i]->removeAll();
+
+ int k = 0;
+ for (int j = 0; j < nSequenceCount; j++)
+ {
+ int nSequence = pSequence[j];
+
+ if (g_viewerSettings.showHidden || !(hdr->pSeqdesc(nSequence).flags & STUDIO_HIDDEN))
+ {
+ if (g_viewerSettings.showActivities)
+ {
+ cSequence[i]->add( hdr->pSeqdesc(nSequence).pszActivityName() );
+ }
+ else
+ {
+ cSequence[i]->add( hdr->pSeqdesc(nSequence).pszLabel() );
+ }
+ iSelectionToSequence[k] = nSequence;
+ iSequenceToSelection[nSequence] = k;
+ k++;
+ }
+ else
+ {
+ // previous valid selection
+ iSequenceToSelection[nSequence] = (k > 0) ? (k - 1) : 0;
+ }
+ }
+ cSequence[i]->select( 0 );
+ slSequence[i]->setValue( 0 );
+ }
+ }
+
+ float flMin, flMax;
+ for (int i = 0; i < NUM_POSEPARAMETERS; i++)
+ {
+ if (g_pStudioModel->GetPoseParameterRange( i, &flMin, &flMax ))
+ {
+ cPoseParameter[i]->removeAll();
+ for (int j = 0; j < hdr->GetNumPoseParameters(); j++)
+ {
+ cPoseParameter[i]->add( hdr->pPoseParameter(j).pszName() );
+ }
+ cPoseParameter[i]->select( i );
+ cPoseParameter[i]->setEnabled( true );
+ cPoseParameter[i]->setVisible( true );
+
+ slPoseParameter[i]->setEnabled( true );
+ slPoseParameter[i]->setRange( flMin, flMax, 1000 );
+ mxToolTip::add (slPoseParameter[i], hdr->pPoseParameter(i).pszName() );
+ slPoseParameter[i]->setVisible( true );
+ lePoseParameter[i]->setVisible( true );
+ lePoseParameter[i]->setLabel( "%.1f", 0.0 );
+ }
+ else
+ {
+ cPoseParameter[i]->setEnabled( false );
+ cPoseParameter[i]->setVisible( false );
+ slPoseParameter[i]->setEnabled( false );
+ slPoseParameter[i]->setVisible( false );
+ lePoseParameter[i]->setVisible( false );
+ }
+ slPoseParameter[i]->setValue( 0.0 );
+ setBlend( i, 0.0 );
+ }
+
+ if ( hdr )
+ {
+ for (int i = 0; i < hdr->GetNumPoseParameters(); i++)
+ {
+ setBlend( i, 0.0 );
+ }
+ }
+}
+
+
+void ControlPanel::setSequence(int index)
+{
+ cSequence[0]->select( iSequenceToSelection[index] );
+ g_pStudioModel->SetSequence(index);
+
+ updateFrameSelection();
+ updateGroundSpeed();
+}
+
+
+void ControlPanel::updateGroundSpeed( void )
+{
+ char sz[100];
+ float flGroundSpeed = g_pStudioModel->GetCurrentVelocity();
+ sprintf( sz, "Speed: %.2f", flGroundSpeed );
+ laGroundSpeed->setLabel( sz );
+}
+
+
+void
+ControlPanel::setOverlaySequence(int num, int index, float weight)
+{
+ cSequence[num]->select( iSequenceToSelection[index] );
+ g_pStudioModel->SetOverlaySequence( num-1, index, weight );
+ slSequence[num]->setValue( weight );
+
+ updateFrameSelection();
+}
+
+
+void ControlPanel::startBlending( void )
+{
+ g_pStudioModel->StartBlending();
+}
+
+void ControlPanel::updateTransitionAmount( void )
+{
+ char sz[ 256 ];
+ sprintf( sz, "%.3f %%", 100.0f * g_pStudioModel->GetTransitionAmount() );
+ laBlendAmount->setLabel( sz );
+}
+
+
+int ControlPanel::getFrameSelection( void )
+{
+ for ( int i = 0; i < MAX_SEQUENCES; i++ )
+ if ( rbFrameSelection[i]->isChecked() )
+ return i;
+ return 0;
+}
+
+void ControlPanel::setFrame( float frame )
+{
+ int iLayer = getFrameSelection();
+ int iFrame = g_pStudioModel->SetFrame( iLayer, frame );
+ char buf[128];
+ sprintf(buf, "%3d", iFrame );
+ lForcedFrame->setLabel( buf );
+}
+
+
+void ControlPanel::updateFrameSelection( void )
+{
+ int iLayer = getFrameSelection();
+ int maxFrame = g_pStudioModel->GetMaxFrame( iLayer );
+ slForceFrame->setRange( 0, maxFrame, maxFrame );
+ slForceFrame->setSteps(1,1);
+}
+
+void ControlPanel::updateFrameSlider( void )
+{
+ int iLayer = getFrameSelection();
+ float flFrame = g_pStudioModel->GetFrame( iLayer );
+ char buf[128];
+ sprintf(buf, "%3.1f", flFrame );
+ lForcedFrame->setLabel( buf );
+ slForceFrame->setValue( flFrame );
+}
+
+void ControlPanel::setSpeedScale( float scale )
+{
+ slSpeedScale->setValue( scale );
+ g_viewerSettings.speedScale = scale;
+
+ updateSpeedScale( );
+}
+
+
+void ControlPanel::updateSpeedScale( void )
+{
+ char szFPS[32];
+ sprintf( szFPS, "x %.2f = %.1f fps", g_viewerSettings.speedScale, g_viewerSettings.speedScale * g_pStudioModel->GetFPS( ) );
+ laFPS->setLabel( szFPS );
+}
+
+
+void ControlPanel::setBlend(int index, float value )
+{
+ g_pStudioModel->SetPoseParameter( index, value );
+ // reset number of frames....
+ updateFrameSelection( );
+
+ updateGroundSpeed( );
+}
+
+void
+ControlPanel::initBodypartChoices()
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ int i;
+ mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
+
+ cBodypart->removeAll();
+ if (hdr->numbodyparts() > 0)
+ {
+ for (i = 0; i < hdr->numbodyparts(); i++)
+ cBodypart->add (pbodyparts[i].pszName());
+
+ cBodypart->select (0);
+
+ cSubmodel->removeAll();
+ for (i = 0; i < pbodyparts[0].nummodels; i++)
+ {
+ char str[64];
+ sprintf (str, "Submodel %d", i );
+ cSubmodel->add (str);
+ }
+ cSubmodel->select (0);
+ }
+ }
+}
+
+
+
+void
+ControlPanel::setBodypart (int index)
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ //cBodypart->setEn
+ cBodypart->select (index);
+ if (index < hdr->numbodyparts())
+ {
+ mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
+ cSubmodel->removeAll();
+
+ for (int i = 0; i < pbodyparts[index].nummodels; i++)
+ {
+ char str[64];
+ sprintf (str, "Submodel %d", i );
+ cSubmodel->add (str);
+ }
+ cSubmodel->select (0);
+ //g_pStudioModel->SetBodygroup (index, 0);
+ }
+ }
+ setModelInfo();
+}
+
+
+
+void
+ControlPanel::setSubmodel (int index)
+{
+ g_pStudioModel->SetBodygroup (cBodypart->getSelectedIndex(), index);
+ //!!g_viewerSettings.submodels[cBodypart->getSelectedIndex()] = index;
+ setModelInfo();
+}
+
+
+
+void
+ControlPanel::initPhysicsBones()
+{
+ cHighlightBone->removeAll();
+ cHighlightBone->add( "None" );
+ for ( int i = 0; i < g_pStudioModel->Physics_GetBoneCount(); i++ )
+ {
+ cHighlightBone->add (g_pStudioModel->Physics_GetBoneName( i ) );
+ }
+ cHighlightBone->select (0);
+}
+
+void
+ControlPanel::initLODs()
+{
+ cLODChoice->removeAll();
+ for ( int i = 0; i < g_pStudioModel->GetNumLODs(); i++ )
+ {
+ char tmp[10];
+ sprintf( tmp, "%d", i );
+ cLODChoice->add( tmp );
+ }
+ setLOD( 0, true, true );
+}
+
+void
+ControlPanel::initBoneControllers()
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ cController->setEnabled (hdr->numbonecontrollers() > 0);
+ slController->setEnabled (hdr->numbonecontrollers() > 0);
+ cController->removeAll();
+
+ int i = 0;
+ for (i; i < hdr->numbonecontrollers(); i++)
+ {
+ char str[32];
+ mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(i);
+ sprintf (str, "Controller %d", pbonecontroller->inputfield);
+ cController->add (str);
+ }
+
+ if (hdr->numbonecontrollers() > 0)
+ {
+ cController->select (0);
+ mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(0);
+ slController->setRange (pbonecontroller->start, pbonecontroller->end);
+ slController->setValue (0);
+ }
+ }
+}
+
+
+
+void
+ControlPanel::setBoneController (int index)
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
+ slController->setRange ( pbonecontroller->start, pbonecontroller->end);
+ slController->setValue (0);
+ }
+}
+
+
+
+void
+ControlPanel::setBoneControllerValue (int index, float value)
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
+ g_pStudioModel->SetController (pbonecontroller->inputfield, value);
+ }
+}
+
+
+
+void
+ControlPanel::initSkinChoices()
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ cSkin->setEnabled (hdr->numskinfamilies() > 0);
+ cSkin->removeAll();
+
+ for (int i = 0; i < hdr->numskinfamilies(); i++)
+ {
+ char str[32];
+ sprintf (str, "Skin %d", i );
+ cSkin->add (str);
+ }
+
+ cSkin->select (0);
+ g_pStudioModel->SetSkin (0);
+ g_viewerSettings.skin = 0;
+ }
+}
+
+void ControlPanel::initMaterialChoices()
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if (hdr)
+ {
+ const studiohdr_t *pStudioHdr = hdr->GetRenderHdr();
+ if (pStudioHdr)
+ {
+ cMaterials->setEnabled(pStudioHdr->numtextures > 0);
+ cMaterials->removeAll();
+
+ for (int i = 0; i < pStudioHdr->numtextures; i++)
+ {
+ char str[512];
+ sprintf (str, "%s", pStudioHdr->pTexture(i)->pszName() );
+ cMaterials->add (str);
+ }
+
+ cMaterials->select (0);
+ g_viewerSettings.materialIndex = 0;
+ }
+ }
+}
+
+void ControlPanel::showActivityModifiers( int sequence )
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ if ( !hdr->SequencesAvailable() )
+ return;
+
+ if ( sequence < 0 || sequence >= hdr->GetNumSeq() )
+ return;
+
+ mstudioseqdesc_t &desc = hdr->pSeqdesc( sequence );
+
+ cActivityModifiers->setEnabled( desc.numactivitymodifiers > 0);
+ cActivityModifiers->removeAll();
+
+ for (int i = 0; i < desc.numactivitymodifiers; i++)
+ {
+ char str[512];
+ sprintf (str, "%s", desc.pActivityModifier( i )->pszName() );
+ cActivityModifiers->add (str);
+ }
+
+ cActivityModifiers->select (0);
+}
+
+void
+ControlPanel::setModelInfo()
+{
+ static char str[2048];
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+
+ if (!hdr)
+ return;
+
+ static int checkSum = 0;
+ static int boneLODCount = 0;
+ static int numBatches = 0;
+ if ( g_pStudioModel && !m_bVMTInfoLoaded )
+ {
+ UpdateMaterialList();
+ }
+
+ if( checkSum == hdr->GetRenderHdr()->checksum && boneLODCount == g_DrawModelResults.m_NumHardwareBones && numBatches == g_DrawModelResults.m_NumBatches)
+ {
+ return;
+ }
+
+ checkSum = hdr->GetRenderHdr()->checksum;
+ boneLODCount = g_DrawModelResults.m_NumHardwareBones;
+ numBatches = g_DrawModelResults.m_NumBatches;
+
+ int hbcount = 0;
+ for ( int s = 0; s < hdr->numhitboxsets(); s++ )
+ {
+ hbcount += hdr->iHitboxCount( s );
+ }
+
+ sprintf (str,
+ "Total bones: %d\n"
+ "HW Bones: %d\n"
+ "Batches: %d\n"
+ "Bone Controllers: %d\n"
+ "Hit Boxes: %d in %d sets\n"
+ "Sequences: %d\n",
+ hdr->numbones(),
+ boneLODCount,
+ numBatches,
+ hdr->numbonecontrollers(),
+ hbcount,
+ hdr->numhitboxsets(),
+ hdr->GetNumSeq()
+ );
+
+ lModelInfo1->setLabel (str);
+
+ sprintf (str,
+ "Materials: %d\n"
+ "Skin Families: %d\n"
+ "Bodyparts: %d\n"
+ "Attachments: %d\n",
+ g_DrawModelResults.m_NumMaterials,
+ hdr->numskinfamilies(),
+ hdr->numbodyparts(),
+ hdr->GetNumAttachments());
+
+ lModelInfo2->setLabel (str);
+}
+
+void ControlPanel::UpdateMaterialList( )
+{
+ cMessageList->removeAll();
+ studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
+ if ( pStudioR )
+ {
+ IMaterial *pMaterials[128];
+ int nMaterials = g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
+
+ for ( int i = 0; i < nMaterials; i++ )
+ {
+ char c_MaterialLine[256];
+ Q_strcpy( c_MaterialLine, "" );
+
+ if ( pMaterials[i]->IsErrorMaterial() )
+ {
+ Q_strcat( c_MaterialLine, "*** ERROR *** Model attempted to load one or more VMTs it can't find." , sizeof( c_MaterialLine ) );
+ }
+ else
+ {
+ Q_strcat( c_MaterialLine, pMaterials[i]->GetName() , sizeof( c_MaterialLine ) );
+ }
+ cMessageList->add( c_MaterialLine );
+ }
+ m_bVMTInfoLoaded = true;
+ }
+}
+
+
+extern matrix3x4_t g_viewtransform;
+
+void ControlPanel::centerView( )
+{
+ Vector min, max;
+
+ int hitboxset = 0; //g_MDLViewer->GetCurrentHitboxSet();
+
+ min.Init( 999999,999999,999999);
+ max.Init( -999999,-999999,-999999);
+
+ matrix3x4_t rootxform;
+ MatrixInvert( g_viewtransform, rootxform );
+
+ HitboxList_t &list = g_pStudioModel->m_HitboxSets[ hitboxset ].m_Hitboxes;
+ for (unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
+ {
+ mstudiobbox_t *pBBox = &list[j].m_BBox;
+
+ Vector tmpmin, tmpmax;
+ matrix3x4_t bonesetup;
+
+ ConcatTransforms( rootxform, *g_pStudioModel->BoneToWorld( pBBox->bone ), bonesetup );
+
+ TransformAABB( bonesetup, pBBox->bbmin, pBBox->bbmax, tmpmin, tmpmax );
+
+ if (tmpmin.x < min.x) min.x = tmpmin.x;
+ if (tmpmin.y < min.y) min.y = tmpmin.y;
+ if (tmpmin.z < min.z) min.z = tmpmin.z;
+ if (tmpmax.x > max.x) max.x = tmpmax.x;
+ if (tmpmax.y > max.y) max.y = tmpmax.y;
+ if (tmpmax.z > max.z) max.z = tmpmax.z;
+ }
+
+ if (min.x > max.x)
+ {
+ g_pStudioModel->ExtractBbox(min, max);
+ }
+
+ float dx = max[0] - min[0];
+ float dy = max[1] - min[1];
+ float dz = max[2] - min[2];
+
+ // Determine the distance from the model such that it will fit in the screen.
+ float d = dx;
+ if (dy > d)
+ d = dy;
+ if (dz > d)
+ d = dz;
+
+ g_pStudioModel->m_origin[0] = d * 1.34f;
+ g_pStudioModel->m_origin[1] = 0.0f;
+ g_pStudioModel->m_origin[2] = min[2] + dz / 2;
+ g_pStudioModel->m_angles[0] = 0.0f;
+ g_pStudioModel->m_angles[1] = 0.0f;
+ g_pStudioModel->m_angles[2] = 0.0f;
+ g_viewerSettings.lightrot[0] = 0.0f;
+ g_viewerSettings.lightrot[1] = 180.0f; // light should aim at models front
+ g_viewerSettings.lightrot[2] = 0.0f;
+ setFOV( 65.0f );
+ d_MatSysWindow->redraw();
+}
+
+void ControlPanel::viewmodelView()
+{
+ // Sit the camera at the origin with a 54 degree FOV for viewmodels
+ g_pStudioModel->m_origin[0] = 0.0f;
+ g_pStudioModel->m_origin[1] = 0.0f;
+ g_pStudioModel->m_origin[2] = 0.0f;
+ g_pStudioModel->m_angles[0] = 0.0f;
+ g_pStudioModel->m_angles[1] = 180.0f;
+ g_pStudioModel->m_angles[2] = 0.0f;
+ g_viewerSettings.lightrot[0] = 0.0f;
+ g_viewerSettings.lightrot[1] = 180.0f; // light should aim at models front
+ g_viewerSettings.lightrot[2] = 0.0f;
+ setFOV( 54.0f );
+ d_MatSysWindow->redraw();
+}
+
+void ControlPanel::setFOV( float fov )
+{
+ char buf[64];
+ g_viewerSettings.fov = fov;
+ sprintf( buf, "%.0f", fov );
+ leFOV->setLabel( buf );
+}
+
+
+void ControlPanel::setOriginAxisLength( float originAxisLength )
+{
+ leOriginAxisLength->setValue( originAxisLength );
+}
+
+
+void ControlPanel::initFlexes()
+{
+ CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
+ LocalFlexController_t i;
+ int j;
+
+ if (hdr)
+ {
+ for (j = 0; j < NUM_FLEX_SLIDERS; j++)
+ {
+ cFlex[j]->removeAll();
+ for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ cFlex[j]->add( hdr->pFlexcontroller(i)->pszName() );
+ }
+ if ( false ) // TODO: Add a configuration option to do it the sensible way
+ {
+ cFlex[j]->select( j );
+ }
+ else
+ {
+ cFlex[j]->select( hdr->numflexcontrollers() - NUM_FLEX_SLIDERS + j );
+ }
+ }
+ }
+
+ for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ g_pStudioModel->SetFlexController( i, 0.0f );
+ hdr->pFlexcontroller( i )->localToGlobal = i;
+ }
+
+ for (j = 0; j < NUM_FLEX_SLIDERS; j++)
+ {
+ i = (LocalFlexController_t)cFlex[j]->getSelectedIndex();
+
+ if (i >= 0)
+ {
+ slFlexScale[j]->setValue( g_pStudioModel->GetFlexControllerRaw( i ) );
+ }
+ }
+}
+
+void ControlPanel::connectFlexes( CStudioHdr *hdr )
+{
+ if ( !g_pStudioModel )
+ return;
+
+ LocalFlexController_t i;
+ LocalFlexController_t j;
+
+ CStudioHdr *root = g_pStudioModel->GetStudioHdr();
+
+ if (hdr && root)
+ {
+ for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
+ {
+ for ( j = LocalFlexController_t(0); j < root->numflexcontrollers(); j++)
+ {
+ if ( stricmp( hdr->pFlexcontroller(i)->pszName(), root->pFlexcontroller(j)->pszName() ) == 0 )
+ {
+ hdr->pFlexcontroller(i)->localToGlobal = root->pFlexcontroller(j)->localToGlobal;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+static void UpdateSliderLabel( mxSlider *slider, mxLabel *label )
+{
+ float value = slider->getValue();
+ char buf[80];
+ sprintf( buf, "%0.2f", value );
+ label->setLabel( buf );
+}
+
+void ControlPanel::UpdateConstraintSliders( int clamp )
+{
+ float vmin = slPhysicsConMin->getValue();
+ float vmax = slPhysicsConMax->getValue();
+
+ // reflect mins/maxs
+ if ( cbLinked->isChecked() )
+ {
+ if ( clamp == IDC_PHYS_CON_MIN && vmin <= 0 )
+ {
+ vmax = -vmin;
+ }
+ else if ( vmax >= 0 )
+ {
+ vmin = -vmax;
+ }
+ }
+
+ if ( vmax < vmin )
+ {
+ if ( clamp == IDC_PHYS_CON_MIN )
+ vmin = vmax;
+ else
+ vmax = vmin;
+ }
+
+ slPhysicsConMin->setValue( vmin );
+ slPhysicsConMax->setValue( vmax );
+ UpdateSliderLabel( slPhysicsConMin, lPhysicsConMin );
+ UpdateSliderLabel( slPhysicsConMax, lPhysicsConMax );
+ UpdateSliderLabel( slPhysicsFriction, lPhysicsFriction );
+}
+
+
+int ControlPanel::handlePhysicsEvent( mxEvent *event )
+{
+ switch( event->action )
+ {
+ case IDC_PHYS_BONE:
+ setupPhysicsBone( cPhysicsBone->getSelectedIndex() );
+ break;
+ case IDC_PHYS_CON_AXIS_X:
+ case IDC_PHYS_CON_AXIS_Y:
+ case IDC_PHYS_CON_AXIS_Z:
+ setupPhysicsAxis( cPhysicsBone->getSelectedIndex(), event->action - IDC_PHYS_CON_AXIS_X );
+ break;
+ case IDC_PHYS_CON_TYPE_FREE:
+ case IDC_PHYS_CON_TYPE_FIXED:
+ case IDC_PHYS_CON_TYPE_LIMIT:
+ break;
+ case IDC_PHYS_CON_MIN:
+ case IDC_PHYS_CON_MAX:
+ case IDC_PHYS_CON_FRICTION:
+ UpdateConstraintSliders( event->action );
+ break;
+ case IDC_PHYS_CON_TEST:
+ g_pStudioModel->Physics_SetPreview( cPhysicsBone->getSelectedIndex(), getPhysicsAxis(), slPhysicsConTest->getValue() );
+ break;
+ case IDC_PHYS_P_MASSBIAS:
+ UpdateSliderLabel( slPhysicsParamMassBias, lPhysicsParamMassBias );
+ break;
+ case IDC_PHYS_P_INERTIA:
+ UpdateSliderLabel( slPhysicsParamInertia, lPhysicsParamInertia );
+ break;
+ case IDC_PHYS_P_DAMPING:
+ UpdateSliderLabel( slPhysicsParamDamping, lPhysicsParamDamping );
+ break;
+ case IDC_PHYS_P_ROT_DAMPING:
+ UpdateSliderLabel( slPhysicsParamRotDamping, lPhysicsParamRotDamping );
+ break;
+ case IDC_PHYS_QCFILE:
+ {
+ writePhysicsData();
+ char *pOut = g_pStudioModel->Physics_DumpQC();
+ if ( pOut )
+ {
+ Sys_CopyStringToClipboard( pOut );
+ }
+ delete[] pOut;
+ return 1;
+ }
+ break;
+
+ }
+ writePhysicsData();
+ return 1;
+}
+
+
+void ControlPanel::handlePhysicsKey( mxEvent *event )
+{
+ if ( event->key == '[' || event->key == ']' )
+ {
+ int boneIndex = cPhysicsBone->getSelectedIndex();
+ int boneCount = cPhysicsBone->getItemCount();
+ int axisIndex = getPhysicsAxis();
+ int axisCount = 3;
+
+ if ( event->key == '[' )
+ {
+ axisIndex = (axisIndex+axisCount-1) % axisCount;
+ if ( axisIndex == (axisCount-1) )
+ {
+ boneIndex = (boneIndex+boneCount-1) % boneCount;
+ }
+ }
+ else
+ {
+ axisIndex = (axisIndex+1) % axisCount;
+ if ( axisIndex == 0 )
+ {
+ boneIndex = (boneIndex+1) % boneCount;
+ }
+ }
+ setPhysicsAxis( axisIndex );
+ cPhysicsBone->select( boneIndex );
+ setupPhysicsBone( boneIndex );
+ }
+}
+
+
+void ControlPanel::setupPhysics( void )
+{
+ if (!PopulatePhysicsBoneList( cPhysicsBone) )
+ return;
+
+ cPhysicsBone->select (0);
+ setPhysicsAxis(0);
+ setupPhysicsBone( 0 );
+
+ char buf[64];
+ sprintf( buf, "%.2f", g_pStudioModel->Physics_GetMass() );
+ leMass->setLabel( buf );
+
+ // Default to "None"
+ setHighlightBone(0);
+}
+
+static void SetSlider( mxSlider *slider, mxLabel *label, float value )
+{
+ slider->setValue( value );
+ UpdateSliderLabel( slider, label );
+}
+
+int ControlPanel::getPhysicsAxis( void )
+{
+ for ( int i = 0; i < 3; i++ )
+ if ( rbConstraintAxis[i]->isChecked() )
+ return i;
+
+ return 0;
+}
+
+
+void ControlPanel::setPhysicsAxis( int axisIndex )
+{
+ for ( int i = 0; i < 3; i++ )
+ {
+ rbConstraintAxis[i]->setChecked( (i==axisIndex)?true : false );
+ }
+}
+
+
+void ControlPanel::setupPhysicsBone( int boneIndex )
+{
+ if (!g_pStudioModel->m_pPhysics)
+ return;
+
+ int axisIndex = getPhysicsAxis();
+ setupPhysicsAxis( boneIndex, axisIndex );
+ // read per-bone data
+ hlmvsolid_t solid;
+ g_pStudioModel->Physics_GetData( boneIndex, &solid, NULL );
+
+ SetSlider( slPhysicsParamMassBias, lPhysicsParamMassBias, solid.massBias );
+ SetSlider( slPhysicsParamInertia, lPhysicsParamInertia, solid.params.inertia );
+ SetSlider( slPhysicsParamDamping, lPhysicsParamDamping, solid.params.damping );
+ SetSlider( slPhysicsParamRotDamping, lPhysicsParamRotDamping, solid.params.rotdamping );
+
+ // Find the bone
+ CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
+ for ( int i = 0; i < pHdr->numbones(); i++ )
+ {
+ mstudiobone_t* pBone = pHdr->pBone(i);
+ if (!stricmp(pBone->pszName(), solid.name ))
+ {
+ // Once found, set the surface property accordingly
+ lPhysicsMaterial->setLabel( g_pStudioModel->m_SurfaceProps[i].String() );
+ break;
+ }
+ }
+
+ // select the render/highlight bone
+ setHighlightBone( boneIndex + 1 );
+
+ redraw();
+}
+
+
+void ControlPanel::setupPhysicsAxis( int boneIndex, int axis )
+{
+ // read the per-axis data
+ constraint_ragdollparams_t constraint;
+
+ g_pStudioModel->Physics_GetData( boneIndex, NULL, &constraint );
+ setPhysicsAxis( axis );
+ SetSlider( slPhysicsConMin, lPhysicsConMin, constraint.axes[axis].minRotation );
+ SetSlider( slPhysicsConMax, lPhysicsConMax, constraint.axes[axis].maxRotation );
+ SetSlider( slPhysicsFriction, lPhysicsFriction, constraint.axes[axis].torque );
+ g_pStudioModel->Physics_SetPreview( -1, 0, 0 );
+ redraw();
+}
+
+void ControlPanel::writePhysicsData( void )
+{
+ int boneIndex = cPhysicsBone->getSelectedIndex();
+ int axis = getPhysicsAxis();
+
+ hlmvsolid_t solid;
+ constraint_ragdollparams_t constraint;
+ // read the existing data
+ g_pStudioModel->Physics_GetData( boneIndex, &solid, &constraint );
+
+ const char *pMass = leMass->getLabel();
+ float mass = 0;
+ if ( pMass )
+ {
+ mass = atof( pMass );
+ }
+
+ g_pStudioModel->Physics_SetMass( mass );
+
+ // write back the data we're editing on this dialog
+ constraint.axes[axis].minRotation = slPhysicsConMin->getValue();
+ constraint.axes[axis].maxRotation = slPhysicsConMax->getValue();
+ constraint.axes[axis].torque = slPhysicsFriction->getValue();
+
+ solid.massBias = slPhysicsParamMassBias->getValue();
+ solid.index = boneIndex;
+ //solid.params.mass;
+ solid.params.inertia = slPhysicsParamInertia->getValue();
+ solid.params.damping = slPhysicsParamDamping->getValue();
+ solid.params.rotdamping = slPhysicsParamRotDamping->getValue();
+
+ // store it in the model
+ g_pStudioModel->Physics_SetData( boneIndex, &solid, &constraint );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void ControlPanel::SetFrameSlider( float flFrame )
+{
+ slForceFrame->setValue( flFrame );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void ControlPanel::UnloadAllMergedModels()
+{
+ for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; ++i )
+ {
+ g_MDLViewer->getMenuBar()->modify( IDC_FILE_UNLOADMERGEDMODEL1 + i, IDC_FILE_UNLOADMERGEDMODEL1 + i, "(empty)" );
+ g_MDLViewer->getMenuBar()->setEnabled( IDC_FILE_UNLOADMERGEDMODEL1 + i, false );
+ V_strcpy_safe( g_viewerSettings.mergeModelFile[i], "" );
+
+ if ( g_pStudioExtraModel[i] )
+ {
+ g_pStudioExtraModel[i]->FreeModel( false );
+ delete g_pStudioExtraModel[i];
+ g_pStudioExtraModel[i] = NULL;
+ }
+ }
+} \ No newline at end of file