Add high-FPS render pacing and telemetry

This commit is contained in:
server
2026-04-16 10:37:08 +02:00
parent 49e8eac809
commit bfe52a81f9
15 changed files with 1402 additions and 233 deletions

View File

@@ -65,6 +65,11 @@ VOID ELTimer_SetFrameMSec()
gs_dwFrameTime = ELTimer_GetMSec();
}
VOID ELTimer_SetFrameMSecValue(DWORD dwFrameTime)
{
gs_dwFrameTime = dwFrameTime;
}
CTimer::CTimer()
{
ELTimer_Init();

View File

@@ -38,4 +38,5 @@ VOID ELTimer_SetServerMSec(DWORD dwServerTime);
DWORD ELTimer_GetServerMSec();
VOID ELTimer_SetFrameMSec();
DWORD ELTimer_GetFrameMSec();
VOID ELTimer_SetFrameMSecValue(DWORD dwFrameTime);
DWORD ELTimer_GetFrameMSec();

View File

@@ -18,6 +18,9 @@ void CActorInstance::INSTANCEBASE_Deform()
void CActorInstance::INSTANCEBASE_Transform()
{
m_v3InterpolationStartPosition = D3DXVECTOR3(m_x, m_y, m_z);
m_fInterpolationStartRotation = m_fcurRotation;
if (m_pkHorse)
{
m_pkHorse->INSTANCEBASE_Transform();
@@ -44,6 +47,30 @@ void CActorInstance::INSTANCEBASE_Transform()
UpdateAttribute();
}
void CActorInstance::ApplyRenderInterpolation(float fInterpolation)
{
const float fAlpha = std::max(0.0f, std::min(1.0f, fInterpolation));
D3DXVECTOR3 v3InterpolatedPosition;
v3InterpolatedPosition.x = m_v3InterpolationStartPosition.x + (m_x - m_v3InterpolationStartPosition.x) * fAlpha;
v3InterpolatedPosition.y = m_v3InterpolationStartPosition.y + (m_y - m_v3InterpolationStartPosition.y) * fAlpha;
v3InterpolatedPosition.z = m_v3InterpolationStartPosition.z + (m_z - m_v3InterpolationStartPosition.z) * fAlpha;
const float fInterpolatedRotation = GetInterpolatedRotation(m_fInterpolationStartRotation, m_fcurRotation, fAlpha);
SetPosition(v3InterpolatedPosition);
if (0.0f != m_rotX || 0.0f != m_rotY)
{
CGraphicObjectInstance::SetRotation(m_rotX, m_rotY, fInterpolatedRotation);
}
else
{
CGraphicObjectInstance::SetRotation(fInterpolatedRotation);
}
Transform();
}
void CActorInstance::OnUpdate()
{
@@ -875,6 +902,7 @@ void CActorInstance::__InitializeRotationData()
{
m_fAtkDirRot = 0.0f;
m_fcurRotation = 0.0f;
m_fInterpolationStartRotation = 0.0f;
m_rotBegin = 0.0f;
m_rotEnd = 0.0f;
m_rotEndTime = 0.0f;

View File

@@ -425,6 +425,7 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
void LookAt(CActorInstance * pInstance);
void LookWith(CActorInstance * pInstance);
void LookAtFromXY(float x, float y, CActorInstance * pDestInstance);
void ApplyRenderInterpolation(float fInterpolation);
void SetReachScale(float fScale);
@@ -767,6 +768,7 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
float m_x;
float m_y;
float m_z;
D3DXVECTOR3 m_v3InterpolationStartPosition;
D3DXVECTOR3 m_v3Pos;
D3DXVECTOR3 m_v3Movement;
BOOL m_bNeedUpdateCollision;
@@ -779,6 +781,7 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
// Rotation
float m_fcurRotation;
float m_fInterpolationStartRotation;
float m_rotBegin;
float m_rotEnd;
float m_rotEndTime;

View File

@@ -245,6 +245,15 @@ void CInstanceBase::SHORSE::Render()
rkActor.Render();
}
void CInstanceBase::SHORSE::ApplyRenderInterpolation(float fInterpolation)
{
if (!IsMounting())
return;
CActorInstance& rkActor = GetActorRef();
rkActor.ApplyRenderInterpolation(fInterpolation);
}
void CInstanceBase::__AttachHorseSaddle()
{
if (!IsMountingHorse())
@@ -1948,6 +1957,12 @@ void CInstanceBase::Transform()
m_GraphicThingInstance.INSTANCEBASE_Transform();
}
void CInstanceBase::ApplyRenderInterpolation(float fInterpolation)
{
m_kHorse.ApplyRenderInterpolation(fInterpolation);
m_GraphicThingInstance.ApplyRenderInterpolation(fInterpolation);
}
void CInstanceBase::Deform()
{

View File

@@ -472,6 +472,7 @@ class CInstanceBase
bool UpdateDeleting();
void Transform();
void ApplyRenderInterpolation(float fInterpolation);
void Deform();
void Render();
void RenderTrace();
@@ -847,6 +848,7 @@ class CInstanceBase
void SetMoveSpeed(UINT uMovSpd);
void Deform();
void Render();
void ApplyRenderInterpolation(float fInterpolation);
CActorInstance& GetActorRef();
CActorInstance* GetActorPtr();
@@ -1139,4 +1141,4 @@ inline int RaceToSex(int race)
}
return 0;
}
}

View File

@@ -6,12 +6,15 @@
#include "EterGrnLib/Material.h"
#include "resource.h"
#include "GameType.h"
#include "PythonApplication.h"
#include "PythonCharacterManager.h"
#include "ProcessScanner.h"
#include <utf8.h>
#include <cstdarg>
#include <cstdlib>
extern void GrannyCreateSharedDeformBuffer();
extern void GrannyDestroySharedDeformBuffer();
@@ -21,6 +24,91 @@ double g_specularSpd=0.007f;
CPythonApplication * CPythonApplication::ms_pInstance;
namespace
{
// Match the legacy custom timer cadence of alternating 17 ms and 16 ms.
constexpr double kFixedUpdateMS = 16.5;
constexpr double kMaxCatchUpDelayMS = 250.0;
float ClampInterpolationFactor(float fInterpolation)
{
return std::max(0.0f, std::min(1.0f, fInterpolation));
}
D3DXVECTOR3 LerpVector3(const D3DXVECTOR3& c_rv3Begin, const D3DXVECTOR3& c_rv3End, float fInterpolation)
{
return D3DXVECTOR3(
c_rv3Begin.x + (c_rv3End.x - c_rv3Begin.x) * fInterpolation,
c_rv3Begin.y + (c_rv3End.y - c_rv3Begin.y) * fInterpolation,
c_rv3Begin.z + (c_rv3End.z - c_rv3Begin.z) * fInterpolation);
}
bool IsRenderTelemetryEnabledFromEnvironment()
{
const char* c_szValue = std::getenv("M2_RENDER_TELEMETRY");
if (!c_szValue || !*c_szValue)
return false;
if (0 == _stricmp(c_szValue, "1") || 0 == _stricmp(c_szValue, "true") || 0 == _stricmp(c_szValue, "yes") || 0 == _stricmp(c_szValue, "on"))
return true;
return false;
}
bool TryReadEnvironmentInt(const char* c_szName, int* piValue)
{
if (!piValue)
return false;
const char* c_szValue = std::getenv(c_szName);
if (!c_szValue || !*c_szValue)
return false;
char* pEnd = nullptr;
const long lValue = std::strtol(c_szValue, &pEnd, 10);
if (pEnd == c_szValue || (pEnd && *pEnd))
return false;
*piValue = static_cast<int>(lValue);
return true;
}
void ResetRenderTelemetryTrace()
{
FILE* fp = nullptr;
if (fopen_s(&fp, "log/render_telemetry.txt", "w") != 0 || !fp)
return;
fprintf(fp, "render telemetry\n");
fclose(fp);
}
void AppendRenderTelemetryTrace(const char* c_szFormat, ...)
{
FILE* fp = nullptr;
if (fopen_s(&fp, "log/render_telemetry.txt", "a") != 0 || !fp)
return;
va_list args;
va_start(args, c_szFormat);
vfprintf(fp, c_szFormat, args);
va_end(args);
fputc('\n', fp);
fclose(fp);
}
void FormatRenderTargetFPSLabel(unsigned int iFPS, char* c_szBuffer, size_t uBufferSize)
{
if (!c_szBuffer || 0 == uBufferSize)
return;
if (iFPS > 0)
_snprintf_s(c_szBuffer, uBufferSize, _TRUNCATE, "%u", iFPS);
else
_snprintf_s(c_szBuffer, uBufferSize, _TRUNCATE, "MAX");
}
}
float c_fDefaultCameraRotateSpeed = 1.5f;
float c_fDefaultCameraPitchSpeed = 1.5f;
float c_fDefaultCameraZoomSpeed = 0.05f;
@@ -35,9 +123,28 @@ m_poMouseHandler(NULL),
m_dwUpdateFPS(0),
m_dwRenderFPS(0),
m_fAveRenderTime(0.0f),
m_bRenderTelemetryEnabled(false),
m_bRenderTelemetryHudVisible(false),
m_dwRenderTelemetryIntervalMS(1000),
m_dwRenderTelemetryWindowStartMS(0),
m_dwRenderTelemetryLoopCount(0),
m_dwRenderTelemetryUpdateCount(0),
m_dwRenderTelemetryRenderCount(0),
m_dwRenderTelemetryBlockedRenderCount(0),
m_dwRenderTelemetryLastPresentTime(0),
m_dwRenderTelemetryPresentGapSamples(0),
m_fRenderTelemetryUpdateTimeSumMS(0.0),
m_fRenderTelemetryRenderTimeSumMS(0.0),
m_fRenderTelemetrySleepTimeSumMS(0.0),
m_fRenderTelemetryInterpolationSum(0.0),
m_fRenderTelemetryPresentGapSumMS(0.0),
m_dwCurRenderTime(0),
m_dwCurUpdateTime(0),
m_dwLoad(0),
m_dwFaceCount(0),
m_fGlobalTime(0.0f),
m_fGlobalElapsedTime(0.0f),
m_fRenderInterpolationFactor(0.0f),
m_dwLButtonDownTime(0),
m_dwLastIdleTime(0),
m_IsMovingMainWindow(false)
@@ -54,12 +161,15 @@ m_IsMovingMainWindow(false)
m_isWindowFullScreenEnable = FALSE;
m_v3CenterPosition = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
m_v3LastCenterPosition = m_v3CenterPosition;
m_dwStartLocalTime = ELTimer_GetMSec();
m_tServerTime = 0;
m_tLocalStartTime = 0;
m_iPort = 0;
m_iFPS = 60;
m_iFPS = std::max(0, m_pySystem.GetRenderFPS());
m_bRenderTelemetryHudVisible = m_pySystem.IsShowPerformanceHUD();
InitializeRenderRuntimeOverrides();
m_isActivateWnd = false;
m_isMinimizedWnd = true;
@@ -168,6 +278,7 @@ void CPythonApplication::RenderGame()
float fFarClip = m_pyBackground.GetFarClip();
m_pyGraphic.SetPerspective(30.0f, fAspect, 100.0, fFarClip);
ApplyRenderInterpolation();
CCullingManager::Instance().Process();
@@ -256,10 +367,137 @@ void CPythonApplication::UpdateGame()
SetCenterPosition(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z);
}
void CPythonApplication::InitializeRenderRuntimeOverrides()
{
m_bRenderTelemetryEnabled = IsRenderTelemetryEnabledFromEnvironment();
int iIntervalMS = 0;
if (TryReadEnvironmentInt("M2_RENDER_TELEMETRY_INTERVAL_MS", &iIntervalMS) && iIntervalMS > 0)
m_dwRenderTelemetryIntervalMS = static_cast<DWORD>(std::min(iIntervalMS, 60000));
if (m_bRenderTelemetryEnabled)
{
ResetRenderTelemetryTrace();
AppendRenderTelemetryTrace("enabled interval_ms=%lu", static_cast<unsigned long>(m_dwRenderTelemetryIntervalMS));
}
int iRenderFPS = 0;
if (TryReadEnvironmentInt("M2_RENDER_FPS", &iRenderFPS))
{
m_iFPS = std::max(0, iRenderFPS);
if (m_bRenderTelemetryEnabled)
AppendRenderTelemetryTrace("env_override target_fps=%u", m_iFPS);
}
char szTargetFPS[16];
FormatRenderTargetFPSLabel(m_iFPS, szTargetFPS, sizeof(szTargetFPS));
m_stRenderTelemetrySummary = "Render telemetry\nTarget FPS: ";
m_stRenderTelemetrySummary += szTargetFPS;
m_stRenderTelemetrySummary += "\nCollecting frame pacing...";
if (IsRenderTelemetrySamplingEnabled())
ResetRenderTelemetryWindow(ELTimer_GetMSec());
}
void CPythonApplication::ResetRenderTelemetryWindow(DWORD dwNow)
{
m_dwRenderTelemetryWindowStartMS = dwNow;
m_dwRenderTelemetryLoopCount = 0;
m_dwRenderTelemetryUpdateCount = 0;
m_dwRenderTelemetryRenderCount = 0;
m_dwRenderTelemetryBlockedRenderCount = 0;
m_dwRenderTelemetryPresentGapSamples = 0;
m_fRenderTelemetryUpdateTimeSumMS = 0.0;
m_fRenderTelemetryRenderTimeSumMS = 0.0;
m_fRenderTelemetrySleepTimeSumMS = 0.0;
m_fRenderTelemetryInterpolationSum = 0.0;
m_fRenderTelemetryPresentGapSumMS = 0.0;
}
void CPythonApplication::FlushRenderTelemetryWindow(DWORD dwNow)
{
if (!IsRenderTelemetrySamplingEnabled() || !m_dwRenderTelemetryWindowStartMS)
return;
const DWORD dwWindowMS = std::max<DWORD>(1, dwNow - m_dwRenderTelemetryWindowStartMS);
const double fWindowMS = static_cast<double>(dwWindowMS);
const double fUpdateFPS = static_cast<double>(m_dwRenderTelemetryUpdateCount) * 1000.0 / fWindowMS;
const double fRenderFPS = static_cast<double>(m_dwRenderTelemetryRenderCount) * 1000.0 / fWindowMS;
const double fAvgUpdateMS = m_dwRenderTelemetryUpdateCount ? (m_fRenderTelemetryUpdateTimeSumMS / static_cast<double>(m_dwRenderTelemetryUpdateCount)) : 0.0;
const double fAvgRenderMS = m_dwRenderTelemetryRenderCount ? (m_fRenderTelemetryRenderTimeSumMS / static_cast<double>(m_dwRenderTelemetryRenderCount)) : 0.0;
const double fAvgSleepMS = m_dwRenderTelemetryLoopCount ? (m_fRenderTelemetrySleepTimeSumMS / static_cast<double>(m_dwRenderTelemetryLoopCount)) : 0.0;
const double fAvgInterpolation = m_dwRenderTelemetryRenderCount ? (m_fRenderTelemetryInterpolationSum / static_cast<double>(m_dwRenderTelemetryRenderCount)) : 0.0;
const double fAvgPresentGapMS = m_dwRenderTelemetryPresentGapSamples ? (m_fRenderTelemetryPresentGapSumMS / static_cast<double>(m_dwRenderTelemetryPresentGapSamples)) : 0.0;
const DWORD dwElapsedMS = dwNow - m_dwStartLocalTime;
char szTargetFPS[16];
char szSummary[256];
FormatRenderTargetFPSLabel(m_iFPS, szTargetFPS, sizeof(szTargetFPS));
_snprintf_s(
szSummary,
sizeof(szSummary),
_TRUNCATE,
"Render %.1f Update %.1f Target %s\nPresent %.1fms Sleep %.1fms CPU %.1f/%.1fms",
fRenderFPS,
fUpdateFPS,
szTargetFPS,
fAvgPresentGapMS,
fAvgSleepMS,
fAvgUpdateMS,
fAvgRenderMS);
m_stRenderTelemetrySummary = szSummary;
if (m_bRenderTelemetryEnabled)
{
AppendRenderTelemetryTrace(
"elapsed_ms=%lu window_ms=%lu target_fps=%u update_fps=%.2f render_fps=%.2f avg_update_ms=%.2f avg_render_ms=%.2f avg_sleep_ms=%.2f avg_present_gap_ms=%.2f avg_interp=%.3f loops=%lu updates=%lu renders=%lu blocked=%lu cur_update_ms=%lu cur_render_ms=%lu",
static_cast<unsigned long>(dwElapsedMS),
static_cast<unsigned long>(dwWindowMS),
m_iFPS,
fUpdateFPS,
fRenderFPS,
fAvgUpdateMS,
fAvgRenderMS,
fAvgSleepMS,
fAvgPresentGapMS,
fAvgInterpolation,
static_cast<unsigned long>(m_dwRenderTelemetryLoopCount),
static_cast<unsigned long>(m_dwRenderTelemetryUpdateCount),
static_cast<unsigned long>(m_dwRenderTelemetryRenderCount),
static_cast<unsigned long>(m_dwRenderTelemetryBlockedRenderCount),
static_cast<unsigned long>(m_dwCurUpdateTime),
static_cast<unsigned long>(m_dwCurRenderTime));
}
ResetRenderTelemetryWindow(dwNow);
}
bool CPythonApplication::IsRenderTelemetrySamplingEnabled() const
{
return m_bRenderTelemetryEnabled || m_bRenderTelemetryHudVisible;
}
void CPythonApplication::RenderPerformanceHUD()
{
if (!m_bRenderTelemetryHudVisible)
return;
CGraphicText* pkDefaultFont = static_cast<CGraphicText*>(DefaultFont_GetResource());
if (!pkDefaultFont)
return;
m_kRenderTelemetryTextLine.SetTextPointer(pkDefaultFont);
m_kRenderTelemetryTextLine.SetOutline(true);
m_kRenderTelemetryTextLine.SetMultiLine(true);
m_kRenderTelemetryTextLine.SetColor(1.0f, 1.0f, 1.0f);
m_kRenderTelemetryTextLine.SetPosition(12.0f, 12.0f);
m_kRenderTelemetryTextLine.SetValueString(m_stRenderTelemetrySummary);
m_kRenderTelemetryTextLine.Update();
m_kRenderTelemetryTextLine.Render();
}
bool CPythonApplication::Process()
{
ELTimer_SetFrameMSec();
// m_Profiler.Clear();
DWORD dwStart = ELTimer_GetMSec();
@@ -269,6 +507,18 @@ bool CPythonApplication::Process()
static DWORD s_dwFaceCount = 0;
static UINT s_uiLoad = 0;
static DWORD s_dwCheckTime = ELTimer_GetMSec();
static double s_fNextUpdateTime = static_cast<double>(ELTimer_GetMSec());
static double s_fNextRenderTime = static_cast<double>(ELTimer_GetMSec());
static double s_fFixedFrameTime = static_cast<double>(ELTimer_GetMSec());
DWORD dwCurrentTime = ELTimer_GetMSec();
const double fCurrentTime = static_cast<double>(dwCurrentTime);
const bool bSampleRenderTelemetry = IsRenderTelemetrySamplingEnabled();
if (bSampleRenderTelemetry && !m_dwRenderTelemetryWindowStartMS)
ResetRenderTelemetryWindow(dwCurrentTime);
if (bSampleRenderTelemetry)
++m_dwRenderTelemetryLoopCount;
if (ELTimer_GetMSec() - s_dwCheckTime > 1000) [[unlikely]] {
m_dwUpdateFPS = s_dwUpdateFrameCount;
@@ -282,278 +532,314 @@ bool CPythonApplication::Process()
s_uiLoad = s_dwFaceCount = s_dwUpdateFrameCount = s_dwRenderFrameCount = 0;
}
// Update Time
static BOOL s_bFrameSkip = false;
static UINT s_uiNextFrameTime = ELTimer_GetMSec();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime1=ELTimer_GetMSec();
#endif
CTimer& rkTimer=CTimer::Instance();
rkTimer.Advance();
m_fGlobalTime = rkTimer.GetCurrentSecond();
m_fGlobalElapsedTime = rkTimer.GetElapsedSecond();
UINT uiFrameTime = rkTimer.GetElapsedMilliecond();
s_uiNextFrameTime += uiFrameTime; //17 - 1ÃÊ´ç 60fps±âÁØ.
DWORD updatestart = ELTimer_GetMSec();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime2=ELTimer_GetMSec();
#endif
// Network I/O
m_pyNetworkStream.Process();
//m_pyNetworkDatagram.Process();
m_kGuildMarkUploader.Process();
m_kGuildMarkDownloader.Process();
m_kAccountConnector.Process();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime3=ELTimer_GetMSec();
#endif
//////////////////////
// Input Process
// Keyboard
UpdateKeyboard();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime4=ELTimer_GetMSec();
#endif
// Mouse
POINT Point;
if (GetCursorPos(&Point)) [[likely]] {
ScreenToClient(m_hWnd, &Point);
OnMouseMove(Point.x, Point.y);
}
//////////////////////
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime5=ELTimer_GetMSec();
#endif
//!@# Alt+Tab Áß SetTransfor ¿¡¼­ ƨ±è Çö»ó ÇØ°áÀ» À§ÇØ - [levites]
//if (m_isActivateWnd)
__UpdateCamera();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime6=ELTimer_GetMSec();
#endif
// Update Game Playing
CResourceManager::Instance().Update();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime7=ELTimer_GetMSec();
#endif
OnCameraUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime8=ELTimer_GetMSec();
#endif
OnMouseUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime9=ELTimer_GetMSec();
#endif
OnUIUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime10=ELTimer_GetMSec();
if (dwUpdateTime10-dwUpdateTime1>10)
{
static FILE* fp=fopen("perf_app_update.txt", "w");
fprintf(fp, "AU.Total %d (Time %d)\n", dwUpdateTime9-dwUpdateTime1, ELTimer_GetMSec());
fprintf(fp, "AU.TU %d\n", dwUpdateTime2-dwUpdateTime1);
fprintf(fp, "AU.NU %d\n", dwUpdateTime3-dwUpdateTime2);
fprintf(fp, "AU.KU %d\n", dwUpdateTime4-dwUpdateTime3);
fprintf(fp, "AU.MP %d\n", dwUpdateTime5-dwUpdateTime4);
fprintf(fp, "AU.CP %d\n", dwUpdateTime6-dwUpdateTime5);
fprintf(fp, "AU.RU %d\n", dwUpdateTime7-dwUpdateTime6);
fprintf(fp, "AU.CU %d\n", dwUpdateTime8-dwUpdateTime7);
fprintf(fp, "AU.MU %d\n", dwUpdateTime9-dwUpdateTime8);
fprintf(fp, "AU.UU %d\n", dwUpdateTime10-dwUpdateTime9);
fprintf(fp, "----------------------------------\n");
fflush(fp);
}
#endif
//UpdateÇϴµ¥ °É¸°½Ã°£.delta°ª
m_dwCurUpdateTime = ELTimer_GetMSec() - updatestart;
DWORD dwCurrentTime = ELTimer_GetMSec();
BOOL bCurrentLateUpdate = FALSE;
s_bFrameSkip = false;
if (dwCurrentTime > s_uiNextFrameTime)
if (fCurrentTime - s_fNextUpdateTime > kMaxCatchUpDelayMS)
{
int dt = dwCurrentTime - s_uiNextFrameTime;
int nAdjustTime = ((float)dt / (float)uiFrameTime) * uiFrameTime;
s_fNextUpdateTime = fCurrentTime;
s_fFixedFrameTime = fCurrentTime;
}
if ( dt >= 500 )
if (fCurrentTime - s_fNextRenderTime > kMaxCatchUpDelayMS)
s_fNextRenderTime = fCurrentTime;
int iUpdateCount = 0;
while (fCurrentTime + 0.0001 >= s_fNextUpdateTime)
{
if (!m_isFrameSkipDisable && iUpdateCount >= 5)
{
s_uiNextFrameTime += nAdjustTime;
printf("FrameSkip º¸Á¤ %d\n",nAdjustTime);
CTimer::Instance().Adjust(nAdjustTime);
s_fNextUpdateTime = fCurrentTime;
s_fFixedFrameTime = fCurrentTime;
break;
}
s_bFrameSkip = true;
bCurrentLateUpdate = TRUE;
}
++iUpdateCount;
s_fNextUpdateTime += kFixedUpdateMS;
s_fFixedFrameTime += kFixedUpdateMS;
ELTimer_SetFrameMSecValue(static_cast<DWORD>(s_fFixedFrameTime));
m_v3LastCenterPosition = m_v3CenterPosition;
//s_bFrameSkip = false;
//if (dwCurrentTime > s_uiNextFrameTime)
//{
// int dt = dwCurrentTime - s_uiNextFrameTime;
// //³Ê¹« ´Ê¾úÀ» °æ¿ì µû¶óÀâ´Â´Ù.
// //±×¸®°í m_dwCurUpdateTime´Â deltaÀε¥ delta¶û absolute timeÀ̶û ºñ±³ÇÏ¸é ¾î¼Àڴ°Ü?
// //if (dt >= 500 || m_dwCurUpdateTime > s_uiNextFrameTime)
// //±âÁ¸ÄÚµå´ë·Î Çϸé 0.5ÃÊ ÀÌÇÏ Â÷À̳­ »óÅ·Πupdate°¡ Áö¼ÓµÇ¸é °è¼Ó rendering frame skip¹ß»ý
// if (dt >= 500 || m_dwCurUpdateTime > s_uiNextFrameTime)
// {
// s_uiNextFrameTime += dt / uiFrameTime * uiFrameTime;
// printf("FrameSkip º¸Á¤ %d\n", dt / uiFrameTime * uiFrameTime);
// CTimer::Instance().Adjust((dt / uiFrameTime) * uiFrameTime);
// s_bFrameSkip = true;
// }
//}
if (m_isFrameSkipDisable)
s_bFrameSkip = false;
#ifdef __VTUNE__
s_bFrameSkip = false;
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime1=ELTimer_GetMSec();
#endif
if (!s_bFrameSkip)
{
// static double pos=0.0f;
// CGrannyMaterial::TranslateSpecularMatrix(fabs(sin(pos)*0.005), fabs(cos(pos)*0.005), 0.0f);
// pos+=0.01f;
CTimer& rkTimer=CTimer::Instance();
rkTimer.Advance();
m_fGlobalTime = rkTimer.GetCurrentSecond();
m_fGlobalElapsedTime = rkTimer.GetElapsedSecond();
DWORD updatestart = ELTimer_GetMSec();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime2=ELTimer_GetMSec();
#endif
// Network I/O
m_pyNetworkStream.Process();
//m_pyNetworkDatagram.Process();
m_kGuildMarkUploader.Process();
m_kGuildMarkDownloader.Process();
m_kAccountConnector.Process();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime3=ELTimer_GetMSec();
#endif
//////////////////////
// Input Process
// Keyboard
UpdateKeyboard();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime4=ELTimer_GetMSec();
#endif
// Mouse
POINT Point;
if (GetCursorPos(&Point)) [[likely]] {
ScreenToClient(m_hWnd, &Point);
OnMouseMove(Point.x, Point.y);
}
//////////////////////
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime5=ELTimer_GetMSec();
#endif
//!@# Alt+Tab Áß SetTransfor ¿¡¼­ ƨ±è Çö»ó ÇØ°áÀ» À§ÇØ - [levites]
//if (m_isActivateWnd)
__UpdateCamera();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime6=ELTimer_GetMSec();
#endif
// Update Game Playing
CResourceManager::Instance().Update();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime7=ELTimer_GetMSec();
#endif
OnCameraUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime8=ELTimer_GetMSec();
#endif
OnMouseUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime9=ELTimer_GetMSec();
#endif
CGrannyMaterial::TranslateSpecularMatrix(g_specularSpd, g_specularSpd, 0.0f);
OnUIUpdate();
DWORD dwRenderStartTime = ELTimer_GetMSec();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime10=ELTimer_GetMSec();
bool canRender = true;
if (m_isMinimizedWnd) [[unlikely]] {
canRender = false;
}
else [[likely]] {
if (m_pyGraphic.IsLostDevice()) [[unlikely]] {
CPythonBackground& rkBG = CPythonBackground::Instance();
rkBG.ReleaseCharacterShadowTexture();
if (m_pyGraphic.RestoreDevice())
rkBG.CreateCharacterShadowTexture();
else
canRender = false;
}
}
if (canRender) [[likely]]
if (dwUpdateTime10-dwUpdateTime1>10)
{
// RestoreLostDevice
CCullingManager::Instance().Update();
if (m_pyGraphic.Begin()) [[likely]] {
static FILE* fp=fopen("perf_app_update.txt", "w");
m_pyGraphic.ClearDepthBuffer();
fprintf(fp, "AU.Total %d (Time %d)\n", dwUpdateTime9-dwUpdateTime1, ELTimer_GetMSec());
fprintf(fp, "AU.TU %d\n", dwUpdateTime2-dwUpdateTime1);
fprintf(fp, "AU.NU %d\n", dwUpdateTime3-dwUpdateTime2);
fprintf(fp, "AU.KU %d\n", dwUpdateTime4-dwUpdateTime3);
fprintf(fp, "AU.MP %d\n", dwUpdateTime5-dwUpdateTime4);
fprintf(fp, "AU.CP %d\n", dwUpdateTime6-dwUpdateTime5);
fprintf(fp, "AU.RU %d\n", dwUpdateTime7-dwUpdateTime6);
fprintf(fp, "AU.CU %d\n", dwUpdateTime8-dwUpdateTime7);
fprintf(fp, "AU.MU %d\n", dwUpdateTime9-dwUpdateTime8);
fprintf(fp, "AU.UU %d\n", dwUpdateTime10-dwUpdateTime9);
fprintf(fp, "----------------------------------\n");
fflush(fp);
}
#endif
//UpdateÇϴµ¥ °É¸°½Ã°£.delta°ª
m_dwCurUpdateTime = ELTimer_GetMSec() - updatestart;
if (bSampleRenderTelemetry)
{
++m_dwRenderTelemetryUpdateCount;
m_fRenderTelemetryUpdateTimeSumMS += static_cast<double>(m_dwCurUpdateTime);
}
++s_dwUpdateFrameCount;
}
const double fPreviousUpdateTime = s_fNextUpdateTime - kFixedUpdateMS;
m_fRenderInterpolationFactor = ClampInterpolationFactor(static_cast<float>((fCurrentTime - fPreviousUpdateTime) / kFixedUpdateMS));
DWORD dwRenderStartTime = ELTimer_GetMSec();
bool canRender = true;
bool didRender = false;
if (m_isMinimizedWnd) [[unlikely]] {
canRender = false;
}
else [[likely]] {
if (m_pyGraphic.IsLostDevice()) [[unlikely]] {
CPythonBackground& rkBG = CPythonBackground::Instance();
rkBG.ReleaseCharacterShadowTexture();
if (m_pyGraphic.RestoreDevice())
rkBG.CreateCharacterShadowTexture();
else
canRender = false;
}
}
if (canRender) [[likely]]
{
// RestoreLostDevice
CCullingManager::Instance().Update();
if (m_pyGraphic.Begin()) [[likely]] {
m_pyGraphic.ClearDepthBuffer();
#ifdef _DEBUG
m_pyGraphic.SetClearColor(0.3f, 0.3f, 0.3f);
m_pyGraphic.Clear();
m_pyGraphic.SetClearColor(0.3f, 0.3f, 0.3f);
m_pyGraphic.Clear();
#endif
/////////////////////
// Interface
m_pyGraphic.SetInterfaceRenderState();
/////////////////////
// Interface
m_pyGraphic.SetInterfaceRenderState();
OnUIRender();
OnMouseRender();
/////////////////////
OnUIRender();
RenderPerformanceHUD();
OnMouseRender();
/////////////////////
m_pyGraphic.End();
m_pyGraphic.End();
m_pyGraphic.Show();
//DWORD t1 = ELTimer_GetMSec();
m_pyGraphic.Show();
//DWORD t2 = ELTimer_GetMSec();
DWORD dwRenderEndTime = ELTimer_GetMSec();
didRender = true;
DWORD dwRenderEndTime = ELTimer_GetMSec();
static DWORD s_dwRenderCheckTime = dwRenderEndTime;
static DWORD s_dwRenderRangeTime = 0;
static DWORD s_dwRenderRangeFrame = 0;
static DWORD s_dwRenderCheckTime = dwRenderEndTime;
static DWORD s_dwRenderRangeTime = 0;
static DWORD s_dwRenderRangeFrame = 0;
m_dwCurRenderTime = dwRenderEndTime - dwRenderStartTime;
s_dwRenderRangeTime += m_dwCurRenderTime;
++s_dwRenderRangeFrame;
m_dwCurRenderTime = dwRenderEndTime - dwRenderStartTime;
s_dwRenderRangeTime += m_dwCurRenderTime;
++s_dwRenderRangeFrame;
if (dwRenderEndTime-s_dwRenderCheckTime>1000) [[unlikely]] {
m_fAveRenderTime=float(double(s_dwRenderRangeTime)/double(s_dwRenderRangeFrame));
if (dwRenderEndTime-s_dwRenderCheckTime>1000) [[unlikely]] {
m_fAveRenderTime=float(double(s_dwRenderRangeTime)/double(s_dwRenderRangeFrame));
s_dwRenderCheckTime=ELTimer_GetMSec();
s_dwRenderRangeTime=0;
s_dwRenderRangeFrame=0;
}
s_dwRenderCheckTime=ELTimer_GetMSec();
s_dwRenderRangeTime=0;
s_dwRenderRangeFrame=0;
}
DWORD dwCurFaceCount=m_pyGraphic.GetFaceCount();
m_pyGraphic.ResetFaceCount();
s_dwFaceCount += dwCurFaceCount;
DWORD dwCurFaceCount=m_pyGraphic.GetFaceCount();
m_pyGraphic.ResetFaceCount();
s_dwFaceCount += dwCurFaceCount;
if (dwCurFaceCount > 5000)
{
m_dwFaceAccCount += dwCurFaceCount;
m_dwFaceAccTime += m_dwCurRenderTime;
if (dwCurFaceCount > 5000)
m_fFaceSpd=(m_dwFaceAccCount/m_dwFaceAccTime);
// °Å¸® ÀÚµ¿ Á¶Àý
if (-1 == m_iForceSightRange)
{
m_dwFaceAccCount += dwCurFaceCount;
m_dwFaceAccTime += m_dwCurRenderTime;
m_fFaceSpd=(m_dwFaceAccCount/m_dwFaceAccTime);
// °Å¸® ÀÚµ¿ Á¶Àý
if (-1 == m_iForceSightRange)
{
static float s_fAveRenderTime = 16.0f;
float fRatio=0.3f;
s_fAveRenderTime=(s_fAveRenderTime*(100.0f-fRatio)+std::max(16.0f, (float)m_dwCurRenderTime)*fRatio)/100.0f;
static float s_fAveRenderTime = 16.0f;
float fRatio=0.3f;
s_fAveRenderTime=(s_fAveRenderTime*(100.0f-fRatio)+std::max(16.0f, (float)m_dwCurRenderTime)*fRatio)/100.0f;
float fFar=25600.0f;
float fNear=MIN_FOG;
double dbAvePow=double(1000.0f/s_fAveRenderTime);
double dbMaxPow=60.0;
float fDistance=std::max((float)(fNear+(fFar-fNear)*(dbAvePow)/dbMaxPow), fNear);
m_pyBackground.SetViewDistanceSet(0, fDistance);
}
// °Å¸® °­Á¦ ¼³Á¤½Ã
else
{
m_pyBackground.SetViewDistanceSet(0, float(m_iForceSightRange));
}
float fFar=25600.0f;
float fNear=MIN_FOG;
double dbAvePow=double(1000.0f/s_fAveRenderTime);
double dbMaxPow=60.0;
float fDistance=std::max((float)(fNear+(fFar-fNear)*(dbAvePow)/dbMaxPow), fNear);
m_pyBackground.SetViewDistanceSet(0, fDistance);
}
// °Å¸® °­Á¦ ¼³Á¤½Ã
else
{
// 10000 Æú¸®°ï º¸´Ù ÀûÀ»¶§´Â °¡Àå ¸Ö¸® º¸ÀÌ°Ô ÇÑ´Ù
m_pyBackground.SetViewDistanceSet(0, 25600.0f);
m_pyBackground.SetViewDistanceSet(0, float(m_iForceSightRange));
}
}
else
{
// 10000 Æú¸®°ï º¸´Ù ÀûÀ»¶§´Â °¡Àå ¸Ö¸® º¸ÀÌ°Ô ÇÑ´Ù
m_pyBackground.SetViewDistanceSet(0, 25600.0f);
}
++s_dwRenderFrameCount;
if (bSampleRenderTelemetry)
{
++m_dwRenderTelemetryRenderCount;
m_fRenderTelemetryRenderTimeSumMS += static_cast<double>(m_dwCurRenderTime);
m_fRenderTelemetryInterpolationSum += static_cast<double>(m_fRenderInterpolationFactor);
if (m_dwRenderTelemetryLastPresentTime)
{
m_fRenderTelemetryPresentGapSumMS += static_cast<double>(dwRenderEndTime - m_dwRenderTelemetryLastPresentTime);
++m_dwRenderTelemetryPresentGapSamples;
}
++s_dwRenderFrameCount;
m_dwRenderTelemetryLastPresentTime = dwRenderEndTime;
}
}
}
int rest = s_uiNextFrameTime - ELTimer_GetMSec();
if (bSampleRenderTelemetry && !didRender)
++m_dwRenderTelemetryBlockedRenderCount;
if (rest > 0 && !bCurrentLateUpdate )
if (m_iFPS > 0)
{
s_uiLoad -= rest; // ½® ½Ã°£Àº ·Îµå¿¡¼­ »«´Ù..
Sleep(rest);
}
const double fRenderFrameMS = 1000.0 / static_cast<double>(m_iFPS);
s_fNextRenderTime += fRenderFrameMS;
++s_dwUpdateFrameCount;
const double fSleepMS = s_fNextRenderTime - static_cast<double>(ELTimer_GetMSec());
if (fSleepMS > 0.999)
{
const UINT uiSleepMS = static_cast<UINT>(fSleepMS);
s_uiLoad -= std::min(s_uiLoad, uiSleepMS);
const DWORD dwSleepStart = ELTimer_GetMSec();
Sleep(static_cast<DWORD>(fSleepMS));
if (bSampleRenderTelemetry)
m_fRenderTelemetrySleepTimeSumMS += static_cast<double>(ELTimer_GetMSec() - dwSleepStart);
}
}
else
{
s_fNextRenderTime = static_cast<double>(ELTimer_GetMSec());
}
s_uiLoad += ELTimer_GetMSec() - dwStart;
//m_Profiler.ProfileByScreen();
const DWORD dwTelemetryNow = ELTimer_GetMSec();
if (bSampleRenderTelemetry && dwTelemetryNow - m_dwRenderTelemetryWindowStartMS >= m_dwRenderTelemetryIntervalMS)
FlushRenderTelemetryWindow(dwTelemetryNow);
//m_Profiler.ProfileByScreen();
return true;
}
void CPythonApplication::ApplyRenderInterpolation()
{
const float fInterpolation = ClampInterpolationFactor(m_fRenderInterpolationFactor);
m_kChrMgr.ApplyRenderInterpolation(fInterpolation);
if (CAMERA_MODE_NORMAL != m_iCameraMode)
return;
if (0.0f != m_kCmrPos.m_fViewDir || 0.0f != m_kCmrPos.m_fCrossDir || 0.0f != m_kCmrPos.m_fUpDir)
return;
CCamera* pCurrentCamera = CCameraManager::Instance().GetCurrentCamera();
if (!pCurrentCamera)
return;
const D3DXVECTOR3 v3CenterPosition = LerpVector3(m_v3LastCenterPosition, m_v3CenterPosition, fInterpolation);
const float fDistance = pCurrentCamera->GetDistance();
const float fPitch = pCurrentCamera->GetPitch();
const float fRotation = pCurrentCamera->GetRoll();
m_pyGraphic.SetPositionCamera(
v3CenterPosition.x,
v3CenterPosition.y,
v3CenterPosition.z + pCurrentCamera->GetTargetHeight(),
fDistance,
fPitch,
fRotation);
}
void CPythonApplication::UpdateClientRect()
{
RECT rcApp;
@@ -1023,7 +1309,39 @@ float CPythonApplication::GetGlobalElapsedTime()
void CPythonApplication::SetFPS(int iFPS)
{
m_iFPS = iFPS;
m_iFPS = std::max(0, iFPS);
char szTargetFPS[16];
FormatRenderTargetFPSLabel(m_iFPS, szTargetFPS, sizeof(szTargetFPS));
m_stRenderTelemetrySummary = "Render telemetry\nTarget FPS: ";
m_stRenderTelemetrySummary += szTargetFPS;
m_stRenderTelemetrySummary += "\nCollecting frame pacing...";
if (IsRenderTelemetrySamplingEnabled())
ResetRenderTelemetryWindow(ELTimer_GetMSec());
if (m_bRenderTelemetryEnabled)
{
AppendRenderTelemetryTrace(
"set_fps elapsed_ms=%lu target_fps=%u",
static_cast<unsigned long>(ELTimer_GetMSec() - m_dwStartLocalTime),
m_iFPS);
}
}
void CPythonApplication::SetPerformanceHUDVisible(bool isVisible)
{
m_bRenderTelemetryHudVisible = isVisible;
if (IsRenderTelemetrySamplingEnabled())
ResetRenderTelemetryWindow(ELTimer_GetMSec());
else
m_dwRenderTelemetryWindowStartMS = 0;
if (m_bRenderTelemetryEnabled)
{
AppendRenderTelemetryTrace(
"set_hud elapsed_ms=%lu visible=%u",
static_cast<unsigned long>(ELTimer_GetMSec() - m_dwStartLocalTime),
m_bRenderTelemetryHudVisible ? 1u : 0u);
}
}
int CPythonApplication::GetWidth()
@@ -1075,6 +1393,7 @@ void CPythonApplication::Destroy()
// SphereMap
CGrannyMaterial::DestroySphereMap();
m_kRenderTelemetryTextLine.Destroy();
m_kWndMgr.Destroy();
CPythonSystem::Instance().SaveConfig();

View File

@@ -4,6 +4,7 @@
#include "eterLib/Input.h"
#include "eterLib/Profiler.h"
#include "eterLib/GrpDevice.h"
#include "EterLib/GrpTextInstance.h"
#include "eterLib/NetDevice.h"
#include "eterLib/GrpLightManager.h"
#include "eterLib/GameThreadPool.h"
@@ -42,7 +43,13 @@
#include "AbstractApplication.h"
#include "MovieMan.h"
#include <qedit.h>
struct IGraphBuilder;
struct IBaseFilter;
struct ISampleGrabber;
struct IMediaControl;
struct IMediaEventEx;
struct IVideoWindow;
struct IBasicVideo;
class CPythonApplication : public CMSApplication, public CInputKeyboard, public IAbstractApplication
{
@@ -206,6 +213,7 @@ class CPythonApplication : public CMSApplication, public CInputKeyboard, public
float GetPitch();
void SetFPS(int iFPS);
void SetPerformanceHUDVisible(bool isVisible);
void SetServerTime(time_t tTime);
time_t GetServerTime();
time_t GetServerTimeStamp();
@@ -303,6 +311,12 @@ class CPythonApplication : public CMSApplication, public CInputKeyboard, public
BOOL __IsContinuousChangeTypeCursor(int iCursorNum);
void __UpdateCamera();
void ApplyRenderInterpolation();
bool IsRenderTelemetrySamplingEnabled() const;
void InitializeRenderRuntimeOverrides();
void ResetRenderTelemetryWindow(DWORD dwNow);
void FlushRenderTelemetryWindow(DWORD dwNow);
void RenderPerformanceHUD();
void __SetFullScreenWindow(HWND hWnd, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP);
void __MinimizeFullScreenWindow(HWND hWnd, DWORD dwWidth, DWORD dwHeight);
@@ -357,9 +371,28 @@ class CPythonApplication : public CMSApplication, public CInputKeyboard, public
PyObject * m_poMouseHandler;
D3DXVECTOR3 m_v3CenterPosition;
D3DXVECTOR3 m_v3LastCenterPosition;
CGraphicTextInstance m_kRenderTelemetryTextLine;
std::string m_stRenderTelemetrySummary;
unsigned int m_iFPS;
float m_fRenderInterpolationFactor;
float m_fAveRenderTime;
bool m_bRenderTelemetryEnabled;
bool m_bRenderTelemetryHudVisible;
DWORD m_dwRenderTelemetryIntervalMS;
DWORD m_dwRenderTelemetryWindowStartMS;
DWORD m_dwRenderTelemetryLoopCount;
DWORD m_dwRenderTelemetryUpdateCount;
DWORD m_dwRenderTelemetryRenderCount;
DWORD m_dwRenderTelemetryBlockedRenderCount;
DWORD m_dwRenderTelemetryLastPresentTime;
DWORD m_dwRenderTelemetryPresentGapSamples;
double m_fRenderTelemetryUpdateTimeSumMS;
double m_fRenderTelemetryRenderTimeSumMS;
double m_fRenderTelemetrySleepTimeSumMS;
double m_fRenderTelemetryInterpolationSum;
double m_fRenderTelemetryPresentGapSumMS;
DWORD m_dwCurRenderTime;
DWORD m_dwCurUpdateTime;
DWORD m_dwLoad;

View File

@@ -358,6 +358,34 @@ struct FCharacterManagerCharacterInstanceDeform
//pInstance->Update();
}
};
struct FCharacterManagerCharacterInstanceApplyRenderInterpolation
{
explicit FCharacterManagerCharacterInstanceApplyRenderInterpolation(float fInterpolation)
: m_fInterpolation(fInterpolation)
{
}
inline void operator () (const std::pair<DWORD, CInstanceBase*>& cr_Pair)
{
cr_Pair.second->ApplyRenderInterpolation(m_fInterpolation);
}
float m_fInterpolation;
};
struct FCharacterManagerCharacterInstanceListApplyRenderInterpolation
{
explicit FCharacterManagerCharacterInstanceListApplyRenderInterpolation(float fInterpolation)
: m_fInterpolation(fInterpolation)
{
}
inline void operator () (CInstanceBase* pInstance)
{
pInstance->ApplyRenderInterpolation(m_fInterpolation);
}
float m_fInterpolation;
};
struct FCharacterManagerCharacterInstanceListDeform
{
inline void operator () (CInstanceBase * pInstance)
@@ -366,6 +394,12 @@ struct FCharacterManagerCharacterInstanceListDeform
}
};
void CPythonCharacterManager::ApplyRenderInterpolation(float fInterpolation)
{
std::for_each(m_kAliveInstMap.begin(), m_kAliveInstMap.end(), FCharacterManagerCharacterInstanceApplyRenderInterpolation(fInterpolation));
std::for_each(m_kDeadInstList.begin(), m_kDeadInstList.end(), FCharacterManagerCharacterInstanceListApplyRenderInterpolation(fInterpolation));
}
void CPythonCharacterManager::Deform()
{
std::for_each(m_kAliveInstMap.begin(), m_kAliveInstMap.end(), FCharacterManagerCharacterInstanceDeform());

View File

@@ -57,6 +57,7 @@ class CPythonCharacterManager : public CSingleton<CPythonCharacterManager>, publ
void DestroyDeviceObjects();
void Update();
void ApplyRenderInterpolation(float fInterpolation);
void Deform();
void Render();
void RenderShadowMainInstance();

View File

@@ -318,6 +318,8 @@ void CPythonSystem::SetDefaultConfig()
m_Config.bAlwaysShowName = DEFAULT_VALUE_ALWAYS_SHOW_NAME;
m_Config.bShowDamage = true;
m_Config.bShowSalesText = true;
m_Config.iRenderFPS = 60;
m_Config.bShowPerformanceHUD = false;
}
bool CPythonSystem::IsWindowed()
@@ -365,6 +367,26 @@ void CPythonSystem::SetShowSalesTextFlag(int iFlag)
m_Config.bShowSalesText = iFlag == 1 ? true : false;
}
int CPythonSystem::GetRenderFPS()
{
return m_Config.iRenderFPS;
}
void CPythonSystem::SetRenderFPS(int iFPS)
{
m_Config.iRenderFPS = std::max(0, std::min(iFPS, 500));
}
bool CPythonSystem::IsShowPerformanceHUD()
{
return m_Config.bShowPerformanceHUD;
}
void CPythonSystem::SetShowPerformanceHUDFlag(int iFlag)
{
m_Config.bShowPerformanceHUD = iFlag == 1 ? true : false;
}
bool CPythonSystem::IsAutoTiling()
{
if (m_Config.bSoftwareTiling == 0)
@@ -462,6 +484,10 @@ bool CPythonSystem::LoadConfig()
m_Config.bShowDamage = atoi(value) == 1 ? true : false;
else if (!stricmp(command, "SHOW_SALESTEXT"))
m_Config.bShowSalesText = atoi(value) == 1 ? true : false;
else if (!stricmp(command, "RENDER_FPS"))
m_Config.iRenderFPS = std::max(0, std::min(atoi(value), 500));
else if (!stricmp(command, "SHOW_PERFORMANCE_HUD"))
m_Config.bShowPerformanceHUD = atoi(value) == 1 ? true : false;
}
if (m_Config.bWindowed)
@@ -552,6 +578,8 @@ bool CPythonSystem::SaveConfig()
fprintf(fp, "USE_DEFAULT_IME %d\n", m_Config.bUseDefaultIME);
fprintf(fp, "SOFTWARE_TILING %d\n", m_Config.bSoftwareTiling);
fprintf(fp, "SHADOW_LEVEL %d\n", m_Config.iShadowLevel);
fprintf(fp, "RENDER_FPS %d\n", m_Config.iRenderFPS);
fprintf(fp, "SHOW_PERFORMANCE_HUD %d\n", m_Config.bShowPerformanceHUD);
// MR-14: Fog update by Alaric
fprintf(fp, "FOG_LEVEL %d\n", m_Config.iFogLevel);
// MR-14: -- END OF -- Fog update by Alaric
@@ -607,6 +635,9 @@ const CPythonSystem::TWindowStatus & CPythonSystem::GetWindowStatusReference(int
void CPythonSystem::ApplyConfig() // 이전 설정과 현재 설정을 비교해서 바뀐 설정을 적용 한다.
{
const bool bRenderFPSChanged = m_OldConfig.iRenderFPS != m_Config.iRenderFPS;
const bool bPerformanceHUDChanged = m_OldConfig.bShowPerformanceHUD != m_Config.bShowPerformanceHUD;
if (m_OldConfig.gamma != m_Config.gamma)
{
float val = 1.0f;
@@ -631,6 +662,12 @@ void CPythonSystem::ApplyConfig() // 이전 설정과 현재 설정을 비교해
CPythonApplication::Instance().SetCursorMode(CPythonApplication::CURSOR_MODE_HARDWARE);
}
if (bRenderFPSChanged)
CPythonApplication::Instance().SetFPS(m_Config.iRenderFPS);
if (bPerformanceHUDChanged)
CPythonApplication::Instance().SetPerformanceHUDVisible(m_Config.bShowPerformanceHUD);
m_OldConfig = m_Config;
ChangeSystem();

View File

@@ -78,6 +78,8 @@ class CPythonSystem : public CSingleton<CPythonSystem>
bool bAlwaysShowName;
bool bShowDamage;
bool bShowSalesText;
int iRenderFPS;
bool bShowPerformanceHUD;
} TConfig;
public:
@@ -157,6 +159,11 @@ class CPythonSystem : public CSingleton<CPythonSystem>
void SetFogLevel(unsigned int level);
// MR-14: -- END OF -- Fog update by Alaric
int GetRenderFPS();
void SetRenderFPS(int iFPS);
bool IsShowPerformanceHUD();
void SetShowPerformanceHUDFlag(int iFlag);
protected:
TResolution m_ResolutionList[RESOLUTION_MAX_NUM];
int m_ResolutionCount;
@@ -167,4 +174,4 @@ class CPythonSystem : public CSingleton<CPythonSystem>
bool m_isInterfaceConfig;
PyObject * m_poInterfaceHandler;
TWindowStatus m_WindowStatus[WINDOW_MAX_NUM];
};
};

View File

@@ -226,6 +226,36 @@ PyObject * systemIsShowSalesText(PyObject * poSelf, PyObject * poArgs)
return Py_BuildValue("i", CPythonSystem::Instance().IsShowSalesText());
}
PyObject * systemGetRenderFPS(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonSystem::Instance().GetRenderFPS());
}
PyObject * systemSetRenderFPS(PyObject * poSelf, PyObject * poArgs)
{
int iFPS;
if (!PyTuple_GetInteger(poArgs, 0, &iFPS))
return Py_BuildException();
CPythonSystem::Instance().SetRenderFPS(iFPS);
return Py_BuildNone();
}
PyObject * systemIsShowPerformanceHUD(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonSystem::Instance().IsShowPerformanceHUD());
}
PyObject * systemSetShowPerformanceHUDFlag(PyObject * poSelf, PyObject * poArgs)
{
int iFlag;
if (!PyTuple_GetInteger(poArgs, 0, &iFlag))
return Py_BuildException();
CPythonSystem::Instance().SetShowPerformanceHUDFlag(iFlag);
return Py_BuildNone();
}
PyObject * systemSetConfig(PyObject * poSelf, PyObject * poArgs)
{
int res_index;
@@ -445,6 +475,11 @@ void initsystem()
{ "SetShowSalesTextFlag", systemSetShowSalesTextFlag, METH_VARARGS },
{ "IsShowSalesText", systemIsShowSalesText, METH_VARARGS },
{ "GetRenderFPS", systemGetRenderFPS, METH_VARARGS },
{ "SetRenderFPS", systemSetRenderFPS, METH_VARARGS },
{ "IsShowPerformanceHUD", systemIsShowPerformanceHUD, METH_VARARGS },
{ "SetShowPerformanceHUDFlag", systemSetShowPerformanceHUDFlag, METH_VARARGS },
{ "GetShadowLevel", systemGetShadowLevel, METH_VARARGS },
{ "SetShadowLevel", systemSetShadowLevel, METH_VARARGS },