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