40#include <wx/arrimpl.cpp>
43#include <wx/dcmemory.h>
44#include <wx/dynarray.h>
48#include <wx/glcanvas.h>
50#include <wx/jsonval.h>
53#include <wx/progdlg.h>
54#include <wx/stopwatch.h>
56#include <wx/tokenzr.h>
60#include "model/own_ship.h"
62#include "model/route.h"
63#include "model/routeman.h"
64#include "model/track.h"
68#include "chart_ctx_factory.h"
74#include "color_handler.h"
77#include "emboss_data.h"
79#include "glChartCanvas.h"
80#include "glTexCache.h"
84#include "mipmap/mipmap.h"
86#include "OCPNPlatform.h"
88#include "pluginmanager.h"
90#include "RolloverWin.h"
92#include "route_point_gui.h"
101#include "iENCToolbar.h"
102#include "shapefile_basemap.h"
103#include "s57_ocpn_utils.h"
105#ifdef USE_ANDROID_GLES2
106#include <GLES2/gl2.h>
112#include "androidUTIL.h"
113#elif defined(__WXQT__) || defined(__WXGTK__)
117#ifndef GL_ETC1_RGB8_OES
118#define GL_ETC1_RGB8_OES 0x8D64
121#ifndef GL_DEPTH_STENCIL_ATTACHMENT
122#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
125#if defined(__UNIX__) && !defined(__WXOSX__)
130 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
134 clock_gettime(CLOCK_REALTIME, &tp_end);
135 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
136 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
145#define printf printf2
146int __cdecl printf2(
const char *format, ...);
149#if defined(__ANDROID__)
150#include "androidUTIL.h"
151#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
155#ifndef GL_ETC1_RGB8_OES
156#define GL_ETC1_RGB8_OES 0x8D64
164extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
165 float near,
float far);
166#define glOrtho(a, b, c, d, e, f) \
168 glOrthof(a, b, c, d, e, f);
176#ifdef USE_ANDROID_GLES2
177#include <GLES2/gl2.h>
180#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
186extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
188extern s52plib *ps52plib;
189extern bool g_bopengl;
190extern bool g_bDebugOGL;
191extern bool g_bSoftwareGL;
194extern bool g_bShowChartBar;
196extern bool b_inCompressAllCharts;
197extern bool g_bShowCompassWin;
199extern GLenum g_texture_rectangle_format;
201extern int g_memCacheLimit;
202extern ColorScheme global_color_scheme;
203extern bool g_bquiting;
205extern int g_mipmap_max_level;
207extern int g_OwnShipIconType;
213extern RouteList *pRouteList;
214extern std::vector<Track *> g_TrackList;
215extern bool b_inCompressAllCharts;
216extern bool g_bGLexpert;
217extern bool g_bcompression_wait;
218extern float g_ShipScaleFactorExp;
220float g_GLMinCartographicLineWidth;
222extern bool g_fog_overzoom;
223extern double g_overzoom_emphasis_base;
224extern bool g_oz_vector_scale;
226extern int g_nCPUCount;
227extern bool g_running;
229extern unsigned int g_canvasConfig;
233extern bool g_PrintingInProgress;
237wxColor s_regionColor;
249#define APIENTRYP APIENTRY *
255#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
256#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
259PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
260PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
261PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
262PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
263PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
264PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
265PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
266PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
267PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
268PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
270PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
271PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
274PFNGLGENBUFFERSPROC s_glGenBuffers;
275PFNGLBINDBUFFERPROC s_glBindBuffer;
276PFNGLBUFFERDATAPROC s_glBufferData;
277PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
279#ifndef USE_ANDROID_GLES2
284typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
286PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
288#include <wx/arrimpl.cpp>
291GLuint g_raster_format = GL_RGB;
295wxStopWatch g_glstopwatch;
296double g_gl_ms_per_frame;
299int g_uncompressed_tile_size;
301extern wxProgressDialog *pprog;
302extern bool b_skipout;
303extern wxSize pprog_size;
304extern int pprog_count;
305extern int pprog_threads;
311bool glChartCanvas::s_b_useScissorTest;
312bool glChartCanvas::s_b_useStencil;
313bool glChartCanvas::s_b_useStencilAP;
314bool glChartCanvas::s_b_useFBO;
316#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
317static int s_tess_vertex_idx;
318static int s_tess_vertex_idx_this;
319static int s_tess_buf_len;
320static GLfloat *s_tess_work_buf;
323static vec4 s_tess_color;
333 while ( upd.HaveRects() )
335 wxRect rect = upd.GetRect();
336 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
343GLboolean QueryExtension(
const char *extName) {
354 extNameLen = strlen(extName);
356 p = (
char *)glGetString(GL_EXTENSIONS);
364 int n = strcspn(p,
" ");
365 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
373int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
374 16, WX_GL_STENCIL_SIZE, 8,
377glTestCanvas::glTestCanvas(wxWindow *parent)
378 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
382int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
383 16, WX_GL_STENCIL_SIZE, 8,
386EVT_PAINT(glChartCanvas::OnPaint)
387EVT_ACTIVATE(glChartCanvas::OnActivate)
388EVT_SIZE(glChartCanvas::OnSize)
389EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
393 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
394 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, _T(""))
397 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
402std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
404 {wxPENSTYLE_DOT, {1, 1}},
405 {wxPENSTYLE_LONG_DASH, {5, 5}},
406 {wxPENSTYLE_SHORT_DASH, {1, 5}},
407 {wxPENSTYLE_DOT_DASH, {5, 1}},
410void glChartCanvas::Init() {
415 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
417 m_cache_current_ch = NULL;
419 m_b_paint_enable =
true;
420 m_in_glpaint =
false;
422 m_cache_tex[0] = m_cache_tex[1] = 0;
425 m_b_BuiltFBO =
false;
426 m_b_DisableFBO =
false;
435 m_bpinchGuard =
false;
436 m_binGesture =
false;
439 m_last_render_time = -1;
446 m_gldc.SetGLCanvas(
this);
449 m_displayScale = 1.0;
450#if defined(__WXOSX__) || defined(__WXGTK3__)
452 m_displayScale = GetContentScaleFactor();
461 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
465 wxEVT_QT_PINCHGESTURE,
466 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
469 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
474 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
476 onGestureFinishTimerEvent,
480 ZOOM_TIMER, wxEVT_TIMER,
481 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
484 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
485 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
486 zoomTimer.SetOwner(
this, ZOOM_TIMER);
488#ifdef USE_ANDROID_GLES2
497#ifdef HAVE_WX_GESTURE_EVENTS
499 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
504 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
506 onGestureFinishTimerEvent,
510 ZOOM_TIMER, wxEVT_TIMER,
511 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
514 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
515 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
516 zoomTimer.SetOwner(
this, ZOOM_TIMER);
521 m_bgestureGuard =
false;
522 m_total_zoom_val = 1.0;
525#ifdef HAVE_WX_GESTURE_EVENTS
526 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
527 wxLogError(
"Failed to enable touch events");
536 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
538 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
539 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
541 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
542 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
544 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
545 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
547 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
548 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
554glChartCanvas::~glChartCanvas() {
560void glChartCanvas::FlushFBO(
void) {
561 if (m_bsetup) BuildFBO();
564void glChartCanvas::OnActivate(wxActivateEvent &event) {
565 m_pParentCanvas->OnActivate(event);
568void glChartCanvas::OnSize(wxSizeEvent &event) {
572 wxLogMessage(_T(
"Got OnSize event while NOT running"));
574 qDebug() <<
"OnSizeB";
581 if (!IsShown())
return;
583 SetCurrent(*m_pcontext);
587 SetSize(GetSize().x, GetSize().y);
595 if (m_bsetup && m_pcontext && IsShown()) {
596 SetCurrent(*m_pcontext);
602 wxLogMessage(_T(
"BuildFBO 3"));
607 ViewPort *vp = m_pParentCanvas->GetpVP();
610 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
613 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
617void glChartCanvas::MouseEvent(wxMouseEvent &event) {
618 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
624 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
626 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
629 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
633 if (m_bgestureGuard) {
634 m_pParentCanvas->r_rband.x = 0;
644 if (event.LeftUp()) {
646 if ((abs(panx) > 2) || (abs(pany) > 2)) {
649 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
656 if (!event.LeftDClick()) {
661 if (m_binPan && event.RightDown()) {
662 qDebug() <<
"Skip right on pan";
665 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
667 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
668 if (!m_bgestureGuard)
678#ifndef GL_MAX_RENDERBUFFER_SIZE
679#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
682#ifndef USE_ANDROID_GLES2
683bool glChartCanvas::buildFBOSize(
int fboSize) {
685 if (IsShown()) SetCurrent(*m_pcontext);
688 glDeleteTextures(2, m_cache_tex);
689 glDeleteFramebuffers(1, &m_fb0);
690 glDeleteRenderbuffers(1, &m_renderbuffer);
691 m_b_BuiltFBO =
false;
694 if (m_b_DisableFBO)
return false;
698 int rb_x = GetSize().x;
699 int rb_y = GetSize().y;
701 while (i < rb_x) i <<= 1;
705 while (i < rb_y) i <<= 1;
708 m_cache_tex_x = wxMax(rb_x, rb_y);
709 m_cache_tex_y = wxMax(rb_x, rb_y);
712 m_cache_tex_x = GetSize().x * m_displayScale;
713 m_cache_tex_y = GetSize().y * m_displayScale;
716 int err = GL_NO_ERROR;
718 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
721 if (err == GL_INVALID_ENUM) {
722 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
726 if (err == GL_NO_ERROR) {
727 if (fboSize > params) {
729 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
730 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
735 glGenFramebuffers(1, &m_fb0);
739 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
745 glGenRenderbuffers(1, &m_renderbuffer);
749 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
755 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
759 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
766 glGenTextures(2, m_cache_tex);
767 for (
int i = 0; i < 2; i++) {
768 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
769 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
771 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
773 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
774 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
777 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
779 if (m_b_useFBOStencil) {
781 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
782 m_cache_tex_x, m_cache_tex_y);
784 int err = glGetError();
787 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
791 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
792 GL_RENDERBUFFER_EXT, m_renderbuffer);
797 _T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"), err);
801 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
802 GL_RENDERBUFFER_EXT, m_renderbuffer);
807 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"),
813 GLenum depth_format = GL_DEPTH_COMPONENT24;
818 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
822 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
824 int err = glGetError();
828 _T(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X"),
834 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
835 GL_RENDERBUFFER_EXT, m_renderbuffer);
841 _T(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X"), err);
847 glBindTexture(GL_TEXTURE_2D, 0);
848 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
851 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
853 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
854 g_texture_rectangle_format, m_cache_tex[0], 0);
856 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
858 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
860 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
862 msg.Printf(_T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X"),
872#ifdef USE_ANDROID_GLES2
873bool glChartCanvas::buildFBOSize(
int fboSize) {
877 int rb_x = GetSize().x;
878 int rb_y = GetSize().y;
880 while (i < rb_x) i <<= 1;
884 while (i < rb_y) i <<= 1;
887 m_cache_tex_x = wxMax(rb_x, rb_y);
888 m_cache_tex_y = wxMax(rb_x, rb_y);
892 int err = GL_NO_ERROR;
894 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
897 if (err == GL_INVALID_ENUM) {
898 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
902 if (err == GL_NO_ERROR) {
903 if (fboSize > params) {
905 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
906 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
911 glGenFramebuffers(1, &m_fb0);
915 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
921 glGenRenderbuffers(1, &m_renderbuffer);
925 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
931 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
935 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
942 glGenTextures(2, m_cache_tex);
943 for (
int i = 0; i < 2; i++) {
944 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
945 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
947 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
949 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
950 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
953 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
956 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
962 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
966 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
967 GL_RENDERBUFFER, m_renderbuffer);
971 msg.Printf(_T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"),
976 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
977 GL_RENDERBUFFER, m_renderbuffer);
982 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"), err);
986 glBindTexture(GL_TEXTURE_2D, 0);
987 glBindFramebuffer(GL_FRAMEBUFFER, 0);
990 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
992 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
993 g_texture_rectangle_format, m_cache_tex[0], 0);
995 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
997 glBindFramebuffer(GL_FRAMEBUFFER, 0);
999 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
1002 _T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X"),
1012void glChartCanvas::BuildFBO() {
1015 glDeleteTextures(2, m_cache_tex);
1016 glDeleteFramebuffers(1, &m_fb0);
1017 glDeleteRenderbuffers(1, &m_renderbuffer);
1018 m_b_BuiltFBO =
false;
1021 if (m_b_DisableFBO)
return;
1024 int gl_width, gl_height;
1025 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
1026 int initialSize = NextPow2(gl_width * m_displayScale);
1031 wxString info = androidGetDeviceInfo();
1033 if (wxNOT_FOUND != info.Find(_T(
"GT-S6312"))) initialSize = 1024;
1036 if (!buildFBOSize(initialSize)) {
1037 glDeleteTextures(2, m_cache_tex);
1038 glDeleteFramebuffers(1, &m_fb0);
1039 glDeleteRenderbuffers(1, &m_renderbuffer);
1041 if (!buildFBOSize(1024)) {
1042 wxLogMessage(_T(
"BuildFBO C"));
1044 m_b_DisableFBO =
true;
1045 wxLogMessage(_T(
"OpenGL-> FBO Framebuffer unavailable"));
1046 m_b_BuiltFBO =
false;
1055 msg.Printf(_T(
"OpenGL-> Framebuffer OK, size = %d"), m_cache_tex_x);
1062 m_b_BuiltFBO =
true;
1067void glChartCanvas::SetupOpenGL() {
1068 SetCurrent(*m_pcontext);
1070 char *str = (
char *)glGetString(GL_RENDERER);
1073 wxLogMessage(_T(
"Failed to initialize OpenGL"));
1077 char render_string[80];
1078 strncpy(render_string, str, 79);
1079 m_renderer = wxString(render_string, wxConvUTF8);
1082 if (g_bSoftwareGL) msg.Printf(_T(
"OpenGL-> Software OpenGL"));
1083 msg.Printf(_T(
"OpenGL-> Renderer String: "));
1087 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1089 char version_string[80];
1090 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1091 msg.Printf(_T(
"OpenGL-> Version reported: "));
1092 m_version = wxString(version_string, wxConvUTF8);
1096 char GLSL_version_string[80];
1097 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1099 msg.Printf(_T(
"OpenGL-> GLSL Version reported: "));
1100 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1101 msg += m_GLSLversion;
1106 GLenum err = glewInit();
1107#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1108 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1113 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1116 wxLogMessage(
"GLEW init success!n");
1121 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1122 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1126#ifndef USE_ANDROID_GLES2
1127 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1129 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1131 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1132 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1139 if (m_renderer.Upper().Find(_T(
"MESA")) != wxNOT_FOUND) {
1141 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1143 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1146 s_b_useScissorTest =
true;
1148 if (GetRendererString().Find(_T(
"RADEON X600")) != wxNOT_FOUND)
1149 s_b_useScissorTest =
false;
1151 if (GetRendererString().Find(_T(
"GeForce")) !=
1153 s_b_useScissorTest =
false;
1155 bool bad_stencil_code =
false;
1158 if (GetRendererString().Find(_T(
"UniChrome")) != wxNOT_FOUND)
1159 bad_stencil_code =
true;
1162 if (GetRendererString().Find(_T(
"Mali")) != wxNOT_FOUND)
1163 bad_stencil_code =
true;
1166 glEnable(GL_STENCIL_TEST);
1167 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1169 glGetIntegerv(GL_STENCIL_BITS, &sb);
1172 glDisable(GL_STENCIL_TEST);
1174 s_b_useStencil =
false;
1175 if (stencil && (sb == 8)) s_b_useStencil =
true;
1177 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1178 g_texture_rectangle_format = GL_TEXTURE_2D;
1179 else if (QueryExtension(
"GL_OES_texture_npot"))
1180 g_texture_rectangle_format = GL_TEXTURE_2D;
1181 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1182 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1183 wxLogMessage(wxString::Format(_T(
"OpenGL-> Texture rectangle format: %x"),
1184 g_texture_rectangle_format));
1187 g_texture_rectangle_format = GL_TEXTURE_2D;
1191 g_b_EnableVBO =
true;
1194 g_b_EnableVBO =
false;
1198 wxLogMessage(_T(
"OpenGL-> Using Vertexbuffer Objects"));
1200 wxLogMessage(_T(
"OpenGL-> Vertexbuffer Objects unavailable"));
1204 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1206 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1209#ifndef USE_ANDROID_GLES2
1211 if (bad_stencil_code) s_b_useStencil =
false;
1225 if (m_displayScale > 1) m_b_DisableFBO =
true;
1234 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1236 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1237 g_texture_rectangle_format, m_cache_tex[0], 0);
1239 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1240 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1242 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1244 msg.Printf(_T(
" OpenGL-> Framebuffer Incomplete: %08X"), fb_status);
1246 m_b_DisableFBO =
true;
1252 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1256 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1258#ifdef USE_ANDROID_GLES2
1259 s_b_useStencilAP = s_b_useStencil;
1266 wxLogMessage(_T(
"OpenGL-> Using Framebuffer Objects"));
1268 if (m_b_useFBOStencil)
1269 wxLogMessage(_T(
"OpenGL-> Using FBO Stencil buffer"));
1271 wxLogMessage(_T(
"OpenGL-> FBO Stencil buffer unavailable"));
1273 wxLogMessage(_T(
"OpenGL-> Framebuffer Objects unavailable"));
1276 wxLogMessage(_T(
"OpenGL-> Using Stencil buffer clipping"));
1278 wxLogMessage(_T(
"OpenGL-> Using Depth buffer clipping"));
1280 if (s_b_useScissorTest && s_b_useStencil)
1281 wxLogMessage(_T(
"OpenGL-> Using Scissor Clipping"));
1284 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1286 MipMap_ResolveRoutines();
1290 lwmsg.Printf(_T(
"OpenGL-> Minimum cartographic line width: %4.1f"),
1291 g_GLMinCartographicLineWidth);
1292 wxLogMessage(lwmsg);
1293 lwmsg.Printf(_T(
"OpenGL-> Minimum symbol line width: %4.1f"),
1294 g_GLMinSymbolLineWidth);
1295 wxLogMessage(lwmsg);
1298 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1300#ifdef USE_ANDROID_GLES2
1301 g_GLOptions.m_bUseAcceleratedPanning =
true;
1307 int tex_dim = g_GLOptions.m_iTextureDimension;
1308 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1309 g_mipmap_max_level = max_level - 1;
1314 g_mipmap_max_level = 4;
1317 s_b_useFBO = m_b_BuiltFBO;
1321 ps52plib->SetGLOptions(
1322 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1323 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1324 g_GLMinSymbolLineWidth);
1328 SendJSONConfigMessage();
1331void glChartCanvas::SendJSONConfigMessage() {
1334 v[_T(
"setupComplete")] = m_bsetup;
1335 v[_T(
"useStencil")] = s_b_useStencil;
1336 v[_T(
"useStencilAP")] = s_b_useStencilAP;
1337 v[_T(
"useScissorTest")] = s_b_useScissorTest;
1338 v[_T(
"useFBO")] = s_b_useFBO;
1339 v[_T(
"useVBO")] = g_b_EnableVBO;
1340 v[_T(
"TextureRectangleFormat")] = g_texture_rectangle_format;
1341 wxString msg_id(_T(
"OCPN_OPENGL_CONFIG"));
1342 SendJSONMessageToAllPlugins(msg_id, v);
1345void glChartCanvas::SetupCompression() {
1346 int dim = g_GLOptions.m_iTextureDimension;
1349 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1350 wxLogMessage(_T(
"OpenGL-> SSE2 Instruction set not available"));
1351 goto no_compression;
1355 g_uncompressed_tile_size = dim * dim * 4;
1356 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1358 g_raster_format = GL_RGB;
1362 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1363 g_raster_format = GL_ETC1_RGB8_OES;
1365 wxLogMessage(_T(
"OpenGL-> Using oes etc1 compression"));
1369 if (GL_RGB == g_raster_format) {
1375 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1376 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1379 if (GetRendererString().Find(_T(
"Gallium")) != wxNOT_FOUND &&
1380 GetRendererString().Find(_T(
"NV")) != wxNOT_FOUND)
1381 g_raster_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
1383 g_raster_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1385 wxLogMessage(_T(
"OpenGL-> Using s3tc dxt1 compression"));
1386 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1387 g_raster_format = GL_COMPRESSED_RGB_FXT1_3DFX;
1389 wxLogMessage(_T(
"OpenGL-> Using 3dfx fxt1 compression"));
1391 wxLogMessage(_T(
"OpenGL-> No Useable compression format found"));
1392 goto no_compression;
1397 g_tile_size = 512 * 512 / 2;
1401 glGenTextures(1, &texture);
1402 glBindTexture(GL_TEXTURE_2D, texture);
1403 glTexImage2D(GL_TEXTURE_2D, 0, g_raster_format, dim, dim, 0, GL_RGB,
1404 GL_UNSIGNED_BYTE, NULL);
1405 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1407 glDeleteTextures(1, &texture);
1411 if (g_tile_size == 0)
goto no_compression;
1413 wxLogMessage(wxString::Format(
1414 _T(
"OpenGL-> Compressed tile size: %dkb (%d:1)"), g_tile_size / 1024,
1415 g_uncompressed_tile_size / g_tile_size));
1419 g_GLOptions.m_bTextureCompression =
false;
1421 g_tile_size = g_uncompressed_tile_size;
1422 wxLogMessage(wxString::Format(_T(
"OpenGL-> Not Using compression")));
1425void glChartCanvas::OnPaint(wxPaintEvent &event) {
1428 if (!m_pcontext)
return;
1436 SetCurrent(*m_pcontext);
1441 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1449 if (!m_b_paint_enable)
return;
1452 if (m_in_glpaint)
return;
1455 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1478bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1480#ifndef USE_ANDROID_GLES2
1481 return vp.m_projection_type == PROJECTION_MERCATOR ||
1482 vp.m_projection_type == PROJECTION_POLAR ||
1483 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1497#define NORM_FACTOR 4096.0
1498void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1499#ifndef USE_ANDROID_GLES2
1501 wxPoint2DDouble point;
1503 switch (vp.m_projection_type) {
1504 case PROJECTION_MERCATOR:
1505 case PROJECTION_EQUIRECTANGULAR:
1506 case PROJECTION_WEB_MERCATOR:
1509 glTranslated(point.m_x, point.m_y, 0);
1514 case PROJECTION_POLAR:
1518 glTranslated(point.m_x, point.m_y, 0);
1519 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1526 printf(
"ERROR: Unhandled projection\n");
1531 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1539 switch (vp.m_projection_type) {
1540 case PROJECTION_MERCATOR:
1541 case PROJECTION_EQUIRECTANGULAR:
1542 case PROJECTION_WEB_MERCATOR:
1546 case PROJECTION_POLAR:
1551 printf(
"ERROR: Unhandled projection\n");
1560bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1561 return vp.m_projection_type == PROJECTION_MERCATOR ||
1562 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1563 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1567 const LLRegion ®ion) {
1568 if (!CanClipViewport(vp))
return vp;
1571 LLBBox bbox = region.GetBox();
1573 if (!bbox.GetValid())
return vp;
1581 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1582 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1583 bbox.GetMaxLon() + 360);
1584 cvp.SetBBoxDirect(bbox);
1585 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1586 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1587 bbox.GetMaxLon() - 360);
1588 cvp.SetBBoxDirect(bbox);
1590 cvp.SetBBoxDirect(bbox);
1595void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1596 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1599 for (
Track *pTrackDraw : g_TrackList) {
1602 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1604 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1607 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1608 node = node->GetNext()) {
1609 Route *pRouteDraw = node->GetData();
1611 if (!pRouteDraw)
continue;
1614 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1619 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1624 if (vp.GetBBox().GetValid() && pWayPointMan) {
1625 for (wxRoutePointListNode *pnode =
1626 pWayPointMan->GetWaypointList()->GetFirst();
1627 pnode; pnode = pnode->GetNext()) {
1630 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1637void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1640 for (
Track *pTrackDraw : g_TrackList) {
1642 if (pActiveTrack && pActiveTrack->IsRunning())
1643 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1647 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1648 node = node->GetNext()) {
1649 Route *pRouteDraw = node->GetData();
1652 if (!pRouteDraw)
continue;
1655 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1661 if (pRouteDraw->IsSelected()) drawit++;
1664 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1665 if (!vp_box.IntersectOut(test_box))
1666 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1672 if (vp.GetBBox().GetValid() && pWayPointMan) {
1673 for (wxRoutePointListNode *pnode =
1674 pWayPointMan->GetWaypointList()->GetFirst();
1675 pnode; pnode = pnode->GetNext()) {
1684static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1688 switch (vp.m_projection_type) {
1689 case PROJECTION_TRANSVERSE_MERCATOR:
1690 lat_dist = 4, lon_dist = 1;
1692 case PROJECTION_POLYCONIC:
1693 lat_dist = 2, lon_dist = 1;
1695 case PROJECTION_ORTHOGRAPHIC:
1696 lat_dist = 2, lon_dist = 2;
1698 case PROJECTION_POLAR:
1699 lat_dist = 180, lon_dist = 1;
1701 case PROJECTION_STEREOGRAPHIC:
1702 case PROJECTION_GNOMONIC:
1703 lat_dist = 2, lon_dist = 1;
1705 case PROJECTION_EQUIRECTANGULAR:
1708 lat_dist = 2, lon_dist = 360;
1711 lat_dist = 180, lon_dist = 360;
1715void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1716 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1717 !ChartData->IsChartAvailable(dbIndex))
1722 ChartData->GetDBBoundingBox(dbIndex, box);
1723 if (!box.GetValid())
return;
1727 if (box.GetLonRange() == 360)
return;
1729 LLBBox vpbox = vp.GetBBox();
1731 double lon_bias = 0;
1733 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1736 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1737 color = GetGlobalColor(_T (
"YELO1" ));
1738 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1739 color = GetGlobalColor(_T (
"GREEN2" ));
1741 color = GetGlobalColor(_T (
"UINFR" ));
1743#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1744 float plylat, plylon;
1746 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1748 glColor3ub(color.Red(), color.Green(), color.Blue());
1749 glLineWidth(g_GLMinSymbolLineWidth);
1751 float lat_dist, lon_dist;
1752 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1755 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1759 nPly = ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1761 nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1763 bool begin =
false, sml_valid =
false;
1765 float lastplylat = 0.0;
1766 float lastplylon = 0.0;
1768 int modulo = (nPly == 0) ? 1 : nPly;
1769 for (
int i = 0; i < nPly + 1; i++) {
1771 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1773 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1777 if (lastplylon - plylon > 180)
1779 else if (lastplylon - plylon < -180)
1786 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1787 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1788 splits = wxMax(lat_splits, lon_splits) + 1;
1795 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1796 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1799 for (
double c = 0; c < splits; c++) {
1801 if (c == splits - 1)
1802 lat = plylat, lon = plylon;
1804 double d = (double)(c + 1) / splits;
1805 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1811 if (!std::isnan(s.m_x)) {
1814 glBegin(GL_LINE_STRIP);
1816 glVertex2f(s.m_x, s.m_y);
1822 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1823 lastplylat = plylat, lastplylon = plylon;
1828 }
while (++j < nAuxPlyEntries);
1830 glDisable(GL_LINE_SMOOTH);
1834 double nominal_line_width_pix =
1835 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1837 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1838 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), nominal_line_width_pix,
1841 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1842 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), nominal_line_width_pix,
1846 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), nominal_line_width_pix,
1849 float plylat1, plylon1;
1853 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
1854 if (0 == nAuxPlyEntries)
1857 std::vector<int> points_vector;
1859 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1860 int nPly = vec.size() / 2;
1862 if (nPly == 0)
return;
1864 for (
int i = 0; i < nPly; i++) {
1865 plylon1 = vec[i * 2];
1866 plylat1 = vec[i * 2 + 1];
1872 points_vector.push_back(pixx1);
1873 points_vector.push_back(pixy1);
1876 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1877 plylon1 += lon_bias;
1883 points_vector.push_back(pixx1);
1884 points_vector.push_back(pixy1);
1886 if (points_vector.size()) {
1887 std::vector<int>::iterator it = points_vector.begin();
1888 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1896 for (
int j = 0; j < nAuxPlyEntries; j++) {
1897 std::vector<int> points_vector;
1899 std::vector<float> vec = ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1900 int nAuxPly = vec.size() / 2;
1902 if (nAuxPly == 0)
continue;
1904 for (
int i = 0; i < nAuxPly; i++) {
1905 plylon1 = vec[i * 2];
1906 plylat1 = vec[i * 2 + 1];
1912 points_vector.push_back(pixx1);
1913 points_vector.push_back(pixy1);
1920 points_vector.push_back(pixx1);
1921 points_vector.push_back(pixy1);
1923 if (points_vector.size()) {
1924 std::vector<int>::iterator it = points_vector.begin();
1925 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1933extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1934 float &MinorSpacing);
1935extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1936void glChartCanvas::GridDraw() {
1937 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1939 ViewPort &vp = m_pParentCanvas->GetVP();
1941 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1945 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1947 double nlat, elon, slat, wlon;
1949 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1952 wxColour GridColor = GetGlobalColor(_T (
"SNDG1" ));
1954 if (!m_gridfont.IsBuilt()) {
1956 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1957 wxFont font = *dFont;
1958 int font_size = wxMax(10, dFont->GetPointSize());
1959 font.SetPointSize(font_size * m_displayScale);
1960 font.SetWeight(wxFONTWEIGHT_NORMAL);
1963 m_gridfont.Build(font, 1, dpi_factor);
1965 m_gridfont.SetColor(GridColor);
1970 LLBBox llbbox = vp.GetBBox();
1971 nlat = llbbox.GetMaxLat();
1972 slat = llbbox.GetMinLat();
1973 elon = llbbox.GetMaxLon();
1974 wlon = llbbox.GetMinLon();
1981 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1982 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1983 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1984 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1985 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1986 vp.m_projection_type == PROJECTION_POLAR ||
1987 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1990 if (straight_latitudes)
1993 latmargin = gridlatMajor / 2;
1995 slat = wxMax(slat, -90 + latmargin);
1996 nlat = wxMin(nlat, 90 - latmargin);
1998 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1999 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
2003 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
2010 float lon_step = elon - wlon;
2011 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
2013 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2015 s.x = INVALID_COORD;
2016 s.y = INVALID_COORD;
2017 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
2019 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2020 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2028 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
2029 lat += gridlatMinor) {
2032 gldc.DrawLine(0, r.y, 10, r.y,
true);
2033 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
2038 float lat_step = nlat - slat;
2039 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
2041 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2043 s.x = INVALID_COORD;
2044 s.y = INVALID_COORD;
2045 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
2047 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2048 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2056 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
2057 lon += gridlonMinor) {
2060 gldc.DrawLine(r.x, 0, r.x, 10,
false);
2061 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
2067 glEnable(GL_TEXTURE_2D);
2069 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2070 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
2073 CalcGridText(lat, gridlatMajor,
true);
2075 m_gridfont.GetTextExtent(st, 0, &iy);
2077 if (straight_latitudes) {
2082 float x = 0, y = -1;
2083 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
2084 if (y < 0 || y > h) {
2086 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
2089 m_gridfont.RenderString(st, x, y);
2093 double y1, y2, lat1, lon1, lat2, lon2;
2102 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2105 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2107 if (fabs(y - y1) < fabs(y - y2))
2113 error = fabs(r.m_x);
2114 if (--maxiters == 0)
break;
2115 }
while (error > 1 && error < lasterror);
2117 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2123 m_gridfont.RenderString(st, r.m_x, r.m_y);
2127 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2128 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2137 else if (xlon <= -180.0)
2140 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2142 m_gridfont.GetTextExtent(st, &ix, 0);
2144 if (straight_longitudes) {
2145 float x = -1, y = 0;
2146 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2147 if (x < 0 || x > w) {
2149 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2152 m_gridfont.RenderString(st, x, y);
2156 double x1, x2, lat1, lon1, lat2, lon2;
2164 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2167 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2169 if (fabs(x - x1) < fabs(x - x2))
2175 error = fabs(r.m_y);
2176 }
while (error > 1 && error < lasterror);
2178 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2183 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2185 m_gridfont.RenderString(st, r.m_x, r.m_y);
2189 glDisable(GL_TEXTURE_2D);
2190 glDisable(GL_BLEND);
2195 if (!emboss)
return;
2197 int w = emboss->width, h = emboss->height;
2199 glEnable(GL_TEXTURE_2D);
2202 if (!emboss->gltexind) {
2204 emboss->glwidth = NextPow2(emboss->width);
2205 emboss->glheight = NextPow2(emboss->height);
2208 int size = emboss->glwidth * emboss->glheight;
2209 char *data =
new char[2 * size];
2210 for (
int i = 0; i < h; i++) {
2211 for (
int j = 0; j < emboss->glwidth; j++) {
2213 data[2 * ((i * emboss->glwidth) + j)] =
2214 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2215 data[2 * ((i * emboss->glwidth) + j) + 1] =
2216 (char)abs((emboss->pmap[(i * w) + j]));
2221 glGenTextures(1, &emboss->gltexind);
2222 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2223 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2224 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2232 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2236 int x = emboss->x, y = emboss->y;
2238 float wp = (float)w / emboss->glwidth;
2239 float hp = (float)h / emboss->glheight;
2265 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2267 glDisable(GL_BLEND);
2268 glDisable(GL_TEXTURE_2D);
2271void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2272 if (!m_pParentCanvas->GetVP().IsValid())
return;
2273 wxPoint GPSOffsetPixels(0, 0);
2274 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2277 float pCog = std::isnan(gCog) ? 0 : gCog;
2278 float pSog = std::isnan(gSog) ? 0 : gSog;
2282 double shift_dx = 0;
2283 double shift_dy = 0;
2284 if (m_pParentCanvas->m_bFollow && !m_pParentCanvas->m_MouseDragging) {
2285 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2286 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2287 if (m_pParentCanvas->m_bLookAhead) {
2293 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2294 angle += m_pParentCanvas->GetVPRotation();
2295 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2297 lGPSPoint.m_x -= shift_dx / cos(gLat * PI / 180.);
2298 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2300 lGPSPoint.m_y += shift_dy / cos(gLat * PI / 180.);
2305 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2306 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2313 lShipMidPoint = lGPSPoint;
2317 float icon_hdt = pCog;
2318 if (!std::isnan(gHdt)) icon_hdt = gHdt;
2321 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2325 double osd_head_lat, osd_head_lon;
2326 wxPoint2DDouble osd_head_point;
2328 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2332 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2334 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2335 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2336 icon_rad += (float)PI;
2340 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2344 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2350 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2351 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2352 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2357 float scale_factor = 1.0;
2359 if ((g_ChartScaleFactorExp > 1.0) && (g_OwnShipIconType == 0))
2360 scale_factor = (log(g_ChartScaleFactorExp) + 1.0) * 1.1;
2362 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2363 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2364 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2366 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2368 float nominal_ownship_size_pixels =
2370 nominal_ownship_size_mm);
2372 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2374 wxPen ppSmallScaleShip;
2375 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2377 wxPen(GetGlobalColor(_T (
"URED" )), v / 5, wxPENSTYLE_SOLID);
2380 wxPen(GetGlobalColor(_T (
"YELO1" )), v / 5, wxPENSTYLE_SOLID);
2381 dc.SetPen(ppSmallScaleShip);
2384 wxBrush(GetGlobalColor(_T (
"URED" )), wxBRUSHSTYLE_TRANSPARENT));
2387 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2388 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2389 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2390 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2393 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2394 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2397 int draw_color = SHIP_INVALID;
2398 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2399 draw_color = SHIP_NORMAL;
2400 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2401 draw_color = SHIP_LOWACCURACY;
2409 ownship_color = draw_color;
2411 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2413 glGenTextures(1, &ownship_tex);
2414 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2420 if (m_pParentCanvas->m_pos_image_user) {
2421 switch (draw_color) {
2423 image = *m_pParentCanvas->m_pos_image_user_grey;
2426 image = *m_pParentCanvas->m_pos_image_user;
2428 case SHIP_LOWACCURACY:
2429 image = *m_pParentCanvas->m_pos_image_user_yellow;
2433 switch (draw_color) {
2435 image = *m_pParentCanvas->m_pos_image_grey;
2438 image = *m_pParentCanvas->m_pos_image_red;
2440 case SHIP_LOWACCURACY:
2441 image = *m_pParentCanvas->m_pos_image_yellow;
2446 int w = image.GetWidth(), h = image.GetHeight();
2447 int glw = NextPow2(w), glh = NextPow2(h);
2448 ownship_size = wxSize(w, h);
2449 ownship_tex_size = wxSize(glw, glh);
2451 unsigned char *d = image.GetData();
2452 unsigned char *a = image.GetAlpha();
2453 unsigned char *e =
new unsigned char[4 * w * h];
2456 for (
int p = 0; p < w * h; p++) {
2457 e[4 * p + 0] = d[3 * p + 0];
2458 e[4 * p + 1] = d[3 * p + 1];
2459 e[4 * p + 2] = d[3 * p + 2];
2460 e[4 * p + 3] = a[p];
2463 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2464 GL_UNSIGNED_BYTE, 0);
2466 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2472#ifndef USE_ANDROID_GLES2
2473 if (m_pParentCanvas->m_pos_image_user)
2474 glColor4ub(255, 255, 255, 255);
2475 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2476 glColor4ub(255, 0, 0, 255);
2477 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2478 glColor4ub(255, 255, 0, 255);
2480 glColor4ub(128, 128, 128, 255);
2482 float scale_factor_y = 1.0;
2483 float scale_factor_x = 1.0;
2485 int ownShipWidth = 22;
2486 int ownShipLength = 84;
2487 lShipMidPoint = lGPSPoint;
2490 if (g_OwnShipIconType != 0)
2491 m_pParentCanvas->ComputeShipScaleFactor(
2492 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2493 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2498 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2499 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2500 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2504 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2505 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2509 float gps_circle_radius = 3.0;
2511 if (g_OwnShipIconType == 0) {
2513 glEnable(GL_TEXTURE_2D);
2514 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2523 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2524 if (m_pParentCanvas->m_pos_image_user)
2525 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2527 float nominal_ownship_size_mm =
2528 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2530 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2531 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2533 float nominal_ownship_size_pixels =
2534 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2536 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2537 nominal_ownship_size_pixels = wxMax(
2538 20.0, nominal_ownship_size_pixels);
2541 float h = nominal_ownship_size_pixels * scale_factor_y;
2542 float w = nominal_ownship_size_pixels * scale_factor_x *
2543 ownship_size.x / ownship_size.y;
2544 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2545 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2551 gps_circle_radius = w / 5;
2553 float uv[8], coords[8];
2572 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2573 lShipMidPoint.m_x, lShipMidPoint.m_y,
2575 glDisable(GL_TEXTURE_2D);
2576 }
else if (g_OwnShipIconType == 1) {
2578 glEnable(GL_TEXTURE_2D);
2579 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2581 float nominal_ownship_size_pixels_y = 84;
2582 float nominal_ownship_size_pixels_x = 22;
2584 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2585 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2587 float u = (float)ownship_size.x / ownship_tex_size.x,
2588 v = (
float)ownship_size.y / ownship_tex_size.y;
2591 gps_circle_radius = w / 5;
2593 float uv[8], coords[8];
2612 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2613 lShipMidPoint.m_x, lShipMidPoint.m_y,
2616 glDisable(GL_TEXTURE_2D);
2617 }
else if (g_OwnShipIconType == 2) {
2625 wxPoint shipPoints[6];
2627 wxColour colour = m_pParentCanvas->ShipColor();
2628 wxPen ppPen(*wxBLACK, 1);
2629 wxBrush ppBrush(colour);
2631 dc.SetBrush(ppBrush);
2633 shipPoints[0].x = 0 * scale_factor_x;
2634 shipPoints[0].y = -28 * scale_factor_y;
2635 shipPoints[1].x = 11 * scale_factor_x;
2636 shipPoints[1].y = -28 * scale_factor_y;
2637 shipPoints[2].x = 11 * scale_factor_x;
2638 shipPoints[2].y = 42 * scale_factor_y;
2639 shipPoints[3].x = 0 * scale_factor_x;
2640 shipPoints[3].y = 42 * scale_factor_y;
2641 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2644 shipPoints[0].x = 0 * scale_factor_x;
2645 shipPoints[0].y = -42 * scale_factor_y;
2646 shipPoints[1].x = 5 * scale_factor_x;
2647 shipPoints[1].y = -42 * scale_factor_y;
2648 shipPoints[2].x = 11 * scale_factor_x;
2649 shipPoints[2].y = -28 * scale_factor_y;
2650 shipPoints[3].x = 0 * scale_factor_x;
2651 shipPoints[3].y = -28 * scale_factor_y;
2652 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2655 shipPoints[0].x = 0 * scale_factor_x;
2656 shipPoints[0].y = -28 * scale_factor_y;
2657 shipPoints[1].x = -11 * scale_factor_x;
2658 shipPoints[1].y = -28 * scale_factor_y;
2659 shipPoints[2].x = -11 * scale_factor_x;
2660 shipPoints[2].y = 42 * scale_factor_y;
2661 shipPoints[3].x = 0 * scale_factor_x;
2662 shipPoints[3].y = 42 * scale_factor_y;
2663 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2666 shipPoints[0].x = 0 * scale_factor_x;
2667 shipPoints[0].y = -42 * scale_factor_y;
2668 shipPoints[1].x = -5 * scale_factor_x;
2669 shipPoints[1].y = -42 * scale_factor_y;
2670 shipPoints[2].x = -11 * scale_factor_x;
2671 shipPoints[2].y = -28 * scale_factor_y;
2672 shipPoints[3].x = 0 * scale_factor_x;
2673 shipPoints[3].y = -28 * scale_factor_y;
2674 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2678 double p1x = -11 * scale_factor_x;
2679 double p2x = 11 * scale_factor_x;
2683 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2685 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2687 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2689 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2690 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2691 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2695 p1y = -42 * scale_factor_y;
2696 p2y = 42 * scale_factor_y;
2697 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2698 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2699 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2700 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2701 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2702 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2705 img_height = ownShipLength * scale_factor_y;
2708 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2710 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
2712 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"CHWHT" ))));
2714 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2718 glDisable(GL_LINE_SMOOTH);
2719 glDisable(GL_POLYGON_SMOOTH);
2720 glDisable(GL_BLEND);
2723 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2727void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2728 ViewPort &vp = m_pParentCanvas->GetVP();
2733 Route *active_route = g_pRouteMan->GetpActiveRoute();
2742 g_overlayCanvas = m_pParentCanvas;
2744 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
2745 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2746 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_LEGACY);
2751 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2753 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2754 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2756 m_pParentCanvas->AlertDraw(dc);
2758 m_pParentCanvas->RenderVisibleSectorLights(dc);
2760 m_pParentCanvas->RenderRouteLegs(dc);
2761 m_pParentCanvas->RenderShipToActive(dc,
true);
2762 m_pParentCanvas->ScaleBarDraw(dc);
2763 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2764 m_pParentCanvas->extendedSectorLegs);
2766 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2767 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_SHIPS);
2771void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2772 if (m_pParentCanvas->GetPiano()) {
2773 int canvas_height = GetClientSize().y;
2774 canvas_height *= m_displayScale;
2776 m_pParentCanvas->GetPiano()->DrawGL(
2777 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2781void glChartCanvas::DrawQuiting() {
2782#ifndef USE_ANDROID_GLES2
2783 GLubyte pattern[8][8];
2784 for (
int y = 0; y < 8; y++)
2785 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2788 glEnable(GL_TEXTURE_2D);
2789 glBindTexture(GL_TEXTURE_2D, 0);
2791 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2792 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2793 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2795 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2799 float x = GetSize().x, y = GetSize().y;
2800 float u = x / 8, v = y / 8;
2813 glDisable(GL_TEXTURE_2D);
2814 glDisable(GL_BLEND);
2818void glChartCanvas::DrawCloseMessage(wxString msg) {
2819#ifndef USE_ANDROID_GLES2
2823 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2827 texfont.Build(*pfont, 1, 1);
2829 texfont.GetTextExtent(msg, &w, &h);
2831 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2832 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2834 glColor3ub(243, 229, 47);
2838 glVertex2i(xp + w, yp);
2839 glVertex2i(xp + w, yp + h);
2840 glVertex2i(xp, yp + h);
2845 glColor3ub(0, 0, 0);
2846 glEnable(GL_TEXTURE_2D);
2847 texfont.RenderString(msg, xp, yp);
2848 glDisable(GL_TEXTURE_2D);
2849 glDisable(GL_BLEND);
2856static std::list<double *> combine_work_data;
2857static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2858 GLfloat weight[4], GLdouble **dataOut) {
2859 double *vertex =
new double[3];
2860 combine_work_data.push_back(vertex);
2861 memcpy(vertex, coords, 3 * (
sizeof *coords));
2865#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2866void vertexCallbackD_GLSL(GLvoid *vertex) {
2868 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2869 int new_buf_len = s_tess_buf_len + 100;
2870 GLfloat *tmp = s_tess_work_buf;
2873 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2874 if (NULL == s_tess_work_buf) {
2878 s_tess_buf_len = new_buf_len;
2881 GLdouble *pointer = (GLdouble *)vertex;
2883 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2884 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2889void beginCallbackD_GLSL(GLenum mode) {
2890 s_tess_vertex_idx_this = s_tess_vertex_idx;
2895void endCallbackD_GLSL() {
2899 shader->SetUniformMatrix4fv(
"MVMatrix",
2900 (GLfloat *)s_tessVP.vp_matrix_transform);
2902 mat4x4 identityMatrix;
2903 mat4x4_identity(identityMatrix);
2904 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2908 colorv[0] = s_regionColor.Red() / float(256);
2909 colorv[1] = s_regionColor.Green() / float(256);
2910 colorv[2] = s_regionColor.Blue() / float(256);
2911 colorv[3] = s_regionColor.Alpha() / float(256);
2912 shader->SetUniform4fv(
"color", colorv);
2914 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2915 shader->SetAttributePointerf(
"position", bufPt);
2917 glDrawArrays(s_tess_mode, 0, s_nvertex);
2922void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2924void beginCallbackD(GLenum mode) { glBegin(mode); }
2926void endCallbackD() { glEnd(); }
2930void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2931 float lat_dist, lon_dist;
2932 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2934 GLUtesselator *tobj = gluNewTess();
2935 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2937#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2938 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2939 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2940 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2941 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2945 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2946 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2947 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2948 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2951 gluTessNormal(tobj, 0, 0, 1);
2953 gluTessBeginPolygon(tobj, NULL);
2954 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2955 i != region.contours.end(); i++) {
2956 gluTessBeginContour(tobj);
2957 contour_pt l = *i->rbegin();
2959 bool sml_valid =
false;
2960 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2961 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2962 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2963 int splits = wxMax(lat_splits, lon_splits) + 1;
2969 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2970 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2973 for (
int i = 0; i < splits; i++) {
2975 if (i == splits - 1)
2976 lat = j->y, lon = j->x;
2978 double d = (double)(i + 1) / splits;
2979 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2983 if (std::isnan(q.m_x))
continue;
2985 double *p =
new double[6];
2990 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2995 gluTessVertex(tobj, p, p);
2996 combine_work_data.push_back(p);
3000 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
3002 gluTessEndContour(tobj);
3004 gluTessEndPolygon(tobj);
3006 gluDeleteTess(tobj);
3008 for (std::list<double *>::iterator i = combine_work_data.begin();
3009 i != combine_work_data.end(); i++)
3011 combine_work_data.clear();
3016void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
3017 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3019 if (s_b_useStencil) {
3021 glEnable(GL_STENCIL_TEST);
3023 glClear(GL_STENCIL_BUFFER_BIT);
3027 glStencilFunc(GL_ALWAYS, 1, 1);
3028 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
3031#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3035 glEnable(GL_DEPTH_TEST);
3036 glDepthFunc(GL_ALWAYS);
3037 glDepthMask(GL_TRUE);
3039 glClear(GL_DEPTH_BUFFER_BIT);
3052 glTranslatef(0, 0, .5);
3056 s_regionColor = wxColor(0, 0, 0, 255);
3057 DrawRegion(vp, region);
3059 if (s_b_useStencil) {
3062 glStencilFunc(GL_EQUAL, 1, 1);
3063 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3066#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3068 glDepthFunc(GL_GREATER);
3069 glDepthMask(GL_FALSE);
3070 glTranslatef(0, 0, -.5);
3073 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3076void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
3080 if (s_b_useStencil && s_b_useScissorTest) {
3082 if (rect != vp_rect) {
3083 glEnable(GL_SCISSOR_TEST);
3084 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3087#ifndef USE_ANDROID_GLES2
3093void glChartCanvas::DisableClipRegion() {
3094 glDisable(GL_SCISSOR_TEST);
3095 glDisable(GL_STENCIL_TEST);
3096 glDisable(GL_DEPTH_TEST);
3099void glChartCanvas::Invalidate() {
3101 m_cache_vp.Invalidate();
3107 if (!pBSBChart)
return;
3109 if (b_inCompressAllCharts)
3113 wxString key = chart->GetHashKey();
3116 ChartPathHashTexfactType &hash = g_glTextureManager->m_chart_texfactory_hash;
3117 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3120 if (ittf == hash.end()) {
3122 hash[key]->SetHashKey(key);
3125 pTexFact = hash[key];
3126 pTexFact->SetLRUTime(++m_LRUtime);
3131 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3132 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3139 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3140 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3141 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3142 base_level = log(scalefactor) / log(2.0);
3146 if (base_level > g_mipmap_max_level) base_level = g_mipmap_max_level;
3151 glEnable(GL_TEXTURE_2D);
3152#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3153 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3155 glEnableClientState(GL_VERTEX_ARRAY);
3156 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3161 pTexFact->GetCenter(lat, lon);
3162 MultMatrixViewPort(vp, lat, lon);
3166 LLBBox box = region.GetBox();
3169 if (g_memCacheLimit > 0) {
3171 GetMemoryStatus(0, &mem_used);
3174 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3175 for (
int i = 0; i < numtiles; i++) {
3177 if (region.IntersectOut(tile->box)) {
3180 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3181 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3183 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3184 global_color_scheme, mem_used);
3188 coords = tile->m_coords;
3190 coords =
new float[2 * tile->m_ncoords];
3191 for (
int i = 0; i < tile->m_ncoords; i++) {
3193 tile->m_coords[2 * i + 1]);
3194 coords[2 * i + 0] = p.m_x;
3195 coords[2 * i + 1] = p.m_y;
3199#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3200 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3201 m_pParentCanvas->GetpVP());
3204 glDisable(GL_TEXTURE_2D);
3208 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3209 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3210 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3212 if (!texture) glEnable(GL_TEXTURE_2D);
3214 if (!use_norm_vp)
delete[] coords;
3218 glDisable(GL_TEXTURE_2D);
3220#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3221 if (use_norm_vp) glPopMatrix();
3223 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3224 glDisableClientState(GL_VERTEX_ARRAY);
3228void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3230 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3231 m_pParentCanvas->m_pQuilt->IsBusy())
3235 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3244 LLRegion region = vp.GetLLRegion(rect_region);
3246 LLRegion rendered_region;
3252 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3260 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3262 LLRegion get_region = pqp->ActiveRegion;
3263 bool b_rendered =
false;
3265 if (!pqp->b_overlay) {
3266 get_region.Intersect(region);
3267 if (!get_region.Empty()) {
3268 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3271 SetClipRegion(vp, get_region );
3272 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3273 DisableClipRegion();
3276 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3277 SetClipRegion(vp, pqp->ActiveRegion );
3278 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3280 DisableClipRegion();
3283 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3284 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3285 RenderNoDTA(vp, get_region);
3286 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3291 if (Chs57->m_RAZBuilt) {
3292 RenderNoDTA(vp, get_region);
3293 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3294 rect_region, get_region);
3295 DisableClipRegion();
3300 const LLRegion &oregion = get_region;
3301 LLBBox box = oregion.GetBox();
3312 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3315 ViewPort cvp = ClippedViewport(vp, get_region);
3316 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3317 SetClipRegion(cvp, get_region);
3318 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3319 GetGlobalColor(_T (
"LANDA" )),
3320 GetGlobalColor(_T (
"DEPMS" )));
3321 RenderWorldChart(gldc, cvp, srect, world);
3322 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3323 global_color_scheme);
3324 DisableClipRegion();
3331 SetClipRegion(vp, get_region);
3332 RenderNoDTA(vp, get_region);
3333 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3335 DisableClipRegion();
3338 SetClipRegion(vp, get_region);
3339 RenderNoDTA(vp, get_region);
3340 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3342 DisableClipRegion();
3358 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3362 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3363 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3365 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3366 if (pqp->b_Valid && pqp->b_overlay &&
3367 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3368 LLRegion get_region = pqp->ActiveRegion;
3370 get_region.Intersect(region);
3371 if (!get_region.Empty()) {
3374 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3379 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3386 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3391 ViewPort vph = m_pParentCanvas->GetVP();
3392 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3395 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3397 if (!hiregion.Empty()) {
3401 switch (global_color_scheme) {
3402 case GLOBAL_COLOR_SCHEME_DAY:
3405 case GLOBAL_COLOR_SCHEME_DUSK:
3408 case GLOBAL_COLOR_SCHEME_NIGHT:
3416#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3418 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3420 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3423 DrawRegion(vp, hiregion);
3425 glDisable(GL_BLEND);
3430 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3432 if (!hiregion.Empty()) {
3436 switch (global_color_scheme) {
3437 case GLOBAL_COLOR_SCHEME_DAY:
3440 case GLOBAL_COLOR_SCHEME_DUSK:
3443 case GLOBAL_COLOR_SCHEME_NIGHT:
3452#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3454 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3456 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3459 DrawRegion(vp, hiregion);
3461 glDisable(GL_BLEND);
3465 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3468void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3470 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3471 m_pParentCanvas->m_pQuilt->IsBusy())
3475 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3477 LLRegion region = vp.GetLLRegion(rect_region);
3479 LLRegion rendered_region;
3481 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3483 LLRegion get_region = pqp->ActiveRegion;
3485 if (!pqp->b_overlay) {
3486 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3489 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3494 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3501 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3529void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3530 ViewPort &vp = m_pParentCanvas->VPoint;
3538 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3539 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3542 LLRegion chart_region;
3544 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3545 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3546 CHART_FAMILY_RASTER) {
3554 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3555 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3556 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3558 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3562 for (
int i = 1; i < 6; i += 2)
3563 if (fabs(ll[i] - ll[i + 2]) > 180) {
3565 for (
int i = 1; i < 8; i += 2)
3566 if (ll[i] < 0) ll[i] += 360;
3570 chart_region = LLRegion(4, ll);
3573 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3575 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3576 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3577 chart_region = LLRegion(4, ll);
3580 chart_region = vp.b_quilt
3581 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3582 : m_pParentCanvas->m_singleChart->GetValidRegion();
3584 bool world_view =
false;
3586 wxRect rect = upd.GetRect();
3587 LLRegion background_region = vp.GetLLRegion(rect);
3590 background_region.Subtract(chart_region);
3592 if (!background_region.Empty()) {
3593 ViewPort cvp = ClippedViewport(vp, background_region);
3594 SetClipRect(cvp, rect,
false);
3595 RenderWorldChart(dc, cvp, rect, world_view);
3596 DisableClipRegion();
3601 RenderQuiltViewGL(vp, rect_region);
3603 LLRegion region = vp.GetLLRegion(rect_region);
3604 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3605 CHART_FAMILY_RASTER) {
3606 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3607 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3608 *m_pcontext, vp, rect_region, region);
3610 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3611 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3612 CHART_FAMILY_VECTOR) {
3613 chart_region.Intersect(region);
3614 RenderNoDTA(vp, chart_region);
3615 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3616 rect_region, region);
3622void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3624 wxColour color = GetGlobalColor(_T (
"NODTA" ));
3625#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3627 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3629 glColor4ub(163, 180, 183, transparency);
3632 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3636 s_regionColor = color;
3639 DrawRegion(vp, region);
3643void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3646 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3648 glEnable(GL_SCISSOR_TEST);
3649 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3655 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3656#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3658 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3662 colorv[0] = water.Red() / float(256);
3663 colorv[1] = water.Green() / float(256);
3664 colorv[2] = water.Blue() / float(256);
3666 shader->SetUniform4fv(
"color", colorv);
3677 shader->SetAttributePointerf(
"position", pf);
3679 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3689 gShapeBasemap.RenderViewOnDC(dc, vp);
3691 glDisable(GL_SCISSOR_TEST);
3699void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3700 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3702 DrawStaticRoutesTracksAndWaypoints(vp);
3704 DisableClipRegion();
3707void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3709 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3713 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3714 if (!bmp.Ok())
return;
3716 wxImage image = bmp.ConvertToImage();
3717 int w = image.GetWidth(), h = image.GetHeight();
3720 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3721 tex_w = w, tex_h = h;
3723 tex_w = NextPow2(w), tex_h = NextPow2(h);
3725 m_tideTexWidth = tex_w;
3726 m_tideTexHeight = tex_h;
3728 unsigned char *d = image.GetData();
3729 unsigned char *a = image.GetAlpha();
3731 unsigned char mr, mg, mb;
3732 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3734 unsigned char *e =
new unsigned char[4 * w * h];
3736 for (
int y = 0; y < h; y++)
3737 for (
int x = 0; x < w; x++) {
3738 unsigned char r, g, b;
3739 int off = (y * w + x);
3749 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3753 glGenTextures(1, &m_tideTex);
3755 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3756 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3757 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3759 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3760 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3761 GL_UNSIGNED_BYTE, e);
3763 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3764 GL_UNSIGNED_BYTE, 0);
3765 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3774 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3775 glEnable(GL_TEXTURE_2D);
3778#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3780 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
3781 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
3784 if ((type ==
't') || (type ==
'T'))
3789 if (BBox.Contains(lat, lon)) {
3798 scale *= getAndroidDisplayDensity();
3800 double width2 =
scale * m_tideTexWidth / 2;
3801 double height2 =
scale * m_tideTexHeight / 2;
3816 coords[0] = xp - width2;
3817 coords[1] = yp - height2;
3818 coords[2] = xp - width2;
3819 coords[3] = yp + height2;
3820 coords[4] = xp + width2;
3821 coords[5] = yp + height2;
3822 coords[6] = xp + width2;
3823 coords[7] = yp - height2;
3825 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3832 glDisable(GL_TEXTURE_2D);
3833 glDisable(GL_BLEND);
3834 glBindTexture(GL_TEXTURE_2D, 0);
3836 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3839void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3840 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3843void glChartCanvas::SetColorScheme(ColorScheme cs) {
3844 if (!m_bsetup)
return;
3846 glDeleteTextures(1, &m_tideTex);
3847 glDeleteTextures(1, &m_currentTex);
3853void glChartCanvas::RenderGLAlertMessage() {
3854 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3855 wxString msg = m_pParentCanvas->GetAlertString();
3858 m_gldc.SetFont(*pfont);
3862 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3869 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3870 int xp = sbr.x + sbr.width + 5;
3872 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
3873 m_gldc.SetPen(ppPen1);
3874 m_gldc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
3876 m_gldc.DrawRectangle(xp, yp, w, h);
3878 m_gldc.DrawText(msg, xp, yp);
3882unsigned long quiltHash;
3884extern wxLongLong s_t0;
3887void glChartCanvas::Render() {
3888 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3889 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3890 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3895 if (!g_PrintingInProgress)
return;
3898 if (m_binPinch)
return;
3900#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3901 loadShaders(GetCanvasIndex());
3902 configureShaders(m_pParentCanvas->VPoint);
3905#ifdef USE_ANDROID_GLES2
3909 if (m_binPinch)
return;
3918 bool recompose =
false;
3919 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3920 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3921 if (m_pParentCanvas->VPoint.IsValid()) {
3922 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3923 m_pParentCanvas->UpdateCanvasControlBar();
3932 if (sw.GetTime() > 2000) {
3938 s_tess_vertex_idx = 0;
3939 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3940 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3946 m_displayScale = GetContentScaleFactor();
3950 m_last_render_time = wxDateTime::Now().GetTicks();
3954 if (g_GLOptions.m_bTextureCompression &&
3955 !g_GLOptions.m_bTextureCompressionCaching)
3956 g_glTextureManager->ClearJobList();
3960 int gl_width, gl_height;
3961 gl_width = m_pParentCanvas->VPoint.
pix_width;
3962 gl_height = m_pParentCanvas->VPoint.
pix_height;
3965 m_glcanvas_width = gl_width;
3966 m_glcanvas_height = gl_height;
3970 if (gl_height & 1) {
3972 ViewPort *vp = m_pParentCanvas->GetpVP();
3979 ViewPort *vp = m_pParentCanvas->GetpVP();
3987 ViewPort *vp = m_pParentCanvas->GetpVP();
3990 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3993 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
4001 ViewPort VPoint = m_pParentCanvas->VPoint;
4003 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
4004 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
4007#if !defined(USE_ANDROID_GLES2)
4008 glMatrixMode(GL_PROJECTION);
4011 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4012 glMatrixMode(GL_MODELVIEW);
4016 if (s_b_useStencil) {
4017 glEnable(GL_STENCIL_TEST);
4018 glStencilMask(0xff);
4019 glClear(GL_STENCIL_BUFFER_BIT);
4020 glDisable(GL_STENCIL_TEST);
4026 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4027 if (g_GLOptions.m_GLPolygonSmoothing)
4028 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4029 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4036 g_glTextureManager->TextureCrunch(0.8);
4041 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
4042 bool useFBO =
false;
4048 if (m_b_BuiltFBO && !bpost_hilite
4053 bool b_newview =
true;
4054 bool b_full =
false;
4062 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
4066#ifdef USE_ANDROID_GLES2
4067 if (recompose) b_newview =
true;
4079 if (VPoint.b_quilt) {
4080 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
4081 if (!chart) b_full =
true;
4090 bool accelerated_pan =
false;
4100 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4101 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4102 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4104 wxPoint2DDouble c_old =
4107 wxPoint2DDouble c_new =
4111 dy = wxRound(c_new.m_y - c_old.m_y);
4112 dx = wxRound(c_new.m_x - c_old.m_x);
4122 double deltax = c_new.m_x - c_old.m_x;
4123 double deltay = c_new.m_y - c_old.m_y;
4125 bool b_whole_pixel =
true;
4126 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4127 b_whole_pixel =
false;
4129 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4130 abs(dy) < m_cache_tex_y &&
4131 (abs(dx) > 0 || (abs(dy) > 0));
4140 if (m_displayScale > 1) accelerated_pan =
false;
4145 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4148#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4151 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4157 if (b_full) accelerated_pan =
false;
4159 if (accelerated_pan) {
4160 if ((dx != 0) || (dy != 0)) {
4172 if (dy > 0 && dy < gl_height)
4173 update_region.Union(
4174 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4176 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4178 if (dx > 0 && dx < gl_width)
4179 update_region.Union(
4180 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4182 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4184 m_cache_page = !m_cache_page;
4187 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4188 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4200 RenderCharts(m_gldc, update_region);
4204 glDisable(g_texture_rectangle_format);
4209 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4210 glEnable(GL_TEXTURE_2D);
4214 float x1, x2, y1, y2;
4227 float tx1, tx2, ty1, ty2;
4233 tx2 = sx / (float)m_cache_tex_x;
4235 ty2 = sy / (float)m_cache_tex_y;
4252 coords[2] = -dx + sx;
4254 coords[4] = -dx + sx;
4255 coords[5] = dy + sy;
4257 coords[7] = dy + sy;
4260 ptexture_2D_shader_program[GetCanvasIndex()];
4264 shader->SetUniform1i(
"uTex", 0);
4268 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4269 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4270 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4272 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4294 shader->SetAttributePointerf(
"aPos", co1);
4295 shader->SetAttributePointerf(
"aUV", tco1);
4297 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4300 shader->SetUniformMatrix4fv(
"MVMatrix",
4301 (GLfloat *)VPoint.vp_matrix_transform);
4304 glBindTexture(g_texture_rectangle_format, 0);
4306 glDisable(g_texture_rectangle_format);
4314 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4315 g_texture_rectangle_format,
4316 m_cache_tex[!m_cache_page], 0);
4327 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4328 glClearColor(color.Red() / 256., color.Green() / 256.,
4329 color.Blue() / 256., 1.0);
4330 glClear(GL_COLOR_BUFFER_BIT);
4336 RenderCharts(m_gldc, rscreen_region);
4341 m_cache_page = !m_cache_page;
4346 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4357 glMatrixMode(GL_PROJECTION);
4360 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4361 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4363 glMatrixMode(GL_MODELVIEW);
4367 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4368 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4370 glGetIntegerv(GL_VIEWPORT, viewport);
4371 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4372 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4381 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4382 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4383 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4385 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4389 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4390 glEnable(g_texture_rectangle_format);
4392 float tx, ty, tx0, ty0, divx, divy;
4395 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4398 divx = m_cache_tex_x;
4399 divy = m_cache_tex_y;
4402 tx0 = m_fbo_offsetx / divx;
4403 ty0 = m_fbo_offsety / divy;
4404 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4405 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4430 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4431 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4433 glClear(GL_COLOR_BUFFER_BIT);
4435 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4438 glDisable(g_texture_rectangle_format);
4440 m_cache_vp = VPoint;
4441 m_cache_vp.Validate();
4443 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4445 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4449 RenderCharts(m_gldc, screen_region);
4455 RenderS57TextOverlay(VPoint);
4456 RenderMBTilesOverlay(VPoint);
4460 wxRect rt = upd.GetRect();
4461 LLRegion region = VPoint.GetLLRegion(rt);
4462 ViewPort cvp = ClippedViewport(VPoint, region);
4463 DrawGroundedOverlayObjects(gldc, cvp);
4466 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4467 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4468 LLBBox screenBox = screenLLRegion.GetBox();
4470 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4473 if (m_pParentCanvas->m_bShowTide) {
4474 m_pParentCanvas->RebuildTideSelectList(screenBox);
4475 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4478 if (m_pParentCanvas->m_bShowCurrent) {
4479 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4480 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4486 if (m_pParentCanvas->m_show_focus_bar &&
4487 (g_canvasConfig != 0)) {
4488 if (m_pParentCanvas == wxWindow::FindFocus()) {
4489 g_focusCanvas = m_pParentCanvas;
4491 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
4492 wxPen ppBlue(colour, 1);
4493 wxBrush ppBrush(colour);
4494 gldc.SetPen(ppBlue);
4495 gldc.SetBrush(ppBrush);
4496 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4497 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4498 wxPoint barPoints[4];
4501 barPoints[1].x = xw;
4503 barPoints[2].x = xw;
4504 barPoints[2].y = rect_pix;
4506 barPoints[3].y = rect_pix;
4508 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4512 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4516 DrawFloatingOverlayObjects(m_gldc);
4518#ifndef USE_ANDROID_GLES2
4521 glMatrixMode(GL_PROJECTION);
4524 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4525 glMatrixMode(GL_MODELVIEW);
4530 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4531 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4534 ViewPort &vp = m_pParentCanvas->GetVP();
4535 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4536 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4537 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_EMBOSS);
4539 if (!g_PrintingInProgress) {
4540 if (m_pParentCanvas->m_pTrackRolloverWin)
4541 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4543 if (m_pParentCanvas->m_pRouteRolloverWin)
4544 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4546 if (m_pParentCanvas->m_pAISRolloverWin)
4547 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4549 if (m_pParentCanvas->GetMUIBar())
4550 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4552 if (g_MainToolbar && m_pParentCanvas->IsPrimaryCanvas())
4553 g_MainToolbar->DrawGL(gldc, m_displayScale);
4555 if (g_iENCToolbar && m_pParentCanvas->IsPrimaryCanvas())
4556 g_iENCToolbar->DrawGL(gldc, m_displayScale);
4564 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4565 int x, y, width, height;
4566 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4567 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4568 wxBitmap bmp(width, height, -1);
4571 dc.SetBackground(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
4574 dc.SetTextBackground(GetGlobalColor(_T (
"UIBCK" )));
4575 dc.SetTextForeground(GetGlobalColor(_T (
"UITX1" )));
4579 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4580 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4582 wxStringTokenizer tkz(s, _T(
"\n"));
4585 while (tkz.HasMoreTokens()) {
4586 token = tkz.GetNextToken();
4587 dc.DrawText(token, xt, yt);
4590 dc.SelectObject(wxNullBitmap);
4592 m_gldc.DrawBitmap(bmp, x, y,
false);
4598 if (g_bShowChartBar) DrawChartBar(m_gldc);
4600 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4602 m_pParentCanvas->m_Compass->Paint(gldc);
4604 if (m_pParentCanvas->IsPrimaryCanvas()) {
4605 auto ¬eman = NotificationManager::GetInstance();
4606 if (noteman.GetNotificationCount()) {
4607 m_pParentCanvas->m_notification_button->SetIconSeverity(
4608 noteman.GetMaxSeverity());
4609 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4610 m_pParentCanvas->m_notification_button->Show(
true);
4611 m_pParentCanvas->m_notification_button->Paint(gldc);
4613 m_pParentCanvas->m_notification_button->Show(
false);
4616 RenderGLAlertMessage();
4620 ViewPort &vp = m_pParentCanvas->GetVP();
4621 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4622 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4623 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_UI);
4624 glActiveTexture(GL_TEXTURE0);
4628 if (g_bquiting) DrawQuiting();
4629 if (g_bcompression_wait)
4630 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4635 if (g_b_needFinish) glFinish();
4639 g_glTextureManager->TextureCrunch(0.8);
4640 g_glTextureManager->FactoryCrunch(0.6);
4645 m_pParentCanvas->PaintCleanup();
4647 m_bforcefull =
false;
4652void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4655 if (VPoint.b_quilt) {
4656 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4657 ps52plib->GetShowS57Text()) {
4658 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4659 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4664 ChPI->ClearPLIBTextList();
4666 ps52plib->ClearTextList();
4676 RenderQuiltViewGLText(vpx, screen_region);
4681void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4684 LLRegion &screenLLRegion) {
4685 ChartBase *chart = ChartData->OpenChartFromDBAndLock(dbIndex, FULL_INIT);
4689 if (chart == NULL)
return;
4696 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4698 wxFileName tileFile(chart->GetFullPath());
4700 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4702 if (!ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4703 (tileSizeMB.GetLo() > 5000)) {
4706 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4707 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4708 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4715 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4719 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4722 std::vector<int> piano_active_array_tiles =
4723 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4724 bool bfound =
false;
4726 if (std::find(piano_active_array_tiles.begin(),
4727 piano_active_array_tiles.end(),
4728 dbIndex) != piano_active_array_tiles.end()) {
4733 piano_active_array_tiles.push_back(dbIndex);
4734 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4738void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4740 std::vector<int> stackIndexArray =
4741 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4742 unsigned int im = stackIndexArray.size();
4745 if (VPoint.b_quilt && im > 0) {
4746 bool regionVPBuilt =
false;
4748 LLRegion screenLLRegion;
4752 std::vector<int> tiles_to_show;
4753 for (
unsigned int is = 0; is < im; is++) {
4755 ChartData->GetChartTableEntry(stackIndexArray[is]);
4756 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4757 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4759 std::vector<int> piano_active_array_tiles =
4760 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4761 bool bfound =
false;
4763 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4764 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4765 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4773 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4774 piano_active_array_tiles);
4779 tiles_to_show.push_back(stackIndexArray[is]);
4780 if (!regionVPBuilt) {
4783 screenLLRegion = VPoint.GetLLRegion(screen_region);
4784 screenBox = screenLLRegion.GetBox();
4792 regionVPBuilt =
true;
4802 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4803 rit != tiles_to_show.rend(); ++rit) {
4804 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4806 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4807 rit != tiles_to_show.rend(); ++rit) {
4808 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4812 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4814 if (!hiregion.Empty()) {
4818 switch (global_color_scheme) {
4819 case GLOBAL_COLOR_SCHEME_DAY:
4822 case GLOBAL_COLOR_SCHEME_DUSK:
4825 case GLOBAL_COLOR_SCHEME_NIGHT:
4833#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4834 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4836 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4839 DrawRegion(VPoint, hiregion);
4841 glDisable(GL_BLEND);
4847void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4851 GetClientSize(&w, &h);
4853 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4854#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4855 glMatrixMode(GL_PROJECTION);
4858 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4859 glMatrixMode(GL_MODELVIEW);
4863 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4865 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4867 bool world_view =
false;
4868 RenderWorldChart(dc, cvp, rtex, world_view);
4869 gShapeBasemap.RenderViewOnDC(dc, cvp);
4875 glViewport(0, 0, (GLint)w, (GLint)h);
4876#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4877 glMatrixMode(GL_PROJECTION);
4880 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4881 glMatrixMode(GL_MODELVIEW);
4887void glChartCanvas::FastPan(
int dx,
int dy) {
4888#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4892void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4894 SetCurrent(*m_pcontext);
4895 float sx = GetSize().x;
4896 float sy = GetSize().y;
4897 glClear(GL_COLOR_BUFFER_BIT);
4900 GetClientSize(&w, &h);
4902 if (s_b_useStencil) {
4903 glEnable(GL_STENCIL_TEST);
4904 glStencilMask(0xff);
4905 glClear(GL_STENCIL_BUFFER_BIT);
4906 glDisable(GL_STENCIL_TEST);
4922 float sxfactor = sx / swidth;
4923 float syfactor = sy / sheight;
4925 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4926 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4927 sx * sx / swidth * 2, sy * sy / sheight * 2);
4928 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4929 glEnable(g_texture_rectangle_format);
4954 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4955 glBindTexture(g_texture_rectangle_format, 0);
4961 float tx, ty, tx0, ty0;
4971 glBindTexture(g_texture_rectangle_format, 0);
4974 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4975 glEnable(g_texture_rectangle_format);
4981 uv[0] = tx0 / m_cache_tex_x;
4982 uv[1] = ty / m_cache_tex_y;
4983 uv[2] = tx / m_cache_tex_x;
4984 uv[3] = ty / m_cache_tex_y;
4985 uv[4] = tx / m_cache_tex_x;
4986 uv[5] = ty0 / m_cache_tex_y;
4987 uv[6] = tx0 / m_cache_tex_x;
4988 uv[7] = ty0 / m_cache_tex_y;
5000 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
5001 sx * sx / swidth, sy * sy / sheight);
5003 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
5005 glDisable(g_texture_rectangle_format);
5006 glBindTexture(g_texture_rectangle_format, 0);
5013 wxColour color = GetGlobalColor(_T(
"GREY1"));
5014 float ht = -offset_y * (sy / sheight);
5015 wxRect r(0, sy - ht, w, ht);
5016 RenderColorRect(r, color);
5019 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
5020 RenderColorRect(rt, color);
5023 float w1 = -offset_x * sx / swidth;
5024 wxRect rl(0, 0, w1, sy);
5025 RenderColorRect(rl, color);
5028 float px = w1 + sx * sx / swidth;
5029 wxRect rr(px, 0, sx - px, sy);
5030 RenderColorRect(rr, color);
5039void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
5042 if (m_nRun < m_nTotal) {
5043 m_runoffsetx += m_offsetxStep;
5044 if (m_offsetxStep > 0)
5045 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
5047 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
5049 m_runoffsety += m_offsetyStep;
5050 if (m_offsetyStep > 0)
5051 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
5053 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
5055 m_runswidth += m_swidthStep;
5056 if (m_swidthStep > 0)
5057 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
5059 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
5061 m_runsheight += m_sheightStep;
5062 if (m_sheightStep > 0)
5063 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
5065 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
5070 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5076 if (m_zoomFinaldx || m_zoomFinaldy) {
5077 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5080 m_zoomFinal =
false;
5084void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5086 int sx = GetSize().x;
5087 int sy = GetSize().y;
5089 m_lastfbo_offsetx = m_fbo_offsetx;
5090 m_lastfbo_offsety = m_fbo_offsety;
5091 m_lastfbo_swidth = m_fbo_swidth;
5092 m_lastfbo_sheight = m_fbo_sheight;
5094 float curr_fbo_offset_x = m_fbo_offsetx;
5095 float curr_fbo_offset_y = m_fbo_offsety;
5096 float curr_fbo_swidth = m_fbo_swidth;
5097 float curr_fbo_sheight = m_fbo_sheight;
5099 float fx = (float)cp_x / sx;
5100 float fy = 1.0 - (float)cp_y / sy;
5102 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5103 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5105 m_fbo_swidth = curr_fbo_swidth / factor;
5106 m_fbo_sheight = curr_fbo_sheight / factor;
5108 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5109 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5111 m_fbo_offsetx += post_x;
5112 m_fbo_offsety += post_y;
5123 float perStep = m_nStep / m_nTotal;
5125 if (zoomTimer.IsRunning()) {
5126 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5127 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5128 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5129 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5132 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5133 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5134 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5135 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5137 m_runoffsetx = m_lastfbo_offsetx;
5138 m_runoffsety = m_lastfbo_offsety;
5139 m_runswidth = m_lastfbo_swidth;
5140 m_runsheight = m_lastfbo_sheight;
5143 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5144 m_zoomFinal =
false;
5150void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5154 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5157 if (m_binPinch)
return;
5158 if (m_bpinchGuard)
return;
5160 int x =
event.GetOffset().x;
5161 int y =
event.GetOffset().y;
5163 int lx =
event.GetLastOffset().x;
5164 int ly =
event.GetLastOffset().y;
5169 switch (event.GetState()) {
5170 case GestureStarted:
5171 if (m_binPan)
break;
5175 m_binGesture =
true;
5179 case GestureUpdated:
5184 m_pParentCanvas->FreezePiano();
5186 m_pParentCanvas->ThawPiano();
5197 case GestureFinished:
5200 m_pParentCanvas->UpdateCanvasControlBar();
5203 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5207 case GestureCanceled:
5209 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5216 m_bgestureGuard =
true;
5217 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5218 m_bforcefull =
false;
5223float zoom_inc = 1.0;
5224bool first_zout =
false;
5226void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5227 float zoom_gain = 1.0;
5228 float zout_gain = 1.0;
5231 float total_zoom_val;
5233 float max_zoom_scale = 1000.;
5234 float min_zoom_scale = 2e8;
5236 if (event.GetScaleFactor() > 1)
5237 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5239 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5241 if (event.GetTotalScaleFactor() > 1)
5242 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5245 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5247 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5250 float max_zoom_scale = 1000.;
5251 if( cc1->GetVP().b_quilt) {
5252 int ref_index = cc1->GetQuiltRefChartdbIndex();
5259 float min_zoom_scale = 2e8;
5263 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5265 double projected_scale =
5266 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5268 switch (event.GetState()) {
5269 case GestureStarted:
5274 m_binGesture =
true;
5276 m_pinchStart =
event.GetCenterPoint();
5277 m_lpinchPoint = m_pinchStart;
5280 event.GetCenterPoint().y, m_pinchlat,
5285 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5286 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5289 SetCurrent(*m_pcontext);
5295 case GestureUpdated:
5297 if (projected_scale < min_zoom_scale) {
5298 wxPoint pinchPoint =
event.GetCenterPoint();
5300 float dx = pinchPoint.x - m_lpinchPoint.x;
5301 float dy = pinchPoint.y - m_lpinchPoint.y;
5303 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5304 -dx / total_zoom_val, dy / total_zoom_val);
5306 m_lpinchPoint = pinchPoint;
5310 if (1 || ((total_zoom_val > 1) && !first_zout)) {
5311 wxPoint pinchPoint =
event.GetCenterPoint();
5313 float dx = pinchPoint.x - m_lpinchPoint.x;
5314 float dy = pinchPoint.y - m_lpinchPoint.y;
5316 if ((projected_scale > max_zoom_scale) &&
5317 (projected_scale < min_zoom_scale))
5318 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5319 -dx / total_zoom_val, dy / total_zoom_val);
5321 m_lpinchPoint = pinchPoint;
5325 zoom_inc *= zoom_val;
5326 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5327 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5331 wxPoint pinchPoint =
event.GetCenterPoint();
5332 float dx = pinchPoint.x - m_lpinchPoint.x;
5333 float dy = pinchPoint.y - m_lpinchPoint.y;
5335 m_lpinchPoint = pinchPoint;
5346 case GestureFinished: {
5350 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5351 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5355 float tzoom = total_zoom_val;
5357 if (projected_scale >= min_zoom_scale)
5358 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5360 if (projected_scale < max_zoom_scale)
5361 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5363 dx = (cc_x - m_cc_x) * tzoom;
5364 dy = -(cc_y - m_cc_y) * tzoom;
5366 if (zoomTimer.IsRunning()) {
5369 m_zoomFinalZoom = tzoom;
5375 double final_projected_scale =
5379 if (final_projected_scale < min_zoom_scale) {
5383 m_pParentCanvas->m_pQuilt->Invalidate();
5384 m_bforcefull =
true;
5391 m_pParentCanvas->m_pQuilt->Invalidate();
5392 m_bforcefull =
true;
5404 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5408 case GestureCanceled:
5410 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5417 m_bgestureGuard =
true;
5419 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5422void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5432 m_bgestureGuard =
false;
5433 m_bpinchGuard =
false;
5434 m_binGesture =
false;
5435 m_bforcefull =
false;
5438void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5442 m_binGesture =
false;
5443 m_bforcefull =
false;
5447#ifdef HAVE_WX_GESTURE_EVENTS
5449void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5453 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5456 if (m_binPinch)
return;
5457 if (m_bpinchGuard)
return;
5459 int dx =
event.GetDelta().x;
5460 int dy =
event.GetDelta().y;
5462 if (event.IsGestureStart()) {
5463 if (m_binPan)
return;
5467 m_binGesture =
true;
5471 else if (event.IsGestureEnd()) {
5473 m_pParentCanvas->UpdateCanvasControlBar();
5475 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5483 m_pParentCanvas->FreezePiano();
5485 m_pParentCanvas->ThawPiano();
5496 m_bgestureGuard =
true;
5497 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5498 m_bforcefull =
false;
5501bool first_zout =
false;
5504void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5505 float zoom_gain = 1.0;
5506 float zout_gain = 1.0;
5508 float last_zoom_val = m_total_zoom_val;
5510 float max_zoom_scale = 1000.;
5511 float min_zoom_scale = 2e8;
5513 if (event.GetZoomFactor() > 1)
5514 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5516 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5518 float inc_zoom_val =
5519 m_total_zoom_val / last_zoom_val;
5521 double projected_scale =
5522 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5524 if (event.IsGestureStart()) {
5530 m_binGesture =
true;
5531 m_pinchStart =
event.GetPosition();
5532 m_lpinchPoint = m_pinchStart;
5533 m_total_zoom_val = 1.0;
5534 m_final_zoom_val = 1.0;
5537 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5541 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5542 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5545 SetCurrent(*m_pcontext);
5548 ViewPort vpr = m_pParentCanvas->VPoint;
5550 GetTouchBackingBitmap(vpr);
5555 if (event.IsGestureEnd()) {
5561 if (!m_binGesture)
return;
5563 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5564 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5568 float tzoom = m_final_zoom_val;
5570 dx = (cc_x - m_cc_x) * tzoom;
5571 dy = -(cc_y - m_cc_y) * tzoom;
5573 if (zoomTimer.IsRunning()) {
5576 m_zoomFinalZoom = tzoom;
5582 double final_projected_scale =
5586 if (final_projected_scale < min_zoom_scale) {
5590 m_pParentCanvas->m_pQuilt->Invalidate();
5591 m_bforcefull =
true;
5598 m_pParentCanvas->m_pQuilt->Invalidate();
5599 m_bforcefull =
true;
5604 m_final_zoom_val = 1.0;
5605 m_total_zoom_val = 1.0;
5606 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5611 if (projected_scale < min_zoom_scale) {
5612 wxPoint pinchPoint =
event.GetPosition();
5614 float dx = pinchPoint.x - m_lpinchPoint.x;
5615 float dy = pinchPoint.y - m_lpinchPoint.y;
5617 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5618 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5620 m_lpinchPoint = pinchPoint;
5621 m_final_zoom_val *= inc_zoom_val;
5625 if (1 || ((m_total_zoom_val > 1) && !first_zout)) {
5626 wxPoint pinchPoint =
event.GetPosition();
5628 float dx = pinchPoint.x - m_lpinchPoint.x;
5629 float dy = pinchPoint.y - m_lpinchPoint.y;
5631 if ((projected_scale > max_zoom_scale) &&
5632 (projected_scale < min_zoom_scale))
5633 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5634 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5636 m_lpinchPoint = pinchPoint;
5637 m_final_zoom_val *= inc_zoom_val;
5641 m_zoom_inc *= inc_zoom_val;
5642 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5643 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5647 wxPoint pinchPoint =
event.GetPosition();
5648 float dx = pinchPoint.x - m_lpinchPoint.x;
5649 float dy = pinchPoint.y - m_lpinchPoint.y;
5651 m_lpinchPoint = pinchPoint;
5655 m_bgestureGuard =
true;
5656 m_bpinchGuard =
true;
5657 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5660void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5670 m_bgestureGuard =
false;
5671 m_bpinchGuard =
false;
5672 m_binGesture =
false;
5673 m_bforcefull =
false;
5676void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5680 m_binGesture =
false;
5681 m_bforcefull =
false;
5687void glChartCanvas::configureShaders(
ViewPort &vp) {
5688#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5694 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5696 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5697 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5718 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5720 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5721 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5733 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5735 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5736 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5739 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5741 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5742 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5750 shader = pAALine_shader_program[GetCanvasIndex()];
5752 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5755 shader = pring_shader_program[GetCanvasIndex()];
5757 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5758 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5762 if (texture_2DA_shader_program) {
5763 glUseProgram(texture_2DA_shader_program);
5764 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5765 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5766 (
const GLfloat *)pvp->vp_matrix_transform);
5768 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5769 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5777void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5780#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5781 int nl = nVertex / 4;
5783 float *luv = uvCoords;
5786 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5794 glEnableClientState(GL_VERTEX_ARRAY);
5795 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5797 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5798 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5799 glDrawArrays(GL_QUADS, 0, 4);
5806void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5807 float *uvCoords,
ViewPort *vp,
float dx,
5808 float dy,
float angle_rad) {
5809#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5811 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5812 if (!shader)
return;
5817 shader->SetUniform1i(
"uTex", 0);
5822 mat4x4_rotate_Z(Q, I, angle_rad);
5828 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5833 shader->SetAttributePointerf(
"aPos", co1);
5834 shader->SetAttributePointerf(
"aUV", tco1);
5841 GLushort indices1[] = {0,1,3,2};
5842 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5854 tco1[0] = uvCoords[0];
5855 tco1[1] = uvCoords[1];
5856 tco1[2] = uvCoords[2];
5857 tco1[3] = uvCoords[3];
5858 tco1[4] = uvCoords[6];
5859 tco1[5] = uvCoords[7];
5860 tco1[6] = uvCoords[4];
5861 tco1[7] = uvCoords[5];
5866 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5878void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5879#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5881 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5884 shader->SetUniformMatrix4fv(
5885 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5888 colorv[0] = color.Red() / float(256);
5889 colorv[1] = color.Green() / float(256);
5890 colorv[2] = color.Blue() / float(256);
5892 shader->SetUniform4fv(
"color", colorv);
5895 pf[0] = r.x + r.width;
5899 pf[4] = r.x + r.width;
5900 pf[5] = r.y + r.height;
5902 pf[7] = r.y + r.height;
5903 shader->SetAttributePointerf(
"position", pf);
5905 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5913void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5914#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5916 ViewPort VPoint = m_pParentCanvas->VPoint;
5920 GetClientSize(&w, &h);
5921 int sx = GetSize().x;
5922 int sy = GetSize().y;
5926 glViewport(0, 0, (GLint)w, (GLint)h);
5928 if (s_b_useStencil) {
5929 glEnable(GL_STENCIL_TEST);
5930 glStencilMask(0xff);
5931 glClear(GL_STENCIL_BUFFER_BIT);
5932 glDisable(GL_STENCIL_TEST);
5936 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5941 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5942 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5943 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5946 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5948 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5949 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5957 if (bRenderCharts) RenderCharts(gldc, screen_region);
5959 if (bRenderOverlays) {
5960 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5961 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5962 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5963 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5964 DrawFloatingOverlayObjects(m_gldc);
5968 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5973wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5975 wxMemoryDC tdc(tbm);
5976 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5984 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5985 dc.SetPen(*wxTRANSPARENT_PEN);
5987 gShapeBasemap.RenderViewOnDC(dc, tvp);
5988 tdc.SelectObject(wxNullBitmap);
5989 m_touch_backing_bitmap = tbm;
5990 CreateBackingTexture();
5992 return m_touch_backing_bitmap;
5995void glChartCanvas::CreateBackingTexture() {
5996 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5997 unsigned char *imgdata = image.GetData();
5998 unsigned char *imgalpha = image.GetAlpha();
5999 m_tex_w = image.GetWidth();
6000 m_tex_h = image.GetHeight();
6001 m_image_width = m_tex_w;
6002 m_image_height = m_tex_h;
6004 GLuint format = GL_RGBA;
6005 GLuint internalformat = g_texture_rectangle_format;
6007 internalformat = GL_RGBA;
6012 unsigned char *teximage =
6013 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6015 for (
int i = 0; i < m_image_height; i++) {
6016 for (
int j = 0; j < m_image_width; j++) {
6017 int s = (i * 3 * m_image_width) + (j * 3);
6018 int d = (i * stride * m_tex_w) + (j * stride);
6020 teximage[d + 0] = imgdata[s + 0];
6021 teximage[d + 1] = imgdata[s + 1];
6022 teximage[d + 2] = imgdata[s + 2];
6023 teximage[d + 3] = 255;
6027 glGenTextures(1, &m_TouchBackingTexture);
6028 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6030 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6031 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6032 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6034 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6036 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6037 GL_UNSIGNED_BYTE, teximage);
6040 glBindTexture(GL_TEXTURE_2D, 0);
Represents an active track that is currently being recorded.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
float GetVPChartScale()
Return the ViewPort chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Manages the chart database and provides access to chart data.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Wrapper class for OpenGL shader programs.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
Represents a navigational route in the navigation system.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
Manages a set of ShapeBaseChart objects at different resolutions.
Window for displaying chart thumbnails.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
bool m_bUseCanvasPanning
Controls OpenGL canvas hardware-accelerated panning mode.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Class NotificationManager.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
Tools to send data to plugins.
Represents an entry in the chart table, containing information about a single chart.