40#include <wx/dcmemory.h>
41#include <wx/dynarray.h>
45#include <wx/glcanvas.h>
47#include <wx/jsonval.h>
50#include <wx/progdlg.h>
51#include <wx/stopwatch.h>
53#include <wx/tokenzr.h>
84#include "mipmap/mipmap.h"
96#include "s57_ocpn_utils.h"
106#ifdef USE_ANDROID_GLES2
107#include <GLES2/gl2.h>
113#include "androidUTIL.h"
114#elif defined(__WXQT__) || defined(__WXGTK__)
118#ifndef GL_ETC1_RGB8_OES
119#define GL_ETC1_RGB8_OES 0x8D64
122#ifndef GL_DEPTH_STENCIL_ATTACHMENT
123#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
127#define printf printf2
128int __cdecl printf2(
const char *format, ...);
131#if defined(__ANDROID__)
132#include "androidUTIL.h"
133#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
140extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
141 float near,
float far);
142#define glOrtho(a, b, c, d, e, f) \
144 glOrthof(a, b, c, d, e, f);
148#ifdef USE_ANDROID_GLES2
149#include <GLES2/gl2.h>
152#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
158#if defined(__UNIX__) && !defined(__WXOSX__)
163 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
167 clock_gettime(CLOCK_REALTIME, &tp_end);
168 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
169 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
182static bool g_b_needFinish;
184static wxColor s_regionColor;
185static float g_GLMinCartographicLineWidth;
191#define APIENTRYP APIENTRY *
197#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
198#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
204PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
205PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
206PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
207PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
208PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
209PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
210PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
211PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
212PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
213PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
215PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
216PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
219PFNGLGENBUFFERSPROC s_glGenBuffers;
220PFNGLBINDBUFFERPROC s_glBindBuffer;
221PFNGLBUFFERDATAPROC s_glBufferData;
222PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
224#ifndef USE_ANDROID_GLES2
229typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
231PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
234static int panx, pany;
238#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
239static int s_tess_vertex_idx;
240static int s_tess_vertex_idx_this;
241static int s_tess_buf_len;
242static GLfloat *s_tess_work_buf;
243static GLenum s_tess_mode;
248bool glChartCanvas::s_b_useScissorTest;
249bool glChartCanvas::s_b_useStencil;
250bool glChartCanvas::s_b_useStencilAP;
251bool glChartCanvas::s_b_useFBO;
258 while ( upd.HaveRects() )
260 wxRect rect = upd.GetRect();
261 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
268GLboolean QueryExtension(
const char *extName) {
279 extNameLen = strlen(extName);
281 p = (
char *)glGetString(GL_EXTENSIONS);
289 int n = strcspn(p,
" ");
290 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
298int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
299 16, WX_GL_STENCIL_SIZE, 8,
302glTestCanvas::glTestCanvas(wxWindow *parent)
303 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
307int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
308 16, WX_GL_STENCIL_SIZE, 8,
311EVT_PAINT(glChartCanvas::OnPaint)
312EVT_ACTIVATE(glChartCanvas::OnActivate)
313EVT_SIZE(glChartCanvas::OnSize)
314EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
318 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
319 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
322 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
327std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
329 {wxPENSTYLE_DOT, {1, 1}},
330 {wxPENSTYLE_LONG_DASH, {5, 5}},
331 {wxPENSTYLE_SHORT_DASH, {1, 5}},
332 {wxPENSTYLE_DOT_DASH, {5, 1}},
335void glChartCanvas::Init() {
340 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
342 m_cache_current_ch = NULL;
344 m_b_paint_enable =
true;
345 m_in_glpaint =
false;
347 m_cache_tex[0] = m_cache_tex[1] = 0;
350 m_b_BuiltFBO =
false;
351 m_b_DisableFBO =
false;
360 m_bpinchGuard =
false;
361 m_binGesture =
false;
362 m_first_zout =
false;
366 m_last_render_time = -1;
373 m_gldc.SetGLCanvas(
this);
376 m_displayScale = 1.0;
377#if defined(__WXOSX__) || defined(__WXGTK3__)
379 m_displayScale = GetContentScaleFactor();
388 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
392 wxEVT_QT_PINCHGESTURE,
393 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
396 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
401 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
403 onGestureFinishTimerEvent,
407 ZOOM_TIMER, wxEVT_TIMER,
408 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
411 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
412 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
413 zoomTimer.SetOwner(
this, ZOOM_TIMER);
415#ifdef USE_ANDROID_GLES2
424#ifdef HAVE_WX_GESTURE_EVENTS
426 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
431 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
433 onGestureFinishTimerEvent,
437 ZOOM_TIMER, wxEVT_TIMER,
438 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
441 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
442 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
443 zoomTimer.SetOwner(
this, ZOOM_TIMER);
448 m_bgestureGuard =
false;
449 m_total_zoom_val = 1.0;
450 m_step_zoom_val = 1.0;
453#ifdef HAVE_WX_GESTURE_EVENTS
454 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
455 wxLogError(
"Failed to enable touch events");
464 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
466 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
467 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
469 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
470 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
472 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
473 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
475 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
476 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
482glChartCanvas::~glChartCanvas() {
488void glChartCanvas::FlushFBO() {
489 if (m_bsetup) BuildFBO();
492void glChartCanvas::OnActivate(wxActivateEvent &event) {
493 m_pParentCanvas->OnActivate(event);
496void glChartCanvas::OnSize(wxSizeEvent &event) {
500 wxLogMessage(
"Got OnSize event while NOT running");
502 qDebug() <<
"OnSizeB";
509 if (!IsShown())
return;
511 SetCurrent(*m_pcontext);
515 SetSize(GetSize().x, GetSize().y);
523 if (m_bsetup && m_pcontext && IsShown()) {
524 SetCurrent(*m_pcontext);
530 wxLogMessage(
"BuildFBO 3");
535 ViewPort *vp = m_pParentCanvas->GetpVP();
538 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
541 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
545void glChartCanvas::MouseEvent(wxMouseEvent &event) {
546 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
552 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
554 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
557 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
561 if (m_bgestureGuard) {
562 m_pParentCanvas->r_rband.x = 0;
572 if (event.LeftUp()) {
574 if ((abs(panx) > 2) || (abs(pany) > 2)) {
577 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
584 if (!event.LeftDClick()) {
589 if (m_binPan && event.RightDown()) {
590 qDebug() <<
"Skip right on pan";
593 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
595 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
596 if (!m_bgestureGuard)
606#ifndef GL_MAX_RENDERBUFFER_SIZE
607#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
610#ifndef USE_ANDROID_GLES2
611bool glChartCanvas::buildFBOSize(
int fboSize) {
613 if (IsShown()) SetCurrent(*m_pcontext);
616 glDeleteTextures(2, m_cache_tex);
617 glDeleteFramebuffers(1, &m_fb0);
618 glDeleteRenderbuffers(1, &m_renderbuffer);
619 m_b_BuiltFBO =
false;
622 if (m_b_DisableFBO)
return false;
626 int rb_x = GetSize().x;
627 int rb_y = GetSize().y;
629 while (i < rb_x) i <<= 1;
633 while (i < rb_y) i <<= 1;
636 m_cache_tex_x = wxMax(rb_x, rb_y);
637 m_cache_tex_y = wxMax(rb_x, rb_y);
640 m_cache_tex_x = GetSize().x * m_displayScale;
641 m_cache_tex_y = GetSize().y * m_displayScale;
644 int err = GL_NO_ERROR;
646 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
649 if (err == GL_INVALID_ENUM) {
650 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
654 if (err == GL_NO_ERROR) {
655 if (fboSize > params) {
657 " OpenGL-> Requested Framebuffer size exceeds "
658 "GL_MAX_RENDERBUFFER_SIZE");
663 glGenFramebuffers(1, &m_fb0);
667 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
672 glGenRenderbuffers(1, &m_renderbuffer);
676 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
681 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
685 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
691 glGenTextures(2, m_cache_tex);
692 for (
int i = 0; i < 2; i++) {
693 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
694 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
696 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
698 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
699 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
702 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
704 if (m_b_useFBOStencil) {
706 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
707 m_cache_tex_x, m_cache_tex_y);
709 int err = glGetError();
712 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
716 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
717 GL_RENDERBUFFER_EXT, m_renderbuffer);
721 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
726 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
727 GL_RENDERBUFFER_EXT, m_renderbuffer);
731 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
737 GLenum depth_format = GL_DEPTH_COMPONENT24;
742 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
746 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
748 int err = glGetError();
751 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
757 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
758 GL_RENDERBUFFER_EXT, m_renderbuffer);
763 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
770 glBindTexture(GL_TEXTURE_2D, 0);
771 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
774 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
776 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
777 g_texture_rectangle_format, m_cache_tex[0], 0);
779 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
781 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
783 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
785 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
795#ifdef USE_ANDROID_GLES2
796bool glChartCanvas::buildFBOSize(
int fboSize) {
800 int rb_x = GetSize().x;
801 int rb_y = GetSize().y;
803 while (i < rb_x) i <<= 1;
807 while (i < rb_y) i <<= 1;
810 m_cache_tex_x = wxMax(rb_x, rb_y);
811 m_cache_tex_y = wxMax(rb_x, rb_y);
815 int err = GL_NO_ERROR;
817 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
820 if (err == GL_INVALID_ENUM) {
821 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
825 if (err == GL_NO_ERROR) {
826 if (fboSize > params) {
828 " OpenGL-> Requested Framebuffer size exceeds "
829 "GL_MAX_RENDERBUFFER_SIZE");
834 glGenFramebuffers(1, &m_fb0);
838 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
843 glGenRenderbuffers(1, &m_renderbuffer);
847 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
852 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
856 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
862 glGenTextures(2, m_cache_tex);
863 for (
int i = 0; i < 2; i++) {
864 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
865 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
867 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
869 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
870 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
873 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
876 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
882 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
886 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
887 GL_RENDERBUFFER, m_renderbuffer);
891 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
896 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
897 GL_RENDERBUFFER, m_renderbuffer);
901 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
906 glBindTexture(GL_TEXTURE_2D, 0);
907 glBindFramebuffer(GL_FRAMEBUFFER, 0);
910 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
912 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
913 g_texture_rectangle_format, m_cache_tex[0], 0);
915 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
917 glBindFramebuffer(GL_FRAMEBUFFER, 0);
919 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
921 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
931void glChartCanvas::BuildFBO() {
934 glDeleteTextures(2, m_cache_tex);
935 glDeleteFramebuffers(1, &m_fb0);
936 glDeleteRenderbuffers(1, &m_renderbuffer);
937 m_b_BuiltFBO =
false;
940 if (m_b_DisableFBO)
return;
943 int gl_width, gl_height;
944 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
945 int initialSize = NextPow2(gl_width * m_displayScale);
950 wxString info = androidGetDeviceInfo();
952 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
955 if (!buildFBOSize(initialSize)) {
956 glDeleteTextures(2, m_cache_tex);
957 glDeleteFramebuffers(1, &m_fb0);
958 glDeleteRenderbuffers(1, &m_renderbuffer);
960 if (!buildFBOSize(1024)) {
961 wxLogMessage(
"BuildFBO C");
963 m_b_DisableFBO =
true;
964 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
965 m_b_BuiltFBO =
false;
974 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
986void glChartCanvas::SetupOpenGL() {
987 if (IsShown()) SetCurrent(*m_pcontext);
989 char *str = (
char *)glGetString(GL_RENDERER);
992 wxLogMessage(
"Failed to initialize OpenGL");
996 char render_string[80];
997 strncpy(render_string, str, 79);
998 m_renderer = wxString(render_string, wxConvUTF8);
1001 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1002 msg.Printf(
"OpenGL-> Renderer String: ");
1006 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1008 char version_string[80];
1009 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1010 msg.Printf(
"OpenGL-> Version reported: ");
1011 m_version = wxString(version_string, wxConvUTF8);
1015 char GLSL_version_string[80];
1016 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1018 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1019 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1020 msg += m_GLSLversion;
1025 GLenum err = glewInit();
1026#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1027 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1032 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1035 wxLogMessage(
"GLEW init success!n");
1040 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1041 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1045#ifndef USE_ANDROID_GLES2
1046 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1048 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1050 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1051 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1058 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1060 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1062 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1065 s_b_useScissorTest =
true;
1067 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1068 s_b_useScissorTest =
false;
1070 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1071 s_b_useScissorTest =
false;
1073 bool bad_stencil_code =
false;
1076 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1077 bad_stencil_code =
true;
1080 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1083 glEnable(GL_STENCIL_TEST);
1084 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1086 glGetIntegerv(GL_STENCIL_BITS, &sb);
1089 glDisable(GL_STENCIL_TEST);
1091 s_b_useStencil =
false;
1092 if (stencil && (sb == 8)) s_b_useStencil =
true;
1094 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1095 g_texture_rectangle_format = GL_TEXTURE_2D;
1096 else if (QueryExtension(
"GL_OES_texture_npot"))
1097 g_texture_rectangle_format = GL_TEXTURE_2D;
1098 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1099 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1100 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1101 g_texture_rectangle_format));
1104 g_texture_rectangle_format = GL_TEXTURE_2D;
1108 g_b_EnableVBO =
true;
1111 g_b_EnableVBO =
false;
1115 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1117 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1121 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1123 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1126#ifndef USE_ANDROID_GLES2
1128 if (bad_stencil_code) s_b_useStencil =
false;
1142 if (m_displayScale > 1) m_b_DisableFBO =
true;
1151 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1153 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1154 g_texture_rectangle_format, m_cache_tex[0], 0);
1156 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1157 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1159 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1161 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1163 m_b_DisableFBO =
true;
1169 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1173 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1175#ifdef USE_ANDROID_GLES2
1176 s_b_useStencilAP = s_b_useStencil;
1183 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1185 if (m_b_useFBOStencil)
1186 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1188 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1190 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1193 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1195 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1197 if (s_b_useScissorTest && s_b_useStencil)
1198 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1201 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1203 MipMap_ResolveRoutines();
1207 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1208 g_GLMinCartographicLineWidth);
1209 wxLogMessage(lwmsg);
1210 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1211 g_GLMinSymbolLineWidth);
1212 wxLogMessage(lwmsg);
1215 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1217#ifdef USE_ANDROID_GLES2
1218 g_GLOptions.m_bUseAcceleratedPanning =
true;
1224 int tex_dim = g_GLOptions.m_iTextureDimension;
1225 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1234 s_b_useFBO = m_b_BuiltFBO;
1238 ps52plib->SetGLOptions(
1239 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1240 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1241 g_GLMinSymbolLineWidth);
1245 SendJSONConfigMessage();
1248void glChartCanvas::SendJSONConfigMessage() {
1251 v[
"setupComplete"] = m_bsetup;
1252 v[
"useStencil"] = s_b_useStencil;
1253 v[
"useStencilAP"] = s_b_useStencilAP;
1254 v[
"useScissorTest"] = s_b_useScissorTest;
1255 v[
"useFBO"] = s_b_useFBO;
1256 v[
"useVBO"] = g_b_EnableVBO;
1257 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1258 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1259 SendJSONMessageToAllPlugins(msg_id, v);
1262void glChartCanvas::SetupCompression() {
1263 int dim = g_GLOptions.m_iTextureDimension;
1266 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1267 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1268 goto no_compression;
1272 g_uncompressed_tile_size = dim * dim * 4;
1273 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1279 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1282 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1292 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1293 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1296 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1297 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1302 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1303 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1306 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1308 wxLogMessage(
"OpenGL-> No Useable compression format found");
1309 goto no_compression;
1314 g_tile_size = 512 * 512 / 2;
1318 glGenTextures(1, &texture);
1319 glBindTexture(GL_TEXTURE_2D, texture);
1321 GL_UNSIGNED_BYTE, NULL);
1322 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1324 glDeleteTextures(1, &texture);
1328 if (g_tile_size == 0)
goto no_compression;
1330 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1332 g_uncompressed_tile_size / g_tile_size));
1336 g_GLOptions.m_bTextureCompression =
false;
1338 g_tile_size = g_uncompressed_tile_size;
1339 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1342void glChartCanvas::OnPaint(wxPaintEvent &event) {
1344 if (!m_pcontext)
return;
1352 if (IsShown()) SetCurrent(*m_pcontext);
1357 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1365 if (!m_b_paint_enable)
return;
1368 if (m_in_glpaint)
return;
1371 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1394bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1396#ifndef USE_ANDROID_GLES2
1397 return vp.m_projection_type == PROJECTION_MERCATOR ||
1398 vp.m_projection_type == PROJECTION_POLAR ||
1399 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1413#define NORM_FACTOR 4096.0
1414void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1415#ifndef USE_ANDROID_GLES2
1417 wxPoint2DDouble point;
1419 switch (vp.m_projection_type) {
1420 case PROJECTION_MERCATOR:
1421 case PROJECTION_EQUIRECTANGULAR:
1422 case PROJECTION_WEB_MERCATOR:
1425 glTranslated(point.m_x, point.m_y, 0);
1430 case PROJECTION_POLAR:
1434 glTranslated(point.m_x, point.m_y, 0);
1435 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1442 printf(
"ERROR: Unhandled projection\n");
1447 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1455 switch (vp.m_projection_type) {
1456 case PROJECTION_MERCATOR:
1457 case PROJECTION_EQUIRECTANGULAR:
1458 case PROJECTION_WEB_MERCATOR:
1462 case PROJECTION_POLAR:
1467 printf(
"ERROR: Unhandled projection\n");
1476bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1477 return vp.m_projection_type == PROJECTION_MERCATOR ||
1478 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1479 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1483 const LLRegion ®ion) {
1484 if (!CanClipViewport(vp))
return vp;
1487 LLBBox bbox = region.GetBox();
1489 if (!bbox.GetValid())
return vp;
1497 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1498 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1499 bbox.GetMaxLon() + 360);
1500 cvp.SetBBoxDirect(bbox);
1501 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1502 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1503 bbox.GetMaxLon() - 360);
1504 cvp.SetBBoxDirect(bbox);
1506 cvp.SetBBoxDirect(bbox);
1511void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1512 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1518 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1520 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1524 if (!pRouteDraw)
continue;
1527 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1530 if (pRouteDraw->m_bIsBeingEdited)
continue;
1532 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1537 if (vp.GetBBox().GetValid() && pWayPointMan) {
1538 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1539 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1540 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1546void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1551 if (pActiveTrack && pActiveTrack->IsRunning())
1552 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1558 if (!pRouteDraw)
continue;
1561 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1564 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1567 if (pRouteDraw->IsSelected()) drawit++;
1570 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1571 if (!vp_box.IntersectOut(test_box))
1572 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1578 if (vp.GetBBox().GetValid() && pWayPointMan) {
1579 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1580 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1587static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1591 switch (vp.m_projection_type) {
1592 case PROJECTION_TRANSVERSE_MERCATOR:
1593 lat_dist = 4, lon_dist = 1;
1595 case PROJECTION_POLYCONIC:
1596 lat_dist = 2, lon_dist = 1;
1598 case PROJECTION_ORTHOGRAPHIC:
1599 lat_dist = 2, lon_dist = 2;
1601 case PROJECTION_POLAR:
1602 lat_dist = 180, lon_dist = 1;
1604 case PROJECTION_STEREOGRAPHIC:
1605 case PROJECTION_GNOMONIC:
1606 lat_dist = 2, lon_dist = 1;
1608 case PROJECTION_EQUIRECTANGULAR:
1611 lat_dist = 2, lon_dist = 360;
1614 lat_dist = 180, lon_dist = 360;
1618void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1619 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1625 ChartData->GetDBBoundingBox(dbIndex, box);
1626 if (!box.GetValid())
return;
1630 if (box.GetLonRange() == 360)
return;
1632 LLBBox vpbox = vp.GetBBox();
1634 double lon_bias = 0;
1636 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1639 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1640 color = GetGlobalColor(
"YELO1");
1641 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1642 color = GetGlobalColor(
"GREEN2");
1644 color = GetGlobalColor(
"UINFR");
1646#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1647 float plylat, plylon;
1649 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1651 glColor3ub(color.Red(), color.Green(), color.Blue());
1652 glLineWidth(g_GLMinSymbolLineWidth);
1654 float lat_dist, lon_dist;
1655 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1658 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1662 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1664 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1666 bool begin =
false, sml_valid =
false;
1668 float lastplylat = 0.0;
1669 float lastplylon = 0.0;
1671 int modulo = (nPly == 0) ? 1 : nPly;
1672 for (
int i = 0; i < nPly + 1; i++) {
1674 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1676 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1680 if (lastplylon - plylon > 180)
1682 else if (lastplylon - plylon < -180)
1689 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1690 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1691 splits = wxMax(lat_splits, lon_splits) + 1;
1698 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1699 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1702 for (
double c = 0; c < splits; c++) {
1704 if (c == splits - 1)
1705 lat = plylat, lon = plylon;
1707 double d = (double)(c + 1) / splits;
1708 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1714 if (!std::isnan(s.m_x)) {
1717 glBegin(GL_LINE_STRIP);
1719 glVertex2f(s.m_x, s.m_y);
1725 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1726 lastplylat = plylat, lastplylon = plylon;
1731 }
while (++j < nAuxPlyEntries);
1733 glDisable(GL_LINE_SMOOTH);
1737 double nominal_line_width_pix =
1738 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1740 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1741 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1744 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1745 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1749 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1752 float plylat1, plylon1;
1756 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1757 if (0 == nAuxPlyEntries)
1760 std::vector<int> points_vector;
1762 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1763 int nPly = vec.size() / 2;
1765 if (nPly == 0)
return;
1767 for (
int i = 0; i < nPly; i++) {
1768 plylon1 = vec[i * 2];
1769 plylat1 = vec[i * 2 + 1];
1775 points_vector.push_back(pixx1);
1776 points_vector.push_back(pixy1);
1779 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1780 plylon1 += lon_bias;
1786 points_vector.push_back(pixx1);
1787 points_vector.push_back(pixy1);
1789 if (points_vector.size()) {
1790 std::vector<int>::iterator it = points_vector.begin();
1791 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1799 for (
int j = 0; j < nAuxPlyEntries; j++) {
1800 std::vector<int> points_vector;
1802 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1803 int nAuxPly = vec.size() / 2;
1805 if (nAuxPly == 0)
continue;
1807 for (
int i = 0; i < nAuxPly; i++) {
1808 plylon1 = vec[i * 2];
1809 plylat1 = vec[i * 2 + 1];
1815 points_vector.push_back(pixx1);
1816 points_vector.push_back(pixy1);
1823 points_vector.push_back(pixx1);
1824 points_vector.push_back(pixy1);
1826 if (points_vector.size()) {
1827 std::vector<int>::iterator it = points_vector.begin();
1828 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1836extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1837 float &MinorSpacing);
1838extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1839void glChartCanvas::GridDraw() {
1840 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1842 ViewPort &vp = m_pParentCanvas->GetVP();
1844 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1848 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1850 double nlat, elon, slat, wlon;
1852 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1855 wxColour GridColor = GetGlobalColor(
"SNDG1");
1857 if (!m_gridfont.IsBuilt()) {
1859 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1860 wxFont font = *dFont;
1861 int font_size = wxMax(10, dFont->GetPointSize());
1862 font.SetPointSize(font_size * m_displayScale);
1863 font.SetWeight(wxFONTWEIGHT_NORMAL);
1866 m_gridfont.Build(font, 1, dpi_factor);
1868 m_gridfont.SetColor(GridColor);
1873 LLBBox llbbox = vp.GetBBox();
1874 nlat = llbbox.GetMaxLat();
1875 slat = llbbox.GetMinLat();
1876 elon = llbbox.GetMaxLon();
1877 wlon = llbbox.GetMinLon();
1884 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1885 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1886 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1887 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1888 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1889 vp.m_projection_type == PROJECTION_POLAR ||
1890 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1893 if (straight_latitudes)
1896 latmargin = gridlatMajor / 2;
1898 slat = wxMax(slat, -90 + latmargin);
1899 nlat = wxMin(nlat, 90 - latmargin);
1901 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1902 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1906 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1913 float lon_step = elon - wlon;
1914 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1916 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1918 s.x = INVALID_COORD;
1919 s.y = INVALID_COORD;
1920 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1922 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1923 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1931 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1932 lat += gridlatMinor) {
1935 gldc.DrawLine(0, r.y, 10, r.y,
true);
1936 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1941 float lat_step = nlat - slat;
1942 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1944 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1946 s.x = INVALID_COORD;
1947 s.y = INVALID_COORD;
1948 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1950 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1951 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1959 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1960 lon += gridlonMinor) {
1963 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1964 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1970 glEnable(GL_TEXTURE_2D);
1972 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1973 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1976 CalcGridText(lat, gridlatMajor,
true);
1978 m_gridfont.GetTextExtent(st, 0, &iy);
1980 if (straight_latitudes) {
1985 float x = 0, y = -1;
1986 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1987 if (y < 0 || y > h) {
1989 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1992 m_gridfont.RenderString(st, x, y);
1996 double y1, y2, lat1, lon1, lat2, lon2;
2005 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2008 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2010 if (fabs(y - y1) < fabs(y - y2))
2016 error = fabs(r.m_x);
2017 if (--maxiters == 0)
break;
2018 }
while (error > 1 && error < lasterror);
2020 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2026 m_gridfont.RenderString(st, r.m_x, r.m_y);
2030 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2031 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2040 else if (xlon <= -180.0)
2043 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2045 m_gridfont.GetTextExtent(st, &ix, 0);
2047 if (straight_longitudes) {
2048 float x = -1, y = 0;
2049 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2050 if (x < 0 || x > w) {
2052 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2055 m_gridfont.RenderString(st, x, y);
2059 double x1, x2, lat1, lon1, lat2, lon2;
2067 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2070 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2072 if (fabs(x - x1) < fabs(x - x2))
2078 error = fabs(r.m_y);
2079 }
while (error > 1 && error < lasterror);
2081 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2086 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2088 m_gridfont.RenderString(st, r.m_x, r.m_y);
2092 glDisable(GL_TEXTURE_2D);
2093 glDisable(GL_BLEND);
2098 if (!emboss)
return;
2100 int w = emboss->width, h = emboss->height;
2102 glEnable(GL_TEXTURE_2D);
2105 if (!emboss->gltexind) {
2107 emboss->glwidth = NextPow2(emboss->width);
2108 emboss->glheight = NextPow2(emboss->height);
2111 int size = emboss->glwidth * emboss->glheight;
2112 char *data =
new char[2 * size];
2113 for (
int i = 0; i < h; i++) {
2114 for (
int j = 0; j < emboss->glwidth; j++) {
2116 data[2 * ((i * emboss->glwidth) + j)] =
2117 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2118 data[2 * ((i * emboss->glwidth) + j) + 1] =
2119 (char)abs((emboss->pmap[(i * w) + j]));
2124 glGenTextures(1, &emboss->gltexind);
2125 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2126 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2127 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2135 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2139 int x = emboss->x, y = emboss->y;
2141 float wp = (float)w / emboss->glwidth;
2142 float hp = (float)h / emboss->glheight;
2168 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2170 glDisable(GL_BLEND);
2171 glDisable(GL_TEXTURE_2D);
2174void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2175 if (!m_pParentCanvas->GetVP().IsValid())
return;
2176 wxPoint GPSOffsetPixels(0, 0);
2177 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2180 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2181 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2185 double shift_dx = 0;
2186 double shift_dy = 0;
2187 bool dynamic = m_pParentCanvas->m_animationActive ||
2188 m_pParentCanvas->m_MouseDragging ||
2189 m_pParentCanvas->m_chart_drag_inertia_active;
2190 if (m_pParentCanvas->m_bFollow && !dynamic) {
2191 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2192 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2193 if (m_pParentCanvas->m_bLookAhead) {
2199 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2200 angle += m_pParentCanvas->GetVPRotation();
2201 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2203 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2204 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2206 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2211 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2212 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2219 lShipMidPoint = lGPSPoint;
2223 float icon_hdt = pCog;
2224 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2227 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2231 double osd_head_lat, osd_head_lon;
2232 wxPoint2DDouble osd_head_point;
2234 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2238 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2240 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2241 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2242 icon_rad += (float)PI;
2246 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2250 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2256 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2257 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2258 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2263 float scale_factor = 1.0;
2268 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2269 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2270 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2272 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2274 float nominal_ownship_size_pixels =
2276 nominal_ownship_size_mm);
2278 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2280 wxPen ppSmallScaleShip;
2281 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2283 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2286 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2287 dc.SetPen(ppSmallScaleShip);
2289 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2292 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2293 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2294 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2295 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2298 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2299 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2302 int draw_color = SHIP_INVALID;
2303 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2304 draw_color = SHIP_NORMAL;
2305 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2306 draw_color = SHIP_LOWACCURACY;
2314 ownship_color = draw_color;
2316 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2318 glGenTextures(1, &ownship_tex);
2319 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2321 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2325 if (m_pParentCanvas->m_pos_image_user) {
2326 switch (draw_color) {
2328 image = *m_pParentCanvas->m_pos_image_user_grey;
2331 image = *m_pParentCanvas->m_pos_image_user;
2333 case SHIP_LOWACCURACY:
2334 image = *m_pParentCanvas->m_pos_image_user_yellow;
2338 switch (draw_color) {
2340 image = *m_pParentCanvas->m_pos_image_grey;
2343 image = *m_pParentCanvas->m_pos_image_red;
2345 case SHIP_LOWACCURACY:
2346 image = *m_pParentCanvas->m_pos_image_yellow;
2351 int w = image.GetWidth(), h = image.GetHeight();
2352 int glw = NextPow2(w), glh = NextPow2(h);
2353 ownship_size = wxSize(w, h);
2354 ownship_tex_size = wxSize(glw, glh);
2356 unsigned char *d = image.GetData();
2357 unsigned char *a = image.GetAlpha();
2358 unsigned char *e =
new unsigned char[4 * w * h];
2361 for (
int p = 0; p < w * h; p++) {
2362 e[4 * p + 0] = d[3 * p + 0];
2363 e[4 * p + 1] = d[3 * p + 1];
2364 e[4 * p + 2] = d[3 * p + 2];
2365 e[4 * p + 3] = a[p];
2368 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2369 GL_UNSIGNED_BYTE, 0);
2371 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2377#ifndef USE_ANDROID_GLES2
2378 if (m_pParentCanvas->m_pos_image_user)
2379 glColor4ub(255, 255, 255, 255);
2380 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2381 glColor4ub(255, 0, 0, 255);
2382 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2383 glColor4ub(255, 255, 0, 255);
2385 glColor4ub(128, 128, 128, 255);
2387 float scale_factor_y = 1.0;
2388 float scale_factor_x = 1.0;
2390 int ownShipWidth = 22;
2391 int ownShipLength = 84;
2392 lShipMidPoint = lGPSPoint;
2395 if (g_OwnShipIconType != 0)
2396 m_pParentCanvas->ComputeShipScaleFactor(
2397 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2398 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2403 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2404 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2405 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2409 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2410 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2414 float gps_circle_radius = 3.0;
2416 if (g_OwnShipIconType == 0) {
2418 glEnable(GL_TEXTURE_2D);
2419 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2428 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2429 if (m_pParentCanvas->m_pos_image_user)
2430 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2432 float nominal_ownship_size_mm =
2433 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2435 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2436 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2438 float nominal_ownship_size_pixels =
2439 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2441 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2442 nominal_ownship_size_pixels = wxMax(
2443 20.0, nominal_ownship_size_pixels);
2446 float h = nominal_ownship_size_pixels * scale_factor_y;
2447 float w = nominal_ownship_size_pixels * scale_factor_x *
2448 ownship_size.x / ownship_size.y;
2449 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2450 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2456 gps_circle_radius = w / 5;
2458 float uv[8], coords[8];
2477 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2478 lShipMidPoint.m_x, lShipMidPoint.m_y,
2480 glDisable(GL_TEXTURE_2D);
2481 }
else if (g_OwnShipIconType == 1) {
2483 glEnable(GL_TEXTURE_2D);
2484 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2486 float nominal_ownship_size_pixels_y = 84;
2487 float nominal_ownship_size_pixels_x = 22;
2489 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2490 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2492 float u = (float)ownship_size.x / ownship_tex_size.x,
2493 v = (
float)ownship_size.y / ownship_tex_size.y;
2496 gps_circle_radius = w / 5;
2498 float uv[8], coords[8];
2517 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2518 lShipMidPoint.m_x, lShipMidPoint.m_y,
2521 glDisable(GL_TEXTURE_2D);
2522 }
else if (g_OwnShipIconType == 2) {
2530 wxPoint shipPoints[6];
2532 wxColour colour = m_pParentCanvas->ShipColor();
2533 wxPen ppPen(*wxBLACK, 1);
2534 wxBrush ppBrush(colour);
2536 dc.SetBrush(ppBrush);
2538 shipPoints[0].x = 0 * scale_factor_x;
2539 shipPoints[0].y = -28 * scale_factor_y;
2540 shipPoints[1].x = 11 * scale_factor_x;
2541 shipPoints[1].y = -28 * scale_factor_y;
2542 shipPoints[2].x = 11 * scale_factor_x;
2543 shipPoints[2].y = 42 * scale_factor_y;
2544 shipPoints[3].x = 0 * scale_factor_x;
2545 shipPoints[3].y = 42 * scale_factor_y;
2546 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2549 shipPoints[0].x = 0 * scale_factor_x;
2550 shipPoints[0].y = -42 * scale_factor_y;
2551 shipPoints[1].x = 5 * scale_factor_x;
2552 shipPoints[1].y = -42 * scale_factor_y;
2553 shipPoints[2].x = 11 * scale_factor_x;
2554 shipPoints[2].y = -28 * scale_factor_y;
2555 shipPoints[3].x = 0 * scale_factor_x;
2556 shipPoints[3].y = -28 * scale_factor_y;
2557 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2560 shipPoints[0].x = 0 * scale_factor_x;
2561 shipPoints[0].y = -28 * scale_factor_y;
2562 shipPoints[1].x = -11 * scale_factor_x;
2563 shipPoints[1].y = -28 * scale_factor_y;
2564 shipPoints[2].x = -11 * scale_factor_x;
2565 shipPoints[2].y = 42 * scale_factor_y;
2566 shipPoints[3].x = 0 * scale_factor_x;
2567 shipPoints[3].y = 42 * scale_factor_y;
2568 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2571 shipPoints[0].x = 0 * scale_factor_x;
2572 shipPoints[0].y = -42 * scale_factor_y;
2573 shipPoints[1].x = -5 * scale_factor_x;
2574 shipPoints[1].y = -42 * scale_factor_y;
2575 shipPoints[2].x = -11 * scale_factor_x;
2576 shipPoints[2].y = -28 * scale_factor_y;
2577 shipPoints[3].x = 0 * scale_factor_x;
2578 shipPoints[3].y = -28 * scale_factor_y;
2579 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2583 double p1x = -11 * scale_factor_x;
2584 double p2x = 11 * scale_factor_x;
2588 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2590 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2592 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2594 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2595 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2596 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2600 p1y = -42 * scale_factor_y;
2601 p2y = 42 * scale_factor_y;
2602 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2603 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2604 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2605 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2606 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2607 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2610 img_height = ownShipLength * scale_factor_y;
2613 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2615 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2617 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2619 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2623 glDisable(GL_LINE_SMOOTH);
2624 glDisable(GL_POLYGON_SMOOTH);
2625 glDisable(GL_BLEND);
2628 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2632void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2633 ViewPort &vp = m_pParentCanvas->GetVP();
2656 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2658 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2659 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2661 m_pParentCanvas->AlertDraw(dc);
2663 m_pParentCanvas->RenderVisibleSectorLights(dc);
2665 m_pParentCanvas->RenderRouteLegs(dc);
2666 m_pParentCanvas->RenderShipToActive(dc,
true);
2667 m_pParentCanvas->ScaleBarDraw(dc);
2668 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2669 m_pParentCanvas->extendedSectorLegs);
2676void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2677 if (m_pParentCanvas->GetPiano()) {
2678 int canvas_height = GetClientSize().y;
2679 canvas_height *= m_displayScale;
2681 m_pParentCanvas->GetPiano()->DrawGL(
2682 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2686void glChartCanvas::DrawQuiting() {
2687#ifndef USE_ANDROID_GLES2
2688 GLubyte pattern[8][8];
2689 for (
int y = 0; y < 8; y++)
2690 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2693 glEnable(GL_TEXTURE_2D);
2694 glBindTexture(GL_TEXTURE_2D, 0);
2696 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2697 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2698 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2700 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2704 float x = GetSize().x, y = GetSize().y;
2705 float u = x / 8, v = y / 8;
2718 glDisable(GL_TEXTURE_2D);
2719 glDisable(GL_BLEND);
2723void glChartCanvas::DrawCloseMessage(wxString msg) {
2724#ifndef USE_ANDROID_GLES2
2728 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2732 texfont.Build(*pfont, 1, 1);
2734 texfont.GetTextExtent(msg, &w, &h);
2736 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2737 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2739 glColor3ub(243, 229, 47);
2743 glVertex2i(xp + w, yp);
2744 glVertex2i(xp + w, yp + h);
2745 glVertex2i(xp, yp + h);
2750 glColor3ub(0, 0, 0);
2751 glEnable(GL_TEXTURE_2D);
2752 texfont.RenderString(msg, xp, yp);
2753 glDisable(GL_TEXTURE_2D);
2754 glDisable(GL_BLEND);
2761static std::list<double *> combine_work_data;
2762static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2763 GLfloat weight[4], GLdouble **dataOut) {
2764 double *vertex =
new double[3];
2765 combine_work_data.push_back(vertex);
2766 memcpy(vertex, coords, 3 * (
sizeof *coords));
2770#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2771void vertexCallbackD_GLSL(GLvoid *vertex) {
2773 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2774 int new_buf_len = s_tess_buf_len + 100;
2775 GLfloat *tmp = s_tess_work_buf;
2778 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2779 if (NULL == s_tess_work_buf) {
2783 s_tess_buf_len = new_buf_len;
2786 GLdouble *pointer = (GLdouble *)vertex;
2788 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2789 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2794void beginCallbackD_GLSL(GLenum mode) {
2795 s_tess_vertex_idx_this = s_tess_vertex_idx;
2800void endCallbackD_GLSL() {
2804 shader->SetUniformMatrix4fv(
"MVMatrix",
2805 (GLfloat *)s_tessVP.vp_matrix_transform);
2807 mat4x4 identityMatrix;
2808 mat4x4_identity(identityMatrix);
2809 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2813 colorv[0] = s_regionColor.Red() / float(256);
2814 colorv[1] = s_regionColor.Green() / float(256);
2815 colorv[2] = s_regionColor.Blue() / float(256);
2816 colorv[3] = s_regionColor.Alpha() / float(256);
2817 shader->SetUniform4fv(
"color", colorv);
2819 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2820 shader->SetAttributePointerf(
"position", bufPt);
2822 glDrawArrays(s_tess_mode, 0, s_nvertex);
2827void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2829void beginCallbackD(GLenum mode) { glBegin(mode); }
2831void endCallbackD() { glEnd(); }
2835void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2836 float lat_dist, lon_dist;
2837 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2839 GLUtesselator *tobj = gluNewTess();
2840 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2842#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2843 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2844 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2845 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2846 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2850 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2851 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2852 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2853 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2856 gluTessNormal(tobj, 0, 0, 1);
2858 gluTessBeginPolygon(tobj, NULL);
2859 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2860 gluTessBeginContour(tobj);
2861 contour_pt l = *i->rbegin();
2863 bool sml_valid =
false;
2864 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2865 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2866 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2867 int splits = wxMax(lat_splits, lon_splits) + 1;
2873 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2874 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2877 for (
int i = 0; i < splits; i++) {
2879 if (i == splits - 1)
2880 lat = j->y, lon = j->x;
2882 double d = (double)(i + 1) / splits;
2883 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2887 if (std::isnan(q.m_x))
continue;
2889 double *p =
new double[6];
2894 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2899 gluTessVertex(tobj, p, p);
2900 combine_work_data.push_back(p);
2904 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2906 gluTessEndContour(tobj);
2908 gluTessEndPolygon(tobj);
2910 gluDeleteTess(tobj);
2912 for (std::list<double *>::iterator i = combine_work_data.begin();
2913 i != combine_work_data.end(); i++)
2915 combine_work_data.clear();
2920void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2921 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2923 if (s_b_useStencil) {
2925 glEnable(GL_STENCIL_TEST);
2927 glClear(GL_STENCIL_BUFFER_BIT);
2931 glStencilFunc(GL_ALWAYS, 1, 1);
2932 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2935#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2939 glEnable(GL_DEPTH_TEST);
2940 glDepthFunc(GL_ALWAYS);
2941 glDepthMask(GL_TRUE);
2943 glClear(GL_DEPTH_BUFFER_BIT);
2956 glTranslatef(0, 0, .5);
2960 s_regionColor = wxColor(0, 0, 0, 255);
2961 DrawRegion(vp, region);
2963 if (s_b_useStencil) {
2966 glStencilFunc(GL_EQUAL, 1, 1);
2967 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2970#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2972 glDepthFunc(GL_GREATER);
2973 glDepthMask(GL_FALSE);
2974 glTranslatef(0, 0, -.5);
2977 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2980void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2984 if (s_b_useStencil && s_b_useScissorTest) {
2986 if (rect != vp_rect) {
2987 glEnable(GL_SCISSOR_TEST);
2988 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2991#ifndef USE_ANDROID_GLES2
2997void glChartCanvas::DisableClipRegion() {
2998 glDisable(GL_SCISSOR_TEST);
2999 glDisable(GL_STENCIL_TEST);
3000 glDisable(GL_DEPTH_TEST);
3003void glChartCanvas::Invalidate() {
3005 m_cache_vp.Invalidate();
3011 if (!pBSBChart)
return;
3017 wxString key = chart->GetHashKey();
3021 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3024 if (ittf == hash.end()) {
3026 hash[key]->SetHashKey(key);
3029 pTexFact = hash[key];
3030 pTexFact->SetLRUTime(++m_LRUtime);
3035 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3036 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3043 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3044 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3045 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3046 base_level = log(scalefactor) / log(2.0);
3055 glEnable(GL_TEXTURE_2D);
3056#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3057 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3059 glEnableClientState(GL_VERTEX_ARRAY);
3060 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3065 pTexFact->GetCenter(lat, lon);
3066 MultMatrixViewPort(vp, lat, lon);
3070 LLBBox box = region.GetBox();
3073 if (g_memCacheLimit > 0) {
3078 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3079 for (
int i = 0; i < numtiles; i++) {
3081 if (region.IntersectOut(tile->box)) {
3084 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3085 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3087 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3088 global_color_scheme, mem_used);
3092 coords = tile->m_coords;
3094 coords =
new float[2 * tile->m_ncoords];
3095 for (
int i = 0; i < tile->m_ncoords; i++) {
3097 tile->m_coords[2 * i + 1]);
3098 coords[2 * i + 0] = p.m_x;
3099 coords[2 * i + 1] = p.m_y;
3103#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3104 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3105 m_pParentCanvas->GetpVP());
3108 glDisable(GL_TEXTURE_2D);
3112 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3113 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3114 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3116 if (!texture) glEnable(GL_TEXTURE_2D);
3118 if (!use_norm_vp)
delete[] coords;
3122 glDisable(GL_TEXTURE_2D);
3124#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3125 if (use_norm_vp) glPopMatrix();
3127 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3128 glDisableClientState(GL_VERTEX_ARRAY);
3132void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3134 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3135 m_pParentCanvas->m_pQuilt->IsBusy())
3139 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3141 printf(
" Chart NULL\n");
3142 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3152 LLRegion region = vp.GetLLRegion(rect_region);
3154 LLRegion rendered_region;
3160 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3168 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3170 LLRegion get_region = pqp->ActiveRegion;
3171 bool b_rendered =
false;
3173 if (!pqp->b_overlay) {
3174 get_region.Intersect(region);
3175 if (!get_region.Empty()) {
3176 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3179 SetClipRegion(vp, get_region );
3180 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3181 DisableClipRegion();
3184 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3185 SetClipRegion(vp, pqp->ActiveRegion );
3186 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3188 DisableClipRegion();
3191 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3192 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3193 RenderNoDTA(vp, get_region);
3194 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3199 if (Chs57->m_RAZBuilt) {
3200 RenderNoDTA(vp, get_region);
3201 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3202 rect_region, get_region);
3203 DisableClipRegion();
3208 const LLRegion &oregion = get_region;
3209 LLBBox box = oregion.GetBox();
3220 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3223 ViewPort cvp = ClippedViewport(vp, get_region);
3224 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3225 SetClipRegion(cvp, get_region);
3226 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3227 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3228 RenderWorldChart(gldc, cvp, srect, world);
3229 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3230 global_color_scheme);
3231 DisableClipRegion();
3238 SetClipRegion(vp, get_region);
3239 RenderNoDTA(vp, get_region);
3240 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3242 DisableClipRegion();
3245 SetClipRegion(vp, get_region);
3246 RenderNoDTA(vp, get_region);
3247 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3249 DisableClipRegion();
3265 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3269 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3270 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3272 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3273 if (pqp->b_Valid && pqp->b_overlay &&
3274 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3275 LLRegion get_region = pqp->ActiveRegion;
3277 get_region.Intersect(region);
3278 if (!get_region.Empty()) {
3281 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3286 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3293 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3298 ViewPort vph = m_pParentCanvas->GetVP();
3299 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3302 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3304 if (!hiregion.Empty()) {
3308 switch (global_color_scheme) {
3309 case GLOBAL_COLOR_SCHEME_DAY:
3312 case GLOBAL_COLOR_SCHEME_DUSK:
3315 case GLOBAL_COLOR_SCHEME_NIGHT:
3323#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3325 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3327 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3330 DrawRegion(vp, hiregion);
3332 glDisable(GL_BLEND);
3337 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3339 if (!hiregion.Empty()) {
3343 switch (global_color_scheme) {
3344 case GLOBAL_COLOR_SCHEME_DAY:
3347 case GLOBAL_COLOR_SCHEME_DUSK:
3350 case GLOBAL_COLOR_SCHEME_NIGHT:
3359#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3361 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3363 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3366 DrawRegion(vp, hiregion);
3368 glDisable(GL_BLEND);
3372 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3375void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3377 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3378 m_pParentCanvas->m_pQuilt->IsBusy())
3382 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3384 LLRegion region = vp.GetLLRegion(rect_region);
3386 LLRegion rendered_region;
3388 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3390 LLRegion get_region = pqp->ActiveRegion;
3392 if (!pqp->b_overlay) {
3393 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3396 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3401 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3408 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3436void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3437 ViewPort &vp = m_pParentCanvas->VPoint;
3445 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3446 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3449 LLRegion chart_region;
3451 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3452 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3453 CHART_FAMILY_RASTER) {
3461 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3462 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3463 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3465 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3469 for (
int i = 1; i < 6; i += 2)
3470 if (fabs(ll[i] - ll[i + 2]) > 180) {
3472 for (
int i = 1; i < 8; i += 2)
3473 if (ll[i] < 0) ll[i] += 360;
3477 chart_region = LLRegion(4, ll);
3480 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3482 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3483 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3484 chart_region = LLRegion(4, ll);
3487 chart_region = vp.b_quilt
3488 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3489 : m_pParentCanvas->m_singleChart->GetValidRegion();
3491 bool world_view =
false;
3493 wxRect rect = upd.GetRect();
3494 LLRegion background_region = vp.GetLLRegion(rect);
3497 background_region.Subtract(chart_region);
3499 if (!background_region.Empty()) {
3500 ViewPort cvp = ClippedViewport(vp, background_region);
3501 SetClipRect(cvp, rect,
false);
3502 RenderWorldChart(dc, cvp, rect, world_view);
3503 DisableClipRegion();
3508 RenderQuiltViewGL(vp, rect_region);
3511 LLRegion region = vp.GetLLRegion(rect_region);
3512 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3513 CHART_FAMILY_RASTER) {
3514 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3515 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3516 *m_pcontext, vp, rect_region, region);
3518 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3519 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3520 CHART_FAMILY_VECTOR) {
3521 chart_region.Intersect(region);
3522 RenderNoDTA(vp, chart_region);
3523 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3524 rect_region, region);
3530void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3532 wxColour color = GetGlobalColor(
"NODTA");
3533#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3535 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3537 glColor4ub(163, 180, 183, transparency);
3540 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3544 s_regionColor = color;
3547 DrawRegion(vp, region);
3551void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3554 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3556 glEnable(GL_SCISSOR_TEST);
3557 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3563 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3564#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3566 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3570 colorv[0] = water.Red() / float(256);
3571 colorv[1] = water.Green() / float(256);
3572 colorv[2] = water.Blue() / float(256);
3574 shader->SetUniform4fv(
"color", colorv);
3585 shader->SetAttributePointerf(
"position", pf);
3587 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3599 glDisable(GL_SCISSOR_TEST);
3607void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3608 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3610 DrawStaticRoutesTracksAndWaypoints(vp);
3612 DisableClipRegion();
3615void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3617 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3621 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3622 if (!bmp.Ok())
return;
3624 wxImage image = bmp.ConvertToImage();
3625 int w = image.GetWidth(), h = image.GetHeight();
3628 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3629 tex_w = w, tex_h = h;
3631 tex_w = NextPow2(w), tex_h = NextPow2(h);
3633 m_tideTexWidth = tex_w;
3634 m_tideTexHeight = tex_h;
3636 unsigned char *d = image.GetData();
3637 unsigned char *a = image.GetAlpha();
3639 unsigned char mr, mg, mb;
3640 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3642 unsigned char *e =
new unsigned char[4 * w * h];
3644 for (
int y = 0; y < h; y++)
3645 for (
int x = 0; x < w; x++) {
3646 unsigned char r, g, b;
3647 int off = (y * w + x);
3657 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3661 glGenTextures(1, &m_tideTex);
3663 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3664 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3667 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3668 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3669 GL_UNSIGNED_BYTE, e);
3671 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3672 GL_UNSIGNED_BYTE, 0);
3673 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3682 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3683 glEnable(GL_TEXTURE_2D);
3686#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3688 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3692 if ((type ==
't') || (type ==
'T'))
3697 if (BBox.Contains(lat, lon)) {
3706 scale *= getAndroidDisplayDensity();
3708 double width2 =
scale * m_tideTexWidth / 2;
3709 double height2 =
scale * m_tideTexHeight / 2;
3724 coords[0] = xp - width2;
3725 coords[1] = yp - height2;
3726 coords[2] = xp - width2;
3727 coords[3] = yp + height2;
3728 coords[4] = xp + width2;
3729 coords[5] = yp + height2;
3730 coords[6] = xp + width2;
3731 coords[7] = yp - height2;
3733 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3740 glDisable(GL_TEXTURE_2D);
3741 glDisable(GL_BLEND);
3742 glBindTexture(GL_TEXTURE_2D, 0);
3744 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3747void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3748 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3751void glChartCanvas::SetColorScheme(ColorScheme cs) {
3752 if (!m_bsetup)
return;
3754 glDeleteTextures(1, &m_tideTex);
3755 glDeleteTextures(1, &m_currentTex);
3761void glChartCanvas::RenderGLAlertMessage() {
3762 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3763 wxString msg = m_pParentCanvas->GetAlertString();
3766 m_gldc.SetFont(*pfont);
3770 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3777 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3778 int xp = sbr.x + sbr.width + 5;
3780 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3781 m_gldc.SetPen(ppPen1);
3782 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3784 m_gldc.DrawRectangle(xp, yp, w, h);
3786 m_gldc.DrawText(msg, xp, yp);
3790unsigned long quiltHash;
3792extern wxLongLong s_t0;
3795void glChartCanvas::Render() {
3796 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3797 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3798 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3803 if (!g_PrintingInProgress)
return;
3806 if (!g_true_zoom && m_binPinch)
return;
3809 long render_start_time = m_glstopwatch.Time();
3811#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3812 loadShaders(GetCanvasIndex());
3813 configureShaders(m_pParentCanvas->VPoint);
3816#ifdef USE_ANDROID_GLES2
3820 if (m_binPinch)
return;
3829 bool recompose =
false;
3830 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3831 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3832 if (m_pParentCanvas->VPoint.IsValid()) {
3833 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3834 m_pParentCanvas->UpdateCanvasControlBar();
3843 if (sw.GetTime() > 2000) {
3849 s_tess_vertex_idx = 0;
3850 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3851 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3857 m_displayScale = GetContentScaleFactor();
3861 m_last_render_time = wxDateTime::Now().GetTicks();
3865 if (g_GLOptions.m_bTextureCompression &&
3866 !g_GLOptions.m_bTextureCompressionCaching)
3871 int gl_width, gl_height;
3872 gl_width = m_pParentCanvas->VPoint.
pix_width;
3873 gl_height = m_pParentCanvas->VPoint.
pix_height;
3876 m_glcanvas_width = gl_width;
3877 m_glcanvas_height = gl_height;
3881 if (gl_height & 1) {
3883 ViewPort *vp = m_pParentCanvas->GetpVP();
3890 ViewPort *vp = m_pParentCanvas->GetpVP();
3898 ViewPort *vp = m_pParentCanvas->GetpVP();
3901 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3904 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3912 ViewPort VPoint = m_pParentCanvas->VPoint;
3914 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3915 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3918#if !defined(USE_ANDROID_GLES2)
3919 glMatrixMode(GL_PROJECTION);
3922 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3923 glMatrixMode(GL_MODELVIEW);
3927 if (s_b_useStencil) {
3928 glEnable(GL_STENCIL_TEST);
3929 glStencilMask(0xff);
3930 glClear(GL_STENCIL_BUFFER_BIT);
3931 glDisable(GL_STENCIL_TEST);
3937 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3938 if (g_GLOptions.m_GLPolygonSmoothing)
3939 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3940 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3952 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3953 bool useFBO =
false;
3959 if (m_b_BuiltFBO && !bpost_hilite
3964 bool b_newview =
true;
3965 bool b_full =
false;
3973 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3977#ifdef USE_ANDROID_GLES2
3978 if (recompose) b_newview =
true;
3990 if (VPoint.b_quilt) {
3991 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3992 if (!chart) b_full =
true;
4001 bool accelerated_pan =
false;
4011 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4012 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4013 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4015 wxPoint2DDouble c_old =
4018 wxPoint2DDouble c_new =
4022 dy = wxRound(c_new.m_y - c_old.m_y);
4023 dx = wxRound(c_new.m_x - c_old.m_x);
4033 double deltax = c_new.m_x - c_old.m_x;
4034 double deltay = c_new.m_y - c_old.m_y;
4036 bool b_whole_pixel =
true;
4037 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4038 b_whole_pixel =
false;
4040 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4041 abs(dy) < m_cache_tex_y &&
4042 (abs(dx) > 0 || (abs(dy) > 0));
4051 if (m_displayScale > 1) accelerated_pan =
false;
4056 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4059#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4062 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4068 if (b_full) accelerated_pan =
false;
4070 if (accelerated_pan) {
4071 if ((dx != 0) || (dy != 0)) {
4083 if (dy > 0 && dy < gl_height)
4084 update_region.Union(
4085 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4087 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4089 if (dx > 0 && dx < gl_width)
4090 update_region.Union(
4091 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4093 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4095 m_cache_page = !m_cache_page;
4098 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4099 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4111 RenderCharts(m_gldc, update_region);
4115 glDisable(g_texture_rectangle_format);
4120 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4121 glEnable(GL_TEXTURE_2D);
4125 float x1, x2, y1, y2;
4138 float tx1, tx2, ty1, ty2;
4144 tx2 = sx / (float)m_cache_tex_x;
4146 ty2 = sy / (float)m_cache_tex_y;
4163 coords[2] = -dx + sx;
4165 coords[4] = -dx + sx;
4166 coords[5] = dy + sy;
4168 coords[7] = dy + sy;
4171 ptexture_2D_shader_program[GetCanvasIndex()];
4175 shader->SetUniform1i(
"uTex", 0);
4179 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4180 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4181 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4183 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4205 shader->SetAttributePointerf(
"aPos", co1);
4206 shader->SetAttributePointerf(
"aUV", tco1);
4208 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4211 shader->SetUniformMatrix4fv(
"MVMatrix",
4212 (GLfloat *)VPoint.vp_matrix_transform);
4215 glBindTexture(g_texture_rectangle_format, 0);
4217 glDisable(g_texture_rectangle_format);
4225 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4226 g_texture_rectangle_format,
4227 m_cache_tex[!m_cache_page], 0);
4238 wxColour color = GetGlobalColor(
"NODTA");
4239 glClearColor(color.Red() / 256., color.Green() / 256.,
4240 color.Blue() / 256., 1.0);
4241 glClear(GL_COLOR_BUFFER_BIT);
4247 RenderCharts(m_gldc, rscreen_region);
4252 m_cache_page = !m_cache_page;
4257 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4268 glMatrixMode(GL_PROJECTION);
4271 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4272 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4274 glMatrixMode(GL_MODELVIEW);
4278 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4279 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4281 glGetIntegerv(GL_VIEWPORT, viewport);
4282 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4283 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4292 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4293 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4294 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4296 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4300 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4301 glEnable(g_texture_rectangle_format);
4303 float tx, ty, tx0, ty0, divx, divy;
4306 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4309 divx = m_cache_tex_x;
4310 divy = m_cache_tex_y;
4313 tx0 = m_fbo_offsetx / divx;
4314 ty0 = m_fbo_offsety / divy;
4315 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4316 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4341 wxColour color = GetGlobalColor(
"NODTA");
4342 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4344 glClear(GL_COLOR_BUFFER_BIT);
4346 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4349 glDisable(g_texture_rectangle_format);
4351 m_cache_vp = VPoint;
4352 m_cache_vp.Validate();
4354 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4356 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4360 RenderCharts(m_gldc, screen_region);
4369 RenderS57TextOverlay(VPoint);
4370 RenderMBTilesOverlay(VPoint);
4376 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4381 wxRect rt = upd.GetRect();
4382 LLRegion region = VPoint.GetLLRegion(rt);
4383 ViewPort cvp = ClippedViewport(VPoint, region);
4384 DrawGroundedOverlayObjects(gldc, cvp);
4387 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4388 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4389 LLBBox screenBox = screenLLRegion.GetBox();
4391 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4394 if (m_pParentCanvas->m_bShowTide) {
4395 m_pParentCanvas->RebuildTideSelectList(screenBox);
4396 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4399 if (m_pParentCanvas->m_bShowCurrent) {
4400 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4401 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4407 if (m_pParentCanvas->m_show_focus_bar &&
4408 (g_canvasConfig != 0)) {
4409 if (m_pParentCanvas == wxWindow::FindFocus()) {
4412 wxColour colour = GetGlobalColor(
"BLUE4");
4413 wxPen ppBlue(colour, 1);
4414 wxBrush ppBrush(colour);
4415 gldc.SetPen(ppBlue);
4416 gldc.SetBrush(ppBrush);
4417 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4418 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4419 wxPoint barPoints[4];
4422 barPoints[1].x = xw;
4424 barPoints[2].x = xw;
4425 barPoints[2].y = rect_pix;
4427 barPoints[3].y = rect_pix;
4429 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4433 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4437 DrawFloatingOverlayObjects(m_gldc);
4439#ifndef USE_ANDROID_GLES2
4442 glMatrixMode(GL_PROJECTION);
4445 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4446 glMatrixMode(GL_MODELVIEW);
4451 if (!g_bhide_depth_units)
4452 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4453 if (!g_bhide_overzoom_flag)
4454 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4457 ViewPort &vp = m_pParentCanvas->GetVP();
4462 if (!g_PrintingInProgress) {
4463 if (m_pParentCanvas->m_pTrackRolloverWin)
4464 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4466 if (m_pParentCanvas->m_pRouteRolloverWin)
4467 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4469 if (m_pParentCanvas->m_pAISRolloverWin)
4470 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4472 if (m_pParentCanvas->GetMUIBar())
4473 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4487 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4488 int x, y, width, height;
4489 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4490 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4491 wxBitmap bmp(width, height, -1);
4494 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4497 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4498 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4502 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4503 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4505 wxStringTokenizer tkz(s,
"\n");
4508 while (tkz.HasMoreTokens()) {
4509 token = tkz.GetNextToken();
4510 dc.DrawText(token, xt, yt);
4513 dc.SelectObject(wxNullBitmap);
4515 m_gldc.DrawBitmap(bmp, x, y,
false);
4521 if (g_bShowChartBar) DrawChartBar(m_gldc);
4523 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4525 m_pParentCanvas->m_Compass->Paint(gldc);
4527 if (m_pParentCanvas->IsPrimaryCanvas()) {
4528 auto ¬eman = NotificationManager::GetInstance();
4529 if (noteman.GetNotificationCount()) {
4530 m_pParentCanvas->m_notification_button->SetIconSeverity(
4531 noteman.GetMaxSeverity());
4532 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4533 m_pParentCanvas->m_notification_button->Show(
true);
4534 m_pParentCanvas->m_notification_button->Paint(gldc);
4536 m_pParentCanvas->m_notification_button->Show(
false);
4539 RenderGLAlertMessage();
4542 ViewPort &vp = m_pParentCanvas->GetVP();
4546 glActiveTexture(GL_TEXTURE0);
4550 if (g_bquiting) DrawQuiting();
4551 if (g_bcompression_wait)
4552 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4557 if (g_b_needFinish) glFinish();
4564 m_pParentCanvas->PaintCleanup();
4565 m_bforcefull =
false;
4574void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4577 if (VPoint.b_quilt) {
4578 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4579 ps52plib->GetShowS57Text()) {
4580 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4581 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4586 ChPI->ClearPLIBTextList();
4588 ps52plib->ClearTextList();
4598 RenderQuiltViewGLText(vpx, screen_region);
4603void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4606 LLRegion &screenLLRegion) {
4611 if (chart == NULL)
return;
4618 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4620 wxFileName tileFile(chart->GetFullPath());
4622 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4624 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4625 (tileSizeMB.GetLo() > 5000)) {
4628 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4629 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4630 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4637 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4641 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4644 std::vector<int> piano_active_array_tiles =
4645 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4646 bool bfound =
false;
4648 if (std::find(piano_active_array_tiles.begin(),
4649 piano_active_array_tiles.end(),
4650 dbIndex) != piano_active_array_tiles.end()) {
4655 piano_active_array_tiles.push_back(dbIndex);
4656 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4660void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4662 std::vector<int> stackIndexArray =
4663 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4664 unsigned int im = stackIndexArray.size();
4667 if (VPoint.b_quilt && im > 0) {
4668 bool regionVPBuilt =
false;
4670 LLRegion screenLLRegion;
4674 std::vector<int> tiles_to_show;
4675 for (
unsigned int is = 0; is < im; is++) {
4677 ChartData->GetChartTableEntry(stackIndexArray[is]);
4678 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4679 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4681 std::vector<int> piano_active_array_tiles =
4682 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4683 bool bfound =
false;
4685 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4686 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4687 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4695 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4696 piano_active_array_tiles);
4701 tiles_to_show.push_back(stackIndexArray[is]);
4702 if (!regionVPBuilt) {
4705 screenLLRegion = VPoint.GetLLRegion(screen_region);
4706 screenBox = screenLLRegion.GetBox();
4714 regionVPBuilt =
true;
4724 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4725 rit != tiles_to_show.rend(); ++rit) {
4726 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4728 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4729 rit != tiles_to_show.rend(); ++rit) {
4730 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4734 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4736 if (!hiregion.Empty()) {
4740 switch (global_color_scheme) {
4741 case GLOBAL_COLOR_SCHEME_DAY:
4744 case GLOBAL_COLOR_SCHEME_DUSK:
4747 case GLOBAL_COLOR_SCHEME_NIGHT:
4755#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4756 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4758 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4761 DrawRegion(VPoint, hiregion);
4763 glDisable(GL_BLEND);
4769void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4773 GetClientSize(&w, &h);
4775 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4776#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4777 glMatrixMode(GL_PROJECTION);
4780 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4781 glMatrixMode(GL_MODELVIEW);
4785 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4787 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4789 bool world_view =
false;
4790 RenderWorldChart(dc, cvp, rtex, world_view);
4797 glViewport(0, 0, (GLint)w, (GLint)h);
4798#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4799 glMatrixMode(GL_PROJECTION);
4802 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4803 glMatrixMode(GL_MODELVIEW);
4809void glChartCanvas::FastPan(
int dx,
int dy) {
4810#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4814void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4816 if (IsShown()) SetCurrent(*m_pcontext);
4817 float sx = GetSize().x;
4818 float sy = GetSize().y;
4819 glClear(GL_COLOR_BUFFER_BIT);
4822 GetClientSize(&w, &h);
4824 if (s_b_useStencil) {
4825 glEnable(GL_STENCIL_TEST);
4826 glStencilMask(0xff);
4827 glClear(GL_STENCIL_BUFFER_BIT);
4828 glDisable(GL_STENCIL_TEST);
4844 float sxfactor = sx / swidth;
4845 float syfactor = sy / sheight;
4847 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4848 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4849 sx * sx / swidth * 2, sy * sy / sheight * 2);
4850 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4851 glEnable(g_texture_rectangle_format);
4876 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4877 glBindTexture(g_texture_rectangle_format, 0);
4883 float tx, ty, tx0, ty0;
4893 glBindTexture(g_texture_rectangle_format, 0);
4896 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4897 glEnable(g_texture_rectangle_format);
4903 uv[0] = tx0 / m_cache_tex_x;
4904 uv[1] = ty / m_cache_tex_y;
4905 uv[2] = tx / m_cache_tex_x;
4906 uv[3] = ty / m_cache_tex_y;
4907 uv[4] = tx / m_cache_tex_x;
4908 uv[5] = ty0 / m_cache_tex_y;
4909 uv[6] = tx0 / m_cache_tex_x;
4910 uv[7] = ty0 / m_cache_tex_y;
4922 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4923 sx * sx / swidth, sy * sy / sheight);
4925 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4927 glDisable(g_texture_rectangle_format);
4928 glBindTexture(g_texture_rectangle_format, 0);
4935 wxColour color = GetGlobalColor(
"GREY1");
4936 float ht = -offset_y * (sy / sheight);
4937 wxRect r(0, sy - ht, w, ht);
4938 RenderColorRect(r, color);
4941 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4942 RenderColorRect(rt, color);
4945 float w1 = -offset_x * sx / swidth;
4946 wxRect rl(0, 0, w1, sy);
4947 RenderColorRect(rl, color);
4950 float px = w1 + sx * sx / swidth;
4951 wxRect rr(px, 0, sx - px, sy);
4952 RenderColorRect(rr, color);
4961void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4964 if (m_nRun < m_nTotal) {
4965 m_runoffsetx += m_offsetxStep;
4966 if (m_offsetxStep > 0)
4967 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4969 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4971 m_runoffsety += m_offsetyStep;
4972 if (m_offsetyStep > 0)
4973 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4975 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4977 m_runswidth += m_swidthStep;
4978 if (m_swidthStep > 0)
4979 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4981 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4983 m_runsheight += m_sheightStep;
4984 if (m_sheightStep > 0)
4985 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4987 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4992 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4998 if (m_zoomFinaldx || m_zoomFinaldy) {
4999 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5002 m_zoomFinal =
false;
5006void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5008 int sx = GetSize().x;
5009 int sy = GetSize().y;
5011 m_lastfbo_offsetx = m_fbo_offsetx;
5012 m_lastfbo_offsety = m_fbo_offsety;
5013 m_lastfbo_swidth = m_fbo_swidth;
5014 m_lastfbo_sheight = m_fbo_sheight;
5016 float curr_fbo_offset_x = m_fbo_offsetx;
5017 float curr_fbo_offset_y = m_fbo_offsety;
5018 float curr_fbo_swidth = m_fbo_swidth;
5019 float curr_fbo_sheight = m_fbo_sheight;
5021 float fx = (float)cp_x / sx;
5022 float fy = 1.0 - (float)cp_y / sy;
5024 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5025 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5027 m_fbo_swidth = curr_fbo_swidth / factor;
5028 m_fbo_sheight = curr_fbo_sheight / factor;
5030 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5031 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5033 m_fbo_offsetx += post_x;
5034 m_fbo_offsety += post_y;
5045 float perStep = m_nStep / m_nTotal;
5047 if (zoomTimer.IsRunning()) {
5048 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5049 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5050 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5051 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5054 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5055 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5056 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5057 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5059 m_runoffsetx = m_lastfbo_offsetx;
5060 m_runoffsety = m_lastfbo_offsety;
5061 m_runswidth = m_lastfbo_swidth;
5062 m_runsheight = m_lastfbo_sheight;
5065 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5066 m_zoomFinal =
false;
5072void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5076 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5079 if (m_binPinch)
return;
5080 if (m_bpinchGuard)
return;
5082 int x =
event.GetOffset().x;
5083 int y =
event.GetOffset().y;
5085 int lx =
event.GetLastOffset().x;
5086 int ly =
event.GetLastOffset().y;
5091 switch (event.GetState()) {
5092 case GestureStarted:
5093 if (m_binPan)
break;
5097 m_binGesture =
true;
5101 case GestureUpdated:
5106 m_pParentCanvas->FreezePiano();
5108 m_pParentCanvas->ThawPiano();
5119 case GestureFinished:
5122 m_pParentCanvas->UpdateCanvasControlBar();
5125 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5129 case GestureCanceled:
5131 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5138 m_bgestureGuard =
true;
5139 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5140 m_bforcefull =
false;
5145float zoom_inc = 1.0;
5147void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5148 float zoom_gain = 1.0;
5149 float zout_gain = 1.0;
5152 float total_zoom_val;
5154 float max_zoom_scale = 1000.;
5155 float min_zoom_scale = 2e8;
5157 if (event.GetScaleFactor() > 1)
5158 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5160 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5162 if (event.GetTotalScaleFactor() > 1)
5163 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5166 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5168 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5171 float max_zoom_scale = 1000.;
5172 if( cc1->GetVP().b_quilt) {
5173 int ref_index = cc1->GetQuiltRefChartdbIndex();
5180 float min_zoom_scale = 2e8;
5184 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5186 double projected_scale =
5187 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5189 switch (event.GetState()) {
5190 case GestureStarted:
5191 m_first_zout =
false;
5195 m_binGesture =
true;
5197 m_pinchStart =
event.GetCenterPoint();
5198 m_lpinchPoint = m_pinchStart;
5201 event.GetCenterPoint().y, m_pinchlat,
5206 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5207 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5210 if (IsShown()) SetCurrent(*m_pcontext);
5216 case GestureUpdated:
5218 if (projected_scale < min_zoom_scale) {
5219 wxPoint pinchPoint =
event.GetCenterPoint();
5221 float dx = pinchPoint.x - m_lpinchPoint.x;
5222 float dy = pinchPoint.y - m_lpinchPoint.y;
5224 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5225 -dx / total_zoom_val, dy / total_zoom_val);
5227 m_lpinchPoint = pinchPoint;
5231 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5232 wxPoint pinchPoint =
event.GetCenterPoint();
5234 float dx = pinchPoint.x - m_lpinchPoint.x;
5235 float dy = pinchPoint.y - m_lpinchPoint.y;
5237 if ((projected_scale > max_zoom_scale) &&
5238 (projected_scale < min_zoom_scale))
5239 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5240 -dx / total_zoom_val, dy / total_zoom_val);
5242 m_lpinchPoint = pinchPoint;
5245 m_first_zout =
true;
5246 zoom_inc *= zoom_val;
5247 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5248 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5252 wxPoint pinchPoint =
event.GetCenterPoint();
5253 float dx = pinchPoint.x - m_lpinchPoint.x;
5254 float dy = pinchPoint.y - m_lpinchPoint.y;
5256 m_lpinchPoint = pinchPoint;
5267 case GestureFinished: {
5271 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5272 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5276 float tzoom = total_zoom_val;
5278 if (projected_scale >= min_zoom_scale)
5279 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5281 if (projected_scale < max_zoom_scale)
5282 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5284 dx = (cc_x - m_cc_x) * tzoom;
5285 dy = -(cc_y - m_cc_y) * tzoom;
5287 if (zoomTimer.IsRunning()) {
5290 m_zoomFinalZoom = tzoom;
5296 double final_projected_scale =
5300 if (final_projected_scale < min_zoom_scale) {
5304 m_pParentCanvas->m_pQuilt->Invalidate();
5305 m_bforcefull =
true;
5312 m_pParentCanvas->m_pQuilt->Invalidate();
5313 m_bforcefull =
true;
5325 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5329 case GestureCanceled:
5331 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5338 m_bgestureGuard =
true;
5340 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5343void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5353 m_bgestureGuard =
false;
5354 m_bpinchGuard =
false;
5355 m_binGesture =
false;
5356 m_bforcefull =
false;
5359void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5363 m_binGesture =
false;
5364 m_bforcefull =
false;
5368#ifdef HAVE_WX_GESTURE_EVENTS
5370void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5373 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5376 if (m_binPinch)
return;
5377 if (m_bpinchGuard)
return;
5379 int dx =
event.GetDelta().x;
5380 int dy =
event.GetDelta().y;
5382 if (event.IsGestureStart()) {
5383 if (m_binPan)
return;
5387 m_binGesture =
true;
5391 else if (event.IsGestureEnd()) {
5393 m_pParentCanvas->UpdateCanvasControlBar();
5395 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5403 m_pParentCanvas->FreezePiano();
5405 m_pParentCanvas->ThawPiano();
5416 m_bgestureGuard =
true;
5417 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5418 m_bforcefull =
false;
5422void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5424 float zoom_gain = 1.0;
5425 float zout_gain = 1.0;
5427 float last_zoom_val = m_step_zoom_val;
5429 float max_zoom_scale = 1000.;
5430 float min_zoom_scale = 2e8;
5432 if (event.GetZoomFactor() > 1)
5433 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5435 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5437 float inc_zoom_val =
5438 m_total_zoom_val / last_zoom_val;
5442 if (event.IsGestureStart()) {
5443 m_glstopwatch.Start();
5444 printf(
"\nStart--------------\n");
5446 m_pParentCanvas->m_inPinch =
true;
5449 m_binGesture =
true;
5450 m_pinchStart =
event.GetPosition();
5451 m_lpinchPoint = m_pinchStart;
5452 m_total_zoom_val = 1.0;
5453 m_final_zoom_val = 1.0;
5454 m_step_zoom_val = 1.0;
5458 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5462 if (event.IsGestureEnd()) {
5464 if (!m_binGesture)
return;
5465 printf(
"EndZoom--------------\n");
5472 m_final_zoom_val = 1.0;
5473 m_total_zoom_val = 1.0;
5474 m_step_zoom_val = 1.0;
5476 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5483 float zoom_step = 5;
5484 float zoom_trigger = 0.05;
5485 if (projected_scale > 1e5)
5487 else if (projected_scale < 3e4)
5490 if (inc_zoom_val != 1.0) {
5491 if (inc_zoom_val > 1 + zoom_step) {
5492 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5493 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5495 if (IsShown()) SetCurrent(*m_pcontext);
5498 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5499 m_step_zoom_val = m_total_zoom_val;
5500 printf(
" Zoom: %6g\n", inc_zoom_val);
5505 bool b_allow_ztp =
true;
5506 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5507 b_allow_ztp =
false;
5509 if (g_bEnableZoomToCursor && b_allow_ztp) {
5515 int dx = r.x -
event.GetPosition().x;
5516 int dy = r.y -
event.GetPosition().y;
5520 if (IsShown()) SetCurrent(*m_pcontext);
5529 float zoom_gain = 1.0;
5530 float zout_gain = 1.0;
5532 float last_zoom_val = m_total_zoom_val;
5534 float max_zoom_scale = 1000.;
5535 float min_zoom_scale = 2e8;
5537 if (event.GetZoomFactor() > 1)
5538 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5540 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5542 float inc_zoom_val =
5543 m_total_zoom_val / last_zoom_val;
5545 double projected_scale =
5546 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5548 if (event.IsGestureStart()) {
5550 m_first_zout =
false;
5554 m_binGesture =
true;
5555 m_pinchStart =
event.GetPosition();
5556 m_lpinchPoint = m_pinchStart;
5557 m_total_zoom_val = 1.0;
5558 m_final_zoom_val = 1.0;
5561 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5565 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5566 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5569 if (IsShown()) SetCurrent(*m_pcontext);
5572 ViewPort vpr = m_pParentCanvas->VPoint;
5574 GetTouchBackingBitmap(vpr);
5579 if (event.IsGestureEnd()) {
5585 if (!m_binGesture)
return;
5587 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5588 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5592 float tzoom = m_final_zoom_val;
5594 dx = (cc_x - m_cc_x) * tzoom;
5595 dy = -(cc_y - m_cc_y) * tzoom;
5597 if (zoomTimer.IsRunning()) {
5600 m_zoomFinalZoom = tzoom;
5606 double final_projected_scale =
5610 if (final_projected_scale < min_zoom_scale) {
5614 m_pParentCanvas->m_pQuilt->Invalidate();
5615 m_bforcefull =
true;
5622 m_pParentCanvas->m_pQuilt->Invalidate();
5623 m_bforcefull =
true;
5628 m_final_zoom_val = 1.0;
5629 m_total_zoom_val = 1.0;
5630 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5635 if (projected_scale < min_zoom_scale) {
5636 wxPoint pinchPoint =
event.GetPosition();
5638 float dx = pinchPoint.x - m_lpinchPoint.x;
5639 float dy = pinchPoint.y - m_lpinchPoint.y;
5641 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5642 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5644 m_lpinchPoint = pinchPoint;
5645 m_final_zoom_val *= inc_zoom_val;
5649 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5650 wxPoint pinchPoint =
event.GetPosition();
5652 float dx = pinchPoint.x - m_lpinchPoint.x;
5653 float dy = pinchPoint.y - m_lpinchPoint.y;
5655 if ((projected_scale > max_zoom_scale) &&
5656 (projected_scale < min_zoom_scale))
5657 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5658 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5660 m_lpinchPoint = pinchPoint;
5661 m_final_zoom_val *= inc_zoom_val;
5664 m_first_zout =
true;
5665 m_zoom_inc *= inc_zoom_val;
5666 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5667 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5671 wxPoint pinchPoint =
event.GetPosition();
5672 float dx = pinchPoint.x - m_lpinchPoint.x;
5673 float dy = pinchPoint.y - m_lpinchPoint.y;
5675 m_lpinchPoint = pinchPoint;
5679 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5682 m_bgestureGuard =
true;
5683 m_bpinchGuard =
true;
5686void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5695 m_bgestureGuard =
false;
5696 m_bpinchGuard =
false;
5697 m_binGesture =
false;
5698 m_bforcefull =
false;
5701void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5705 m_binGesture =
false;
5706 m_bforcefull =
false;
5708 m_pParentCanvas->m_inPinch =
false;
5709 printf(
"******Finish\n");
5715void glChartCanvas::configureShaders(
ViewPort &vp) {
5716#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5722 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5724 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5725 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5746 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5748 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5749 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5761 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5763 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5764 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5767 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5769 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5770 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5778 shader = pAALine_shader_program[GetCanvasIndex()];
5780 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5783 shader = pring_shader_program[GetCanvasIndex()];
5785 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5786 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5790 if (texture_2DA_shader_program) {
5791 glUseProgram(texture_2DA_shader_program);
5792 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5793 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5794 (
const GLfloat *)pvp->vp_matrix_transform);
5796 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5797 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5805void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5808#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5809 int nl = nVertex / 4;
5811 float *luv = uvCoords;
5814 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5822 glEnableClientState(GL_VERTEX_ARRAY);
5823 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5825 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5826 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5827 glDrawArrays(GL_QUADS, 0, 4);
5834void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5835 float *uvCoords,
ViewPort *vp,
float dx,
5836 float dy,
float angle_rad) {
5837#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5839 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5840 if (!shader)
return;
5845 shader->SetUniform1i(
"uTex", 0);
5850 mat4x4_rotate_Z(Q, I, angle_rad);
5856 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5861 shader->SetAttributePointerf(
"aPos", co1);
5862 shader->SetAttributePointerf(
"aUV", tco1);
5869 GLushort indices1[] = {0,1,3,2};
5870 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5882 tco1[0] = uvCoords[0];
5883 tco1[1] = uvCoords[1];
5884 tco1[2] = uvCoords[2];
5885 tco1[3] = uvCoords[3];
5886 tco1[4] = uvCoords[6];
5887 tco1[5] = uvCoords[7];
5888 tco1[6] = uvCoords[4];
5889 tco1[7] = uvCoords[5];
5894 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5906void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5907#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5909 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5912 shader->SetUniformMatrix4fv(
5913 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5916 colorv[0] = color.Red() / float(256);
5917 colorv[1] = color.Green() / float(256);
5918 colorv[2] = color.Blue() / float(256);
5920 shader->SetUniform4fv(
"color", colorv);
5923 pf[0] = r.x + r.width;
5927 pf[4] = r.x + r.width;
5928 pf[5] = r.y + r.height;
5930 pf[7] = r.y + r.height;
5931 shader->SetAttributePointerf(
"position", pf);
5933 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5941void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5942#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5944 ViewPort VPoint = m_pParentCanvas->VPoint;
5948 GetClientSize(&w, &h);
5949 int sx = GetSize().x;
5950 int sy = GetSize().y;
5954 glViewport(0, 0, (GLint)w, (GLint)h);
5956 if (s_b_useStencil) {
5957 glEnable(GL_STENCIL_TEST);
5958 glStencilMask(0xff);
5959 glClear(GL_STENCIL_BUFFER_BIT);
5960 glDisable(GL_STENCIL_TEST);
5964 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5969 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5970 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5971 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5974 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5976 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5977 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5985 if (bRenderCharts) RenderCharts(gldc, screen_region);
5987 if (bRenderOverlays) {
5988 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5989 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5995 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5998 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5999 DrawDynamicRoutesTracksAndWaypoints(VPoint);
6000 DrawFloatingOverlayObjects(m_gldc);
6004 glBindFramebuffer(GL_FRAMEBUFFER, 0);
6009wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
6011 wxMemoryDC tdc(tbm);
6012 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6020 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6021 dc.SetPen(*wxTRANSPARENT_PEN);
6024 tdc.SelectObject(wxNullBitmap);
6025 m_touch_backing_bitmap = tbm;
6026 CreateBackingTexture();
6028 return m_touch_backing_bitmap;
6031void glChartCanvas::CreateBackingTexture() {
6032 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6033 unsigned char *imgdata = image.GetData();
6034 unsigned char *imgalpha = image.GetAlpha();
6035 m_tex_w = image.GetWidth();
6036 m_tex_h = image.GetHeight();
6037 m_image_width = m_tex_w;
6038 m_image_height = m_tex_h;
6040 GLuint format = GL_RGBA;
6041 GLuint internalformat = g_texture_rectangle_format;
6043 internalformat = GL_RGBA;
6048 unsigned char *teximage =
6049 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6051 for (
int i = 0; i < m_image_height; i++) {
6052 for (
int j = 0; j < m_image_width; j++) {
6053 int s = (i * 3 * m_image_width) + (j * 3);
6054 int d = (i * stride * m_tex_w) + (j * stride);
6056 teximage[d + 0] = imgdata[s + 0];
6057 teximage[d + 1] = imgdata[s + 1];
6058 teximage[d + 2] = imgdata[s + 2];
6059 teximage[d + 3] = 255;
6063 glGenTextures(1, &m_TouchBackingTexture);
6064 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6066 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6067 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6068 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6070 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6072 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6073 GL_UNSIGNED_BYTE, teximage);
6076 glBindTexture(GL_TEXTURE_2D, 0);
Wrapper for creating a ChartCtx based on global vars.
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
Represents an active track that is currently being recorded.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
float GetVPChartScale()
Return the ViewPort chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
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)
Get 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.
Represents a navigational route in the navigation system.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
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.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
bool m_bUseCanvasPanning
Controls OpenGL canvas hardware-accelerated panning mode.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
Class cm93chart and helpers – CM93 chart state.
Global color handling by name.
Global variables stored in configuration file.
Texture emboss effects storage.
bool g_running
Android only.
GLuint g_raster_format
Global instance.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
GLuint g_raster_format
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
bool b_inCompressAllCharts
Flag to control adaptive UI scaling.
int g_mipmap_max_level
Global instance.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
MUI (Modern User Interface) Control bar.
User notifications manager.
#define OVERLAY_CHARTS
Lowest priority for overlays to render above all basic charts.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Purpose: Track and Trackpoint drawing stuff.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
float g_ChartScaleFactorExp
Global instance.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Track and Trackpoint drawing stuff.
Geographic projection and coordinate transformations.