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";
512 if (!m_bsetup)
return;
514 if (!IsShown())
return;
516 SetCurrent(*m_pcontext);
520 SetSize(GetSize().x, GetSize().y);
528 if (m_pcontext && IsShown()) {
529 SetCurrent(*m_pcontext);
534 wxLogDebug(
"BuildFBO 3");
538 ViewPort *vp = m_pParentCanvas->GetpVP();
541 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
544 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
548void glChartCanvas::MouseEvent(wxMouseEvent &event) {
549 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
555 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
557 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
560 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
564 if (m_bgestureGuard) {
565 m_pParentCanvas->r_rband.x = 0;
575 if (event.LeftUp()) {
577 if ((abs(panx) > 2) || (abs(pany) > 2)) {
580 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
587 if (!event.LeftDClick()) {
592 if (m_binPan && event.RightDown()) {
593 qDebug() <<
"Skip right on pan";
596 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
598 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
599 if (!m_bgestureGuard)
609#ifndef GL_MAX_RENDERBUFFER_SIZE
610#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
613#ifndef USE_ANDROID_GLES2
614bool glChartCanvas::buildFBOSize(
int fboSize) {
616 if (IsShown()) SetCurrent(*m_pcontext);
619 glDeleteTextures(2, m_cache_tex);
620 glDeleteFramebuffers(1, &m_fb0);
621 glDeleteRenderbuffers(1, &m_renderbuffer);
622 m_b_BuiltFBO =
false;
625 if (m_b_DisableFBO)
return false;
629 int rb_x = GetSize().x;
630 int rb_y = GetSize().y;
632 while (i < rb_x) i <<= 1;
636 while (i < rb_y) i <<= 1;
639 m_cache_tex_x = wxMax(rb_x, rb_y);
640 m_cache_tex_y = wxMax(rb_x, rb_y);
643 m_cache_tex_x = GetSize().x * m_displayScale;
644 m_cache_tex_y = GetSize().y * m_displayScale;
647 int err = GL_NO_ERROR;
649 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
652 if (err == GL_INVALID_ENUM) {
653 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
657 if (err == GL_NO_ERROR) {
658 if (fboSize > params) {
660 " OpenGL-> Requested Framebuffer size exceeds "
661 "GL_MAX_RENDERBUFFER_SIZE");
666 glGenFramebuffers(1, &m_fb0);
670 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
675 glGenRenderbuffers(1, &m_renderbuffer);
679 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
684 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
688 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
694 glGenTextures(2, m_cache_tex);
695 for (
int i = 0; i < 2; i++) {
696 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
697 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
699 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
701 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
702 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
705 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
707 if (m_b_useFBOStencil) {
709 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
710 m_cache_tex_x, m_cache_tex_y);
712 int err = glGetError();
715 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
719 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
720 GL_RENDERBUFFER_EXT, m_renderbuffer);
724 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
729 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
730 GL_RENDERBUFFER_EXT, m_renderbuffer);
734 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
740 GLenum depth_format = GL_DEPTH_COMPONENT24;
745 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
749 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
751 int err = glGetError();
754 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
760 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
761 GL_RENDERBUFFER_EXT, m_renderbuffer);
766 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
773 glBindTexture(GL_TEXTURE_2D, 0);
774 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
777 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
779 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
780 g_texture_rectangle_format, m_cache_tex[0], 0);
782 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
784 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
786 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
788 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
798#ifdef USE_ANDROID_GLES2
799bool glChartCanvas::buildFBOSize(
int fboSize) {
803 int rb_x = GetSize().x;
804 int rb_y = GetSize().y;
806 while (i < rb_x) i <<= 1;
810 while (i < rb_y) i <<= 1;
813 m_cache_tex_x = wxMax(rb_x, rb_y);
814 m_cache_tex_y = wxMax(rb_x, rb_y);
818 int err = GL_NO_ERROR;
820 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
823 if (err == GL_INVALID_ENUM) {
824 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
828 if (err == GL_NO_ERROR) {
829 if (fboSize > params) {
831 " OpenGL-> Requested Framebuffer size exceeds "
832 "GL_MAX_RENDERBUFFER_SIZE");
837 glGenFramebuffers(1, &m_fb0);
841 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
846 glGenRenderbuffers(1, &m_renderbuffer);
850 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
855 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
859 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
865 glGenTextures(2, m_cache_tex);
866 for (
int i = 0; i < 2; i++) {
867 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
868 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
870 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
872 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
873 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
876 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
879 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
885 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
889 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
890 GL_RENDERBUFFER, m_renderbuffer);
894 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
899 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
900 GL_RENDERBUFFER, m_renderbuffer);
904 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
909 glBindTexture(GL_TEXTURE_2D, 0);
910 glBindFramebuffer(GL_FRAMEBUFFER, 0);
913 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
915 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
916 g_texture_rectangle_format, m_cache_tex[0], 0);
918 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
920 glBindFramebuffer(GL_FRAMEBUFFER, 0);
922 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
924 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
934void glChartCanvas::BuildFBO() {
937 glDeleteTextures(2, m_cache_tex);
938 glDeleteFramebuffers(1, &m_fb0);
939 glDeleteRenderbuffers(1, &m_renderbuffer);
940 m_b_BuiltFBO =
false;
943 if (m_b_DisableFBO)
return;
946 int gl_width, gl_height;
947 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
948 int initialSize = NextPow2(gl_width * m_displayScale);
953 wxString info = androidGetDeviceInfo();
955 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
958 if (!buildFBOSize(initialSize)) {
959 glDeleteTextures(2, m_cache_tex);
960 glDeleteFramebuffers(1, &m_fb0);
961 glDeleteRenderbuffers(1, &m_renderbuffer);
963 if (!buildFBOSize(1024)) {
964 wxLogMessage(
"BuildFBO C");
966 m_b_DisableFBO =
true;
967 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
968 m_b_BuiltFBO =
false;
977 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
989void glChartCanvas::SetupOpenGL() {
990 if (IsShown()) SetCurrent(*m_pcontext);
992 char *str = (
char *)glGetString(GL_RENDERER);
995 wxLogMessage(
"Failed to initialize OpenGL");
999 char render_string[80];
1000 strncpy(render_string, str, 79);
1001 m_renderer = wxString(render_string, wxConvUTF8);
1004 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1005 msg.Printf(
"OpenGL-> Renderer String: ");
1009 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1011 char version_string[80];
1012 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1013 msg.Printf(
"OpenGL-> Version reported: ");
1014 m_version = wxString(version_string, wxConvUTF8);
1018 char GLSL_version_string[80];
1019 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1021 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1022 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1023 msg += m_GLSLversion;
1028 GLenum err = glewInit();
1029#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1030 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1035 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1038 wxLogMessage(
"GLEW init success!n");
1043 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1044 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1048#ifndef USE_ANDROID_GLES2
1049 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1051 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1053 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1054 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1061 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1063 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1065 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1068 s_b_useScissorTest =
true;
1070 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1071 s_b_useScissorTest =
false;
1073 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1074 s_b_useScissorTest =
false;
1076 bool bad_stencil_code =
false;
1079 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1080 bad_stencil_code =
true;
1083 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1086 glEnable(GL_STENCIL_TEST);
1087 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1089 glGetIntegerv(GL_STENCIL_BITS, &sb);
1092 glDisable(GL_STENCIL_TEST);
1094 s_b_useStencil =
false;
1095 if (stencil && (sb == 8)) s_b_useStencil =
true;
1097 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1098 g_texture_rectangle_format = GL_TEXTURE_2D;
1099 else if (QueryExtension(
"GL_OES_texture_npot"))
1100 g_texture_rectangle_format = GL_TEXTURE_2D;
1101 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1102 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1103 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1104 g_texture_rectangle_format));
1107 g_texture_rectangle_format = GL_TEXTURE_2D;
1111 g_b_EnableVBO =
true;
1114 g_b_EnableVBO =
false;
1118 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1120 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1124 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1126 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1129#ifndef USE_ANDROID_GLES2
1131 if (bad_stencil_code) s_b_useStencil =
false;
1145 if (m_displayScale > 1) m_b_DisableFBO =
true;
1154 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1156 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1157 g_texture_rectangle_format, m_cache_tex[0], 0);
1159 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1160 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1162 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1164 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1166 m_b_DisableFBO =
true;
1172 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1176 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1178#ifdef USE_ANDROID_GLES2
1179 s_b_useStencilAP = s_b_useStencil;
1186 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1188 if (m_b_useFBOStencil)
1189 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1191 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1193 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1196 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1198 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1200 if (s_b_useScissorTest && s_b_useStencil)
1201 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1204 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1206 MipMap_ResolveRoutines();
1210 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1211 g_GLMinCartographicLineWidth);
1212 wxLogMessage(lwmsg);
1213 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1214 g_GLMinSymbolLineWidth);
1215 wxLogMessage(lwmsg);
1218 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1220#ifdef USE_ANDROID_GLES2
1221 g_GLOptions.m_bUseAcceleratedPanning =
true;
1227 int tex_dim = g_GLOptions.m_iTextureDimension;
1228 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1237 s_b_useFBO = m_b_BuiltFBO;
1241 ps52plib->SetGLOptions(
1242 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1243 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1244 g_GLMinSymbolLineWidth);
1248 SendJSONConfigMessage();
1251void glChartCanvas::SendJSONConfigMessage() {
1254 v[
"setupComplete"] = m_bsetup;
1255 v[
"useStencil"] = s_b_useStencil;
1256 v[
"useStencilAP"] = s_b_useStencilAP;
1257 v[
"useScissorTest"] = s_b_useScissorTest;
1258 v[
"useFBO"] = s_b_useFBO;
1259 v[
"useVBO"] = g_b_EnableVBO;
1260 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1261 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1262 SendJSONMessageToAllPlugins(msg_id, v);
1265void glChartCanvas::SetupCompression() {
1266 int dim = g_GLOptions.m_iTextureDimension;
1269 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1270 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1271 goto no_compression;
1275 g_uncompressed_tile_size = dim * dim * 4;
1276 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1282 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1285 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1295 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1296 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1299 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1300 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1305 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1306 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1309 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1311 wxLogMessage(
"OpenGL-> No Useable compression format found");
1312 goto no_compression;
1317 g_tile_size = 512 * 512 / 2;
1321 glGenTextures(1, &texture);
1322 glBindTexture(GL_TEXTURE_2D, texture);
1324 GL_UNSIGNED_BYTE, NULL);
1325 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1327 glDeleteTextures(1, &texture);
1331 if (g_tile_size == 0)
goto no_compression;
1333 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1335 g_uncompressed_tile_size / g_tile_size));
1339 g_GLOptions.m_bTextureCompression =
false;
1341 g_tile_size = g_uncompressed_tile_size;
1342 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1345void glChartCanvas::OnPaint(wxPaintEvent &event) {
1347 if (!m_pcontext)
return;
1356 if (IsShown()) SetCurrent(*m_pcontext);
1361 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1369 if (!m_b_paint_enable)
return;
1372 if (m_in_glpaint)
return;
1375 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1398bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1400#ifndef USE_ANDROID_GLES2
1401 return vp.m_projection_type == PROJECTION_MERCATOR ||
1402 vp.m_projection_type == PROJECTION_POLAR ||
1403 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1417#define NORM_FACTOR 4096.0
1418void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1419#ifndef USE_ANDROID_GLES2
1421 wxPoint2DDouble point;
1423 switch (vp.m_projection_type) {
1424 case PROJECTION_MERCATOR:
1425 case PROJECTION_EQUIRECTANGULAR:
1426 case PROJECTION_WEB_MERCATOR:
1429 glTranslated(point.m_x, point.m_y, 0);
1434 case PROJECTION_POLAR:
1438 glTranslated(point.m_x, point.m_y, 0);
1439 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1446 printf(
"ERROR: Unhandled projection\n");
1451 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1459 switch (vp.m_projection_type) {
1460 case PROJECTION_MERCATOR:
1461 case PROJECTION_EQUIRECTANGULAR:
1462 case PROJECTION_WEB_MERCATOR:
1466 case PROJECTION_POLAR:
1471 printf(
"ERROR: Unhandled projection\n");
1480bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1481 return vp.m_projection_type == PROJECTION_MERCATOR ||
1482 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1483 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1487 const LLRegion ®ion) {
1488 if (!CanClipViewport(vp))
return vp;
1491 LLBBox bbox = region.GetBox();
1493 if (!bbox.GetValid())
return vp;
1501 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1502 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1503 bbox.GetMaxLon() + 360);
1504 cvp.SetBBoxDirect(bbox);
1505 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1506 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1507 bbox.GetMaxLon() - 360);
1508 cvp.SetBBoxDirect(bbox);
1510 cvp.SetBBoxDirect(bbox);
1515void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1516 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1522 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1524 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1528 if (!pRouteDraw)
continue;
1531 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1534 if (pRouteDraw->m_bIsBeingEdited)
continue;
1536 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1541 if (vp.GetBBox().GetValid() && pWayPointMan) {
1542 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1543 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1544 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1550void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1555 if (pActiveTrack && pActiveTrack->IsRunning())
1556 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1562 if (!pRouteDraw)
continue;
1565 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1568 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1571 if (pRouteDraw->IsSelected()) drawit++;
1574 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1575 if (!vp_box.IntersectOut(test_box))
1576 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1582 if (vp.GetBBox().GetValid() && pWayPointMan) {
1583 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1584 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1591static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1595 switch (vp.m_projection_type) {
1596 case PROJECTION_TRANSVERSE_MERCATOR:
1597 lat_dist = 4, lon_dist = 1;
1599 case PROJECTION_POLYCONIC:
1600 lat_dist = 2, lon_dist = 1;
1602 case PROJECTION_ORTHOGRAPHIC:
1603 lat_dist = 2, lon_dist = 2;
1605 case PROJECTION_POLAR:
1606 lat_dist = 180, lon_dist = 1;
1608 case PROJECTION_STEREOGRAPHIC:
1609 case PROJECTION_GNOMONIC:
1610 lat_dist = 2, lon_dist = 1;
1612 case PROJECTION_EQUIRECTANGULAR:
1615 lat_dist = 2, lon_dist = 360;
1618 lat_dist = 180, lon_dist = 360;
1622void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1623 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1629 ChartData->GetDBBoundingBox(dbIndex, box);
1630 if (!box.GetValid())
return;
1634 if (box.GetLonRange() == 360)
return;
1636 LLBBox vpbox = vp.GetBBox();
1638 double lon_bias = 0;
1640 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1643 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1644 color = GetGlobalColor(
"YELO1");
1645 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1646 color = GetGlobalColor(
"GREEN2");
1648 color = GetGlobalColor(
"UINFR");
1650#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1651 float plylat, plylon;
1653 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1655 glColor3ub(color.Red(), color.Green(), color.Blue());
1656 glLineWidth(g_GLMinSymbolLineWidth);
1658 float lat_dist, lon_dist;
1659 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1662 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1666 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1668 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1670 bool begin =
false, sml_valid =
false;
1672 float lastplylat = 0.0;
1673 float lastplylon = 0.0;
1675 int modulo = (nPly == 0) ? 1 : nPly;
1676 for (
int i = 0; i < nPly + 1; i++) {
1678 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1680 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1684 if (lastplylon - plylon > 180)
1686 else if (lastplylon - plylon < -180)
1693 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1694 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1695 splits = wxMax(lat_splits, lon_splits) + 1;
1702 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1703 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1706 for (
double c = 0; c < splits; c++) {
1708 if (c == splits - 1)
1709 lat = plylat, lon = plylon;
1711 double d = (double)(c + 1) / splits;
1712 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1718 if (!std::isnan(s.m_x)) {
1721 glBegin(GL_LINE_STRIP);
1723 glVertex2f(s.m_x, s.m_y);
1729 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1730 lastplylat = plylat, lastplylon = plylon;
1735 }
while (++j < nAuxPlyEntries);
1737 glDisable(GL_LINE_SMOOTH);
1741 double nominal_line_width_pix =
1742 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1744 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1745 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1748 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1749 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1753 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1756 float plylat1, plylon1;
1760 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1761 if (0 == nAuxPlyEntries)
1764 std::vector<int> points_vector;
1766 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1767 int nPly = vec.size() / 2;
1769 if (nPly == 0)
return;
1771 for (
int i = 0; i < nPly; i++) {
1772 plylon1 = vec[i * 2];
1773 plylat1 = vec[i * 2 + 1];
1779 points_vector.push_back(pixx1);
1780 points_vector.push_back(pixy1);
1783 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1784 plylon1 += lon_bias;
1790 points_vector.push_back(pixx1);
1791 points_vector.push_back(pixy1);
1793 if (points_vector.size()) {
1794 std::vector<int>::iterator it = points_vector.begin();
1795 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1803 for (
int j = 0; j < nAuxPlyEntries; j++) {
1804 std::vector<int> points_vector;
1806 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1807 int nAuxPly = vec.size() / 2;
1809 if (nAuxPly == 0)
continue;
1811 for (
int i = 0; i < nAuxPly; i++) {
1812 plylon1 = vec[i * 2];
1813 plylat1 = vec[i * 2 + 1];
1819 points_vector.push_back(pixx1);
1820 points_vector.push_back(pixy1);
1827 points_vector.push_back(pixx1);
1828 points_vector.push_back(pixy1);
1830 if (points_vector.size()) {
1831 std::vector<int>::iterator it = points_vector.begin();
1832 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1840extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1841 float &MinorSpacing);
1842extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1843void glChartCanvas::GridDraw() {
1844 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1846 ViewPort &vp = m_pParentCanvas->GetVP();
1848 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1852 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1854 double nlat, elon, slat, wlon;
1856 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1859 wxColour GridColor = GetGlobalColor(
"SNDG1");
1861 if (!m_gridfont.IsBuilt()) {
1863 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1864 wxFont font = *dFont;
1867 int font_size = wxMax(10, dFont->GetPointSize());
1868 font.SetPointSize(font_size);
1869 font.SetWeight(wxFONTWEIGHT_NORMAL);
1872 m_gridfont.Build(font, m_displayScale, dpi_factor);
1874 m_gridfont.SetColor(GridColor);
1879 LLBBox llbbox = vp.GetBBox();
1880 nlat = llbbox.GetMaxLat();
1881 slat = llbbox.GetMinLat();
1882 elon = llbbox.GetMaxLon();
1883 wlon = llbbox.GetMinLon();
1890 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1891 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1892 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1893 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1894 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1895 vp.m_projection_type == PROJECTION_POLAR ||
1896 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1899 if (straight_latitudes)
1902 latmargin = gridlatMajor / 2;
1904 slat = wxMax(slat, -90 + latmargin);
1905 nlat = wxMin(nlat, 90 - latmargin);
1907 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1908 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1912 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1919 float lon_step = elon - wlon;
1920 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1922 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1924 s.x = INVALID_COORD;
1925 s.y = INVALID_COORD;
1926 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1928 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1929 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1937 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1938 lat += gridlatMinor) {
1941 gldc.DrawLine(0, r.y, 10, r.y,
true);
1942 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1947 float lat_step = nlat - slat;
1948 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1950 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1952 s.x = INVALID_COORD;
1953 s.y = INVALID_COORD;
1954 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1956 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1957 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1965 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1966 lon += gridlonMinor) {
1969 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1970 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1976 glEnable(GL_TEXTURE_2D);
1978 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1979 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1982 CalcGridText(lat, gridlatMajor,
true);
1984 m_gridfont.GetTextExtent(st, 0, &iy);
1986 if (straight_latitudes) {
1991 float x = 0, y = -1;
1992 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1993 if (y < 0 || y > h) {
1995 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1998 m_gridfont.RenderString(st, x, y);
2002 double y1, y2, lat1, lon1, lat2, lon2;
2011 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2014 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2016 if (fabs(y - y1) < fabs(y - y2))
2022 error = fabs(r.m_x);
2023 if (--maxiters == 0)
break;
2024 }
while (error > 1 && error < lasterror);
2026 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2032 m_gridfont.RenderString(st, r.m_x, r.m_y);
2036 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2037 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2046 else if (xlon <= -180.0)
2049 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2051 m_gridfont.GetTextExtent(st, &ix, 0);
2053 if (straight_longitudes) {
2054 float x = -1, y = 0;
2055 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2056 if (x < 0 || x > w) {
2058 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2061 m_gridfont.RenderString(st, x, y);
2065 double x1, x2, lat1, lon1, lat2, lon2;
2073 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2076 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2078 if (fabs(x - x1) < fabs(x - x2))
2084 error = fabs(r.m_y);
2085 }
while (error > 1 && error < lasterror);
2087 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2092 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2094 m_gridfont.RenderString(st, r.m_x, r.m_y);
2098 glDisable(GL_TEXTURE_2D);
2099 glDisable(GL_BLEND);
2104 if (!emboss)
return;
2106 int w = emboss->width, h = emboss->height;
2108 glEnable(GL_TEXTURE_2D);
2111 if (!emboss->gltexind) {
2113 emboss->glwidth = NextPow2(emboss->width);
2114 emboss->glheight = NextPow2(emboss->height);
2117 int size = emboss->glwidth * emboss->glheight;
2118 char *data =
new char[2 * size];
2119 for (
int i = 0; i < h; i++) {
2120 for (
int j = 0; j < emboss->glwidth; j++) {
2122 data[2 * ((i * emboss->glwidth) + j)] =
2123 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2124 data[2 * ((i * emboss->glwidth) + j) + 1] =
2125 (char)abs((emboss->pmap[(i * w) + j]));
2130 glGenTextures(1, &emboss->gltexind);
2131 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2132 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2133 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2141 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2145 int x = emboss->x, y = emboss->y;
2147 float wp = (float)w / emboss->glwidth;
2148 float hp = (float)h / emboss->glheight;
2174 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2176 glDisable(GL_BLEND);
2177 glDisable(GL_TEXTURE_2D);
2180void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2181 if (!m_pParentCanvas->GetVP().IsValid())
return;
2182 wxPoint GPSOffsetPixels(0, 0);
2183 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2186 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2187 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2191 double shift_dx = 0;
2192 double shift_dy = 0;
2193 bool dynamic = m_pParentCanvas->m_animationActive ||
2194 m_pParentCanvas->m_MouseDragging ||
2195 m_pParentCanvas->m_chart_drag_inertia_active;
2196 if (m_pParentCanvas->m_bFollow && !dynamic) {
2197 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2198 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2199 if (m_pParentCanvas->m_bLookAhead) {
2205 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2206 angle += m_pParentCanvas->GetVPRotation();
2207 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2209 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2210 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2212 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2217 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2218 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2225 lShipMidPoint = lGPSPoint;
2229 float icon_hdt = pCog;
2230 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2233 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2237 double osd_head_lat, osd_head_lon;
2238 wxPoint2DDouble osd_head_point;
2240 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2244 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2246 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2247 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2248 icon_rad += (float)PI;
2252 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2256 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2262 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2263 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2264 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2269 float scale_factor = 1.0;
2274 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2275 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2276 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2278 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2280 float nominal_ownship_size_pixels =
2282 nominal_ownship_size_mm);
2284 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2286 wxPen ppSmallScaleShip;
2287 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2289 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2292 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2293 dc.SetPen(ppSmallScaleShip);
2295 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2298 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2299 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2300 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2301 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2304 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2305 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2308 int draw_color = SHIP_INVALID;
2309 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2310 draw_color = SHIP_NORMAL;
2311 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2312 draw_color = SHIP_LOWACCURACY;
2320 ownship_color = draw_color;
2322 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2324 glGenTextures(1, &ownship_tex);
2325 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2327 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2328 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2331 if (m_pParentCanvas->m_pos_image_user) {
2332 switch (draw_color) {
2334 image = *m_pParentCanvas->m_pos_image_user_grey;
2337 image = *m_pParentCanvas->m_pos_image_user;
2339 case SHIP_LOWACCURACY:
2340 image = *m_pParentCanvas->m_pos_image_user_yellow;
2344 switch (draw_color) {
2346 image = *m_pParentCanvas->m_pos_image_grey;
2349 image = *m_pParentCanvas->m_pos_image_red;
2351 case SHIP_LOWACCURACY:
2352 image = *m_pParentCanvas->m_pos_image_yellow;
2357 int w = image.GetWidth(), h = image.GetHeight();
2358 int glw = NextPow2(w), glh = NextPow2(h);
2359 ownship_size = wxSize(w, h);
2360 ownship_tex_size = wxSize(glw, glh);
2362 unsigned char *d = image.GetData();
2363 unsigned char *a = image.GetAlpha();
2364 unsigned char *e =
new unsigned char[4 * w * h];
2367 for (
int p = 0; p < w * h; p++) {
2368 e[4 * p + 0] = d[3 * p + 0];
2369 e[4 * p + 1] = d[3 * p + 1];
2370 e[4 * p + 2] = d[3 * p + 2];
2371 e[4 * p + 3] = a[p];
2374 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2375 GL_UNSIGNED_BYTE, 0);
2377 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2383#ifndef USE_ANDROID_GLES2
2384 if (m_pParentCanvas->m_pos_image_user)
2385 glColor4ub(255, 255, 255, 255);
2386 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2387 glColor4ub(255, 0, 0, 255);
2388 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2389 glColor4ub(255, 255, 0, 255);
2391 glColor4ub(128, 128, 128, 255);
2393 float scale_factor_y = 1.0;
2394 float scale_factor_x = 1.0;
2396 int ownShipWidth = 22;
2397 int ownShipLength = 84;
2398 lShipMidPoint = lGPSPoint;
2401 if (g_OwnShipIconType != 0)
2402 m_pParentCanvas->ComputeShipScaleFactor(
2403 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2404 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2409 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2410 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2411 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2415 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2416 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2420 float gps_circle_radius = 3.0;
2422 if (g_OwnShipIconType == 0) {
2424 glEnable(GL_TEXTURE_2D);
2425 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2434 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2435 if (m_pParentCanvas->m_pos_image_user)
2436 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2438 float nominal_ownship_size_mm =
2439 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2441 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2442 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2444 float nominal_ownship_size_pixels =
2445 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2447 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2448 nominal_ownship_size_pixels = wxMax(
2449 20.0, nominal_ownship_size_pixels);
2452 float h = nominal_ownship_size_pixels * scale_factor_y;
2453 float w = nominal_ownship_size_pixels * scale_factor_x *
2454 ownship_size.x / ownship_size.y;
2455 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2456 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2462 gps_circle_radius = w / 5;
2464 float uv[8], coords[8];
2483 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2484 lShipMidPoint.m_x, lShipMidPoint.m_y,
2486 glDisable(GL_TEXTURE_2D);
2487 }
else if (g_OwnShipIconType == 1) {
2489 glEnable(GL_TEXTURE_2D);
2490 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2492 float nominal_ownship_size_pixels_y = 84;
2493 float nominal_ownship_size_pixels_x = 22;
2495 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2496 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2498 float u = (float)ownship_size.x / ownship_tex_size.x,
2499 v = (
float)ownship_size.y / ownship_tex_size.y;
2502 gps_circle_radius = w / 5;
2504 float uv[8], coords[8];
2523 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2524 lShipMidPoint.m_x, lShipMidPoint.m_y,
2527 glDisable(GL_TEXTURE_2D);
2528 }
else if (g_OwnShipIconType == 2) {
2536 wxPoint shipPoints[6];
2538 wxColour colour = m_pParentCanvas->ShipColor();
2539 wxPen ppPen(*wxBLACK, 1);
2540 wxBrush ppBrush(colour);
2542 dc.SetBrush(ppBrush);
2544 shipPoints[0].x = 0 * scale_factor_x;
2545 shipPoints[0].y = -28 * scale_factor_y;
2546 shipPoints[1].x = 11 * scale_factor_x;
2547 shipPoints[1].y = -28 * scale_factor_y;
2548 shipPoints[2].x = 11 * scale_factor_x;
2549 shipPoints[2].y = 42 * scale_factor_y;
2550 shipPoints[3].x = 0 * scale_factor_x;
2551 shipPoints[3].y = 42 * scale_factor_y;
2552 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2555 shipPoints[0].x = 0 * scale_factor_x;
2556 shipPoints[0].y = -42 * scale_factor_y;
2557 shipPoints[1].x = 5 * scale_factor_x;
2558 shipPoints[1].y = -42 * scale_factor_y;
2559 shipPoints[2].x = 11 * scale_factor_x;
2560 shipPoints[2].y = -28 * scale_factor_y;
2561 shipPoints[3].x = 0 * scale_factor_x;
2562 shipPoints[3].y = -28 * scale_factor_y;
2563 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2566 shipPoints[0].x = 0 * scale_factor_x;
2567 shipPoints[0].y = -28 * scale_factor_y;
2568 shipPoints[1].x = -11 * scale_factor_x;
2569 shipPoints[1].y = -28 * scale_factor_y;
2570 shipPoints[2].x = -11 * scale_factor_x;
2571 shipPoints[2].y = 42 * scale_factor_y;
2572 shipPoints[3].x = 0 * scale_factor_x;
2573 shipPoints[3].y = 42 * scale_factor_y;
2574 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2577 shipPoints[0].x = 0 * scale_factor_x;
2578 shipPoints[0].y = -42 * scale_factor_y;
2579 shipPoints[1].x = -5 * scale_factor_x;
2580 shipPoints[1].y = -42 * scale_factor_y;
2581 shipPoints[2].x = -11 * scale_factor_x;
2582 shipPoints[2].y = -28 * scale_factor_y;
2583 shipPoints[3].x = 0 * scale_factor_x;
2584 shipPoints[3].y = -28 * scale_factor_y;
2585 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2589 double p1x = -11 * scale_factor_x;
2590 double p2x = 11 * scale_factor_x;
2594 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2596 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2598 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2600 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2601 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2602 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2606 p1y = -42 * scale_factor_y;
2607 p2y = 42 * scale_factor_y;
2608 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2609 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2610 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2611 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2612 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2613 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2616 img_height = ownShipLength * scale_factor_y;
2619 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2621 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2623 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2625 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2629 glDisable(GL_LINE_SMOOTH);
2630 glDisable(GL_POLYGON_SMOOTH);
2631 glDisable(GL_BLEND);
2634 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2638void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2639 ViewPort &vp = m_pParentCanvas->GetVP();
2662 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2664 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2665 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2667 m_pParentCanvas->AlertDraw(dc);
2669 m_pParentCanvas->RenderVisibleSectorLights(dc);
2671 m_pParentCanvas->RenderRouteLegs(dc);
2672 m_pParentCanvas->RenderShipToActive(dc,
true);
2673 m_pParentCanvas->ScaleBarDraw(dc);
2674 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2675 m_pParentCanvas->extendedSectorLegs);
2682void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2683 if (m_pParentCanvas->GetPiano()) {
2684 int canvas_height = GetClientSize().y;
2685 canvas_height *= m_displayScale;
2687 m_pParentCanvas->GetPiano()->DrawGL(
2688 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2692void glChartCanvas::DrawQuiting() {
2693#ifndef USE_ANDROID_GLES2
2694 GLubyte pattern[8][8];
2695 for (
int y = 0; y < 8; y++)
2696 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2699 glEnable(GL_TEXTURE_2D);
2700 glBindTexture(GL_TEXTURE_2D, 0);
2702 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2703 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2704 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2706 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2710 float x = GetSize().x, y = GetSize().y;
2711 float u = x / 8, v = y / 8;
2724 glDisable(GL_TEXTURE_2D);
2725 glDisable(GL_BLEND);
2729void glChartCanvas::DrawCloseMessage(wxString msg) {
2730#ifndef USE_ANDROID_GLES2
2734 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2738 texfont.Build(*pfont, 1, 1);
2740 texfont.GetTextExtent(msg, &w, &h);
2742 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2743 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2745 glColor3ub(243, 229, 47);
2749 glVertex2i(xp + w, yp);
2750 glVertex2i(xp + w, yp + h);
2751 glVertex2i(xp, yp + h);
2756 glColor3ub(0, 0, 0);
2757 glEnable(GL_TEXTURE_2D);
2758 texfont.RenderString(msg, xp, yp);
2759 glDisable(GL_TEXTURE_2D);
2760 glDisable(GL_BLEND);
2767static std::list<double *> combine_work_data;
2768static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2769 GLfloat weight[4], GLdouble **dataOut) {
2770 double *vertex =
new double[3];
2771 combine_work_data.push_back(vertex);
2772 memcpy(vertex, coords, 3 * (
sizeof *coords));
2776#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2777void vertexCallbackD_GLSL(GLvoid *vertex) {
2779 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2780 int new_buf_len = s_tess_buf_len + 100;
2781 GLfloat *tmp = s_tess_work_buf;
2784 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2785 if (NULL == s_tess_work_buf) {
2789 s_tess_buf_len = new_buf_len;
2792 GLdouble *pointer = (GLdouble *)vertex;
2794 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2795 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2800void beginCallbackD_GLSL(GLenum mode) {
2801 s_tess_vertex_idx_this = s_tess_vertex_idx;
2806void endCallbackD_GLSL() {
2810 shader->SetUniformMatrix4fv(
"MVMatrix",
2811 (GLfloat *)s_tessVP.vp_matrix_transform);
2813 mat4x4 identityMatrix;
2814 mat4x4_identity(identityMatrix);
2815 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2819 colorv[0] = s_regionColor.Red() / float(256);
2820 colorv[1] = s_regionColor.Green() / float(256);
2821 colorv[2] = s_regionColor.Blue() / float(256);
2822 colorv[3] = s_regionColor.Alpha() / float(256);
2823 shader->SetUniform4fv(
"color", colorv);
2825 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2826 shader->SetAttributePointerf(
"position", bufPt);
2828 glDrawArrays(s_tess_mode, 0, s_nvertex);
2833void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2835void beginCallbackD(GLenum mode) { glBegin(mode); }
2837void endCallbackD() { glEnd(); }
2841void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2842 float lat_dist, lon_dist;
2843 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2845 GLUtesselator *tobj = gluNewTess();
2846 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2848#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2849 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2850 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2851 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2852 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2856 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2857 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2858 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2859 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2862 gluTessNormal(tobj, 0, 0, 1);
2864 gluTessBeginPolygon(tobj, NULL);
2865 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2866 gluTessBeginContour(tobj);
2867 contour_pt l = *i->rbegin();
2869 bool sml_valid =
false;
2870 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2871 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2872 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2873 int splits = wxMax(lat_splits, lon_splits) + 1;
2879 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2880 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2883 for (
int i = 0; i < splits; i++) {
2885 if (i == splits - 1)
2886 lat = j->y, lon = j->x;
2888 double d = (double)(i + 1) / splits;
2889 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2893 if (std::isnan(q.m_x))
continue;
2895 double *p =
new double[6];
2900 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2905 gluTessVertex(tobj, p, p);
2906 combine_work_data.push_back(p);
2910 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2912 gluTessEndContour(tobj);
2914 gluTessEndPolygon(tobj);
2916 gluDeleteTess(tobj);
2918 for (std::list<double *>::iterator i = combine_work_data.begin();
2919 i != combine_work_data.end(); i++)
2921 combine_work_data.clear();
2926void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2927 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2929 if (s_b_useStencil) {
2931 glEnable(GL_STENCIL_TEST);
2933 glClear(GL_STENCIL_BUFFER_BIT);
2937 glStencilFunc(GL_ALWAYS, 1, 1);
2938 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2941#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2945 glEnable(GL_DEPTH_TEST);
2946 glDepthFunc(GL_ALWAYS);
2947 glDepthMask(GL_TRUE);
2949 glClear(GL_DEPTH_BUFFER_BIT);
2962 glTranslatef(0, 0, .5);
2966 s_regionColor = wxColor(0, 0, 0, 255);
2967 DrawRegion(vp, region);
2969 if (s_b_useStencil) {
2972 glStencilFunc(GL_EQUAL, 1, 1);
2973 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2976#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2978 glDepthFunc(GL_GREATER);
2979 glDepthMask(GL_FALSE);
2980 glTranslatef(0, 0, -.5);
2983 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2986void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2990 if (s_b_useStencil && s_b_useScissorTest) {
2992 if (rect != vp_rect) {
2993 glEnable(GL_SCISSOR_TEST);
2994 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2997#ifndef USE_ANDROID_GLES2
3003void glChartCanvas::DisableClipRegion() {
3004 glDisable(GL_SCISSOR_TEST);
3005 glDisable(GL_STENCIL_TEST);
3006 glDisable(GL_DEPTH_TEST);
3009void glChartCanvas::Invalidate() {
3011 m_cache_vp.Invalidate();
3017 if (!pBSBChart)
return;
3023 wxString key = chart->GetHashKey();
3027 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3030 if (ittf == hash.end()) {
3032 hash[key]->SetHashKey(key);
3035 pTexFact = hash[key];
3036 pTexFact->SetLRUTime(++m_LRUtime);
3041 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3042 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3049 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3050 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3051 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3052 base_level = log(scalefactor) / log(2.0);
3061 glEnable(GL_TEXTURE_2D);
3062#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3063 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3065 glEnableClientState(GL_VERTEX_ARRAY);
3066 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3071 pTexFact->GetCenter(lat, lon);
3072 MultMatrixViewPort(vp, lat, lon);
3076 LLBBox box = region.GetBox();
3079 if (g_memCacheLimit > 0) {
3084 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3085 for (
int i = 0; i < numtiles; i++) {
3087 if (region.IntersectOut(tile->box)) {
3090 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3091 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3093 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3094 global_color_scheme, mem_used);
3098 coords = tile->m_coords;
3100 coords =
new float[2 * tile->m_ncoords];
3101 for (
int i = 0; i < tile->m_ncoords; i++) {
3103 tile->m_coords[2 * i + 1]);
3104 coords[2 * i + 0] = p.m_x;
3105 coords[2 * i + 1] = p.m_y;
3109#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3110 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3111 m_pParentCanvas->GetpVP());
3114 glDisable(GL_TEXTURE_2D);
3118 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3119 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3120 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3122 if (!texture) glEnable(GL_TEXTURE_2D);
3124 if (!use_norm_vp)
delete[] coords;
3128 glDisable(GL_TEXTURE_2D);
3130#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3131 if (use_norm_vp) glPopMatrix();
3133 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3134 glDisableClientState(GL_VERTEX_ARRAY);
3138void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3140 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3141 m_pParentCanvas->m_pQuilt->IsBusy())
3145 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3147 printf(
" Chart NULL\n");
3148 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3158 LLRegion region = vp.GetLLRegion(rect_region);
3160 LLRegion rendered_region;
3166 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3174 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3176 LLRegion get_region = pqp->ActiveRegion;
3177 bool b_rendered =
false;
3179 if (!pqp->b_overlay) {
3180 get_region.Intersect(region);
3181 if (!get_region.Empty()) {
3182 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3185 SetClipRegion(vp, get_region );
3186 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3187 DisableClipRegion();
3190 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3191 SetClipRegion(vp, pqp->ActiveRegion );
3192 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3194 DisableClipRegion();
3197 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3198 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3199 RenderNoDTA(vp, get_region);
3200 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3205 if (Chs57->m_RAZBuilt) {
3206 RenderNoDTA(vp, get_region);
3207 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3208 rect_region, get_region);
3209 DisableClipRegion();
3214 const LLRegion &oregion = get_region;
3215 LLBBox box = oregion.GetBox();
3226 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3229 ViewPort cvp = ClippedViewport(vp, get_region);
3230 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3231 SetClipRegion(cvp, get_region);
3232 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3233 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3234 RenderWorldChart(gldc, cvp, srect, world);
3235 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3236 global_color_scheme);
3237 DisableClipRegion();
3244 SetClipRegion(vp, get_region);
3245 RenderNoDTA(vp, get_region);
3246 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3248 DisableClipRegion();
3251 SetClipRegion(vp, get_region);
3252 RenderNoDTA(vp, get_region);
3253 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3255 DisableClipRegion();
3271 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3275 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3276 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3278 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3279 if (pqp->b_Valid && pqp->b_overlay &&
3280 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3281 LLRegion get_region = pqp->ActiveRegion;
3283 get_region.Intersect(region);
3284 if (!get_region.Empty()) {
3287 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3292 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3299 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3304 ViewPort vph = m_pParentCanvas->GetVP();
3305 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3308 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3310 if (!hiregion.Empty()) {
3314 switch (global_color_scheme) {
3315 case GLOBAL_COLOR_SCHEME_DAY:
3318 case GLOBAL_COLOR_SCHEME_DUSK:
3321 case GLOBAL_COLOR_SCHEME_NIGHT:
3329#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3331 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3333 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3336 DrawRegion(vp, hiregion);
3338 glDisable(GL_BLEND);
3343 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3345 if (!hiregion.Empty()) {
3349 switch (global_color_scheme) {
3350 case GLOBAL_COLOR_SCHEME_DAY:
3353 case GLOBAL_COLOR_SCHEME_DUSK:
3356 case GLOBAL_COLOR_SCHEME_NIGHT:
3365#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3367 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3369 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3372 DrawRegion(vp, hiregion);
3374 glDisable(GL_BLEND);
3378 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3381void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3383 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3384 m_pParentCanvas->m_pQuilt->IsBusy())
3388 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3390 LLRegion region = vp.GetLLRegion(rect_region);
3392 LLRegion rendered_region;
3394 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3396 LLRegion get_region = pqp->ActiveRegion;
3398 if (!pqp->b_overlay) {
3399 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3402 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3407 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3414 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3442void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3443 ViewPort &vp = m_pParentCanvas->VPoint;
3451 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3452 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3455 LLRegion chart_region;
3457 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3458 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3459 CHART_FAMILY_RASTER) {
3467 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3468 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3469 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3471 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3475 for (
int i = 1; i < 6; i += 2)
3476 if (fabs(ll[i] - ll[i + 2]) > 180) {
3478 for (
int i = 1; i < 8; i += 2)
3479 if (ll[i] < 0) ll[i] += 360;
3483 chart_region = LLRegion(4, ll);
3486 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3488 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3489 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3490 chart_region = LLRegion(4, ll);
3493 chart_region = vp.b_quilt
3494 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3495 : m_pParentCanvas->m_singleChart->GetValidRegion();
3497 bool world_view =
false;
3499 wxRect rect = upd.GetRect();
3500 LLRegion background_region = vp.GetLLRegion(rect);
3503 background_region.Subtract(chart_region);
3505 if (!background_region.Empty()) {
3506 ViewPort cvp = ClippedViewport(vp, background_region);
3507 SetClipRect(cvp, rect,
false);
3508 RenderWorldChart(dc, cvp, rect, world_view);
3509 DisableClipRegion();
3514 RenderQuiltViewGL(vp, rect_region);
3517 LLRegion region = vp.GetLLRegion(rect_region);
3518 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3519 CHART_FAMILY_RASTER) {
3520 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3521 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3522 *m_pcontext, vp, rect_region, region);
3524 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3525 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3526 CHART_FAMILY_VECTOR) {
3527 chart_region.Intersect(region);
3528 RenderNoDTA(vp, chart_region);
3529 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3530 rect_region, region);
3536void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3538 wxColour color = GetGlobalColor(
"NODTA");
3539#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3541 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3543 glColor4ub(163, 180, 183, transparency);
3546 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3550 s_regionColor = color;
3553 DrawRegion(vp, region);
3557void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3560 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3562 glEnable(GL_SCISSOR_TEST);
3563 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3569 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3570#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3572 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3576 colorv[0] = water.Red() / float(256);
3577 colorv[1] = water.Green() / float(256);
3578 colorv[2] = water.Blue() / float(256);
3580 shader->SetUniform4fv(
"color", colorv);
3591 shader->SetAttributePointerf(
"position", pf);
3593 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3605 glDisable(GL_SCISSOR_TEST);
3613void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3614 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3616 DrawStaticRoutesTracksAndWaypoints(vp);
3618 DisableClipRegion();
3621void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3623 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3627 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3628 if (!bmp.Ok())
return;
3630 wxImage image = bmp.ConvertToImage();
3631 int w = image.GetWidth(), h = image.GetHeight();
3634 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3635 tex_w = w, tex_h = h;
3637 tex_w = NextPow2(w), tex_h = NextPow2(h);
3639 m_tideTexWidth = tex_w;
3640 m_tideTexHeight = tex_h;
3642 unsigned char *d = image.GetData();
3643 unsigned char *a = image.GetAlpha();
3645 unsigned char mr, mg, mb;
3646 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3648 unsigned char *e =
new unsigned char[4 * w * h];
3650 for (
int y = 0; y < h; y++)
3651 for (
int x = 0; x < w; x++) {
3652 unsigned char r, g, b;
3653 int off = (y * w + x);
3663 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3667 glGenTextures(1, &m_tideTex);
3669 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3670 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3671 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3673 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3674 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3675 GL_UNSIGNED_BYTE, e);
3677 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3678 GL_UNSIGNED_BYTE, 0);
3679 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3688 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3689 glEnable(GL_TEXTURE_2D);
3692#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3694 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3698 if ((type ==
't') || (type ==
'T'))
3703 if (BBox.Contains(lat, lon)) {
3712 scale *= getAndroidDisplayDensity();
3714 double width2 =
scale * m_tideTexWidth / 2;
3715 double height2 =
scale * m_tideTexHeight / 2;
3730 coords[0] = xp - width2;
3731 coords[1] = yp - height2;
3732 coords[2] = xp - width2;
3733 coords[3] = yp + height2;
3734 coords[4] = xp + width2;
3735 coords[5] = yp + height2;
3736 coords[6] = xp + width2;
3737 coords[7] = yp - height2;
3739 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3746 glDisable(GL_TEXTURE_2D);
3747 glDisable(GL_BLEND);
3748 glBindTexture(GL_TEXTURE_2D, 0);
3750 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3753void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3754 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3757void glChartCanvas::SetColorScheme(ColorScheme cs) {
3758 if (!m_bsetup)
return;
3760 glDeleteTextures(1, &m_tideTex);
3761 glDeleteTextures(1, &m_currentTex);
3767void glChartCanvas::RenderGLAlertMessage() {
3768 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3769 wxString msg = m_pParentCanvas->GetAlertString();
3772 m_gldc.SetFont(*pfont);
3776 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3783 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3784 int xp = sbr.x + sbr.width + 5;
3786 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3787 m_gldc.SetPen(ppPen1);
3788 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3790 m_gldc.DrawRectangle(xp, yp, w, h);
3792 m_gldc.DrawText(msg, xp, yp);
3796unsigned long quiltHash;
3798extern wxLongLong s_t0;
3801void glChartCanvas::Render() {
3802 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3803 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3804 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3809 if (!g_PrintingInProgress)
return;
3812 if (!g_true_zoom && m_binPinch)
return;
3815 long render_start_time = m_glstopwatch.Time();
3817#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3818 loadShaders(GetCanvasIndex());
3819 configureShaders(m_pParentCanvas->VPoint);
3822#ifdef USE_ANDROID_GLES2
3826 if (m_binPinch)
return;
3835 bool recompose =
false;
3836 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3837 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3838 if (m_pParentCanvas->VPoint.IsValid()) {
3839 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3840 m_pParentCanvas->UpdateCanvasControlBar();
3849 if (sw.GetTime() > 2000) {
3855 s_tess_vertex_idx = 0;
3856 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3857 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3863 m_displayScale = GetContentScaleFactor();
3867 m_last_render_time = wxDateTime::Now().GetTicks();
3871 if (g_GLOptions.m_bTextureCompression &&
3872 !g_GLOptions.m_bTextureCompressionCaching)
3877 int gl_width, gl_height;
3878 gl_width = m_pParentCanvas->VPoint.
pix_width;
3879 gl_height = m_pParentCanvas->VPoint.
pix_height;
3882 m_glcanvas_width = gl_width;
3883 m_glcanvas_height = gl_height;
3887 if (gl_height & 1) {
3889 ViewPort *vp = m_pParentCanvas->GetpVP();
3896 ViewPort *vp = m_pParentCanvas->GetpVP();
3904 ViewPort *vp = m_pParentCanvas->GetpVP();
3907 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3910 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3918 ViewPort VPoint = m_pParentCanvas->VPoint;
3920 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3921 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3924#if !defined(USE_ANDROID_GLES2)
3925 glMatrixMode(GL_PROJECTION);
3928 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3929 glMatrixMode(GL_MODELVIEW);
3933 if (s_b_useStencil) {
3934 glEnable(GL_STENCIL_TEST);
3935 glStencilMask(0xff);
3936 glClear(GL_STENCIL_BUFFER_BIT);
3937 glDisable(GL_STENCIL_TEST);
3943 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3944 if (g_GLOptions.m_GLPolygonSmoothing)
3945 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3946 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3958 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3959 bool useFBO =
false;
3965 if (m_b_BuiltFBO && !bpost_hilite
3970 bool b_newview =
true;
3971 bool b_full =
false;
3979 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3983#ifdef USE_ANDROID_GLES2
3984 if (recompose) b_newview =
true;
3996 if (VPoint.b_quilt) {
3997 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3998 if (!chart) b_full =
true;
4007 bool accelerated_pan =
false;
4017 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4018 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4019 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4021 wxPoint2DDouble c_old =
4024 wxPoint2DDouble c_new =
4028 dy = wxRound(c_new.m_y - c_old.m_y);
4029 dx = wxRound(c_new.m_x - c_old.m_x);
4039 double deltax = c_new.m_x - c_old.m_x;
4040 double deltay = c_new.m_y - c_old.m_y;
4042 bool b_whole_pixel =
true;
4043 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4044 b_whole_pixel =
false;
4046 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4047 abs(dy) < m_cache_tex_y &&
4048 (abs(dx) > 0 || (abs(dy) > 0));
4057 if (m_displayScale > 1) accelerated_pan =
false;
4062 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4065#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4068 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4074 if (b_full) accelerated_pan =
false;
4076 if (accelerated_pan) {
4077 if ((dx != 0) || (dy != 0)) {
4089 if (dy > 0 && dy < gl_height)
4090 update_region.Union(
4091 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4093 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4095 if (dx > 0 && dx < gl_width)
4096 update_region.Union(
4097 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4099 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4101 m_cache_page = !m_cache_page;
4104 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4105 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4117 RenderCharts(m_gldc, update_region);
4121 glDisable(g_texture_rectangle_format);
4126 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4127 glEnable(GL_TEXTURE_2D);
4131 float x1, x2, y1, y2;
4144 float tx1, tx2, ty1, ty2;
4150 tx2 = sx / (float)m_cache_tex_x;
4152 ty2 = sy / (float)m_cache_tex_y;
4169 coords[2] = -dx + sx;
4171 coords[4] = -dx + sx;
4172 coords[5] = dy + sy;
4174 coords[7] = dy + sy;
4177 ptexture_2D_shader_program[GetCanvasIndex()];
4181 shader->SetUniform1i(
"uTex", 0);
4185 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4186 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4187 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4189 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4211 shader->SetAttributePointerf(
"aPos", co1);
4212 shader->SetAttributePointerf(
"aUV", tco1);
4214 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4217 shader->SetUniformMatrix4fv(
"MVMatrix",
4218 (GLfloat *)VPoint.vp_matrix_transform);
4221 glBindTexture(g_texture_rectangle_format, 0);
4223 glDisable(g_texture_rectangle_format);
4231 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4232 g_texture_rectangle_format,
4233 m_cache_tex[!m_cache_page], 0);
4244 wxColour color = GetGlobalColor(
"NODTA");
4245 glClearColor(color.Red() / 256., color.Green() / 256.,
4246 color.Blue() / 256., 1.0);
4247 glClear(GL_COLOR_BUFFER_BIT);
4253 RenderCharts(m_gldc, rscreen_region);
4258 m_cache_page = !m_cache_page;
4263 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4274 glMatrixMode(GL_PROJECTION);
4277 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4278 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4280 glMatrixMode(GL_MODELVIEW);
4284 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4285 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4287 glGetIntegerv(GL_VIEWPORT, viewport);
4288 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4289 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4298 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4299 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4300 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4302 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4306 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4307 glEnable(g_texture_rectangle_format);
4309 float tx, ty, tx0, ty0, divx, divy;
4312 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4315 divx = m_cache_tex_x;
4316 divy = m_cache_tex_y;
4319 tx0 = m_fbo_offsetx / divx;
4320 ty0 = m_fbo_offsety / divy;
4321 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4322 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4347 wxColour color = GetGlobalColor(
"NODTA");
4348 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4350 glClear(GL_COLOR_BUFFER_BIT);
4352 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4355 glDisable(g_texture_rectangle_format);
4357 m_cache_vp = VPoint;
4358 m_cache_vp.Validate();
4360 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4362 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4366 RenderCharts(m_gldc, screen_region);
4375 RenderS57TextOverlay(VPoint);
4376 RenderMBTilesOverlay(VPoint);
4382 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4387 wxRect rt = upd.GetRect();
4388 LLRegion region = VPoint.GetLLRegion(rt);
4389 ViewPort cvp = ClippedViewport(VPoint, region);
4390 DrawGroundedOverlayObjects(gldc, cvp);
4393 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4394 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4395 LLBBox screenBox = screenLLRegion.GetBox();
4397 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4400 if (m_pParentCanvas->m_bShowTide) {
4401 m_pParentCanvas->RebuildTideSelectList(screenBox);
4402 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4405 if (m_pParentCanvas->m_bShowCurrent) {
4406 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4407 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4413 if (m_pParentCanvas->m_show_focus_bar &&
4414 (g_canvasConfig != 0)) {
4415 if (m_pParentCanvas == wxWindow::FindFocus()) {
4418 wxColour colour = GetGlobalColor(
"BLUE4");
4419 wxPen ppBlue(colour, 1);
4420 wxBrush ppBrush(colour);
4421 gldc.SetPen(ppBlue);
4422 gldc.SetBrush(ppBrush);
4423 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4424 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4425 wxPoint barPoints[4];
4428 barPoints[1].x = xw;
4430 barPoints[2].x = xw;
4431 barPoints[2].y = rect_pix;
4433 barPoints[3].y = rect_pix;
4435 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4439 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4443 DrawFloatingOverlayObjects(m_gldc);
4445#ifndef USE_ANDROID_GLES2
4448 glMatrixMode(GL_PROJECTION);
4451 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4452 glMatrixMode(GL_MODELVIEW);
4457 if (!g_bhide_depth_units)
4458 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4459 if (!g_bhide_overzoom_flag)
4460 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4463 ViewPort &vp = m_pParentCanvas->GetVP();
4468 if (!g_PrintingInProgress) {
4469 if (m_pParentCanvas->m_pTrackRolloverWin)
4470 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4472 if (m_pParentCanvas->m_pRouteRolloverWin)
4473 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4475 if (m_pParentCanvas->m_pAISRolloverWin)
4476 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4478 if (m_pParentCanvas->GetMUIBar())
4479 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4493 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4494 int x, y, width, height;
4495 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4496 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4497 wxBitmap bmp(width, height, -1);
4500 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4503 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4504 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4508 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4509 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4511 wxStringTokenizer tkz(s,
"\n");
4514 while (tkz.HasMoreTokens()) {
4515 token = tkz.GetNextToken();
4516 dc.DrawText(token, xt, yt);
4519 dc.SelectObject(wxNullBitmap);
4521 m_gldc.DrawBitmap(bmp, x, y,
false);
4527 if (g_bShowChartBar) DrawChartBar(m_gldc);
4529 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4531 m_pParentCanvas->m_Compass->Paint(gldc);
4533 if (m_pParentCanvas->IsPrimaryCanvas()) {
4534 auto ¬eman = NotificationManager::GetInstance();
4535 if (noteman.GetNotificationCount()) {
4536 m_pParentCanvas->m_notification_button->SetIconSeverity(
4537 noteman.GetMaxSeverity());
4538 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4539 m_pParentCanvas->m_notification_button->Show(
true);
4540 m_pParentCanvas->m_notification_button->Paint(gldc);
4542 m_pParentCanvas->m_notification_button->Show(
false);
4545 RenderGLAlertMessage();
4548 ViewPort &vp = m_pParentCanvas->GetVP();
4552 glActiveTexture(GL_TEXTURE0);
4556 if (g_bquiting) DrawQuiting();
4557 if (g_bcompression_wait)
4558 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4563 if (g_b_needFinish) glFinish();
4570 m_pParentCanvas->PaintCleanup();
4571 m_bforcefull =
false;
4580void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4583 if (VPoint.b_quilt) {
4584 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4585 ps52plib->GetShowS57Text()) {
4586 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4587 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4592 ChPI->ClearPLIBTextList();
4594 ps52plib->ClearTextList();
4604 RenderQuiltViewGLText(vpx, screen_region);
4609void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4612 LLRegion &screenLLRegion) {
4617 if (chart == NULL)
return;
4624 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4626 wxFileName tileFile(chart->GetFullPath());
4628 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4630 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4631 (tileSizeMB.GetLo() > 5000)) {
4634 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4635 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4636 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4643 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4647 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4650 std::vector<int> piano_active_array_tiles =
4651 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4652 bool bfound =
false;
4654 if (std::find(piano_active_array_tiles.begin(),
4655 piano_active_array_tiles.end(),
4656 dbIndex) != piano_active_array_tiles.end()) {
4661 piano_active_array_tiles.push_back(dbIndex);
4662 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4666void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4668 std::vector<int> stackIndexArray =
4669 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4670 unsigned int im = stackIndexArray.size();
4673 if (VPoint.b_quilt && im > 0) {
4674 bool regionVPBuilt =
false;
4676 LLRegion screenLLRegion;
4680 std::vector<int> tiles_to_show;
4681 for (
unsigned int is = 0; is < im; is++) {
4683 ChartData->GetChartTableEntry(stackIndexArray[is]);
4684 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4685 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4687 std::vector<int> piano_active_array_tiles =
4688 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4689 bool bfound =
false;
4691 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4692 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4693 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4701 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4702 piano_active_array_tiles);
4707 tiles_to_show.push_back(stackIndexArray[is]);
4708 if (!regionVPBuilt) {
4711 screenLLRegion = VPoint.GetLLRegion(screen_region);
4712 screenBox = screenLLRegion.GetBox();
4720 regionVPBuilt =
true;
4730 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4731 rit != tiles_to_show.rend(); ++rit) {
4732 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4734 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4735 rit != tiles_to_show.rend(); ++rit) {
4736 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4740 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4742 if (!hiregion.Empty()) {
4746 switch (global_color_scheme) {
4747 case GLOBAL_COLOR_SCHEME_DAY:
4750 case GLOBAL_COLOR_SCHEME_DUSK:
4753 case GLOBAL_COLOR_SCHEME_NIGHT:
4761#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4762 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4764 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4767 DrawRegion(VPoint, hiregion);
4769 glDisable(GL_BLEND);
4775void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4779 GetClientSize(&w, &h);
4781 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4782#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4783 glMatrixMode(GL_PROJECTION);
4786 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4787 glMatrixMode(GL_MODELVIEW);
4791 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4793 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4795 bool world_view =
false;
4796 RenderWorldChart(dc, cvp, rtex, world_view);
4803 glViewport(0, 0, (GLint)w, (GLint)h);
4804#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4805 glMatrixMode(GL_PROJECTION);
4808 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4809 glMatrixMode(GL_MODELVIEW);
4815void glChartCanvas::FastPan(
int dx,
int dy) {
4816#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4820void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4822 if (IsShown()) SetCurrent(*m_pcontext);
4823 float sx = GetSize().x;
4824 float sy = GetSize().y;
4825 glClear(GL_COLOR_BUFFER_BIT);
4828 GetClientSize(&w, &h);
4830 if (s_b_useStencil) {
4831 glEnable(GL_STENCIL_TEST);
4832 glStencilMask(0xff);
4833 glClear(GL_STENCIL_BUFFER_BIT);
4834 glDisable(GL_STENCIL_TEST);
4850 float sxfactor = sx / swidth;
4851 float syfactor = sy / sheight;
4853 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4854 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4855 sx * sx / swidth * 2, sy * sy / sheight * 2);
4856 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4857 glEnable(g_texture_rectangle_format);
4882 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4883 glBindTexture(g_texture_rectangle_format, 0);
4889 float tx, ty, tx0, ty0;
4899 glBindTexture(g_texture_rectangle_format, 0);
4902 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4903 glEnable(g_texture_rectangle_format);
4909 uv[0] = tx0 / m_cache_tex_x;
4910 uv[1] = ty / m_cache_tex_y;
4911 uv[2] = tx / m_cache_tex_x;
4912 uv[3] = ty / m_cache_tex_y;
4913 uv[4] = tx / m_cache_tex_x;
4914 uv[5] = ty0 / m_cache_tex_y;
4915 uv[6] = tx0 / m_cache_tex_x;
4916 uv[7] = ty0 / m_cache_tex_y;
4928 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4929 sx * sx / swidth, sy * sy / sheight);
4931 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4933 glDisable(g_texture_rectangle_format);
4934 glBindTexture(g_texture_rectangle_format, 0);
4941 wxColour color = GetGlobalColor(
"GREY1");
4942 float ht = -offset_y * (sy / sheight);
4943 wxRect r(0, sy - ht, w, ht);
4944 RenderColorRect(r, color);
4947 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4948 RenderColorRect(rt, color);
4951 float w1 = -offset_x * sx / swidth;
4952 wxRect rl(0, 0, w1, sy);
4953 RenderColorRect(rl, color);
4956 float px = w1 + sx * sx / swidth;
4957 wxRect rr(px, 0, sx - px, sy);
4958 RenderColorRect(rr, color);
4967void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4970 if (m_nRun < m_nTotal) {
4971 m_runoffsetx += m_offsetxStep;
4972 if (m_offsetxStep > 0)
4973 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4975 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4977 m_runoffsety += m_offsetyStep;
4978 if (m_offsetyStep > 0)
4979 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4981 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4983 m_runswidth += m_swidthStep;
4984 if (m_swidthStep > 0)
4985 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4987 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4989 m_runsheight += m_sheightStep;
4990 if (m_sheightStep > 0)
4991 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4993 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4998 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5004 if (m_zoomFinaldx || m_zoomFinaldy) {
5005 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5008 m_zoomFinal =
false;
5012void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5014 int sx = GetSize().x;
5015 int sy = GetSize().y;
5017 m_lastfbo_offsetx = m_fbo_offsetx;
5018 m_lastfbo_offsety = m_fbo_offsety;
5019 m_lastfbo_swidth = m_fbo_swidth;
5020 m_lastfbo_sheight = m_fbo_sheight;
5022 float curr_fbo_offset_x = m_fbo_offsetx;
5023 float curr_fbo_offset_y = m_fbo_offsety;
5024 float curr_fbo_swidth = m_fbo_swidth;
5025 float curr_fbo_sheight = m_fbo_sheight;
5027 float fx = (float)cp_x / sx;
5028 float fy = 1.0 - (float)cp_y / sy;
5030 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5031 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5033 m_fbo_swidth = curr_fbo_swidth / factor;
5034 m_fbo_sheight = curr_fbo_sheight / factor;
5036 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5037 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5039 m_fbo_offsetx += post_x;
5040 m_fbo_offsety += post_y;
5051 float perStep = m_nStep / m_nTotal;
5053 if (zoomTimer.IsRunning()) {
5054 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5055 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5056 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5057 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5060 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5061 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5062 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5063 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5065 m_runoffsetx = m_lastfbo_offsetx;
5066 m_runoffsety = m_lastfbo_offsety;
5067 m_runswidth = m_lastfbo_swidth;
5068 m_runsheight = m_lastfbo_sheight;
5071 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5072 m_zoomFinal =
false;
5078void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5082 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5085 if (m_binPinch)
return;
5086 if (m_bpinchGuard)
return;
5088 int x =
event.GetOffset().x;
5089 int y =
event.GetOffset().y;
5091 int lx =
event.GetLastOffset().x;
5092 int ly =
event.GetLastOffset().y;
5097 switch (event.GetState()) {
5098 case GestureStarted:
5099 if (m_binPan)
break;
5103 m_binGesture =
true;
5107 case GestureUpdated:
5112 m_pParentCanvas->FreezePiano();
5114 m_pParentCanvas->ThawPiano();
5125 case GestureFinished:
5128 m_pParentCanvas->UpdateCanvasControlBar();
5131 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5135 case GestureCanceled:
5137 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5144 m_bgestureGuard =
true;
5145 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5146 m_bforcefull =
false;
5151float zoom_inc = 1.0;
5153void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5154 float zoom_gain = 1.0;
5155 float zout_gain = 1.0;
5158 float total_zoom_val;
5160 float max_zoom_scale = 1000.;
5161 float min_zoom_scale = 2e8;
5163 if (event.GetScaleFactor() > 1)
5164 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5166 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5168 if (event.GetTotalScaleFactor() > 1)
5169 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5172 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5174 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5177 float max_zoom_scale = 1000.;
5178 if( cc1->GetVP().b_quilt) {
5179 int ref_index = cc1->GetQuiltRefChartdbIndex();
5186 float min_zoom_scale = 2e8;
5190 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5192 double projected_scale =
5193 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5195 switch (event.GetState()) {
5196 case GestureStarted:
5197 m_first_zout =
false;
5201 m_binGesture =
true;
5203 m_pinchStart =
event.GetCenterPoint();
5204 m_lpinchPoint = m_pinchStart;
5207 event.GetCenterPoint().y, m_pinchlat,
5212 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5213 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5216 if (IsShown()) SetCurrent(*m_pcontext);
5222 case GestureUpdated:
5224 if (projected_scale < min_zoom_scale) {
5225 wxPoint pinchPoint =
event.GetCenterPoint();
5227 float dx = pinchPoint.x - m_lpinchPoint.x;
5228 float dy = pinchPoint.y - m_lpinchPoint.y;
5230 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5231 -dx / total_zoom_val, dy / total_zoom_val);
5233 m_lpinchPoint = pinchPoint;
5237 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5238 wxPoint pinchPoint =
event.GetCenterPoint();
5240 float dx = pinchPoint.x - m_lpinchPoint.x;
5241 float dy = pinchPoint.y - m_lpinchPoint.y;
5243 if ((projected_scale > max_zoom_scale) &&
5244 (projected_scale < min_zoom_scale))
5245 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5246 -dx / total_zoom_val, dy / total_zoom_val);
5248 m_lpinchPoint = pinchPoint;
5251 m_first_zout =
true;
5252 zoom_inc *= zoom_val;
5253 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5254 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5258 wxPoint pinchPoint =
event.GetCenterPoint();
5259 float dx = pinchPoint.x - m_lpinchPoint.x;
5260 float dy = pinchPoint.y - m_lpinchPoint.y;
5262 m_lpinchPoint = pinchPoint;
5273 case GestureFinished: {
5277 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5278 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5282 float tzoom = total_zoom_val;
5284 if (projected_scale >= min_zoom_scale)
5285 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5287 if (projected_scale < max_zoom_scale)
5288 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5290 dx = (cc_x - m_cc_x) * tzoom;
5291 dy = -(cc_y - m_cc_y) * tzoom;
5293 if (zoomTimer.IsRunning()) {
5296 m_zoomFinalZoom = tzoom;
5302 double final_projected_scale =
5306 if (final_projected_scale < min_zoom_scale) {
5310 m_pParentCanvas->m_pQuilt->Invalidate();
5311 m_bforcefull =
true;
5318 m_pParentCanvas->m_pQuilt->Invalidate();
5319 m_bforcefull =
true;
5331 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5335 case GestureCanceled:
5337 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5344 m_bgestureGuard =
true;
5346 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5349void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5359 m_bgestureGuard =
false;
5360 m_bpinchGuard =
false;
5361 m_binGesture =
false;
5362 m_bforcefull =
false;
5365void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5369 m_binGesture =
false;
5370 m_bforcefull =
false;
5374#ifdef HAVE_WX_GESTURE_EVENTS
5376void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5379 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5382 if (m_binPinch)
return;
5383 if (m_bpinchGuard)
return;
5385 int dx =
event.GetDelta().x;
5386 int dy =
event.GetDelta().y;
5388 if (event.IsGestureStart()) {
5389 if (m_binPan)
return;
5393 m_binGesture =
true;
5397 else if (event.IsGestureEnd()) {
5399 m_pParentCanvas->UpdateCanvasControlBar();
5401 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5409 m_pParentCanvas->FreezePiano();
5411 m_pParentCanvas->ThawPiano();
5422 m_bgestureGuard =
true;
5423 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5424 m_bforcefull =
false;
5428void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5430 float zoom_gain = 1.0;
5431 float zout_gain = 1.0;
5433 float last_zoom_val = m_step_zoom_val;
5435 float max_zoom_scale = 1000.;
5436 float min_zoom_scale = 2e8;
5438 if (event.GetZoomFactor() > 1)
5439 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5441 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5443 float inc_zoom_val =
5444 m_total_zoom_val / last_zoom_val;
5448 if (event.IsGestureStart()) {
5449 m_glstopwatch.Start();
5450 printf(
"\nStart--------------\n");
5452 m_pParentCanvas->m_inPinch =
true;
5455 m_binGesture =
true;
5456 m_pinchStart =
event.GetPosition();
5457 m_lpinchPoint = m_pinchStart;
5458 m_total_zoom_val = 1.0;
5459 m_final_zoom_val = 1.0;
5460 m_step_zoom_val = 1.0;
5464 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5468 if (event.IsGestureEnd()) {
5470 if (!m_binGesture)
return;
5471 printf(
"EndZoom--------------\n");
5478 m_final_zoom_val = 1.0;
5479 m_total_zoom_val = 1.0;
5480 m_step_zoom_val = 1.0;
5482 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5489 float zoom_step = 5;
5490 float zoom_trigger = 0.05;
5491 if (projected_scale > 1e5)
5493 else if (projected_scale < 3e4)
5496 if (inc_zoom_val != 1.0) {
5497 if (inc_zoom_val > 1 + zoom_step) {
5498 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5499 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5501 if (IsShown()) SetCurrent(*m_pcontext);
5504 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5505 m_step_zoom_val = m_total_zoom_val;
5506 printf(
" Zoom: %6g\n", inc_zoom_val);
5511 bool b_allow_ztp =
true;
5512 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5513 b_allow_ztp =
false;
5515 if (g_bEnableZoomToCursor && b_allow_ztp) {
5521 int dx = r.x -
event.GetPosition().x;
5522 int dy = r.y -
event.GetPosition().y;
5526 if (IsShown()) SetCurrent(*m_pcontext);
5535 float zoom_gain = 1.0;
5536 float zout_gain = 1.0;
5538 float last_zoom_val = m_total_zoom_val;
5540 float max_zoom_scale = 1000.;
5541 float min_zoom_scale = 2e8;
5543 if (event.GetZoomFactor() > 1)
5544 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5546 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5548 float inc_zoom_val =
5549 m_total_zoom_val / last_zoom_val;
5551 double projected_scale =
5552 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5554 if (event.IsGestureStart()) {
5556 m_first_zout =
false;
5560 m_binGesture =
true;
5561 m_pinchStart =
event.GetPosition();
5562 m_lpinchPoint = m_pinchStart;
5563 m_total_zoom_val = 1.0;
5564 m_final_zoom_val = 1.0;
5567 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5571 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5572 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5575 if (IsShown()) SetCurrent(*m_pcontext);
5578 ViewPort vpr = m_pParentCanvas->VPoint;
5580 GetTouchBackingBitmap(vpr);
5585 if (event.IsGestureEnd()) {
5591 if (!m_binGesture)
return;
5593 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5594 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5598 float tzoom = m_final_zoom_val;
5600 dx = (cc_x - m_cc_x) * tzoom;
5601 dy = -(cc_y - m_cc_y) * tzoom;
5603 if (zoomTimer.IsRunning()) {
5606 m_zoomFinalZoom = tzoom;
5612 double final_projected_scale =
5616 if (final_projected_scale < min_zoom_scale) {
5620 m_pParentCanvas->m_pQuilt->Invalidate();
5621 m_bforcefull =
true;
5628 m_pParentCanvas->m_pQuilt->Invalidate();
5629 m_bforcefull =
true;
5634 m_final_zoom_val = 1.0;
5635 m_total_zoom_val = 1.0;
5636 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5641 if (projected_scale < min_zoom_scale) {
5642 wxPoint pinchPoint =
event.GetPosition();
5644 float dx = pinchPoint.x - m_lpinchPoint.x;
5645 float dy = pinchPoint.y - m_lpinchPoint.y;
5647 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5648 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5650 m_lpinchPoint = pinchPoint;
5651 m_final_zoom_val *= inc_zoom_val;
5655 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5656 wxPoint pinchPoint =
event.GetPosition();
5658 float dx = pinchPoint.x - m_lpinchPoint.x;
5659 float dy = pinchPoint.y - m_lpinchPoint.y;
5661 if ((projected_scale > max_zoom_scale) &&
5662 (projected_scale < min_zoom_scale))
5663 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5664 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5666 m_lpinchPoint = pinchPoint;
5667 m_final_zoom_val *= inc_zoom_val;
5670 m_first_zout =
true;
5671 m_zoom_inc *= inc_zoom_val;
5672 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5673 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5677 wxPoint pinchPoint =
event.GetPosition();
5678 float dx = pinchPoint.x - m_lpinchPoint.x;
5679 float dy = pinchPoint.y - m_lpinchPoint.y;
5681 m_lpinchPoint = pinchPoint;
5685 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5688 m_bgestureGuard =
true;
5689 m_bpinchGuard =
true;
5692void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5701 m_bgestureGuard =
false;
5702 m_bpinchGuard =
false;
5703 m_binGesture =
false;
5704 m_bforcefull =
false;
5707void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5711 m_binGesture =
false;
5712 m_bforcefull =
false;
5714 m_pParentCanvas->m_inPinch =
false;
5715 printf(
"******Finish\n");
5721void glChartCanvas::configureShaders(
ViewPort &vp) {
5722#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5728 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5730 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5731 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5752 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5754 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5755 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5767 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5769 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5770 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5773 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5775 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5776 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5784 shader = pAALine_shader_program[GetCanvasIndex()];
5786 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5789 shader = pring_shader_program[GetCanvasIndex()];
5791 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5792 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5796 if (texture_2DA_shader_program) {
5797 glUseProgram(texture_2DA_shader_program);
5798 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5799 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5800 (
const GLfloat *)pvp->vp_matrix_transform);
5802 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5803 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5811void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5814#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5815 int nl = nVertex / 4;
5817 float *luv = uvCoords;
5820 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5828 glEnableClientState(GL_VERTEX_ARRAY);
5829 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5831 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5832 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5833 glDrawArrays(GL_QUADS, 0, 4);
5840void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5841 float *uvCoords,
ViewPort *vp,
float dx,
5842 float dy,
float angle_rad) {
5843#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5845 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5846 if (!shader)
return;
5851 shader->SetUniform1i(
"uTex", 0);
5856 mat4x4_rotate_Z(Q, I, angle_rad);
5862 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5867 shader->SetAttributePointerf(
"aPos", co1);
5868 shader->SetAttributePointerf(
"aUV", tco1);
5875 GLushort indices1[] = {0,1,3,2};
5876 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5888 tco1[0] = uvCoords[0];
5889 tco1[1] = uvCoords[1];
5890 tco1[2] = uvCoords[2];
5891 tco1[3] = uvCoords[3];
5892 tco1[4] = uvCoords[6];
5893 tco1[5] = uvCoords[7];
5894 tco1[6] = uvCoords[4];
5895 tco1[7] = uvCoords[5];
5900 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5912void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5913#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5915 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5918 shader->SetUniformMatrix4fv(
5919 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5922 colorv[0] = color.Red() / float(256);
5923 colorv[1] = color.Green() / float(256);
5924 colorv[2] = color.Blue() / float(256);
5926 shader->SetUniform4fv(
"color", colorv);
5929 pf[0] = r.x + r.width;
5933 pf[4] = r.x + r.width;
5934 pf[5] = r.y + r.height;
5936 pf[7] = r.y + r.height;
5937 shader->SetAttributePointerf(
"position", pf);
5939 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5947void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5948#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5950 ViewPort VPoint = m_pParentCanvas->VPoint;
5954 GetClientSize(&w, &h);
5955 int sx = GetSize().x;
5956 int sy = GetSize().y;
5960 glViewport(0, 0, (GLint)w, (GLint)h);
5962 if (s_b_useStencil) {
5963 glEnable(GL_STENCIL_TEST);
5964 glStencilMask(0xff);
5965 glClear(GL_STENCIL_BUFFER_BIT);
5966 glDisable(GL_STENCIL_TEST);
5970 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5975 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5976 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5977 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5980 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5982 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5983 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5991 if (bRenderCharts) RenderCharts(gldc, screen_region);
5993 if (bRenderOverlays) {
5994 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5995 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
6001 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
6004 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
6005 DrawDynamicRoutesTracksAndWaypoints(VPoint);
6006 DrawFloatingOverlayObjects(m_gldc);
6010 glBindFramebuffer(GL_FRAMEBUFFER, 0);
6015wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
6017 wxMemoryDC tdc(tbm);
6018 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6026 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6027 dc.SetPen(*wxTRANSPARENT_PEN);
6030 tdc.SelectObject(wxNullBitmap);
6031 m_touch_backing_bitmap = tbm;
6032 CreateBackingTexture();
6034 return m_touch_backing_bitmap;
6037void glChartCanvas::CreateBackingTexture() {
6038 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6039 unsigned char *imgdata = image.GetData();
6040 unsigned char *imgalpha = image.GetAlpha();
6041 m_tex_w = image.GetWidth();
6042 m_tex_h = image.GetHeight();
6043 m_image_width = m_tex_w;
6044 m_image_height = m_tex_h;
6046 GLuint format = GL_RGBA;
6047 GLuint internalformat = g_texture_rectangle_format;
6049 internalformat = GL_RGBA;
6054 unsigned char *teximage =
6055 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6057 for (
int i = 0; i < m_image_height; i++) {
6058 for (
int j = 0; j < m_image_width; j++) {
6059 int s = (i * 3 * m_image_width) + (j * 3);
6060 int d = (i * stride * m_tex_w) + (j * stride);
6062 teximage[d + 0] = imgdata[s + 0];
6063 teximage[d + 1] = imgdata[s + 1];
6064 teximage[d + 2] = imgdata[s + 2];
6065 teximage[d + 3] = 255;
6069 glGenTextures(1, &m_TouchBackingTexture);
6070 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6072 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6073 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6074 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6076 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6078 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6079 GL_UNSIGNED_BYTE, teximage);
6082 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.