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 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1092 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1096 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1098 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1101#ifndef USE_ANDROID_GLES2
1103 if (bad_stencil_code) s_b_useStencil =
false;
1117 if (m_displayScale > 1) m_b_DisableFBO =
true;
1126 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1128 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1129 g_texture_rectangle_format, m_cache_tex[0], 0);
1131 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1132 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1134 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1136 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1138 m_b_DisableFBO =
true;
1144 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1148 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1150#ifdef USE_ANDROID_GLES2
1151 s_b_useStencilAP = s_b_useStencil;
1158 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1160 if (m_b_useFBOStencil)
1161 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1163 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1165 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1168 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1170 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1172 if (s_b_useScissorTest && s_b_useStencil)
1173 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1176 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1178 MipMap_ResolveRoutines();
1182 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1183 g_GLMinCartographicLineWidth);
1184 wxLogMessage(lwmsg);
1185 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1186 g_GLMinSymbolLineWidth);
1187 wxLogMessage(lwmsg);
1190 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1192#ifdef USE_ANDROID_GLES2
1193 g_GLOptions.m_bUseAcceleratedPanning =
true;
1199 int tex_dim = g_GLOptions.m_iTextureDimension;
1200 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1209 s_b_useFBO = m_b_BuiltFBO;
1213 ps52plib->SetGLOptions(
1214 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1215 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1216 g_GLMinSymbolLineWidth);
1220 SendJSONConfigMessage();
1223void glChartCanvas::SendJSONConfigMessage() {
1226 v[
"setupComplete"] = m_bsetup;
1227 v[
"useStencil"] = s_b_useStencil;
1228 v[
"useStencilAP"] = s_b_useStencilAP;
1229 v[
"useScissorTest"] = s_b_useScissorTest;
1230 v[
"useFBO"] = s_b_useFBO;
1231 v[
"useVBO"] = g_b_EnableVBO;
1232 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1233 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1234 SendJSONMessageToAllPlugins(msg_id, v);
1237void glChartCanvas::SetupCompression() {
1238 int dim = g_GLOptions.m_iTextureDimension;
1241 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1242 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1243 goto no_compression;
1247 g_uncompressed_tile_size = dim * dim * 4;
1248 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1254 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1257 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1267 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1268 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1271 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1272 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1277 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1278 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1281 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1283 wxLogMessage(
"OpenGL-> No Useable compression format found");
1284 goto no_compression;
1289 g_tile_size = 512 * 512 / 2;
1293 glGenTextures(1, &texture);
1294 glBindTexture(GL_TEXTURE_2D, texture);
1296 GL_UNSIGNED_BYTE, NULL);
1297 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1299 glDeleteTextures(1, &texture);
1303 if (g_tile_size == 0)
goto no_compression;
1305 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1307 g_uncompressed_tile_size / g_tile_size));
1311 g_GLOptions.m_bTextureCompression =
false;
1313 g_tile_size = g_uncompressed_tile_size;
1314 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1317void glChartCanvas::OnPaint(wxPaintEvent &event) {
1319 if (!m_pcontext)
return;
1328 if (IsShown()) SetCurrent(*m_pcontext);
1333 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1341 if (!m_b_paint_enable)
return;
1344 if (m_in_glpaint)
return;
1347 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1370bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1372#ifndef USE_ANDROID_GLES2
1373 return vp.m_projection_type == PROJECTION_MERCATOR ||
1374 vp.m_projection_type == PROJECTION_POLAR ||
1375 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1389#define NORM_FACTOR 4096.0
1390void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1391#ifndef USE_ANDROID_GLES2
1393 wxPoint2DDouble point;
1395 switch (vp.m_projection_type) {
1396 case PROJECTION_MERCATOR:
1397 case PROJECTION_EQUIRECTANGULAR:
1398 case PROJECTION_WEB_MERCATOR:
1401 glTranslated(point.m_x, point.m_y, 0);
1406 case PROJECTION_POLAR:
1410 glTranslated(point.m_x, point.m_y, 0);
1411 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1418 printf(
"ERROR: Unhandled projection\n");
1423 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1431 switch (vp.m_projection_type) {
1432 case PROJECTION_MERCATOR:
1433 case PROJECTION_EQUIRECTANGULAR:
1434 case PROJECTION_WEB_MERCATOR:
1438 case PROJECTION_POLAR:
1443 printf(
"ERROR: Unhandled projection\n");
1452bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1453 return vp.m_projection_type == PROJECTION_MERCATOR ||
1454 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1455 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1459 const LLRegion ®ion) {
1460 if (!CanClipViewport(vp))
return vp;
1463 LLBBox bbox = region.GetBox();
1465 if (!bbox.GetValid())
return vp;
1473 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1474 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1475 bbox.GetMaxLon() + 360);
1476 cvp.SetBBoxDirect(bbox);
1477 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1478 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1479 bbox.GetMaxLon() - 360);
1480 cvp.SetBBoxDirect(bbox);
1482 cvp.SetBBoxDirect(bbox);
1487void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1488 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1494 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1496 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1500 if (!pRouteDraw)
continue;
1503 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1506 if (pRouteDraw->m_bIsBeingEdited)
continue;
1508 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1513 if (vp.GetBBox().GetValid() && pWayPointMan) {
1514 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1515 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1516 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1522void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1527 if (pActiveTrack && pActiveTrack->IsRunning())
1528 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1534 if (!pRouteDraw)
continue;
1537 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1540 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1543 if (pRouteDraw->IsSelected()) drawit++;
1546 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1547 if (!vp_box.IntersectOut(test_box))
1548 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1554 if (vp.GetBBox().GetValid() && pWayPointMan) {
1555 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1556 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1563static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1567 switch (vp.m_projection_type) {
1568 case PROJECTION_TRANSVERSE_MERCATOR:
1569 lat_dist = 4, lon_dist = 1;
1571 case PROJECTION_POLYCONIC:
1572 lat_dist = 2, lon_dist = 1;
1574 case PROJECTION_ORTHOGRAPHIC:
1575 lat_dist = 2, lon_dist = 2;
1577 case PROJECTION_POLAR:
1578 lat_dist = 180, lon_dist = 1;
1580 case PROJECTION_STEREOGRAPHIC:
1581 case PROJECTION_GNOMONIC:
1582 lat_dist = 2, lon_dist = 1;
1584 case PROJECTION_EQUIRECTANGULAR:
1587 lat_dist = 2, lon_dist = 360;
1590 lat_dist = 180, lon_dist = 360;
1594void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1595 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1601 ChartData->GetDBBoundingBox(dbIndex, box);
1602 if (!box.GetValid())
return;
1606 if (box.GetLonRange() == 360)
return;
1608 LLBBox vpbox = vp.GetBBox();
1610 double lon_bias = 0;
1612 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1615 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1616 color = GetGlobalColor(
"YELO1");
1617 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1618 color = GetGlobalColor(
"GREEN2");
1620 color = GetGlobalColor(
"UINFR");
1622#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1623 float plylat, plylon;
1625 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1627 glColor3ub(color.Red(), color.Green(), color.Blue());
1628 glLineWidth(g_GLMinSymbolLineWidth);
1630 float lat_dist, lon_dist;
1631 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1634 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1638 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1640 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1642 bool begin =
false, sml_valid =
false;
1644 float lastplylat = 0.0;
1645 float lastplylon = 0.0;
1647 int modulo = (nPly == 0) ? 1 : nPly;
1648 for (
int i = 0; i < nPly + 1; i++) {
1650 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1652 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1656 if (lastplylon - plylon > 180)
1658 else if (lastplylon - plylon < -180)
1665 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1666 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1667 splits = wxMax(lat_splits, lon_splits) + 1;
1674 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1675 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1678 for (
double c = 0; c < splits; c++) {
1680 if (c == splits - 1)
1681 lat = plylat, lon = plylon;
1683 double d = (double)(c + 1) / splits;
1684 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1690 if (!std::isnan(s.m_x)) {
1693 glBegin(GL_LINE_STRIP);
1695 glVertex2f(s.m_x, s.m_y);
1701 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1702 lastplylat = plylat, lastplylon = plylon;
1707 }
while (++j < nAuxPlyEntries);
1709 glDisable(GL_LINE_SMOOTH);
1713 double nominal_line_width_pix =
1714 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1716 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1717 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1720 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1721 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1725 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1728 float plylat1, plylon1;
1732 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1733 if (0 == nAuxPlyEntries)
1736 std::vector<int> points_vector;
1738 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1739 int nPly = vec.size() / 2;
1741 if (nPly == 0)
return;
1743 for (
int i = 0; i < nPly; i++) {
1744 plylon1 = vec[i * 2];
1745 plylat1 = vec[i * 2 + 1];
1751 points_vector.push_back(pixx1);
1752 points_vector.push_back(pixy1);
1755 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1756 plylon1 += lon_bias;
1762 points_vector.push_back(pixx1);
1763 points_vector.push_back(pixy1);
1765 if (points_vector.size()) {
1766 std::vector<int>::iterator it = points_vector.begin();
1767 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1775 for (
int j = 0; j < nAuxPlyEntries; j++) {
1776 std::vector<int> points_vector;
1778 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1779 int nAuxPly = vec.size() / 2;
1781 if (nAuxPly == 0)
continue;
1783 for (
int i = 0; i < nAuxPly; i++) {
1784 plylon1 = vec[i * 2];
1785 plylat1 = vec[i * 2 + 1];
1791 points_vector.push_back(pixx1);
1792 points_vector.push_back(pixy1);
1799 points_vector.push_back(pixx1);
1800 points_vector.push_back(pixy1);
1802 if (points_vector.size()) {
1803 std::vector<int>::iterator it = points_vector.begin();
1804 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1812extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1813 float &MinorSpacing);
1814extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1815void glChartCanvas::GridDraw() {
1816 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1818 ViewPort &vp = m_pParentCanvas->GetVP();
1820 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1824 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1826 double nlat, elon, slat, wlon;
1828 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1831 wxColour GridColor = GetGlobalColor(
"SNDG1");
1833 if (!m_gridfont.IsBuilt()) {
1835 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1836 wxFont font = *dFont;
1839 int font_size = wxMax(10, dFont->GetPointSize());
1840 font.SetPointSize(font_size);
1841 font.SetWeight(wxFONTWEIGHT_NORMAL);
1844 m_gridfont.Build(font, m_displayScale, dpi_factor);
1846 m_gridfont.SetColor(GridColor);
1851 LLBBox llbbox = vp.GetBBox();
1852 nlat = llbbox.GetMaxLat();
1853 slat = llbbox.GetMinLat();
1854 elon = llbbox.GetMaxLon();
1855 wlon = llbbox.GetMinLon();
1862 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1863 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1864 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1865 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1866 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1867 vp.m_projection_type == PROJECTION_POLAR ||
1868 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1871 if (straight_latitudes)
1874 latmargin = gridlatMajor / 2;
1876 slat = wxMax(slat, -90 + latmargin);
1877 nlat = wxMin(nlat, 90 - latmargin);
1879 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1880 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1884 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1891 float lon_step = elon - wlon;
1892 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1894 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1896 s.x = INVALID_COORD;
1897 s.y = INVALID_COORD;
1898 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1900 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1901 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1909 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1910 lat += gridlatMinor) {
1913 gldc.DrawLine(0, r.y, 10, r.y,
true);
1914 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1919 float lat_step = nlat - slat;
1920 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1922 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1924 s.x = INVALID_COORD;
1925 s.y = INVALID_COORD;
1926 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1928 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1929 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1937 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1938 lon += gridlonMinor) {
1941 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1942 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1948 glEnable(GL_TEXTURE_2D);
1950 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1951 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1954 CalcGridText(lat, gridlatMajor,
true);
1956 m_gridfont.GetTextExtent(st, 0, &iy);
1958 if (straight_latitudes) {
1963 float x = 0, y = -1;
1964 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1965 if (y < 0 || y > h) {
1967 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1970 m_gridfont.RenderString(st, x, y);
1974 double y1, y2, lat1, lon1, lat2, lon2;
1983 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
1986 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
1988 if (fabs(y - y1) < fabs(y - y2))
1994 error = fabs(r.m_x);
1995 if (--maxiters == 0)
break;
1996 }
while (error > 1 && error < lasterror);
1998 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2004 m_gridfont.RenderString(st, r.m_x, r.m_y);
2008 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2009 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2018 else if (xlon <= -180.0)
2021 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2023 m_gridfont.GetTextExtent(st, &ix, 0);
2025 if (straight_longitudes) {
2026 float x = -1, y = 0;
2027 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2028 if (x < 0 || x > w) {
2030 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2033 m_gridfont.RenderString(st, x, y);
2037 double x1, x2, lat1, lon1, lat2, lon2;
2045 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2048 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2050 if (fabs(x - x1) < fabs(x - x2))
2056 error = fabs(r.m_y);
2057 }
while (error > 1 && error < lasterror);
2059 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2064 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2066 m_gridfont.RenderString(st, r.m_x, r.m_y);
2070 glDisable(GL_TEXTURE_2D);
2071 glDisable(GL_BLEND);
2076 if (!emboss)
return;
2078 int w = emboss->width, h = emboss->height;
2080 glEnable(GL_TEXTURE_2D);
2083 if (!emboss->gltexind) {
2085 emboss->glwidth = NextPow2(emboss->width);
2086 emboss->glheight = NextPow2(emboss->height);
2089 int size = emboss->glwidth * emboss->glheight;
2090 char *data =
new char[2 * size];
2091 for (
int i = 0; i < h; i++) {
2092 for (
int j = 0; j < emboss->glwidth; j++) {
2094 data[2 * ((i * emboss->glwidth) + j)] =
2095 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2096 data[2 * ((i * emboss->glwidth) + j) + 1] =
2097 (char)abs((emboss->pmap[(i * w) + j]));
2102 glGenTextures(1, &emboss->gltexind);
2103 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2104 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2105 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2107 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2108 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2113 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2117 int x = emboss->x, y = emboss->y;
2119 float wp = (float)w / emboss->glwidth;
2120 float hp = (float)h / emboss->glheight;
2146 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2148 glDisable(GL_BLEND);
2149 glDisable(GL_TEXTURE_2D);
2152void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2153 if (!m_pParentCanvas->GetVP().IsValid())
return;
2154 wxPoint GPSOffsetPixels(0, 0);
2155 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2158 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2159 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2163 double shift_dx = 0;
2164 double shift_dy = 0;
2165 bool dynamic = m_pParentCanvas->m_animationActive ||
2166 m_pParentCanvas->m_MouseDragging ||
2167 m_pParentCanvas->m_chart_drag_inertia_active;
2168 if (m_pParentCanvas->m_bFollow && !dynamic) {
2169 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2170 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2171 if (m_pParentCanvas->m_bLookAhead) {
2177 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2178 angle += m_pParentCanvas->GetVPRotation();
2179 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2181 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2182 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2184 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2189 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2190 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2197 lShipMidPoint = lGPSPoint;
2201 float icon_hdt = pCog;
2202 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2205 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2209 double osd_head_lat, osd_head_lon;
2210 wxPoint2DDouble osd_head_point;
2212 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2216 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2218 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2219 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2220 icon_rad += (float)PI;
2224 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2228 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2234 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2235 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2236 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2241 float scale_factor = 1.0;
2246 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2247 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2248 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2250 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2252 float nominal_ownship_size_pixels =
2254 nominal_ownship_size_mm);
2256 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2258 wxPen ppSmallScaleShip;
2259 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2261 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2264 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2265 dc.SetPen(ppSmallScaleShip);
2267 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2270 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2271 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2272 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2273 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2276 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2277 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2280 int draw_color = SHIP_INVALID;
2281 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2282 draw_color = SHIP_NORMAL;
2283 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2284 draw_color = SHIP_LOWACCURACY;
2292 ownship_color = draw_color;
2294 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2296 glGenTextures(1, &ownship_tex);
2297 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2303 if (m_pParentCanvas->m_pos_image_user) {
2304 switch (draw_color) {
2306 image = *m_pParentCanvas->m_pos_image_user_grey;
2309 image = *m_pParentCanvas->m_pos_image_user;
2311 case SHIP_LOWACCURACY:
2312 image = *m_pParentCanvas->m_pos_image_user_yellow;
2316 switch (draw_color) {
2318 image = *m_pParentCanvas->m_pos_image_grey;
2321 image = *m_pParentCanvas->m_pos_image_red;
2323 case SHIP_LOWACCURACY:
2324 image = *m_pParentCanvas->m_pos_image_yellow;
2329 int w = image.GetWidth(), h = image.GetHeight();
2330 int glw = NextPow2(w), glh = NextPow2(h);
2331 ownship_size = wxSize(w, h);
2332 ownship_tex_size = wxSize(glw, glh);
2334 unsigned char *d = image.GetData();
2335 unsigned char *a = image.GetAlpha();
2336 unsigned char *e =
new unsigned char[4 * w * h];
2339 for (
int p = 0; p < w * h; p++) {
2340 e[4 * p + 0] = d[3 * p + 0];
2341 e[4 * p + 1] = d[3 * p + 1];
2342 e[4 * p + 2] = d[3 * p + 2];
2343 e[4 * p + 3] = a[p];
2346 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2347 GL_UNSIGNED_BYTE, 0);
2349 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2355#ifndef USE_ANDROID_GLES2
2356 if (m_pParentCanvas->m_pos_image_user)
2357 glColor4ub(255, 255, 255, 255);
2358 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2359 glColor4ub(255, 0, 0, 255);
2360 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2361 glColor4ub(255, 255, 0, 255);
2363 glColor4ub(128, 128, 128, 255);
2365 float scale_factor_y = 1.0;
2366 float scale_factor_x = 1.0;
2368 int ownShipWidth = 22;
2369 int ownShipLength = 84;
2370 lShipMidPoint = lGPSPoint;
2373 if (g_OwnShipIconType != 0)
2374 m_pParentCanvas->ComputeShipScaleFactor(
2375 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2376 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2381 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2382 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2383 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2387 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2388 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2392 float gps_circle_radius = 3.0;
2394 if (g_OwnShipIconType == 0) {
2396 glEnable(GL_TEXTURE_2D);
2397 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2406 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2407 if (m_pParentCanvas->m_pos_image_user)
2408 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2410 float nominal_ownship_size_mm =
2411 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2413 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2414 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2416 float nominal_ownship_size_pixels =
2417 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2419 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2420 nominal_ownship_size_pixels = wxMax(
2421 20.0, nominal_ownship_size_pixels);
2424 float h = nominal_ownship_size_pixels * scale_factor_y;
2425 float w = nominal_ownship_size_pixels * scale_factor_x *
2426 ownship_size.x / ownship_size.y;
2427 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2428 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2434 gps_circle_radius = w / 5;
2436 float uv[8], coords[8];
2455 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2456 lShipMidPoint.m_x, lShipMidPoint.m_y,
2458 glDisable(GL_TEXTURE_2D);
2459 }
else if (g_OwnShipIconType == 1) {
2461 glEnable(GL_TEXTURE_2D);
2462 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2464 float nominal_ownship_size_pixels_y = 84;
2465 float nominal_ownship_size_pixels_x = 22;
2467 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2468 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2470 float u = (float)ownship_size.x / ownship_tex_size.x,
2471 v = (
float)ownship_size.y / ownship_tex_size.y;
2474 gps_circle_radius = w / 5;
2476 float uv[8], coords[8];
2495 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2496 lShipMidPoint.m_x, lShipMidPoint.m_y,
2499 glDisable(GL_TEXTURE_2D);
2500 }
else if (g_OwnShipIconType == 2) {
2508 wxPoint shipPoints[6];
2510 wxColour colour = m_pParentCanvas->ShipColor();
2511 wxPen ppPen(*wxBLACK, 1);
2512 wxBrush ppBrush(colour);
2514 dc.SetBrush(ppBrush);
2516 shipPoints[0].x = 0 * scale_factor_x;
2517 shipPoints[0].y = -28 * scale_factor_y;
2518 shipPoints[1].x = 11 * scale_factor_x;
2519 shipPoints[1].y = -28 * scale_factor_y;
2520 shipPoints[2].x = 11 * scale_factor_x;
2521 shipPoints[2].y = 42 * scale_factor_y;
2522 shipPoints[3].x = 0 * scale_factor_x;
2523 shipPoints[3].y = 42 * scale_factor_y;
2524 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2527 shipPoints[0].x = 0 * scale_factor_x;
2528 shipPoints[0].y = -42 * scale_factor_y;
2529 shipPoints[1].x = 5 * scale_factor_x;
2530 shipPoints[1].y = -42 * scale_factor_y;
2531 shipPoints[2].x = 11 * scale_factor_x;
2532 shipPoints[2].y = -28 * scale_factor_y;
2533 shipPoints[3].x = 0 * scale_factor_x;
2534 shipPoints[3].y = -28 * scale_factor_y;
2535 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2538 shipPoints[0].x = 0 * scale_factor_x;
2539 shipPoints[0].y = -28 * scale_factor_y;
2540 shipPoints[1].x = -11 * scale_factor_x;
2541 shipPoints[1].y = -28 * scale_factor_y;
2542 shipPoints[2].x = -11 * scale_factor_x;
2543 shipPoints[2].y = 42 * scale_factor_y;
2544 shipPoints[3].x = 0 * scale_factor_x;
2545 shipPoints[3].y = 42 * scale_factor_y;
2546 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2549 shipPoints[0].x = 0 * scale_factor_x;
2550 shipPoints[0].y = -42 * scale_factor_y;
2551 shipPoints[1].x = -5 * scale_factor_x;
2552 shipPoints[1].y = -42 * scale_factor_y;
2553 shipPoints[2].x = -11 * scale_factor_x;
2554 shipPoints[2].y = -28 * scale_factor_y;
2555 shipPoints[3].x = 0 * scale_factor_x;
2556 shipPoints[3].y = -28 * scale_factor_y;
2557 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2561 double p1x = -11 * scale_factor_x;
2562 double p2x = 11 * scale_factor_x;
2566 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2568 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2570 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2572 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2573 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2574 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2578 p1y = -42 * scale_factor_y;
2579 p2y = 42 * scale_factor_y;
2580 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2581 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2582 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2583 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2584 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2585 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2588 img_height = ownShipLength * scale_factor_y;
2591 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2593 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2595 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2597 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2601 glDisable(GL_LINE_SMOOTH);
2602 glDisable(GL_POLYGON_SMOOTH);
2603 glDisable(GL_BLEND);
2606 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2610void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2611 ViewPort &vp = m_pParentCanvas->GetVP();
2634 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2636 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2637 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2639 m_pParentCanvas->AlertDraw(dc);
2641 m_pParentCanvas->RenderVisibleSectorLights(dc);
2643 m_pParentCanvas->RenderRouteLegs(dc);
2644 m_pParentCanvas->RenderShipToActive(dc,
true);
2645 m_pParentCanvas->ScaleBarDraw(dc);
2646 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2647 m_pParentCanvas->extendedSectorLegs);
2654void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2655 if (m_pParentCanvas->GetPiano()) {
2656 int canvas_height = GetClientSize().y;
2657 canvas_height *= m_displayScale;
2659 m_pParentCanvas->GetPiano()->DrawGL(
2660 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2664void glChartCanvas::DrawQuiting() {
2665#ifndef USE_ANDROID_GLES2
2666 GLubyte pattern[8][8];
2667 for (
int y = 0; y < 8; y++)
2668 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2671 glEnable(GL_TEXTURE_2D);
2672 glBindTexture(GL_TEXTURE_2D, 0);
2674 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2675 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2676 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2678 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2682 float x = GetSize().x, y = GetSize().y;
2683 float u = x / 8, v = y / 8;
2696 glDisable(GL_TEXTURE_2D);
2697 glDisable(GL_BLEND);
2701void glChartCanvas::DrawCloseMessage(wxString msg) {
2702#ifndef USE_ANDROID_GLES2
2706 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2710 texfont.Build(*pfont, 1, 1);
2712 texfont.GetTextExtent(msg, &w, &h);
2714 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2715 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2717 glColor3ub(243, 229, 47);
2721 glVertex2i(xp + w, yp);
2722 glVertex2i(xp + w, yp + h);
2723 glVertex2i(xp, yp + h);
2728 glColor3ub(0, 0, 0);
2729 glEnable(GL_TEXTURE_2D);
2730 texfont.RenderString(msg, xp, yp);
2731 glDisable(GL_TEXTURE_2D);
2732 glDisable(GL_BLEND);
2739static std::list<double *> combine_work_data;
2740static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2741 GLfloat weight[4], GLdouble **dataOut) {
2742 double *vertex =
new double[3];
2743 combine_work_data.push_back(vertex);
2744 memcpy(vertex, coords, 3 * (
sizeof *coords));
2748#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2749void vertexCallbackD_GLSL(GLvoid *vertex) {
2750 GLdouble *pointer = (GLdouble *)vertex;
2751 s_tess_vertex_work.push_back(pointer[0]);
2752 s_tess_vertex_work.push_back(pointer[1]);
2755void beginCallbackD_GLSL(GLenum mode) {
2757 s_tess_vertex_work.clear();
2760void endCallbackD_GLSL() {
2761 if (!s_tess_vertex_work.empty() && (s_tess_vertex_work.size() % 2 == 0)) {
2765 shader->SetUniformMatrix4fv(
"MVMatrix",
2766 (GLfloat *)s_tessVP.vp_matrix_transform);
2768 mat4x4 identityMatrix;
2769 mat4x4_identity(identityMatrix);
2770 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2774 colorv[0] = s_regionColor.Red() / float(256);
2775 colorv[1] = s_regionColor.Green() / float(256);
2776 colorv[2] = s_regionColor.Blue() / float(256);
2777 colorv[3] = s_regionColor.Alpha() / float(256);
2778 shader->SetUniform4fv(
"color", colorv);
2779 shader->SetAttributePointerf(
"position", s_tess_vertex_work.data());
2781 glDrawArrays(s_tess_mode, 0, s_tess_vertex_work.size() / 2);
2786 "::endCallbackD_GLSL() called with wrong tess vertex vector length "
2788 s_tess_vertex_work.size());
2791void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2793void beginCallbackD(GLenum mode) { glBegin(mode); }
2795void endCallbackD() { glEnd(); }
2799void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2800 float lat_dist, lon_dist;
2801 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2803 GLUtesselator *tobj = gluNewTess();
2804 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2806#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2807 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2808 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2809 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2810 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2814 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2815 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2816 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2817 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2820 gluTessNormal(tobj, 0, 0, 1);
2822 gluTessBeginPolygon(tobj, NULL);
2823 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2824 gluTessBeginContour(tobj);
2825 contour_pt l = *i->rbegin();
2827 bool sml_valid =
false;
2828 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2829 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2830 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2831 int splits = wxMax(lat_splits, lon_splits) + 1;
2837 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2838 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2841 for (
int i = 0; i < splits; i++) {
2843 if (i == splits - 1)
2844 lat = j->y, lon = j->x;
2846 double d = (double)(i + 1) / splits;
2847 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2851 if (std::isnan(q.m_x))
continue;
2853 double *p =
new double[6];
2858 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2863 gluTessVertex(tobj, p, p);
2864 combine_work_data.push_back(p);
2868 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2870 gluTessEndContour(tobj);
2872 gluTessEndPolygon(tobj);
2874 gluDeleteTess(tobj);
2876 for (std::list<double *>::iterator i = combine_work_data.begin();
2877 i != combine_work_data.end(); i++)
2879 combine_work_data.clear();
2884void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2885 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2887 if (s_b_useStencil) {
2889 glEnable(GL_STENCIL_TEST);
2891 glClear(GL_STENCIL_BUFFER_BIT);
2895 glStencilFunc(GL_ALWAYS, 1, 1);
2896 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2899#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2903 glEnable(GL_DEPTH_TEST);
2904 glDepthFunc(GL_ALWAYS);
2905 glDepthMask(GL_TRUE);
2907 glClear(GL_DEPTH_BUFFER_BIT);
2920 glTranslatef(0, 0, .5);
2924 s_regionColor = wxColor(0, 0, 0, 255);
2925 DrawRegion(vp, region);
2927 if (s_b_useStencil) {
2930 glStencilFunc(GL_EQUAL, 1, 1);
2931 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2934#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2936 glDepthFunc(GL_GREATER);
2937 glDepthMask(GL_FALSE);
2938 glTranslatef(0, 0, -.5);
2941 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2944void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2948 if (s_b_useStencil && s_b_useScissorTest) {
2950 if (rect != vp_rect) {
2951 glEnable(GL_SCISSOR_TEST);
2952 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2955#ifndef USE_ANDROID_GLES2
2961void glChartCanvas::DisableClipRegion() {
2962 glDisable(GL_SCISSOR_TEST);
2963 glDisable(GL_STENCIL_TEST);
2964 glDisable(GL_DEPTH_TEST);
2967void glChartCanvas::Invalidate() {
2969 m_cache_vp.Invalidate();
2975 if (!pBSBChart)
return;
2981 wxString key = chart->GetHashKey();
2985 ChartPathHashTexfactType::iterator ittf = hash.find(key);
2988 if (ittf == hash.end()) {
2990 hash[key]->SetHashKey(key);
2993 pTexFact = hash[key];
2994 pTexFact->SetLRUTime(++m_LRUtime);
2999 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3000 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3007 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3008 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3009 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3010 base_level = log(scalefactor) / log(2.0);
3019 glEnable(GL_TEXTURE_2D);
3020#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3021 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3023 glEnableClientState(GL_VERTEX_ARRAY);
3024 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3029 pTexFact->GetCenter(lat, lon);
3030 MultMatrixViewPort(vp, lat, lon);
3034 LLBBox box = region.GetBox();
3037 if (g_memCacheLimit > 0) {
3042 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3043 for (
int i = 0; i < numtiles; i++) {
3045 if (region.IntersectOut(tile->box)) {
3048 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3049 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3051 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3052 global_color_scheme, mem_used);
3056 coords = tile->m_coords;
3058 coords =
new float[2 * tile->m_ncoords];
3059 for (
int i = 0; i < tile->m_ncoords; i++) {
3061 tile->m_coords[2 * i + 1]);
3062 coords[2 * i + 0] = p.m_x;
3063 coords[2 * i + 1] = p.m_y;
3067#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3068 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3069 m_pParentCanvas->GetpVP());
3072 glDisable(GL_TEXTURE_2D);
3076 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3077 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3078 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3080 if (!texture) glEnable(GL_TEXTURE_2D);
3082 if (!use_norm_vp)
delete[] coords;
3086 glDisable(GL_TEXTURE_2D);
3088#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3089 if (use_norm_vp) glPopMatrix();
3091 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3092 glDisableClientState(GL_VERTEX_ARRAY);
3096void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3098 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3099 m_pParentCanvas->m_pQuilt->IsBusy())
3103 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3105 printf(
" Chart NULL\n");
3106 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3116 LLRegion region = vp.GetLLRegion(rect_region);
3118 LLRegion rendered_region;
3124 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3132 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3134 LLRegion get_region = pqp->ActiveRegion;
3135 bool b_rendered =
false;
3137 if (!pqp->b_overlay) {
3138 get_region.Intersect(region);
3139 if (!get_region.Empty()) {
3140 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3143 SetClipRegion(vp, get_region );
3144 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3145 DisableClipRegion();
3148 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3149 SetClipRegion(vp, pqp->ActiveRegion );
3150 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3152 DisableClipRegion();
3155 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3156 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3157 RenderNoDTA(vp, get_region);
3158 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3163 if (Chs57->m_RAZBuilt) {
3164 RenderNoDTA(vp, get_region);
3165 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3166 rect_region, get_region);
3167 DisableClipRegion();
3172 const LLRegion &oregion = get_region;
3173 LLBBox box = oregion.GetBox();
3184 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3187 ViewPort cvp = ClippedViewport(vp, get_region);
3188 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3189 SetClipRegion(cvp, get_region);
3190 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3191 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3192 RenderWorldChart(gldc, cvp, srect, world);
3193 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3194 global_color_scheme);
3195 DisableClipRegion();
3202 SetClipRegion(vp, get_region);
3203 RenderNoDTA(vp, get_region);
3204 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3206 DisableClipRegion();
3209 SetClipRegion(vp, get_region);
3210 RenderNoDTA(vp, get_region);
3211 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3213 DisableClipRegion();
3229 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3233 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3234 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3236 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3237 if (pqp->b_Valid && pqp->b_overlay &&
3238 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3239 LLRegion get_region = pqp->ActiveRegion;
3241 get_region.Intersect(region);
3242 if (!get_region.Empty()) {
3245 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3250 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3257 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3262 ViewPort vph = m_pParentCanvas->GetVP();
3263 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3266 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3268 if (!hiregion.Empty()) {
3272 switch (global_color_scheme) {
3273 case GLOBAL_COLOR_SCHEME_DAY:
3276 case GLOBAL_COLOR_SCHEME_DUSK:
3279 case GLOBAL_COLOR_SCHEME_NIGHT:
3287#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3289 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3291 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3294 DrawRegion(vp, hiregion);
3296 glDisable(GL_BLEND);
3301 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3303 if (!hiregion.Empty()) {
3307 switch (global_color_scheme) {
3308 case GLOBAL_COLOR_SCHEME_DAY:
3311 case GLOBAL_COLOR_SCHEME_DUSK:
3314 case GLOBAL_COLOR_SCHEME_NIGHT:
3323#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3325 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3327 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3330 DrawRegion(vp, hiregion);
3332 glDisable(GL_BLEND);
3336 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3339void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3341 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3342 m_pParentCanvas->m_pQuilt->IsBusy())
3346 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3348 LLRegion region = vp.GetLLRegion(rect_region);
3350 LLRegion rendered_region;
3352 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3354 LLRegion get_region = pqp->ActiveRegion;
3356 if (!pqp->b_overlay) {
3357 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3360 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3365 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3372 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3400void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3401 ViewPort &vp = m_pParentCanvas->VPoint;
3409 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3410 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3413 LLRegion chart_region;
3415 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3416 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3417 CHART_FAMILY_RASTER) {
3425 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3426 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3427 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3429 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3433 for (
int i = 1; i < 6; i += 2)
3434 if (fabs(ll[i] - ll[i + 2]) > 180) {
3436 for (
int i = 1; i < 8; i += 2)
3437 if (ll[i] < 0) ll[i] += 360;
3441 chart_region = LLRegion(4, ll);
3444 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3446 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3447 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3448 chart_region = LLRegion(4, ll);
3451 chart_region = vp.b_quilt
3452 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3453 : m_pParentCanvas->m_singleChart->GetValidRegion();
3455 bool world_view =
false;
3457 wxRect rect = upd.GetRect();
3458 LLRegion background_region = vp.GetLLRegion(rect);
3461 background_region.Subtract(chart_region);
3463 if (!background_region.Empty()) {
3464 ViewPort cvp = ClippedViewport(vp, background_region);
3465 SetClipRect(cvp, rect,
false);
3466 RenderWorldChart(dc, cvp, rect, world_view);
3467 DisableClipRegion();
3472 RenderQuiltViewGL(vp, rect_region);
3475 LLRegion region = vp.GetLLRegion(rect_region);
3476 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3477 CHART_FAMILY_RASTER) {
3478 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3479 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3480 *m_pcontext, vp, rect_region, region);
3482 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3483 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3484 CHART_FAMILY_VECTOR) {
3485 chart_region.Intersect(region);
3486 RenderNoDTA(vp, chart_region);
3487 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3488 rect_region, region);
3494void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3496 wxColour color = GetGlobalColor(
"NODTA");
3497#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3499 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3501 glColor4ub(163, 180, 183, transparency);
3504 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3508 s_regionColor = color;
3511 DrawRegion(vp, region);
3515void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3518 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3520 glEnable(GL_SCISSOR_TEST);
3521 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3527 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3528#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3530 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3534 colorv[0] = water.Red() / float(256);
3535 colorv[1] = water.Green() / float(256);
3536 colorv[2] = water.Blue() / float(256);
3538 shader->SetUniform4fv(
"color", colorv);
3549 shader->SetAttributePointerf(
"position", pf);
3551 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3563 glDisable(GL_SCISSOR_TEST);
3571void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3572 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3574 DrawStaticRoutesTracksAndWaypoints(vp);
3576 DisableClipRegion();
3579void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3581 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3585 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3586 if (!bmp.Ok())
return;
3588 wxImage image = bmp.ConvertToImage();
3589 int w = image.GetWidth(), h = image.GetHeight();
3592 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3593 tex_w = w, tex_h = h;
3595 tex_w = NextPow2(w), tex_h = NextPow2(h);
3597 m_tideTexWidth = tex_w;
3598 m_tideTexHeight = tex_h;
3600 unsigned char *d = image.GetData();
3601 unsigned char *a = image.GetAlpha();
3603 unsigned char mr, mg, mb;
3604 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3606 unsigned char *e =
new unsigned char[4 * w * h];
3608 for (
int y = 0; y < h; y++)
3609 for (
int x = 0; x < w; x++) {
3610 unsigned char r, g, b;
3611 int off = (y * w + x);
3621 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3625 glGenTextures(1, &m_tideTex);
3627 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3628 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3629 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3631 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3632 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3633 GL_UNSIGNED_BYTE, e);
3635 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3636 GL_UNSIGNED_BYTE, 0);
3637 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3646 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3647 glEnable(GL_TEXTURE_2D);
3650#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3652 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3656 if ((type ==
't') || (type ==
'T'))
3661 if (BBox.Contains(lat, lon)) {
3670 scale *= getAndroidDisplayDensity();
3672 double width2 =
scale * m_tideTexWidth / 2;
3673 double height2 =
scale * m_tideTexHeight / 2;
3688 coords[0] = xp - width2;
3689 coords[1] = yp - height2;
3690 coords[2] = xp - width2;
3691 coords[3] = yp + height2;
3692 coords[4] = xp + width2;
3693 coords[5] = yp + height2;
3694 coords[6] = xp + width2;
3695 coords[7] = yp - height2;
3697 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3704 glDisable(GL_TEXTURE_2D);
3705 glDisable(GL_BLEND);
3706 glBindTexture(GL_TEXTURE_2D, 0);
3708 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3711void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3712 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3715void glChartCanvas::SetColorScheme(ColorScheme cs) {
3716 if (!m_bsetup)
return;
3718 glDeleteTextures(1, &m_tideTex);
3719 glDeleteTextures(1, &m_currentTex);
3725void glChartCanvas::RenderGLAlertMessage() {
3726 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3727 wxString msg = m_pParentCanvas->GetAlertString();
3730 m_gldc.SetFont(*pfont);
3734 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3741 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3742 int xp = sbr.x + sbr.width + 5;
3744 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3745 m_gldc.SetPen(ppPen1);
3746 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3748 m_gldc.DrawRectangle(xp, yp, w, h);
3750 m_gldc.DrawText(msg, xp, yp);
3754unsigned long quiltHash;
3756extern wxLongLong s_t0;
3759void glChartCanvas::Render() {
3760 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3761 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3762 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3767 if (!g_PrintingInProgress)
return;
3770 if (!g_true_zoom && m_binPinch)
return;
3773 long render_start_time = m_glstopwatch.Time();
3775#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3776 loadShaders(GetCanvasIndex());
3777 configureShaders(m_pParentCanvas->VPoint);
3780#ifdef USE_ANDROID_GLES2
3784 if (m_binPinch)
return;
3793 bool recompose =
false;
3794 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3795 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3796 if (m_pParentCanvas->VPoint.IsValid()) {
3797 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3798 m_pParentCanvas->UpdateCanvasControlBar();
3807 if (sw.GetTime() > 2000) {
3813 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3814 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3820 m_displayScale = GetContentScaleFactor();
3824 m_last_render_time = wxDateTime::Now().GetTicks();
3828 if (g_GLOptions.m_bTextureCompression &&
3829 !g_GLOptions.m_bTextureCompressionCaching)
3834 int gl_width, gl_height;
3835 gl_width = m_pParentCanvas->VPoint.
pix_width;
3836 gl_height = m_pParentCanvas->VPoint.
pix_height;
3839 m_glcanvas_width = gl_width;
3840 m_glcanvas_height = gl_height;
3846 ViewPort VPoint = m_pParentCanvas->VPoint;
3848 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3849 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3852#if !defined(USE_ANDROID_GLES2)
3853 glMatrixMode(GL_PROJECTION);
3856 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3857 glMatrixMode(GL_MODELVIEW);
3861 if (s_b_useStencil) {
3862 glEnable(GL_STENCIL_TEST);
3863 glStencilMask(0xff);
3864 glClear(GL_STENCIL_BUFFER_BIT);
3865 glDisable(GL_STENCIL_TEST);
3871 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3872 if (g_GLOptions.m_GLPolygonSmoothing)
3873 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3874 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3886 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3887 bool useFBO =
false;
3893 if (m_b_BuiltFBO && !bpost_hilite
3898 bool b_newview =
true;
3899 bool b_full =
false;
3907 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3911#ifdef USE_ANDROID_GLES2
3912 if (recompose) b_newview =
true;
3924 if (VPoint.b_quilt) {
3925 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3926 if (!chart) b_full =
true;
3935 bool accelerated_pan =
false;
3945 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
3946 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
3947 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
3949 wxPoint2DDouble c_old =
3952 wxPoint2DDouble c_new =
3956 dy = wxRound(c_new.m_y - c_old.m_y);
3957 dx = wxRound(c_new.m_x - c_old.m_x);
3967 double deltax = c_new.m_x - c_old.m_x;
3968 double deltay = c_new.m_y - c_old.m_y;
3970 bool b_whole_pixel =
true;
3971 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
3972 b_whole_pixel =
false;
3974 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
3975 abs(dy) < m_cache_tex_y &&
3976 (abs(dx) > 0 || (abs(dy) > 0));
3985 if (m_displayScale > 1) accelerated_pan =
false;
3990 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
3993#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3996 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4002 if (b_full) accelerated_pan =
false;
4004 if (accelerated_pan) {
4005 if ((dx != 0) || (dy != 0)) {
4017 if (dy > 0 && dy < gl_height)
4018 update_region.Union(
4019 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4021 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4023 if (dx > 0 && dx < gl_width)
4024 update_region.Union(
4025 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4027 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4029 m_cache_page = !m_cache_page;
4032 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4033 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4045 RenderCharts(m_gldc, update_region);
4049 glDisable(g_texture_rectangle_format);
4054 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4055 glEnable(GL_TEXTURE_2D);
4059 float x1, x2, y1, y2;
4072 float tx1, tx2, ty1, ty2;
4078 tx2 = sx / (float)m_cache_tex_x;
4080 ty2 = sy / (float)m_cache_tex_y;
4097 coords[2] = -dx + sx;
4099 coords[4] = -dx + sx;
4100 coords[5] = dy + sy;
4102 coords[7] = dy + sy;
4105 ptexture_2D_shader_program[GetCanvasIndex()];
4109 shader->SetUniform1i(
"uTex", 0);
4113 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4114 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4115 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4117 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4139 shader->SetAttributePointerf(
"aPos", co1);
4140 shader->SetAttributePointerf(
"aUV", tco1);
4142 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4145 shader->SetUniformMatrix4fv(
"MVMatrix",
4146 (GLfloat *)VPoint.vp_matrix_transform);
4149 glBindTexture(g_texture_rectangle_format, 0);
4151 glDisable(g_texture_rectangle_format);
4159 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4160 g_texture_rectangle_format,
4161 m_cache_tex[!m_cache_page], 0);
4172 wxColour color = GetGlobalColor(
"NODTA");
4173 glClearColor(color.Red() / 256., color.Green() / 256.,
4174 color.Blue() / 256., 1.0);
4175 glClear(GL_COLOR_BUFFER_BIT);
4181 RenderCharts(m_gldc, rscreen_region);
4186 m_cache_page = !m_cache_page;
4191 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4202 glMatrixMode(GL_PROJECTION);
4205 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4206 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4208 glMatrixMode(GL_MODELVIEW);
4212 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4213 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4215 glGetIntegerv(GL_VIEWPORT, viewport);
4216 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4217 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4226 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4227 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4228 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4230 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4234 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4235 glEnable(g_texture_rectangle_format);
4237 float tx, ty, tx0, ty0, divx, divy;
4240 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4243 divx = m_cache_tex_x;
4244 divy = m_cache_tex_y;
4247 tx0 = m_fbo_offsetx / divx;
4248 ty0 = m_fbo_offsety / divy;
4249 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4250 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4275 wxColour color = GetGlobalColor(
"NODTA");
4276 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4278 glClear(GL_COLOR_BUFFER_BIT);
4280 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4283 glDisable(g_texture_rectangle_format);
4285 m_cache_vp = VPoint;
4286 m_cache_vp.Validate();
4288 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4290 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4294 RenderCharts(m_gldc, screen_region);
4303 RenderS57TextOverlay(VPoint);
4304 RenderMBTilesOverlay(VPoint);
4310 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4315 wxRect rt = upd.GetRect();
4316 LLRegion region = VPoint.GetLLRegion(rt);
4317 ViewPort cvp = ClippedViewport(VPoint, region);
4318 DrawGroundedOverlayObjects(gldc, cvp);
4321 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4322 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4323 LLBBox screenBox = screenLLRegion.GetBox();
4325 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4328 if (m_pParentCanvas->m_bShowTide) {
4329 m_pParentCanvas->RebuildTideSelectList(screenBox);
4330 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4333 if (m_pParentCanvas->m_bShowCurrent) {
4334 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4335 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4341 if (m_pParentCanvas->m_show_focus_bar &&
4342 (g_canvasConfig != 0)) {
4343 if (m_pParentCanvas == wxWindow::FindFocus()) {
4346 wxColour colour = GetGlobalColor(
"BLUE4");
4347 wxPen ppBlue(colour, 1);
4348 wxBrush ppBrush(colour);
4349 gldc.SetPen(ppBlue);
4350 gldc.SetBrush(ppBrush);
4351 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4352 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4353 wxPoint barPoints[4];
4356 barPoints[1].x = xw;
4358 barPoints[2].x = xw;
4359 barPoints[2].y = rect_pix;
4361 barPoints[3].y = rect_pix;
4363 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4367 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4371 DrawFloatingOverlayObjects(m_gldc);
4373#ifndef USE_ANDROID_GLES2
4376 glMatrixMode(GL_PROJECTION);
4379 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4380 glMatrixMode(GL_MODELVIEW);
4385 if (!g_bhide_depth_units)
4386 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4387 if (!g_bhide_overzoom_flag)
4388 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4391 ViewPort &vp = m_pParentCanvas->GetVP();
4396 if (!g_PrintingInProgress) {
4397 if (m_pParentCanvas->m_pTrackRolloverWin)
4398 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4400 if (m_pParentCanvas->m_pRouteRolloverWin)
4401 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4403 if (m_pParentCanvas->m_pAISRolloverWin)
4404 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4406 if (m_pParentCanvas->GetMUIBar())
4407 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4421 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4422 int x, y, width, height;
4423 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4424 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4425 wxBitmap bmp(width, height, -1);
4428 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4431 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4432 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4436 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4437 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4439 wxStringTokenizer tkz(s,
"\n");
4442 while (tkz.HasMoreTokens()) {
4443 token = tkz.GetNextToken();
4444 dc.DrawText(token, xt, yt);
4447 dc.SelectObject(wxNullBitmap);
4449 m_gldc.DrawBitmap(bmp, x, y,
false);
4455 if (g_bShowChartBar) DrawChartBar(m_gldc);
4457 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4459 m_pParentCanvas->m_Compass->Paint(gldc);
4461 if (m_pParentCanvas->IsPrimaryCanvas() &&
4462 m_pParentCanvas->m_notification_button) {
4463 auto ¬eman = NotificationManager::GetInstance();
4464 if (noteman.GetNotificationCount()) {
4465 m_pParentCanvas->m_notification_button->SetIconSeverity(
4466 noteman.GetMaxSeverity());
4467 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4468 m_pParentCanvas->m_notification_button->Show(
true);
4469 m_pParentCanvas->m_notification_button->Paint(gldc);
4471 m_pParentCanvas->m_notification_button->Show(
false);
4474 RenderGLAlertMessage();
4477 ViewPort &vp = m_pParentCanvas->GetVP();
4481 glActiveTexture(GL_TEXTURE0);
4485 if (g_bquiting) DrawQuiting();
4486 if (g_bcompression_wait)
4487 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4497 m_pParentCanvas->PaintCleanup();
4498 m_bforcefull =
false;
4507void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4510 if (VPoint.b_quilt) {
4511 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4512 ps52plib->GetShowS57Text()) {
4513 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4514 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4519 ChPI->ClearPLIBTextList();
4521 ps52plib->ClearTextList();
4531 RenderQuiltViewGLText(vpx, screen_region);
4536void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4539 LLRegion &screenLLRegion) {
4544 if (chart == NULL)
return;
4551 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4553 wxFileName tileFile(chart->GetFullPath());
4555 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4558 bool isBasemap = tileFile.GetPath().Lower().Contains(
"basemap");
4564 (double)chart->GetNativeScale();
4566 if (zoom_ratio > g_tile_basemap_zoom_factor)
return;
4569 if (!isBasemap && (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4570 (tileSizeMB.GetLo() > 5000))) {
4573 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4574 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4575 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4582 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4586 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4589 std::vector<int> piano_active_array_tiles =
4590 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4591 bool bfound =
false;
4593 if (std::find(piano_active_array_tiles.begin(),
4594 piano_active_array_tiles.end(),
4595 dbIndex) != piano_active_array_tiles.end()) {
4600 piano_active_array_tiles.push_back(dbIndex);
4601 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4605void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4607 std::vector<int> stackIndexArray =
4608 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4609 unsigned int im = stackIndexArray.size();
4612 if (VPoint.b_quilt && im > 0) {
4613 bool regionVPBuilt =
false;
4615 LLRegion screenLLRegion;
4619 std::vector<int> tiles_to_show;
4620 for (
unsigned int is = 0; is < im; is++) {
4622 ChartData->GetChartTableEntry(stackIndexArray[is]);
4623 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4624 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4626 std::vector<int> piano_active_array_tiles =
4627 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4628 bool bfound =
false;
4630 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4631 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4632 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4640 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4641 piano_active_array_tiles);
4646 tiles_to_show.push_back(stackIndexArray[is]);
4647 if (!regionVPBuilt) {
4650 screenLLRegion = VPoint.GetLLRegion(screen_region);
4651 screenBox = screenLLRegion.GetBox();
4659 regionVPBuilt =
true;
4669 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4670 rit != tiles_to_show.rend(); ++rit) {
4671 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4673 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4674 rit != tiles_to_show.rend(); ++rit) {
4675 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4679 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4681 if (!hiregion.Empty()) {
4685 switch (global_color_scheme) {
4686 case GLOBAL_COLOR_SCHEME_DAY:
4689 case GLOBAL_COLOR_SCHEME_DUSK:
4692 case GLOBAL_COLOR_SCHEME_NIGHT:
4700#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4701 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4703 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4706 DrawRegion(VPoint, hiregion);
4708 glDisable(GL_BLEND);
4714void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4718 GetClientSize(&w, &h);
4720 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4721#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4722 glMatrixMode(GL_PROJECTION);
4725 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4726 glMatrixMode(GL_MODELVIEW);
4730 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4732 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4734 bool world_view =
false;
4735 RenderWorldChart(dc, cvp, rtex, world_view);
4742 glViewport(0, 0, (GLint)w, (GLint)h);
4743#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4744 glMatrixMode(GL_PROJECTION);
4747 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4748 glMatrixMode(GL_MODELVIEW);
4754void glChartCanvas::FastPan(
int dx,
int dy) {
4755#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4759void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4761 if (IsShown()) SetCurrent(*m_pcontext);
4762 float sx = GetSize().x;
4763 float sy = GetSize().y;
4764 glClear(GL_COLOR_BUFFER_BIT);
4767 GetClientSize(&w, &h);
4769 if (s_b_useStencil) {
4770 glEnable(GL_STENCIL_TEST);
4771 glStencilMask(0xff);
4772 glClear(GL_STENCIL_BUFFER_BIT);
4773 glDisable(GL_STENCIL_TEST);
4789 float sxfactor = sx / swidth;
4790 float syfactor = sy / sheight;
4792 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4793 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4794 sx * sx / swidth * 2, sy * sy / sheight * 2);
4795 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4796 glEnable(g_texture_rectangle_format);
4821 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4822 glBindTexture(g_texture_rectangle_format, 0);
4828 float tx, ty, tx0, ty0;
4838 glBindTexture(g_texture_rectangle_format, 0);
4841 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4842 glEnable(g_texture_rectangle_format);
4848 uv[0] = tx0 / m_cache_tex_x;
4849 uv[1] = ty / m_cache_tex_y;
4850 uv[2] = tx / m_cache_tex_x;
4851 uv[3] = ty / m_cache_tex_y;
4852 uv[4] = tx / m_cache_tex_x;
4853 uv[5] = ty0 / m_cache_tex_y;
4854 uv[6] = tx0 / m_cache_tex_x;
4855 uv[7] = ty0 / m_cache_tex_y;
4867 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4868 sx * sx / swidth, sy * sy / sheight);
4870 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4872 glDisable(g_texture_rectangle_format);
4873 glBindTexture(g_texture_rectangle_format, 0);
4880 wxColour color = GetGlobalColor(
"GREY1");
4881 float ht = -offset_y * (sy / sheight);
4882 wxRect r(0, sy - ht, w, ht);
4883 RenderColorRect(r, color);
4886 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4887 RenderColorRect(rt, color);
4890 float w1 = -offset_x * sx / swidth;
4891 wxRect rl(0, 0, w1, sy);
4892 RenderColorRect(rl, color);
4895 float px = w1 + sx * sx / swidth;
4896 wxRect rr(px, 0, sx - px, sy);
4897 RenderColorRect(rr, color);
4906void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4909 if (m_nRun < m_nTotal) {
4910 m_runoffsetx += m_offsetxStep;
4911 if (m_offsetxStep > 0)
4912 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4914 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4916 m_runoffsety += m_offsetyStep;
4917 if (m_offsetyStep > 0)
4918 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4920 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4922 m_runswidth += m_swidthStep;
4923 if (m_swidthStep > 0)
4924 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4926 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4928 m_runsheight += m_sheightStep;
4929 if (m_sheightStep > 0)
4930 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4932 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4937 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4943 if (m_zoomFinaldx || m_zoomFinaldy) {
4944 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
4947 m_zoomFinal =
false;
4951void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
4953 int sx = GetSize().x;
4954 int sy = GetSize().y;
4956 m_lastfbo_offsetx = m_fbo_offsetx;
4957 m_lastfbo_offsety = m_fbo_offsety;
4958 m_lastfbo_swidth = m_fbo_swidth;
4959 m_lastfbo_sheight = m_fbo_sheight;
4961 float curr_fbo_offset_x = m_fbo_offsetx;
4962 float curr_fbo_offset_y = m_fbo_offsety;
4963 float curr_fbo_swidth = m_fbo_swidth;
4964 float curr_fbo_sheight = m_fbo_sheight;
4966 float fx = (float)cp_x / sx;
4967 float fy = 1.0 - (float)cp_y / sy;
4969 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
4970 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
4972 m_fbo_swidth = curr_fbo_swidth / factor;
4973 m_fbo_sheight = curr_fbo_sheight / factor;
4975 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
4976 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
4978 m_fbo_offsetx += post_x;
4979 m_fbo_offsety += post_y;
4990 float perStep = m_nStep / m_nTotal;
4992 if (zoomTimer.IsRunning()) {
4993 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
4994 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
4995 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
4996 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
4999 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5000 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5001 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5002 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5004 m_runoffsetx = m_lastfbo_offsetx;
5005 m_runoffsety = m_lastfbo_offsety;
5006 m_runswidth = m_lastfbo_swidth;
5007 m_runsheight = m_lastfbo_sheight;
5010 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5011 m_zoomFinal =
false;
5017void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5021 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5024 if (m_binPinch)
return;
5025 if (m_bpinchGuard)
return;
5027 int x =
event.GetOffset().x;
5028 int y =
event.GetOffset().y;
5030 int lx =
event.GetLastOffset().x;
5031 int ly =
event.GetLastOffset().y;
5036 switch (event.GetState()) {
5037 case GestureStarted:
5038 if (m_binPan)
break;
5042 m_binGesture =
true;
5046 case GestureUpdated:
5051 m_pParentCanvas->FreezePiano();
5053 m_pParentCanvas->ThawPiano();
5064 case GestureFinished:
5067 m_pParentCanvas->UpdateCanvasControlBar();
5070 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5074 case GestureCanceled:
5076 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5083 m_bgestureGuard =
true;
5084 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5085 m_bforcefull =
false;
5090float zoom_inc = 1.0;
5092void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5093 float zoom_gain = 1.0;
5094 float zout_gain = 1.0;
5097 float total_zoom_val;
5099 float max_zoom_scale = 1000.;
5100 float min_zoom_scale = 2e8;
5102 if (event.GetScaleFactor() > 1)
5103 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5105 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5107 if (event.GetTotalScaleFactor() > 1)
5108 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5111 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5113 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5116 float max_zoom_scale = 1000.;
5117 if( cc1->GetVP().b_quilt) {
5118 int ref_index = cc1->GetQuiltRefChartdbIndex();
5125 float min_zoom_scale = 2e8;
5129 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5131 double projected_scale =
5132 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5134 switch (event.GetState()) {
5135 case GestureStarted:
5136 m_first_zout =
false;
5140 m_binGesture =
true;
5142 m_pinchStart =
event.GetCenterPoint();
5143 m_lpinchPoint = m_pinchStart;
5146 event.GetCenterPoint().y, m_pinchlat,
5151 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5152 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5155 if (IsShown()) SetCurrent(*m_pcontext);
5161 case GestureUpdated:
5163 if (projected_scale < min_zoom_scale) {
5164 wxPoint pinchPoint =
event.GetCenterPoint();
5166 float dx = pinchPoint.x - m_lpinchPoint.x;
5167 float dy = pinchPoint.y - m_lpinchPoint.y;
5169 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5170 -dx / total_zoom_val, dy / total_zoom_val);
5172 m_lpinchPoint = pinchPoint;
5176 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5177 wxPoint pinchPoint =
event.GetCenterPoint();
5179 float dx = pinchPoint.x - m_lpinchPoint.x;
5180 float dy = pinchPoint.y - m_lpinchPoint.y;
5182 if ((projected_scale > max_zoom_scale) &&
5183 (projected_scale < min_zoom_scale))
5184 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5185 -dx / total_zoom_val, dy / total_zoom_val);
5187 m_lpinchPoint = pinchPoint;
5190 m_first_zout =
true;
5191 zoom_inc *= zoom_val;
5192 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5193 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5197 wxPoint pinchPoint =
event.GetCenterPoint();
5198 float dx = pinchPoint.x - m_lpinchPoint.x;
5199 float dy = pinchPoint.y - m_lpinchPoint.y;
5201 m_lpinchPoint = pinchPoint;
5212 case GestureFinished: {
5216 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5217 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5221 float tzoom = total_zoom_val;
5223 if (projected_scale >= min_zoom_scale)
5224 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5226 if (projected_scale < max_zoom_scale)
5227 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5229 dx = (cc_x - m_cc_x) * tzoom;
5230 dy = -(cc_y - m_cc_y) * tzoom;
5232 if (zoomTimer.IsRunning()) {
5235 m_zoomFinalZoom = tzoom;
5241 double final_projected_scale =
5245 if (final_projected_scale < min_zoom_scale) {
5249 m_pParentCanvas->m_pQuilt->Invalidate();
5250 m_bforcefull =
true;
5257 m_pParentCanvas->m_pQuilt->Invalidate();
5258 m_bforcefull =
true;
5270 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5274 case GestureCanceled:
5276 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5283 m_bgestureGuard =
true;
5285 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5288void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5298 m_bgestureGuard =
false;
5299 m_bpinchGuard =
false;
5300 m_binGesture =
false;
5301 m_bforcefull =
false;
5304void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5308 m_binGesture =
false;
5309 m_bforcefull =
false;
5313#ifdef HAVE_WX_GESTURE_EVENTS
5315void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5318 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5321 if (m_binPinch)
return;
5322 if (m_bpinchGuard)
return;
5324 int dx =
event.GetDelta().x;
5325 int dy =
event.GetDelta().y;
5327 if (event.IsGestureStart()) {
5328 if (m_binPan)
return;
5332 m_binGesture =
true;
5336 else if (event.IsGestureEnd()) {
5338 m_pParentCanvas->UpdateCanvasControlBar();
5340 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5348 m_pParentCanvas->FreezePiano();
5350 m_pParentCanvas->ThawPiano();
5361 m_bgestureGuard =
true;
5362 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5363 m_bforcefull =
false;
5367void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5369 float zoom_gain = 1.0;
5370 float zout_gain = 1.0;
5372 float last_zoom_val = m_step_zoom_val;
5374 float max_zoom_scale = 1000.;
5375 float min_zoom_scale = 2e8;
5377 if (event.GetZoomFactor() > 1)
5378 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5380 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5382 float inc_zoom_val =
5383 m_total_zoom_val / last_zoom_val;
5387 if (event.IsGestureStart()) {
5388 m_glstopwatch.Start();
5389 printf(
"\nStart--------------\n");
5391 m_pParentCanvas->m_inPinch =
true;
5394 m_binGesture =
true;
5395 m_pinchStart =
event.GetPosition();
5396 m_lpinchPoint = m_pinchStart;
5397 m_total_zoom_val = 1.0;
5398 m_final_zoom_val = 1.0;
5399 m_step_zoom_val = 1.0;
5403 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5407 if (event.IsGestureEnd()) {
5409 if (!m_binGesture)
return;
5410 printf(
"EndZoom--------------\n");
5417 m_final_zoom_val = 1.0;
5418 m_total_zoom_val = 1.0;
5419 m_step_zoom_val = 1.0;
5421 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5428 float zoom_step = 5;
5429 float zoom_trigger = 0.05;
5430 if (projected_scale > 1e5)
5432 else if (projected_scale < 3e4)
5435 if (inc_zoom_val != 1.0) {
5436 if (inc_zoom_val > 1 + zoom_step) {
5437 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5438 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5440 if (IsShown()) SetCurrent(*m_pcontext);
5443 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5444 m_step_zoom_val = m_total_zoom_val;
5445 printf(
" Zoom: %6g\n", inc_zoom_val);
5450 bool b_allow_ztp =
true;
5451 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5452 b_allow_ztp =
false;
5454 if (g_bEnableZoomToCursor && b_allow_ztp) {
5460 int dx = r.x -
event.GetPosition().x;
5461 int dy = r.y -
event.GetPosition().y;
5465 if (IsShown()) SetCurrent(*m_pcontext);
5474 float zoom_gain = 1.0;
5475 float zout_gain = 1.0;
5477 float last_zoom_val = m_total_zoom_val;
5479 float max_zoom_scale = 1000.;
5480 float min_zoom_scale = 2e8;
5482 if (event.GetZoomFactor() > 1)
5483 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5485 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5487 float inc_zoom_val =
5488 m_total_zoom_val / last_zoom_val;
5490 double projected_scale =
5491 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5493 if (event.IsGestureStart()) {
5495 m_first_zout =
false;
5499 m_binGesture =
true;
5500 m_pinchStart =
event.GetPosition();
5501 m_lpinchPoint = m_pinchStart;
5502 m_total_zoom_val = 1.0;
5503 m_final_zoom_val = 1.0;
5506 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5510 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5511 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5514 if (IsShown()) SetCurrent(*m_pcontext);
5517 ViewPort vpr = m_pParentCanvas->VPoint;
5519 GetTouchBackingBitmap(vpr);
5524 if (event.IsGestureEnd()) {
5530 if (!m_binGesture)
return;
5532 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5533 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5537 float tzoom = m_final_zoom_val;
5539 dx = (cc_x - m_cc_x) * tzoom;
5540 dy = -(cc_y - m_cc_y) * tzoom;
5542 if (zoomTimer.IsRunning()) {
5545 m_zoomFinalZoom = tzoom;
5551 double final_projected_scale =
5555 if (final_projected_scale < min_zoom_scale) {
5559 m_pParentCanvas->m_pQuilt->Invalidate();
5560 m_bforcefull =
true;
5567 m_pParentCanvas->m_pQuilt->Invalidate();
5568 m_bforcefull =
true;
5573 m_final_zoom_val = 1.0;
5574 m_total_zoom_val = 1.0;
5575 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5580 if (projected_scale < min_zoom_scale) {
5581 wxPoint pinchPoint =
event.GetPosition();
5583 float dx = pinchPoint.x - m_lpinchPoint.x;
5584 float dy = pinchPoint.y - m_lpinchPoint.y;
5586 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5587 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5589 m_lpinchPoint = pinchPoint;
5590 m_final_zoom_val *= inc_zoom_val;
5594 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5595 wxPoint pinchPoint =
event.GetPosition();
5597 float dx = pinchPoint.x - m_lpinchPoint.x;
5598 float dy = pinchPoint.y - m_lpinchPoint.y;
5600 if ((projected_scale > max_zoom_scale) &&
5601 (projected_scale < min_zoom_scale))
5602 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5603 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5605 m_lpinchPoint = pinchPoint;
5606 m_final_zoom_val *= inc_zoom_val;
5609 m_first_zout =
true;
5610 m_zoom_inc *= inc_zoom_val;
5611 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5612 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5616 wxPoint pinchPoint =
event.GetPosition();
5617 float dx = pinchPoint.x - m_lpinchPoint.x;
5618 float dy = pinchPoint.y - m_lpinchPoint.y;
5620 m_lpinchPoint = pinchPoint;
5624 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5627 m_bgestureGuard =
true;
5628 m_bpinchGuard =
true;
5631void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5640 m_bgestureGuard =
false;
5641 m_bpinchGuard =
false;
5642 m_binGesture =
false;
5643 m_bforcefull =
false;
5646void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5650 m_binGesture =
false;
5651 m_bforcefull =
false;
5653 m_pParentCanvas->m_inPinch =
false;
5654 printf(
"******Finish\n");
5660void glChartCanvas::configureShaders(
ViewPort &vp) {
5661#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5667 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5669 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5670 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5691 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5693 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5694 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5706 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5708 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5709 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5712 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5714 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5715 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5723 shader = pAALine_shader_program[GetCanvasIndex()];
5725 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5728 shader = pring_shader_program[GetCanvasIndex()];
5730 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5731 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5735 if (texture_2DA_shader_program) {
5736 glUseProgram(texture_2DA_shader_program);
5737 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5738 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5739 (
const GLfloat *)pvp->vp_matrix_transform);
5741 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5742 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5750void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5753#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5754 int nl = nVertex / 4;
5756 float *luv = uvCoords;
5759 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5767 glEnableClientState(GL_VERTEX_ARRAY);
5768 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5770 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5771 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5772 glDrawArrays(GL_QUADS, 0, 4);
5779void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5780 float *uvCoords,
ViewPort *vp,
float dx,
5781 float dy,
float angle_rad) {
5782#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5784 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5785 if (!shader)
return;
5790 shader->SetUniform1i(
"uTex", 0);
5795 mat4x4_rotate_Z(Q, I, angle_rad);
5801 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5806 shader->SetAttributePointerf(
"aPos", co1);
5807 shader->SetAttributePointerf(
"aUV", tco1);
5814 GLushort indices1[] = {0,1,3,2};
5815 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5827 tco1[0] = uvCoords[0];
5828 tco1[1] = uvCoords[1];
5829 tco1[2] = uvCoords[2];
5830 tco1[3] = uvCoords[3];
5831 tco1[4] = uvCoords[6];
5832 tco1[5] = uvCoords[7];
5833 tco1[6] = uvCoords[4];
5834 tco1[7] = uvCoords[5];
5839 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5851void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5852#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5854 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5857 shader->SetUniformMatrix4fv(
5858 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5861 colorv[0] = color.Red() / float(256);
5862 colorv[1] = color.Green() / float(256);
5863 colorv[2] = color.Blue() / float(256);
5865 shader->SetUniform4fv(
"color", colorv);
5868 pf[0] = r.x + r.width;
5872 pf[4] = r.x + r.width;
5873 pf[5] = r.y + r.height;
5875 pf[7] = r.y + r.height;
5876 shader->SetAttributePointerf(
"position", pf);
5878 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5886void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5887#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5889 ViewPort VPoint = m_pParentCanvas->VPoint;
5893 GetClientSize(&w, &h);
5894 int sx = GetSize().x;
5895 int sy = GetSize().y;
5899 glViewport(0, 0, (GLint)w, (GLint)h);
5901 if (s_b_useStencil) {
5902 glEnable(GL_STENCIL_TEST);
5903 glStencilMask(0xff);
5904 glClear(GL_STENCIL_BUFFER_BIT);
5905 glDisable(GL_STENCIL_TEST);
5909 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5914 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5915 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5916 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5919 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5921 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5922 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5930 if (bRenderCharts) RenderCharts(gldc, screen_region);
5932 if (bRenderOverlays) {
5933 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5934 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5940 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5943 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5944 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5945 DrawFloatingOverlayObjects(m_gldc);
5949 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5954wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5956 wxMemoryDC tdc(tbm);
5957 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5965 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5966 dc.SetPen(*wxTRANSPARENT_PEN);
5969 tdc.SelectObject(wxNullBitmap);
5970 m_touch_backing_bitmap = tbm;
5971 CreateBackingTexture();
5973 return m_touch_backing_bitmap;
5976void glChartCanvas::CreateBackingTexture() {
5977 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5978 unsigned char *imgdata = image.GetData();
5979 unsigned char *imgalpha = image.GetAlpha();
5980 m_tex_w = image.GetWidth();
5981 m_tex_h = image.GetHeight();
5982 m_image_width = m_tex_w;
5983 m_image_height = m_tex_h;
5985 GLuint format = GL_RGBA;
5986 GLuint internalformat = g_texture_rectangle_format;
5988 internalformat = GL_RGBA;
5993 unsigned char *teximage =
5994 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
5996 for (
int i = 0; i < m_image_height; i++) {
5997 for (
int j = 0; j < m_image_width; j++) {
5998 int s = (i * 3 * m_image_width) + (j * 3);
5999 int d = (i * stride * m_tex_w) + (j * stride);
6001 teximage[d + 0] = imgdata[s + 0];
6002 teximage[d + 1] = imgdata[s + 1];
6003 teximage[d + 2] = imgdata[s + 2];
6004 teximage[d + 3] = 255;
6008 glGenTextures(1, &m_TouchBackingTexture);
6009 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6011 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6012 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6013 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6015 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6017 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6018 GL_UNSIGNED_BYTE, teximage);
6021 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.