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() {
488void glChartCanvas::FlushFBO() {
489 if (m_bsetup) BuildFBO();
492void glChartCanvas::OnActivate(wxActivateEvent &event) {
493 m_pParentCanvas->OnActivate(event);
496void glChartCanvas::OnSize(wxSizeEvent &event) {
500 wxLogMessage(
"Got OnSize event while NOT running");
502 qDebug() <<
"OnSizeB";
509 if (!IsShown() || !m_bsetup)
return;
511 SetCurrent(*m_pcontext);
515 SetSize(GetSize().x, GetSize().y);
523 if (m_pcontext && IsShown()) {
524 SetCurrent(*m_pcontext);
529 wxLogDebug(
"BuildFBO 3");
533 ViewPort *vp = m_pParentCanvas->GetpVP();
536 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
539 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
543void glChartCanvas::MouseEvent(wxMouseEvent &event) {
544 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
550 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
552 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
555 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
559 if (m_bgestureGuard) {
560 m_pParentCanvas->r_rband.x = 0;
570 if (event.LeftUp()) {
572 if ((abs(panx) > 2) || (abs(pany) > 2)) {
575 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
582 if (!event.LeftDClick()) {
587 if (m_binPan && event.RightDown()) {
588 qDebug() <<
"Skip right on pan";
591 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
593 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
594 if (!m_bgestureGuard)
604#ifndef GL_MAX_RENDERBUFFER_SIZE
605#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
608#ifndef USE_ANDROID_GLES2
609bool glChartCanvas::buildFBOSize(
int fboSize) {
611 if (IsShown()) SetCurrent(*m_pcontext);
614 glDeleteTextures(2, m_cache_tex);
615 glDeleteFramebuffers(1, &m_fb0);
616 glDeleteRenderbuffers(1, &m_renderbuffer);
617 m_b_BuiltFBO =
false;
620 if (m_b_DisableFBO)
return false;
624 int rb_x = GetSize().x;
625 int rb_y = GetSize().y;
627 while (i < rb_x) i <<= 1;
631 while (i < rb_y) i <<= 1;
634 m_cache_tex_x = wxMax(rb_x, rb_y);
635 m_cache_tex_y = wxMax(rb_x, rb_y);
638 m_cache_tex_x = GetSize().x * m_displayScale;
639 m_cache_tex_y = GetSize().y * m_displayScale;
642 int err = GL_NO_ERROR;
644 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
647 if (err == GL_INVALID_ENUM) {
648 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
652 if (err == GL_NO_ERROR) {
653 if (fboSize > params) {
655 " OpenGL-> Requested Framebuffer size exceeds "
656 "GL_MAX_RENDERBUFFER_SIZE");
661 glGenFramebuffers(1, &m_fb0);
665 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
670 glGenRenderbuffers(1, &m_renderbuffer);
674 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
679 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
683 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
689 glGenTextures(2, m_cache_tex);
690 for (
int i = 0; i < 2; i++) {
691 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
692 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
694 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
696 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
697 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
700 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
702 if (m_b_useFBOStencil) {
704 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
705 m_cache_tex_x, m_cache_tex_y);
707 int err = glGetError();
710 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
714 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
715 GL_RENDERBUFFER_EXT, m_renderbuffer);
719 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
724 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
725 GL_RENDERBUFFER_EXT, m_renderbuffer);
729 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
735 GLenum depth_format = GL_DEPTH_COMPONENT24;
740 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
744 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
746 int err = glGetError();
749 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
755 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
756 GL_RENDERBUFFER_EXT, m_renderbuffer);
761 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
768 glBindTexture(GL_TEXTURE_2D, 0);
769 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
772 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
774 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
775 g_texture_rectangle_format, m_cache_tex[0], 0);
777 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
779 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
781 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
783 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
793#ifdef USE_ANDROID_GLES2
794bool glChartCanvas::buildFBOSize(
int fboSize) {
798 int rb_x = GetSize().x;
799 int rb_y = GetSize().y;
801 while (i < rb_x) i <<= 1;
805 while (i < rb_y) i <<= 1;
808 m_cache_tex_x = wxMax(rb_x, rb_y);
809 m_cache_tex_y = wxMax(rb_x, rb_y);
813 int err = GL_NO_ERROR;
815 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
818 if (err == GL_INVALID_ENUM) {
819 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
823 if (err == GL_NO_ERROR) {
824 if (fboSize > params) {
826 " OpenGL-> Requested Framebuffer size exceeds "
827 "GL_MAX_RENDERBUFFER_SIZE");
832 glGenFramebuffers(1, &m_fb0);
836 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
841 glGenRenderbuffers(1, &m_renderbuffer);
845 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
850 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
854 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
860 glGenTextures(2, m_cache_tex);
861 for (
int i = 0; i < 2; i++) {
862 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
863 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
865 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
867 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
868 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
871 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
874 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
880 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
884 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
885 GL_RENDERBUFFER, m_renderbuffer);
889 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
894 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
895 GL_RENDERBUFFER, m_renderbuffer);
899 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
904 glBindTexture(GL_TEXTURE_2D, 0);
905 glBindFramebuffer(GL_FRAMEBUFFER, 0);
908 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
910 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
911 g_texture_rectangle_format, m_cache_tex[0], 0);
913 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
915 glBindFramebuffer(GL_FRAMEBUFFER, 0);
917 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
919 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
929void glChartCanvas::BuildFBO() {
932 glDeleteTextures(2, m_cache_tex);
933 glDeleteFramebuffers(1, &m_fb0);
934 glDeleteRenderbuffers(1, &m_renderbuffer);
935 m_b_BuiltFBO =
false;
938 if (m_b_DisableFBO)
return;
941 int gl_width, gl_height;
942 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
943 int initialSize = NextPow2(gl_width * m_displayScale);
948 wxString info = androidGetDeviceInfo();
950 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
953 if (!buildFBOSize(initialSize)) {
954 glDeleteTextures(2, m_cache_tex);
955 glDeleteFramebuffers(1, &m_fb0);
956 glDeleteRenderbuffers(1, &m_renderbuffer);
958 if (!buildFBOSize(1024)) {
959 wxLogMessage(
"BuildFBO C");
961 m_b_DisableFBO =
true;
962 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
963 m_b_BuiltFBO =
false;
972 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
984void glChartCanvas::SetupOpenGL() {
985 if (IsShown()) SetCurrent(*m_pcontext);
987 char *str = (
char *)glGetString(GL_RENDERER);
990 wxLogMessage(
"Failed to initialize OpenGL");
994 char render_string[80];
995 strncpy(render_string, str, 79);
996 m_renderer = wxString(render_string, wxConvUTF8);
999 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1000 msg.Printf(
"OpenGL-> Renderer String: ");
1004 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1006 char version_string[80];
1007 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1008 msg.Printf(
"OpenGL-> Version reported: ");
1009 m_version = wxString(version_string, wxConvUTF8);
1013 char GLSL_version_string[80];
1014 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1016 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1017 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1018 msg += m_GLSLversion;
1023 GLenum err = glewInit();
1024#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1025 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1030 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1033 wxLogMessage(
"GLEW init success!n");
1038 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1039 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1043#ifndef USE_ANDROID_GLES2
1044 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1046 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1048 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1049 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1056 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1058 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1060 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1063 s_b_useScissorTest =
true;
1065 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1066 s_b_useScissorTest =
false;
1068 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1069 s_b_useScissorTest =
false;
1071 bool bad_stencil_code =
false;
1074 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1075 bad_stencil_code =
true;
1078 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1081 glEnable(GL_STENCIL_TEST);
1082 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1084 glGetIntegerv(GL_STENCIL_BITS, &sb);
1087 glDisable(GL_STENCIL_TEST);
1089 s_b_useStencil =
false;
1090 if (stencil && (sb == 8)) s_b_useStencil =
true;
1092 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1093 g_texture_rectangle_format = GL_TEXTURE_2D;
1094 else if (QueryExtension(
"GL_OES_texture_npot"))
1095 g_texture_rectangle_format = GL_TEXTURE_2D;
1096 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1097 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1098 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1099 g_texture_rectangle_format));
1102 g_texture_rectangle_format = GL_TEXTURE_2D;
1106 g_b_EnableVBO =
true;
1109 g_b_EnableVBO =
false;
1113 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1115 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1119 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1121 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1124#ifndef USE_ANDROID_GLES2
1126 if (bad_stencil_code) s_b_useStencil =
false;
1140 if (m_displayScale > 1) m_b_DisableFBO =
true;
1149 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1151 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1152 g_texture_rectangle_format, m_cache_tex[0], 0);
1154 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1155 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1157 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1159 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1161 m_b_DisableFBO =
true;
1167 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1171 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1173#ifdef USE_ANDROID_GLES2
1174 s_b_useStencilAP = s_b_useStencil;
1181 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1183 if (m_b_useFBOStencil)
1184 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1186 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1188 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1191 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1193 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1195 if (s_b_useScissorTest && s_b_useStencil)
1196 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1199 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1201 MipMap_ResolveRoutines();
1205 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1206 g_GLMinCartographicLineWidth);
1207 wxLogMessage(lwmsg);
1208 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1209 g_GLMinSymbolLineWidth);
1210 wxLogMessage(lwmsg);
1213 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1215#ifdef USE_ANDROID_GLES2
1216 g_GLOptions.m_bUseAcceleratedPanning =
true;
1222 int tex_dim = g_GLOptions.m_iTextureDimension;
1223 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1232 s_b_useFBO = m_b_BuiltFBO;
1236 ps52plib->SetGLOptions(
1237 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1238 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1239 g_GLMinSymbolLineWidth);
1243 SendJSONConfigMessage();
1246void glChartCanvas::SendJSONConfigMessage() {
1249 v[
"setupComplete"] = m_bsetup;
1250 v[
"useStencil"] = s_b_useStencil;
1251 v[
"useStencilAP"] = s_b_useStencilAP;
1252 v[
"useScissorTest"] = s_b_useScissorTest;
1253 v[
"useFBO"] = s_b_useFBO;
1254 v[
"useVBO"] = g_b_EnableVBO;
1255 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1256 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1257 SendJSONMessageToAllPlugins(msg_id, v);
1260void glChartCanvas::SetupCompression() {
1261 int dim = g_GLOptions.m_iTextureDimension;
1264 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1265 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1266 goto no_compression;
1270 g_uncompressed_tile_size = dim * dim * 4;
1271 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1277 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1280 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1290 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1291 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1294 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1295 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1300 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1301 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1304 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1306 wxLogMessage(
"OpenGL-> No Useable compression format found");
1307 goto no_compression;
1312 g_tile_size = 512 * 512 / 2;
1316 glGenTextures(1, &texture);
1317 glBindTexture(GL_TEXTURE_2D, texture);
1319 GL_UNSIGNED_BYTE, NULL);
1320 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1322 glDeleteTextures(1, &texture);
1326 if (g_tile_size == 0)
goto no_compression;
1328 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1330 g_uncompressed_tile_size / g_tile_size));
1334 g_GLOptions.m_bTextureCompression =
false;
1336 g_tile_size = g_uncompressed_tile_size;
1337 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1340void glChartCanvas::OnPaint(wxPaintEvent &event) {
1342 if (!m_pcontext)
return;
1350 if (IsShown()) SetCurrent(*m_pcontext);
1355 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1363 if (!m_b_paint_enable)
return;
1366 if (m_in_glpaint)
return;
1369 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1392bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1394#ifndef USE_ANDROID_GLES2
1395 return vp.m_projection_type == PROJECTION_MERCATOR ||
1396 vp.m_projection_type == PROJECTION_POLAR ||
1397 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1411#define NORM_FACTOR 4096.0
1412void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1413#ifndef USE_ANDROID_GLES2
1415 wxPoint2DDouble point;
1417 switch (vp.m_projection_type) {
1418 case PROJECTION_MERCATOR:
1419 case PROJECTION_EQUIRECTANGULAR:
1420 case PROJECTION_WEB_MERCATOR:
1423 glTranslated(point.m_x, point.m_y, 0);
1428 case PROJECTION_POLAR:
1432 glTranslated(point.m_x, point.m_y, 0);
1433 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1440 printf(
"ERROR: Unhandled projection\n");
1445 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1453 switch (vp.m_projection_type) {
1454 case PROJECTION_MERCATOR:
1455 case PROJECTION_EQUIRECTANGULAR:
1456 case PROJECTION_WEB_MERCATOR:
1460 case PROJECTION_POLAR:
1465 printf(
"ERROR: Unhandled projection\n");
1474bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1475 return vp.m_projection_type == PROJECTION_MERCATOR ||
1476 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1477 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1481 const LLRegion ®ion) {
1482 if (!CanClipViewport(vp))
return vp;
1485 LLBBox bbox = region.GetBox();
1487 if (!bbox.GetValid())
return vp;
1495 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1496 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1497 bbox.GetMaxLon() + 360);
1498 cvp.SetBBoxDirect(bbox);
1499 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1500 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1501 bbox.GetMaxLon() - 360);
1502 cvp.SetBBoxDirect(bbox);
1504 cvp.SetBBoxDirect(bbox);
1509void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1510 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1516 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1518 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1522 if (!pRouteDraw)
continue;
1525 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1528 if (pRouteDraw->m_bIsBeingEdited)
continue;
1530 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1535 if (vp.GetBBox().GetValid() && pWayPointMan) {
1536 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1537 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1538 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1544void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1549 if (pActiveTrack && pActiveTrack->IsRunning())
1550 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1556 if (!pRouteDraw)
continue;
1559 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1562 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1565 if (pRouteDraw->IsSelected()) drawit++;
1568 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1569 if (!vp_box.IntersectOut(test_box))
1570 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1576 if (vp.GetBBox().GetValid() && pWayPointMan) {
1577 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1578 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1585static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1589 switch (vp.m_projection_type) {
1590 case PROJECTION_TRANSVERSE_MERCATOR:
1591 lat_dist = 4, lon_dist = 1;
1593 case PROJECTION_POLYCONIC:
1594 lat_dist = 2, lon_dist = 1;
1596 case PROJECTION_ORTHOGRAPHIC:
1597 lat_dist = 2, lon_dist = 2;
1599 case PROJECTION_POLAR:
1600 lat_dist = 180, lon_dist = 1;
1602 case PROJECTION_STEREOGRAPHIC:
1603 case PROJECTION_GNOMONIC:
1604 lat_dist = 2, lon_dist = 1;
1606 case PROJECTION_EQUIRECTANGULAR:
1609 lat_dist = 2, lon_dist = 360;
1612 lat_dist = 180, lon_dist = 360;
1616void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1617 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1623 ChartData->GetDBBoundingBox(dbIndex, box);
1624 if (!box.GetValid())
return;
1628 if (box.GetLonRange() == 360)
return;
1630 LLBBox vpbox = vp.GetBBox();
1632 double lon_bias = 0;
1634 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1637 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1638 color = GetGlobalColor(
"YELO1");
1639 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1640 color = GetGlobalColor(
"GREEN2");
1642 color = GetGlobalColor(
"UINFR");
1644#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1645 float plylat, plylon;
1647 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1649 glColor3ub(color.Red(), color.Green(), color.Blue());
1650 glLineWidth(g_GLMinSymbolLineWidth);
1652 float lat_dist, lon_dist;
1653 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1656 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1660 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1662 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1664 bool begin =
false, sml_valid =
false;
1666 float lastplylat = 0.0;
1667 float lastplylon = 0.0;
1669 int modulo = (nPly == 0) ? 1 : nPly;
1670 for (
int i = 0; i < nPly + 1; i++) {
1672 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1674 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1678 if (lastplylon - plylon > 180)
1680 else if (lastplylon - plylon < -180)
1687 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1688 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1689 splits = wxMax(lat_splits, lon_splits) + 1;
1696 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1697 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1700 for (
double c = 0; c < splits; c++) {
1702 if (c == splits - 1)
1703 lat = plylat, lon = plylon;
1705 double d = (double)(c + 1) / splits;
1706 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1712 if (!std::isnan(s.m_x)) {
1715 glBegin(GL_LINE_STRIP);
1717 glVertex2f(s.m_x, s.m_y);
1723 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1724 lastplylat = plylat, lastplylon = plylon;
1729 }
while (++j < nAuxPlyEntries);
1731 glDisable(GL_LINE_SMOOTH);
1735 double nominal_line_width_pix =
1736 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1738 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1739 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1742 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1743 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1747 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1750 float plylat1, plylon1;
1754 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1755 if (0 == nAuxPlyEntries)
1758 std::vector<int> points_vector;
1760 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1761 int nPly = vec.size() / 2;
1763 if (nPly == 0)
return;
1765 for (
int i = 0; i < nPly; i++) {
1766 plylon1 = vec[i * 2];
1767 plylat1 = vec[i * 2 + 1];
1773 points_vector.push_back(pixx1);
1774 points_vector.push_back(pixy1);
1777 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1778 plylon1 += lon_bias;
1784 points_vector.push_back(pixx1);
1785 points_vector.push_back(pixy1);
1787 if (points_vector.size()) {
1788 std::vector<int>::iterator it = points_vector.begin();
1789 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1797 for (
int j = 0; j < nAuxPlyEntries; j++) {
1798 std::vector<int> points_vector;
1800 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1801 int nAuxPly = vec.size() / 2;
1803 if (nAuxPly == 0)
continue;
1805 for (
int i = 0; i < nAuxPly; i++) {
1806 plylon1 = vec[i * 2];
1807 plylat1 = vec[i * 2 + 1];
1813 points_vector.push_back(pixx1);
1814 points_vector.push_back(pixy1);
1821 points_vector.push_back(pixx1);
1822 points_vector.push_back(pixy1);
1824 if (points_vector.size()) {
1825 std::vector<int>::iterator it = points_vector.begin();
1826 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1834extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1835 float &MinorSpacing);
1836extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1837void glChartCanvas::GridDraw() {
1838 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1840 ViewPort &vp = m_pParentCanvas->GetVP();
1842 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1846 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1848 double nlat, elon, slat, wlon;
1850 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1853 wxColour GridColor = GetGlobalColor(
"SNDG1");
1855 if (!m_gridfont.IsBuilt()) {
1857 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1858 wxFont font = *dFont;
1859 int font_size = wxMax(10, dFont->GetPointSize());
1860 font.SetPointSize(font_size * m_displayScale);
1861 font.SetWeight(wxFONTWEIGHT_NORMAL);
1864 m_gridfont.Build(font, 1, dpi_factor);
1866 m_gridfont.SetColor(GridColor);
1871 LLBBox llbbox = vp.GetBBox();
1872 nlat = llbbox.GetMaxLat();
1873 slat = llbbox.GetMinLat();
1874 elon = llbbox.GetMaxLon();
1875 wlon = llbbox.GetMinLon();
1882 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1883 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1884 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1885 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1886 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1887 vp.m_projection_type == PROJECTION_POLAR ||
1888 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1891 if (straight_latitudes)
1894 latmargin = gridlatMajor / 2;
1896 slat = wxMax(slat, -90 + latmargin);
1897 nlat = wxMin(nlat, 90 - latmargin);
1899 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1900 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1904 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1911 float lon_step = elon - wlon;
1912 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1914 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1916 s.x = INVALID_COORD;
1917 s.y = INVALID_COORD;
1918 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1920 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1921 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1929 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1930 lat += gridlatMinor) {
1933 gldc.DrawLine(0, r.y, 10, r.y,
true);
1934 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1939 float lat_step = nlat - slat;
1940 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1942 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1944 s.x = INVALID_COORD;
1945 s.y = INVALID_COORD;
1946 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1948 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1949 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1957 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1958 lon += gridlonMinor) {
1961 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1962 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1968 glEnable(GL_TEXTURE_2D);
1970 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1971 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1974 CalcGridText(lat, gridlatMajor,
true);
1976 m_gridfont.GetTextExtent(st, 0, &iy);
1978 if (straight_latitudes) {
1983 float x = 0, y = -1;
1984 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1985 if (y < 0 || y > h) {
1987 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1990 m_gridfont.RenderString(st, x, y);
1994 double y1, y2, lat1, lon1, lat2, lon2;
2003 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2006 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2008 if (fabs(y - y1) < fabs(y - y2))
2014 error = fabs(r.m_x);
2015 if (--maxiters == 0)
break;
2016 }
while (error > 1 && error < lasterror);
2018 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2024 m_gridfont.RenderString(st, r.m_x, r.m_y);
2028 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2029 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2038 else if (xlon <= -180.0)
2041 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2043 m_gridfont.GetTextExtent(st, &ix, 0);
2045 if (straight_longitudes) {
2046 float x = -1, y = 0;
2047 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2048 if (x < 0 || x > w) {
2050 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2053 m_gridfont.RenderString(st, x, y);
2057 double x1, x2, lat1, lon1, lat2, lon2;
2065 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2068 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2070 if (fabs(x - x1) < fabs(x - x2))
2076 error = fabs(r.m_y);
2077 }
while (error > 1 && error < lasterror);
2079 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2084 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2086 m_gridfont.RenderString(st, r.m_x, r.m_y);
2090 glDisable(GL_TEXTURE_2D);
2091 glDisable(GL_BLEND);
2096 if (!emboss)
return;
2098 int w = emboss->width, h = emboss->height;
2100 glEnable(GL_TEXTURE_2D);
2103 if (!emboss->gltexind) {
2105 emboss->glwidth = NextPow2(emboss->width);
2106 emboss->glheight = NextPow2(emboss->height);
2109 int size = emboss->glwidth * emboss->glheight;
2110 char *data =
new char[2 * size];
2111 for (
int i = 0; i < h; i++) {
2112 for (
int j = 0; j < emboss->glwidth; j++) {
2114 data[2 * ((i * emboss->glwidth) + j)] =
2115 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2116 data[2 * ((i * emboss->glwidth) + j) + 1] =
2117 (char)abs((emboss->pmap[(i * w) + j]));
2122 glGenTextures(1, &emboss->gltexind);
2123 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2124 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2125 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2133 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2137 int x = emboss->x, y = emboss->y;
2139 float wp = (float)w / emboss->glwidth;
2140 float hp = (float)h / emboss->glheight;
2166 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2168 glDisable(GL_BLEND);
2169 glDisable(GL_TEXTURE_2D);
2172void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2173 if (!m_pParentCanvas->GetVP().IsValid())
return;
2174 wxPoint GPSOffsetPixels(0, 0);
2175 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2178 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2179 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2183 double shift_dx = 0;
2184 double shift_dy = 0;
2185 bool dynamic = m_pParentCanvas->m_animationActive ||
2186 m_pParentCanvas->m_MouseDragging ||
2187 m_pParentCanvas->m_chart_drag_inertia_active;
2188 if (m_pParentCanvas->m_bFollow && !dynamic) {
2189 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2190 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2191 if (m_pParentCanvas->m_bLookAhead) {
2197 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2198 angle += m_pParentCanvas->GetVPRotation();
2199 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2201 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2202 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2204 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2209 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2210 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2217 lShipMidPoint = lGPSPoint;
2221 float icon_hdt = pCog;
2222 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2225 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2229 double osd_head_lat, osd_head_lon;
2230 wxPoint2DDouble osd_head_point;
2232 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2236 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2238 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2239 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2240 icon_rad += (float)PI;
2244 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2248 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2254 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2255 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2256 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2261 float scale_factor = 1.0;
2266 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2267 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2268 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2270 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2272 float nominal_ownship_size_pixels =
2274 nominal_ownship_size_mm);
2276 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2278 wxPen ppSmallScaleShip;
2279 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2281 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2284 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2285 dc.SetPen(ppSmallScaleShip);
2287 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2290 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2291 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2292 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2293 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2296 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2297 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2300 int draw_color = SHIP_INVALID;
2301 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2302 draw_color = SHIP_NORMAL;
2303 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2304 draw_color = SHIP_LOWACCURACY;
2312 ownship_color = draw_color;
2314 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2316 glGenTextures(1, &ownship_tex);
2317 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2319 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2320 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2323 if (m_pParentCanvas->m_pos_image_user) {
2324 switch (draw_color) {
2326 image = *m_pParentCanvas->m_pos_image_user_grey;
2329 image = *m_pParentCanvas->m_pos_image_user;
2331 case SHIP_LOWACCURACY:
2332 image = *m_pParentCanvas->m_pos_image_user_yellow;
2336 switch (draw_color) {
2338 image = *m_pParentCanvas->m_pos_image_grey;
2341 image = *m_pParentCanvas->m_pos_image_red;
2343 case SHIP_LOWACCURACY:
2344 image = *m_pParentCanvas->m_pos_image_yellow;
2349 int w = image.GetWidth(), h = image.GetHeight();
2350 int glw = NextPow2(w), glh = NextPow2(h);
2351 ownship_size = wxSize(w, h);
2352 ownship_tex_size = wxSize(glw, glh);
2354 unsigned char *d = image.GetData();
2355 unsigned char *a = image.GetAlpha();
2356 unsigned char *e =
new unsigned char[4 * w * h];
2359 for (
int p = 0; p < w * h; p++) {
2360 e[4 * p + 0] = d[3 * p + 0];
2361 e[4 * p + 1] = d[3 * p + 1];
2362 e[4 * p + 2] = d[3 * p + 2];
2363 e[4 * p + 3] = a[p];
2366 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2367 GL_UNSIGNED_BYTE, 0);
2369 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2375#ifndef USE_ANDROID_GLES2
2376 if (m_pParentCanvas->m_pos_image_user)
2377 glColor4ub(255, 255, 255, 255);
2378 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2379 glColor4ub(255, 0, 0, 255);
2380 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2381 glColor4ub(255, 255, 0, 255);
2383 glColor4ub(128, 128, 128, 255);
2385 float scale_factor_y = 1.0;
2386 float scale_factor_x = 1.0;
2388 int ownShipWidth = 22;
2389 int ownShipLength = 84;
2390 lShipMidPoint = lGPSPoint;
2393 if (g_OwnShipIconType != 0)
2394 m_pParentCanvas->ComputeShipScaleFactor(
2395 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2396 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2401 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2402 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2403 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2407 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2408 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2412 float gps_circle_radius = 3.0;
2414 if (g_OwnShipIconType == 0) {
2416 glEnable(GL_TEXTURE_2D);
2417 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2426 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2427 if (m_pParentCanvas->m_pos_image_user)
2428 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2430 float nominal_ownship_size_mm =
2431 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2433 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2434 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2436 float nominal_ownship_size_pixels =
2437 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2439 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2440 nominal_ownship_size_pixels = wxMax(
2441 20.0, nominal_ownship_size_pixels);
2444 float h = nominal_ownship_size_pixels * scale_factor_y;
2445 float w = nominal_ownship_size_pixels * scale_factor_x *
2446 ownship_size.x / ownship_size.y;
2447 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2448 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2454 gps_circle_radius = w / 5;
2456 float uv[8], coords[8];
2475 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2476 lShipMidPoint.m_x, lShipMidPoint.m_y,
2478 glDisable(GL_TEXTURE_2D);
2479 }
else if (g_OwnShipIconType == 1) {
2481 glEnable(GL_TEXTURE_2D);
2482 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2484 float nominal_ownship_size_pixels_y = 84;
2485 float nominal_ownship_size_pixels_x = 22;
2487 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2488 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2490 float u = (float)ownship_size.x / ownship_tex_size.x,
2491 v = (
float)ownship_size.y / ownship_tex_size.y;
2494 gps_circle_radius = w / 5;
2496 float uv[8], coords[8];
2515 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2516 lShipMidPoint.m_x, lShipMidPoint.m_y,
2519 glDisable(GL_TEXTURE_2D);
2520 }
else if (g_OwnShipIconType == 2) {
2528 wxPoint shipPoints[6];
2530 wxColour colour = m_pParentCanvas->ShipColor();
2531 wxPen ppPen(*wxBLACK, 1);
2532 wxBrush ppBrush(colour);
2534 dc.SetBrush(ppBrush);
2536 shipPoints[0].x = 0 * scale_factor_x;
2537 shipPoints[0].y = -28 * scale_factor_y;
2538 shipPoints[1].x = 11 * scale_factor_x;
2539 shipPoints[1].y = -28 * scale_factor_y;
2540 shipPoints[2].x = 11 * scale_factor_x;
2541 shipPoints[2].y = 42 * scale_factor_y;
2542 shipPoints[3].x = 0 * scale_factor_x;
2543 shipPoints[3].y = 42 * scale_factor_y;
2544 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2547 shipPoints[0].x = 0 * scale_factor_x;
2548 shipPoints[0].y = -42 * scale_factor_y;
2549 shipPoints[1].x = 5 * scale_factor_x;
2550 shipPoints[1].y = -42 * scale_factor_y;
2551 shipPoints[2].x = 11 * scale_factor_x;
2552 shipPoints[2].y = -28 * scale_factor_y;
2553 shipPoints[3].x = 0 * scale_factor_x;
2554 shipPoints[3].y = -28 * scale_factor_y;
2555 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2558 shipPoints[0].x = 0 * scale_factor_x;
2559 shipPoints[0].y = -28 * scale_factor_y;
2560 shipPoints[1].x = -11 * scale_factor_x;
2561 shipPoints[1].y = -28 * scale_factor_y;
2562 shipPoints[2].x = -11 * scale_factor_x;
2563 shipPoints[2].y = 42 * scale_factor_y;
2564 shipPoints[3].x = 0 * scale_factor_x;
2565 shipPoints[3].y = 42 * scale_factor_y;
2566 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2569 shipPoints[0].x = 0 * scale_factor_x;
2570 shipPoints[0].y = -42 * scale_factor_y;
2571 shipPoints[1].x = -5 * scale_factor_x;
2572 shipPoints[1].y = -42 * scale_factor_y;
2573 shipPoints[2].x = -11 * scale_factor_x;
2574 shipPoints[2].y = -28 * scale_factor_y;
2575 shipPoints[3].x = 0 * scale_factor_x;
2576 shipPoints[3].y = -28 * scale_factor_y;
2577 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2581 double p1x = -11 * scale_factor_x;
2582 double p2x = 11 * scale_factor_x;
2586 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2588 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2590 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2592 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2593 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2594 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2598 p1y = -42 * scale_factor_y;
2599 p2y = 42 * scale_factor_y;
2600 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2601 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2602 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2603 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2604 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2605 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2608 img_height = ownShipLength * scale_factor_y;
2611 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2613 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2615 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2617 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2621 glDisable(GL_LINE_SMOOTH);
2622 glDisable(GL_POLYGON_SMOOTH);
2623 glDisable(GL_BLEND);
2626 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2630void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2631 ViewPort &vp = m_pParentCanvas->GetVP();
2654 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2656 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2657 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2659 m_pParentCanvas->AlertDraw(dc);
2661 m_pParentCanvas->RenderVisibleSectorLights(dc);
2663 m_pParentCanvas->RenderRouteLegs(dc);
2664 m_pParentCanvas->RenderShipToActive(dc,
true);
2665 m_pParentCanvas->ScaleBarDraw(dc);
2666 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2667 m_pParentCanvas->extendedSectorLegs);
2674void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2675 if (m_pParentCanvas->GetPiano()) {
2676 int canvas_height = GetClientSize().y;
2677 canvas_height *= m_displayScale;
2679 m_pParentCanvas->GetPiano()->DrawGL(
2680 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2684void glChartCanvas::DrawQuiting() {
2685#ifndef USE_ANDROID_GLES2
2686 GLubyte pattern[8][8];
2687 for (
int y = 0; y < 8; y++)
2688 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2691 glEnable(GL_TEXTURE_2D);
2692 glBindTexture(GL_TEXTURE_2D, 0);
2694 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2695 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2696 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2698 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2702 float x = GetSize().x, y = GetSize().y;
2703 float u = x / 8, v = y / 8;
2716 glDisable(GL_TEXTURE_2D);
2717 glDisable(GL_BLEND);
2721void glChartCanvas::DrawCloseMessage(wxString msg) {
2722#ifndef USE_ANDROID_GLES2
2726 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2730 texfont.Build(*pfont, 1, 1);
2732 texfont.GetTextExtent(msg, &w, &h);
2734 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2735 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2737 glColor3ub(243, 229, 47);
2741 glVertex2i(xp + w, yp);
2742 glVertex2i(xp + w, yp + h);
2743 glVertex2i(xp, yp + h);
2748 glColor3ub(0, 0, 0);
2749 glEnable(GL_TEXTURE_2D);
2750 texfont.RenderString(msg, xp, yp);
2751 glDisable(GL_TEXTURE_2D);
2752 glDisable(GL_BLEND);
2759static std::list<double *> combine_work_data;
2760static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2761 GLfloat weight[4], GLdouble **dataOut) {
2762 double *vertex =
new double[3];
2763 combine_work_data.push_back(vertex);
2764 memcpy(vertex, coords, 3 * (
sizeof *coords));
2768#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2769void vertexCallbackD_GLSL(GLvoid *vertex) {
2771 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2772 int new_buf_len = s_tess_buf_len + 100;
2773 GLfloat *tmp = s_tess_work_buf;
2776 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2777 if (NULL == s_tess_work_buf) {
2781 s_tess_buf_len = new_buf_len;
2784 GLdouble *pointer = (GLdouble *)vertex;
2786 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2787 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2792void beginCallbackD_GLSL(GLenum mode) {
2793 s_tess_vertex_idx_this = s_tess_vertex_idx;
2798void endCallbackD_GLSL() {
2802 shader->SetUniformMatrix4fv(
"MVMatrix",
2803 (GLfloat *)s_tessVP.vp_matrix_transform);
2805 mat4x4 identityMatrix;
2806 mat4x4_identity(identityMatrix);
2807 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2811 colorv[0] = s_regionColor.Red() / float(256);
2812 colorv[1] = s_regionColor.Green() / float(256);
2813 colorv[2] = s_regionColor.Blue() / float(256);
2814 colorv[3] = s_regionColor.Alpha() / float(256);
2815 shader->SetUniform4fv(
"color", colorv);
2817 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2818 shader->SetAttributePointerf(
"position", bufPt);
2820 glDrawArrays(s_tess_mode, 0, s_nvertex);
2825void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2827void beginCallbackD(GLenum mode) { glBegin(mode); }
2829void endCallbackD() { glEnd(); }
2833void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2834 float lat_dist, lon_dist;
2835 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2837 GLUtesselator *tobj = gluNewTess();
2838 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2840#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2841 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2842 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2843 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2844 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2848 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2849 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2850 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2851 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2854 gluTessNormal(tobj, 0, 0, 1);
2856 gluTessBeginPolygon(tobj, NULL);
2857 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2858 gluTessBeginContour(tobj);
2859 contour_pt l = *i->rbegin();
2861 bool sml_valid =
false;
2862 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2863 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2864 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2865 int splits = wxMax(lat_splits, lon_splits) + 1;
2871 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2872 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2875 for (
int i = 0; i < splits; i++) {
2877 if (i == splits - 1)
2878 lat = j->y, lon = j->x;
2880 double d = (double)(i + 1) / splits;
2881 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2885 if (std::isnan(q.m_x))
continue;
2887 double *p =
new double[6];
2892 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2897 gluTessVertex(tobj, p, p);
2898 combine_work_data.push_back(p);
2902 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2904 gluTessEndContour(tobj);
2906 gluTessEndPolygon(tobj);
2908 gluDeleteTess(tobj);
2910 for (std::list<double *>::iterator i = combine_work_data.begin();
2911 i != combine_work_data.end(); i++)
2913 combine_work_data.clear();
2918void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2919 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2921 if (s_b_useStencil) {
2923 glEnable(GL_STENCIL_TEST);
2925 glClear(GL_STENCIL_BUFFER_BIT);
2929 glStencilFunc(GL_ALWAYS, 1, 1);
2930 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2933#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2937 glEnable(GL_DEPTH_TEST);
2938 glDepthFunc(GL_ALWAYS);
2939 glDepthMask(GL_TRUE);
2941 glClear(GL_DEPTH_BUFFER_BIT);
2954 glTranslatef(0, 0, .5);
2958 s_regionColor = wxColor(0, 0, 0, 255);
2959 DrawRegion(vp, region);
2961 if (s_b_useStencil) {
2964 glStencilFunc(GL_EQUAL, 1, 1);
2965 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2968#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2970 glDepthFunc(GL_GREATER);
2971 glDepthMask(GL_FALSE);
2972 glTranslatef(0, 0, -.5);
2975 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2978void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2982 if (s_b_useStencil && s_b_useScissorTest) {
2984 if (rect != vp_rect) {
2985 glEnable(GL_SCISSOR_TEST);
2986 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2989#ifndef USE_ANDROID_GLES2
2995void glChartCanvas::DisableClipRegion() {
2996 glDisable(GL_SCISSOR_TEST);
2997 glDisable(GL_STENCIL_TEST);
2998 glDisable(GL_DEPTH_TEST);
3001void glChartCanvas::Invalidate() {
3003 m_cache_vp.Invalidate();
3009 if (!pBSBChart)
return;
3015 wxString key = chart->GetHashKey();
3019 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3022 if (ittf == hash.end()) {
3024 hash[key]->SetHashKey(key);
3027 pTexFact = hash[key];
3028 pTexFact->SetLRUTime(++m_LRUtime);
3033 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3034 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3041 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3042 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3043 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3044 base_level = log(scalefactor) / log(2.0);
3053 glEnable(GL_TEXTURE_2D);
3054#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3055 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3057 glEnableClientState(GL_VERTEX_ARRAY);
3058 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3063 pTexFact->GetCenter(lat, lon);
3064 MultMatrixViewPort(vp, lat, lon);
3068 LLBBox box = region.GetBox();
3071 if (g_memCacheLimit > 0) {
3076 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3077 for (
int i = 0; i < numtiles; i++) {
3079 if (region.IntersectOut(tile->box)) {
3082 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3083 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3085 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3086 global_color_scheme, mem_used);
3090 coords = tile->m_coords;
3092 coords =
new float[2 * tile->m_ncoords];
3093 for (
int i = 0; i < tile->m_ncoords; i++) {
3095 tile->m_coords[2 * i + 1]);
3096 coords[2 * i + 0] = p.m_x;
3097 coords[2 * i + 1] = p.m_y;
3101#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3102 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3103 m_pParentCanvas->GetpVP());
3106 glDisable(GL_TEXTURE_2D);
3110 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3111 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3112 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3114 if (!texture) glEnable(GL_TEXTURE_2D);
3116 if (!use_norm_vp)
delete[] coords;
3120 glDisable(GL_TEXTURE_2D);
3122#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3123 if (use_norm_vp) glPopMatrix();
3125 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3126 glDisableClientState(GL_VERTEX_ARRAY);
3130void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3132 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3133 m_pParentCanvas->m_pQuilt->IsBusy())
3137 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3139 printf(
" Chart NULL\n");
3140 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3150 LLRegion region = vp.GetLLRegion(rect_region);
3152 LLRegion rendered_region;
3158 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3166 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3168 LLRegion get_region = pqp->ActiveRegion;
3169 bool b_rendered =
false;
3171 if (!pqp->b_overlay) {
3172 get_region.Intersect(region);
3173 if (!get_region.Empty()) {
3174 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3177 SetClipRegion(vp, get_region );
3178 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3179 DisableClipRegion();
3182 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3183 SetClipRegion(vp, pqp->ActiveRegion );
3184 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3186 DisableClipRegion();
3189 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3190 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3191 RenderNoDTA(vp, get_region);
3192 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3197 if (Chs57->m_RAZBuilt) {
3198 RenderNoDTA(vp, get_region);
3199 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3200 rect_region, get_region);
3201 DisableClipRegion();
3206 const LLRegion &oregion = get_region;
3207 LLBBox box = oregion.GetBox();
3218 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3221 ViewPort cvp = ClippedViewport(vp, get_region);
3222 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3223 SetClipRegion(cvp, get_region);
3224 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3225 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3226 RenderWorldChart(gldc, cvp, srect, world);
3227 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3228 global_color_scheme);
3229 DisableClipRegion();
3236 SetClipRegion(vp, get_region);
3237 RenderNoDTA(vp, get_region);
3238 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3240 DisableClipRegion();
3243 SetClipRegion(vp, get_region);
3244 RenderNoDTA(vp, get_region);
3245 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3247 DisableClipRegion();
3263 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3267 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3268 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3270 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3271 if (pqp->b_Valid && pqp->b_overlay &&
3272 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3273 LLRegion get_region = pqp->ActiveRegion;
3275 get_region.Intersect(region);
3276 if (!get_region.Empty()) {
3279 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3284 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3291 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3296 ViewPort vph = m_pParentCanvas->GetVP();
3297 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3300 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3302 if (!hiregion.Empty()) {
3306 switch (global_color_scheme) {
3307 case GLOBAL_COLOR_SCHEME_DAY:
3310 case GLOBAL_COLOR_SCHEME_DUSK:
3313 case GLOBAL_COLOR_SCHEME_NIGHT:
3321#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3323 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3325 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3328 DrawRegion(vp, hiregion);
3330 glDisable(GL_BLEND);
3335 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3337 if (!hiregion.Empty()) {
3341 switch (global_color_scheme) {
3342 case GLOBAL_COLOR_SCHEME_DAY:
3345 case GLOBAL_COLOR_SCHEME_DUSK:
3348 case GLOBAL_COLOR_SCHEME_NIGHT:
3357#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3359 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3361 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3364 DrawRegion(vp, hiregion);
3366 glDisable(GL_BLEND);
3370 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3373void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3375 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3376 m_pParentCanvas->m_pQuilt->IsBusy())
3380 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3382 LLRegion region = vp.GetLLRegion(rect_region);
3384 LLRegion rendered_region;
3386 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3388 LLRegion get_region = pqp->ActiveRegion;
3390 if (!pqp->b_overlay) {
3391 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3394 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3399 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3406 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3434void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3435 ViewPort &vp = m_pParentCanvas->VPoint;
3443 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3444 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3447 LLRegion chart_region;
3449 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3450 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3451 CHART_FAMILY_RASTER) {
3459 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3460 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3461 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3463 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3467 for (
int i = 1; i < 6; i += 2)
3468 if (fabs(ll[i] - ll[i + 2]) > 180) {
3470 for (
int i = 1; i < 8; i += 2)
3471 if (ll[i] < 0) ll[i] += 360;
3475 chart_region = LLRegion(4, ll);
3478 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3480 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3481 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3482 chart_region = LLRegion(4, ll);
3485 chart_region = vp.b_quilt
3486 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3487 : m_pParentCanvas->m_singleChart->GetValidRegion();
3489 bool world_view =
false;
3491 wxRect rect = upd.GetRect();
3492 LLRegion background_region = vp.GetLLRegion(rect);
3495 background_region.Subtract(chart_region);
3497 if (!background_region.Empty()) {
3498 ViewPort cvp = ClippedViewport(vp, background_region);
3499 SetClipRect(cvp, rect,
false);
3500 RenderWorldChart(dc, cvp, rect, world_view);
3501 DisableClipRegion();
3506 RenderQuiltViewGL(vp, rect_region);
3509 LLRegion region = vp.GetLLRegion(rect_region);
3510 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3511 CHART_FAMILY_RASTER) {
3512 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3513 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3514 *m_pcontext, vp, rect_region, region);
3516 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3517 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3518 CHART_FAMILY_VECTOR) {
3519 chart_region.Intersect(region);
3520 RenderNoDTA(vp, chart_region);
3521 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3522 rect_region, region);
3528void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3530 wxColour color = GetGlobalColor(
"NODTA");
3531#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3533 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3535 glColor4ub(163, 180, 183, transparency);
3538 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3542 s_regionColor = color;
3545 DrawRegion(vp, region);
3549void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3552 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3554 glEnable(GL_SCISSOR_TEST);
3555 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3561 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3562#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3564 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3568 colorv[0] = water.Red() / float(256);
3569 colorv[1] = water.Green() / float(256);
3570 colorv[2] = water.Blue() / float(256);
3572 shader->SetUniform4fv(
"color", colorv);
3583 shader->SetAttributePointerf(
"position", pf);
3585 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3597 glDisable(GL_SCISSOR_TEST);
3605void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3606 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3608 DrawStaticRoutesTracksAndWaypoints(vp);
3610 DisableClipRegion();
3613void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3615 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3619 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3620 if (!bmp.Ok())
return;
3622 wxImage image = bmp.ConvertToImage();
3623 int w = image.GetWidth(), h = image.GetHeight();
3626 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3627 tex_w = w, tex_h = h;
3629 tex_w = NextPow2(w), tex_h = NextPow2(h);
3631 m_tideTexWidth = tex_w;
3632 m_tideTexHeight = tex_h;
3634 unsigned char *d = image.GetData();
3635 unsigned char *a = image.GetAlpha();
3637 unsigned char mr, mg, mb;
3638 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3640 unsigned char *e =
new unsigned char[4 * w * h];
3642 for (
int y = 0; y < h; y++)
3643 for (
int x = 0; x < w; x++) {
3644 unsigned char r, g, b;
3645 int off = (y * w + x);
3655 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3659 glGenTextures(1, &m_tideTex);
3661 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3662 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3663 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3665 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3666 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3667 GL_UNSIGNED_BYTE, e);
3669 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3670 GL_UNSIGNED_BYTE, 0);
3671 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3680 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3681 glEnable(GL_TEXTURE_2D);
3684#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3686 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3690 if ((type ==
't') || (type ==
'T'))
3695 if (BBox.Contains(lat, lon)) {
3704 scale *= getAndroidDisplayDensity();
3706 double width2 =
scale * m_tideTexWidth / 2;
3707 double height2 =
scale * m_tideTexHeight / 2;
3722 coords[0] = xp - width2;
3723 coords[1] = yp - height2;
3724 coords[2] = xp - width2;
3725 coords[3] = yp + height2;
3726 coords[4] = xp + width2;
3727 coords[5] = yp + height2;
3728 coords[6] = xp + width2;
3729 coords[7] = yp - height2;
3731 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3738 glDisable(GL_TEXTURE_2D);
3739 glDisable(GL_BLEND);
3740 glBindTexture(GL_TEXTURE_2D, 0);
3742 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3745void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3746 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3749void glChartCanvas::SetColorScheme(ColorScheme cs) {
3750 if (!m_bsetup)
return;
3752 glDeleteTextures(1, &m_tideTex);
3753 glDeleteTextures(1, &m_currentTex);
3759void glChartCanvas::RenderGLAlertMessage() {
3760 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3761 wxString msg = m_pParentCanvas->GetAlertString();
3764 m_gldc.SetFont(*pfont);
3768 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3775 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3776 int xp = sbr.x + sbr.width + 5;
3778 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3779 m_gldc.SetPen(ppPen1);
3780 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3782 m_gldc.DrawRectangle(xp, yp, w, h);
3784 m_gldc.DrawText(msg, xp, yp);
3788unsigned long quiltHash;
3790extern wxLongLong s_t0;
3793void glChartCanvas::Render() {
3794 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3795 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3796 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3801 if (!g_PrintingInProgress)
return;
3804 if (!g_true_zoom && m_binPinch)
return;
3807 long render_start_time = m_glstopwatch.Time();
3809#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3810 loadShaders(GetCanvasIndex());
3811 configureShaders(m_pParentCanvas->VPoint);
3814#ifdef USE_ANDROID_GLES2
3818 if (m_binPinch)
return;
3827 bool recompose =
false;
3828 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3829 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3830 if (m_pParentCanvas->VPoint.IsValid()) {
3831 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3832 m_pParentCanvas->UpdateCanvasControlBar();
3841 if (sw.GetTime() > 2000) {
3847 s_tess_vertex_idx = 0;
3848 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3849 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3855 m_displayScale = GetContentScaleFactor();
3859 m_last_render_time = wxDateTime::Now().GetTicks();
3863 if (g_GLOptions.m_bTextureCompression &&
3864 !g_GLOptions.m_bTextureCompressionCaching)
3869 int gl_width, gl_height;
3870 gl_width = m_pParentCanvas->VPoint.
pix_width;
3871 gl_height = m_pParentCanvas->VPoint.
pix_height;
3874 m_glcanvas_width = gl_width;
3875 m_glcanvas_height = gl_height;
3879 if (gl_height & 1) {
3881 ViewPort *vp = m_pParentCanvas->GetpVP();
3888 ViewPort *vp = m_pParentCanvas->GetpVP();
3896 ViewPort *vp = m_pParentCanvas->GetpVP();
3899 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3902 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3910 ViewPort VPoint = m_pParentCanvas->VPoint;
3912 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3913 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3916#if !defined(USE_ANDROID_GLES2)
3917 glMatrixMode(GL_PROJECTION);
3920 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3921 glMatrixMode(GL_MODELVIEW);
3925 if (s_b_useStencil) {
3926 glEnable(GL_STENCIL_TEST);
3927 glStencilMask(0xff);
3928 glClear(GL_STENCIL_BUFFER_BIT);
3929 glDisable(GL_STENCIL_TEST);
3935 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3936 if (g_GLOptions.m_GLPolygonSmoothing)
3937 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3938 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3950 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3951 bool useFBO =
false;
3957 if (m_b_BuiltFBO && !bpost_hilite
3962 bool b_newview =
true;
3963 bool b_full =
false;
3971 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3975#ifdef USE_ANDROID_GLES2
3976 if (recompose) b_newview =
true;
3988 if (VPoint.b_quilt) {
3989 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3990 if (!chart) b_full =
true;
3999 bool accelerated_pan =
false;
4009 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4010 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4011 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4013 wxPoint2DDouble c_old =
4016 wxPoint2DDouble c_new =
4020 dy = wxRound(c_new.m_y - c_old.m_y);
4021 dx = wxRound(c_new.m_x - c_old.m_x);
4031 double deltax = c_new.m_x - c_old.m_x;
4032 double deltay = c_new.m_y - c_old.m_y;
4034 bool b_whole_pixel =
true;
4035 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4036 b_whole_pixel =
false;
4038 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4039 abs(dy) < m_cache_tex_y &&
4040 (abs(dx) > 0 || (abs(dy) > 0));
4049 if (m_displayScale > 1) accelerated_pan =
false;
4054 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4057#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4060 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4066 if (b_full) accelerated_pan =
false;
4068 if (accelerated_pan) {
4069 if ((dx != 0) || (dy != 0)) {
4081 if (dy > 0 && dy < gl_height)
4082 update_region.Union(
4083 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4085 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4087 if (dx > 0 && dx < gl_width)
4088 update_region.Union(
4089 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4091 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4093 m_cache_page = !m_cache_page;
4096 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4097 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4109 RenderCharts(m_gldc, update_region);
4113 glDisable(g_texture_rectangle_format);
4118 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4119 glEnable(GL_TEXTURE_2D);
4123 float x1, x2, y1, y2;
4136 float tx1, tx2, ty1, ty2;
4142 tx2 = sx / (float)m_cache_tex_x;
4144 ty2 = sy / (float)m_cache_tex_y;
4161 coords[2] = -dx + sx;
4163 coords[4] = -dx + sx;
4164 coords[5] = dy + sy;
4166 coords[7] = dy + sy;
4169 ptexture_2D_shader_program[GetCanvasIndex()];
4173 shader->SetUniform1i(
"uTex", 0);
4177 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4178 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4179 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4181 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4203 shader->SetAttributePointerf(
"aPos", co1);
4204 shader->SetAttributePointerf(
"aUV", tco1);
4206 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4209 shader->SetUniformMatrix4fv(
"MVMatrix",
4210 (GLfloat *)VPoint.vp_matrix_transform);
4213 glBindTexture(g_texture_rectangle_format, 0);
4215 glDisable(g_texture_rectangle_format);
4223 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4224 g_texture_rectangle_format,
4225 m_cache_tex[!m_cache_page], 0);
4236 wxColour color = GetGlobalColor(
"NODTA");
4237 glClearColor(color.Red() / 256., color.Green() / 256.,
4238 color.Blue() / 256., 1.0);
4239 glClear(GL_COLOR_BUFFER_BIT);
4245 RenderCharts(m_gldc, rscreen_region);
4250 m_cache_page = !m_cache_page;
4255 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4266 glMatrixMode(GL_PROJECTION);
4269 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4270 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4272 glMatrixMode(GL_MODELVIEW);
4276 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4277 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4279 glGetIntegerv(GL_VIEWPORT, viewport);
4280 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4281 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4290 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4291 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4292 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4294 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4298 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4299 glEnable(g_texture_rectangle_format);
4301 float tx, ty, tx0, ty0, divx, divy;
4304 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4307 divx = m_cache_tex_x;
4308 divy = m_cache_tex_y;
4311 tx0 = m_fbo_offsetx / divx;
4312 ty0 = m_fbo_offsety / divy;
4313 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4314 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4339 wxColour color = GetGlobalColor(
"NODTA");
4340 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4342 glClear(GL_COLOR_BUFFER_BIT);
4344 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4347 glDisable(g_texture_rectangle_format);
4349 m_cache_vp = VPoint;
4350 m_cache_vp.Validate();
4352 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4354 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4358 RenderCharts(m_gldc, screen_region);
4367 RenderS57TextOverlay(VPoint);
4368 RenderMBTilesOverlay(VPoint);
4374 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4379 wxRect rt = upd.GetRect();
4380 LLRegion region = VPoint.GetLLRegion(rt);
4381 ViewPort cvp = ClippedViewport(VPoint, region);
4382 DrawGroundedOverlayObjects(gldc, cvp);
4385 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4386 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4387 LLBBox screenBox = screenLLRegion.GetBox();
4389 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4392 if (m_pParentCanvas->m_bShowTide) {
4393 m_pParentCanvas->RebuildTideSelectList(screenBox);
4394 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4397 if (m_pParentCanvas->m_bShowCurrent) {
4398 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4399 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4405 if (m_pParentCanvas->m_show_focus_bar &&
4406 (g_canvasConfig != 0)) {
4407 if (m_pParentCanvas == wxWindow::FindFocus()) {
4410 wxColour colour = GetGlobalColor(
"BLUE4");
4411 wxPen ppBlue(colour, 1);
4412 wxBrush ppBrush(colour);
4413 gldc.SetPen(ppBlue);
4414 gldc.SetBrush(ppBrush);
4415 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4416 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4417 wxPoint barPoints[4];
4420 barPoints[1].x = xw;
4422 barPoints[2].x = xw;
4423 barPoints[2].y = rect_pix;
4425 barPoints[3].y = rect_pix;
4427 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4431 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4435 DrawFloatingOverlayObjects(m_gldc);
4437#ifndef USE_ANDROID_GLES2
4440 glMatrixMode(GL_PROJECTION);
4443 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4444 glMatrixMode(GL_MODELVIEW);
4449 if (!g_bhide_depth_units)
4450 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4451 if (!g_bhide_overzoom_flag)
4452 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4455 ViewPort &vp = m_pParentCanvas->GetVP();
4460 if (!g_PrintingInProgress) {
4461 if (m_pParentCanvas->m_pTrackRolloverWin)
4462 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4464 if (m_pParentCanvas->m_pRouteRolloverWin)
4465 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4467 if (m_pParentCanvas->m_pAISRolloverWin)
4468 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4470 if (m_pParentCanvas->GetMUIBar())
4471 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4485 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4486 int x, y, width, height;
4487 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4488 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4489 wxBitmap bmp(width, height, -1);
4492 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4495 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4496 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4500 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4501 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4503 wxStringTokenizer tkz(s,
"\n");
4506 while (tkz.HasMoreTokens()) {
4507 token = tkz.GetNextToken();
4508 dc.DrawText(token, xt, yt);
4511 dc.SelectObject(wxNullBitmap);
4513 m_gldc.DrawBitmap(bmp, x, y,
false);
4519 if (g_bShowChartBar) DrawChartBar(m_gldc);
4521 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4523 m_pParentCanvas->m_Compass->Paint(gldc);
4525 if (m_pParentCanvas->IsPrimaryCanvas()) {
4526 auto ¬eman = NotificationManager::GetInstance();
4527 if (noteman.GetNotificationCount()) {
4528 m_pParentCanvas->m_notification_button->SetIconSeverity(
4529 noteman.GetMaxSeverity());
4530 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4531 m_pParentCanvas->m_notification_button->Show(
true);
4532 m_pParentCanvas->m_notification_button->Paint(gldc);
4534 m_pParentCanvas->m_notification_button->Show(
false);
4537 RenderGLAlertMessage();
4540 ViewPort &vp = m_pParentCanvas->GetVP();
4544 glActiveTexture(GL_TEXTURE0);
4548 if (g_bquiting) DrawQuiting();
4549 if (g_bcompression_wait)
4550 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4555 if (g_b_needFinish) glFinish();
4562 m_pParentCanvas->PaintCleanup();
4563 m_bforcefull =
false;
4572void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4575 if (VPoint.b_quilt) {
4576 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4577 ps52plib->GetShowS57Text()) {
4578 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4579 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4584 ChPI->ClearPLIBTextList();
4586 ps52plib->ClearTextList();
4596 RenderQuiltViewGLText(vpx, screen_region);
4601void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4604 LLRegion &screenLLRegion) {
4609 if (chart == NULL)
return;
4616 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4618 wxFileName tileFile(chart->GetFullPath());
4620 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4622 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4623 (tileSizeMB.GetLo() > 5000)) {
4626 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4627 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4628 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4635 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4639 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4642 std::vector<int> piano_active_array_tiles =
4643 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4644 bool bfound =
false;
4646 if (std::find(piano_active_array_tiles.begin(),
4647 piano_active_array_tiles.end(),
4648 dbIndex) != piano_active_array_tiles.end()) {
4653 piano_active_array_tiles.push_back(dbIndex);
4654 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4658void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4660 std::vector<int> stackIndexArray =
4661 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4662 unsigned int im = stackIndexArray.size();
4665 if (VPoint.b_quilt && im > 0) {
4666 bool regionVPBuilt =
false;
4668 LLRegion screenLLRegion;
4672 std::vector<int> tiles_to_show;
4673 for (
unsigned int is = 0; is < im; is++) {
4675 ChartData->GetChartTableEntry(stackIndexArray[is]);
4676 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4677 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4679 std::vector<int> piano_active_array_tiles =
4680 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4681 bool bfound =
false;
4683 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4684 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4685 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4693 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4694 piano_active_array_tiles);
4699 tiles_to_show.push_back(stackIndexArray[is]);
4700 if (!regionVPBuilt) {
4703 screenLLRegion = VPoint.GetLLRegion(screen_region);
4704 screenBox = screenLLRegion.GetBox();
4712 regionVPBuilt =
true;
4722 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4723 rit != tiles_to_show.rend(); ++rit) {
4724 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4726 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4727 rit != tiles_to_show.rend(); ++rit) {
4728 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4732 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4734 if (!hiregion.Empty()) {
4738 switch (global_color_scheme) {
4739 case GLOBAL_COLOR_SCHEME_DAY:
4742 case GLOBAL_COLOR_SCHEME_DUSK:
4745 case GLOBAL_COLOR_SCHEME_NIGHT:
4753#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4754 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4756 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4759 DrawRegion(VPoint, hiregion);
4761 glDisable(GL_BLEND);
4767void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4771 GetClientSize(&w, &h);
4773 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4774#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4775 glMatrixMode(GL_PROJECTION);
4778 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4779 glMatrixMode(GL_MODELVIEW);
4783 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4785 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4787 bool world_view =
false;
4788 RenderWorldChart(dc, cvp, rtex, world_view);
4795 glViewport(0, 0, (GLint)w, (GLint)h);
4796#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4797 glMatrixMode(GL_PROJECTION);
4800 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4801 glMatrixMode(GL_MODELVIEW);
4807void glChartCanvas::FastPan(
int dx,
int dy) {
4808#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4812void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4814 if (IsShown()) SetCurrent(*m_pcontext);
4815 float sx = GetSize().x;
4816 float sy = GetSize().y;
4817 glClear(GL_COLOR_BUFFER_BIT);
4820 GetClientSize(&w, &h);
4822 if (s_b_useStencil) {
4823 glEnable(GL_STENCIL_TEST);
4824 glStencilMask(0xff);
4825 glClear(GL_STENCIL_BUFFER_BIT);
4826 glDisable(GL_STENCIL_TEST);
4842 float sxfactor = sx / swidth;
4843 float syfactor = sy / sheight;
4845 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4846 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4847 sx * sx / swidth * 2, sy * sy / sheight * 2);
4848 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4849 glEnable(g_texture_rectangle_format);
4874 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4875 glBindTexture(g_texture_rectangle_format, 0);
4881 float tx, ty, tx0, ty0;
4891 glBindTexture(g_texture_rectangle_format, 0);
4894 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4895 glEnable(g_texture_rectangle_format);
4901 uv[0] = tx0 / m_cache_tex_x;
4902 uv[1] = ty / m_cache_tex_y;
4903 uv[2] = tx / m_cache_tex_x;
4904 uv[3] = ty / m_cache_tex_y;
4905 uv[4] = tx / m_cache_tex_x;
4906 uv[5] = ty0 / m_cache_tex_y;
4907 uv[6] = tx0 / m_cache_tex_x;
4908 uv[7] = ty0 / m_cache_tex_y;
4920 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4921 sx * sx / swidth, sy * sy / sheight);
4923 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4925 glDisable(g_texture_rectangle_format);
4926 glBindTexture(g_texture_rectangle_format, 0);
4933 wxColour color = GetGlobalColor(
"GREY1");
4934 float ht = -offset_y * (sy / sheight);
4935 wxRect r(0, sy - ht, w, ht);
4936 RenderColorRect(r, color);
4939 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4940 RenderColorRect(rt, color);
4943 float w1 = -offset_x * sx / swidth;
4944 wxRect rl(0, 0, w1, sy);
4945 RenderColorRect(rl, color);
4948 float px = w1 + sx * sx / swidth;
4949 wxRect rr(px, 0, sx - px, sy);
4950 RenderColorRect(rr, color);
4959void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4962 if (m_nRun < m_nTotal) {
4963 m_runoffsetx += m_offsetxStep;
4964 if (m_offsetxStep > 0)
4965 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4967 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4969 m_runoffsety += m_offsetyStep;
4970 if (m_offsetyStep > 0)
4971 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4973 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4975 m_runswidth += m_swidthStep;
4976 if (m_swidthStep > 0)
4977 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4979 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4981 m_runsheight += m_sheightStep;
4982 if (m_sheightStep > 0)
4983 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4985 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4990 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4996 if (m_zoomFinaldx || m_zoomFinaldy) {
4997 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5000 m_zoomFinal =
false;
5004void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5006 int sx = GetSize().x;
5007 int sy = GetSize().y;
5009 m_lastfbo_offsetx = m_fbo_offsetx;
5010 m_lastfbo_offsety = m_fbo_offsety;
5011 m_lastfbo_swidth = m_fbo_swidth;
5012 m_lastfbo_sheight = m_fbo_sheight;
5014 float curr_fbo_offset_x = m_fbo_offsetx;
5015 float curr_fbo_offset_y = m_fbo_offsety;
5016 float curr_fbo_swidth = m_fbo_swidth;
5017 float curr_fbo_sheight = m_fbo_sheight;
5019 float fx = (float)cp_x / sx;
5020 float fy = 1.0 - (float)cp_y / sy;
5022 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5023 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5025 m_fbo_swidth = curr_fbo_swidth / factor;
5026 m_fbo_sheight = curr_fbo_sheight / factor;
5028 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5029 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5031 m_fbo_offsetx += post_x;
5032 m_fbo_offsety += post_y;
5043 float perStep = m_nStep / m_nTotal;
5045 if (zoomTimer.IsRunning()) {
5046 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5047 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5048 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5049 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5052 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5053 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5054 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5055 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5057 m_runoffsetx = m_lastfbo_offsetx;
5058 m_runoffsety = m_lastfbo_offsety;
5059 m_runswidth = m_lastfbo_swidth;
5060 m_runsheight = m_lastfbo_sheight;
5063 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5064 m_zoomFinal =
false;
5070void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5074 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5077 if (m_binPinch)
return;
5078 if (m_bpinchGuard)
return;
5080 int x =
event.GetOffset().x;
5081 int y =
event.GetOffset().y;
5083 int lx =
event.GetLastOffset().x;
5084 int ly =
event.GetLastOffset().y;
5089 switch (event.GetState()) {
5090 case GestureStarted:
5091 if (m_binPan)
break;
5095 m_binGesture =
true;
5099 case GestureUpdated:
5104 m_pParentCanvas->FreezePiano();
5106 m_pParentCanvas->ThawPiano();
5117 case GestureFinished:
5120 m_pParentCanvas->UpdateCanvasControlBar();
5123 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5127 case GestureCanceled:
5129 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5136 m_bgestureGuard =
true;
5137 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5138 m_bforcefull =
false;
5143float zoom_inc = 1.0;
5145void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5146 float zoom_gain = 1.0;
5147 float zout_gain = 1.0;
5150 float total_zoom_val;
5152 float max_zoom_scale = 1000.;
5153 float min_zoom_scale = 2e8;
5155 if (event.GetScaleFactor() > 1)
5156 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5158 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5160 if (event.GetTotalScaleFactor() > 1)
5161 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5164 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5166 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5169 float max_zoom_scale = 1000.;
5170 if( cc1->GetVP().b_quilt) {
5171 int ref_index = cc1->GetQuiltRefChartdbIndex();
5178 float min_zoom_scale = 2e8;
5182 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5184 double projected_scale =
5185 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5187 switch (event.GetState()) {
5188 case GestureStarted:
5189 m_first_zout =
false;
5193 m_binGesture =
true;
5195 m_pinchStart =
event.GetCenterPoint();
5196 m_lpinchPoint = m_pinchStart;
5199 event.GetCenterPoint().y, m_pinchlat,
5204 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5205 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5208 if (IsShown()) SetCurrent(*m_pcontext);
5214 case GestureUpdated:
5216 if (projected_scale < min_zoom_scale) {
5217 wxPoint pinchPoint =
event.GetCenterPoint();
5219 float dx = pinchPoint.x - m_lpinchPoint.x;
5220 float dy = pinchPoint.y - m_lpinchPoint.y;
5222 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5223 -dx / total_zoom_val, dy / total_zoom_val);
5225 m_lpinchPoint = pinchPoint;
5229 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5230 wxPoint pinchPoint =
event.GetCenterPoint();
5232 float dx = pinchPoint.x - m_lpinchPoint.x;
5233 float dy = pinchPoint.y - m_lpinchPoint.y;
5235 if ((projected_scale > max_zoom_scale) &&
5236 (projected_scale < min_zoom_scale))
5237 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5238 -dx / total_zoom_val, dy / total_zoom_val);
5240 m_lpinchPoint = pinchPoint;
5243 m_first_zout =
true;
5244 zoom_inc *= zoom_val;
5245 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5246 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5250 wxPoint pinchPoint =
event.GetCenterPoint();
5251 float dx = pinchPoint.x - m_lpinchPoint.x;
5252 float dy = pinchPoint.y - m_lpinchPoint.y;
5254 m_lpinchPoint = pinchPoint;
5265 case GestureFinished: {
5269 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5270 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5274 float tzoom = total_zoom_val;
5276 if (projected_scale >= min_zoom_scale)
5277 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5279 if (projected_scale < max_zoom_scale)
5280 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5282 dx = (cc_x - m_cc_x) * tzoom;
5283 dy = -(cc_y - m_cc_y) * tzoom;
5285 if (zoomTimer.IsRunning()) {
5288 m_zoomFinalZoom = tzoom;
5294 double final_projected_scale =
5298 if (final_projected_scale < min_zoom_scale) {
5302 m_pParentCanvas->m_pQuilt->Invalidate();
5303 m_bforcefull =
true;
5310 m_pParentCanvas->m_pQuilt->Invalidate();
5311 m_bforcefull =
true;
5323 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5327 case GestureCanceled:
5329 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5336 m_bgestureGuard =
true;
5338 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5341void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5351 m_bgestureGuard =
false;
5352 m_bpinchGuard =
false;
5353 m_binGesture =
false;
5354 m_bforcefull =
false;
5357void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5361 m_binGesture =
false;
5362 m_bforcefull =
false;
5366#ifdef HAVE_WX_GESTURE_EVENTS
5368void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5371 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5374 if (m_binPinch)
return;
5375 if (m_bpinchGuard)
return;
5377 int dx =
event.GetDelta().x;
5378 int dy =
event.GetDelta().y;
5380 if (event.IsGestureStart()) {
5381 if (m_binPan)
return;
5385 m_binGesture =
true;
5389 else if (event.IsGestureEnd()) {
5391 m_pParentCanvas->UpdateCanvasControlBar();
5393 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5401 m_pParentCanvas->FreezePiano();
5403 m_pParentCanvas->ThawPiano();
5414 m_bgestureGuard =
true;
5415 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5416 m_bforcefull =
false;
5420void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5422 float zoom_gain = 1.0;
5423 float zout_gain = 1.0;
5425 float last_zoom_val = m_step_zoom_val;
5427 float max_zoom_scale = 1000.;
5428 float min_zoom_scale = 2e8;
5430 if (event.GetZoomFactor() > 1)
5431 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5433 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5435 float inc_zoom_val =
5436 m_total_zoom_val / last_zoom_val;
5440 if (event.IsGestureStart()) {
5441 m_glstopwatch.Start();
5442 printf(
"\nStart--------------\n");
5444 m_pParentCanvas->m_inPinch =
true;
5447 m_binGesture =
true;
5448 m_pinchStart =
event.GetPosition();
5449 m_lpinchPoint = m_pinchStart;
5450 m_total_zoom_val = 1.0;
5451 m_final_zoom_val = 1.0;
5452 m_step_zoom_val = 1.0;
5456 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5460 if (event.IsGestureEnd()) {
5462 if (!m_binGesture)
return;
5463 printf(
"EndZoom--------------\n");
5470 m_final_zoom_val = 1.0;
5471 m_total_zoom_val = 1.0;
5472 m_step_zoom_val = 1.0;
5474 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5481 float zoom_step = 5;
5482 float zoom_trigger = 0.05;
5483 if (projected_scale > 1e5)
5485 else if (projected_scale < 3e4)
5488 if (inc_zoom_val != 1.0) {
5489 if (inc_zoom_val > 1 + zoom_step) {
5490 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5491 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5493 if (IsShown()) SetCurrent(*m_pcontext);
5496 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5497 m_step_zoom_val = m_total_zoom_val;
5498 printf(
" Zoom: %6g\n", inc_zoom_val);
5503 bool b_allow_ztp =
true;
5504 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5505 b_allow_ztp =
false;
5507 if (g_bEnableZoomToCursor && b_allow_ztp) {
5513 int dx = r.x -
event.GetPosition().x;
5514 int dy = r.y -
event.GetPosition().y;
5518 if (IsShown()) SetCurrent(*m_pcontext);
5527 float zoom_gain = 1.0;
5528 float zout_gain = 1.0;
5530 float last_zoom_val = m_total_zoom_val;
5532 float max_zoom_scale = 1000.;
5533 float min_zoom_scale = 2e8;
5535 if (event.GetZoomFactor() > 1)
5536 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5538 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5540 float inc_zoom_val =
5541 m_total_zoom_val / last_zoom_val;
5543 double projected_scale =
5544 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5546 if (event.IsGestureStart()) {
5548 m_first_zout =
false;
5552 m_binGesture =
true;
5553 m_pinchStart =
event.GetPosition();
5554 m_lpinchPoint = m_pinchStart;
5555 m_total_zoom_val = 1.0;
5556 m_final_zoom_val = 1.0;
5559 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5563 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5564 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5567 if (IsShown()) SetCurrent(*m_pcontext);
5570 ViewPort vpr = m_pParentCanvas->VPoint;
5572 GetTouchBackingBitmap(vpr);
5577 if (event.IsGestureEnd()) {
5583 if (!m_binGesture)
return;
5585 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5586 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5590 float tzoom = m_final_zoom_val;
5592 dx = (cc_x - m_cc_x) * tzoom;
5593 dy = -(cc_y - m_cc_y) * tzoom;
5595 if (zoomTimer.IsRunning()) {
5598 m_zoomFinalZoom = tzoom;
5604 double final_projected_scale =
5608 if (final_projected_scale < min_zoom_scale) {
5612 m_pParentCanvas->m_pQuilt->Invalidate();
5613 m_bforcefull =
true;
5620 m_pParentCanvas->m_pQuilt->Invalidate();
5621 m_bforcefull =
true;
5626 m_final_zoom_val = 1.0;
5627 m_total_zoom_val = 1.0;
5628 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5633 if (projected_scale < min_zoom_scale) {
5634 wxPoint pinchPoint =
event.GetPosition();
5636 float dx = pinchPoint.x - m_lpinchPoint.x;
5637 float dy = pinchPoint.y - m_lpinchPoint.y;
5639 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5640 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5642 m_lpinchPoint = pinchPoint;
5643 m_final_zoom_val *= inc_zoom_val;
5647 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5648 wxPoint pinchPoint =
event.GetPosition();
5650 float dx = pinchPoint.x - m_lpinchPoint.x;
5651 float dy = pinchPoint.y - m_lpinchPoint.y;
5653 if ((projected_scale > max_zoom_scale) &&
5654 (projected_scale < min_zoom_scale))
5655 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5656 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5658 m_lpinchPoint = pinchPoint;
5659 m_final_zoom_val *= inc_zoom_val;
5662 m_first_zout =
true;
5663 m_zoom_inc *= inc_zoom_val;
5664 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5665 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5669 wxPoint pinchPoint =
event.GetPosition();
5670 float dx = pinchPoint.x - m_lpinchPoint.x;
5671 float dy = pinchPoint.y - m_lpinchPoint.y;
5673 m_lpinchPoint = pinchPoint;
5677 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5680 m_bgestureGuard =
true;
5681 m_bpinchGuard =
true;
5684void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5693 m_bgestureGuard =
false;
5694 m_bpinchGuard =
false;
5695 m_binGesture =
false;
5696 m_bforcefull =
false;
5699void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5703 m_binGesture =
false;
5704 m_bforcefull =
false;
5706 m_pParentCanvas->m_inPinch =
false;
5707 printf(
"******Finish\n");
5713void glChartCanvas::configureShaders(
ViewPort &vp) {
5714#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5720 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5722 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5723 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5744 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5746 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5747 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5759 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5761 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5762 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5765 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5767 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5768 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5776 shader = pAALine_shader_program[GetCanvasIndex()];
5778 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5781 shader = pring_shader_program[GetCanvasIndex()];
5783 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5784 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5788 if (texture_2DA_shader_program) {
5789 glUseProgram(texture_2DA_shader_program);
5790 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5791 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5792 (
const GLfloat *)pvp->vp_matrix_transform);
5794 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5795 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5803void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5806#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5807 int nl = nVertex / 4;
5809 float *luv = uvCoords;
5812 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5820 glEnableClientState(GL_VERTEX_ARRAY);
5821 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5823 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5824 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5825 glDrawArrays(GL_QUADS, 0, 4);
5832void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5833 float *uvCoords,
ViewPort *vp,
float dx,
5834 float dy,
float angle_rad) {
5835#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5837 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5838 if (!shader)
return;
5843 shader->SetUniform1i(
"uTex", 0);
5848 mat4x4_rotate_Z(Q, I, angle_rad);
5854 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5859 shader->SetAttributePointerf(
"aPos", co1);
5860 shader->SetAttributePointerf(
"aUV", tco1);
5867 GLushort indices1[] = {0,1,3,2};
5868 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5880 tco1[0] = uvCoords[0];
5881 tco1[1] = uvCoords[1];
5882 tco1[2] = uvCoords[2];
5883 tco1[3] = uvCoords[3];
5884 tco1[4] = uvCoords[6];
5885 tco1[5] = uvCoords[7];
5886 tco1[6] = uvCoords[4];
5887 tco1[7] = uvCoords[5];
5892 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5904void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5905#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5907 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5910 shader->SetUniformMatrix4fv(
5911 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5914 colorv[0] = color.Red() / float(256);
5915 colorv[1] = color.Green() / float(256);
5916 colorv[2] = color.Blue() / float(256);
5918 shader->SetUniform4fv(
"color", colorv);
5921 pf[0] = r.x + r.width;
5925 pf[4] = r.x + r.width;
5926 pf[5] = r.y + r.height;
5928 pf[7] = r.y + r.height;
5929 shader->SetAttributePointerf(
"position", pf);
5931 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5939void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5940#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5942 ViewPort VPoint = m_pParentCanvas->VPoint;
5946 GetClientSize(&w, &h);
5947 int sx = GetSize().x;
5948 int sy = GetSize().y;
5952 glViewport(0, 0, (GLint)w, (GLint)h);
5954 if (s_b_useStencil) {
5955 glEnable(GL_STENCIL_TEST);
5956 glStencilMask(0xff);
5957 glClear(GL_STENCIL_BUFFER_BIT);
5958 glDisable(GL_STENCIL_TEST);
5962 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5967 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5968 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5969 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5972 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5974 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5975 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5983 if (bRenderCharts) RenderCharts(gldc, screen_region);
5985 if (bRenderOverlays) {
5986 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5987 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5993 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5996 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5997 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5998 DrawFloatingOverlayObjects(m_gldc);
6002 glBindFramebuffer(GL_FRAMEBUFFER, 0);
6007wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
6009 wxMemoryDC tdc(tbm);
6010 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6018 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6019 dc.SetPen(*wxTRANSPARENT_PEN);
6022 tdc.SelectObject(wxNullBitmap);
6023 m_touch_backing_bitmap = tbm;
6024 CreateBackingTexture();
6026 return m_touch_backing_bitmap;
6029void glChartCanvas::CreateBackingTexture() {
6030 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6031 unsigned char *imgdata = image.GetData();
6032 unsigned char *imgalpha = image.GetAlpha();
6033 m_tex_w = image.GetWidth();
6034 m_tex_h = image.GetHeight();
6035 m_image_width = m_tex_w;
6036 m_image_height = m_tex_h;
6038 GLuint format = GL_RGBA;
6039 GLuint internalformat = g_texture_rectangle_format;
6041 internalformat = GL_RGBA;
6046 unsigned char *teximage =
6047 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6049 for (
int i = 0; i < m_image_height; i++) {
6050 for (
int j = 0; j < m_image_width; j++) {
6051 int s = (i * 3 * m_image_width) + (j * 3);
6052 int d = (i * stride * m_tex_w) + (j * stride);
6054 teximage[d + 0] = imgdata[s + 0];
6055 teximage[d + 1] = imgdata[s + 1];
6056 teximage[d + 2] = imgdata[s + 2];
6057 teximage[d + 3] = 255;
6061 glGenTextures(1, &m_TouchBackingTexture);
6062 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6064 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6065 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6066 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6068 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6070 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6071 GL_UNSIGNED_BYTE, teximage);
6074 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.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
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.
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.