32#include "model/ocpn_types.h"
33#include "model/own_ship.h"
38#include "glChartCanvas.h"
39#include "ocpn_frame.h"
42extern bool g_bSatValid;
43extern int g_SatsInView;
45extern bool g_btenhertz;
48#define GL_RGBA8 0x8058
51ocpnCompass::ocpnCompass(
ChartCanvas* parent,
bool bShowGPS) {
53 m_bshowGPS = bShowGPS;
56 _img_compass = style->GetIcon(_T(
"CompassRose"));
57 _img_gpsRed = style->GetIcon(_T(
"gpsRed"));
61 m_pStatBoxToolStaticBmp = NULL;
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());
76 m_cs = GLOBAL_COLOR_SCHEME_RGB;
79ocpnCompass::~ocpnCompass() {
82 glDeleteTextures(1, &m_texobj);
87 delete m_pStatBoxToolStaticBmp;
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) {
96 glGenTextures(1, &m_texobj);
100 if (g_bopengl && m_texobj ) {
101 glBindTexture(GL_TEXTURE_2D, m_texobj);
102 glEnable(GL_TEXTURE_2D);
104#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
111 uv[2] = (float)m_image_width / m_tex_w;
113 uv[4] = (float)m_image_width / m_tex_w;
114 uv[5] = (float)m_image_height / m_tex_h;
116 uv[7] = (float)m_image_height / m_tex_h;
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;
128 m_parent->GetglCanvas()->RenderTextures(dc, coords, uv, 4,
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);
147 glDisable(GL_TEXTURE_2D);
153 double scale = m_parent->GetContentScaleFactor();
155 wxImage image = m_StatBmp.ConvertToImage();
156 image.Rescale(image.GetWidth() *
scale, image.GetHeight() *
scale);
158 dc.DrawBitmap(bmp, m_rect.x, m_rect.y,
true);
160 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
162 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
164 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
169 dc.DrawBitmap(m_StatBmp, m_rect.x, m_rect.y,
true);
174bool ocpnCompass::MouseEvent(wxMouseEvent& event) {
179 if (!logicalRect.Contains(event.GetPosition())) {
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);
190 m_parent->SetUpMode(NORTH_UP_MODE);
196void ocpnCompass::SetColorScheme(ColorScheme cs) {
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()));
207 double scaleFactor = m_parent->GetContentScaleFactor();
209 wxPoint(m_rect.GetX() / scaleFactor, m_rect.GetY() / scaleFactor),
210 wxSize(m_rect.GetWidth() / scaleFactor,
211 m_rect.GetHeight() / scaleFactor));
215 wxRect logicalRect = m_rect;
220void ocpnCompass::UpdateStatus(
bool bnew) {
221 if (bnew) m_lastgpsIconName.Clear();
226 if (g_bopengl && m_texobj) CreateTexture();
230void ocpnCompass::SetScaleFactor(
float factor) {
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);
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);
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);
264 compassBg.GetWidth() + gpsBg.GetWidth() + style->GetCompassLeftMargin();
265 if (!style->marginsInvisible)
266 width += style->GetCompassLeftMargin() + style->GetToolSeparation();
268 m_rect = wxRect(style->GetCompassXOffset(), style->GetCompassYOffset(), width,
269 compassBg.GetHeight() + style->GetCompassTopMargin() +
270 style->GetCompassBottomMargin());
273void ocpnCompass::CreateBmp(
bool newColorScheme) {
276 wxString gpsIconName;
282 static wxBitmap compassBg, gpsBg;
283 static wxSize toolsize;
284 static int topmargin, leftmargin, radius;
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);
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);
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);
310 leftmargin = style->GetCompassLeftMargin();
311 topmargin = style->GetCompassTopMargin();
312 radius = style->GetCompassCornerRadius();
314 if (orient == wxTB_VERTICAL) style->SetOrientation(wxTB_VERTICAL);
317 bool b_need_refresh =
false;
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");
327 gpsIconName = _T(
"gpsGrn");
329 gpsIconName = _T(
"gpsRed");
331 if (m_lastgpsIconName != gpsIconName) b_need_refresh =
true;
333 double rose_angle = -999.;
335 if ((fabs(m_parent->GetVPRotation()) > .01) ||
336 (fabs(m_parent->GetVPSkew()) > .01)) {
337 rose_angle = -m_parent->GetVPRotation();
341 if (fabs(m_rose_angle - rose_angle) > .1) b_need_refresh =
true;
345 int width = compassBg.GetWidth();
346 if (m_bshowGPS) width += gpsBg.GetWidth() + leftmargin;
348 if (!style->marginsInvisible)
349 width += leftmargin + style->GetToolSeparation();
351 m_StatBmp.Create(width, compassBg.GetHeight() + topmargin +
352 style->GetCompassBottomMargin());
354 m_rect.width = m_StatBmp.GetWidth();
355 m_rect.height = m_StatBmp.GetHeight();
359 m_MaskBmp = wxBitmap(m_StatBmp.GetWidth(), m_StatBmp.GetHeight());
360 if (style->marginsInvisible) {
361 wxMemoryDC sdc(m_MaskBmp);
362 sdc.SetBackground(*wxWHITE_BRUSH);
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);
371 wxMemoryDC sdc(m_MaskBmp);
372 sdc.SetBackground(*wxWHITE_BRUSH);
374 sdc.SetBrush(*wxBLACK_BRUSH);
375 sdc.SetPen(*wxBLACK_PEN);
376 sdc.DrawRoundedRectangle(0, 0, m_MaskBmp.GetWidth(), m_MaskBmp.GetHeight(),
378 sdc.SelectObject(wxNullBitmap);
380#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
381 m_StatBmp.SetMask(
new wxMask(m_MaskBmp, *wxWHITE));
385 mdc.SelectObject(m_StatBmp);
386 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"COMP1")), wxBRUSHSTYLE_SOLID));
389 mdc.SetPen(wxPen(GetGlobalColor(_T(
"UITX1")), 1));
390 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UITX1")), wxBRUSHSTYLE_TRANSPARENT));
392 if (!style->marginsInvisible)
393 mdc.DrawRoundedRectangle(0, 0, m_StatBmp.GetWidth(), m_StatBmp.GetHeight(),
396 wxPoint offset(leftmargin, topmargin);
400 wxPoint after_rotate;
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);
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);
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);
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));
426 if (style->HasBackground()) {
427 iconBm = MergeBitmaps(compassBg, BMPRose, wxSize(0, 0));
432 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
434 mdc.DrawBitmap(iconBm, offset);
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);
444 offset.x += iconBm.GetWidth();
445 offset.x += style->GetToolSeparation();
447 m_rose_angle = rose_angle;
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);
460 wxBitmap gicon = style->GetIcon(gpsIconName, swidth, sheight);
461 if (gicon.GetHeight() != sheight)
462 gicon = style->GetIcon(gpsIconName, swidth - 1, sheight - 1,
true);
464 if (style->HasBackground()) {
465 iconBm = MergeBitmaps(gpsBg, gicon, wxSize(0, 0));
470 iconBm = ConvertTo24Bit(wxColor(0, 0, 0), iconBm);
471 mdc.DrawBitmap(iconBm, offset);
472 mdc.SelectObject(wxNullBitmap);
474 m_lastgpsIconName = gpsIconName;
478void ocpnCompass::CreateTexture() {
479#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
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;
492 int width_pot = m_tex_w;
493 int height_pot = m_tex_h;
495 int xp = image.GetWidth();
496 if (((xp != 0) && !(xp & (xp - 1))))
507 xp = image.GetHeight();
508 if (((xp != 0) && !(xp & (xp - 1))))
520 m_tex_h = height_pot;
522 GLuint format = GL_RGBA;
523 GLuint internalformat = GL_RGBA8;
527 unsigned char* teximage =
528 (
unsigned char*)malloc(stride * m_tex_w * m_tex_h);
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);
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;
542 glBindTexture(GL_TEXTURE_2D, m_texobj);
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,
548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
550 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0,
551 format, GL_UNSIGNED_BYTE, teximage);
554 glBindTexture(GL_TEXTURE_2D, 0);
561void ocpnCompass::UpdateTexture() {
562#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
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;
575 int width_pot = m_tex_w;
576 int height_pot = m_tex_h;
578 int xp = image.GetWidth();
579 if (((xp != 0) && !(xp & (xp - 1))))
590 xp = image.GetHeight();
591 if (((xp != 0) && !(xp & (xp - 1))))
603 m_tex_h = height_pot;
605 GLuint format = GL_RGBA;
606 GLuint internalformat = GL_RGBA8;
610 unsigned char* teximage =
611 (
unsigned char*)malloc(stride * m_tex_w * m_tex_h);
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);
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;
625 glBindTexture(GL_TEXTURE_2D, m_texobj);
626 glEnable(GL_TEXTURE_2D);
628 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_tex_w, m_tex_h, format,
629 GL_UNSIGNED_BYTE, teximage);
632 glBindTexture(GL_TEXTURE_2D, 0);
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.