OSDN Git Service

OpenGLによる描画に実装を切り替え。
[gvonavish/GVONavish.git] / GVONavish / GVONavish / GVORenderer.cpp
1 #include "stdafx.h"
2 #include "GVORenderer.h"
3 #include "GVOWorldMap.h"
4 #include "GVOConfig.h"
5 #include "GVOTexture.h"
6 #include "GVOShipRouteList.h"
7 #include "GVOShipRoute.h"
8
9
10
11 namespace {
12         const double k_scaleStep = 0.125;       // 12.5%
13         const double k_minScale = 0.125;        // 12.5%
14         const double k_maxScale = 4.00;         // 400%
15
16         // Google\90æ\90\9eH\82­\81u\92n\8b\85\82Ì\8aO\8eü\82Í40,075km\81v\81u1\83m\83b\83g\82Í1.85200km\81v
17         // 1\90¢\8aE\8dÀ\95W\82Í40,075km/16384points
18         // \8eÀ\8e\9e\8aÔ1\95b\82Å\83Q\81[\83\80\93à0.4\8e\9e\8aÔ
19         //
20         // \92n\8b\85\8aO\8eü\82ð\90Ô\93¹\94¼\8ca\82©\82ç\8eZ\8fo\82·\82é\81B
21         // \90Ô\93¹\94¼\8ca\82Í6378.137\82È\82Ì\82Å\8aO\8eü\82Í2*M_PI_*6378.137
22         inline double s_velocityByKnot( const double velocity )
23         {
24                 static const double k_knotFactor = (2 * M_PI * 6378.137) / 16384.0 / 0.4 / 1.852;
25                 return velocity * k_knotFactor;
26         }
27 }
28
29
30 void GVORenderer::setup( const GVOConfig * config, HDC hdcPrimary, const GVOWorldMap * worldMap )
31 {
32         m_hdcPrimary = hdcPrimary;
33         setConfig( config );
34         setupGL();
35         setWorldMap( worldMap );
36 }
37
38
39 void GVORenderer::teardown()
40 {
41         delete m_worldMapTexture;
42         m_worldMapTexture = NULL;
43
44         ::wglMakeCurrent( NULL, NULL );
45         ::wglDeleteContext( m_hglrc );
46         m_hglrc = NULL;
47         m_hdcPrimary = NULL;
48 }
49
50
51 void GVORenderer::setConfig( const GVOConfig * config )
52 {
53         m_focusPointInWorldCoord = config->m_initialSurveyCoord;
54         m_shipPointInWorld.x = -1;
55         m_shipPointInWorld.y = -1;
56         m_shipVectorLineEnabled = config->m_shipVectorLineEnabled;
57         m_speedMeterEnabled = config->m_speedMeterEnabled;
58         m_traceShipEnabled = config->m_traceShipPositionEnabled;
59 }
60
61
62 void GVORenderer::setupGL()
63 {
64         PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd) };
65         pfd.nVersion = 1;
66         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE;
67         pfd.iPixelType = PFD_TYPE_RGBA;
68         pfd.cColorBits = 24;
69         pfd.cAlphaBits = 8;
70         pfd.cDepthBits = 16;
71         pfd.iLayerType = PFD_MAIN_PLANE;
72         ::SetPixelFormat( m_hdcPrimary, ::ChoosePixelFormat( m_hdcPrimary, &pfd ), &pfd );
73         m_hglrc = ::wglCreateContext( m_hdcPrimary );
74         ::wglMakeCurrent( m_hdcPrimary, m_hglrc );
75         ::glDisable( GL_DEPTH_TEST );
76         ::glDisable( GL_LIGHTING );
77         ::glEnable( GL_CULL_FACE );
78         ::glCullFace( GL_BACK );
79 }
80
81
82 void GVORenderer::setWorldMap( const GVOWorldMap * worldMap )
83 {
84         m_worldMap = worldMap;
85         m_worldMapTexture = new GVOTexture();
86         m_worldMapTexture->setImage( &worldMap->image() );
87 }
88
89
90 void GVORenderer::setViewSize( const SIZE& viewSize )
91 {
92         m_viewSize = viewSize;
93         ::wglMakeCurrent( m_hdcPrimary, m_hglrc );
94         ::glMatrixMode( GL_PROJECTION );
95         ::glLoadIdentity();
96         ::glViewport( 0, 0, m_viewSize.cx, m_viewSize.cy );
97         ::gluOrtho2D( 0, m_viewSize.cx, m_viewSize.cy, 0 );
98 }
99
100
101 SIZE GVORenderer::scaledMapSize() const
102 {
103         SIZE size = {
104                 LONG( m_worldMap->image().width() * m_viewScale ),
105                 LONG( m_worldMap->image().height() * m_viewScale )
106         };
107         return size;
108 }
109
110
111 POINT GVORenderer::mapOriginInView() const
112 {
113         const POINT viewCenter = viewCenterPoint();
114         const SIZE mapSize = scaledMapSize();
115         const POINT worldPosInView = drawOffsetFromWorldCoord( m_focusPointInWorldCoord );
116
117         POINT mapTopLeft = {
118                 viewCenter.x - worldPosInView.x,
119                 viewCenter.y - worldPosInView.y
120         };
121         if ( m_viewSize.cx < mapSize.cx ) {
122                 while ( 0 < mapTopLeft.x ) {
123                         mapTopLeft.x -= mapSize.cx;
124                 }
125         }
126
127         return mapTopLeft;
128 }
129
130
131 void GVORenderer::offsetFocusInViewCoord( const POINT& offset )
132 {
133         const double dx = ((double)offset.x / m_viewScale) / m_worldMap->image().width();
134         const double dy = ((double)offset.y / m_viewScale) / m_worldMap->image().height();
135
136         LONG x = m_focusPointInWorldCoord.x + LONG( dx * k_worldWidth );
137         LONG y = m_focusPointInWorldCoord.y + LONG( dy * k_worldHeight );
138         y = std::max<LONG>( 0, std::min<LONG>( y, k_worldHeight ) );
139         while ( x < 0 ) {
140                 x += k_worldWidth;
141         }
142         while ( k_worldWidth < x ) {
143                 x -= k_worldWidth;
144         }
145
146         m_focusPointInWorldCoord.x = x;
147         m_focusPointInWorldCoord.y = y;
148 }
149
150
151 bool GVORenderer::zoomIn()
152 {
153         double scale = m_viewScale;
154         double step = k_scaleStep;
155
156         scale = m_viewScale + step;
157         if ( k_maxScale < scale ) {
158                 scale = k_maxScale;
159         }
160         if ( m_viewScale != scale ) {
161                 m_viewScale = scale;
162                 return true;
163         }
164         return false;
165 }
166
167
168 bool GVORenderer::zoomOut()
169 {
170         double scale = m_viewScale;
171         double step = k_scaleStep;
172
173         scale = m_viewScale - step;
174         if ( scale < k_minScale ) {
175                 scale = k_minScale;
176         }
177         if ( m_viewScale != scale ) {
178                 m_viewScale = scale;
179                 return true;
180         }
181         return false;
182 }
183
184
185 void GVORenderer::resetViewScale()
186 {
187         m_viewScale = 1.0;
188 }
189
190
191 POINT GVORenderer::drawOffsetFromWorldCoord( const POINT&worldCoord ) const
192 {
193         const POINT worldPosInImage = m_worldMap->imageCoordFromWorldCoord( worldCoord );
194         const POINT drawOffset = {
195                 LONG( worldPosInImage.x * m_viewScale ),
196                 LONG( worldPosInImage.y * m_viewScale )
197         };
198         return drawOffset;
199 }
200
201
202 void GVORenderer::setShipPositionInWorld( const POINT& shipPositionInWorld )
203 {
204         if ( m_traceShipEnabled ) {
205                 m_focusPointInWorldCoord = shipPositionInWorld;
206         }
207         m_shipPointInWorld = shipPositionInWorld;
208 }
209
210
211 void GVORenderer::render( const GVOVector& shipVector, double shipVelocity, const GVOShipRouteList * shipRouteList )
212 {
213         ::wglMakeCurrent( m_hdcPrimary, m_hglrc );
214         ::glClearColor( 0.2f, 0.2f, 0.3f, 0.0f );
215         ::glClear( GL_COLOR_BUFFER_BIT );
216
217         renderMap( shipVector, shipRouteList );
218
219         if ( m_speedMeterEnabled ) {
220                 renderSpeedMeter( shipVelocity );
221         }
222
223         ::glFlush();
224         ::SwapBuffers( m_hdcPrimary );
225         ::wglMakeCurrent( NULL, NULL );
226 }
227
228
229 void GVORenderer::renderMap( const GVOVector& shipVector, const GVOShipRouteList * shipRouteList )
230 {
231         _ASSERT( m_worldMapTexture != NULL );
232
233         const SIZE mapSize = scaledMapSize();
234
235         const POINT mapTopLeft = mapOriginInView();
236         int xDrawOrigin, yDrawOrigin;
237         xDrawOrigin = mapTopLeft.x;
238         yDrawOrigin = mapTopLeft.y;
239         if ( 0 < xDrawOrigin ) {
240                 xDrawOrigin = (xDrawOrigin % mapSize.cx) - mapSize.cx;
241         }
242         const int xInitial = xDrawOrigin;       // \8d\92[\82Ì\95`\89æ\8aJ\8enx\8dÀ\95W
243         int drawn = xInitial;
244
245         // \90¢\8aE\92n\90}\82ð\89¡\82É\95À\82×\82Ä\95`\89æ
246         // \81i\95`\89æ\8dÅ\93K\89»\82Í\8fÈ\97ª\81j
247         ::glMatrixMode( GL_MODELVIEW );
248         ::glLoadIdentity();
249         ::glTranslatef( (float)xDrawOrigin, (float)yDrawOrigin, 0 );
250         while ( drawn < m_viewSize.cx ) {
251                 // \92n\90}\82ð1\96\87\95`\89æ
252                 m_worldMapTexture->bind();
253                 renderTexture( (float)mapSize.cx, (float)mapSize.cy );
254                 m_worldMapTexture->unbind();
255
256                 // \8fI\92\85\82µ\82Ä\82¢\82È\82¢\8dq\98H\82ð1\96\87\95ª\95`\89æ
257                 renderShipRouteList( mapSize.cx, mapSize.cy, shipRouteList );
258
259                 xDrawOrigin += mapSize.cx;
260                 drawn += mapSize.cx;
261                 ::glTranslatef( (float)mapSize.cx, 0.0f, 0.0f );
262         }
263
264
265         // \95s\90³\82È\8e©\91D\88Ê\92u\82È\82ç\82±\82ê\88È\8d~\82Ì\95`\89æ\82Í\82µ\82È\82¢\81B
266         if ( m_shipPointInWorld.x < 0 || m_shipPointInWorld.y < 0 ) {
267                 return;
268         }
269
270         const POINT shipPointOffset = drawOffsetFromWorldCoord( m_shipPointInWorld );
271
272         // \90j\98H\97\\91ª\90ü\82ð\95`\89æ
273         if ( shipVector.length() != 0.0 && m_shipVectorLineEnabled ) {
274                 const float lineWidth = max<float>( 1, float( 1 * m_viewScale ) );
275                 ::glLineWidth( lineWidth );
276                 ::glColor3f( 255, 0, 255 );
277
278                 const LONG k_lineLength = k_worldHeight;
279                 const POINT reachPointOffset = drawOffsetFromWorldCoord(
280                         shipVector.pointFromOriginWithLength( m_shipPointInWorld, k_lineLength )
281                         );
282
283                 // \8c©\82¦\82Ä\82é\92n\90}\89æ\91\9c\82Ì\95ª\82¾\82¯\95`\89æ\82·\82é
284                 drawn = xInitial;
285                 xDrawOrigin = xInitial;
286                 ::glMatrixMode( GL_MODELVIEW );
287                 ::glLoadIdentity();
288                 ::glTranslatef( (float)xDrawOrigin, (float)yDrawOrigin, 0 );
289                 while ( drawn < m_viewSize.cx ) {
290                         ::glBegin( GL_LINES );
291                         ::glVertex2i( shipPointOffset.x, shipPointOffset.y );
292                         ::glVertex2i( reachPointOffset.x, reachPointOffset.y );
293                         ::glEnd();
294
295                         xDrawOrigin += mapSize.cx;
296                         drawn += mapSize.cx;
297                         ::glTranslatef( (float)mapSize.cx, 0.0f, 0.0f );
298                 }
299         }
300
301
302         // \8e©\91D\82Ì\88Ê\92u\82ð\95`\89æ
303         const float shipMarkSize = 6.0f;
304
305         // \8c©\82¦\82Ä\82é\92n\90}\89æ\91\9c\82Ì\95ª\82¾\82¯\95`\89æ\82·\82é
306         drawn = xInitial;
307         xDrawOrigin = xInitial;
308         ::glMatrixMode( GL_MODELVIEW );
309         ::glLoadIdentity();
310         ::glLineWidth( 1.0f );
311         ::glTranslatef( (float)xDrawOrigin, (float)yDrawOrigin, 0 );
312         while ( drawn < m_viewSize.cx ) {
313                 const float x = shipPointOffset.x - shipMarkSize / 2.0f;
314                 const float y = shipPointOffset.y - shipMarkSize / 2.0f;
315
316                 ::glColor3f( 51.0f / 255.0f, 238.0f / 255.0f, 153.0f / 255.0f );
317                 ::glBegin( GL_QUADS );
318                 ::glVertex2f( x, y );
319                 ::glVertex2f( x, y + shipMarkSize );
320                 ::glVertex2f( x + shipMarkSize, y + shipMarkSize );
321                 ::glVertex2f( x + shipMarkSize, y );
322                 ::glEnd();
323
324                 ::glColor3f( 0.0f, 0.0f, 0.0f );
325                 ::glBegin( GL_LINES );
326                 ::glVertex2f( x, y );
327                 ::glVertex2f( x, y + shipMarkSize );
328                 ::glVertex2f( x + shipMarkSize, y + shipMarkSize );
329                 ::glVertex2f( x + shipMarkSize, y );
330                 ::glEnd();
331
332                 xDrawOrigin += mapSize.cx;
333                 drawn += mapSize.cx;
334                 ::glTranslatef( (float)mapSize.cx, 0.0f, 0.0f );
335         }
336 }
337
338
339 void GVORenderer::renderShipRouteList( int width, int height, const GVOShipRouteList * shipRouteList )
340 {
341         _ASSERT( 0 <= width );
342         _ASSERT( 0 <= height );
343         _ASSERT(shipRouteList != NULL);
344
345         const float lineWidth = max<float>( 1, float( 1 * m_viewScale ) );
346         ::glLineWidth( lineWidth );
347         // \8dÅ\90V\8dq\98H\88È\8aO\82ð\94¼\93§\96¾\82Å\95`\89æ
348         ::glEnable( GL_BLEND );
349         ::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
350         ::glColor4f( 1.0f, 1.0f, 1.0f, 0.5f );
351
352         for ( const GVOShipRoute *route : shipRouteList->getList() ) {
353                 // \8dÅ\90V\8dq\98H\82¾\82¯\82ð\95s\93§\96¾\82Å\95`\89æ
354                 if ( shipRouteList->getList().back() == route ) {
355                         ::glColor3f( 1.0f, 1.0f, 1.0f );
356                         ::glDisable( GL_BLEND );
357                 }
358
359                 for ( const GVOShipRoute::Line & line : route->getLines() ) {
360                         if ( line.size() < 2 ) {
361                                 // 2\93_\96¢\96\9e\82Å\82Í\90ü\82ð\88ø\82¯\82È\82¢
362                                 continue;
363                         }
364                         ::glBegin( GL_LINE_STRIP );
365                         for ( const GVONormalizedPoint & point : line ) {
366                                 const float x = point.x() * width;
367                                 const float y = point.y() * height;
368                                 ::glVertex2f( x, y );
369                         }
370                         ::glEnd();
371                 }
372         }
373 }
374
375
376 void GVORenderer::renderSpeedMeter( double shipVelocity )
377 {
378         // THE\8eè\94²\82«\95\8e\9a\83|\83\8a\83S\83\93\8dì\90¬
379
380         HDC hdcMem = ::CreateCompatibleDC( m_hdcPrimary );
381         ::SaveDC( hdcMem );
382
383         const double velocity = s_velocityByKnot( shipVelocity );
384         wchar_t buf[4096] = { 0 };
385         swprintf( buf, _countof( buf ), L"%.2f kt", velocity );
386
387         RECT rc = { 0 };
388         ::DrawText( hdcMem, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP | DT_CALCRECT );
389         const int width = rc.right - rc.left;
390         const int stride = width + (4 - width % 4) % 4;
391         const int height = rc.bottom - rc.top;
392         GVOImage workImage;
393         workImage.createDIBImage( stride, height );
394         ::SelectObject( hdcMem, workImage.bitmapHandle() );
395         ::DrawText( hdcMem, buf, -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_TOP );
396         ::RestoreDC( hdcMem, -1 );
397         ::DeleteDC( hdcMem );
398
399         GVOTexture workTexture;
400         workTexture.setImage( &workImage );
401
402         ::glMatrixMode( GL_MODELVIEW );
403         ::glLoadIdentity();
404         workTexture.bind();
405         renderTexture( float( m_viewSize.cx - stride ), 0.0f, (float)stride, (float)height );
406         workTexture.unbind();
407 }
408
409
410 void GVORenderer::renderTexture( float w, float h )
411 {
412         renderTexture( 0, 0, w, h );
413 }
414
415 void GVORenderer::renderTexture( float x, float y, float w, float h )
416 {
417         ::glBegin( GL_QUADS );
418
419         ::glTexCoord2d( 0, 0 );
420         ::glVertex2d( x, y );
421
422         ::glTexCoord2d( 0, 1 );
423         ::glVertex2d( x, y + h );
424
425         ::glTexCoord2d( 1, 1 );
426         ::glVertex2d( x + w, y + h );
427
428         ::glTexCoord2d( 1, 0 );
429         ::glVertex2d( x + w, y );
430
431         ::glEnd();
432 }