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"
77#include "emboss_data.h"
79#include "glChartCanvas.h"
80#include "glTexCache.h"
84#include "mipmap/mipmap.h"
86#include "OCPNPlatform.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;
232extern bool g_PrintingInProgress;
233extern bool g_bhide_depth_units;
234extern bool g_bhide_overzoom_flag;
236wxColor s_regionColor;
250#define APIENTRYP APIENTRY *
256#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
257#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
260PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
261PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
262PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
263PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
264PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
265PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
266PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
267PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
268PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
269PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
271PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
272PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
275PFNGLGENBUFFERSPROC s_glGenBuffers;
276PFNGLBINDBUFFERPROC s_glBindBuffer;
277PFNGLBUFFERDATAPROC s_glBufferData;
278PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
280#ifndef USE_ANDROID_GLES2
285typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
287PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
289#include <wx/arrimpl.cpp>
292GLuint g_raster_format = GL_RGB;
296wxStopWatch g_glstopwatch;
297double g_gl_ms_per_frame;
300int g_uncompressed_tile_size;
302extern wxProgressDialog *pprog;
303extern bool b_skipout;
304extern wxSize pprog_size;
305extern int pprog_count;
306extern int pprog_threads;
312bool glChartCanvas::s_b_useScissorTest;
313bool glChartCanvas::s_b_useStencil;
314bool glChartCanvas::s_b_useStencilAP;
315bool glChartCanvas::s_b_useFBO;
317#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
318static int s_tess_vertex_idx;
319static int s_tess_vertex_idx_this;
320static int s_tess_buf_len;
321static GLfloat *s_tess_work_buf;
324static vec4 s_tess_color;
334 while ( upd.HaveRects() )
336 wxRect rect = upd.GetRect();
337 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
344GLboolean QueryExtension(
const char *extName) {
355 extNameLen = strlen(extName);
357 p = (
char *)glGetString(GL_EXTENSIONS);
365 int n = strcspn(p,
" ");
366 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
374int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
375 16, WX_GL_STENCIL_SIZE, 8,
378glTestCanvas::glTestCanvas(wxWindow *parent)
379 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
383int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
384 16, WX_GL_STENCIL_SIZE, 8,
387EVT_PAINT(glChartCanvas::OnPaint)
388EVT_ACTIVATE(glChartCanvas::OnActivate)
389EVT_SIZE(glChartCanvas::OnSize)
390EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
394 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
395 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
398 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
403std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
405 {wxPENSTYLE_DOT, {1, 1}},
406 {wxPENSTYLE_LONG_DASH, {5, 5}},
407 {wxPENSTYLE_SHORT_DASH, {1, 5}},
408 {wxPENSTYLE_DOT_DASH, {5, 1}},
411void glChartCanvas::Init() {
416 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
418 m_cache_current_ch = NULL;
420 m_b_paint_enable =
true;
421 m_in_glpaint =
false;
423 m_cache_tex[0] = m_cache_tex[1] = 0;
426 m_b_BuiltFBO =
false;
427 m_b_DisableFBO =
false;
436 m_bpinchGuard =
false;
437 m_binGesture =
false;
440 m_last_render_time = -1;
447 m_gldc.SetGLCanvas(
this);
450 m_displayScale = 1.0;
451#if defined(__WXOSX__) || defined(__WXGTK3__)
453 m_displayScale = GetContentScaleFactor();
462 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
466 wxEVT_QT_PINCHGESTURE,
467 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
470 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
475 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
477 onGestureFinishTimerEvent,
481 ZOOM_TIMER, wxEVT_TIMER,
482 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
485 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
486 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
487 zoomTimer.SetOwner(
this, ZOOM_TIMER);
489#ifdef USE_ANDROID_GLES2
498#ifdef HAVE_WX_GESTURE_EVENTS
500 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
505 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
507 onGestureFinishTimerEvent,
511 ZOOM_TIMER, wxEVT_TIMER,
512 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
515 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
516 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
517 zoomTimer.SetOwner(
this, ZOOM_TIMER);
522 m_bgestureGuard =
false;
523 m_total_zoom_val = 1.0;
526#ifdef HAVE_WX_GESTURE_EVENTS
527 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
528 wxLogError(
"Failed to enable touch events");
537 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
539 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
540 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
542 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
543 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
545 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
546 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
548 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
549 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
555glChartCanvas::~glChartCanvas() {
561void glChartCanvas::FlushFBO(
void) {
562 if (m_bsetup) BuildFBO();
565void glChartCanvas::OnActivate(wxActivateEvent &event) {
566 m_pParentCanvas->OnActivate(event);
569void glChartCanvas::OnSize(wxSizeEvent &event) {
573 wxLogMessage(
"Got OnSize event while NOT running");
575 qDebug() <<
"OnSizeB";
582 if (!IsShown())
return;
584 SetCurrent(*m_pcontext);
588 SetSize(GetSize().x, GetSize().y);
596 if (m_bsetup && m_pcontext && IsShown()) {
597 SetCurrent(*m_pcontext);
603 wxLogMessage(
"BuildFBO 3");
608 ViewPort *vp = m_pParentCanvas->GetpVP();
611 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
614 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
618void glChartCanvas::MouseEvent(wxMouseEvent &event) {
619 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
625 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
627 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
630 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
634 if (m_bgestureGuard) {
635 m_pParentCanvas->r_rband.x = 0;
645 if (event.LeftUp()) {
647 if ((abs(panx) > 2) || (abs(pany) > 2)) {
650 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
657 if (!event.LeftDClick()) {
662 if (m_binPan && event.RightDown()) {
663 qDebug() <<
"Skip right on pan";
666 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
668 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
669 if (!m_bgestureGuard)
679#ifndef GL_MAX_RENDERBUFFER_SIZE
680#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
683#ifndef USE_ANDROID_GLES2
684bool glChartCanvas::buildFBOSize(
int fboSize) {
686 if (IsShown()) SetCurrent(*m_pcontext);
689 glDeleteTextures(2, m_cache_tex);
690 glDeleteFramebuffers(1, &m_fb0);
691 glDeleteRenderbuffers(1, &m_renderbuffer);
692 m_b_BuiltFBO =
false;
695 if (m_b_DisableFBO)
return false;
699 int rb_x = GetSize().x;
700 int rb_y = GetSize().y;
702 while (i < rb_x) i <<= 1;
706 while (i < rb_y) i <<= 1;
709 m_cache_tex_x = wxMax(rb_x, rb_y);
710 m_cache_tex_y = wxMax(rb_x, rb_y);
713 m_cache_tex_x = GetSize().x * m_displayScale;
714 m_cache_tex_y = GetSize().y * m_displayScale;
717 int err = GL_NO_ERROR;
719 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
722 if (err == GL_INVALID_ENUM) {
723 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
727 if (err == GL_NO_ERROR) {
728 if (fboSize > params) {
730 " OpenGL-> Requested Framebuffer size exceeds "
731 "GL_MAX_RENDERBUFFER_SIZE");
736 glGenFramebuffers(1, &m_fb0);
740 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
745 glGenRenderbuffers(1, &m_renderbuffer);
749 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
754 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
758 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
764 glGenTextures(2, m_cache_tex);
765 for (
int i = 0; i < 2; i++) {
766 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
767 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
769 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
771 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
772 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
775 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
777 if (m_b_useFBOStencil) {
779 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
780 m_cache_tex_x, m_cache_tex_y);
782 int err = glGetError();
785 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
789 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
790 GL_RENDERBUFFER_EXT, m_renderbuffer);
794 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
799 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
800 GL_RENDERBUFFER_EXT, m_renderbuffer);
804 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
810 GLenum depth_format = GL_DEPTH_COMPONENT24;
815 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
819 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
821 int err = glGetError();
824 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
830 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
831 GL_RENDERBUFFER_EXT, m_renderbuffer);
836 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
843 glBindTexture(GL_TEXTURE_2D, 0);
844 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
847 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
849 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
850 g_texture_rectangle_format, m_cache_tex[0], 0);
852 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
854 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
856 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
858 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
868#ifdef USE_ANDROID_GLES2
869bool glChartCanvas::buildFBOSize(
int fboSize) {
873 int rb_x = GetSize().x;
874 int rb_y = GetSize().y;
876 while (i < rb_x) i <<= 1;
880 while (i < rb_y) i <<= 1;
883 m_cache_tex_x = wxMax(rb_x, rb_y);
884 m_cache_tex_y = wxMax(rb_x, rb_y);
888 int err = GL_NO_ERROR;
890 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
893 if (err == GL_INVALID_ENUM) {
894 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
898 if (err == GL_NO_ERROR) {
899 if (fboSize > params) {
901 " OpenGL-> Requested Framebuffer size exceeds "
902 "GL_MAX_RENDERBUFFER_SIZE");
907 glGenFramebuffers(1, &m_fb0);
911 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
916 glGenRenderbuffers(1, &m_renderbuffer);
920 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
925 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
929 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
935 glGenTextures(2, m_cache_tex);
936 for (
int i = 0; i < 2; i++) {
937 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
938 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
940 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
942 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
943 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
946 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
949 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
955 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
959 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
960 GL_RENDERBUFFER, m_renderbuffer);
964 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
969 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
970 GL_RENDERBUFFER, m_renderbuffer);
974 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
979 glBindTexture(GL_TEXTURE_2D, 0);
980 glBindFramebuffer(GL_FRAMEBUFFER, 0);
983 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
985 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
986 g_texture_rectangle_format, m_cache_tex[0], 0);
988 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
990 glBindFramebuffer(GL_FRAMEBUFFER, 0);
992 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
994 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
1004void glChartCanvas::BuildFBO() {
1007 glDeleteTextures(2, m_cache_tex);
1008 glDeleteFramebuffers(1, &m_fb0);
1009 glDeleteRenderbuffers(1, &m_renderbuffer);
1010 m_b_BuiltFBO =
false;
1013 if (m_b_DisableFBO)
return;
1016 int gl_width, gl_height;
1017 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
1018 int initialSize = NextPow2(gl_width * m_displayScale);
1023 wxString info = androidGetDeviceInfo();
1025 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
1028 if (!buildFBOSize(initialSize)) {
1029 glDeleteTextures(2, m_cache_tex);
1030 glDeleteFramebuffers(1, &m_fb0);
1031 glDeleteRenderbuffers(1, &m_renderbuffer);
1033 if (!buildFBOSize(1024)) {
1034 wxLogMessage(
"BuildFBO C");
1036 m_b_DisableFBO =
true;
1037 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
1038 m_b_BuiltFBO =
false;
1047 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
1054 m_b_BuiltFBO =
true;
1059void glChartCanvas::SetupOpenGL() {
1060 SetCurrent(*m_pcontext);
1062 char *str = (
char *)glGetString(GL_RENDERER);
1065 wxLogMessage(
"Failed to initialize OpenGL");
1069 char render_string[80];
1070 strncpy(render_string, str, 79);
1071 m_renderer = wxString(render_string, wxConvUTF8);
1074 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1075 msg.Printf(
"OpenGL-> Renderer String: ");
1079 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1081 char version_string[80];
1082 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1083 msg.Printf(
"OpenGL-> Version reported: ");
1084 m_version = wxString(version_string, wxConvUTF8);
1088 char GLSL_version_string[80];
1089 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1091 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1092 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1093 msg += m_GLSLversion;
1098 GLenum err = glewInit();
1099#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1100 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1105 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1108 wxLogMessage(
"GLEW init success!n");
1113 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1114 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1118#ifndef USE_ANDROID_GLES2
1119 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1121 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1123 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1124 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1131 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1133 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1135 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1138 s_b_useScissorTest =
true;
1140 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1141 s_b_useScissorTest =
false;
1143 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1144 s_b_useScissorTest =
false;
1146 bool bad_stencil_code =
false;
1149 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1150 bad_stencil_code =
true;
1153 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1156 glEnable(GL_STENCIL_TEST);
1157 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1159 glGetIntegerv(GL_STENCIL_BITS, &sb);
1162 glDisable(GL_STENCIL_TEST);
1164 s_b_useStencil =
false;
1165 if (stencil && (sb == 8)) s_b_useStencil =
true;
1167 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1168 g_texture_rectangle_format = GL_TEXTURE_2D;
1169 else if (QueryExtension(
"GL_OES_texture_npot"))
1170 g_texture_rectangle_format = GL_TEXTURE_2D;
1171 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1172 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1173 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1174 g_texture_rectangle_format));
1177 g_texture_rectangle_format = GL_TEXTURE_2D;
1181 g_b_EnableVBO =
true;
1184 g_b_EnableVBO =
false;
1188 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1190 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1194 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1196 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1199#ifndef USE_ANDROID_GLES2
1201 if (bad_stencil_code) s_b_useStencil =
false;
1215 if (m_displayScale > 1) m_b_DisableFBO =
true;
1224 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1226 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1227 g_texture_rectangle_format, m_cache_tex[0], 0);
1229 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1230 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1232 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1234 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1236 m_b_DisableFBO =
true;
1242 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1246 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1248#ifdef USE_ANDROID_GLES2
1249 s_b_useStencilAP = s_b_useStencil;
1256 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1258 if (m_b_useFBOStencil)
1259 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1261 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1263 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1266 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1268 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1270 if (s_b_useScissorTest && s_b_useStencil)
1271 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1274 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1276 MipMap_ResolveRoutines();
1280 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1281 g_GLMinCartographicLineWidth);
1282 wxLogMessage(lwmsg);
1283 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1284 g_GLMinSymbolLineWidth);
1285 wxLogMessage(lwmsg);
1288 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1290#ifdef USE_ANDROID_GLES2
1291 g_GLOptions.m_bUseAcceleratedPanning =
true;
1297 int tex_dim = g_GLOptions.m_iTextureDimension;
1298 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1299 g_mipmap_max_level = max_level - 1;
1304 g_mipmap_max_level = 4;
1307 s_b_useFBO = m_b_BuiltFBO;
1311 ps52plib->SetGLOptions(
1312 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1313 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1314 g_GLMinSymbolLineWidth);
1318 SendJSONConfigMessage();
1321void glChartCanvas::SendJSONConfigMessage() {
1324 v[
"setupComplete"] = m_bsetup;
1325 v[
"useStencil"] = s_b_useStencil;
1326 v[
"useStencilAP"] = s_b_useStencilAP;
1327 v[
"useScissorTest"] = s_b_useScissorTest;
1328 v[
"useFBO"] = s_b_useFBO;
1329 v[
"useVBO"] = g_b_EnableVBO;
1330 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1331 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1332 SendJSONMessageToAllPlugins(msg_id, v);
1335void glChartCanvas::SetupCompression() {
1336 int dim = g_GLOptions.m_iTextureDimension;
1339 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1340 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1341 goto no_compression;
1345 g_uncompressed_tile_size = dim * dim * 4;
1346 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1348 g_raster_format = GL_RGB;
1352 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1353 g_raster_format = GL_ETC1_RGB8_OES;
1355 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1359 if (GL_RGB == g_raster_format) {
1365 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1366 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1369 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1370 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1371 g_raster_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
1373 g_raster_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1375 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1376 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1377 g_raster_format = GL_COMPRESSED_RGB_FXT1_3DFX;
1379 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1381 wxLogMessage(
"OpenGL-> No Useable compression format found");
1382 goto no_compression;
1387 g_tile_size = 512 * 512 / 2;
1391 glGenTextures(1, &texture);
1392 glBindTexture(GL_TEXTURE_2D, texture);
1393 glTexImage2D(GL_TEXTURE_2D, 0, g_raster_format, dim, dim, 0, GL_RGB,
1394 GL_UNSIGNED_BYTE, NULL);
1395 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1397 glDeleteTextures(1, &texture);
1401 if (g_tile_size == 0)
goto no_compression;
1403 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1405 g_uncompressed_tile_size / g_tile_size));
1409 g_GLOptions.m_bTextureCompression =
false;
1411 g_tile_size = g_uncompressed_tile_size;
1412 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1415void glChartCanvas::OnPaint(wxPaintEvent &event) {
1418 if (!m_pcontext)
return;
1426 SetCurrent(*m_pcontext);
1431 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1439 if (!m_b_paint_enable)
return;
1442 if (m_in_glpaint)
return;
1445 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1468bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1470#ifndef USE_ANDROID_GLES2
1471 return vp.m_projection_type == PROJECTION_MERCATOR ||
1472 vp.m_projection_type == PROJECTION_POLAR ||
1473 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1487#define NORM_FACTOR 4096.0
1488void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1489#ifndef USE_ANDROID_GLES2
1491 wxPoint2DDouble point;
1493 switch (vp.m_projection_type) {
1494 case PROJECTION_MERCATOR:
1495 case PROJECTION_EQUIRECTANGULAR:
1496 case PROJECTION_WEB_MERCATOR:
1499 glTranslated(point.m_x, point.m_y, 0);
1504 case PROJECTION_POLAR:
1508 glTranslated(point.m_x, point.m_y, 0);
1509 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1516 printf(
"ERROR: Unhandled projection\n");
1521 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1529 switch (vp.m_projection_type) {
1530 case PROJECTION_MERCATOR:
1531 case PROJECTION_EQUIRECTANGULAR:
1532 case PROJECTION_WEB_MERCATOR:
1536 case PROJECTION_POLAR:
1541 printf(
"ERROR: Unhandled projection\n");
1550bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1551 return vp.m_projection_type == PROJECTION_MERCATOR ||
1552 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1553 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1557 const LLRegion ®ion) {
1558 if (!CanClipViewport(vp))
return vp;
1561 LLBBox bbox = region.GetBox();
1563 if (!bbox.GetValid())
return vp;
1571 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1572 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1573 bbox.GetMaxLon() + 360);
1574 cvp.SetBBoxDirect(bbox);
1575 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1576 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1577 bbox.GetMaxLon() - 360);
1578 cvp.SetBBoxDirect(bbox);
1580 cvp.SetBBoxDirect(bbox);
1585void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1586 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1589 for (
Track *pTrackDraw : g_TrackList) {
1592 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1594 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1597 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1598 node = node->GetNext()) {
1599 Route *pRouteDraw = node->GetData();
1601 if (!pRouteDraw)
continue;
1604 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1609 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1614 if (vp.GetBBox().GetValid() && pWayPointMan) {
1615 for (wxRoutePointListNode *pnode =
1616 pWayPointMan->GetWaypointList()->GetFirst();
1617 pnode; pnode = pnode->GetNext()) {
1620 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1627void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1630 for (
Track *pTrackDraw : g_TrackList) {
1632 if (pActiveTrack && pActiveTrack->IsRunning())
1633 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1637 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1638 node = node->GetNext()) {
1639 Route *pRouteDraw = node->GetData();
1642 if (!pRouteDraw)
continue;
1645 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1651 if (pRouteDraw->IsSelected()) drawit++;
1654 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1655 if (!vp_box.IntersectOut(test_box))
1656 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1662 if (vp.GetBBox().GetValid() && pWayPointMan) {
1663 for (wxRoutePointListNode *pnode =
1664 pWayPointMan->GetWaypointList()->GetFirst();
1665 pnode; pnode = pnode->GetNext()) {
1674static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1678 switch (vp.m_projection_type) {
1679 case PROJECTION_TRANSVERSE_MERCATOR:
1680 lat_dist = 4, lon_dist = 1;
1682 case PROJECTION_POLYCONIC:
1683 lat_dist = 2, lon_dist = 1;
1685 case PROJECTION_ORTHOGRAPHIC:
1686 lat_dist = 2, lon_dist = 2;
1688 case PROJECTION_POLAR:
1689 lat_dist = 180, lon_dist = 1;
1691 case PROJECTION_STEREOGRAPHIC:
1692 case PROJECTION_GNOMONIC:
1693 lat_dist = 2, lon_dist = 1;
1695 case PROJECTION_EQUIRECTANGULAR:
1698 lat_dist = 2, lon_dist = 360;
1701 lat_dist = 180, lon_dist = 360;
1705void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1706 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1712 ChartData->GetDBBoundingBox(dbIndex, box);
1713 if (!box.GetValid())
return;
1717 if (box.GetLonRange() == 360)
return;
1719 LLBBox vpbox = vp.GetBBox();
1721 double lon_bias = 0;
1723 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1726 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1727 color = GetGlobalColor(_T (
"YELO1" ));
1728 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1729 color = GetGlobalColor(_T (
"GREEN2" ));
1731 color = GetGlobalColor(_T (
"UINFR" ));
1733#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1734 float plylat, plylon;
1736 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1738 glColor3ub(color.Red(), color.Green(), color.Blue());
1739 glLineWidth(g_GLMinSymbolLineWidth);
1741 float lat_dist, lon_dist;
1742 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1745 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1749 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1751 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1753 bool begin =
false, sml_valid =
false;
1755 float lastplylat = 0.0;
1756 float lastplylon = 0.0;
1758 int modulo = (nPly == 0) ? 1 : nPly;
1759 for (
int i = 0; i < nPly + 1; i++) {
1761 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1763 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1767 if (lastplylon - plylon > 180)
1769 else if (lastplylon - plylon < -180)
1776 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1777 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1778 splits = wxMax(lat_splits, lon_splits) + 1;
1785 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1786 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1789 for (
double c = 0; c < splits; c++) {
1791 if (c == splits - 1)
1792 lat = plylat, lon = plylon;
1794 double d = (double)(c + 1) / splits;
1795 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1801 if (!std::isnan(s.m_x)) {
1804 glBegin(GL_LINE_STRIP);
1806 glVertex2f(s.m_x, s.m_y);
1812 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1813 lastplylat = plylat, lastplylon = plylon;
1818 }
while (++j < nAuxPlyEntries);
1820 glDisable(GL_LINE_SMOOTH);
1824 double nominal_line_width_pix =
1825 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1827 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1828 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), nominal_line_width_pix,
1831 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1832 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), nominal_line_width_pix,
1836 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), nominal_line_width_pix,
1839 float plylat1, plylon1;
1843 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1844 if (0 == nAuxPlyEntries)
1847 std::vector<int> points_vector;
1849 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1850 int nPly = vec.size() / 2;
1852 if (nPly == 0)
return;
1854 for (
int i = 0; i < nPly; i++) {
1855 plylon1 = vec[i * 2];
1856 plylat1 = vec[i * 2 + 1];
1862 points_vector.push_back(pixx1);
1863 points_vector.push_back(pixy1);
1866 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1867 plylon1 += lon_bias;
1873 points_vector.push_back(pixx1);
1874 points_vector.push_back(pixy1);
1876 if (points_vector.size()) {
1877 std::vector<int>::iterator it = points_vector.begin();
1878 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1886 for (
int j = 0; j < nAuxPlyEntries; j++) {
1887 std::vector<int> points_vector;
1889 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1890 int nAuxPly = vec.size() / 2;
1892 if (nAuxPly == 0)
continue;
1894 for (
int i = 0; i < nAuxPly; i++) {
1895 plylon1 = vec[i * 2];
1896 plylat1 = vec[i * 2 + 1];
1902 points_vector.push_back(pixx1);
1903 points_vector.push_back(pixy1);
1910 points_vector.push_back(pixx1);
1911 points_vector.push_back(pixy1);
1913 if (points_vector.size()) {
1914 std::vector<int>::iterator it = points_vector.begin();
1915 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1923extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1924 float &MinorSpacing);
1925extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1926void glChartCanvas::GridDraw() {
1927 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1929 ViewPort &vp = m_pParentCanvas->GetVP();
1931 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1935 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1937 double nlat, elon, slat, wlon;
1939 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1942 wxColour GridColor = GetGlobalColor(_T (
"SNDG1" ));
1944 if (!m_gridfont.IsBuilt()) {
1946 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1947 wxFont font = *dFont;
1948 int font_size = wxMax(10, dFont->GetPointSize());
1949 font.SetPointSize(font_size * m_displayScale);
1950 font.SetWeight(wxFONTWEIGHT_NORMAL);
1953 m_gridfont.Build(font, 1, dpi_factor);
1955 m_gridfont.SetColor(GridColor);
1960 LLBBox llbbox = vp.GetBBox();
1961 nlat = llbbox.GetMaxLat();
1962 slat = llbbox.GetMinLat();
1963 elon = llbbox.GetMaxLon();
1964 wlon = llbbox.GetMinLon();
1971 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1972 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1973 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1974 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1975 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1976 vp.m_projection_type == PROJECTION_POLAR ||
1977 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1980 if (straight_latitudes)
1983 latmargin = gridlatMajor / 2;
1985 slat = wxMax(slat, -90 + latmargin);
1986 nlat = wxMin(nlat, 90 - latmargin);
1988 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1989 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1993 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
2000 float lon_step = elon - wlon;
2001 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
2003 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2005 s.x = INVALID_COORD;
2006 s.y = INVALID_COORD;
2007 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
2009 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2010 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2018 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
2019 lat += gridlatMinor) {
2022 gldc.DrawLine(0, r.y, 10, r.y,
true);
2023 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
2028 float lat_step = nlat - slat;
2029 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
2031 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2033 s.x = INVALID_COORD;
2034 s.y = INVALID_COORD;
2035 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
2037 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2038 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2046 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
2047 lon += gridlonMinor) {
2050 gldc.DrawLine(r.x, 0, r.x, 10,
false);
2051 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
2057 glEnable(GL_TEXTURE_2D);
2059 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2060 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
2063 CalcGridText(lat, gridlatMajor,
true);
2065 m_gridfont.GetTextExtent(st, 0, &iy);
2067 if (straight_latitudes) {
2072 float x = 0, y = -1;
2073 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
2074 if (y < 0 || y > h) {
2076 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
2079 m_gridfont.RenderString(st, x, y);
2083 double y1, y2, lat1, lon1, lat2, lon2;
2092 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2095 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2097 if (fabs(y - y1) < fabs(y - y2))
2103 error = fabs(r.m_x);
2104 if (--maxiters == 0)
break;
2105 }
while (error > 1 && error < lasterror);
2107 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2113 m_gridfont.RenderString(st, r.m_x, r.m_y);
2117 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2118 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2127 else if (xlon <= -180.0)
2130 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2132 m_gridfont.GetTextExtent(st, &ix, 0);
2134 if (straight_longitudes) {
2135 float x = -1, y = 0;
2136 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2137 if (x < 0 || x > w) {
2139 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2142 m_gridfont.RenderString(st, x, y);
2146 double x1, x2, lat1, lon1, lat2, lon2;
2154 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2157 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2159 if (fabs(x - x1) < fabs(x - x2))
2165 error = fabs(r.m_y);
2166 }
while (error > 1 && error < lasterror);
2168 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2173 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2175 m_gridfont.RenderString(st, r.m_x, r.m_y);
2179 glDisable(GL_TEXTURE_2D);
2180 glDisable(GL_BLEND);
2185 if (!emboss)
return;
2187 int w = emboss->width, h = emboss->height;
2189 glEnable(GL_TEXTURE_2D);
2192 if (!emboss->gltexind) {
2194 emboss->glwidth = NextPow2(emboss->width);
2195 emboss->glheight = NextPow2(emboss->height);
2198 int size = emboss->glwidth * emboss->glheight;
2199 char *data =
new char[2 * size];
2200 for (
int i = 0; i < h; i++) {
2201 for (
int j = 0; j < emboss->glwidth; j++) {
2203 data[2 * ((i * emboss->glwidth) + j)] =
2204 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2205 data[2 * ((i * emboss->glwidth) + j) + 1] =
2206 (char)abs((emboss->pmap[(i * w) + j]));
2211 glGenTextures(1, &emboss->gltexind);
2212 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2213 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2214 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2216 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2217 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2222 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2226 int x = emboss->x, y = emboss->y;
2228 float wp = (float)w / emboss->glwidth;
2229 float hp = (float)h / emboss->glheight;
2255 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2257 glDisable(GL_BLEND);
2258 glDisable(GL_TEXTURE_2D);
2261void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2262 if (!m_pParentCanvas->GetVP().IsValid())
return;
2263 wxPoint GPSOffsetPixels(0, 0);
2264 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2267 float pCog = std::isnan(gCog) ? 0 : gCog;
2268 float pSog = std::isnan(gSog) ? 0 : gSog;
2272 double shift_dx = 0;
2273 double shift_dy = 0;
2274 bool dynamic = m_pParentCanvas->m_animationActive ||
2275 m_pParentCanvas->m_MouseDragging ||
2276 m_pParentCanvas->m_chart_drag_inertia_active;
2277 if (m_pParentCanvas->m_bFollow && !dynamic) {
2278 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2279 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2280 if (m_pParentCanvas->m_bLookAhead) {
2286 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2287 angle += m_pParentCanvas->GetVPRotation();
2288 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2290 lGPSPoint.m_x -= shift_dx / cos(gLat * PI / 180.);
2291 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2293 lGPSPoint.m_y += shift_dy / cos(gLat * PI / 180.);
2298 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2299 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2306 lShipMidPoint = lGPSPoint;
2310 float icon_hdt = pCog;
2311 if (!std::isnan(gHdt)) icon_hdt = gHdt;
2314 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2318 double osd_head_lat, osd_head_lon;
2319 wxPoint2DDouble osd_head_point;
2321 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2325 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2327 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2328 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2329 icon_rad += (float)PI;
2333 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2337 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2343 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2344 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2345 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2350 float scale_factor = 1.0;
2352 if ((g_ChartScaleFactorExp > 1.0) && (g_OwnShipIconType == 0))
2353 scale_factor = (log(g_ChartScaleFactorExp) + 1.0) * 1.1;
2355 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2356 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2357 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2359 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2361 float nominal_ownship_size_pixels =
2363 nominal_ownship_size_mm);
2365 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2367 wxPen ppSmallScaleShip;
2368 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2370 wxPen(GetGlobalColor(_T (
"URED" )), v / 5, wxPENSTYLE_SOLID);
2373 wxPen(GetGlobalColor(_T (
"YELO1" )), v / 5, wxPENSTYLE_SOLID);
2374 dc.SetPen(ppSmallScaleShip);
2377 wxBrush(GetGlobalColor(_T (
"URED" )), wxBRUSHSTYLE_TRANSPARENT));
2380 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2381 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2382 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2383 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2386 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2387 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2390 int draw_color = SHIP_INVALID;
2391 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2392 draw_color = SHIP_NORMAL;
2393 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2394 draw_color = SHIP_LOWACCURACY;
2402 ownship_color = draw_color;
2404 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2406 glGenTextures(1, &ownship_tex);
2407 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2409 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2410 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2413 if (m_pParentCanvas->m_pos_image_user) {
2414 switch (draw_color) {
2416 image = *m_pParentCanvas->m_pos_image_user_grey;
2419 image = *m_pParentCanvas->m_pos_image_user;
2421 case SHIP_LOWACCURACY:
2422 image = *m_pParentCanvas->m_pos_image_user_yellow;
2426 switch (draw_color) {
2428 image = *m_pParentCanvas->m_pos_image_grey;
2431 image = *m_pParentCanvas->m_pos_image_red;
2433 case SHIP_LOWACCURACY:
2434 image = *m_pParentCanvas->m_pos_image_yellow;
2439 int w = image.GetWidth(), h = image.GetHeight();
2440 int glw = NextPow2(w), glh = NextPow2(h);
2441 ownship_size = wxSize(w, h);
2442 ownship_tex_size = wxSize(glw, glh);
2444 unsigned char *d = image.GetData();
2445 unsigned char *a = image.GetAlpha();
2446 unsigned char *e =
new unsigned char[4 * w * h];
2449 for (
int p = 0; p < w * h; p++) {
2450 e[4 * p + 0] = d[3 * p + 0];
2451 e[4 * p + 1] = d[3 * p + 1];
2452 e[4 * p + 2] = d[3 * p + 2];
2453 e[4 * p + 3] = a[p];
2456 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2457 GL_UNSIGNED_BYTE, 0);
2459 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2465#ifndef USE_ANDROID_GLES2
2466 if (m_pParentCanvas->m_pos_image_user)
2467 glColor4ub(255, 255, 255, 255);
2468 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2469 glColor4ub(255, 0, 0, 255);
2470 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2471 glColor4ub(255, 255, 0, 255);
2473 glColor4ub(128, 128, 128, 255);
2475 float scale_factor_y = 1.0;
2476 float scale_factor_x = 1.0;
2478 int ownShipWidth = 22;
2479 int ownShipLength = 84;
2480 lShipMidPoint = lGPSPoint;
2483 if (g_OwnShipIconType != 0)
2484 m_pParentCanvas->ComputeShipScaleFactor(
2485 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2486 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2491 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2492 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2493 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2497 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2498 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2502 float gps_circle_radius = 3.0;
2504 if (g_OwnShipIconType == 0) {
2506 glEnable(GL_TEXTURE_2D);
2507 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2516 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2517 if (m_pParentCanvas->m_pos_image_user)
2518 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2520 float nominal_ownship_size_mm =
2521 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2523 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2524 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2526 float nominal_ownship_size_pixels =
2527 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2529 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2530 nominal_ownship_size_pixels = wxMax(
2531 20.0, nominal_ownship_size_pixels);
2534 float h = nominal_ownship_size_pixels * scale_factor_y;
2535 float w = nominal_ownship_size_pixels * scale_factor_x *
2536 ownship_size.x / ownship_size.y;
2537 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2538 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2544 gps_circle_radius = w / 5;
2546 float uv[8], coords[8];
2565 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2566 lShipMidPoint.m_x, lShipMidPoint.m_y,
2568 glDisable(GL_TEXTURE_2D);
2569 }
else if (g_OwnShipIconType == 1) {
2571 glEnable(GL_TEXTURE_2D);
2572 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2574 float nominal_ownship_size_pixels_y = 84;
2575 float nominal_ownship_size_pixels_x = 22;
2577 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2578 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2580 float u = (float)ownship_size.x / ownship_tex_size.x,
2581 v = (
float)ownship_size.y / ownship_tex_size.y;
2584 gps_circle_radius = w / 5;
2586 float uv[8], coords[8];
2605 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2606 lShipMidPoint.m_x, lShipMidPoint.m_y,
2609 glDisable(GL_TEXTURE_2D);
2610 }
else if (g_OwnShipIconType == 2) {
2618 wxPoint shipPoints[6];
2620 wxColour colour = m_pParentCanvas->ShipColor();
2621 wxPen ppPen(*wxBLACK, 1);
2622 wxBrush ppBrush(colour);
2624 dc.SetBrush(ppBrush);
2626 shipPoints[0].x = 0 * scale_factor_x;
2627 shipPoints[0].y = -28 * scale_factor_y;
2628 shipPoints[1].x = 11 * scale_factor_x;
2629 shipPoints[1].y = -28 * scale_factor_y;
2630 shipPoints[2].x = 11 * scale_factor_x;
2631 shipPoints[2].y = 42 * scale_factor_y;
2632 shipPoints[3].x = 0 * scale_factor_x;
2633 shipPoints[3].y = 42 * scale_factor_y;
2634 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2637 shipPoints[0].x = 0 * scale_factor_x;
2638 shipPoints[0].y = -42 * scale_factor_y;
2639 shipPoints[1].x = 5 * scale_factor_x;
2640 shipPoints[1].y = -42 * scale_factor_y;
2641 shipPoints[2].x = 11 * scale_factor_x;
2642 shipPoints[2].y = -28 * scale_factor_y;
2643 shipPoints[3].x = 0 * scale_factor_x;
2644 shipPoints[3].y = -28 * scale_factor_y;
2645 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2648 shipPoints[0].x = 0 * scale_factor_x;
2649 shipPoints[0].y = -28 * scale_factor_y;
2650 shipPoints[1].x = -11 * scale_factor_x;
2651 shipPoints[1].y = -28 * scale_factor_y;
2652 shipPoints[2].x = -11 * scale_factor_x;
2653 shipPoints[2].y = 42 * scale_factor_y;
2654 shipPoints[3].x = 0 * scale_factor_x;
2655 shipPoints[3].y = 42 * scale_factor_y;
2656 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2659 shipPoints[0].x = 0 * scale_factor_x;
2660 shipPoints[0].y = -42 * scale_factor_y;
2661 shipPoints[1].x = -5 * scale_factor_x;
2662 shipPoints[1].y = -42 * scale_factor_y;
2663 shipPoints[2].x = -11 * scale_factor_x;
2664 shipPoints[2].y = -28 * scale_factor_y;
2665 shipPoints[3].x = 0 * scale_factor_x;
2666 shipPoints[3].y = -28 * scale_factor_y;
2667 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2671 double p1x = -11 * scale_factor_x;
2672 double p2x = 11 * scale_factor_x;
2676 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2678 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2680 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2682 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2683 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2684 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2688 p1y = -42 * scale_factor_y;
2689 p2y = 42 * scale_factor_y;
2690 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2691 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2692 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2693 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2694 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2695 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2698 img_height = ownShipLength * scale_factor_y;
2701 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2703 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
2705 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"CHWHT" ))));
2707 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2711 glDisable(GL_LINE_SMOOTH);
2712 glDisable(GL_POLYGON_SMOOTH);
2713 glDisable(GL_BLEND);
2716 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2720void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2721 ViewPort &vp = m_pParentCanvas->GetVP();
2726 Route *active_route = g_pRouteMan->GetpActiveRoute();
2737 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
2738 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2744 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2746 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2747 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2749 m_pParentCanvas->AlertDraw(dc);
2751 m_pParentCanvas->RenderVisibleSectorLights(dc);
2753 m_pParentCanvas->RenderRouteLegs(dc);
2754 m_pParentCanvas->RenderShipToActive(dc,
true);
2755 m_pParentCanvas->ScaleBarDraw(dc);
2756 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2757 m_pParentCanvas->extendedSectorLegs);
2759 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2764void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2765 if (m_pParentCanvas->GetPiano()) {
2766 int canvas_height = GetClientSize().y;
2767 canvas_height *= m_displayScale;
2769 m_pParentCanvas->GetPiano()->DrawGL(
2770 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2774void glChartCanvas::DrawQuiting() {
2775#ifndef USE_ANDROID_GLES2
2776 GLubyte pattern[8][8];
2777 for (
int y = 0; y < 8; y++)
2778 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2781 glEnable(GL_TEXTURE_2D);
2782 glBindTexture(GL_TEXTURE_2D, 0);
2784 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2785 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2786 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2788 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2792 float x = GetSize().x, y = GetSize().y;
2793 float u = x / 8, v = y / 8;
2806 glDisable(GL_TEXTURE_2D);
2807 glDisable(GL_BLEND);
2811void glChartCanvas::DrawCloseMessage(wxString msg) {
2812#ifndef USE_ANDROID_GLES2
2816 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2820 texfont.Build(*pfont, 1, 1);
2822 texfont.GetTextExtent(msg, &w, &h);
2824 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2825 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2827 glColor3ub(243, 229, 47);
2831 glVertex2i(xp + w, yp);
2832 glVertex2i(xp + w, yp + h);
2833 glVertex2i(xp, yp + h);
2838 glColor3ub(0, 0, 0);
2839 glEnable(GL_TEXTURE_2D);
2840 texfont.RenderString(msg, xp, yp);
2841 glDisable(GL_TEXTURE_2D);
2842 glDisable(GL_BLEND);
2849static std::list<double *> combine_work_data;
2850static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2851 GLfloat weight[4], GLdouble **dataOut) {
2852 double *vertex =
new double[3];
2853 combine_work_data.push_back(vertex);
2854 memcpy(vertex, coords, 3 * (
sizeof *coords));
2858#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2859void vertexCallbackD_GLSL(GLvoid *vertex) {
2861 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2862 int new_buf_len = s_tess_buf_len + 100;
2863 GLfloat *tmp = s_tess_work_buf;
2866 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2867 if (NULL == s_tess_work_buf) {
2871 s_tess_buf_len = new_buf_len;
2874 GLdouble *pointer = (GLdouble *)vertex;
2876 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2877 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2882void beginCallbackD_GLSL(GLenum mode) {
2883 s_tess_vertex_idx_this = s_tess_vertex_idx;
2888void endCallbackD_GLSL() {
2892 shader->SetUniformMatrix4fv(
"MVMatrix",
2893 (GLfloat *)s_tessVP.vp_matrix_transform);
2895 mat4x4 identityMatrix;
2896 mat4x4_identity(identityMatrix);
2897 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2901 colorv[0] = s_regionColor.Red() / float(256);
2902 colorv[1] = s_regionColor.Green() / float(256);
2903 colorv[2] = s_regionColor.Blue() / float(256);
2904 colorv[3] = s_regionColor.Alpha() / float(256);
2905 shader->SetUniform4fv(
"color", colorv);
2907 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2908 shader->SetAttributePointerf(
"position", bufPt);
2910 glDrawArrays(s_tess_mode, 0, s_nvertex);
2915void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2917void beginCallbackD(GLenum mode) { glBegin(mode); }
2919void endCallbackD() { glEnd(); }
2923void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2924 float lat_dist, lon_dist;
2925 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2927 GLUtesselator *tobj = gluNewTess();
2928 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2930#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2931 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2932 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2933 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2934 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2938 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2939 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2940 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2941 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2944 gluTessNormal(tobj, 0, 0, 1);
2946 gluTessBeginPolygon(tobj, NULL);
2947 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2948 i != region.contours.end(); i++) {
2949 gluTessBeginContour(tobj);
2950 contour_pt l = *i->rbegin();
2952 bool sml_valid =
false;
2953 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2954 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2955 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2956 int splits = wxMax(lat_splits, lon_splits) + 1;
2962 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2963 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2966 for (
int i = 0; i < splits; i++) {
2968 if (i == splits - 1)
2969 lat = j->y, lon = j->x;
2971 double d = (double)(i + 1) / splits;
2972 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2976 if (std::isnan(q.m_x))
continue;
2978 double *p =
new double[6];
2983 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2988 gluTessVertex(tobj, p, p);
2989 combine_work_data.push_back(p);
2993 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2995 gluTessEndContour(tobj);
2997 gluTessEndPolygon(tobj);
2999 gluDeleteTess(tobj);
3001 for (std::list<double *>::iterator i = combine_work_data.begin();
3002 i != combine_work_data.end(); i++)
3004 combine_work_data.clear();
3009void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
3010 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3012 if (s_b_useStencil) {
3014 glEnable(GL_STENCIL_TEST);
3016 glClear(GL_STENCIL_BUFFER_BIT);
3020 glStencilFunc(GL_ALWAYS, 1, 1);
3021 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
3024#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3028 glEnable(GL_DEPTH_TEST);
3029 glDepthFunc(GL_ALWAYS);
3030 glDepthMask(GL_TRUE);
3032 glClear(GL_DEPTH_BUFFER_BIT);
3045 glTranslatef(0, 0, .5);
3049 s_regionColor = wxColor(0, 0, 0, 255);
3050 DrawRegion(vp, region);
3052 if (s_b_useStencil) {
3055 glStencilFunc(GL_EQUAL, 1, 1);
3056 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3059#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3061 glDepthFunc(GL_GREATER);
3062 glDepthMask(GL_FALSE);
3063 glTranslatef(0, 0, -.5);
3066 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3069void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
3073 if (s_b_useStencil && s_b_useScissorTest) {
3075 if (rect != vp_rect) {
3076 glEnable(GL_SCISSOR_TEST);
3077 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3080#ifndef USE_ANDROID_GLES2
3086void glChartCanvas::DisableClipRegion() {
3087 glDisable(GL_SCISSOR_TEST);
3088 glDisable(GL_STENCIL_TEST);
3089 glDisable(GL_DEPTH_TEST);
3092void glChartCanvas::Invalidate() {
3094 m_cache_vp.Invalidate();
3100 if (!pBSBChart)
return;
3102 if (b_inCompressAllCharts)
3106 wxString key = chart->GetHashKey();
3109 ChartPathHashTexfactType &hash = g_glTextureManager->m_chart_texfactory_hash;
3110 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3113 if (ittf == hash.end()) {
3115 hash[key]->SetHashKey(key);
3118 pTexFact = hash[key];
3119 pTexFact->SetLRUTime(++m_LRUtime);
3124 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3125 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3132 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3133 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3134 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3135 base_level = log(scalefactor) / log(2.0);
3139 if (base_level > g_mipmap_max_level) base_level = g_mipmap_max_level;
3144 glEnable(GL_TEXTURE_2D);
3145#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3146 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3148 glEnableClientState(GL_VERTEX_ARRAY);
3149 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3154 pTexFact->GetCenter(lat, lon);
3155 MultMatrixViewPort(vp, lat, lon);
3159 LLBBox box = region.GetBox();
3162 if (g_memCacheLimit > 0) {
3164 GetMemoryStatus(0, &mem_used);
3167 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3168 for (
int i = 0; i < numtiles; i++) {
3170 if (region.IntersectOut(tile->box)) {
3173 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3174 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3176 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3177 global_color_scheme, mem_used);
3181 coords = tile->m_coords;
3183 coords =
new float[2 * tile->m_ncoords];
3184 for (
int i = 0; i < tile->m_ncoords; i++) {
3186 tile->m_coords[2 * i + 1]);
3187 coords[2 * i + 0] = p.m_x;
3188 coords[2 * i + 1] = p.m_y;
3192#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3193 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3194 m_pParentCanvas->GetpVP());
3197 glDisable(GL_TEXTURE_2D);
3201 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3202 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3203 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3205 if (!texture) glEnable(GL_TEXTURE_2D);
3207 if (!use_norm_vp)
delete[] coords;
3211 glDisable(GL_TEXTURE_2D);
3213#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3214 if (use_norm_vp) glPopMatrix();
3216 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3217 glDisableClientState(GL_VERTEX_ARRAY);
3221void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3223 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3224 m_pParentCanvas->m_pQuilt->IsBusy())
3228 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3237 LLRegion region = vp.GetLLRegion(rect_region);
3239 LLRegion rendered_region;
3245 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3253 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3255 LLRegion get_region = pqp->ActiveRegion;
3256 bool b_rendered =
false;
3258 if (!pqp->b_overlay) {
3259 get_region.Intersect(region);
3260 if (!get_region.Empty()) {
3261 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3264 SetClipRegion(vp, get_region );
3265 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3266 DisableClipRegion();
3269 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3270 SetClipRegion(vp, pqp->ActiveRegion );
3271 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3273 DisableClipRegion();
3276 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3277 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3278 RenderNoDTA(vp, get_region);
3279 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3284 if (Chs57->m_RAZBuilt) {
3285 RenderNoDTA(vp, get_region);
3286 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3287 rect_region, get_region);
3288 DisableClipRegion();
3293 const LLRegion &oregion = get_region;
3294 LLBBox box = oregion.GetBox();
3305 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3308 ViewPort cvp = ClippedViewport(vp, get_region);
3309 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3310 SetClipRegion(cvp, get_region);
3311 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3312 GetGlobalColor(_T (
"LANDA" )),
3313 GetGlobalColor(_T (
"DEPMS" )));
3314 RenderWorldChart(gldc, cvp, srect, world);
3315 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3316 global_color_scheme);
3317 DisableClipRegion();
3324 SetClipRegion(vp, get_region);
3325 RenderNoDTA(vp, get_region);
3326 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3328 DisableClipRegion();
3331 SetClipRegion(vp, get_region);
3332 RenderNoDTA(vp, get_region);
3333 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3335 DisableClipRegion();
3351 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3355 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3356 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3358 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3359 if (pqp->b_Valid && pqp->b_overlay &&
3360 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3361 LLRegion get_region = pqp->ActiveRegion;
3363 get_region.Intersect(region);
3364 if (!get_region.Empty()) {
3367 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3372 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3379 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3384 ViewPort vph = m_pParentCanvas->GetVP();
3385 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3388 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3390 if (!hiregion.Empty()) {
3394 switch (global_color_scheme) {
3395 case GLOBAL_COLOR_SCHEME_DAY:
3398 case GLOBAL_COLOR_SCHEME_DUSK:
3401 case GLOBAL_COLOR_SCHEME_NIGHT:
3409#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3411 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3413 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3416 DrawRegion(vp, hiregion);
3418 glDisable(GL_BLEND);
3423 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3425 if (!hiregion.Empty()) {
3429 switch (global_color_scheme) {
3430 case GLOBAL_COLOR_SCHEME_DAY:
3433 case GLOBAL_COLOR_SCHEME_DUSK:
3436 case GLOBAL_COLOR_SCHEME_NIGHT:
3445#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3447 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3449 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3452 DrawRegion(vp, hiregion);
3454 glDisable(GL_BLEND);
3458 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3461void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3463 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3464 m_pParentCanvas->m_pQuilt->IsBusy())
3468 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3470 LLRegion region = vp.GetLLRegion(rect_region);
3472 LLRegion rendered_region;
3474 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3476 LLRegion get_region = pqp->ActiveRegion;
3478 if (!pqp->b_overlay) {
3479 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3482 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3487 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3494 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3522void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3523 ViewPort &vp = m_pParentCanvas->VPoint;
3531 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3532 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3535 LLRegion chart_region;
3537 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3538 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3539 CHART_FAMILY_RASTER) {
3547 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3548 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3549 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3551 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3555 for (
int i = 1; i < 6; i += 2)
3556 if (fabs(ll[i] - ll[i + 2]) > 180) {
3558 for (
int i = 1; i < 8; i += 2)
3559 if (ll[i] < 0) ll[i] += 360;
3563 chart_region = LLRegion(4, ll);
3566 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3568 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3569 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3570 chart_region = LLRegion(4, ll);
3573 chart_region = vp.b_quilt
3574 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3575 : m_pParentCanvas->m_singleChart->GetValidRegion();
3577 bool world_view =
false;
3579 wxRect rect = upd.GetRect();
3580 LLRegion background_region = vp.GetLLRegion(rect);
3583 background_region.Subtract(chart_region);
3585 if (!background_region.Empty()) {
3586 ViewPort cvp = ClippedViewport(vp, background_region);
3587 SetClipRect(cvp, rect,
false);
3588 RenderWorldChart(dc, cvp, rect, world_view);
3589 DisableClipRegion();
3594 RenderQuiltViewGL(vp, rect_region);
3596 LLRegion region = vp.GetLLRegion(rect_region);
3597 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3598 CHART_FAMILY_RASTER) {
3599 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3600 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3601 *m_pcontext, vp, rect_region, region);
3603 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3604 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3605 CHART_FAMILY_VECTOR) {
3606 chart_region.Intersect(region);
3607 RenderNoDTA(vp, chart_region);
3608 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3609 rect_region, region);
3615void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3617 wxColour color = GetGlobalColor(_T (
"NODTA" ));
3618#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3620 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3622 glColor4ub(163, 180, 183, transparency);
3625 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3629 s_regionColor = color;
3632 DrawRegion(vp, region);
3636void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3639 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3641 glEnable(GL_SCISSOR_TEST);
3642 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3648 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3649#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3651 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3655 colorv[0] = water.Red() / float(256);
3656 colorv[1] = water.Green() / float(256);
3657 colorv[2] = water.Blue() / float(256);
3659 shader->SetUniform4fv(
"color", colorv);
3670 shader->SetAttributePointerf(
"position", pf);
3672 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3682 gShapeBasemap.RenderViewOnDC(dc, vp);
3684 glDisable(GL_SCISSOR_TEST);
3692void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3693 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3695 DrawStaticRoutesTracksAndWaypoints(vp);
3697 DisableClipRegion();
3700void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3702 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3706 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3707 if (!bmp.Ok())
return;
3709 wxImage image = bmp.ConvertToImage();
3710 int w = image.GetWidth(), h = image.GetHeight();
3713 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3714 tex_w = w, tex_h = h;
3716 tex_w = NextPow2(w), tex_h = NextPow2(h);
3718 m_tideTexWidth = tex_w;
3719 m_tideTexHeight = tex_h;
3721 unsigned char *d = image.GetData();
3722 unsigned char *a = image.GetAlpha();
3724 unsigned char mr, mg, mb;
3725 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3727 unsigned char *e =
new unsigned char[4 * w * h];
3729 for (
int y = 0; y < h; y++)
3730 for (
int x = 0; x < w; x++) {
3731 unsigned char r, g, b;
3732 int off = (y * w + x);
3742 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3746 glGenTextures(1, &m_tideTex);
3748 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3749 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3750 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3752 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3753 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3754 GL_UNSIGNED_BYTE, e);
3756 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3757 GL_UNSIGNED_BYTE, 0);
3758 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3767 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3768 glEnable(GL_TEXTURE_2D);
3771#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3773 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
3774 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
3777 if ((type ==
't') || (type ==
'T'))
3782 if (BBox.Contains(lat, lon)) {
3791 scale *= getAndroidDisplayDensity();
3793 double width2 =
scale * m_tideTexWidth / 2;
3794 double height2 =
scale * m_tideTexHeight / 2;
3809 coords[0] = xp - width2;
3810 coords[1] = yp - height2;
3811 coords[2] = xp - width2;
3812 coords[3] = yp + height2;
3813 coords[4] = xp + width2;
3814 coords[5] = yp + height2;
3815 coords[6] = xp + width2;
3816 coords[7] = yp - height2;
3818 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3825 glDisable(GL_TEXTURE_2D);
3826 glDisable(GL_BLEND);
3827 glBindTexture(GL_TEXTURE_2D, 0);
3829 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3832void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3833 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3836void glChartCanvas::SetColorScheme(ColorScheme cs) {
3837 if (!m_bsetup)
return;
3839 glDeleteTextures(1, &m_tideTex);
3840 glDeleteTextures(1, &m_currentTex);
3846void glChartCanvas::RenderGLAlertMessage() {
3847 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3848 wxString msg = m_pParentCanvas->GetAlertString();
3851 m_gldc.SetFont(*pfont);
3855 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3862 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3863 int xp = sbr.x + sbr.width + 5;
3865 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
3866 m_gldc.SetPen(ppPen1);
3867 m_gldc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
3869 m_gldc.DrawRectangle(xp, yp, w, h);
3871 m_gldc.DrawText(msg, xp, yp);
3875unsigned long quiltHash;
3877extern wxLongLong s_t0;
3880void glChartCanvas::Render() {
3881 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3882 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3883 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3888 if (!g_PrintingInProgress)
return;
3891 if (m_binPinch)
return;
3893#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3894 loadShaders(GetCanvasIndex());
3895 configureShaders(m_pParentCanvas->VPoint);
3898#ifdef USE_ANDROID_GLES2
3902 if (m_binPinch)
return;
3911 bool recompose =
false;
3912 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3913 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3914 if (m_pParentCanvas->VPoint.IsValid()) {
3915 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3916 m_pParentCanvas->UpdateCanvasControlBar();
3925 if (sw.GetTime() > 2000) {
3931 s_tess_vertex_idx = 0;
3932 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3933 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3939 m_displayScale = GetContentScaleFactor();
3943 m_last_render_time = wxDateTime::Now().GetTicks();
3947 if (g_GLOptions.m_bTextureCompression &&
3948 !g_GLOptions.m_bTextureCompressionCaching)
3949 g_glTextureManager->ClearJobList();
3953 int gl_width, gl_height;
3954 gl_width = m_pParentCanvas->VPoint.
pix_width;
3955 gl_height = m_pParentCanvas->VPoint.
pix_height;
3958 m_glcanvas_width = gl_width;
3959 m_glcanvas_height = gl_height;
3963 if (gl_height & 1) {
3965 ViewPort *vp = m_pParentCanvas->GetpVP();
3972 ViewPort *vp = m_pParentCanvas->GetpVP();
3980 ViewPort *vp = m_pParentCanvas->GetpVP();
3983 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3986 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3994 ViewPort VPoint = m_pParentCanvas->VPoint;
3996 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3997 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
4000#if !defined(USE_ANDROID_GLES2)
4001 glMatrixMode(GL_PROJECTION);
4004 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4005 glMatrixMode(GL_MODELVIEW);
4009 if (s_b_useStencil) {
4010 glEnable(GL_STENCIL_TEST);
4011 glStencilMask(0xff);
4012 glClear(GL_STENCIL_BUFFER_BIT);
4013 glDisable(GL_STENCIL_TEST);
4019 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4020 if (g_GLOptions.m_GLPolygonSmoothing)
4021 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4022 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4029 g_glTextureManager->TextureCrunch(0.8);
4034 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
4035 bool useFBO =
false;
4041 if (m_b_BuiltFBO && !bpost_hilite
4046 bool b_newview =
true;
4047 bool b_full =
false;
4055 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
4059#ifdef USE_ANDROID_GLES2
4060 if (recompose) b_newview =
true;
4072 if (VPoint.b_quilt) {
4073 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
4074 if (!chart) b_full =
true;
4083 bool accelerated_pan =
false;
4093 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4094 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4095 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4097 wxPoint2DDouble c_old =
4100 wxPoint2DDouble c_new =
4104 dy = wxRound(c_new.m_y - c_old.m_y);
4105 dx = wxRound(c_new.m_x - c_old.m_x);
4115 double deltax = c_new.m_x - c_old.m_x;
4116 double deltay = c_new.m_y - c_old.m_y;
4118 bool b_whole_pixel =
true;
4119 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4120 b_whole_pixel =
false;
4122 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4123 abs(dy) < m_cache_tex_y &&
4124 (abs(dx) > 0 || (abs(dy) > 0));
4133 if (m_displayScale > 1) accelerated_pan =
false;
4138 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4141#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4144 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4150 if (b_full) accelerated_pan =
false;
4152 if (accelerated_pan) {
4153 if ((dx != 0) || (dy != 0)) {
4165 if (dy > 0 && dy < gl_height)
4166 update_region.Union(
4167 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4169 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4171 if (dx > 0 && dx < gl_width)
4172 update_region.Union(
4173 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4175 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4177 m_cache_page = !m_cache_page;
4180 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4181 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4193 RenderCharts(m_gldc, update_region);
4197 glDisable(g_texture_rectangle_format);
4202 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4203 glEnable(GL_TEXTURE_2D);
4207 float x1, x2, y1, y2;
4220 float tx1, tx2, ty1, ty2;
4226 tx2 = sx / (float)m_cache_tex_x;
4228 ty2 = sy / (float)m_cache_tex_y;
4245 coords[2] = -dx + sx;
4247 coords[4] = -dx + sx;
4248 coords[5] = dy + sy;
4250 coords[7] = dy + sy;
4253 ptexture_2D_shader_program[GetCanvasIndex()];
4257 shader->SetUniform1i(
"uTex", 0);
4261 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4262 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4263 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4265 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4287 shader->SetAttributePointerf(
"aPos", co1);
4288 shader->SetAttributePointerf(
"aUV", tco1);
4290 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4293 shader->SetUniformMatrix4fv(
"MVMatrix",
4294 (GLfloat *)VPoint.vp_matrix_transform);
4297 glBindTexture(g_texture_rectangle_format, 0);
4299 glDisable(g_texture_rectangle_format);
4307 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4308 g_texture_rectangle_format,
4309 m_cache_tex[!m_cache_page], 0);
4320 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4321 glClearColor(color.Red() / 256., color.Green() / 256.,
4322 color.Blue() / 256., 1.0);
4323 glClear(GL_COLOR_BUFFER_BIT);
4329 RenderCharts(m_gldc, rscreen_region);
4334 m_cache_page = !m_cache_page;
4339 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4350 glMatrixMode(GL_PROJECTION);
4353 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4354 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4356 glMatrixMode(GL_MODELVIEW);
4360 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4361 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4363 glGetIntegerv(GL_VIEWPORT, viewport);
4364 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4365 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4374 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4375 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4376 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4378 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4382 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4383 glEnable(g_texture_rectangle_format);
4385 float tx, ty, tx0, ty0, divx, divy;
4388 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4391 divx = m_cache_tex_x;
4392 divy = m_cache_tex_y;
4395 tx0 = m_fbo_offsetx / divx;
4396 ty0 = m_fbo_offsety / divy;
4397 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4398 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4423 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4424 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4426 glClear(GL_COLOR_BUFFER_BIT);
4428 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4431 glDisable(g_texture_rectangle_format);
4433 m_cache_vp = VPoint;
4434 m_cache_vp.Validate();
4436 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4438 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4442 RenderCharts(m_gldc, screen_region);
4447 RenderS57TextOverlay(VPoint);
4448 RenderMBTilesOverlay(VPoint);
4452 g_pi_manager->SendViewPortToRequestingPlugIns(VPoint);
4453 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4454 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4459 wxRect rt = upd.GetRect();
4460 LLRegion region = VPoint.GetLLRegion(rt);
4461 ViewPort cvp = ClippedViewport(VPoint, region);
4462 DrawGroundedOverlayObjects(gldc, cvp);
4465 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4466 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4467 LLBBox screenBox = screenLLRegion.GetBox();
4469 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4472 if (m_pParentCanvas->m_bShowTide) {
4473 m_pParentCanvas->RebuildTideSelectList(screenBox);
4474 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4477 if (m_pParentCanvas->m_bShowCurrent) {
4478 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4479 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4485 if (m_pParentCanvas->m_show_focus_bar &&
4486 (g_canvasConfig != 0)) {
4487 if (m_pParentCanvas == wxWindow::FindFocus()) {
4490 wxColour colour = GetGlobalColor(
"BLUE4");
4491 wxPen ppBlue(colour, 1);
4492 wxBrush ppBrush(colour);
4493 gldc.SetPen(ppBlue);
4494 gldc.SetBrush(ppBrush);
4495 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4496 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4497 wxPoint barPoints[4];
4500 barPoints[1].x = xw;
4502 barPoints[2].x = xw;
4503 barPoints[2].y = rect_pix;
4505 barPoints[3].y = rect_pix;
4507 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4511 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4515 DrawFloatingOverlayObjects(m_gldc);
4517#ifndef USE_ANDROID_GLES2
4520 glMatrixMode(GL_PROJECTION);
4523 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4524 glMatrixMode(GL_MODELVIEW);
4529 if (!g_bhide_depth_units)
4530 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4531 if (!g_bhide_overzoom_flag)
4532 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4535 ViewPort &vp = m_pParentCanvas->GetVP();
4536 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4537 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4540 if (!g_PrintingInProgress) {
4541 if (m_pParentCanvas->m_pTrackRolloverWin)
4542 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4544 if (m_pParentCanvas->m_pRouteRolloverWin)
4545 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4547 if (m_pParentCanvas->m_pAISRolloverWin)
4548 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4550 if (m_pParentCanvas->GetMUIBar())
4551 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4553 if (g_MainToolbar && m_pParentCanvas->IsPrimaryCanvas())
4554 g_MainToolbar->DrawGL(gldc, m_displayScale);
4556 if (g_iENCToolbar && m_pParentCanvas->IsPrimaryCanvas())
4557 g_iENCToolbar->DrawGL(gldc, m_displayScale);
4565 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4566 int x, y, width, height;
4567 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4568 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4569 wxBitmap bmp(width, height, -1);
4572 dc.SetBackground(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
4575 dc.SetTextBackground(GetGlobalColor(_T (
"UIBCK" )));
4576 dc.SetTextForeground(GetGlobalColor(_T (
"UITX1" )));
4580 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4581 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4583 wxStringTokenizer tkz(s,
"\n");
4586 while (tkz.HasMoreTokens()) {
4587 token = tkz.GetNextToken();
4588 dc.DrawText(token, xt, yt);
4591 dc.SelectObject(wxNullBitmap);
4593 m_gldc.DrawBitmap(bmp, x, y,
false);
4599 if (g_bShowChartBar) DrawChartBar(m_gldc);
4601 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4603 m_pParentCanvas->m_Compass->Paint(gldc);
4605 if (m_pParentCanvas->IsPrimaryCanvas()) {
4606 auto ¬eman = NotificationManager::GetInstance();
4607 if (noteman.GetNotificationCount()) {
4608 m_pParentCanvas->m_notification_button->SetIconSeverity(
4609 noteman.GetMaxSeverity());
4610 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4611 m_pParentCanvas->m_notification_button->Show(
true);
4612 m_pParentCanvas->m_notification_button->Paint(gldc);
4614 m_pParentCanvas->m_notification_button->Show(
false);
4617 RenderGLAlertMessage();
4620 ViewPort &vp = m_pParentCanvas->GetVP();
4621 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4622 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
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) {
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(
"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);
5965 g_pi_manager->SendViewPortToRequestingPlugIns(VPoint);
5966 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
5967 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5970 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5971 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5972 DrawFloatingOverlayObjects(m_gldc);
5976 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5981wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5983 wxMemoryDC tdc(tbm);
5984 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5992 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5993 dc.SetPen(*wxTRANSPARENT_PEN);
5995 gShapeBasemap.RenderViewOnDC(dc, tvp);
5996 tdc.SelectObject(wxNullBitmap);
5997 m_touch_backing_bitmap = tbm;
5998 CreateBackingTexture();
6000 return m_touch_backing_bitmap;
6003void glChartCanvas::CreateBackingTexture() {
6004 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6005 unsigned char *imgdata = image.GetData();
6006 unsigned char *imgalpha = image.GetAlpha();
6007 m_tex_w = image.GetWidth();
6008 m_tex_h = image.GetHeight();
6009 m_image_width = m_tex_w;
6010 m_image_height = m_tex_h;
6012 GLuint format = GL_RGBA;
6013 GLuint internalformat = g_texture_rectangle_format;
6015 internalformat = GL_RGBA;
6020 unsigned char *teximage =
6021 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6023 for (
int i = 0; i < m_image_height; i++) {
6024 for (
int j = 0; j < m_image_width; j++) {
6025 int s = (i * 3 * m_image_width) + (j * 3);
6026 int d = (i * stride * m_tex_w) + (j * stride);
6028 teximage[d + 0] = imgdata[s + 0];
6029 teximage[d + 1] = imgdata[s + 1];
6030 teximage[d + 2] = imgdata[s + 2];
6031 teximage[d + 3] = 255;
6035 glGenTextures(1, &m_TouchBackingTexture);
6036 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6038 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6039 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6040 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6042 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6044 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6045 GL_UNSIGNED_BYTE, teximage);
6048 glBindTexture(GL_TEXTURE_2D, 0);
Wrapper for creating a ChartCtx based on global vars.
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
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.
Class cm93chart and helpers – CM93 chart state.
Global color handling by name.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Class NotificationManager.
#define OVERLAY_CHARTS
Lowest priority for overlays to render above all basic charts.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
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.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents an entry in the chart table, containing information about a single chart.