OSDN Git Service

OpenGLによる描画に実装を切り替え。
[gvonavish/GVONavish.git] / GVONavish / GVONavish / GVOGameProcess.cpp
1 #include "stdafx.h"
2 #include <process.h>
3 #include "GVONavish.h"
4 #include "GVOGameProcess.h"
5 #include "GVOWorldMap.h"
6 #include "GVOSurveyCoordExtractor.h"
7
8
9 // \89æ\91\9c\89ð\90Í\83f\83o\83b\83O\97p\81BGVOGameProcess
10 //#define GVO_ANALYZE_DEBUG
11
12 extern HWND g_hwndMain;
13 extern HDC g_hdcMain;
14
15 namespace {
16 #ifdef GVO_ANALYZE_DEBUG
17         LPCWSTR const k_debugImageFileName = L"..\\debug.png";
18 #endif
19
20 #ifndef NDEBUG
21         // \83f\83o\83b\83O\97p\8e©\93®\8dq\8ds\95Ï\90\94
22         static double s_xDebugAutoCruise;
23         static double s_yDebugAutoCruise;
24         static double s_debugAutoCruiseAngle = 0;
25         static bool s_debugAutoCruiseEnabled = false;
26         static double s_debugAutoCruiseVelocity = 0;
27         static uint32_t s_debugAutoCruiseTurnInterval;
28         static double s_debugAutoCruiseTurnAngle;
29 #endif
30
31         LPWSTR const k_gvoWindowClassName = L"Greate Voyages Online Game MainFrame";
32         LPWSTR const k_gvoWindowCaption = L"\91å\8dq\8aC\8e\9e\91ã Online";
33
34         const POINT k_surveyCoordOffsetFromRightBottom = { 70, 273 };
35         const SIZE k_surveyCoordSize = { 60, 11 };
36 };
37
38
39
40 void GVOGameProcess::clear()
41 {
42         if ( m_process ) {
43                 ::CloseHandle( m_process );
44                 m_process = NULL;
45         }
46         m_window = NULL;
47 }
48
49
50 void GVOGameProcess::setup( const GVOConfig& config )
51 {
52         m_surveyCoord = config.m_initialSurveyCoord;
53         m_ship.setInitialSurveyCoord( config.m_initialSurveyCoord );
54         m_pollingInterval = config.m_pollingInterval;
55 #ifndef NDEBUG
56         s_xDebugAutoCruise = config.m_initialSurveyCoord.x;
57         s_yDebugAutoCruise = config.m_initialSurveyCoord.y;
58         s_debugAutoCruiseEnabled = config.m_debugAutoCruiseEnabled;
59         s_debugAutoCruiseVelocity = config.m_debugAutoCruiseVelocity;
60         s_debugAutoCruiseTurnInterval = config.m_debugAutoCruiseTurnInterval;
61         s_debugAutoCruiseTurnAngle = config.m_debugAutoCruiseTurnAngle;
62 #endif
63
64         m_pollingTimerEventID = ::timeSetEvent( m_pollingInterval, 1, LPTIMECALLBACK( m_pollingTimerEvent ), 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET );
65         m_threadQuitSignal = ::CreateEvent( NULL, TRUE, FALSE, NULL );
66         m_workerThread = (HANDLE)::_beginthreadex( NULL, 0, threadMainThunk, this, 0, NULL );
67 }
68
69
70 void GVOGameProcess::teardown()
71 {
72         if ( m_workerThread ) {
73                 ::SetEvent( m_threadQuitSignal );
74                 ::WaitForSingleObject( m_workerThread, INFINITE );
75                 ::CloseHandle( m_workerThread );
76                 ::CloseHandle( m_threadQuitSignal );
77                 m_threadQuitSignal = NULL;
78                 m_workerThread = NULL;
79         }
80         if ( m_pollingTimerEventID ) {
81                 ::timeKillEvent( m_pollingTimerEventID );
82                 m_pollingTimerEventID = 0;
83         }
84 }
85
86
87 #ifndef NDEBUG
88 void GVOGameProcess::enableDebugAutoCruise( bool enabled )
89 {
90         s_debugAutoCruiseEnabled = enabled;
91 }
92 #endif
93
94 bool GVOGameProcess::updateState()
95 {
96         GVOGameStatus status;
97
98
99 #ifdef GVO_ANALYZE_DEBUG
100         {
101                 static bool done = false;
102                 if ( !done ) {
103                         done = true;
104                 }
105                 else {
106                         return false;
107                 }
108
109                 static GVOImage debugImage;
110                 if ( !debugImage.bitmapHandle() ) {
111                         if ( !debugImage.loadFromFile( ::g_makeFullPath( k_debugImageFileName ) ) ) {
112                                 ::MessageBox( NULL, L"\83f\83o\83b\83O\83C\83\81\81[\83W\82ª\82È\82¢\82æ", L"\82¦\82ç\81[", MB_ICONERROR );
113                                 exit( 0 );
114                         }
115                 }
116                 HDC hdc = ::GetWindowDC( ::GetDesktopWindow() );
117                 HDC hdcMem = ::CreateCompatibleDC( hdc );
118                 ::SaveDC( hdcMem );
119                 ::SelectObject( hdcMem, debugImage.bitmapHandle() );
120                 grabImage( hdcMem, POINT(), debugImage.size() );
121
122                 ::RestoreDC( hdcMem, -1 );
123                 ::DeleteDC( hdcMem );
124                 ::ReleaseDC( NULL, hdc );
125
126                 updateSurveyCoord();
127                 return true;
128         }
129 #endif
130
131 #ifndef NDEBUG
132         if ( s_debugAutoCruiseEnabled ) {
133                 static bool isRandInitialized = false;
134                 if ( !isRandInitialized ) {
135                         srand( ::timeGetTime() );
136                         isRandInitialized = true;
137                 }
138
139                 const double rad = ((s_debugAutoCruiseAngle)* M_PI) / 180;
140                 const double vx = ::cos( rad );
141                 const double vy = ::sin( rad );
142
143                 s_xDebugAutoCruise += vx * s_debugAutoCruiseVelocity;
144                 s_yDebugAutoCruise += vy * s_debugAutoCruiseVelocity;
145
146                 static DWORD tick = ::timeGetTime();
147                 static DWORD count = 0;
148                 if ( (tick + s_debugAutoCruiseTurnInterval) < ::timeGetTime() ) {
149                         if ( 10 < (++count) ) {
150                                 count = 0;
151                                 s_debugAutoCruiseAngle += 90 + (LONG( rand() / double( RAND_MAX ) * 90 ) & ~0x1);
152                         }
153                         else {
154                                 s_debugAutoCruiseAngle += (rand() & 1) ? s_debugAutoCruiseTurnAngle : -s_debugAutoCruiseTurnAngle;
155                         }
156                         tick = ::timeGetTime();
157                 }
158                 s_debugAutoCruiseAngle = fmod( ::fabs( s_debugAutoCruiseAngle ), 360 );
159
160                 if ( s_xDebugAutoCruise < 0 ) {
161                         s_xDebugAutoCruise += k_worldWidth;
162                 }
163                 if ( s_yDebugAutoCruise < 0 ) {
164                         s_yDebugAutoCruise += k_worldHeight;
165                 }
166                 s_xDebugAutoCruise = fmod( s_xDebugAutoCruise, (double)k_worldWidth );
167                 s_yDebugAutoCruise = fmod( s_yDebugAutoCruise, (double)k_worldHeight );
168
169                 //// \92n\90}\82ð\8c×\82®\8f\88\97\9d\82Ì\8am\94F\97p\83f\83o\83b\83O\83R\81[\83h
170                 //if ( 100 <= s_xDebugAutoCruise && s_xDebugAutoCruise <= (GVOWorldMap::k_worldWidth - 100) ) {
171                 //      s_xDebugAutoCruise = 0;
172                 //}
173
174                 m_surveyCoord.x = LONG( s_xDebugAutoCruise );
175                 m_surveyCoord.y = LONG( s_yDebugAutoCruise );
176                 uint32_t timeStamp = ::timeGetTime();
177                 m_speedMeter.updateVelocity( m_ship.velocity(), timeStamp );
178                 m_ship.updateWithSurveyCoord( m_surveyCoord, timeStamp );
179
180                 status.m_surveyCoord = m_surveyCoord;
181                 status.m_shipVector = m_ship.vector();
182                 status.m_shipVelocity = m_speedMeter.velocity();
183                 status.m_timeStamp = timeStamp;
184
185                 ::EnterCriticalSection( &m_lock );
186                 m_statusArray.push_back( status );
187                 ::SetEvent( m_dataReadyEvent );
188                 ::LeaveCriticalSection( &m_lock );
189                 return true;
190         }
191 #endif
192
193         if ( !m_window ) {
194                 m_window = ::FindWindow( k_gvoWindowClassName, k_gvoWindowCaption );
195         }
196         if ( m_window ) {
197                 if ( !m_process ) {
198                         DWORD pid = 0;
199                         ::GetWindowThreadProcessId( m_window, &pid );
200                         m_process = ::OpenProcess( SYNCHRONIZE, FALSE, pid );
201                 }
202
203                 RECT rc;
204                 POINT clientOrg = { 0 };
205                 ::ClientToScreen( m_window, &clientOrg );
206                 ::GetClientRect( m_window, &rc );
207                 SIZE size;
208                 size.cx = rc.right;
209                 size.cy = rc.bottom;
210
211                 HDC hdc = ::GetDC( ::GetDesktopWindow() );
212                 if ( !hdc ) {
213                         return false;
214                 }
215                 grabImage( hdc, clientOrg, size );
216                 ::ReleaseDC( ::GetDesktopWindow(), hdc );
217                 m_timeStamp = ::timeGetTime();
218
219                 if ( !updateSurveyCoord() ) {
220                         return false;
221                 }
222
223                 m_speedMeter.updateVelocity( m_ship.velocity(), m_timeStamp );
224                 m_ship.updateWithSurveyCoord( m_surveyCoord, m_timeStamp );
225
226                 status.m_surveyCoord = m_surveyCoord;
227                 status.m_shipVector = m_ship.vector();
228                 status.m_shipVelocity = m_speedMeter.velocity();
229                 status.m_timeStamp = m_timeStamp;
230
231                 ::EnterCriticalSection( &m_lock );
232                 m_statusArray.push_back( status );
233                 ::SetEvent( m_dataReadyEvent );
234                 ::LeaveCriticalSection( &m_lock );
235
236                 return true;
237         }
238         return false;
239 }
240
241 std::vector<GVOGameStatus> GVOGameProcess::getState()
242 {
243         std::vector<GVOGameStatus> statusArray;
244
245         ::EnterCriticalSection( &m_lock );
246         m_statusArray.swap( statusArray );
247         ::ResetEvent( m_dataReadyEvent );
248         ::LeaveCriticalSection( &m_lock );
249
250         return statusArray;
251 }
252
253
254 UINT CALLBACK GVOGameProcess::threadMainThunk( LPVOID arg )
255 {
256         GVOGameProcess *self = reinterpret_cast<GVOGameProcess *>(arg);
257         self->threadMain();
258         return 0;
259 }
260
261
262 void GVOGameProcess::threadMain()
263 {
264         std::vector<HANDLE> signals;
265         signals.push_back( m_threadQuitSignal );
266         signals.push_back( m_pollingTimerEvent );
267
268         for ( ; ; ) {
269                 const DWORD ret = ::WaitForMultipleObjects( signals.size(), &signals[0], FALSE, INFINITE );
270                 if ( signals.size() <= ret ) {
271                         exit( -1 );
272                 }
273                 HANDLE const active = signals[ret];
274                 if ( active == m_threadQuitSignal ) {
275                         break;
276                 }
277
278                 if ( active == m_pollingTimerEvent ) {
279                         ::ResetEvent( m_pollingTimerEvent );
280                         
281                         updateState();
282
283                         continue;
284                 }
285         }
286 }
287
288
289 void GVOGameProcess::grabImage( HDC hdc, const POINT& offset, const SIZE& size )
290 {
291         if ( !m_surveyCoordImage.bitmapHandle() ) {
292                 m_surveyCoordImage.createDIBImage( k_surveyCoordSize );
293         }
294
295         HDC hdcMem = ::CreateCompatibleDC( hdc );
296         ::SaveDC( hdcMem );
297
298         const int leftEdge = offset.x;
299         const int rightEdge = leftEdge + size.cx;
300         const int topEdge = offset.y;
301         const int bottomEdge = offset.y + size.cy;
302
303         // \91ª\97Ê\8dÀ\95W\83L\83\83\83v\83`\83\83
304         const int xSurvey = rightEdge - k_surveyCoordOffsetFromRightBottom.x;
305         const int ySurvey = bottomEdge - k_surveyCoordOffsetFromRightBottom.y;
306         ::SelectObject( hdcMem, m_surveyCoordImage.bitmapHandle() );
307         ::BitBlt( hdcMem, 0, 0, k_surveyCoordSize.cx, k_surveyCoordSize.cy, hdc, xSurvey, ySurvey, SRCCOPY );
308         ::GdiFlush();
309
310         ::RestoreDC( hdcMem, -1 );
311         ::DeleteDC( hdcMem );
312 }
313
314
315 bool GVOGameProcess::updateSurveyCoord()
316 {
317         bool succeeded = false;
318         GVOSurveyCoordExtractor extractor( m_surveyCoordImage );
319
320         const std::vector<int>& values = extractor.extractNumbers();
321         if ( values.size() == 2 ) {
322                 m_surveyCoord.x = values[0];
323                 m_surveyCoord.y = values[1];
324                 succeeded = true;
325         }
326         return succeeded;
327 }