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"
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;
234extern bool g_bhide_depth_units;
235extern bool g_bhide_overzoom_flag;
239wxColor s_regionColor;
251#define APIENTRYP APIENTRY *
257#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
258#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
261PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
262PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
263PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
264PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
265PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
266PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
267PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
268PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
269PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
270PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
272PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
273PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
276PFNGLGENBUFFERSPROC s_glGenBuffers;
277PFNGLBINDBUFFERPROC s_glBindBuffer;
278PFNGLBUFFERDATAPROC s_glBufferData;
279PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
281#ifndef USE_ANDROID_GLES2
286typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
288PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
290#include <wx/arrimpl.cpp>
293GLuint g_raster_format = GL_RGB;
297wxStopWatch g_glstopwatch;
298double g_gl_ms_per_frame;
301int g_uncompressed_tile_size;
303extern wxProgressDialog *pprog;
304extern bool b_skipout;
305extern wxSize pprog_size;
306extern int pprog_count;
307extern int pprog_threads;
313bool glChartCanvas::s_b_useScissorTest;
314bool glChartCanvas::s_b_useStencil;
315bool glChartCanvas::s_b_useStencilAP;
316bool glChartCanvas::s_b_useFBO;
318#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
319static int s_tess_vertex_idx;
320static int s_tess_vertex_idx_this;
321static int s_tess_buf_len;
322static GLfloat *s_tess_work_buf;
325static vec4 s_tess_color;
335 while ( upd.HaveRects() )
337 wxRect rect = upd.GetRect();
338 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
345GLboolean QueryExtension(
const char *extName) {
356 extNameLen = strlen(extName);
358 p = (
char *)glGetString(GL_EXTENSIONS);
366 int n = strcspn(p,
" ");
367 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
375int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
376 16, WX_GL_STENCIL_SIZE, 8,
379glTestCanvas::glTestCanvas(wxWindow *parent)
380 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
384int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
385 16, WX_GL_STENCIL_SIZE, 8,
388EVT_PAINT(glChartCanvas::OnPaint)
389EVT_ACTIVATE(glChartCanvas::OnActivate)
390EVT_SIZE(glChartCanvas::OnSize)
391EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
395 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
396 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, _T(""))
399 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
404std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
406 {wxPENSTYLE_DOT, {1, 1}},
407 {wxPENSTYLE_LONG_DASH, {5, 5}},
408 {wxPENSTYLE_SHORT_DASH, {1, 5}},
409 {wxPENSTYLE_DOT_DASH, {5, 1}},
412void glChartCanvas::Init() {
417 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
419 m_cache_current_ch = NULL;
421 m_b_paint_enable =
true;
422 m_in_glpaint =
false;
424 m_cache_tex[0] = m_cache_tex[1] = 0;
427 m_b_BuiltFBO =
false;
428 m_b_DisableFBO =
false;
437 m_bpinchGuard =
false;
438 m_binGesture =
false;
441 m_last_render_time = -1;
448 m_gldc.SetGLCanvas(
this);
451 m_displayScale = 1.0;
452#if defined(__WXOSX__) || defined(__WXGTK3__)
454 m_displayScale = GetContentScaleFactor();
463 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
467 wxEVT_QT_PINCHGESTURE,
468 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
471 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
476 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
478 onGestureFinishTimerEvent,
482 ZOOM_TIMER, wxEVT_TIMER,
483 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
486 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
487 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
488 zoomTimer.SetOwner(
this, ZOOM_TIMER);
490#ifdef USE_ANDROID_GLES2
499#ifdef HAVE_WX_GESTURE_EVENTS
501 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
506 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
508 onGestureFinishTimerEvent,
512 ZOOM_TIMER, wxEVT_TIMER,
513 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
516 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
517 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
518 zoomTimer.SetOwner(
this, ZOOM_TIMER);
523 m_bgestureGuard =
false;
524 m_total_zoom_val = 1.0;
527#ifdef HAVE_WX_GESTURE_EVENTS
528 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
529 wxLogError(
"Failed to enable touch events");
538 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
540 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
541 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
543 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
544 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
546 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
547 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
549 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
550 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
556glChartCanvas::~glChartCanvas() {
562void glChartCanvas::FlushFBO(
void) {
563 if (m_bsetup) BuildFBO();
566void glChartCanvas::OnActivate(wxActivateEvent &event) {
567 m_pParentCanvas->OnActivate(event);
570void glChartCanvas::OnSize(wxSizeEvent &event) {
574 wxLogMessage(_T(
"Got OnSize event while NOT running"));
576 qDebug() <<
"OnSizeB";
583 if (!IsShown())
return;
585 SetCurrent(*m_pcontext);
589 SetSize(GetSize().x, GetSize().y);
597 if (m_bsetup && m_pcontext && IsShown()) {
598 SetCurrent(*m_pcontext);
604 wxLogMessage(_T(
"BuildFBO 3"));
609 ViewPort *vp = m_pParentCanvas->GetpVP();
612 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
615 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
619void glChartCanvas::MouseEvent(wxMouseEvent &event) {
620 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
626 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
628 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
631 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
635 if (m_bgestureGuard) {
636 m_pParentCanvas->r_rband.x = 0;
646 if (event.LeftUp()) {
648 if ((abs(panx) > 2) || (abs(pany) > 2)) {
651 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
658 if (!event.LeftDClick()) {
663 if (m_binPan && event.RightDown()) {
664 qDebug() <<
"Skip right on pan";
667 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
669 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
670 if (!m_bgestureGuard)
680#ifndef GL_MAX_RENDERBUFFER_SIZE
681#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
684#ifndef USE_ANDROID_GLES2
685bool glChartCanvas::buildFBOSize(
int fboSize) {
687 if (IsShown()) SetCurrent(*m_pcontext);
690 glDeleteTextures(2, m_cache_tex);
691 glDeleteFramebuffers(1, &m_fb0);
692 glDeleteRenderbuffers(1, &m_renderbuffer);
693 m_b_BuiltFBO =
false;
696 if (m_b_DisableFBO)
return false;
700 int rb_x = GetSize().x;
701 int rb_y = GetSize().y;
703 while (i < rb_x) i <<= 1;
707 while (i < rb_y) i <<= 1;
710 m_cache_tex_x = wxMax(rb_x, rb_y);
711 m_cache_tex_y = wxMax(rb_x, rb_y);
714 m_cache_tex_x = GetSize().x * m_displayScale;
715 m_cache_tex_y = GetSize().y * m_displayScale;
718 int err = GL_NO_ERROR;
720 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
723 if (err == GL_INVALID_ENUM) {
724 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
728 if (err == GL_NO_ERROR) {
729 if (fboSize > params) {
731 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
732 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
737 glGenFramebuffers(1, &m_fb0);
741 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
747 glGenRenderbuffers(1, &m_renderbuffer);
751 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
757 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
761 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
768 glGenTextures(2, m_cache_tex);
769 for (
int i = 0; i < 2; i++) {
770 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
771 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
773 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
775 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
776 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
779 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
781 if (m_b_useFBOStencil) {
783 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
784 m_cache_tex_x, m_cache_tex_y);
786 int err = glGetError();
789 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
793 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
794 GL_RENDERBUFFER_EXT, m_renderbuffer);
799 _T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"), err);
803 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
804 GL_RENDERBUFFER_EXT, m_renderbuffer);
809 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"),
815 GLenum depth_format = GL_DEPTH_COMPONENT24;
820 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
824 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
826 int err = glGetError();
830 _T(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X"),
836 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
837 GL_RENDERBUFFER_EXT, m_renderbuffer);
843 _T(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X"), err);
849 glBindTexture(GL_TEXTURE_2D, 0);
850 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
853 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
855 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
856 g_texture_rectangle_format, m_cache_tex[0], 0);
858 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
860 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
862 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
864 msg.Printf(_T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X"),
874#ifdef USE_ANDROID_GLES2
875bool glChartCanvas::buildFBOSize(
int fboSize) {
879 int rb_x = GetSize().x;
880 int rb_y = GetSize().y;
882 while (i < rb_x) i <<= 1;
886 while (i < rb_y) i <<= 1;
889 m_cache_tex_x = wxMax(rb_x, rb_y);
890 m_cache_tex_y = wxMax(rb_x, rb_y);
894 int err = GL_NO_ERROR;
896 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
899 if (err == GL_INVALID_ENUM) {
900 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
904 if (err == GL_NO_ERROR) {
905 if (fboSize > params) {
907 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
908 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
913 glGenFramebuffers(1, &m_fb0);
917 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
923 glGenRenderbuffers(1, &m_renderbuffer);
927 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
933 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
937 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
944 glGenTextures(2, m_cache_tex);
945 for (
int i = 0; i < 2; i++) {
946 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
947 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
949 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
951 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
952 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
955 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
958 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
964 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
968 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
969 GL_RENDERBUFFER, m_renderbuffer);
973 msg.Printf(_T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"),
978 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
979 GL_RENDERBUFFER, m_renderbuffer);
984 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"), err);
988 glBindTexture(GL_TEXTURE_2D, 0);
989 glBindFramebuffer(GL_FRAMEBUFFER, 0);
992 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
994 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
995 g_texture_rectangle_format, m_cache_tex[0], 0);
997 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
999 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1001 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
1004 _T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X"),
1014void glChartCanvas::BuildFBO() {
1017 glDeleteTextures(2, m_cache_tex);
1018 glDeleteFramebuffers(1, &m_fb0);
1019 glDeleteRenderbuffers(1, &m_renderbuffer);
1020 m_b_BuiltFBO =
false;
1023 if (m_b_DisableFBO)
return;
1026 int gl_width, gl_height;
1027 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
1028 int initialSize = NextPow2(gl_width * m_displayScale);
1033 wxString info = androidGetDeviceInfo();
1035 if (wxNOT_FOUND != info.Find(_T(
"GT-S6312"))) initialSize = 1024;
1038 if (!buildFBOSize(initialSize)) {
1039 glDeleteTextures(2, m_cache_tex);
1040 glDeleteFramebuffers(1, &m_fb0);
1041 glDeleteRenderbuffers(1, &m_renderbuffer);
1043 if (!buildFBOSize(1024)) {
1044 wxLogMessage(_T(
"BuildFBO C"));
1046 m_b_DisableFBO =
true;
1047 wxLogMessage(_T(
"OpenGL-> FBO Framebuffer unavailable"));
1048 m_b_BuiltFBO =
false;
1057 msg.Printf(_T(
"OpenGL-> Framebuffer OK, size = %d"), m_cache_tex_x);
1064 m_b_BuiltFBO =
true;
1069void glChartCanvas::SetupOpenGL() {
1070 SetCurrent(*m_pcontext);
1072 char *str = (
char *)glGetString(GL_RENDERER);
1075 wxLogMessage(_T(
"Failed to initialize OpenGL"));
1079 char render_string[80];
1080 strncpy(render_string, str, 79);
1081 m_renderer = wxString(render_string, wxConvUTF8);
1084 if (g_bSoftwareGL) msg.Printf(_T(
"OpenGL-> Software OpenGL"));
1085 msg.Printf(_T(
"OpenGL-> Renderer String: "));
1089 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1091 char version_string[80];
1092 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1093 msg.Printf(_T(
"OpenGL-> Version reported: "));
1094 m_version = wxString(version_string, wxConvUTF8);
1098 char GLSL_version_string[80];
1099 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1101 msg.Printf(_T(
"OpenGL-> GLSL Version reported: "));
1102 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1103 msg += m_GLSLversion;
1108 GLenum err = glewInit();
1109#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1110 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1115 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1118 wxLogMessage(
"GLEW init success!n");
1123 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1124 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1128#ifndef USE_ANDROID_GLES2
1129 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1131 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1133 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1134 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1141 if (m_renderer.Upper().Find(_T(
"MESA")) != wxNOT_FOUND) {
1143 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1145 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1148 s_b_useScissorTest =
true;
1150 if (GetRendererString().Find(_T(
"RADEON X600")) != wxNOT_FOUND)
1151 s_b_useScissorTest =
false;
1153 if (GetRendererString().Find(_T(
"GeForce")) !=
1155 s_b_useScissorTest =
false;
1157 bool bad_stencil_code =
false;
1160 if (GetRendererString().Find(_T(
"UniChrome")) != wxNOT_FOUND)
1161 bad_stencil_code =
true;
1164 if (GetRendererString().Find(_T(
"Mali")) != wxNOT_FOUND)
1165 bad_stencil_code =
true;
1168 glEnable(GL_STENCIL_TEST);
1169 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1171 glGetIntegerv(GL_STENCIL_BITS, &sb);
1174 glDisable(GL_STENCIL_TEST);
1176 s_b_useStencil =
false;
1177 if (stencil && (sb == 8)) s_b_useStencil =
true;
1179 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1180 g_texture_rectangle_format = GL_TEXTURE_2D;
1181 else if (QueryExtension(
"GL_OES_texture_npot"))
1182 g_texture_rectangle_format = GL_TEXTURE_2D;
1183 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1184 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1185 wxLogMessage(wxString::Format(_T(
"OpenGL-> Texture rectangle format: %x"),
1186 g_texture_rectangle_format));
1189 g_texture_rectangle_format = GL_TEXTURE_2D;
1193 g_b_EnableVBO =
true;
1196 g_b_EnableVBO =
false;
1200 wxLogMessage(_T(
"OpenGL-> Using Vertexbuffer Objects"));
1202 wxLogMessage(_T(
"OpenGL-> Vertexbuffer Objects unavailable"));
1206 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1208 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1211#ifndef USE_ANDROID_GLES2
1213 if (bad_stencil_code) s_b_useStencil =
false;
1227 if (m_displayScale > 1) m_b_DisableFBO =
true;
1236 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1238 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1239 g_texture_rectangle_format, m_cache_tex[0], 0);
1241 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1242 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1244 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1246 msg.Printf(_T(
" OpenGL-> Framebuffer Incomplete: %08X"), fb_status);
1248 m_b_DisableFBO =
true;
1254 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1258 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1260#ifdef USE_ANDROID_GLES2
1261 s_b_useStencilAP = s_b_useStencil;
1268 wxLogMessage(_T(
"OpenGL-> Using Framebuffer Objects"));
1270 if (m_b_useFBOStencil)
1271 wxLogMessage(_T(
"OpenGL-> Using FBO Stencil buffer"));
1273 wxLogMessage(_T(
"OpenGL-> FBO Stencil buffer unavailable"));
1275 wxLogMessage(_T(
"OpenGL-> Framebuffer Objects unavailable"));
1278 wxLogMessage(_T(
"OpenGL-> Using Stencil buffer clipping"));
1280 wxLogMessage(_T(
"OpenGL-> Using Depth buffer clipping"));
1282 if (s_b_useScissorTest && s_b_useStencil)
1283 wxLogMessage(_T(
"OpenGL-> Using Scissor Clipping"));
1286 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1288 MipMap_ResolveRoutines();
1292 lwmsg.Printf(_T(
"OpenGL-> Minimum cartographic line width: %4.1f"),
1293 g_GLMinCartographicLineWidth);
1294 wxLogMessage(lwmsg);
1295 lwmsg.Printf(_T(
"OpenGL-> Minimum symbol line width: %4.1f"),
1296 g_GLMinSymbolLineWidth);
1297 wxLogMessage(lwmsg);
1300 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1302#ifdef USE_ANDROID_GLES2
1303 g_GLOptions.m_bUseAcceleratedPanning =
true;
1309 int tex_dim = g_GLOptions.m_iTextureDimension;
1310 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1311 g_mipmap_max_level = max_level - 1;
1316 g_mipmap_max_level = 4;
1319 s_b_useFBO = m_b_BuiltFBO;
1323 ps52plib->SetGLOptions(
1324 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1325 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1326 g_GLMinSymbolLineWidth);
1330 SendJSONConfigMessage();
1333void glChartCanvas::SendJSONConfigMessage() {
1336 v[_T(
"setupComplete")] = m_bsetup;
1337 v[_T(
"useStencil")] = s_b_useStencil;
1338 v[_T(
"useStencilAP")] = s_b_useStencilAP;
1339 v[_T(
"useScissorTest")] = s_b_useScissorTest;
1340 v[_T(
"useFBO")] = s_b_useFBO;
1341 v[_T(
"useVBO")] = g_b_EnableVBO;
1342 v[_T(
"TextureRectangleFormat")] = g_texture_rectangle_format;
1343 wxString msg_id(_T(
"OCPN_OPENGL_CONFIG"));
1344 SendJSONMessageToAllPlugins(msg_id, v);
1347void glChartCanvas::SetupCompression() {
1348 int dim = g_GLOptions.m_iTextureDimension;
1351 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1352 wxLogMessage(_T(
"OpenGL-> SSE2 Instruction set not available"));
1353 goto no_compression;
1357 g_uncompressed_tile_size = dim * dim * 4;
1358 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1360 g_raster_format = GL_RGB;
1364 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1365 g_raster_format = GL_ETC1_RGB8_OES;
1367 wxLogMessage(_T(
"OpenGL-> Using oes etc1 compression"));
1371 if (GL_RGB == g_raster_format) {
1377 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1378 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1381 if (GetRendererString().Find(_T(
"Gallium")) != wxNOT_FOUND &&
1382 GetRendererString().Find(_T(
"NV")) != wxNOT_FOUND)
1383 g_raster_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
1385 g_raster_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1387 wxLogMessage(_T(
"OpenGL-> Using s3tc dxt1 compression"));
1388 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1389 g_raster_format = GL_COMPRESSED_RGB_FXT1_3DFX;
1391 wxLogMessage(_T(
"OpenGL-> Using 3dfx fxt1 compression"));
1393 wxLogMessage(_T(
"OpenGL-> No Useable compression format found"));
1394 goto no_compression;
1399 g_tile_size = 512 * 512 / 2;
1403 glGenTextures(1, &texture);
1404 glBindTexture(GL_TEXTURE_2D, texture);
1405 glTexImage2D(GL_TEXTURE_2D, 0, g_raster_format, dim, dim, 0, GL_RGB,
1406 GL_UNSIGNED_BYTE, NULL);
1407 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1409 glDeleteTextures(1, &texture);
1413 if (g_tile_size == 0)
goto no_compression;
1415 wxLogMessage(wxString::Format(
1416 _T(
"OpenGL-> Compressed tile size: %dkb (%d:1)"), g_tile_size / 1024,
1417 g_uncompressed_tile_size / g_tile_size));
1421 g_GLOptions.m_bTextureCompression =
false;
1423 g_tile_size = g_uncompressed_tile_size;
1424 wxLogMessage(wxString::Format(_T(
"OpenGL-> Not Using compression")));
1427void glChartCanvas::OnPaint(wxPaintEvent &event) {
1430 if (!m_pcontext)
return;
1438 SetCurrent(*m_pcontext);
1443 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1451 if (!m_b_paint_enable)
return;
1454 if (m_in_glpaint)
return;
1457 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1480bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1482#ifndef USE_ANDROID_GLES2
1483 return vp.m_projection_type == PROJECTION_MERCATOR ||
1484 vp.m_projection_type == PROJECTION_POLAR ||
1485 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1499#define NORM_FACTOR 4096.0
1500void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1501#ifndef USE_ANDROID_GLES2
1503 wxPoint2DDouble point;
1505 switch (vp.m_projection_type) {
1506 case PROJECTION_MERCATOR:
1507 case PROJECTION_EQUIRECTANGULAR:
1508 case PROJECTION_WEB_MERCATOR:
1511 glTranslated(point.m_x, point.m_y, 0);
1516 case PROJECTION_POLAR:
1520 glTranslated(point.m_x, point.m_y, 0);
1521 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1528 printf(
"ERROR: Unhandled projection\n");
1533 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1541 switch (vp.m_projection_type) {
1542 case PROJECTION_MERCATOR:
1543 case PROJECTION_EQUIRECTANGULAR:
1544 case PROJECTION_WEB_MERCATOR:
1548 case PROJECTION_POLAR:
1553 printf(
"ERROR: Unhandled projection\n");
1562bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1563 return vp.m_projection_type == PROJECTION_MERCATOR ||
1564 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1565 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1569 const LLRegion ®ion) {
1570 if (!CanClipViewport(vp))
return vp;
1573 LLBBox bbox = region.GetBox();
1575 if (!bbox.GetValid())
return vp;
1583 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1584 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1585 bbox.GetMaxLon() + 360);
1586 cvp.SetBBoxDirect(bbox);
1587 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1588 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1589 bbox.GetMaxLon() - 360);
1590 cvp.SetBBoxDirect(bbox);
1592 cvp.SetBBoxDirect(bbox);
1597void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1598 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1601 for (
Track *pTrackDraw : g_TrackList) {
1604 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1606 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1609 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1610 node = node->GetNext()) {
1611 Route *pRouteDraw = node->GetData();
1613 if (!pRouteDraw)
continue;
1616 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1621 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1626 if (vp.GetBBox().GetValid() && pWayPointMan) {
1627 for (wxRoutePointListNode *pnode =
1628 pWayPointMan->GetWaypointList()->GetFirst();
1629 pnode; pnode = pnode->GetNext()) {
1632 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1639void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1642 for (
Track *pTrackDraw : g_TrackList) {
1644 if (pActiveTrack && pActiveTrack->IsRunning())
1645 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1649 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1650 node = node->GetNext()) {
1651 Route *pRouteDraw = node->GetData();
1654 if (!pRouteDraw)
continue;
1657 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1663 if (pRouteDraw->IsSelected()) drawit++;
1666 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1667 if (!vp_box.IntersectOut(test_box))
1668 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1674 if (vp.GetBBox().GetValid() && pWayPointMan) {
1675 for (wxRoutePointListNode *pnode =
1676 pWayPointMan->GetWaypointList()->GetFirst();
1677 pnode; pnode = pnode->GetNext()) {
1686static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1690 switch (vp.m_projection_type) {
1691 case PROJECTION_TRANSVERSE_MERCATOR:
1692 lat_dist = 4, lon_dist = 1;
1694 case PROJECTION_POLYCONIC:
1695 lat_dist = 2, lon_dist = 1;
1697 case PROJECTION_ORTHOGRAPHIC:
1698 lat_dist = 2, lon_dist = 2;
1700 case PROJECTION_POLAR:
1701 lat_dist = 180, lon_dist = 1;
1703 case PROJECTION_STEREOGRAPHIC:
1704 case PROJECTION_GNOMONIC:
1705 lat_dist = 2, lon_dist = 1;
1707 case PROJECTION_EQUIRECTANGULAR:
1710 lat_dist = 2, lon_dist = 360;
1713 lat_dist = 180, lon_dist = 360;
1717void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1718 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1719 !ChartData->IsChartAvailable(dbIndex))
1724 ChartData->GetDBBoundingBox(dbIndex, box);
1725 if (!box.GetValid())
return;
1729 if (box.GetLonRange() == 360)
return;
1731 LLBBox vpbox = vp.GetBBox();
1733 double lon_bias = 0;
1735 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1738 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1739 color = GetGlobalColor(_T (
"YELO1" ));
1740 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1741 color = GetGlobalColor(_T (
"GREEN2" ));
1743 color = GetGlobalColor(_T (
"UINFR" ));
1745#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1746 float plylat, plylon;
1748 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1750 glColor3ub(color.Red(), color.Green(), color.Blue());
1751 glLineWidth(g_GLMinSymbolLineWidth);
1753 float lat_dist, lon_dist;
1754 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1757 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1761 nPly = ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1763 nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1765 bool begin =
false, sml_valid =
false;
1767 float lastplylat = 0.0;
1768 float lastplylon = 0.0;
1770 int modulo = (nPly == 0) ? 1 : nPly;
1771 for (
int i = 0; i < nPly + 1; i++) {
1773 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1775 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1779 if (lastplylon - plylon > 180)
1781 else if (lastplylon - plylon < -180)
1788 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1789 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1790 splits = wxMax(lat_splits, lon_splits) + 1;
1797 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1798 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1801 for (
double c = 0; c < splits; c++) {
1803 if (c == splits - 1)
1804 lat = plylat, lon = plylon;
1806 double d = (double)(c + 1) / splits;
1807 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1813 if (!std::isnan(s.m_x)) {
1816 glBegin(GL_LINE_STRIP);
1818 glVertex2f(s.m_x, s.m_y);
1824 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1825 lastplylat = plylat, lastplylon = plylon;
1830 }
while (++j < nAuxPlyEntries);
1832 glDisable(GL_LINE_SMOOTH);
1836 double nominal_line_width_pix =
1837 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1839 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1840 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), nominal_line_width_pix,
1843 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1844 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), nominal_line_width_pix,
1848 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), nominal_line_width_pix,
1851 float plylat1, plylon1;
1855 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
1856 if (0 == nAuxPlyEntries)
1859 std::vector<int> points_vector;
1861 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1862 int nPly = vec.size() / 2;
1864 if (nPly == 0)
return;
1866 for (
int i = 0; i < nPly; i++) {
1867 plylon1 = vec[i * 2];
1868 plylat1 = vec[i * 2 + 1];
1874 points_vector.push_back(pixx1);
1875 points_vector.push_back(pixy1);
1878 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1879 plylon1 += lon_bias;
1885 points_vector.push_back(pixx1);
1886 points_vector.push_back(pixy1);
1888 if (points_vector.size()) {
1889 std::vector<int>::iterator it = points_vector.begin();
1890 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1898 for (
int j = 0; j < nAuxPlyEntries; j++) {
1899 std::vector<int> points_vector;
1901 std::vector<float> vec = ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1902 int nAuxPly = vec.size() / 2;
1904 if (nAuxPly == 0)
continue;
1906 for (
int i = 0; i < nAuxPly; i++) {
1907 plylon1 = vec[i * 2];
1908 plylat1 = vec[i * 2 + 1];
1914 points_vector.push_back(pixx1);
1915 points_vector.push_back(pixy1);
1922 points_vector.push_back(pixx1);
1923 points_vector.push_back(pixy1);
1925 if (points_vector.size()) {
1926 std::vector<int>::iterator it = points_vector.begin();
1927 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1935extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1936 float &MinorSpacing);
1937extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1938void glChartCanvas::GridDraw() {
1939 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1941 ViewPort &vp = m_pParentCanvas->GetVP();
1943 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1947 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1949 double nlat, elon, slat, wlon;
1951 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1954 wxColour GridColor = GetGlobalColor(_T (
"SNDG1" ));
1956 if (!m_gridfont.IsBuilt()) {
1958 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1959 wxFont font = *dFont;
1960 int font_size = wxMax(10, dFont->GetPointSize());
1961 font.SetPointSize(font_size * m_displayScale);
1962 font.SetWeight(wxFONTWEIGHT_NORMAL);
1965 m_gridfont.Build(font, 1, dpi_factor);
1967 m_gridfont.SetColor(GridColor);
1972 LLBBox llbbox = vp.GetBBox();
1973 nlat = llbbox.GetMaxLat();
1974 slat = llbbox.GetMinLat();
1975 elon = llbbox.GetMaxLon();
1976 wlon = llbbox.GetMinLon();
1983 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1984 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1985 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1986 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1987 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1988 vp.m_projection_type == PROJECTION_POLAR ||
1989 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1992 if (straight_latitudes)
1995 latmargin = gridlatMajor / 2;
1997 slat = wxMax(slat, -90 + latmargin);
1998 nlat = wxMin(nlat, 90 - latmargin);
2000 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
2001 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
2005 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
2012 float lon_step = elon - wlon;
2013 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
2015 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2017 s.x = INVALID_COORD;
2018 s.y = INVALID_COORD;
2019 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
2021 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2022 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2030 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
2031 lat += gridlatMinor) {
2034 gldc.DrawLine(0, r.y, 10, r.y,
true);
2035 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
2040 float lat_step = nlat - slat;
2041 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
2043 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2045 s.x = INVALID_COORD;
2046 s.y = INVALID_COORD;
2047 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
2049 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2050 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2058 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
2059 lon += gridlonMinor) {
2062 gldc.DrawLine(r.x, 0, r.x, 10,
false);
2063 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
2069 glEnable(GL_TEXTURE_2D);
2071 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2072 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
2075 CalcGridText(lat, gridlatMajor,
true);
2077 m_gridfont.GetTextExtent(st, 0, &iy);
2079 if (straight_latitudes) {
2084 float x = 0, y = -1;
2085 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
2086 if (y < 0 || y > h) {
2088 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
2091 m_gridfont.RenderString(st, x, y);
2095 double y1, y2, lat1, lon1, lat2, lon2;
2104 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2107 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2109 if (fabs(y - y1) < fabs(y - y2))
2115 error = fabs(r.m_x);
2116 if (--maxiters == 0)
break;
2117 }
while (error > 1 && error < lasterror);
2119 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2125 m_gridfont.RenderString(st, r.m_x, r.m_y);
2129 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2130 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2139 else if (xlon <= -180.0)
2142 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2144 m_gridfont.GetTextExtent(st, &ix, 0);
2146 if (straight_longitudes) {
2147 float x = -1, y = 0;
2148 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2149 if (x < 0 || x > w) {
2151 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2154 m_gridfont.RenderString(st, x, y);
2158 double x1, x2, lat1, lon1, lat2, lon2;
2166 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2169 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2171 if (fabs(x - x1) < fabs(x - x2))
2177 error = fabs(r.m_y);
2178 }
while (error > 1 && error < lasterror);
2180 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2185 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2187 m_gridfont.RenderString(st, r.m_x, r.m_y);
2191 glDisable(GL_TEXTURE_2D);
2192 glDisable(GL_BLEND);
2197 if (!emboss)
return;
2199 int w = emboss->width, h = emboss->height;
2201 glEnable(GL_TEXTURE_2D);
2204 if (!emboss->gltexind) {
2206 emboss->glwidth = NextPow2(emboss->width);
2207 emboss->glheight = NextPow2(emboss->height);
2210 int size = emboss->glwidth * emboss->glheight;
2211 char *data =
new char[2 * size];
2212 for (
int i = 0; i < h; i++) {
2213 for (
int j = 0; j < emboss->glwidth; j++) {
2215 data[2 * ((i * emboss->glwidth) + j)] =
2216 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2217 data[2 * ((i * emboss->glwidth) + j) + 1] =
2218 (char)abs((emboss->pmap[(i * w) + j]));
2223 glGenTextures(1, &emboss->gltexind);
2224 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2225 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2226 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2234 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2238 int x = emboss->x, y = emboss->y;
2240 float wp = (float)w / emboss->glwidth;
2241 float hp = (float)h / emboss->glheight;
2267 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2269 glDisable(GL_BLEND);
2270 glDisable(GL_TEXTURE_2D);
2273void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2274 if (!m_pParentCanvas->GetVP().IsValid())
return;
2275 wxPoint GPSOffsetPixels(0, 0);
2276 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2279 float pCog = std::isnan(gCog) ? 0 : gCog;
2280 float pSog = std::isnan(gSog) ? 0 : gSog;
2284 double shift_dx = 0;
2285 double shift_dy = 0;
2286 if ((!m_pParentCanvas->m_animationActive) && m_pParentCanvas->m_bFollow &&
2287 !m_pParentCanvas->m_MouseDragging) {
2288 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2289 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2290 if (m_pParentCanvas->m_bLookAhead) {
2296 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2297 angle += m_pParentCanvas->GetVPRotation();
2298 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2300 lGPSPoint.m_x -= shift_dx / cos(gLat * PI / 180.);
2301 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2303 lGPSPoint.m_y += shift_dy / cos(gLat * PI / 180.);
2308 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2309 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2316 lShipMidPoint = lGPSPoint;
2320 float icon_hdt = pCog;
2321 if (!std::isnan(gHdt)) icon_hdt = gHdt;
2324 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2328 double osd_head_lat, osd_head_lon;
2329 wxPoint2DDouble osd_head_point;
2331 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2335 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2337 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2338 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2339 icon_rad += (float)PI;
2343 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2347 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2353 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2354 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2355 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2360 float scale_factor = 1.0;
2362 if ((g_ChartScaleFactorExp > 1.0) && (g_OwnShipIconType == 0))
2363 scale_factor = (log(g_ChartScaleFactorExp) + 1.0) * 1.1;
2365 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2366 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2367 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2369 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2371 float nominal_ownship_size_pixels =
2373 nominal_ownship_size_mm);
2375 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2377 wxPen ppSmallScaleShip;
2378 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2380 wxPen(GetGlobalColor(_T (
"URED" )), v / 5, wxPENSTYLE_SOLID);
2383 wxPen(GetGlobalColor(_T (
"YELO1" )), v / 5, wxPENSTYLE_SOLID);
2384 dc.SetPen(ppSmallScaleShip);
2387 wxBrush(GetGlobalColor(_T (
"URED" )), wxBRUSHSTYLE_TRANSPARENT));
2390 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2391 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2392 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2393 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2396 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2397 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2400 int draw_color = SHIP_INVALID;
2401 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2402 draw_color = SHIP_NORMAL;
2403 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2404 draw_color = SHIP_LOWACCURACY;
2412 ownship_color = draw_color;
2414 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2416 glGenTextures(1, &ownship_tex);
2417 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2419 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2420 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2423 if (m_pParentCanvas->m_pos_image_user) {
2424 switch (draw_color) {
2426 image = *m_pParentCanvas->m_pos_image_user_grey;
2429 image = *m_pParentCanvas->m_pos_image_user;
2431 case SHIP_LOWACCURACY:
2432 image = *m_pParentCanvas->m_pos_image_user_yellow;
2436 switch (draw_color) {
2438 image = *m_pParentCanvas->m_pos_image_grey;
2441 image = *m_pParentCanvas->m_pos_image_red;
2443 case SHIP_LOWACCURACY:
2444 image = *m_pParentCanvas->m_pos_image_yellow;
2449 int w = image.GetWidth(), h = image.GetHeight();
2450 int glw = NextPow2(w), glh = NextPow2(h);
2451 ownship_size = wxSize(w, h);
2452 ownship_tex_size = wxSize(glw, glh);
2454 unsigned char *d = image.GetData();
2455 unsigned char *a = image.GetAlpha();
2456 unsigned char *e =
new unsigned char[4 * w * h];
2459 for (
int p = 0; p < w * h; p++) {
2460 e[4 * p + 0] = d[3 * p + 0];
2461 e[4 * p + 1] = d[3 * p + 1];
2462 e[4 * p + 2] = d[3 * p + 2];
2463 e[4 * p + 3] = a[p];
2466 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2467 GL_UNSIGNED_BYTE, 0);
2469 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2475#ifndef USE_ANDROID_GLES2
2476 if (m_pParentCanvas->m_pos_image_user)
2477 glColor4ub(255, 255, 255, 255);
2478 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2479 glColor4ub(255, 0, 0, 255);
2480 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2481 glColor4ub(255, 255, 0, 255);
2483 glColor4ub(128, 128, 128, 255);
2485 float scale_factor_y = 1.0;
2486 float scale_factor_x = 1.0;
2488 int ownShipWidth = 22;
2489 int ownShipLength = 84;
2490 lShipMidPoint = lGPSPoint;
2493 if (g_OwnShipIconType != 0)
2494 m_pParentCanvas->ComputeShipScaleFactor(
2495 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2496 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2501 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2502 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2503 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2507 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2508 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2512 float gps_circle_radius = 3.0;
2514 if (g_OwnShipIconType == 0) {
2516 glEnable(GL_TEXTURE_2D);
2517 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2526 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2527 if (m_pParentCanvas->m_pos_image_user)
2528 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2530 float nominal_ownship_size_mm =
2531 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2533 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2534 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2536 float nominal_ownship_size_pixels =
2537 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2539 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2540 nominal_ownship_size_pixels = wxMax(
2541 20.0, nominal_ownship_size_pixels);
2544 float h = nominal_ownship_size_pixels * scale_factor_y;
2545 float w = nominal_ownship_size_pixels * scale_factor_x *
2546 ownship_size.x / ownship_size.y;
2547 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2548 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2554 gps_circle_radius = w / 5;
2556 float uv[8], coords[8];
2575 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2576 lShipMidPoint.m_x, lShipMidPoint.m_y,
2578 glDisable(GL_TEXTURE_2D);
2579 }
else if (g_OwnShipIconType == 1) {
2581 glEnable(GL_TEXTURE_2D);
2582 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2584 float nominal_ownship_size_pixels_y = 84;
2585 float nominal_ownship_size_pixels_x = 22;
2587 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2588 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2590 float u = (float)ownship_size.x / ownship_tex_size.x,
2591 v = (
float)ownship_size.y / ownship_tex_size.y;
2594 gps_circle_radius = w / 5;
2596 float uv[8], coords[8];
2615 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2616 lShipMidPoint.m_x, lShipMidPoint.m_y,
2619 glDisable(GL_TEXTURE_2D);
2620 }
else if (g_OwnShipIconType == 2) {
2628 wxPoint shipPoints[6];
2630 wxColour colour = m_pParentCanvas->ShipColor();
2631 wxPen ppPen(*wxBLACK, 1);
2632 wxBrush ppBrush(colour);
2634 dc.SetBrush(ppBrush);
2636 shipPoints[0].x = 0 * scale_factor_x;
2637 shipPoints[0].y = -28 * scale_factor_y;
2638 shipPoints[1].x = 11 * scale_factor_x;
2639 shipPoints[1].y = -28 * scale_factor_y;
2640 shipPoints[2].x = 11 * scale_factor_x;
2641 shipPoints[2].y = 42 * scale_factor_y;
2642 shipPoints[3].x = 0 * scale_factor_x;
2643 shipPoints[3].y = 42 * scale_factor_y;
2644 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2647 shipPoints[0].x = 0 * scale_factor_x;
2648 shipPoints[0].y = -42 * scale_factor_y;
2649 shipPoints[1].x = 5 * scale_factor_x;
2650 shipPoints[1].y = -42 * scale_factor_y;
2651 shipPoints[2].x = 11 * scale_factor_x;
2652 shipPoints[2].y = -28 * scale_factor_y;
2653 shipPoints[3].x = 0 * scale_factor_x;
2654 shipPoints[3].y = -28 * scale_factor_y;
2655 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2658 shipPoints[0].x = 0 * scale_factor_x;
2659 shipPoints[0].y = -28 * scale_factor_y;
2660 shipPoints[1].x = -11 * scale_factor_x;
2661 shipPoints[1].y = -28 * scale_factor_y;
2662 shipPoints[2].x = -11 * scale_factor_x;
2663 shipPoints[2].y = 42 * scale_factor_y;
2664 shipPoints[3].x = 0 * scale_factor_x;
2665 shipPoints[3].y = 42 * scale_factor_y;
2666 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2669 shipPoints[0].x = 0 * scale_factor_x;
2670 shipPoints[0].y = -42 * scale_factor_y;
2671 shipPoints[1].x = -5 * scale_factor_x;
2672 shipPoints[1].y = -42 * scale_factor_y;
2673 shipPoints[2].x = -11 * scale_factor_x;
2674 shipPoints[2].y = -28 * scale_factor_y;
2675 shipPoints[3].x = 0 * scale_factor_x;
2676 shipPoints[3].y = -28 * scale_factor_y;
2677 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2681 double p1x = -11 * scale_factor_x;
2682 double p2x = 11 * scale_factor_x;
2686 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2688 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2690 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2692 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2693 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2694 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2698 p1y = -42 * scale_factor_y;
2699 p2y = 42 * scale_factor_y;
2700 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2701 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2702 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2703 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2704 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2705 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2708 img_height = ownShipLength * scale_factor_y;
2711 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2713 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
2715 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"CHWHT" ))));
2717 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2721 glDisable(GL_LINE_SMOOTH);
2722 glDisable(GL_POLYGON_SMOOTH);
2723 glDisable(GL_BLEND);
2726 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2730void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2731 ViewPort &vp = m_pParentCanvas->GetVP();
2736 Route *active_route = g_pRouteMan->GetpActiveRoute();
2745 g_overlayCanvas = m_pParentCanvas;
2747 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
2748 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2754 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2756 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2757 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2759 m_pParentCanvas->AlertDraw(dc);
2761 m_pParentCanvas->RenderVisibleSectorLights(dc);
2763 m_pParentCanvas->RenderRouteLegs(dc);
2764 m_pParentCanvas->RenderShipToActive(dc,
true);
2765 m_pParentCanvas->ScaleBarDraw(dc);
2766 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2767 m_pParentCanvas->extendedSectorLegs);
2769 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2774void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2775 if (m_pParentCanvas->GetPiano()) {
2776 int canvas_height = GetClientSize().y;
2777 canvas_height *= m_displayScale;
2779 m_pParentCanvas->GetPiano()->DrawGL(
2780 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2784void glChartCanvas::DrawQuiting() {
2785#ifndef USE_ANDROID_GLES2
2786 GLubyte pattern[8][8];
2787 for (
int y = 0; y < 8; y++)
2788 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2791 glEnable(GL_TEXTURE_2D);
2792 glBindTexture(GL_TEXTURE_2D, 0);
2794 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2795 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2796 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2798 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2802 float x = GetSize().x, y = GetSize().y;
2803 float u = x / 8, v = y / 8;
2816 glDisable(GL_TEXTURE_2D);
2817 glDisable(GL_BLEND);
2821void glChartCanvas::DrawCloseMessage(wxString msg) {
2822#ifndef USE_ANDROID_GLES2
2826 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2830 texfont.Build(*pfont, 1, 1);
2832 texfont.GetTextExtent(msg, &w, &h);
2834 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2835 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2837 glColor3ub(243, 229, 47);
2841 glVertex2i(xp + w, yp);
2842 glVertex2i(xp + w, yp + h);
2843 glVertex2i(xp, yp + h);
2848 glColor3ub(0, 0, 0);
2849 glEnable(GL_TEXTURE_2D);
2850 texfont.RenderString(msg, xp, yp);
2851 glDisable(GL_TEXTURE_2D);
2852 glDisable(GL_BLEND);
2859static std::list<double *> combine_work_data;
2860static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2861 GLfloat weight[4], GLdouble **dataOut) {
2862 double *vertex =
new double[3];
2863 combine_work_data.push_back(vertex);
2864 memcpy(vertex, coords, 3 * (
sizeof *coords));
2868#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2869void vertexCallbackD_GLSL(GLvoid *vertex) {
2871 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2872 int new_buf_len = s_tess_buf_len + 100;
2873 GLfloat *tmp = s_tess_work_buf;
2876 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2877 if (NULL == s_tess_work_buf) {
2881 s_tess_buf_len = new_buf_len;
2884 GLdouble *pointer = (GLdouble *)vertex;
2886 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2887 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2892void beginCallbackD_GLSL(GLenum mode) {
2893 s_tess_vertex_idx_this = s_tess_vertex_idx;
2898void endCallbackD_GLSL() {
2902 shader->SetUniformMatrix4fv(
"MVMatrix",
2903 (GLfloat *)s_tessVP.vp_matrix_transform);
2905 mat4x4 identityMatrix;
2906 mat4x4_identity(identityMatrix);
2907 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2911 colorv[0] = s_regionColor.Red() / float(256);
2912 colorv[1] = s_regionColor.Green() / float(256);
2913 colorv[2] = s_regionColor.Blue() / float(256);
2914 colorv[3] = s_regionColor.Alpha() / float(256);
2915 shader->SetUniform4fv(
"color", colorv);
2917 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2918 shader->SetAttributePointerf(
"position", bufPt);
2920 glDrawArrays(s_tess_mode, 0, s_nvertex);
2925void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2927void beginCallbackD(GLenum mode) { glBegin(mode); }
2929void endCallbackD() { glEnd(); }
2933void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2934 float lat_dist, lon_dist;
2935 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2937 GLUtesselator *tobj = gluNewTess();
2938 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2940#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2941 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2942 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2943 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2944 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2948 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2949 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2950 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2951 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2954 gluTessNormal(tobj, 0, 0, 1);
2956 gluTessBeginPolygon(tobj, NULL);
2957 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2958 i != region.contours.end(); i++) {
2959 gluTessBeginContour(tobj);
2960 contour_pt l = *i->rbegin();
2962 bool sml_valid =
false;
2963 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2964 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2965 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2966 int splits = wxMax(lat_splits, lon_splits) + 1;
2972 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2973 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2976 for (
int i = 0; i < splits; i++) {
2978 if (i == splits - 1)
2979 lat = j->y, lon = j->x;
2981 double d = (double)(i + 1) / splits;
2982 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2986 if (std::isnan(q.m_x))
continue;
2988 double *p =
new double[6];
2993 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2998 gluTessVertex(tobj, p, p);
2999 combine_work_data.push_back(p);
3003 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
3005 gluTessEndContour(tobj);
3007 gluTessEndPolygon(tobj);
3009 gluDeleteTess(tobj);
3011 for (std::list<double *>::iterator i = combine_work_data.begin();
3012 i != combine_work_data.end(); i++)
3014 combine_work_data.clear();
3019void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
3020 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3022 if (s_b_useStencil) {
3024 glEnable(GL_STENCIL_TEST);
3026 glClear(GL_STENCIL_BUFFER_BIT);
3030 glStencilFunc(GL_ALWAYS, 1, 1);
3031 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
3034#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3038 glEnable(GL_DEPTH_TEST);
3039 glDepthFunc(GL_ALWAYS);
3040 glDepthMask(GL_TRUE);
3042 glClear(GL_DEPTH_BUFFER_BIT);
3055 glTranslatef(0, 0, .5);
3059 s_regionColor = wxColor(0, 0, 0, 255);
3060 DrawRegion(vp, region);
3062 if (s_b_useStencil) {
3065 glStencilFunc(GL_EQUAL, 1, 1);
3066 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3069#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3071 glDepthFunc(GL_GREATER);
3072 glDepthMask(GL_FALSE);
3073 glTranslatef(0, 0, -.5);
3076 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3079void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
3083 if (s_b_useStencil && s_b_useScissorTest) {
3085 if (rect != vp_rect) {
3086 glEnable(GL_SCISSOR_TEST);
3087 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3090#ifndef USE_ANDROID_GLES2
3096void glChartCanvas::DisableClipRegion() {
3097 glDisable(GL_SCISSOR_TEST);
3098 glDisable(GL_STENCIL_TEST);
3099 glDisable(GL_DEPTH_TEST);
3102void glChartCanvas::Invalidate() {
3104 m_cache_vp.Invalidate();
3110 if (!pBSBChart)
return;
3112 if (b_inCompressAllCharts)
3116 wxString key = chart->GetHashKey();
3119 ChartPathHashTexfactType &hash = g_glTextureManager->m_chart_texfactory_hash;
3120 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3123 if (ittf == hash.end()) {
3125 hash[key]->SetHashKey(key);
3128 pTexFact = hash[key];
3129 pTexFact->SetLRUTime(++m_LRUtime);
3134 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3135 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3142 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3143 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3144 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3145 base_level = log(scalefactor) / log(2.0);
3149 if (base_level > g_mipmap_max_level) base_level = g_mipmap_max_level;
3154 glEnable(GL_TEXTURE_2D);
3155#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3156 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3158 glEnableClientState(GL_VERTEX_ARRAY);
3159 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3164 pTexFact->GetCenter(lat, lon);
3165 MultMatrixViewPort(vp, lat, lon);
3169 LLBBox box = region.GetBox();
3172 if (g_memCacheLimit > 0) {
3174 GetMemoryStatus(0, &mem_used);
3177 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3178 for (
int i = 0; i < numtiles; i++) {
3180 if (region.IntersectOut(tile->box)) {
3183 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3184 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3186 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3187 global_color_scheme, mem_used);
3191 coords = tile->m_coords;
3193 coords =
new float[2 * tile->m_ncoords];
3194 for (
int i = 0; i < tile->m_ncoords; i++) {
3196 tile->m_coords[2 * i + 1]);
3197 coords[2 * i + 0] = p.m_x;
3198 coords[2 * i + 1] = p.m_y;
3202#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3203 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3204 m_pParentCanvas->GetpVP());
3207 glDisable(GL_TEXTURE_2D);
3211 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3212 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3213 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3215 if (!texture) glEnable(GL_TEXTURE_2D);
3217 if (!use_norm_vp)
delete[] coords;
3221 glDisable(GL_TEXTURE_2D);
3223#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3224 if (use_norm_vp) glPopMatrix();
3226 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3227 glDisableClientState(GL_VERTEX_ARRAY);
3231void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3233 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3234 m_pParentCanvas->m_pQuilt->IsBusy())
3238 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3247 LLRegion region = vp.GetLLRegion(rect_region);
3249 LLRegion rendered_region;
3255 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3263 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3265 LLRegion get_region = pqp->ActiveRegion;
3266 bool b_rendered =
false;
3268 if (!pqp->b_overlay) {
3269 get_region.Intersect(region);
3270 if (!get_region.Empty()) {
3271 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3274 SetClipRegion(vp, get_region );
3275 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3276 DisableClipRegion();
3279 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3280 SetClipRegion(vp, pqp->ActiveRegion );
3281 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3283 DisableClipRegion();
3286 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3287 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3288 RenderNoDTA(vp, get_region);
3289 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3294 if (Chs57->m_RAZBuilt) {
3295 RenderNoDTA(vp, get_region);
3296 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3297 rect_region, get_region);
3298 DisableClipRegion();
3303 const LLRegion &oregion = get_region;
3304 LLBBox box = oregion.GetBox();
3315 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3318 ViewPort cvp = ClippedViewport(vp, get_region);
3319 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3320 SetClipRegion(cvp, get_region);
3321 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3322 GetGlobalColor(_T (
"LANDA" )),
3323 GetGlobalColor(_T (
"DEPMS" )));
3324 RenderWorldChart(gldc, cvp, srect, world);
3325 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3326 global_color_scheme);
3327 DisableClipRegion();
3334 SetClipRegion(vp, get_region);
3335 RenderNoDTA(vp, get_region);
3336 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3338 DisableClipRegion();
3341 SetClipRegion(vp, get_region);
3342 RenderNoDTA(vp, get_region);
3343 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3345 DisableClipRegion();
3361 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3365 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3366 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3368 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3369 if (pqp->b_Valid && pqp->b_overlay &&
3370 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3371 LLRegion get_region = pqp->ActiveRegion;
3373 get_region.Intersect(region);
3374 if (!get_region.Empty()) {
3377 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3382 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3389 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3394 ViewPort vph = m_pParentCanvas->GetVP();
3395 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3398 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3400 if (!hiregion.Empty()) {
3404 switch (global_color_scheme) {
3405 case GLOBAL_COLOR_SCHEME_DAY:
3408 case GLOBAL_COLOR_SCHEME_DUSK:
3411 case GLOBAL_COLOR_SCHEME_NIGHT:
3419#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3421 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3423 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3426 DrawRegion(vp, hiregion);
3428 glDisable(GL_BLEND);
3433 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3435 if (!hiregion.Empty()) {
3439 switch (global_color_scheme) {
3440 case GLOBAL_COLOR_SCHEME_DAY:
3443 case GLOBAL_COLOR_SCHEME_DUSK:
3446 case GLOBAL_COLOR_SCHEME_NIGHT:
3455#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3457 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3459 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3462 DrawRegion(vp, hiregion);
3464 glDisable(GL_BLEND);
3468 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3471void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3473 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3474 m_pParentCanvas->m_pQuilt->IsBusy())
3478 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3480 LLRegion region = vp.GetLLRegion(rect_region);
3482 LLRegion rendered_region;
3484 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3486 LLRegion get_region = pqp->ActiveRegion;
3488 if (!pqp->b_overlay) {
3489 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3492 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3497 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3504 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3532void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3533 ViewPort &vp = m_pParentCanvas->VPoint;
3541 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3542 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3545 LLRegion chart_region;
3547 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3548 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3549 CHART_FAMILY_RASTER) {
3557 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3558 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3559 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3561 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3565 for (
int i = 1; i < 6; i += 2)
3566 if (fabs(ll[i] - ll[i + 2]) > 180) {
3568 for (
int i = 1; i < 8; i += 2)
3569 if (ll[i] < 0) ll[i] += 360;
3573 chart_region = LLRegion(4, ll);
3576 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3578 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3579 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3580 chart_region = LLRegion(4, ll);
3583 chart_region = vp.b_quilt
3584 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3585 : m_pParentCanvas->m_singleChart->GetValidRegion();
3587 bool world_view =
false;
3589 wxRect rect = upd.GetRect();
3590 LLRegion background_region = vp.GetLLRegion(rect);
3593 background_region.Subtract(chart_region);
3595 if (!background_region.Empty()) {
3596 ViewPort cvp = ClippedViewport(vp, background_region);
3597 SetClipRect(cvp, rect,
false);
3598 RenderWorldChart(dc, cvp, rect, world_view);
3599 DisableClipRegion();
3604 RenderQuiltViewGL(vp, rect_region);
3606 LLRegion region = vp.GetLLRegion(rect_region);
3607 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3608 CHART_FAMILY_RASTER) {
3609 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3610 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3611 *m_pcontext, vp, rect_region, region);
3613 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3614 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3615 CHART_FAMILY_VECTOR) {
3616 chart_region.Intersect(region);
3617 RenderNoDTA(vp, chart_region);
3618 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3619 rect_region, region);
3625void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3627 wxColour color = GetGlobalColor(_T (
"NODTA" ));
3628#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3630 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3632 glColor4ub(163, 180, 183, transparency);
3635 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3639 s_regionColor = color;
3642 DrawRegion(vp, region);
3646void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3649 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3651 glEnable(GL_SCISSOR_TEST);
3652 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3658 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3659#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3661 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3665 colorv[0] = water.Red() / float(256);
3666 colorv[1] = water.Green() / float(256);
3667 colorv[2] = water.Blue() / float(256);
3669 shader->SetUniform4fv(
"color", colorv);
3680 shader->SetAttributePointerf(
"position", pf);
3682 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3692 gShapeBasemap.RenderViewOnDC(dc, vp);
3694 glDisable(GL_SCISSOR_TEST);
3702void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3703 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3705 DrawStaticRoutesTracksAndWaypoints(vp);
3707 DisableClipRegion();
3710void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3712 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3716 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3717 if (!bmp.Ok())
return;
3719 wxImage image = bmp.ConvertToImage();
3720 int w = image.GetWidth(), h = image.GetHeight();
3723 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3724 tex_w = w, tex_h = h;
3726 tex_w = NextPow2(w), tex_h = NextPow2(h);
3728 m_tideTexWidth = tex_w;
3729 m_tideTexHeight = tex_h;
3731 unsigned char *d = image.GetData();
3732 unsigned char *a = image.GetAlpha();
3734 unsigned char mr, mg, mb;
3735 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3737 unsigned char *e =
new unsigned char[4 * w * h];
3739 for (
int y = 0; y < h; y++)
3740 for (
int x = 0; x < w; x++) {
3741 unsigned char r, g, b;
3742 int off = (y * w + x);
3752 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3756 glGenTextures(1, &m_tideTex);
3758 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3759 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3760 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3762 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3763 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3764 GL_UNSIGNED_BYTE, e);
3766 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3767 GL_UNSIGNED_BYTE, 0);
3768 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3777 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3778 glEnable(GL_TEXTURE_2D);
3781#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3783 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
3784 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
3787 if ((type ==
't') || (type ==
'T'))
3792 if (BBox.Contains(lat, lon)) {
3801 scale *= getAndroidDisplayDensity();
3803 double width2 =
scale * m_tideTexWidth / 2;
3804 double height2 =
scale * m_tideTexHeight / 2;
3819 coords[0] = xp - width2;
3820 coords[1] = yp - height2;
3821 coords[2] = xp - width2;
3822 coords[3] = yp + height2;
3823 coords[4] = xp + width2;
3824 coords[5] = yp + height2;
3825 coords[6] = xp + width2;
3826 coords[7] = yp - height2;
3828 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3835 glDisable(GL_TEXTURE_2D);
3836 glDisable(GL_BLEND);
3837 glBindTexture(GL_TEXTURE_2D, 0);
3839 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3842void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3843 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3846void glChartCanvas::SetColorScheme(ColorScheme cs) {
3847 if (!m_bsetup)
return;
3849 glDeleteTextures(1, &m_tideTex);
3850 glDeleteTextures(1, &m_currentTex);
3856void glChartCanvas::RenderGLAlertMessage() {
3857 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3858 wxString msg = m_pParentCanvas->GetAlertString();
3861 m_gldc.SetFont(*pfont);
3865 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3872 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3873 int xp = sbr.x + sbr.width + 5;
3875 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
3876 m_gldc.SetPen(ppPen1);
3877 m_gldc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
3879 m_gldc.DrawRectangle(xp, yp, w, h);
3881 m_gldc.DrawText(msg, xp, yp);
3885unsigned long quiltHash;
3887extern wxLongLong s_t0;
3890void glChartCanvas::Render() {
3891 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3892 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3893 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3898 if (!g_PrintingInProgress)
return;
3901 if (m_binPinch)
return;
3903#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3904 loadShaders(GetCanvasIndex());
3905 configureShaders(m_pParentCanvas->VPoint);
3908#ifdef USE_ANDROID_GLES2
3912 if (m_binPinch)
return;
3921 bool recompose =
false;
3922 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3923 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3924 if (m_pParentCanvas->VPoint.IsValid()) {
3925 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3926 m_pParentCanvas->UpdateCanvasControlBar();
3935 if (sw.GetTime() > 2000) {
3941 s_tess_vertex_idx = 0;
3942 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3943 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3949 m_displayScale = GetContentScaleFactor();
3953 m_last_render_time = wxDateTime::Now().GetTicks();
3957 if (g_GLOptions.m_bTextureCompression &&
3958 !g_GLOptions.m_bTextureCompressionCaching)
3959 g_glTextureManager->ClearJobList();
3963 int gl_width, gl_height;
3964 gl_width = m_pParentCanvas->VPoint.
pix_width;
3965 gl_height = m_pParentCanvas->VPoint.
pix_height;
3968 m_glcanvas_width = gl_width;
3969 m_glcanvas_height = gl_height;
3973 if (gl_height & 1) {
3975 ViewPort *vp = m_pParentCanvas->GetpVP();
3982 ViewPort *vp = m_pParentCanvas->GetpVP();
3990 ViewPort *vp = m_pParentCanvas->GetpVP();
3993 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3996 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
4004 ViewPort VPoint = m_pParentCanvas->VPoint;
4006 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
4007 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
4010#if !defined(USE_ANDROID_GLES2)
4011 glMatrixMode(GL_PROJECTION);
4014 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4015 glMatrixMode(GL_MODELVIEW);
4019 if (s_b_useStencil) {
4020 glEnable(GL_STENCIL_TEST);
4021 glStencilMask(0xff);
4022 glClear(GL_STENCIL_BUFFER_BIT);
4023 glDisable(GL_STENCIL_TEST);
4029 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4030 if (g_GLOptions.m_GLPolygonSmoothing)
4031 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4032 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4039 g_glTextureManager->TextureCrunch(0.8);
4044 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
4045 bool useFBO =
false;
4051 if (m_b_BuiltFBO && !bpost_hilite
4056 bool b_newview =
true;
4057 bool b_full =
false;
4065 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
4069#ifdef USE_ANDROID_GLES2
4070 if (recompose) b_newview =
true;
4082 if (VPoint.b_quilt) {
4083 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
4084 if (!chart) b_full =
true;
4093 bool accelerated_pan =
false;
4103 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4104 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4105 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4107 wxPoint2DDouble c_old =
4110 wxPoint2DDouble c_new =
4114 dy = wxRound(c_new.m_y - c_old.m_y);
4115 dx = wxRound(c_new.m_x - c_old.m_x);
4125 double deltax = c_new.m_x - c_old.m_x;
4126 double deltay = c_new.m_y - c_old.m_y;
4128 bool b_whole_pixel =
true;
4129 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4130 b_whole_pixel =
false;
4132 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4133 abs(dy) < m_cache_tex_y &&
4134 (abs(dx) > 0 || (abs(dy) > 0));
4143 if (m_displayScale > 1) accelerated_pan =
false;
4148 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4151#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4154 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4160 if (b_full) accelerated_pan =
false;
4162 if (accelerated_pan) {
4163 if ((dx != 0) || (dy != 0)) {
4175 if (dy > 0 && dy < gl_height)
4176 update_region.Union(
4177 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4179 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4181 if (dx > 0 && dx < gl_width)
4182 update_region.Union(
4183 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4185 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4187 m_cache_page = !m_cache_page;
4190 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4191 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4203 RenderCharts(m_gldc, update_region);
4207 glDisable(g_texture_rectangle_format);
4212 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4213 glEnable(GL_TEXTURE_2D);
4217 float x1, x2, y1, y2;
4230 float tx1, tx2, ty1, ty2;
4236 tx2 = sx / (float)m_cache_tex_x;
4238 ty2 = sy / (float)m_cache_tex_y;
4255 coords[2] = -dx + sx;
4257 coords[4] = -dx + sx;
4258 coords[5] = dy + sy;
4260 coords[7] = dy + sy;
4263 ptexture_2D_shader_program[GetCanvasIndex()];
4267 shader->SetUniform1i(
"uTex", 0);
4271 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4272 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4273 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4275 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4297 shader->SetAttributePointerf(
"aPos", co1);
4298 shader->SetAttributePointerf(
"aUV", tco1);
4300 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4303 shader->SetUniformMatrix4fv(
"MVMatrix",
4304 (GLfloat *)VPoint.vp_matrix_transform);
4307 glBindTexture(g_texture_rectangle_format, 0);
4309 glDisable(g_texture_rectangle_format);
4317 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4318 g_texture_rectangle_format,
4319 m_cache_tex[!m_cache_page], 0);
4330 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4331 glClearColor(color.Red() / 256., color.Green() / 256.,
4332 color.Blue() / 256., 1.0);
4333 glClear(GL_COLOR_BUFFER_BIT);
4339 RenderCharts(m_gldc, rscreen_region);
4344 m_cache_page = !m_cache_page;
4349 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4360 glMatrixMode(GL_PROJECTION);
4363 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4364 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4366 glMatrixMode(GL_MODELVIEW);
4370 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4371 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4373 glGetIntegerv(GL_VIEWPORT, viewport);
4374 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4375 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4384 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4385 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4386 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4388 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4392 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4393 glEnable(g_texture_rectangle_format);
4395 float tx, ty, tx0, ty0, divx, divy;
4398 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4401 divx = m_cache_tex_x;
4402 divy = m_cache_tex_y;
4405 tx0 = m_fbo_offsetx / divx;
4406 ty0 = m_fbo_offsety / divy;
4407 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4408 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4433 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4434 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4436 glClear(GL_COLOR_BUFFER_BIT);
4438 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4441 glDisable(g_texture_rectangle_format);
4443 m_cache_vp = VPoint;
4444 m_cache_vp.Validate();
4446 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4448 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4452 RenderCharts(m_gldc, screen_region);
4458 RenderS57TextOverlay(VPoint);
4459 RenderMBTilesOverlay(VPoint);
4463 wxRect rt = upd.GetRect();
4464 LLRegion region = VPoint.GetLLRegion(rt);
4465 ViewPort cvp = ClippedViewport(VPoint, region);
4466 DrawGroundedOverlayObjects(gldc, cvp);
4469 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4470 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4471 LLBBox screenBox = screenLLRegion.GetBox();
4473 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4476 if (m_pParentCanvas->m_bShowTide) {
4477 m_pParentCanvas->RebuildTideSelectList(screenBox);
4478 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4481 if (m_pParentCanvas->m_bShowCurrent) {
4482 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4483 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4489 if (m_pParentCanvas->m_show_focus_bar &&
4490 (g_canvasConfig != 0)) {
4491 if (m_pParentCanvas == wxWindow::FindFocus()) {
4492 g_focusCanvas = m_pParentCanvas;
4494 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
4495 wxPen ppBlue(colour, 1);
4496 wxBrush ppBrush(colour);
4497 gldc.SetPen(ppBlue);
4498 gldc.SetBrush(ppBrush);
4499 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4500 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4501 wxPoint barPoints[4];
4504 barPoints[1].x = xw;
4506 barPoints[2].x = xw;
4507 barPoints[2].y = rect_pix;
4509 barPoints[3].y = rect_pix;
4511 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4515 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4519 DrawFloatingOverlayObjects(m_gldc);
4521#ifndef USE_ANDROID_GLES2
4524 glMatrixMode(GL_PROJECTION);
4527 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4528 glMatrixMode(GL_MODELVIEW);
4533 if (!g_bhide_depth_units)
4534 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4535 if (!g_bhide_overzoom_flag)
4536 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4539 ViewPort &vp = m_pParentCanvas->GetVP();
4540 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4541 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4544 if (!g_PrintingInProgress) {
4545 if (m_pParentCanvas->m_pTrackRolloverWin)
4546 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4548 if (m_pParentCanvas->m_pRouteRolloverWin)
4549 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4551 if (m_pParentCanvas->m_pAISRolloverWin)
4552 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4554 if (m_pParentCanvas->GetMUIBar())
4555 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4557 if (g_MainToolbar && m_pParentCanvas->IsPrimaryCanvas())
4558 g_MainToolbar->DrawGL(gldc, m_displayScale);
4560 if (g_iENCToolbar && m_pParentCanvas->IsPrimaryCanvas())
4561 g_iENCToolbar->DrawGL(gldc, m_displayScale);
4569 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4570 int x, y, width, height;
4571 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4572 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4573 wxBitmap bmp(width, height, -1);
4576 dc.SetBackground(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
4579 dc.SetTextBackground(GetGlobalColor(_T (
"UIBCK" )));
4580 dc.SetTextForeground(GetGlobalColor(_T (
"UITX1" )));
4584 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4585 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4587 wxStringTokenizer tkz(s, _T(
"\n"));
4590 while (tkz.HasMoreTokens()) {
4591 token = tkz.GetNextToken();
4592 dc.DrawText(token, xt, yt);
4595 dc.SelectObject(wxNullBitmap);
4597 m_gldc.DrawBitmap(bmp, x, y,
false);
4603 if (g_bShowChartBar) DrawChartBar(m_gldc);
4605 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4607 m_pParentCanvas->m_Compass->Paint(gldc);
4609 if (m_pParentCanvas->IsPrimaryCanvas()) {
4610 auto ¬eman = NotificationManager::GetInstance();
4611 if (noteman.GetNotificationCount()) {
4612 m_pParentCanvas->m_notification_button->SetIconSeverity(
4613 noteman.GetMaxSeverity());
4614 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4615 m_pParentCanvas->m_notification_button->Show(
true);
4616 m_pParentCanvas->m_notification_button->Paint(gldc);
4618 m_pParentCanvas->m_notification_button->Show(
false);
4621 RenderGLAlertMessage();
4625 ViewPort &vp = m_pParentCanvas->GetVP();
4626 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4627 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4629 glActiveTexture(GL_TEXTURE0);
4633 if (g_bquiting) DrawQuiting();
4634 if (g_bcompression_wait)
4635 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4640 if (g_b_needFinish) glFinish();
4644 g_glTextureManager->TextureCrunch(0.8);
4645 g_glTextureManager->FactoryCrunch(0.6);
4650 m_pParentCanvas->PaintCleanup();
4652 m_bforcefull =
false;
4657void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4660 if (VPoint.b_quilt) {
4661 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4662 ps52plib->GetShowS57Text()) {
4663 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4664 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4669 ChPI->ClearPLIBTextList();
4671 ps52plib->ClearTextList();
4681 RenderQuiltViewGLText(vpx, screen_region);
4686void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4689 LLRegion &screenLLRegion) {
4690 ChartBase *chart = ChartData->OpenChartFromDBAndLock(dbIndex, FULL_INIT);
4694 if (chart == NULL)
return;
4701 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4703 wxFileName tileFile(chart->GetFullPath());
4705 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4707 if (!ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4708 (tileSizeMB.GetLo() > 5000)) {
4711 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4712 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4713 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4720 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4724 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4727 std::vector<int> piano_active_array_tiles =
4728 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4729 bool bfound =
false;
4731 if (std::find(piano_active_array_tiles.begin(),
4732 piano_active_array_tiles.end(),
4733 dbIndex) != piano_active_array_tiles.end()) {
4738 piano_active_array_tiles.push_back(dbIndex);
4739 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4743void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4745 std::vector<int> stackIndexArray =
4746 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4747 unsigned int im = stackIndexArray.size();
4750 if (VPoint.b_quilt && im > 0) {
4751 bool regionVPBuilt =
false;
4753 LLRegion screenLLRegion;
4757 std::vector<int> tiles_to_show;
4758 for (
unsigned int is = 0; is < im; is++) {
4760 ChartData->GetChartTableEntry(stackIndexArray[is]);
4761 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4762 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4764 std::vector<int> piano_active_array_tiles =
4765 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4766 bool bfound =
false;
4768 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4769 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4770 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4778 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4779 piano_active_array_tiles);
4784 tiles_to_show.push_back(stackIndexArray[is]);
4785 if (!regionVPBuilt) {
4788 screenLLRegion = VPoint.GetLLRegion(screen_region);
4789 screenBox = screenLLRegion.GetBox();
4797 regionVPBuilt =
true;
4807 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4808 rit != tiles_to_show.rend(); ++rit) {
4809 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4811 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4812 rit != tiles_to_show.rend(); ++rit) {
4813 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4817 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4819 if (!hiregion.Empty()) {
4823 switch (global_color_scheme) {
4824 case GLOBAL_COLOR_SCHEME_DAY:
4827 case GLOBAL_COLOR_SCHEME_DUSK:
4830 case GLOBAL_COLOR_SCHEME_NIGHT:
4838#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4839 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4841 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4844 DrawRegion(VPoint, hiregion);
4846 glDisable(GL_BLEND);
4852void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4856 GetClientSize(&w, &h);
4858 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4859#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4860 glMatrixMode(GL_PROJECTION);
4863 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4864 glMatrixMode(GL_MODELVIEW);
4868 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4870 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4872 bool world_view =
false;
4873 RenderWorldChart(dc, cvp, rtex, world_view);
4874 gShapeBasemap.RenderViewOnDC(dc, cvp);
4880 glViewport(0, 0, (GLint)w, (GLint)h);
4881#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4882 glMatrixMode(GL_PROJECTION);
4885 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4886 glMatrixMode(GL_MODELVIEW);
4892void glChartCanvas::FastPan(
int dx,
int dy) {
4893#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4897void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4899 SetCurrent(*m_pcontext);
4900 float sx = GetSize().x;
4901 float sy = GetSize().y;
4902 glClear(GL_COLOR_BUFFER_BIT);
4905 GetClientSize(&w, &h);
4907 if (s_b_useStencil) {
4908 glEnable(GL_STENCIL_TEST);
4909 glStencilMask(0xff);
4910 glClear(GL_STENCIL_BUFFER_BIT);
4911 glDisable(GL_STENCIL_TEST);
4927 float sxfactor = sx / swidth;
4928 float syfactor = sy / sheight;
4930 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4931 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4932 sx * sx / swidth * 2, sy * sy / sheight * 2);
4933 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4934 glEnable(g_texture_rectangle_format);
4959 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4960 glBindTexture(g_texture_rectangle_format, 0);
4966 float tx, ty, tx0, ty0;
4976 glBindTexture(g_texture_rectangle_format, 0);
4979 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4980 glEnable(g_texture_rectangle_format);
4986 uv[0] = tx0 / m_cache_tex_x;
4987 uv[1] = ty / m_cache_tex_y;
4988 uv[2] = tx / m_cache_tex_x;
4989 uv[3] = ty / m_cache_tex_y;
4990 uv[4] = tx / m_cache_tex_x;
4991 uv[5] = ty0 / m_cache_tex_y;
4992 uv[6] = tx0 / m_cache_tex_x;
4993 uv[7] = ty0 / m_cache_tex_y;
5005 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
5006 sx * sx / swidth, sy * sy / sheight);
5008 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
5010 glDisable(g_texture_rectangle_format);
5011 glBindTexture(g_texture_rectangle_format, 0);
5018 wxColour color = GetGlobalColor(_T(
"GREY1"));
5019 float ht = -offset_y * (sy / sheight);
5020 wxRect r(0, sy - ht, w, ht);
5021 RenderColorRect(r, color);
5024 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
5025 RenderColorRect(rt, color);
5028 float w1 = -offset_x * sx / swidth;
5029 wxRect rl(0, 0, w1, sy);
5030 RenderColorRect(rl, color);
5033 float px = w1 + sx * sx / swidth;
5034 wxRect rr(px, 0, sx - px, sy);
5035 RenderColorRect(rr, color);
5044void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
5047 if (m_nRun < m_nTotal) {
5048 m_runoffsetx += m_offsetxStep;
5049 if (m_offsetxStep > 0)
5050 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
5052 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
5054 m_runoffsety += m_offsetyStep;
5055 if (m_offsetyStep > 0)
5056 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
5058 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
5060 m_runswidth += m_swidthStep;
5061 if (m_swidthStep > 0)
5062 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
5064 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
5066 m_runsheight += m_sheightStep;
5067 if (m_sheightStep > 0)
5068 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
5070 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
5075 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5081 if (m_zoomFinaldx || m_zoomFinaldy) {
5082 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5085 m_zoomFinal =
false;
5089void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5091 int sx = GetSize().x;
5092 int sy = GetSize().y;
5094 m_lastfbo_offsetx = m_fbo_offsetx;
5095 m_lastfbo_offsety = m_fbo_offsety;
5096 m_lastfbo_swidth = m_fbo_swidth;
5097 m_lastfbo_sheight = m_fbo_sheight;
5099 float curr_fbo_offset_x = m_fbo_offsetx;
5100 float curr_fbo_offset_y = m_fbo_offsety;
5101 float curr_fbo_swidth = m_fbo_swidth;
5102 float curr_fbo_sheight = m_fbo_sheight;
5104 float fx = (float)cp_x / sx;
5105 float fy = 1.0 - (float)cp_y / sy;
5107 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5108 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5110 m_fbo_swidth = curr_fbo_swidth / factor;
5111 m_fbo_sheight = curr_fbo_sheight / factor;
5113 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5114 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5116 m_fbo_offsetx += post_x;
5117 m_fbo_offsety += post_y;
5128 float perStep = m_nStep / m_nTotal;
5130 if (zoomTimer.IsRunning()) {
5131 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5132 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5133 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5134 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5137 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5138 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5139 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5140 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5142 m_runoffsetx = m_lastfbo_offsetx;
5143 m_runoffsety = m_lastfbo_offsety;
5144 m_runswidth = m_lastfbo_swidth;
5145 m_runsheight = m_lastfbo_sheight;
5148 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5149 m_zoomFinal =
false;
5155void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5159 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5162 if (m_binPinch)
return;
5163 if (m_bpinchGuard)
return;
5165 int x =
event.GetOffset().x;
5166 int y =
event.GetOffset().y;
5168 int lx =
event.GetLastOffset().x;
5169 int ly =
event.GetLastOffset().y;
5174 switch (event.GetState()) {
5175 case GestureStarted:
5176 if (m_binPan)
break;
5180 m_binGesture =
true;
5184 case GestureUpdated:
5189 m_pParentCanvas->FreezePiano();
5191 m_pParentCanvas->ThawPiano();
5202 case GestureFinished:
5205 m_pParentCanvas->UpdateCanvasControlBar();
5208 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5212 case GestureCanceled:
5214 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5221 m_bgestureGuard =
true;
5222 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5223 m_bforcefull =
false;
5228float zoom_inc = 1.0;
5229bool first_zout =
false;
5231void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5232 float zoom_gain = 1.0;
5233 float zout_gain = 1.0;
5236 float total_zoom_val;
5238 float max_zoom_scale = 1000.;
5239 float min_zoom_scale = 2e8;
5241 if (event.GetScaleFactor() > 1)
5242 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5244 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5246 if (event.GetTotalScaleFactor() > 1)
5247 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5250 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5252 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5255 float max_zoom_scale = 1000.;
5256 if( cc1->GetVP().b_quilt) {
5257 int ref_index = cc1->GetQuiltRefChartdbIndex();
5264 float min_zoom_scale = 2e8;
5268 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5270 double projected_scale =
5271 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5273 switch (event.GetState()) {
5274 case GestureStarted:
5279 m_binGesture =
true;
5281 m_pinchStart =
event.GetCenterPoint();
5282 m_lpinchPoint = m_pinchStart;
5285 event.GetCenterPoint().y, m_pinchlat,
5290 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5291 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5294 SetCurrent(*m_pcontext);
5300 case GestureUpdated:
5302 if (projected_scale < min_zoom_scale) {
5303 wxPoint pinchPoint =
event.GetCenterPoint();
5305 float dx = pinchPoint.x - m_lpinchPoint.x;
5306 float dy = pinchPoint.y - m_lpinchPoint.y;
5308 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5309 -dx / total_zoom_val, dy / total_zoom_val);
5311 m_lpinchPoint = pinchPoint;
5315 if (1 || ((total_zoom_val > 1) && !first_zout)) {
5316 wxPoint pinchPoint =
event.GetCenterPoint();
5318 float dx = pinchPoint.x - m_lpinchPoint.x;
5319 float dy = pinchPoint.y - m_lpinchPoint.y;
5321 if ((projected_scale > max_zoom_scale) &&
5322 (projected_scale < min_zoom_scale))
5323 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5324 -dx / total_zoom_val, dy / total_zoom_val);
5326 m_lpinchPoint = pinchPoint;
5330 zoom_inc *= zoom_val;
5331 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5332 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5336 wxPoint pinchPoint =
event.GetCenterPoint();
5337 float dx = pinchPoint.x - m_lpinchPoint.x;
5338 float dy = pinchPoint.y - m_lpinchPoint.y;
5340 m_lpinchPoint = pinchPoint;
5351 case GestureFinished: {
5355 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5356 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5360 float tzoom = total_zoom_val;
5362 if (projected_scale >= min_zoom_scale)
5363 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5365 if (projected_scale < max_zoom_scale)
5366 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5368 dx = (cc_x - m_cc_x) * tzoom;
5369 dy = -(cc_y - m_cc_y) * tzoom;
5371 if (zoomTimer.IsRunning()) {
5374 m_zoomFinalZoom = tzoom;
5380 double final_projected_scale =
5384 if (final_projected_scale < min_zoom_scale) {
5388 m_pParentCanvas->m_pQuilt->Invalidate();
5389 m_bforcefull =
true;
5396 m_pParentCanvas->m_pQuilt->Invalidate();
5397 m_bforcefull =
true;
5409 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5413 case GestureCanceled:
5415 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5422 m_bgestureGuard =
true;
5424 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5427void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5437 m_bgestureGuard =
false;
5438 m_bpinchGuard =
false;
5439 m_binGesture =
false;
5440 m_bforcefull =
false;
5443void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5447 m_binGesture =
false;
5448 m_bforcefull =
false;
5452#ifdef HAVE_WX_GESTURE_EVENTS
5454void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5458 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5461 if (m_binPinch)
return;
5462 if (m_bpinchGuard)
return;
5464 int dx =
event.GetDelta().x;
5465 int dy =
event.GetDelta().y;
5467 if (event.IsGestureStart()) {
5468 if (m_binPan)
return;
5472 m_binGesture =
true;
5476 else if (event.IsGestureEnd()) {
5478 m_pParentCanvas->UpdateCanvasControlBar();
5480 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5488 m_pParentCanvas->FreezePiano();
5490 m_pParentCanvas->ThawPiano();
5501 m_bgestureGuard =
true;
5502 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5503 m_bforcefull =
false;
5506bool first_zout =
false;
5509void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5510 float zoom_gain = 1.0;
5511 float zout_gain = 1.0;
5513 float last_zoom_val = m_total_zoom_val;
5515 float max_zoom_scale = 1000.;
5516 float min_zoom_scale = 2e8;
5518 if (event.GetZoomFactor() > 1)
5519 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5521 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5523 float inc_zoom_val =
5524 m_total_zoom_val / last_zoom_val;
5526 double projected_scale =
5527 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5529 if (event.IsGestureStart()) {
5535 m_binGesture =
true;
5536 m_pinchStart =
event.GetPosition();
5537 m_lpinchPoint = m_pinchStart;
5538 m_total_zoom_val = 1.0;
5539 m_final_zoom_val = 1.0;
5542 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5546 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5547 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5550 SetCurrent(*m_pcontext);
5553 ViewPort vpr = m_pParentCanvas->VPoint;
5555 GetTouchBackingBitmap(vpr);
5560 if (event.IsGestureEnd()) {
5566 if (!m_binGesture)
return;
5568 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5569 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5573 float tzoom = m_final_zoom_val;
5575 dx = (cc_x - m_cc_x) * tzoom;
5576 dy = -(cc_y - m_cc_y) * tzoom;
5578 if (zoomTimer.IsRunning()) {
5581 m_zoomFinalZoom = tzoom;
5587 double final_projected_scale =
5591 if (final_projected_scale < min_zoom_scale) {
5595 m_pParentCanvas->m_pQuilt->Invalidate();
5596 m_bforcefull =
true;
5603 m_pParentCanvas->m_pQuilt->Invalidate();
5604 m_bforcefull =
true;
5609 m_final_zoom_val = 1.0;
5610 m_total_zoom_val = 1.0;
5611 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5616 if (projected_scale < min_zoom_scale) {
5617 wxPoint pinchPoint =
event.GetPosition();
5619 float dx = pinchPoint.x - m_lpinchPoint.x;
5620 float dy = pinchPoint.y - m_lpinchPoint.y;
5622 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5623 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5625 m_lpinchPoint = pinchPoint;
5626 m_final_zoom_val *= inc_zoom_val;
5630 if (1 || ((m_total_zoom_val > 1) && !first_zout)) {
5631 wxPoint pinchPoint =
event.GetPosition();
5633 float dx = pinchPoint.x - m_lpinchPoint.x;
5634 float dy = pinchPoint.y - m_lpinchPoint.y;
5636 if ((projected_scale > max_zoom_scale) &&
5637 (projected_scale < min_zoom_scale))
5638 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5639 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5641 m_lpinchPoint = pinchPoint;
5642 m_final_zoom_val *= inc_zoom_val;
5646 m_zoom_inc *= inc_zoom_val;
5647 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5648 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5652 wxPoint pinchPoint =
event.GetPosition();
5653 float dx = pinchPoint.x - m_lpinchPoint.x;
5654 float dy = pinchPoint.y - m_lpinchPoint.y;
5656 m_lpinchPoint = pinchPoint;
5660 m_bgestureGuard =
true;
5661 m_bpinchGuard =
true;
5662 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5665void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5675 m_bgestureGuard =
false;
5676 m_bpinchGuard =
false;
5677 m_binGesture =
false;
5678 m_bforcefull =
false;
5681void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5685 m_binGesture =
false;
5686 m_bforcefull =
false;
5692void glChartCanvas::configureShaders(
ViewPort &vp) {
5693#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5699 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5701 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5702 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5723 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5725 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5726 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5738 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5740 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5741 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5744 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5746 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5747 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5755 shader = pAALine_shader_program[GetCanvasIndex()];
5757 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5760 shader = pring_shader_program[GetCanvasIndex()];
5762 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5763 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5767 if (texture_2DA_shader_program) {
5768 glUseProgram(texture_2DA_shader_program);
5769 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5770 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5771 (
const GLfloat *)pvp->vp_matrix_transform);
5773 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5774 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5782void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5785#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5786 int nl = nVertex / 4;
5788 float *luv = uvCoords;
5791 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5799 glEnableClientState(GL_VERTEX_ARRAY);
5800 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5802 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5803 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5804 glDrawArrays(GL_QUADS, 0, 4);
5811void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5812 float *uvCoords,
ViewPort *vp,
float dx,
5813 float dy,
float angle_rad) {
5814#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5816 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5817 if (!shader)
return;
5822 shader->SetUniform1i(
"uTex", 0);
5827 mat4x4_rotate_Z(Q, I, angle_rad);
5833 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5838 shader->SetAttributePointerf(
"aPos", co1);
5839 shader->SetAttributePointerf(
"aUV", tco1);
5846 GLushort indices1[] = {0,1,3,2};
5847 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5859 tco1[0] = uvCoords[0];
5860 tco1[1] = uvCoords[1];
5861 tco1[2] = uvCoords[2];
5862 tco1[3] = uvCoords[3];
5863 tco1[4] = uvCoords[6];
5864 tco1[5] = uvCoords[7];
5865 tco1[6] = uvCoords[4];
5866 tco1[7] = uvCoords[5];
5871 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5883void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5884#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5886 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5889 shader->SetUniformMatrix4fv(
5890 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5893 colorv[0] = color.Red() / float(256);
5894 colorv[1] = color.Green() / float(256);
5895 colorv[2] = color.Blue() / float(256);
5897 shader->SetUniform4fv(
"color", colorv);
5900 pf[0] = r.x + r.width;
5904 pf[4] = r.x + r.width;
5905 pf[5] = r.y + r.height;
5907 pf[7] = r.y + r.height;
5908 shader->SetAttributePointerf(
"position", pf);
5910 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5918void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5919#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5921 ViewPort VPoint = m_pParentCanvas->VPoint;
5925 GetClientSize(&w, &h);
5926 int sx = GetSize().x;
5927 int sy = GetSize().y;
5931 glViewport(0, 0, (GLint)w, (GLint)h);
5933 if (s_b_useStencil) {
5934 glEnable(GL_STENCIL_TEST);
5935 glStencilMask(0xff);
5936 glClear(GL_STENCIL_BUFFER_BIT);
5937 glDisable(GL_STENCIL_TEST);
5941 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5946 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5947 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5948 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5951 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5953 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5954 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5962 if (bRenderCharts) RenderCharts(gldc, screen_region);
5964 if (bRenderOverlays) {
5965 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5966 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5967 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5968 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5969 DrawFloatingOverlayObjects(m_gldc);
5973 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5978wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5980 wxMemoryDC tdc(tbm);
5981 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5989 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5990 dc.SetPen(*wxTRANSPARENT_PEN);
5992 gShapeBasemap.RenderViewOnDC(dc, tvp);
5993 tdc.SelectObject(wxNullBitmap);
5994 m_touch_backing_bitmap = tbm;
5995 CreateBackingTexture();
5997 return m_touch_backing_bitmap;
6000void glChartCanvas::CreateBackingTexture() {
6001 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6002 unsigned char *imgdata = image.GetData();
6003 unsigned char *imgalpha = image.GetAlpha();
6004 m_tex_w = image.GetWidth();
6005 m_tex_h = image.GetHeight();
6006 m_image_width = m_tex_w;
6007 m_image_height = m_tex_h;
6009 GLuint format = GL_RGBA;
6010 GLuint internalformat = g_texture_rectangle_format;
6012 internalformat = GL_RGBA;
6017 unsigned char *teximage =
6018 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6020 for (
int i = 0; i < m_image_height; i++) {
6021 for (
int j = 0; j < m_image_width; j++) {
6022 int s = (i * 3 * m_image_width) + (j * 3);
6023 int d = (i * stride * m_tex_w) + (j * stride);
6025 teximage[d + 0] = imgdata[s + 0];
6026 teximage[d + 1] = imgdata[s + 1];
6027 teximage[d + 2] = imgdata[s + 2];
6028 teximage[d + 3] = 255;
6032 glGenTextures(1, &m_TouchBackingTexture);
6033 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6035 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6036 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6037 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6039 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6041 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6042 GL_UNSIGNED_BYTE, teximage);
6045 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.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
Tools to send data to plugins.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents an entry in the chart table, containing information about a single chart.