40#include <wx/dcmemory.h>
41#include <wx/dynarray.h>
45#include <wx/glcanvas.h>
47#include <wx/jsonval.h>
50#include <wx/progdlg.h>
51#include <wx/stopwatch.h>
53#include <wx/tokenzr.h>
84#include "mipmap/mipmap.h"
96#include "s57_ocpn_utils.h"
106#ifdef USE_ANDROID_GLES2
107#include <GLES2/gl2.h>
113#include "androidUTIL.h"
114#elif defined(__WXQT__) || defined(__WXGTK__)
118#ifndef GL_ETC1_RGB8_OES
119#define GL_ETC1_RGB8_OES 0x8D64
122#ifndef GL_DEPTH_STENCIL_ATTACHMENT
123#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
127#define printf printf2
128int __cdecl printf2(
const char *format, ...);
131#if defined(__ANDROID__)
132#include "androidUTIL.h"
133#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
140extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
141 float near,
float far);
142#define glOrtho(a, b, c, d, e, f) \
144 glOrthof(a, b, c, d, e, f);
148#ifdef USE_ANDROID_GLES2
149#include <GLES2/gl2.h>
152#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
158#if defined(__UNIX__) && !defined(__WXOSX__)
163 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
167 clock_gettime(CLOCK_REALTIME, &tp_end);
168 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
169 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
182static bool g_b_needFinish;
184static wxColor s_regionColor;
185static float g_GLMinCartographicLineWidth;
191#define APIENTRYP APIENTRY *
197#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
198#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
204PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
205PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
206PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
207PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
208PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
209PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
210PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
211PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
212PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
213PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
215PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
216PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
219PFNGLGENBUFFERSPROC s_glGenBuffers;
220PFNGLBINDBUFFERPROC s_glBindBuffer;
221PFNGLBUFFERDATAPROC s_glBufferData;
222PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
224#ifndef USE_ANDROID_GLES2
229typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
231PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
234static int panx, pany;
238#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
239static int s_tess_vertex_idx;
240static int s_tess_vertex_idx_this;
241static int s_tess_buf_len;
242static GLfloat *s_tess_work_buf;
243static GLenum s_tess_mode;
248bool glChartCanvas::s_b_useScissorTest;
249bool glChartCanvas::s_b_useStencil;
250bool glChartCanvas::s_b_useStencilAP;
251bool glChartCanvas::s_b_useFBO;
258 while ( upd.HaveRects() )
260 wxRect rect = upd.GetRect();
261 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
268GLboolean QueryExtension(
const char *extName) {
279 extNameLen = strlen(extName);
281 p = (
char *)glGetString(GL_EXTENSIONS);
289 int n = strcspn(p,
" ");
290 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
298int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
299 16, WX_GL_STENCIL_SIZE, 8,
302glTestCanvas::glTestCanvas(wxWindow *parent)
303 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
307int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
308 16, WX_GL_STENCIL_SIZE, 8,
311EVT_PAINT(glChartCanvas::OnPaint)
312EVT_ACTIVATE(glChartCanvas::OnActivate)
313EVT_SIZE(glChartCanvas::OnSize)
314EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
318 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
319 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
322 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
327std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
329 {wxPENSTYLE_DOT, {1, 1}},
330 {wxPENSTYLE_LONG_DASH, {5, 5}},
331 {wxPENSTYLE_SHORT_DASH, {1, 5}},
332 {wxPENSTYLE_DOT_DASH, {5, 1}},
335void glChartCanvas::Init() {
340 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
342 m_cache_current_ch = NULL;
344 m_b_paint_enable =
true;
345 m_in_glpaint =
false;
347 m_cache_tex[0] = m_cache_tex[1] = 0;
350 m_b_BuiltFBO =
false;
351 m_b_DisableFBO =
false;
360 m_bpinchGuard =
false;
361 m_binGesture =
false;
362 m_first_zout =
false;
366 m_last_render_time = -1;
373 m_gldc.SetGLCanvas(
this);
376 m_displayScale = 1.0;
377#if defined(__WXOSX__) || defined(__WXGTK3__)
379 m_displayScale = GetContentScaleFactor();
388 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
392 wxEVT_QT_PINCHGESTURE,
393 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
396 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
401 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
403 onGestureFinishTimerEvent,
407 ZOOM_TIMER, wxEVT_TIMER,
408 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
411 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
412 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
413 zoomTimer.SetOwner(
this, ZOOM_TIMER);
415#ifdef USE_ANDROID_GLES2
424#ifdef HAVE_WX_GESTURE_EVENTS
426 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
431 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
433 onGestureFinishTimerEvent,
437 ZOOM_TIMER, wxEVT_TIMER,
438 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
441 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
442 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
443 zoomTimer.SetOwner(
this, ZOOM_TIMER);
448 m_bgestureGuard =
false;
449 m_total_zoom_val = 1.0;
450 m_step_zoom_val = 1.0;
453#ifdef HAVE_WX_GESTURE_EVENTS
454 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
455 wxLogError(
"Failed to enable touch events");
464 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
466 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
467 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
469 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
470 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
472 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
473 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
475 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
476 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
482glChartCanvas::~glChartCanvas() {
488int glChartCanvas::GetCanvasIndex() {
return m_pParentCanvas->m_canvasIndex; }
490void glChartCanvas::FlushFBO() {
491 if (m_bsetup) BuildFBO();
494void glChartCanvas::OnActivate(wxActivateEvent &event) {
495 m_pParentCanvas->OnActivate(event);
498void glChartCanvas::OnSize(wxSizeEvent &event) {
502 wxLogMessage(
"Got OnSize event while NOT running");
504 qDebug() <<
"OnSizeB";
511 if (!IsShown() || !m_bsetup)
return;
513 SetCurrent(*m_pcontext);
517 SetSize(GetSize().x, GetSize().y);
525 if (m_pcontext && IsShown()) {
526 SetCurrent(*m_pcontext);
531 wxLogDebug(
"BuildFBO 3");
535 ViewPort *vp = m_pParentCanvas->GetpVP();
538 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
541 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
545void glChartCanvas::MouseEvent(wxMouseEvent &event) {
546 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
552 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
554 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
557 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
561 if (m_bgestureGuard) {
562 m_pParentCanvas->r_rband.x = 0;
572 if (event.LeftUp()) {
574 if ((abs(panx) > 2) || (abs(pany) > 2)) {
577 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
584 if (!event.LeftDClick()) {
589 if (m_binPan && event.RightDown()) {
590 qDebug() <<
"Skip right on pan";
593 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
595 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
596 if (!m_bgestureGuard)
606#ifndef GL_MAX_RENDERBUFFER_SIZE
607#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
610#ifndef USE_ANDROID_GLES2
611bool glChartCanvas::buildFBOSize(
int fboSize) {
613 if (IsShown()) SetCurrent(*m_pcontext);
616 glDeleteTextures(2, m_cache_tex);
617 glDeleteFramebuffers(1, &m_fb0);
618 glDeleteRenderbuffers(1, &m_renderbuffer);
619 m_b_BuiltFBO =
false;
622 if (m_b_DisableFBO)
return false;
626 int rb_x = GetSize().x;
627 int rb_y = GetSize().y;
629 while (i < rb_x) i <<= 1;
633 while (i < rb_y) i <<= 1;
636 m_cache_tex_x = wxMax(rb_x, rb_y);
637 m_cache_tex_y = wxMax(rb_x, rb_y);
640 m_cache_tex_x = GetSize().x * m_displayScale;
641 m_cache_tex_y = GetSize().y * m_displayScale;
644 int err = GL_NO_ERROR;
646 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
649 if (err == GL_INVALID_ENUM) {
650 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
654 if (err == GL_NO_ERROR) {
655 if (fboSize > params) {
657 " OpenGL-> Requested Framebuffer size exceeds "
658 "GL_MAX_RENDERBUFFER_SIZE");
663 glGenFramebuffers(1, &m_fb0);
667 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
672 glGenRenderbuffers(1, &m_renderbuffer);
676 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
681 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
685 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
691 glGenTextures(2, m_cache_tex);
692 for (
int i = 0; i < 2; i++) {
693 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
694 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
696 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
698 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
699 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
702 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
704 if (m_b_useFBOStencil) {
706 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
707 m_cache_tex_x, m_cache_tex_y);
709 int err = glGetError();
712 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
716 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
717 GL_RENDERBUFFER_EXT, m_renderbuffer);
721 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
726 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
727 GL_RENDERBUFFER_EXT, m_renderbuffer);
731 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
737 GLenum depth_format = GL_DEPTH_COMPONENT24;
742 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
746 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
748 int err = glGetError();
751 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
757 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
758 GL_RENDERBUFFER_EXT, m_renderbuffer);
763 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
770 glBindTexture(GL_TEXTURE_2D, 0);
771 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
774 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
776 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
777 g_texture_rectangle_format, m_cache_tex[0], 0);
779 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
781 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
783 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
785 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
795#ifdef USE_ANDROID_GLES2
796bool glChartCanvas::buildFBOSize(
int fboSize) {
800 int rb_x = GetSize().x;
801 int rb_y = GetSize().y;
803 while (i < rb_x) i <<= 1;
807 while (i < rb_y) i <<= 1;
810 m_cache_tex_x = wxMax(rb_x, rb_y);
811 m_cache_tex_y = wxMax(rb_x, rb_y);
815 int err = GL_NO_ERROR;
817 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
820 if (err == GL_INVALID_ENUM) {
821 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
825 if (err == GL_NO_ERROR) {
826 if (fboSize > params) {
828 " OpenGL-> Requested Framebuffer size exceeds "
829 "GL_MAX_RENDERBUFFER_SIZE");
834 glGenFramebuffers(1, &m_fb0);
838 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
843 glGenRenderbuffers(1, &m_renderbuffer);
847 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
852 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
856 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
862 glGenTextures(2, m_cache_tex);
863 for (
int i = 0; i < 2; i++) {
864 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
865 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
867 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
869 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
870 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
873 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
876 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
882 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
886 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
887 GL_RENDERBUFFER, m_renderbuffer);
891 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
896 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
897 GL_RENDERBUFFER, m_renderbuffer);
901 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
906 glBindTexture(GL_TEXTURE_2D, 0);
907 glBindFramebuffer(GL_FRAMEBUFFER, 0);
910 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
912 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
913 g_texture_rectangle_format, m_cache_tex[0], 0);
915 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
917 glBindFramebuffer(GL_FRAMEBUFFER, 0);
919 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
921 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
931void glChartCanvas::BuildFBO() {
934 glDeleteTextures(2, m_cache_tex);
935 glDeleteFramebuffers(1, &m_fb0);
936 glDeleteRenderbuffers(1, &m_renderbuffer);
937 m_b_BuiltFBO =
false;
940 if (m_b_DisableFBO)
return;
943 int gl_width, gl_height;
944 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
945 int initialSize = NextPow2(gl_width * m_displayScale);
950 wxString info = androidGetDeviceInfo();
952 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
955 if (!buildFBOSize(initialSize)) {
956 glDeleteTextures(2, m_cache_tex);
957 glDeleteFramebuffers(1, &m_fb0);
958 glDeleteRenderbuffers(1, &m_renderbuffer);
960 if (!buildFBOSize(1024)) {
961 wxLogMessage(
"BuildFBO C");
963 m_b_DisableFBO =
true;
964 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
965 m_b_BuiltFBO =
false;
974 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
986void glChartCanvas::SetupOpenGL() {
987 if (IsShown()) SetCurrent(*m_pcontext);
989 char *str = (
char *)glGetString(GL_RENDERER);
992 wxLogMessage(
"Failed to initialize OpenGL");
996 char render_string[80];
997 strncpy(render_string, str, 79);
998 m_renderer = wxString(render_string, wxConvUTF8);
1001 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1002 msg.Printf(
"OpenGL-> Renderer String: ");
1006 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1008 char version_string[80];
1009 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1010 msg.Printf(
"OpenGL-> Version reported: ");
1011 m_version = wxString(version_string, wxConvUTF8);
1015 char GLSL_version_string[80];
1016 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1018 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1019 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1020 msg += m_GLSLversion;
1025 GLenum err = glewInit();
1026#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1027 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1032 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1035 wxLogMessage(
"GLEW init success!n");
1040 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1041 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1045#ifndef USE_ANDROID_GLES2
1046 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1048 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1050 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1051 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1058 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1060 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1062 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1065 s_b_useScissorTest =
true;
1067 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1068 s_b_useScissorTest =
false;
1070 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1071 s_b_useScissorTest =
false;
1073 bool bad_stencil_code =
false;
1076 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1077 bad_stencil_code =
true;
1080 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1083 glEnable(GL_STENCIL_TEST);
1084 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1086 glGetIntegerv(GL_STENCIL_BITS, &sb);
1089 glDisable(GL_STENCIL_TEST);
1091 s_b_useStencil =
false;
1092 if (stencil && (sb == 8)) s_b_useStencil =
true;
1094 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1095 g_texture_rectangle_format = GL_TEXTURE_2D;
1096 else if (QueryExtension(
"GL_OES_texture_npot"))
1097 g_texture_rectangle_format = GL_TEXTURE_2D;
1098 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1099 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1100 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1101 g_texture_rectangle_format));
1104 g_texture_rectangle_format = GL_TEXTURE_2D;
1108 g_b_EnableVBO =
true;
1111 g_b_EnableVBO =
false;
1115 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1117 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1121 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1123 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1126#ifndef USE_ANDROID_GLES2
1128 if (bad_stencil_code) s_b_useStencil =
false;
1142 if (m_displayScale > 1) m_b_DisableFBO =
true;
1151 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1153 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1154 g_texture_rectangle_format, m_cache_tex[0], 0);
1156 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1157 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1159 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1161 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1163 m_b_DisableFBO =
true;
1169 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1173 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1175#ifdef USE_ANDROID_GLES2
1176 s_b_useStencilAP = s_b_useStencil;
1183 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1185 if (m_b_useFBOStencil)
1186 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1188 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1190 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1193 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1195 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1197 if (s_b_useScissorTest && s_b_useStencil)
1198 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1201 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1203 MipMap_ResolveRoutines();
1207 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1208 g_GLMinCartographicLineWidth);
1209 wxLogMessage(lwmsg);
1210 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1211 g_GLMinSymbolLineWidth);
1212 wxLogMessage(lwmsg);
1215 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1217#ifdef USE_ANDROID_GLES2
1218 g_GLOptions.m_bUseAcceleratedPanning =
true;
1224 int tex_dim = g_GLOptions.m_iTextureDimension;
1225 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1234 s_b_useFBO = m_b_BuiltFBO;
1238 ps52plib->SetGLOptions(
1239 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1240 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1241 g_GLMinSymbolLineWidth);
1245 SendJSONConfigMessage();
1248void glChartCanvas::SendJSONConfigMessage() {
1251 v[
"setupComplete"] = m_bsetup;
1252 v[
"useStencil"] = s_b_useStencil;
1253 v[
"useStencilAP"] = s_b_useStencilAP;
1254 v[
"useScissorTest"] = s_b_useScissorTest;
1255 v[
"useFBO"] = s_b_useFBO;
1256 v[
"useVBO"] = g_b_EnableVBO;
1257 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1258 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1259 SendJSONMessageToAllPlugins(msg_id, v);
1262void glChartCanvas::SetupCompression() {
1263 int dim = g_GLOptions.m_iTextureDimension;
1266 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1267 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1268 goto no_compression;
1272 g_uncompressed_tile_size = dim * dim * 4;
1273 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1279 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1282 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1292 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1293 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1296 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1297 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1302 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1303 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1306 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1308 wxLogMessage(
"OpenGL-> No Useable compression format found");
1309 goto no_compression;
1314 g_tile_size = 512 * 512 / 2;
1318 glGenTextures(1, &texture);
1319 glBindTexture(GL_TEXTURE_2D, texture);
1321 GL_UNSIGNED_BYTE, NULL);
1322 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1324 glDeleteTextures(1, &texture);
1328 if (g_tile_size == 0)
goto no_compression;
1330 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1332 g_uncompressed_tile_size / g_tile_size));
1336 g_GLOptions.m_bTextureCompression =
false;
1338 g_tile_size = g_uncompressed_tile_size;
1339 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1342void glChartCanvas::OnPaint(wxPaintEvent &event) {
1344 if (!m_pcontext)
return;
1353 if (IsShown()) SetCurrent(*m_pcontext);
1358 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1366 if (!m_b_paint_enable)
return;
1369 if (m_in_glpaint)
return;
1372 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1395bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1397#ifndef USE_ANDROID_GLES2
1398 return vp.m_projection_type == PROJECTION_MERCATOR ||
1399 vp.m_projection_type == PROJECTION_POLAR ||
1400 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1414#define NORM_FACTOR 4096.0
1415void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1416#ifndef USE_ANDROID_GLES2
1418 wxPoint2DDouble point;
1420 switch (vp.m_projection_type) {
1421 case PROJECTION_MERCATOR:
1422 case PROJECTION_EQUIRECTANGULAR:
1423 case PROJECTION_WEB_MERCATOR:
1426 glTranslated(point.m_x, point.m_y, 0);
1431 case PROJECTION_POLAR:
1435 glTranslated(point.m_x, point.m_y, 0);
1436 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1443 printf(
"ERROR: Unhandled projection\n");
1448 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1456 switch (vp.m_projection_type) {
1457 case PROJECTION_MERCATOR:
1458 case PROJECTION_EQUIRECTANGULAR:
1459 case PROJECTION_WEB_MERCATOR:
1463 case PROJECTION_POLAR:
1468 printf(
"ERROR: Unhandled projection\n");
1477bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1478 return vp.m_projection_type == PROJECTION_MERCATOR ||
1479 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1480 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1484 const LLRegion ®ion) {
1485 if (!CanClipViewport(vp))
return vp;
1488 LLBBox bbox = region.GetBox();
1490 if (!bbox.GetValid())
return vp;
1498 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1499 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1500 bbox.GetMaxLon() + 360);
1501 cvp.SetBBoxDirect(bbox);
1502 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1503 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1504 bbox.GetMaxLon() - 360);
1505 cvp.SetBBoxDirect(bbox);
1507 cvp.SetBBoxDirect(bbox);
1512void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1513 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1519 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1521 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1525 if (!pRouteDraw)
continue;
1528 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1531 if (pRouteDraw->m_bIsBeingEdited)
continue;
1533 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1538 if (vp.GetBBox().GetValid() && pWayPointMan) {
1539 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1540 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1541 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1547void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1552 if (pActiveTrack && pActiveTrack->IsRunning())
1553 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1559 if (!pRouteDraw)
continue;
1562 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1565 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1568 if (pRouteDraw->IsSelected()) drawit++;
1571 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1572 if (!vp_box.IntersectOut(test_box))
1573 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1579 if (vp.GetBBox().GetValid() && pWayPointMan) {
1580 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1581 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1588static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1592 switch (vp.m_projection_type) {
1593 case PROJECTION_TRANSVERSE_MERCATOR:
1594 lat_dist = 4, lon_dist = 1;
1596 case PROJECTION_POLYCONIC:
1597 lat_dist = 2, lon_dist = 1;
1599 case PROJECTION_ORTHOGRAPHIC:
1600 lat_dist = 2, lon_dist = 2;
1602 case PROJECTION_POLAR:
1603 lat_dist = 180, lon_dist = 1;
1605 case PROJECTION_STEREOGRAPHIC:
1606 case PROJECTION_GNOMONIC:
1607 lat_dist = 2, lon_dist = 1;
1609 case PROJECTION_EQUIRECTANGULAR:
1612 lat_dist = 2, lon_dist = 360;
1615 lat_dist = 180, lon_dist = 360;
1619void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1620 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1626 ChartData->GetDBBoundingBox(dbIndex, box);
1627 if (!box.GetValid())
return;
1631 if (box.GetLonRange() == 360)
return;
1633 LLBBox vpbox = vp.GetBBox();
1635 double lon_bias = 0;
1637 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1640 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1641 color = GetGlobalColor(
"YELO1");
1642 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1643 color = GetGlobalColor(
"GREEN2");
1645 color = GetGlobalColor(
"UINFR");
1647#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1648 float plylat, plylon;
1650 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1652 glColor3ub(color.Red(), color.Green(), color.Blue());
1653 glLineWidth(g_GLMinSymbolLineWidth);
1655 float lat_dist, lon_dist;
1656 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1659 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1663 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1665 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1667 bool begin =
false, sml_valid =
false;
1669 float lastplylat = 0.0;
1670 float lastplylon = 0.0;
1672 int modulo = (nPly == 0) ? 1 : nPly;
1673 for (
int i = 0; i < nPly + 1; i++) {
1675 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1677 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1681 if (lastplylon - plylon > 180)
1683 else if (lastplylon - plylon < -180)
1690 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1691 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1692 splits = wxMax(lat_splits, lon_splits) + 1;
1699 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1700 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1703 for (
double c = 0; c < splits; c++) {
1705 if (c == splits - 1)
1706 lat = plylat, lon = plylon;
1708 double d = (double)(c + 1) / splits;
1709 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1715 if (!std::isnan(s.m_x)) {
1718 glBegin(GL_LINE_STRIP);
1720 glVertex2f(s.m_x, s.m_y);
1726 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1727 lastplylat = plylat, lastplylon = plylon;
1732 }
while (++j < nAuxPlyEntries);
1734 glDisable(GL_LINE_SMOOTH);
1738 double nominal_line_width_pix =
1739 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1741 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1742 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1745 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1746 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1750 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1753 float plylat1, plylon1;
1757 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1758 if (0 == nAuxPlyEntries)
1761 std::vector<int> points_vector;
1763 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1764 int nPly = vec.size() / 2;
1766 if (nPly == 0)
return;
1768 for (
int i = 0; i < nPly; i++) {
1769 plylon1 = vec[i * 2];
1770 plylat1 = vec[i * 2 + 1];
1776 points_vector.push_back(pixx1);
1777 points_vector.push_back(pixy1);
1780 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1781 plylon1 += lon_bias;
1787 points_vector.push_back(pixx1);
1788 points_vector.push_back(pixy1);
1790 if (points_vector.size()) {
1791 std::vector<int>::iterator it = points_vector.begin();
1792 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1800 for (
int j = 0; j < nAuxPlyEntries; j++) {
1801 std::vector<int> points_vector;
1803 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1804 int nAuxPly = vec.size() / 2;
1806 if (nAuxPly == 0)
continue;
1808 for (
int i = 0; i < nAuxPly; i++) {
1809 plylon1 = vec[i * 2];
1810 plylat1 = vec[i * 2 + 1];
1816 points_vector.push_back(pixx1);
1817 points_vector.push_back(pixy1);
1824 points_vector.push_back(pixx1);
1825 points_vector.push_back(pixy1);
1827 if (points_vector.size()) {
1828 std::vector<int>::iterator it = points_vector.begin();
1829 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1837extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1838 float &MinorSpacing);
1839extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1840void glChartCanvas::GridDraw() {
1841 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1843 ViewPort &vp = m_pParentCanvas->GetVP();
1845 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1849 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1851 double nlat, elon, slat, wlon;
1853 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1856 wxColour GridColor = GetGlobalColor(
"SNDG1");
1858 if (!m_gridfont.IsBuilt()) {
1860 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1861 wxFont font = *dFont;
1862 int font_size = wxMax(10, dFont->GetPointSize());
1863 font.SetPointSize(font_size * m_displayScale);
1864 font.SetWeight(wxFONTWEIGHT_NORMAL);
1867 m_gridfont.Build(font, 1, dpi_factor);
1869 m_gridfont.SetColor(GridColor);
1874 LLBBox llbbox = vp.GetBBox();
1875 nlat = llbbox.GetMaxLat();
1876 slat = llbbox.GetMinLat();
1877 elon = llbbox.GetMaxLon();
1878 wlon = llbbox.GetMinLon();
1885 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1886 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1887 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1888 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1889 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1890 vp.m_projection_type == PROJECTION_POLAR ||
1891 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1894 if (straight_latitudes)
1897 latmargin = gridlatMajor / 2;
1899 slat = wxMax(slat, -90 + latmargin);
1900 nlat = wxMin(nlat, 90 - latmargin);
1902 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1903 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1907 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1914 float lon_step = elon - wlon;
1915 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1917 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1919 s.x = INVALID_COORD;
1920 s.y = INVALID_COORD;
1921 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1923 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1924 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1932 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1933 lat += gridlatMinor) {
1936 gldc.DrawLine(0, r.y, 10, r.y,
true);
1937 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1942 float lat_step = nlat - slat;
1943 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1945 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1947 s.x = INVALID_COORD;
1948 s.y = INVALID_COORD;
1949 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1951 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1952 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1960 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1961 lon += gridlonMinor) {
1964 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1965 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1971 glEnable(GL_TEXTURE_2D);
1973 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1974 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1977 CalcGridText(lat, gridlatMajor,
true);
1979 m_gridfont.GetTextExtent(st, 0, &iy);
1981 if (straight_latitudes) {
1986 float x = 0, y = -1;
1987 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1988 if (y < 0 || y > h) {
1990 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1993 m_gridfont.RenderString(st, x, y);
1997 double y1, y2, lat1, lon1, lat2, lon2;
2006 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2009 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2011 if (fabs(y - y1) < fabs(y - y2))
2017 error = fabs(r.m_x);
2018 if (--maxiters == 0)
break;
2019 }
while (error > 1 && error < lasterror);
2021 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2027 m_gridfont.RenderString(st, r.m_x, r.m_y);
2031 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2032 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2041 else if (xlon <= -180.0)
2044 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2046 m_gridfont.GetTextExtent(st, &ix, 0);
2048 if (straight_longitudes) {
2049 float x = -1, y = 0;
2050 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2051 if (x < 0 || x > w) {
2053 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2056 m_gridfont.RenderString(st, x, y);
2060 double x1, x2, lat1, lon1, lat2, lon2;
2068 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2071 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2073 if (fabs(x - x1) < fabs(x - x2))
2079 error = fabs(r.m_y);
2080 }
while (error > 1 && error < lasterror);
2082 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2087 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2089 m_gridfont.RenderString(st, r.m_x, r.m_y);
2093 glDisable(GL_TEXTURE_2D);
2094 glDisable(GL_BLEND);
2099 if (!emboss)
return;
2101 int w = emboss->width, h = emboss->height;
2103 glEnable(GL_TEXTURE_2D);
2106 if (!emboss->gltexind) {
2108 emboss->glwidth = NextPow2(emboss->width);
2109 emboss->glheight = NextPow2(emboss->height);
2112 int size = emboss->glwidth * emboss->glheight;
2113 char *data =
new char[2 * size];
2114 for (
int i = 0; i < h; i++) {
2115 for (
int j = 0; j < emboss->glwidth; j++) {
2117 data[2 * ((i * emboss->glwidth) + j)] =
2118 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2119 data[2 * ((i * emboss->glwidth) + j) + 1] =
2120 (char)abs((emboss->pmap[(i * w) + j]));
2125 glGenTextures(1, &emboss->gltexind);
2126 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2127 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2128 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2136 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2140 int x = emboss->x, y = emboss->y;
2142 float wp = (float)w / emboss->glwidth;
2143 float hp = (float)h / emboss->glheight;
2169 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2171 glDisable(GL_BLEND);
2172 glDisable(GL_TEXTURE_2D);
2175void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2176 if (!m_pParentCanvas->GetVP().IsValid())
return;
2177 wxPoint GPSOffsetPixels(0, 0);
2178 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2181 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2182 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2186 double shift_dx = 0;
2187 double shift_dy = 0;
2188 bool dynamic = m_pParentCanvas->m_animationActive ||
2189 m_pParentCanvas->m_MouseDragging ||
2190 m_pParentCanvas->m_chart_drag_inertia_active;
2191 if (m_pParentCanvas->m_bFollow && !dynamic) {
2192 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2193 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2194 if (m_pParentCanvas->m_bLookAhead) {
2200 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2201 angle += m_pParentCanvas->GetVPRotation();
2202 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2204 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2205 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2207 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2212 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2213 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2220 lShipMidPoint = lGPSPoint;
2224 float icon_hdt = pCog;
2225 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2228 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2232 double osd_head_lat, osd_head_lon;
2233 wxPoint2DDouble osd_head_point;
2235 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2239 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2241 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2242 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2243 icon_rad += (float)PI;
2247 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2251 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2257 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2258 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2259 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2264 float scale_factor = 1.0;
2269 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2270 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2271 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2273 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2275 float nominal_ownship_size_pixels =
2277 nominal_ownship_size_mm);
2279 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2281 wxPen ppSmallScaleShip;
2282 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2284 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2287 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2288 dc.SetPen(ppSmallScaleShip);
2290 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2293 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2294 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2295 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2296 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2299 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2300 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2303 int draw_color = SHIP_INVALID;
2304 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2305 draw_color = SHIP_NORMAL;
2306 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2307 draw_color = SHIP_LOWACCURACY;
2315 ownship_color = draw_color;
2317 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2319 glGenTextures(1, &ownship_tex);
2320 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2326 if (m_pParentCanvas->m_pos_image_user) {
2327 switch (draw_color) {
2329 image = *m_pParentCanvas->m_pos_image_user_grey;
2332 image = *m_pParentCanvas->m_pos_image_user;
2334 case SHIP_LOWACCURACY:
2335 image = *m_pParentCanvas->m_pos_image_user_yellow;
2339 switch (draw_color) {
2341 image = *m_pParentCanvas->m_pos_image_grey;
2344 image = *m_pParentCanvas->m_pos_image_red;
2346 case SHIP_LOWACCURACY:
2347 image = *m_pParentCanvas->m_pos_image_yellow;
2352 int w = image.GetWidth(), h = image.GetHeight();
2353 int glw = NextPow2(w), glh = NextPow2(h);
2354 ownship_size = wxSize(w, h);
2355 ownship_tex_size = wxSize(glw, glh);
2357 unsigned char *d = image.GetData();
2358 unsigned char *a = image.GetAlpha();
2359 unsigned char *e =
new unsigned char[4 * w * h];
2362 for (
int p = 0; p < w * h; p++) {
2363 e[4 * p + 0] = d[3 * p + 0];
2364 e[4 * p + 1] = d[3 * p + 1];
2365 e[4 * p + 2] = d[3 * p + 2];
2366 e[4 * p + 3] = a[p];
2369 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2370 GL_UNSIGNED_BYTE, 0);
2372 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2378#ifndef USE_ANDROID_GLES2
2379 if (m_pParentCanvas->m_pos_image_user)
2380 glColor4ub(255, 255, 255, 255);
2381 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2382 glColor4ub(255, 0, 0, 255);
2383 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2384 glColor4ub(255, 255, 0, 255);
2386 glColor4ub(128, 128, 128, 255);
2388 float scale_factor_y = 1.0;
2389 float scale_factor_x = 1.0;
2391 int ownShipWidth = 22;
2392 int ownShipLength = 84;
2393 lShipMidPoint = lGPSPoint;
2396 if (g_OwnShipIconType != 0)
2397 m_pParentCanvas->ComputeShipScaleFactor(
2398 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2399 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2404 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2405 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2406 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2410 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2411 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2415 float gps_circle_radius = 3.0;
2417 if (g_OwnShipIconType == 0) {
2419 glEnable(GL_TEXTURE_2D);
2420 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2429 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2430 if (m_pParentCanvas->m_pos_image_user)
2431 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2433 float nominal_ownship_size_mm =
2434 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2436 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2437 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2439 float nominal_ownship_size_pixels =
2440 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2442 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2443 nominal_ownship_size_pixels = wxMax(
2444 20.0, nominal_ownship_size_pixels);
2447 float h = nominal_ownship_size_pixels * scale_factor_y;
2448 float w = nominal_ownship_size_pixels * scale_factor_x *
2449 ownship_size.x / ownship_size.y;
2450 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2451 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2457 gps_circle_radius = w / 5;
2459 float uv[8], coords[8];
2478 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2479 lShipMidPoint.m_x, lShipMidPoint.m_y,
2481 glDisable(GL_TEXTURE_2D);
2482 }
else if (g_OwnShipIconType == 1) {
2484 glEnable(GL_TEXTURE_2D);
2485 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2487 float nominal_ownship_size_pixels_y = 84;
2488 float nominal_ownship_size_pixels_x = 22;
2490 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2491 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2493 float u = (float)ownship_size.x / ownship_tex_size.x,
2494 v = (
float)ownship_size.y / ownship_tex_size.y;
2497 gps_circle_radius = w / 5;
2499 float uv[8], coords[8];
2518 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2519 lShipMidPoint.m_x, lShipMidPoint.m_y,
2522 glDisable(GL_TEXTURE_2D);
2523 }
else if (g_OwnShipIconType == 2) {
2531 wxPoint shipPoints[6];
2533 wxColour colour = m_pParentCanvas->ShipColor();
2534 wxPen ppPen(*wxBLACK, 1);
2535 wxBrush ppBrush(colour);
2537 dc.SetBrush(ppBrush);
2539 shipPoints[0].x = 0 * scale_factor_x;
2540 shipPoints[0].y = -28 * scale_factor_y;
2541 shipPoints[1].x = 11 * scale_factor_x;
2542 shipPoints[1].y = -28 * scale_factor_y;
2543 shipPoints[2].x = 11 * scale_factor_x;
2544 shipPoints[2].y = 42 * scale_factor_y;
2545 shipPoints[3].x = 0 * scale_factor_x;
2546 shipPoints[3].y = 42 * scale_factor_y;
2547 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2550 shipPoints[0].x = 0 * scale_factor_x;
2551 shipPoints[0].y = -42 * scale_factor_y;
2552 shipPoints[1].x = 5 * scale_factor_x;
2553 shipPoints[1].y = -42 * scale_factor_y;
2554 shipPoints[2].x = 11 * scale_factor_x;
2555 shipPoints[2].y = -28 * scale_factor_y;
2556 shipPoints[3].x = 0 * scale_factor_x;
2557 shipPoints[3].y = -28 * scale_factor_y;
2558 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2561 shipPoints[0].x = 0 * scale_factor_x;
2562 shipPoints[0].y = -28 * scale_factor_y;
2563 shipPoints[1].x = -11 * scale_factor_x;
2564 shipPoints[1].y = -28 * scale_factor_y;
2565 shipPoints[2].x = -11 * scale_factor_x;
2566 shipPoints[2].y = 42 * scale_factor_y;
2567 shipPoints[3].x = 0 * scale_factor_x;
2568 shipPoints[3].y = 42 * scale_factor_y;
2569 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2572 shipPoints[0].x = 0 * scale_factor_x;
2573 shipPoints[0].y = -42 * scale_factor_y;
2574 shipPoints[1].x = -5 * scale_factor_x;
2575 shipPoints[1].y = -42 * scale_factor_y;
2576 shipPoints[2].x = -11 * scale_factor_x;
2577 shipPoints[2].y = -28 * scale_factor_y;
2578 shipPoints[3].x = 0 * scale_factor_x;
2579 shipPoints[3].y = -28 * scale_factor_y;
2580 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2584 double p1x = -11 * scale_factor_x;
2585 double p2x = 11 * scale_factor_x;
2589 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2591 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2593 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2595 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2596 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2597 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2601 p1y = -42 * scale_factor_y;
2602 p2y = 42 * scale_factor_y;
2603 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2604 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2605 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2606 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2607 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2608 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2611 img_height = ownShipLength * scale_factor_y;
2614 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2616 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2618 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2620 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2624 glDisable(GL_LINE_SMOOTH);
2625 glDisable(GL_POLYGON_SMOOTH);
2626 glDisable(GL_BLEND);
2629 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2633void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2634 ViewPort &vp = m_pParentCanvas->GetVP();
2657 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2659 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2660 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2662 m_pParentCanvas->AlertDraw(dc);
2664 m_pParentCanvas->RenderVisibleSectorLights(dc);
2666 m_pParentCanvas->RenderRouteLegs(dc);
2667 m_pParentCanvas->RenderShipToActive(dc,
true);
2668 m_pParentCanvas->ScaleBarDraw(dc);
2669 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2670 m_pParentCanvas->extendedSectorLegs);
2677void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2678 if (m_pParentCanvas->GetPiano()) {
2679 int canvas_height = GetClientSize().y;
2680 canvas_height *= m_displayScale;
2682 m_pParentCanvas->GetPiano()->DrawGL(
2683 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2687void glChartCanvas::DrawQuiting() {
2688#ifndef USE_ANDROID_GLES2
2689 GLubyte pattern[8][8];
2690 for (
int y = 0; y < 8; y++)
2691 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2694 glEnable(GL_TEXTURE_2D);
2695 glBindTexture(GL_TEXTURE_2D, 0);
2697 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2698 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2699 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2701 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2705 float x = GetSize().x, y = GetSize().y;
2706 float u = x / 8, v = y / 8;
2719 glDisable(GL_TEXTURE_2D);
2720 glDisable(GL_BLEND);
2724void glChartCanvas::DrawCloseMessage(wxString msg) {
2725#ifndef USE_ANDROID_GLES2
2729 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2733 texfont.Build(*pfont, 1, 1);
2735 texfont.GetTextExtent(msg, &w, &h);
2737 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2738 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2740 glColor3ub(243, 229, 47);
2744 glVertex2i(xp + w, yp);
2745 glVertex2i(xp + w, yp + h);
2746 glVertex2i(xp, yp + h);
2751 glColor3ub(0, 0, 0);
2752 glEnable(GL_TEXTURE_2D);
2753 texfont.RenderString(msg, xp, yp);
2754 glDisable(GL_TEXTURE_2D);
2755 glDisable(GL_BLEND);
2762static std::list<double *> combine_work_data;
2763static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2764 GLfloat weight[4], GLdouble **dataOut) {
2765 double *vertex =
new double[3];
2766 combine_work_data.push_back(vertex);
2767 memcpy(vertex, coords, 3 * (
sizeof *coords));
2771#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2772void vertexCallbackD_GLSL(GLvoid *vertex) {
2774 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2775 int new_buf_len = s_tess_buf_len + 100;
2776 GLfloat *tmp = s_tess_work_buf;
2779 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2780 if (NULL == s_tess_work_buf) {
2784 s_tess_buf_len = new_buf_len;
2787 GLdouble *pointer = (GLdouble *)vertex;
2789 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2790 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2795void beginCallbackD_GLSL(GLenum mode) {
2796 s_tess_vertex_idx_this = s_tess_vertex_idx;
2801void endCallbackD_GLSL() {
2805 shader->SetUniformMatrix4fv(
"MVMatrix",
2806 (GLfloat *)s_tessVP.vp_matrix_transform);
2808 mat4x4 identityMatrix;
2809 mat4x4_identity(identityMatrix);
2810 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2814 colorv[0] = s_regionColor.Red() / float(256);
2815 colorv[1] = s_regionColor.Green() / float(256);
2816 colorv[2] = s_regionColor.Blue() / float(256);
2817 colorv[3] = s_regionColor.Alpha() / float(256);
2818 shader->SetUniform4fv(
"color", colorv);
2820 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2821 shader->SetAttributePointerf(
"position", bufPt);
2823 glDrawArrays(s_tess_mode, 0, s_nvertex);
2828void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2830void beginCallbackD(GLenum mode) { glBegin(mode); }
2832void endCallbackD() { glEnd(); }
2836void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2837 float lat_dist, lon_dist;
2838 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2840 GLUtesselator *tobj = gluNewTess();
2841 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2843#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2844 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2845 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2846 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2847 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2851 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2852 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2853 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2854 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2857 gluTessNormal(tobj, 0, 0, 1);
2859 gluTessBeginPolygon(tobj, NULL);
2860 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2861 gluTessBeginContour(tobj);
2862 contour_pt l = *i->rbegin();
2864 bool sml_valid =
false;
2865 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2866 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2867 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2868 int splits = wxMax(lat_splits, lon_splits) + 1;
2874 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2875 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2878 for (
int i = 0; i < splits; i++) {
2880 if (i == splits - 1)
2881 lat = j->y, lon = j->x;
2883 double d = (double)(i + 1) / splits;
2884 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2888 if (std::isnan(q.m_x))
continue;
2890 double *p =
new double[6];
2895 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2900 gluTessVertex(tobj, p, p);
2901 combine_work_data.push_back(p);
2905 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2907 gluTessEndContour(tobj);
2909 gluTessEndPolygon(tobj);
2911 gluDeleteTess(tobj);
2913 for (std::list<double *>::iterator i = combine_work_data.begin();
2914 i != combine_work_data.end(); i++)
2916 combine_work_data.clear();
2921void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2922 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2924 if (s_b_useStencil) {
2926 glEnable(GL_STENCIL_TEST);
2928 glClear(GL_STENCIL_BUFFER_BIT);
2932 glStencilFunc(GL_ALWAYS, 1, 1);
2933 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2936#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2940 glEnable(GL_DEPTH_TEST);
2941 glDepthFunc(GL_ALWAYS);
2942 glDepthMask(GL_TRUE);
2944 glClear(GL_DEPTH_BUFFER_BIT);
2957 glTranslatef(0, 0, .5);
2961 s_regionColor = wxColor(0, 0, 0, 255);
2962 DrawRegion(vp, region);
2964 if (s_b_useStencil) {
2967 glStencilFunc(GL_EQUAL, 1, 1);
2968 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2971#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2973 glDepthFunc(GL_GREATER);
2974 glDepthMask(GL_FALSE);
2975 glTranslatef(0, 0, -.5);
2978 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2981void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2985 if (s_b_useStencil && s_b_useScissorTest) {
2987 if (rect != vp_rect) {
2988 glEnable(GL_SCISSOR_TEST);
2989 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2992#ifndef USE_ANDROID_GLES2
2998void glChartCanvas::DisableClipRegion() {
2999 glDisable(GL_SCISSOR_TEST);
3000 glDisable(GL_STENCIL_TEST);
3001 glDisable(GL_DEPTH_TEST);
3004void glChartCanvas::Invalidate() {
3006 m_cache_vp.Invalidate();
3012 if (!pBSBChart)
return;
3018 wxString key = chart->GetHashKey();
3022 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3025 if (ittf == hash.end()) {
3027 hash[key]->SetHashKey(key);
3030 pTexFact = hash[key];
3031 pTexFact->SetLRUTime(++m_LRUtime);
3036 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3037 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3044 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3045 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3046 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3047 base_level = log(scalefactor) / log(2.0);
3056 glEnable(GL_TEXTURE_2D);
3057#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3058 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3060 glEnableClientState(GL_VERTEX_ARRAY);
3061 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3066 pTexFact->GetCenter(lat, lon);
3067 MultMatrixViewPort(vp, lat, lon);
3071 LLBBox box = region.GetBox();
3074 if (g_memCacheLimit > 0) {
3079 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3080 for (
int i = 0; i < numtiles; i++) {
3082 if (region.IntersectOut(tile->box)) {
3085 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3086 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3088 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3089 global_color_scheme, mem_used);
3093 coords = tile->m_coords;
3095 coords =
new float[2 * tile->m_ncoords];
3096 for (
int i = 0; i < tile->m_ncoords; i++) {
3098 tile->m_coords[2 * i + 1]);
3099 coords[2 * i + 0] = p.m_x;
3100 coords[2 * i + 1] = p.m_y;
3104#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3105 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3106 m_pParentCanvas->GetpVP());
3109 glDisable(GL_TEXTURE_2D);
3113 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3114 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3115 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3117 if (!texture) glEnable(GL_TEXTURE_2D);
3119 if (!use_norm_vp)
delete[] coords;
3123 glDisable(GL_TEXTURE_2D);
3125#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3126 if (use_norm_vp) glPopMatrix();
3128 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3129 glDisableClientState(GL_VERTEX_ARRAY);
3133void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3135 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3136 m_pParentCanvas->m_pQuilt->IsBusy())
3140 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3142 printf(
" Chart NULL\n");
3143 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3153 LLRegion region = vp.GetLLRegion(rect_region);
3155 LLRegion rendered_region;
3161 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3169 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3171 LLRegion get_region = pqp->ActiveRegion;
3172 bool b_rendered =
false;
3174 if (!pqp->b_overlay) {
3175 get_region.Intersect(region);
3176 if (!get_region.Empty()) {
3177 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3180 SetClipRegion(vp, get_region );
3181 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3182 DisableClipRegion();
3185 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3186 SetClipRegion(vp, pqp->ActiveRegion );
3187 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3189 DisableClipRegion();
3192 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3193 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3194 RenderNoDTA(vp, get_region);
3195 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3200 if (Chs57->m_RAZBuilt) {
3201 RenderNoDTA(vp, get_region);
3202 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3203 rect_region, get_region);
3204 DisableClipRegion();
3209 const LLRegion &oregion = get_region;
3210 LLBBox box = oregion.GetBox();
3221 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3224 ViewPort cvp = ClippedViewport(vp, get_region);
3225 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3226 SetClipRegion(cvp, get_region);
3227 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3228 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3229 RenderWorldChart(gldc, cvp, srect, world);
3230 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3231 global_color_scheme);
3232 DisableClipRegion();
3239 SetClipRegion(vp, get_region);
3240 RenderNoDTA(vp, get_region);
3241 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3243 DisableClipRegion();
3246 SetClipRegion(vp, get_region);
3247 RenderNoDTA(vp, get_region);
3248 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3250 DisableClipRegion();
3266 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3270 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3271 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3273 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3274 if (pqp->b_Valid && pqp->b_overlay &&
3275 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3276 LLRegion get_region = pqp->ActiveRegion;
3278 get_region.Intersect(region);
3279 if (!get_region.Empty()) {
3282 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3287 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3294 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3299 ViewPort vph = m_pParentCanvas->GetVP();
3300 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3303 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3305 if (!hiregion.Empty()) {
3309 switch (global_color_scheme) {
3310 case GLOBAL_COLOR_SCHEME_DAY:
3313 case GLOBAL_COLOR_SCHEME_DUSK:
3316 case GLOBAL_COLOR_SCHEME_NIGHT:
3324#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3326 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3328 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3331 DrawRegion(vp, hiregion);
3333 glDisable(GL_BLEND);
3338 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3340 if (!hiregion.Empty()) {
3344 switch (global_color_scheme) {
3345 case GLOBAL_COLOR_SCHEME_DAY:
3348 case GLOBAL_COLOR_SCHEME_DUSK:
3351 case GLOBAL_COLOR_SCHEME_NIGHT:
3360#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3362 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3364 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3367 DrawRegion(vp, hiregion);
3369 glDisable(GL_BLEND);
3373 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3376void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3378 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3379 m_pParentCanvas->m_pQuilt->IsBusy())
3383 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3385 LLRegion region = vp.GetLLRegion(rect_region);
3387 LLRegion rendered_region;
3389 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3391 LLRegion get_region = pqp->ActiveRegion;
3393 if (!pqp->b_overlay) {
3394 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3397 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3402 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3409 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3437void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3438 ViewPort &vp = m_pParentCanvas->VPoint;
3446 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3447 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3450 LLRegion chart_region;
3452 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3453 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3454 CHART_FAMILY_RASTER) {
3462 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3463 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3464 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3466 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3470 for (
int i = 1; i < 6; i += 2)
3471 if (fabs(ll[i] - ll[i + 2]) > 180) {
3473 for (
int i = 1; i < 8; i += 2)
3474 if (ll[i] < 0) ll[i] += 360;
3478 chart_region = LLRegion(4, ll);
3481 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3483 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3484 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3485 chart_region = LLRegion(4, ll);
3488 chart_region = vp.b_quilt
3489 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3490 : m_pParentCanvas->m_singleChart->GetValidRegion();
3492 bool world_view =
false;
3494 wxRect rect = upd.GetRect();
3495 LLRegion background_region = vp.GetLLRegion(rect);
3498 background_region.Subtract(chart_region);
3500 if (!background_region.Empty()) {
3501 ViewPort cvp = ClippedViewport(vp, background_region);
3502 SetClipRect(cvp, rect,
false);
3503 RenderWorldChart(dc, cvp, rect, world_view);
3504 DisableClipRegion();
3509 RenderQuiltViewGL(vp, rect_region);
3512 LLRegion region = vp.GetLLRegion(rect_region);
3513 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3514 CHART_FAMILY_RASTER) {
3515 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3516 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3517 *m_pcontext, vp, rect_region, region);
3519 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3520 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3521 CHART_FAMILY_VECTOR) {
3522 chart_region.Intersect(region);
3523 RenderNoDTA(vp, chart_region);
3524 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3525 rect_region, region);
3531void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3533 wxColour color = GetGlobalColor(
"NODTA");
3534#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3536 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3538 glColor4ub(163, 180, 183, transparency);
3541 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3545 s_regionColor = color;
3548 DrawRegion(vp, region);
3552void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3555 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3557 glEnable(GL_SCISSOR_TEST);
3558 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3564 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3565#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3567 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3571 colorv[0] = water.Red() / float(256);
3572 colorv[1] = water.Green() / float(256);
3573 colorv[2] = water.Blue() / float(256);
3575 shader->SetUniform4fv(
"color", colorv);
3586 shader->SetAttributePointerf(
"position", pf);
3588 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3600 glDisable(GL_SCISSOR_TEST);
3608void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3609 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3611 DrawStaticRoutesTracksAndWaypoints(vp);
3613 DisableClipRegion();
3616void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3618 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3622 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3623 if (!bmp.Ok())
return;
3625 wxImage image = bmp.ConvertToImage();
3626 int w = image.GetWidth(), h = image.GetHeight();
3629 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3630 tex_w = w, tex_h = h;
3632 tex_w = NextPow2(w), tex_h = NextPow2(h);
3634 m_tideTexWidth = tex_w;
3635 m_tideTexHeight = tex_h;
3637 unsigned char *d = image.GetData();
3638 unsigned char *a = image.GetAlpha();
3640 unsigned char mr, mg, mb;
3641 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3643 unsigned char *e =
new unsigned char[4 * w * h];
3645 for (
int y = 0; y < h; y++)
3646 for (
int x = 0; x < w; x++) {
3647 unsigned char r, g, b;
3648 int off = (y * w + x);
3658 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3662 glGenTextures(1, &m_tideTex);
3664 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3666 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3668 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3669 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3670 GL_UNSIGNED_BYTE, e);
3672 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3673 GL_UNSIGNED_BYTE, 0);
3674 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3683 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3684 glEnable(GL_TEXTURE_2D);
3687#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3689 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3693 if ((type ==
't') || (type ==
'T'))
3698 if (BBox.Contains(lat, lon)) {
3707 scale *= getAndroidDisplayDensity();
3709 double width2 =
scale * m_tideTexWidth / 2;
3710 double height2 =
scale * m_tideTexHeight / 2;
3725 coords[0] = xp - width2;
3726 coords[1] = yp - height2;
3727 coords[2] = xp - width2;
3728 coords[3] = yp + height2;
3729 coords[4] = xp + width2;
3730 coords[5] = yp + height2;
3731 coords[6] = xp + width2;
3732 coords[7] = yp - height2;
3734 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3741 glDisable(GL_TEXTURE_2D);
3742 glDisable(GL_BLEND);
3743 glBindTexture(GL_TEXTURE_2D, 0);
3745 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3748void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3749 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3752void glChartCanvas::SetColorScheme(ColorScheme cs) {
3753 if (!m_bsetup)
return;
3755 glDeleteTextures(1, &m_tideTex);
3756 glDeleteTextures(1, &m_currentTex);
3762void glChartCanvas::RenderGLAlertMessage() {
3763 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3764 wxString msg = m_pParentCanvas->GetAlertString();
3767 m_gldc.SetFont(*pfont);
3771 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3778 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3779 int xp = sbr.x + sbr.width + 5;
3781 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3782 m_gldc.SetPen(ppPen1);
3783 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3785 m_gldc.DrawRectangle(xp, yp, w, h);
3787 m_gldc.DrawText(msg, xp, yp);
3791unsigned long quiltHash;
3793extern wxLongLong s_t0;
3796void glChartCanvas::Render() {
3797 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3798 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3799 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3804 if (!g_PrintingInProgress)
return;
3807 if (!g_true_zoom && m_binPinch)
return;
3810 long render_start_time = m_glstopwatch.Time();
3812#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3813 loadShaders(GetCanvasIndex());
3814 configureShaders(m_pParentCanvas->VPoint);
3817#ifdef USE_ANDROID_GLES2
3821 if (m_binPinch)
return;
3830 bool recompose =
false;
3831 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3832 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3833 if (m_pParentCanvas->VPoint.IsValid()) {
3834 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3835 m_pParentCanvas->UpdateCanvasControlBar();
3844 if (sw.GetTime() > 2000) {
3850 s_tess_vertex_idx = 0;
3851 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3852 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3858 m_displayScale = GetContentScaleFactor();
3862 m_last_render_time = wxDateTime::Now().GetTicks();
3866 if (g_GLOptions.m_bTextureCompression &&
3867 !g_GLOptions.m_bTextureCompressionCaching)
3872 int gl_width, gl_height;
3873 gl_width = m_pParentCanvas->VPoint.
pix_width;
3874 gl_height = m_pParentCanvas->VPoint.
pix_height;
3877 m_glcanvas_width = gl_width;
3878 m_glcanvas_height = gl_height;
3882 if (gl_height & 1) {
3884 ViewPort *vp = m_pParentCanvas->GetpVP();
3891 ViewPort *vp = m_pParentCanvas->GetpVP();
3899 ViewPort *vp = m_pParentCanvas->GetpVP();
3902 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3905 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3913 ViewPort VPoint = m_pParentCanvas->VPoint;
3915 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3916 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3919#if !defined(USE_ANDROID_GLES2)
3920 glMatrixMode(GL_PROJECTION);
3923 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3924 glMatrixMode(GL_MODELVIEW);
3928 if (s_b_useStencil) {
3929 glEnable(GL_STENCIL_TEST);
3930 glStencilMask(0xff);
3931 glClear(GL_STENCIL_BUFFER_BIT);
3932 glDisable(GL_STENCIL_TEST);
3938 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3939 if (g_GLOptions.m_GLPolygonSmoothing)
3940 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3941 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3953 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3954 bool useFBO =
false;
3960 if (m_b_BuiltFBO && !bpost_hilite
3965 bool b_newview =
true;
3966 bool b_full =
false;
3974 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3978#ifdef USE_ANDROID_GLES2
3979 if (recompose) b_newview =
true;
3991 if (VPoint.b_quilt) {
3992 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3993 if (!chart) b_full =
true;
4002 bool accelerated_pan =
false;
4012 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4013 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4014 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4016 wxPoint2DDouble c_old =
4019 wxPoint2DDouble c_new =
4023 dy = wxRound(c_new.m_y - c_old.m_y);
4024 dx = wxRound(c_new.m_x - c_old.m_x);
4034 double deltax = c_new.m_x - c_old.m_x;
4035 double deltay = c_new.m_y - c_old.m_y;
4037 bool b_whole_pixel =
true;
4038 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4039 b_whole_pixel =
false;
4041 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4042 abs(dy) < m_cache_tex_y &&
4043 (abs(dx) > 0 || (abs(dy) > 0));
4052 if (m_displayScale > 1) accelerated_pan =
false;
4057 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4060#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4063 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4069 if (b_full) accelerated_pan =
false;
4071 if (accelerated_pan) {
4072 if ((dx != 0) || (dy != 0)) {
4084 if (dy > 0 && dy < gl_height)
4085 update_region.Union(
4086 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4088 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4090 if (dx > 0 && dx < gl_width)
4091 update_region.Union(
4092 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4094 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4096 m_cache_page = !m_cache_page;
4099 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4100 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4112 RenderCharts(m_gldc, update_region);
4116 glDisable(g_texture_rectangle_format);
4121 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4122 glEnable(GL_TEXTURE_2D);
4126 float x1, x2, y1, y2;
4139 float tx1, tx2, ty1, ty2;
4145 tx2 = sx / (float)m_cache_tex_x;
4147 ty2 = sy / (float)m_cache_tex_y;
4164 coords[2] = -dx + sx;
4166 coords[4] = -dx + sx;
4167 coords[5] = dy + sy;
4169 coords[7] = dy + sy;
4172 ptexture_2D_shader_program[GetCanvasIndex()];
4176 shader->SetUniform1i(
"uTex", 0);
4180 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4181 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4182 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4184 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4206 shader->SetAttributePointerf(
"aPos", co1);
4207 shader->SetAttributePointerf(
"aUV", tco1);
4209 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4212 shader->SetUniformMatrix4fv(
"MVMatrix",
4213 (GLfloat *)VPoint.vp_matrix_transform);
4216 glBindTexture(g_texture_rectangle_format, 0);
4218 glDisable(g_texture_rectangle_format);
4226 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4227 g_texture_rectangle_format,
4228 m_cache_tex[!m_cache_page], 0);
4239 wxColour color = GetGlobalColor(
"NODTA");
4240 glClearColor(color.Red() / 256., color.Green() / 256.,
4241 color.Blue() / 256., 1.0);
4242 glClear(GL_COLOR_BUFFER_BIT);
4248 RenderCharts(m_gldc, rscreen_region);
4253 m_cache_page = !m_cache_page;
4258 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4269 glMatrixMode(GL_PROJECTION);
4272 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4273 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4275 glMatrixMode(GL_MODELVIEW);
4279 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4280 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4282 glGetIntegerv(GL_VIEWPORT, viewport);
4283 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4284 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4293 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4294 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4295 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4297 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4301 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4302 glEnable(g_texture_rectangle_format);
4304 float tx, ty, tx0, ty0, divx, divy;
4307 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4310 divx = m_cache_tex_x;
4311 divy = m_cache_tex_y;
4314 tx0 = m_fbo_offsetx / divx;
4315 ty0 = m_fbo_offsety / divy;
4316 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4317 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4342 wxColour color = GetGlobalColor(
"NODTA");
4343 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4345 glClear(GL_COLOR_BUFFER_BIT);
4347 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4350 glDisable(g_texture_rectangle_format);
4352 m_cache_vp = VPoint;
4353 m_cache_vp.Validate();
4355 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4357 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4361 RenderCharts(m_gldc, screen_region);
4370 RenderS57TextOverlay(VPoint);
4371 RenderMBTilesOverlay(VPoint);
4377 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4382 wxRect rt = upd.GetRect();
4383 LLRegion region = VPoint.GetLLRegion(rt);
4384 ViewPort cvp = ClippedViewport(VPoint, region);
4385 DrawGroundedOverlayObjects(gldc, cvp);
4388 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4389 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4390 LLBBox screenBox = screenLLRegion.GetBox();
4392 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4395 if (m_pParentCanvas->m_bShowTide) {
4396 m_pParentCanvas->RebuildTideSelectList(screenBox);
4397 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4400 if (m_pParentCanvas->m_bShowCurrent) {
4401 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4402 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4408 if (m_pParentCanvas->m_show_focus_bar &&
4409 (g_canvasConfig != 0)) {
4410 if (m_pParentCanvas == wxWindow::FindFocus()) {
4413 wxColour colour = GetGlobalColor(
"BLUE4");
4414 wxPen ppBlue(colour, 1);
4415 wxBrush ppBrush(colour);
4416 gldc.SetPen(ppBlue);
4417 gldc.SetBrush(ppBrush);
4418 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4419 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4420 wxPoint barPoints[4];
4423 barPoints[1].x = xw;
4425 barPoints[2].x = xw;
4426 barPoints[2].y = rect_pix;
4428 barPoints[3].y = rect_pix;
4430 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4434 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4438 DrawFloatingOverlayObjects(m_gldc);
4440#ifndef USE_ANDROID_GLES2
4443 glMatrixMode(GL_PROJECTION);
4446 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4447 glMatrixMode(GL_MODELVIEW);
4452 if (!g_bhide_depth_units)
4453 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4454 if (!g_bhide_overzoom_flag)
4455 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4458 ViewPort &vp = m_pParentCanvas->GetVP();
4463 if (!g_PrintingInProgress) {
4464 if (m_pParentCanvas->m_pTrackRolloverWin)
4465 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4467 if (m_pParentCanvas->m_pRouteRolloverWin)
4468 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4470 if (m_pParentCanvas->m_pAISRolloverWin)
4471 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4473 if (m_pParentCanvas->GetMUIBar())
4474 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4488 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4489 int x, y, width, height;
4490 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4491 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4492 wxBitmap bmp(width, height, -1);
4495 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4498 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4499 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4503 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4504 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4506 wxStringTokenizer tkz(s,
"\n");
4509 while (tkz.HasMoreTokens()) {
4510 token = tkz.GetNextToken();
4511 dc.DrawText(token, xt, yt);
4514 dc.SelectObject(wxNullBitmap);
4516 m_gldc.DrawBitmap(bmp, x, y,
false);
4522 if (g_bShowChartBar) DrawChartBar(m_gldc);
4524 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4526 m_pParentCanvas->m_Compass->Paint(gldc);
4528 if (m_pParentCanvas->IsPrimaryCanvas()) {
4529 auto ¬eman = NotificationManager::GetInstance();
4530 if (noteman.GetNotificationCount()) {
4531 m_pParentCanvas->m_notification_button->SetIconSeverity(
4532 noteman.GetMaxSeverity());
4533 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4534 m_pParentCanvas->m_notification_button->Show(
true);
4535 m_pParentCanvas->m_notification_button->Paint(gldc);
4537 m_pParentCanvas->m_notification_button->Show(
false);
4540 RenderGLAlertMessage();
4543 ViewPort &vp = m_pParentCanvas->GetVP();
4547 glActiveTexture(GL_TEXTURE0);
4551 if (g_bquiting) DrawQuiting();
4552 if (g_bcompression_wait)
4553 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4558 if (g_b_needFinish) glFinish();
4565 m_pParentCanvas->PaintCleanup();
4566 m_bforcefull =
false;
4575void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4578 if (VPoint.b_quilt) {
4579 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4580 ps52plib->GetShowS57Text()) {
4581 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4582 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4587 ChPI->ClearPLIBTextList();
4589 ps52plib->ClearTextList();
4599 RenderQuiltViewGLText(vpx, screen_region);
4604void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4607 LLRegion &screenLLRegion) {
4612 if (chart == NULL)
return;
4619 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4621 wxFileName tileFile(chart->GetFullPath());
4623 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4625 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4626 (tileSizeMB.GetLo() > 5000)) {
4629 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4630 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4631 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4638 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4642 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4645 std::vector<int> piano_active_array_tiles =
4646 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4647 bool bfound =
false;
4649 if (std::find(piano_active_array_tiles.begin(),
4650 piano_active_array_tiles.end(),
4651 dbIndex) != piano_active_array_tiles.end()) {
4656 piano_active_array_tiles.push_back(dbIndex);
4657 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4661void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4663 std::vector<int> stackIndexArray =
4664 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4665 unsigned int im = stackIndexArray.size();
4668 if (VPoint.b_quilt && im > 0) {
4669 bool regionVPBuilt =
false;
4671 LLRegion screenLLRegion;
4675 std::vector<int> tiles_to_show;
4676 for (
unsigned int is = 0; is < im; is++) {
4678 ChartData->GetChartTableEntry(stackIndexArray[is]);
4679 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4680 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4682 std::vector<int> piano_active_array_tiles =
4683 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4684 bool bfound =
false;
4686 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4687 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4688 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4696 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4697 piano_active_array_tiles);
4702 tiles_to_show.push_back(stackIndexArray[is]);
4703 if (!regionVPBuilt) {
4706 screenLLRegion = VPoint.GetLLRegion(screen_region);
4707 screenBox = screenLLRegion.GetBox();
4715 regionVPBuilt =
true;
4725 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4726 rit != tiles_to_show.rend(); ++rit) {
4727 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4729 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4730 rit != tiles_to_show.rend(); ++rit) {
4731 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4735 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4737 if (!hiregion.Empty()) {
4741 switch (global_color_scheme) {
4742 case GLOBAL_COLOR_SCHEME_DAY:
4745 case GLOBAL_COLOR_SCHEME_DUSK:
4748 case GLOBAL_COLOR_SCHEME_NIGHT:
4756#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4757 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4759 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4762 DrawRegion(VPoint, hiregion);
4764 glDisable(GL_BLEND);
4770void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4774 GetClientSize(&w, &h);
4776 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4777#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4778 glMatrixMode(GL_PROJECTION);
4781 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4782 glMatrixMode(GL_MODELVIEW);
4786 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4788 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4790 bool world_view =
false;
4791 RenderWorldChart(dc, cvp, rtex, world_view);
4798 glViewport(0, 0, (GLint)w, (GLint)h);
4799#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4800 glMatrixMode(GL_PROJECTION);
4803 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4804 glMatrixMode(GL_MODELVIEW);
4810void glChartCanvas::FastPan(
int dx,
int dy) {
4811#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4815void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4817 if (IsShown()) SetCurrent(*m_pcontext);
4818 float sx = GetSize().x;
4819 float sy = GetSize().y;
4820 glClear(GL_COLOR_BUFFER_BIT);
4823 GetClientSize(&w, &h);
4825 if (s_b_useStencil) {
4826 glEnable(GL_STENCIL_TEST);
4827 glStencilMask(0xff);
4828 glClear(GL_STENCIL_BUFFER_BIT);
4829 glDisable(GL_STENCIL_TEST);
4845 float sxfactor = sx / swidth;
4846 float syfactor = sy / sheight;
4848 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4849 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4850 sx * sx / swidth * 2, sy * sy / sheight * 2);
4851 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4852 glEnable(g_texture_rectangle_format);
4877 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4878 glBindTexture(g_texture_rectangle_format, 0);
4884 float tx, ty, tx0, ty0;
4894 glBindTexture(g_texture_rectangle_format, 0);
4897 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4898 glEnable(g_texture_rectangle_format);
4904 uv[0] = tx0 / m_cache_tex_x;
4905 uv[1] = ty / m_cache_tex_y;
4906 uv[2] = tx / m_cache_tex_x;
4907 uv[3] = ty / m_cache_tex_y;
4908 uv[4] = tx / m_cache_tex_x;
4909 uv[5] = ty0 / m_cache_tex_y;
4910 uv[6] = tx0 / m_cache_tex_x;
4911 uv[7] = ty0 / m_cache_tex_y;
4923 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4924 sx * sx / swidth, sy * sy / sheight);
4926 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4928 glDisable(g_texture_rectangle_format);
4929 glBindTexture(g_texture_rectangle_format, 0);
4936 wxColour color = GetGlobalColor(
"GREY1");
4937 float ht = -offset_y * (sy / sheight);
4938 wxRect r(0, sy - ht, w, ht);
4939 RenderColorRect(r, color);
4942 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4943 RenderColorRect(rt, color);
4946 float w1 = -offset_x * sx / swidth;
4947 wxRect rl(0, 0, w1, sy);
4948 RenderColorRect(rl, color);
4951 float px = w1 + sx * sx / swidth;
4952 wxRect rr(px, 0, sx - px, sy);
4953 RenderColorRect(rr, color);
4962void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4965 if (m_nRun < m_nTotal) {
4966 m_runoffsetx += m_offsetxStep;
4967 if (m_offsetxStep > 0)
4968 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4970 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4972 m_runoffsety += m_offsetyStep;
4973 if (m_offsetyStep > 0)
4974 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4976 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4978 m_runswidth += m_swidthStep;
4979 if (m_swidthStep > 0)
4980 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4982 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4984 m_runsheight += m_sheightStep;
4985 if (m_sheightStep > 0)
4986 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4988 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4993 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4999 if (m_zoomFinaldx || m_zoomFinaldy) {
5000 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5003 m_zoomFinal =
false;
5007void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5009 int sx = GetSize().x;
5010 int sy = GetSize().y;
5012 m_lastfbo_offsetx = m_fbo_offsetx;
5013 m_lastfbo_offsety = m_fbo_offsety;
5014 m_lastfbo_swidth = m_fbo_swidth;
5015 m_lastfbo_sheight = m_fbo_sheight;
5017 float curr_fbo_offset_x = m_fbo_offsetx;
5018 float curr_fbo_offset_y = m_fbo_offsety;
5019 float curr_fbo_swidth = m_fbo_swidth;
5020 float curr_fbo_sheight = m_fbo_sheight;
5022 float fx = (float)cp_x / sx;
5023 float fy = 1.0 - (float)cp_y / sy;
5025 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5026 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5028 m_fbo_swidth = curr_fbo_swidth / factor;
5029 m_fbo_sheight = curr_fbo_sheight / factor;
5031 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5032 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5034 m_fbo_offsetx += post_x;
5035 m_fbo_offsety += post_y;
5046 float perStep = m_nStep / m_nTotal;
5048 if (zoomTimer.IsRunning()) {
5049 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5050 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5051 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5052 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5055 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5056 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5057 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5058 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5060 m_runoffsetx = m_lastfbo_offsetx;
5061 m_runoffsety = m_lastfbo_offsety;
5062 m_runswidth = m_lastfbo_swidth;
5063 m_runsheight = m_lastfbo_sheight;
5066 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5067 m_zoomFinal =
false;
5073void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5077 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5080 if (m_binPinch)
return;
5081 if (m_bpinchGuard)
return;
5083 int x =
event.GetOffset().x;
5084 int y =
event.GetOffset().y;
5086 int lx =
event.GetLastOffset().x;
5087 int ly =
event.GetLastOffset().y;
5092 switch (event.GetState()) {
5093 case GestureStarted:
5094 if (m_binPan)
break;
5098 m_binGesture =
true;
5102 case GestureUpdated:
5107 m_pParentCanvas->FreezePiano();
5109 m_pParentCanvas->ThawPiano();
5120 case GestureFinished:
5123 m_pParentCanvas->UpdateCanvasControlBar();
5126 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5130 case GestureCanceled:
5132 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5139 m_bgestureGuard =
true;
5140 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5141 m_bforcefull =
false;
5146float zoom_inc = 1.0;
5148void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5149 float zoom_gain = 1.0;
5150 float zout_gain = 1.0;
5153 float total_zoom_val;
5155 float max_zoom_scale = 1000.;
5156 float min_zoom_scale = 2e8;
5158 if (event.GetScaleFactor() > 1)
5159 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5161 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5163 if (event.GetTotalScaleFactor() > 1)
5164 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5167 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5169 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5172 float max_zoom_scale = 1000.;
5173 if( cc1->GetVP().b_quilt) {
5174 int ref_index = cc1->GetQuiltRefChartdbIndex();
5181 float min_zoom_scale = 2e8;
5185 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5187 double projected_scale =
5188 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5190 switch (event.GetState()) {
5191 case GestureStarted:
5192 m_first_zout =
false;
5196 m_binGesture =
true;
5198 m_pinchStart =
event.GetCenterPoint();
5199 m_lpinchPoint = m_pinchStart;
5202 event.GetCenterPoint().y, m_pinchlat,
5207 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5208 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5211 if (IsShown()) SetCurrent(*m_pcontext);
5217 case GestureUpdated:
5219 if (projected_scale < min_zoom_scale) {
5220 wxPoint pinchPoint =
event.GetCenterPoint();
5222 float dx = pinchPoint.x - m_lpinchPoint.x;
5223 float dy = pinchPoint.y - m_lpinchPoint.y;
5225 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5226 -dx / total_zoom_val, dy / total_zoom_val);
5228 m_lpinchPoint = pinchPoint;
5232 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5233 wxPoint pinchPoint =
event.GetCenterPoint();
5235 float dx = pinchPoint.x - m_lpinchPoint.x;
5236 float dy = pinchPoint.y - m_lpinchPoint.y;
5238 if ((projected_scale > max_zoom_scale) &&
5239 (projected_scale < min_zoom_scale))
5240 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5241 -dx / total_zoom_val, dy / total_zoom_val);
5243 m_lpinchPoint = pinchPoint;
5246 m_first_zout =
true;
5247 zoom_inc *= zoom_val;
5248 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5249 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5253 wxPoint pinchPoint =
event.GetCenterPoint();
5254 float dx = pinchPoint.x - m_lpinchPoint.x;
5255 float dy = pinchPoint.y - m_lpinchPoint.y;
5257 m_lpinchPoint = pinchPoint;
5268 case GestureFinished: {
5272 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5273 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5277 float tzoom = total_zoom_val;
5279 if (projected_scale >= min_zoom_scale)
5280 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5282 if (projected_scale < max_zoom_scale)
5283 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5285 dx = (cc_x - m_cc_x) * tzoom;
5286 dy = -(cc_y - m_cc_y) * tzoom;
5288 if (zoomTimer.IsRunning()) {
5291 m_zoomFinalZoom = tzoom;
5297 double final_projected_scale =
5301 if (final_projected_scale < min_zoom_scale) {
5305 m_pParentCanvas->m_pQuilt->Invalidate();
5306 m_bforcefull =
true;
5313 m_pParentCanvas->m_pQuilt->Invalidate();
5314 m_bforcefull =
true;
5326 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5330 case GestureCanceled:
5332 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5339 m_bgestureGuard =
true;
5341 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5344void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5354 m_bgestureGuard =
false;
5355 m_bpinchGuard =
false;
5356 m_binGesture =
false;
5357 m_bforcefull =
false;
5360void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5364 m_binGesture =
false;
5365 m_bforcefull =
false;
5369#ifdef HAVE_WX_GESTURE_EVENTS
5371void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5374 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5377 if (m_binPinch)
return;
5378 if (m_bpinchGuard)
return;
5380 int dx =
event.GetDelta().x;
5381 int dy =
event.GetDelta().y;
5383 if (event.IsGestureStart()) {
5384 if (m_binPan)
return;
5388 m_binGesture =
true;
5392 else if (event.IsGestureEnd()) {
5394 m_pParentCanvas->UpdateCanvasControlBar();
5396 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5404 m_pParentCanvas->FreezePiano();
5406 m_pParentCanvas->ThawPiano();
5417 m_bgestureGuard =
true;
5418 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5419 m_bforcefull =
false;
5423void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5425 float zoom_gain = 1.0;
5426 float zout_gain = 1.0;
5428 float last_zoom_val = m_step_zoom_val;
5430 float max_zoom_scale = 1000.;
5431 float min_zoom_scale = 2e8;
5433 if (event.GetZoomFactor() > 1)
5434 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5436 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5438 float inc_zoom_val =
5439 m_total_zoom_val / last_zoom_val;
5443 if (event.IsGestureStart()) {
5444 m_glstopwatch.Start();
5445 printf(
"\nStart--------------\n");
5447 m_pParentCanvas->m_inPinch =
true;
5450 m_binGesture =
true;
5451 m_pinchStart =
event.GetPosition();
5452 m_lpinchPoint = m_pinchStart;
5453 m_total_zoom_val = 1.0;
5454 m_final_zoom_val = 1.0;
5455 m_step_zoom_val = 1.0;
5459 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5463 if (event.IsGestureEnd()) {
5465 if (!m_binGesture)
return;
5466 printf(
"EndZoom--------------\n");
5473 m_final_zoom_val = 1.0;
5474 m_total_zoom_val = 1.0;
5475 m_step_zoom_val = 1.0;
5477 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5484 float zoom_step = 5;
5485 float zoom_trigger = 0.05;
5486 if (projected_scale > 1e5)
5488 else if (projected_scale < 3e4)
5491 if (inc_zoom_val != 1.0) {
5492 if (inc_zoom_val > 1 + zoom_step) {
5493 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5494 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5496 if (IsShown()) SetCurrent(*m_pcontext);
5499 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5500 m_step_zoom_val = m_total_zoom_val;
5501 printf(
" Zoom: %6g\n", inc_zoom_val);
5506 bool b_allow_ztp =
true;
5507 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5508 b_allow_ztp =
false;
5510 if (g_bEnableZoomToCursor && b_allow_ztp) {
5516 int dx = r.x -
event.GetPosition().x;
5517 int dy = r.y -
event.GetPosition().y;
5521 if (IsShown()) SetCurrent(*m_pcontext);
5530 float zoom_gain = 1.0;
5531 float zout_gain = 1.0;
5533 float last_zoom_val = m_total_zoom_val;
5535 float max_zoom_scale = 1000.;
5536 float min_zoom_scale = 2e8;
5538 if (event.GetZoomFactor() > 1)
5539 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5541 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5543 float inc_zoom_val =
5544 m_total_zoom_val / last_zoom_val;
5546 double projected_scale =
5547 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5549 if (event.IsGestureStart()) {
5551 m_first_zout =
false;
5555 m_binGesture =
true;
5556 m_pinchStart =
event.GetPosition();
5557 m_lpinchPoint = m_pinchStart;
5558 m_total_zoom_val = 1.0;
5559 m_final_zoom_val = 1.0;
5562 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5566 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5567 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5570 if (IsShown()) SetCurrent(*m_pcontext);
5573 ViewPort vpr = m_pParentCanvas->VPoint;
5575 GetTouchBackingBitmap(vpr);
5580 if (event.IsGestureEnd()) {
5586 if (!m_binGesture)
return;
5588 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5589 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5593 float tzoom = m_final_zoom_val;
5595 dx = (cc_x - m_cc_x) * tzoom;
5596 dy = -(cc_y - m_cc_y) * tzoom;
5598 if (zoomTimer.IsRunning()) {
5601 m_zoomFinalZoom = tzoom;
5607 double final_projected_scale =
5611 if (final_projected_scale < min_zoom_scale) {
5615 m_pParentCanvas->m_pQuilt->Invalidate();
5616 m_bforcefull =
true;
5623 m_pParentCanvas->m_pQuilt->Invalidate();
5624 m_bforcefull =
true;
5629 m_final_zoom_val = 1.0;
5630 m_total_zoom_val = 1.0;
5631 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5636 if (projected_scale < min_zoom_scale) {
5637 wxPoint pinchPoint =
event.GetPosition();
5639 float dx = pinchPoint.x - m_lpinchPoint.x;
5640 float dy = pinchPoint.y - m_lpinchPoint.y;
5642 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5643 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5645 m_lpinchPoint = pinchPoint;
5646 m_final_zoom_val *= inc_zoom_val;
5650 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5651 wxPoint pinchPoint =
event.GetPosition();
5653 float dx = pinchPoint.x - m_lpinchPoint.x;
5654 float dy = pinchPoint.y - m_lpinchPoint.y;
5656 if ((projected_scale > max_zoom_scale) &&
5657 (projected_scale < min_zoom_scale))
5658 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5659 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5661 m_lpinchPoint = pinchPoint;
5662 m_final_zoom_val *= inc_zoom_val;
5665 m_first_zout =
true;
5666 m_zoom_inc *= inc_zoom_val;
5667 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5668 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5672 wxPoint pinchPoint =
event.GetPosition();
5673 float dx = pinchPoint.x - m_lpinchPoint.x;
5674 float dy = pinchPoint.y - m_lpinchPoint.y;
5676 m_lpinchPoint = pinchPoint;
5680 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5683 m_bgestureGuard =
true;
5684 m_bpinchGuard =
true;
5687void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5696 m_bgestureGuard =
false;
5697 m_bpinchGuard =
false;
5698 m_binGesture =
false;
5699 m_bforcefull =
false;
5702void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5706 m_binGesture =
false;
5707 m_bforcefull =
false;
5709 m_pParentCanvas->m_inPinch =
false;
5710 printf(
"******Finish\n");
5716void glChartCanvas::configureShaders(
ViewPort &vp) {
5717#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5723 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5725 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5726 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5747 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5749 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5750 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5762 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5764 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5765 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5768 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5770 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5771 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5779 shader = pAALine_shader_program[GetCanvasIndex()];
5781 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5784 shader = pring_shader_program[GetCanvasIndex()];
5786 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5787 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5791 if (texture_2DA_shader_program) {
5792 glUseProgram(texture_2DA_shader_program);
5793 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5794 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5795 (
const GLfloat *)pvp->vp_matrix_transform);
5797 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5798 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5806void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5809#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5810 int nl = nVertex / 4;
5812 float *luv = uvCoords;
5815 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5823 glEnableClientState(GL_VERTEX_ARRAY);
5824 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5826 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5827 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5828 glDrawArrays(GL_QUADS, 0, 4);
5835void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5836 float *uvCoords,
ViewPort *vp,
float dx,
5837 float dy,
float angle_rad) {
5838#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5840 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5841 if (!shader)
return;
5846 shader->SetUniform1i(
"uTex", 0);
5851 mat4x4_rotate_Z(Q, I, angle_rad);
5857 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5862 shader->SetAttributePointerf(
"aPos", co1);
5863 shader->SetAttributePointerf(
"aUV", tco1);
5870 GLushort indices1[] = {0,1,3,2};
5871 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5883 tco1[0] = uvCoords[0];
5884 tco1[1] = uvCoords[1];
5885 tco1[2] = uvCoords[2];
5886 tco1[3] = uvCoords[3];
5887 tco1[4] = uvCoords[6];
5888 tco1[5] = uvCoords[7];
5889 tco1[6] = uvCoords[4];
5890 tco1[7] = uvCoords[5];
5895 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5907void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5908#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5910 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5913 shader->SetUniformMatrix4fv(
5914 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5917 colorv[0] = color.Red() / float(256);
5918 colorv[1] = color.Green() / float(256);
5919 colorv[2] = color.Blue() / float(256);
5921 shader->SetUniform4fv(
"color", colorv);
5924 pf[0] = r.x + r.width;
5928 pf[4] = r.x + r.width;
5929 pf[5] = r.y + r.height;
5931 pf[7] = r.y + r.height;
5932 shader->SetAttributePointerf(
"position", pf);
5934 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5942void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5943#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5945 ViewPort VPoint = m_pParentCanvas->VPoint;
5949 GetClientSize(&w, &h);
5950 int sx = GetSize().x;
5951 int sy = GetSize().y;
5955 glViewport(0, 0, (GLint)w, (GLint)h);
5957 if (s_b_useStencil) {
5958 glEnable(GL_STENCIL_TEST);
5959 glStencilMask(0xff);
5960 glClear(GL_STENCIL_BUFFER_BIT);
5961 glDisable(GL_STENCIL_TEST);
5965 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5970 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5971 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5972 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5975 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5977 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5978 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5986 if (bRenderCharts) RenderCharts(gldc, screen_region);
5988 if (bRenderOverlays) {
5989 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5990 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5996 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5999 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
6000 DrawDynamicRoutesTracksAndWaypoints(VPoint);
6001 DrawFloatingOverlayObjects(m_gldc);
6005 glBindFramebuffer(GL_FRAMEBUFFER, 0);
6010wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
6012 wxMemoryDC tdc(tbm);
6013 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6021 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6022 dc.SetPen(*wxTRANSPARENT_PEN);
6025 tdc.SelectObject(wxNullBitmap);
6026 m_touch_backing_bitmap = tbm;
6027 CreateBackingTexture();
6029 return m_touch_backing_bitmap;
6032void glChartCanvas::CreateBackingTexture() {
6033 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6034 unsigned char *imgdata = image.GetData();
6035 unsigned char *imgalpha = image.GetAlpha();
6036 m_tex_w = image.GetWidth();
6037 m_tex_h = image.GetHeight();
6038 m_image_width = m_tex_w;
6039 m_image_height = m_tex_h;
6041 GLuint format = GL_RGBA;
6042 GLuint internalformat = g_texture_rectangle_format;
6044 internalformat = GL_RGBA;
6049 unsigned char *teximage =
6050 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6052 for (
int i = 0; i < m_image_height; i++) {
6053 for (
int j = 0; j < m_image_width; j++) {
6054 int s = (i * 3 * m_image_width) + (j * 3);
6055 int d = (i * stride * m_tex_w) + (j * stride);
6057 teximage[d + 0] = imgdata[s + 0];
6058 teximage[d + 1] = imgdata[s + 1];
6059 teximage[d + 2] = imgdata[s + 2];
6060 teximage[d + 3] = 255;
6064 glGenTextures(1, &m_TouchBackingTexture);
6065 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6067 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6068 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6069 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6071 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6073 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6074 GL_UNSIGNED_BYTE, teximage);
6077 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.