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 "gl_chart_canvas.h"
36#include "tooltip.h"
37#include "ocpn_frame.h" // FIXME (dave) colorschemes
38#include "styles.h"
39
40#ifndef GL_RGBA8
41#define GL_RGBA8 0x8058
42#endif
43
44ocpnCompass::ocpnCompass(ChartCanvas* parent, bool bShowGPS) {
45 m_parent = parent;
46 m_bshowGPS = bShowGPS;
47
48 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
49 _img_compass = style->GetIcon("CompassRose");
50 _img_gpsRed = style->GetIcon("gpsRed");
51
52 m_rose_angle = -999; // force a refresh when first used
53
54 m_pStatBoxToolStaticBmp = NULL;
55
56 m_rect =
57 wxRect(style->GetCompassXOffset(), style->GetCompassYOffset(),
58 _img_compass.GetWidth() + _img_gpsRed.GetWidth() +
59 style->GetCompassLeftMargin() * 2 + style->GetToolSeparation(),
60 _img_compass.GetHeight() + style->GetCompassTopMargin() +
61 style->GetCompassBottomMargin());
62
63#ifdef ocpnUSE_GL
64 m_texobj = 0;
65#endif
66 m_texOK = false;
67
68 m_scale = 1.0;
69 m_cs = GLOBAL_COLOR_SCHEME_RGB;
70 SetToolTip("");
71}
72
73ocpnCompass::~ocpnCompass() {
74 // Hide any active tooltips for this compass
76
77#ifdef ocpnUSE_GL
78 if (m_texobj) {
79 glDeleteTextures(1, &m_texobj);
80 m_texobj = 0;
81 }
82#endif
83
84 delete m_pStatBoxToolStaticBmp;
85}
86
87void ocpnCompass::Paint(ocpnDC& dc) {
88 if (m_shown && m_StatBmp.IsOk()) {
89#if defined(ocpnUSE_GLES) || defined(ocpnUSE_GL)
90 if (g_bopengl && !m_texobj) {
91 // The glContext is known active here,
92 // so safe to create a texture.
93 glGenTextures(1, &m_texobj);
94 CreateTexture();
95 }
96
97 if (g_bopengl && m_texobj /*&& m_texOK*/) {
98 glBindTexture(GL_TEXTURE_2D, m_texobj);
99 glEnable(GL_TEXTURE_2D);
100
101#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
102 float coords[8];
103 float uv[8];
104
105 // normal uv, normalized to POT
106 uv[0] = 0;
107 uv[1] = 0;
108 uv[2] = (float)m_image_width / m_tex_w;
109 uv[3] = 0;
110 uv[4] = (float)m_image_width / m_tex_w;
111 uv[5] = (float)m_image_height / m_tex_h;
112 uv[6] = 0;
113 uv[7] = (float)m_image_height / m_tex_h;
114
115 // pixels
116 coords[0] = m_rect.x;
117 coords[1] = m_rect.y;
118 coords[2] = m_rect.x + m_rect.width;
119 coords[3] = m_rect.y;
120 coords[4] = m_rect.x + m_rect.width;
121 coords[5] = m_rect.y + m_rect.height;
122 coords[6] = m_rect.x;
123 coords[7] = m_rect.y + m_rect.height;
124
125 m_parent->GetglCanvas()->RenderTextures(dc, coords, uv, 4,
126 m_parent->GetpVP());
127#else
128
129 glBegin(GL_QUADS);
130
131 glTexCoord2f(0, 0);
132 glVertex2i(m_rect.x, m_rect.y);
133 glTexCoord2f((float)m_image_width / m_tex_w, 0);
134 glVertex2i(m_rect.x + m_rect.width, m_rect.y);
135 glTexCoord2f((float)m_image_width / m_tex_w,
136 (float)m_image_height / m_tex_h);
137 glVertex2i(m_rect.x + m_rect.width, m_rect.y + m_rect.height);
138 glTexCoord2f(0, (float)m_image_height / m_tex_h);
139 glVertex2i(m_rect.x, m_rect.y + m_rect.height);
140
141 glEnd();
142#endif
143
144 glDisable(GL_TEXTURE_2D);
145
146 } else {
147#ifdef __WXOSX__
148 // Support MacBook Retina display
149 if (g_bopengl) {
150 double scale = m_parent->GetContentScaleFactor();
151 if (scale > 1) {
152 wxImage image = m_StatBmp.ConvertToImage();
153 image.Rescale(image.GetWidth() * scale, image.GetHeight() * scale);
154 wxBitmap bmp(image);
155 dc.DrawBitmap(bmp, m_rect.x, m_rect.y, true);
156 } else
157 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
158 } else
159 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
160#else
161 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
162#endif
163 }
164
165#else
166 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y, true);
167#endif
168 }
169}
170
171bool ocpnCompass::MouseEvent(wxMouseEvent& event) {
172 wxRect logicalRect = GetLogicalRect();
173 if (!m_shown) {
174 return false;
175 }
176 if (!logicalRect.Contains(event.GetPosition())) {
177 // User is moving away from compass widget. Hide universal tooltip.
179 return false;
180 }
181
182 if (event.LeftDown()) {
183 if (m_parent->GetUpMode() == NORTH_UP_MODE)
184 m_parent->SetUpMode(COURSE_UP_MODE);
185 else if (m_parent->GetUpMode() == COURSE_UP_MODE)
186 m_parent->SetUpMode(HEAD_UP_MODE);
187 else
188 m_parent->SetUpMode(NORTH_UP_MODE);
189 }
190 if (event.LeftUp() || event.Entering() || event.Moving()) {
191 // Show tooltip on hover or after the user has changed the compass mode.
192 if (!m_tooltip.IsEmpty()) {
193 wxPoint screenPos = wxGetMousePosition();
194 screenPos.x += 15; // Default offset from mouse
195 screenPos.y += 15;
196
197 TooltipManager::Get().ShowTooltipAtPosition(m_parent, m_tooltip,
198 screenPos);
199 }
200 }
201
202 return true;
203}
204
205void ocpnCompass::SetColorScheme(ColorScheme cs) {
206 m_cs = cs;
207 UpdateStatus(true);
208
209 // Update universal tooltip color scheme
211}
212
213void ocpnCompass::SetToolTip(const wxString& tooltip) { m_tooltip = tooltip; }
214
216#ifdef wxHAS_DPI_INDEPENDENT_PIXELS
217#if wxCHECK_VERSION(3, 1, 6)
218 wxRect logicalRect = wxRect(m_parent->FromPhys(m_rect.GetPosition()),
219 m_parent->FromPhys(m_rect.GetSize()));
220#else
221 double scaleFactor = m_parent->GetContentScaleFactor();
222 wxRect logicalRect(
223 wxPoint(m_rect.GetX() / scaleFactor, m_rect.GetY() / scaleFactor),
224 wxSize(m_rect.GetWidth() / scaleFactor,
225 m_rect.GetHeight() / scaleFactor));
226#endif
227#else
228 // On platforms without DPI-independent pixels, logical = physical.
229 wxRect logicalRect = m_rect;
230#endif
231 return logicalRect;
232}
233
234void ocpnCompass::UpdateStatus(bool bnew) {
235 if (bnew) m_lastgpsIconName.Clear(); // force an update to occur
236
237 CreateBmp(bnew);
238
239#ifdef ocpnUSE_GL
240 if (g_bopengl && m_texobj) CreateTexture();
241#endif
242
243 // Show a tooltip with the current compass mode and GPS status.
244 wxString tooltipText;
245 if (m_parent->GetUpMode() == NORTH_UP_MODE)
246 tooltipText = _("North Up");
247 else if (m_parent->GetUpMode() == COURSE_UP_MODE)
248 tooltipText = _("Course Up");
249 else
250 tooltipText = _("Heading Up");
251
252 if (m_bshowGPS) {
253 tooltipText += "\n";
254 if (bGPSValid) {
255 if (g_bSatValid)
256 tooltipText +=
257 wxString::Format(_("GNSS (%d satellites)"), g_SatsInView);
258 else
259 // Satellite watchdog timer has expired, no data has been received
260 // recently.
261 tooltipText += _("GNSS data stale");
262 } else {
263 tooltipText += _("No GNSS data");
264 }
265 }
266 SetToolTip(tooltipText);
267}
268
269void ocpnCompass::SetScaleFactor(float factor) {
270 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
271
272 if (factor > 0.1)
273 m_scale = factor;
274 else
275 m_scale = 1.0;
276
277 // Precalculate the background sizes to get m_rect width/height
278 wxBitmap compassBg, gpsBg;
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 int width =
303 compassBg.GetWidth() + gpsBg.GetWidth() + style->GetCompassLeftMargin();
304 if (!style->marginsInvisible)
305 width += style->GetCompassLeftMargin() + style->GetToolSeparation();
306
307 m_rect = wxRect(style->GetCompassXOffset(), style->GetCompassYOffset(), width,
308 compassBg.GetHeight() + style->GetCompassTopMargin() +
309 style->GetCompassBottomMargin());
310}
311
312void ocpnCompass::CreateBmp(bool newColorScheme) {
313 // if (!m_shown) return;
314
315 wxString gpsIconName;
316 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
317
318 // In order to draw a horizontal compass window when the toolbar is vertical,
319 // we need to save away the sizes and backgrounds for the two icons.
320
321 static wxBitmap compassBg, gpsBg;
322 static wxSize toolsize;
323 static int topmargin, leftmargin, radius;
324
325 if (!compassBg.IsOk() || newColorScheme) {
326 int orient = style->GetOrientation();
327 style->SetOrientation(wxTB_HORIZONTAL);
328 if (style->HasBackground()) {
329 compassBg = style->GetNormalBG();
330 style->DrawToolbarLineStart(compassBg);
331 compassBg = style->SetBitmapBrightness(compassBg, m_cs);
332 gpsBg = style->GetNormalBG();
333 style->DrawToolbarLineEnd(gpsBg);
334 gpsBg = style->SetBitmapBrightness(gpsBg, m_cs);
335 }
336
337 if (fabs(m_scale - 1.0) > 0.1) {
338 wxImage bg_img = compassBg.ConvertToImage();
339 bg_img.Rescale(compassBg.GetWidth() * m_scale,
340 compassBg.GetHeight() * m_scale, wxIMAGE_QUALITY_NORMAL);
341 compassBg = wxBitmap(bg_img);
342
343 bg_img = gpsBg.ConvertToImage();
344 bg_img.Rescale(gpsBg.GetWidth() * m_scale, gpsBg.GetHeight() * m_scale,
345 wxIMAGE_QUALITY_NORMAL);
346 gpsBg = wxBitmap(bg_img);
347 }
348
349 leftmargin = style->GetCompassLeftMargin();
350 topmargin = style->GetCompassTopMargin();
351 radius = style->GetCompassCornerRadius();
352
353 if (orient == wxTB_VERTICAL) style->SetOrientation(wxTB_VERTICAL);
354 }
355
356 bool b_need_refresh = false;
357
358 if (bGPSValid) {
359 if (g_bSatValid) {
360 gpsIconName = "gps3Bar";
361 if (g_SatsInView <= 8) gpsIconName = "gps2Bar";
362 if (g_SatsInView <= 4) gpsIconName = "gps1Bar";
363 if (g_SatsInView < 0) gpsIconName = "gpsGry";
364
365 } else
366 gpsIconName = "gpsGrn";
367 } else
368 gpsIconName = "gpsRed";
369
370 if (m_lastgpsIconName != gpsIconName) b_need_refresh = true;
371
372 double rose_angle = -999.;
373
374 if ((fabs(m_parent->GetVPRotation()) > .01) ||
375 (fabs(m_parent->GetVPSkew()) > .01)) {
376 rose_angle = -m_parent->GetVPRotation();
377 } else
378 rose_angle = 0.;
379
380 if (fabs(m_rose_angle - rose_angle) > .1) b_need_refresh = true;
381
382 // if (!b_need_refresh) return;
383
384 int width = compassBg.GetWidth();
385 if (m_bshowGPS) width += gpsBg.GetWidth() + leftmargin;
386
387 if (!style->marginsInvisible)
388 width += leftmargin + style->GetToolSeparation();
389
390 m_StatBmp.Create(width, compassBg.GetHeight() + topmargin +
391 style->GetCompassBottomMargin());
392
393 m_rect.width = m_StatBmp.GetWidth();
394 m_rect.height = m_StatBmp.GetHeight();
395
396 // if (!m_StatBmp.IsOk()) return;
397
398 m_MaskBmp = wxBitmap(m_StatBmp.GetWidth(), m_StatBmp.GetHeight());
399 if (style->marginsInvisible) {
400 wxMemoryDC sdc(m_MaskBmp);
401 sdc.SetBackground(*wxWHITE_BRUSH);
402 sdc.Clear();
403 sdc.SetBrush(*wxBLACK_BRUSH);
404 sdc.SetPen(*wxBLACK_PEN);
405 wxSize maskSize = wxSize(m_MaskBmp.GetWidth() - leftmargin,
406 m_MaskBmp.GetHeight() - (2 * topmargin));
407 sdc.DrawRoundedRectangle(wxPoint(leftmargin, topmargin), maskSize, radius);
408 sdc.SelectObject(wxNullBitmap);
409 } else if (radius) {
410 wxMemoryDC sdc(m_MaskBmp);
411 sdc.SetBackground(*wxWHITE_BRUSH);
412 sdc.Clear();
413 sdc.SetBrush(*wxBLACK_BRUSH);
414 sdc.SetPen(*wxBLACK_PEN);
415 sdc.DrawRoundedRectangle(0, 0, m_MaskBmp.GetWidth(), m_MaskBmp.GetHeight(),
416 radius);
417 sdc.SelectObject(wxNullBitmap);
418 }
419#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
420 m_StatBmp.SetMask(new wxMask(m_MaskBmp, *wxWHITE));
421#endif
422
423 wxMemoryDC mdc;
424 mdc.SelectObject(m_StatBmp);
425 mdc.SetBackground(wxBrush(GetGlobalColor("COMP1"), wxBRUSHSTYLE_SOLID));
426 mdc.Clear();
427
428 mdc.SetPen(wxPen(GetGlobalColor("UITX1"), 1));
429 mdc.SetBrush(wxBrush(GetGlobalColor("UITX1"), wxBRUSHSTYLE_TRANSPARENT));
430
431 if (!style->marginsInvisible)
432 mdc.DrawRoundedRectangle(0, 0, m_StatBmp.GetWidth(), m_StatBmp.GetHeight(),
433 radius);
434
435 wxPoint offset(leftmargin, topmargin);
436
437 // Build Compass Rose, rotated...
438 wxBitmap BMPRose;
439 wxPoint after_rotate;
440
441 int cwidth = style->GetToolSize().x * m_scale;
442 int cheight = style->GetToolSize().y * m_scale;
443 cheight = wxMin(cheight, compassBg.GetHeight());
444 cwidth = wxMin(cwidth, cheight);
445 cheight = cwidth;
446
447 if (m_parent->GetUpMode() == COURSE_UP_MODE)
448 BMPRose = style->GetIcon("CompassRose", cwidth, cheight);
449 else if (m_parent->GetUpMode() == HEAD_UP_MODE)
450 BMPRose = style->GetIcon("CompassRoseMag", cwidth, cheight);
451 else
452 BMPRose = style->GetIcon("CompassRoseBlue", cwidth, cheight);
453 if ((fabs(m_parent->GetVPRotation()) > .01) ||
454 (fabs(m_parent->GetVPSkew()) > .01)) {
455 wxImage rose_img = BMPRose.ConvertToImage();
456 wxPoint rot_ctr(cwidth / 2, cheight / 2);
457 wxImage rot_image =
458 rose_img.Rotate(rose_angle, rot_ctr, true, &after_rotate);
459 BMPRose = wxBitmap(rot_image).GetSubBitmap(
460 wxRect(-after_rotate.x, -after_rotate.y, cwidth, cheight));
461 }
462
463 wxBitmap iconBm;
464
465 if (style->HasBackground()) {
466 iconBm = MergeBitmaps(compassBg, BMPRose, wxSize(0, 0));
467 } else {
468 iconBm = BMPRose;
469 }
470
471 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
472
473 mdc.DrawBitmap(iconBm, offset);
474
475 if (g_btenhertz) {
476 mdc.SetPen(wxPen(GetGlobalColor("BLUE3"), 1));
477 mdc.SetBrush(wxBrush(GetGlobalColor("BLUE3"), wxBRUSHSTYLE_SOLID));
478 int hight = m_StatBmp.GetHeight();
479 int dot_diam = wxMax(2, hight / 12);
480 mdc.DrawCircle(5, hight - 5, dot_diam);
481 }
482
483 offset.x += iconBm.GetWidth();
484 offset.x += style->GetToolSeparation();
485
486 m_rose_angle = rose_angle;
487
488 if (m_bshowGPS) {
489 // GPS Icon
490 int twidth = style->GetToolSize().x * m_scale;
491 int theight = style->GetToolSize().y * m_scale;
492 theight = wxMin(cheight, compassBg.GetHeight());
493 int swidth = wxMax(twidth, theight);
494 int sheight = wxMin(twidth, theight);
495
496 // Sometimes, the SVG renderer gets the size wrong due to some internal
497 // rounding error. If so found, it seems to work OK by just reducing the
498 // requested size by one pixel....
499 wxBitmap gicon = style->GetIcon(gpsIconName, swidth, sheight);
500 if (gicon.GetHeight() != sheight)
501 gicon = style->GetIcon(gpsIconName, swidth - 1, sheight - 1, true);
502
503 if (style->HasBackground()) {
504 iconBm = MergeBitmaps(gpsBg, gicon, wxSize(0, 0));
505 } else {
506 iconBm = gicon;
507 }
508
509 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
510 mdc.DrawBitmap(iconBm, offset);
511 mdc.SelectObject(wxNullBitmap);
512
513 m_lastgpsIconName = gpsIconName;
514 }
515}
516
517void ocpnCompass::CreateTexture() {
518#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
519 // GLES does not do ocpnDC::DrawBitmap(), so use
520 // texture
521 if (g_bopengl) {
522 wxImage image = m_StatBmp.ConvertToImage();
523 unsigned char* imgdata = image.GetData();
524 unsigned char* imgalpha = image.GetAlpha();
525 m_tex_w = image.GetWidth();
526 m_tex_h = image.GetHeight();
527 m_image_width = m_tex_w;
528 m_image_height = m_tex_h;
529
530 // Make it POT
531 int width_pot = m_tex_w;
532 int height_pot = m_tex_h;
533
534 int xp = image.GetWidth();
535 if (((xp != 0) && !(xp & (xp - 1)))) // detect POT
536 width_pot = xp;
537 else {
538 int a = 0;
539 while (xp) {
540 xp = xp >> 1;
541 a++;
542 }
543 width_pot = 1 << a;
544 }
545
546 xp = image.GetHeight();
547 if (((xp != 0) && !(xp & (xp - 1))))
548 height_pot = xp;
549 else {
550 int a = 0;
551 while (xp) {
552 xp = xp >> 1;
553 a++;
554 }
555 height_pot = 1 << a;
556 }
557
558 m_tex_w = width_pot;
559 m_tex_h = height_pot;
560
561 GLuint format = GL_RGBA;
562 GLuint internalformat = GL_RGBA8; // format;
563 int stride = 4;
564
565 if (imgdata) {
566 unsigned char* teximage =
567 (unsigned char*)malloc(stride * m_tex_w * m_tex_h);
568
569 for (int i = 0; i < m_image_height; i++) {
570 for (int j = 0; j < m_image_width; j++) {
571 int s = (i * 3 * m_image_width) + (j * 3);
572 int d = (i * stride * m_tex_w) + (j * stride);
573
574 teximage[d + 0] = imgdata[s + 0];
575 teximage[d + 1] = imgdata[s + 1];
576 teximage[d + 2] = imgdata[s + 2];
577 teximage[d + 3] = 255;
578 }
579 }
580
581 glBindTexture(GL_TEXTURE_2D, m_texobj);
582
583 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
584 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
585 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
586 GL_NEAREST); // No mipmapping
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
588
589 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0,
590 format, GL_UNSIGNED_BYTE, teximage);
591
592 free(teximage);
593 glBindTexture(GL_TEXTURE_2D, 0);
594 m_texOK = true;
595 }
596 }
597#endif
598}
599
600void ocpnCompass::UpdateTexture() {
601#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
602 // GLES does not do ocpnDC::DrawBitmap(), so use
603 // texture
604 if (g_bopengl) {
605 wxImage image = m_StatBmp.ConvertToImage();
606 unsigned char* imgdata = image.GetData();
607 unsigned char* imgalpha = image.GetAlpha();
608 m_tex_w = image.GetWidth();
609 m_tex_h = image.GetHeight();
610 m_image_width = m_tex_w;
611 m_image_height = m_tex_h;
612
613 // Make it POT
614 int width_pot = m_tex_w;
615 int height_pot = m_tex_h;
616
617 int xp = image.GetWidth();
618 if (((xp != 0) && !(xp & (xp - 1)))) // detect POT
619 width_pot = xp;
620 else {
621 int a = 0;
622 while (xp) {
623 xp = xp >> 1;
624 a++;
625 }
626 width_pot = 1 << a;
627 }
628
629 xp = image.GetHeight();
630 if (((xp != 0) && !(xp & (xp - 1))))
631 height_pot = xp;
632 else {
633 int a = 0;
634 while (xp) {
635 xp = xp >> 1;
636 a++;
637 }
638 height_pot = 1 << a;
639 }
640
641 m_tex_w = width_pot;
642 m_tex_h = height_pot;
643
644 GLuint format = GL_RGBA;
645 GLuint internalformat = GL_RGBA8; // format;
646 int stride = 4;
647
648 if (imgdata) {
649 unsigned char* teximage =
650 (unsigned char*)malloc(stride * m_tex_w * m_tex_h);
651
652 for (int i = 0; i < m_image_height; i++) {
653 for (int j = 0; j < m_image_width; j++) {
654 int s = (i * 3 * m_image_width) + (j * 3);
655 int d = (i * stride * m_tex_w) + (j * stride);
656
657 teximage[d + 0] = imgdata[s + 0];
658 teximage[d + 1] = imgdata[s + 1];
659 teximage[d + 2] = imgdata[s + 2];
660 teximage[d + 3] = 255;
661 }
662 }
663
664 glBindTexture(GL_TEXTURE_2D, m_texobj);
665 glEnable(GL_TEXTURE_2D);
666
667 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_tex_w, m_tex_h, format,
668 GL_UNSIGNED_BYTE, teximage);
669
670 free(teximage);
671 glBindTexture(GL_TEXTURE_2D, 0);
672 }
673 }
674#endif
675}
Generic Chart canvas base.
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:157
void SetColorScheme(ColorScheme cs)
Set color scheme for all tooltips.
Definition tooltip.cpp:373
static TooltipManager & Get()
Get the singleton instance.
Definition tooltip.cpp:308
void HideTooltip()
Hide the current tooltip.
Definition tooltip.cpp:362
void ShowTooltipAtPosition(wxWindow *parent, const wxString &text, const wxPoint &position, bool hiviz=false)
Show tooltip at specified position in absolute screen coordinates (physical pixels).
Definition tooltip.cpp:315
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Definition compass.cpp:215
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:60
bool g_bSatValid
Indicates valid GNSS reception status based on satellite visibility and successful parsing of NMEA018...
Definition comm_vars.cpp:32
Variables maintained by comm stack, read-only access for others.
Global variables stored in configuration file.
OpenGL chart rendering canvas.
OpenCPN top window.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
Definition own_ship.cpp:34
Position, course, speed, etc.
wxBitmap MergeBitmaps(wxBitmap back, wxBitmap front, wxSize offset)
Definition styles.cpp:66
Chart Symbols.