OpenCPN Partial API docs
Loading...
Searching...
No Matches
compass.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: OpenCPN Main wxWidgets Program
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 ***************************************************************************
25 *
26 */
27#include <wx/wxprec.h>
28#ifndef WX_PRECOMP
29#include <wx/wx.h>
30#endif // precompiled headers
31#include "config.h"
32#include "model/ocpn_types.h"
33#include "model/own_ship.h"
34#include "compass.h"
35#include "chcanv.h"
36#include "styles.h"
37
38#include "glChartCanvas.h"
39#include "ocpn_frame.h" // FIXME (dave) colorschemes
40
41extern ocpnStyle::StyleManager* g_StyleManager;
42extern bool g_bSatValid;
43extern int g_SatsInView;
44extern bool g_bopengl;
45extern bool g_btenhertz;
46
47#ifndef GL_RGBA8
48#define GL_RGBA8 0x8058
49#endif
50
51ocpnCompass::ocpnCompass(ChartCanvas* parent, bool bShowGPS) {
52 m_parent = parent;
53 m_bshowGPS = bShowGPS;
54
55 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
56 _img_compass = style->GetIcon(_T("CompassRose"));
57 _img_gpsRed = style->GetIcon(_T("gpsRed"));
58
59 m_rose_angle = -999; // force a refresh when first used
60
61 m_pStatBoxToolStaticBmp = NULL;
62
63 m_rect =
64 wxRect(style->GetCompassXOffset(), style->GetCompassYOffset(),
65 _img_compass.GetWidth() + _img_gpsRed.GetWidth() +
66 style->GetCompassLeftMargin() * 2 + style->GetToolSeparation(),
67 _img_compass.GetHeight() + style->GetCompassTopMargin() +
68 style->GetCompassBottomMargin());
69
70#ifdef ocpnUSE_GL
71 m_texobj = 0;
72#endif
73 m_texOK = false;
74
75 m_scale = 1.0;
76 m_cs = GLOBAL_COLOR_SCHEME_RGB;
77}
78
79ocpnCompass::~ocpnCompass() {
80#ifdef ocpnUSE_GL
81 if (m_texobj) {
82 glDeleteTextures(1, &m_texobj);
83 m_texobj = 0;
84 }
85#endif
86
87 delete m_pStatBoxToolStaticBmp;
88}
89
90void ocpnCompass::Paint(ocpnDC& dc) {
91 if (m_shown && m_StatBmp.IsOk()) {
92#if defined(ocpnUSE_GLES) || defined(ocpnUSE_GL)
93 if (g_bopengl && !m_texobj) {
94 // The glContext is known active here,
95 // so safe to create a texture.
96 glGenTextures(1, &m_texobj);
97 CreateTexture();
98 }
99
100 if (g_bopengl && m_texobj /*&& m_texOK*/) {
101 glBindTexture(GL_TEXTURE_2D, m_texobj);
102 glEnable(GL_TEXTURE_2D);
103
104#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
105 float coords[8];
106 float uv[8];
107
108 // normal uv, normalized to POT
109 uv[0] = 0;
110 uv[1] = 0;
111 uv[2] = (float)m_image_width / m_tex_w;
112 uv[3] = 0;
113 uv[4] = (float)m_image_width / m_tex_w;
114 uv[5] = (float)m_image_height / m_tex_h;
115 uv[6] = 0;
116 uv[7] = (float)m_image_height / m_tex_h;
117
118 // pixels
119 coords[0] = m_rect.x;
120 coords[1] = m_rect.y;
121 coords[2] = m_rect.x + m_rect.width;
122 coords[3] = m_rect.y;
123 coords[4] = m_rect.x + m_rect.width;
124 coords[5] = m_rect.y + m_rect.height;
125 coords[6] = m_rect.x;
126 coords[7] = m_rect.y + m_rect.height;
127
128 m_parent->GetglCanvas()->RenderTextures(dc, coords, uv, 4,
129 m_parent->GetpVP());
130#else
131
132 glBegin(GL_QUADS);
133
134 glTexCoord2f(0, 0);
135 glVertex2i(m_rect.x, m_rect.y);
136 glTexCoord2f((float)m_image_width / m_tex_w, 0);
137 glVertex2i(m_rect.x + m_rect.width, m_rect.y);
138 glTexCoord2f((float)m_image_width / m_tex_w,
139 (float)m_image_height / m_tex_h);
140 glVertex2i(m_rect.x + m_rect.width, m_rect.y + m_rect.height);
141 glTexCoord2f(0, (float)m_image_height / m_tex_h);
142 glVertex2i(m_rect.x, m_rect.y + m_rect.height);
143
144 glEnd();
145#endif
146
147 glDisable(GL_TEXTURE_2D);
148
149 } else {
150#ifdef __WXOSX__
151 // Support MacBook Retina display
152 if (g_bopengl) {
153 double scale = m_parent->GetContentScaleFactor();
154 if (scale > 1) {
155 wxImage image = m_StatBmp.ConvertToImage();
156 image.Rescale(image.GetWidth() * scale, image.GetHeight() * scale);
157 wxBitmap bmp(image);
158 dc.DrawBitmap(bmp, m_rect.x, m_rect.y, true);
159 } else
160 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
161 } else
162 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
163#else
164 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
165#endif
166 }
167
168#else
169 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
170#endif
171 }
172}
173
174bool ocpnCompass::MouseEvent(wxMouseEvent& event) {
175 wxRect logicalRect = GetLogicalRect();
176 if (!m_shown) {
177 return false;
178 }
179 if (!logicalRect.Contains(event.GetPosition())) {
180 // User is moving away from compass widget.
181 return false;
182 }
183
184 if (event.LeftDown()) {
185 if (m_parent->GetUpMode() == NORTH_UP_MODE)
186 m_parent->SetUpMode(COURSE_UP_MODE);
187 else if (m_parent->GetUpMode() == COURSE_UP_MODE)
188 m_parent->SetUpMode(HEAD_UP_MODE);
189 else
190 m_parent->SetUpMode(NORTH_UP_MODE);
191 }
192
193 return true;
194}
195
196void ocpnCompass::SetColorScheme(ColorScheme cs) {
197 m_cs = cs;
198 UpdateStatus(true);
199}
200
201wxRect ocpnCompass::GetLogicalRect(void) const {
202#ifdef wxHAS_DPI_INDEPENDENT_PIXELS
203#if wxCHECK_VERSION(3, 1, 6)
204 wxRect logicalRect = wxRect(m_parent->FromPhys(m_rect.GetPosition()),
205 m_parent->FromPhys(m_rect.GetSize()));
206#else
207 double scaleFactor = m_parent->GetContentScaleFactor();
208 wxRect logicalRect(
209 wxPoint(m_rect.GetX() / scaleFactor, m_rect.GetY() / scaleFactor),
210 wxSize(m_rect.GetWidth() / scaleFactor,
211 m_rect.GetHeight() / scaleFactor));
212#endif
213#else
214 // On platforms without DPI-independent pixels, logical = physical.
215 wxRect logicalRect = m_rect;
216#endif
217 return logicalRect;
218}
219
220void ocpnCompass::UpdateStatus(bool bnew) {
221 if (bnew) m_lastgpsIconName.Clear(); // force an update to occur
222
223 CreateBmp(bnew);
224
225#ifdef ocpnUSE_GL
226 if (g_bopengl && m_texobj) CreateTexture();
227#endif
228}
229
230void ocpnCompass::SetScaleFactor(float factor) {
231 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
232
233 if (factor > 0.1)
234 m_scale = factor;
235 else
236 m_scale = 1.0;
237
238 // Precalculate the background sizes to get m_rect width/height
239 wxBitmap compassBg, gpsBg;
240 int orient = style->GetOrientation();
241 style->SetOrientation(wxTB_HORIZONTAL);
242 if (style->HasBackground()) {
243 compassBg = style->GetNormalBG();
244 style->DrawToolbarLineStart(compassBg);
245 compassBg = style->SetBitmapBrightness(compassBg, m_cs);
246 gpsBg = style->GetNormalBG();
247 style->DrawToolbarLineEnd(gpsBg);
248 gpsBg = style->SetBitmapBrightness(gpsBg, m_cs);
249 }
250
251 if (fabs(m_scale - 1.0) > 0.1) {
252 wxImage bg_img = compassBg.ConvertToImage();
253 bg_img.Rescale(compassBg.GetWidth() * m_scale,
254 compassBg.GetHeight() * m_scale, wxIMAGE_QUALITY_NORMAL);
255 compassBg = wxBitmap(bg_img);
256
257 bg_img = gpsBg.ConvertToImage();
258 bg_img.Rescale(gpsBg.GetWidth() * m_scale, gpsBg.GetHeight() * m_scale,
259 wxIMAGE_QUALITY_NORMAL);
260 gpsBg = wxBitmap(bg_img);
261 }
262
263 int width =
264 compassBg.GetWidth() + gpsBg.GetWidth() + style->GetCompassLeftMargin();
265 if (!style->marginsInvisible)
266 width += style->GetCompassLeftMargin() + style->GetToolSeparation();
267
268 m_rect = wxRect(style->GetCompassXOffset(), style->GetCompassYOffset(), width,
269 compassBg.GetHeight() + style->GetCompassTopMargin() +
270 style->GetCompassBottomMargin());
271}
272
273void ocpnCompass::CreateBmp(bool newColorScheme) {
274 // if (!m_shown) return;
275
276 wxString gpsIconName;
277 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
278
279 // In order to draw a horizontal compass window when the toolbar is vertical,
280 // we need to save away the sizes and backgrounds for the two icons.
281
282 static wxBitmap compassBg, gpsBg;
283 static wxSize toolsize;
284 static int topmargin, leftmargin, radius;
285
286 if (!compassBg.IsOk() || newColorScheme) {
287 int orient = style->GetOrientation();
288 style->SetOrientation(wxTB_HORIZONTAL);
289 if (style->HasBackground()) {
290 compassBg = style->GetNormalBG();
291 style->DrawToolbarLineStart(compassBg);
292 compassBg = style->SetBitmapBrightness(compassBg, m_cs);
293 gpsBg = style->GetNormalBG();
294 style->DrawToolbarLineEnd(gpsBg);
295 gpsBg = style->SetBitmapBrightness(gpsBg, m_cs);
296 }
297
298 if (fabs(m_scale - 1.0) > 0.1) {
299 wxImage bg_img = compassBg.ConvertToImage();
300 bg_img.Rescale(compassBg.GetWidth() * m_scale,
301 compassBg.GetHeight() * m_scale, wxIMAGE_QUALITY_NORMAL);
302 compassBg = wxBitmap(bg_img);
303
304 bg_img = gpsBg.ConvertToImage();
305 bg_img.Rescale(gpsBg.GetWidth() * m_scale, gpsBg.GetHeight() * m_scale,
306 wxIMAGE_QUALITY_NORMAL);
307 gpsBg = wxBitmap(bg_img);
308 }
309
310 leftmargin = style->GetCompassLeftMargin();
311 topmargin = style->GetCompassTopMargin();
312 radius = style->GetCompassCornerRadius();
313
314 if (orient == wxTB_VERTICAL) style->SetOrientation(wxTB_VERTICAL);
315 }
316
317 bool b_need_refresh = false;
318
319 if (bGPSValid) {
320 if (g_bSatValid) {
321 gpsIconName = _T("gps3Bar");
322 if (g_SatsInView <= 8) gpsIconName = _T("gps2Bar");
323 if (g_SatsInView <= 4) gpsIconName = _T("gps1Bar");
324 if (g_SatsInView < 0) gpsIconName = _T("gpsGry");
325
326 } else
327 gpsIconName = _T("gpsGrn");
328 } else
329 gpsIconName = _T("gpsRed");
330
331 if (m_lastgpsIconName != gpsIconName) b_need_refresh = true;
332
333 double rose_angle = -999.;
334
335 if ((fabs(m_parent->GetVPRotation()) > .01) ||
336 (fabs(m_parent->GetVPSkew()) > .01)) {
337 rose_angle = -m_parent->GetVPRotation();
338 } else
339 rose_angle = 0.;
340
341 if (fabs(m_rose_angle - rose_angle) > .1) b_need_refresh = true;
342
343 // if (!b_need_refresh) return;
344
345 int width = compassBg.GetWidth();
346 if (m_bshowGPS) width += gpsBg.GetWidth() + leftmargin;
347
348 if (!style->marginsInvisible)
349 width += leftmargin + style->GetToolSeparation();
350
351 m_StatBmp.Create(width, compassBg.GetHeight() + topmargin +
352 style->GetCompassBottomMargin());
353
354 m_rect.width = m_StatBmp.GetWidth();
355 m_rect.height = m_StatBmp.GetHeight();
356
357 // if (!m_StatBmp.IsOk()) return;
358
359 m_MaskBmp = wxBitmap(m_StatBmp.GetWidth(), m_StatBmp.GetHeight());
360 if (style->marginsInvisible) {
361 wxMemoryDC sdc(m_MaskBmp);
362 sdc.SetBackground(*wxWHITE_BRUSH);
363 sdc.Clear();
364 sdc.SetBrush(*wxBLACK_BRUSH);
365 sdc.SetPen(*wxBLACK_PEN);
366 wxSize maskSize = wxSize(m_MaskBmp.GetWidth() - leftmargin,
367 m_MaskBmp.GetHeight() - (2 * topmargin));
368 sdc.DrawRoundedRectangle(wxPoint(leftmargin, topmargin), maskSize, radius);
369 sdc.SelectObject(wxNullBitmap);
370 } else if (radius) {
371 wxMemoryDC sdc(m_MaskBmp);
372 sdc.SetBackground(*wxWHITE_BRUSH);
373 sdc.Clear();
374 sdc.SetBrush(*wxBLACK_BRUSH);
375 sdc.SetPen(*wxBLACK_PEN);
376 sdc.DrawRoundedRectangle(0, 0, m_MaskBmp.GetWidth(), m_MaskBmp.GetHeight(),
377 radius);
378 sdc.SelectObject(wxNullBitmap);
379 }
380#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
381 m_StatBmp.SetMask(new wxMask(m_MaskBmp, *wxWHITE));
382#endif
383
384 wxMemoryDC mdc;
385 mdc.SelectObject(m_StatBmp);
386 mdc.SetBackground(wxBrush(GetGlobalColor(_T("COMP1")), wxBRUSHSTYLE_SOLID));
387 mdc.Clear();
388
389 mdc.SetPen(wxPen(GetGlobalColor(_T("UITX1")), 1));
390 mdc.SetBrush(wxBrush(GetGlobalColor(_T("UITX1")), wxBRUSHSTYLE_TRANSPARENT));
391
392 if (!style->marginsInvisible)
393 mdc.DrawRoundedRectangle(0, 0, m_StatBmp.GetWidth(), m_StatBmp.GetHeight(),
394 radius);
395
396 wxPoint offset(leftmargin, topmargin);
397
398 // Build Compass Rose, rotated...
399 wxBitmap BMPRose;
400 wxPoint after_rotate;
401
402 int cwidth = style->GetToolSize().x * m_scale;
403 int cheight = style->GetToolSize().y * m_scale;
404 cheight = wxMin(cheight, compassBg.GetHeight());
405 cwidth = wxMin(cwidth, cheight);
406 cheight = cwidth;
407
408 if (m_parent->GetUpMode() == COURSE_UP_MODE)
409 BMPRose = style->GetIcon(_T("CompassRose"), cwidth, cheight);
410 else if (m_parent->GetUpMode() == HEAD_UP_MODE)
411 BMPRose = style->GetIcon(_T("CompassRoseMag"), cwidth, cheight);
412 else
413 BMPRose = style->GetIcon(_T("CompassRoseBlue"), cwidth, cheight);
414 if ((fabs(m_parent->GetVPRotation()) > .01) ||
415 (fabs(m_parent->GetVPSkew()) > .01)) {
416 wxImage rose_img = BMPRose.ConvertToImage();
417 wxPoint rot_ctr(cwidth / 2, cheight / 2);
418 wxImage rot_image =
419 rose_img.Rotate(rose_angle, rot_ctr, true, &after_rotate);
420 BMPRose = wxBitmap(rot_image).GetSubBitmap(
421 wxRect(-after_rotate.x, -after_rotate.y, cwidth, cheight));
422 }
423
424 wxBitmap iconBm;
425
426 if (style->HasBackground()) {
427 iconBm = MergeBitmaps(compassBg, BMPRose, wxSize(0, 0));
428 } else {
429 iconBm = BMPRose;
430 }
431
432 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
433
434 mdc.DrawBitmap(iconBm, offset);
435
436 if (g_btenhertz) {
437 mdc.SetPen(wxPen(GetGlobalColor("BLUE3"), 1));
438 mdc.SetBrush(wxBrush(GetGlobalColor("BLUE3"), wxBRUSHSTYLE_SOLID));
439 int hight = m_StatBmp.GetHeight();
440 int dot_diam = wxMax(2, hight / 12);
441 mdc.DrawCircle(5, hight - 5, dot_diam);
442 }
443
444 offset.x += iconBm.GetWidth();
445 offset.x += style->GetToolSeparation();
446
447 m_rose_angle = rose_angle;
448
449 if (m_bshowGPS) {
450 // GPS Icon
451 int twidth = style->GetToolSize().x * m_scale;
452 int theight = style->GetToolSize().y * m_scale;
453 theight = wxMin(cheight, compassBg.GetHeight());
454 int swidth = wxMax(twidth, theight);
455 int sheight = wxMin(twidth, theight);
456
457 // Sometimes, the SVG renderer gets the size wrong due to some internal
458 // rounding error. If so found, it seems to work OK by just reducing the
459 // requested size by one pixel....
460 wxBitmap gicon = style->GetIcon(gpsIconName, swidth, sheight);
461 if (gicon.GetHeight() != sheight)
462 gicon = style->GetIcon(gpsIconName, swidth - 1, sheight - 1, true);
463
464 if (style->HasBackground()) {
465 iconBm = MergeBitmaps(gpsBg, gicon, wxSize(0, 0));
466 } else {
467 iconBm = gicon;
468 }
469
470 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
471 mdc.DrawBitmap(iconBm, offset);
472 mdc.SelectObject(wxNullBitmap);
473
474 m_lastgpsIconName = gpsIconName;
475 }
476}
477
478void ocpnCompass::CreateTexture() {
479#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
480 // GLES does not do ocpnDC::DrawBitmap(), so use
481 // texture
482 if (g_bopengl) {
483 wxImage image = m_StatBmp.ConvertToImage();
484 unsigned char* imgdata = image.GetData();
485 unsigned char* imgalpha = image.GetAlpha();
486 m_tex_w = image.GetWidth();
487 m_tex_h = image.GetHeight();
488 m_image_width = m_tex_w;
489 m_image_height = m_tex_h;
490
491 // Make it POT
492 int width_pot = m_tex_w;
493 int height_pot = m_tex_h;
494
495 int xp = image.GetWidth();
496 if (((xp != 0) && !(xp & (xp - 1)))) // detect POT
497 width_pot = xp;
498 else {
499 int a = 0;
500 while (xp) {
501 xp = xp >> 1;
502 a++;
503 }
504 width_pot = 1 << a;
505 }
506
507 xp = image.GetHeight();
508 if (((xp != 0) && !(xp & (xp - 1))))
509 height_pot = xp;
510 else {
511 int a = 0;
512 while (xp) {
513 xp = xp >> 1;
514 a++;
515 }
516 height_pot = 1 << a;
517 }
518
519 m_tex_w = width_pot;
520 m_tex_h = height_pot;
521
522 GLuint format = GL_RGBA;
523 GLuint internalformat = GL_RGBA8; // format;
524 int stride = 4;
525
526 if (imgdata) {
527 unsigned char* teximage =
528 (unsigned char*)malloc(stride * m_tex_w * m_tex_h);
529
530 for (int i = 0; i < m_image_height; i++) {
531 for (int j = 0; j < m_image_width; j++) {
532 int s = (i * 3 * m_image_width) + (j * 3);
533 int d = (i * stride * m_tex_w) + (j * stride);
534
535 teximage[d + 0] = imgdata[s + 0];
536 teximage[d + 1] = imgdata[s + 1];
537 teximage[d + 2] = imgdata[s + 2];
538 teximage[d + 3] = 255;
539 }
540 }
541
542 glBindTexture(GL_TEXTURE_2D, m_texobj);
543
544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
545 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
546 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
547 GL_NEAREST); // No mipmapping
548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
549
550 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0,
551 format, GL_UNSIGNED_BYTE, teximage);
552
553 free(teximage);
554 glBindTexture(GL_TEXTURE_2D, 0);
555 m_texOK = true;
556 }
557 }
558#endif
559}
560
561void ocpnCompass::UpdateTexture() {
562#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
563 // GLES does not do ocpnDC::DrawBitmap(), so use
564 // texture
565 if (g_bopengl) {
566 wxImage image = m_StatBmp.ConvertToImage();
567 unsigned char* imgdata = image.GetData();
568 unsigned char* imgalpha = image.GetAlpha();
569 m_tex_w = image.GetWidth();
570 m_tex_h = image.GetHeight();
571 m_image_width = m_tex_w;
572 m_image_height = m_tex_h;
573
574 // Make it POT
575 int width_pot = m_tex_w;
576 int height_pot = m_tex_h;
577
578 int xp = image.GetWidth();
579 if (((xp != 0) && !(xp & (xp - 1)))) // detect POT
580 width_pot = xp;
581 else {
582 int a = 0;
583 while (xp) {
584 xp = xp >> 1;
585 a++;
586 }
587 width_pot = 1 << a;
588 }
589
590 xp = image.GetHeight();
591 if (((xp != 0) && !(xp & (xp - 1))))
592 height_pot = xp;
593 else {
594 int a = 0;
595 while (xp) {
596 xp = xp >> 1;
597 a++;
598 }
599 height_pot = 1 << a;
600 }
601
602 m_tex_w = width_pot;
603 m_tex_h = height_pot;
604
605 GLuint format = GL_RGBA;
606 GLuint internalformat = GL_RGBA8; // format;
607 int stride = 4;
608
609 if (imgdata) {
610 unsigned char* teximage =
611 (unsigned char*)malloc(stride * m_tex_w * m_tex_h);
612
613 for (int i = 0; i < m_image_height; i++) {
614 for (int j = 0; j < m_image_width; j++) {
615 int s = (i * 3 * m_image_width) + (j * 3);
616 int d = (i * stride * m_tex_w) + (j * stride);
617
618 teximage[d + 0] = imgdata[s + 0];
619 teximage[d + 1] = imgdata[s + 1];
620 teximage[d + 2] = imgdata[s + 2];
621 teximage[d + 3] = 255;
622 }
623 }
624
625 glBindTexture(GL_TEXTURE_2D, m_texobj);
626 glEnable(GL_TEXTURE_2D);
627
628 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_tex_w, m_tex_h, format,
629 GL_UNSIGNED_BYTE, teximage);
630
631 free(teximage);
632 glBindTexture(GL_TEXTURE_2D, 0);
633 }
634 }
635#endif
636}
Chart display canvas.
Definition chcanv.h:135
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Definition compass.cpp:201
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:64