From 3bf9df6b2785fa6d951086978a3e66f49427166a Mon Sep 17 00:00:00 2001 From: FluorescentCIAAfricanAmerican <0934gj3049fk@protonmail.com> Date: Wed, 22 Apr 2020 12:56:21 -0400 Subject: 1 --- utils/hlmv/studio_render.cpp | 2368 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2368 insertions(+) create mode 100644 utils/hlmv/studio_render.cpp (limited to 'utils/hlmv/studio_render.cpp') diff --git a/utils/hlmv/studio_render.cpp b/utils/hlmv/studio_render.cpp new file mode 100644 index 0000000..340ec67 --- /dev/null +++ b/utils/hlmv/studio_render.cpp @@ -0,0 +1,2368 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// studio_render.cpp: routines for drawing Half-Life 3DStudio models +// updates: +// 1-4-99 fixed AdvanceFrame wraping bug + +#include +#include +#include +#include + +#include // for OutputDebugString. . has to be a better way! + + +#include "ViewerSettings.h" +#include "StudioModel.h" +#include "vphysics/constraints.h" +#include "physmesh.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "matsyswin.h" +#include "istudiorender.h" +#include "utldict.h" +#include "filesystem.h" +#include "studio_render.h" +#include "materialsystem/imesh.h" +#include "bone_setup.h" +#include "materialsystem/MaterialSystem_Config.h" +#include "MDLViewer.h" +#include "bone_accessor.h" +#include "jigglebones.h" +#include "debugdrawmodel.h" + +// FIXME: +extern ViewerSettings g_viewerSettings; +int g_dxlevel = 0; + +#pragma warning( disable : 4244 ) // double to float + +//////////////////////////////////////////////////////////////////////// + +CStudioHdr *g_pCacheHdr = NULL; + +Vector g_flexedverts[MAXSTUDIOVERTS]; +Vector g_flexednorms[MAXSTUDIOVERTS]; +int g_flexages[MAXSTUDIOVERTS]; + +Vector *g_pflexedverts; +Vector *g_pflexednorms; +int *g_pflexages; + +int g_smodels_total; // cookie + +matrix3x4_t g_viewtransform; // view transformation +//matrix3x4_t g_posetoworld[MAXSTUDIOBONES]; // bone transformation matrix +matrix3x4_t g_mCachedViewTransform; // copy of view transform for boneMerge passes + +static int maxNumVertices; +static int first = 1; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +mstudioseqdesc_t &StudioModel::GetSeqDesc( int seq ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + return pStudioHdr->pSeqdesc( seq ); +} + +mstudioanimdesc_t &StudioModel::GetAnimDesc( int anim ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + return pStudioHdr->pAnimdesc( anim ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Keeps a global clock to autoplay sequences to run from +// Also deals with speedScale changes +//----------------------------------------------------------------------------- +float GetAutoPlayTime( void ) +{ + static int g_prevTicks; + static float g_time; + + int ticks = GetTickCount(); + // limit delta so that float time doesn't overflow + if (g_prevTicks == 0) + g_prevTicks = ticks; + + g_time += ( (ticks - g_prevTicks) / 1000.0f ) * g_viewerSettings.speedScale; + g_prevTicks = ticks; + + return g_time; +} + + +//----------------------------------------------------------------------------- +// Purpose: Keeps a global clock for "realtime" overlays to run from +//----------------------------------------------------------------------------- +float GetRealtimeTime( void ) +{ + // renamed static's so debugger doesn't get confused and show the wrong one + static int g_prevTicksRT; + static float g_timeRT; + + int ticks = GetTickCount(); + // limit delta so that float time doesn't overflow + if (g_prevTicksRT == 0) + g_prevTicksRT = ticks; + + g_timeRT += ( (ticks - g_prevTicksRT) / 1000.0f ); + g_prevTicksRT = ticks; + + return g_timeRT; +} + +void StudioModel::AdvanceFrame( float dt ) +{ + if (dt > 0.1) + dt = 0.1f; + + m_dt = dt; + + float t = GetDuration( ); + + if (t > 0) + { + if (dt > 0) + { + m_cycle += dt / t; + m_sequencetime += dt; + + // wrap + m_cycle -= (int)(m_cycle); + } + } + else + { + m_cycle = 0; + } + + + for (int i = 0; i < MAXSTUDIOANIMLAYERS; i++) + { + t = GetDuration( m_Layer[i].m_sequence ); + if (t > 0) + { + if (dt > 0) + { + m_Layer[i].m_cycle += (dt / t) * m_Layer[i].m_playbackrate; + m_Layer[i].m_cycle -= (int)(m_Layer[i].m_cycle); + } + } + else + { + m_Layer[i].m_cycle = 0; + } + } +} + +float StudioModel::GetInterval( void ) +{ + return m_dt; +} + +float StudioModel::GetCycle( void ) +{ + return m_cycle; +} + +float StudioModel::GetFrame( void ) +{ + return GetCycle() * GetMaxFrame(); +} + +int StudioModel::GetMaxFrame( void ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + return Studio_MaxFrame( pStudioHdr, m_sequence, m_poseparameter ); +} + +int StudioModel::SetFrame( int frame ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + if ( !pStudioHdr ) + return 0; + + if ( frame <= 0 ) + frame = 0; + + int maxFrame = GetMaxFrame(); + if ( frame >= maxFrame ) + { + frame = maxFrame; + m_cycle = 0.99999; + return frame; + } + + m_cycle = frame / (float)maxFrame; + return frame; +} + + +float StudioModel::GetCycle( int iLayer ) +{ + if (iLayer == 0) + { + return m_cycle; + } + else if (iLayer <= MAXSTUDIOANIMLAYERS) + { + int index = iLayer - 1; + return m_Layer[index].m_cycle; + } + return 0; +} + + +float StudioModel::GetFrame( int iLayer ) +{ + return GetCycle( iLayer ) * GetMaxFrame( iLayer ); +} + + +int StudioModel::GetMaxFrame( int iLayer ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + if ( pStudioHdr ) + { + if (iLayer == 0) + return Studio_MaxFrame( pStudioHdr, m_sequence, m_poseparameter ); + + if (iLayer <= MAXSTUDIOANIMLAYERS) + { + int index = iLayer - 1; + return Studio_MaxFrame( pStudioHdr, m_Layer[index].m_sequence, m_poseparameter ); + } + } + + return 0; +} + + +int StudioModel::SetFrame( int iLayer, int frame ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + if ( !pStudioHdr ) + return 0; + + if ( frame <= 0 ) + frame = 0; + + int maxFrame = GetMaxFrame( iLayer ); + float cycle = 0; + if (maxFrame) + { + if ( frame >= maxFrame ) + { + frame = maxFrame; + cycle = 0.99999; + } + cycle = frame / (float)maxFrame; + } + + if (iLayer == 0) + { + m_cycle = cycle; + } + else if (iLayer <= MAXSTUDIOANIMLAYERS) + { + int index = iLayer - 1; + m_Layer[index].m_cycle = cycle; + } + + return frame; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Maps from local axis (X,Y,Z) to Half-Life (PITCH,YAW,ROLL) axis/rotation mappings +//----------------------------------------------------------------------------- +static int RemapAxis( int axis ) +{ + switch( axis ) + { + case 0: + return 2; + case 1: + return 0; + case 2: + return 1; + } + + return 0; +} + +void StudioModel::Physics_SetPreview( int previewBone, int axis, float t ) +{ + m_physPreviewBone = previewBone; + m_physPreviewAxis = axis; + m_physPreviewParam = t; +} + + +void StudioModel::OverrideBones( bool *override ) +{ + matrix3x4_t basematrix; + matrix3x4_t bonematrix; + + QAngle tmp; + // offset for the base pose to world transform of 90 degrees around up axis + tmp[0] = 0; tmp[1] = 90; tmp[2] = 0; + AngleMatrix( tmp, bonematrix ); + ConcatTransforms( g_viewtransform, bonematrix, basematrix ); + + for ( int i = 0; i < m_pPhysics->Count(); i++ ) + { + CPhysmesh *pmesh = m_pPhysics->GetMesh( i ); + // BUGBUG: Cache this if you care about performance! + int boneIndex = FindBone(pmesh->m_boneName); + + // bone is not constrained, don't override rotations + if ( pmesh->m_constraint.parentIndex == 0 && pmesh->m_constraint.childIndex == 0 ) + { + boneIndex = -1; + } + + if ( boneIndex >= 0 ) + { + matrix3x4_t *parentMatrix = &basematrix; + override[boneIndex] = true; + int parentBone = -1; + if ( pmesh->m_constraint.parentIndex >= 0 ) + { + parentBone = FindBone( m_pPhysics->GetMesh(pmesh->m_constraint.parentIndex)->m_boneName ); + } + if ( parentBone >= 0 ) + { + parentMatrix = &m_pBoneToWorld[ parentBone ]; + } + + if ( m_physPreviewBone == i ) + { + matrix3x4_t tmpmatrix; + QAngle rot; + constraint_axislimit_t *axis = pmesh->m_constraint.axes + m_physPreviewAxis; + + int hlAxis = RemapAxis( m_physPreviewAxis ); + rot.Init(); + rot[hlAxis] = axis->minRotation + (axis->maxRotation - axis->minRotation) * m_physPreviewParam; + AngleMatrix( rot, tmpmatrix ); + ConcatTransforms( pmesh->m_matrix, tmpmatrix, bonematrix ); + } + else + { + MatrixCopy( pmesh->m_matrix, bonematrix ); + } + + ConcatTransforms( *parentMatrix, bonematrix, m_pBoneToWorld[ boneIndex ] ); + } + } +} + + +int StudioModel::BoneMask( void ) +{ + int lod = g_viewerSettings.autoLOD ? 0 : g_viewerSettings.lod; + + int mask = BONE_USED_BY_VERTEX_AT_LOD(lod); + if (g_viewerSettings.showAttachments || g_viewerSettings.m_iEditAttachment != -1 || m_nSolveHeadTurn != 0 || LookupAttachment( "eyes" ) != -1) + { + mask |= BONE_USED_BY_ATTACHMENT; + } + + if (g_viewerSettings.showHitBoxes) + { + mask |= BONE_USED_BY_HITBOX; + } + + mask |= BONE_USED_BY_BONE_MERGE; + + return mask; + // return BONE_USED_BY_ANYTHING_AT_LOD( lod ); + + // return BONE_USED_BY_ANYTHING; +} + +void StudioModel::SetUpBones( bool mergeBones ) +{ + int i, j; + + mstudiobone_t *pbones; + + static Vector pos[MAXSTUDIOBONES]; + matrix3x4_t bonematrix; + static Quaternion q[MAXSTUDIOBONES]; + bool override[MAXSTUDIOBONES]; + + static matrix3x4_t boneCache[MAXSTUDIOBONES]; + + // For blended transitions + static Vector pos2[MAXSTUDIOBONES]; + static Quaternion q2[MAXSTUDIOBONES]; + + CStudioHdr *pStudioHdr = GetStudioHdr(); + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_sequence ); + + QAngle a1; + Vector p1; + MatrixAngles( g_viewtransform, a1, p1 ); + CIKContext *pIK = NULL; + m_ik.Init( pStudioHdr, a1, p1, GetRealtimeTime(), m_iFramecounter, BoneMask( ) ); + if ( g_viewerSettings.enableIK ) + { + pIK = &m_ik; + } + + IBoneSetup boneSetup( pStudioHdr, BoneMask(), m_poseparameter ); + + boneSetup.InitPose( pos, q ); + + boneSetup.AccumulatePose( pos, q, m_sequence, m_cycle, 1.0, GetRealtimeTime(), pIK ); + + if ( g_viewerSettings.blendSequenceChanges && + m_sequencetime < m_blendtime && + m_prevsequence != m_sequence && + m_prevsequence < pStudioHdr->GetNumSeq() && + !(seqdesc.flags & STUDIO_SNAP) ) + { + // Make sure frame is valid + if ( m_prevcycle >= 1.0 ) + { + m_prevcycle = 0.0f; + } + + float s = 1.0 - ( m_sequencetime / m_blendtime ); + s = 3 * s * s - 2 * s * s * s; + + boneSetup.AccumulatePose( pos, q, m_prevsequence, m_prevcycle, s, GetRealtimeTime(), NULL ); + // Con_DPrintf("%d %f : %d %f : %f\n", pev->sequence, f, pev->prevsequence, pev->prevframe, s ); + } + else + { + m_prevcycle = m_cycle; + } + + int iMaxPriority = 0; + for (i = 0; i < MAXSTUDIOANIMLAYERS; i++) + { + if (m_Layer[i].m_weight > 0) + { + iMaxPriority = max( m_Layer[i].m_priority, iMaxPriority ); + } + } + + for (j = 0; j <= iMaxPriority; j++) + { + for (i = 0; i < MAXSTUDIOANIMLAYERS; i++) + { + if (m_Layer[i].m_priority == j && m_Layer[i].m_weight > 0) + { + boneSetup.AccumulatePose( pos, q, m_Layer[i].m_sequence, m_Layer[i].m_cycle, m_Layer[i].m_weight, GetRealtimeTime(), pIK ); + } + } + } + + if (m_nSolveHeadTurn != 0) + { + GetBodyPoseParametersFromFlex( ); + } + + CalcHeadRotation( pos, q ); + + CIKContext auto_ik; + auto_ik.Init( pStudioHdr, a1, p1, 0.0, 0, BoneMask( ) ); + boneSetup.CalcAutoplaySequences( pos, q, GetAutoPlayTime(), &auto_ik ); + + boneSetup.CalcBoneAdj( pos, q, m_controller ); + + CBoneBitList boneComputed; + if (pIK) + { + Vector deltaPos; + QAngle deltaAngles; + + GetMovement( m_prevIKCycles, deltaPos, deltaAngles ); + + Vector tmp; + VectorRotate( deltaPos, g_viewtransform, tmp ); + deltaPos = tmp; + + pIK->UpdateTargets( pos, q, m_pBoneToWorld, boneComputed ); + + // FIXME: check number of slots? + for (int i = 0; i < pIK->m_target.Count(); i++) + { + trace_t tr; + CIKTarget *pTarget = &pIK->m_target[i]; + + switch( pTarget->type ) + { + case IK_GROUND: + { + // drawLine( pTarget->est.pos, pTarget->est.pos + pTarget->offset.pos, 0, 255, 0 ); + + // hack in movement + pTarget->est.pos -= deltaPos; + + matrix3x4_t invViewTransform; + MatrixInvert( g_viewtransform, invViewTransform ); + Vector tmp; + VectorTransform( pTarget->est.pos, invViewTransform, tmp ); + tmp.z = pTarget->est.floor; + VectorTransform( tmp, g_viewtransform, pTarget->est.pos ); + Vector p1; + Quaternion q1; + MatrixAngles( g_viewtransform, q1, p1 ); + pTarget->est.q = q1; + + float color[4] = { 0, 0, 0, 0 }; + float wirecolor[4] = { 1, 1, 0, 1 }; + if (pTarget->est.latched > 0.0) + { + wirecolor[1] = 1.0 - pTarget->est.flWeight; + } + else + { + wirecolor[0] = 1.0 - pTarget->est.flWeight; + } + + float r = max(pTarget->est.radius,1.f); + Vector p0 = tmp + Vector( -r, -r, 0 ); + Vector p2 = tmp + Vector( r, r, 0 ); + drawTransparentBox( p0, p2, g_viewtransform, color, wirecolor ); + + + if (!g_viewerSettings.enableTargetIK) + { + pTarget->est.flWeight = 0.0; + } + } + break; + case IK_ATTACHMENT: + { + matrix3x4_t m; + + QuaternionMatrix( pTarget->est.q, pTarget->est.pos, m ); + + drawTransform( m, 4 ); + } + break; + } + + // drawLine( pTarget->est.pos, pTarget->latched.pos, 255, 0, 0 ); + } + + pIK->SolveDependencies( pos, q, m_pBoneToWorld, boneComputed ); + } + + pbones = pStudioHdr->pBone( 0 ); + + memset( override, 0, sizeof(bool)*pStudioHdr->numbones() ); + + if ( g_viewerSettings.showPhysicsPreview ) + { + OverrideBones( override ); + } + + for (i = 0; i < pStudioHdr->numbones(); i++) + { + if ( !(pStudioHdr->pBone( i )->flags & BoneMask())) + { + int j, k; + for (j = 0; j < 3; j++) + { + for (k = 0; k < 4; k++) + { + m_pBoneToWorld[i][j][k] = VEC_T_NAN; + } + } + continue; + } + + if ( override[i] ) + { + continue; + } + else if (boneComputed.IsBoneMarked(i)) + { + // already calculated + } + else if (CalcProceduralBone( pStudioHdr, i, CBoneAccessor( m_pBoneToWorld ) )) + { + continue; + } + else + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if ( (pStudioHdr->pBone( 0 )[i].flags & BONE_ALWAYS_PROCEDURAL) && + (pStudioHdr->pBone( 0 )[i].proctype & STUDIO_PROC_JIGGLE) ) + { + // + // Physics-based "jiggle" bone + // Bone is assumed to be along the Z axis + // Pitch around X, yaw around Y + // + + // compute desired bone orientation + matrix3x4_t goalMX; + + if (pbones[i].parent == -1) + { + ConcatTransforms( g_viewtransform, bonematrix, goalMX ); + } + else + { + ConcatTransforms( m_pBoneToWorld[ pbones[i].parent ], bonematrix, goalMX ); + } + + // get jiggle properties from QC data + mstudiojigglebone_t *jiggleInfo = (mstudiojigglebone_t *)pStudioHdr->pBone( 0 )[i].pProcedure( ); + + if (!m_pJiggleBones) + { + m_pJiggleBones = new CJiggleBones; + } + + // do jiggle physics + m_pJiggleBones->BuildJiggleTransformations( i, GetRealtimeTime(), jiggleInfo, goalMX, m_pBoneToWorld[ i ] ); + } + else if (pbones[i].parent == -1) + { + ConcatTransforms( g_viewtransform, bonematrix, m_pBoneToWorld[ i ] ); + // MatrixCopy(bonematrix, g_bonetoworld[i]); + } + else + { + ConcatTransforms( m_pBoneToWorld[ pbones[i].parent ], bonematrix, m_pBoneToWorld[ i ] ); + } + } + + if (!mergeBones) + { + g_pCacheHdr = pStudioHdr; + MatrixCopy( m_pBoneToWorld[ i ], boneCache[i] ); + } + else if (g_pCacheHdr) + { + for (j = 0; j < g_pCacheHdr->numbones(); j++) + { + if ( Q_stricmp( pStudioHdr->pBone( i )->pszName(), g_pCacheHdr->pBone( j )->pszName() ) == 0 ) + break; + } + if (j < g_pCacheHdr->numbones()) + { + MatrixCopy( boneCache[j], m_pBoneToWorld[ i ] ); + } + } + } + + if ( mergeBones ) + { + Studio_RunBoneFlexDrivers( m_flexweight, pStudioHdr, pos, m_pBoneToWorld, g_mCachedViewTransform ); + } + else + { + MatrixCopy( g_viewtransform, g_mCachedViewTransform ); + Studio_RunBoneFlexDrivers( m_flexweight, pStudioHdr, pos, m_pBoneToWorld, g_viewtransform ); + } + + if (g_viewerSettings.showAttachments) + { + // drawTransform( m_pBoneToWorld[ 0 ] ); + } +} + + + +/* +================ +StudioModel::SetupLighting + set some global variables based on entity position +inputs: +outputs: +================ +*/ +void StudioModel::SetupLighting ( ) +{ + LightDesc_t light[2]; + + light[0].m_Type = MATERIAL_LIGHT_DIRECTIONAL; + light[0].m_Attenuation0 = 1.0f; + light[0].m_Attenuation1 = 0.0; + light[0].m_Attenuation2 = 0.0; + light[0].m_Color[0] = g_viewerSettings.lColor[0]; + light[0].m_Color[1] = g_viewerSettings.lColor[1]; + light[0].m_Color[2] = g_viewerSettings.lColor[2]; + light[0].m_Range = 2000; + + // DEBUG: Spin the light around the head for debugging +// g_viewerSettings.lightrot = QAngle( 0, 0, 0 ); +// g_viewerSettings.lightrot.y = fmod( (90 * GetTickCount( ) / 1000.0), 360.0); + + AngleVectors( g_viewerSettings.lightrot, &light[0].m_Direction, NULL, NULL ); + g_pStudioRender->SetLocalLights( 1, light ); + +#if 0 + light[1].m_Type = MATERIAL_LIGHT_DIRECTIONAL; + light[1].m_Attenuation0 = 1.0f; + light[1].m_Attenuation1 = 0.0; + light[1].m_Attenuation2 = 0.0; + light[1].m_Range = 2000; + light[1].m_Color[0] = g_viewerSettings.lColor[2]; + light[1].m_Color[1] = g_viewerSettings.lColor[1]; + light[1].m_Color[2] = g_viewerSettings.lColor[0]; + light[1].m_Direction.x = -light[0].m_Direction.y; + light[1].m_Direction.y = light[0].m_Direction.x; + light[1].m_Direction.z = light[0].m_Direction.z; + g_pStudioRender->SetLocalLights( 2, light ); +#endif + + int i; + for( i = 0; i < g_pStudioRender->GetNumAmbientLightSamples(); i++ ) + { + m_AmbientLightColors[i][0] = g_viewerSettings.aColor[0]; + m_AmbientLightColors[i][1] = g_viewerSettings.aColor[1]; + m_AmbientLightColors[i][2] = g_viewerSettings.aColor[2]; + } + + //m_AmbientLightColors[0][0] = 1.0; + //m_AmbientLightColors[0][1] = 1.0; + //m_AmbientLightColors[0][2] = 1.0; + + g_pStudioRender->SetAmbientLightColors( m_AmbientLightColors ); +} + + +int FindBoneIndex( CStudioHdr *pstudiohdr, const char *pName ) +{ + mstudiobone_t *pbones = pstudiohdr->pBone( 0 ); + for (int i = 0; i < pstudiohdr->numbones(); i++) + { + if ( !strcmpi( pName, pbones[i].pszName() ) ) + return i; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: Find the named bone index, -1 if not found +// Input : *pName - bone name +//----------------------------------------------------------------------------- +int StudioModel::FindBone( const char *pName ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + return FindBoneIndex( pStudioHdr, pName ); +} + + +int StudioModel::Physics_GetBoneIndex( const char *pName ) +{ + for (int i = 0; i < m_pPhysics->Count(); i++) + { + CPhysmesh *pmesh = m_pPhysics->GetMesh(i); + if ( !strcmpi( pName, pmesh[i].m_boneName ) ) + return i; + } + + return -1; +} + + +/* +================= +StudioModel::SetupModel + based on the body part, figure out which mesh it should be using. +inputs: + currententity +outputs: + pstudiomesh + pmdl +================= +*/ + +void StudioModel::SetupModel ( int bodypart ) +{ + int index; + + CStudioHdr *pStudioHdr = GetStudioHdr(); + if (bodypart > pStudioHdr->numbodyparts()) + { + // Con_DPrintf ("StudioModel::SetupModel: no such bodypart %d\n", bodypart); + bodypart = 0; + } + + mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( bodypart ); + + index = m_bodynum / pbodypart->base; + index = index % pbodypart->nummodels; + + m_pmodel = pbodypart->pModel( index ); + + if(first){ + maxNumVertices = m_pmodel->numvertices; + first = 0; + } +} + + +static IMaterial *g_pAlpha; + + +//----------------------------------------------------------------------------- +// Draws a box, not wireframed +//----------------------------------------------------------------------------- + +void StudioModel::drawBox (Vector const *v, float const * color ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + + CMeshBuilder meshBuilder; + + // The four sides + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 * 4 ); + for (int i = 0; i < 10; i++) + { + meshBuilder.Position3fv (v[i & 7].Base() ); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + } + meshBuilder.End(); + pMesh->Draw(); + + // top and bottom + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 ); + + meshBuilder.Position3fv (v[6].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[0].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[4].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[2].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 ); + + meshBuilder.Position3fv (v[1].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[7].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[3].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[5].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Draws a wireframed box +//----------------------------------------------------------------------------- + +void StudioModel::drawWireframeBox (Vector const *v, float const* color ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + + CMeshBuilder meshBuilder; + + // The four sides + meshBuilder.Begin( pMesh, MATERIAL_LINES, 4 ); + for (int i = 0; i < 10; i++) + { + meshBuilder.Position3fv (v[i & 7].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + } + meshBuilder.End(); + pMesh->Draw(); + + // top and bottom + meshBuilder.Begin( pMesh, MATERIAL_LINE_STRIP, 4 ); + + meshBuilder.Position3fv (v[6].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[0].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[2].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[4].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[6].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + + meshBuilder.Begin( pMesh, MATERIAL_LINE_STRIP, 4 ); + + meshBuilder.Position3fv (v[1].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[7].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[5].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[3].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv (v[1].Base()); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Draws the position and axies of a transformation matrix, x=red,y=green,z=blue +//----------------------------------------------------------------------------- +void StudioModel::drawTransform( matrix3x4_t& m, float flLength ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + + for (int k = 0; k < 3; k++) + { + static unsigned char color[3][3] = + { + { 255, 0, 0 }, + { 0, 255, 0 }, + { 0, 0, 255 } + }; + + meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 ); + + meshBuilder.Color3ubv( color[k] ); + meshBuilder.Position3f( m[0][3], m[1][3], m[2][3]); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3ubv( color[k] ); + meshBuilder.Position3f( m[0][3] + m[0][k] * flLength, m[1][3] + m[1][k] * flLength, m[2][3] + m[2][k] * flLength); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + } +} + +void drawLine( Vector const &p1, Vector const &p2, int r, int g, int b, bool noDepthTest, float duration ) +{ + g_pStudioModel->drawLine( p1, p2, r, g, b ); +} + + +void StudioModel::drawLine( Vector const &p1, Vector const &p2, int r, int g, int b ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( g_materialVertexColor ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + + meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 ); + + meshBuilder.Color3ub( r, g, b ); + meshBuilder.Position3f( p1.x, p1.y, p1.z ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3ub( r, g, b ); + meshBuilder.Position3f( p2.x, p2.y, p2.z ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Draws a transparent box with a wireframe outline +//----------------------------------------------------------------------------- +void StudioModel::drawTransparentBox( Vector const &bbmin, Vector const &bbmax, + const matrix3x4_t& m, float const *color, float const *wirecolor ) +{ + Vector v[8], v2[8]; + + v[0][0] = bbmin[0]; + v[0][1] = bbmax[1]; + v[0][2] = bbmin[2]; + + v[1][0] = bbmin[0]; + v[1][1] = bbmin[1]; + v[1][2] = bbmin[2]; + + v[2][0] = bbmax[0]; + v[2][1] = bbmax[1]; + v[2][2] = bbmin[2]; + + v[3][0] = bbmax[0]; + v[3][1] = bbmin[1]; + v[3][2] = bbmin[2]; + + v[4][0] = bbmax[0]; + v[4][1] = bbmax[1]; + v[4][2] = bbmax[2]; + + v[5][0] = bbmax[0]; + v[5][1] = bbmin[1]; + v[5][2] = bbmax[2]; + + v[6][0] = bbmin[0]; + v[6][1] = bbmax[1]; + v[6][2] = bbmax[2]; + + v[7][0] = bbmin[0]; + v[7][1] = bbmin[1]; + v[7][2] = bbmax[2]; + + VectorTransform (v[0], m, v2[0]); + VectorTransform (v[1], m, v2[1]); + VectorTransform (v[2], m, v2[2]); + VectorTransform (v[3], m, v2[3]); + VectorTransform (v[4], m, v2[4]); + VectorTransform (v[5], m, v2[5]); + VectorTransform (v[6], m, v2[6]); + VectorTransform (v[7], m, v2[7]); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( g_pAlpha ); + drawBox( v2, color ); + + pRenderContext->Bind( g_materialBones ); + drawWireframeBox( v2, wirecolor ); +} + + + +void StudioModel::UpdateStudioRenderConfig( bool bWireframe, bool bZBufferWireframe, bool bNormals, bool bTangentFrame ) +{ + StudioRenderConfig_t config; + memset( &config, 0, sizeof( config ) ); + config.fEyeShiftX = 0.0f; + config.fEyeShiftY = 0.0f; + config.fEyeShiftZ = 0.0f; + config.fEyeSize = 0; + config.drawEntities = 1; + config.skin = 0; + config.fullbright = 0; + config.bEyeMove = true; + config.bWireframe = bWireframe; + + if ( g_viewerSettings.renderMode == RM_WIREFRAME || g_viewerSettings.softwareSkin || config.bWireframe || bNormals || bTangentFrame ) + { + config.bSoftwareSkin = true; + } + else + { + config.bSoftwareSkin = false; + } + + config.bSoftwareLighting = false; + config.bNoHardware = false; + config.bNoSoftware = false; + config.bTeeth = true; + config.bEyes = true; + config.bFlex = true; + config.bDrawNormals = bNormals; + config.bDrawTangentFrame = bTangentFrame; + config.bDrawZBufferedWireframe = bZBufferWireframe; + config.bShowEnvCubemapOnly = false; + g_pStudioRender->UpdateConfig( config ); + + MaterialSystem_Config_t matSysConfig = g_pMaterialSystem->GetCurrentConfigForVideoCard(); + extern void InitMaterialSystemConfig(MaterialSystem_Config_t *pConfig); + InitMaterialSystemConfig( &matSysConfig ); + matSysConfig.nFullbright = 0; + if( g_viewerSettings.renderMode == RM_SMOOTHSHADED ) + { + matSysConfig.nFullbright = 2; + } + + if ( g_dxlevel != 0 ) + { + matSysConfig.dxSupportLevel = g_dxlevel; + } + g_pMaterialSystem->OverrideConfig( matSysConfig, false ); +} + + +//----------------------------------------------------------------------------- +// Draws the skeleton +//----------------------------------------------------------------------------- +void StudioModel::DrawBones( ) +{ + // draw bones + if (!g_viewerSettings.showBones && (g_viewerSettings.highlightBone < 0)) + return; + + CStudioHdr *pStudioHdr = GetStudioHdr(); + mstudiobone_t *pbones = pStudioHdr->pBone( 0 ); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( g_materialBones ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + + bool drawRed = (g_viewerSettings.highlightBone >= 0); + + for (int i = 0; i < pStudioHdr->numbones(); i++) + { + if ( !(pStudioHdr->pBone( i )->flags & BoneMask())) + continue; + + if ( pbones[i].parent >= 0 ) + { + int j = pbones[i].parent; + if ( (g_viewerSettings.highlightBone < 0 ) || (j == g_viewerSettings.highlightBone) ) + { + meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 ); + + if (drawRed) + meshBuilder.Color3ub( 255, 255, 0 ); + else + meshBuilder.Color3ub( 0, 255, 255 ); + meshBuilder.Position3f( m_pBoneToWorld[j][0][3], m_pBoneToWorld[j][1][3], m_pBoneToWorld[j][2][3]); + meshBuilder.AdvanceVertex(); + + if (drawRed) + meshBuilder.Color3ub( 255, 255, 0 ); + else + meshBuilder.Color3ub( 0, 255, 255 ); + meshBuilder.Position3f( m_pBoneToWorld[i][0][3], m_pBoneToWorld[i][1][3], m_pBoneToWorld[i][2][3]); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + } + } + + if (g_viewerSettings.highlightBone >= 0) + { + if (i != g_viewerSettings.highlightBone) + continue; + } + + drawTransform( m_pBoneToWorld[i] ); + } + + // manadatory to access correct verts + SetCurrentModel(); + + // highlight used vertices with point + /* + if (g_viewerSettings.highlightBone >= 0) + { + int k, j, n; + for (i = 0; i < pStudioHdr->numbodyparts; i++) + { + for (j = 0; j < pStudioHdr->pBodypart( i )->nummodels; j++) + { + mstudiomodel_t *pModel = pStudioHdr->pBodypart( i )->pModel( j ); + + const mstudio_modelvertexdata_t *vertData = pModel->GetVertexData(); + Assert( vertData ); // This can only return NULL on X360 for now + + meshBuilder.Begin( pMesh, MATERIAL_POINTS, 1 ); + + for (k = 0; k < pModel->numvertices; k++) + { + for (n = 0; n < vertData->BoneWeights( k )->numbones; n++) + { + if (vertData->BoneWeights( k )->bone[n] == g_viewerSettings.highlightBone) + { + Vector tmp; + Transform( *vertData->Position( k ), vertData->BoneWeights( k ), tmp ); + + meshBuilder.Color3ub( 0, 255, 255 ); + meshBuilder.Position3f( tmp.x, tmp.y, tmp.z ); + meshBuilder.AdvanceVertex(); + break; + } + } + } + + meshBuilder.End(); + pMesh->Draw(); + } + } + } + */ +} + + +//----------------------------------------------------------------------------- +// Draws attachments +//----------------------------------------------------------------------------- +void StudioModel::DrawAttachments( ) +{ + if ( !g_viewerSettings.showAttachments ) + return; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( g_materialBones ); + + CStudioHdr *pStudioHdr = GetStudioHdr(); + for (int i = 0; i < pStudioHdr->GetNumAttachments(); i++) + { + mstudioattachment_t &pattachments = (mstudioattachment_t &)pStudioHdr->pAttachment( i ); + + matrix3x4_t world; + ConcatTransforms( m_pBoneToWorld[ pStudioHdr->GetAttachmentBone( i ) ], pattachments.local, world ); + + drawTransform( world ); + } +} + + +//----------------------------------------------------------------------------- +// Draws Axis +//----------------------------------------------------------------------------- +void StudioModel::DrawOriginAxis( ) +{ + if ( !g_viewerSettings.showOriginAxis ) + return; + + const float fAxisLength = g_viewerSettings.originAxisLength; + if ( fAxisLength <= 0.0f ) + return; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( g_materialBones ); + + pRenderContext->MatrixMode(MATERIAL_MODEL); + pRenderContext->PushMatrix();; + pRenderContext->LoadIdentity(); + + pRenderContext->MatrixMode(MATERIAL_VIEW); + pRenderContext->PushMatrix();; + pRenderContext->LoadIdentity(); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity( ); + + pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up + pRenderContext->Rotate( -90, 0, 0, 1 ); + + pRenderContext->Translate( -g_pStudioModel->m_origin[0], -g_pStudioModel->m_origin[1], -g_pStudioModel->m_origin[2] ); + + pRenderContext->Rotate( g_pStudioModel->m_angles[1], 0, 0, 1 ); + pRenderContext->Rotate( g_pStudioModel->m_angles[0], 0, 1, 0 ); + pRenderContext->Rotate( g_pStudioModel->m_angles[2], 1, 0, 0 ); + + IMesh *pMesh = pRenderContext->GetDynamicMesh( ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 ); + + meshBuilder.Position3f( 0.0f, 0.0f, 0.0f ); + meshBuilder.Color4ub( 255, 0, 0, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( fAxisLength, 0.0f, 0.0f ); + meshBuilder.Color4ub( 255, 0, 0, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( 0.0f, 0.0f, 0.0f ); + meshBuilder.Color4ub( 0, 255, 0, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( 0.0f, fAxisLength, 0.0f ); + meshBuilder.Color4ub( 0, 255, 0, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( 0.0f, 0.0f, 0.0f ); + meshBuilder.Color4ub( 0, 0, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( 0.0f, 0.0f, fAxisLength ); + meshBuilder.Color4ub( 0, 0, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + + pRenderContext->MatrixMode(MATERIAL_MODEL); + pRenderContext->PopMatrix(); + pRenderContext->MatrixMode(MATERIAL_VIEW); + pRenderContext->PopMatrix(); +} + + +void StudioModel::DrawEditAttachment() +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + int iEditAttachment = g_viewerSettings.m_iEditAttachment; + if ( iEditAttachment >= 0 && iEditAttachment < pStudioHdr->GetNumAttachments() ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( g_materialBones ); + + mstudioattachment_t &pAttachment = (mstudioattachment_t &)pStudioHdr->pAttachment( iEditAttachment ); + + matrix3x4_t world; + ConcatTransforms( m_pBoneToWorld[ pStudioHdr->GetAttachmentBone( iEditAttachment ) ], pAttachment.local, world ); + + drawTransform( world ); + } +} + + +//----------------------------------------------------------------------------- +// Draws hitboxes +//----------------------------------------------------------------------------- + + +static float hullcolor[8][4] = +{ + { 1.0, 1.0, 1.0, 1.0 }, + { 1.0, 0.5, 0.5, 1.0 }, + { 0.5, 1.0, 0.5, 1.0 }, + { 1.0, 1.0, 0.5, 1.0 }, + { 0.5, 0.5, 1.0, 1.0 }, + { 1.0, 0.5, 1.0, 1.0 }, + { 0.5, 1.0, 1.0, 1.0 }, + { 1.0, 1.0, 1.0, 1.0 } +}; + + +void StudioModel::DrawHitboxes( ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + if (!g_pAlpha) + { + g_pAlpha = g_pMaterialSystem->FindMaterial("debug/debughitbox", TEXTURE_GROUP_OTHER, false); + if ( g_pAlpha ) + { + g_pAlpha->AddRef(); + } + } + + if (g_viewerSettings.showHitBoxes || (g_viewerSettings.highlightHitbox >= 0)) + { + int hitboxset = g_MDLViewer->GetCurrentHitboxSet(); + + HitboxList_t &list = g_pStudioModel->m_HitboxSets[ hitboxset ].m_Hitboxes; + for (unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) ) + { + // Only draw one hitbox if we've selected it. + if ((g_viewerSettings.highlightHitbox >= 0) && + (g_viewerSettings.highlightHitbox != j)) + continue; + + mstudiobbox_t *pBBox = &list[j].m_BBox; + + float interiorcolor[4]; + int c = pBBox->group % 8; + interiorcolor[0] = hullcolor[c][0] * 0.7; + interiorcolor[1] = hullcolor[c][1] * 0.7; + interiorcolor[2] = hullcolor[c][2] * 0.7; + interiorcolor[3] = hullcolor[c][3] * 0.4; + + drawTransparentBox( pBBox->bbmin, pBBox->bbmax, m_pBoneToWorld[ pBBox->bone ], interiorcolor, hullcolor[ c ] ); + } + } + + /* + float color2[] = { 0, 0.7, 1, 0.6 }; + float wirecolor2[] = { 0, 1, 1, 1.0 }; + drawTransparentBox( pStudioHdr->min, pStudioHdr->max, g_viewtransform, color2, wirecolor2 ); + */ + + if (g_viewerSettings.showSequenceBoxes) + { + float color[] = { 0.7, 1, 0, 0.6 }; + float wirecolor[] = { 1, 1, 0, 1.0 }; + + drawTransparentBox( pStudioHdr->pSeqdesc( m_sequence ).bbmin, pStudioHdr->pSeqdesc( m_sequence ).bbmax, g_viewtransform, color, wirecolor ); + } +} + +void StudioModel::DrawIllumPosition( ) +{ + if( !g_viewerSettings.showIllumPosition ) + return; + + CStudioHdr *pStudioHdr = GetStudioHdr(); + + Vector modelPt0; + Vector modelPt1; + Vector worldPt0; + Vector worldPt1; + + // draw axis through illum position + VectorCopy(pStudioHdr->illumposition(), modelPt0); + VectorCopy(pStudioHdr->illumposition(), modelPt1); + modelPt0.x -= 4; + modelPt1.x += 4; + VectorTransform (modelPt0, g_viewtransform, worldPt0); + VectorTransform (modelPt1, g_viewtransform, worldPt1); + drawLine( worldPt0, worldPt1, 255, 0, 0 ); + + VectorCopy(pStudioHdr->illumposition(), modelPt0); + VectorCopy(pStudioHdr->illumposition(), modelPt1); + modelPt0.y -= 4; + modelPt1.y += 4; + VectorTransform (modelPt0, g_viewtransform, worldPt0); + VectorTransform (modelPt1, g_viewtransform, worldPt1); + drawLine( worldPt0, worldPt1, 0, 255, 0 ); + + VectorCopy(pStudioHdr->illumposition(), modelPt0); + VectorCopy(pStudioHdr->illumposition(), modelPt1); + modelPt0.z -= 4; + modelPt1.z += 4; + VectorTransform (modelPt0, g_viewtransform, worldPt0); + VectorTransform (modelPt1, g_viewtransform, worldPt1); + drawLine( worldPt0, worldPt1, 0, 0, 255 ); + +} + +//----------------------------------------------------------------------------- +// Draws the physics model +//----------------------------------------------------------------------------- + +void StudioModel::DrawPhysicsModel( ) +{ + if (!g_viewerSettings.showPhysicsModel) + return; + + if ( g_viewerSettings.renderMode == RM_WIREFRAME && m_pPhysics->Count() == 1 ) + { + // show the convex pieces in solid + DrawPhysConvex( m_pPhysics->GetMesh(0), g_materialFlatshaded ); + } + else + { + for (int i = 0; i < m_pPhysics->Count(); i++) + { + float red[] = { 1.0, 0, 0, 0.25 }; + float yellow[] = { 1.0, 1.0, 0, 0.5 }; + + CPhysmesh *pmesh = m_pPhysics->GetMesh(i); + int boneIndex = FindBone(pmesh->m_boneName); + + if ( boneIndex >= 0 ) + { + if ( (i+1) == g_viewerSettings.highlightPhysicsBone ) + { + DrawPhysmesh( pmesh, boneIndex, g_materialBones, red ); + } + else + { + if ( g_viewerSettings.highlightPhysicsBone < 1 ) + { + // yellow for most + DrawPhysmesh( pmesh, boneIndex, g_materialBones, yellow ); + } + } + } + else + { + DrawPhysmesh( pmesh, -1, g_materialBones, red ); + } + } + } +} + + + + +void StudioModel::SetViewTarget( void ) +{ + // only valid if the attachment bones are used + if ((BoneMask() & BONE_USED_BY_ATTACHMENT) == 0) + { + return; + } + + int iEyeAttachment = LookupAttachment( "eyes" ); + + if (iEyeAttachment == -1) + return; + + Vector local; + Vector tmp; + + // look forward + CStudioHdr *pStudioHdr = GetStudioHdr(); + mstudioattachment_t &patt = (mstudioattachment_t &)pStudioHdr->pAttachment( iEyeAttachment ); + matrix3x4_t attToWorld; + ConcatTransforms( m_pBoneToWorld[ pStudioHdr->GetAttachmentBone( iEyeAttachment ) ], patt.local, attToWorld ); + local = Vector( 32, 0, 0 ); + Vector vEyes; + MatrixPosition( attToWorld, vEyes ); + + // aim the eyes if there's a target + if (m_vecHeadTargets.Count() > 0 && !m_vecHeadTargets.Tail().m_bSelf) + { + VectorITransform( m_vecHeadTargets.Tail().m_vecPosition - vEyes, attToWorld, local ); + } + + float flDist = local.Length(); + + VectorNormalize( local ); + + // calculate animated eye deflection + Vector eyeDeflect; + QAngle eyeAng( GetFlexController("eyes_updown"), GetFlexController("eyes_rightleft"), 0 ); + + // debugoverlay->AddTextOverlay( m_vecOrigin + Vector( 0, 0, 64 ), 0, 0, "%.2f %.2f", eyeAng.x, eyeAng.y ); + + AngleVectors( eyeAng, &eyeDeflect ); + eyeDeflect.x = 0; + + // reduce deflection the more the eye is off center + // FIXME: this angles make no damn sense + eyeDeflect = eyeDeflect * (local.x * local.x); + local = local + eyeDeflect; + VectorNormalize( local ); + + // check to see if the eye is aiming outside the max eye deflection + float flMaxEyeDeflection = pStudioHdr->MaxEyeDeflection(); + if ( local.x < flMaxEyeDeflection ) + { + // if so, clamp it to 30 degrees offset + // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 1, 0, "%5.3f %5.3f %5.3f", local.x, local.y, local.z ); + local.x = 0; + float d = local.LengthSqr(); + if ( d > 0.0f ) + { + d = sqrtf( ( 1.0f - flMaxEyeDeflection * flMaxEyeDeflection ) / ( local.y*local.y + local.z*local.z ) ); + local.x = flMaxEyeDeflection; + local.y = local.y * d; + local.z = local.z * d; + } + else + { + local.x = 1.0; + } + } + local = local * flDist; + VectorTransform( local, attToWorld, tmp ); + + g_pStudioRender->SetEyeViewTarget( pStudioHdr->GetRenderHdr(), m_bodynum, tmp ); +} + + +float UTIL_VecToYaw( const matrix3x4_t& matrix, const Vector &vec ) +{ + Vector tmp = vec; + VectorNormalize( tmp ); + + float x = matrix[0][0] * tmp.x + matrix[1][0] * tmp.y + matrix[2][0] * tmp.z; + float y = matrix[0][1] * tmp.x + matrix[1][1] * tmp.y + matrix[2][1] * tmp.z; + + if (x == 0.0f && y == 0.0f) + return 0.0f; + + float yaw = atan2( -y, x ); + + yaw = RAD2DEG(yaw); + + if (yaw < 0) + yaw += 360; + + return yaw; +} + + +float UTIL_VecToPitch( const matrix3x4_t& matrix, const Vector &vec ) +{ + Vector tmp = vec; + VectorNormalize( tmp ); + + float x = matrix[0][0] * tmp.x + matrix[1][0] * tmp.y + matrix[2][0] * tmp.z; + float z = matrix[0][2] * tmp.x + matrix[1][2] * tmp.y + matrix[2][2] * tmp.z; + + if (x == 0.0f && z == 0.0f) + return 0.0f; + + float pitch = atan2( z, x ); + + pitch = RAD2DEG(pitch); + + if (pitch < 0) + pitch += 360; + + return pitch; +} + + +float UTIL_AngleDiff( float destAngle, float srcAngle ) +{ + float delta; + + delta = destAngle - srcAngle; + if ( destAngle > srcAngle ) + { + while ( delta >= 180 ) + delta -= 360; + } + else + { + while ( delta <= -180 ) + delta += 360; + } + return delta; +} + + +void StudioModel::UpdateBoneChain( + Vector pos[], + Quaternion q[], + int iBone, + matrix3x4_t *pBoneToWorld ) +{ + matrix3x4_t bonematrix; + + QuaternionMatrix( q[iBone], pos[iBone], bonematrix ); + + CStudioHdr *pStudioHdr = GetStudioHdr(); + int parent = pStudioHdr->pBone( iBone )->parent; + if (parent == -1) + { + ConcatTransforms( g_viewtransform, bonematrix, pBoneToWorld[iBone] ); + } + else + { + // evil recursive!!! + UpdateBoneChain( pos, q, parent, pBoneToWorld ); + ConcatTransforms( pBoneToWorld[parent], bonematrix, pBoneToWorld[iBone] ); + } +} + + + + +void StudioModel::GetBodyPoseParametersFromFlex( ) +{ + float flGoal; + + flGoal = GetFlexController( "move_rightleft" ); + SetPoseParameter( "body_trans_Y", flGoal ); + + flGoal = GetFlexController( "move_forwardback" ); + SetPoseParameter( "body_trans_X", flGoal ); + + flGoal = GetFlexController( "move_updown" ); + SetPoseParameter( "body_lift", flGoal ); + + flGoal = GetFlexController( "body_rightleft" ) + GetBodyYaw(); + SetPoseParameter( "body_yaw", flGoal ); + + flGoal = GetFlexController( "body_updown" ); + SetPoseParameter( "body_pitch", flGoal ); + + flGoal = GetFlexController( "body_tilt" ); + SetPoseParameter( "body_roll", flGoal ); + + flGoal = GetFlexController( "chest_rightleft" ) + GetSpineYaw(); + SetPoseParameter( "spine_yaw", flGoal ); + + flGoal = GetFlexController( "chest_updown" ); + SetPoseParameter( "spine_pitch", flGoal ); + + flGoal = GetFlexController( "chest_tilt" ); + SetPoseParameter( "spine_roll", flGoal ); + + flGoal = GetFlexController( "head_forwardback" ); + SetPoseParameter( "neck_trans", flGoal ); + + flGoal = GetFlexController( "gesture_updown" ); + SetPoseParameter( "gesture_height", flGoal ); + + flGoal = GetFlexController( "gesture_rightleft" ); + SetPoseParameter( "gesture_width", flGoal ); +} + + + + +void StudioModel::CalcHeadRotation( Vector pos[], Quaternion q[] ) +{ + static Vector pos2[MAXSTUDIOBONES]; + static Quaternion q2[MAXSTUDIOBONES]; + + if (m_nSolveHeadTurn == 0) + return; + + if (m_dt == 0.0f) + { + m_dt = 0.1; + } + + // GetAttachment( "eyes", vEyePosition, vEyeAngles ); + int iForwardAttachment = LookupAttachment( "forward" ); + if (iForwardAttachment == -1) + return; + + CStudioHdr *pStudioHdr = GetStudioHdr(); + mstudioattachment_t &patt = (mstudioattachment_t &)pStudioHdr->pAttachment( iForwardAttachment ); + + matrix3x4_t attToWorld; + int iBone = pStudioHdr->GetAttachmentBone( iForwardAttachment ); + BuildBoneChain( pStudioHdr, g_viewtransform, pos, q, iBone, m_pBoneToWorld ); + ConcatTransforms( m_pBoneToWorld[ iBone ], patt.local, attToWorld ); + + Vector vForward; + VectorRotate( Vector( 1, 0, 0 ), attToWorld, vForward ); + + float dt = m_dt; + if (m_nSolveHeadTurn == 2) + { + dt = 0.1; + } + + Vector vEyes; + MatrixPosition( attToWorld, vEyes ); + + Vector vHead = vForward; + float flHeadInfluence = 0.0; + int i; + for (i = 0; i < m_vecHeadTargets.Count(); i++) + { + Vector dir; + + if (m_vecHeadTargets[i].m_bSelf) + { + dir = vForward; + } + else + { + dir = m_vecHeadTargets[i].m_vecPosition - vEyes; + } + VectorNormalize( dir ); + float flInterest = m_vecHeadTargets[i].m_flWeight; + if (flInterest > 0.0) + { + if (flHeadInfluence == 0.0) + { + vHead = dir; + flHeadInfluence = flInterest; + } + else + { + flHeadInfluence = flHeadInfluence * (1 - flInterest) + flInterest; + float w = flInterest / flHeadInfluence; + vHead = vHead * (1 - w) + dir * w; + } + } + } + + Vector vTargetDir = Vector( 0, 0, 0 ); + vTargetDir = vForward * (1.0 - flHeadInfluence) + vHead * flHeadInfluence; + VectorNormalize( vTargetDir ); + + SetPoseParameter( "head_pitch", 0.0 ); + SetPoseParameter( "head_yaw", 0.0 ); + SetPoseParameter( "head_roll", 0.0 ); + SetHeadPosition( attToWorld, vTargetDir, dt ); + + // Msg( "yaw %f pitch %f\n", vEyeAngles.y, vEyeAngles.x ); +} + + + +float StudioModel::SetHeadPosition( matrix3x4_t& attToWorld, Vector const &vTargetPos, float dt ) +{ + float flDiff; + int iPose; + QAngle vEyeAngles; + float flMoved = 0.0f; + matrix3x4_t targetXform, invAttToWorld; + matrix3x4_t headXform; + + // align current "forward direction" to target direction + targetXform = attToWorld; + Studio_AlignIKMatrix( targetXform, vTargetPos ); + + // calc head movement needed + MatrixInvert( attToWorld, invAttToWorld ); + ConcatTransforms( invAttToWorld, targetXform, headXform ); + + MatrixAngles( headXform, vEyeAngles ); + + // FIXME: add chest compression + + // Msg( "yaw %f pitch %f\n", vEyeAngles.y, vEyeAngles.x ); + + float flMin, flMax; + +#if 1 + //-------------------------------------- + // Set head yaw + //-------------------------------------- + // flDiff = vEyeAngles.y + GetFlexController( "head_rightleft" ); + iPose = LookupPoseParameter( "head_yaw" ); + GetPoseParameterRange( iPose, &flMin, &flMax ); + flDiff = RangeCompressor( vEyeAngles.y + GetFlexController( "head_rightleft" ), flMin, flMax, 0.0 ); + SetPoseParameter( iPose, flDiff ); +#endif + +#if 1 + //-------------------------------------- + // Set head pitch + //-------------------------------------- + iPose = LookupPoseParameter( "head_pitch" ); + GetPoseParameterRange( iPose, &flMin, &flMax ); + flDiff = RangeCompressor( vEyeAngles.x + GetFlexController( "head_updown" ), flMin, flMax, 0.0 ); + SetPoseParameter( iPose, flDiff ); +#endif + +#if 1 + //-------------------------------------- + // Set head roll + //-------------------------------------- + iPose = LookupPoseParameter( "head_roll" ); + GetPoseParameterRange( iPose, &flMin, &flMax ); + flDiff = RangeCompressor( vEyeAngles.z + GetFlexController( "head_tilt" ), flMin, flMax, 0.0 ); + SetPoseParameter( iPose, flDiff ); +#endif + + return flMoved; +} + + +DrawModelInfo_t g_DrawModelInfo; +DrawModelResults_t g_DrawModelResults; +bool g_bDrawModelInfoValid = false; + + +void StudioModel::GetModelTransform( matrix3x4_t &mat ) +{ + AngleMatrix( m_angles, mat ); + + Vector vecModelOrigin; + VectorMultiply( m_origin, -1.0f, vecModelOrigin ); + MatrixSetColumn( vecModelOrigin, 3, mat ); +} + +void StudioModel::SetModelTransform( const matrix3x4_t &mat ) +{ + m_origin.x = -mat.m_flMatVal[0][3]; + m_origin.y = -mat.m_flMatVal[1][3]; + m_origin.z = -mat.m_flMatVal[2][3]; + + MatrixAngles( mat, m_angles ); +} + + +/* +================ +StudioModel::DrawModel +inputs: + currententity + r_entorigin +================ +*/ +int StudioModel::DrawModel( bool mergeBones ) +{ + MDLCACHE_CRITICAL_SECTION_( g_pMDLCache ); + + CStudioHdr *pStudioHdr = GetStudioHdr(); + if (!pStudioHdr) + return 0; + + g_smodels_total++; // render data cache cookie + + // JasonM & garymcthack - should really only do this once a frame and at init time. + UpdateStudioRenderConfig( g_viewerSettings.renderMode == RM_WIREFRAME, false, + g_viewerSettings.showNormals, + g_viewerSettings.showTangentFrame ); + + // NOTE: UpdateStudioRenderConfig can delete the studio hdr + pStudioHdr = GetStudioHdr(); + if ( !pStudioHdr || pStudioHdr->numbodyparts() == 0) + return 0; + + // Construct a transform to apply to the model. The camera is stuck in a fixed position + static Vector vecModelOrigin; + if ( !mergeBones ) + { + AngleMatrix( m_angles, g_viewtransform ); + VectorMultiply( m_origin, -1.0f, vecModelOrigin ); + MatrixSetColumn( vecModelOrigin, 3, g_viewtransform ); + } + + // These values HAVE to be sent down for LOD to work correctly. + Vector viewOrigin, viewRight, viewUp, viewPlaneNormal; + g_pStudioRender->SetViewState( vec3_origin, Vector(0, 1, 0), Vector(0, 0, 1), Vector( 1, 0, 0 ) ); + + // g_pStudioRender->SetEyeViewTarget( viewOrigin ); + + SetUpBones( mergeBones ); + + SetupLighting( ); + + SetViewTarget( ); + + + extern float g_flexdescweight[MAXSTUDIOFLEXDESC]; // garymcthack + extern float g_flexdescweight2[MAXSTUDIOFLEXDESC]; // garymcthack + + int i; + for (i = 0; i < pStudioHdr->numflexdesc(); i++) + { + g_flexdescweight[i] = 0.0; + } + + RunFlexRules( ); + + float d = 0.8; + + if (m_dt != 0) + { + d = ExponentialDecay( 0.8, 0.033, m_dt ); + } + + float *pFlexWeights, *pFlexDelayedWeights; + g_pStudioRender->LockFlexWeights( pStudioHdr->numflexdesc(), &pFlexWeights, &pFlexDelayedWeights ); + + for (i = 0; i < pStudioHdr->numflexdesc(); i++) + { + g_flexdescweight2[i] = g_flexdescweight2[i] * d + g_flexdescweight[i] * (1 - d); + + pFlexWeights[i] = g_flexdescweight[i]; + pFlexDelayedWeights[i] = g_flexdescweight2[i]; + } + + g_pStudioRender->UnlockFlexWeights( ); + + + // draw + + g_pStudioRender->SetAlphaModulation( 1.0f ); + + g_bDrawModelInfoValid = true; + memset( &g_DrawModelInfo, 0, sizeof( g_DrawModelInfo ) ); + g_DrawModelInfo.m_pStudioHdr = (studiohdr_t *)pStudioHdr->GetRenderHdr(); + g_DrawModelInfo.m_pHardwareData = GetHardwareData(); + if ( !g_DrawModelInfo.m_pHardwareData ) + return 0; + g_DrawModelInfo.m_Decals = STUDIORENDER_DECAL_INVALID; + g_DrawModelInfo.m_Skin = m_skinnum; + g_DrawModelInfo.m_Body = m_bodynum; + g_DrawModelInfo.m_HitboxSet = g_MDLViewer->GetCurrentHitboxSet(); + g_DrawModelInfo.m_pClientEntity = NULL; + g_DrawModelInfo.m_Lod = g_viewerSettings.autoLOD ? -1 : g_viewerSettings.lod; + g_DrawModelInfo.m_pColorMeshes = NULL; + + + if( g_viewerSettings.renderMode == RM_SHOWBADVERTEXDATA ) + { + DebugDrawModelBadVerts( g_pStudioRender, g_DrawModelInfo, m_pBoneToWorld, vecModelOrigin ); + + DebugDrawModelWireframe( g_pStudioRender, g_DrawModelInfo, m_pBoneToWorld, vecModelOrigin, Vector( 0.2f, 0.2f, 0.2f ) ); + + g_DrawModelInfo.m_Lod = m_LodUsed; + g_pStudioRender->GetPerfStats( &g_DrawModelResults, g_DrawModelInfo, NULL ); + +#if 0 + // overlay wireframe + + // Set the state to trigger wireframe rendering + UpdateStudioRenderConfig( true, true, false, false ); + + // Draw wireframe + count = g_pStudioRender->DrawModel( &g_DrawModelResults, g_DrawModelInfo, m_pBoneToWorld, + pFlexWeights, pFlexDelayedWeights, vecModelOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL ); + m_LodUsed = g_DrawModelResults.m_nLODUsed; + m_LodMetric = g_DrawModelResults.m_flLodMetric; + g_DrawModelInfo.m_Lod = m_LodUsed; + + // Restore the studio render config + UpdateStudioRenderConfig( g_viewerSettings.renderMode == RM_WIREFRAME, false, + g_viewerSettings.showNormals, + g_viewerSettings.showTangentFrame ); +#endif + } + else if( g_viewerSettings.renderMode == RM_BONEWEIGHTS ) + { + g_DrawModelInfo.m_Lod = 0; + DebugDrawModelBoneWeights( g_pStudioRender, g_DrawModelInfo, m_pBoneToWorld, vecModelOrigin ); + g_DrawModelInfo.m_Lod = m_LodUsed; + g_pStudioRender->GetPerfStats( &g_DrawModelResults, g_DrawModelInfo, NULL ); + } + else if( g_viewerSettings.renderMode == RM_TEXCOORDS ) + { + const char *pMatName = ""; + if ( g_DrawModelInfo.m_pHardwareData->m_pLODs && g_viewerSettings.materialIndex < g_DrawModelInfo.m_pHardwareData->m_pLODs[0].numMaterials ) + { + pMatName = g_DrawModelInfo.m_pHardwareData->m_pLODs[0].ppMaterials[g_viewerSettings.materialIndex]->GetName(); + } + DebugDrawModelTexCoord( g_pStudioRender, pMatName, g_DrawModelInfo, m_pBoneToWorld, g_viewerSettings.width, g_viewerSettings.height ); + g_pStudioRender->GetPerfStats( &g_DrawModelResults, g_DrawModelInfo, NULL ); + m_LodUsed = g_DrawModelInfo.m_Lod; + } + else + { + // Draw the model normally (may include normal and/or tangent line segments) + g_pStudioRender->DrawModel( &g_DrawModelResults, g_DrawModelInfo, m_pBoneToWorld, + pFlexWeights, pFlexDelayedWeights, vecModelOrigin ); + m_LodUsed = g_DrawModelResults.m_nLODUsed; + m_LodMetric = g_DrawModelResults.m_flLODMetric; + + g_pStudioRender->GetPerfStats( &g_DrawModelResults, g_DrawModelInfo, NULL ); + + // Optionally overlay wireframe... + if ( g_viewerSettings.overlayWireframe && !(g_viewerSettings.renderMode == RM_WIREFRAME) ) + { + // Set the state to trigger wireframe rendering + UpdateStudioRenderConfig( true, true, false, false ); + + // Draw the wireframe over top of the model + g_pStudioRender->DrawModel( NULL, g_DrawModelInfo, m_pBoneToWorld, + pFlexWeights, pFlexDelayedWeights, vecModelOrigin ); + + // Restore the studio render config + UpdateStudioRenderConfig( g_viewerSettings.renderMode == RM_WIREFRAME, false, + g_viewerSettings.showNormals, + g_viewerSettings.showTangentFrame ); + } + } + + int nCount = g_DrawModelResults.m_ActualTriCount; + + DrawBones(); + DrawAttachments(); + DrawOriginAxis(); + DrawEditAttachment(); + DrawHitboxes(); + DrawPhysicsModel(); + DrawIllumPosition(); + + // Only draw the shadow if the ground is also drawn + if ( g_viewerSettings.showShadow && g_viewerSettings.showGround ) + { + matrix3x4_t invViewTransform; + + MatrixInvert( g_viewtransform, invViewTransform ); + + for (int i = 0; i < pStudioHdr->numbones(); i++) + { + matrix3x4_t *pMatrix = &m_pBoneToWorld[ i ]; + + matrix3x4_t tmp1; + + ConcatTransforms( invViewTransform, *pMatrix, tmp1 ); + tmp1[2][0] = 0.0; + tmp1[2][1] = 0.0; + tmp1[2][2] = 0.0; + tmp1[2][3] = 0.05; + ConcatTransforms( g_viewtransform, tmp1, *pMatrix ); + } + g_DrawModelInfo.m_Lod = GetHardwareData()->m_NumLODs - 1; + + float zero[4] = { 0, 0, 0, 0 }; + g_pStudioRender->SetColorModulation( zero ); + g_pStudioRender->ForcedMaterialOverride( g_materialShadow ); + + // Turn off any wireframe, normals or tangent frame display for the drop shadow + UpdateStudioRenderConfig( false, false, false, false ); + + g_pStudioRender->DrawModel( NULL, g_DrawModelInfo, m_pBoneToWorld, + pFlexWeights, pFlexDelayedWeights, vecModelOrigin ); + + // Restore the studio render config + UpdateStudioRenderConfig( g_viewerSettings.renderMode == RM_WIREFRAME, false, + g_viewerSettings.showNormals, + g_viewerSettings.showTangentFrame ); + + g_pStudioRender->ForcedMaterialOverride( NULL ); + float one[4] = { 1, 1, 1, 1 }; + g_pStudioRender->SetColorModulation( one ); + } + + return nCount; +} + + +void StudioModel::DrawPhysmesh( CPhysmesh *pMesh, int boneIndex, IMaterial* pMaterial, float* color ) +{ + matrix3x4_t *pMatrix; + if ( boneIndex >= 0 ) + { + pMatrix = &m_pBoneToWorld[ boneIndex ]; + } + else + { + pMatrix = &g_viewtransform; + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( pMaterial ); + IMesh* pMatMesh = pRenderContext->GetDynamicMesh( ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMatMesh, MATERIAL_TRIANGLES, pMesh->m_vertCount/3 ); + + int vertIndex = 0; + for ( int i = 0; i < pMesh->m_vertCount; i+=3 ) + { + Vector v; + + VectorTransform (pMesh->m_pVerts[vertIndex], *pMatrix, v); + meshBuilder.Position3fv( v.Base() ); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + vertIndex ++; + VectorTransform (pMesh->m_pVerts[vertIndex], *pMatrix, v); + meshBuilder.Position3fv( v.Base() ); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + vertIndex ++; + VectorTransform (pMesh->m_pVerts[vertIndex], *pMatrix, v); + meshBuilder.Position3fv( v.Base() ); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + + vertIndex ++; + } + meshBuilder.End(); + pMatMesh->Draw(); +} + + +void RandomColor( float *color, int key ) +{ + static bool first = true; + static colorVec colors[256]; + + if ( first ) + { + int r, g, b; + first = false; + for ( int i = 0; i < 256; i++ ) + { + do + { + r = rand()&255; + g = rand()&255; + b = rand()&255; + } while ( (r+g+b)<256 ); + colors[i].r = r; + colors[i].g = g; + colors[i].b = b; + colors[i].a = 255; + } + } + + int index = key & 255; + color[0] = colors[index].r * (1.f / 255.f); + color[1] = colors[index].g * (1.f / 255.f); + color[2] = colors[index].b * (1.f / 255.f); + color[3] = colors[index].a * (1.f / 255.f); +} + +void StudioModel::DrawPhysConvex( CPhysmesh *pMesh, IMaterial* pMaterial ) +{ + matrix3x4_t &matrix = g_viewtransform; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( pMaterial ); + + for ( int i = 0; i < pMesh->m_pCollisionModel->ConvexCount(); i++ ) + { + float color[4]; + RandomColor( color, i ); + IMesh* pMatMesh = pRenderContext->GetDynamicMesh( ); + CMeshBuilder meshBuilder; + int triCount = pMesh->m_pCollisionModel->TriangleCount( i ); + meshBuilder.Begin( pMatMesh, MATERIAL_TRIANGLES, triCount ); + + for ( int j = 0; j < triCount; j++ ) + { + Vector objectSpaceVerts[3]; + pMesh->m_pCollisionModel->GetTriangleVerts( i, j, objectSpaceVerts ); + + for ( int k = 0; k < 3; k++ ) + { + Vector v; + + VectorTransform (objectSpaceVerts[k], matrix, v); + meshBuilder.Position3fv( v.Base() ); + meshBuilder.Color4fv( color ); + meshBuilder.AdvanceVertex(); + } + } + meshBuilder.End(); + pMatMesh->Draw(); + } +} + + + +/* +================ + +================ +*/ + + +int StudioModel::GetLodUsed( void ) +{ + return m_LodUsed; +} + +float StudioModel::GetLodMetric( void ) +{ + return m_LodMetric; +} + + +const char *StudioModel::GetKeyValueText( int iSequence ) +{ + CStudioHdr *pStudioHdr = GetStudioHdr(); + return Studio_GetKeyValueText( pStudioHdr, iSequence ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : solve - +//----------------------------------------------------------------------------- +void StudioModel::SetSolveHeadTurn( int solve ) +{ + m_nSolveHeadTurn = solve; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int StudioModel::GetSolveHeadTurn() const +{ + return m_nSolveHeadTurn; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : target - +//----------------------------------------------------------------------------- +void StudioModel::ClearLookTargets( void ) +{ + m_vecHeadTargets.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : target - +//----------------------------------------------------------------------------- +void StudioModel::AddLookTarget( const Vector& vecPosition, float flWeight ) +{ + if (m_vecHeadTargets.Count() > 8) + return; + + StudioLookTarget tmp; + + tmp.m_flWeight = flWeight; + tmp.m_vecPosition = vecPosition; + tmp.m_bSelf = false; + + m_vecHeadTargets.AddToTail( tmp ); +} + + +void StudioModel::AddLookTargetSelf( float flWeight ) +{ + if (m_vecHeadTargets.Count() > 8) + return; + + StudioLookTarget tmp; + + tmp.m_flWeight = flWeight; + tmp.m_vecPosition = Vector(0,0,0); + tmp.m_bSelf = true; + + m_vecHeadTargets.AddToTail( tmp ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +void StudioModel::SetModelYaw( float flYaw ) +{ + m_flModelYaw = flYaw; +} + +float StudioModel::GetModelYaw( void ) const +{ + return m_flModelYaw; +} + +void StudioModel::SetBodyYaw( float flYaw ) +{ + m_flBodyYaw = flYaw; +} + +float StudioModel::GetBodyYaw( void ) const +{ + return m_flBodyYaw; +} + +void StudioModel::SetSpineYaw( float flYaw ) +{ + m_flSpineYaw = flYaw; +} + +float StudioModel::GetSpineYaw( void ) const +{ + return m_flSpineYaw; +} + -- cgit v1.2.3