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;
181static wxColor s_regionColor;
182static float g_GLMinCartographicLineWidth;
188#define APIENTRYP APIENTRY *
194#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
195#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
201PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
202PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
203PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
204PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
205PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
206PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
207PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
208PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
209PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
210PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
212PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
213PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
216PFNGLGENBUFFERSPROC s_glGenBuffers;
217PFNGLBINDBUFFERPROC s_glBindBuffer;
218PFNGLBUFFERDATAPROC s_glBufferData;
219PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
221#ifndef USE_ANDROID_GLES2
226typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
228PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
231static int panx, pany;
235#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
236std::vector<GLfloat> s_tess_vertex_work;
237static GLenum s_tess_mode;
241bool glChartCanvas::s_b_useScissorTest;
242bool glChartCanvas::s_b_useStencil;
243bool glChartCanvas::s_b_useStencilAP;
244bool glChartCanvas::s_b_useFBO;
251 while ( upd.HaveRects() )
253 wxRect rect = upd.GetRect();
254 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
261GLboolean QueryExtension(
const char *extName) {
272 extNameLen = strlen(extName);
274 p = (
char *)glGetString(GL_EXTENSIONS);
282 int n = strcspn(p,
" ");
283 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
291int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
292 16, WX_GL_STENCIL_SIZE, 8,
295glTestCanvas::glTestCanvas(wxWindow *parent)
296 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
300int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
301 16, WX_GL_STENCIL_SIZE, 8,
304EVT_PAINT(glChartCanvas::OnPaint)
305EVT_ACTIVATE(glChartCanvas::OnActivate)
306EVT_SIZE(glChartCanvas::OnSize)
307EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
311 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
312 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
315 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
320std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
322 {wxPENSTYLE_DOT, {1, 1}},
323 {wxPENSTYLE_LONG_DASH, {5, 5}},
324 {wxPENSTYLE_SHORT_DASH, {1, 5}},
325 {wxPENSTYLE_DOT_DASH, {5, 1}},
328void glChartCanvas::Init() {
333 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
335 m_cache_current_ch = NULL;
337 m_b_paint_enable =
true;
338 m_in_glpaint =
false;
340 m_cache_tex[0] = m_cache_tex[1] = 0;
343 m_b_BuiltFBO =
false;
344 m_b_DisableFBO =
false;
353 m_bpinchGuard =
false;
354 m_binGesture =
false;
355 m_first_zout =
false;
359 m_last_render_time = -1;
366 m_gldc.SetGLCanvas(
this);
369 m_displayScale = 1.0;
370#if defined(__WXOSX__) || defined(__WXGTK3__)
372 m_displayScale = GetContentScaleFactor();
381 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
385 wxEVT_QT_PINCHGESTURE,
386 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
389 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
394 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
396 onGestureFinishTimerEvent,
400 ZOOM_TIMER, wxEVT_TIMER,
401 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
404 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
405 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
406 zoomTimer.SetOwner(
this, ZOOM_TIMER);
408#ifdef USE_ANDROID_GLES2
417#ifdef HAVE_WX_GESTURE_EVENTS
419 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
424 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
426 onGestureFinishTimerEvent,
430 ZOOM_TIMER, wxEVT_TIMER,
431 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
434 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
435 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
436 zoomTimer.SetOwner(
this, ZOOM_TIMER);
441 m_bgestureGuard =
false;
442 m_total_zoom_val = 1.0;
443 m_step_zoom_val = 1.0;
446#ifdef HAVE_WX_GESTURE_EVENTS
447 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
448 wxLogError(
"Failed to enable touch events");
457 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
459 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
460 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
462 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
463 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
465 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
466 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
468 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
469 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
475glChartCanvas::~glChartCanvas() {
481int glChartCanvas::GetCanvasIndex() {
return m_pParentCanvas->m_canvasIndex; }
483void glChartCanvas::FlushFBO() {
484 if (m_bsetup) BuildFBO();
487void glChartCanvas::OnActivate(wxActivateEvent &event) {
488 m_pParentCanvas->OnActivate(event);
491void glChartCanvas::OnSize(wxSizeEvent &event) {
494 ViewPort *vp = m_pParentCanvas->GetpVP();
495 vp->SetVPTransformMatrix();
498 if (!m_bsetup)
return;
500 if (!IsShown())
return;
502 SetCurrent(*m_pcontext);
506 SetSize(GetSize().x, GetSize().y);
514 if (m_pcontext && IsShown()) {
515 SetCurrent(*m_pcontext);
518 wxLogDebug(
"BuildFBO 3");
522void glChartCanvas::MouseEvent(wxMouseEvent &event) {
523 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
529 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
531 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
534 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
538 if (m_bgestureGuard) {
539 m_pParentCanvas->r_rband.x = 0;
549 if (event.LeftUp()) {
551 if ((abs(panx) > 2) || (abs(pany) > 2)) {
554 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
561 if (!event.LeftDClick()) {
566 if (m_binPan && event.RightDown()) {
567 qDebug() <<
"Skip right on pan";
570 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
572 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
573 if (!m_bgestureGuard)
583#ifndef GL_MAX_RENDERBUFFER_SIZE
584#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
587#ifndef USE_ANDROID_GLES2
588bool glChartCanvas::buildFBOSize(
int fboSize) {
590 if (IsShown()) SetCurrent(*m_pcontext);
593 glDeleteTextures(2, m_cache_tex);
594 glDeleteFramebuffers(1, &m_fb0);
595 glDeleteRenderbuffers(1, &m_renderbuffer);
596 m_b_BuiltFBO =
false;
599 if (m_b_DisableFBO)
return false;
603 int rb_x = GetSize().x;
604 int rb_y = GetSize().y;
606 while (i < rb_x) i <<= 1;
610 while (i < rb_y) i <<= 1;
613 m_cache_tex_x = wxMax(rb_x, rb_y);
614 m_cache_tex_y = wxMax(rb_x, rb_y);
617 m_cache_tex_x = GetSize().x * m_displayScale;
618 m_cache_tex_y = GetSize().y * m_displayScale;
621 int err = GL_NO_ERROR;
623 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
626 if (err == GL_INVALID_ENUM) {
627 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
631 if (err == GL_NO_ERROR) {
632 if (fboSize > params) {
634 " OpenGL-> Requested Framebuffer size exceeds "
635 "GL_MAX_RENDERBUFFER_SIZE");
640 glGenFramebuffers(1, &m_fb0);
644 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
649 glGenRenderbuffers(1, &m_renderbuffer);
653 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
658 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
662 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
668 glGenTextures(2, m_cache_tex);
669 for (
int i = 0; i < 2; i++) {
670 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
671 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
673 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
675 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
676 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
679 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
681 if (m_b_useFBOStencil) {
683 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
684 m_cache_tex_x, m_cache_tex_y);
686 int err = glGetError();
689 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
693 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
694 GL_RENDERBUFFER_EXT, m_renderbuffer);
698 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
703 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
704 GL_RENDERBUFFER_EXT, m_renderbuffer);
708 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
714 GLenum depth_format = GL_DEPTH_COMPONENT24;
719 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
723 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
725 int err = glGetError();
728 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
734 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
735 GL_RENDERBUFFER_EXT, m_renderbuffer);
740 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
747 glBindTexture(GL_TEXTURE_2D, 0);
748 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
751 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
753 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
754 g_texture_rectangle_format, m_cache_tex[0], 0);
756 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
758 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
760 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
762 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
772#ifdef USE_ANDROID_GLES2
773bool glChartCanvas::buildFBOSize(
int fboSize) {
777 int rb_x = GetSize().x;
778 int rb_y = GetSize().y;
780 while (i < rb_x) i <<= 1;
784 while (i < rb_y) i <<= 1;
787 m_cache_tex_x = wxMax(rb_x, rb_y);
788 m_cache_tex_y = wxMax(rb_x, rb_y);
792 int err = GL_NO_ERROR;
794 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
797 if (err == GL_INVALID_ENUM) {
798 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
802 if (err == GL_NO_ERROR) {
803 if (fboSize > params) {
805 " OpenGL-> Requested Framebuffer size exceeds "
806 "GL_MAX_RENDERBUFFER_SIZE");
811 glGenFramebuffers(1, &m_fb0);
815 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
820 glGenRenderbuffers(1, &m_renderbuffer);
824 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
829 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
833 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
839 glGenTextures(2, m_cache_tex);
840 for (
int i = 0; i < 2; i++) {
841 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
842 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
844 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
846 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
847 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
850 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
853 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
859 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
863 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
864 GL_RENDERBUFFER, m_renderbuffer);
868 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
873 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
874 GL_RENDERBUFFER, m_renderbuffer);
878 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
883 glBindTexture(GL_TEXTURE_2D, 0);
884 glBindFramebuffer(GL_FRAMEBUFFER, 0);
887 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
889 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
890 g_texture_rectangle_format, m_cache_tex[0], 0);
892 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
894 glBindFramebuffer(GL_FRAMEBUFFER, 0);
896 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
898 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
908void glChartCanvas::BuildFBO() {
909 if (g_b_needFinish) glFinish();
913 glDeleteTextures(2, m_cache_tex);
914 glDeleteFramebuffers(1, &m_fb0);
915 glDeleteRenderbuffers(1, &m_renderbuffer);
916 m_b_BuiltFBO =
false;
919 if (m_b_DisableFBO)
return;
922 int gl_width, gl_height;
923 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
924 int initialSize = NextPow2(gl_width * m_displayScale);
929 wxString info = androidGetDeviceInfo();
931 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
934 if (!buildFBOSize(initialSize)) {
935 glDeleteTextures(2, m_cache_tex);
936 glDeleteFramebuffers(1, &m_fb0);
937 glDeleteRenderbuffers(1, &m_renderbuffer);
939 if (!buildFBOSize(1024)) {
940 wxLogMessage(
"BuildFBO C");
942 m_b_DisableFBO =
true;
943 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
944 m_b_BuiltFBO =
false;
953 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
965void glChartCanvas::SetupOpenGL() {
966 if (IsShown()) SetCurrent(*m_pcontext);
968 char *str = (
char *)glGetString(GL_RENDERER);
971 wxLogMessage(
"Failed to initialize OpenGL");
975 char render_string[80];
976 strncpy(render_string, str, 79);
977 m_renderer = wxString(render_string, wxConvUTF8);
980 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
981 msg.Printf(
"OpenGL-> Renderer String: ");
985 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
987 char version_string[80];
988 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
989 msg.Printf(
"OpenGL-> Version reported: ");
990 m_version = wxString(version_string, wxConvUTF8);
994 char GLSL_version_string[80];
995 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
997 msg.Printf(
"OpenGL-> GLSL Version reported: ");
998 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
999 msg += m_GLSLversion;
1004 GLenum err = glewInit();
1005#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1006 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1011 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1014 wxLogMessage(
"GLEW init success!n");
1019 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1020 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1024#ifndef USE_ANDROID_GLES2
1025 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1027 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1029 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1030 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1037 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1039 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1041 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1044 s_b_useScissorTest =
true;
1046 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1047 s_b_useScissorTest =
false;
1049 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1050 s_b_useScissorTest =
false;
1052 bool bad_stencil_code =
false;
1055 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1056 bad_stencil_code =
true;
1059 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1062 glEnable(GL_STENCIL_TEST);
1063 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1065 glGetIntegerv(GL_STENCIL_BITS, &sb);
1068 glDisable(GL_STENCIL_TEST);
1070 s_b_useStencil =
false;
1071 if (stencil && (sb == 8)) s_b_useStencil =
true;
1073 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1074 g_texture_rectangle_format = GL_TEXTURE_2D;
1075 else if (QueryExtension(
"GL_OES_texture_npot"))
1076 g_texture_rectangle_format = GL_TEXTURE_2D;
1077 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1078 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1079 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1080 g_texture_rectangle_format));
1083 g_texture_rectangle_format = GL_TEXTURE_2D;
1087 g_b_EnableVBO =
true;
1090 g_b_EnableVBO =
false;
1094 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1096 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1100 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1102 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1105#ifndef USE_ANDROID_GLES2
1107 if (bad_stencil_code) s_b_useStencil =
false;
1121 if (m_displayScale > 1) m_b_DisableFBO =
true;
1130 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1132 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1133 g_texture_rectangle_format, m_cache_tex[0], 0);
1135 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1136 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1138 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1140 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1142 m_b_DisableFBO =
true;
1148 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1152 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1154#ifdef USE_ANDROID_GLES2
1155 s_b_useStencilAP = s_b_useStencil;
1162 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1164 if (m_b_useFBOStencil)
1165 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1167 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1169 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1172 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1174 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1176 if (s_b_useScissorTest && s_b_useStencil)
1177 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1180 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1182 MipMap_ResolveRoutines();
1186 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1187 g_GLMinCartographicLineWidth);
1188 wxLogMessage(lwmsg);
1189 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1190 g_GLMinSymbolLineWidth);
1191 wxLogMessage(lwmsg);
1194 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1196#ifdef USE_ANDROID_GLES2
1197 g_GLOptions.m_bUseAcceleratedPanning =
true;
1203 int tex_dim = g_GLOptions.m_iTextureDimension;
1204 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1213 s_b_useFBO = m_b_BuiltFBO;
1217 ps52plib->SetGLOptions(
1218 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1219 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1220 g_GLMinSymbolLineWidth);
1224 SendJSONConfigMessage();
1227void glChartCanvas::SendJSONConfigMessage() {
1230 v[
"setupComplete"] = m_bsetup;
1231 v[
"useStencil"] = s_b_useStencil;
1232 v[
"useStencilAP"] = s_b_useStencilAP;
1233 v[
"useScissorTest"] = s_b_useScissorTest;
1234 v[
"useFBO"] = s_b_useFBO;
1235 v[
"useVBO"] = g_b_EnableVBO;
1236 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1237 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1238 SendJSONMessageToAllPlugins(msg_id, v);
1241void glChartCanvas::SetupCompression() {
1242 int dim = g_GLOptions.m_iTextureDimension;
1245 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1246 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1247 goto no_compression;
1251 g_uncompressed_tile_size = dim * dim * 4;
1252 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1258 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1261 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1271 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1272 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1275 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1276 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1281 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1282 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1285 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1287 wxLogMessage(
"OpenGL-> No Useable compression format found");
1288 goto no_compression;
1293 g_tile_size = 512 * 512 / 2;
1297 glGenTextures(1, &texture);
1298 glBindTexture(GL_TEXTURE_2D, texture);
1300 GL_UNSIGNED_BYTE, NULL);
1301 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1303 glDeleteTextures(1, &texture);
1307 if (g_tile_size == 0)
goto no_compression;
1309 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1311 g_uncompressed_tile_size / g_tile_size));
1315 g_GLOptions.m_bTextureCompression =
false;
1317 g_tile_size = g_uncompressed_tile_size;
1318 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1321void glChartCanvas::OnPaint(wxPaintEvent &event) {
1323 if (!m_pcontext)
return;
1332 if (IsShown()) SetCurrent(*m_pcontext);
1337 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1345 if (!m_b_paint_enable)
return;
1348 if (m_in_glpaint)
return;
1351 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1374bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1376#ifndef USE_ANDROID_GLES2
1377 return vp.m_projection_type == PROJECTION_MERCATOR ||
1378 vp.m_projection_type == PROJECTION_POLAR ||
1379 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1393#define NORM_FACTOR 4096.0
1394void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1395#ifndef USE_ANDROID_GLES2
1397 wxPoint2DDouble point;
1399 switch (vp.m_projection_type) {
1400 case PROJECTION_MERCATOR:
1401 case PROJECTION_EQUIRECTANGULAR:
1402 case PROJECTION_WEB_MERCATOR:
1405 glTranslated(point.m_x, point.m_y, 0);
1410 case PROJECTION_POLAR:
1414 glTranslated(point.m_x, point.m_y, 0);
1415 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1422 printf(
"ERROR: Unhandled projection\n");
1427 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1435 switch (vp.m_projection_type) {
1436 case PROJECTION_MERCATOR:
1437 case PROJECTION_EQUIRECTANGULAR:
1438 case PROJECTION_WEB_MERCATOR:
1442 case PROJECTION_POLAR:
1447 printf(
"ERROR: Unhandled projection\n");
1456bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1457 return vp.m_projection_type == PROJECTION_MERCATOR ||
1458 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1459 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1463 const LLRegion ®ion) {
1464 if (!CanClipViewport(vp))
return vp;
1467 LLBBox bbox = region.GetBox();
1469 if (!bbox.GetValid())
return vp;
1477 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1478 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1479 bbox.GetMaxLon() + 360);
1480 cvp.SetBBoxDirect(bbox);
1481 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1482 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1483 bbox.GetMaxLon() - 360);
1484 cvp.SetBBoxDirect(bbox);
1486 cvp.SetBBoxDirect(bbox);
1491void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1492 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1498 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1500 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1504 if (!pRouteDraw)
continue;
1507 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1510 if (pRouteDraw->m_bIsBeingEdited)
continue;
1512 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1517 if (vp.GetBBox().GetValid() && pWayPointMan) {
1518 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1519 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1520 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1526void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1531 if (pActiveTrack && pActiveTrack->IsRunning())
1532 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1538 if (!pRouteDraw)
continue;
1541 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1544 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1547 if (pRouteDraw->IsSelected()) drawit++;
1550 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1551 if (!vp_box.IntersectOut(test_box))
1552 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1558 if (vp.GetBBox().GetValid() && pWayPointMan) {
1559 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1560 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1567static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1571 switch (vp.m_projection_type) {
1572 case PROJECTION_TRANSVERSE_MERCATOR:
1573 lat_dist = 4, lon_dist = 1;
1575 case PROJECTION_POLYCONIC:
1576 lat_dist = 2, lon_dist = 1;
1578 case PROJECTION_ORTHOGRAPHIC:
1579 lat_dist = 2, lon_dist = 2;
1581 case PROJECTION_POLAR:
1582 lat_dist = 180, lon_dist = 1;
1584 case PROJECTION_STEREOGRAPHIC:
1585 case PROJECTION_GNOMONIC:
1586 lat_dist = 2, lon_dist = 1;
1588 case PROJECTION_EQUIRECTANGULAR:
1591 lat_dist = 2, lon_dist = 360;
1594 lat_dist = 180, lon_dist = 360;
1598void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1599 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1605 ChartData->GetDBBoundingBox(dbIndex, box);
1606 if (!box.GetValid())
return;
1610 if (box.GetLonRange() == 360)
return;
1612 LLBBox vpbox = vp.GetBBox();
1614 double lon_bias = 0;
1616 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1619 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1620 color = GetGlobalColor(
"YELO1");
1621 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1622 color = GetGlobalColor(
"GREEN2");
1624 color = GetGlobalColor(
"UINFR");
1626#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1627 float plylat, plylon;
1629 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1631 glColor3ub(color.Red(), color.Green(), color.Blue());
1632 glLineWidth(g_GLMinSymbolLineWidth);
1634 float lat_dist, lon_dist;
1635 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1638 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1642 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1644 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1646 bool begin =
false, sml_valid =
false;
1648 float lastplylat = 0.0;
1649 float lastplylon = 0.0;
1651 int modulo = (nPly == 0) ? 1 : nPly;
1652 for (
int i = 0; i < nPly + 1; i++) {
1654 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1656 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1660 if (lastplylon - plylon > 180)
1662 else if (lastplylon - plylon < -180)
1669 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1670 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1671 splits = wxMax(lat_splits, lon_splits) + 1;
1678 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1679 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1682 for (
double c = 0; c < splits; c++) {
1684 if (c == splits - 1)
1685 lat = plylat, lon = plylon;
1687 double d = (double)(c + 1) / splits;
1688 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1694 if (!std::isnan(s.m_x)) {
1697 glBegin(GL_LINE_STRIP);
1699 glVertex2f(s.m_x, s.m_y);
1705 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1706 lastplylat = plylat, lastplylon = plylon;
1711 }
while (++j < nAuxPlyEntries);
1713 glDisable(GL_LINE_SMOOTH);
1717 double nominal_line_width_pix =
1718 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1720 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1721 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1724 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1725 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1729 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1732 float plylat1, plylon1;
1736 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1737 if (0 == nAuxPlyEntries)
1740 std::vector<int> points_vector;
1742 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1743 int nPly = vec.size() / 2;
1745 if (nPly == 0)
return;
1747 for (
int i = 0; i < nPly; i++) {
1748 plylon1 = vec[i * 2];
1749 plylat1 = vec[i * 2 + 1];
1755 points_vector.push_back(pixx1);
1756 points_vector.push_back(pixy1);
1759 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1760 plylon1 += lon_bias;
1766 points_vector.push_back(pixx1);
1767 points_vector.push_back(pixy1);
1769 if (points_vector.size()) {
1770 std::vector<int>::iterator it = points_vector.begin();
1771 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1779 for (
int j = 0; j < nAuxPlyEntries; j++) {
1780 std::vector<int> points_vector;
1782 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1783 int nAuxPly = vec.size() / 2;
1785 if (nAuxPly == 0)
continue;
1787 for (
int i = 0; i < nAuxPly; i++) {
1788 plylon1 = vec[i * 2];
1789 plylat1 = vec[i * 2 + 1];
1795 points_vector.push_back(pixx1);
1796 points_vector.push_back(pixy1);
1803 points_vector.push_back(pixx1);
1804 points_vector.push_back(pixy1);
1806 if (points_vector.size()) {
1807 std::vector<int>::iterator it = points_vector.begin();
1808 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1816extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1817 float &MinorSpacing);
1818extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1819void glChartCanvas::GridDraw() {
1820 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1822 ViewPort &vp = m_pParentCanvas->GetVP();
1824 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1828 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1830 double nlat, elon, slat, wlon;
1832 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1835 wxColour GridColor = GetGlobalColor(
"SNDG1");
1837 if (!m_gridfont.IsBuilt()) {
1839 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1840 wxFont font = *dFont;
1843 int font_size = wxMax(10, dFont->GetPointSize());
1844 font.SetPointSize(font_size);
1845 font.SetWeight(wxFONTWEIGHT_NORMAL);
1848 m_gridfont.Build(font, m_displayScale, dpi_factor);
1850 m_gridfont.SetColor(GridColor);
1855 LLBBox llbbox = vp.GetBBox();
1856 nlat = llbbox.GetMaxLat();
1857 slat = llbbox.GetMinLat();
1858 elon = llbbox.GetMaxLon();
1859 wlon = llbbox.GetMinLon();
1866 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1867 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1868 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1869 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1870 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1871 vp.m_projection_type == PROJECTION_POLAR ||
1872 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1875 if (straight_latitudes)
1878 latmargin = gridlatMajor / 2;
1880 slat = wxMax(slat, -90 + latmargin);
1881 nlat = wxMin(nlat, 90 - latmargin);
1883 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1884 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1888 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1895 float lon_step = elon - wlon;
1896 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1898 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1900 s.x = INVALID_COORD;
1901 s.y = INVALID_COORD;
1902 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1904 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1905 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1913 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1914 lat += gridlatMinor) {
1917 gldc.DrawLine(0, r.y, 10, r.y,
true);
1918 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1923 float lat_step = nlat - slat;
1924 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1926 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1928 s.x = INVALID_COORD;
1929 s.y = INVALID_COORD;
1930 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1932 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1933 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1941 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1942 lon += gridlonMinor) {
1945 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1946 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1952 glEnable(GL_TEXTURE_2D);
1954 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1955 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1958 CalcGridText(lat, gridlatMajor,
true);
1960 m_gridfont.GetTextExtent(st, 0, &iy);
1962 if (straight_latitudes) {
1967 float x = 0, y = -1;
1968 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1969 if (y < 0 || y > h) {
1971 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1974 m_gridfont.RenderString(st, x, y);
1978 double y1, y2, lat1, lon1, lat2, lon2;
1987 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
1990 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
1992 if (fabs(y - y1) < fabs(y - y2))
1998 error = fabs(r.m_x);
1999 if (--maxiters == 0)
break;
2000 }
while (error > 1 && error < lasterror);
2002 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2008 m_gridfont.RenderString(st, r.m_x, r.m_y);
2012 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2013 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2022 else if (xlon <= -180.0)
2025 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2027 m_gridfont.GetTextExtent(st, &ix, 0);
2029 if (straight_longitudes) {
2030 float x = -1, y = 0;
2031 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2032 if (x < 0 || x > w) {
2034 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2037 m_gridfont.RenderString(st, x, y);
2041 double x1, x2, lat1, lon1, lat2, lon2;
2049 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2052 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2054 if (fabs(x - x1) < fabs(x - x2))
2060 error = fabs(r.m_y);
2061 }
while (error > 1 && error < lasterror);
2063 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2068 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2070 m_gridfont.RenderString(st, r.m_x, r.m_y);
2074 glDisable(GL_TEXTURE_2D);
2075 glDisable(GL_BLEND);
2080 if (!emboss)
return;
2082 int w = emboss->width, h = emboss->height;
2084 glEnable(GL_TEXTURE_2D);
2087 if (!emboss->gltexind) {
2089 emboss->glwidth = NextPow2(emboss->width);
2090 emboss->glheight = NextPow2(emboss->height);
2093 int size = emboss->glwidth * emboss->glheight;
2094 char *data =
new char[2 * size];
2095 for (
int i = 0; i < h; i++) {
2096 for (
int j = 0; j < emboss->glwidth; j++) {
2098 data[2 * ((i * emboss->glwidth) + j)] =
2099 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2100 data[2 * ((i * emboss->glwidth) + j) + 1] =
2101 (char)abs((emboss->pmap[(i * w) + j]));
2106 glGenTextures(1, &emboss->gltexind);
2107 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2108 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2109 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2117 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2121 int x = emboss->x, y = emboss->y;
2123 float wp = (float)w / emboss->glwidth;
2124 float hp = (float)h / emboss->glheight;
2150 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2152 glDisable(GL_BLEND);
2153 glDisable(GL_TEXTURE_2D);
2156void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2157 if (!m_pParentCanvas->GetVP().IsValid())
return;
2158 wxPoint GPSOffsetPixels(0, 0);
2159 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2162 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2163 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2167 double shift_dx = 0;
2168 double shift_dy = 0;
2169 bool dynamic = m_pParentCanvas->m_animationActive ||
2170 m_pParentCanvas->m_MouseDragging ||
2171 m_pParentCanvas->m_chart_drag_inertia_active;
2172 if (m_pParentCanvas->m_bFollow && !dynamic) {
2173 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2174 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2175 if (m_pParentCanvas->m_bLookAhead) {
2181 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2182 angle += m_pParentCanvas->GetVPRotation();
2183 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2185 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2186 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2188 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2193 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2194 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2201 lShipMidPoint = lGPSPoint;
2205 float icon_hdt = pCog;
2206 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2209 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2213 double osd_head_lat, osd_head_lon;
2214 wxPoint2DDouble osd_head_point;
2216 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2220 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2222 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2223 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2224 icon_rad += (float)PI;
2228 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2232 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2238 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2239 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2240 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2245 float scale_factor = 1.0;
2250 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2251 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2252 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2254 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2256 float nominal_ownship_size_pixels =
2258 nominal_ownship_size_mm);
2260 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2262 wxPen ppSmallScaleShip;
2263 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2265 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2268 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2269 dc.SetPen(ppSmallScaleShip);
2271 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2274 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2275 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2276 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2277 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2280 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2281 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2284 int draw_color = SHIP_INVALID;
2285 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2286 draw_color = SHIP_NORMAL;
2287 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2288 draw_color = SHIP_LOWACCURACY;
2296 ownship_color = draw_color;
2298 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2300 glGenTextures(1, &ownship_tex);
2301 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2307 if (m_pParentCanvas->m_pos_image_user) {
2308 switch (draw_color) {
2310 image = *m_pParentCanvas->m_pos_image_user_grey;
2313 image = *m_pParentCanvas->m_pos_image_user;
2315 case SHIP_LOWACCURACY:
2316 image = *m_pParentCanvas->m_pos_image_user_yellow;
2320 switch (draw_color) {
2322 image = *m_pParentCanvas->m_pos_image_grey;
2325 image = *m_pParentCanvas->m_pos_image_red;
2327 case SHIP_LOWACCURACY:
2328 image = *m_pParentCanvas->m_pos_image_yellow;
2333 int w = image.GetWidth(), h = image.GetHeight();
2334 int glw = NextPow2(w), glh = NextPow2(h);
2335 ownship_size = wxSize(w, h);
2336 ownship_tex_size = wxSize(glw, glh);
2338 unsigned char *d = image.GetData();
2339 unsigned char *a = image.GetAlpha();
2340 unsigned char *e =
new unsigned char[4 * w * h];
2343 for (
int p = 0; p < w * h; p++) {
2344 e[4 * p + 0] = d[3 * p + 0];
2345 e[4 * p + 1] = d[3 * p + 1];
2346 e[4 * p + 2] = d[3 * p + 2];
2347 e[4 * p + 3] = a[p];
2350 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2351 GL_UNSIGNED_BYTE, 0);
2353 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2359#ifndef USE_ANDROID_GLES2
2360 if (m_pParentCanvas->m_pos_image_user)
2361 glColor4ub(255, 255, 255, 255);
2362 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2363 glColor4ub(255, 0, 0, 255);
2364 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2365 glColor4ub(255, 255, 0, 255);
2367 glColor4ub(128, 128, 128, 255);
2369 float scale_factor_y = 1.0;
2370 float scale_factor_x = 1.0;
2372 int ownShipWidth = 22;
2373 int ownShipLength = 84;
2374 lShipMidPoint = lGPSPoint;
2377 if (g_OwnShipIconType != 0)
2378 m_pParentCanvas->ComputeShipScaleFactor(
2379 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2380 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2385 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2386 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2387 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2391 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2392 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2396 float gps_circle_radius = 3.0;
2398 if (g_OwnShipIconType == 0) {
2400 glEnable(GL_TEXTURE_2D);
2401 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2410 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2411 if (m_pParentCanvas->m_pos_image_user)
2412 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2414 float nominal_ownship_size_mm =
2415 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2417 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2418 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2420 float nominal_ownship_size_pixels =
2421 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2423 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2424 nominal_ownship_size_pixels = wxMax(
2425 20.0, nominal_ownship_size_pixels);
2428 float h = nominal_ownship_size_pixels * scale_factor_y;
2429 float w = nominal_ownship_size_pixels * scale_factor_x *
2430 ownship_size.x / ownship_size.y;
2431 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2432 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2438 gps_circle_radius = w / 5;
2440 float uv[8], coords[8];
2459 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2460 lShipMidPoint.m_x, lShipMidPoint.m_y,
2462 glDisable(GL_TEXTURE_2D);
2463 }
else if (g_OwnShipIconType == 1) {
2465 glEnable(GL_TEXTURE_2D);
2466 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2468 float nominal_ownship_size_pixels_y = 84;
2469 float nominal_ownship_size_pixels_x = 22;
2471 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2472 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2474 float u = (float)ownship_size.x / ownship_tex_size.x,
2475 v = (
float)ownship_size.y / ownship_tex_size.y;
2478 gps_circle_radius = w / 5;
2480 float uv[8], coords[8];
2499 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2500 lShipMidPoint.m_x, lShipMidPoint.m_y,
2503 glDisable(GL_TEXTURE_2D);
2504 }
else if (g_OwnShipIconType == 2) {
2512 wxPoint shipPoints[6];
2514 wxColour colour = m_pParentCanvas->ShipColor();
2515 wxPen ppPen(*wxBLACK, 1);
2516 wxBrush ppBrush(colour);
2518 dc.SetBrush(ppBrush);
2520 shipPoints[0].x = 0 * scale_factor_x;
2521 shipPoints[0].y = -28 * scale_factor_y;
2522 shipPoints[1].x = 11 * scale_factor_x;
2523 shipPoints[1].y = -28 * scale_factor_y;
2524 shipPoints[2].x = 11 * scale_factor_x;
2525 shipPoints[2].y = 42 * scale_factor_y;
2526 shipPoints[3].x = 0 * scale_factor_x;
2527 shipPoints[3].y = 42 * scale_factor_y;
2528 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2531 shipPoints[0].x = 0 * scale_factor_x;
2532 shipPoints[0].y = -42 * scale_factor_y;
2533 shipPoints[1].x = 5 * scale_factor_x;
2534 shipPoints[1].y = -42 * scale_factor_y;
2535 shipPoints[2].x = 11 * scale_factor_x;
2536 shipPoints[2].y = -28 * scale_factor_y;
2537 shipPoints[3].x = 0 * scale_factor_x;
2538 shipPoints[3].y = -28 * scale_factor_y;
2539 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2542 shipPoints[0].x = 0 * scale_factor_x;
2543 shipPoints[0].y = -28 * scale_factor_y;
2544 shipPoints[1].x = -11 * scale_factor_x;
2545 shipPoints[1].y = -28 * scale_factor_y;
2546 shipPoints[2].x = -11 * scale_factor_x;
2547 shipPoints[2].y = 42 * scale_factor_y;
2548 shipPoints[3].x = 0 * scale_factor_x;
2549 shipPoints[3].y = 42 * scale_factor_y;
2550 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2553 shipPoints[0].x = 0 * scale_factor_x;
2554 shipPoints[0].y = -42 * scale_factor_y;
2555 shipPoints[1].x = -5 * scale_factor_x;
2556 shipPoints[1].y = -42 * scale_factor_y;
2557 shipPoints[2].x = -11 * scale_factor_x;
2558 shipPoints[2].y = -28 * scale_factor_y;
2559 shipPoints[3].x = 0 * scale_factor_x;
2560 shipPoints[3].y = -28 * scale_factor_y;
2561 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2565 double p1x = -11 * scale_factor_x;
2566 double p2x = 11 * scale_factor_x;
2570 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2572 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2574 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2576 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2577 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2578 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2582 p1y = -42 * scale_factor_y;
2583 p2y = 42 * scale_factor_y;
2584 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2585 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2586 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2587 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2588 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2589 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2592 img_height = ownShipLength * scale_factor_y;
2595 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2597 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2599 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2601 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2605 glDisable(GL_LINE_SMOOTH);
2606 glDisable(GL_POLYGON_SMOOTH);
2607 glDisable(GL_BLEND);
2610 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2614void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2615 ViewPort &vp = m_pParentCanvas->GetVP();
2638 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2640 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2641 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2643 m_pParentCanvas->AlertDraw(dc);
2645 m_pParentCanvas->RenderVisibleSectorLights(dc);
2647 m_pParentCanvas->RenderRouteLegs(dc);
2648 m_pParentCanvas->RenderShipToActive(dc,
true);
2649 m_pParentCanvas->ScaleBarDraw(dc);
2650 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2651 m_pParentCanvas->extendedSectorLegs);
2658void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2659 if (m_pParentCanvas->GetPiano()) {
2660 int canvas_height = GetClientSize().y;
2661 canvas_height *= m_displayScale;
2663 m_pParentCanvas->GetPiano()->DrawGL(
2664 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2668void glChartCanvas::DrawQuiting() {
2669#ifndef USE_ANDROID_GLES2
2670 GLubyte pattern[8][8];
2671 for (
int y = 0; y < 8; y++)
2672 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2675 glEnable(GL_TEXTURE_2D);
2676 glBindTexture(GL_TEXTURE_2D, 0);
2678 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2679 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2680 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2682 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2686 float x = GetSize().x, y = GetSize().y;
2687 float u = x / 8, v = y / 8;
2700 glDisable(GL_TEXTURE_2D);
2701 glDisable(GL_BLEND);
2705void glChartCanvas::DrawCloseMessage(wxString msg) {
2706#ifndef USE_ANDROID_GLES2
2710 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2714 texfont.Build(*pfont, 1, 1);
2716 texfont.GetTextExtent(msg, &w, &h);
2718 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2719 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2721 glColor3ub(243, 229, 47);
2725 glVertex2i(xp + w, yp);
2726 glVertex2i(xp + w, yp + h);
2727 glVertex2i(xp, yp + h);
2732 glColor3ub(0, 0, 0);
2733 glEnable(GL_TEXTURE_2D);
2734 texfont.RenderString(msg, xp, yp);
2735 glDisable(GL_TEXTURE_2D);
2736 glDisable(GL_BLEND);
2743static std::list<double *> combine_work_data;
2744static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2745 GLfloat weight[4], GLdouble **dataOut) {
2746 double *vertex =
new double[3];
2747 combine_work_data.push_back(vertex);
2748 memcpy(vertex, coords, 3 * (
sizeof *coords));
2752#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2753void vertexCallbackD_GLSL(GLvoid *vertex) {
2754 GLdouble *pointer = (GLdouble *)vertex;
2755 s_tess_vertex_work.push_back(pointer[0]);
2756 s_tess_vertex_work.push_back(pointer[1]);
2759void beginCallbackD_GLSL(GLenum mode) {
2761 s_tess_vertex_work.clear();
2764void endCallbackD_GLSL() {
2765 if (!s_tess_vertex_work.empty() && (s_tess_vertex_work.size() % 2 == 0)) {
2769 shader->SetUniformMatrix4fv(
"MVMatrix",
2770 (GLfloat *)s_tessVP.vp_matrix_transform);
2772 mat4x4 identityMatrix;
2773 mat4x4_identity(identityMatrix);
2774 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2778 colorv[0] = s_regionColor.Red() / float(256);
2779 colorv[1] = s_regionColor.Green() / float(256);
2780 colorv[2] = s_regionColor.Blue() / float(256);
2781 colorv[3] = s_regionColor.Alpha() / float(256);
2782 shader->SetUniform4fv(
"color", colorv);
2783 shader->SetAttributePointerf(
"position", s_tess_vertex_work.data());
2785 glDrawArrays(s_tess_mode, 0, s_tess_vertex_work.size() / 2);
2790 "::endCallbackD_GLSL() called with wrong tess vertex vector length "
2792 s_tess_vertex_work.size());
2795void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2797void beginCallbackD(GLenum mode) { glBegin(mode); }
2799void endCallbackD() { glEnd(); }
2803void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2804 float lat_dist, lon_dist;
2805 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2807 GLUtesselator *tobj = gluNewTess();
2808 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2810#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2811 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2812 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2813 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2814 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2818 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2819 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2820 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2821 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2824 gluTessNormal(tobj, 0, 0, 1);
2826 gluTessBeginPolygon(tobj, NULL);
2827 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2828 gluTessBeginContour(tobj);
2829 contour_pt l = *i->rbegin();
2831 bool sml_valid =
false;
2832 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2833 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2834 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2835 int splits = wxMax(lat_splits, lon_splits) + 1;
2841 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2842 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2845 for (
int i = 0; i < splits; i++) {
2847 if (i == splits - 1)
2848 lat = j->y, lon = j->x;
2850 double d = (double)(i + 1) / splits;
2851 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2855 if (std::isnan(q.m_x))
continue;
2857 double *p =
new double[6];
2862 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2867 gluTessVertex(tobj, p, p);
2868 combine_work_data.push_back(p);
2872 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2874 gluTessEndContour(tobj);
2876 gluTessEndPolygon(tobj);
2878 gluDeleteTess(tobj);
2880 for (std::list<double *>::iterator i = combine_work_data.begin();
2881 i != combine_work_data.end(); i++)
2883 combine_work_data.clear();
2888void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2889 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2891 if (s_b_useStencil) {
2893 glEnable(GL_STENCIL_TEST);
2895 glClear(GL_STENCIL_BUFFER_BIT);
2899 glStencilFunc(GL_ALWAYS, 1, 1);
2900 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2903#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2907 glEnable(GL_DEPTH_TEST);
2908 glDepthFunc(GL_ALWAYS);
2909 glDepthMask(GL_TRUE);
2911 glClear(GL_DEPTH_BUFFER_BIT);
2924 glTranslatef(0, 0, .5);
2928 s_regionColor = wxColor(0, 0, 0, 255);
2929 DrawRegion(vp, region);
2931 if (s_b_useStencil) {
2934 glStencilFunc(GL_EQUAL, 1, 1);
2935 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2938#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2940 glDepthFunc(GL_GREATER);
2941 glDepthMask(GL_FALSE);
2942 glTranslatef(0, 0, -.5);
2945 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2948void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2952 if (s_b_useStencil && s_b_useScissorTest) {
2954 if (rect != vp_rect) {
2955 glEnable(GL_SCISSOR_TEST);
2956 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2959#ifndef USE_ANDROID_GLES2
2965void glChartCanvas::DisableClipRegion() {
2966 glDisable(GL_SCISSOR_TEST);
2967 glDisable(GL_STENCIL_TEST);
2968 glDisable(GL_DEPTH_TEST);
2971void glChartCanvas::Invalidate() {
2973 m_cache_vp.Invalidate();
2979 if (!pBSBChart)
return;
2985 wxString key = chart->GetHashKey();
2989 ChartPathHashTexfactType::iterator ittf = hash.find(key);
2992 if (ittf == hash.end()) {
2994 hash[key]->SetHashKey(key);
2997 pTexFact = hash[key];
2998 pTexFact->SetLRUTime(++m_LRUtime);
3003 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3004 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3011 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3012 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3013 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3014 base_level = log(scalefactor) / log(2.0);
3023 glEnable(GL_TEXTURE_2D);
3024#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3025 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3027 glEnableClientState(GL_VERTEX_ARRAY);
3028 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3033 pTexFact->GetCenter(lat, lon);
3034 MultMatrixViewPort(vp, lat, lon);
3038 LLBBox box = region.GetBox();
3041 if (g_memCacheLimit > 0) {
3046 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3047 for (
int i = 0; i < numtiles; i++) {
3049 if (region.IntersectOut(tile->box)) {
3052 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3053 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3055 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3056 global_color_scheme, mem_used);
3060 coords = tile->m_coords;
3062 coords =
new float[2 * tile->m_ncoords];
3063 for (
int i = 0; i < tile->m_ncoords; i++) {
3065 tile->m_coords[2 * i + 1]);
3066 coords[2 * i + 0] = p.m_x;
3067 coords[2 * i + 1] = p.m_y;
3071#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3072 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3073 m_pParentCanvas->GetpVP());
3076 glDisable(GL_TEXTURE_2D);
3080 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3081 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3082 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3084 if (!texture) glEnable(GL_TEXTURE_2D);
3086 if (!use_norm_vp)
delete[] coords;
3090 glDisable(GL_TEXTURE_2D);
3092#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3093 if (use_norm_vp) glPopMatrix();
3095 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3096 glDisableClientState(GL_VERTEX_ARRAY);
3100void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3102 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3103 m_pParentCanvas->m_pQuilt->IsBusy())
3107 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3109 printf(
" Chart NULL\n");
3110 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3120 LLRegion region = vp.GetLLRegion(rect_region);
3122 LLRegion rendered_region;
3128 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3136 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3138 LLRegion get_region = pqp->ActiveRegion;
3139 bool b_rendered =
false;
3141 if (!pqp->b_overlay) {
3142 get_region.Intersect(region);
3143 if (!get_region.Empty()) {
3144 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3147 SetClipRegion(vp, get_region );
3148 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3149 DisableClipRegion();
3152 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3153 SetClipRegion(vp, pqp->ActiveRegion );
3154 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3156 DisableClipRegion();
3159 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3160 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3161 RenderNoDTA(vp, get_region);
3162 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3167 if (Chs57->m_RAZBuilt) {
3168 RenderNoDTA(vp, get_region);
3169 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3170 rect_region, get_region);
3171 DisableClipRegion();
3176 const LLRegion &oregion = get_region;
3177 LLBBox box = oregion.GetBox();
3188 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3191 ViewPort cvp = ClippedViewport(vp, get_region);
3192 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3193 SetClipRegion(cvp, get_region);
3194 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3195 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3196 RenderWorldChart(gldc, cvp, srect, world);
3197 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3198 global_color_scheme);
3199 DisableClipRegion();
3206 SetClipRegion(vp, get_region);
3207 RenderNoDTA(vp, get_region);
3208 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3210 DisableClipRegion();
3213 SetClipRegion(vp, get_region);
3214 RenderNoDTA(vp, get_region);
3215 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3217 DisableClipRegion();
3233 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3237 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3238 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3240 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3241 if (pqp->b_Valid && pqp->b_overlay &&
3242 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3243 LLRegion get_region = pqp->ActiveRegion;
3245 get_region.Intersect(region);
3246 if (!get_region.Empty()) {
3249 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3254 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3261 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3266 ViewPort vph = m_pParentCanvas->GetVP();
3267 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3270 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3272 if (!hiregion.Empty()) {
3276 switch (global_color_scheme) {
3277 case GLOBAL_COLOR_SCHEME_DAY:
3280 case GLOBAL_COLOR_SCHEME_DUSK:
3283 case GLOBAL_COLOR_SCHEME_NIGHT:
3291#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3293 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3295 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3298 DrawRegion(vp, hiregion);
3300 glDisable(GL_BLEND);
3305 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3307 if (!hiregion.Empty()) {
3311 switch (global_color_scheme) {
3312 case GLOBAL_COLOR_SCHEME_DAY:
3315 case GLOBAL_COLOR_SCHEME_DUSK:
3318 case GLOBAL_COLOR_SCHEME_NIGHT:
3327#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3329 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3331 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3334 DrawRegion(vp, hiregion);
3336 glDisable(GL_BLEND);
3340 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3343void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3345 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3346 m_pParentCanvas->m_pQuilt->IsBusy())
3350 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3352 LLRegion region = vp.GetLLRegion(rect_region);
3354 LLRegion rendered_region;
3356 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3358 LLRegion get_region = pqp->ActiveRegion;
3360 if (!pqp->b_overlay) {
3361 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3364 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3369 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3376 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3404void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3405 ViewPort &vp = m_pParentCanvas->VPoint;
3413 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3414 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3417 LLRegion chart_region;
3419 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3420 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3421 CHART_FAMILY_RASTER) {
3429 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3430 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3431 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3433 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3437 for (
int i = 1; i < 6; i += 2)
3438 if (fabs(ll[i] - ll[i + 2]) > 180) {
3440 for (
int i = 1; i < 8; i += 2)
3441 if (ll[i] < 0) ll[i] += 360;
3445 chart_region = LLRegion(4, ll);
3448 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3450 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3451 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3452 chart_region = LLRegion(4, ll);
3455 chart_region = vp.b_quilt
3456 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3457 : m_pParentCanvas->m_singleChart->GetValidRegion();
3459 bool world_view =
false;
3461 wxRect rect = upd.GetRect();
3462 LLRegion background_region = vp.GetLLRegion(rect);
3465 background_region.Subtract(chart_region);
3467 if (!background_region.Empty()) {
3468 ViewPort cvp = ClippedViewport(vp, background_region);
3469 SetClipRect(cvp, rect,
false);
3470 RenderWorldChart(dc, cvp, rect, world_view);
3471 DisableClipRegion();
3476 RenderQuiltViewGL(vp, rect_region);
3479 LLRegion region = vp.GetLLRegion(rect_region);
3480 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3481 CHART_FAMILY_RASTER) {
3482 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3483 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3484 *m_pcontext, vp, rect_region, region);
3486 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3487 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3488 CHART_FAMILY_VECTOR) {
3489 chart_region.Intersect(region);
3490 RenderNoDTA(vp, chart_region);
3491 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3492 rect_region, region);
3498void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3500 wxColour color = GetGlobalColor(
"NODTA");
3501#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3503 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3505 glColor4ub(163, 180, 183, transparency);
3508 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3512 s_regionColor = color;
3515 DrawRegion(vp, region);
3519void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3522 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3524 glEnable(GL_SCISSOR_TEST);
3525 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3531 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3532#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3534 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3538 colorv[0] = water.Red() / float(256);
3539 colorv[1] = water.Green() / float(256);
3540 colorv[2] = water.Blue() / float(256);
3542 shader->SetUniform4fv(
"color", colorv);
3553 shader->SetAttributePointerf(
"position", pf);
3555 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3567 glDisable(GL_SCISSOR_TEST);
3575void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3576 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3578 DrawStaticRoutesTracksAndWaypoints(vp);
3580 DisableClipRegion();
3583void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3585 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3589 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3590 if (!bmp.Ok())
return;
3592 wxImage image = bmp.ConvertToImage();
3593 int w = image.GetWidth(), h = image.GetHeight();
3596 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3597 tex_w = w, tex_h = h;
3599 tex_w = NextPow2(w), tex_h = NextPow2(h);
3601 m_tideTexWidth = tex_w;
3602 m_tideTexHeight = tex_h;
3604 unsigned char *d = image.GetData();
3605 unsigned char *a = image.GetAlpha();
3607 unsigned char mr, mg, mb;
3608 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3610 unsigned char *e =
new unsigned char[4 * w * h];
3612 for (
int y = 0; y < h; y++)
3613 for (
int x = 0; x < w; x++) {
3614 unsigned char r, g, b;
3615 int off = (y * w + x);
3625 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3629 glGenTextures(1, &m_tideTex);
3631 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3632 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3633 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3635 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3636 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3637 GL_UNSIGNED_BYTE, e);
3639 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3640 GL_UNSIGNED_BYTE, 0);
3641 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3650 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3651 glEnable(GL_TEXTURE_2D);
3654#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3656 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3660 if ((type ==
't') || (type ==
'T'))
3665 if (BBox.Contains(lat, lon)) {
3674 scale *= getAndroidDisplayDensity();
3676 double width2 =
scale * m_tideTexWidth / 2;
3677 double height2 =
scale * m_tideTexHeight / 2;
3692 coords[0] = xp - width2;
3693 coords[1] = yp - height2;
3694 coords[2] = xp - width2;
3695 coords[3] = yp + height2;
3696 coords[4] = xp + width2;
3697 coords[5] = yp + height2;
3698 coords[6] = xp + width2;
3699 coords[7] = yp - height2;
3701 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3708 glDisable(GL_TEXTURE_2D);
3709 glDisable(GL_BLEND);
3710 glBindTexture(GL_TEXTURE_2D, 0);
3712 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3715void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3716 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3719void glChartCanvas::SetColorScheme(ColorScheme cs) {
3720 if (!m_bsetup)
return;
3722 glDeleteTextures(1, &m_tideTex);
3723 glDeleteTextures(1, &m_currentTex);
3729void glChartCanvas::RenderGLAlertMessage() {
3730 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3731 wxString msg = m_pParentCanvas->GetAlertString();
3734 m_gldc.SetFont(*pfont);
3738 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3745 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3746 int xp = sbr.x + sbr.width + 5;
3748 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3749 m_gldc.SetPen(ppPen1);
3750 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3752 m_gldc.DrawRectangle(xp, yp, w, h);
3754 m_gldc.DrawText(msg, xp, yp);
3758unsigned long quiltHash;
3760extern wxLongLong s_t0;
3763void glChartCanvas::Render() {
3764 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3765 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3766 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3771 if (!g_PrintingInProgress)
return;
3774 if (!g_true_zoom && m_binPinch)
return;
3777 long render_start_time = m_glstopwatch.Time();
3779#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3780 loadShaders(GetCanvasIndex());
3781 configureShaders(m_pParentCanvas->VPoint);
3784#ifdef USE_ANDROID_GLES2
3788 if (m_binPinch)
return;
3797 bool recompose =
false;
3798 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3799 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3800 if (m_pParentCanvas->VPoint.IsValid()) {
3801 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3802 m_pParentCanvas->UpdateCanvasControlBar();
3811 if (sw.GetTime() > 2000) {
3817 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3818 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3824 m_displayScale = GetContentScaleFactor();
3828 m_last_render_time = wxDateTime::Now().GetTicks();
3832 if (g_GLOptions.m_bTextureCompression &&
3833 !g_GLOptions.m_bTextureCompressionCaching)
3838 int gl_width, gl_height;
3839 gl_width = m_pParentCanvas->VPoint.
pix_width;
3840 gl_height = m_pParentCanvas->VPoint.
pix_height;
3843 m_glcanvas_width = gl_width;
3844 m_glcanvas_height = gl_height;
3850 ViewPort VPoint = m_pParentCanvas->VPoint;
3852 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3853 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3856#if !defined(USE_ANDROID_GLES2)
3857 glMatrixMode(GL_PROJECTION);
3860 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3861 glMatrixMode(GL_MODELVIEW);
3865 if (s_b_useStencil) {
3866 glEnable(GL_STENCIL_TEST);
3867 glStencilMask(0xff);
3868 glClear(GL_STENCIL_BUFFER_BIT);
3869 glDisable(GL_STENCIL_TEST);
3875 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3876 if (g_GLOptions.m_GLPolygonSmoothing)
3877 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3878 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3890 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3891 bool useFBO =
false;
3897 if (m_b_BuiltFBO && !bpost_hilite
3902 bool b_newview =
true;
3903 bool b_full =
false;
3911 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3915#ifdef USE_ANDROID_GLES2
3916 if (recompose) b_newview =
true;
3928 if (VPoint.b_quilt) {
3929 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3930 if (!chart) b_full =
true;
3939 bool accelerated_pan =
false;
3949 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
3950 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
3951 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
3953 wxPoint2DDouble c_old =
3956 wxPoint2DDouble c_new =
3960 dy = wxRound(c_new.m_y - c_old.m_y);
3961 dx = wxRound(c_new.m_x - c_old.m_x);
3971 double deltax = c_new.m_x - c_old.m_x;
3972 double deltay = c_new.m_y - c_old.m_y;
3974 bool b_whole_pixel =
true;
3975 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
3976 b_whole_pixel =
false;
3978 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
3979 abs(dy) < m_cache_tex_y &&
3980 (abs(dx) > 0 || (abs(dy) > 0));
3989 if (m_displayScale > 1) accelerated_pan =
false;
3994 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
3997#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4000 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4006 if (b_full) accelerated_pan =
false;
4008 if (accelerated_pan) {
4009 if ((dx != 0) || (dy != 0)) {
4021 if (dy > 0 && dy < gl_height)
4022 update_region.Union(
4023 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4025 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4027 if (dx > 0 && dx < gl_width)
4028 update_region.Union(
4029 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4031 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4033 m_cache_page = !m_cache_page;
4036 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4037 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4049 RenderCharts(m_gldc, update_region);
4053 glDisable(g_texture_rectangle_format);
4058 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4059 glEnable(GL_TEXTURE_2D);
4063 float x1, x2, y1, y2;
4076 float tx1, tx2, ty1, ty2;
4082 tx2 = sx / (float)m_cache_tex_x;
4084 ty2 = sy / (float)m_cache_tex_y;
4101 coords[2] = -dx + sx;
4103 coords[4] = -dx + sx;
4104 coords[5] = dy + sy;
4106 coords[7] = dy + sy;
4109 ptexture_2D_shader_program[GetCanvasIndex()];
4113 shader->SetUniform1i(
"uTex", 0);
4117 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4118 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4119 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4121 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4143 shader->SetAttributePointerf(
"aPos", co1);
4144 shader->SetAttributePointerf(
"aUV", tco1);
4146 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4149 shader->SetUniformMatrix4fv(
"MVMatrix",
4150 (GLfloat *)VPoint.vp_matrix_transform);
4153 glBindTexture(g_texture_rectangle_format, 0);
4155 glDisable(g_texture_rectangle_format);
4163 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4164 g_texture_rectangle_format,
4165 m_cache_tex[!m_cache_page], 0);
4176 wxColour color = GetGlobalColor(
"NODTA");
4177 glClearColor(color.Red() / 256., color.Green() / 256.,
4178 color.Blue() / 256., 1.0);
4179 glClear(GL_COLOR_BUFFER_BIT);
4185 RenderCharts(m_gldc, rscreen_region);
4190 m_cache_page = !m_cache_page;
4195 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4206 glMatrixMode(GL_PROJECTION);
4209 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4210 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4212 glMatrixMode(GL_MODELVIEW);
4216 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4217 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4219 glGetIntegerv(GL_VIEWPORT, viewport);
4220 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4221 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4230 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4231 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4232 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4234 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4238 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4239 glEnable(g_texture_rectangle_format);
4241 float tx, ty, tx0, ty0, divx, divy;
4244 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4247 divx = m_cache_tex_x;
4248 divy = m_cache_tex_y;
4251 tx0 = m_fbo_offsetx / divx;
4252 ty0 = m_fbo_offsety / divy;
4253 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4254 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4279 wxColour color = GetGlobalColor(
"NODTA");
4280 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4282 glClear(GL_COLOR_BUFFER_BIT);
4284 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4287 glDisable(g_texture_rectangle_format);
4289 m_cache_vp = VPoint;
4290 m_cache_vp.Validate();
4292 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4294 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4298 RenderCharts(m_gldc, screen_region);
4307 RenderS57TextOverlay(VPoint);
4308 RenderMBTilesOverlay(VPoint);
4314 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4319 wxRect rt = upd.GetRect();
4320 LLRegion region = VPoint.GetLLRegion(rt);
4321 ViewPort cvp = ClippedViewport(VPoint, region);
4322 DrawGroundedOverlayObjects(gldc, cvp);
4325 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4326 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4327 LLBBox screenBox = screenLLRegion.GetBox();
4329 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4332 if (m_pParentCanvas->m_bShowTide) {
4333 m_pParentCanvas->RebuildTideSelectList(screenBox);
4334 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4337 if (m_pParentCanvas->m_bShowCurrent) {
4338 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4339 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4345 if (m_pParentCanvas->m_show_focus_bar &&
4346 (g_canvasConfig != 0)) {
4347 if (m_pParentCanvas == wxWindow::FindFocus()) {
4350 wxColour colour = GetGlobalColor(
"BLUE4");
4351 wxPen ppBlue(colour, 1);
4352 wxBrush ppBrush(colour);
4353 gldc.SetPen(ppBlue);
4354 gldc.SetBrush(ppBrush);
4355 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4356 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4357 wxPoint barPoints[4];
4360 barPoints[1].x = xw;
4362 barPoints[2].x = xw;
4363 barPoints[2].y = rect_pix;
4365 barPoints[3].y = rect_pix;
4367 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4371 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4375 DrawFloatingOverlayObjects(m_gldc);
4377#ifndef USE_ANDROID_GLES2
4380 glMatrixMode(GL_PROJECTION);
4383 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4384 glMatrixMode(GL_MODELVIEW);
4389 if (!g_bhide_depth_units)
4390 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4391 if (!g_bhide_overzoom_flag)
4392 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4395 ViewPort &vp = m_pParentCanvas->GetVP();
4400 if (!g_PrintingInProgress) {
4401 if (m_pParentCanvas->m_pTrackRolloverWin)
4402 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4404 if (m_pParentCanvas->m_pRouteRolloverWin)
4405 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4407 if (m_pParentCanvas->m_pAISRolloverWin)
4408 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4410 if (m_pParentCanvas->GetMUIBar())
4411 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4425 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4426 int x, y, width, height;
4427 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4428 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4429 wxBitmap bmp(width, height, -1);
4432 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4435 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4436 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4440 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4441 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4443 wxStringTokenizer tkz(s,
"\n");
4446 while (tkz.HasMoreTokens()) {
4447 token = tkz.GetNextToken();
4448 dc.DrawText(token, xt, yt);
4451 dc.SelectObject(wxNullBitmap);
4453 m_gldc.DrawBitmap(bmp, x, y,
false);
4459 if (g_bShowChartBar) DrawChartBar(m_gldc);
4461 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4463 m_pParentCanvas->m_Compass->Paint(gldc);
4465 if (m_pParentCanvas->IsPrimaryCanvas() &&
4466 m_pParentCanvas->m_notification_button) {
4467 auto ¬eman = NotificationManager::GetInstance();
4468 if (noteman.GetNotificationCount()) {
4469 m_pParentCanvas->m_notification_button->SetIconSeverity(
4470 noteman.GetMaxSeverity());
4471 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4472 m_pParentCanvas->m_notification_button->Show(
true);
4473 m_pParentCanvas->m_notification_button->Paint(gldc);
4475 m_pParentCanvas->m_notification_button->Show(
false);
4478 RenderGLAlertMessage();
4481 ViewPort &vp = m_pParentCanvas->GetVP();
4485 glActiveTexture(GL_TEXTURE0);
4489 if (g_bquiting) DrawQuiting();
4490 if (g_bcompression_wait)
4491 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4501 m_pParentCanvas->PaintCleanup();
4502 m_bforcefull =
false;
4511void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4514 if (VPoint.b_quilt) {
4515 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4516 ps52plib->GetShowS57Text()) {
4517 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4518 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4523 ChPI->ClearPLIBTextList();
4525 ps52plib->ClearTextList();
4535 RenderQuiltViewGLText(vpx, screen_region);
4540void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4543 LLRegion &screenLLRegion) {
4548 if (chart == NULL)
return;
4555 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4557 wxFileName tileFile(chart->GetFullPath());
4559 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4562 bool isBasemap = tileFile.GetPath().Lower().Contains(
"basemap");
4568 (double)chart->GetNativeScale();
4570 if (zoom_ratio > g_tile_basemap_zoom_factor)
return;
4573 if (!isBasemap && (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4574 (tileSizeMB.GetLo() > 5000))) {
4577 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4578 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4579 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4586 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4590 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4593 std::vector<int> piano_active_array_tiles =
4594 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4595 bool bfound =
false;
4597 if (std::find(piano_active_array_tiles.begin(),
4598 piano_active_array_tiles.end(),
4599 dbIndex) != piano_active_array_tiles.end()) {
4604 piano_active_array_tiles.push_back(dbIndex);
4605 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4609void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4611 std::vector<int> stackIndexArray =
4612 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4613 unsigned int im = stackIndexArray.size();
4616 if (VPoint.b_quilt && im > 0) {
4617 bool regionVPBuilt =
false;
4619 LLRegion screenLLRegion;
4623 std::vector<int> tiles_to_show;
4624 for (
unsigned int is = 0; is < im; is++) {
4626 ChartData->GetChartTableEntry(stackIndexArray[is]);
4627 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4628 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4630 std::vector<int> piano_active_array_tiles =
4631 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4632 bool bfound =
false;
4634 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4635 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4636 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4644 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4645 piano_active_array_tiles);
4650 tiles_to_show.push_back(stackIndexArray[is]);
4651 if (!regionVPBuilt) {
4654 screenLLRegion = VPoint.GetLLRegion(screen_region);
4655 screenBox = screenLLRegion.GetBox();
4663 regionVPBuilt =
true;
4673 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4674 rit != tiles_to_show.rend(); ++rit) {
4675 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4677 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4678 rit != tiles_to_show.rend(); ++rit) {
4679 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4683 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4685 if (!hiregion.Empty()) {
4689 switch (global_color_scheme) {
4690 case GLOBAL_COLOR_SCHEME_DAY:
4693 case GLOBAL_COLOR_SCHEME_DUSK:
4696 case GLOBAL_COLOR_SCHEME_NIGHT:
4704#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4705 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4707 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4710 DrawRegion(VPoint, hiregion);
4712 glDisable(GL_BLEND);
4718void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4722 GetClientSize(&w, &h);
4724 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4725#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4726 glMatrixMode(GL_PROJECTION);
4729 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4730 glMatrixMode(GL_MODELVIEW);
4734 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4736 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4738 bool world_view =
false;
4739 RenderWorldChart(dc, cvp, rtex, world_view);
4746 glViewport(0, 0, (GLint)w, (GLint)h);
4747#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4748 glMatrixMode(GL_PROJECTION);
4751 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4752 glMatrixMode(GL_MODELVIEW);
4758void glChartCanvas::FastPan(
int dx,
int dy) {
4759#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4763void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4765 if (IsShown()) SetCurrent(*m_pcontext);
4766 float sx = GetSize().x;
4767 float sy = GetSize().y;
4768 glClear(GL_COLOR_BUFFER_BIT);
4771 GetClientSize(&w, &h);
4773 if (s_b_useStencil) {
4774 glEnable(GL_STENCIL_TEST);
4775 glStencilMask(0xff);
4776 glClear(GL_STENCIL_BUFFER_BIT);
4777 glDisable(GL_STENCIL_TEST);
4793 float sxfactor = sx / swidth;
4794 float syfactor = sy / sheight;
4796 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4797 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4798 sx * sx / swidth * 2, sy * sy / sheight * 2);
4799 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4800 glEnable(g_texture_rectangle_format);
4825 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4826 glBindTexture(g_texture_rectangle_format, 0);
4832 float tx, ty, tx0, ty0;
4842 glBindTexture(g_texture_rectangle_format, 0);
4845 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4846 glEnable(g_texture_rectangle_format);
4852 uv[0] = tx0 / m_cache_tex_x;
4853 uv[1] = ty / m_cache_tex_y;
4854 uv[2] = tx / m_cache_tex_x;
4855 uv[3] = ty / m_cache_tex_y;
4856 uv[4] = tx / m_cache_tex_x;
4857 uv[5] = ty0 / m_cache_tex_y;
4858 uv[6] = tx0 / m_cache_tex_x;
4859 uv[7] = ty0 / m_cache_tex_y;
4871 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4872 sx * sx / swidth, sy * sy / sheight);
4874 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4876 glDisable(g_texture_rectangle_format);
4877 glBindTexture(g_texture_rectangle_format, 0);
4884 wxColour color = GetGlobalColor(
"GREY1");
4885 float ht = -offset_y * (sy / sheight);
4886 wxRect r(0, sy - ht, w, ht);
4887 RenderColorRect(r, color);
4890 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4891 RenderColorRect(rt, color);
4894 float w1 = -offset_x * sx / swidth;
4895 wxRect rl(0, 0, w1, sy);
4896 RenderColorRect(rl, color);
4899 float px = w1 + sx * sx / swidth;
4900 wxRect rr(px, 0, sx - px, sy);
4901 RenderColorRect(rr, color);
4910void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4913 if (m_nRun < m_nTotal) {
4914 m_runoffsetx += m_offsetxStep;
4915 if (m_offsetxStep > 0)
4916 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4918 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4920 m_runoffsety += m_offsetyStep;
4921 if (m_offsetyStep > 0)
4922 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4924 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4926 m_runswidth += m_swidthStep;
4927 if (m_swidthStep > 0)
4928 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4930 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4932 m_runsheight += m_sheightStep;
4933 if (m_sheightStep > 0)
4934 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4936 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4941 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4947 if (m_zoomFinaldx || m_zoomFinaldy) {
4948 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
4951 m_zoomFinal =
false;
4955void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
4957 int sx = GetSize().x;
4958 int sy = GetSize().y;
4960 m_lastfbo_offsetx = m_fbo_offsetx;
4961 m_lastfbo_offsety = m_fbo_offsety;
4962 m_lastfbo_swidth = m_fbo_swidth;
4963 m_lastfbo_sheight = m_fbo_sheight;
4965 float curr_fbo_offset_x = m_fbo_offsetx;
4966 float curr_fbo_offset_y = m_fbo_offsety;
4967 float curr_fbo_swidth = m_fbo_swidth;
4968 float curr_fbo_sheight = m_fbo_sheight;
4970 float fx = (float)cp_x / sx;
4971 float fy = 1.0 - (float)cp_y / sy;
4973 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
4974 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
4976 m_fbo_swidth = curr_fbo_swidth / factor;
4977 m_fbo_sheight = curr_fbo_sheight / factor;
4979 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
4980 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
4982 m_fbo_offsetx += post_x;
4983 m_fbo_offsety += post_y;
4994 float perStep = m_nStep / m_nTotal;
4996 if (zoomTimer.IsRunning()) {
4997 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
4998 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
4999 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5000 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5003 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5004 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5005 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5006 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5008 m_runoffsetx = m_lastfbo_offsetx;
5009 m_runoffsety = m_lastfbo_offsety;
5010 m_runswidth = m_lastfbo_swidth;
5011 m_runsheight = m_lastfbo_sheight;
5014 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5015 m_zoomFinal =
false;
5021void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5025 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5028 if (m_binPinch)
return;
5029 if (m_bpinchGuard)
return;
5031 int x =
event.GetOffset().x;
5032 int y =
event.GetOffset().y;
5034 int lx =
event.GetLastOffset().x;
5035 int ly =
event.GetLastOffset().y;
5040 switch (event.GetState()) {
5041 case GestureStarted:
5042 if (m_binPan)
break;
5046 m_binGesture =
true;
5050 case GestureUpdated:
5055 m_pParentCanvas->FreezePiano();
5057 m_pParentCanvas->ThawPiano();
5068 case GestureFinished:
5071 m_pParentCanvas->UpdateCanvasControlBar();
5074 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5078 case GestureCanceled:
5080 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5087 m_bgestureGuard =
true;
5088 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5089 m_bforcefull =
false;
5094float zoom_inc = 1.0;
5096void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5097 float zoom_gain = 1.0;
5098 float zout_gain = 1.0;
5101 float total_zoom_val;
5103 float max_zoom_scale = 1000.;
5104 float min_zoom_scale = 2e8;
5106 if (event.GetScaleFactor() > 1)
5107 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5109 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5111 if (event.GetTotalScaleFactor() > 1)
5112 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5115 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5117 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5120 float max_zoom_scale = 1000.;
5121 if( cc1->GetVP().b_quilt) {
5122 int ref_index = cc1->GetQuiltRefChartdbIndex();
5129 float min_zoom_scale = 2e8;
5133 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5135 double projected_scale =
5136 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5138 switch (event.GetState()) {
5139 case GestureStarted:
5140 m_first_zout =
false;
5144 m_binGesture =
true;
5146 m_pinchStart =
event.GetCenterPoint();
5147 m_lpinchPoint = m_pinchStart;
5150 event.GetCenterPoint().y, m_pinchlat,
5155 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5156 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5159 if (IsShown()) SetCurrent(*m_pcontext);
5165 case GestureUpdated:
5167 if (projected_scale < min_zoom_scale) {
5168 wxPoint pinchPoint =
event.GetCenterPoint();
5170 float dx = pinchPoint.x - m_lpinchPoint.x;
5171 float dy = pinchPoint.y - m_lpinchPoint.y;
5173 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5174 -dx / total_zoom_val, dy / total_zoom_val);
5176 m_lpinchPoint = pinchPoint;
5180 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5181 wxPoint pinchPoint =
event.GetCenterPoint();
5183 float dx = pinchPoint.x - m_lpinchPoint.x;
5184 float dy = pinchPoint.y - m_lpinchPoint.y;
5186 if ((projected_scale > max_zoom_scale) &&
5187 (projected_scale < min_zoom_scale))
5188 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5189 -dx / total_zoom_val, dy / total_zoom_val);
5191 m_lpinchPoint = pinchPoint;
5194 m_first_zout =
true;
5195 zoom_inc *= zoom_val;
5196 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5197 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5201 wxPoint pinchPoint =
event.GetCenterPoint();
5202 float dx = pinchPoint.x - m_lpinchPoint.x;
5203 float dy = pinchPoint.y - m_lpinchPoint.y;
5205 m_lpinchPoint = pinchPoint;
5216 case GestureFinished: {
5220 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5221 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5225 float tzoom = total_zoom_val;
5227 if (projected_scale >= min_zoom_scale)
5228 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5230 if (projected_scale < max_zoom_scale)
5231 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5233 dx = (cc_x - m_cc_x) * tzoom;
5234 dy = -(cc_y - m_cc_y) * tzoom;
5236 if (zoomTimer.IsRunning()) {
5239 m_zoomFinalZoom = tzoom;
5245 double final_projected_scale =
5249 if (final_projected_scale < min_zoom_scale) {
5253 m_pParentCanvas->m_pQuilt->Invalidate();
5254 m_bforcefull =
true;
5261 m_pParentCanvas->m_pQuilt->Invalidate();
5262 m_bforcefull =
true;
5274 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5278 case GestureCanceled:
5280 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5287 m_bgestureGuard =
true;
5289 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5292void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5302 m_bgestureGuard =
false;
5303 m_bpinchGuard =
false;
5304 m_binGesture =
false;
5305 m_bforcefull =
false;
5308void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5312 m_binGesture =
false;
5313 m_bforcefull =
false;
5317#ifdef HAVE_WX_GESTURE_EVENTS
5319void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5322 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5325 if (m_binPinch)
return;
5326 if (m_bpinchGuard)
return;
5328 int dx =
event.GetDelta().x;
5329 int dy =
event.GetDelta().y;
5331 if (event.IsGestureStart()) {
5332 if (m_binPan)
return;
5336 m_binGesture =
true;
5340 else if (event.IsGestureEnd()) {
5342 m_pParentCanvas->UpdateCanvasControlBar();
5344 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5352 m_pParentCanvas->FreezePiano();
5354 m_pParentCanvas->ThawPiano();
5365 m_bgestureGuard =
true;
5366 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5367 m_bforcefull =
false;
5371void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5373 float zoom_gain = 1.0;
5374 float zout_gain = 1.0;
5376 float last_zoom_val = m_step_zoom_val;
5378 float max_zoom_scale = 1000.;
5379 float min_zoom_scale = 2e8;
5381 if (event.GetZoomFactor() > 1)
5382 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5384 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5386 float inc_zoom_val =
5387 m_total_zoom_val / last_zoom_val;
5391 if (event.IsGestureStart()) {
5392 m_glstopwatch.Start();
5393 printf(
"\nStart--------------\n");
5395 m_pParentCanvas->m_inPinch =
true;
5398 m_binGesture =
true;
5399 m_pinchStart =
event.GetPosition();
5400 m_lpinchPoint = m_pinchStart;
5401 m_total_zoom_val = 1.0;
5402 m_final_zoom_val = 1.0;
5403 m_step_zoom_val = 1.0;
5407 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5411 if (event.IsGestureEnd()) {
5413 if (!m_binGesture)
return;
5414 printf(
"EndZoom--------------\n");
5421 m_final_zoom_val = 1.0;
5422 m_total_zoom_val = 1.0;
5423 m_step_zoom_val = 1.0;
5425 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5432 float zoom_step = 5;
5433 float zoom_trigger = 0.05;
5434 if (projected_scale > 1e5)
5436 else if (projected_scale < 3e4)
5439 if (inc_zoom_val != 1.0) {
5440 if (inc_zoom_val > 1 + zoom_step) {
5441 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5442 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5444 if (IsShown()) SetCurrent(*m_pcontext);
5447 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5448 m_step_zoom_val = m_total_zoom_val;
5449 printf(
" Zoom: %6g\n", inc_zoom_val);
5454 bool b_allow_ztp =
true;
5455 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5456 b_allow_ztp =
false;
5458 if (g_bEnableZoomToCursor && b_allow_ztp) {
5464 int dx = r.x -
event.GetPosition().x;
5465 int dy = r.y -
event.GetPosition().y;
5469 if (IsShown()) SetCurrent(*m_pcontext);
5478 float zoom_gain = 1.0;
5479 float zout_gain = 1.0;
5481 float last_zoom_val = m_total_zoom_val;
5483 float max_zoom_scale = 1000.;
5484 float min_zoom_scale = 2e8;
5486 if (event.GetZoomFactor() > 1)
5487 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5489 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5491 float inc_zoom_val =
5492 m_total_zoom_val / last_zoom_val;
5494 double projected_scale =
5495 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5497 if (event.IsGestureStart()) {
5499 m_first_zout =
false;
5503 m_binGesture =
true;
5504 m_pinchStart =
event.GetPosition();
5505 m_lpinchPoint = m_pinchStart;
5506 m_total_zoom_val = 1.0;
5507 m_final_zoom_val = 1.0;
5510 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5514 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5515 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5518 if (IsShown()) SetCurrent(*m_pcontext);
5521 ViewPort vpr = m_pParentCanvas->VPoint;
5523 GetTouchBackingBitmap(vpr);
5528 if (event.IsGestureEnd()) {
5534 if (!m_binGesture)
return;
5536 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5537 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5541 float tzoom = m_final_zoom_val;
5543 dx = (cc_x - m_cc_x) * tzoom;
5544 dy = -(cc_y - m_cc_y) * tzoom;
5546 if (zoomTimer.IsRunning()) {
5549 m_zoomFinalZoom = tzoom;
5555 double final_projected_scale =
5559 if (final_projected_scale < min_zoom_scale) {
5563 m_pParentCanvas->m_pQuilt->Invalidate();
5564 m_bforcefull =
true;
5571 m_pParentCanvas->m_pQuilt->Invalidate();
5572 m_bforcefull =
true;
5577 m_final_zoom_val = 1.0;
5578 m_total_zoom_val = 1.0;
5579 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5584 if (projected_scale < min_zoom_scale) {
5585 wxPoint pinchPoint =
event.GetPosition();
5587 float dx = pinchPoint.x - m_lpinchPoint.x;
5588 float dy = pinchPoint.y - m_lpinchPoint.y;
5590 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5591 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5593 m_lpinchPoint = pinchPoint;
5594 m_final_zoom_val *= inc_zoom_val;
5598 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5599 wxPoint pinchPoint =
event.GetPosition();
5601 float dx = pinchPoint.x - m_lpinchPoint.x;
5602 float dy = pinchPoint.y - m_lpinchPoint.y;
5604 if ((projected_scale > max_zoom_scale) &&
5605 (projected_scale < min_zoom_scale))
5606 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5607 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5609 m_lpinchPoint = pinchPoint;
5610 m_final_zoom_val *= inc_zoom_val;
5613 m_first_zout =
true;
5614 m_zoom_inc *= inc_zoom_val;
5615 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5616 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5620 wxPoint pinchPoint =
event.GetPosition();
5621 float dx = pinchPoint.x - m_lpinchPoint.x;
5622 float dy = pinchPoint.y - m_lpinchPoint.y;
5624 m_lpinchPoint = pinchPoint;
5628 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5631 m_bgestureGuard =
true;
5632 m_bpinchGuard =
true;
5635void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5644 m_bgestureGuard =
false;
5645 m_bpinchGuard =
false;
5646 m_binGesture =
false;
5647 m_bforcefull =
false;
5650void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5654 m_binGesture =
false;
5655 m_bforcefull =
false;
5657 m_pParentCanvas->m_inPinch =
false;
5658 printf(
"******Finish\n");
5664void glChartCanvas::configureShaders(
ViewPort &vp) {
5665#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5671 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5673 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5674 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5695 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5697 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5698 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5710 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5712 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5713 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5716 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5718 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5719 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5727 shader = pAALine_shader_program[GetCanvasIndex()];
5729 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5732 shader = pring_shader_program[GetCanvasIndex()];
5734 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5735 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5739 if (texture_2DA_shader_program) {
5740 glUseProgram(texture_2DA_shader_program);
5741 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5742 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5743 (
const GLfloat *)pvp->vp_matrix_transform);
5745 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5746 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5754void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5757#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5758 int nl = nVertex / 4;
5760 float *luv = uvCoords;
5763 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5771 glEnableClientState(GL_VERTEX_ARRAY);
5772 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5774 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5775 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5776 glDrawArrays(GL_QUADS, 0, 4);
5783void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5784 float *uvCoords,
ViewPort *vp,
float dx,
5785 float dy,
float angle_rad) {
5786#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5788 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5789 if (!shader)
return;
5794 shader->SetUniform1i(
"uTex", 0);
5799 mat4x4_rotate_Z(Q, I, angle_rad);
5805 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5810 shader->SetAttributePointerf(
"aPos", co1);
5811 shader->SetAttributePointerf(
"aUV", tco1);
5818 GLushort indices1[] = {0,1,3,2};
5819 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5831 tco1[0] = uvCoords[0];
5832 tco1[1] = uvCoords[1];
5833 tco1[2] = uvCoords[2];
5834 tco1[3] = uvCoords[3];
5835 tco1[4] = uvCoords[6];
5836 tco1[5] = uvCoords[7];
5837 tco1[6] = uvCoords[4];
5838 tco1[7] = uvCoords[5];
5843 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5855void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5856#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5858 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5861 shader->SetUniformMatrix4fv(
5862 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5865 colorv[0] = color.Red() / float(256);
5866 colorv[1] = color.Green() / float(256);
5867 colorv[2] = color.Blue() / float(256);
5869 shader->SetUniform4fv(
"color", colorv);
5872 pf[0] = r.x + r.width;
5876 pf[4] = r.x + r.width;
5877 pf[5] = r.y + r.height;
5879 pf[7] = r.y + r.height;
5880 shader->SetAttributePointerf(
"position", pf);
5882 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5890void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5891#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5893 ViewPort VPoint = m_pParentCanvas->VPoint;
5897 GetClientSize(&w, &h);
5898 int sx = GetSize().x;
5899 int sy = GetSize().y;
5903 glViewport(0, 0, (GLint)w, (GLint)h);
5905 if (s_b_useStencil) {
5906 glEnable(GL_STENCIL_TEST);
5907 glStencilMask(0xff);
5908 glClear(GL_STENCIL_BUFFER_BIT);
5909 glDisable(GL_STENCIL_TEST);
5913 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5918 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5919 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5920 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5923 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5925 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5926 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5934 if (bRenderCharts) RenderCharts(gldc, screen_region);
5936 if (bRenderOverlays) {
5937 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5938 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5944 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5947 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5948 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5949 DrawFloatingOverlayObjects(m_gldc);
5953 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5958wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5960 wxMemoryDC tdc(tbm);
5961 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5969 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5970 dc.SetPen(*wxTRANSPARENT_PEN);
5973 tdc.SelectObject(wxNullBitmap);
5974 m_touch_backing_bitmap = tbm;
5975 CreateBackingTexture();
5977 return m_touch_backing_bitmap;
5980void glChartCanvas::CreateBackingTexture() {
5981 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5982 unsigned char *imgdata = image.GetData();
5983 unsigned char *imgalpha = image.GetAlpha();
5984 m_tex_w = image.GetWidth();
5985 m_tex_h = image.GetHeight();
5986 m_image_width = m_tex_w;
5987 m_image_height = m_tex_h;
5989 GLuint format = GL_RGBA;
5990 GLuint internalformat = g_texture_rectangle_format;
5992 internalformat = GL_RGBA;
5997 unsigned char *teximage =
5998 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6000 for (
int i = 0; i < m_image_height; i++) {
6001 for (
int j = 0; j < m_image_width; j++) {
6002 int s = (i * 3 * m_image_width) + (j * 3);
6003 int d = (i * stride * m_tex_w) + (j * stride);
6005 teximage[d + 0] = imgdata[s + 0];
6006 teximage[d + 1] = imgdata[s + 1];
6007 teximage[d + 2] = imgdata[s + 2];
6008 teximage[d + 3] = 255;
6012 glGenTextures(1, &m_TouchBackingTexture);
6013 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6015 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6016 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6017 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6019 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6021 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6022 GL_UNSIGNED_BYTE, teximage);
6025 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.
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.
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
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.