5 // PNG
\82Æ
\82©
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
\97p
7 #pragma comment(lib, "gdiplus.lib")
11 #pragma comment(lib, "shlwapi.lib")
14 #pragma comment(lib, "comctl32.lib")
16 #pragma comment(lib, "Comdlg32.lib")
19 #include "GVONavish.h"
20 #include "GVOConfig.h"
21 #include "GVOGameProcess.h"
22 #include "GVOWorldMap.h"
24 #include "GVOSpeedMeter.h"
29 //
\83f
\83o
\83b
\83O
\8e\9e\82Ì
\95`
\89æ
\83p
\83t
\83H
\81[
\83}
\83\93\83X
\91ª
\92è
\97p
\81B
30 //#define GVO_PERF_CHECK
34 //
\83O
\83\8d\81[
\83o
\83\8b\95Ï
\90\94:
35 HINSTANCE g_hinst; //
\8c»
\8dÝ
\82Ì
\83C
\83\93\83^
\81[
\83t
\83F
\83C
\83X
40 //
\8aÖ
\90\94\83v
\83\8d\83g
\83^
\83C
\83v
\90é
\8c¾
41 static ATOM MyRegisterClass( HINSTANCE hInstance );
42 static BOOL InitInstance( HINSTANCE, int );
43 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
44 static LRESULT s_mainLoop();
47 //
\83\81\83b
\83Z
\81[
\83W
\83n
\83\93\83h
\83\89
48 static bool s_onCreate( HWND, LPCREATESTRUCT );
49 static void s_onMove( HWND, WORD, WORD );
50 static void s_onSize( HWND, UINT, WORD, WORD );
51 static void s_onMouseWheel( HWND, int16_t, UINT, int16_t, int16_t );
52 static void s_onMouseMove( HWND, UINT, int16_t, int16_t );
53 static void s_onMouseLeftButtonDown( HWND, UINT, int16_t, int16_t );
54 static void s_onMouseLeftButtonUp( HWND, UINT, int16_t, int16_t );
55 static void s_onMouseLeftButtonDoubleClick( HWND, UINT, int16_t, int16_t );
56 static void s_onMouseRightButtonUp( HWND, UINT, int16_t, int16_t );
57 static void s_onPaint( HWND );
60 //
\83A
\83v
\83\8a\8f\88\97\9d
61 static std::wstring s_makeVersionString();
62 static std::wstring s_getMapFileName();
63 static void s_updateFrame(HWND hwnd, HDC hdc);
64 static void s_updateWindowTitle( HWND );
65 static void s_toggleKeepForeground( HWND );
66 static void s_popupMenu( HWND, int16_t, int16_t );
67 static void s_popupCoord( HWND, int16_t, int16_t );
70 //
\83\8d\81[
\83J
\83\8b\95Ï
\90\94
71 static LPCWSTR const k_appName = L"GVONavi
\81i
\82Á
\82Û
\82¢
\89½
\82©
\81j"; //
\83A
\83v
\83\8a\83P
\81[
\83V
\83\87\83\93\96¼
72 static LPCWSTR const k_version = L"ver 1.0.1"; //
\83o
\81[
\83W
\83\87\83\93\94Ô
\8d\86
73 static LPCWSTR const k_copyright = L"copyright(c) mandheling"; //
\92\98\8dì
\8c \95\
\8e¦
\81i
\82¢
\82¿
\82¨
\81[
\81j
75 static LPCWSTR const k_windowClassName = L"GVONavish"; //
\83\81\83C
\83\93 \83E
\83B
\83\93\83h
\83E
\83N
\83\89\83X
\96¼
76 static const LPCWSTR k_configFileName = L"GVONavish.ini"; //
\90Ý
\92è
\83t
\83@
\83C
\83\8b\96¼
77 static LPCWSTR const k_appMutexName = L"Global\\{7554E265-3247-4FCA-BC60-5AA814658351}";
78 static HANDLE s_appMutex;
80 static const std::wstring k_aboutText = s_makeVersionString(); //
\83o
\81[
\83W
\83\87\83\93\8fî
\95ñ
\83e
\83L
\83X
\83g
82 static GVOImage s_backbuffer; //!<@brief
\95`
\89æ
\97p24bit
\83C
\83\81\81[
\83W
\83o
\83b
\83t
\83@
83 static HANDLE s_pollingTimerEvent = ::CreateEvent( NULL, TRUE, TRUE, NULL );
84 static UINT s_pollingTimerID = 0;
86 static Gdiplus::GdiplusStartupInput s_gdisi;
87 static ULONG_PTR s_gdiToken;
89 static GVOConfig s_config( k_configFileName );
90 static GVOGameProcess s_gvoGameProcess;
91 static GVOWorldMap s_worldMap;
92 static GVOShip s_ship;
93 static GVOSpeedMeter s_speedMeter;
95 static UINT s_pollingInterval = 1000; //
\8fó
\91Ô
\8aÄ
\8e\8b\8aÔ
\8au
\81i1
\95b
\81j
96 static bool s_isUpdated = false; //
\8fó
\91Ô
\8dX
\90V
\83t
\83\89\83O
97 static bool s_isDragging = false; //
\83h
\83\89\83b
\83O
\8fó
\91Ô
\83t
\83\89\83O
98 static SIZE s_clientSize; //
\83N
\83\89\83C
\83A
\83\93\83g
\97Ì
\88æ
\82Ì
\91å
\82«
\82³
99 static POINT s_dragOrg; //
\83h
\83\89\83b
\83O
\8c´
\93_
\81i
\88Ú
\93®
\97Ê
\8eZ
\8fo
\97p
\81j
103 //
\83f
\83o
\83b
\83O
\97p
\8e©
\93®
\8dq
\8ds
\95Ï
\90\94
104 static double s_xDebugAutoCruise;
105 static double s_yDebugAutoCruise;
106 static double s_debugAutoCruiseAngle = 0;
112 int APIENTRY _tWinMain( _In_ HINSTANCE hInstance,
113 _In_opt_ HINSTANCE hPrevInstance,
114 _In_ LPTSTR lpCmdLine,
117 UNREFERENCED_PARAMETER( hPrevInstance );
118 UNREFERENCED_PARAMETER( lpCmdLine );
120 ::SetLastError( NOERROR );
121 s_appMutex = ::CreateMutex( NULL, TRUE, k_appMutexName );
122 if ( ::GetLastError() == ERROR_ALREADY_EXISTS ) {
123 HWND hwnd = ::FindWindow( k_windowClassName, NULL );
125 ::SetForegroundWindow( hwnd );
130 ::CoInitialize( NULL );
132 ::timeGetDevCaps( &tc, sizeof(tc) );
133 ::timeBeginPeriod( tc.wPeriodMin );
134 INITCOMMONCONTROLSEX icc = { sizeof(icc), ICC_WIN95_CLASSES };
135 ::InitCommonControlsEx( &icc );
136 GdiplusStartup( &s_gdiToken, &s_gdisi, NULL );
139 MyRegisterClass( hInstance );
141 //
\83A
\83v
\83\8a\83P
\81[
\83V
\83\87\83\93\82Ì
\8f\89\8aú
\89»
\82ð
\8eÀ
\8ds
\82µ
\82Ü
\82·:
142 if ( !InitInstance( hInstance, nCmdShow ) ) {
146 s_pollingTimerID = ::timeSetEvent( s_config.m_pollingInterval, tc.wPeriodMin, LPTIMECALLBACK( s_pollingTimerEvent ), 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET );
148 //
\83\81\83C
\83\93 \83\81\83b
\83Z
\81[
\83W
\83\8b\81[
\83v:
149 const LRESULT retVal = s_mainLoop();
151 ::timeKillEvent( s_pollingTimerID );
154 Gdiplus::GdiplusShutdown( s_gdiToken );
155 ::timeEndPeriod( tc.wPeriodMin );
160 static ATOM MyRegisterClass( HINSTANCE hInstance )
162 WNDCLASSEX wcex = { sizeof(wcex) };
164 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
165 wcex.lpfnWndProc = WndProc;
166 wcex.hInstance = hInstance;
167 wcex.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE( IDR_MAINFRAME ) );
168 wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
169 wcex.hbrBackground = (HBRUSH)::GetStockObject( BLACK_BRUSH );
170 //wcex.lpszMenuName = MAKEINTRESOURCE(IDC_GVONAVISH);
171 wcex.lpszClassName = k_windowClassName;
172 wcex.hIconSm = LoadIcon( wcex.hInstance, MAKEINTRESOURCE( IDI_SMALL ) );
174 return RegisterClassEx( &wcex );
177 static BOOL InitInstance( HINSTANCE hInstance, int nCmdShow )
179 if ( !s_worldMap.loadFromFile( s_config ) ) {
180 //
\8e¸
\94s
\82·
\82ê
\82Î
\95Û
\91¶
\82³
\82ê
\82È
\82¢
\82Ì
\82Å
\91å
\8fä
\95v
\81B
181 s_config.m_mapFileName = s_getMapFileName();
182 if ( !s_worldMap.loadFromFile( s_config ) ) {
184 L"
\83}
\83b
\83v
\89æ
\91\9c\82ð
\8aJ
\82¯
\82Ü
\82¹
\82ñ
\82Å
\82µ
\82½
\81B",
186 MB_ICONERROR | MB_SETFOREGROUND | MB_OK );
193 g_hinst = hInstance; //
\83O
\83\8d\81[
\83o
\83\8b\95Ï
\90\94\82É
\83C
\83\93\83X
\83^
\83\93\83X
\8f\88\97\9d\82ð
\8ai
\94[
\82µ
\82Ü
\82·
\81B
196 if ( s_config.m_keepForeground ) {
197 exStyle |= WS_EX_TOPMOST;
199 hwnd = CreateWindowEx( exStyle, k_windowClassName, k_appName, WS_OVERLAPPEDWINDOW,
200 s_config.m_windowPos.x, s_config.m_windowPos.y,
201 s_config.m_windowSize.cx, s_config.m_windowSize.cy,
202 NULL, NULL, hInstance, NULL );
208 s_pollingInterval = s_config.m_pollingInterval;
209 s_gvoGameProcess.setConfig( s_config );
210 s_worldMap.setConfig( s_config );
211 s_ship.setInitialSurveyCoord( s_config.m_initialSurveyCoord );
213 s_xDebugAutoCruise = s_config.m_initialSurveyCoord.x;
214 s_yDebugAutoCruise = s_config.m_initialSurveyCoord.y;
217 if ( s_gvoGameProcess.updateState() ) {
218 s_ship.updateWithSurveyCoord( s_gvoGameProcess.surveyCoord(), s_gvoGameProcess.timeStamp() );
219 s_worldMap.setShipPosition( s_gvoGameProcess.surveyCoord(), s_config.m_traceShipPositionEnabled );
221 s_updateWindowTitle( hwnd );
223 ShowWindow( hwnd, nCmdShow );
224 UpdateWindow( hwnd );
226 g_hdcMain = ::GetDC( g_hwndMain );
231 static LRESULT s_mainLoop()
236 hAccelTable = LoadAccelerators( g_hinst, MAKEINTRESOURCE( IDC_GVONAVISH ) );
239 if ( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
240 if ( msg.message == WM_QUIT ) {
243 if ( !TranslateAccelerator( msg.hwnd, hAccelTable, &msg ) ) {
244 TranslateMessage( &msg );
245 DispatchMessage( &msg );
249 std::vector<HANDLE> handles;
251 //
\8aÄ
\8e\8b\82·
\82é
\83n
\83\93\83h
\83\8b\82ð
\92Ç
\89Á
\82·
\82é
\81B
252 if ( s_gvoGameProcess.processHandle() ) {
253 handles.push_back( s_gvoGameProcess.processHandle() );
255 handles.push_back( s_pollingTimerEvent );
257 if ( handles.empty() ) {
262 DWORD const waitResult = ::MsgWaitForMultipleObjects( handles.size(), &handles[0], FALSE, INFINITE, QS_ALLINPUT );
263 if ( handles.size() <= waitResult ) {
267 //
\8aÄ
\8e\8b\82·
\82é
\83n
\83\93\83h
\83\8b\82É
\91Î
\89\9e\82·
\82é
\81B
268 HANDLE const activeHandle = handles[waitResult];
270 if ( activeHandle == s_gvoGameProcess.processHandle() ) {
271 //
\83Q
\81[
\83\80\83v
\83\8d\83Z
\83X
\82ª
\8fI
\97¹
\82µ
\82½
\81B
272 s_gvoGameProcess.clear();
275 if ( activeHandle == s_pollingTimerEvent ) {
276 ::ResetEvent( s_pollingTimerEvent );
277 s_updateFrame( g_hwndMain, g_hdcMain );
281 return (int)msg.wParam;
285 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp )
297 s_onMove( hwnd, int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
300 s_onSize( hwnd, wp, LOWORD( lp ), HIWORD( lp ) );
305 wmEvent = HIWORD( wp );
306 //
\91I
\91ð
\82³
\82ê
\82½
\83\81\83j
\83\85\81[
\82Ì
\89ð
\90Í:
312 MB_OK | MB_ICONINFORMATION );
315 DestroyWindow( hwnd );
317 case IDM_TOGGLE_TRACE_SHIP:
318 s_config.m_traceShipPositionEnabled = !s_config.m_traceShipPositionEnabled;
320 case IDM_ERASE_SHIP_ROUTE:
321 s_worldMap.clearShipRoute();
323 case IDM_TOGGLE_KEEP_FOREGROUND:
324 s_toggleKeepForeground( hwnd );
326 case IDM_TOGGLE_SPEED_METER:
327 s_config.m_speedMeterEnabled = !s_config.m_speedMeterEnabled;
328 ::InvalidateRect( hwnd, NULL, FALSE );
330 case IDM_TOGGLE_VECTOR_LINE:
331 s_config.m_shipVectorLineEnabled = !s_config.m_shipVectorLineEnabled;
332 s_worldMap.setVisibleShipRoute( s_config.m_shipVectorLineEnabled );
335 return DefWindowProc( hwnd, message, wp, lp );
342 s_toggleKeepForeground( hwnd );
345 if ( s_worldMap.zoomIn() ) {
346 s_updateWindowTitle( hwnd );
347 ::InvalidateRect( hwnd, NULL, FALSE );
351 if ( s_worldMap.zoomOut() ) {
352 s_updateWindowTitle( hwnd );
353 ::InvalidateRect( hwnd, NULL, FALSE );
362 s_onMouseWheel( hwnd, HIWORD( wp ), LOWORD( wp ), int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
365 s_onMouseMove( hwnd, wp, int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
368 s_onMouseLeftButtonDown( hwnd, wp, int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
371 s_onMouseLeftButtonUp( hwnd, wp, int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
374 s_onMouseRightButtonUp( hwnd, wp, int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
376 case WM_LBUTTONDBLCLK:
377 s_onMouseLeftButtonDoubleClick( hwnd, wp, int16_t( LOWORD( lp ) ), int16_t( HIWORD( lp ) ) );
381 if ( !s_onCreate( hwnd, reinterpret_cast<LPCREATESTRUCT>(lp) ) ) {
386 PostQuitMessage( 0 );
389 return DefWindowProc( hwnd, message, wp, lp );
395 static bool s_onCreate( HWND hwnd, LPCREATESTRUCT /*cs*/ )
401 static void s_onMove( HWND hwnd, WORD /*cx*/, WORD /*cy*/ )
403 const DWORD style = ::GetWindowLong( hwnd, GWL_STYLE );
404 if ( style & WS_MAXIMIZE ) {
408 ::GetWindowRect( hwnd, &rc );
409 s_config.m_windowPos.x = rc.left;
410 s_config.m_windowPos.y = rc.top;
414 static void s_onSize( HWND hwnd, UINT state, WORD cx, WORD cy )
420 ::GetWindowRect( hwnd, &rc );
421 s_config.m_windowSize.cx = rc.right - rc.left;
422 s_config.m_windowSize.cy = rc.bottom - rc.top;
430 if ( s_clientSize.cx != cx || s_clientSize.cy != cy ) {
431 s_clientSize.cx = cx;
432 s_clientSize.cy = cy;
433 if ( !s_backbuffer.isCompatible( s_clientSize ) ) {
434 s_backbuffer.createDIBImage( s_clientSize );
436 s_worldMap.setViewSize( s_clientSize );
441 static void s_onMouseWheel( HWND hwnd, int16_t delta, UINT vkey, int16_t x, int16_t y )
443 bool isChanged = false;
446 isChanged = s_worldMap.zoomIn();
449 isChanged = s_worldMap.zoomOut();
453 s_updateWindowTitle( hwnd );
454 ::InvalidateRect( hwnd, NULL, FALSE );
459 static void s_onMouseMove( HWND hwnd, UINT vkey, int16_t x, int16_t y )
461 if ( s_isDragging ) {
462 const int dx = x - s_dragOrg.x;
463 const int dy = y - s_dragOrg.y;
464 const int threshold = 1; //
\8a´
\93x
\82ª
\97Ç
\82·
\82¬
\82é
\82Æ
\92Ç
\8f]
\82ª
\8aÈ
\92P
\82É
\90Ø
\82ê
\82Ä
\82µ
\82Ü
\82¤
\82Ì
\82Å
\93K
\93\96\82É
\91Î
\8dô
465 if ( s_config.m_traceShipPositionEnabled ) {
466 if ( ::abs( dx ) <= threshold && ::abs( dy ) < threshold ) {
470 const POINT offset = { -dx, -dy };
472 s_worldMap.offsetFocusInViewCoord( offset );
473 ::InvalidateRect( hwnd, NULL, FALSE );
477 s_config.m_traceShipPositionEnabled = false;
485 static void s_onMouseLeftButtonDown( HWND hwnd, UINT vkey, int16_t x, int16_t y )
487 if ( s_isDragging ) {
491 ::SetCapture( hwnd );
499 static void s_onMouseLeftButtonUp( HWND hwnd, UINT vkey, int16_t x, int16_t y )
501 if ( s_isDragging ) {
503 s_isDragging = false;
513 static void s_onMouseLeftButtonDoubleClick( HWND hwnd, UINT vkey, int16_t x, int16_t y )
515 if ( s_isDragging ) {
519 s_popupCoord( hwnd, x, y );
524 static void s_onMouseRightButtonUp( HWND hwnd, UINT vkey, int16_t x, int16_t y )
526 if ( s_isDragging ) {
530 s_popupMenu( hwnd, x, y );
535 //
\83_
\83u
\83\8b\83o
\83b
\83t
\83@
\83\8a\83\93\83O
\82Å
\82¿
\82ç
\82Â
\82«
\96h
\8e~
\81B
536 static void s_onPaint( HWND hwnd )
538 #ifdef GVO_PERF_CHECK
539 int64_t perfBegin = 0, perfEnd = 0;
540 ::QueryPerformanceCounter((LARGE_INTEGER*)&perfBegin);
542 if ( !s_backbuffer.bitmapHandle() ) {
543 s_backbuffer.createDIBImage( s_clientSize );
547 HDC hdc = BeginPaint( hwnd, &ps );
548 HDC hdcBackbuffer = ::CreateCompatibleDC( hdc );
549 ::SaveDC( hdcBackbuffer );
550 ::SelectObject( hdcBackbuffer, s_backbuffer.bitmapHandle() );
551 RECT rc = { 0, 0, s_clientSize.cx, s_clientSize.cy };
552 ::FillRect( hdcBackbuffer, &rc, (HBRUSH)::GetStockObject( BLACK_BRUSH ) );
554 //
\95`
\89æ
\82ðhdcBackbuffer
\82É
\91Î
\82µ
\82Ä
\8ds
\82¤
\81B
555 s_worldMap.drawMap( hdcBackbuffer, s_ship );
557 //
\91¬
\93x
\8cv
\82ð
\95`
\89æ
558 if ( s_config.m_speedMeterEnabled ) {
559 const double velocity = s_speedMeter.velocityByKnot();
560 wchar_t buf[4096] = { 0 };
561 swprintf( buf, _countof( buf ), L"%.2f kt", velocity );
564 ::DrawText( hdcBackbuffer, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP | DT_CALCRECT );
565 const int width = rc.right - rc.left;
566 rc.left = s_clientSize.cx - width;
567 rc.right = rc.left + width;
568 ::DrawText( hdcBackbuffer, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP );
572 //
\91ª
\97Ê
\8dÀ
\95W
\82ð
\95`
\89æ
574 const GVOImage& surveyCoordImage = s_gvoGameProcess.surveyCoordImage();
575 HDC hdcSurvey = ::CreateCompatibleDC( hdcBackbuffer );
576 ::SaveDC( hdcSurvey );
577 ::SelectObject( hdcSurvey, surveyCoordImage.bitmapHandle() );
578 ::BitBlt( hdcBackbuffer, 0, 0, surveyCoordImage.size().cx, surveyCoordImage.size().cy,
579 hdcSurvey, 0, 0, SRCCOPY );
580 ::RestoreDC( hdcSurvey, -1 );
581 ::DeleteDC( hdcSurvey );
586 if ( s_config.m_debugAutoCruiseEnabled ) {
587 const double rad = ((s_debugAutoCruiseAngle)* M_PI) / 180;
588 const double vx = ::cos( rad );
589 const double vy = ::sin( rad );
590 const LONG length = max( s_clientSize.cx, s_clientSize.cy );
592 COLORREF rgb = (::fabs(s_ship.vector().angleTo(GVOVector(vx,vy))) <= FLT_EPSILON) ? RGB( 0, 255, 0 ) : RGB( 255, 255, 0 );
594 LONG x2 = s_clientSize.cx / 2 + LONG( vx * length );
595 LONG y2 = s_clientSize.cy / 2 + LONG( vy * length );
596 HPEN pen = ::CreatePen( PS_SOLID, 3, rgb );
597 HGDIOBJ old = ::SelectObject( hdcBackbuffer, pen );
598 ::MoveToEx( hdcBackbuffer, s_clientSize.cx / 2, s_clientSize.cy / 2, NULL );
599 ::LineTo( hdcBackbuffer, x2, y2 );
600 ::SelectObject( hdcBackbuffer, old );
601 ::DeleteObject( pen );
603 #endif // #ifndef NDEBUG
605 ::BitBlt( hdc, 0, 0, s_clientSize.cx, s_clientSize.cy,
606 hdcBackbuffer, 0, 0, SRCCOPY );
608 ::RestoreDC( hdcBackbuffer, -1 );
609 ::DeleteDC( hdcBackbuffer );
610 EndPaint( hwnd, &ps );
613 #ifdef GVO_PERF_CHECK
614 ::QueryPerformanceCounter((LARGE_INTEGER*)&perfEnd);
616 ::QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
617 const double deltaPerSec = (double(perfEnd - perfBegin) / double(freq)) * 1000.0;
618 typedef std::list<double> PerfList;
619 static PerfList perf;
620 perf.push_back(deltaPerSec);
622 const double ave = std::accumulate( perf.begin(), perf.end(), 0.0 ) / perf.size();
623 if ( 100 < perf.size() ) {
628 s = std::wstring( L"perf:" ) + std::to_wstring( ave ) + L"(ms)\n";
629 ::SetWindowText( hwnd, s.c_str() );
630 ::InvalidateRect( hwnd, NULL, FALSE );
635 static std::wstring s_makeVersionString()
638 s += std::wstring(k_appName) + L" " + k_version + L"\n";
644 //
\83}
\83b
\83v
\89æ
\91\9c\82ð
\91I
\91ð
\82³
\82¹
\82é
645 static std::wstring s_getMapFileName()
647 wchar_t dir[MAX_PATH] = { 0 };
648 ::GetModuleFileName( g_hinst, dir, _countof( dir ) );
649 ::PathRemoveFileSpec( dir );
651 wchar_t filePath[MAX_PATH] = { 0 };
652 OPENFILENAME ofn = { sizeof(ofn) };
653 ofn.lpstrTitle = L"
\83}
\83b
\83v
\89æ
\91\9c\83t
\83@
\83C
\83\8b\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81B";
654 ofn.lpstrInitialDir = &dir[0];
655 ofn.lpstrFilter = L"
\83C
\83\81\81[
\83W
\83t
\83@
\83C
\83\8b\0L" L"*.bmp;*.jpg;*.jpeg;*.png;*.gif;*.tif;*.tiff" L"\0"
656 L"
\91S
\82Ä
\82Ì
\83t
\83@
\83C
\83\8b\0" L"*.*" L"\0\0";
657 ofn.Flags = OFN_READONLY | OFN_FILEMUSTEXIST;
658 ofn.nMaxFile = _countof( filePath );
659 ofn.lpstrFile = &filePath[0];
660 if ( !::GetOpenFileName( &ofn ) ) {
667 static void s_updateFrame( HWND hwnd, HDC hdc )
670 if ( s_config.m_debugAutoCruiseEnabled ) {
671 static bool isRandInitialized = false;
672 if ( !isRandInitialized ) {
673 srand( ::timeGetTime() );
674 isRandInitialized = true;
677 const double rad = ((s_debugAutoCruiseAngle)* M_PI) / 180;
678 const double vx = ::cos( rad );
679 const double vy = ::sin( rad );
681 s_xDebugAutoCruise += vx * s_config.m_debugAutoCruiseVelocity;
682 s_yDebugAutoCruise += vy * s_config.m_debugAutoCruiseVelocity;
684 static DWORD tick = ::timeGetTime();
685 static DWORD count = 0;
686 if ( (tick + s_config.m_debugAutoCruiseTurnInterval) < ::timeGetTime() ) {
687 if ( 10 < (++count) ) {
689 s_debugAutoCruiseAngle += 90 + (LONG( rand() / double( RAND_MAX ) * 90 ) & ~0x1);
692 s_debugAutoCruiseAngle += (rand() & 1) ? s_config.m_debugAutoCruiseTurnAngle : -s_config.m_debugAutoCruiseTurnAngle;
694 tick = ::timeGetTime();
696 s_debugAutoCruiseAngle = fmod( ::fabs( s_debugAutoCruiseAngle ), 360 );
698 if ( s_xDebugAutoCruise < 0 ) {
699 s_xDebugAutoCruise += k_worldWidth;
701 if ( s_yDebugAutoCruise < 0 ) {
702 s_yDebugAutoCruise += k_worldHeight;
704 s_xDebugAutoCruise = fmod( s_xDebugAutoCruise, (double)k_worldWidth );
705 s_yDebugAutoCruise = fmod( s_yDebugAutoCruise, (double)k_worldHeight );
707 ////
\92n
\90}
\82ð
\8c×
\82®
\8f\88\97\9d\82Ì
\8am
\94F
\97p
\83f
\83o
\83b
\83O
\83R
\81[
\83h
708 //if ( 100 <= s_xDebugAutoCruise && s_xDebugAutoCruise <= (GVOWorldMap::k_worldWidth - 100) ) {
709 // s_xDebugAutoCruise = 0;
714 LONG( s_xDebugAutoCruise ),
715 LONG( s_yDebugAutoCruise )
717 uint32_t timeStamp = ::timeGetTime();
718 s_ship.updateWithSurveyCoord( p, timeStamp );
719 s_speedMeter.updateVelocity( s_ship.velocity(), timeStamp );
720 s_gvoGameProcess.setSurveyCoord( p );
721 s_worldMap.setShipPosition( p, s_config.m_traceShipPositionEnabled );
722 s_worldMap.updateShipRouteMap( hdc );
723 s_updateWindowTitle( hwnd );
724 ::InvalidateRect( hwnd, NULL, FALSE );
727 #endif // #ifndef NDEBUG
729 s_isUpdated = s_gvoGameProcess.updateState();
732 s_config.m_initialSurveyCoord = s_gvoGameProcess.surveyCoord();
733 s_ship.updateWithSurveyCoord( s_gvoGameProcess.surveyCoord(), s_gvoGameProcess.timeStamp() );
734 s_speedMeter.updateVelocity( s_ship.velocity(), s_gvoGameProcess.timeStamp() );
735 s_worldMap.setShipPosition( s_gvoGameProcess.surveyCoord(), s_config.m_traceShipPositionEnabled );
736 s_worldMap.updateShipRouteMap( hdc );
737 s_updateWindowTitle( hwnd );
738 ::InvalidateRect( hwnd, NULL, FALSE );
743 static void s_updateWindowTitle( HWND hwnd )
745 const POINT& surveyCoord = s_gvoGameProcess.surveyCoord();
747 std::vector<wchar_t> buf( 4096 );
748 ::swprintf( &buf[0], buf.size(), L"%d,%d - (%.1f%%) - %s %s",
749 surveyCoord.x, surveyCoord.y,
750 s_worldMap.viewScale() * s_worldMap.viewScaleOrder(),
753 ::SetWindowText( hwnd, &buf[0] );
757 static void s_toggleKeepForeground( HWND hwnd )
759 if ( ::GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) {
760 ::SetWindowPos( hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW );
761 s_config.m_keepForeground = false;
764 ::SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW );
765 s_config.m_keepForeground = true;
770 static void s_popupMenu( HWND hwnd, int16_t x, int16_t y )
772 HMENU hmenu = ::LoadMenu( g_hinst, MAKEINTRESOURCE( IDC_POPUPMENU ) );
773 HMENU popupMenu = ::GetSubMenu( hmenu, 0 );
775 ::CheckMenuItem( popupMenu, IDM_TOGGLE_TRACE_SHIP, s_config.m_traceShipPositionEnabled ? MF_CHECKED : MF_UNCHECKED );
776 ::CheckMenuItem( popupMenu, IDM_TOGGLE_KEEP_FOREGROUND, s_config.m_keepForeground ? MF_CHECKED : MF_UNCHECKED );
777 ::CheckMenuItem( popupMenu, IDM_TOGGLE_SPEED_METER, s_config.m_speedMeterEnabled ? MF_CHECKED : MF_UNCHECKED );
778 ::CheckMenuItem( popupMenu, IDM_TOGGLE_VECTOR_LINE, s_config.m_shipVectorLineEnabled ? MF_CHECKED : MF_UNCHECKED );
781 ::ClientToScreen( hwnd, &p );
782 ::TrackPopupMenu( popupMenu, TPM_NONOTIFY | TPM_NOANIMATION | TPM_LEFTALIGN | TPM_TOPALIGN,
783 p.x, p.y, 0, hwnd, NULL );
787 static void s_popupCoord( HWND hwnd, int16_t x, int16_t y )