40#include <wx/arrimpl.cpp>
43#include <wx/dcmemory.h>
44#include <wx/dynarray.h>
48#include <wx/glcanvas.h>
50#include <wx/jsonval.h>
53#include <wx/progdlg.h>
54#include <wx/stopwatch.h>
56#include <wx/tokenzr.h>
60#include "model/own_ship.h"
62#include "model/route.h"
63#include "model/routeman.h"
64#include "model/track.h"
68#include "chart_ctx_factory.h"
74#include "color_handler.h"
77#include "emboss_data.h"
79#include "glChartCanvas.h"
80#include "glTexCache.h"
84#include "mipmap/mipmap.h"
86#include "OCPNPlatform.h"
88#include "pluginmanager.h"
90#include "RolloverWin.h"
92#include "route_point_gui.h"
101#include "iENCToolbar.h"
102#include "shapefile_basemap.h"
103#include "s57_ocpn_utils.h"
105#ifdef USE_ANDROID_GLES2
106#include <GLES2/gl2.h>
112#include "androidUTIL.h"
113#elif defined(__WXQT__) || defined(__WXGTK__)
117#ifndef GL_ETC1_RGB8_OES
118#define GL_ETC1_RGB8_OES 0x8D64
121#ifndef GL_DEPTH_STENCIL_ATTACHMENT
122#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
125#if defined(__UNIX__) && !defined(__WXOSX__)
130 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
134 clock_gettime(CLOCK_REALTIME, &tp_end);
135 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
136 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
145#define printf printf2
146int __cdecl printf2(
const char *format, ...);
149#if defined(__ANDROID__)
150#include "androidUTIL.h"
151#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
155#ifndef GL_ETC1_RGB8_OES
156#define GL_ETC1_RGB8_OES 0x8D64
164extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
165 float near,
float far);
166#define glOrtho(a, b, c, d, e, f) \
168 glOrthof(a, b, c, d, e, f);
176#ifdef USE_ANDROID_GLES2
177#include <GLES2/gl2.h>
180#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
186extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
188extern s52plib *ps52plib;
189extern bool g_bopengl;
190extern bool g_bDebugOGL;
191extern bool g_bSoftwareGL;
194extern bool g_bShowChartBar;
196extern bool b_inCompressAllCharts;
197extern bool g_bShowCompassWin;
199extern GLenum g_texture_rectangle_format;
201extern int g_memCacheLimit;
202extern ColorScheme global_color_scheme;
203extern bool g_bquiting;
205extern int g_mipmap_max_level;
207extern int g_OwnShipIconType;
213extern RouteList *pRouteList;
214extern std::vector<Track *> g_TrackList;
215extern bool b_inCompressAllCharts;
216extern bool g_bGLexpert;
217extern bool g_bcompression_wait;
218extern float g_ShipScaleFactorExp;
220float g_GLMinCartographicLineWidth;
222extern bool g_fog_overzoom;
223extern double g_overzoom_emphasis_base;
224extern bool g_oz_vector_scale;
226extern int g_nCPUCount;
227extern bool g_running;
229extern unsigned int g_canvasConfig;
233extern bool g_PrintingInProgress;
237wxColor s_regionColor;
249#define APIENTRYP APIENTRY *
255#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
256#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
259PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
260PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
261PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
262PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
263PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
264PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
265PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
266PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
267PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
268PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
270PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
271PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
274PFNGLGENBUFFERSPROC s_glGenBuffers;
275PFNGLBINDBUFFERPROC s_glBindBuffer;
276PFNGLBUFFERDATAPROC s_glBufferData;
277PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
279#ifndef USE_ANDROID_GLES2
284typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
286PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
288#include <wx/arrimpl.cpp>
291GLuint g_raster_format = GL_RGB;
295wxStopWatch g_glstopwatch;
296double g_gl_ms_per_frame;
299int g_uncompressed_tile_size;
301extern wxProgressDialog *pprog;
302extern bool b_skipout;
303extern wxSize pprog_size;
304extern int pprog_count;
305extern int pprog_threads;
311bool glChartCanvas::s_b_useScissorTest;
312bool glChartCanvas::s_b_useStencil;
313bool glChartCanvas::s_b_useStencilAP;
314bool glChartCanvas::s_b_useFBO;
316#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
317static int s_tess_vertex_idx;
318static int s_tess_vertex_idx_this;
319static int s_tess_buf_len;
320static GLfloat *s_tess_work_buf;
323static vec4 s_tess_color;
333 while ( upd.HaveRects() )
335 wxRect rect = upd.GetRect();
336 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
343GLboolean QueryExtension(
const char *extName) {
354 extNameLen = strlen(extName);
356 p = (
char *)glGetString(GL_EXTENSIONS);
364 int n = strcspn(p,
" ");
365 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
373int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
374 16, WX_GL_STENCIL_SIZE, 8,
377glTestCanvas::glTestCanvas(wxWindow *parent)
378 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
382int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
383 16, WX_GL_STENCIL_SIZE, 8,
386EVT_PAINT(glChartCanvas::OnPaint)
387EVT_ACTIVATE(glChartCanvas::OnActivate)
388EVT_SIZE(glChartCanvas::OnSize)
389EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
393 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
394 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, _T(""))
397 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
402std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
404 {wxPENSTYLE_DOT, {1, 1}},
405 {wxPENSTYLE_LONG_DASH, {5, 5}},
406 {wxPENSTYLE_SHORT_DASH, {1, 5}},
407 {wxPENSTYLE_DOT_DASH, {5, 1}},
410void glChartCanvas::Init() {
415 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
417 m_cache_current_ch = NULL;
419 m_b_paint_enable =
true;
420 m_in_glpaint =
false;
422 m_cache_tex[0] = m_cache_tex[1] = 0;
425 m_b_BuiltFBO =
false;
426 m_b_DisableFBO =
false;
435 m_bpinchGuard =
false;
436 m_binGesture =
false;
439 m_last_render_time = -1;
446 m_gldc.SetGLCanvas(
this);
449 m_displayScale = 1.0;
450#if defined(__WXOSX__) || defined(__WXGTK3__)
452 m_displayScale = GetContentScaleFactor();
461 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
465 wxEVT_QT_PINCHGESTURE,
466 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
469 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
474 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
476 onGestureFinishTimerEvent,
480 ZOOM_TIMER, wxEVT_TIMER,
481 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
484 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
485 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
486 zoomTimer.SetOwner(
this, ZOOM_TIMER);
488#ifdef USE_ANDROID_GLES2
497#ifdef HAVE_WX_GESTURE_EVENTS
499 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
504 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
506 onGestureFinishTimerEvent,
510 ZOOM_TIMER, wxEVT_TIMER,
511 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
514 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
515 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
516 zoomTimer.SetOwner(
this, ZOOM_TIMER);
521 m_bgestureGuard =
false;
522 m_total_zoom_val = 1.0;
525#ifdef HAVE_WX_GESTURE_EVENTS
526 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
527 wxLogError(
"Failed to enable touch events");
536 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
538 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
539 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
541 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
542 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
544 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
545 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
547 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
548 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
554glChartCanvas::~glChartCanvas() {
560void glChartCanvas::FlushFBO(
void) {
561 if (m_bsetup) BuildFBO();
564void glChartCanvas::OnActivate(wxActivateEvent &event) {
565 m_pParentCanvas->OnActivate(event);
568void glChartCanvas::OnSize(wxSizeEvent &event) {
572 wxLogMessage(_T(
"Got OnSize event while NOT running"));
574 qDebug() <<
"OnSizeB";
581 if (!IsShown())
return;
583 SetCurrent(*m_pcontext);
587 SetSize(GetSize().x, GetSize().y);
595 if (m_bsetup && m_pcontext && IsShown()) {
596 SetCurrent(*m_pcontext);
602 wxLogMessage(_T(
"BuildFBO 3"));
607 ViewPort *vp = m_pParentCanvas->GetpVP();
610 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
613 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
617void glChartCanvas::MouseEvent(wxMouseEvent &event) {
618 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
624 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
626 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
629 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
633 if (m_bgestureGuard) {
634 m_pParentCanvas->r_rband.x = 0;
644 if (event.LeftUp()) {
646 if ((abs(panx) > 2) || (abs(pany) > 2)) {
649 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
656 if (!event.LeftDClick()) {
661 if (m_binPan && event.RightDown()) {
662 qDebug() <<
"Skip right on pan";
665 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
667 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
668 if (!m_bgestureGuard)
678#ifndef GL_MAX_RENDERBUFFER_SIZE
679#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
682#ifndef USE_ANDROID_GLES2
683bool glChartCanvas::buildFBOSize(
int fboSize) {
685 if (IsShown()) SetCurrent(*m_pcontext);
688 glDeleteTextures(2, m_cache_tex);
689 glDeleteFramebuffers(1, &m_fb0);
690 glDeleteRenderbuffers(1, &m_renderbuffer);
691 m_b_BuiltFBO =
false;
694 if (m_b_DisableFBO)
return false;
698 int rb_x = GetSize().x;
699 int rb_y = GetSize().y;
701 while (i < rb_x) i <<= 1;
705 while (i < rb_y) i <<= 1;
708 m_cache_tex_x = wxMax(rb_x, rb_y);
709 m_cache_tex_y = wxMax(rb_x, rb_y);
712 m_cache_tex_x = GetSize().x * m_displayScale;
713 m_cache_tex_y = GetSize().y * m_displayScale;
716 int err = GL_NO_ERROR;
718 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
721 if (err == GL_INVALID_ENUM) {
722 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
726 if (err == GL_NO_ERROR) {
727 if (fboSize > params) {
729 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
730 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
735 glGenFramebuffers(1, &m_fb0);
739 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
745 glGenRenderbuffers(1, &m_renderbuffer);
749 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
755 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
759 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
766 glGenTextures(2, m_cache_tex);
767 for (
int i = 0; i < 2; i++) {
768 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
769 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
771 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
773 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
774 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
777 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
779 if (m_b_useFBOStencil) {
781 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
782 m_cache_tex_x, m_cache_tex_y);
784 int err = glGetError();
787 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
791 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
792 GL_RENDERBUFFER_EXT, m_renderbuffer);
797 _T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"), err);
801 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
802 GL_RENDERBUFFER_EXT, m_renderbuffer);
807 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"),
813 GLenum depth_format = GL_DEPTH_COMPONENT24;
818 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
822 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
824 int err = glGetError();
828 _T(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X"),
834 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
835 GL_RENDERBUFFER_EXT, m_renderbuffer);
841 _T(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X"), err);
847 glBindTexture(GL_TEXTURE_2D, 0);
848 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
851 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
853 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
854 g_texture_rectangle_format, m_cache_tex[0], 0);
856 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
858 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
860 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
862 msg.Printf(_T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X"),
872#ifdef USE_ANDROID_GLES2
873bool glChartCanvas::buildFBOSize(
int fboSize) {
877 int rb_x = GetSize().x;
878 int rb_y = GetSize().y;
880 while (i < rb_x) i <<= 1;
884 while (i < rb_y) i <<= 1;
887 m_cache_tex_x = wxMax(rb_x, rb_y);
888 m_cache_tex_y = wxMax(rb_x, rb_y);
892 int err = GL_NO_ERROR;
894 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
897 if (err == GL_INVALID_ENUM) {
898 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
902 if (err == GL_NO_ERROR) {
903 if (fboSize > params) {
905 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
906 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
911 glGenFramebuffers(1, &m_fb0);
915 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
921 glGenRenderbuffers(1, &m_renderbuffer);
925 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
931 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
935 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
942 glGenTextures(2, m_cache_tex);
943 for (
int i = 0; i < 2; i++) {
944 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
945 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
947 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
949 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
950 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
953 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
956 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
962 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
966 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
967 GL_RENDERBUFFER, m_renderbuffer);
971 msg.Printf(_T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"),
976 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
977 GL_RENDERBUFFER, m_renderbuffer);
982 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"), err);
986 glBindTexture(GL_TEXTURE_2D, 0);
987 glBindFramebuffer(GL_FRAMEBUFFER, 0);
990 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
992 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
993 g_texture_rectangle_format, m_cache_tex[0], 0);
995 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
997 glBindFramebuffer(GL_FRAMEBUFFER, 0);
999 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
1002 _T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X"),
1012void glChartCanvas::BuildFBO() {
1015 glDeleteTextures(2, m_cache_tex);
1016 glDeleteFramebuffers(1, &m_fb0);
1017 glDeleteRenderbuffers(1, &m_renderbuffer);
1018 m_b_BuiltFBO =
false;
1021 if (m_b_DisableFBO)
return;
1024 int gl_width, gl_height;
1025 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
1026 int initialSize = NextPow2(gl_width * m_displayScale);
1031 wxString info = androidGetDeviceInfo();
1033 if (wxNOT_FOUND != info.Find(_T(
"GT-S6312"))) initialSize = 1024;
1036 if (!buildFBOSize(initialSize)) {
1037 glDeleteTextures(2, m_cache_tex);
1038 glDeleteFramebuffers(1, &m_fb0);
1039 glDeleteRenderbuffers(1, &m_renderbuffer);
1041 if (!buildFBOSize(1024)) {
1042 wxLogMessage(_T(
"BuildFBO C"));
1044 m_b_DisableFBO =
true;
1045 wxLogMessage(_T(
"OpenGL-> FBO Framebuffer unavailable"));
1046 m_b_BuiltFBO =
false;
1055 msg.Printf(_T(
"OpenGL-> Framebuffer OK, size = %d"), m_cache_tex_x);
1062 m_b_BuiltFBO =
true;
1067void glChartCanvas::SetupOpenGL() {
1068 SetCurrent(*m_pcontext);
1070 char *str = (
char *)glGetString(GL_RENDERER);
1073 wxLogMessage(_T(
"Failed to initialize OpenGL"));
1077 char render_string[80];
1078 strncpy(render_string, str, 79);
1079 m_renderer = wxString(render_string, wxConvUTF8);
1082 if (g_bSoftwareGL) msg.Printf(_T(
"OpenGL-> Software OpenGL"));
1083 msg.Printf(_T(
"OpenGL-> Renderer String: "));
1087 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1089 char version_string[80];
1090 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1091 msg.Printf(_T(
"OpenGL-> Version reported: "));
1092 m_version = wxString(version_string, wxConvUTF8);
1096 char GLSL_version_string[80];
1097 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1099 msg.Printf(_T(
"OpenGL-> GLSL Version reported: "));
1100 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1101 msg += m_GLSLversion;
1106 GLenum err = glewInit();
1107#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1108 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1113 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1116 wxLogMessage(
"GLEW init success!n");
1121 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1122 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1126#ifndef USE_ANDROID_GLES2
1127 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1129 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1131 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1132 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1139 if (m_renderer.Upper().Find(_T(
"MESA")) != wxNOT_FOUND) {
1141 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1143 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1146 s_b_useScissorTest =
true;
1148 if (GetRendererString().Find(_T(
"RADEON X600")) != wxNOT_FOUND)
1149 s_b_useScissorTest =
false;
1151 if (GetRendererString().Find(_T(
"GeForce")) !=
1153 s_b_useScissorTest =
false;
1155 bool bad_stencil_code =
false;
1158 if (GetRendererString().Find(_T(
"UniChrome")) != wxNOT_FOUND)
1159 bad_stencil_code =
true;
1162 if (GetRendererString().Find(_T(
"Mali")) != wxNOT_FOUND)
1163 bad_stencil_code =
true;
1166 glEnable(GL_STENCIL_TEST);
1167 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1169 glGetIntegerv(GL_STENCIL_BITS, &sb);
1172 glDisable(GL_STENCIL_TEST);
1174 s_b_useStencil =
false;
1175 if (stencil && (sb == 8)) s_b_useStencil =
true;
1177 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1178 g_texture_rectangle_format = GL_TEXTURE_2D;
1179 else if (QueryExtension(
"GL_OES_texture_npot"))
1180 g_texture_rectangle_format = GL_TEXTURE_2D;
1181 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1182 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1183 wxLogMessage(wxString::Format(_T(
"OpenGL-> Texture rectangle format: %x"),
1184 g_texture_rectangle_format));
1187 g_texture_rectangle_format = GL_TEXTURE_2D;
1191 g_b_EnableVBO =
true;
1194 g_b_EnableVBO =
false;
1198 wxLogMessage(_T(
"OpenGL-> Using Vertexbuffer Objects"));
1200 wxLogMessage(_T(
"OpenGL-> Vertexbuffer Objects unavailable"));
1204 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1206 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1209#ifndef USE_ANDROID_GLES2
1211 if (bad_stencil_code) s_b_useStencil =
false;
1225 if (m_displayScale > 1) m_b_DisableFBO =
true;
1234 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1236 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1237 g_texture_rectangle_format, m_cache_tex[0], 0);
1239 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1240 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1242 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1244 msg.Printf(_T(
" OpenGL-> Framebuffer Incomplete: %08X"), fb_status);
1246 m_b_DisableFBO =
true;
1252 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1256 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1258#ifdef USE_ANDROID_GLES2
1259 s_b_useStencilAP = s_b_useStencil;
1266 wxLogMessage(_T(
"OpenGL-> Using Framebuffer Objects"));
1268 if (m_b_useFBOStencil)
1269 wxLogMessage(_T(
"OpenGL-> Using FBO Stencil buffer"));
1271 wxLogMessage(_T(
"OpenGL-> FBO Stencil buffer unavailable"));
1273 wxLogMessage(_T(
"OpenGL-> Framebuffer Objects unavailable"));
1276 wxLogMessage(_T(
"OpenGL-> Using Stencil buffer clipping"));
1278 wxLogMessage(_T(
"OpenGL-> Using Depth buffer clipping"));
1280 if (s_b_useScissorTest && s_b_useStencil)
1281 wxLogMessage(_T(
"OpenGL-> Using Scissor Clipping"));
1284 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1286 MipMap_ResolveRoutines();
1290 lwmsg.Printf(_T(
"OpenGL-> Minimum cartographic line width: %4.1f"),
1291 g_GLMinCartographicLineWidth);
1292 wxLogMessage(lwmsg);
1293 lwmsg.Printf(_T(
"OpenGL-> Minimum symbol line width: %4.1f"),
1294 g_GLMinSymbolLineWidth);
1295 wxLogMessage(lwmsg);
1298 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1300#ifdef USE_ANDROID_GLES2
1301 g_GLOptions.m_bUseAcceleratedPanning =
true;
1307 int tex_dim = g_GLOptions.m_iTextureDimension;
1308 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1309 g_mipmap_max_level = max_level - 1;
1314 g_mipmap_max_level = 4;
1317 s_b_useFBO = m_b_BuiltFBO;
1321 ps52plib->SetGLOptions(
1322 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1323 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1324 g_GLMinSymbolLineWidth);
1328 SendJSONConfigMessage();
1331void glChartCanvas::SendJSONConfigMessage() {
1334 v[_T(
"setupComplete")] = m_bsetup;
1335 v[_T(
"useStencil")] = s_b_useStencil;
1336 v[_T(
"useStencilAP")] = s_b_useStencilAP;
1337 v[_T(
"useScissorTest")] = s_b_useScissorTest;
1338 v[_T(
"useFBO")] = s_b_useFBO;
1339 v[_T(
"useVBO")] = g_b_EnableVBO;
1340 v[_T(
"TextureRectangleFormat")] = g_texture_rectangle_format;
1341 wxString msg_id(_T(
"OCPN_OPENGL_CONFIG"));
1342 SendJSONMessageToAllPlugins(msg_id, v);
1345void glChartCanvas::SetupCompression() {
1346 int dim = g_GLOptions.m_iTextureDimension;
1349 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1350 wxLogMessage(_T(
"OpenGL-> SSE2 Instruction set not available"));
1351 goto no_compression;
1355 g_uncompressed_tile_size = dim * dim * 4;
1356 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1358 g_raster_format = GL_RGB;
1362 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1363 g_raster_format = GL_ETC1_RGB8_OES;
1365 wxLogMessage(_T(
"OpenGL-> Using oes etc1 compression"));
1369 if (GL_RGB == g_raster_format) {
1375 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1376 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1379 if (GetRendererString().Find(_T(
"Gallium")) != wxNOT_FOUND &&
1380 GetRendererString().Find(_T(
"NV")) != wxNOT_FOUND)
1381 g_raster_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
1383 g_raster_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1385 wxLogMessage(_T(
"OpenGL-> Using s3tc dxt1 compression"));
1386 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1387 g_raster_format = GL_COMPRESSED_RGB_FXT1_3DFX;
1389 wxLogMessage(_T(
"OpenGL-> Using 3dfx fxt1 compression"));
1391 wxLogMessage(_T(
"OpenGL-> No Useable compression format found"));
1392 goto no_compression;
1397 g_tile_size = 512 * 512 / 2;
1401 glGenTextures(1, &texture);
1402 glBindTexture(GL_TEXTURE_2D, texture);
1403 glTexImage2D(GL_TEXTURE_2D, 0, g_raster_format, dim, dim, 0, GL_RGB,
1404 GL_UNSIGNED_BYTE, NULL);
1405 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1407 glDeleteTextures(1, &texture);
1411 if (g_tile_size == 0)
goto no_compression;
1413 wxLogMessage(wxString::Format(
1414 _T(
"OpenGL-> Compressed tile size: %dkb (%d:1)"), g_tile_size / 1024,
1415 g_uncompressed_tile_size / g_tile_size));
1419 g_GLOptions.m_bTextureCompression =
false;
1421 g_tile_size = g_uncompressed_tile_size;
1422 wxLogMessage(wxString::Format(_T(
"OpenGL-> Not Using compression")));
1425void glChartCanvas::OnPaint(wxPaintEvent &event) {
1428 if (!m_pcontext)
return;
1436 SetCurrent(*m_pcontext);
1441 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1449 if (!m_b_paint_enable)
return;
1452 if (m_in_glpaint)
return;
1455 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1478bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1480#ifndef USE_ANDROID_GLES2
1481 return vp.m_projection_type == PROJECTION_MERCATOR ||
1482 vp.m_projection_type == PROJECTION_POLAR ||
1483 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1497#define NORM_FACTOR 4096.0
1498void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1499#ifndef USE_ANDROID_GLES2
1501 wxPoint2DDouble point;
1503 switch (vp.m_projection_type) {
1504 case PROJECTION_MERCATOR:
1505 case PROJECTION_EQUIRECTANGULAR:
1506 case PROJECTION_WEB_MERCATOR:
1509 glTranslated(point.m_x, point.m_y, 0);
1514 case PROJECTION_POLAR:
1518 glTranslated(point.m_x, point.m_y, 0);
1519 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1526 printf(
"ERROR: Unhandled projection\n");
1531 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1539 switch (vp.m_projection_type) {
1540 case PROJECTION_MERCATOR:
1541 case PROJECTION_EQUIRECTANGULAR:
1542 case PROJECTION_WEB_MERCATOR:
1546 case PROJECTION_POLAR:
1551 printf(
"ERROR: Unhandled projection\n");
1560bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1561 return vp.m_projection_type == PROJECTION_MERCATOR ||
1562 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1563 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1567 const LLRegion ®ion) {
1568 if (!CanClipViewport(vp))
return vp;
1571 LLBBox bbox = region.GetBox();
1573 if (!bbox.GetValid())
return vp;
1581 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1582 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1583 bbox.GetMaxLon() + 360);
1584 cvp.SetBBoxDirect(bbox);
1585 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1586 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1587 bbox.GetMaxLon() - 360);
1588 cvp.SetBBoxDirect(bbox);
1590 cvp.SetBBoxDirect(bbox);
1595void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1596 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1599 for (
Track *pTrackDraw : g_TrackList) {
1602 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1604 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1607 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1608 node = node->GetNext()) {
1609 Route *pRouteDraw = node->GetData();
1611 if (!pRouteDraw)
continue;
1614 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1619 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1624 if (vp.GetBBox().GetValid() && pWayPointMan) {
1625 for (wxRoutePointListNode *pnode =
1626 pWayPointMan->GetWaypointList()->GetFirst();
1627 pnode; pnode = pnode->GetNext()) {
1630 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1637void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1640 for (
Track *pTrackDraw : g_TrackList) {
1642 if (pActiveTrack && pActiveTrack->IsRunning())
1643 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1647 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1648 node = node->GetNext()) {
1649 Route *pRouteDraw = node->GetData();
1652 if (!pRouteDraw)
continue;
1655 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1661 if (pRouteDraw->IsSelected()) drawit++;
1664 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1665 if (!vp_box.IntersectOut(test_box))
1666 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1672 if (vp.GetBBox().GetValid() && pWayPointMan) {
1673 for (wxRoutePointListNode *pnode =
1674 pWayPointMan->GetWaypointList()->GetFirst();
1675 pnode; pnode = pnode->GetNext()) {
1684static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1688 switch (vp.m_projection_type) {
1689 case PROJECTION_TRANSVERSE_MERCATOR:
1690 lat_dist = 4, lon_dist = 1;
1692 case PROJECTION_POLYCONIC:
1693 lat_dist = 2, lon_dist = 1;
1695 case PROJECTION_ORTHOGRAPHIC:
1696 lat_dist = 2, lon_dist = 2;
1698 case PROJECTION_POLAR:
1699 lat_dist = 180, lon_dist = 1;
1701 case PROJECTION_STEREOGRAPHIC:
1702 case PROJECTION_GNOMONIC:
1703 lat_dist = 2, lon_dist = 1;
1705 case PROJECTION_EQUIRECTANGULAR:
1708 lat_dist = 2, lon_dist = 360;
1711 lat_dist = 180, lon_dist = 360;
1715void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1716 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1717 !ChartData->IsChartAvailable(dbIndex))
1722 ChartData->GetDBBoundingBox(dbIndex, box);
1723 if (!box.GetValid())
return;
1727 if (box.GetLonRange() == 360)
return;
1729 LLBBox vpbox = vp.GetBBox();
1731 double lon_bias = 0;
1733 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1736 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1737 color = GetGlobalColor(_T (
"YELO1" ));
1738 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1739 color = GetGlobalColor(_T (
"GREEN2" ));
1741 color = GetGlobalColor(_T (
"UINFR" ));
1743#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1744 float plylat, plylon;
1746 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1748 glColor3ub(color.Red(), color.Green(), color.Blue());
1749 glLineWidth(g_GLMinSymbolLineWidth);
1751 float lat_dist, lon_dist;
1752 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1755 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1759 nPly = ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1761 nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1763 bool begin =
false, sml_valid =
false;
1765 float lastplylat = 0.0;
1766 float lastplylon = 0.0;
1768 int modulo = (nPly == 0) ? 1 : nPly;
1769 for (
int i = 0; i < nPly + 1; i++) {
1771 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1773 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1777 if (lastplylon - plylon > 180)
1779 else if (lastplylon - plylon < -180)
1786 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1787 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1788 splits = wxMax(lat_splits, lon_splits) + 1;
1795 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1796 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1799 for (
double c = 0; c < splits; c++) {
1801 if (c == splits - 1)
1802 lat = plylat, lon = plylon;
1804 double d = (double)(c + 1) / splits;
1805 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1811 if (!std::isnan(s.m_x)) {
1814 glBegin(GL_LINE_STRIP);
1816 glVertex2f(s.m_x, s.m_y);
1822 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1823 lastplylat = plylat, lastplylon = plylon;
1828 }
while (++j < nAuxPlyEntries);
1830 glDisable(GL_LINE_SMOOTH);
1834 double nominal_line_width_pix =
1835 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1837 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1838 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), nominal_line_width_pix,
1841 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1842 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), nominal_line_width_pix,
1846 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), nominal_line_width_pix,
1849 float plylat1, plylon1;
1853 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
1854 if (0 == nAuxPlyEntries)
1857 std::vector<int> points_vector;
1859 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1860 int nPly = vec.size() / 2;
1862 if (nPly == 0)
return;
1864 for (
int i = 0; i < nPly; i++) {
1865 plylon1 = vec[i * 2];
1866 plylat1 = vec[i * 2 + 1];
1872 points_vector.push_back(pixx1);
1873 points_vector.push_back(pixy1);
1876 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1877 plylon1 += lon_bias;
1883 points_vector.push_back(pixx1);
1884 points_vector.push_back(pixy1);
1886 if (points_vector.size()) {
1887 std::vector<int>::iterator it = points_vector.begin();
1888 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1896 for (
int j = 0; j < nAuxPlyEntries; j++) {
1897 std::vector<int> points_vector;
1899 std::vector<float> vec = ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1900 int nAuxPly = vec.size() / 2;
1902 if (nAuxPly == 0)
continue;
1904 for (
int i = 0; i < nAuxPly; i++) {
1905 plylon1 = vec[i * 2];
1906 plylat1 = vec[i * 2 + 1];
1912 points_vector.push_back(pixx1);
1913 points_vector.push_back(pixy1);
1920 points_vector.push_back(pixx1);
1921 points_vector.push_back(pixy1);
1923 if (points_vector.size()) {
1924 std::vector<int>::iterator it = points_vector.begin();
1925 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1933extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1934 float &MinorSpacing);
1935extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1936void glChartCanvas::GridDraw() {
1937 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1939 ViewPort &vp = m_pParentCanvas->GetVP();
1941 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1945 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1947 double nlat, elon, slat, wlon;
1949 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1952 wxColour GridColor = GetGlobalColor(_T (
"SNDG1" ));
1954 if (!m_gridfont.IsBuilt()) {
1956 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1957 wxFont font = *dFont;
1958 int font_size = wxMax(10, dFont->GetPointSize());
1959 font.SetPointSize(font_size * m_displayScale);
1960 font.SetWeight(wxFONTWEIGHT_NORMAL);
1963 m_gridfont.Build(font, 1, dpi_factor);
1965 m_gridfont.SetColor(GridColor);
1970 LLBBox llbbox = vp.GetBBox();
1971 nlat = llbbox.GetMaxLat();
1972 slat = llbbox.GetMinLat();
1973 elon = llbbox.GetMaxLon();
1974 wlon = llbbox.GetMinLon();
1981 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1982 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1983 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1984 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1985 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1986 vp.m_projection_type == PROJECTION_POLAR ||
1987 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1990 if (straight_latitudes)
1993 latmargin = gridlatMajor / 2;
1995 slat = wxMax(slat, -90 + latmargin);
1996 nlat = wxMin(nlat, 90 - latmargin);
1998 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1999 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
2003 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
2010 float lon_step = elon - wlon;
2011 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
2013 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2015 s.x = INVALID_COORD;
2016 s.y = INVALID_COORD;
2017 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
2019 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2020 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2028 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
2029 lat += gridlatMinor) {
2032 gldc.DrawLine(0, r.y, 10, r.y,
true);
2033 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
2038 float lat_step = nlat - slat;
2039 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
2041 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2043 s.x = INVALID_COORD;
2044 s.y = INVALID_COORD;
2045 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
2047 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2048 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2056 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
2057 lon += gridlonMinor) {
2060 gldc.DrawLine(r.x, 0, r.x, 10,
false);
2061 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
2067 glEnable(GL_TEXTURE_2D);
2069 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2070 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
2073 CalcGridText(lat, gridlatMajor,
true);
2075 m_gridfont.GetTextExtent(st, 0, &iy);
2077 if (straight_latitudes) {
2082 float x = 0, y = -1;
2083 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
2084 if (y < 0 || y > h) {
2086 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
2089 m_gridfont.RenderString(st, x, y);
2093 double y1, y2, lat1, lon1, lat2, lon2;
2102 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2105 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2107 if (fabs(y - y1) < fabs(y - y2))
2113 error = fabs(r.m_x);
2114 if (--maxiters == 0)
break;
2115 }
while (error > 1 && error < lasterror);
2117 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2123 m_gridfont.RenderString(st, r.m_x, r.m_y);
2127 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2128 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2137 else if (xlon <= -180.0)
2140 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2142 m_gridfont.GetTextExtent(st, &ix, 0);
2144 if (straight_longitudes) {
2145 float x = -1, y = 0;
2146 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2147 if (x < 0 || x > w) {
2149 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2152 m_gridfont.RenderString(st, x, y);
2156 double x1, x2, lat1, lon1, lat2, lon2;
2164 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2167 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2169 if (fabs(x - x1) < fabs(x - x2))
2175 error = fabs(r.m_y);
2176 }
while (error > 1 && error < lasterror);
2178 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2183 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2185 m_gridfont.RenderString(st, r.m_x, r.m_y);
2189 glDisable(GL_TEXTURE_2D);
2190 glDisable(GL_BLEND);
2195 if (!emboss)
return;
2197 int w = emboss->width, h = emboss->height;
2199 glEnable(GL_TEXTURE_2D);
2202 if (!emboss->gltexind) {
2204 emboss->glwidth = NextPow2(emboss->width);
2205 emboss->glheight = NextPow2(emboss->height);
2208 int size = emboss->glwidth * emboss->glheight;
2209 char *data =
new char[2 * size];
2210 for (
int i = 0; i < h; i++) {
2211 for (
int j = 0; j < emboss->glwidth; j++) {
2213 data[2 * ((i * emboss->glwidth) + j)] =
2214 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2215 data[2 * ((i * emboss->glwidth) + j) + 1] =
2216 (char)abs((emboss->pmap[(i * w) + j]));
2221 glGenTextures(1, &emboss->gltexind);
2222 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2223 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2224 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2232 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2236 int x = emboss->x, y = emboss->y;
2238 float wp = (float)w / emboss->glwidth;
2239 float hp = (float)h / emboss->glheight;
2265 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2267 glDisable(GL_BLEND);
2268 glDisable(GL_TEXTURE_2D);
2271void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2272 if (!m_pParentCanvas->GetVP().IsValid())
return;
2273 wxPoint GPSOffsetPixels(0, 0);
2274 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2277 float pCog = std::isnan(gCog) ? 0 : gCog;
2278 float pSog = std::isnan(gSog) ? 0 : gSog;
2282 double shift_dx = 0;
2283 double shift_dy = 0;
2284 if ((!m_pParentCanvas->m_animationActive) && m_pParentCanvas->m_bFollow &&
2285 !m_pParentCanvas->m_MouseDragging) {
2286 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2287 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2288 if (m_pParentCanvas->m_bLookAhead) {
2294 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2295 angle += m_pParentCanvas->GetVPRotation();
2296 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2298 lGPSPoint.m_x -= shift_dx / cos(gLat * PI / 180.);
2299 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2301 lGPSPoint.m_y += shift_dy / cos(gLat * PI / 180.);
2306 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2307 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2314 lShipMidPoint = lGPSPoint;
2318 float icon_hdt = pCog;
2319 if (!std::isnan(gHdt)) icon_hdt = gHdt;
2322 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2326 double osd_head_lat, osd_head_lon;
2327 wxPoint2DDouble osd_head_point;
2329 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2333 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2335 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2336 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2337 icon_rad += (float)PI;
2341 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2345 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2351 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2352 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2353 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2358 float scale_factor = 1.0;
2360 if ((g_ChartScaleFactorExp > 1.0) && (g_OwnShipIconType == 0))
2361 scale_factor = (log(g_ChartScaleFactorExp) + 1.0) * 1.1;
2363 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2364 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2365 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2367 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2369 float nominal_ownship_size_pixels =
2371 nominal_ownship_size_mm);
2373 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2375 wxPen ppSmallScaleShip;
2376 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2378 wxPen(GetGlobalColor(_T (
"URED" )), v / 5, wxPENSTYLE_SOLID);
2381 wxPen(GetGlobalColor(_T (
"YELO1" )), v / 5, wxPENSTYLE_SOLID);
2382 dc.SetPen(ppSmallScaleShip);
2385 wxBrush(GetGlobalColor(_T (
"URED" )), wxBRUSHSTYLE_TRANSPARENT));
2388 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2389 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2390 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2391 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2394 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2395 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2398 int draw_color = SHIP_INVALID;
2399 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2400 draw_color = SHIP_NORMAL;
2401 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2402 draw_color = SHIP_LOWACCURACY;
2410 ownship_color = draw_color;
2412 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2414 glGenTextures(1, &ownship_tex);
2415 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2418 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2421 if (m_pParentCanvas->m_pos_image_user) {
2422 switch (draw_color) {
2424 image = *m_pParentCanvas->m_pos_image_user_grey;
2427 image = *m_pParentCanvas->m_pos_image_user;
2429 case SHIP_LOWACCURACY:
2430 image = *m_pParentCanvas->m_pos_image_user_yellow;
2434 switch (draw_color) {
2436 image = *m_pParentCanvas->m_pos_image_grey;
2439 image = *m_pParentCanvas->m_pos_image_red;
2441 case SHIP_LOWACCURACY:
2442 image = *m_pParentCanvas->m_pos_image_yellow;
2447 int w = image.GetWidth(), h = image.GetHeight();
2448 int glw = NextPow2(w), glh = NextPow2(h);
2449 ownship_size = wxSize(w, h);
2450 ownship_tex_size = wxSize(glw, glh);
2452 unsigned char *d = image.GetData();
2453 unsigned char *a = image.GetAlpha();
2454 unsigned char *e =
new unsigned char[4 * w * h];
2457 for (
int p = 0; p < w * h; p++) {
2458 e[4 * p + 0] = d[3 * p + 0];
2459 e[4 * p + 1] = d[3 * p + 1];
2460 e[4 * p + 2] = d[3 * p + 2];
2461 e[4 * p + 3] = a[p];
2464 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2465 GL_UNSIGNED_BYTE, 0);
2467 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2473#ifndef USE_ANDROID_GLES2
2474 if (m_pParentCanvas->m_pos_image_user)
2475 glColor4ub(255, 255, 255, 255);
2476 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2477 glColor4ub(255, 0, 0, 255);
2478 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2479 glColor4ub(255, 255, 0, 255);
2481 glColor4ub(128, 128, 128, 255);
2483 float scale_factor_y = 1.0;
2484 float scale_factor_x = 1.0;
2486 int ownShipWidth = 22;
2487 int ownShipLength = 84;
2488 lShipMidPoint = lGPSPoint;
2491 if (g_OwnShipIconType != 0)
2492 m_pParentCanvas->ComputeShipScaleFactor(
2493 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2494 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2499 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2500 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2501 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2505 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2506 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2510 float gps_circle_radius = 3.0;
2512 if (g_OwnShipIconType == 0) {
2514 glEnable(GL_TEXTURE_2D);
2515 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2524 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2525 if (m_pParentCanvas->m_pos_image_user)
2526 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2528 float nominal_ownship_size_mm =
2529 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2531 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2532 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2534 float nominal_ownship_size_pixels =
2535 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2537 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2538 nominal_ownship_size_pixels = wxMax(
2539 20.0, nominal_ownship_size_pixels);
2542 float h = nominal_ownship_size_pixels * scale_factor_y;
2543 float w = nominal_ownship_size_pixels * scale_factor_x *
2544 ownship_size.x / ownship_size.y;
2545 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2546 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2552 gps_circle_radius = w / 5;
2554 float uv[8], coords[8];
2573 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2574 lShipMidPoint.m_x, lShipMidPoint.m_y,
2576 glDisable(GL_TEXTURE_2D);
2577 }
else if (g_OwnShipIconType == 1) {
2579 glEnable(GL_TEXTURE_2D);
2580 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2582 float nominal_ownship_size_pixels_y = 84;
2583 float nominal_ownship_size_pixels_x = 22;
2585 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2586 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2588 float u = (float)ownship_size.x / ownship_tex_size.x,
2589 v = (
float)ownship_size.y / ownship_tex_size.y;
2592 gps_circle_radius = w / 5;
2594 float uv[8], coords[8];
2613 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2614 lShipMidPoint.m_x, lShipMidPoint.m_y,
2617 glDisable(GL_TEXTURE_2D);
2618 }
else if (g_OwnShipIconType == 2) {
2626 wxPoint shipPoints[6];
2628 wxColour colour = m_pParentCanvas->ShipColor();
2629 wxPen ppPen(*wxBLACK, 1);
2630 wxBrush ppBrush(colour);
2632 dc.SetBrush(ppBrush);
2634 shipPoints[0].x = 0 * scale_factor_x;
2635 shipPoints[0].y = -28 * scale_factor_y;
2636 shipPoints[1].x = 11 * scale_factor_x;
2637 shipPoints[1].y = -28 * scale_factor_y;
2638 shipPoints[2].x = 11 * scale_factor_x;
2639 shipPoints[2].y = 42 * scale_factor_y;
2640 shipPoints[3].x = 0 * scale_factor_x;
2641 shipPoints[3].y = 42 * scale_factor_y;
2642 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2645 shipPoints[0].x = 0 * scale_factor_x;
2646 shipPoints[0].y = -42 * scale_factor_y;
2647 shipPoints[1].x = 5 * scale_factor_x;
2648 shipPoints[1].y = -42 * scale_factor_y;
2649 shipPoints[2].x = 11 * scale_factor_x;
2650 shipPoints[2].y = -28 * scale_factor_y;
2651 shipPoints[3].x = 0 * scale_factor_x;
2652 shipPoints[3].y = -28 * scale_factor_y;
2653 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2656 shipPoints[0].x = 0 * scale_factor_x;
2657 shipPoints[0].y = -28 * scale_factor_y;
2658 shipPoints[1].x = -11 * scale_factor_x;
2659 shipPoints[1].y = -28 * scale_factor_y;
2660 shipPoints[2].x = -11 * scale_factor_x;
2661 shipPoints[2].y = 42 * scale_factor_y;
2662 shipPoints[3].x = 0 * scale_factor_x;
2663 shipPoints[3].y = 42 * scale_factor_y;
2664 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2667 shipPoints[0].x = 0 * scale_factor_x;
2668 shipPoints[0].y = -42 * scale_factor_y;
2669 shipPoints[1].x = -5 * scale_factor_x;
2670 shipPoints[1].y = -42 * scale_factor_y;
2671 shipPoints[2].x = -11 * scale_factor_x;
2672 shipPoints[2].y = -28 * scale_factor_y;
2673 shipPoints[3].x = 0 * scale_factor_x;
2674 shipPoints[3].y = -28 * scale_factor_y;
2675 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2679 double p1x = -11 * scale_factor_x;
2680 double p2x = 11 * scale_factor_x;
2684 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2686 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2688 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2690 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2691 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2692 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2696 p1y = -42 * scale_factor_y;
2697 p2y = 42 * scale_factor_y;
2698 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2699 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2700 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2701 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2702 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2703 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2706 img_height = ownShipLength * scale_factor_y;
2709 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2711 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
2713 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"CHWHT" ))));
2715 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2719 glDisable(GL_LINE_SMOOTH);
2720 glDisable(GL_POLYGON_SMOOTH);
2721 glDisable(GL_BLEND);
2724 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2728void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2729 ViewPort &vp = m_pParentCanvas->GetVP();
2734 Route *active_route = g_pRouteMan->GetpActiveRoute();
2743 g_overlayCanvas = m_pParentCanvas;
2745 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
2746 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2747 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_LEGACY);
2752 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2754 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2755 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2757 m_pParentCanvas->AlertDraw(dc);
2759 m_pParentCanvas->RenderVisibleSectorLights(dc);
2761 m_pParentCanvas->RenderRouteLegs(dc);
2762 m_pParentCanvas->RenderShipToActive(dc,
true);
2763 m_pParentCanvas->ScaleBarDraw(dc);
2764 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2765 m_pParentCanvas->extendedSectorLegs);
2767 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2768 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_SHIPS);
2772void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2773 if (m_pParentCanvas->GetPiano()) {
2774 int canvas_height = GetClientSize().y;
2775 canvas_height *= m_displayScale;
2777 m_pParentCanvas->GetPiano()->DrawGL(
2778 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2782void glChartCanvas::DrawQuiting() {
2783#ifndef USE_ANDROID_GLES2
2784 GLubyte pattern[8][8];
2785 for (
int y = 0; y < 8; y++)
2786 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2789 glEnable(GL_TEXTURE_2D);
2790 glBindTexture(GL_TEXTURE_2D, 0);
2792 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2793 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2794 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2796 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2800 float x = GetSize().x, y = GetSize().y;
2801 float u = x / 8, v = y / 8;
2814 glDisable(GL_TEXTURE_2D);
2815 glDisable(GL_BLEND);
2819void glChartCanvas::DrawCloseMessage(wxString msg) {
2820#ifndef USE_ANDROID_GLES2
2824 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2828 texfont.Build(*pfont, 1, 1);
2830 texfont.GetTextExtent(msg, &w, &h);
2832 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2833 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2835 glColor3ub(243, 229, 47);
2839 glVertex2i(xp + w, yp);
2840 glVertex2i(xp + w, yp + h);
2841 glVertex2i(xp, yp + h);
2846 glColor3ub(0, 0, 0);
2847 glEnable(GL_TEXTURE_2D);
2848 texfont.RenderString(msg, xp, yp);
2849 glDisable(GL_TEXTURE_2D);
2850 glDisable(GL_BLEND);
2857static std::list<double *> combine_work_data;
2858static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2859 GLfloat weight[4], GLdouble **dataOut) {
2860 double *vertex =
new double[3];
2861 combine_work_data.push_back(vertex);
2862 memcpy(vertex, coords, 3 * (
sizeof *coords));
2866#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2867void vertexCallbackD_GLSL(GLvoid *vertex) {
2869 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2870 int new_buf_len = s_tess_buf_len + 100;
2871 GLfloat *tmp = s_tess_work_buf;
2874 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2875 if (NULL == s_tess_work_buf) {
2879 s_tess_buf_len = new_buf_len;
2882 GLdouble *pointer = (GLdouble *)vertex;
2884 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2885 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2890void beginCallbackD_GLSL(GLenum mode) {
2891 s_tess_vertex_idx_this = s_tess_vertex_idx;
2896void endCallbackD_GLSL() {
2900 shader->SetUniformMatrix4fv(
"MVMatrix",
2901 (GLfloat *)s_tessVP.vp_matrix_transform);
2903 mat4x4 identityMatrix;
2904 mat4x4_identity(identityMatrix);
2905 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2909 colorv[0] = s_regionColor.Red() / float(256);
2910 colorv[1] = s_regionColor.Green() / float(256);
2911 colorv[2] = s_regionColor.Blue() / float(256);
2912 colorv[3] = s_regionColor.Alpha() / float(256);
2913 shader->SetUniform4fv(
"color", colorv);
2915 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2916 shader->SetAttributePointerf(
"position", bufPt);
2918 glDrawArrays(s_tess_mode, 0, s_nvertex);
2923void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2925void beginCallbackD(GLenum mode) { glBegin(mode); }
2927void endCallbackD() { glEnd(); }
2931void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2932 float lat_dist, lon_dist;
2933 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2935 GLUtesselator *tobj = gluNewTess();
2936 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2938#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2939 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2940 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2941 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2942 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2946 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2947 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2948 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2949 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2952 gluTessNormal(tobj, 0, 0, 1);
2954 gluTessBeginPolygon(tobj, NULL);
2955 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2956 i != region.contours.end(); i++) {
2957 gluTessBeginContour(tobj);
2958 contour_pt l = *i->rbegin();
2960 bool sml_valid =
false;
2961 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2962 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2963 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2964 int splits = wxMax(lat_splits, lon_splits) + 1;
2970 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2971 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2974 for (
int i = 0; i < splits; i++) {
2976 if (i == splits - 1)
2977 lat = j->y, lon = j->x;
2979 double d = (double)(i + 1) / splits;
2980 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2984 if (std::isnan(q.m_x))
continue;
2986 double *p =
new double[6];
2991 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2996 gluTessVertex(tobj, p, p);
2997 combine_work_data.push_back(p);
3001 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
3003 gluTessEndContour(tobj);
3005 gluTessEndPolygon(tobj);
3007 gluDeleteTess(tobj);
3009 for (std::list<double *>::iterator i = combine_work_data.begin();
3010 i != combine_work_data.end(); i++)
3012 combine_work_data.clear();
3017void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
3018 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3020 if (s_b_useStencil) {
3022 glEnable(GL_STENCIL_TEST);
3024 glClear(GL_STENCIL_BUFFER_BIT);
3028 glStencilFunc(GL_ALWAYS, 1, 1);
3029 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
3032#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3036 glEnable(GL_DEPTH_TEST);
3037 glDepthFunc(GL_ALWAYS);
3038 glDepthMask(GL_TRUE);
3040 glClear(GL_DEPTH_BUFFER_BIT);
3053 glTranslatef(0, 0, .5);
3057 s_regionColor = wxColor(0, 0, 0, 255);
3058 DrawRegion(vp, region);
3060 if (s_b_useStencil) {
3063 glStencilFunc(GL_EQUAL, 1, 1);
3064 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3067#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3069 glDepthFunc(GL_GREATER);
3070 glDepthMask(GL_FALSE);
3071 glTranslatef(0, 0, -.5);
3074 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3077void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
3081 if (s_b_useStencil && s_b_useScissorTest) {
3083 if (rect != vp_rect) {
3084 glEnable(GL_SCISSOR_TEST);
3085 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3088#ifndef USE_ANDROID_GLES2
3094void glChartCanvas::DisableClipRegion() {
3095 glDisable(GL_SCISSOR_TEST);
3096 glDisable(GL_STENCIL_TEST);
3097 glDisable(GL_DEPTH_TEST);
3100void glChartCanvas::Invalidate() {
3102 m_cache_vp.Invalidate();
3108 if (!pBSBChart)
return;
3110 if (b_inCompressAllCharts)
3114 wxString key = chart->GetHashKey();
3117 ChartPathHashTexfactType &hash = g_glTextureManager->m_chart_texfactory_hash;
3118 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3121 if (ittf == hash.end()) {
3123 hash[key]->SetHashKey(key);
3126 pTexFact = hash[key];
3127 pTexFact->SetLRUTime(++m_LRUtime);
3132 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3133 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3140 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3141 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3142 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3143 base_level = log(scalefactor) / log(2.0);
3147 if (base_level > g_mipmap_max_level) base_level = g_mipmap_max_level;
3152 glEnable(GL_TEXTURE_2D);
3153#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3154 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3156 glEnableClientState(GL_VERTEX_ARRAY);
3157 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3162 pTexFact->GetCenter(lat, lon);
3163 MultMatrixViewPort(vp, lat, lon);
3167 LLBBox box = region.GetBox();
3170 if (g_memCacheLimit > 0) {
3172 GetMemoryStatus(0, &mem_used);
3175 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3176 for (
int i = 0; i < numtiles; i++) {
3178 if (region.IntersectOut(tile->box)) {
3181 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3182 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3184 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3185 global_color_scheme, mem_used);
3189 coords = tile->m_coords;
3191 coords =
new float[2 * tile->m_ncoords];
3192 for (
int i = 0; i < tile->m_ncoords; i++) {
3194 tile->m_coords[2 * i + 1]);
3195 coords[2 * i + 0] = p.m_x;
3196 coords[2 * i + 1] = p.m_y;
3200#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3201 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3202 m_pParentCanvas->GetpVP());
3205 glDisable(GL_TEXTURE_2D);
3209 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3210 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3211 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3213 if (!texture) glEnable(GL_TEXTURE_2D);
3215 if (!use_norm_vp)
delete[] coords;
3219 glDisable(GL_TEXTURE_2D);
3221#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3222 if (use_norm_vp) glPopMatrix();
3224 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3225 glDisableClientState(GL_VERTEX_ARRAY);
3229void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3231 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3232 m_pParentCanvas->m_pQuilt->IsBusy())
3236 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3245 LLRegion region = vp.GetLLRegion(rect_region);
3247 LLRegion rendered_region;
3253 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3261 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3263 LLRegion get_region = pqp->ActiveRegion;
3264 bool b_rendered =
false;
3266 if (!pqp->b_overlay) {
3267 get_region.Intersect(region);
3268 if (!get_region.Empty()) {
3269 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3272 SetClipRegion(vp, get_region );
3273 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3274 DisableClipRegion();
3277 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3278 SetClipRegion(vp, pqp->ActiveRegion );
3279 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3281 DisableClipRegion();
3284 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3285 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3286 RenderNoDTA(vp, get_region);
3287 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3292 if (Chs57->m_RAZBuilt) {
3293 RenderNoDTA(vp, get_region);
3294 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3295 rect_region, get_region);
3296 DisableClipRegion();
3301 const LLRegion &oregion = get_region;
3302 LLBBox box = oregion.GetBox();
3313 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3316 ViewPort cvp = ClippedViewport(vp, get_region);
3317 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3318 SetClipRegion(cvp, get_region);
3319 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3320 GetGlobalColor(_T (
"LANDA" )),
3321 GetGlobalColor(_T (
"DEPMS" )));
3322 RenderWorldChart(gldc, cvp, srect, world);
3323 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3324 global_color_scheme);
3325 DisableClipRegion();
3332 SetClipRegion(vp, get_region);
3333 RenderNoDTA(vp, get_region);
3334 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3336 DisableClipRegion();
3339 SetClipRegion(vp, get_region);
3340 RenderNoDTA(vp, get_region);
3341 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3343 DisableClipRegion();
3359 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3363 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3364 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3366 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3367 if (pqp->b_Valid && pqp->b_overlay &&
3368 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3369 LLRegion get_region = pqp->ActiveRegion;
3371 get_region.Intersect(region);
3372 if (!get_region.Empty()) {
3375 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3380 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3387 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3392 ViewPort vph = m_pParentCanvas->GetVP();
3393 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3396 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3398 if (!hiregion.Empty()) {
3402 switch (global_color_scheme) {
3403 case GLOBAL_COLOR_SCHEME_DAY:
3406 case GLOBAL_COLOR_SCHEME_DUSK:
3409 case GLOBAL_COLOR_SCHEME_NIGHT:
3417#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3419 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3421 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3424 DrawRegion(vp, hiregion);
3426 glDisable(GL_BLEND);
3431 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3433 if (!hiregion.Empty()) {
3437 switch (global_color_scheme) {
3438 case GLOBAL_COLOR_SCHEME_DAY:
3441 case GLOBAL_COLOR_SCHEME_DUSK:
3444 case GLOBAL_COLOR_SCHEME_NIGHT:
3453#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3455 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3457 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3460 DrawRegion(vp, hiregion);
3462 glDisable(GL_BLEND);
3466 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3469void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3471 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3472 m_pParentCanvas->m_pQuilt->IsBusy())
3476 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3478 LLRegion region = vp.GetLLRegion(rect_region);
3480 LLRegion rendered_region;
3482 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3484 LLRegion get_region = pqp->ActiveRegion;
3486 if (!pqp->b_overlay) {
3487 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3490 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3495 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3502 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3530void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3531 ViewPort &vp = m_pParentCanvas->VPoint;
3539 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3540 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3543 LLRegion chart_region;
3545 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3546 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3547 CHART_FAMILY_RASTER) {
3555 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3556 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3557 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3559 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3563 for (
int i = 1; i < 6; i += 2)
3564 if (fabs(ll[i] - ll[i + 2]) > 180) {
3566 for (
int i = 1; i < 8; i += 2)
3567 if (ll[i] < 0) ll[i] += 360;
3571 chart_region = LLRegion(4, ll);
3574 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3576 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3577 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3578 chart_region = LLRegion(4, ll);
3581 chart_region = vp.b_quilt
3582 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3583 : m_pParentCanvas->m_singleChart->GetValidRegion();
3585 bool world_view =
false;
3587 wxRect rect = upd.GetRect();
3588 LLRegion background_region = vp.GetLLRegion(rect);
3591 background_region.Subtract(chart_region);
3593 if (!background_region.Empty()) {
3594 ViewPort cvp = ClippedViewport(vp, background_region);
3595 SetClipRect(cvp, rect,
false);
3596 RenderWorldChart(dc, cvp, rect, world_view);
3597 DisableClipRegion();
3602 RenderQuiltViewGL(vp, rect_region);
3604 LLRegion region = vp.GetLLRegion(rect_region);
3605 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3606 CHART_FAMILY_RASTER) {
3607 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3608 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3609 *m_pcontext, vp, rect_region, region);
3611 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3612 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3613 CHART_FAMILY_VECTOR) {
3614 chart_region.Intersect(region);
3615 RenderNoDTA(vp, chart_region);
3616 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3617 rect_region, region);
3623void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3625 wxColour color = GetGlobalColor(_T (
"NODTA" ));
3626#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3628 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3630 glColor4ub(163, 180, 183, transparency);
3633 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3637 s_regionColor = color;
3640 DrawRegion(vp, region);
3644void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3647 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3649 glEnable(GL_SCISSOR_TEST);
3650 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3656 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3657#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3659 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3663 colorv[0] = water.Red() / float(256);
3664 colorv[1] = water.Green() / float(256);
3665 colorv[2] = water.Blue() / float(256);
3667 shader->SetUniform4fv(
"color", colorv);
3678 shader->SetAttributePointerf(
"position", pf);
3680 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3690 gShapeBasemap.RenderViewOnDC(dc, vp);
3692 glDisable(GL_SCISSOR_TEST);
3700void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3701 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3703 DrawStaticRoutesTracksAndWaypoints(vp);
3705 DisableClipRegion();
3708void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3710 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3714 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3715 if (!bmp.Ok())
return;
3717 wxImage image = bmp.ConvertToImage();
3718 int w = image.GetWidth(), h = image.GetHeight();
3721 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3722 tex_w = w, tex_h = h;
3724 tex_w = NextPow2(w), tex_h = NextPow2(h);
3726 m_tideTexWidth = tex_w;
3727 m_tideTexHeight = tex_h;
3729 unsigned char *d = image.GetData();
3730 unsigned char *a = image.GetAlpha();
3732 unsigned char mr, mg, mb;
3733 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3735 unsigned char *e =
new unsigned char[4 * w * h];
3737 for (
int y = 0; y < h; y++)
3738 for (
int x = 0; x < w; x++) {
3739 unsigned char r, g, b;
3740 int off = (y * w + x);
3750 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3754 glGenTextures(1, &m_tideTex);
3756 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3757 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3758 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3760 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3761 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3762 GL_UNSIGNED_BYTE, e);
3764 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3765 GL_UNSIGNED_BYTE, 0);
3766 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3775 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3776 glEnable(GL_TEXTURE_2D);
3779#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3781 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
3782 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
3785 if ((type ==
't') || (type ==
'T'))
3790 if (BBox.Contains(lat, lon)) {
3799 scale *= getAndroidDisplayDensity();
3801 double width2 =
scale * m_tideTexWidth / 2;
3802 double height2 =
scale * m_tideTexHeight / 2;
3817 coords[0] = xp - width2;
3818 coords[1] = yp - height2;
3819 coords[2] = xp - width2;
3820 coords[3] = yp + height2;
3821 coords[4] = xp + width2;
3822 coords[5] = yp + height2;
3823 coords[6] = xp + width2;
3824 coords[7] = yp - height2;
3826 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3833 glDisable(GL_TEXTURE_2D);
3834 glDisable(GL_BLEND);
3835 glBindTexture(GL_TEXTURE_2D, 0);
3837 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3840void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3841 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3844void glChartCanvas::SetColorScheme(ColorScheme cs) {
3845 if (!m_bsetup)
return;
3847 glDeleteTextures(1, &m_tideTex);
3848 glDeleteTextures(1, &m_currentTex);
3854void glChartCanvas::RenderGLAlertMessage() {
3855 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3856 wxString msg = m_pParentCanvas->GetAlertString();
3859 m_gldc.SetFont(*pfont);
3863 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3870 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3871 int xp = sbr.x + sbr.width + 5;
3873 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
3874 m_gldc.SetPen(ppPen1);
3875 m_gldc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
3877 m_gldc.DrawRectangle(xp, yp, w, h);
3879 m_gldc.DrawText(msg, xp, yp);
3883unsigned long quiltHash;
3885extern wxLongLong s_t0;
3888void glChartCanvas::Render() {
3889 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3890 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3891 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3896 if (!g_PrintingInProgress)
return;
3899 if (m_binPinch)
return;
3901#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3902 loadShaders(GetCanvasIndex());
3903 configureShaders(m_pParentCanvas->VPoint);
3906#ifdef USE_ANDROID_GLES2
3910 if (m_binPinch)
return;
3919 bool recompose =
false;
3920 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3921 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3922 if (m_pParentCanvas->VPoint.IsValid()) {
3923 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3924 m_pParentCanvas->UpdateCanvasControlBar();
3933 if (sw.GetTime() > 2000) {
3939 s_tess_vertex_idx = 0;
3940 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3941 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3947 m_displayScale = GetContentScaleFactor();
3951 m_last_render_time = wxDateTime::Now().GetTicks();
3955 if (g_GLOptions.m_bTextureCompression &&
3956 !g_GLOptions.m_bTextureCompressionCaching)
3957 g_glTextureManager->ClearJobList();
3961 int gl_width, gl_height;
3962 gl_width = m_pParentCanvas->VPoint.
pix_width;
3963 gl_height = m_pParentCanvas->VPoint.
pix_height;
3966 m_glcanvas_width = gl_width;
3967 m_glcanvas_height = gl_height;
3971 if (gl_height & 1) {
3973 ViewPort *vp = m_pParentCanvas->GetpVP();
3980 ViewPort *vp = m_pParentCanvas->GetpVP();
3988 ViewPort *vp = m_pParentCanvas->GetpVP();
3991 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3994 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
4002 ViewPort VPoint = m_pParentCanvas->VPoint;
4004 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
4005 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
4008#if !defined(USE_ANDROID_GLES2)
4009 glMatrixMode(GL_PROJECTION);
4012 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4013 glMatrixMode(GL_MODELVIEW);
4017 if (s_b_useStencil) {
4018 glEnable(GL_STENCIL_TEST);
4019 glStencilMask(0xff);
4020 glClear(GL_STENCIL_BUFFER_BIT);
4021 glDisable(GL_STENCIL_TEST);
4027 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4028 if (g_GLOptions.m_GLPolygonSmoothing)
4029 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4030 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4037 g_glTextureManager->TextureCrunch(0.8);
4042 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
4043 bool useFBO =
false;
4049 if (m_b_BuiltFBO && !bpost_hilite
4054 bool b_newview =
true;
4055 bool b_full =
false;
4063 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
4067#ifdef USE_ANDROID_GLES2
4068 if (recompose) b_newview =
true;
4080 if (VPoint.b_quilt) {
4081 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
4082 if (!chart) b_full =
true;
4091 bool accelerated_pan =
false;
4101 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4102 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4103 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4105 wxPoint2DDouble c_old =
4108 wxPoint2DDouble c_new =
4112 dy = wxRound(c_new.m_y - c_old.m_y);
4113 dx = wxRound(c_new.m_x - c_old.m_x);
4123 double deltax = c_new.m_x - c_old.m_x;
4124 double deltay = c_new.m_y - c_old.m_y;
4126 bool b_whole_pixel =
true;
4127 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4128 b_whole_pixel =
false;
4130 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4131 abs(dy) < m_cache_tex_y &&
4132 (abs(dx) > 0 || (abs(dy) > 0));
4141 if (m_displayScale > 1) accelerated_pan =
false;
4146 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4149#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4152 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4158 if (b_full) accelerated_pan =
false;
4160 if (accelerated_pan) {
4161 if ((dx != 0) || (dy != 0)) {
4173 if (dy > 0 && dy < gl_height)
4174 update_region.Union(
4175 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4177 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4179 if (dx > 0 && dx < gl_width)
4180 update_region.Union(
4181 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4183 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4185 m_cache_page = !m_cache_page;
4188 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4189 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4201 RenderCharts(m_gldc, update_region);
4205 glDisable(g_texture_rectangle_format);
4210 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4211 glEnable(GL_TEXTURE_2D);
4215 float x1, x2, y1, y2;
4228 float tx1, tx2, ty1, ty2;
4234 tx2 = sx / (float)m_cache_tex_x;
4236 ty2 = sy / (float)m_cache_tex_y;
4253 coords[2] = -dx + sx;
4255 coords[4] = -dx + sx;
4256 coords[5] = dy + sy;
4258 coords[7] = dy + sy;
4261 ptexture_2D_shader_program[GetCanvasIndex()];
4265 shader->SetUniform1i(
"uTex", 0);
4269 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4270 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4271 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4273 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4295 shader->SetAttributePointerf(
"aPos", co1);
4296 shader->SetAttributePointerf(
"aUV", tco1);
4298 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4301 shader->SetUniformMatrix4fv(
"MVMatrix",
4302 (GLfloat *)VPoint.vp_matrix_transform);
4305 glBindTexture(g_texture_rectangle_format, 0);
4307 glDisable(g_texture_rectangle_format);
4315 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4316 g_texture_rectangle_format,
4317 m_cache_tex[!m_cache_page], 0);
4328 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4329 glClearColor(color.Red() / 256., color.Green() / 256.,
4330 color.Blue() / 256., 1.0);
4331 glClear(GL_COLOR_BUFFER_BIT);
4337 RenderCharts(m_gldc, rscreen_region);
4342 m_cache_page = !m_cache_page;
4347 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4358 glMatrixMode(GL_PROJECTION);
4361 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4362 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4364 glMatrixMode(GL_MODELVIEW);
4368 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4369 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4371 glGetIntegerv(GL_VIEWPORT, viewport);
4372 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4373 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4382 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4383 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4384 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4386 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4390 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4391 glEnable(g_texture_rectangle_format);
4393 float tx, ty, tx0, ty0, divx, divy;
4396 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4399 divx = m_cache_tex_x;
4400 divy = m_cache_tex_y;
4403 tx0 = m_fbo_offsetx / divx;
4404 ty0 = m_fbo_offsety / divy;
4405 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4406 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4431 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4432 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4434 glClear(GL_COLOR_BUFFER_BIT);
4436 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4439 glDisable(g_texture_rectangle_format);
4441 m_cache_vp = VPoint;
4442 m_cache_vp.Validate();
4444 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4446 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4450 RenderCharts(m_gldc, screen_region);
4456 RenderS57TextOverlay(VPoint);
4457 RenderMBTilesOverlay(VPoint);
4461 wxRect rt = upd.GetRect();
4462 LLRegion region = VPoint.GetLLRegion(rt);
4463 ViewPort cvp = ClippedViewport(VPoint, region);
4464 DrawGroundedOverlayObjects(gldc, cvp);
4467 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4468 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4469 LLBBox screenBox = screenLLRegion.GetBox();
4471 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4474 if (m_pParentCanvas->m_bShowTide) {
4475 m_pParentCanvas->RebuildTideSelectList(screenBox);
4476 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4479 if (m_pParentCanvas->m_bShowCurrent) {
4480 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4481 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4487 if (m_pParentCanvas->m_show_focus_bar &&
4488 (g_canvasConfig != 0)) {
4489 if (m_pParentCanvas == wxWindow::FindFocus()) {
4490 g_focusCanvas = m_pParentCanvas;
4492 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
4493 wxPen ppBlue(colour, 1);
4494 wxBrush ppBrush(colour);
4495 gldc.SetPen(ppBlue);
4496 gldc.SetBrush(ppBrush);
4497 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4498 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4499 wxPoint barPoints[4];
4502 barPoints[1].x = xw;
4504 barPoints[2].x = xw;
4505 barPoints[2].y = rect_pix;
4507 barPoints[3].y = rect_pix;
4509 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4513 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4517 DrawFloatingOverlayObjects(m_gldc);
4519#ifndef USE_ANDROID_GLES2
4522 glMatrixMode(GL_PROJECTION);
4525 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4526 glMatrixMode(GL_MODELVIEW);
4531 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
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(
4538 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_EMBOSS);
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, _T(
"\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();
4621 ViewPort &vp = m_pParentCanvas->GetVP();
4622 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4623 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4624 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_UI);
4625 glActiveTexture(GL_TEXTURE0);
4629 if (g_bquiting) DrawQuiting();
4630 if (g_bcompression_wait)
4631 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4636 if (g_b_needFinish) glFinish();
4640 g_glTextureManager->TextureCrunch(0.8);
4641 g_glTextureManager->FactoryCrunch(0.6);
4646 m_pParentCanvas->PaintCleanup();
4648 m_bforcefull =
false;
4653void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4656 if (VPoint.b_quilt) {
4657 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4658 ps52plib->GetShowS57Text()) {
4659 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4660 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4665 ChPI->ClearPLIBTextList();
4667 ps52plib->ClearTextList();
4677 RenderQuiltViewGLText(vpx, screen_region);
4682void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4685 LLRegion &screenLLRegion) {
4686 ChartBase *chart = ChartData->OpenChartFromDBAndLock(dbIndex, FULL_INIT);
4690 if (chart == NULL)
return;
4697 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4699 wxFileName tileFile(chart->GetFullPath());
4701 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4703 if (!ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4704 (tileSizeMB.GetLo() > 5000)) {
4707 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4708 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4709 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4716 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4720 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4723 std::vector<int> piano_active_array_tiles =
4724 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4725 bool bfound =
false;
4727 if (std::find(piano_active_array_tiles.begin(),
4728 piano_active_array_tiles.end(),
4729 dbIndex) != piano_active_array_tiles.end()) {
4734 piano_active_array_tiles.push_back(dbIndex);
4735 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4739void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4741 std::vector<int> stackIndexArray =
4742 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4743 unsigned int im = stackIndexArray.size();
4746 if (VPoint.b_quilt && im > 0) {
4747 bool regionVPBuilt =
false;
4749 LLRegion screenLLRegion;
4753 std::vector<int> tiles_to_show;
4754 for (
unsigned int is = 0; is < im; is++) {
4756 ChartData->GetChartTableEntry(stackIndexArray[is]);
4757 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4758 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4760 std::vector<int> piano_active_array_tiles =
4761 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4762 bool bfound =
false;
4764 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4765 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4766 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4774 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4775 piano_active_array_tiles);
4780 tiles_to_show.push_back(stackIndexArray[is]);
4781 if (!regionVPBuilt) {
4784 screenLLRegion = VPoint.GetLLRegion(screen_region);
4785 screenBox = screenLLRegion.GetBox();
4793 regionVPBuilt =
true;
4803 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4804 rit != tiles_to_show.rend(); ++rit) {
4805 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4807 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4808 rit != tiles_to_show.rend(); ++rit) {
4809 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4813 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4815 if (!hiregion.Empty()) {
4819 switch (global_color_scheme) {
4820 case GLOBAL_COLOR_SCHEME_DAY:
4823 case GLOBAL_COLOR_SCHEME_DUSK:
4826 case GLOBAL_COLOR_SCHEME_NIGHT:
4834#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4835 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4837 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4840 DrawRegion(VPoint, hiregion);
4842 glDisable(GL_BLEND);
4848void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4852 GetClientSize(&w, &h);
4854 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4855#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4856 glMatrixMode(GL_PROJECTION);
4859 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4860 glMatrixMode(GL_MODELVIEW);
4864 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4866 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4868 bool world_view =
false;
4869 RenderWorldChart(dc, cvp, rtex, world_view);
4870 gShapeBasemap.RenderViewOnDC(dc, cvp);
4876 glViewport(0, 0, (GLint)w, (GLint)h);
4877#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4878 glMatrixMode(GL_PROJECTION);
4881 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4882 glMatrixMode(GL_MODELVIEW);
4888void glChartCanvas::FastPan(
int dx,
int dy) {
4889#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4893void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4895 SetCurrent(*m_pcontext);
4896 float sx = GetSize().x;
4897 float sy = GetSize().y;
4898 glClear(GL_COLOR_BUFFER_BIT);
4901 GetClientSize(&w, &h);
4903 if (s_b_useStencil) {
4904 glEnable(GL_STENCIL_TEST);
4905 glStencilMask(0xff);
4906 glClear(GL_STENCIL_BUFFER_BIT);
4907 glDisable(GL_STENCIL_TEST);
4923 float sxfactor = sx / swidth;
4924 float syfactor = sy / sheight;
4926 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4927 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4928 sx * sx / swidth * 2, sy * sy / sheight * 2);
4929 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4930 glEnable(g_texture_rectangle_format);
4955 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4956 glBindTexture(g_texture_rectangle_format, 0);
4962 float tx, ty, tx0, ty0;
4972 glBindTexture(g_texture_rectangle_format, 0);
4975 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4976 glEnable(g_texture_rectangle_format);
4982 uv[0] = tx0 / m_cache_tex_x;
4983 uv[1] = ty / m_cache_tex_y;
4984 uv[2] = tx / m_cache_tex_x;
4985 uv[3] = ty / m_cache_tex_y;
4986 uv[4] = tx / m_cache_tex_x;
4987 uv[5] = ty0 / m_cache_tex_y;
4988 uv[6] = tx0 / m_cache_tex_x;
4989 uv[7] = ty0 / m_cache_tex_y;
5001 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
5002 sx * sx / swidth, sy * sy / sheight);
5004 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
5006 glDisable(g_texture_rectangle_format);
5007 glBindTexture(g_texture_rectangle_format, 0);
5014 wxColour color = GetGlobalColor(_T(
"GREY1"));
5015 float ht = -offset_y * (sy / sheight);
5016 wxRect r(0, sy - ht, w, ht);
5017 RenderColorRect(r, color);
5020 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
5021 RenderColorRect(rt, color);
5024 float w1 = -offset_x * sx / swidth;
5025 wxRect rl(0, 0, w1, sy);
5026 RenderColorRect(rl, color);
5029 float px = w1 + sx * sx / swidth;
5030 wxRect rr(px, 0, sx - px, sy);
5031 RenderColorRect(rr, color);
5040void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
5043 if (m_nRun < m_nTotal) {
5044 m_runoffsetx += m_offsetxStep;
5045 if (m_offsetxStep > 0)
5046 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
5048 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
5050 m_runoffsety += m_offsetyStep;
5051 if (m_offsetyStep > 0)
5052 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
5054 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
5056 m_runswidth += m_swidthStep;
5057 if (m_swidthStep > 0)
5058 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
5060 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
5062 m_runsheight += m_sheightStep;
5063 if (m_sheightStep > 0)
5064 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
5066 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
5071 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5077 if (m_zoomFinaldx || m_zoomFinaldy) {
5078 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5081 m_zoomFinal =
false;
5085void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5087 int sx = GetSize().x;
5088 int sy = GetSize().y;
5090 m_lastfbo_offsetx = m_fbo_offsetx;
5091 m_lastfbo_offsety = m_fbo_offsety;
5092 m_lastfbo_swidth = m_fbo_swidth;
5093 m_lastfbo_sheight = m_fbo_sheight;
5095 float curr_fbo_offset_x = m_fbo_offsetx;
5096 float curr_fbo_offset_y = m_fbo_offsety;
5097 float curr_fbo_swidth = m_fbo_swidth;
5098 float curr_fbo_sheight = m_fbo_sheight;
5100 float fx = (float)cp_x / sx;
5101 float fy = 1.0 - (float)cp_y / sy;
5103 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5104 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5106 m_fbo_swidth = curr_fbo_swidth / factor;
5107 m_fbo_sheight = curr_fbo_sheight / factor;
5109 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5110 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5112 m_fbo_offsetx += post_x;
5113 m_fbo_offsety += post_y;
5124 float perStep = m_nStep / m_nTotal;
5126 if (zoomTimer.IsRunning()) {
5127 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5128 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5129 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5130 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5133 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5134 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5135 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5136 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5138 m_runoffsetx = m_lastfbo_offsetx;
5139 m_runoffsety = m_lastfbo_offsety;
5140 m_runswidth = m_lastfbo_swidth;
5141 m_runsheight = m_lastfbo_sheight;
5144 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5145 m_zoomFinal =
false;
5151void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5155 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5158 if (m_binPinch)
return;
5159 if (m_bpinchGuard)
return;
5161 int x =
event.GetOffset().x;
5162 int y =
event.GetOffset().y;
5164 int lx =
event.GetLastOffset().x;
5165 int ly =
event.GetLastOffset().y;
5170 switch (event.GetState()) {
5171 case GestureStarted:
5172 if (m_binPan)
break;
5176 m_binGesture =
true;
5180 case GestureUpdated:
5185 m_pParentCanvas->FreezePiano();
5187 m_pParentCanvas->ThawPiano();
5198 case GestureFinished:
5201 m_pParentCanvas->UpdateCanvasControlBar();
5204 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5208 case GestureCanceled:
5210 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5217 m_bgestureGuard =
true;
5218 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5219 m_bforcefull =
false;
5224float zoom_inc = 1.0;
5225bool first_zout =
false;
5227void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5228 float zoom_gain = 1.0;
5229 float zout_gain = 1.0;
5232 float total_zoom_val;
5234 float max_zoom_scale = 1000.;
5235 float min_zoom_scale = 2e8;
5237 if (event.GetScaleFactor() > 1)
5238 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5240 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5242 if (event.GetTotalScaleFactor() > 1)
5243 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5246 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5248 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5251 float max_zoom_scale = 1000.;
5252 if( cc1->GetVP().b_quilt) {
5253 int ref_index = cc1->GetQuiltRefChartdbIndex();
5260 float min_zoom_scale = 2e8;
5264 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5266 double projected_scale =
5267 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5269 switch (event.GetState()) {
5270 case GestureStarted:
5275 m_binGesture =
true;
5277 m_pinchStart =
event.GetCenterPoint();
5278 m_lpinchPoint = m_pinchStart;
5281 event.GetCenterPoint().y, m_pinchlat,
5286 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5287 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5290 SetCurrent(*m_pcontext);
5296 case GestureUpdated:
5298 if (projected_scale < min_zoom_scale) {
5299 wxPoint pinchPoint =
event.GetCenterPoint();
5301 float dx = pinchPoint.x - m_lpinchPoint.x;
5302 float dy = pinchPoint.y - m_lpinchPoint.y;
5304 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5305 -dx / total_zoom_val, dy / total_zoom_val);
5307 m_lpinchPoint = pinchPoint;
5311 if (1 || ((total_zoom_val > 1) && !first_zout)) {
5312 wxPoint pinchPoint =
event.GetCenterPoint();
5314 float dx = pinchPoint.x - m_lpinchPoint.x;
5315 float dy = pinchPoint.y - m_lpinchPoint.y;
5317 if ((projected_scale > max_zoom_scale) &&
5318 (projected_scale < min_zoom_scale))
5319 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5320 -dx / total_zoom_val, dy / total_zoom_val);
5322 m_lpinchPoint = pinchPoint;
5326 zoom_inc *= zoom_val;
5327 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5328 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5332 wxPoint pinchPoint =
event.GetCenterPoint();
5333 float dx = pinchPoint.x - m_lpinchPoint.x;
5334 float dy = pinchPoint.y - m_lpinchPoint.y;
5336 m_lpinchPoint = pinchPoint;
5347 case GestureFinished: {
5351 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5352 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5356 float tzoom = total_zoom_val;
5358 if (projected_scale >= min_zoom_scale)
5359 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5361 if (projected_scale < max_zoom_scale)
5362 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5364 dx = (cc_x - m_cc_x) * tzoom;
5365 dy = -(cc_y - m_cc_y) * tzoom;
5367 if (zoomTimer.IsRunning()) {
5370 m_zoomFinalZoom = tzoom;
5376 double final_projected_scale =
5380 if (final_projected_scale < min_zoom_scale) {
5384 m_pParentCanvas->m_pQuilt->Invalidate();
5385 m_bforcefull =
true;
5392 m_pParentCanvas->m_pQuilt->Invalidate();
5393 m_bforcefull =
true;
5405 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5409 case GestureCanceled:
5411 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5418 m_bgestureGuard =
true;
5420 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5423void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5433 m_bgestureGuard =
false;
5434 m_bpinchGuard =
false;
5435 m_binGesture =
false;
5436 m_bforcefull =
false;
5439void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5443 m_binGesture =
false;
5444 m_bforcefull =
false;
5448#ifdef HAVE_WX_GESTURE_EVENTS
5450void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5454 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5457 if (m_binPinch)
return;
5458 if (m_bpinchGuard)
return;
5460 int dx =
event.GetDelta().x;
5461 int dy =
event.GetDelta().y;
5463 if (event.IsGestureStart()) {
5464 if (m_binPan)
return;
5468 m_binGesture =
true;
5472 else if (event.IsGestureEnd()) {
5474 m_pParentCanvas->UpdateCanvasControlBar();
5476 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5484 m_pParentCanvas->FreezePiano();
5486 m_pParentCanvas->ThawPiano();
5497 m_bgestureGuard =
true;
5498 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5499 m_bforcefull =
false;
5502bool first_zout =
false;
5505void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5506 float zoom_gain = 1.0;
5507 float zout_gain = 1.0;
5509 float last_zoom_val = m_total_zoom_val;
5511 float max_zoom_scale = 1000.;
5512 float min_zoom_scale = 2e8;
5514 if (event.GetZoomFactor() > 1)
5515 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5517 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5519 float inc_zoom_val =
5520 m_total_zoom_val / last_zoom_val;
5522 double projected_scale =
5523 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5525 if (event.IsGestureStart()) {
5531 m_binGesture =
true;
5532 m_pinchStart =
event.GetPosition();
5533 m_lpinchPoint = m_pinchStart;
5534 m_total_zoom_val = 1.0;
5535 m_final_zoom_val = 1.0;
5538 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5542 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5543 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5546 SetCurrent(*m_pcontext);
5549 ViewPort vpr = m_pParentCanvas->VPoint;
5551 GetTouchBackingBitmap(vpr);
5556 if (event.IsGestureEnd()) {
5562 if (!m_binGesture)
return;
5564 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5565 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5569 float tzoom = m_final_zoom_val;
5571 dx = (cc_x - m_cc_x) * tzoom;
5572 dy = -(cc_y - m_cc_y) * tzoom;
5574 if (zoomTimer.IsRunning()) {
5577 m_zoomFinalZoom = tzoom;
5583 double final_projected_scale =
5587 if (final_projected_scale < min_zoom_scale) {
5591 m_pParentCanvas->m_pQuilt->Invalidate();
5592 m_bforcefull =
true;
5599 m_pParentCanvas->m_pQuilt->Invalidate();
5600 m_bforcefull =
true;
5605 m_final_zoom_val = 1.0;
5606 m_total_zoom_val = 1.0;
5607 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5612 if (projected_scale < min_zoom_scale) {
5613 wxPoint pinchPoint =
event.GetPosition();
5615 float dx = pinchPoint.x - m_lpinchPoint.x;
5616 float dy = pinchPoint.y - m_lpinchPoint.y;
5618 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5619 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5621 m_lpinchPoint = pinchPoint;
5622 m_final_zoom_val *= inc_zoom_val;
5626 if (1 || ((m_total_zoom_val > 1) && !first_zout)) {
5627 wxPoint pinchPoint =
event.GetPosition();
5629 float dx = pinchPoint.x - m_lpinchPoint.x;
5630 float dy = pinchPoint.y - m_lpinchPoint.y;
5632 if ((projected_scale > max_zoom_scale) &&
5633 (projected_scale < min_zoom_scale))
5634 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5635 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5637 m_lpinchPoint = pinchPoint;
5638 m_final_zoom_val *= inc_zoom_val;
5642 m_zoom_inc *= inc_zoom_val;
5643 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5644 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5648 wxPoint pinchPoint =
event.GetPosition();
5649 float dx = pinchPoint.x - m_lpinchPoint.x;
5650 float dy = pinchPoint.y - m_lpinchPoint.y;
5652 m_lpinchPoint = pinchPoint;
5656 m_bgestureGuard =
true;
5657 m_bpinchGuard =
true;
5658 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5661void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5671 m_bgestureGuard =
false;
5672 m_bpinchGuard =
false;
5673 m_binGesture =
false;
5674 m_bforcefull =
false;
5677void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5681 m_binGesture =
false;
5682 m_bforcefull =
false;
5688void glChartCanvas::configureShaders(
ViewPort &vp) {
5689#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5695 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5697 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5698 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5719 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5721 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5722 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5734 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5736 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5737 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5740 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5742 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5743 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5751 shader = pAALine_shader_program[GetCanvasIndex()];
5753 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5756 shader = pring_shader_program[GetCanvasIndex()];
5758 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5759 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5763 if (texture_2DA_shader_program) {
5764 glUseProgram(texture_2DA_shader_program);
5765 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5766 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5767 (
const GLfloat *)pvp->vp_matrix_transform);
5769 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5770 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5778void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5781#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5782 int nl = nVertex / 4;
5784 float *luv = uvCoords;
5787 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5795 glEnableClientState(GL_VERTEX_ARRAY);
5796 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5798 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5799 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5800 glDrawArrays(GL_QUADS, 0, 4);
5807void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5808 float *uvCoords,
ViewPort *vp,
float dx,
5809 float dy,
float angle_rad) {
5810#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5812 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5813 if (!shader)
return;
5818 shader->SetUniform1i(
"uTex", 0);
5823 mat4x4_rotate_Z(Q, I, angle_rad);
5829 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5834 shader->SetAttributePointerf(
"aPos", co1);
5835 shader->SetAttributePointerf(
"aUV", tco1);
5842 GLushort indices1[] = {0,1,3,2};
5843 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5855 tco1[0] = uvCoords[0];
5856 tco1[1] = uvCoords[1];
5857 tco1[2] = uvCoords[2];
5858 tco1[3] = uvCoords[3];
5859 tco1[4] = uvCoords[6];
5860 tco1[5] = uvCoords[7];
5861 tco1[6] = uvCoords[4];
5862 tco1[7] = uvCoords[5];
5867 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5879void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5880#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5882 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5885 shader->SetUniformMatrix4fv(
5886 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5889 colorv[0] = color.Red() / float(256);
5890 colorv[1] = color.Green() / float(256);
5891 colorv[2] = color.Blue() / float(256);
5893 shader->SetUniform4fv(
"color", colorv);
5896 pf[0] = r.x + r.width;
5900 pf[4] = r.x + r.width;
5901 pf[5] = r.y + r.height;
5903 pf[7] = r.y + r.height;
5904 shader->SetAttributePointerf(
"position", pf);
5906 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5914void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5915#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5917 ViewPort VPoint = m_pParentCanvas->VPoint;
5921 GetClientSize(&w, &h);
5922 int sx = GetSize().x;
5923 int sy = GetSize().y;
5927 glViewport(0, 0, (GLint)w, (GLint)h);
5929 if (s_b_useStencil) {
5930 glEnable(GL_STENCIL_TEST);
5931 glStencilMask(0xff);
5932 glClear(GL_STENCIL_BUFFER_BIT);
5933 glDisable(GL_STENCIL_TEST);
5937 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5942 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5943 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5944 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5947 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5949 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5950 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5958 if (bRenderCharts) RenderCharts(gldc, screen_region);
5960 if (bRenderOverlays) {
5961 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5962 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5963 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5964 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5965 DrawFloatingOverlayObjects(m_gldc);
5969 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5974wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5976 wxMemoryDC tdc(tbm);
5977 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5985 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5986 dc.SetPen(*wxTRANSPARENT_PEN);
5988 gShapeBasemap.RenderViewOnDC(dc, tvp);
5989 tdc.SelectObject(wxNullBitmap);
5990 m_touch_backing_bitmap = tbm;
5991 CreateBackingTexture();
5993 return m_touch_backing_bitmap;
5996void glChartCanvas::CreateBackingTexture() {
5997 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5998 unsigned char *imgdata = image.GetData();
5999 unsigned char *imgalpha = image.GetAlpha();
6000 m_tex_w = image.GetWidth();
6001 m_tex_h = image.GetHeight();
6002 m_image_width = m_tex_w;
6003 m_image_height = m_tex_h;
6005 GLuint format = GL_RGBA;
6006 GLuint internalformat = g_texture_rectangle_format;
6008 internalformat = GL_RGBA;
6013 unsigned char *teximage =
6014 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6016 for (
int i = 0; i < m_image_height; i++) {
6017 for (
int j = 0; j < m_image_width; j++) {
6018 int s = (i * 3 * m_image_width) + (j * 3);
6019 int d = (i * stride * m_tex_w) + (j * stride);
6021 teximage[d + 0] = imgdata[s + 0];
6022 teximage[d + 1] = imgdata[s + 1];
6023 teximage[d + 2] = imgdata[s + 2];
6024 teximage[d + 3] = 255;
6028 glGenTextures(1, &m_TouchBackingTexture);
6029 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6031 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6032 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6033 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6035 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6037 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6038 GL_UNSIGNED_BYTE, teximage);
6041 glBindTexture(GL_TEXTURE_2D, 0);
Represents an active track that is currently being recorded.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
float GetVPChartScale()
Return the ViewPort chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Manages the chart database and provides access to chart data.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Wrapper class for OpenGL shader programs.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
Represents a navigational route in the navigation system.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
Manages a set of ShapeBaseChart objects at different resolutions.
Window for displaying chart thumbnails.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
bool m_bUseCanvasPanning
Controls OpenGL canvas hardware-accelerated panning mode.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Class NotificationManager.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
Tools to send data to plugins.
Represents an entry in the chart table, containing information about a single chart.