#include "stdafx.h" #include "K3DCamera.h" #include "SGameCamera.h" #include "SGame.h" #include "SGameMessage.h" #include "kviewport.h" #include "GameRule.h" #include #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(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(); } // }