Files
2026-06-01 12:46:52 +02:00

620 lines
15 KiB
C++

#include "stdafx.h"
#include "K3DCamera.h"
#include "SGameCamera.h"
#include "SGame.h"
#include "SGameMessage.h"
#include "kviewport.h"
#include "GameRule.h"
#include <toolkit/XStringUtil.h>
#include "SGameCameraWork.h"
#include "SGameOption.h"
// New Camera parameters
const float SGameCamera::PI = 3.14159265358979f;
const float SGameCamera::CAMERA_ELEVATION_BASE=0.05f;
const float SGameCamera::CAMERA_ROTATION_CONSTANT=(PI/-512.f);
const float SGameCamera::CAMERA_ELEVATION_CONSTANT=0.004f;
const float SGameCamera::CAMERA_DOLLY_CONSTANT = -0.18f;
const float SGameCamera::CAMERA_DISTANCE_ZOOM_MIN=40.0f;
const float SGameCamera::CAMERA_DISTANCE_ZOOM_BASE = 0.01f;
const float SGameCamera::CAMERA_DISTANCE_ZOOM_MIN_MAX = PI * 0.5f;
const float SGameCamera::CAMERA_DISTANCE_MIN = 1.0f;
const float SGameCamera::CAMERA_DISTANCE_MAX = GameRule::DEFAULT_UNIT_SIZE * 75.0f; // AziaMafia Zoom 24.0f ;
const DWORD SGameCamera::CAMERA_ZOOM_IN_OUT_TIME = 300;
SGameCamera::SGameCamera( K3DCamera * pCamera, SGame * pGame ) : m_pCamera(pCamera), m_pGame(pGame)
{
m_dwPrevProcessTime = 0;
m_dwCameraVibrateTimeDueTime = 0;
m_dwCameraVibrateVar = 0;
m_nEffect = EFFECT_NONE;
m_nCameraMoveMode=MODE_APPROACH; // 디폴트 카메라 접근모드 : 리니지 모드
//m_nCameraMoveMode=MODE_LOOKUP; // 와우 모드
m_bFollowTerrain=false; // 바닥 따라가기
m_fRadius = 55.0f; // 카메라 초기 거리
m_fPrevRadius = m_fRadius;
m_fCurRadius = m_fRadius;
m_dwLerpTime = 0;
m_fDollyConstant = CAMERA_DOLLY_CONSTANT;
m_fXYAngle=0.5*PI; // 북쪽 -> 남쪽 (캐릭터 얼굴 방향)
m_fElevationFactor=0.4f; // 카메라 초기 높이
m_fTargetZOffSet = 0.0f;
m_fAngleX = PI/4.0f;
m_fAngleZ = PI/4.0;
K3DMatrixIdentity( m_matCam );
m_fDistanceDelta = 0.0f;
m_bDistanceDelta = false;
m_pCameraWork = NULL;
m_nCameraMode = CAMERA_GAME_MODE;
}
SGameCamera::~SGameCamera()
{
}
//최소 줌으로
void SGameCamera::SetMinZoom()
{
m_fRadius=CAMERA_DISTANCE_MAX; // 최소 줌 == 가장 먼 카메라
}
//북향 45'
void SGameCamera::SetNorth45()
{
m_fElevationFactor=1.0f; // 45도
m_fXYAngle=1.5f*PI; // 남쪽에서 북쪽으로
// Note : 45도는 너무 높음. 20~30도 정도로 조절하는게 좋을 듯?
}
void SGameCamera::Zoom(short zDelta)
{
m_nMode = MODE_ZOOM;
m_nDelta = zDelta;
m_dwStartTime = 0;
}
void SGameCamera::SetTargetZOffSet( float fZ )
{
m_fTargetZOffSet = fZ;
}
void SGameCamera::DefaultDollyConstant()
{
m_fDollyConstant = CAMERA_DOLLY_CONSTANT;
}
void SGameCamera::SetDollyConstant( float fDollyConstant )
{
m_fDollyConstant = fDollyConstant;
}
bool SGameCamera::Process( DWORD time, unsigned long uProcessBitVector )
{
DWORD dwTimeGap = time - m_dwPrevProcessTime;
m_dwTime = time;
if( m_pCameraWork )
{
if( m_nCameraMode == CAMERA_STANDING_MODE ||
m_nCameraMode == CAMERA_ENDING_MODE )
{
m_pCameraWork->Process( 0 );
}
else if( m_nCameraMode == CAMERA_EVSCENE_MODE )
{
m_pCameraWork->Process( m_dwTime );
}
else if( m_nCameraMode == CAMERA_GAME_MODE )
{
SetCameraWork( NULL );
}
}
else
{
//타격 효과
if( m_nEffect != EFFECT_NONE )
{
// 카메라 진동 처리
if( m_dwCameraVibrateTimeDueTime )
{
m_dwCameraVibrateVar += dwTimeGap;
if( m_dwCameraVibrateTimeDueTime < m_dwTime )
{
m_dwCameraVibrateVar = 0;
m_dwCameraVibrateTimeDueTime = 0;
m_nEffect = EFFECT_NONE;
}
else
{
if( m_dwCameraVibrateVar > 50 )
{
m_dwCameraVibrateVar -= 50;
m_fDeltaX = 0 - m_fDeltaX;
//_oprint( "Camera Effect : Angle [%f]\n", m_fDeltaX );
if( m_nEffect == EFFECT_01 )
m_pCamera->Turn( m_fDeltaX ); // NOTE : calculateCamera()와 합치는게 맞을 듯 ??
else if( m_nEffect == EFFECT_02 )
m_pCamera->Elevation( m_fDeltaX );
m_pCamera->Zoom( m_fDeltaX*40 );
}
}
}
}
}
m_dwPrevProcessTime = time;
return true;
}
bool SGameCamera::Render( unsigned long uRenderBitVector, KViewportObject** ppViewportList, int nViewportCount )
{
for(int vit = 0; vit < nViewportCount; ++vit)
{
//m_pCamera->Render( ppViewportList[vit] );
ppViewportList[vit]->SetCamera(m_pCamera);
}
// { [sonador][COLLIDABLE_CAMERA]
std::for_each( m_animators.begin(), m_animators.end(),
std::bind2nd( std::mem_fun( &IGameCameraAnimator::Render ), ppViewportList[ 0 ] ) );
// }
return true;
}
void SGameCamera::SendGameMsg( SGameMessage * msg ) //바로 처리
{
if( msg->nType == MSG_CAMERA_EFFECT )
{
SMSG_CAMERA_EFFECT * pCamMsg = static_cast<SMSG_CAMERA_EFFECT*>(msg);
m_nEffect = pCamMsg->nEffect;
m_dwCameraVibrateTimeDueTime = m_dwTime; //시작 시간
m_dwCameraVibrateTimeDueTime += pCamMsg->dwKeepTime; //지속 시간
m_fDeltaX = pCamMsg->fDeltaX;
m_fDeltaY = pCamMsg->fDeltaY;
K3DVector vCamPos = m_pCamera->GetCamPos();
m_pCamera->SetCamPos( vCamPos.x, vCamPos.y, vCamPos.z );
}
}
//
// 카메라 거동 제어
//
//static bool bUseNewCame = false;
//static float fElevate = 0.0f;
//static float fTurn = 0.0f;
//static float fDistance = 0.0f;
void SGameCamera::Rotate(float radianDelta) // 좌우 회전 변위값
{
static float sfRadian = 2.0f * PI;
m_fAngleZ += radianDelta;
if( m_fAngleZ >= sfRadian )
m_fAngleZ = radianDelta;
if( m_fAngleZ <= -sfRadian )
m_fAngleZ = radianDelta;
// fTurn = radianDelta;
ResetDistanceDelta();
// _oprint("Rotate: %f\n", m_fAngleZ );
}
void SGameCamera::Elevate(float elevationFactorDelta) // 상하 이동 변위값
{
static float sfZDisMinMax = CAMERA_DISTANCE_ZOOM_MIN_MAX - CAMERA_DISTANCE_ZOOM_BASE;
m_fAngleX -= elevationFactorDelta;
if( m_fAngleX >= sfZDisMinMax )
m_fAngleX = sfZDisMinMax;
if( m_fAngleX <= -sfZDisMinMax )
m_fAngleX = -sfZDisMinMax;
/// 2010.12.24 1.51이면 대략 86.56 degree값 정도 된다.
/// 정확한 원인은 찾지 못하였으나 짐벌락 문제로 추정됨 1.51값은 테스트후에 나온 값이다. - prodongi
if (m_fAngleX > 1.51f)
m_fAngleX = 1.51f;
// fElevate = elevationFactorDelta;
ResetDistanceDelta();
// _oprint("Elevate: %f\n", m_fAngleX );
}
void SGameCamera::Distance(float distanceDelta) // 평면거리 변위값
{
float fOldRadius = m_fRadius;
if ( GetGameOption().IsInverseWheel() ) m_fRadius -= distanceDelta;
else m_fRadius += distanceDelta;
m_fDistanceDelta = distanceDelta;
m_bDistanceDelta = true;
if( m_fRadius <= CAMERA_DISTANCE_MIN )
m_fRadius = CAMERA_DISTANCE_MIN;
if( m_fRadius >= CAMERA_DISTANCE_MAX )
m_fRadius = CAMERA_DISTANCE_MAX;
if( fOldRadius != m_fRadius )
{
m_dwLerpTime = m_dwTime;
m_fPrevRadius = m_fCurRadius;
}
// fDistance = distanceDelta;
// _oprint("Distance: %f\n", m_fRadius);
}
void SGameCamera::Turn(int turnvalue) //카메라 왼쪽 오른쪽 회전
{
Rotate( CAMERA_ROTATION_CONSTANT * (float)turnvalue );
}
void SGameCamera::Updown(int elevationValue) //카메라 위 아래 회전
{
Elevate( CAMERA_ROTATION_CONSTANT * (float)elevationValue );
}
void SGameCamera::Dolly(int delta) //카메라 줌 인 줌 아웃
{
Distance( m_fDollyConstant * (float)delta );
}
void SGameCamera::SetTargetPosition(K3DVector pos) // 카메라 이동 target. 나중에 적당한 함수로 보간
{
m_targetPositionDestination = pos;
}
void SGameCamera::ResetDistanceDelta()
{
m_fDistanceDelta = 0.0f;
m_bDistanceDelta = false;
}
//
// 카메라 상대위치 계산
//
void SGameCamera::CalculateCamera( float fBaseHeight, bool bBaseHeight )
{
/* if( bUseNewCame )
{
K3DVector tarpos = m_targetPositionDestination;
K3DVector orgpos = m_pCamera->GetCamOrgPos();
K3DVector vTarget = m_pCamera->GetTargetPos();
vTarget.z -= m_fTargetZOffSet;
vTarget = m_targetPositionDestination - vTarget;
orgpos += vTarget;
K3DVector vtView = m_pCamera->GetTargetPos() - m_pCamera->GetCamPos();
vtView.z = 0.0f;
Normalize(vtView);
K3DVector vtUp = m_pCamera->GetUpVector();
Normalize(vtUp);
K3DVector vtRes;
vtRes = CrossProduct( vtView, vtUp );
K3DMatrix mat( vtRes, vtUp, vtView );
K3DMatrix invMat;
K3DMatrixInverse(invMat,mat);
K3DMatrix rotmat;
K3DMatrixRotationYawPitchRoll( rotmat, -fTurn, -fElevate, 0 );
K3DMatrixMultiply( invMat, invMat, rotmat );
K3DMatrix resMat;
K3DMatrixMultiply( resMat, invMat, mat);
orgpos -= tarpos;
K3DVectorTransform( orgpos, orgpos, resMat );
orgpos += tarpos;
tarpos.z = m_targetPositionDestination.z + m_fTargetZOffSet;
vtView = tarpos - orgpos;
Normalize(vtView);
orgpos -= vtView * fDistance;
m_pCamera->SetTargetPos( m_targetPositionDestination.x, m_targetPositionDestination.y, m_targetPositionDestination.z + m_fTargetZOffSet );
m_pCamera->SetOrgCamPos(orgpos.x, orgpos.y, orgpos.z );
m_pCamera->SetCurCamPos(orgpos.x, orgpos.y, orgpos.z + m_fTargetZOffSet + m_targetPositionDestination.z );
fTurn = 0.0f;
fElevate = 0.0f;
fDistance = 0.0f;
return;
}*/
m_fCurRadius = m_fRadius;
if( m_fPrevRadius != m_fRadius )
{
if( m_dwLerpTime == 0 ) m_dwLerpTime = m_dwTime;
if( m_dwTime - m_dwLerpTime > CAMERA_ZOOM_IN_OUT_TIME )
{
m_dwLerpTime = 0;
m_fPrevRadius = m_fRadius;
}
else
{
m_fCurRadius = m_fPrevRadius + ( ((float)(m_dwTime-m_dwLerpTime)/CAMERA_ZOOM_IN_OUT_TIME) * ( m_fRadius - m_fPrevRadius ) );
}
}
K3DMatrix matRotX, matRotZ;
K3DMatrixRotationX( matRotX, m_fAngleX );
K3DMatrixRotationZ( matRotZ, m_fAngleZ );
K3DMatrixMultiply( m_matCam, matRotX, matRotZ );
m_relativeCameraPosition = K3DVector( 0.0f, 1.0f, 0.0f) * m_fCurRadius;
K3DVectorTransform( m_relativeCameraPosition, m_relativeCameraPosition, m_matCam );
// [sonador][COLLIDABLE_CAMERA]
//m_relativeCameraPosition.z += m_targetPositionDestination.z + m_fTargetZOffSet;
//K3DVector tpos( 0.0f, 0.0f, 0.0f );
//K3DVector cpos = m_relativeCameraPosition;
//cpos.z = 0.0f;
//
// float fLength = K3DVectorLength( tpos - cpos );
//m_relativeCameraPosition.z += m_targetPositionDestination.z + m_fTargetZOffSet;
//if( bBaseHeight )
//{
// if (m_relativeCameraPosition.z < fBaseHeight + (CAMERA_ELEVATION_BASE*fLength) )
// {
// if( m_bDistanceDelta )
// {
// m_fAngleX -= m_fDistanceDelta * CAMERA_ROTATION_CONSTANT;
// if( m_fAngleX >= CAMERA_DISTANCE_ZOOM_MIN_MAX - CAMERA_DISTANCE_ZOOM_BASE )
// m_fAngleX = CAMERA_DISTANCE_ZOOM_MIN_MAX - CAMERA_DISTANCE_ZOOM_BASE;
// if( m_fAngleX <= -CAMERA_DISTANCE_ZOOM_MIN_MAX + CAMERA_DISTANCE_ZOOM_BASE )
// m_fAngleX = -CAMERA_DISTANCE_ZOOM_MIN_MAX + CAMERA_DISTANCE_ZOOM_BASE;
// ResetDistanceDelta();
// }
// m_relativeCameraPosition.z = fBaseHeight + (CAMERA_ELEVATION_BASE*fLength);
// }
//}
// 카메라 타겟 움직임
m_targetPositionCurrent = m_targetPositionDestination;
m_targetPositionCurrent.z += m_fTargetZOffSet;
ProcessAnimator();
}
//
// 실제 카메라 위치 가져오는 함수
//
K3DVector SGameCamera::GetCameraPosition() const // 카메라 위치
{
/* if( bUseNewCame )
{
return m_pCamera->GetCamPos();
}*/
//K3DVector pos=m_targetPositionCurrent+m_relativeCameraPosition;
//pos.z=m_relativeCameraPosition.z;
//return pos;
return m_targetPositionCurrent + m_relativeCameraPosition;
}
K3DVector SGameCamera::GetCameraTargetPosition() const // 카메라 타겟 위치
{
/* if( bUseNewCame )
{
return m_pCamera->GetTargetPos();
}*/
return m_targetPositionCurrent;
}
void SGameCamera::ApplyCameraPositions()
{
// if( bUseNewCame ) return;
K3DVector pos=GetCameraPosition();
m_pCamera->SetCurCamPos(pos.x, pos.y, pos.z);
pos=GetCameraTargetPosition();
m_pCamera->SetTargetPos(pos.x, pos.y, pos.z);
}
void SGameCamera::FileTextOut( FILE* pF, bool bDetail )
{
if( pF )
{
fprintf( pF, "RADIUS|%f|" , m_fRadius );
fprintf( pF, "XANGLE|%f|" , m_fAngleX );
fprintf( pF, "ZANGLE|%f|" , m_fAngleZ );
if( bDetail )
{
K3DVector pos;
m_pCamera->GetCamPos(pos.x, pos.y, pos.z);
fprintf( pF, "CAMPOS|%f|%f|%f|" , pos.x, pos.y, pos.z );
m_pCamera->GetTargetPos(pos.x, pos.y, pos.z);
fprintf( pF, "TARPOS|%f|%f|%f|" , pos.x, pos.y, pos.z );
}
}
}
void SGameCamera::FileTextIn( char *pBuf, bool bDetail )
{
if( pBuf )
{
std::vector< std::string > vString;
XStringUtil::Split( pBuf, vString, "|\r\n" );
int nLoop = (int)vString.size();
if( bDetail )
{
if( nLoop >= 14 )
{
for( int i(0); 1>i; i++ )
{
vString[i++].c_str(); //Radius
m_fRadius = atof( vString[i++].c_str() );
vString[i++].c_str(); //XAngle
m_fAngleX = atof( vString[i++].c_str() );
vString[i++].c_str(); //ZAngle
m_fAngleZ = atof( vString[i++].c_str() );
vString[i++].c_str(); //CAMPOS
K3DVector pos, tar_pos;
pos.x = atof( vString[i++].c_str() );
pos.y = atof( vString[i++].c_str() );
pos.z = atof( vString[i++].c_str() );
m_cameraPosition = pos;
m_pCamera->SetCamPos(pos.x, pos.y, pos.z);
vString[i++].c_str(); //TARPOS
tar_pos.x = atof( vString[i++].c_str() );
tar_pos.y = atof( vString[i++].c_str() );
tar_pos.z = atof( vString[i++].c_str() );
m_targetPositionDestination = tar_pos;
m_pCamera->SetTargetPos(tar_pos.x, tar_pos.y, tar_pos.z);
vString.clear();
return;
}
}
}
//
if( nLoop >= 6 )
{
for( int i(0); 1>i; i++ )
{
vString[i++].c_str(); //Radius
m_fRadius = atof( vString[i++].c_str() );
vString[i++].c_str(); //XAngle
m_fAngleX = atof( vString[i++].c_str() );
vString[i++].c_str(); //ZAngle
m_fAngleZ = atof( vString[i++].c_str() );
}
}
vString.clear();
}
}
void SGameCamera::SetCameraWork( SGameCameraWork* pCameraWork )
{
if( pCameraWork )
{
if( m_pCameraWork ) SAFE_DELETE( m_pCameraWork );
m_nCameraMode = CAMERA_STANDING_MODE;
m_pCameraWork = pCameraWork;
}
else
{
SAFE_DELETE( m_pCameraWork );
}
}
void SGameCamera::StopCameraWork()
{
if( m_pCameraWork )
{
m_pCameraWork->Stop();
}
else
{
if( m_nCameraMode != CAMERA_GAME_MODE )
{
m_nCameraMode = CAMERA_GAME_MODE;
}
}
}
bool SGameCamera::IsStopCameraWork()
{
if( m_pCameraWork )
return m_pCameraWork->IsStop();
return true;
}
// { [sonador][COLLIDABLE_CAMERA]
void SGameCamera::ProcessAnimator()
{
t_animator_vector::iterator itAnimatorEnd = m_animators.end();
for (t_animator_vector::iterator itAnimator = m_animators.begin();
itAnimator != itAnimatorEnd; ++itAnimator)
{
(*itAnimator)->Animate(m_dwTime, *this);
}
}
void SGameCamera::AddAnimator( IGameCameraAnimator& animator )
{
m_animators.push_back( &animator );
}
void SGameCamera::RemoveAnimator( IGameCameraAnimator& animator )
{
m_animators.erase( std::remove( m_animators.begin(), m_animators.end(), &animator ), m_animators.end() );
}
void SGameCamera::RemoveAllAnimator()
{
m_animators.clear();
}
// }