41#define GL_RGBA8 0x8058
44ocpnCompass::ocpnCompass(
ChartCanvas* parent,
bool bShowGPS) {
46 m_bshowGPS = bShowGPS;
49 _img_compass = style->GetIcon(
"CompassRose");
50 _img_gpsRed = style->GetIcon(
"gpsRed");
54 m_pStatBoxToolStaticBmp = NULL;
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());
69 m_cs = GLOBAL_COLOR_SCHEME_RGB;
73ocpnCompass::~ocpnCompass() {
79 glDeleteTextures(1, &m_texobj);
84 delete m_pStatBoxToolStaticBmp;
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) {
93 glGenTextures(1, &m_texobj);
97 if (g_bopengl && m_texobj ) {
98 glBindTexture(GL_TEXTURE_2D, m_texobj);
99 glEnable(GL_TEXTURE_2D);
101#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
108 uv[2] = (float)m_image_width / m_tex_w;
110 uv[4] = (float)m_image_width / m_tex_w;
111 uv[5] = (float)m_image_height / m_tex_h;
113 uv[7] = (float)m_image_height / m_tex_h;
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;
125 m_parent->GetglCanvas()->RenderTextures(dc, coords, uv, 4,
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);
144 glDisable(GL_TEXTURE_2D);
150 double scale = m_parent->GetContentScaleFactor();
152 wxImage image = m_StatBmp.ConvertToImage();
153 image.Rescale(image.GetWidth() *
scale, image.GetHeight() *
scale);
155 dc.DrawBitmap(bmp, m_rect.x, m_rect.y,
true);
157 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
159 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
161 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
166 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
171bool ocpnCompass::MouseEvent(wxMouseEvent& event) {
176 if (!logicalRect.Contains(event.GetPosition())) {
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);
188 m_parent->SetUpMode(NORTH_UP_MODE);
190 if (event.LeftUp() || event.Entering() || event.Moving()) {
192 if (!m_tooltip.IsEmpty()) {
193 wxPoint screenPos = wxGetMousePosition();
205void ocpnCompass::SetColorScheme(ColorScheme cs) {
213void ocpnCompass::SetToolTip(
const wxString& tooltip) { m_tooltip = tooltip; }
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()));
221 double scaleFactor = m_parent->GetContentScaleFactor();
223 wxPoint(m_rect.GetX() / scaleFactor, m_rect.GetY() / scaleFactor),
224 wxSize(m_rect.GetWidth() / scaleFactor,
225 m_rect.GetHeight() / scaleFactor));
229 wxRect logicalRect = m_rect;
234void ocpnCompass::UpdateStatus(
bool bnew) {
235 if (bnew) m_lastgpsIconName.Clear();
240 if (g_bopengl && m_texobj) CreateTexture();
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");
250 tooltipText = _(
"Heading Up");
257 wxString::Format(_(
"GNSS (%d satellites)"), g_SatsInView);
261 tooltipText += _(
"GNSS data stale");
263 tooltipText += _(
"No GNSS data");
266 SetToolTip(tooltipText);
269void ocpnCompass::SetScaleFactor(
float factor) {
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);
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);
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);
303 compassBg.GetWidth() + gpsBg.GetWidth() + style->GetCompassLeftMargin();
304 if (!style->marginsInvisible)
305 width += style->GetCompassLeftMargin() + style->GetToolSeparation();
307 m_rect = wxRect(style->GetCompassXOffset(), style->GetCompassYOffset(), width,
308 compassBg.GetHeight() + style->GetCompassTopMargin() +
309 style->GetCompassBottomMargin());
312void ocpnCompass::CreateBmp(
bool newColorScheme) {
315 wxString gpsIconName;
321 static wxBitmap compassBg, gpsBg;
322 static wxSize toolsize;
323 static int topmargin, leftmargin, radius;
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);
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);
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);
349 leftmargin = style->GetCompassLeftMargin();
350 topmargin = style->GetCompassTopMargin();
351 radius = style->GetCompassCornerRadius();
353 if (orient == wxTB_VERTICAL) style->SetOrientation(wxTB_VERTICAL);
356 bool b_need_refresh =
false;
360 gpsIconName =
"gps3Bar";
361 if (g_SatsInView <= 8) gpsIconName =
"gps2Bar";
362 if (g_SatsInView <= 4) gpsIconName =
"gps1Bar";
363 if (g_SatsInView < 0) gpsIconName =
"gpsGry";
366 gpsIconName =
"gpsGrn";
368 gpsIconName =
"gpsRed";
370 if (m_lastgpsIconName != gpsIconName) b_need_refresh =
true;
372 double rose_angle = -999.;
374 if ((fabs(m_parent->GetVPRotation()) > .01) ||
375 (fabs(m_parent->GetVPSkew()) > .01)) {
376 rose_angle = -m_parent->GetVPRotation();
380 if (fabs(m_rose_angle - rose_angle) > .1) b_need_refresh =
true;
384 int width = compassBg.GetWidth();
385 if (m_bshowGPS) width += gpsBg.GetWidth() + leftmargin;
387 if (!style->marginsInvisible)
388 width += leftmargin + style->GetToolSeparation();
390 m_StatBmp.Create(width, compassBg.GetHeight() + topmargin +
391 style->GetCompassBottomMargin());
393 m_rect.width = m_StatBmp.GetWidth();
394 m_rect.height = m_StatBmp.GetHeight();
398 m_MaskBmp = wxBitmap(m_StatBmp.GetWidth(), m_StatBmp.GetHeight());
399 if (style->marginsInvisible) {
400 wxMemoryDC sdc(m_MaskBmp);
401 sdc.SetBackground(*wxWHITE_BRUSH);
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);
410 wxMemoryDC sdc(m_MaskBmp);
411 sdc.SetBackground(*wxWHITE_BRUSH);
413 sdc.SetBrush(*wxBLACK_BRUSH);
414 sdc.SetPen(*wxBLACK_PEN);
415 sdc.DrawRoundedRectangle(0, 0, m_MaskBmp.GetWidth(), m_MaskBmp.GetHeight(),
417 sdc.SelectObject(wxNullBitmap);
419#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
420 m_StatBmp.SetMask(
new wxMask(m_MaskBmp, *wxWHITE));
424 mdc.SelectObject(m_StatBmp);
425 mdc.SetBackground(wxBrush(GetGlobalColor(
"COMP1"), wxBRUSHSTYLE_SOLID));
428 mdc.SetPen(wxPen(GetGlobalColor(
"UITX1"), 1));
429 mdc.SetBrush(wxBrush(GetGlobalColor(
"UITX1"), wxBRUSHSTYLE_TRANSPARENT));
431 if (!style->marginsInvisible)
432 mdc.DrawRoundedRectangle(0, 0, m_StatBmp.GetWidth(), m_StatBmp.GetHeight(),
435 wxPoint offset(leftmargin, topmargin);
439 wxPoint after_rotate;
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);
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);
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);
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));
465 if (style->HasBackground()) {
466 iconBm =
MergeBitmaps(compassBg, BMPRose, wxSize(0, 0));
471 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
473 mdc.DrawBitmap(iconBm, offset);
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);
483 offset.x += iconBm.GetWidth();
484 offset.x += style->GetToolSeparation();
486 m_rose_angle = rose_angle;
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);
499 wxBitmap gicon = style->GetIcon(gpsIconName, swidth, sheight);
500 if (gicon.GetHeight() != sheight)
501 gicon = style->GetIcon(gpsIconName, swidth - 1, sheight - 1,
true);
503 if (style->HasBackground()) {
509 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
510 mdc.DrawBitmap(iconBm, offset);
511 mdc.SelectObject(wxNullBitmap);
513 m_lastgpsIconName = gpsIconName;
517void ocpnCompass::CreateTexture() {
518#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
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;
531 int width_pot = m_tex_w;
532 int height_pot = m_tex_h;
534 int xp = image.GetWidth();
535 if (((xp != 0) && !(xp & (xp - 1))))
546 xp = image.GetHeight();
547 if (((xp != 0) && !(xp & (xp - 1))))
559 m_tex_h = height_pot;
561 GLuint format = GL_RGBA;
562 GLuint internalformat = GL_RGBA8;
566 unsigned char* teximage =
567 (
unsigned char*)malloc(stride * m_tex_w * m_tex_h);
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);
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;
581 glBindTexture(GL_TEXTURE_2D, m_texobj);
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,
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
589 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0,
590 format, GL_UNSIGNED_BYTE, teximage);
593 glBindTexture(GL_TEXTURE_2D, 0);
600void ocpnCompass::UpdateTexture() {
601#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
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;
614 int width_pot = m_tex_w;
615 int height_pot = m_tex_h;
617 int xp = image.GetWidth();
618 if (((xp != 0) && !(xp & (xp - 1))))
629 xp = image.GetHeight();
630 if (((xp != 0) && !(xp & (xp - 1))))
642 m_tex_h = height_pot;
644 GLuint format = GL_RGBA;
645 GLuint internalformat = GL_RGBA8;
649 unsigned char* teximage =
650 (
unsigned char*)malloc(stride * m_tex_w * m_tex_h);
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);
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;
664 glBindTexture(GL_TEXTURE_2D, m_texobj);
665 glEnable(GL_TEXTURE_2D);
667 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_tex_w, m_tex_h, format,
668 GL_UNSIGNED_BYTE, teximage);
671 glBindTexture(GL_TEXTURE_2D, 0);
Generic Chart canvas base.
ChartCanvas - Main chart display and interaction component.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
bool g_bSatValid
Indicates valid GNSS reception status based on satellite visibility and successful parsing of NMEA018...
Variables maintained by comm stack, read-only access for others.
Global variables stored in configuration file.
OpenGL chart rendering canvas.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
Position, course, speed, etc.
wxBitmap MergeBitmaps(wxBitmap back, wxBitmap front, wxSize offset)