const LPCWSTR m_debugSectionName = L"debug";
#endif
-public:
- const LPCWSTR m_defaultMapFileName = L"map.png";
public:
std::wstring m_mapFileName;
GVOConfig( LPCWSTR fileName )
: m_fileName( g_makeFullPath( fileName ) )
+ , m_mapFileName( L"map.png" )
, m_pollingInterval( 1000 )
, m_windowPos( defaultPosition() )
, m_windowSize( defaultSize() )
std::vector<wchar_t> buf(4096);
section = m_coreSectionName;
- ::GetPrivateProfileStringW(section, L"map", m_defaultMapFileName, &buf[0], buf.size(), fn);
+ ::GetPrivateProfileStringW(section, L"map", m_mapFileName.c_str(), &buf[0], buf.size(), fn);
m_mapFileName = &buf[0];
- m_pollingInterval = ::GetPrivateProfileInt( section, L"polingInterval", m_pollingInterval, fn );
+ m_pollingInterval = ::GetPrivateProfileInt( section, L"pollingInterval", m_pollingInterval, fn );
m_traceShipPositionEnabled = ::GetPrivateProfileInt( section, L"traceEnabled", m_traceShipPositionEnabled, fn ) != 0;
m_speedMeterEnabled = ::GetPrivateProfileInt( section, L"speedMeterEnabled", m_speedMeterEnabled, fn ) != 0;
m_shipVectorLineEnabled = ::GetPrivateProfileInt( section, L"shipVectorLineEnabled", m_shipVectorLineEnabled, fn ) != 0;
#include "stdafx.h"
+#include <process.h>
#include "GVONavish.h"
#include "GVOGameProcess.h"
#include "GVOWorldMap.h"
// \89æ\91\9c\89ð\90Í\83f\83o\83b\83O\97p\81BGVOGameProcess
//#define GVO_ANALYZE_DEBUG
+extern HWND g_hwndMain;
+extern HDC g_hdcMain;
+
namespace {
#ifdef GVO_ANALYZE_DEBUG
LPCWSTR const k_debugImageFileName = L"..\\debug.png";
#endif
+#ifndef NDEBUG
+ // \83f\83o\83b\83O\97p\8e©\93®\8dq\8ds\95Ï\90\94
+ static double s_xDebugAutoCruise;
+ static double s_yDebugAutoCruise;
+ static double s_debugAutoCruiseAngle = 0;
+ static bool s_debugAutoCruiseEnabled = false;
+ static double s_debugAutoCruiseVelocity = 0;
+ static uint32_t s_debugAutoCruiseTurnInterval;
+ static double s_debugAutoCruiseTurnAngle;
+#endif
+
LPWSTR const k_gvoWindowClassName = L"Greate Voyages Online Game MainFrame";
LPWSTR const k_gvoWindowCaption = L"\91å\8dq\8aC\8e\9e\91ã Online";
}
-void GVOGameProcess::setConfig( const GVOConfig& config )
+void GVOGameProcess::setup( const GVOConfig& config )
{
m_surveyCoord = config.m_initialSurveyCoord;
+ m_ship.setInitialSurveyCoord( config.m_initialSurveyCoord );
+ m_pollingInterval = config.m_pollingInterval;
+#ifndef NDEBUG
+ s_xDebugAutoCruise = config.m_initialSurveyCoord.x;
+ s_yDebugAutoCruise = config.m_initialSurveyCoord.y;
+ s_debugAutoCruiseEnabled = config.m_debugAutoCruiseEnabled;
+ s_debugAutoCruiseVelocity = config.m_debugAutoCruiseVelocity;
+ s_debugAutoCruiseTurnInterval = config.m_debugAutoCruiseTurnInterval;
+ s_debugAutoCruiseTurnAngle = config.m_debugAutoCruiseTurnAngle;
+#endif
+
+ m_pollingTimerEventID = ::timeSetEvent( m_pollingInterval, 1, LPTIMECALLBACK( m_pollingTimerEvent ), 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET );
+ m_threadQuitSignal = ::CreateEvent( NULL, TRUE, FALSE, NULL );
+ m_workerThread = (HANDLE)::_beginthreadex( NULL, 0, threadMainThunk, this, 0, NULL );
+}
+
+
+void GVOGameProcess::teardown()
+{
+ if ( m_workerThread ) {
+ ::SetEvent( m_threadQuitSignal );
+ ::WaitForSingleObject( m_workerThread, INFINITE );
+ ::CloseHandle( m_workerThread );
+ ::CloseHandle( m_threadQuitSignal );
+ m_threadQuitSignal = NULL;
+ m_workerThread = NULL;
+ }
+ if ( m_pollingTimerEventID ) {
+ ::timeKillEvent( m_pollingTimerEventID );
+ m_pollingTimerEventID = 0;
+ }
+}
+
+
+#ifndef NDEBUG
+void GVOGameProcess::enableDebugAutoCruise( bool enabled )
+{
+ s_debugAutoCruiseEnabled = enabled;
}
+#endif
bool GVOGameProcess::updateState()
{
+ GVOGameStatus status;
+
+
#ifdef GVO_ANALYZE_DEBUG
{
static bool done = false;
return true;
}
#endif
+
+ if ( s_debugAutoCruiseEnabled ) {
+ static bool isRandInitialized = false;
+ if ( !isRandInitialized ) {
+ srand( ::timeGetTime() );
+ isRandInitialized = true;
+ }
+
+ const double rad = ((s_debugAutoCruiseAngle)* M_PI) / 180;
+ const double vx = ::cos( rad );
+ const double vy = ::sin( rad );
+
+ s_xDebugAutoCruise += vx * s_debugAutoCruiseVelocity;
+ s_yDebugAutoCruise += vy * s_debugAutoCruiseVelocity;
+
+ static DWORD tick = ::timeGetTime();
+ static DWORD count = 0;
+ if ( (tick + s_debugAutoCruiseTurnInterval) < ::timeGetTime() ) {
+ if ( 10 < (++count) ) {
+ count = 0;
+ s_debugAutoCruiseAngle += 90 + (LONG( rand() / double( RAND_MAX ) * 90 ) & ~0x1);
+ }
+ else {
+ s_debugAutoCruiseAngle += (rand() & 1) ? s_debugAutoCruiseTurnAngle : -s_debugAutoCruiseTurnAngle;
+ }
+ tick = ::timeGetTime();
+ }
+ s_debugAutoCruiseAngle = fmod( ::fabs( s_debugAutoCruiseAngle ), 360 );
+
+ if ( s_xDebugAutoCruise < 0 ) {
+ s_xDebugAutoCruise += k_worldWidth;
+ }
+ if ( s_yDebugAutoCruise < 0 ) {
+ s_yDebugAutoCruise += k_worldHeight;
+ }
+ s_xDebugAutoCruise = fmod( s_xDebugAutoCruise, (double)k_worldWidth );
+ s_yDebugAutoCruise = fmod( s_yDebugAutoCruise, (double)k_worldHeight );
+
+ //// \92n\90}\82ð\8c×\82®\8f\88\97\9d\82Ì\8am\94F\97p\83f\83o\83b\83O\83R\81[\83h
+ //if ( 100 <= s_xDebugAutoCruise && s_xDebugAutoCruise <= (GVOWorldMap::k_worldWidth - 100) ) {
+ // s_xDebugAutoCruise = 0;
+ //}
+
+ m_surveyCoord.x = LONG( s_xDebugAutoCruise );
+ m_surveyCoord.y = LONG( s_yDebugAutoCruise );
+ uint32_t timeStamp = ::timeGetTime();
+ m_speedMeter.updateVelocity( m_ship.velocity(), timeStamp );
+ m_ship.updateWithSurveyCoord( m_surveyCoord, timeStamp );
+
+ status.m_surveyCoord = m_surveyCoord;
+ status.m_shipVector = m_ship.vector();
+ status.m_shipVelocity = m_speedMeter.velocity();
+
+ ::EnterCriticalSection( &m_lock );
+ m_statusArray.push_back( status );
+ ::SetEvent( m_dataReadyEvent );
+ ::LeaveCriticalSection( &m_lock );
+ return true;
+ }
+
if ( !m_window ) {
m_window = ::FindWindow( k_gvoWindowClassName, k_gvoWindowCaption );
}
if ( !updateSurveyCoord() ) {
return false;
}
+
+ m_speedMeter.updateVelocity( m_ship.velocity(), m_timeStamp );
+ m_ship.updateWithSurveyCoord( m_surveyCoord, m_timeStamp );
+
+ status.m_surveyCoord = m_surveyCoord;
+ status.m_shipVector = m_ship.vector();
+ status.m_shipVelocity = m_speedMeter.velocity();
+
+ ::EnterCriticalSection( &m_lock );
+ m_statusArray.push_back( status );
+ ::SetEvent( m_dataReadyEvent );
+ ::LeaveCriticalSection( &m_lock );
+
return true;
}
return false;
}
+std::vector<GVOGameStatus> GVOGameProcess::getState()
+{
+ std::vector<GVOGameStatus> statusArray;
+
+ ::EnterCriticalSection( &m_lock );
+ m_statusArray.swap( statusArray );
+ ::ResetEvent( m_dataReadyEvent );
+ ::LeaveCriticalSection( &m_lock );
+
+ return statusArray;
+}
+
+
+UINT CALLBACK GVOGameProcess::threadMainThunk( LPVOID arg )
+{
+ GVOGameProcess *self = reinterpret_cast<GVOGameProcess *>(arg);
+ self->threadMain();
+ return 0;
+}
+
+
+void GVOGameProcess::threadMain()
+{
+ std::vector<HANDLE> signals;
+ signals.push_back( m_threadQuitSignal );
+ signals.push_back( m_pollingTimerEvent );
+
+ for ( ; ; ) {
+ const DWORD ret = ::WaitForMultipleObjects( signals.size(), &signals[0], FALSE, INFINITE );
+ if ( signals.size() <= ret ) {
+ exit( -1 );
+ }
+ HANDLE const active = signals[ret];
+ if ( active == m_threadQuitSignal ) {
+ break;
+ }
+
+ if ( active == m_pollingTimerEvent ) {
+ ::ResetEvent( m_pollingTimerEvent );
+
+ updateState();
+
+ continue;
+ }
+ }
+}
+
+
void GVOGameProcess::grabImage( HDC hdc, const POINT& offset, const SIZE& size )
{
if ( !m_surveyCoordImage.bitmapHandle() ) {
::DeleteDC( hdcMem );
}
+
bool GVOGameProcess::updateSurveyCoord()
{
bool succeeded = false;
#pragma once
+#include "GVONoncopyable.h"
#include "GVOImage.h"
#include "GVOConfig.h"
+#include "GVOSpeedMeter.h"
+#include "GVOShip.h"
+
+#include "GVOGameStatus.h"
+
//!@brief \91å\8dq\8aC\8e\9e\91ãOnline\83v\83\8d\83Z\83X
-class GVOGameProcess {
-private:
- GVOGameProcess( const GVOGameProcess& );
- GVOGameProcess& operator=(const GVOGameProcess&);
+class GVOGameProcess : private GVONoncopyable {
private:
HANDLE m_process;
HWND m_window;
POINT m_surveyCoord;
DWORD m_timeStamp;
+ GVOSpeedMeter m_speedMeter;
+ GVOShip m_ship;
+
+ uint32_t m_pollingInterval;
+ HANDLE m_pollingTimerEvent;
+ UINT m_pollingTimerEventID;
+
+ HANDLE m_workerThread;
+ HANDLE m_threadQuitSignal;
+ HANDLE m_dataReadyEvent;
+ CRITICAL_SECTION m_lock;
+
+ std::vector<GVOGameStatus> m_statusArray;
public:
GVOGameProcess() :
m_process( NULL ),
m_window( NULL ),
m_surveyCoord(),
- m_timeStamp()
+ m_timeStamp(),
+ m_pollingInterval(),
+ m_pollingTimerEvent( ::CreateEvent( NULL, TRUE, TRUE, NULL ) ),
+ m_pollingTimerEventID(),
+ m_workerThread(),
+ m_dataReadyEvent( ::CreateEvent( NULL, TRUE, FALSE, NULL ) )
{
+ ::InitializeCriticalSection( &m_lock );
}
virtual ~GVOGameProcess()
{
clear();
+ ::CloseHandle( m_dataReadyEvent );
+ ::CloseHandle( m_pollingTimerEvent );
+ ::DeleteCriticalSection( &m_lock );
}
HANDLE processHandle() const
void clear();
//!@brief \90Ý\92è\8fî\95ñ\82Å\8f\89\8aú\89»\82·\82é
- void setConfig( const GVOConfig& config );
-
- //!@brief \83Q\81[\83\80\89æ\96Ê\82ð\93Ç\82Ý\8eæ\82é
- //!@retval true \93Ç\82Ý\8eæ\82è\90¬\8c÷\81B
- //!@retval false \93Ç\82Ý\8eæ\82è\8e¸\94s\81B\82¨\82»\82ç\82\83Q\81[\83\80\82ª\8bN\93®\82µ\82Ä\82¢\82È\82¢\81B
- bool updateState();
+ void setup( const GVOConfig& config );
+ void teardown();
+#ifndef NDEBUG
+ void enableDebugAutoCruise( bool enabled );
+#endif
- //!@brief \91ª\97Ê\8dÀ\95W
- POINT surveyCoord() const
- {
- return m_surveyCoord;
- }
+ //!@brief \83Q\81[\83\80\89æ\96Ê\82ð\93Ç\82Ý\8eæ\82Á\82½\8c\8b\89Ê\82ð\8eó\82¯\8eæ\82é
+ //!@return \93Ç\82Ý\8eæ\82è\90¬\8c÷\8e\9e\82É\82Í\91ª\97Ê\8dÀ\95W\81A\8e©\91D\83x\83N\83g\83\8b\81A\8e©\91D\91¬\93x\82ª\8c\8b\89Ê\82Æ\82µ\82Ä\93n\82³\82ê\82é\81B
+ //!@note \8eÀ\8ds\82·\82é\82Æ\92~\90Ï\82³\82ê\82½\8fó\91Ô\82Í\91S\82Ä\8fÁ\8b\8e\82³\82ê\82é
+ std::vector<GVOGameStatus> getState();
//!@brief \83Q\81[\83\80\89æ\96Ê\93Ç\82Ý\8eæ\82è\90¬\8c÷\8e\9e\82Ì\8e\9e\8aÔ
DWORD timeStamp() const
return m_timeStamp;
}
-#ifndef NDEBUG
- //!@brief \83f\83o\83b\83O\97p
- void setSurveyCoord( const POINT& worldCoord )
+ // Wait\97p
+ HANDLE dataReadyEvent() const
{
- m_surveyCoord = worldCoord;
+ return m_dataReadyEvent;
}
+
+#ifndef NDEBUG
//!@brief \83f\83o\83b\83O\97p\91ª\97Ê\8dÀ\95W\89æ\91\9c
const GVOImage& surveyCoordImage() const
{
#endif
private:
+ bool updateState();
+ static UINT CALLBACK threadMainThunk( LPVOID arg );
+ void threadMain();
void grabImage( HDC hdc, const POINT& offset, const SIZE& size );
bool updateSurveyCoord();
};
-
--- /dev/null
+#pragma once
+#include <cinttypes>
+#include <Windows.h>
+
+#include "GVOVector.h"
+
+
+//!@brief \83Q\81[\83\80\83v\83\8d\83Z\83X\82©\82ç\8eæ\93¾\82µ\82½\8fó\91Ô\82ð\93Z\82ß\82½\83\82\83m
+class GVOGameStatus
+{
+public:
+ POINT m_surveyCoord; //!<@brief \91ª\97Ê\8dÀ\95W
+ GVOVector m_shipVector; //!<@brief \8e©\91D\82Ì\8cü\82«
+ double m_shipVelocity; //!<@brief \8e©\91D\82Ì\91¬\93x(\90\84\91ª\92l\81j
+
+ GVOGameStatus() : m_shipVelocity()
+ {
+ }
+
+};
--- /dev/null
+#include "stdafx.h"
+
+// PNG\82Æ\82©\82Ì\93Ç\82Ý\8d\9e\82Ý\97p
+#include <objbase.h>
+#include <gdiplus.h>
+#include <gdiplusbitmap.h>
+
+#include "GVOImage.h"
+
+
+namespace {
+ inline uint32_t s_strideFromWidthAndBitsPerPixel( const uint32_t width, const uint32_t bpp )
+ {
+ uint32_t stride = width * bpp / 8;
+ stride = stride + (4 - stride % 4) % 4;
+ return stride;
+ }
+ inline void s_copyImage24From32( uint8_t * const dst, const uint8_t * const src, const uint32_t width, const uint32_t height)
+ {
+ const uint32_t srcStride = s_strideFromWidthAndBitsPerPixel( width, 32 );
+ const uint32_t dstStride = s_strideFromWidthAndBitsPerPixel( width, 24 );
+
+ const uint8_t * s = src;
+ uint8_t * d = dst;
+
+ for ( uint32_t y = 0; y < height; ++y ) {
+ s = src + (y * srcStride);
+ d = dst + (y * dstStride);
+ for ( uint32_t x = 0; x < width; ++x ) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ ++s;
+ }
+ }
+ }
+}
+
+
+bool GVOImage::stretchCopy( const GVOImage& src, uint32_t width, uint32_t height )
+{
+ if ( !createDIBImage( width, height ) ) {
+ return false;
+ }
+
+ HDC hdc = ::GetDC( NULL );
+ HDC hdcSrc = ::CreateCompatibleDC( hdc );
+ HDC hdcDst = ::CreateCompatibleDC( hdc );
+
+ ::SaveDC( hdcSrc );
+ ::SaveDC( hdcDst );
+ ::SelectObject( hdcDst, m_hbmp );
+ ::SelectObject( hdcSrc, src.m_hbmp );
+
+ if ( m_size.cx != src.m_size.cx || m_size.cy != src.m_size.cy ) {
+ POINT org;
+ ::GetBrushOrgEx( hdcDst, &org );
+ ::SetStretchBltMode( hdcDst, HALFTONE );
+ ::SetBrushOrgEx( hdcDst, org.x, org.y, NULL );
+
+ ::StretchBlt( hdcDst, 0, 0, m_size.cx, m_size.cy,
+ hdcSrc, 0, 0, src.m_size.cx, src.m_size.cy,
+ SRCCOPY );
+ }
+ else {
+ ::BitBlt( hdcDst, 0, 0, m_size.cx, m_size.cy,
+ hdcSrc, 0, 0, SRCCOPY );
+ }
+
+ ::RestoreDC( hdcSrc, -1 );
+ ::DeleteDC( hdcSrc );
+ ::RestoreDC( hdcDst, -1 );
+ ::DeleteDC( hdcDst );
+ ::ReleaseDC( NULL, hdc );
+ m_fileName = L"";
+ return true;
+}
+
+
+bool GVOImage::createDIBImage( int width, int height )
+{
+ reset();
+
+ BITMAPINFOHEADER bmih = { sizeof(bmih) };
+ bmih.biWidth = width;
+ bmih.biHeight = -height;
+ bmih.biPlanes = 1;
+ bmih.biBitCount = 24;
+ bmih.biSizeImage = width * height * 3;
+ m_hbmp = ::CreateDIBSection( NULL, (LPBITMAPINFO)&bmih, DIB_RGB_COLORS, (void **)&m_bits, NULL, 0 );
+ if ( !m_hbmp ) {
+ return false;
+ }
+ m_size.cx = width;
+ m_size.cy = height;
+ m_stride = s_strideFromWidthAndBitsPerPixel( width, bmih.biBitCount );
+ m_fileName = L"";
+ return true;
+}
+
+
+bool GVOImage::loadFromFile( const std::wstring& fileName )
+{
+ reset();
+
+ std::auto_ptr<Gdiplus::Bitmap> image;
+ HBITMAP hbmp = NULL;
+ image.reset( Gdiplus::Bitmap::FromFile( fileName.c_str() ) );
+ image->GetHBITMAP( Gdiplus::Color( 0, 0, 0 ), &hbmp );
+ image.reset();
+ if ( !hbmp ) {
+ return false;
+ }
+ BITMAP bmp = { 0 };
+ ::GetObject( hbmp, sizeof(bmp), &bmp );
+ if ( !createDIBImage( bmp.bmWidth, bmp.bmHeight ) ) {
+ ::DeleteObject( hbmp );
+ return false;
+ }
+
+ std::vector<uint8_t> buffer;
+ buffer.resize( ::GetBitmapBits( hbmp, 0, NULL ) );
+ ::GetBitmapBits( hbmp, buffer.size(), &buffer[0] );
+ ::DeleteObject( hbmp );
+
+ switch ( bmp.bmBitsPixel ) {
+ case 24:
+ ::memcpy( m_bits, &buffer[0], m_stride );
+ break;
+ case 32:
+ ::s_copyImage24From32( m_bits, &buffer[0], m_size.cx, m_size.cy );
+ break;
+ default:
+ return false;
+ }
+
+ m_fileName = fileName;
+
+ return true;
+}
#pragma once
#include <cstdint>
#include <memory>
+#include <vector>
#include <Windows.h>
-// PNG\82Æ\82©\82Ì\93Ç\82Ý\8d\9e\82Ý\97p
-#include <objbase.h>
-#include <gdiplus.h>
-#include <gdiplusbitmap.h>
+#include "GVONoncopyable.h"
-class GVOImage {
-private:
- GVOImage( const GVOImage& );
- GVOImage& operator=(const GVOImage&);
-
+class GVOImage :private GVONoncopyable {
private:
std::wstring m_fileName;
HBITMAP m_hbmp;
SIZE m_size;
uint8_t * m_bits;
+ uint32_t m_stride;
public:
- GVOImage() : m_hbmp(), m_size(), m_bits()
+ GVOImage() :
+ m_hbmp(),
+ m_size(),
+ m_bits(),
+ m_stride()
{
}
~GVOImage()
m_hbmp = NULL;
}
m_fileName = L"";
+ m_size = SIZE();
+ m_stride = 0;
}
- bool stretchCopy( const GVOImage& src, const SIZE& size )
+ void copy( const GVOImage & src )
{
- return stretchCopy( src, size.cx, size.cy );
+ createDIBImage( src.m_size );
+ ::memcpy( m_bits, src.m_bits, src.m_size.cy * src.m_stride );
}
- bool stretchCopy( const GVOImage& src, uint32_t width, uint32_t height )
+ bool stretchCopy( const GVOImage& src, const SIZE& size )
{
- const SIZE size = { width, height };
- if ( !createDIBImage( size ) ) {
- return false;
- }
-
- HDC hdc = ::GetDC( NULL );
- HDC hdcSrc = ::CreateCompatibleDC( hdc );
- HDC hdcDst = ::CreateCompatibleDC( hdc );
-
- ::SaveDC( hdcSrc );
- ::SaveDC( hdcDst );
- ::SelectObject( hdcDst, m_hbmp );
- ::SelectObject( hdcSrc, src.m_hbmp );
-
- if ( m_size.cx != src.m_size.cx || m_size.cy != src.m_size.cy ) {
- POINT org;
- ::GetBrushOrgEx( hdcDst, &org );
- ::SetStretchBltMode( hdcDst, HALFTONE );
- ::SetBrushOrgEx( hdcDst, org.x, org.y, NULL );
-
- ::StretchBlt( hdcDst, 0, 0, m_size.cx, m_size.cy,
- hdcSrc, 0, 0, src.m_size.cx, src.m_size.cy,
- SRCCOPY );
- }
- else {
- ::BitBlt( hdcDst, 0, 0, m_size.cx, m_size.cy,
- hdcSrc, 0, 0, SRCCOPY );
- }
-
- ::RestoreDC( hdcSrc, -1 );
- ::DeleteDC( hdcSrc );
- ::RestoreDC( hdcDst, -1 );
- ::DeleteDC( hdcDst );
- ::ReleaseDC( NULL, hdc );
- return true;
+ return stretchCopy( src, size.cx, size.cy );
}
+ bool stretchCopy( const GVOImage& src, uint32_t width, uint32_t height );
bool isCompatible( const SIZE& size ) const
{
if ( !m_hbmp ) {
{
return m_size.cy;
}
+ uint32_t stride() const
+ {
+ return m_stride;
+ }
const uint8_t * imageBits() const
{
return m_bits;
return m_fileName;
}
- bool createDIBImage( int width, int height )
- {
- reset();
-
- BITMAPINFOHEADER bmih = { sizeof(bmih) };
- bmih.biWidth = width;
- bmih.biHeight = -height;
- bmih.biPlanes = 1;
- bmih.biBitCount = 24;
- bmih.biSizeImage = width * height * 3;
- m_hbmp = ::CreateDIBSection( NULL, (LPBITMAPINFO)&bmih, DIB_RGB_COLORS, (void **)&m_bits, NULL, 0 );
- if ( !m_hbmp ) {
- return false;
- }
- m_size.cx = width;
- m_size.cy = height;
- return true;
- }
+ bool createDIBImage( int width, int height );
bool createDIBImage( const SIZE& size )
{
- reset();
-
- BITMAPINFOHEADER bmih = { sizeof(bmih) };
- bmih.biWidth = size.cx;
- bmih.biHeight = -size.cy;
- bmih.biPlanes = 1;
- bmih.biBitCount = 24;
- bmih.biSizeImage = bmih.biWidth * bmih.biHeight * 3;
- m_hbmp = ::CreateDIBSection( NULL, (LPBITMAPINFO)&bmih, DIB_RGB_COLORS, (void **)&m_bits, NULL, 0 );
- if ( !m_hbmp ) {
- return false;
- }
- m_size = size;
- return true;
- }
- bool loadFromFile( const std::wstring& fileName )
- {
- std::auto_ptr<Gdiplus::Bitmap> image;
- image.reset( Gdiplus::Bitmap::FromFile( fileName.c_str() ) );
- image->GetHBITMAP( Gdiplus::Color( 0, 0, 0 ), &m_hbmp );
- image.reset();
- if ( !m_hbmp ) {
- return false;
- }
- BITMAP bmp = { 0 };
- ::GetObject( m_hbmp, sizeof(bmp), &bmp );
- m_size.cx = bmp.bmWidth;
- m_size.cy = ::abs( bmp.bmHeight );
- m_fileName = fileName;
- return true;
+ return createDIBImage( size.cx, size.cy );
}
+ bool loadFromFile( const std::wstring& fileName );
};
#include "GVOGameProcess.h"
#include "GVOWorldMap.h"
#include "GVOShip.h"
-#include "GVOSpeedMeter.h"
// \83A\83v\83\8a\8f\88\97\9d
static std::wstring s_makeVersionString();
static std::wstring s_getMapFileName();
-static void s_updateFrame(HWND hwnd, HDC hdc);
-static void s_updateWindowTitle( HWND );
+static void s_updateFrame(HWND);
+static void s_updateWindowTitle( HWND, POINT, double );
static void s_toggleKeepForeground( HWND );
static void s_popupMenu( HWND, int16_t, int16_t );
static void s_popupCoord( HWND, int16_t, int16_t );
static const std::wstring k_aboutText = s_makeVersionString(); // \83o\81[\83W\83\87\83\93\8fî\95ñ\83e\83L\83X\83g
-static GVOImage s_backbuffer; //!<@brief \95`\89æ\97p24bit\83C\83\81\81[\83W\83o\83b\83t\83@
-static HANDLE s_pollingTimerEvent = ::CreateEvent( NULL, TRUE, TRUE, NULL );
-static UINT s_pollingTimerID = 0;
-
static Gdiplus::GdiplusStartupInput s_gdisi;
static ULONG_PTR s_gdiToken;
static GVOConfig s_config( k_configFileName );
static GVOGameProcess s_gvoGameProcess;
+static GVORenderer s_renderer;
static GVOWorldMap s_worldMap;
-static GVOShip s_ship;
-static GVOSpeedMeter s_speedMeter;
+static POINT s_latestSurveyCoord;
static UINT s_pollingInterval = 1000; // \8fó\91Ô\8aÄ\8e\8b\8aÔ\8au\81i1\95b\81j
-static bool s_isUpdated = false; // \8fó\91Ô\8dX\90V\83t\83\89\83O
static bool s_isDragging = false; // \83h\83\89\83b\83O\8fó\91Ô\83t\83\89\83O
static SIZE s_clientSize; // \83N\83\89\83C\83A\83\93\83g\97Ì\88æ\82Ì\91å\82«\82³
static POINT s_dragOrg; // \83h\83\89\83b\83O\8c´\93_\81i\88Ú\93®\97Ê\8eZ\8fo\97p\81j
-
-#ifndef NDEBUG
-// \83f\83o\83b\83O\97p\8e©\93®\8dq\8ds\95Ï\90\94
-static double s_xDebugAutoCruise;
-static double s_yDebugAutoCruise;
-static double s_debugAutoCruiseAngle = 0;
+#ifdef GVO_PERF_CHECK
+typedef std::deque<double> PerfCountList;
+static PerfCountList s_perfCountList;
#endif
+
int APIENTRY _tWinMain( _In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
return 0;
}
- s_pollingTimerID = ::timeSetEvent( s_config.m_pollingInterval, tc.wPeriodMin, LPTIMECALLBACK( s_pollingTimerEvent ), 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET );
-
// \83\81\83C\83\93 \83\81\83b\83Z\81[\83W \83\8b\81[\83v:
const LRESULT retVal = s_mainLoop();
- ::timeKillEvent( s_pollingTimerID );
+ s_gvoGameProcess.teardown();
s_config.save();
Gdiplus::GdiplusShutdown( s_gdiToken );
static BOOL InitInstance( HINSTANCE hInstance, int nCmdShow )
{
- if ( !s_worldMap.loadFromFile( s_config ) ) {
- // \8e¸\94s\82·\82ê\82Î\95Û\91¶\82³\82ê\82È\82¢\82Ì\82Å\91å\8fä\95v\81B
- s_config.m_mapFileName = s_getMapFileName();
- if ( !s_worldMap.loadFromFile( s_config ) ) {
+ if ( !s_worldMap.loadFromFile( s_config.m_mapFileName ) ) {
+ std::wstring fileName = s_getMapFileName();
+ if ( !s_worldMap.loadFromFile( fileName ) ) {
::MessageBox( NULL,
L"\83}\83b\83v\89æ\91\9c\82ð\8aJ\82¯\82Ü\82¹\82ñ\82Å\82µ\82½\81B",
k_appName,
MB_ICONERROR | MB_SETFOREGROUND | MB_OK );
return FALSE;
}
+ s_config.m_mapFileName = fileName;
}
+ s_renderer.setWorldMap( s_worldMap );
HWND hwnd;
if ( s_config.m_keepForeground ) {
exStyle |= WS_EX_TOPMOST;
}
- hwnd = CreateWindowEx( exStyle, k_windowClassName, k_appName, WS_OVERLAPPEDWINDOW,
+ DWORD style = 0;
+ style |= WS_OVERLAPPEDWINDOW;
+ style |= WS_CLIPCHILDREN;
+ style |= WS_CLIPSIBLINGS;
+ hwnd = CreateWindowEx( exStyle, k_windowClassName, k_appName, style,
s_config.m_windowPos.x, s_config.m_windowPos.y,
s_config.m_windowSize.cx, s_config.m_windowSize.cy,
NULL, NULL, hInstance, NULL );
return FALSE;
}
+ g_hwndMain = hwnd;
+ g_hdcMain = ::GetDC( g_hwndMain );
+ s_renderer.setup( g_hdcMain );
+
s_pollingInterval = s_config.m_pollingInterval;
- s_gvoGameProcess.setConfig( s_config );
- s_worldMap.setConfig( s_config );
- s_ship.setInitialSurveyCoord( s_config.m_initialSurveyCoord );
-#ifndef NDEBUG
- s_xDebugAutoCruise = s_config.m_initialSurveyCoord.x;
- s_yDebugAutoCruise = s_config.m_initialSurveyCoord.y;
-#endif
+ s_gvoGameProcess.setup( s_config );
+ s_renderer.setConfig( s_config );
- if ( s_gvoGameProcess.updateState() ) {
- s_ship.updateWithSurveyCoord( s_gvoGameProcess.surveyCoord(), s_gvoGameProcess.timeStamp() );
- s_worldMap.setShipPosition( s_gvoGameProcess.surveyCoord(), s_config.m_traceShipPositionEnabled );
- }
- s_updateWindowTitle( hwnd );
+ s_updateWindowTitle( hwnd, s_config.m_initialSurveyCoord, s_renderer.viewScale() );
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
- g_hwndMain = hwnd;
- g_hdcMain = ::GetDC( g_hwndMain );
return TRUE;
}
if ( s_gvoGameProcess.processHandle() ) {
handles.push_back( s_gvoGameProcess.processHandle() );
}
- handles.push_back( s_pollingTimerEvent );
+ //handles.push_back( s_pollingTimerEvent );
+ handles.push_back( s_gvoGameProcess.dataReadyEvent() );
if ( handles.empty() ) {
::WaitMessage();
s_gvoGameProcess.clear();
continue;
}
- if ( activeHandle == s_pollingTimerEvent ) {
- ::ResetEvent( s_pollingTimerEvent );
- s_updateFrame( g_hwndMain, g_hdcMain );
+
+ if ( activeHandle == s_gvoGameProcess.dataReadyEvent() ) {
+ s_updateFrame( g_hwndMain );
continue;
}
}
break;
case IDM_TOGGLE_TRACE_SHIP:
s_config.m_traceShipPositionEnabled = !s_config.m_traceShipPositionEnabled;
+ s_renderer.enableTraceShip( s_config.m_traceShipPositionEnabled );
break;
case IDM_ERASE_SHIP_ROUTE:
- s_worldMap.clearShipRoute();
+ s_renderer.clearShipRoute();
break;
case IDM_TOGGLE_KEEP_FOREGROUND:
s_toggleKeepForeground( hwnd );
break;
case IDM_TOGGLE_SPEED_METER:
s_config.m_speedMeterEnabled = !s_config.m_speedMeterEnabled;
+ s_renderer.enableSpeedMeter( s_config.m_speedMeterEnabled );
::InvalidateRect( hwnd, NULL, FALSE );
break;
case IDM_TOGGLE_VECTOR_LINE:
s_config.m_shipVectorLineEnabled = !s_config.m_shipVectorLineEnabled;
- s_worldMap.setVisibleShipRoute( s_config.m_shipVectorLineEnabled );
+ s_renderer.setVisibleShipRoute( s_config.m_shipVectorLineEnabled );
break;
- default:
- return DefWindowProc( hwnd, message, wp, lp );
- }
- break;
-
- case WM_KEYUP:
- switch ( wp ) {
- case VK_F1:
- s_toggleKeepForeground( hwnd );
+ case IDM_SAME_SCALE:
+ if ( s_renderer.viewScale() != 1.0 ) {
+ s_renderer.resetViewScale();
+ }
break;
- case VK_ADD:
- if ( s_worldMap.zoomIn() ) {
- s_updateWindowTitle( hwnd );
+ case IDM_ZOOM_IN:
+ if ( s_renderer.zoomIn() ) {
+#ifdef GVO_PERF_CHECK
+ s_perfCountList.clear();
+#endif
+ s_updateWindowTitle( hwnd, s_latestSurveyCoord, s_renderer.viewScale() );
::InvalidateRect( hwnd, NULL, FALSE );
}
break;
- case VK_OEM_MINUS:
- if ( s_worldMap.zoomOut() ) {
- s_updateWindowTitle( hwnd );
+ case IDM_ZOOM_OUT:
+ if ( s_renderer.zoomOut() ) {
+#ifdef GVO_PERF_CHECK
+ s_perfCountList.clear();
+#endif
+ s_updateWindowTitle( hwnd, s_latestSurveyCoord, s_renderer.viewScale() );
::InvalidateRect( hwnd, NULL, FALSE );
}
break;
- default:
+#ifndef NDEBUG
+ case IDM_TOGGLE_DEBUG_AUTO_CRUISE:
+ s_config.m_debugAutoCruiseEnabled = !s_config.m_debugAutoCruiseEnabled;
+ s_gvoGameProcess.enableDebugAutoCruise( s_config.m_debugAutoCruiseEnabled );
break;
+#endif
+
+ default:
+ return DefWindowProc( hwnd, message, wp, lp );
}
break;
}
break;
case WM_DESTROY:
+ s_renderer.teardown();
PostQuitMessage( 0 );
break;
default:
if ( s_clientSize.cx != cx || s_clientSize.cy != cy ) {
s_clientSize.cx = cx;
s_clientSize.cy = cy;
- if ( !s_backbuffer.isCompatible( s_clientSize ) ) {
- s_backbuffer.createDIBImage( s_clientSize );
- }
- s_worldMap.setViewSize( s_clientSize );
+ s_renderer.setViewSize( s_clientSize );
}
}
bool isChanged = false;
if ( 0 < delta ) {
- isChanged = s_worldMap.zoomIn();
+ isChanged = s_renderer.zoomIn();
}
else {
- isChanged = s_worldMap.zoomOut();
+ isChanged = s_renderer.zoomOut();
}
if ( isChanged ) {
- s_updateWindowTitle( hwnd );
+#ifdef GVO_PERF_CHECK
+ s_perfCountList.clear();
+#endif
+ s_updateWindowTitle( hwnd, s_latestSurveyCoord, s_renderer.viewScale() );
::InvalidateRect( hwnd, NULL, FALSE );
}
}
}
const POINT offset = { -dx, -dy };
- s_worldMap.offsetFocusInViewCoord( offset );
+ s_renderer.offsetFocusInViewCoord( offset );
::InvalidateRect( hwnd, NULL, FALSE );
s_dragOrg.x = x;
s_dragOrg.y = y;
s_config.m_traceShipPositionEnabled = false;
+ s_renderer.enableTraceShip( s_config.m_traceShipPositionEnabled );
}
else {
}
-// \83_\83u\83\8b\83o\83b\83t\83@\83\8a\83\93\83O\82Å\82¿\82ç\82Â\82«\96h\8e~\81B
static void s_onPaint( HWND hwnd )
{
#ifdef GVO_PERF_CHECK
- int64_t perfBegin = 0, perfEnd = 0;
- ::QueryPerformanceCounter((LARGE_INTEGER*)&perfBegin);
+ const int64_t perfBegin = g_queryPerformanceCounter();
#endif
- if ( !s_backbuffer.bitmapHandle() ) {
- s_backbuffer.createDIBImage( s_clientSize );
- }
-
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint( hwnd, &ps );
- HDC hdcBackbuffer = ::CreateCompatibleDC( hdc );
- ::SaveDC( hdcBackbuffer );
- ::SelectObject( hdcBackbuffer, s_backbuffer.bitmapHandle() );
- RECT rc = { 0, 0, s_clientSize.cx, s_clientSize.cy };
- ::FillRect( hdcBackbuffer, &rc, (HBRUSH)::GetStockObject( BLACK_BRUSH ) );
-
- // \95`\89æ\82ðhdcBackbuffer\82É\91Î\82µ\82Ä\8ds\82¤\81B
- s_worldMap.drawMap( hdcBackbuffer, s_ship );
-
- // \91¬\93x\8cv\82ð\95`\89æ
- if ( s_config.m_speedMeterEnabled ) {
- const double velocity = s_speedMeter.velocityByKnot();
- wchar_t buf[4096] = { 0 };
- swprintf( buf, _countof( buf ), L"%.2f kt", velocity );
-
- RECT rc = { 0 };
- ::DrawText( hdcBackbuffer, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP | DT_CALCRECT );
- const int width = rc.right - rc.left;
- rc.left = s_clientSize.cx - width;
- rc.right = rc.left + width;
- ::DrawText( hdcBackbuffer, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP );
- }
-
-#ifndef NDEBUG
- // \91ª\97Ê\8dÀ\95W\82ð\95`\89æ
- {
- const GVOImage& surveyCoordImage = s_gvoGameProcess.surveyCoordImage();
- HDC hdcSurvey = ::CreateCompatibleDC( hdcBackbuffer );
- ::SaveDC( hdcSurvey );
- ::SelectObject( hdcSurvey, surveyCoordImage.bitmapHandle() );
- ::BitBlt( hdcBackbuffer, 0, 0, surveyCoordImage.size().cx, surveyCoordImage.size().cy,
- hdcSurvey, 0, 0, SRCCOPY );
- ::RestoreDC( hdcSurvey, -1 );
- ::DeleteDC( hdcSurvey );
- }
-#endif
-
-#ifndef NDEBUG
- if ( s_config.m_debugAutoCruiseEnabled ) {
- const double rad = ((s_debugAutoCruiseAngle)* M_PI) / 180;
- const double vx = ::cos( rad );
- const double vy = ::sin( rad );
- const LONG length = max( s_clientSize.cx, s_clientSize.cy );
-
- COLORREF rgb = (::fabs(s_ship.vector().angleTo(GVOVector(vx,vy))) <= FLT_EPSILON) ? RGB( 0, 255, 0 ) : RGB( 255, 255, 0 );
-
- LONG x2 = s_clientSize.cx / 2 + LONG( vx * length );
- LONG y2 = s_clientSize.cy / 2 + LONG( vy * length );
- HPEN pen = ::CreatePen( PS_SOLID, 3, rgb );
- HGDIOBJ old = ::SelectObject( hdcBackbuffer, pen );
- ::MoveToEx( hdcBackbuffer, s_clientSize.cx / 2, s_clientSize.cy / 2, NULL );
- ::LineTo( hdcBackbuffer, x2, y2 );
- ::SelectObject( hdcBackbuffer, old );
- ::DeleteObject( pen );
- }
-#endif // #ifndef NDEBUG
-
- ::BitBlt( hdc, 0, 0, s_clientSize.cx, s_clientSize.cy,
- hdcBackbuffer, 0, 0, SRCCOPY );
-
- ::RestoreDC( hdcBackbuffer, -1 );
- ::DeleteDC( hdcBackbuffer );
- EndPaint( hwnd, &ps );
+ s_renderer.render();
+ ::ValidateRect( hwnd, NULL );
#ifdef GVO_PERF_CHECK
- ::QueryPerformanceCounter((LARGE_INTEGER*)&perfEnd);
- int64_t freq = 0;
- ::QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
+ const int64_t perfEnd = g_queryPerformanceCounter();
+ const int64_t freq = g_queryPerformanceFrequency();
const double deltaPerSec = (double(perfEnd - perfBegin) / double(freq)) * 1000.0;
- typedef std::list<double> PerfList;
- static PerfList perf;
- perf.push_back(deltaPerSec);
+ s_perfCountList.push_back(deltaPerSec);
- const double ave = std::accumulate( perf.begin(), perf.end(), 0.0 ) / perf.size();
- if ( 100 < perf.size() ) {
- perf.pop_front();
+ const double ave = std::accumulate( s_perfCountList.begin(), s_perfCountList.end(), 0.0 ) / s_perfCountList.size();
+ if ( 100 < s_perfCountList.size() ) {
+ s_perfCountList.pop_front();
}
std::wstring s;
- s = std::wstring( L"perf:" ) + std::to_wstring( ave ) + L"(ms)\n";
+ s = std::wstring( L"\95`\89æ\91¬\93x:" ) + std::to_wstring( ave ) + L"(ms)\n";
::SetWindowText( hwnd, s.c_str() );
- ::InvalidateRect( hwnd, NULL, FALSE );
#endif
}
}
-static void s_updateFrame( HWND hwnd, HDC hdc )
+static void s_updateFrame( HWND hwnd )
{
-#ifndef NDEBUG
- if ( s_config.m_debugAutoCruiseEnabled ) {
- static bool isRandInitialized = false;
- if ( !isRandInitialized ) {
- srand( ::timeGetTime() );
- isRandInitialized = true;
- }
-
- const double rad = ((s_debugAutoCruiseAngle)* M_PI) / 180;
- const double vx = ::cos( rad );
- const double vy = ::sin( rad );
-
- s_xDebugAutoCruise += vx * s_config.m_debugAutoCruiseVelocity;
- s_yDebugAutoCruise += vy * s_config.m_debugAutoCruiseVelocity;
-
- static DWORD tick = ::timeGetTime();
- static DWORD count = 0;
- if ( (tick + s_config.m_debugAutoCruiseTurnInterval) < ::timeGetTime() ) {
- if ( 10 < (++count) ) {
- count = 0;
- s_debugAutoCruiseAngle += 90 + (LONG( rand() / double( RAND_MAX ) * 90 ) & ~0x1);
- }
- else {
- s_debugAutoCruiseAngle += (rand() & 1) ? s_config.m_debugAutoCruiseTurnAngle : -s_config.m_debugAutoCruiseTurnAngle;
- }
- tick = ::timeGetTime();
- }
- s_debugAutoCruiseAngle = fmod( ::fabs( s_debugAutoCruiseAngle ), 360 );
-
- if ( s_xDebugAutoCruise < 0 ) {
- s_xDebugAutoCruise += k_worldWidth;
- }
- if ( s_yDebugAutoCruise < 0 ) {
- s_yDebugAutoCruise += k_worldHeight;
- }
- s_xDebugAutoCruise = fmod( s_xDebugAutoCruise, (double)k_worldWidth );
- s_yDebugAutoCruise = fmod( s_yDebugAutoCruise, (double)k_worldHeight );
-
- //// \92n\90}\82ð\8c×\82®\8f\88\97\9d\82Ì\8am\94F\97p\83f\83o\83b\83O\83R\81[\83h
- //if ( 100 <= s_xDebugAutoCruise && s_xDebugAutoCruise <= (GVOWorldMap::k_worldWidth - 100) ) {
- // s_xDebugAutoCruise = 0;
- //}
-
-
- POINT p = {
- LONG( s_xDebugAutoCruise ),
- LONG( s_yDebugAutoCruise )
- };
- uint32_t timeStamp = ::timeGetTime();
- s_ship.updateWithSurveyCoord( p, timeStamp );
- s_speedMeter.updateVelocity( s_ship.velocity(), timeStamp );
- s_gvoGameProcess.setSurveyCoord( p );
- s_worldMap.setShipPosition( p, s_config.m_traceShipPositionEnabled );
- s_worldMap.updateShipRouteMap( hdc );
- s_updateWindowTitle( hwnd );
- ::InvalidateRect( hwnd, NULL, FALSE );
+ std::vector<GVOGameStatus> gameStats;
+ gameStats = s_gvoGameProcess.getState();
+ if ( gameStats.empty() ) {
return;
}
-#endif // #ifndef NDEBUG
-
- s_isUpdated = s_gvoGameProcess.updateState();
- if ( s_isUpdated ) {
- s_config.m_initialSurveyCoord = s_gvoGameProcess.surveyCoord();
- s_ship.updateWithSurveyCoord( s_gvoGameProcess.surveyCoord(), s_gvoGameProcess.timeStamp() );
- s_speedMeter.updateVelocity( s_ship.velocity(), s_gvoGameProcess.timeStamp() );
- s_worldMap.setShipPosition( s_gvoGameProcess.surveyCoord(), s_config.m_traceShipPositionEnabled );
- s_worldMap.updateShipRouteMap( hdc );
- s_updateWindowTitle( hwnd );
- ::InvalidateRect( hwnd, NULL, FALSE );
+ for ( std::vector<GVOGameStatus>::const_iterator it = gameStats.begin(); it != gameStats.end(); ++it ) {
+ const GVOGameStatus& status = *it;
+ s_latestSurveyCoord = status.m_surveyCoord;
+ s_config.m_initialSurveyCoord = s_latestSurveyCoord;
+ s_renderer.updateShipState( s_latestSurveyCoord, status.m_shipVector, status.m_shipVelocity );
}
+#ifndef GVO_PERF_CHECK
+ s_updateWindowTitle( hwnd, s_latestSurveyCoord, s_renderer.viewScale() );
+#endif
+ ::InvalidateRect( hwnd, NULL, FALSE );
}
-static void s_updateWindowTitle( HWND hwnd )
+static void s_updateWindowTitle( HWND hwnd, POINT surveyCoord, double viewScale )
{
- const POINT& surveyCoord = s_gvoGameProcess.surveyCoord();
-
std::vector<wchar_t> buf( 4096 );
::swprintf( &buf[0], buf.size(), L"%d,%d - (%.1f%%) - %s %s",
surveyCoord.x, surveyCoord.y,
- s_worldMap.viewScale() * s_worldMap.viewScaleOrder(),
+ viewScale * 100.0,
k_appName, k_version
);
::SetWindowText( hwnd, &buf[0] );
::CheckMenuItem( popupMenu, IDM_TOGGLE_SPEED_METER, s_config.m_speedMeterEnabled ? MF_CHECKED : MF_UNCHECKED );
::CheckMenuItem( popupMenu, IDM_TOGGLE_VECTOR_LINE, s_config.m_shipVectorLineEnabled ? MF_CHECKED : MF_UNCHECKED );
+#ifndef NDEBUG
+ MENUITEMINFO mii = { sizeof(mii) };
+ mii.fMask = MIIM_TYPE | MIIM_ID;
+ mii.fType = MFT_STRING;
+ mii.wID = IDM_TOGGLE_DEBUG_AUTO_CRUISE;
+ mii.dwTypeData = L"[DEBUG]\8e©\93®\8dq\8ds\82ð\97L\8cø";
+ ::InsertMenuItem( popupMenu, ::GetMenuItemCount( popupMenu ), TRUE, &mii );
+
+ ::CheckMenuItem( popupMenu, IDM_TOGGLE_DEBUG_AUTO_CRUISE, s_config.m_debugAutoCruiseEnabled ? MF_CHECKED : MF_UNCHECKED );
+#endif
+
POINT p = { x, y };
::ClientToScreen( hwnd, &p );
::TrackPopupMenu( popupMenu, TPM_NONOTIFY | TPM_NOANIMATION | TPM_LEFTALIGN | TPM_TOPALIGN,
p.x, p.y, 0, hwnd, NULL );
+
+ ::DestroyMenu( popupMenu );
}
{
return degree * (M_PI / 180.0);
}
+
+inline int64_t g_queryPerformanceCounter()
+{
+ int64_t v = 0;
+ ::QueryPerformanceCounter( (LARGE_INTEGER *)&v );
+ return v;
+}
+
+inline int64_t g_queryPerformanceFrequency()
+{
+ int64_t v = 0;
+ ::QueryPerformanceFrequency( (LARGE_INTEGER *)&v );
+ return v;
+}
<ItemGroup>
<ClInclude Include="GVOConfig.h" />
<ClInclude Include="GVOGameProcess.h" />
+ <ClInclude Include="GVOGameStatus.h" />
<ClInclude Include="GVOImage.h" />
<ClInclude Include="GVONavish.h" />
+ <ClInclude Include="GVONoncopyable.h" />
+ <ClInclude Include="GVORenderer.h" />
<ClInclude Include="GVOSpeedMeter.h" />
<ClInclude Include="GVOSurveyCoordExtractor.h" />
<ClInclude Include="GVOVector.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="GVOGameProcess.cpp" />
+ <ClCompile Include="GVOImage.cpp" />
<ClCompile Include="GVONavish.cpp" />
+ <ClCompile Include="GVORenderer.cpp" />
<ClCompile Include="GVOShip.cpp" />
<ClCompile Include="GVOSurveyCoordExtractor.cpp" />
<ClCompile Include="GVOWorldMap.cpp" />
<Image Include="small.ico" />
</ItemGroup>
<ItemGroup>
- <Text Include="ReadMe.txt" />
+ <Text Include="ReadMe.txt">
+ <DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
+ </Text>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
- <Filter Include="ソース ファイル">
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
- <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ <Filter Include="その他">
+ <UniqueIdentifier>{74884f52-7488-4c60-850e-6b05edacc52d}</UniqueIdentifier>
</Filter>
- <Filter Include="ヘッダー ファイル">
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
- <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
- </Filter>
- <Filter Include="リソース ファイル">
+ <Filter Include="その他\リソース ファイル">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
+ <Filter Include="本体">
+ <UniqueIdentifier>{b14ab327-228c-4825-b165-abb6cc117c44}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\アプリケーション">
+ <UniqueIdentifier>{17d24797-f10b-4315-862e-1d0e1739496f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\ゲームプロセス">
+ <UniqueIdentifier>{810563df-1604-4ced-902d-9bd6b305c74a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\画像">
+ <UniqueIdentifier>{e9afeb05-3270-4142-a4fd-2ab80da5c7b1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\画像解析">
+ <UniqueIdentifier>{28825152-a54b-4310-a26d-1311a1e7e120}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\自船">
+ <UniqueIdentifier>{41df506f-09c5-4aca-82ee-435f1cb853b7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\地図">
+ <UniqueIdentifier>{251fb7e2-7c32-42ce-bd2f-eabe6409bb3f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="本体\描画">
+ <UniqueIdentifier>{42636208-5d9a-42f1-87ee-2dd90224fe00}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
- <ClInclude Include="stdafx.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOImage.h">
+ <Filter>本体\画像</Filter>
</ClInclude>
- <ClInclude Include="targetver.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOShip.h">
+ <Filter>本体\自船</Filter>
</ClInclude>
- <ClInclude Include="Resource.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOVector.h">
+ <Filter>本体\自船</Filter>
</ClInclude>
- <ClInclude Include="GVONavish.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOVelocity.h">
+ <Filter>本体\自船</Filter>
</ClInclude>
- <ClInclude Include="GVOConfig.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOWorldMap.h">
+ <Filter>本体\地図</Filter>
</ClInclude>
<ClInclude Include="GVOGameProcess.h">
- <Filter>ヘッダー ファイル</Filter>
+ <Filter>本体\ゲームプロセス</Filter>
</ClInclude>
- <ClInclude Include="GVOImage.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOSpeedMeter.h">
+ <Filter>本体\自船</Filter>
</ClInclude>
<ClInclude Include="GVOSurveyCoordExtractor.h">
- <Filter>ヘッダー ファイル</Filter>
+ <Filter>本体\画像解析</Filter>
</ClInclude>
- <ClInclude Include="GVOWorldMap.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVOConfig.h">
+ <Filter>本体\アプリケーション</Filter>
</ClInclude>
- <ClInclude Include="GVOShip.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="GVONavish.h">
+ <Filter>本体\アプリケーション</Filter>
</ClInclude>
- <ClInclude Include="GVOVector.h">
- <Filter>ã\83\98ã\83\83ã\83\80ã\83¼ ファイル</Filter>
+ <ClInclude Include="Resource.h">
+ <Filter>ã\81\9dã\81®ä»\96\ã\83ªã\82½ã\83¼ã\82¹ ファイル</Filter>
</ClInclude>
- <ClInclude Include="GVOSpeedMeter.h">
- <Filter>ã\83\98ã\83\83ã\83\80ã\83¼ ã\83\95ã\82¡ã\82¤ã\83«</Filter>
+ <ClInclude Include="stdafx.h">
+ <Filter>ã\81\9dã\81®ä»\96</Filter>
</ClInclude>
- <ClInclude Include="GVOVelocity.h">
- <Filter>ヘッダー ファイル</Filter>
+ <ClInclude Include="targetver.h">
+ <Filter>その他</Filter>
+ </ClInclude>
+ <ClInclude Include="GVORenderer.h">
+ <Filter>本体\描画</Filter>
+ </ClInclude>
+ <ClInclude Include="GVOGameStatus.h">
+ <Filter>本体\ゲームプロセス</Filter>
+ </ClInclude>
+ <ClInclude Include="GVONoncopyable.h">
+ <Filter>その他</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="stdafx.cpp">
- <Filter>ソース ファイル</Filter>
+ <ClCompile Include="GVOImage.cpp">
+ <Filter>本体\画像</Filter>
</ClCompile>
- <ClCompile Include="GVONavish.cpp">
- <Filter>ソース ファイル</Filter>
+ <ClCompile Include="GVOShip.cpp">
+ <Filter>本体\自船</Filter>
</ClCompile>
- <ClCompile Include="GVOGameProcess.cpp">
- <Filter>ソース ファイル</Filter>
+ <ClCompile Include="GVOWorldMap.cpp">
+ <Filter>本体\地図</Filter>
</ClCompile>
<ClCompile Include="GVOSurveyCoordExtractor.cpp">
- <Filter>ソース ファイル</Filter>
+ <Filter>本体\画像解析</Filter>
</ClCompile>
- <ClCompile Include="GVOWorldMap.cpp">
- <Filter>ソース ファイル</Filter>
+ <ClCompile Include="GVOGameProcess.cpp">
+ <Filter>本体\ゲームプロセス</Filter>
</ClCompile>
- <ClCompile Include="GVOShip.cpp">
- <Filter>ソース ファイル</Filter>
+ <ClCompile Include="GVONavish.cpp">
+ <Filter>本体\アプリケーション</Filter>
+ </ClCompile>
+ <ClCompile Include="stdafx.cpp">
+ <Filter>その他</Filter>
+ </ClCompile>
+ <ClCompile Include="GVORenderer.cpp">
+ <Filter>本体\描画</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GVONavish.rc">
- <Filter>リソース ファイル</Filter>
+ <Filter>ã\81\9dã\81®ä»\96\ã\83ªã\82½ã\83¼ã\82¹ ã\83\95ã\82¡ã\82¤ã\83«</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="small.ico">
- <Filter>リソース ファイル</Filter>
+ <Filter>ã\81\9dã\81®ä»\96\ã\83ªã\82½ã\83¼ã\82¹ ã\83\95ã\82¡ã\82¤ã\83«</Filter>
</Image>
<Image Include="GVONavish.ico">
- <Filter>リソース ファイル</Filter>
+ <Filter>ã\81\9dã\81®ä»\96\ã\83ªã\82½ã\83¼ã\82¹ ã\83\95ã\82¡ã\82¤ã\83«</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt">
- <Filter>リソース ファイル</Filter>
+ <Filter>ã\81\9dã\81®ä»\96\ã\83ªã\82½ã\83¼ã\82¹ ã\83\95ã\82¡ã\82¤ã\83«</Filter>
</Text>
</ItemGroup>
</Project>
\ No newline at end of file
--- /dev/null
+#pragma once
+
+class GVONoncopyable {
+private:
+ GVONoncopyable() = default;
+ GVONoncopyable( const GVONoncopyable & ) = delete;
+ GVONoncopyable& operator=(const GVONoncopyable&) = delete;
+};
+
--- /dev/null
+#include "stdafx.h"
+#include "GVORenderer.h"
+#include "GVOWorldMap.h"
+#include "GVOConfig.h"
+
+
+
+namespace {
+ const double k_scaleStep = 0.125; // 12.5%
+ const double k_minScale = 0.125; // 12.5%
+ const double k_maxScale = 4.00; // 400%
+
+ // Google\90æ\90¶\9eH\82\81u\92n\8b\85\82Ì\8aO\8eü\82Í40,075km\81v\81u1\83m\83b\83g\82Í1.85200km\81v
+ // 1\90¢\8aE\8dÀ\95W\82Í40,075km/16384points
+ // \8eÀ\8e\9e\8aÔ1\95b\82Å\83Q\81[\83\80\93à0.4\8e\9e\8aÔ
+ //
+ // \92n\8b\85\8aO\8eü\82ð\90Ô\93¹\94¼\8ca\82©\82ç\8eZ\8fo\82·\82é\81B
+ // \90Ô\93¹\94¼\8ca\82Í6378.137\82È\82Ì\82Å\8aO\8eü\82Í2*M_PI_*6378.137
+ inline double s_velocityByKnot( const double velocity )
+ {
+ static const double k_knotFactor = (2 * M_PI * 6378.137) / 16384.0 / 0.4 / 1.852;
+ return velocity * k_knotFactor;
+ }
+}
+
+
+void GVORenderer::setup( HDC hdcPrimary )
+{
+ m_hdcPrimary = hdcPrimary;
+}
+
+
+void GVORenderer::teardown()
+{
+ m_hdcPrimary = NULL;
+}
+
+
+void GVORenderer::setWorldMap( const GVOWorldMap& worldMap )
+{
+ m_worldMap = &worldMap;
+ const GVOImage & map = m_worldMap->image();
+ m_mapImage.copy( map );
+}
+
+
+void GVORenderer::setConfig( const GVOConfig& config )
+{
+ m_positionUpdated = config.m_traceShipPositionEnabled;
+ m_focusPointInWorldCoord = config.m_initialSurveyCoord;
+ m_shipPointInWorld = config.m_initialSurveyCoord;
+ m_previousDrawPointInWorld = m_shipPointInWorld;
+ m_shipVectorLineEnabled = config.m_shipVectorLineEnabled;
+ m_speedMeterEnabled = config.m_speedMeterEnabled;
+ m_traceShipEnabled = config.m_traceShipPositionEnabled;
+}
+
+
+void GVORenderer::setViewSize( const SIZE& viewSize )
+{
+ m_viewSize = viewSize;
+}
+
+
+SIZE GVORenderer::scaledMapSize() const
+{
+ SIZE size = {
+ LONG( m_mapImage.width() * m_viewScale ),
+ LONG( m_mapImage.height() * m_viewScale )
+ };
+ return size;
+}
+
+
+POINT GVORenderer::mapOriginInView() const
+{
+ const POINT viewCenter = viewCenterPoint();
+ const SIZE mapSize = scaledMapSize();
+ const POINT worldPosInView = drawOffsetFromWorldCoord( m_focusPointInWorldCoord );
+
+ POINT mapTopLeft = {
+ viewCenter.x - worldPosInView.x,
+ viewCenter.y - worldPosInView.y
+ };
+ if ( m_viewSize.cx < mapSize.cx ) {
+ while ( 0 < mapTopLeft.x ) {
+ mapTopLeft.x -= mapSize.cx;
+ }
+ }
+
+ return mapTopLeft;
+}
+
+
+void GVORenderer::offsetFocusInViewCoord( const POINT& offset )
+{
+ const double dx = ((double)offset.x / m_viewScale) / m_mapImage.width();
+ const double dy = ((double)offset.y / m_viewScale) / m_mapImage.height();
+
+ LONG x = m_focusPointInWorldCoord.x + LONG( dx * k_worldWidth );
+ LONG y = m_focusPointInWorldCoord.y + LONG( dy * k_worldHeight );
+ y = max( 0, min( y, k_worldHeight ) );
+ while ( x < 0 ) {
+ x += k_worldWidth;
+ }
+ while ( k_worldWidth < x ) {
+ x -= k_worldWidth;
+ }
+
+ m_focusPointInWorldCoord.x = x;
+ m_focusPointInWorldCoord.y = y;
+}
+
+
+bool GVORenderer::zoomIn()
+{
+ double scale = m_viewScale;
+ double step = k_scaleStep;
+
+ scale = m_viewScale + step;
+ if ( k_maxScale < scale ) {
+ scale = k_maxScale;
+ }
+ if ( m_viewScale != scale ) {
+ m_viewScale = scale;
+ return true;
+ }
+ return false;
+}
+
+
+bool GVORenderer::zoomOut()
+{
+ double scale = m_viewScale;
+ double step = k_scaleStep;
+
+ scale = m_viewScale - step;
+ if ( scale < k_minScale ) {
+ scale = k_minScale;
+ }
+ if ( m_viewScale != scale ) {
+ m_viewScale = scale;
+ return true;
+ }
+ return false;
+}
+
+
+void GVORenderer::resetViewScale()
+{
+ m_viewScale = 1.0;
+}
+
+
+POINT GVORenderer::drawOffsetFromWorldCoord( const POINT&worldCoord ) const
+{
+ const POINT worldPosInImage = m_worldMap->imageCoordFromWorldCoord( worldCoord );
+ const POINT drawOffset = {
+ LONG( worldPosInImage.x * m_viewScale ),
+ LONG( worldPosInImage.y * m_viewScale )
+ };
+ return drawOffset;
+}
+
+
+void GVORenderer::updateShipState( const POINT& worldCoord, const GVOVector& shipVector, const double shipVelocity )
+{
+ m_shipVector = shipVector;
+ m_shipVelocity = shipVelocity;
+
+ if ( m_traceShipEnabled ) {
+ m_focusPointInWorldCoord = worldCoord;
+ }
+ if ( m_shipPointInWorld.x != worldCoord.x
+ || m_shipPointInWorld.y != worldCoord.y ) {
+
+ m_positionUpdated = true;
+ m_shipPointInWorld = worldCoord;
+ }
+ updateShipRouteMap();
+}
+
+
+void GVORenderer::updateShipRouteMap()
+{
+ // \88Ú\93®\82µ\82Ä\82¢\82È\82¯\82ê\82Î\89½\82à\82µ\82È\82¢
+ if ( !m_positionUpdated ) {
+ return;
+ }
+ // \88Ú\93®\82µ\82Ä\82¢\82Ä\82à\8dq\98H\82ð\8cq\82°\82È\82¢\82È\82ç\95`\89æ\82µ\82È\82¢
+ if ( !m_linkRoute ) {
+ m_previousDrawPointInWorld = m_shipPointInWorld;
+ m_linkRoute = true;
+ return;
+ }
+
+ const POINT& latestPoint = m_worldMap->imageCoordFromWorldCoord( m_shipPointInWorld );
+ const POINT& previousPoint = m_worldMap->imageCoordFromWorldCoord( m_previousDrawPointInWorld );
+
+ // \95`\89æ\8dÀ\95W\82ª\88ê\8f\8f\82È\82ç\89½\82à\82µ\82È\82¢
+ if ( latestPoint.x == previousPoint.x
+ && latestPoint.y == previousPoint.y ) {
+ return;
+ }
+
+
+ // \8dÅ\90V\8dÀ\95W\82©\82ç\88ê\82Â\91O\82Ì\8dÀ\95W\82Ö\90ü\82ð\88ø\82
+ // \90¢\8aE\82ð\8c×\82®\8fê\8d\87\82É\8dl\97¶\82ª\95K\97v\81B
+ // \88Ú\93®\97Ê\82ª\88ê\92è\82ð\92´\82¦\82½\82ç\95`\89æ\8f\88\97\9d\82µ\82È\82¢\82æ\82¤\82É\82·\82é\82Ì\82ª\83X\83}\81[\83g\82©\82È
+
+
+ // \90¢\8aE\82ð\8c×\82¢\82¾\82Æ\82Ý\82È\82·è\87\92l
+ const int k_distanceThreshold = m_mapImage.width() / 2;
+
+ const LONG xMin = min( latestPoint.x, previousPoint.x );
+ const LONG xMax = max( latestPoint.x, previousPoint.x );
+ const int xDistance = xMax - xMin;
+
+
+ HDC hdcMem = ::CreateCompatibleDC( m_hdcPrimary );
+ ::SaveDC( hdcMem );
+
+ HPEN hpen = ::CreatePen( PS_SOLID, 1, RGB( 255, 255, 255 ) );
+
+ ::SelectObject( hdcMem, m_mapImage.bitmapHandle() );
+ ::SelectObject( hdcMem, hpen );
+
+ if ( k_distanceThreshold < xDistance ) {
+ if ( previousPoint.x < latestPoint.x ) { // \90¢\8aE\82ð\90¼\82É\8cü\82©\82Á\82Ä\8c×\82¢\82¾
+ // \8d¶\82Ì\89æ\96Ê\8aO\82©\82ç\8cü\82©\82¤\90ü\82ð\95`\89æ
+ LONG x3 = latestPoint.x - m_mapImage.width();
+
+ ::MoveToEx( hdcMem, x3, latestPoint.y, NULL );
+ ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
+
+ // \89E\82Ì\89æ\96Ê\8aO\82É\8cü\82©\82¤\90ü\82ð\95`\89æ
+ LONG x4 = previousPoint.x + m_mapImage.width();
+ ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
+ ::LineTo( hdcMem, x4, previousPoint.y );
+ }
+ else { // \90¢\8aE\82ð\93\8c\82É\8cü\82©\82Á\82Ä\8c×\82¢\82¾
+ // \8d¶\82Ì\89æ\96Ê\8aO\82©\82ç\8cü\82©\82¤\90ü\82ð\95`\89æ
+ LONG x3 = previousPoint.x - m_mapImage.width();
+
+ ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
+ ::LineTo( hdcMem, x3, previousPoint.y );
+
+ // \89E\82Ì\89æ\96Ê\8aO\82É\8cü\82©\82¤\90ü\82ð\95`\89æ
+ LONG x4 = latestPoint.x + m_mapImage.width();
+ ::MoveToEx( hdcMem, x4, latestPoint.y, NULL );
+ ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
+ }
+ }
+ else {
+ // \8c×\82ª\82È\82¢\95`\89æ
+ ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
+ ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
+ }
+
+
+ ::RestoreDC( hdcMem, -1 );
+ ::DeleteDC( hdcMem );
+ ::DeleteObject( hpen );
+
+ m_previousDrawPointInWorld = m_shipPointInWorld;
+}
+
+
+void GVORenderer::clearShipRoute()
+{
+ m_mapImage.copy( m_worldMap->image() );
+}
+
+
+void GVORenderer::render()
+{
+ if ( !m_backBuffer.isCompatible(m_viewSize) ) {
+ m_backBuffer.createDIBImage( m_viewSize );
+ }
+ HDC hdcBackbuffer = ::CreateCompatibleDC( m_hdcPrimary );
+ ::SaveDC( hdcBackbuffer );
+
+ ::SelectObject( hdcBackbuffer, m_backBuffer.bitmapHandle() );
+ RECT rc = { 0, 0, m_backBuffer.width(), m_backBuffer.height()};
+ ::FillRect( hdcBackbuffer, &rc, (HBRUSH)::GetStockObject( BLACK_BRUSH ) );
+
+ drawMap( hdcBackbuffer, m_shipVector );
+
+ if ( m_speedMeterEnabled ) {
+ drawSpeedMeter( hdcBackbuffer, m_shipVelocity );
+ }
+
+ ::BitBlt( m_hdcPrimary, 0, 0, m_backBuffer.width(), m_backBuffer.height(),
+ hdcBackbuffer, 0, 0, SRCCOPY );
+ ::RestoreDC( hdcBackbuffer, -1 );
+ ::DeleteDC( hdcBackbuffer );
+}
+
+
+void GVORenderer::drawMap( HDC hdc, const GVOVector& shipVector )
+{
+ const SIZE mapSize = scaledMapSize();
+ const GVOImage *mapImage = &m_mapImage;
+
+ ::SaveDC( hdc );
+ if ( m_viewScale < 1.0 ) {
+ POINT org;
+ ::GetBrushOrgEx( hdc, &org );
+ ::SetStretchBltMode( hdc, HALFTONE );
+ ::SetBrushOrgEx( hdc, org.x, org.y, NULL );
+ }
+ else {
+ ::SetStretchBltMode( hdc, COLORONCOLOR );
+ }
+
+ HDC hdcMem = ::CreateCompatibleDC( hdc );
+ ::SaveDC( hdcMem );
+
+ ::SelectObject( hdcMem, mapImage->bitmapHandle() );
+
+ const POINT mapTopLeft = mapOriginInView();
+
+ int xDrawOrigin, yDrawOrigin;
+ xDrawOrigin = mapTopLeft.x;
+ yDrawOrigin = mapTopLeft.y;
+
+ if ( 0 < xDrawOrigin ) {
+ xDrawOrigin = (xDrawOrigin % mapSize.cx) - mapSize.cx;
+ }
+ const int xInitial = xDrawOrigin; // \8d¶\92[\82Ì\95`\89æ\8aJ\8enx\8dÀ\95W
+ int drawn = xInitial; // \95`\89æ\8dÏ\82Ý\8dÀ\95W
+
+ // \90¢\8aE\92n\90}\82ð\89¡\82É\95À\82×\82Ä\95`\89æ
+ // \81i\95`\89æ\8dÅ\93K\89»\82Í\8fÈ\97ª\81j
+ while ( drawn < m_viewSize.cx ) {
+ ::StretchBlt( hdc,
+ xDrawOrigin, yDrawOrigin,
+ mapSize.cx, mapSize.cy,
+ hdcMem,
+ 0, 0,
+ mapImage->width(), mapImage->height(),
+ SRCCOPY );
+
+ xDrawOrigin += mapSize.cx;
+ drawn += mapSize.cx;
+ }
+
+
+ const POINT shipPointOffset = drawOffsetFromWorldCoord( m_shipPointInWorld );
+
+ // \90j\98H\97\\91ª\90ü\82ð\95`\89æ
+ if ( shipVector.length() != 0.0 && m_shipVectorLineEnabled ) {
+ const int penWidth = max( 1, int( 1 * m_viewScale ) );
+ HPEN courseLinePen = ::CreatePen( PS_SOLID, penWidth, RGB( 255, 0, 255 ) );
+ HGDIOBJ oldPen = ::SelectObject( hdc, courseLinePen );
+
+ const LONG k_lineLength = k_worldHeight;
+ const POINT reachPointOffset = drawOffsetFromWorldCoord(
+ shipVector.pointFromOriginWithLength( m_shipPointInWorld, k_lineLength )
+ );
+
+ // \8c©\82¦\82Ä\82é\92n\90}\89æ\91\9c\82Ì\95ª\82¾\82¯\95`\89æ\82·\82é
+ drawn = xInitial;
+ xDrawOrigin = xInitial;
+ while ( drawn < m_viewSize.cx ) {
+ const POINT shipPointInView = {
+ xDrawOrigin + shipPointOffset.x,
+ yDrawOrigin + shipPointOffset.y
+ };
+ const POINT reachPointInView = {
+ xDrawOrigin + reachPointOffset.x,
+ yDrawOrigin + reachPointOffset.y
+ };
+ ::MoveToEx( hdc, shipPointInView.x, shipPointInView.y, NULL );
+ ::LineTo( hdc, reachPointInView.x, reachPointInView.y );
+ xDrawOrigin += mapSize.cx;
+ drawn += mapSize.cx;
+ }
+
+ ::SelectObject( hdc, oldPen );
+ ::DeleteObject( courseLinePen );
+ }
+
+ // \8e©\91D\82Ì\88Ê\92u\82ð\95`\89æ
+ const SIZE shipMarkSize = { 6, 6 };
+ HBRUSH shipBrush = ::CreateSolidBrush( RGB( 51, 238, 153 ) );
+ HGDIOBJ prevBrush = ::SelectObject( hdc, shipBrush );
+
+ // \8c©\82¦\82Ä\82é\92n\90}\89æ\91\9c\82Ì\95ª\82¾\82¯\95`\89æ\82·\82é
+ drawn = xInitial;
+ xDrawOrigin = xInitial;
+ while ( drawn < m_viewSize.cx ) {
+ ::Ellipse( hdc,
+ xDrawOrigin + shipPointOffset.x - shipMarkSize.cx / 2,
+ yDrawOrigin + shipPointOffset.y - shipMarkSize.cy / 2,
+ xDrawOrigin + shipPointOffset.x + shipMarkSize.cx,
+ yDrawOrigin + shipPointOffset.y + shipMarkSize.cy );
+
+ xDrawOrigin += mapSize.cx;
+ drawn += mapSize.cx;
+ }
+ ::SelectObject( hdc, prevBrush );
+ ::DeleteObject( shipBrush );
+
+
+ ::RestoreDC( hdcMem, -1 );
+ ::DeleteDC( hdcMem );
+ ::RestoreDC( hdc, -1 );
+}
+
+
+void GVORenderer::drawSpeedMeter( HDC hdc, double shipVelocity )
+{
+ const double velocity = s_velocityByKnot( shipVelocity );
+ wchar_t buf[4096] = { 0 };
+ swprintf( buf, _countof( buf ), L"%.2f kt", velocity );
+
+ RECT rc = { 0 };
+ ::DrawText( hdc, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP | DT_CALCRECT );
+ const int width = rc.right - rc.left;
+ rc.left = m_viewSize.cx - width;
+ rc.right = rc.left + width;
+ ::DrawText( hdc, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP );
+}
--- /dev/null
+#pragma once
+#include "GVONoncopyable.h"
+#include "GVOVector.h"
+#include "GVOImage.h"
+
+class GVOConfig;
+class GVOWorldMap;
+
+class GVORenderer :private GVONoncopyable {
+private:
+ const GVOWorldMap * m_worldMap; //!<@brief \90¢\8aE\92n\90}
+ GVOImage m_mapImage; //!<@brief \90¢\8aE\92n\90}\89æ\91\9c\8c\93\8dq\90Õ
+
+ HDC m_hdcPrimary;
+ GVOImage m_backBuffer;
+
+ SIZE m_viewSize;
+ double m_viewScale;
+
+ POINT m_focusPointInWorldCoord; //!<@brief \89æ\96Ê\92\86\89\9b\82É\88Ê\92u\82·\82é\83s\83N\83Z\83\8b\82Ì\90¢\8aE\8dÀ\95W
+ POINT m_shipPointInWorld; //!<@brief \8e©\91D\82Ì\88Ê\92u
+ bool m_positionUpdated; //!<@brief \8e©\91D\82Ì\88Ê\92u\8dX\90V\8fó\91Ô
+ POINT m_previousDrawPointInWorld; //!<@brief \92¼\91O\82Ì\95`\89æ\88Ê\92u
+ bool m_linkRoute; //!<@brief \8dq\98H\82ð\8cq\82°\82Ä\95`\89æ\82·\82é\83t\83\89\83O
+ bool m_shipVectorLineEnabled; //!<@brief \90j\98H\95`\89æ\83t\83\89\83O
+ bool m_speedMeterEnabled; //!<@brief \91¬\93x\8cv\95`\89æ\83t\83\89\83O
+ bool m_traceShipEnabled; //!<@brief \8e©\91D\88Ê\92u\92Ç\8f]\83t\83\89\83O
+ GVOVector m_shipVector;
+ double m_shipVelocity;
+
+public:
+ GVORenderer() :
+ m_hdcPrimary(),
+ m_viewSize(),
+ m_viewScale(1.0),
+ m_focusPointInWorldCoord(),
+ m_shipPointInWorld(),
+ m_positionUpdated(),
+ m_previousDrawPointInWorld(),
+ m_linkRoute( true ),
+ m_shipVectorLineEnabled( true ),
+ m_speedMeterEnabled( true ),
+ m_traceShipEnabled( true ),
+ m_shipVector(),
+ m_shipVelocity()
+ {
+ }
+ ~GVORenderer()
+ {
+ }
+
+ void setup( HDC hdcPrimary );
+ void teardown();
+
+ void setWorldMap( const GVOWorldMap& worldMap );
+
+ //!@brief \90Ý\92è\8fî\95ñ\82Å\8f\89\8aú\89»\82·\82é
+ void setConfig( const GVOConfig& config );
+
+ void setViewSize( const SIZE& viewSize );
+private:
+ SIZE scaledMapSize() const;
+ POINT mapOriginInView() const;
+
+public:
+ bool zoomIn();
+ bool zoomOut();
+ void resetViewScale();
+
+ inline double viewScale() const
+ {
+ return m_viewScale;
+ }
+
+ //!@note \83h\83\89\83b\83O\8f\88\97\9d\97p
+ void offsetFocusInViewCoord( const POINT& offset );
+
+ //!@brief \8e©\91D\82Ì\8fó\91Ô\82ð\90Ý\92è\82·\82é
+ void updateShipState( const POINT& worldCoord, const GVOVector& shipVector, const double shipVelocity );
+ void enableTraceShip( bool enabled )
+ {
+ m_traceShipEnabled = enabled;
+ }
+ void setVisibleShipRoute( bool visible )
+ {
+ m_shipVectorLineEnabled = visible;
+ }
+ void clearShipRoute();
+ void render();
+ void enableSpeedMeter( bool enabled )
+ {
+ m_speedMeterEnabled = enabled;
+ }
+private:
+ POINT drawOffsetFromWorldCoord( const POINT&worldCoord ) const;
+ void updateShipRouteMap();
+ void drawMap( HDC hdc, const GVOVector& shipVector );
+ void drawSpeedMeter( HDC hdc, double shipVelocity );
+ inline POINT viewCenterPoint() const
+ {
+ POINT p = {
+ m_viewSize.cx / 2,
+ m_viewSize.cy / 2
+ };
+ return p;
+ }
+};
}
// \82»\82Ì\83x\83N\83g\83\8b\82Å\95\\8c»\8fo\97\88\82é\83Q\81[\83\80\93à\95û\8ap\82Ì\95ª\89ð\94\\82ð\8eZ\8fo
+ // \83e\83L\83g\81[\89ß\82¬\82é\82ñ\82Å\82»\82Ì\82¤\82¿\92¼\82·\81B
inline double s_resolutionForVector( const GVOVector& vector )
{
- const double length = ::fabs( vector.length() );
+ const double length = vector.length();
if ( length == 0.0 ) {
return 0.0;
}
- if ( length < 2 ) {
- return g_radianFromDegree( 90 + 90 / 2 );
- }
if ( 90.0 <= length ) {
- return M_PI_2 / 90.0; // \82Q\93x\82ª\8dÅ\8d\82
+ return g_radianFromDegree( 2 ); // \82Q\93x\82ª\8dÅ\8d\82
+ }
+ if ( length < 2 ) {
+ return g_radianFromDegree( 90 );
}
const double resolution = M_PI_2 / length;
return resolution;
#include <Windows.h>
#include <vector>
#include <deque>
+#include "GVONoncopyable.h"
#include "GVONavish.h"
#include "GVOVector.h"
#include "GVOVelocity.h"
-class GVOShip {
+class GVOShip : private GVONoncopyable {
private:
typedef std::deque<GVOVector> VectorArray;
m_surveyCoord = initialSurveyCoord;
}
- //!@brief \8e©\91D\82Ì\95û\8cü\82ª\97L\8cø\82©\82Ç\82¤\82©
- inline bool isVectorEnabled() const
- {
- return m_vector.length() != 0.0;
- }
-
inline const GVOVector& vector() const
{
return m_vector;
//!@brief \91ª\97Ê\8dÀ\95W\82É\82æ\82é\8dÅ\90V\88Ê\92u\82ð\8dX\90V
void updateWithSurveyCoord( const POINT& surveyCoord, const uint32_t timeStamp );
- //!@brief \8c´\93_\82Æ\83x\83N\83g\83\8b\92·\82ð\8ew\92è\82µ\82Ä\8dÀ\95W\82ð\93¾\82é
- POINT pointFromOriginWithLength( const POINT& origin, const LONG length ) const
- {
- GVOVector v = m_vector.normalizedVector();
- const POINT p = {
- origin.x + LONG( v.x() * length ),
- origin.y + LONG( v.y() * length )
- };
- return p;
- }
-
+ //!@brief \8e©\91D\82Ì\95b\8aÔ\88Ú\93®\8b\97\97£\81i\90\84\91ª\92l\81j
inline double velocity() const
{
return m_velocityPerSecond.velocity();
#pragma once
#include <deque>
#include <algorithm>
+#include "GVONoncopyable.h"
-
-class GVOSpeedMeter {
+class GVOSpeedMeter : private GVONoncopyable {
private:
typedef std::deque<double> Array;
struct VelocityLogItem {
m_velocity = fastestVelocity();;
}
- // Google\90æ\90¶\9eH\82\81u\92n\8b\85\82Ì\8aO\8eü\82Í40,075km\81v\81u1\83m\83b\83g\82Í1.85200km\81v
- // 1\90¢\8aE\8dÀ\95W\82Í40,075km/16384points
- // \8eÀ\8e\9e\8aÔ1\95b\82Å\83Q\81[\83\80\93à0.4\8e\9e\8aÔ
- //
- // \90Ô\93¹\94¼\8ca\82Í6378.137\82Æ\82·\82é\82Æ\8aO\8eü\82Í2*M_PI_*6378.137=40075.016685578483111
- inline double velocityByKnot() const
+ double velocity() const
{
- //
- //static const double k_knotFactor = 40075.0 / 16384.0 / 0.4 / 1.85200;
- static const double k_knotFactor = (2 * M_PI * 6378.137) / 16384.0 / 0.4 / 1.85200;
- return m_velocity * k_knotFactor;
+ return m_velocity;
}
private:
#include <vector>
#include <map>
+#include "GVONoncopyable.h"
#include "GVOImage.h"
//!@brief \90\94\92l\82ð\92\8a\8fo\82·\82é\83N\83\89\83X
-class GVOSurveyCoordExtractor {
+class GVOSurveyCoordExtractor : private GVONoncopyable{
private:
typedef std::map<const std::string *, int> BitsDictionary;
m_length = calcLength( m_x, m_y );
}
+ //!@brief \8c´\93_\82Æ\83x\83N\83g\83\8b\92·\82ð\8ew\92è\82µ\82Ä\8dÀ\95W\82ð\93¾\82é
+ POINT pointFromOriginWithLength( const POINT& origin, const LONG length ) const
+ {
+ GVOVector v = normalizedVector();
+ const POINT p = {
+ origin.x + LONG( v.x() * length ),
+ origin.y + LONG( v.y() * length )
+ };
+ return p;
+ }
private:
// \83x\83N\83g\83\8b\92·\82ð\8cv\8eZ\82·\82é
static inline double calcLength(const double x, const double y)
-namespace {
- const double k_scaleStep = 0.125; // 12.5%
- const double k_minScale = 0.125; // 12.5%
- const double k_maxScale = 4.00; // 400%
-}
-
-bool GVOWorldMap::loadFromFile( const GVOConfig& config )
+bool GVOWorldMap::loadFromFile( const std::wstring& fileNmee )
{
+ GVOImage workImage;
std::wstring filePath;
- filePath = g_makeFullPath( config.m_mapFileName );
- if ( !m_mapImage.loadFromFile( filePath.c_str() ) ) {
- filePath = g_makeFullPath( config.m_defaultMapFileName );
- if ( !m_mapImage.loadFromFile( filePath.c_str() ) ) {
- return false;
- }
+ filePath = g_makeFullPath( fileNmee );
+ if ( !workImage.loadFromFile( filePath.c_str() ) ) {
+ return false;
}
-
- // \89æ\91\9c\82Ì\8d\82\82³\82Æ\88Ü\93x\82Ì\94ä\97¦\82Ì\83X\83P\81[\83\8a\83\93\83O\82Ì\8aî\8f\80\82Æ\82È\82é\81B
- const double mapHeight = m_mapImage.height();
- m_ratioForImageCoordFromWorldCoord = mapHeight / k_worldHeight;
-
- SIZE size;
- size.cx = LONG( m_mapImage.width() * 0.5 );
- size.cy = LONG( m_mapImage.height() * 0.5 );
- m_mapImageMipmap1.stretchCopy( m_mapImage, size );
- size.cx = LONG( m_mapImage.width() * k_minScale );
- size.cy = LONG( m_mapImage.height() * k_minScale );
- m_mapImageMipmap2.stretchCopy( m_mapImage, size );
+ m_mapImage.copy( workImage );
+ workImage.reset();
return true;
}
-void GVOWorldMap::setViewSize( const SIZE& viewSize )
-{
- m_viewSize = viewSize;
-}
-
-
-void GVOWorldMap::offsetFocusInViewCoord( const POINT& offset )
-{
- const double dx = ((double)offset.x / m_viewScale) / m_mapImage.width();
- const double dy = ((double)offset.y / m_viewScale) / m_mapImage.height();
-
- LONG x = m_focusPointInWorldCoord.x + LONG( dx * k_worldWidth );
- LONG y = m_focusPointInWorldCoord.y + LONG( dy * k_worldHeight );
- y = max( 0, min( y, k_worldHeight ) );
- while ( x < 0 ) {
- x += k_worldWidth;
- }
- while ( k_worldWidth < x ) {
- x -= k_worldWidth;
- }
-
- m_focusPointInWorldCoord.x = x;
- m_focusPointInWorldCoord.y = y;
-}
-
-
-void GVOWorldMap::setConfig( const GVOConfig& config )
-{
- m_positionUpdated = config.m_traceShipPositionEnabled;
- m_focusPointInWorldCoord = config.m_initialSurveyCoord;
- m_shipPointInWorld = config.m_initialSurveyCoord;
- m_previousDrawPointInWorld = m_shipPointInWorld;
- m_shipVectorLineEnabled = config.m_shipVectorLineEnabled;
-}
-
-
-void GVOWorldMap::setShipPosition( const POINT& worldCoord, bool isSyncCenter )
-{
- if ( isSyncCenter ) {
- m_focusPointInWorldCoord = worldCoord;
- }
- if ( m_shipPointInWorld.x != worldCoord.x
- || m_shipPointInWorld.y != worldCoord.y ) {
-
- m_positionUpdated = true;
- m_shipPointInWorld = worldCoord;
- }
-}
-
-
-bool GVOWorldMap::zoomIn()
-{
- double scale = m_viewScale;
- double step = k_scaleStep;
-
- scale = m_viewScale + step;
- if ( k_maxScale < scale ) {
- scale = k_maxScale;
- }
- if ( m_viewScale != scale ) {
- m_viewScale = scale;
- return true;
- }
- return false;
-}
-
-
-bool GVOWorldMap::zoomOut()
-{
- double scale = m_viewScale;
- double step = k_scaleStep;
-
- scale = m_viewScale - step;
- if ( scale < k_minScale ) {
- scale = k_minScale;
- }
- if ( m_viewScale != scale ) {
- m_viewScale = scale;
- return true;
- }
- return false;
-}
-
-
-void GVOWorldMap::drawMap( HDC hdc, const GVOShip& ship )
-{
- const SIZE mapSize = scaledMapSize();
- GVOImage scaledMapImage;
- GVOImage *mapImage = &m_mapImage;
-
- ::SaveDC( hdc );
- if ( m_viewScale < 1.0 ) {
- if ( 0.5 <= m_viewScale ) {
- mapImage = &m_mapImageMipmap1;
- }
- else {
- mapImage = &m_mapImageMipmap2;
- }
- }
- ::SetStretchBltMode( hdc, COLORONCOLOR );
-
- HDC hdcMem = ::CreateCompatibleDC( hdc );
- ::SaveDC( hdcMem );
-
- ::SelectObject( hdcMem, mapImage->bitmapHandle() );
-
- const POINT mapTopLeft = mapOriginInView();
-
- int xDrawOrigin, yDrawOrigin;
- xDrawOrigin = mapTopLeft.x;
- yDrawOrigin = mapTopLeft.y;
-
- if ( 0 < xDrawOrigin ) {
- xDrawOrigin = (xDrawOrigin % mapSize.cx) - mapSize.cx;
- }
- const int xInitial = xDrawOrigin; // \8d¶\92[\82Ì\95`\89æ\8aJ\8enx\8dÀ\95W
- int drawn = xInitial; // \95`\89æ\8dÏ\82Ý\8dÀ\95W
-
- // \90¢\8aE\92n\90}\82ð\89¡\82É\95À\82×\82Ä\95`\89æ
- // \81i\95`\89æ\8dÅ\93K\89»\82Í\8fÈ\97ª\81j
- while ( drawn < m_viewSize.cx ) {
- ::StretchBlt( hdc,
- xDrawOrigin, yDrawOrigin,
- mapSize.cx, mapSize.cy,
- hdcMem,
- 0, 0,
- mapImage->width(), mapImage->height(),
- SRCCOPY );
-
- xDrawOrigin += mapSize.cx;
- drawn += mapSize.cx;
- }
-
-
- const POINT shipPointOffset = drawOffsetFromWorldCoord( m_shipPointInWorld );
-
- // \90j\98H\97\\91ª\90ü\82ð\95`\89æ
- if ( ship.isVectorEnabled() && m_shipVectorLineEnabled ) {
- const int penWidth = max( 1, int(1 * m_viewScale) );
- HPEN courseLinePen = ::CreatePen( PS_SOLID, penWidth, RGB( 255, 0, 255 ) );
- HGDIOBJ oldPen = ::SelectObject( hdc, courseLinePen );
-
- const LONG k_lineLength = k_worldHeight;
- const POINT reachPointOffset = drawOffsetFromWorldCoord(
- ship.pointFromOriginWithLength( m_shipPointInWorld, k_lineLength )
- );
-
- // \8c©\82¦\82Ä\82é\92n\90}\89æ\91\9c\82Ì\95ª\82¾\82¯\95`\89æ\82·\82é
- drawn = xInitial;
- xDrawOrigin = xInitial;
- while ( drawn < m_viewSize.cx ) {
- const POINT shipPointInView = {
- xDrawOrigin + shipPointOffset.x,
- yDrawOrigin + shipPointOffset.y
- };
- const POINT reachPointInView = {
- xDrawOrigin + reachPointOffset.x,
- yDrawOrigin + reachPointOffset.y
- };
- ::MoveToEx( hdc, shipPointInView.x, shipPointInView.y, NULL );
- ::LineTo( hdc, reachPointInView.x, reachPointInView.y );
- xDrawOrigin += mapSize.cx;
- drawn += mapSize.cx;
- }
-
- ::SelectObject( hdc, oldPen );
- ::DeleteObject( courseLinePen );
- }
-
- // \8e©\91D\82Ì\88Ê\92u\82ð\95`\89æ
- const SIZE shipMarkSize = { 6, 6 };
- HBRUSH shipBrush = ::CreateSolidBrush( RGB( 51, 238, 153 ) );
- HGDIOBJ prevBrush = ::SelectObject( hdc, shipBrush );
-
- // \8c©\82¦\82Ä\82é\92n\90}\89æ\91\9c\82Ì\95ª\82¾\82¯\95`\89æ\82·\82é
- drawn = xInitial;
- xDrawOrigin = xInitial;
- while ( drawn < m_viewSize.cx ) {
- ::Ellipse( hdc,
- xDrawOrigin + shipPointOffset.x - shipMarkSize.cx / 2,
- yDrawOrigin + shipPointOffset.y - shipMarkSize.cy / 2,
- xDrawOrigin + shipPointOffset.x + shipMarkSize.cx,
- yDrawOrigin + shipPointOffset.y + shipMarkSize.cy );
-
- xDrawOrigin += mapSize.cx;
- drawn += mapSize.cx;
- }
- ::SelectObject( hdc, prevBrush );
- ::DeleteObject( shipBrush );
-
-
- ::RestoreDC( hdcMem, -1 );
- ::DeleteDC( hdcMem );
- ::RestoreDC( hdc, -1 );
-}
-
-
-void GVOWorldMap::updateShipRouteMap( HDC hdc )
-{
- // \88Ú\93®\82µ\82Ä\82¢\82È\82¯\82ê\82Î\89½\82à\82µ\82È\82¢
- if ( !m_positionUpdated ) {
- return;
- }
- // \88Ú\93®\82µ\82Ä\82¢\82Ä\82à\8dq\98H\82ð\8cq\82°\82È\82¢\82È\82ç\95`\89æ\82µ\82È\82¢
- if ( !m_linkRoute ) {
- m_previousDrawPointInWorld = m_shipPointInWorld;
- m_linkRoute = true;
- return;
- }
-
- const POINT& latestPoint = imageCoordFromWorldCoord( m_shipPointInWorld );
- const POINT& previousPoint = imageCoordFromWorldCoord( m_previousDrawPointInWorld );
-
- // \95`\89æ\8dÀ\95W\82ª\88ê\8f\8f\82È\82ç\89½\82à\82µ\82È\82¢
- if ( latestPoint.x == previousPoint.x
- && latestPoint.y == previousPoint.y ) {
- return;
- }
-
-
- // \8dÅ\90V\8dÀ\95W\82©\82ç\88ê\82Â\91O\82Ì\8dÀ\95W\82Ö\90ü\82ð\88ø\82
- // \90¢\8aE\82ð\8c×\82®\8fê\8d\87\82É\8dl\97¶\82ª\95K\97v\81B
- // \88Ú\93®\97Ê\82ª\88ê\92è\82ð\92´\82¦\82½\82ç\95`\89æ\8f\88\97\9d\82µ\82È\82¢\82æ\82¤\82É\82·\82é\82Ì\82ª\83X\83}\81[\83g\82©\82È
-
-
- // \90¢\8aE\82ð\8c×\82¢\82¾\82Æ\82Ý\82È\82·è\87\92l
- const int k_distanceThreshold = m_mapImage.width() / 2;
-
- const LONG xMin = min( latestPoint.x, previousPoint.x );
- const LONG xMax = max( latestPoint.x, previousPoint.x );
- const int xDistance = xMax - xMin;
-
-
- HDC hdcMem = ::CreateCompatibleDC( hdc );
- ::SaveDC( hdcMem );
-
- HPEN hpen = ::CreatePen( PS_SOLID, 1, RGB( 255, 255, 255 ) );
-
- ::SelectObject( hdcMem, m_mapImage.bitmapHandle() );
- ::SelectObject( hdcMem, hpen );
-
- if ( k_distanceThreshold < xDistance ) {
- if ( previousPoint.x < latestPoint.x ) { // \90¢\8aE\82ð\90¼\82É\8cü\82©\82Á\82Ä\8c×\82¢\82¾
- // \8d¶\82Ì\89æ\96Ê\8aO\82©\82ç\8cü\82©\82¤\90ü\82ð\95`\89æ
- LONG x3 = latestPoint.x - m_mapImage.width();
-
- ::MoveToEx( hdcMem, x3, latestPoint.y, NULL );
- ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
-
- // \89E\82Ì\89æ\96Ê\8aO\82É\8cü\82©\82¤\90ü\82ð\95`\89æ
- LONG x4 = previousPoint.x + m_mapImage.width();
- ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
- ::LineTo( hdcMem, x4, previousPoint.y );
- }
- else { // \90¢\8aE\82ð\93\8c\82É\8cü\82©\82Á\82Ä\8c×\82¢\82¾
- // \8d¶\82Ì\89æ\96Ê\8aO\82©\82ç\8cü\82©\82¤\90ü\82ð\95`\89æ
- LONG x3 = previousPoint.x - m_mapImage.width();
-
- ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
- ::LineTo( hdcMem, x3, previousPoint.y );
-
- // \89E\82Ì\89æ\96Ê\8aO\82É\8cü\82©\82¤\90ü\82ð\95`\89æ
- LONG x4 = latestPoint.x + m_mapImage.width();
- ::MoveToEx( hdcMem, x4, latestPoint.y, NULL );
- ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
- }
- }
- else {
- // \8c×\82ª\82È\82¢\95`\89æ
- ::MoveToEx( hdcMem, latestPoint.x, latestPoint.y, NULL );
- ::LineTo( hdcMem, previousPoint.x, previousPoint.y );
- }
-
-
- ::RestoreDC( hdcMem, -1 );
- ::DeleteDC( hdcMem );
- ::DeleteObject( hpen );
-
- m_previousDrawPointInWorld = m_shipPointInWorld;
-}
-
-
-void GVOWorldMap::clearShipRoute()
-{
- const std::wstring fileName = m_mapImage.fileName();
- m_mapImage.loadFromFile( fileName );
-}
-
-
-POINT GVOWorldMap::mapOriginInView()
-{
- const POINT viewCenter = viewCenterPoint();
- const SIZE mapSize = scaledMapSize();
- const POINT worldPosInView = drawOffsetFromWorldCoord( m_focusPointInWorldCoord );
-
- POINT mapTopLeft = {
- viewCenter.x - worldPosInView.x,
- viewCenter.y - worldPosInView.y
- };
- if ( m_viewSize.cx < mapSize.cx ) {
- while ( 0 < mapTopLeft.x ) {
- mapTopLeft.x -= mapSize.cx;
- }
- }
-
- return mapTopLeft;
-}
-
-
POINT GVOWorldMap::imageCoordFromWorldCoord( const POINT& worldCoord ) const
{
const double xNormPos = worldCoord.x / (double)k_worldWidth;
};
return worldPosInImage;
}
-
-POINT GVOWorldMap::drawOffsetFromWorldCoord( const POINT&worldCoord ) const
-{
- const POINT worldPosInImage = imageCoordFromWorldCoord( worldCoord );
- const POINT drawOffset = {
- LONG( worldPosInImage.x * m_viewScale ),
- LONG( worldPosInImage.y * m_viewScale )
- };
- return drawOffset;
-}
#pragma once
-#include <list>
+#include "GVONoncopyable.h"
#include "GVOImage.h"
-#include "GVOShip.h"
#include "GVOConfig.h"
+#include "GVOVector.h"
+
+#include "GVORenderer.h" // \88ê\8e\9e\92u\82«
//!@brief \90¢\8aE\92n\90}
//!@brief \95\\8e¦\8dÀ\95W\8cn\82Æ\90¢\8aE\8dÀ\95W\8cn\82Ì\95Ï\8a·\82È\82Ç\82ª\8ed\8e\96\81B
-class GVOWorldMap {
+class GVOWorldMap : private GVONoncopyable {
+ friend class GVORenderer;
public:
private:
- //typedef std::list<POINT> ShipRouteType;
- GVOWorldMap( const GVOWorldMap& );
- GVOWorldMap& operator=(const GVOWorldMap&);
-
-private:
GVOImage m_mapImage;
- GVOImage m_mapImageMipmap1;
- GVOImage m_mapImageMipmap2;
- POINT m_focusPointInWorldCoord;
- SIZE m_viewSize;
-
- double m_viewScale;
- double m_ratioForImageCoordFromWorldCoord; //!<@brief \90¢\8aE\8dÀ\95W\8cn\82©\82ç\89æ\91\9c\8dÀ\95W\8cn\82Ö\82Ì\95Ï\8a·\94ä\97¦
-
- POINT m_shipPointInWorld; //!<@brief \8e©\91D\82Ì\88Ê\92u
- bool m_positionUpdated; //!<@brief \8e©\91D\82Ì\88Ê\92u\8dX\90V\8fó\91Ô
- POINT m_previousDrawPointInWorld; //!<@brief \92¼\91O\82Ì\95`\89æ\88Ê\92u
- bool m_linkRoute; //!<@brief \8dq\98H\82ð\8cq\82°\82Ä\95`\89æ\82·\82é\83t\83\89\83O
- bool m_shipVectorLineEnabled; //!<@brief \90j\98H\95`\89æ\83t\83\89\83O
public:
- GVOWorldMap() :
- m_viewScale( 1.0 ),
- m_ratioForImageCoordFromWorldCoord(),
- m_positionUpdated(),
- m_linkRoute(),
- m_shipVectorLineEnabled( true )
+ GVOWorldMap()
{
}
virtual ~GVOWorldMap()
{
-
}
- bool loadFromFile( const GVOConfig& config );
- void setViewSize( const SIZE& viewSize );
- //!@note \83h\83\89\83b\83O\8f\88\97\9d\97p
- void offsetFocusInViewCoord( const POINT& offset );
-
- //!@brief \90Ý\92è\8fî\95ñ\82Å\8f\89\8aú\89»\82·\82é
- void setConfig( const GVOConfig& config );
+ bool loadFromFile( const std::wstring& fileNmee );
- //!@brief \8e©\91D\82Ì\88Ê\92u\82ð\90Ý\92è\82·\82é
- void setShipPosition( const POINT& worldCoord, bool isSyncCenter );
-
- bool zoomIn();
- bool zoomOut();
- inline double viewScale() const
- {
- return m_viewScale;
- }
- inline double viewScaleOrder() const
+ const GVOImage& image() const
{
- return 100;
+ return m_mapImage;
}
- //!@note \82Æ\82è\82 \82¦\82¸\95`\89æ\82à\82â\82ç\82µ\82Ä\82¨\82\81B
- void drawMap( HDC hdc, const GVOShip& ship );
- void updateShipRouteMap( HDC hdc );
- void clearShipRoute();
-
- void setVisibleShipRoute( bool visible )
- {
- m_shipVectorLineEnabled = visible;
- }
-private:
- inline POINT viewCenterPoint() const
- {
- POINT p = {
- m_viewSize.cx / 2,
- m_viewSize.cy / 2
- };
- return p;
- }
- inline SIZE scaledMapSize() const
- {
- SIZE size = {
- LONG( m_mapImage.width() * m_viewScale ),
- LONG( m_mapImage.height() * m_viewScale )
- };
- return size;
- }
- POINT mapOriginInView();
POINT imageCoordFromWorldCoord( const POINT& worldCoord ) const;
- POINT drawOffsetFromWorldCoord( const POINT&worldCoord ) const;
};
#define IDM_TOGGLE_KEEP_FOREGROUND 204
#define IDM_TOGGLE_SPEED_METER 205
#define IDM_TOGGLE_VECTOR_LINE 206
+#define IDM_TOGGLE_DEBUG_AUTO_CRUISE 207
+#define IDM_SAME_SCALE 208
+#define IDM_ZOOM_IN 209
+#define IDM_ZOOM_OUT 210
#ifndef IDC_STATIC
#define IDC_STATIC -1
#define _SECURE_SCL 0
#endif
#define WIN32_LEAN_AND_MEAN // Windows \83w\83b\83_\81[\82©\82ç\8eg\97p\82³\82ê\82Ä\82¢\82È\82¢\95\94\95ª\82ð\8f\9c\8aO\82µ\82Ü\82·\81B
+#define _NO_MIN_MAX
+#include <algorithm>
+using std::min;
+using std::max;
// Windows \83w\83b\83_\81[ \83t\83@\83C\83\8b:
#include <windows.h>
#include <cstdint>
#include <numeric>
+#include <memory>
+#include <vector>
+#include <map>
+#include <set>
+#include <deque>