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"
97#include "s57_ocpn_utils.h"
107#ifdef USE_ANDROID_GLES2
108#include <GLES2/gl2.h>
114#include "androidUTIL.h"
115#elif defined(__WXQT__) || defined(__WXGTK__)
119#ifndef GL_ETC1_RGB8_OES
120#define GL_ETC1_RGB8_OES 0x8D64
123#ifndef GL_DEPTH_STENCIL_ATTACHMENT
124#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
128#define printf printf2
129int __cdecl printf2(
const char *format, ...);
132#if defined(__ANDROID__)
133#include "androidUTIL.h"
134#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
141extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
142 float near,
float far);
143#define glOrtho(a, b, c, d, e, f) \
145 glOrthof(a, b, c, d, e, f);
149#ifdef USE_ANDROID_GLES2
150#include <GLES2/gl2.h>
153#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
159#if defined(__UNIX__) && !defined(__WXOSX__)
164 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
168 clock_gettime(CLOCK_REALTIME, &tp_end);
169 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
170 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
182static wxColor s_regionColor;
183static float g_GLMinCartographicLineWidth;
189#define APIENTRYP APIENTRY *
195#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
196#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
202PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
203PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
204PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
205PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
206PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
207PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
208PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
209PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
210PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
211PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
213PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
214PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
217PFNGLGENBUFFERSPROC s_glGenBuffers;
218PFNGLBINDBUFFERPROC s_glBindBuffer;
219PFNGLBUFFERDATAPROC s_glBufferData;
220PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
222#ifndef USE_ANDROID_GLES2
227typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
229PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
232static int panx, pany;
236#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
237std::vector<GLfloat> s_tess_vertex_work;
238static GLenum s_tess_mode;
242bool glChartCanvas::s_b_useScissorTest;
243bool glChartCanvas::s_b_useStencil;
244bool glChartCanvas::s_b_useStencilAP;
245bool glChartCanvas::s_b_useFBO;
252 while ( upd.HaveRects() )
254 wxRect rect = upd.GetRect();
255 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
262GLboolean QueryExtension(
const char *extName) {
273 extNameLen = strlen(extName);
275 p = (
char *)glGetString(GL_EXTENSIONS);
283 int n = strcspn(p,
" ");
284 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
292int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
293 16, WX_GL_STENCIL_SIZE, 8,
296glTestCanvas::glTestCanvas(wxWindow *parent)
297 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
301int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
302 16, WX_GL_STENCIL_SIZE, 8,
305EVT_PAINT(glChartCanvas::OnPaint)
306EVT_ACTIVATE(glChartCanvas::OnActivate)
307EVT_SIZE(glChartCanvas::OnSize)
308EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
312 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
313 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
316 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
321std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
323 {wxPENSTYLE_DOT, {1, 1}},
324 {wxPENSTYLE_LONG_DASH, {5, 5}},
325 {wxPENSTYLE_SHORT_DASH, {1, 5}},
326 {wxPENSTYLE_DOT_DASH, {5, 1}},
329void glChartCanvas::Init() {
334 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
336 m_cache_current_ch = NULL;
338 m_b_paint_enable =
true;
339 m_in_glpaint =
false;
341 m_cache_tex[0] = m_cache_tex[1] = 0;
344 m_b_BuiltFBO =
false;
345 m_b_DisableFBO =
false;
354 m_bpinchGuard =
false;
355 m_binGesture =
false;
356 m_first_zout =
false;
360 m_last_render_time = -1;
367 m_gldc.SetGLCanvas(
this);
370 m_displayScale = 1.0;
371#if defined(__WXOSX__) || defined(__WXGTK3__)
373 m_displayScale = GetContentScaleFactor();
382 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
386 wxEVT_QT_PINCHGESTURE,
387 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
390 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
395 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
397 onGestureFinishTimerEvent,
401 ZOOM_TIMER, wxEVT_TIMER,
402 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
405 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
406 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
407 zoomTimer.SetOwner(
this, ZOOM_TIMER);
409#ifdef USE_ANDROID_GLES2
418#ifdef HAVE_WX_GESTURE_EVENTS
420 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
425 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
427 onGestureFinishTimerEvent,
431 ZOOM_TIMER, wxEVT_TIMER,
432 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
435 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
436 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
437 zoomTimer.SetOwner(
this, ZOOM_TIMER);
442 m_bgestureGuard =
false;
443 m_total_zoom_val = 1.0;
444 m_step_zoom_val = 1.0;
447#ifdef HAVE_WX_GESTURE_EVENTS
448 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
449 wxLogError(
"Failed to enable touch events");
458 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
460 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
461 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
463 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
464 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
466 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
467 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
469 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
470 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
476glChartCanvas::~glChartCanvas() {
482int glChartCanvas::GetCanvasIndex() {
return m_pParentCanvas->m_canvasIndex; }
484void glChartCanvas::FlushFBO() {
485 if (m_bsetup) BuildFBO();
488void glChartCanvas::OnActivate(wxActivateEvent &event) {
489 m_pParentCanvas->OnActivate(event);
492void glChartCanvas::OnSize(wxSizeEvent &event) {
495 ViewPort *vp = m_pParentCanvas->GetpVP();
496 vp->SetVPTransformMatrix();
499 if (!m_bsetup)
return;
501 if (!IsShown())
return;
503 SetCurrent(*m_pcontext);
507 SetSize(GetSize().x, GetSize().y);
515 if (m_pcontext && IsShown()) {
516 SetCurrent(*m_pcontext);
519 wxLogDebug(
"BuildFBO 3");
523void glChartCanvas::MouseEvent(wxMouseEvent &event) {
524 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
530 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
532 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
535 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
539 if (m_bgestureGuard) {
540 m_pParentCanvas->r_rband.x = 0;
550 if (event.LeftUp()) {
552 if ((abs(panx) > 2) || (abs(pany) > 2)) {
555 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
562 if (!event.LeftDClick()) {
567 if (m_binPan && event.RightDown()) {
568 qDebug() <<
"Skip right on pan";
571 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
573 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
574 if (!m_bgestureGuard)
584#ifndef GL_MAX_RENDERBUFFER_SIZE
585#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
588#ifndef USE_ANDROID_GLES2
589bool glChartCanvas::buildFBOSize(
int fboSize) {
591 if (IsShown()) SetCurrent(*m_pcontext);
594 glDeleteTextures(2, m_cache_tex);
595 glDeleteFramebuffers(1, &m_fb0);
596 glDeleteRenderbuffers(1, &m_renderbuffer);
597 m_b_BuiltFBO =
false;
600 if (m_b_DisableFBO)
return false;
604 int rb_x = GetSize().x;
605 int rb_y = GetSize().y;
607 while (i < rb_x) i <<= 1;
611 while (i < rb_y) i <<= 1;
614 m_cache_tex_x = wxMax(rb_x, rb_y);
615 m_cache_tex_y = wxMax(rb_x, rb_y);
618 m_cache_tex_x = GetSize().x * m_displayScale;
619 m_cache_tex_y = GetSize().y * m_displayScale;
622 int err = GL_NO_ERROR;
624 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
627 if (err == GL_INVALID_ENUM) {
628 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
632 if (err == GL_NO_ERROR) {
633 if (fboSize > params) {
635 " OpenGL-> Requested Framebuffer size exceeds "
636 "GL_MAX_RENDERBUFFER_SIZE");
641 glGenFramebuffers(1, &m_fb0);
645 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
650 glGenRenderbuffers(1, &m_renderbuffer);
654 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
659 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
663 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
669 glGenTextures(2, m_cache_tex);
670 for (
int i = 0; i < 2; i++) {
671 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
672 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
674 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
676 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
677 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
680 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
682 if (m_b_useFBOStencil) {
684 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
685 m_cache_tex_x, m_cache_tex_y);
687 int err = glGetError();
690 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
694 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
695 GL_RENDERBUFFER_EXT, m_renderbuffer);
699 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
704 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
705 GL_RENDERBUFFER_EXT, m_renderbuffer);
709 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
715 GLenum depth_format = GL_DEPTH_COMPONENT24;
720 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
724 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
726 int err = glGetError();
729 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
735 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
736 GL_RENDERBUFFER_EXT, m_renderbuffer);
741 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
748 glBindTexture(GL_TEXTURE_2D, 0);
749 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
752 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
754 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
755 g_texture_rectangle_format, m_cache_tex[0], 0);
757 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
759 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
761 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
763 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
773#ifdef USE_ANDROID_GLES2
774bool glChartCanvas::buildFBOSize(
int fboSize) {
778 int rb_x = GetSize().x;
779 int rb_y = GetSize().y;
781 while (i < rb_x) i <<= 1;
785 while (i < rb_y) i <<= 1;
788 m_cache_tex_x = wxMax(rb_x, rb_y);
789 m_cache_tex_y = wxMax(rb_x, rb_y);
793 int err = GL_NO_ERROR;
795 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
798 if (err == GL_INVALID_ENUM) {
799 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
803 if (err == GL_NO_ERROR) {
804 if (fboSize > params) {
806 " OpenGL-> Requested Framebuffer size exceeds "
807 "GL_MAX_RENDERBUFFER_SIZE");
812 glGenFramebuffers(1, &m_fb0);
816 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
821 glGenRenderbuffers(1, &m_renderbuffer);
825 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
830 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
834 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
840 glGenTextures(2, m_cache_tex);
841 for (
int i = 0; i < 2; i++) {
842 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
843 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
845 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
847 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
848 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
851 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
854 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
860 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
864 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
865 GL_RENDERBUFFER, m_renderbuffer);
869 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
874 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
875 GL_RENDERBUFFER, m_renderbuffer);
879 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
884 glBindTexture(GL_TEXTURE_2D, 0);
885 glBindFramebuffer(GL_FRAMEBUFFER, 0);
888 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
890 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
891 g_texture_rectangle_format, m_cache_tex[0], 0);
893 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
895 glBindFramebuffer(GL_FRAMEBUFFER, 0);
897 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
899 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
909void glChartCanvas::BuildFBO() {
910 if (g_b_needFinish) glFinish();
914 glDeleteTextures(2, m_cache_tex);
915 glDeleteFramebuffers(1, &m_fb0);
916 glDeleteRenderbuffers(1, &m_renderbuffer);
917 m_b_BuiltFBO =
false;
920 if (m_b_DisableFBO)
return;
923 int gl_width, gl_height;
924 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
925 int initialSize = NextPow2(gl_width * m_displayScale);
930 wxString info = androidGetDeviceInfo();
932 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
935 if (!buildFBOSize(initialSize)) {
936 glDeleteTextures(2, m_cache_tex);
937 glDeleteFramebuffers(1, &m_fb0);
938 glDeleteRenderbuffers(1, &m_renderbuffer);
940 if (!buildFBOSize(1024)) {
941 wxLogMessage(
"BuildFBO C");
943 m_b_DisableFBO =
true;
944 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
945 m_b_BuiltFBO =
false;
954 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
966void glChartCanvas::SetupOpenGL() {
969 if (IsShown()) SetCurrent(*m_pcontext);
971 char *str = (
char *)glGetString(GL_RENDERER);
974 wxLogMessage(
"Failed to initialize OpenGL");
978 char render_string[80];
979 strncpy(render_string, str, 79);
980 m_renderer = wxString(render_string, wxConvUTF8);
983 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
984 msg.Printf(
"OpenGL-> Renderer String: ");
988 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
990 char version_string[80];
991 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
992 msg.Printf(
"OpenGL-> Version reported: ");
993 m_version = wxString(version_string, wxConvUTF8);
997 char GLSL_version_string[80];
998 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1000 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1001 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1002 msg += m_GLSLversion;
1007 GLenum err = glewInit();
1008#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1009 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1014 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1017 wxLogMessage(
"GLEW init success!n");
1022 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1023 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1027#ifndef USE_ANDROID_GLES2
1028 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1030 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1032 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1033 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1040 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1042 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1044 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1047 s_b_useScissorTest =
true;
1049 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1050 s_b_useScissorTest =
false;
1052 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1053 s_b_useScissorTest =
false;
1055 bool bad_stencil_code =
false;
1058 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1059 bad_stencil_code =
true;
1062 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1065 glEnable(GL_STENCIL_TEST);
1066 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1068 glGetIntegerv(GL_STENCIL_BITS, &sb);
1071 glDisable(GL_STENCIL_TEST);
1073 s_b_useStencil =
false;
1074 if (stencil && (sb == 8)) s_b_useStencil =
true;
1076 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1077 g_texture_rectangle_format = GL_TEXTURE_2D;
1078 else if (QueryExtension(
"GL_OES_texture_npot"))
1079 g_texture_rectangle_format = GL_TEXTURE_2D;
1080 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1081 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1082 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1083 g_texture_rectangle_format));
1086 g_texture_rectangle_format = GL_TEXTURE_2D;
1090 g_b_EnableVBO =
true;
1093 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1095 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1099 if (ps52plib) ps52plib->SetGLRendererString(GetRendererString());
1103 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1105 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1108#ifndef USE_ANDROID_GLES2
1110 if (bad_stencil_code) s_b_useStencil =
false;
1124 if (m_displayScale > 1) m_b_DisableFBO =
true;
1133 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1135 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1136 g_texture_rectangle_format, m_cache_tex[0], 0);
1138 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1139 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1141 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1143 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1145 m_b_DisableFBO =
true;
1151 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1155 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1157#ifdef USE_ANDROID_GLES2
1158 s_b_useStencilAP = s_b_useStencil;
1165 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1167 if (m_b_useFBOStencil)
1168 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1170 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1172 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1175 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1177 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1179 if (s_b_useScissorTest && s_b_useStencil)
1180 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1183 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1185 MipMap_ResolveRoutines();
1189 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1190 g_GLMinCartographicLineWidth);
1191 wxLogMessage(lwmsg);
1192 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1193 g_GLMinSymbolLineWidth);
1194 wxLogMessage(lwmsg);
1197 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1199#ifdef USE_ANDROID_GLES2
1200 g_GLOptions.m_bUseAcceleratedPanning =
true;
1206 int tex_dim = g_GLOptions.m_iTextureDimension;
1207 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1216 s_b_useFBO = m_b_BuiltFBO;
1220 ps52plib->SetGLOptions(
1221 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1222 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1223 g_GLMinSymbolLineWidth);
1227 SendJSONConfigMessage();
1230void glChartCanvas::SendJSONConfigMessage() {
1233 v[
"setupComplete"] = m_bsetup;
1234 v[
"useStencil"] = s_b_useStencil;
1235 v[
"useStencilAP"] = s_b_useStencilAP;
1236 v[
"useScissorTest"] = s_b_useScissorTest;
1237 v[
"useFBO"] = s_b_useFBO;
1238 v[
"useVBO"] = g_b_EnableVBO;
1239 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1240 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1241 SendJSONMessageToAllPlugins(msg_id, v);
1244void glChartCanvas::SetupCompression() {
1245 int dim = g_GLOptions.m_iTextureDimension;
1248 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1249 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1250 goto no_compression;
1254 g_uncompressed_tile_size = dim * dim * 4;
1255 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1261 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1264 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1274 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1275 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1278 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1279 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1284 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1285 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1288 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1290 wxLogMessage(
"OpenGL-> No Useable compression format found");
1291 goto no_compression;
1296 g_tile_size = 512 * 512 / 2;
1300 glGenTextures(1, &texture);
1301 glBindTexture(GL_TEXTURE_2D, texture);
1303 GL_UNSIGNED_BYTE, NULL);
1304 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1306 glDeleteTextures(1, &texture);
1310 if (g_tile_size == 0)
goto no_compression;
1312 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1314 g_uncompressed_tile_size / g_tile_size));
1318 g_GLOptions.m_bTextureCompression =
false;
1320 g_tile_size = g_uncompressed_tile_size;
1321 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1324void glChartCanvas::OnPaint(wxPaintEvent &event) {
1326 if (!m_pcontext)
return;
1335 if (IsShown()) SetCurrent(*m_pcontext);
1340 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1348 if (!m_b_paint_enable)
return;
1351 if (m_in_glpaint)
return;
1354 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1377bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1379#ifndef USE_ANDROID_GLES2
1380 return vp.m_projection_type == PROJECTION_MERCATOR ||
1381 vp.m_projection_type == PROJECTION_POLAR ||
1382 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1396#define NORM_FACTOR 4096.0
1397void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1398#ifndef USE_ANDROID_GLES2
1400 wxPoint2DDouble point;
1402 switch (vp.m_projection_type) {
1403 case PROJECTION_MERCATOR:
1404 case PROJECTION_EQUIRECTANGULAR:
1405 case PROJECTION_WEB_MERCATOR:
1408 glTranslated(point.m_x, point.m_y, 0);
1413 case PROJECTION_POLAR:
1417 glTranslated(point.m_x, point.m_y, 0);
1418 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1425 printf(
"ERROR: Unhandled projection\n");
1430 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1438 switch (vp.m_projection_type) {
1439 case PROJECTION_MERCATOR:
1440 case PROJECTION_EQUIRECTANGULAR:
1441 case PROJECTION_WEB_MERCATOR:
1445 case PROJECTION_POLAR:
1450 printf(
"ERROR: Unhandled projection\n");
1459bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1460 return vp.m_projection_type == PROJECTION_MERCATOR ||
1461 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1462 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1466 const LLRegion ®ion) {
1467 if (!CanClipViewport(vp))
return vp;
1470 LLBBox bbox = region.GetBox();
1472 if (!bbox.GetValid())
return vp;
1480 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1481 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1482 bbox.GetMaxLon() + 360);
1483 cvp.SetBBoxDirect(bbox);
1484 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1485 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1486 bbox.GetMaxLon() - 360);
1487 cvp.SetBBoxDirect(bbox);
1489 cvp.SetBBoxDirect(bbox);
1494void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1495 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1501 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1503 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1507 if (!pRouteDraw)
continue;
1510 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1513 if (pRouteDraw->m_bIsBeingEdited)
continue;
1515 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1520 if (vp.GetBBox().GetValid() && pWayPointMan) {
1521 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1522 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1523 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1529void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1534 if (pActiveTrack && pActiveTrack->IsRunning())
1535 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1541 if (!pRouteDraw)
continue;
1544 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1547 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1550 if (pRouteDraw->IsSelected()) drawit++;
1553 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1554 if (!vp_box.IntersectOut(test_box))
1555 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1561 if (vp.GetBBox().GetValid() && pWayPointMan) {
1562 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1563 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1570static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1574 switch (vp.m_projection_type) {
1575 case PROJECTION_TRANSVERSE_MERCATOR:
1576 lat_dist = 4, lon_dist = 1;
1578 case PROJECTION_POLYCONIC:
1579 lat_dist = 2, lon_dist = 1;
1581 case PROJECTION_ORTHOGRAPHIC:
1582 lat_dist = 2, lon_dist = 2;
1584 case PROJECTION_POLAR:
1585 lat_dist = 180, lon_dist = 1;
1587 case PROJECTION_STEREOGRAPHIC:
1588 case PROJECTION_GNOMONIC:
1589 lat_dist = 2, lon_dist = 1;
1591 case PROJECTION_EQUIRECTANGULAR:
1594 lat_dist = 2, lon_dist = 360;
1597 lat_dist = 180, lon_dist = 360;
1601void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1602 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1608 ChartData->GetDBBoundingBox(dbIndex, box);
1609 if (!box.GetValid())
return;
1613 if (box.GetLonRange() == 360)
return;
1615 LLBBox vpbox = vp.GetBBox();
1617 double lon_bias = 0;
1619 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1622 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1623 color = GetGlobalColor(
"YELO1");
1624 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1625 color = GetGlobalColor(
"GREEN2");
1627 color = GetGlobalColor(
"UINFR");
1629#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1630 float plylat, plylon;
1632 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1634 glColor3ub(color.Red(), color.Green(), color.Blue());
1635 glLineWidth(g_GLMinSymbolLineWidth);
1637 float lat_dist, lon_dist;
1638 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1641 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1645 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1647 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1649 bool begin =
false, sml_valid =
false;
1651 float lastplylat = 0.0;
1652 float lastplylon = 0.0;
1654 int modulo = (nPly == 0) ? 1 : nPly;
1655 for (
int i = 0; i < nPly + 1; i++) {
1657 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1659 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1663 if (lastplylon - plylon > 180)
1665 else if (lastplylon - plylon < -180)
1672 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1673 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1674 splits = wxMax(lat_splits, lon_splits) + 1;
1681 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1682 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1685 for (
double c = 0; c < splits; c++) {
1687 if (c == splits - 1)
1688 lat = plylat, lon = plylon;
1690 double d = (double)(c + 1) / splits;
1691 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1697 if (!std::isnan(s.m_x)) {
1700 glBegin(GL_LINE_STRIP);
1702 glVertex2f(s.m_x, s.m_y);
1708 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1709 lastplylat = plylat, lastplylon = plylon;
1714 }
while (++j < nAuxPlyEntries);
1716 glDisable(GL_LINE_SMOOTH);
1720 double nominal_line_width_pix =
1721 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1723 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1724 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1727 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1728 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1732 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1735 float plylat1, plylon1;
1739 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1740 if (0 == nAuxPlyEntries)
1743 std::vector<int> points_vector;
1745 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1746 int nPly = vec.size() / 2;
1748 if (nPly == 0)
return;
1750 for (
int i = 0; i < nPly; i++) {
1751 plylon1 = vec[i * 2];
1752 plylat1 = vec[i * 2 + 1];
1758 points_vector.push_back(pixx1);
1759 points_vector.push_back(pixy1);
1762 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1763 plylon1 += lon_bias;
1769 points_vector.push_back(pixx1);
1770 points_vector.push_back(pixy1);
1772 if (points_vector.size()) {
1773 std::vector<int>::iterator it = points_vector.begin();
1774 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1782 for (
int j = 0; j < nAuxPlyEntries; j++) {
1783 std::vector<int> points_vector;
1785 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1786 int nAuxPly = vec.size() / 2;
1788 if (nAuxPly == 0)
continue;
1790 for (
int i = 0; i < nAuxPly; i++) {
1791 plylon1 = vec[i * 2];
1792 plylat1 = vec[i * 2 + 1];
1798 points_vector.push_back(pixx1);
1799 points_vector.push_back(pixy1);
1806 points_vector.push_back(pixx1);
1807 points_vector.push_back(pixy1);
1809 if (points_vector.size()) {
1810 std::vector<int>::iterator it = points_vector.begin();
1811 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1819extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1820 float &MinorSpacing);
1821extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1822void glChartCanvas::GridDraw() {
1823 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1825 ViewPort &vp = m_pParentCanvas->GetVP();
1827 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1831 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1833 double nlat, elon, slat, wlon;
1835 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1838 wxColour GridColor = GetGlobalColor(
"SNDG1");
1840 if (!m_gridfont.IsBuilt()) {
1842 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1843 wxFont font = *dFont;
1846 int font_size = wxMax(10, dFont->GetPointSize());
1847 font.SetPointSize(font_size);
1848 font.SetWeight(wxFONTWEIGHT_NORMAL);
1851 m_gridfont.Build(font, m_displayScale, dpi_factor);
1853 m_gridfont.SetColor(GridColor);
1858 LLBBox llbbox = vp.GetBBox();
1859 nlat = llbbox.GetMaxLat();
1860 slat = llbbox.GetMinLat();
1861 elon = llbbox.GetMaxLon();
1862 wlon = llbbox.GetMinLon();
1869 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1870 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1871 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1872 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1873 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1874 vp.m_projection_type == PROJECTION_POLAR ||
1875 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1878 if (straight_latitudes)
1881 latmargin = gridlatMajor / 2;
1883 slat = wxMax(slat, -90 + latmargin);
1884 nlat = wxMin(nlat, 90 - latmargin);
1886 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1887 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1891 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1898 float lon_step = elon - wlon;
1899 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1901 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1903 s.x = INVALID_COORD;
1904 s.y = INVALID_COORD;
1905 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1907 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1908 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1916 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1917 lat += gridlatMinor) {
1920 gldc.DrawLine(0, r.y, 10, r.y,
true);
1921 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1926 float lat_step = nlat - slat;
1927 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1929 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1931 s.x = INVALID_COORD;
1932 s.y = INVALID_COORD;
1933 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1935 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1936 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1944 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1945 lon += gridlonMinor) {
1948 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1949 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1955 glEnable(GL_TEXTURE_2D);
1957 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1958 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1961 CalcGridText(lat, gridlatMajor,
true);
1963 m_gridfont.GetTextExtent(st, 0, &iy);
1965 if (straight_latitudes) {
1970 float x = 0, y = -1;
1971 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1972 if (y < 0 || y > h) {
1974 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1977 m_gridfont.RenderString(st, x, y);
1981 double y1, y2, lat1, lon1, lat2, lon2;
1990 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
1993 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
1995 if (fabs(y - y1) < fabs(y - y2))
2001 error = fabs(r.m_x);
2002 if (--maxiters == 0)
break;
2003 }
while (error > 1 && error < lasterror);
2005 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2011 m_gridfont.RenderString(st, r.m_x, r.m_y);
2015 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2016 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2025 else if (xlon <= -180.0)
2028 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2030 m_gridfont.GetTextExtent(st, &ix, 0);
2032 if (straight_longitudes) {
2033 float x = -1, y = 0;
2034 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2035 if (x < 0 || x > w) {
2037 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2040 m_gridfont.RenderString(st, x, y);
2044 double x1, x2, lat1, lon1, lat2, lon2;
2052 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2055 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2057 if (fabs(x - x1) < fabs(x - x2))
2063 error = fabs(r.m_y);
2064 }
while (error > 1 && error < lasterror);
2066 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2071 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2073 m_gridfont.RenderString(st, r.m_x, r.m_y);
2077 glDisable(GL_TEXTURE_2D);
2078 glDisable(GL_BLEND);
2083 if (!emboss)
return;
2085 int w = emboss->width, h = emboss->height;
2087 glEnable(GL_TEXTURE_2D);
2090 if (!emboss->gltexind) {
2092 emboss->glwidth = NextPow2(emboss->width);
2093 emboss->glheight = NextPow2(emboss->height);
2096 int size = emboss->glwidth * emboss->glheight;
2097 char *data =
new char[2 * size];
2098 for (
int i = 0; i < h; i++) {
2099 for (
int j = 0; j < emboss->glwidth; j++) {
2101 data[2 * ((i * emboss->glwidth) + j)] =
2102 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2103 data[2 * ((i * emboss->glwidth) + j) + 1] =
2104 (char)abs((emboss->pmap[(i * w) + j]));
2109 glGenTextures(1, &emboss->gltexind);
2110 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2111 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2112 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2120 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2124 int x = emboss->x, y = emboss->y;
2126 float wp = (float)w / emboss->glwidth;
2127 float hp = (float)h / emboss->glheight;
2153 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2155 glDisable(GL_BLEND);
2156 glDisable(GL_TEXTURE_2D);
2159void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2160 if (!m_pParentCanvas->GetVP().IsValid())
return;
2161 wxPoint GPSOffsetPixels(0, 0);
2162 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2165 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2166 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2170 double shift_dx = 0;
2171 double shift_dy = 0;
2172 bool dynamic = m_pParentCanvas->m_animationActive ||
2173 m_pParentCanvas->m_MouseDragging ||
2174 m_pParentCanvas->m_chart_drag_inertia_active;
2175 if (m_pParentCanvas->m_bFollow && !dynamic) {
2176 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2177 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2178 if (m_pParentCanvas->m_bLookAhead) {
2184 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2185 angle += m_pParentCanvas->GetVPRotation();
2186 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2188 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2189 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2191 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2196 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2197 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2204 lShipMidPoint = lGPSPoint;
2208 float icon_hdt = pCog;
2209 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2212 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2216 double osd_head_lat, osd_head_lon;
2217 wxPoint2DDouble osd_head_point;
2219 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2223 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2225 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2226 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2227 icon_rad += (float)PI;
2231 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2235 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2241 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2242 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2243 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2248 float scale_factor = 1.0;
2253 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2254 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2255 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2257 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2259 float nominal_ownship_size_pixels =
2261 nominal_ownship_size_mm);
2263 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2265 wxPen ppSmallScaleShip;
2266 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2268 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2271 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2272 dc.SetPen(ppSmallScaleShip);
2274 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2277 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2278 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2279 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2280 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2283 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2284 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2287 int draw_color = SHIP_INVALID;
2288 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2289 draw_color = SHIP_NORMAL;
2290 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2291 draw_color = SHIP_LOWACCURACY;
2299 ownship_color = draw_color;
2301 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2303 glGenTextures(1, &ownship_tex);
2304 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2307 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2310 if (m_pParentCanvas->m_pos_image_user) {
2311 switch (draw_color) {
2313 image = *m_pParentCanvas->m_pos_image_user_grey;
2316 image = *m_pParentCanvas->m_pos_image_user;
2318 case SHIP_LOWACCURACY:
2319 image = *m_pParentCanvas->m_pos_image_user_yellow;
2323 switch (draw_color) {
2325 image = *m_pParentCanvas->m_pos_image_grey;
2328 image = *m_pParentCanvas->m_pos_image_red;
2330 case SHIP_LOWACCURACY:
2331 image = *m_pParentCanvas->m_pos_image_yellow;
2336 int w = image.GetWidth(), h = image.GetHeight();
2337 int glw = NextPow2(w), glh = NextPow2(h);
2338 ownship_size = wxSize(w, h);
2339 ownship_tex_size = wxSize(glw, glh);
2341 unsigned char *d = image.GetData();
2342 unsigned char *a = image.GetAlpha();
2343 unsigned char *e =
new unsigned char[4 * w * h];
2346 for (
int p = 0; p < w * h; p++) {
2347 e[4 * p + 0] = d[3 * p + 0];
2348 e[4 * p + 1] = d[3 * p + 1];
2349 e[4 * p + 2] = d[3 * p + 2];
2350 e[4 * p + 3] = a[p];
2353 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2354 GL_UNSIGNED_BYTE, 0);
2356 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2362#ifndef USE_ANDROID_GLES2
2363 if (m_pParentCanvas->m_pos_image_user)
2364 glColor4ub(255, 255, 255, 255);
2365 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2366 glColor4ub(255, 0, 0, 255);
2367 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2368 glColor4ub(255, 255, 0, 255);
2370 glColor4ub(128, 128, 128, 255);
2372 float scale_factor_y = 1.0;
2373 float scale_factor_x = 1.0;
2375 int ownShipWidth = 22;
2376 int ownShipLength = 84;
2377 lShipMidPoint = lGPSPoint;
2380 if (g_OwnShipIconType != 0)
2381 m_pParentCanvas->ComputeShipScaleFactor(
2382 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2383 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2388 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2389 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2390 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2394 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2395 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2399 float gps_circle_radius = 3.0;
2401 if (g_OwnShipIconType == 0) {
2403 glEnable(GL_TEXTURE_2D);
2404 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2413 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2414 if (m_pParentCanvas->m_pos_image_user)
2415 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2417 float nominal_ownship_size_mm =
2418 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2420 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2421 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2423 float nominal_ownship_size_pixels =
2424 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2426 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2427 nominal_ownship_size_pixels = wxMax(
2428 20.0, nominal_ownship_size_pixels);
2431 float h = nominal_ownship_size_pixels * scale_factor_y;
2432 float w = nominal_ownship_size_pixels * scale_factor_x *
2433 ownship_size.x / ownship_size.y;
2434 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2435 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2441 gps_circle_radius = w / 5;
2443 float uv[8], coords[8];
2462 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2463 lShipMidPoint.m_x, lShipMidPoint.m_y,
2465 glDisable(GL_TEXTURE_2D);
2466 }
else if (g_OwnShipIconType == 1) {
2468 glEnable(GL_TEXTURE_2D);
2469 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2471 float nominal_ownship_size_pixels_y = 84;
2472 float nominal_ownship_size_pixels_x = 22;
2474 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2475 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2477 float u = (float)ownship_size.x / ownship_tex_size.x,
2478 v = (
float)ownship_size.y / ownship_tex_size.y;
2481 gps_circle_radius = w / 5;
2483 float uv[8], coords[8];
2502 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2503 lShipMidPoint.m_x, lShipMidPoint.m_y,
2506 glDisable(GL_TEXTURE_2D);
2507 }
else if (g_OwnShipIconType == 2) {
2515 wxPoint shipPoints[6];
2517 wxColour colour = m_pParentCanvas->ShipColor();
2518 wxPen ppPen(*wxBLACK, 1);
2519 wxBrush ppBrush(colour);
2521 dc.SetBrush(ppBrush);
2523 shipPoints[0].x = 0 * scale_factor_x;
2524 shipPoints[0].y = -28 * scale_factor_y;
2525 shipPoints[1].x = 11 * scale_factor_x;
2526 shipPoints[1].y = -28 * scale_factor_y;
2527 shipPoints[2].x = 11 * scale_factor_x;
2528 shipPoints[2].y = 42 * scale_factor_y;
2529 shipPoints[3].x = 0 * scale_factor_x;
2530 shipPoints[3].y = 42 * scale_factor_y;
2531 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2534 shipPoints[0].x = 0 * scale_factor_x;
2535 shipPoints[0].y = -42 * scale_factor_y;
2536 shipPoints[1].x = 5 * scale_factor_x;
2537 shipPoints[1].y = -42 * scale_factor_y;
2538 shipPoints[2].x = 11 * scale_factor_x;
2539 shipPoints[2].y = -28 * scale_factor_y;
2540 shipPoints[3].x = 0 * scale_factor_x;
2541 shipPoints[3].y = -28 * scale_factor_y;
2542 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2545 shipPoints[0].x = 0 * scale_factor_x;
2546 shipPoints[0].y = -28 * scale_factor_y;
2547 shipPoints[1].x = -11 * scale_factor_x;
2548 shipPoints[1].y = -28 * scale_factor_y;
2549 shipPoints[2].x = -11 * scale_factor_x;
2550 shipPoints[2].y = 42 * scale_factor_y;
2551 shipPoints[3].x = 0 * scale_factor_x;
2552 shipPoints[3].y = 42 * scale_factor_y;
2553 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2556 shipPoints[0].x = 0 * scale_factor_x;
2557 shipPoints[0].y = -42 * scale_factor_y;
2558 shipPoints[1].x = -5 * scale_factor_x;
2559 shipPoints[1].y = -42 * scale_factor_y;
2560 shipPoints[2].x = -11 * scale_factor_x;
2561 shipPoints[2].y = -28 * scale_factor_y;
2562 shipPoints[3].x = 0 * scale_factor_x;
2563 shipPoints[3].y = -28 * scale_factor_y;
2564 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2568 double p1x = -11 * scale_factor_x;
2569 double p2x = 11 * scale_factor_x;
2573 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2575 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2577 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2579 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2580 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2581 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2585 p1y = -42 * scale_factor_y;
2586 p2y = 42 * scale_factor_y;
2587 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2588 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2589 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2590 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2591 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2592 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2595 img_height = ownShipLength * scale_factor_y;
2598 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2600 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2602 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2604 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2608 glDisable(GL_LINE_SMOOTH);
2609 glDisable(GL_POLYGON_SMOOTH);
2610 glDisable(GL_BLEND);
2613 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2617void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2618 ViewPort &vp = m_pParentCanvas->GetVP();
2641 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2643 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2644 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2646 m_pParentCanvas->AlertDraw(dc);
2648 m_pParentCanvas->RenderVisibleSectorLights(dc);
2650 m_pParentCanvas->RenderRouteLegs(dc);
2651 m_pParentCanvas->RenderShipToActive(dc,
true);
2652 m_pParentCanvas->ScaleBarDraw(dc);
2653 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2654 m_pParentCanvas->extendedSectorLegs);
2661void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2662 if (m_pParentCanvas->GetPiano()) {
2663 int canvas_height = GetClientSize().y;
2664 canvas_height *= m_displayScale;
2666 m_pParentCanvas->GetPiano()->DrawGL(
2667 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2671void glChartCanvas::DrawQuiting() {
2672#ifndef USE_ANDROID_GLES2
2673 GLubyte pattern[8][8];
2674 for (
int y = 0; y < 8; y++)
2675 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2678 glEnable(GL_TEXTURE_2D);
2679 glBindTexture(GL_TEXTURE_2D, 0);
2681 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2682 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2685 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2689 float x = GetSize().x, y = GetSize().y;
2690 float u = x / 8, v = y / 8;
2703 glDisable(GL_TEXTURE_2D);
2704 glDisable(GL_BLEND);
2708void glChartCanvas::DrawCloseMessage(wxString msg) {
2709#ifndef USE_ANDROID_GLES2
2713 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2717 texfont.Build(*pfont, 1, 1);
2719 texfont.GetTextExtent(msg, &w, &h);
2721 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2722 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2724 glColor3ub(243, 229, 47);
2728 glVertex2i(xp + w, yp);
2729 glVertex2i(xp + w, yp + h);
2730 glVertex2i(xp, yp + h);
2735 glColor3ub(0, 0, 0);
2736 glEnable(GL_TEXTURE_2D);
2737 texfont.RenderString(msg, xp, yp);
2738 glDisable(GL_TEXTURE_2D);
2739 glDisable(GL_BLEND);
2746static std::list<double *> combine_work_data;
2747static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2748 GLfloat weight[4], GLdouble **dataOut) {
2749 double *vertex =
new double[3];
2750 combine_work_data.push_back(vertex);
2751 memcpy(vertex, coords, 3 * (
sizeof *coords));
2755#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2756void vertexCallbackD_GLSL(GLvoid *vertex) {
2757 GLdouble *pointer = (GLdouble *)vertex;
2758 s_tess_vertex_work.push_back(pointer[0]);
2759 s_tess_vertex_work.push_back(pointer[1]);
2762void beginCallbackD_GLSL(GLenum mode) {
2764 s_tess_vertex_work.clear();
2767void endCallbackD_GLSL() {
2768 if (!s_tess_vertex_work.empty() && (s_tess_vertex_work.size() % 2 == 0)) {
2772 shader->SetUniformMatrix4fv(
"MVMatrix",
2773 (GLfloat *)s_tessVP.vp_matrix_transform);
2775 mat4x4 identityMatrix;
2776 mat4x4_identity(identityMatrix);
2777 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2781 colorv[0] = s_regionColor.Red() / float(256);
2782 colorv[1] = s_regionColor.Green() / float(256);
2783 colorv[2] = s_regionColor.Blue() / float(256);
2784 colorv[3] = s_regionColor.Alpha() / float(256);
2785 shader->SetUniform4fv(
"color", colorv);
2786 shader->SetAttributePointerf(
"position", s_tess_vertex_work.data());
2788 glDrawArrays(s_tess_mode, 0, s_tess_vertex_work.size() / 2);
2793 "::endCallbackD_GLSL() called with wrong tess vertex vector length "
2795 s_tess_vertex_work.size());
2798void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2800void beginCallbackD(GLenum mode) { glBegin(mode); }
2802void endCallbackD() { glEnd(); }
2806void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2807 float lat_dist, lon_dist;
2808 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2810 GLUtesselator *tobj = gluNewTess();
2811 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2813#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2814 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2815 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2816 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2817 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2821 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2822 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2823 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2824 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2827 gluTessNormal(tobj, 0, 0, 1);
2829 gluTessBeginPolygon(tobj, NULL);
2830 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2831 gluTessBeginContour(tobj);
2832 contour_pt l = *i->rbegin();
2834 bool sml_valid =
false;
2835 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2836 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2837 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2838 int splits = wxMax(lat_splits, lon_splits) + 1;
2844 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2845 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2848 for (
int i = 0; i < splits; i++) {
2850 if (i == splits - 1)
2851 lat = j->y, lon = j->x;
2853 double d = (double)(i + 1) / splits;
2854 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2858 if (std::isnan(q.m_x))
continue;
2860 double *p =
new double[6];
2865 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2870 gluTessVertex(tobj, p, p);
2871 combine_work_data.push_back(p);
2875 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2877 gluTessEndContour(tobj);
2879 gluTessEndPolygon(tobj);
2881 gluDeleteTess(tobj);
2883 for (std::list<double *>::iterator i = combine_work_data.begin();
2884 i != combine_work_data.end(); i++)
2886 combine_work_data.clear();
2891void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2892 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2894 if (s_b_useStencil) {
2896 glEnable(GL_STENCIL_TEST);
2898 glClear(GL_STENCIL_BUFFER_BIT);
2902 glStencilFunc(GL_ALWAYS, 1, 1);
2903 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2906#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2910 glEnable(GL_DEPTH_TEST);
2911 glDepthFunc(GL_ALWAYS);
2912 glDepthMask(GL_TRUE);
2914 glClear(GL_DEPTH_BUFFER_BIT);
2927 glTranslatef(0, 0, .5);
2931 s_regionColor = wxColor(0, 0, 0, 255);
2932 DrawRegion(vp, region);
2934 if (s_b_useStencil) {
2937 glStencilFunc(GL_EQUAL, 1, 1);
2938 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2941#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2943 glDepthFunc(GL_GREATER);
2944 glDepthMask(GL_FALSE);
2945 glTranslatef(0, 0, -.5);
2948 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2951void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2955 if (s_b_useStencil && s_b_useScissorTest) {
2957 if (rect != vp_rect) {
2958 glEnable(GL_SCISSOR_TEST);
2959 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2962#ifndef USE_ANDROID_GLES2
2968void glChartCanvas::DisableClipRegion() {
2969 glDisable(GL_SCISSOR_TEST);
2970 glDisable(GL_STENCIL_TEST);
2971 glDisable(GL_DEPTH_TEST);
2974void glChartCanvas::Invalidate() {
2976 m_cache_vp.Invalidate();
2982 if (!pBSBChart)
return;
2988 wxString key = chart->GetHashKey();
2992 ChartPathHashTexfactType::iterator ittf = hash.find(key);
2995 if (ittf == hash.end()) {
2997 hash[key]->SetHashKey(key);
3000 pTexFact = hash[key];
3001 pTexFact->SetLRUTime(++m_LRUtime);
3006 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3007 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3014 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3015 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3016 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3017 base_level = log(scalefactor) / log(2.0);
3026 glEnable(GL_TEXTURE_2D);
3027#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3028 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3030 glEnableClientState(GL_VERTEX_ARRAY);
3031 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3036 pTexFact->GetCenter(lat, lon);
3037 MultMatrixViewPort(vp, lat, lon);
3041 LLBBox box = region.GetBox();
3044 if (g_memCacheLimit > 0) {
3049 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3050 for (
int i = 0; i < numtiles; i++) {
3052 if (region.IntersectOut(tile->box)) {
3055 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3056 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3058 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3059 global_color_scheme, mem_used);
3063 coords = tile->m_coords;
3065 coords =
new float[2 * tile->m_ncoords];
3066 for (
int i = 0; i < tile->m_ncoords; i++) {
3068 tile->m_coords[2 * i + 1]);
3069 coords[2 * i + 0] = p.m_x;
3070 coords[2 * i + 1] = p.m_y;
3074#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3075 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3076 m_pParentCanvas->GetpVP());
3079 glDisable(GL_TEXTURE_2D);
3083 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3084 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3085 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3087 if (!texture) glEnable(GL_TEXTURE_2D);
3089 if (!use_norm_vp)
delete[] coords;
3093 glDisable(GL_TEXTURE_2D);
3095#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3096 if (use_norm_vp) glPopMatrix();
3098 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3099 glDisableClientState(GL_VERTEX_ARRAY);
3103void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3105 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3106 m_pParentCanvas->m_pQuilt->IsBusy())
3110 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3112 printf(
" Chart NULL\n");
3113 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3123 LLRegion region = vp.GetLLRegion(rect_region);
3125 LLRegion rendered_region;
3131 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3139 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3141 LLRegion get_region = pqp->ActiveRegion;
3142 bool b_rendered =
false;
3144 if (!pqp->b_overlay) {
3145 get_region.Intersect(region);
3146 if (!get_region.Empty()) {
3147 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3150 SetClipRegion(vp, get_region );
3151 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3152 DisableClipRegion();
3155 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3156 SetClipRegion(vp, pqp->ActiveRegion );
3157 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3159 DisableClipRegion();
3162 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3163 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3164 RenderNoDTA(vp, get_region);
3165 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3170 if (Chs57->m_RAZBuilt) {
3171 RenderNoDTA(vp, get_region);
3172 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3173 rect_region, get_region);
3174 DisableClipRegion();
3179 const LLRegion &oregion = get_region;
3180 LLBBox box = oregion.GetBox();
3191 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3194 ViewPort cvp = ClippedViewport(vp, get_region);
3195 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3196 SetClipRegion(cvp, get_region);
3197 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3198 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3199 RenderWorldChart(gldc, cvp, srect, world);
3200 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3201 global_color_scheme);
3202 DisableClipRegion();
3209 SetClipRegion(vp, get_region);
3210 RenderNoDTA(vp, get_region);
3211 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3213 DisableClipRegion();
3216 SetClipRegion(vp, get_region);
3217 RenderNoDTA(vp, get_region);
3218 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3220 DisableClipRegion();
3236 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3240 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3241 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3243 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3244 if (pqp->b_Valid && pqp->b_overlay &&
3245 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3246 LLRegion get_region = pqp->ActiveRegion;
3248 get_region.Intersect(region);
3249 if (!get_region.Empty()) {
3252 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3257 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3264 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3269 ViewPort vph = m_pParentCanvas->GetVP();
3270 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3273 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3275 if (!hiregion.Empty()) {
3279 switch (global_color_scheme) {
3280 case GLOBAL_COLOR_SCHEME_DAY:
3283 case GLOBAL_COLOR_SCHEME_DUSK:
3286 case GLOBAL_COLOR_SCHEME_NIGHT:
3294#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3296 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3298 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3301 DrawRegion(vp, hiregion);
3303 glDisable(GL_BLEND);
3308 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3310 if (!hiregion.Empty()) {
3314 switch (global_color_scheme) {
3315 case GLOBAL_COLOR_SCHEME_DAY:
3318 case GLOBAL_COLOR_SCHEME_DUSK:
3321 case GLOBAL_COLOR_SCHEME_NIGHT:
3330#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3332 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3334 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3337 DrawRegion(vp, hiregion);
3339 glDisable(GL_BLEND);
3343 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3346void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3348 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3349 m_pParentCanvas->m_pQuilt->IsBusy())
3353 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3355 LLRegion region = vp.GetLLRegion(rect_region);
3357 LLRegion rendered_region;
3359 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3361 LLRegion get_region = pqp->ActiveRegion;
3363 if (!pqp->b_overlay) {
3364 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3367 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3372 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3379 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3407void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3408 ViewPort &vp = m_pParentCanvas->VPoint;
3416 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3417 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3420 LLRegion chart_region;
3422 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3423 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3424 CHART_FAMILY_RASTER) {
3432 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3433 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3434 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3436 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3440 for (
int i = 1; i < 6; i += 2)
3441 if (fabs(ll[i] - ll[i + 2]) > 180) {
3443 for (
int i = 1; i < 8; i += 2)
3444 if (ll[i] < 0) ll[i] += 360;
3448 chart_region = LLRegion(4, ll);
3451 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3453 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3454 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3455 chart_region = LLRegion(4, ll);
3458 chart_region = vp.b_quilt
3459 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3460 : m_pParentCanvas->m_singleChart->GetValidRegion();
3462 bool world_view =
false;
3464 wxRect rect = upd.GetRect();
3465 LLRegion background_region = vp.GetLLRegion(rect);
3468 background_region.Subtract(chart_region);
3470 if (!background_region.Empty()) {
3471 ViewPort cvp = ClippedViewport(vp, background_region);
3472 SetClipRect(cvp, rect,
false);
3473 RenderWorldChart(dc, cvp, rect, world_view);
3474 DisableClipRegion();
3479 RenderQuiltViewGL(vp, rect_region);
3482 LLRegion region = vp.GetLLRegion(rect_region);
3483 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3484 CHART_FAMILY_RASTER) {
3485 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3486 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3487 *m_pcontext, vp, rect_region, region);
3489 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3490 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3491 CHART_FAMILY_VECTOR) {
3492 chart_region.Intersect(region);
3493 RenderNoDTA(vp, chart_region);
3494 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3495 rect_region, region);
3501void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3503 wxColour color = GetGlobalColor(
"NODTA");
3504#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3506 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3508 glColor4ub(163, 180, 183, transparency);
3511 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3515 s_regionColor = color;
3518 DrawRegion(vp, region);
3522void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3525 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3527 glEnable(GL_SCISSOR_TEST);
3528 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3534 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3535#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3537 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3541 colorv[0] = water.Red() / float(256);
3542 colorv[1] = water.Green() / float(256);
3543 colorv[2] = water.Blue() / float(256);
3545 shader->SetUniform4fv(
"color", colorv);
3556 shader->SetAttributePointerf(
"position", pf);
3558 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3570 glDisable(GL_SCISSOR_TEST);
3578void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3579 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3581 DrawStaticRoutesTracksAndWaypoints(vp);
3583 DisableClipRegion();
3586void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3588 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3592 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3593 if (!bmp.Ok())
return;
3595 wxImage image = bmp.ConvertToImage();
3596 int w = image.GetWidth(), h = image.GetHeight();
3599 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3600 tex_w = w, tex_h = h;
3602 tex_w = NextPow2(w), tex_h = NextPow2(h);
3604 m_tideTexWidth = tex_w;
3605 m_tideTexHeight = tex_h;
3607 unsigned char *d = image.GetData();
3608 unsigned char *a = image.GetAlpha();
3610 unsigned char mr, mg, mb;
3611 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3613 unsigned char *e =
new unsigned char[4 * w * h];
3615 for (
int y = 0; y < h; y++)
3616 for (
int x = 0; x < w; x++) {
3617 unsigned char r, g, b;
3618 int off = (y * w + x);
3628 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3632 glGenTextures(1, &m_tideTex);
3634 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3635 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3636 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3638 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3639 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3640 GL_UNSIGNED_BYTE, e);
3642 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3643 GL_UNSIGNED_BYTE, 0);
3644 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3653 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3654 glEnable(GL_TEXTURE_2D);
3657#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3659 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3663 if ((type ==
't') || (type ==
'T'))
3668 if (BBox.Contains(lat, lon)) {
3677 scale *= getAndroidDisplayDensity();
3679 double width2 =
scale * m_tideTexWidth / 2;
3680 double height2 =
scale * m_tideTexHeight / 2;
3695 coords[0] = xp - width2;
3696 coords[1] = yp - height2;
3697 coords[2] = xp - width2;
3698 coords[3] = yp + height2;
3699 coords[4] = xp + width2;
3700 coords[5] = yp + height2;
3701 coords[6] = xp + width2;
3702 coords[7] = yp - height2;
3704 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3711 glDisable(GL_TEXTURE_2D);
3712 glDisable(GL_BLEND);
3713 glBindTexture(GL_TEXTURE_2D, 0);
3715 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3718void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3719 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3722void glChartCanvas::SetColorScheme(ColorScheme cs) {
3723 if (!m_bsetup)
return;
3725 glDeleteTextures(1, &m_tideTex);
3726 glDeleteTextures(1, &m_currentTex);
3732void glChartCanvas::RenderGLAlertMessage() {
3733 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3734 wxString msg = m_pParentCanvas->GetAlertString();
3737 m_gldc.SetFont(*pfont);
3741 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3748 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3749 int xp = sbr.x + sbr.width + 5;
3751 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3752 m_gldc.SetPen(ppPen1);
3753 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3755 m_gldc.DrawRectangle(xp, yp, w, h);
3757 m_gldc.DrawText(msg, xp, yp);
3761unsigned long quiltHash;
3763extern wxLongLong s_t0;
3766void glChartCanvas::Render() {
3767 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3768 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3769 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3774 if (!g_PrintingInProgress)
return;
3777 if (!g_true_zoom && m_binPinch)
return;
3780 long render_start_time = m_glstopwatch.Time();
3782#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3783 loadShaders(GetCanvasIndex());
3784 configureShaders(m_pParentCanvas->VPoint);
3787#ifdef USE_ANDROID_GLES2
3791 if (m_binPinch)
return;
3800 bool recompose =
false;
3801 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3802 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3803 if (m_pParentCanvas->VPoint.IsValid()) {
3804 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3805 m_pParentCanvas->UpdateCanvasControlBar();
3814 if (sw.GetTime() > 2000) {
3820 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3821 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3827 m_displayScale = GetContentScaleFactor();
3831 m_last_render_time = wxDateTime::Now().GetTicks();
3835 if (g_GLOptions.m_bTextureCompression &&
3836 !g_GLOptions.m_bTextureCompressionCaching)
3841 int gl_width, gl_height;
3842 gl_width = m_pParentCanvas->VPoint.
pix_width;
3843 gl_height = m_pParentCanvas->VPoint.
pix_height;
3846 m_glcanvas_width = gl_width;
3847 m_glcanvas_height = gl_height;
3853 ViewPort VPoint = m_pParentCanvas->VPoint;
3855 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3856 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3859#if !defined(USE_ANDROID_GLES2)
3860 glMatrixMode(GL_PROJECTION);
3863 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3864 glMatrixMode(GL_MODELVIEW);
3868 if (s_b_useStencil) {
3869 glEnable(GL_STENCIL_TEST);
3870 glStencilMask(0xff);
3871 glClear(GL_STENCIL_BUFFER_BIT);
3872 glDisable(GL_STENCIL_TEST);
3878 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3879 if (g_GLOptions.m_GLPolygonSmoothing)
3880 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3881 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3893 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3894 bool useFBO =
false;
3900 if (m_b_BuiltFBO && !bpost_hilite
3905 bool b_newview =
true;
3906 bool b_full =
false;
3914 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3918#ifdef USE_ANDROID_GLES2
3919 if (recompose) b_newview =
true;
3931 if (VPoint.b_quilt) {
3932 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3933 if (!chart) b_full =
true;
3942 bool accelerated_pan =
false;
3952 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
3953 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
3954 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
3956 wxPoint2DDouble c_old =
3959 wxPoint2DDouble c_new =
3963 dy = wxRound(c_new.m_y - c_old.m_y);
3964 dx = wxRound(c_new.m_x - c_old.m_x);
3974 double deltax = c_new.m_x - c_old.m_x;
3975 double deltay = c_new.m_y - c_old.m_y;
3977 bool b_whole_pixel =
true;
3978 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
3979 b_whole_pixel =
false;
3981 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
3982 abs(dy) < m_cache_tex_y &&
3983 (abs(dx) > 0 || (abs(dy) > 0));
3992 if (m_displayScale > 1) accelerated_pan =
false;
3997 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4000#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4003 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4009 if (b_full) accelerated_pan =
false;
4011 if (accelerated_pan) {
4012 if ((dx != 0) || (dy != 0)) {
4024 if (dy > 0 && dy < gl_height)
4025 update_region.Union(
4026 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4028 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4030 if (dx > 0 && dx < gl_width)
4031 update_region.Union(
4032 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4034 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4036 m_cache_page = !m_cache_page;
4039 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4040 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4052 RenderCharts(m_gldc, update_region);
4056 glDisable(g_texture_rectangle_format);
4061 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4062 glEnable(GL_TEXTURE_2D);
4066 float x1, x2, y1, y2;
4079 float tx1, tx2, ty1, ty2;
4085 tx2 = sx / (float)m_cache_tex_x;
4087 ty2 = sy / (float)m_cache_tex_y;
4104 coords[2] = -dx + sx;
4106 coords[4] = -dx + sx;
4107 coords[5] = dy + sy;
4109 coords[7] = dy + sy;
4112 ptexture_2D_shader_program[GetCanvasIndex()];
4116 shader->SetUniform1i(
"uTex", 0);
4120 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4121 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4122 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4124 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4146 shader->SetAttributePointerf(
"aPos", co1);
4147 shader->SetAttributePointerf(
"aUV", tco1);
4149 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4152 shader->SetUniformMatrix4fv(
"MVMatrix",
4153 (GLfloat *)VPoint.vp_matrix_transform);
4156 glBindTexture(g_texture_rectangle_format, 0);
4158 glDisable(g_texture_rectangle_format);
4166 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4167 g_texture_rectangle_format,
4168 m_cache_tex[!m_cache_page], 0);
4179 wxColour color = GetGlobalColor(
"NODTA");
4180 glClearColor(color.Red() / 256., color.Green() / 256.,
4181 color.Blue() / 256., 1.0);
4182 glClear(GL_COLOR_BUFFER_BIT);
4188 RenderCharts(m_gldc, rscreen_region);
4193 m_cache_page = !m_cache_page;
4198 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4209 glMatrixMode(GL_PROJECTION);
4212 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4213 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4215 glMatrixMode(GL_MODELVIEW);
4219 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4220 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4222 glGetIntegerv(GL_VIEWPORT, viewport);
4223 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4224 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4233 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4234 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4235 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4237 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4241 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4242 glEnable(g_texture_rectangle_format);
4244 float tx, ty, tx0, ty0, divx, divy;
4247 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4250 divx = m_cache_tex_x;
4251 divy = m_cache_tex_y;
4254 tx0 = m_fbo_offsetx / divx;
4255 ty0 = m_fbo_offsety / divy;
4256 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4257 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4282 wxColour color = GetGlobalColor(
"NODTA");
4283 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4285 glClear(GL_COLOR_BUFFER_BIT);
4287 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4290 glDisable(g_texture_rectangle_format);
4292 m_cache_vp = VPoint;
4293 m_cache_vp.Validate();
4295 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4297 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4301 RenderCharts(m_gldc, screen_region);
4310 RenderS57TextOverlay(VPoint);
4311 RenderMBTilesOverlay(VPoint);
4317 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4322 wxRect rt = upd.GetRect();
4323 LLRegion region = VPoint.GetLLRegion(rt);
4324 ViewPort cvp = ClippedViewport(VPoint, region);
4325 DrawGroundedOverlayObjects(gldc, cvp);
4328 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4329 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4330 LLBBox screenBox = screenLLRegion.GetBox();
4332 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4335 if (m_pParentCanvas->m_bShowTide) {
4336 m_pParentCanvas->RebuildTideSelectList(screenBox);
4337 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4340 if (m_pParentCanvas->m_bShowCurrent) {
4341 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4342 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4348 if (m_pParentCanvas->m_show_focus_bar &&
4349 (g_canvasConfig != 0)) {
4350 if (m_pParentCanvas == wxWindow::FindFocus()) {
4353 wxColour colour = GetGlobalColor(
"BLUE4");
4354 wxPen ppBlue(colour, 1);
4355 wxBrush ppBrush(colour);
4356 gldc.SetPen(ppBlue);
4357 gldc.SetBrush(ppBrush);
4358 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4359 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4360 wxPoint barPoints[4];
4363 barPoints[1].x = xw;
4365 barPoints[2].x = xw;
4366 barPoints[2].y = rect_pix;
4368 barPoints[3].y = rect_pix;
4370 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4374 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4378 DrawFloatingOverlayObjects(m_gldc);
4380#ifndef USE_ANDROID_GLES2
4383 glMatrixMode(GL_PROJECTION);
4386 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4387 glMatrixMode(GL_MODELVIEW);
4392 if (!g_bhide_depth_units)
4393 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4394 if (!g_bhide_overzoom_flag)
4395 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4398 ViewPort &vp = m_pParentCanvas->GetVP();
4403 if (!g_PrintingInProgress) {
4404 if (m_pParentCanvas->m_pTrackRolloverWin)
4405 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4407 if (m_pParentCanvas->m_pRouteRolloverWin)
4408 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4410 if (m_pParentCanvas->m_pAISRolloverWin)
4411 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4413 if (m_pParentCanvas->GetMUIBar())
4414 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4428 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4429 int x, y, width, height;
4430 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4431 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4432 wxBitmap bmp(width, height, -1);
4435 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4438 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4439 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4443 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4444 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4446 wxStringTokenizer tkz(s,
"\n");
4449 while (tkz.HasMoreTokens()) {
4450 token = tkz.GetNextToken();
4451 dc.DrawText(token, xt, yt);
4454 dc.SelectObject(wxNullBitmap);
4456 m_gldc.DrawBitmap(bmp, x, y,
false);
4462 if (g_bShowChartBar) DrawChartBar(m_gldc);
4464 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4466 m_pParentCanvas->m_Compass->Paint(gldc);
4468 if (m_pParentCanvas->IsPrimaryCanvas() &&
4469 m_pParentCanvas->m_notification_button) {
4470 auto ¬eman = NotificationManager::GetInstance();
4471 if (noteman.GetNotificationCount()) {
4472 m_pParentCanvas->m_notification_button->SetIconSeverity(
4473 noteman.GetMaxSeverity());
4474 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4475 m_pParentCanvas->m_notification_button->Show(
true);
4476 m_pParentCanvas->m_notification_button->Paint(gldc);
4478 m_pParentCanvas->m_notification_button->Show(
false);
4481 RenderGLAlertMessage();
4484 ViewPort &vp = m_pParentCanvas->GetVP();
4488 glActiveTexture(GL_TEXTURE0);
4492 if (g_bquiting) DrawQuiting();
4493 if (g_bcompression_wait)
4494 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4504 m_pParentCanvas->PaintCleanup();
4505 m_bforcefull =
false;
4514void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4517 if (VPoint.b_quilt) {
4518 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4519 ps52plib->GetShowS57Text()) {
4520 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4521 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4526 ChPI->ClearPLIBTextList();
4528 ps52plib->ClearTextList();
4538 RenderQuiltViewGLText(vpx, screen_region);
4543void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4546 LLRegion &screenLLRegion) {
4551 if (chart == NULL)
return;
4558 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4560 wxFileName tileFile(chart->GetFullPath());
4562 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4565 bool isBasemap = tileFile.GetPath().Lower().Contains(
"basemap");
4571 (double)chart->GetNativeScale();
4573 if (zoom_ratio > g_tile_basemap_zoom_factor)
return;
4576 if (!isBasemap && (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4577 (tileSizeMB.GetLo() > 5000))) {
4580 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4581 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4582 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4589 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4593 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4596 std::vector<int> piano_active_array_tiles =
4597 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4598 bool bfound =
false;
4600 if (std::find(piano_active_array_tiles.begin(),
4601 piano_active_array_tiles.end(),
4602 dbIndex) != piano_active_array_tiles.end()) {
4607 piano_active_array_tiles.push_back(dbIndex);
4608 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4612void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4614 std::vector<int> stackIndexArray =
4615 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4616 unsigned int im = stackIndexArray.size();
4619 if (VPoint.b_quilt && im > 0) {
4620 bool regionVPBuilt =
false;
4622 LLRegion screenLLRegion;
4626 std::vector<int> tiles_to_show;
4627 for (
unsigned int is = 0; is < im; is++) {
4629 ChartData->GetChartTableEntry(stackIndexArray[is]);
4630 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4631 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4633 std::vector<int> piano_active_array_tiles =
4634 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4635 bool bfound =
false;
4637 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4638 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4639 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4647 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4648 piano_active_array_tiles);
4653 tiles_to_show.push_back(stackIndexArray[is]);
4654 if (!regionVPBuilt) {
4657 screenLLRegion = VPoint.GetLLRegion(screen_region);
4658 screenBox = screenLLRegion.GetBox();
4666 regionVPBuilt =
true;
4676 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4677 rit != tiles_to_show.rend(); ++rit) {
4678 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4680 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4681 rit != tiles_to_show.rend(); ++rit) {
4682 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4686 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4688 if (!hiregion.Empty()) {
4692 switch (global_color_scheme) {
4693 case GLOBAL_COLOR_SCHEME_DAY:
4696 case GLOBAL_COLOR_SCHEME_DUSK:
4699 case GLOBAL_COLOR_SCHEME_NIGHT:
4707#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4708 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4710 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4713 DrawRegion(VPoint, hiregion);
4715 glDisable(GL_BLEND);
4721void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4725 GetClientSize(&w, &h);
4727 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4728#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4729 glMatrixMode(GL_PROJECTION);
4732 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4733 glMatrixMode(GL_MODELVIEW);
4737 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4739 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4741 bool world_view =
false;
4742 RenderWorldChart(dc, cvp, rtex, world_view);
4749 glViewport(0, 0, (GLint)w, (GLint)h);
4750#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4751 glMatrixMode(GL_PROJECTION);
4754 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4755 glMatrixMode(GL_MODELVIEW);
4761void glChartCanvas::FastPan(
int dx,
int dy) {
4762#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4766void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4768 if (IsShown()) SetCurrent(*m_pcontext);
4769 float sx = GetSize().x;
4770 float sy = GetSize().y;
4771 glClear(GL_COLOR_BUFFER_BIT);
4774 GetClientSize(&w, &h);
4776 if (s_b_useStencil) {
4777 glEnable(GL_STENCIL_TEST);
4778 glStencilMask(0xff);
4779 glClear(GL_STENCIL_BUFFER_BIT);
4780 glDisable(GL_STENCIL_TEST);
4796 float sxfactor = sx / swidth;
4797 float syfactor = sy / sheight;
4799 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4800 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4801 sx * sx / swidth * 2, sy * sy / sheight * 2);
4802 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4803 glEnable(g_texture_rectangle_format);
4828 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4829 glBindTexture(g_texture_rectangle_format, 0);
4835 float tx, ty, tx0, ty0;
4845 glBindTexture(g_texture_rectangle_format, 0);
4848 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4849 glEnable(g_texture_rectangle_format);
4855 uv[0] = tx0 / m_cache_tex_x;
4856 uv[1] = ty / m_cache_tex_y;
4857 uv[2] = tx / m_cache_tex_x;
4858 uv[3] = ty / m_cache_tex_y;
4859 uv[4] = tx / m_cache_tex_x;
4860 uv[5] = ty0 / m_cache_tex_y;
4861 uv[6] = tx0 / m_cache_tex_x;
4862 uv[7] = ty0 / m_cache_tex_y;
4874 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4875 sx * sx / swidth, sy * sy / sheight);
4877 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4879 glDisable(g_texture_rectangle_format);
4880 glBindTexture(g_texture_rectangle_format, 0);
4887 wxColour color = GetGlobalColor(
"GREY1");
4888 float ht = -offset_y * (sy / sheight);
4889 wxRect r(0, sy - ht, w, ht);
4890 RenderColorRect(r, color);
4893 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4894 RenderColorRect(rt, color);
4897 float w1 = -offset_x * sx / swidth;
4898 wxRect rl(0, 0, w1, sy);
4899 RenderColorRect(rl, color);
4902 float px = w1 + sx * sx / swidth;
4903 wxRect rr(px, 0, sx - px, sy);
4904 RenderColorRect(rr, color);
4913void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4916 if (m_nRun < m_nTotal) {
4917 m_runoffsetx += m_offsetxStep;
4918 if (m_offsetxStep > 0)
4919 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4921 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4923 m_runoffsety += m_offsetyStep;
4924 if (m_offsetyStep > 0)
4925 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4927 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4929 m_runswidth += m_swidthStep;
4930 if (m_swidthStep > 0)
4931 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4933 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4935 m_runsheight += m_sheightStep;
4936 if (m_sheightStep > 0)
4937 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4939 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4944 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4950 if (m_zoomFinaldx || m_zoomFinaldy) {
4951 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
4954 m_zoomFinal =
false;
4958void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
4960 int sx = GetSize().x;
4961 int sy = GetSize().y;
4963 m_lastfbo_offsetx = m_fbo_offsetx;
4964 m_lastfbo_offsety = m_fbo_offsety;
4965 m_lastfbo_swidth = m_fbo_swidth;
4966 m_lastfbo_sheight = m_fbo_sheight;
4968 float curr_fbo_offset_x = m_fbo_offsetx;
4969 float curr_fbo_offset_y = m_fbo_offsety;
4970 float curr_fbo_swidth = m_fbo_swidth;
4971 float curr_fbo_sheight = m_fbo_sheight;
4973 float fx = (float)cp_x / sx;
4974 float fy = 1.0 - (float)cp_y / sy;
4976 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
4977 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
4979 m_fbo_swidth = curr_fbo_swidth / factor;
4980 m_fbo_sheight = curr_fbo_sheight / factor;
4982 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
4983 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
4985 m_fbo_offsetx += post_x;
4986 m_fbo_offsety += post_y;
4997 float perStep = m_nStep / m_nTotal;
4999 if (zoomTimer.IsRunning()) {
5000 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5001 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5002 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5003 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5006 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5007 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5008 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5009 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5011 m_runoffsetx = m_lastfbo_offsetx;
5012 m_runoffsety = m_lastfbo_offsety;
5013 m_runswidth = m_lastfbo_swidth;
5014 m_runsheight = m_lastfbo_sheight;
5017 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5018 m_zoomFinal =
false;
5024void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5028 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5031 if (m_binPinch)
return;
5032 if (m_bpinchGuard)
return;
5034 int x =
event.GetOffset().x;
5035 int y =
event.GetOffset().y;
5037 int lx =
event.GetLastOffset().x;
5038 int ly =
event.GetLastOffset().y;
5043 switch (event.GetState()) {
5044 case GestureStarted:
5045 if (m_binPan)
break;
5049 m_binGesture =
true;
5053 case GestureUpdated:
5058 m_pParentCanvas->FreezePiano();
5060 m_pParentCanvas->ThawPiano();
5071 case GestureFinished:
5074 m_pParentCanvas->UpdateCanvasControlBar();
5077 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5081 case GestureCanceled:
5083 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5090 m_bgestureGuard =
true;
5091 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5092 m_bforcefull =
false;
5097float zoom_inc = 1.0;
5099void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5100 float zoom_gain = 1.0;
5101 float zout_gain = 1.0;
5104 float total_zoom_val;
5106 float max_zoom_scale = 1000.;
5107 float min_zoom_scale = 2e8;
5109 if (event.GetScaleFactor() > 1)
5110 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5112 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5114 if (event.GetTotalScaleFactor() > 1)
5115 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5118 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5120 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5123 float max_zoom_scale = 1000.;
5124 if( cc1->GetVP().b_quilt) {
5125 int ref_index = cc1->GetQuiltRefChartdbIndex();
5132 float min_zoom_scale = 2e8;
5136 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5138 double projected_scale =
5139 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5141 switch (event.GetState()) {
5142 case GestureStarted:
5143 m_first_zout =
false;
5147 m_binGesture =
true;
5149 m_pinchStart =
event.GetCenterPoint();
5150 m_lpinchPoint = m_pinchStart;
5153 event.GetCenterPoint().y, m_pinchlat,
5158 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5159 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5162 if (IsShown()) SetCurrent(*m_pcontext);
5168 case GestureUpdated:
5170 if (projected_scale < min_zoom_scale) {
5171 wxPoint pinchPoint =
event.GetCenterPoint();
5173 float dx = pinchPoint.x - m_lpinchPoint.x;
5174 float dy = pinchPoint.y - m_lpinchPoint.y;
5176 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5177 -dx / total_zoom_val, dy / total_zoom_val);
5179 m_lpinchPoint = pinchPoint;
5183 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5184 wxPoint pinchPoint =
event.GetCenterPoint();
5186 float dx = pinchPoint.x - m_lpinchPoint.x;
5187 float dy = pinchPoint.y - m_lpinchPoint.y;
5189 if ((projected_scale > max_zoom_scale) &&
5190 (projected_scale < min_zoom_scale))
5191 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5192 -dx / total_zoom_val, dy / total_zoom_val);
5194 m_lpinchPoint = pinchPoint;
5197 m_first_zout =
true;
5198 zoom_inc *= zoom_val;
5199 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5200 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5204 wxPoint pinchPoint =
event.GetCenterPoint();
5205 float dx = pinchPoint.x - m_lpinchPoint.x;
5206 float dy = pinchPoint.y - m_lpinchPoint.y;
5208 m_lpinchPoint = pinchPoint;
5219 case GestureFinished: {
5223 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5224 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5228 float tzoom = total_zoom_val;
5230 if (projected_scale >= min_zoom_scale)
5231 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5233 if (projected_scale < max_zoom_scale)
5234 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5236 dx = (cc_x - m_cc_x) * tzoom;
5237 dy = -(cc_y - m_cc_y) * tzoom;
5239 if (zoomTimer.IsRunning()) {
5242 m_zoomFinalZoom = tzoom;
5248 double final_projected_scale =
5252 if (final_projected_scale < min_zoom_scale) {
5256 m_pParentCanvas->m_pQuilt->Invalidate();
5257 m_bforcefull =
true;
5264 m_pParentCanvas->m_pQuilt->Invalidate();
5265 m_bforcefull =
true;
5277 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5281 case GestureCanceled:
5283 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5290 m_bgestureGuard =
true;
5292 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5295void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5305 m_bgestureGuard =
false;
5306 m_bpinchGuard =
false;
5307 m_binGesture =
false;
5308 m_bforcefull =
false;
5311void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5315 m_binGesture =
false;
5316 m_bforcefull =
false;
5320#ifdef HAVE_WX_GESTURE_EVENTS
5322void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5325 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5328 if (m_binPinch)
return;
5329 if (m_bpinchGuard)
return;
5331 int dx =
event.GetDelta().x;
5332 int dy =
event.GetDelta().y;
5334 if (event.IsGestureStart()) {
5335 if (m_binPan)
return;
5339 m_binGesture =
true;
5343 else if (event.IsGestureEnd()) {
5345 m_pParentCanvas->UpdateCanvasControlBar();
5347 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5355 m_pParentCanvas->FreezePiano();
5357 m_pParentCanvas->ThawPiano();
5368 m_bgestureGuard =
true;
5369 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5370 m_bforcefull =
false;
5374void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5376 float zoom_gain = 1.0;
5377 float zout_gain = 1.0;
5379 float last_zoom_val = m_step_zoom_val;
5381 float max_zoom_scale = 1000.;
5382 float min_zoom_scale = 2e8;
5384 if (event.GetZoomFactor() > 1)
5385 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5387 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5389 float inc_zoom_val =
5390 m_total_zoom_val / last_zoom_val;
5394 if (event.IsGestureStart()) {
5395 m_glstopwatch.Start();
5396 printf(
"\nStart--------------\n");
5398 m_pParentCanvas->m_inPinch =
true;
5401 m_binGesture =
true;
5402 m_pinchStart =
event.GetPosition();
5403 m_lpinchPoint = m_pinchStart;
5404 m_total_zoom_val = 1.0;
5405 m_final_zoom_val = 1.0;
5406 m_step_zoom_val = 1.0;
5410 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5414 if (event.IsGestureEnd()) {
5416 if (!m_binGesture)
return;
5417 printf(
"EndZoom--------------\n");
5424 m_final_zoom_val = 1.0;
5425 m_total_zoom_val = 1.0;
5426 m_step_zoom_val = 1.0;
5428 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5435 float zoom_step = 5;
5436 float zoom_trigger = 0.05;
5437 if (projected_scale > 1e5)
5439 else if (projected_scale < 3e4)
5442 if (inc_zoom_val != 1.0) {
5443 if (inc_zoom_val > 1 + zoom_step) {
5444 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5445 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5447 if (IsShown()) SetCurrent(*m_pcontext);
5450 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5451 m_step_zoom_val = m_total_zoom_val;
5452 printf(
" Zoom: %6g\n", inc_zoom_val);
5457 bool b_allow_ztp =
true;
5458 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5459 b_allow_ztp =
false;
5461 if (g_bEnableZoomToCursor && b_allow_ztp) {
5467 int dx = r.x -
event.GetPosition().x;
5468 int dy = r.y -
event.GetPosition().y;
5472 if (IsShown()) SetCurrent(*m_pcontext);
5481 float zoom_gain = 1.0;
5482 float zout_gain = 1.0;
5484 float last_zoom_val = m_total_zoom_val;
5486 float max_zoom_scale = 1000.;
5487 float min_zoom_scale = 2e8;
5489 if (event.GetZoomFactor() > 1)
5490 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5492 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5494 float inc_zoom_val =
5495 m_total_zoom_val / last_zoom_val;
5497 double projected_scale =
5498 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5500 if (event.IsGestureStart()) {
5502 m_first_zout =
false;
5506 m_binGesture =
true;
5507 m_pinchStart =
event.GetPosition();
5508 m_lpinchPoint = m_pinchStart;
5509 m_total_zoom_val = 1.0;
5510 m_final_zoom_val = 1.0;
5513 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5517 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5518 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5521 if (IsShown()) SetCurrent(*m_pcontext);
5524 ViewPort vpr = m_pParentCanvas->VPoint;
5526 GetTouchBackingBitmap(vpr);
5531 if (event.IsGestureEnd()) {
5537 if (!m_binGesture)
return;
5539 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5540 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5544 float tzoom = m_final_zoom_val;
5546 dx = (cc_x - m_cc_x) * tzoom;
5547 dy = -(cc_y - m_cc_y) * tzoom;
5549 if (zoomTimer.IsRunning()) {
5552 m_zoomFinalZoom = tzoom;
5558 double final_projected_scale =
5562 if (final_projected_scale < min_zoom_scale) {
5566 m_pParentCanvas->m_pQuilt->Invalidate();
5567 m_bforcefull =
true;
5574 m_pParentCanvas->m_pQuilt->Invalidate();
5575 m_bforcefull =
true;
5580 m_final_zoom_val = 1.0;
5581 m_total_zoom_val = 1.0;
5582 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5587 if (projected_scale < min_zoom_scale) {
5588 wxPoint pinchPoint =
event.GetPosition();
5590 float dx = pinchPoint.x - m_lpinchPoint.x;
5591 float dy = pinchPoint.y - m_lpinchPoint.y;
5593 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5594 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5596 m_lpinchPoint = pinchPoint;
5597 m_final_zoom_val *= inc_zoom_val;
5601 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5602 wxPoint pinchPoint =
event.GetPosition();
5604 float dx = pinchPoint.x - m_lpinchPoint.x;
5605 float dy = pinchPoint.y - m_lpinchPoint.y;
5607 if ((projected_scale > max_zoom_scale) &&
5608 (projected_scale < min_zoom_scale))
5609 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5610 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5612 m_lpinchPoint = pinchPoint;
5613 m_final_zoom_val *= inc_zoom_val;
5616 m_first_zout =
true;
5617 m_zoom_inc *= inc_zoom_val;
5618 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5619 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5623 wxPoint pinchPoint =
event.GetPosition();
5624 float dx = pinchPoint.x - m_lpinchPoint.x;
5625 float dy = pinchPoint.y - m_lpinchPoint.y;
5627 m_lpinchPoint = pinchPoint;
5631 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5634 m_bgestureGuard =
true;
5635 m_bpinchGuard =
true;
5638void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5647 m_bgestureGuard =
false;
5648 m_bpinchGuard =
false;
5649 m_binGesture =
false;
5650 m_bforcefull =
false;
5653void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5657 m_binGesture =
false;
5658 m_bforcefull =
false;
5660 m_pParentCanvas->m_inPinch =
false;
5661 printf(
"******Finish\n");
5667void glChartCanvas::configureShaders(
ViewPort &vp) {
5668#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5674 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5676 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5677 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5698 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5700 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5701 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5713 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5715 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5716 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5719 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5721 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5722 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5730 shader = pAALine_shader_program[GetCanvasIndex()];
5732 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5735 shader = pring_shader_program[GetCanvasIndex()];
5737 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5738 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5742 if (texture_2DA_shader_program) {
5743 glUseProgram(texture_2DA_shader_program);
5744 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5745 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5746 (
const GLfloat *)pvp->vp_matrix_transform);
5748 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5749 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5757void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5760#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5761 int nl = nVertex / 4;
5763 float *luv = uvCoords;
5766 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5774 glEnableClientState(GL_VERTEX_ARRAY);
5775 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5777 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5778 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5779 glDrawArrays(GL_QUADS, 0, 4);
5786void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5787 float *uvCoords,
ViewPort *vp,
float dx,
5788 float dy,
float angle_rad) {
5789#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5791 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5792 if (!shader)
return;
5797 shader->SetUniform1i(
"uTex", 0);
5802 mat4x4_rotate_Z(Q, I, angle_rad);
5808 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5813 shader->SetAttributePointerf(
"aPos", co1);
5814 shader->SetAttributePointerf(
"aUV", tco1);
5821 GLushort indices1[] = {0,1,3,2};
5822 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5834 tco1[0] = uvCoords[0];
5835 tco1[1] = uvCoords[1];
5836 tco1[2] = uvCoords[2];
5837 tco1[3] = uvCoords[3];
5838 tco1[4] = uvCoords[6];
5839 tco1[5] = uvCoords[7];
5840 tco1[6] = uvCoords[4];
5841 tco1[7] = uvCoords[5];
5846 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5858void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5859#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5861 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5864 shader->SetUniformMatrix4fv(
5865 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5868 colorv[0] = color.Red() / float(256);
5869 colorv[1] = color.Green() / float(256);
5870 colorv[2] = color.Blue() / float(256);
5872 shader->SetUniform4fv(
"color", colorv);
5875 pf[0] = r.x + r.width;
5879 pf[4] = r.x + r.width;
5880 pf[5] = r.y + r.height;
5882 pf[7] = r.y + r.height;
5883 shader->SetAttributePointerf(
"position", pf);
5885 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5893void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5894#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5896 ViewPort VPoint = m_pParentCanvas->VPoint;
5900 GetClientSize(&w, &h);
5901 int sx = GetSize().x;
5902 int sy = GetSize().y;
5906 glViewport(0, 0, (GLint)w, (GLint)h);
5908 if (s_b_useStencil) {
5909 glEnable(GL_STENCIL_TEST);
5910 glStencilMask(0xff);
5911 glClear(GL_STENCIL_BUFFER_BIT);
5912 glDisable(GL_STENCIL_TEST);
5916 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5921 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5922 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5923 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5926 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5928 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5929 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5937 if (bRenderCharts) RenderCharts(gldc, screen_region);
5939 if (bRenderOverlays) {
5940 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5941 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5947 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5950 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5951 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5952 DrawFloatingOverlayObjects(m_gldc);
5956 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5961wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5963 wxMemoryDC tdc(tbm);
5964 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5972 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5973 dc.SetPen(*wxTRANSPARENT_PEN);
5976 tdc.SelectObject(wxNullBitmap);
5977 m_touch_backing_bitmap = tbm;
5978 CreateBackingTexture();
5980 return m_touch_backing_bitmap;
5983void glChartCanvas::CreateBackingTexture() {
5984 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5985 unsigned char *imgdata = image.GetData();
5986 unsigned char *imgalpha = image.GetAlpha();
5987 m_tex_w = image.GetWidth();
5988 m_tex_h = image.GetHeight();
5989 m_image_width = m_tex_w;
5990 m_image_height = m_tex_h;
5992 GLuint format = GL_RGBA;
5993 GLuint internalformat = g_texture_rectangle_format;
5995 internalformat = GL_RGBA;
6000 unsigned char *teximage =
6001 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6003 for (
int i = 0; i < m_image_height; i++) {
6004 for (
int j = 0; j < m_image_width; j++) {
6005 int s = (i * 3 * m_image_width) + (j * 3);
6006 int d = (i * stride * m_tex_w) + (j * stride);
6008 teximage[d + 0] = imgdata[s + 0];
6009 teximage[d + 1] = imgdata[s + 1];
6010 teximage[d + 2] = imgdata[s + 2];
6011 teximage[d + 3] = 255;
6015 glGenTextures(1, &m_TouchBackingTexture);
6016 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6018 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6019 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6020 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6022 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6024 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6025 GL_UNSIGNED_BYTE, teximage);
6028 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.