|
|
//======== Copyright � 1996-2009, Valve, L.L.C., All rights reserved. ========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// $Header: $
// $NoKeywords: $
//
// Purpose:
//
//=============================================================================
// Valve includes
#include "datamodel/dmelement.h"
#include "datamodel/idatamodel.h"
#include "dmxeditlib/dmxedit.h"
#include "mdlobjects/dmeeyeball.h"
#include "mdlobjects/dmeeyelid.h"
#include "mdlobjects/dmemouth.h"
#include "movieobjects/dmobjserializer.h"
#include "movieobjects/dmemakefile.h"
#include "movieobjects/dmemodel.h"
#include "movieobjects/dmeflexrules.h"
#include "tier1/utlstack.h"
#include "dmeutils/dmmeshutils.h"
#include "meshutils/mesh.h"
#include <time.h>
#ifndef __func__
# ifdef __FUNCTION__
# define __func__ __FUNCTION__
# else
# define __func__ DmxEdit
# endif
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CDmxEdit : public CBaseAppSystem< IDmxEdit > { typedef CBaseAppSystem< IDmxEdit > BaseClass;
public:
CDmxEdit() : m_nDistanceType( CDmeMesh::DIST_ABSOLUTE ) , m_pDmeMakefile( NULL ) { }
CDmeMakefile *GetMakefile() { if ( !m_pDmeMakefile ) { m_pDmeMakefile = CreateElement< CDmeMakefile >( "python dmxedit", DMFILEID_INVALID ); }
if ( !m_pDmeMakefile ) return NULL;
return m_pDmeMakefile; }
CDmeSource *AddSource( const char *pszSource, bool bDmx ) { CDmeMakefile *pDmeMakefile = GetMakefile(); if ( !pDmeMakefile ) return NULL;
CDmeSource *pDmeSource = pDmeMakefile->AddSource< CDmeSource >( pszSource ); if ( pDmeSource ) { if ( bDmx ) { pDmeSource->SetValue( "LoadDmx", true ); } else { pDmeSource->SetValue( "LoadObj", true ); } }
return pDmeSource; }
virtual DmxEditErrorState_t GetErrorState() const { return m_nErrorState; }
virtual void ResetErrorState() { m_nErrorState = DMXEDIT_OK; m_sErrorString.Set( "" ); }
virtual const char *GetErrorString() const { return m_nErrorState == DMXEDIT_OK ? NULL : m_sErrorString.Get(); }
int SetErrorString( DmxEditErrorState_t nErrorState, const char *pszErrorString, ... ) { va_list marker; va_start( marker, pszErrorString ); const int nRetVal = IntSetErrorString( nErrorState, pszErrorString, marker ); va_end( marker ); return nRetVal; }
//-----------------------------------------------------------------------------
// This is a bit of a hack but CDmxEdit is already a friend of CDmeMesh...
//-----------------------------------------------------------------------------
static bool RemoveBaseState( CDmeMesh *pDmeMesh, CDmeVertexData *pDmeVertexData ) { return pDmeMesh->RemoveBaseState( pDmeVertexData ); }
//-----------------------------------------------------------------------------
// This is a bit of a hack but CDmxEdit is already a friend of CDmeMesh...
//-----------------------------------------------------------------------------
static CDmeVertexData *FindOrAddBaseState( CDmeMesh *pDmeMesh, CDmeVertexData *pDmeVertexData ) { return pDmeMesh->FindOrAddBaseState( pDmeVertexData ); }
void SetDistanceType( CDmeMesh::Distance_t nDistanceType ) { m_nDistanceType = nDistanceType; }
CDmeMesh::Distance_t GetDistanceType() const { return m_nDistanceType; }
protected: DmxEditErrorState_t m_nErrorState; CUtlString m_sErrorString;
int IntSetErrorString( DmxEditErrorState_t nErrorState, const char *pszErrorString, va_list vaList ) { m_nErrorState = nErrorState;
char tmpBuf[ BUFSIZ ] = "dmxedit."; enum { kOffset = 8 };
#ifdef _WIN32
int len = _vsnprintf( tmpBuf + kOffset, sizeof( tmpBuf ) - 1 - kOffset, pszErrorString, vaList ); #elif POSIX
int len = vsnprintf( tmpBuf + kOffset, sizeof( tmpBuf ) - 1 - kOffset, pszErrorString, vaList ); #else
#error "define vsnprintf type."
#endif
// Len < 0 represents an overflow
if( len < 0 ) { len = sizeof( tmpBuf ) - 1; tmpBuf[sizeof( tmpBuf ) - 1] = 0; }
m_sErrorString.Set( tmpBuf );
return len; }
CDmeMesh::Distance_t m_nDistanceType;
CDmeMakefile *m_pDmeMakefile; };
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static CDmxEdit g_DmxEdit; CDmxEdit *g_pDmxEditImpl = &g_DmxEdit; IDmxEdit *g_pDmxEdit = &g_DmxEdit;
//-----------------------------------------------------------------------------
// Macros for error
//-----------------------------------------------------------------------------
#define DMXEDIT_ERROR( ... ) \
g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ );
#define DMXEDIT_ERROR_RETURN_NULL( ... ) \
{ \ g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ ); \ return NULL; \ }
#define DMXEDIT_ERROR_RETURN_FALSE( ... ) \
{ \ g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ ); \ return NULL; \ }
#define DMXEDIT_ERROR_RETURN_EMPTY_STRING( ... ) \
{ \ g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ ); \ return ""; \ }
#define DMXEDIT_WARNING( ... ) \
g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ );
#define DMXEDIT_WARNING_RETURN_NULL( ... ) \
{ \ g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ ); \ return NULL; \ }
#define DMXEDIT_WARNING_RETURN_FALSE( ... ) \
{ \ g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ ); \ return NULL; \ }
#define DMXEDIT_WARNING_RETURN_EMPTY_STRING( ... ) \
{ \ g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ ); \ return ""; \ }
#define DMXEDIT_MESH_ERROR_RETURN_NULL( pDmeMesh ) \
{ \ if ( !pDmeMesh ) \ { \ g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": No mesh specified" __VA_ARGS__ ); \ return NULL; \ } \ }
#define DMXEDIT_MESH_ERROR_RETURN_FALSE( pDmeMesh ) \
{ \ if ( !pDmeMesh ) \ { \ g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": No mesh specified" __VA_ARGS__ ); \ return false; \ } \ }
#define DMXEDIT_MESH_ERROR_RETURN_EMPTY_STRING( pDmeMesh ) \
{ \ if ( !pDmeMesh ) \ { \ g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": No mesh specified" __VA_ARGS__ ); \ return ""; \ } \ }
#define DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh ) \
{ \ if ( !pDmeMesh ) \ { \ g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": No mesh specified" __VA_ARGS__ ); \ return NULL; \ } \ }
#define DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh ) \
{ \ if ( !pDmeMesh ) \ { \ g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": No mesh specified" __VA_ARGS__ ); \ return false; \ } \ }
#define DMXEDIT_MESH_WARNING_RETURN_EMPTY_STRING( pDmeMesh ) \
{ \ if ( !pDmeMesh ) \ { \ g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": No mesh specified" __VA_ARGS__ ); \ return false; \ } \ }
//-----------------------------------------------------------------------------
// Checks whether the specified mesh & base state are valid and the base
// state actually belongs to the mesh
//-----------------------------------------------------------------------------
bool BaseStateSanityCheck( CDmeMesh *pDmeMesh, CDmeVertexData *pDmeBaseState, const char *pszFuncName ) { if ( !pDmeMesh ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No mesh specified", pszFuncName ); return false; }
if ( !pDmeBaseState ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No base state specified", pszFuncName ); return false; }
CDmeVertexData *pDmeBaseStateCheck = pDmeMesh->FindBaseState( pDmeBaseState->GetName() ); if ( !pDmeBaseStateCheck || pDmeBaseState != pDmeBaseStateCheck ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Base state \"%s\" doesn't belong to mesh \"%s\"", pszFuncName, pDmeBaseState->GetName(), pDmeMesh->GetName() ); return false; }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static const char s_szEditBaseStateName[] = "__dmxedit_edit"; static const char s_szEditOldCurrentState[] = "__dmxedit_oldCurrentState";
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CleanupMeshEditBaseState( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState(); if ( !BaseStateSanityCheck( pDmeMesh, pDmeBindBaseState, __func__ ) ) return false;
if ( !Q_strcmp( pDmeBindBaseState->GetName(), s_szEditOldCurrentState ) ) return false;
// Remove edit base state and restore current base state
if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) ) { CDmeVertexData *pDmeOldCurrentBaseState = pDmeMesh->GetValueElement< CDmeVertexData >( s_szEditOldCurrentState ); if ( pDmeOldCurrentBaseState ) { pDmeMesh->SetCurrentBaseState( pDmeOldCurrentBaseState->GetName() ); } pDmeMesh->RemoveAttribute( s_szEditOldCurrentState ); } else { pDmeMesh->SetCurrentBaseState( pDmeBindBaseState->GetName() ); }
pDmeMesh->DeleteBaseState( s_szEditBaseStateName );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeVertexData *FindMeshEditBaseState( CDmeMesh *pDmeMesh, const char *pszFuncName ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeVertexData *pDmeEditBaseState = pDmeMesh->FindBaseState( s_szEditBaseStateName );
if ( pDmeEditBaseState && BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, pszFuncName ) ) return pDmeEditBaseState;
return NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeVertexData *FindOrCreateMeshEditBaseState( CDmeMesh *pDmeMesh, const char *pszFuncName ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeVertexData *pDmeEditBaseState = pDmeMesh->FindBaseState( s_szEditBaseStateName ); if ( pDmeEditBaseState ) { if ( BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, pszFuncName ) ) return pDmeEditBaseState;
return NULL; }
CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState(); if ( !pDmeBindBaseState ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No bind base state found on mesh \"%s\"", pszFuncName, pDmeMesh->GetName() ); return NULL; }
pDmeEditBaseState = pDmeMesh->FindOrCreateBaseState( s_szEditBaseStateName ); if ( !pDmeEditBaseState ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Couldn't create edit base state on mesh \"%s\"", pszFuncName, pDmeMesh->GetName() ); return NULL; }
pDmeBindBaseState->CopyTo( pDmeEditBaseState ); pDmeEditBaseState->SetFileId( DMFILEID_INVALID, TD_ALL );
// Save the current base state so we can restore it on save
CDmAttribute *pDmeOldCurrentStateAttr = NULL;
if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) ) { pDmeOldCurrentStateAttr = pDmeMesh->GetAttribute( s_szEditOldCurrentState ); if ( !pDmeOldCurrentStateAttr ) { Msg( "WARNING %s: Attribute %s.%s is of type %s, not AT_ELEMENT, removing", pszFuncName, pDmeMesh->GetName(), pDmeOldCurrentStateAttr->GetName(), pDmeOldCurrentStateAttr->GetTypeString() ); pDmeMesh->RemoveAttribute( s_szEditOldCurrentState ); pDmeOldCurrentStateAttr = NULL; } }
if ( pDmeOldCurrentStateAttr == NULL ) { pDmeOldCurrentStateAttr = pDmeMesh->AddAttributeElement< CDmeVertexData >( s_szEditOldCurrentState ); if ( !pDmeOldCurrentStateAttr ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Couldn't create %s.%s attribute", pszFuncName, pDmeMesh->GetName(), s_szEditOldCurrentState ); return NULL; }
pDmeOldCurrentStateAttr->AddFlag( FATTRIB_DONTSAVE ); }
pDmeOldCurrentStateAttr->SetValue< CDmeVertexData >( pDmeMesh->GetCurrentBaseState() );
pDmeMesh->SetCurrentBaseState( pDmeEditBaseState->GetName() );
CDmeVertexData *pDmeBaseState = pDmeMesh->GetCurrentBaseState();
if ( BaseStateSanityCheck( pDmeMesh, pDmeBaseState, pszFuncName ) ) return pDmeBaseState;
return NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmElement *LoadDmx( const char *pszFilename ) { CDmElement *pRoot = NULL;
if ( !Q_stricmp( "dmx", Q_GetFileExtension( pszFilename ) ) ) { g_pDmxEditImpl->AddSource( pszFilename, true ); g_pDataModel->RestoreFromFile( pszFilename, NULL, NULL, &pRoot, CR_COPY_NEW ); if ( !pRoot ) DMXEDIT_ERROR_RETURN_NULL( "DMX Load Fail: \"%s\"", pszFilename ); } else DMXEDIT_ERROR_RETURN_NULL( "File without .dmx extension passed to LoadDmx: \"%s\"", pszFilename );
return pRoot; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmElement *LoadObj( const char *pszFilename, const char *pszLoadType /* = "ABSOLUTE" */ ) { CDmElement *pRoot = NULL;
if ( !Q_stricmp( "obj", Q_GetFileExtension( pszFilename ) ) ) { g_pDmxEditImpl->AddSource( pszFilename, false ); // Load OBJs
bool bAbsoluteObjs = true; if ( pszLoadType ) { if ( !Q_stricmp( "absolute", pszLoadType ) ) { bAbsoluteObjs = true; } else if ( !Q_stricmp( "relative", pszLoadType ) ) { bAbsoluteObjs = false; } else DMXEDIT_ERROR_RETURN_NULL( "Invalid OBJ loadType specified (%s), must be \"ABSOLUTE\" or \"RELATIVE\"", pszLoadType ); }
pRoot = CDmObjSerializer().ReadOBJ( pszFilename, NULL, true, bAbsoluteObjs ); if ( !pRoot ) DMXEDIT_ERROR_RETURN_NULL( "OBJ Load Fail: \"%s\"", pszFilename ); } else DMXEDIT_ERROR_RETURN_NULL( "File without .obj extension passed to LoadObj: \"%s\"", pszFilename );
return pRoot; }
//-----------------------------------------------------------------------------
// Not really pushing and popping as it's not implemented as a stack
// only one level or push allowed. Could be a DM_ELEMENT_ARRAY if needed
// to support arbitrary nesting if required but currently only called
// by Save
//-----------------------------------------------------------------------------
void PushPopEditState( CDmeMesh *pDmeMesh, bool bPush ) { if ( !pDmeMesh ) return;
const char szPushEdit[] = "__dmxedit_pushEditBase"; const char szPushCurr[] = "__dmxedit_pushCurrBase";
if ( bPush ) { CDmeVertexData *pDmeEditBaseState = FindMeshEditBaseState( pDmeMesh, __func__ ); if ( !pDmeEditBaseState || pDmeMesh->BaseStateCount() <= 1 ) return;
pDmeMesh->SetValue( szPushEdit, pDmeEditBaseState ); pDmeMesh->GetAttribute( szPushEdit )->AddFlag( FATTRIB_DONTSAVE );
CDmeVertexData *pDmeCurrentBaseState = pDmeMesh->GetCurrentBaseState(); if ( pDmeCurrentBaseState == pDmeEditBaseState ) { pDmeMesh->SetValue( szPushCurr, pDmeCurrentBaseState ); pDmeMesh->GetAttribute( szPushCurr )->AddFlag( FATTRIB_DONTSAVE ); }
CDmxEdit::RemoveBaseState( pDmeMesh, pDmeEditBaseState );
if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) ) { CDmeVertexData *pDmeOldCurrentVertexData = pDmeMesh->GetValueElement< CDmeVertexData >( s_szEditOldCurrentState ); if ( pDmeOldCurrentVertexData ) { pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() ); } else { pDmeOldCurrentVertexData = pDmeMesh->GetBindBaseState(); if ( pDmeOldCurrentVertexData ) { pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() ); } else { pDmeMesh->SetCurrentBaseState( pDmeMesh->GetBaseState( 0 )->GetName() ); } } } } else { if ( pDmeMesh->HasAttribute( szPushEdit ) ) { CDmxEdit::FindOrAddBaseState( pDmeMesh, pDmeMesh->GetValueElement< CDmeVertexData >( szPushEdit ) ); pDmeMesh->RemoveAttribute( szPushEdit ); }
if ( pDmeMesh->HasAttribute( szPushCurr ) ) { pDmeMesh->SetCurrentBaseState( pDmeMesh->GetValueElement< CDmeVertexData >( szPushCurr )->GetName() ); pDmeMesh->RemoveAttribute( szPushCurr ); } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void PushPopEditStates( CDmElement *pDmRoot, bool bPush ) { if ( !pDmRoot ) return;
CDmeDag *pDmeDag = CastElement< CDmeDag >( pDmRoot ); if ( !pDmeDag ) { pDmeDag = pDmRoot->GetValueElement< CDmeDag >( "model" ); }
if ( !pDmeDag ) return;
CUtlStack< CDmeDag * > traverseStack; traverseStack.Push( pDmeDag );
while ( traverseStack.Count() ) { traverseStack.Pop( pDmeDag ); if ( !pDmeDag ) continue;
for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { traverseStack.Push( pDmeDag->GetChild( i ) ); }
CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() ); if ( !pDmeMesh ) continue;
PushPopEditState( pDmeMesh, bPush ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CleanupDmxEdit( CDmeMesh *pDmeMesh ) { if ( !pDmeMesh ) return;
const char szPushEdit[] = "__dmxedit_pushEditBase"; const char szPushCurr[] = "__dmxedit_pushCurrBase";
CDmeVertexData *pDmeEditBaseState = FindMeshEditBaseState( pDmeMesh, __func__ ); if ( !pDmeEditBaseState || pDmeMesh->BaseStateCount() <= 1 ) return;
pDmeMesh->SetValue( szPushEdit, pDmeEditBaseState ); pDmeMesh->GetAttribute( szPushEdit )->AddFlag( FATTRIB_DONTSAVE );
CDmeVertexData *pDmeCurrentBaseState = pDmeMesh->GetCurrentBaseState(); if ( pDmeCurrentBaseState == pDmeEditBaseState ) { pDmeMesh->SetValue( szPushCurr, pDmeCurrentBaseState ); pDmeMesh->GetAttribute( szPushCurr )->AddFlag( FATTRIB_DONTSAVE ); }
CDmxEdit::RemoveBaseState( pDmeMesh, pDmeEditBaseState );
if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) ) { CDmeVertexData *pDmeOldCurrentVertexData = pDmeMesh->GetValueElement< CDmeVertexData >( s_szEditOldCurrentState ); if ( pDmeOldCurrentVertexData ) { pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() ); } else { pDmeOldCurrentVertexData = pDmeMesh->GetBindBaseState(); if ( pDmeOldCurrentVertexData ) { pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() ); } else { pDmeMesh->SetCurrentBaseState( pDmeMesh->GetBaseState( 0 )->GetName() ); } } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void UpdateMakefile( CDmElement *pDmeRoot ) { if ( !pDmeRoot ) return;
CDmeMakefile *pDmeMakefile = g_pDmxEditImpl->GetMakefile(); if ( !pDmeMakefile ) return;
pDmeRoot->SetValue( "makefile", pDmeMakefile ); pDmeMakefile->SetFileId( pDmeRoot->GetFileId(), TD_ALL ); }
//-----------------------------------------------------------------------------
// In winstuff.cpp
//-----------------------------------------------------------------------------
void MyGetUserName( char *pszBuf, unsigned long *pBufSiz ); void MyGetComputerName( char *pszBuf, unsigned long *pBufSiz );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void AddExportTags( CDmElement *pDmeRoot, const char *pszFilename ) { if ( !pDmeRoot ) return;
CDmElement *pExportTags = CreateElement< CDmElement >( "python_dmxedit_exportTags", pDmeRoot->GetFileId() );
char szTmpBuf[ BUFSIZ ];
_strdate( szTmpBuf ); pExportTags->SetValue( "date", szTmpBuf );
_strtime( szTmpBuf ); pExportTags->SetValue( "time", szTmpBuf );
unsigned long dwSize( sizeof( szTmpBuf ) );
*szTmpBuf ='\0'; MyGetUserName( szTmpBuf, &dwSize); pExportTags->SetValue( "user", szTmpBuf );
*szTmpBuf ='\0'; dwSize = sizeof( szTmpBuf ); MyGetComputerName( szTmpBuf, &dwSize); pExportTags->SetValue( "machine", szTmpBuf );
pExportTags->SetValue( "app", "python" ); pExportTags->SetValue( "cmdLine", "python <wuzza>" );
CDmAttribute *pDmeLoadDmxAttr = pExportTags->AddAttribute( "LoadDmx", AT_STRING_ARRAY ); CDmAttribute *pDmeLoadObjAttr = pExportTags->AddAttribute( "LoadObj", AT_STRING_ARRAY ); CDmeMakefile *pDmeMakefile = g_pDmxEditImpl->GetMakefile(); if ( pDmeMakefile ) { const int nSourceCount = pDmeMakefile->GetSourceCount(); for ( int i = 0; i < nSourceCount; ++i ) { CDmeSource *pDmeSource = pDmeMakefile->GetSource( i ); if ( pDmeSource->HasAttribute( "LoadDmx" ) ) { CDmrStringArray( pDmeLoadDmxAttr ).AddToTail( pDmeSource->GetName() ); } else { CDmrStringArray( pDmeLoadObjAttr ).AddToTail( pDmeSource->GetName() ); } } } pExportTags->SetValue( "Save", pszFilename );
pDmeRoot->SetValue( "python_dmxedit_exportTags", pExportTags ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void RemoveExportTags( CDmElement *pRoot, const char *pExportTagsName ) { if ( !pRoot ) return;
pRoot->RemoveAttribute( pExportTagsName ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SaveDmx( CDmElement *pDmeRoot, const char *pszFilename ) { if ( !pszFilename ) DMXEDIT_WARNING_RETURN_FALSE( "No filename specified" );
if ( !pDmeRoot ) DMXEDIT_WARNING_RETURN_FALSE( "No root DmElement specified" );
RemoveExportTags( pDmeRoot, "vsDmxIO_exportTags" ); AddExportTags( pDmeRoot, pszFilename ); UpdateMakefile( pDmeRoot );
PushPopEditStates( pDmeRoot, true ); // push - hide them on save
bool bRetVal = false;
if ( !Q_stricmp( "dmx", Q_GetFileExtension( pszFilename ) ) ) { bRetVal = g_pDataModel->SaveToFile( pszFilename, NULL, "keyvalues2", "model", pDmeRoot ); if ( !bRetVal ) { DMXEDIT_WARNING( "Couldn't write dmx file \"%s\"", pszFilename ); } } else { DMXEDIT_WARNING( "Filename without .dmx extension passed to SaveDmx( \"%s\" )", pszFilename ); }
PushPopEditStates( pDmeRoot, false ); // pop
return bRetVal; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SaveObj( CDmElement *pDmeRoot, const char *pszFilename, const char *pszObjSaveType /* = "ABSOLUTE" */, const char *pszDeltaName /* = NULL */ ) { if ( !pszFilename ) DMXEDIT_WARNING_RETURN_FALSE( "No filename specified" );
if ( !pDmeRoot ) DMXEDIT_WARNING_RETURN_FALSE( "No root DmElement specified" );
PushPopEditStates( pDmeRoot, true ); // push - hide them on save
bool bRetVal = false;
if ( !Q_stricmp( "obj", Q_GetFileExtension( pszFilename ) ) ) { bool bAbsoluteObjs = true; if ( pszObjSaveType ) { if ( !Q_stricmp( "absolute", pszObjSaveType ) ) { bAbsoluteObjs = true; } else if ( !Q_stricmp( "relative", pszObjSaveType ) ) { bAbsoluteObjs = false; } else { DMXEDIT_ERROR( "Invalid OBJ Save specified (%s), must be \"ABSOLUTE\" or \"RELATIVE\"", pszObjSaveType ); } }
if ( pszDeltaName ) { if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) ) { bRetVal = CDmObjSerializer().WriteOBJ( pszFilename, pDmeRoot, false, NULL, bAbsoluteObjs ); } else { bRetVal = CDmObjSerializer().WriteOBJ( pszFilename, pDmeRoot, true, pszDeltaName, bAbsoluteObjs ); } } else { bRetVal = CDmObjSerializer().WriteOBJ( pszFilename, pDmeRoot, true, NULL, bAbsoluteObjs ); } } else { DMXEDIT_WARNING( "Filename without .obj extension passed to SaveDmx( \"%s\" )", pszFilename ); }
PushPopEditStates( pDmeRoot, false ); // pop
return bRetVal; }
//-----------------------------------------------------------------------------
// The internal version of FindMesh
//-----------------------------------------------------------------------------
CDmeMesh *FindMesh( CDmElement *pRoot, const char *pszMeshSearchName, bool bComboOnly ) { if ( !pRoot ) return NULL;
CDmeDag *pDmeDag = CastElement< CDmeDag >( pRoot ); if ( !pDmeDag ) { pDmeDag = pRoot->GetValueElement< CDmeDag >( "model" ); }
if ( !pDmeDag ) DMXEDIT_WARNING_RETURN_NULL( "Invalid DmElement passed, DmeDag or element with \"model\" attribute required" );
CUtlStack< CDmeDag * > traverseStack; traverseStack.Push( pDmeDag );
while ( traverseStack.Count() ) { traverseStack.Pop( pDmeDag ); if ( !pDmeDag ) continue;
for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { traverseStack.Push( pDmeDag->GetChild( i ) ); }
CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() ); if ( !pDmeMesh ) continue;
// Looking for a named mesh? Return if found
if ( pszMeshSearchName && ( !Q_strcmp( pszMeshSearchName, pDmeDag->GetName() ) || !Q_strcmp( pszMeshSearchName, pDmeMesh->GetName() ) ) ) return pDmeMesh;
// Looking for a combo mesh? Return if found
if ( bComboOnly && pDmeMesh->DeltaStateCount() ) return pDmeMesh;
// Looking for a named or combo mesh, this wasn't it so keep looking
if ( bComboOnly || pszMeshSearchName ) continue;
// Looking for the first mesh? Ok!
return pDmeMesh; }
// No mesh found
return NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeMesh *GetFirstComboMesh( CDmElement *pRoot ) { CDmeMesh *pDmeMesh = FindMesh( pRoot, NULL, true ); if ( !pDmeMesh ) DMXEDIT_WARNING_RETURN_NULL( "No mesh with combinations found" );
return pDmeMesh; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeMesh *GetNamedMesh( CDmElement *pRoot, const char *pszMeshSearchName ) { CDmeMesh *pDmeMesh = FindMesh( pRoot, pszMeshSearchName, false ); if ( !pDmeMesh ) DMXEDIT_WARNING_RETURN_NULL( "No mesh named \"%s\" found", pszMeshSearchName );
return pDmeMesh; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeMesh *GetFirstMesh( CDmElement *pDmeRoot ) { CDmeMesh *pDmeMesh = FindMesh( pDmeRoot, NULL, false ); if ( !pDmeMesh ) DMXEDIT_WARNING_RETURN_NULL( "No mesh found" );
return pDmeMesh; }
//-----------------------------------------------------------------------------
// Do a depth first walk of all siblings of the dmeDag owning this mesh
//-----------------------------------------------------------------------------
CDmeMesh *GetNextMesh( CDmeMesh *pCurrentDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pCurrentDmeMesh );
CDmeDag *pDmeDag = FindReferringElement< CDmeDag >( pCurrentDmeMesh, "shape" ); if ( !pDmeDag ) DMXEDIT_WARNING_RETURN_NULL( "No dmeDag owning mesh \"%s\"", pCurrentDmeMesh->GetName() );
// Walk up to the root
CDmeDag *pDmeDagParent = NULL; for ( ;; ) { pDmeDagParent = FindReferringElement< CDmeDag >( pDmeDag, "children" ); if ( !pDmeDagParent ) break; pDmeDag = pDmeDagParent; }
CUtlStack< CDmeDag * > traverseStack; for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { traverseStack.Push( pDmeDag->GetChild( i ) ); }
bool bNext = false; while ( traverseStack.Count() ) { traverseStack.Pop( pDmeDag ); if ( !pDmeDag ) continue;
for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { traverseStack.Push( pDmeDag->GetChild( i ) ); }
CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() ); if ( !pDmeMesh ) continue;
if ( pDmeMesh == pCurrentDmeMesh ) { bNext = true; continue; }
if ( bNext ) return pDmeMesh; }
return NULL; }
//-----------------------------------------------------------------------------
// Prints a list of all of the deltas present in the specified mesh
//-----------------------------------------------------------------------------
bool ListDeltas( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
const int nDeltas = pDmeMesh->DeltaStateCount(); if ( nDeltas <= 0 ) DMXEDIT_WARNING_RETURN_FALSE( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
for ( int i( 0 ); i < nDeltas; ++i ) { Msg( "# Delta %d: %s\n", i, pDmeMesh->GetDeltaState( i )->GetName() ); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int DeltaCount( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
return pDmeMesh->DeltaStateCount(); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
const char *DeltaName( CDmeMesh *pDmeMesh, int nDeltaIndex ) { DMXEDIT_MESH_WARNING_RETURN_EMPTY_STRING( pDmeMesh );
const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
if ( nDeltaStateCount <= 0 ) DMXEDIT_WARNING_RETURN_EMPTY_STRING( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
if ( nDeltaIndex < 0 && nDeltaIndex >= nDeltaStateCount ) DMXEDIT_WARNING_RETURN_EMPTY_STRING( "Delta %n out of range, Mesh \"%s\" has %d deltas", nDeltaIndex, pDmeMesh->GetName(), nDeltaStateCount );
return pDmeMesh->GetDeltaState( nDeltaIndex )->GetName(); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeVertexDeltaData *GetDeltaState( CDmeMesh *pDmeMesh, int nDeltaIndex ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
if ( nDeltaStateCount <= 0 ) DMXEDIT_WARNING_RETURN_NULL( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
if ( nDeltaIndex < 0 && nDeltaIndex >= nDeltaStateCount ) DMXEDIT_WARNING_RETURN_NULL( "Delta %n out of range, Mesh \"%s\" has %d deltas", nDeltaIndex, pDmeMesh->GetName(), nDeltaStateCount );
return pDmeMesh->GetDeltaState( nDeltaIndex ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeVertexDeltaData *GetDeltaState( CDmeMesh *pDmeMesh, const char *pszDeltaName ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( pDmeDelta ) DMXEDIT_WARNING_RETURN_NULL( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
return pDmeDelta; }
//-----------------------------------------------------------------------------
// Checks whether the specified mesh & base state are valid and the base
// state actually belongs to the mesh
// TODO: verify base state is the same as bind state?
// TODO: Size checks?
//-----------------------------------------------------------------------------
bool DeltaStateSanityCheck( CDmeMesh *pDmeMesh, CDmeVertexDeltaData *pDmeDeltaState, const char *pszFuncName ) { if ( !pDmeMesh ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No mesh specified", pszFuncName ); return false; }
if ( !pDmeDeltaState ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Non-existent delta state specified", pszFuncName ); return false; }
CDmeVertexDeltaData *pDmeDeltaStateCheck = pDmeMesh->FindDeltaState( pDmeDeltaState->GetName() ); if ( !pDmeDeltaStateCheck || pDmeDeltaState != pDmeDeltaStateCheck ) { g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Delta state \"%s\" doesn't belong to mesh \"%s\"", pszFuncName, pDmeDeltaState->GetName(), pDmeMesh->GetName() ); return false; }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ResetState( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexData *pDmeEditBaseState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, __func__ ) ) return false;
return pDmeMesh->SetBaseStateToDelta( NULL, pDmeEditBaseState ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetState( CDmeMesh *pDmeMesh, const char *pszDeltaName ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexData *pDmeEditBaseState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !pDmeEditBaseState ) return false;
if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) ) return ResetState( pDmeMesh );
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !DeltaStateSanityCheck( pDmeMesh, pDmeDelta, __func__ ) ) return false; pDmeDelta->Resolve();
return pDmeMesh->SetBaseStateToDelta( pDmeDelta, pDmeEditBaseState ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool RemoveFacesWithMaterial( CDmeMesh *pDmeMesh, const char *pszMaterialName ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
return CDmMeshUtils::RemoveFacesWithMaterial( pDmeMesh, pszMaterialName ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool RemoveFacesWithMoreThanNVerts( CDmeMesh *pDmeMesh, int nVertexCount ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
return CDmMeshUtils::RemoveFacesWithMoreThanNVerts( pDmeMesh, nVertexCount ); }
//-----------------------------------------------------------------------------
// After an operation to the bind base state, copy the bind data around to all
// other base states...
//-----------------------------------------------------------------------------
void FixupBaseStates( CDmeMesh * pDmeMesh ) { CDmeVertexData *pBindState = pDmeMesh->GetBindBaseState(); if ( pBindState ) { const int nBaseStateCount = pDmeMesh->BaseStateCount(); for ( int i = 0; i < nBaseStateCount; ++i ) { CDmeVertexData *pBaseState = pDmeMesh->GetBaseState( i ); if ( pBindState != pBaseState ) { pBindState->CopyTo( pBaseState ); } } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Mirror( CDmeMesh *pDmeMesh, const char *pszAxis /* = "x" */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
if ( !pszAxis || !*pszAxis ) DMXEDIT_WARNING_RETURN_FALSE( "No axis specified" );
int nAxis = -1; switch ( *pszAxis ) { case 'x': case 'X': nAxis = 0; break; case 'y': case 'Y': nAxis = 1; break; case 'z': case 'Z': nAxis = 2; break; }
if ( nAxis < 0 ) DMXEDIT_WARNING_RETURN_FALSE( "Invalid axis \"%s\" specified, must be one of \"x\", \"y\" or \"z\"", pszAxis );
// Mirror operates on "bind" state
const bool bRetVal = CDmMeshUtils::Mirror( pDmeMesh, nAxis );
FixupBaseStates( pDmeMesh );
return bRetVal; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ComputeNormals( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
pDmeMesh->ComputeDeltaStateNormals();
return true; }
//-----------------------------------------------------------------------------
// Returns the CDmeCombinationOperator ultimately controlling the specified
// DmeMesh by searched backwards on elements referring to "targets"
// Returns NULL if not found
//-----------------------------------------------------------------------------
CDmeCombinationOperator *GetComboOpFromMesh( CDmeMesh *pDmeMesh ) { if ( !pDmeMesh ) return NULL;
CUtlRBTree< CDmElement * > visited( CDefOps< CDmElement * >::LessFunc ); visited.Insert( pDmeMesh );
const CUtlSymbolLarge sTargets = g_pDataModel->GetSymbol( "targets" ); const CUtlSymbolLarge sTarget = g_pDataModel->GetSymbol( "target" );
CDmElement *pDmThisElement = pDmeMesh; CDmElement *pDmNextElement = NULL;
while ( pDmThisElement ) { pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTargets ); if ( !pDmNextElement ) { pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTarget ); }
if ( !pDmNextElement ) break;
pDmThisElement = pDmNextElement;
if ( CastElement< CDmeCombinationOperator >( pDmThisElement ) ) return CastElement< CDmeCombinationOperator >( pDmThisElement );
if ( visited.IsValidIndex( visited.Find( pDmThisElement ) ) ) break;
visited.Insert( pDmThisElement ); }
return NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ComputeWrinkles( CDmeMesh *pDmeMesh, bool bOverwrite /* = false */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
pDmeCombo->GenerateWrinkleDeltas( bOverwrite );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ComputeNormalWrinkles( CDmeMesh *pDmeMesh, float flScale, bool bOverwrite /* = false */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
pDmeCombo->GenerateWrinkleDeltas( bOverwrite, true, flScale );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ComputeWrinkle( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flScale, const char *pszOperation /* = "replace" */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !pDmeDelta ) DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
CDmMeshUtils::WrinkleOp wrinkleOp = StringHasPrefix( pszOperation, "r" ) ? CDmMeshUtils::kReplace : CDmMeshUtils::kAdd;
const int nControlCount = pDmeCombo->GetControlCount(); for ( int nControlIndex = 0; nControlIndex < nControlCount; ++nControlIndex ) { const int nRawControlCount = pDmeCombo->GetRawControlCount( nControlIndex ); for ( int nRawControlIndex = 0; nRawControlIndex < nRawControlCount; ++nRawControlIndex ) { if ( Q_strcmp( pszDeltaName, pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ) ) ) continue;
pDmeCombo->SetWrinkleScale( nControlIndex, pszDeltaName, 1.0f );
break; } }
CDmeVertexData *pDmeBindState = pDmeMesh->GetBindBaseState(); CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
return CDmMeshUtils::CreateWrinkleDeltaFromBaseState( pDmeDelta, flScale, wrinkleOp, pDmeMesh, pDmeBindState, pDmeEditState ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ComputeNormalWrinkle( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flScale, const char *pszOperation /* = "replace" */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !pDmeDelta ) DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
CDmMeshUtils::WrinkleOp wrinkleOp = StringHasPrefix( pszOperation, "r" ) ? CDmMeshUtils::kReplace : CDmMeshUtils::kAdd;
const int nControlCount = pDmeCombo->GetControlCount(); for ( int nControlIndex = 0; nControlIndex < nControlCount; ++nControlIndex ) { const int nRawControlCount = pDmeCombo->GetRawControlCount( nControlIndex ); for ( int nRawControlIndex = 0; nRawControlIndex < nRawControlCount; ++nRawControlIndex ) { if ( Q_strcmp( pszDeltaName, pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ) ) ) continue;
pDmeCombo->SetWrinkleScale( nControlIndex, pszDeltaName, 1.0f );
break; } }
CDmeVertexData *pDmeBindState = pDmeMesh->GetBindBaseState(); CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
return CDmMeshUtils::CreateWrinkleDeltaFromBaseState( pDmeDelta, flScale, wrinkleOp, pDmeMesh, pDmeBindState, pDmeEditState, true ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SaveDelta( CDmeMesh *pDmeMesh, const char *pszDeltaName ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
// See if it's the "base" state we're updating and not a new delta state at all
if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) ) { CDmeVertexData *pDmeBind = pDmeMesh->GetBindBaseState(); if ( !pDmeBind ) DMXEDIT_WARNING_RETURN_FALSE( "Couldn't get bind base state from mesh \"%s\"", pDmeMesh->GetName() );
if ( pDmeEditState == pDmeBind ) DMXEDIT_WARNING_RETURN_FALSE( "Current state on mesh is the bind state on mesh \"%s\"", pDmeMesh->GetName() );
pDmeEditState->CopyTo( pDmeBind );
return true; }
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->ModifyOrCreateDeltaStateFromBaseState( pszDeltaName, pDmeEditState ); if ( pDmeDelta ) { pDmeDelta->Resolve(); return true; }
DMXEDIT_WARNING_RETURN_FALSE( "Couldn't create new delta state from base state on mesh \"%s\"", pDmeMesh->GetName() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool DeleteDelta( CDmeMesh *pDmeMesh, const char *pszDeltaName ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !pDmeDelta ) DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
return pDmeMesh->DeleteDeltaState( pszDeltaName ); }
//-----------------------------------------------------------------------------
// Helper function for Scale
//-----------------------------------------------------------------------------
static void ScaleDeltaPositions( const CDmrArrayConst< Vector > &bindPosData, CDmeVertexDeltaData *pDmeDelta, float flScaleX, float flScaleY, float flScaleZ ) { const int nPosIndex = pDmeDelta->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); if ( nPosIndex < 0 ) return;
CDmrArray< Vector > posData = pDmeDelta->GetVertexData( nPosIndex ); const int nPosDataCount = posData.Count(); if ( nPosDataCount <= 0 ) return;
Vector *pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) );
for ( int j = 0; j < nPosDataCount; ++j ) { const Vector &s = posData.Get( j ); Vector &d = pPosArray[ j ]; d.x = s.x * flScaleX; d.y = s.y * flScaleY; d.z = s.z * flScaleZ; }
posData.SetMultiple( 0, nPosDataCount, pPosArray ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Scale( CDmeMesh *pDmeMesh, float flScaleX, float flScaleY, float flScaleZ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
int nArraySize = 0; Vector *pPosArray = NULL;
const int nBaseStateCount = pDmeMesh->BaseStateCount(); for ( int i = 0; i < nBaseStateCount; ++i ) { CDmeVertexData *pBase = pDmeMesh->GetBaseState( i ); const int nPosIndex = pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); if ( nPosIndex < 0 ) continue;
CDmrArray< Vector > posData = pBase->GetVertexData( nPosIndex ); const int nPosDataCount = posData.Count(); if ( nPosDataCount <= 0 ) continue;
if ( nArraySize < nPosDataCount || pPosArray == NULL ) { pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) ); if ( pPosArray ) { nArraySize = nPosDataCount; } }
if ( nArraySize < nPosDataCount ) continue;
for ( int j = 0; j < nPosDataCount; ++j ) { const Vector &s = posData.Get( j ); Vector &d = pPosArray[ j ]; d.x = s.x * flScaleX; d.y = s.y * flScaleY; d.z = s.z * flScaleZ; }
posData.SetMultiple( 0, nPosDataCount, pPosArray ); }
{ CDmeVertexData *pBind = pDmeMesh->GetBindBaseState(); const int nPosIndex = pBind ? pBind->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) : -1;
if ( !pBind || nPosIndex < 0 ) DMXEDIT_WARNING_RETURN_FALSE( "Can't scale delta states on mesh \"%s\"", pDmeMesh->GetName() );
const CDmrArrayConst< Vector > posData = pBind->GetVertexData( nPosIndex );
const int nDeltaStateCount = pDmeMesh->DeltaStateCount(); for ( int i = 0; i < nDeltaStateCount; ++i ) { ScaleDeltaPositions( posData, pDmeMesh->GetDeltaState( i ), flScaleX, flScaleY, flScaleZ ); } }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Scale( CDmeMesh *pDmeMesh, float flScale ) { return Scale( pDmeMesh, flScale, flScale, flScale ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetStereoControl( CDmeMesh *pDmeMesh, const char *pszControlName, bool bStereo /* = true */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName ); if ( nControlIndex < 0 ) DMXEDIT_WARNING_RETURN_FALSE( "No control named \"%s\" found on combo op \"%s\" on mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
pDmeCombo->SetStereoControl( nControlIndex, bStereo );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetEyelidControl( CDmeMesh *pDmeMesh, const char *pszControlName, bool bEyelid /* = true */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName ); if ( nControlIndex < 0 ) DMXEDIT_WARNING_RETURN_FALSE( "No control named \"%s\" found on combo op \"%s\" on mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
pDmeCombo->SetEyelidControl( nControlIndex, bEyelid );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
float MaxDeltaDistance( CDmeMesh *pDmeMesh, const char *pszDeltaName ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !pDmeDelta ) DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
if ( !pDmeDelta ) return 0.0f;
float fSqMaxDelta = 0.0f; float fTmpSqLength;
const CUtlVector< Vector > &positions = pDmeDelta->GetPositionData();
const int nPositionCount = positions.Count(); for ( int i = 0; i < nPositionCount; ++i ) { fTmpSqLength = positions[ i ].LengthSqr(); if ( fTmpSqLength < fSqMaxDelta ) continue;
fSqMaxDelta = fTmpSqLength; }
return sqrt( fSqMaxDelta ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetWrinkleScale( CDmeMesh *pDmeMesh, const char *pszControlName, const char *pszRawControlName, float flScale ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName ); if ( nControlIndex < 0 ) DMXEDIT_WARNING_RETURN_FALSE( "No control named \"%s\" found on combo op \"%s\" on mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
// Check to see if the raw control exists
bool bFoundRawControl = false; for ( int nRawControlIndex = 0; nRawControlIndex < pDmeCombo->GetRawControlCount( nControlIndex ); ++nRawControlIndex ) { if ( !Q_strcmp( pszRawControlName, pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ) ) ) { bFoundRawControl = true; break; } }
if ( !bFoundRawControl ) { CUtlString rawControls; for ( int nRawControlIndex = 0; nRawControlIndex < pDmeCombo->GetRawControlCount( nControlIndex ); ++nRawControlIndex ) { if ( rawControls.Length() > 0 ) { rawControls += ", "; } rawControls += pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ); }
DMXEDIT_WARNING_RETURN_FALSE( "Control \"%s\" does not have Raw Control \"%s\" on combo op \"%s\" on mesh \"%s\"", pszControlName, pszRawControlName, pDmeCombo->GetName(), pDmeMesh->GetName() ); }
pDmeCombo->SetWrinkleScale( nControlIndex, pszRawControlName, flScale );
return true; }
//-----------------------------------------------------------------------------
// If it finds a duplicate control name, reports an error message and
// returns it found one
// Helper function for GroupControls
//-----------------------------------------------------------------------------
bool HasDuplicateControlName( CDmeCombinationOperator *pDmeCombo, const char *pControlName, CUtlVector< const char * > &retiredControlNames ) { int i; int nRetiredControlNameCount = retiredControlNames.Count(); for ( i = 0; i < nRetiredControlNameCount; ++i ) { if ( !Q_stricmp( retiredControlNames[i], pControlName ) ) break; }
if ( i == nRetiredControlNameCount ) { if ( pDmeCombo->FindControlIndex( pControlName ) >= 0 ) return true; }
return false; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool GroupControls( CDmeMesh *pDmeMesh, const char *pszGroupName, CUtlVector< const char * > &rawControlNames ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
// Loop through controls to see if any are already group controls, warn and remove
CUtlVector< const char * > validControlNames; bool bStereo = false; bool bEyelid = false;
for ( int i = 0; i < rawControlNames.Count(); ++i ) { ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( rawControlNames[ i ] ); if ( nControlIndex < 0 ) { DMXEDIT_WARNING( "Control \"%s\" Doesn't Exist, Ignoring", pszGroupName ); continue; }
if ( pDmeCombo->GetRawControlCount( nControlIndex ) > 1 ) { DMXEDIT_WARNING( "Control \"%s\" Isn't A Raw Control, Ignoring", pszGroupName ); continue; }
validControlNames.AddToTail( rawControlNames[ i ] );
if ( pDmeCombo->IsStereoControl( nControlIndex ) ) { bStereo = true; }
if ( pDmeCombo->IsEyelidControl( nControlIndex ) ) { bEyelid = true; } }
if ( HasDuplicateControlName( pDmeCombo, pszGroupName, validControlNames ) ) DMXEDIT_WARNING_RETURN_FALSE( "Duplicate Control \"%s\" Found", pszGroupName );
if ( validControlNames.Count() <= 0 ) DMXEDIT_WARNING_RETURN_FALSE( "No Valid Controls Specified" );
// Remove the old controls
for ( int i = 0; i < validControlNames.Count(); ++i ) { pDmeCombo->RemoveControl( validControlNames[i] ); }
// Create new control
ControlIndex_t nNewControl = pDmeCombo->FindOrCreateControl( pszGroupName, bStereo ); pDmeCombo->SetEyelidControl( nNewControl, bEyelid ); for ( int i = 0; i < validControlNames.Count(); ++i ) { pDmeCombo->AddRawControl( nNewControl, validControlNames[i] ); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void GetDeltaNames( CDmeMesh *pDmeMesh, CUtlVector< const char * > *pOutStringList ) { if ( !pOutStringList ) { DMXEDIT_WARNING( "No storage passed for result" ); return; }
pOutStringList->RemoveAll();
if ( !pDmeMesh ) { DMXEDIT_WARNING( "No mesh specified" ); return; }
const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
for ( int i = 0; i < nDeltaStateCount; ++i ) { const CDmeVertexDeltaData *pDmeDelta = pDmeMesh->GetDeltaState( i ); if ( !pDmeDelta ) { pOutStringList->AddToTail( "<unknown>" ); } else { pOutStringList->AddToTail( pDmeDelta->GetName() ); } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void GetRawControlNames( CDmeMesh *pDmeMesh, CUtlVector< const char * > *pOutStringList, const char *pszControlName /* = NULL */ ) { if ( !pOutStringList ) { DMXEDIT_WARNING( "No storage passed for result" ); return; }
pOutStringList->RemoveAll();
if ( !pDmeMesh ) { DMXEDIT_WARNING( "No mesh specified" ); return; }
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) { DMXEDIT_WARNING( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() ); return; }
if ( pszControlName ) { const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName ); if ( nControlIndex < 0 ) { DMXEDIT_WARNING( "No control named \"%s\" on DmeCombinationOperator \"%s\" controlling mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() ); } else { const int nRawControlCount = pDmeCombo->GetRawControlCount( nControlIndex ); for ( int i = 0; i < nRawControlCount; ++i ) { pOutStringList->AddToTail( pDmeCombo->GetRawControlName( nControlIndex, i ) ); } } } else { const int nRawControlCount = pDmeCombo->GetRawControlCount(); for ( int i = 0; i < nRawControlCount; ++i ) { pOutStringList->AddToTail( pDmeCombo->GetRawControlName( i ) ); } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void GetControlNames( CDmeMesh *pDmeMesh, CUtlVector< const char * > *pOutStringList ) { if ( !pOutStringList ) { DMXEDIT_WARNING( "No storage passed for result" ); return; }
pOutStringList->RemoveAll();
if ( !pDmeMesh ) { DMXEDIT_WARNING( "No mesh specified" ); return; }
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) { DMXEDIT_WARNING( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() ); return; }
const int nControlCount = pDmeCombo->GetControlCount(); for ( int i = 0; i < nControlCount; ++i ) { pOutStringList->AddToTail( pDmeCombo->GetControlName( i ) ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ReorderControls( CDmeMesh *pDmeMesh, CUtlVector< const char * > &controlNames ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
// Loop through controls to see if any are already group controls, warn and remove
CUtlVector< const char * > validControlNames;
for ( int i = 0; i < controlNames.Count(); ++i ) { ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( controlNames[ i ] ); if ( nControlIndex < 0 ) { DMXEDIT_WARNING( "Control \"%s\" doesn't exist, ignoring", controlNames[ i ] ); continue; }
validControlNames.AddToTail( controlNames[ i ] ); }
if ( validControlNames.Count() <= 0 ) DMXEDIT_WARNING_RETURN_FALSE( "No Valid Controls Specified" );
for ( int i = 0; i < validControlNames.Count(); ++i ) { pDmeCombo->MoveControlBefore( validControlNames[ i ], pDmeCombo->GetControlName( i ) ); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool AddDominationRule( CDmeMesh *pDmeMesh, CUtlVector< const char * > &dominators, CUtlVector< const char * > &supressed ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh ); if ( !pDmeCombo ) DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
pDmeCombo->AddDominationRule( dominators.Count(), ( const char ** )dominators.Base(), supressed.Count(), ( const char ** )supressed.Base() );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static const char s_szSelAttrName[] = "__dmxedit_selection";
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeSingleIndexedComponent *FindOrCreateMeshSelection( CDmeMesh *pDmeMesh, CDmeSingleIndexedComponent *pDmePassedSelection ) { if ( pDmePassedSelection ) return pDmePassedSelection;
DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmAttribute *pDmeSelAttr = NULL;
if ( pDmeMesh->HasAttribute( s_szSelAttrName ) ) { pDmeSelAttr = pDmeMesh->GetAttribute( s_szSelAttrName, AT_ELEMENT ); if ( !pDmeSelAttr ) { DMXEDIT_WARNING( "Attribute %s.%s is of type %s, not AT_ELEMENT, removing", pDmeMesh->GetName(), pDmeSelAttr->GetName(), pDmeSelAttr->GetTypeString() ); pDmeMesh->RemoveAttribute( s_szSelAttrName ); pDmeSelAttr = NULL; } }
if ( pDmeSelAttr == NULL ) { CDmeSingleIndexedComponent *pTempSelection = CreateElement< CDmeSingleIndexedComponent >( s_szSelAttrName, DMFILEID_INVALID ); if ( !pTempSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't create CDmeSingleIndexedComponent %s element", s_szSelAttrName );
pDmeSelAttr = pDmeMesh->AddAttributeElement< CDmeSingleIndexedComponent >( s_szSelAttrName ); if ( !pDmeSelAttr ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't create %s.%s attribute", pDmeMesh->GetName(), s_szSelAttrName );
pDmeSelAttr->AddFlag( FATTRIB_DONTSAVE ); pDmeSelAttr->SetValue< CDmeSingleIndexedComponent >( pTempSelection ); }
return pDmeSelAttr->GetValueElement< CDmeSingleIndexedComponent >(); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CleanupMeshSelection( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
pDmeMesh->RemoveAttribute( s_szSelAttrName );
return true; }
//-----------------------------------------------------------------------------
// Combines the two selections via the selectOp and puts result into pOriginal
//-----------------------------------------------------------------------------
void DoSelectOp( const SelectOp_t &nSelectOp, CDmeSingleIndexedComponent *pDmeOriginalSel, const CDmeSingleIndexedComponent *pDmeNewSel ) { if ( !pDmeOriginalSel || !pDmeNewSel ) return;
switch ( nSelectOp ) { case ADD_SELECT_OP: pDmeOriginalSel->Add( pDmeNewSel ); break; case SUBTRACT_SELECT_OP: pDmeOriginalSel->Subtract( pDmeNewSel ); break; case TOGGLE_SELECT_OP: { CDmeSingleIndexedComponent *pIntersection = CreateElement< CDmeSingleIndexedComponent >( "__dmxedit_intersection", DMFILEID_INVALID ); if ( !pIntersection ) return;
CDmeSingleIndexedComponent *pNewCopy = CreateElement< CDmeSingleIndexedComponent >( "__dmxedit_newCopy", DMFILEID_INVALID ); if ( !pNewCopy ) { g_pDataModel->DestroyElement( pIntersection->GetHandle() ); return; }
pDmeOriginalSel->CopyAttributesTo( pIntersection ); pIntersection->Intersection( pDmeNewSel ); pDmeOriginalSel->Subtract( pIntersection );
pDmeNewSel->CopyAttributesTo( pNewCopy ); pNewCopy->Subtract( pIntersection ); pDmeOriginalSel->Add( pNewCopy );
g_pDataModel->DestroyElement( pIntersection->GetHandle() ); g_pDataModel->DestroyElement( pNewCopy->GetHandle() ); } break; case INTERSECT_SELECT_OP: pDmeOriginalSel->Intersection( pDmeNewSel ); break; case REPLACE_SELECT_OP: { CUtlString originalName = pDmeOriginalSel->GetName(); pDmeNewSel->CopyAttributesTo( pDmeOriginalSel ); pDmeOriginalSel->SetName( originalName ); } break; } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeSingleIndexedComponent *Select( CDmeMesh *pDmeMesh, SelectOp_t nSelectOp, const char *pszSelectString, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
if ( nSelectOp < 0 || nSelectOp >= INVALID_SELECT_OP ) return NULL;
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
// Figure out if pszSelectString is one of the keywords, all, none or a delta state
// NOTE: This means that delta states with a name of all or none are not selectable
if ( !Q_stricmp( "ALL", pszSelectString ) ) { pDmeMesh->SelectAllVertices( pDmeSelection ); } else if ( !Q_stricmp( "NONE", pszSelectString ) ) { pDmeSelection->Clear(); } else { CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszSelectString ); if ( !pDmeDelta ) DMXEDIT_WARNING_RETURN_NULL( "Mesh \"%s\" does not have a delta state named \"%s\" to select", pDmeMesh->GetName(), pszSelectString );
if ( nSelectOp == REPLACE_SELECT_OP ) { pDmeMesh->SelectVerticesFromDelta( pDmeDelta, pDmeSelection ); } else { CDmeSingleIndexedComponent *pDmeTmpSelection = CreateElement< CDmeSingleIndexedComponent >( "__dmxedit_tmpSelection", DMFILEID_INVALID ); if ( !pDmeTmpSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't create a tmp selection element while selecting delta \"%s\" on mesh \"%s\"", pszSelectString, pDmeMesh->GetName() );
pDmeMesh->SelectVerticesFromDelta( pDmeDelta, pDmeTmpSelection ); DoSelectOp( nSelectOp, pDmeSelection, pDmeTmpSelection );
g_pDataModel->DestroyElement( pDmeTmpSelection->GetHandle() ); } }
return pDmeSelection; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
SelectOp_t StringToSelectOp_t( const char *pszSelectOpString ) { if ( StringHasPrefix( pszSelectOpString, "A" ) ) return ADD_SELECT_OP;
if ( StringHasPrefix( pszSelectOpString, "S" ) ) return SUBTRACT_SELECT_OP;
if ( StringHasPrefix( pszSelectOpString, "T" ) ) return TOGGLE_SELECT_OP;
if ( StringHasPrefix( pszSelectOpString, "I" ) ) return INTERSECT_SELECT_OP;
if ( StringHasPrefix( pszSelectOpString, "R" ) ) return REPLACE_SELECT_OP;
DMXEDIT_WARNING( "Invalid Selection Operation string specified: \"%s\"", pszSelectOpString );
return INVALID_SELECT_OP; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeSingleIndexedComponent *Select( CDmeMesh *pDmeMesh, const char *pszSelectString, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { return Select( pDmeMesh, REPLACE_SELECT_OP, pszSelectString, pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeSingleIndexedComponent *Select( CDmeMesh *pDmeMesh, const char *pszSelectOpString, const char *pszSelectString, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { return Select( pDmeMesh, StringToSelectOp_t( pszSelectOpString ), pszSelectString, pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
// An Efficient Bounding Sphere
// by Jack Ritter
// from "Graphics Gems", Academic Press, 1990
//
// Routine to calculate tight bounding sphere over
// a set of points in 3D
// This contains the routine find_bounding_sphere(),
// the struct definition, and the globals used for parameters.
// The abs() of all coordinates must be < BIGNUMBER
// Code written by Jack Ritter and Lyle Rains.
//-----------------------------------------------------------------------------
void FindBoundingSphere( CUtlVector< Vector > &points, Vector &cen, float &fRad ) { if ( points.Count() <= 0 ) { cen.Zero(); fRad = 0.0f;
return; }
double dx,dy,dz; double rad_sq,xspan,yspan,zspan,maxspan; double old_to_p,old_to_p_sq,old_to_new; Vector xmin,xmax,ymin,ymax,zmin,zmax,dia1,dia2;
// DVec cen;
double rad;
cen = points[ 0 ]; fRad = 0.0f;
xmin.x=ymin.y=zmin.z= FLT_MAX; /* initialize for min/max compare */ xmax.x=ymax.y=zmax.z= -FLT_MAX;
for ( int i = 0; i < points.Count(); ++i ) { const Vector &caller_p = points[ i ];
if (caller_p.x<xmin.x) xmin = caller_p; /* New xminimum point */ if (caller_p.x>xmax.x) xmax = caller_p; if (caller_p.y<ymin.y) ymin = caller_p; if (caller_p.y>ymax.y) ymax = caller_p; if (caller_p.z<zmin.z) zmin = caller_p; if (caller_p.z>zmax.z) zmax = caller_p; }
/* Set xspan = distance between the 2 points xmin & xmax (squared) */ dx = xmax.x - xmin.x; dy = xmax.y - xmin.y; dz = xmax.z - xmin.z; xspan = dx*dx + dy*dy + dz*dz;
/* Same for y & z spans */ dx = ymax.x - ymin.x; dy = ymax.y - ymin.y; dz = ymax.z - ymin.z; yspan = dx*dx + dy*dy + dz*dz;
dx = zmax.x - zmin.x; dy = zmax.y - zmin.y; dz = zmax.z - zmin.z; zspan = dx*dx + dy*dy + dz*dz;
/* Set points dia1 & dia2 to the maximally separated pair */ dia1 = xmin; dia2 = xmax; /* assume xspan biggest */ maxspan = xspan; if (yspan>maxspan) { maxspan = yspan; dia1 = ymin; dia2 = ymax; } if (zspan>maxspan) { dia1 = zmin; dia2 = zmax; }
/* dia1,dia2 is a diameter of initial sphere */ /* calc initial center */ cen.x = (dia1.x+dia2.x)/2.0; cen.y = (dia1.y+dia2.y)/2.0; cen.z = (dia1.z+dia2.z)/2.0; /* calculate initial radius**2 and radius */ dx = dia2.x-cen.x; /* x component of radius vector */ dy = dia2.y-cen.y; /* y component of radius vector */ dz = dia2.z-cen.z; /* z component of radius vector */ rad_sq = dx*dx + dy*dy + dz*dz; rad = sqrt(rad_sq);
/* SECOND PASS: increment current sphere */
for ( int i = 0; i < points.Count(); ++i ) { const Vector &caller_p = points[ i ];
dx = caller_p.x-cen.x; dy = caller_p.y-cen.y; dz = caller_p.z-cen.z; old_to_p_sq = dx*dx + dy*dy + dz*dz; if (old_to_p_sq > rad_sq) /* do r**2 test first */ { /* this point is outside of current sphere */ old_to_p = sqrt(old_to_p_sq); /* calc radius of new sphere */ rad = (rad + old_to_p) / 2.0; rad_sq = rad*rad; /* for next r**2 compare */ old_to_new = old_to_p - rad; /* calc center of new sphere */ cen.x = (rad*cen.x + old_to_new*caller_p.x) / old_to_p; cen.y = (rad*cen.y + old_to_new*caller_p.y) / old_to_p; cen.z = (rad*cen.z + old_to_new*caller_p.z) / old_to_p; } }
/*
fCen.x = cen.x; fCen.y = cen.y; fCen.z = cen.z; */ fRad = rad; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
float DeltaRadius( CDmeMesh *pDmeMesh, const char *pszDeltaName ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeVertexData *pBind = pDmeMesh->GetBindBaseState(); if ( !pBind || !BaseStateSanityCheck( pDmeMesh, pBind, __func__ ) ) return 0.0f;
CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !pDelta || !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) ) return 0.0f;
const CUtlVector< Vector > &bindPos = pBind->GetPositionData(); const CUtlVector< int > &deltaPosIndices = pDelta->GetVertexIndexData( CDmeVertexData::FIELD_POSITION ); const CUtlVector< Vector > &deltaPos = pDelta->GetPositionData();
Assert( deltaPosIndices.Count() == deltaPos.Count() );
CUtlVector< Vector > newPos; newPos.SetSize( deltaPos.Count() );
for ( int i = 0; i < newPos.Count(); ++i ) { newPos[ i ] = bindPos[ deltaPosIndices[ i ] ] + deltaPos[ i ]; }
Vector vCenter; float flRadius = 0.0;
FindBoundingSphere( newPos, vCenter, flRadius );
return flRadius; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
float SelectionRadius( CDmeMesh *pDmeMesh, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) { DMXEDIT_WARNING( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() ); return 0.0f; }
if ( pDmeSelection->Count() == 0 ) return 0.0f;
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return 0.0f;
CUtlVector< int > selection; pDmeSelection->GetComponents( selection ); const CUtlVector< Vector > &pos = pDmeEditState->GetPositionData();
CUtlVector< Vector > newPos; newPos.SetSize( selection.Count() );
for ( int i = 0; i < newPos.Count(); ++i ) { newPos[ i ] = pos[ selection[ i ] ]; }
Vector vCenter; float flRadius = 0.0;
FindBoundingSphere( newPos, vCenter, flRadius );
return flRadius; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool GrowSelection( CDmeMesh *pDmeMesh, int nSize /* = 1 */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) { DMXEDIT_WARNING( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() ); return 0.0f; }
// TODO: Cache the CDmMeshComp object, make it into winged or half edge data structure
pDmeMesh->GrowSelection( nSize, pDmeSelection, NULL );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ShrinkSelection( CDmeMesh *pDmeMesh, int nSize /* = 1 */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) { DMXEDIT_WARNING( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() ); return 0.0f; }
// TODO: Cache the CDmMeshComp object, make it into winged or half edge data structure
pDmeMesh->ShrinkSelection( nSize, pDmeSelection, NULL );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int StringToDistanceType( const char *pszDistanceTypeString ) { if ( pszDistanceTypeString && ( *pszDistanceTypeString == 'a' || *pszDistanceTypeString == 'A' ) ) return CDmeMesh::DIST_ABSOLUTE;
if ( pszDistanceTypeString && ( *pszDistanceTypeString == 'r' || *pszDistanceTypeString == 'R' ) ) return CDmeMesh::DIST_RELATIVE;
if ( pszDistanceTypeString && ( *pszDistanceTypeString == 'd' || *pszDistanceTypeString == 'D' ) ) return CDmeMesh::DIST_DEFAULT;
DMXEDIT_WARNING( "Invalid Distance Type string specified: \"%s\"", pszDistanceTypeString ); return -1; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetDistanceType( CDmeMesh::Distance_t nDistanceType ) { if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
g_pDmxEditImpl->SetDistanceType( nDistanceType );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetDistanceType( const char *pszDistanceType ) { const int nDistanceType = StringToDistanceType( pszDistanceType ); if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) return false;
return SetDistanceType( static_cast< CDmeMesh::Distance_t >( nDistanceType ) ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int StringToFalloffType( const char *pszFalloffTypeString ) { if ( !Q_strnicmp( pszFalloffTypeString, "L", 1 ) ) return CDmeMesh::LINEAR;
else if ( !Q_strnicmp( pszFalloffTypeString, "ST", 2 ) ) return CDmeMesh::STRAIGHT;
else if ( !Q_strnicmp( pszFalloffTypeString, "B", 1 ) ) return CDmeMesh::BELL;
else if ( !Q_strnicmp( pszFalloffTypeString, "SM", 2 ) ) return CDmeMesh::SMOOTH;
else if ( !Q_strnicmp( pszFalloffTypeString, "SP", 2 ) ) return CDmeMesh::SPIKE;
else if ( !Q_strnicmp( pszFalloffTypeString, "D", 1 ) ) return CDmeMesh::DOME;
DMXEDIT_WARNING( "Invalid Falloff Type string specified: \"%s\"", pszFalloffTypeString ); return -1; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Interp( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flWeight /* = 1.0f */, float flFeatherDistance /* = 0.0f */, CDmeMesh::Falloff_t nFalloffType /* CDmeMesh::STRAIGHT */, CDmeMesh::Distance_t nDistanceType /* = CDmeMesh::DIST_DEFAULT */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown falloff type: %d", nFalloffType );
nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : NULL;
bool bRetVal = false;
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) ) { bRetVal = pDmeMesh->InterpMaskedDelta( NULL, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection ); } else { CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) ) return false;
bRetVal = pDmeMesh->InterpMaskedDelta( pDelta, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection ); }
if ( pNewSelection ) { g_pDataModel->DestroyElement( pNewSelection->GetHandle() ); }
return bRetVal; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Interp( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flWeight /* = 1.0f */, float flFeatherDistance /* = 0.0f */, const char *pszFalloffType /* = "STRAIGHT" */, const char *pszDistanceType /* = "DEFAULT" */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { const int nFalloffType = StringToFalloffType( pszFalloffType ); if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) return false;
const int nDistanceType = StringToDistanceType( pszDistanceType ); if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) return false;
return Interp( pDmeMesh, pszDeltaName, flWeight, flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), CDmeMesh::Distance_t( nDistanceType ), pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Add( CDmeMesh *pDmeMesh, const char *pDeltaName, float flWeight /* = 1.0f */, float flFeatherDistance /* = 0.0f */, CDmeMesh::Falloff_t nFalloffType /* = CDmeMesh::STRAIGHT */, CDmeMesh::Distance_t nDistanceType /* = CDmeMesh::DIST_DEFAULT */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown falloff type: %d", nFalloffType );
nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : NULL;
bool bRetVal = false;
CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pDeltaName ); if ( !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) ) return false;
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
bRetVal = pDmeMesh->AddMaskedDelta( pDelta, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection );
if ( pNewSelection ) { g_pDataModel->DestroyElement( pNewSelection->GetHandle() ); }
return bRetVal; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Add( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flWeight /* = 1.0f */, float flFeatherDistance /* = 0.0f */, const char *pszFalloffType /* = "STRAIGHT" */, const char *pszDistanceType /* = "DEFAULT" */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { const int nFalloffType = StringToFalloffType( pszFalloffType ); if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) return false;
const int nDistanceType = StringToDistanceType( pszDistanceType ); if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) return false;
return Add( pDmeMesh, pszDeltaName, flWeight, flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), CDmeMesh::Distance_t( nDistanceType ), pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool AddCorrected( CDmeMesh *pDmeMesh, const char *pDeltaName, float flWeight /* = 1.0f */, float flFeatherDistance /* = 0.0f */, CDmeMesh::Falloff_t nFalloffType /* = CDmeMesh::STRAIGHT */, CDmeMesh::Distance_t nDistanceType /* = CDmeMesh::DIST_DEFAULT */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown falloff type: %d", nFalloffType );
nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : NULL;
bool bRetVal = false;
CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pDeltaName ); if ( !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) ) return false;
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
bRetVal = pDmeMesh->AddCorrectedMaskedDelta( pDelta, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection );
if ( pNewSelection ) { g_pDataModel->DestroyElement( pNewSelection->GetHandle() ); }
return bRetVal; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool AddCorrected( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flWeight /* = 1.0f */, float flFeatherDistance /* = 0.0f */, const char *pszFalloffType /* = "STRAIGHT" */, const char *pszDistanceType /* = "DEFAULT" */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { const int nFalloffType = StringToFalloffType( pszFalloffType ); if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) return false;
const int nDistanceType = StringToDistanceType( pszDistanceType ); if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) return false;
return AddCorrected( pDmeMesh, pszDeltaName, flWeight, flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), CDmeMesh::Distance_t( nDistanceType ), pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Translate( CDmeMesh *pDmeMesh, Vector vT, float flFeatherDistance, CDmeMesh::Falloff_t nFalloffType, CDmeMesh::Distance_t nDistanceType, CDmeSingleIndexedComponent *pDmePassedSelection ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
CDmeSingleIndexedComponent *pTmpSelection = NULL;
if ( !pDmeSelection || pDmeSelection->Count() == 0 ) { pTmpSelection = CreateElement< CDmeSingleIndexedComponent >( "__selectAll", DMFILEID_INVALID ); pDmeSelection = pTmpSelection; pDmeMesh->SelectAllVertices( pDmeSelection ); }
CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : pDmeSelection;
int nArraySize = 0; Vector *pPosArray = NULL;
const int nPosIndex = pDmeEditState->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); if ( nPosIndex < 0 ) return false;
CDmrArray< Vector > posData = pDmeEditState->GetVertexData( nPosIndex ); const int nPosDataCount = posData.Count(); if ( nPosDataCount <= 0 ) return false;
if ( nArraySize < nPosDataCount || pPosArray == NULL ) { pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) ); if ( pPosArray ) { nArraySize = nPosDataCount; } }
if ( nArraySize < nPosDataCount ) return false;
if ( nDistanceType == CDmeMesh::DIST_RELATIVE ) { Vector vCenter; float fRadius;
pDmeMesh->GetBoundingSphere( vCenter, fRadius, pDmeEditState, pDmeSelection );
vT *= fRadius; }
if ( pNewSelection ) { memcpy( pPosArray, posData.Base(), nPosDataCount * sizeof( Vector ) );
const int nSelectionCount = pNewSelection->Count(); int nIndex; float fWeight; for ( int j = 0; j < nSelectionCount; ++j ) { pNewSelection->GetComponent( j, nIndex, fWeight ); const Vector &s = posData.Get( nIndex ); Vector &d = pPosArray[ nIndex ]; d = s + vT * fWeight; } } else { for ( int j = 0; j < nPosDataCount; ++j ) { const Vector &s = posData.Get( j ); Vector &d = pPosArray[ j ]; d = s + vT; } }
posData.SetMultiple( 0, nPosDataCount, pPosArray );
if ( pTmpSelection ) { g_pDataModel->DestroyElement( pTmpSelection->GetHandle() ); }
if ( pNewSelection != pDmeSelection ) { g_pDataModel->DestroyElement( pNewSelection->GetHandle() ); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Translate( CDmeMesh *pDmeMesh, float flTx, float flTy, float flTz, float flFeatherDistance /* = 0.0f */, const char *pszFalloffType /* = "STRAIGHT" */, const char *pszDistanceType /* = "DEFAULT" */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { const int nFalloffType = StringToFalloffType( pszFalloffType ); if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) return false;
const int nDistanceType = StringToDistanceType( pszDistanceType ); if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) return false;
return Translate( pDmeMesh, Vector( flTx, flTy, flTz ), flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), static_cast< CDmeMesh::Distance_t >( nDistanceType ), pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Rotate( CDmeMesh *pDmeMesh, Vector vR, Vector vO, float flFeatherDistance, CDmeMesh::Falloff_t nFalloffType, CDmeMesh::Distance_t nDistanceType, CDmeSingleIndexedComponent *pDmePassedSelection ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) ) return false;
CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection ); if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
CDmeSingleIndexedComponent *pTmpSelection = NULL;
if ( !pDmeSelection || pDmeSelection->Count() == 0 ) { pTmpSelection = CreateElement< CDmeSingleIndexedComponent >( "__selectAll", DMFILEID_INVALID ); pDmeSelection = pTmpSelection; pDmeMesh->SelectAllVertices( pDmeSelection ); }
CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : pDmeSelection; int nArraySize = 0; Vector *pPosArray = NULL;
const int nPosIndex = pDmeEditState->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); if ( nPosIndex < 0 ) return false;
CDmrArray< Vector > posData = pDmeEditState->GetVertexData( nPosIndex ); const int nPosDataCount = posData.Count(); if ( nPosDataCount <= 0 ) return false;
if ( nArraySize < nPosDataCount || pPosArray == NULL ) { pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) ); if ( pPosArray ) { nArraySize = nPosDataCount; } }
if ( nArraySize < nPosDataCount ) return false;
Vector vCenter; float fRadius;
pDmeMesh->GetBoundingSphere( vCenter, fRadius, pDmeEditState, pDmeSelection );
if ( nDistanceType == CDmeMesh::DIST_RELATIVE ) { vR *= fRadius; }
VectorAdd( vCenter, vO, vCenter );
matrix3x4_t rpMat; SetIdentityMatrix( rpMat ); PositionMatrix( vCenter, rpMat );
matrix3x4_t rpiMat; SetIdentityMatrix( rpiMat ); PositionMatrix( -vCenter, rpiMat );
matrix3x4_t rMat; SetIdentityMatrix( rMat );
if ( pNewSelection ) { memcpy( pPosArray, posData.Base(), nPosDataCount * sizeof( Vector ) );
const int nSelectionCount = pNewSelection->Count(); int nIndex; float fWeight; for ( int j = 0; j < nSelectionCount; ++j ) { pNewSelection->GetComponent( j, nIndex, fWeight ); const Vector &s = posData.Get( nIndex ); Vector &d = pPosArray[ nIndex ]; AngleMatrix( RadianEuler( DEG2RAD( vR.x * fWeight ), DEG2RAD( vR.y * fWeight ), DEG2RAD( vR.z * fWeight ) ), rMat );
ConcatTransforms( rpMat, rMat, rMat ); ConcatTransforms( rMat, rpiMat, rMat );
VectorTransform( s, rMat, d ); } } else { AngleMatrix( RadianEuler( DEG2RAD( vR.x ), DEG2RAD( vR.y ), DEG2RAD( vR.z ) ), rMat );
ConcatTransforms( rpMat, rMat, rMat ); ConcatTransforms( rMat, rpiMat, rMat );
for ( int j = 0; j < nPosDataCount; ++j ) { const Vector &s = posData.Get( j ); Vector &d = pPosArray[ j ]; VectorTransform( s, rMat, d ); } }
posData.SetMultiple( 0, nPosDataCount, pPosArray );
if ( pTmpSelection ) { g_pDataModel->DestroyElement( pTmpSelection->GetHandle() ); }
if ( pNewSelection != pDmeSelection ) { g_pDataModel->DestroyElement( pNewSelection->GetHandle() ); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Rotate( CDmeMesh *pDmeMesh, float flRx, float flRy, float flRz, float flOx /* = 0.0f */, float flOy /* = 0.0f */, float flOz /* = 0.0f */, float flFeatherDistance /* = 0.0f */, const char *pszFalloffType /* = "STRAIGHT" */, const char *pszDistanceType /* = "DEFAULT" */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
const int nFalloffType = StringToFalloffType( pszFalloffType ); if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME ) return false;
const int nDistanceType = StringToDistanceType( pszDistanceType ); if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT ) return false;
return Rotate( pDmeMesh, Vector( flRx, flRy, flRz ), Vector( flOx, flOy, flOz ), flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), static_cast< CDmeMesh::Distance_t >( nDistanceType ), pDmePassedSelection ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool RemapMaterial( CDmeMesh *pDmeMesh, int nMaterialIndex, const char *pszNewMaterialName ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
return CDmMeshUtils::RemapMaterial( pDmeMesh, nMaterialIndex, pszNewMaterialName ); }
//-----------------------------------------------------------------------------
// Adds the src mesh into the dst mesh
//-----------------------------------------------------------------------------
bool Combine( CDmeMesh *pDmeMesh, CDmeMesh *pDmeSrcMesh, const char *pszDstSkinningBoneName /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh ); DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeSrcMesh );
int nSkinningJointIndex = -1;
if ( pszDstSkinningBoneName ) { // Find the DmeModel of the destination mesh scene
CDmeDag *pDmeDag = FindReferringElement< CDmeDag >( pDmeMesh, "shape" ); while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) ) { pDmeDag = pDmeDag->GetParent(); }
CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag ); if ( pDmeModel ) { CDmeDag *pDmeJoint = pDmeModel->GetJoint( pszDstSkinningBoneName ); if ( pDmeJoint ) { nSkinningJointIndex = pDmeModel->GetJointIndex( pDmeJoint ); } } else { DMXEDIT_WARNING( "Couldn't find the DmeModel associated with mesh \"%s\"", pDmeMesh->GetName() ); }
if ( nSkinningJointIndex < 0 ) { DMXEDIT_WARNING( "Couldn't find bone named \"%s\", for skinning", pszDstSkinningBoneName ); } }
const bool bRetVal = CDmMeshUtils::Merge( pDmeSrcMesh, pDmeMesh, nSkinningJointIndex );
FixupBaseStates( pDmeMesh );
return bRetVal; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Merge( CDmElement *pDmDstRoot, CDmeMesh *pSrcMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pSrcMesh );
if ( !pDmDstRoot ) DMXEDIT_WARNING_RETURN_FALSE( "No element passed" );
CDmMeshComp srcComp( pSrcMesh );
CUtlVector< CUtlVector< CDmMeshComp::CEdge * > > srcBorderEdgesList; if ( srcComp.GetBorderEdges( srcBorderEdgesList ) == 0 ) return false;
CDmeMesh *pDmeSocketMesh = CastElement< CDmeMesh >( pDmDstRoot ); if ( pDmeSocketMesh ) { const int nEdgeListIndex = CDmMeshUtils::FindMergeSocket( srcBorderEdgesList, pDmeSocketMesh ); if ( nEdgeListIndex < 0 ) DMXEDIT_WARNING_RETURN_FALSE( "No merge socket found on specified mesh: \"%s\"\n", pDmeSocketMesh->GetName() );
CleanupMeshEditBaseState( pSrcMesh ); CleanupMeshSelection( pSrcMesh );
bool bRetVal = CDmMeshUtils::Merge( srcComp, srcBorderEdgesList[ nEdgeListIndex ], pDmeSocketMesh );
FixupBaseStates( pDmeSocketMesh );
pDmeSocketMesh->Resolve();
return bRetVal; }
CDmeDag *pDmeDag = CastElement< CDmeDag >( pDmDstRoot ); if ( !pDmeDag ) { pDmeDag = pDmDstRoot->GetValueElement< CDmeDag >( "model" ); }
if ( !pDmeDag ) DMXEDIT_WARNING_RETURN_FALSE( "Invalid DmElement passed, DmeMesh, DmeDag or DmElement with \"model\" attribute required" );
Vector vSrcCenter; float flSrcRadius;
pSrcMesh->GetBoundingSphere( vSrcCenter, flSrcRadius );
Vector vDstCenter; float flDstRadius;
float flSqDist = FLT_MAX;
int nEdgeListIndex = -1;
CUtlStack< CDmeDag * > traverseStack; traverseStack.Push( pDmeDag );
while ( traverseStack.Count() ) { traverseStack.Pop( pDmeDag ); if ( !pDmeDag ) continue;
for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { traverseStack.Push( pDmeDag->GetChild( i ) ); }
CDmeMesh *pDmeTmpMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() ); if ( !pDmeTmpMesh ) continue;
const int nTmpEdgeListIndex = CDmMeshUtils::FindMergeSocket( srcBorderEdgesList, pDmeTmpMesh ); if ( nTmpEdgeListIndex < 0 ) continue;
pDmeTmpMesh->GetBoundingSphere( vDstCenter, flDstRadius ); flDstRadius = vDstCenter.DistToSqr( vSrcCenter );
if ( flDstRadius < flSqDist ) { flSqDist = flDstRadius; pDmeSocketMesh = pDmeTmpMesh; nEdgeListIndex = nTmpEdgeListIndex; } }
if ( pDmeSocketMesh && nEdgeListIndex >= 0 ) { CleanupMeshEditBaseState( pSrcMesh ); CleanupMeshSelection( pSrcMesh );
bool bRetVal = CDmMeshUtils::Merge( srcComp, srcBorderEdgesList[ nEdgeListIndex ], pDmeSocketMesh );
FixupBaseStates( pDmeSocketMesh );
pDmeSocketMesh->Resolve();
return bRetVal; }
DMXEDIT_WARNING_RETURN_FALSE( "No merge socket found in specified scene, i.e. a Set of border edges on the source model that are found on the merge model" ); }
bool ApplyMaskToDelta( CDmeVertexDeltaData *pTheDelta, CDmeSingleIndexedComponent *pDmePassedSelection ) { CDmrArray< int > positionIndices = pTheDelta->GetAttribute( "positionsIndices" ); CDmrArray< Vector > positions = pTheDelta->GetAttribute( "positions" ); CDmrArray< float > weightData = pDmePassedSelection->GetAttribute( "weights" ); int numVerts = positionIndices.Count();
for ( int n=0; n < numVerts; n++ ) { int idx = positionIndices[ n ]; float fWeight = weightData[ idx ]; const Vector vNewPos = positions[ n ] * fWeight;
positions.Set( n, vNewPos ); }
//do we have normals to deal with?
CDmAttribute *pNormalsIndicesAttr = pTheDelta->GetAttribute( "normalsIndices" ); if ( pNormalsIndicesAttr ) { CDmrArray< int > normalsIndices = pNormalsIndicesAttr; CDmrArray< Vector > normals = pTheDelta->GetAttribute( "normals" );
for ( int n=0; n < numVerts; n++ ) { int idx = normalsIndices[ n ]; float fWeight = weightData[ idx ];
Vector vNewNormal = normals[ n ] * fWeight; vNewNormal.NormalizeInPlace();
normals.Set( n, Vector( vNewNormal ) ); } }
return pTheDelta == NULL; }
bool CreateDeltaFromMesh( CDmeMesh *pBaseMesh, CDmeMesh *pMeshToUseAsDelta, const char *pDeltaName, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pBaseMesh );
DMXEDIT_MESH_WARNING_RETURN_FALSE( pMeshToUseAsDelta );
CDmeVertexDeltaData *pRet = pBaseMesh->ModifyOrCreateDeltaStateFromBaseState( pDeltaName, pMeshToUseAsDelta->GetCurrentBaseState(), true );
if ( pDmePassedSelection ) { ApplyMaskToDelta( pRet, pDmePassedSelection ); }
return pRet == NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeMesh *ComputeConvexHull3D( CDmeMesh *pDmeMesh, float flCoplanarEpsilon /* = ONE_32ND_UNIT */ ) { CMesh mesh;
if ( ConvertMeshFromDMX( &mesh, pDmeMesh ) ) { CMesh convexHullMesh; ConvexHull3D( &convexHullMesh, mesh, flCoplanarEpsilon );
CUtlString meshName( pDmeMesh->GetName() ); meshName += "_convexHull";
CDmeMesh *pDmeConvexHullMesh = CreateElement< CDmeMesh >( meshName.Get(), pDmeMesh->GetFileId() ); if ( pDmeConvexHullMesh ) { ConvertMeshToDMX( pDmeConvexHullMesh, &convexHullMesh, true );
return pDmeConvexHullMesh; } }
return NULL; } //-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeCombinationOperator *FindOrCreateComboOp( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeCombinationOperator *pDmeComboOp = GetComboOpFromMesh( pDmeMesh ); if ( pDmeComboOp ) return pDmeComboOp;
// Find the DmeModel of the destination mesh scene
CDmeDag *pDmeDag = FindReferringElement< CDmeDag >( pDmeMesh, "shape" ); while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) ) { pDmeDag = pDmeDag->GetParent(); }
CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag ); if ( !pDmeModel ) DMXEDIT_ERROR_RETURN_NULL( "Couldn't Find The DmeModel for the mesh: \"%s\"", pDmeMesh->GetName() );
// Find the root node for the DmeModel (by "model" or "skeleton" attribute):
CDmElement *pDmRoot = FindReferringElement< CDmElement >( pDmeModel, "model" ); if ( !pDmRoot ) { pDmRoot = FindReferringElement< CDmElement >( pDmeModel, "skeleton" ); }
if ( !pDmRoot ) DMXEDIT_ERROR_RETURN_NULL( "Couldn't Find The root Dme node referring to the DmeModel \"%s\" for the mesh: \"%s\"", pDmeModel->GetName(), pDmeMesh->GetName() );
pDmeComboOp = pDmRoot->GetValueElement< CDmeCombinationOperator >( "combinationOperator" ); if ( !pDmeComboOp ) {
CUtlString comboOpName = pDmeMesh->GetName(); comboOpName += "_comboOp";
pDmeComboOp = CreateElement< CDmeCombinationOperator >( comboOpName.Get(), pDmeMesh->GetFileId() );
if ( !pDmeComboOp ) DMXEDIT_WARNING_RETURN_NULL( "Couldn't create DmeCombinationOperator for \"%s\"", pDmeMesh->GetName() );
pDmRoot->SetValue( "combinationOperator", pDmeComboOp ); }
pDmeComboOp->AddTarget( pDmeMesh ); return pDmeComboOp; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetMeshFromSkeleton( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState(); if ( !BaseStateSanityCheck( pDmeMesh, pDmeBindBaseState, __func__ ) ) return false;
CDmeVertexData *pDmeEditBaseState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, __func__ ) ) return false;
if ( !pDmeBindBaseState->HasSkinningData() ) DMXEDIT_ERROR_RETURN_FALSE( "No skinning data on specified mesh: \"%s\"", pDmeMesh->GetName() );
const FieldIndex_t nBindPosField = pDmeBindBaseState->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); if ( nBindPosField < 0 ) DMXEDIT_ERROR_RETURN_FALSE( "Cannot find position data on mesh \"%s\" base state", pDmeMesh->GetName() );
const FieldIndex_t nEditPosField = pDmeEditBaseState->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); if ( nEditPosField < 0 ) DMXEDIT_ERROR_RETURN_FALSE( "Cannot find position data on mesh \"%s\" edit state", pDmeMesh->GetName() );
CDmeDag *pDmeDag = pDmeMesh->GetParent(); while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) ) { pDmeDag = pDmeDag->GetParent(); } CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag ); if ( !pDmeModel ) DMXEDIT_ERROR_RETURN_NULL( "Couldn't Find The DmeModel for the mesh: \"%s\"", pDmeMesh->GetName() );
const CUtlVector< Vector > &posData = CDmrArrayConst< Vector >( pDmeBindBaseState->GetVertexData( nBindPosField ) ).Get(); const int nVertexCount = posData.Count();
const CUtlVector< Vector > &editPosData = CDmrArrayConst< Vector >( pDmeEditBaseState->GetVertexData( nEditPosField ) ).Get(); const int nEditVertexCount = editPosData.Count();
Assert( nVertexCount == nEditVertexCount ); if ( nVertexCount != nEditVertexCount ) DMXEDIT_ERROR_RETURN_FALSE( "Base Pos Count: %d Versus Edit Pos Count: %d\n", nVertexCount, nEditVertexCount );
Vector *pVertices = reinterpret_cast< Vector * >( alloca( nVertexCount * sizeof( Vector ) ) );
matrix3x4_t shapeToWorld; SetIdentityMatrix( shapeToWorld );
CDmeModel::s_ModelStack.Push( pDmeModel ); matrix3x4_t *pPoseToWorld = CDmeModel::SetupModelRenderState( shapeToWorld, pDmeBindBaseState->HasSkinningData(), true ); CDmeModel::s_ModelStack.Pop();
CDmeMeshRenderInfo renderInfo( pDmeBindBaseState ); Assert( renderInfo.HasPositionData() );
for ( int i = 0; i < nVertexCount; ++i ) { renderInfo.ComputePosition( i, pPoseToWorld, static_cast< Vector * >( NULL ), pVertices ); }
pDmeEditBaseState->SetVertexData( nEditPosField, 0, nVertexCount, AT_VECTOR3, pVertices );
CDmeModel::CleanupModelRenderState();
return false; }
//-----------------------------------------------------------------------------
// Sets wrinkle deltas from the specified selection
//-----------------------------------------------------------------------------
void SetWrinkleWeight( CDmeVertexData *pDmeBindBaseState, CDmeVertexDeltaData *pDmeDelta, CDmeSingleIndexedComponent *pDmeSelection, float flScale ) { FieldIndex_t nPosIndex = pDmeDelta->FindFieldIndex( CDmeVertexDeltaData::FIELD_POSITION ); if ( nPosIndex < 0 ) return;
FieldIndex_t nBaseTexCoordIndex = pDmeBindBaseState->FindFieldIndex( CDmeVertexData::FIELD_TEXCOORD ); if ( nBaseTexCoordIndex < 0 ) return;
FieldIndex_t nWrinkleIndex = pDmeDelta->FindFieldIndex( CDmeVertexDeltaData::FIELD_WRINKLE ); if ( nWrinkleIndex < 0 ) { nWrinkleIndex = pDmeDelta->CreateField( CDmeVertexDeltaData::FIELD_WRINKLE ); }
const CUtlVector<int> &baseTexCoordIndices = pDmeBindBaseState->GetVertexIndexData( nBaseTexCoordIndex );
CDmrArrayConst<Vector2D> texData( pDmeBindBaseState->GetVertexData( nBaseTexCoordIndex ) ); const int nBaseTexCoordCount = texData.Count(); const int nBufSize = ( ( nBaseTexCoordCount + 7 ) >> 3 ); unsigned char *pUsedBits = (unsigned char*)_alloca( nBufSize ); memset( pUsedBits, 0, nBufSize );
// Construct a temporary array of wrinkle values for the entire mesh
// Same size as the number of texture coordinate values
// 0 means no wrinkle data, so initialize to 0
CUtlVector< float > wrinkleData; wrinkleData.SetCount( nBaseTexCoordCount ); memset( wrinkleData.Base(), 0, wrinkleData.Count() * sizeof( float ) );
// Copy the old wrinkle data if any exists
CDmAttribute *pWrinkleDeltaAttr = pDmeDelta->GetVertexData( nWrinkleIndex ); if ( pWrinkleDeltaAttr ) { CDmrArrayConst< float > wrinkleDeltaArray( pWrinkleDeltaAttr ); if ( wrinkleDeltaArray.Count() ) { const CUtlVector< int > &wrinkleDeltaIndices = pDmeDelta->GetVertexIndexData( nWrinkleIndex ); Assert( wrinkleDeltaIndices.Count() == wrinkleDeltaArray.Count() );
int nWrinkleIndex; for ( int i = 0; i < wrinkleDeltaIndices.Count(); ++i ) { nWrinkleIndex = wrinkleDeltaIndices[ i ]; wrinkleData[ nWrinkleIndex ] = wrinkleDeltaArray[ i ]; } } }
// Write new wrinkle values overtop of existing wrinkle values
int nComponentIndex; float flWeight;
for ( int i = 0; i < pDmeSelection->Count(); ++i ) { if ( !pDmeSelection->GetComponent( i, nComponentIndex, flWeight ) ) continue;
flWeight *= flScale;
// NOTE: This will produce bad behavior in cases where two positions share the
// same texcoord, which shouldn't theoretically happen.
const CUtlVector< int > &baseVerts = pDmeBindBaseState->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_POSITION, nComponentIndex ); for ( int j = 0; j < baseVerts.Count(); ++j ) { // See if we have a delta for this texcoord...
const int nTexCoordIndex = baseTexCoordIndices[ baseVerts[j] ]; if ( pUsedBits[ nTexCoordIndex >> 3 ] & ( 1 << ( nTexCoordIndex & 0x7 ) ) ) continue;
pUsedBits[ nTexCoordIndex >> 3 ] |= 1 << ( nTexCoordIndex & 0x7 );
wrinkleData[ nTexCoordIndex ] = flWeight; } }
// Remove previous wrinkle data (if any exists)
pDmeDelta->RemoveAllVertexData( nWrinkleIndex );
// Write new non-zero wrinkles
for ( int i = 0; i < wrinkleData.Count(); ++i ) { if ( fabs( wrinkleData[ i ] ) < 0.00001 ) continue;
int nDeltaIndex = pDmeDelta->AddVertexData( nWrinkleIndex, 1 ); pDmeDelta->SetVertexIndices( nWrinkleIndex, nDeltaIndex, 1, &i ); pDmeDelta->SetVertexData( nWrinkleIndex, nDeltaIndex, 1, AT_FLOAT, &wrinkleData[ i ] ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetWrinkleWeight( CDmeMesh *pDmeMesh, const char *pszDeltaName, CDmeSingleIndexedComponent *pDmeSelection, float flScale /* = 1.0 */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState(); if ( !BaseStateSanityCheck( pDmeMesh, pDmeBindBaseState, __func__ ) ) return false;
CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName ); if ( !pDmeDelta ) DMXEDIT_WARNING_RETURN_FALSE( "Mesh \"%s\" has no delta named \"%s\"", pDmeMesh->GetName(), pszDeltaName );
if ( !pDmeSelection ) DMXEDIT_WARNING_RETURN_FALSE( "No selection specified\n" );
SetWrinkleWeight( pDmeBindBaseState, pDmeDelta, pDmeSelection, flScale );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
float WrapDeform_ComputeOptimalDistSqr( const CUtlVector< Vector > &iPos, const CUtlVector< Vector > &tPos ) { float flRetDistSqr = 0.0f; float flMaxDistSqr; float flTmpDistSqr;
for ( int i = 0; i < tPos.Count(); ++i ) { flMaxDistSqr = 0.0f; const Vector &vt = tPos[i];
for ( int j = 0; j < iPos.Count(); ++j ) { flTmpDistSqr = vt.DistToSqr( iPos[j] ); if ( flTmpDistSqr > flMaxDistSqr ) { flMaxDistSqr = flTmpDistSqr; } }
if ( flMaxDistSqr > flRetDistSqr ) { flRetDistSqr = flMaxDistSqr; } }
return flRetDistSqr; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CWrapVert { public: CWrapVert() : m_flTotalDist( 0.0f ) {}
void AddInfluenceVert( int nInfluenceVert, float flDistSqr ) { const float flDist = sqrtf( flDistSqr );
if ( Count() < s_nMaxInfluence ) { WrapVert_s &wrapVert = m_wrapVerts[ m_wrapVerts.AddToTail() ]; wrapVert.m_nInfluenceIndex = nInfluenceVert; wrapVert.m_flDist = sqrtf( flDistSqr ); m_flTotalDist += wrapVert.m_flDist; } else { WrapVert_s &wrapVert = m_wrapVerts.Tail(); if ( flDist >= wrapVert.m_flDist ) return;
wrapVert.m_nInfluenceIndex = nInfluenceVert; wrapVert.m_flDist = sqrtf( flDistSqr ); m_flTotalDist = 0.0f; for ( int i = 0; i < m_wrapVerts.Count(); ++i ) { m_flTotalDist += m_wrapVerts[i].m_flDist; } }
qsort( m_wrapVerts.Base(), m_wrapVerts.Count(), sizeof( WrapVert_s ), SortWrapVertFunc ); }
int Count() const { return m_wrapVerts.Count(); }
bool GetInfluenceIndexAndWeight( int &nInfluenceIndex, float &flWeight, int nLocalIndex ) const { const int nCount = Count();
if ( nCount <= 0 || nLocalIndex >= nCount || nLocalIndex < 0 || m_flTotalDist <= 0.0f ) return false;
const WrapVert_s &wrapVert = m_wrapVerts[nLocalIndex]; nInfluenceIndex = wrapVert.m_nInfluenceIndex; if ( nCount == 1 ) { flWeight = 1.0f; } else { float flTotal = 0.0f; for ( int i = 0; i < m_wrapVerts.Count(); ++i ) { flTotal += ( m_flTotalDist - m_wrapVerts[i].m_flDist ); } flWeight = ( m_flTotalDist - wrapVert.m_flDist ) / flTotal; }
return true; }
protected:
static int SortWrapVertFunc( const void *pLhs, const void *pRhs ) { const WrapVert_s &lWrapVert = *reinterpret_cast< const WrapVert_s * >( pLhs ); const WrapVert_s &rWrapVert = *reinterpret_cast< const WrapVert_s * >( pRhs );
if ( lWrapVert.m_flDist < rWrapVert.m_flDist ) return -1;
if ( lWrapVert.m_flDist > rWrapVert.m_flDist ) return 1;
return 0; }
struct WrapVert_s { int m_nInfluenceIndex; float m_flDist; };
CUtlVector< WrapVert_s > m_wrapVerts; float m_flTotalDist;
static int s_nMaxInfluence; };
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int CWrapVert::s_nMaxInfluence = 10;
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void WrapDeform_ComputeInfluence( CUtlVector< CWrapVert > &influenceIndices, const CUtlVector< Vector > &iPos, const CUtlVector< Vector > &tPos, float flMaxDistSqr ) { influenceIndices.SetCount( tPos.Count() );
float flTmpDistSqr;
for ( int i = 0; i < tPos.Count(); ++i ) { const Vector &vt = tPos[i]; CWrapVert &wrapVert = influenceIndices[i];
for ( int j = 0; j < iPos.Count(); ++j ) { flTmpDistSqr = vt.DistToSqr( iPos[j] ); if ( flTmpDistSqr <= flMaxDistSqr ) { wrapVert.AddInfluenceVert( j, flTmpDistSqr ); } } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void WrapDeform_ComputeWrap( CUtlVector< Vector > &tPosCurr, const CUtlVector< CWrapVert > &influenceIndices, const CUtlVector< Vector > &iPosBind, const CUtlVector< Vector > &iPosCurr, const CUtlVector< Vector > &tPosBind ) { Assert( tPosBind.Count() == influenceIndices.Count() );
tPosCurr = tPosBind; // Copy as a default and to set size
int nInfluenceIndex; float flInfluenceWeight; Vector vTemp0; Vector vTemp1;
for ( int i = 0; i < tPosCurr.Count(); ++i ) { Vector &vt = tPosCurr[i];
const CWrapVert &wrapVert = influenceIndices[i]; for ( int j = 0; j < wrapVert.Count(); ++j ) { wrapVert.GetInfluenceIndexAndWeight( nInfluenceIndex, flInfluenceWeight, j ); VectorSubtract( iPosCurr[nInfluenceIndex], iPosBind[nInfluenceIndex], vTemp0 ); VectorScale( vTemp0, flInfluenceWeight, vTemp1 ); VectorAdd( vTemp1, vt, vt ); } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool WrapDeform( CDmeMesh *pDmeInfluenceMesh, CDmeMesh *pDmeTargetMesh ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeInfluenceMesh ); CDmeVertexData *pIBind = pDmeInfluenceMesh->GetBindBaseState(); if ( !BaseStateSanityCheck( pDmeInfluenceMesh, pIBind, __func__ ) ) return false; pIBind->Resolve();
CDmeVertexData *pICurrent = pDmeInfluenceMesh->GetCurrentBaseState(); if ( !BaseStateSanityCheck( pDmeInfluenceMesh, pICurrent, __func__ ) ) return false; pICurrent->Resolve();
if ( pIBind == pICurrent ) DMXEDIT_ERROR_RETURN_FALSE( "Bind base state must be different from current base state on influence mesh in order for Wrap to do anything" );
DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeTargetMesh ); CDmeVertexData *pTBind = pDmeTargetMesh->GetBindBaseState(); if ( !BaseStateSanityCheck( pDmeTargetMesh, pTBind, __func__ ) ) return false; pTBind->Resolve();
CDmeVertexData *pTEdit = FindOrCreateMeshEditBaseState( pDmeTargetMesh, __func__ ); if ( !BaseStateSanityCheck( pDmeTargetMesh, pTEdit, __func__ ) ) return false;
const CUtlVector< Vector > &iPosBind = pIBind->GetPositionData(); const CUtlVector< Vector > &tPosBind = pTBind->GetPositionData();
const float flMinDistSqr = WrapDeform_ComputeOptimalDistSqr( iPosBind, tPosBind ) + 4.0 + FLT_EPSILON;
CUtlVector< CWrapVert > influenceIndices; WrapDeform_ComputeInfluence( influenceIndices, iPosBind, tPosBind, flMinDistSqr );
const CUtlVector< Vector > &iPosCurr = pICurrent->GetPositionData(); CUtlVector< Vector > tPosCurr;
WrapDeform_ComputeWrap( tPosCurr, influenceIndices, iPosBind, iPosCurr, tPosBind );
const int nEditPosField = pTEdit->FindFieldIndex( CDmeVertexData::FIELD_POSITION ); pTEdit->RemoveAllVertexData( nEditPosField ); pTEdit->AddVertexData( nEditPosField, tPosCurr.Count() ); pTEdit->SetVertexData( nEditPosField, 0, tPosCurr.Count(), AT_VECTOR3, tPosCurr.Base() );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
Vector ComputeMean( const CUtlVector< Vector > &pointList ) { Vector vMean; vMean.Zero();
const int nPointCount = pointList.Count(); for ( int i = 0; i < nPointCount; ++i ) { VectorAdd( vMean, pointList[i], vMean ); }
VectorDivide( vMean, static_cast< float >( nPointCount ), vMean );
return vMean; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
matrix3x4_t ComputeCovariantMatrix( const CUtlVector< Vector > &pointList, const Vector &vMean ) { matrix3x4_t mCovariant; SetIdentityMatrix( mCovariant );
const int nPointCount = pointList.Count();
if ( nPointCount <= 0 ) return mCovariant;
CUtlVector< Vector > skewedPointList; skewedPointList = pointList;
Assert( nPointCount == skewedPointList.Count() );
for ( int i = 0; i < nPointCount; ++i ) { VectorSubtract( skewedPointList[i], vMean, skewedPointList[i] ); }
float flCovariance;
for ( int i = 0; i < 3; ++i ) { for ( int j = 0; j < 3; ++j ) { flCovariance = 0.0f;
for ( int k = 0; k < nPointCount; ++k ) { flCovariance += skewedPointList[k][i] * skewedPointList[k][j]; }
mCovariant[i][j] = flCovariance / static_cast< float >( nPointCount ); } }
return mCovariant; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
matrix3x4_t ComputeCovariantMatrix( const CUtlVector< Vector > &pointList ) { const Vector vMean = ComputeMean( pointList );
return ComputeCovariantMatrix( pointList, vMean ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool MergeMeshAndSkeleton( CDmeMesh *pDstMesh, CDmeMesh *pSrcMesh ) { return CDmMeshUtils::MergeMeshAndSkeleton( pDstMesh, pSrcMesh ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool FlexLocalVar( CDmeMesh *pDmeMesh, const char *pszFlexRuleLocalVar ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeFlexRules *pDmeFlexRules = FindOrAddDmeFlexRules( pDmeMesh ); if ( !pDmeFlexRules ) DMXEDIT_WARNING_RETURN_FALSE( "DmeFlexRules could not be created for mesh \"%s\"", pDmeMesh->GetName() );
CDmeFlexRuleLocalVar *pDmeFlexRuleLocalVar = CreateElement< CDmeFlexRuleLocalVar >( pszFlexRuleLocalVar, pDmeMesh->GetFileId() ); pDmeFlexRules->AddFlexRule( pDmeFlexRuleLocalVar );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool FlexRuleExpression( CDmeMesh *pDmeMesh, const char *pszExpression ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeFlexRules *pDmeFlexRules = FindOrAddDmeFlexRules( pDmeMesh ); if ( !pDmeFlexRules ) DMXEDIT_WARNING_RETURN_FALSE( "DmeFlexRules could not be created for mesh \"%s\"", pDmeMesh->GetName() );
char szBuf[ 512 ]; if ( sscanf( pszExpression, "%512s =", szBuf ) != 1 ) DMXEDIT_WARNING_RETURN_FALSE( "Improperly formatted expression: \"%s\"", pszExpression );
CDmeFlexRuleExpression *pDmeFlexRuleExpression = CreateElement< CDmeFlexRuleExpression >( szBuf, pDmeMesh->GetFileId() ); pDmeFlexRuleExpression->SetExpression( pszExpression ); pDmeFlexRules->AddFlexRule( pDmeFlexRuleExpression );
return true; }
//-----------------------------------------------------------------------------
// Returns the CDmeFlexRules ultimately controlling the specified
// DmeMesh by searched backwards on elements referring to "targets" or "target"
// Returns NULL if not found
//-----------------------------------------------------------------------------
static CDmeFlexRules *GetFlexRulesForMesh( CDmeMesh *pDmeMesh ) { if ( !pDmeMesh ) return NULL;
CUtlRBTree< CDmElement * > visited( CDefOps< CDmElement * >::LessFunc ); visited.Insert( pDmeMesh );
const CUtlSymbolLarge sTargets = g_pDataModel->GetSymbol( "targets" ); const CUtlSymbolLarge sTarget = g_pDataModel->GetSymbol( "target" );
CDmElement *pDmThisElement = pDmeMesh; CDmElement *pDmNextElement = NULL;
while ( pDmThisElement ) { pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTargets ); if ( !pDmNextElement ) { pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTarget ); }
if ( !pDmNextElement ) break;
pDmThisElement = pDmNextElement;
if ( CastElement< CDmeFlexRules >( pDmThisElement ) ) return CastElement< CDmeFlexRules >( pDmThisElement );
if ( visited.IsValidIndex( visited.Find( pDmThisElement ) ) ) break;
visited.Insert( pDmThisElement ); }
return NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeFlexRules *FindOrAddDmeFlexRules( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeFlexRules *pDmeFlexRules = GetFlexRulesForMesh( pDmeMesh ); if ( pDmeFlexRules ) return pDmeFlexRules;
CDmeCombinationOperator *pDmeComboOp = FindOrCreateComboOp( pDmeMesh ); if ( !pDmeComboOp ) DMXEDIT_WARNING_RETURN_NULL( "DmeCombinationOperator could not be created for mesh \"%s\"", pDmeMesh->GetName() );
CUtlString flexRulesName = pDmeMesh->GetName(); flexRulesName += "_flexRules";
pDmeFlexRules = CreateElement< CDmeFlexRules >( flexRulesName.Get(), pDmeMesh->GetFileId() ); if ( !pDmeFlexRules ) DMXEDIT_WARNING_RETURN_NULL( "DmeFlexRules could not be created for mesh \"%s\"", pDmeMesh->GetName() );
pDmeComboOp->RemoveAllTargets();
pDmeComboOp->AddTarget( pDmeFlexRules );
pDmeFlexRules->SetTarget( pDmeMesh );
return pDmeFlexRules; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
ControlIndex_t FlexControl( CDmeMesh *pDmeMesh, const char *pszName, float flMin /* = 0.0f */, float flMax /* = 1.0f */ ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeComboOp = FindOrCreateComboOp( pDmeMesh ); if ( !pDmeComboOp ) DMXEDIT_WARNING_RETURN_FALSE( "DmeCombinationOperator could not be created for mesh \"%s\"", pDmeMesh->GetName() );
const ControlIndex_t nIndex = pDmeComboOp->FindOrCreateControl( pszName, false, true );
if ( nIndex >= 0 && ( flMin != 0.0f || flMax != 1.0f ) ) { SetControlMinMax( pDmeMesh, nIndex, flMin, flMax ); }
return nIndex; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetControlMinMax( CDmeMesh *pDmeMesh, ControlIndex_t nControlIndex, float flMin, float flMax ) { DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
CDmeCombinationOperator *pDmeComboOp = FindOrCreateComboOp( pDmeMesh ); if ( !pDmeComboOp ) DMXEDIT_WARNING_RETURN_FALSE( "DmeCombinationOperator could not be created for mesh \"%s\"", pDmeMesh->GetName() );
CDmAttribute *pControlsAttr = pDmeComboOp->GetAttribute( "controls", AT_ELEMENT_ARRAY ); if ( !pControlsAttr ) DMXEDIT_WARNING_RETURN_FALSE( "No 'controls' attribute on ComboOp \"%s\"", pDmeComboOp->GetName() );
CDmrElementArray< CDmElement > controlsAttr( pControlsAttr ); if ( nControlIndex < controlsAttr.Count() ) { CDmElement *pControlElement = controlsAttr[ nControlIndex ]; if ( pControlElement ) { pControlElement->SetValue( "flexMin", flMin ); pControlElement->SetValue( "flexMax", flMax ); } }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static CDmeModel *GetDmeModel( CDmeMesh *pDmeMesh ) { if ( !pDmeMesh ) return NULL;
// Find the DmeModel of the destination mesh scene
CDmeDag *pDmeDag = pDmeMesh->GetParent(); while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) ) { pDmeDag = pDmeDag->GetParent(); }
return CastElement< CDmeModel >( pDmeDag ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmAttribute *GetQcModelElementsAttr( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeModel *pDmeModel = GetDmeModel( pDmeMesh ); if ( !pDmeModel ) DMXEDIT_WARNING_RETURN_NULL( "Can't Find DmeModel for mesh \"%s\"", pDmeMesh->GetName() );
CDmAttribute *pDmAttr = pDmeModel->GetAttribute( "qcModelElements" ); if ( !pDmAttr ) { pDmAttr = pDmeModel->AddAttribute( "qcModelElements", AT_ELEMENT_ARRAY ); }
if ( !pDmAttr || pDmAttr->GetType() != AT_ELEMENT_ARRAY ) DMXEDIT_WARNING_RETURN_NULL( "Can't find or create %s.qcModelElements element array attribute", pDmeModel->GetName() );
return pDmAttr; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Eyeball( CDmeMesh *pDmeMesh, const char *pszName, const char *pszBoneName, const Vector &vPosition, const char *pszMaterialName, const float flDiameter, const float flAngle, const float flPupilScale ) { CDmAttribute *pDmAttr = GetQcModelElementsAttr( pDmeMesh ); if ( !pDmAttr ) return false;
CDmrElementArray<> qcModelElements( pDmAttr );
CDmeEyeball *pDmeEyeball = CreateElement< CDmeEyeball >( pszName, pDmAttr->GetOwner()->GetFileId() ); if ( !pDmeEyeball ) DMXEDIT_WARNING_RETURN_FALSE( "Can't create DmeEyeball element" );
pDmeEyeball->m_sParentBoneName.Set( pszBoneName ); pDmeEyeball->m_vPosition.Set( vPosition ); pDmeEyeball->m_sMaterialName.Set( pszMaterialName ); pDmeEyeball->m_flRadius.Set( flDiameter / 2.0f ); pDmeEyeball->m_flYawAngle.Set( flAngle ); pDmeEyeball->m_flIrisScale.Set( flPupilScale );
qcModelElements.AddToTail( pDmeEyeball );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Eyelid( CDmeMesh *pDmeMesh, bool bUpper, const char *pszLowererFlex, float flLowererHeight, const char *pszNeutralFlex, float flNeutralHeight, const char *pszRaiserFlex, float flRaiserHeight, const char *pszRightMaterialName, const char *pszLeftMaterialName ) { CDmAttribute *pDmAttr = GetQcModelElementsAttr( pDmeMesh ); if ( !pDmAttr ) return false;
CDmrElementArray<> qcModelElements( pDmAttr );
CDmeEyelid *pDmeEyelid = CreateElement< CDmeEyelid >( bUpper ? "upper" : "lower", pDmAttr->GetOwner()->GetFileId() ); if ( !pDmeEyelid ) DMXEDIT_WARNING_RETURN_FALSE( "Can't create DmeEyelid element" );
pDmeEyelid->m_bUpper.Set( bUpper ); pDmeEyelid->m_sLowererFlex.Set( pszLowererFlex ); pDmeEyelid->m_flLowererHeight.Set( flLowererHeight ); pDmeEyelid->m_sNeutralFlex.Set( pszNeutralFlex ); pDmeEyelid->m_flNeutralHeight.Set( flNeutralHeight ); pDmeEyelid->m_sRaiserFlex.Set( pszRaiserFlex ); pDmeEyelid->m_flRaiserHeight.Set( flRaiserHeight ); pDmeEyelid->m_sRightEyeballName.Set( pszRightMaterialName ); pDmeEyelid->m_sLeftEyeballName.Set( pszLeftMaterialName );
qcModelElements.AddToTail( pDmeEyelid );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool Mouth( CDmeMesh *pDmeMesh, int nMouthNumber, const char *pszFlexControllerName, const char *pszBoneName, const Vector &vForward ) { CDmAttribute *pDmAttr = GetQcModelElementsAttr( pDmeMesh ); if ( !pDmAttr ) return false;
CDmrElementArray<> qcModelElements( pDmAttr );
CUtlString sMouthName( "mouth" ); sMouthName += nMouthNumber;
CDmeMouth *pDmeMouth = CreateElement< CDmeMouth >( sMouthName.Get(), pDmAttr->GetOwner()->GetFileId() ); if ( !pDmeMouth ) DMXEDIT_WARNING_RETURN_FALSE( "Can't create DmeMouth element" );
pDmeMouth->m_nMouthNumber.Set( nMouthNumber ); pDmeMouth->m_sFlexControllerName.Set( pszFlexControllerName ); pDmeMouth->m_sBoneName.Set( pszBoneName ); pDmeMouth->m_vForward.Set( vForward );
qcModelElements.AddToTail( pDmeMouth );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ClearFlexRules( CDmeMesh *pDmeMesh ) { DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
CDmeFlexRules *pDmeFlexRules = GetFlexRulesForMesh( pDmeMesh ); if ( pDmeFlexRules ) { pDmeFlexRules->RemoveAllRules(); }
CDmeCombinationOperator *pDmeComboOp = GetComboOpFromMesh( pDmeMesh ); if ( pDmeComboOp ) { pDmeComboOp->RemoveAllControls(); }
return true; }
|