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);
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.