⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 studio_render.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/***
*
*	Copyright (c) 1998, Valve LLC. All rights reserved.
*	
*	This product contains software technology licensed from Id 
*	Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc. 
*	All Rights Reserved.
*
****/
// studio_render.cpp: routines for drawing Half-Life 3DStudio models
// updates:
// 1-4-99	fixed AdvanceFrame wraping bug

#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>

#include <windows.h> // 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 "studio_render.h"
#include "materialsystem/IMesh.h"
#include "bone_setup.h"
#include "materialsystem/MaterialSystem_Config.h"
#include "MDLViewer.h"

// FIXME:
extern ViewerSettings g_viewerSettings;
int g_dxlevel = 0;

#pragma warning( disable : 4244 ) // double to float

////////////////////////////////////////////////////////////////////////

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

static int			maxNumVertices;
static int			first = 1;
////////////////////////////////////////////////////////////////////////


mstudioseqdesc_t *StudioModel::GetSeqDesc( int seq )
{
	// these should be dynamcially loaded
	return m_pstudiohdr->pSeqdesc( seq );
}

mstudioanimdesc_t *StudioModel::GetAnimDesc( int anim )
{
	return m_pstudiohdr->pAnimdesc( anim );
}

mstudioanim_t *StudioModel::GetAnim( int anim )
{
	mstudioanimdesc_t *panimdesc = GetAnimDesc( anim );
	return panimdesc->pAnim( 0 );
}

//-----------------------------------------------------------------------------
// Purpose: Keeps a global clock to autoplay sequences to run from
//			Also deals with speedScale changes
//-----------------------------------------------------------------------------
float GetAutoPlayTime( void )
{
	static float g_prevTicks;
	static float g_time;

	g_time += ( (GetTickCount() - g_prevTicks) / 1000.0f ) * g_viewerSettings.speedScale;
	g_prevTicks = GetTickCount();

	return g_time;
}

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::GetCycle( void )
{
	return m_cycle;
}

float StudioModel::GetFrame( void )
{
	return GetCycle() * GetMaxFrame();
}

int StudioModel::GetMaxFrame( void )
{
	return Studio_MaxFrame( m_pstudiohdr, m_sequence, m_poseparameter );
}

int StudioModel::SetFrame( int frame )
{
	if ( !m_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 )
{
	if (iLayer == 0)
	{
		return Studio_MaxFrame( m_pstudiohdr, m_sequence, m_poseparameter );
	}
	else if (iLayer <= MAXSTUDIOANIMLAYERS)
	{
		int index = iLayer - 1;
		return Studio_MaxFrame( m_pstudiohdr, m_Layer[index].m_sequence, m_poseparameter );
	}
	return 0;
}


int StudioModel::SetFrame( int iLayer, int frame )
{
	if ( !m_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);

		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_pStudioRender->GetBoneToWorld( 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_pStudioRender->GetBoneToWorld( boneIndex ));
		}
	}
}


static CIKContext ik;


void StudioModel::SetUpBones ( void )
{
	int					i, j;

	mstudiobone_t		*pbones;

	static Vector		pos[MAXSTUDIOBONES];
	matrix3x4_t			bonematrix;
	static Quaternion	q[MAXSTUDIOBONES];
	bool				override[MAXSTUDIOBONES];

	// For blended transitions
	static Vector		pos2[MAXSTUDIOBONES];
	static Quaternion	q2[MAXSTUDIOBONES];

	mstudioseqdesc_t	*pseqdesc;
	pseqdesc = m_pstudiohdr->pSeqdesc( m_sequence );

	QAngle a1;
	Vector p1;
	MatrixAngles( g_viewtransform, a1 );
	MatrixPosition( g_viewtransform, p1 );
	CIKContext *pIK = NULL;
	if ( g_viewerSettings.enableIK )
	{
		pIK = &ik;
		ik.Init( m_pstudiohdr, a1, p1, 0.0 );
	}

	InitPose(  m_pstudiohdr, pos, q );
	
	AccumulatePose( m_pstudiohdr, pIK, pos, q, m_sequence, m_cycle, m_poseparameter, BONE_USED_BY_ANYTHING );

	if ( g_viewerSettings.blendSequenceChanges &&
		m_sequencetime < m_blendtime && 
		m_prevsequence != m_sequence &&
		m_prevsequence < m_pstudiohdr->numseq &&
		!(pseqdesc->flags & STUDIO_SNAP) )
	{
		// Make sure frame is valid
		pseqdesc = m_pstudiohdr->pSeqdesc( m_prevsequence );
		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;

		AccumulatePose( m_pstudiohdr, NULL, pos, q, m_prevsequence, m_prevcycle, m_poseparameter, BONE_USED_BY_ANYTHING, s );
		// 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)
			{
				AccumulatePose( m_pstudiohdr, pIK, pos, q, m_Layer[i].m_sequence, m_Layer[i].m_cycle, m_poseparameter, BONE_USED_BY_ANYTHING, m_Layer[i].m_weight );
			}
		}
	}

	if (g_viewerSettings.solveHeadTurn != 0)
	{
		GetBodyPoseParametersFromFlex( );
	}

	SetHeadPosition( pos, q );

	CIKContext auto_ik;
	auto_ik.Init( m_pstudiohdr, a1, p1, 0.0 );

	CalcAutoplaySequences( m_pstudiohdr, &auto_ik, pos, q, m_poseparameter, BONE_USED_BY_ANYTHING, GetAutoPlayTime() );

	CalcBoneAdj( m_pstudiohdr, pos, q, m_controller, BONE_USED_BY_ANYTHING );

	if (pIK)
	{
		pIK->SolveDependencies( pos, q );
	}

	pbones = m_pstudiohdr->pBone( 0 );

	memset( override, 0, sizeof(bool)*m_pstudiohdr->numbones );

	if ( g_viewerSettings.showPhysicsPreview )
	{
		OverrideBones( override );
	}

	for (i = 0; i < m_pstudiohdr->numbones; i++) 
	{
		if ( override[i] )
		{
			continue;
		}
		else if (CalcProceduralBone( m_pstudiohdr, i, m_pStudioRender->GetBoneToWorldArray() ))
		{
			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 (pbones[i].parent == -1) 
			{
				ConcatTransforms (g_viewtransform, bonematrix, *m_pStudioRender->GetBoneToWorld( i ));
				// MatrixCopy(bonematrix, g_bonetoworld[i]);
			} 
			else 
			{
				ConcatTransforms (*m_pStudioRender->GetBoneToWorld( pbones[i].parent ), bonematrix, *m_pStudioRender->GetBoneToWorld( i ) );
			}
		}
	}

	if (g_viewerSettings.showAttachments)
	{
		// drawTransform( m_pStudioRender->GetBoneToWorld( 0 ) );
	}
}



/*
================
StudioModel::SetupLighting
	set some global variables based on entity position
inputs:
outputs:
================
*/
void StudioModel::SetupLighting ( )
{
	LightDesc_t light;

	light.m_Type = MATERIAL_LIGHT_DIRECTIONAL;
	light.m_Attenuation0 = 1.0f;
	light.m_Attenuation1 = 0.0;
	light.m_Attenuation2 = 0.0;
	light.m_Color[0] = g_viewerSettings.lColor[0];
	light.m_Color[1] = g_viewerSettings.lColor[1];
	light.m_Color[2] = g_viewerSettings.lColor[2];
	light.m_Range = 2000;

	// DEBUG: Spin the light around the head for debugging
	// g_viewerSettings.lightrot = Vector( 0, 0, 0 );
	// g_viewerSettings.lightrot.y = fmod( (90 * GetTickCount( ) / 1000.0), 360.0);

	AngleVectors( g_viewerSettings.lightrot, &light.m_Direction, NULL, NULL );
	m_pStudioRender->SetLocalLights( 1, &light );
	int i;
	for( i = 0; i < m_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_TotalLightColors[i][0] = m_AmbientLightColors[i][0] + 
			-light.m_Attenuation0 * DotProduct( light.m_Direction, m_pStudioRender->GetAmbientLightDirections()[i] ) * 
			light.m_Color[0];
		m_TotalLightColors[i][1] = m_AmbientLightColors[i][1] + 
			-light.m_Attenuation0 * DotProduct( light.m_Direction, m_pStudioRender->GetAmbientLightDirections()[i] ) * 
			light.m_Color[1];
		m_TotalLightColors[i][2] = m_AmbientLightColors[i][2] + 
			-light.m_Attenuation0 * DotProduct( light.m_Direction, m_pStudioRender->GetAmbientLightDirections()[i] ) * 
			light.m_Color[2];
	}
	m_pStudioRender->SetAmbientLightColors( m_AmbientLightColors, m_TotalLightColors );
}


int FindBoneIndex( studiohdr_t *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 )
{
	return FindBoneIndex( m_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;

	if (bodypart > m_pstudiohdr->numbodyparts)
	{
		// Con_DPrintf ("StudioModel::SetupModel: no such bodypart %d\n", bodypart);
		bodypart = 0;
	}

	mstudiobodyparts_t   *pbodypart = m_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 )
{
	IMesh* pMesh = g_pMaterialSystem->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() );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -