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())
return;
511 SetCurrent(*m_pcontext);
515 SetSize(GetSize().x, GetSize().y);
523 if (m_bsetup && m_pcontext && IsShown()) {
524 SetCurrent(*m_pcontext);
530 wxLogMessage(
"BuildFBO 3");
535 ViewPort *vp = m_pParentCanvas->GetpVP();
538 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
541 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
545void glChartCanvas::MouseEvent(wxMouseEvent &event) {
546 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
552 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
554 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
557 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
561 if (m_bgestureGuard) {
562 m_pParentCanvas->r_rband.x = 0;
572 if (event.LeftUp()) {
574 if ((abs(panx) > 2) || (abs(pany) > 2)) {
577 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
584 if (!event.LeftDClick()) {
589 if (m_binPan && event.RightDown()) {
590 qDebug() <<
"Skip right on pan";
593 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
595 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
596 if (!m_bgestureGuard)
606#ifndef GL_MAX_RENDERBUFFER_SIZE
607#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
610#ifndef USE_ANDROID_GLES2
611bool glChartCanvas::buildFBOSize(
int fboSize) {
613 if (IsShown()) SetCurrent(*m_pcontext);
616 glDeleteTextures(2, m_cache_tex);
617 glDeleteFramebuffers(1, &m_fb0);
618 glDeleteRenderbuffers(1, &m_renderbuffer);
619 m_b_BuiltFBO =
false;
622 if (m_b_DisableFBO)
return false;
626 int rb_x = GetSize().x;
627 int rb_y = GetSize().y;
629 while (i < rb_x) i <<= 1;
633 while (i < rb_y) i <<= 1;
636 m_cache_tex_x = wxMax(rb_x, rb_y);
637 m_cache_tex_y = wxMax(rb_x, rb_y);
640 m_cache_tex_x = GetSize().x * m_displayScale;
641 m_cache_tex_y = GetSize().y * m_displayScale;
644 int err = GL_NO_ERROR;
646 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
649 if (err == GL_INVALID_ENUM) {
650 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
654 if (err == GL_NO_ERROR) {
655 if (fboSize > params) {
657 " OpenGL-> Requested Framebuffer size exceeds "
658 "GL_MAX_RENDERBUFFER_SIZE");
663 glGenFramebuffers(1, &m_fb0);
667 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
672 glGenRenderbuffers(1, &m_renderbuffer);
676 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
681 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
685 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
691 glGenTextures(2, m_cache_tex);
692 for (
int i = 0; i < 2; i++) {
693 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
694 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
696 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
698 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
699 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
702 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
704 if (m_b_useFBOStencil) {
706 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
707 m_cache_tex_x, m_cache_tex_y);
709 int err = glGetError();
712 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
716 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
717 GL_RENDERBUFFER_EXT, m_renderbuffer);
721 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
726 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
727 GL_RENDERBUFFER_EXT, m_renderbuffer);
731 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
737 GLenum depth_format = GL_DEPTH_COMPONENT24;
742 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
746 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
748 int err = glGetError();
751 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
757 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
758 GL_RENDERBUFFER_EXT, m_renderbuffer);
763 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
770 glBindTexture(GL_TEXTURE_2D, 0);
771 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
774 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
776 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
777 g_texture_rectangle_format, m_cache_tex[0], 0);
779 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
781 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
783 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
785 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
795#ifdef USE_ANDROID_GLES2
796bool glChartCanvas::buildFBOSize(
int fboSize) {
800 int rb_x = GetSize().x;
801 int rb_y = GetSize().y;
803 while (i < rb_x) i <<= 1;
807 while (i < rb_y) i <<= 1;
810 m_cache_tex_x = wxMax(rb_x, rb_y);
811 m_cache_tex_y = wxMax(rb_x, rb_y);
815 int err = GL_NO_ERROR;
817 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
820 if (err == GL_INVALID_ENUM) {
821 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
825 if (err == GL_NO_ERROR) {
826 if (fboSize > params) {
828 " OpenGL-> Requested Framebuffer size exceeds "
829 "GL_MAX_RENDERBUFFER_SIZE");
834 glGenFramebuffers(1, &m_fb0);
838 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
843 glGenRenderbuffers(1, &m_renderbuffer);
847 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
852 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
856 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
862 glGenTextures(2, m_cache_tex);
863 for (
int i = 0; i < 2; i++) {
864 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
865 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
867 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
869 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
870 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
873 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
876 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
882 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
886 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
887 GL_RENDERBUFFER, m_renderbuffer);
891 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
896 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
897 GL_RENDERBUFFER, m_renderbuffer);
901 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
906 glBindTexture(GL_TEXTURE_2D, 0);
907 glBindFramebuffer(GL_FRAMEBUFFER, 0);
910 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
912 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
913 g_texture_rectangle_format, m_cache_tex[0], 0);
915 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
917 glBindFramebuffer(GL_FRAMEBUFFER, 0);
919 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
921 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
931void glChartCanvas::BuildFBO() {
934 glDeleteTextures(2, m_cache_tex);
935 glDeleteFramebuffers(1, &m_fb0);
936 glDeleteRenderbuffers(1, &m_renderbuffer);
937 m_b_BuiltFBO =
false;
940 if (m_b_DisableFBO)
return;
943 int gl_width, gl_height;
944 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
945 int initialSize = NextPow2(gl_width * m_displayScale);
950 wxString info = androidGetDeviceInfo();
952 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
955 if (!buildFBOSize(initialSize)) {
956 glDeleteTextures(2, m_cache_tex);
957 glDeleteFramebuffers(1, &m_fb0);
958 glDeleteRenderbuffers(1, &m_renderbuffer);
960 if (!buildFBOSize(1024)) {
961 wxLogMessage(
"BuildFBO C");
963 m_b_DisableFBO =
true;
964 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
965 m_b_BuiltFBO =
false;
974 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
986void glChartCanvas::SetupOpenGL() {
987 SetCurrent(*m_pcontext);
989 char *str = (
char *)glGetString(GL_RENDERER);
992 wxLogMessage(
"Failed to initialize OpenGL");
996 char render_string[80];
997 strncpy(render_string, str, 79);
998 m_renderer = wxString(render_string, wxConvUTF8);
1001 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1002 msg.Printf(
"OpenGL-> Renderer String: ");
1006 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1008 char version_string[80];
1009 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1010 msg.Printf(
"OpenGL-> Version reported: ");
1011 m_version = wxString(version_string, wxConvUTF8);
1015 char GLSL_version_string[80];
1016 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1018 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1019 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1020 msg += m_GLSLversion;
1025 GLenum err = glewInit();
1026#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1027 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1032 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1035 wxLogMessage(
"GLEW init success!n");
1040 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1041 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1045#ifndef USE_ANDROID_GLES2
1046 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1048 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1050 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1051 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1058 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1060 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1062 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1065 s_b_useScissorTest =
true;
1067 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1068 s_b_useScissorTest =
false;
1070 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1071 s_b_useScissorTest =
false;
1073 bool bad_stencil_code =
false;
1076 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1077 bad_stencil_code =
true;
1080 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1083 glEnable(GL_STENCIL_TEST);
1084 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1086 glGetIntegerv(GL_STENCIL_BITS, &sb);
1089 glDisable(GL_STENCIL_TEST);
1091 s_b_useStencil =
false;
1092 if (stencil && (sb == 8)) s_b_useStencil =
true;
1094 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1095 g_texture_rectangle_format = GL_TEXTURE_2D;
1096 else if (QueryExtension(
"GL_OES_texture_npot"))
1097 g_texture_rectangle_format = GL_TEXTURE_2D;
1098 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1099 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1100 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1101 g_texture_rectangle_format));
1104 g_texture_rectangle_format = GL_TEXTURE_2D;
1108 g_b_EnableVBO =
true;
1111 g_b_EnableVBO =
false;
1115 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1117 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1121 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1123 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1126#ifndef USE_ANDROID_GLES2
1128 if (bad_stencil_code) s_b_useStencil =
false;
1142 if (m_displayScale > 1) m_b_DisableFBO =
true;
1151 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1153 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1154 g_texture_rectangle_format, m_cache_tex[0], 0);
1156 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1157 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1159 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1161 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1163 m_b_DisableFBO =
true;
1169 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1173 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1175#ifdef USE_ANDROID_GLES2
1176 s_b_useStencilAP = s_b_useStencil;
1183 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1185 if (m_b_useFBOStencil)
1186 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1188 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1190 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1193 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1195 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1197 if (s_b_useScissorTest && s_b_useStencil)
1198 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1201 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1203 MipMap_ResolveRoutines();
1207 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1208 g_GLMinCartographicLineWidth);
1209 wxLogMessage(lwmsg);
1210 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1211 g_GLMinSymbolLineWidth);
1212 wxLogMessage(lwmsg);
1215 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1217#ifdef USE_ANDROID_GLES2
1218 g_GLOptions.m_bUseAcceleratedPanning =
true;
1224 int tex_dim = g_GLOptions.m_iTextureDimension;
1225 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1234 s_b_useFBO = m_b_BuiltFBO;
1238 ps52plib->SetGLOptions(
1239 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1240 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1241 g_GLMinSymbolLineWidth);
1245 SendJSONConfigMessage();
1248void glChartCanvas::SendJSONConfigMessage() {
1251 v[
"setupComplete"] = m_bsetup;
1252 v[
"useStencil"] = s_b_useStencil;
1253 v[
"useStencilAP"] = s_b_useStencilAP;
1254 v[
"useScissorTest"] = s_b_useScissorTest;
1255 v[
"useFBO"] = s_b_useFBO;
1256 v[
"useVBO"] = g_b_EnableVBO;
1257 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1258 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1259 SendJSONMessageToAllPlugins(msg_id, v);
1262void glChartCanvas::SetupCompression() {
1263 int dim = g_GLOptions.m_iTextureDimension;
1266 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1267 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1268 goto no_compression;
1272 g_uncompressed_tile_size = dim * dim * 4;
1273 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1279 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1282 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1292 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1293 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1296 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1297 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1302 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1303 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1306 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1308 wxLogMessage(
"OpenGL-> No Useable compression format found");
1309 goto no_compression;
1314 g_tile_size = 512 * 512 / 2;
1318 glGenTextures(1, &texture);
1319 glBindTexture(GL_TEXTURE_2D, texture);
1321 GL_UNSIGNED_BYTE, NULL);
1322 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1324 glDeleteTextures(1, &texture);
1328 if (g_tile_size == 0)
goto no_compression;
1330 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1332 g_uncompressed_tile_size / g_tile_size));
1336 g_GLOptions.m_bTextureCompression =
false;
1338 g_tile_size = g_uncompressed_tile_size;
1339 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1342void glChartCanvas::OnPaint(wxPaintEvent &event) {
1344 if (!m_pcontext)
return;
1352 SetCurrent(*m_pcontext);
1357 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1365 if (!m_b_paint_enable)
return;
1368 if (m_in_glpaint)
return;
1371 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1394bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1396#ifndef USE_ANDROID_GLES2
1397 return vp.m_projection_type == PROJECTION_MERCATOR ||
1398 vp.m_projection_type == PROJECTION_POLAR ||
1399 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1413#define NORM_FACTOR 4096.0
1414void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1415#ifndef USE_ANDROID_GLES2
1417 wxPoint2DDouble point;
1419 switch (vp.m_projection_type) {
1420 case PROJECTION_MERCATOR:
1421 case PROJECTION_EQUIRECTANGULAR:
1422 case PROJECTION_WEB_MERCATOR:
1425 glTranslated(point.m_x, point.m_y, 0);
1430 case PROJECTION_POLAR:
1434 glTranslated(point.m_x, point.m_y, 0);
1435 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1442 printf(
"ERROR: Unhandled projection\n");
1447 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1455 switch (vp.m_projection_type) {
1456 case PROJECTION_MERCATOR:
1457 case PROJECTION_EQUIRECTANGULAR:
1458 case PROJECTION_WEB_MERCATOR:
1462 case PROJECTION_POLAR:
1467 printf(
"ERROR: Unhandled projection\n");
1476bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1477 return vp.m_projection_type == PROJECTION_MERCATOR ||
1478 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1479 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1483 const LLRegion ®ion) {
1484 if (!CanClipViewport(vp))
return vp;
1487 LLBBox bbox = region.GetBox();
1489 if (!bbox.GetValid())
return vp;
1497 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1498 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1499 bbox.GetMaxLon() + 360);
1500 cvp.SetBBoxDirect(bbox);
1501 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1502 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1503 bbox.GetMaxLon() - 360);
1504 cvp.SetBBoxDirect(bbox);
1506 cvp.SetBBoxDirect(bbox);
1511void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1512 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1518 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1520 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1524 if (!pRouteDraw)
continue;
1527 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1530 if (pRouteDraw->m_bIsBeingEdited)
continue;
1532 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1537 if (vp.GetBBox().GetValid() && pWayPointMan) {
1538 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1539 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1540 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1546void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1551 if (pActiveTrack && pActiveTrack->IsRunning())
1552 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1558 if (!pRouteDraw)
continue;
1561 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1564 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1567 if (pRouteDraw->IsSelected()) drawit++;
1570 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1571 if (!vp_box.IntersectOut(test_box))
1572 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1578 if (vp.GetBBox().GetValid() && pWayPointMan) {
1579 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1580 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1587static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1591 switch (vp.m_projection_type) {
1592 case PROJECTION_TRANSVERSE_MERCATOR:
1593 lat_dist = 4, lon_dist = 1;
1595 case PROJECTION_POLYCONIC:
1596 lat_dist = 2, lon_dist = 1;
1598 case PROJECTION_ORTHOGRAPHIC:
1599 lat_dist = 2, lon_dist = 2;
1601 case PROJECTION_POLAR:
1602 lat_dist = 180, lon_dist = 1;
1604 case PROJECTION_STEREOGRAPHIC:
1605 case PROJECTION_GNOMONIC:
1606 lat_dist = 2, lon_dist = 1;
1608 case PROJECTION_EQUIRECTANGULAR:
1611 lat_dist = 2, lon_dist = 360;
1614 lat_dist = 180, lon_dist = 360;
1618void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1619 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1625 ChartData->GetDBBoundingBox(dbIndex, box);
1626 if (!box.GetValid())
return;
1630 if (box.GetLonRange() == 360)
return;
1632 LLBBox vpbox = vp.GetBBox();
1634 double lon_bias = 0;
1636 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1639 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1640 color = GetGlobalColor(
"YELO1");
1641 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1642 color = GetGlobalColor(
"GREEN2");
1644 color = GetGlobalColor(
"UINFR");
1646#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1647 float plylat, plylon;
1649 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1651 glColor3ub(color.Red(), color.Green(), color.Blue());
1652 glLineWidth(g_GLMinSymbolLineWidth);
1654 float lat_dist, lon_dist;
1655 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1658 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1662 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1664 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1666 bool begin =
false, sml_valid =
false;
1668 float lastplylat = 0.0;
1669 float lastplylon = 0.0;
1671 int modulo = (nPly == 0) ? 1 : nPly;
1672 for (
int i = 0; i < nPly + 1; i++) {
1674 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1676 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1680 if (lastplylon - plylon > 180)
1682 else if (lastplylon - plylon < -180)
1689 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1690 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1691 splits = wxMax(lat_splits, lon_splits) + 1;
1698 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1699 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1702 for (
double c = 0; c < splits; c++) {
1704 if (c == splits - 1)
1705 lat = plylat, lon = plylon;
1707 double d = (double)(c + 1) / splits;
1708 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1714 if (!std::isnan(s.m_x)) {
1717 glBegin(GL_LINE_STRIP);
1719 glVertex2f(s.m_x, s.m_y);
1725 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1726 lastplylat = plylat, lastplylon = plylon;
1731 }
while (++j < nAuxPlyEntries);
1733 glDisable(GL_LINE_SMOOTH);
1737 double nominal_line_width_pix =
1738 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1740 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1741 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1744 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1745 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1749 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1752 float plylat1, plylon1;
1756 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1757 if (0 == nAuxPlyEntries)
1760 std::vector<int> points_vector;
1762 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1763 int nPly = vec.size() / 2;
1765 if (nPly == 0)
return;
1767 for (
int i = 0; i < nPly; i++) {
1768 plylon1 = vec[i * 2];
1769 plylat1 = vec[i * 2 + 1];
1775 points_vector.push_back(pixx1);
1776 points_vector.push_back(pixy1);
1779 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1780 plylon1 += lon_bias;
1786 points_vector.push_back(pixx1);
1787 points_vector.push_back(pixy1);
1789 if (points_vector.size()) {
1790 std::vector<int>::iterator it = points_vector.begin();
1791 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1799 for (
int j = 0; j < nAuxPlyEntries; j++) {
1800 std::vector<int> points_vector;
1802 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1803 int nAuxPly = vec.size() / 2;
1805 if (nAuxPly == 0)
continue;
1807 for (
int i = 0; i < nAuxPly; i++) {
1808 plylon1 = vec[i * 2];
1809 plylat1 = vec[i * 2 + 1];
1815 points_vector.push_back(pixx1);
1816 points_vector.push_back(pixy1);
1823 points_vector.push_back(pixx1);
1824 points_vector.push_back(pixy1);
1826 if (points_vector.size()) {
1827 std::vector<int>::iterator it = points_vector.begin();
1828 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1836extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1837 float &MinorSpacing);
1838extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1839void glChartCanvas::GridDraw() {
1840 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1842 ViewPort &vp = m_pParentCanvas->GetVP();
1844 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1848 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1850 double nlat, elon, slat, wlon;
1852 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1855 wxColour GridColor = GetGlobalColor(
"SNDG1");
1857 if (!m_gridfont.IsBuilt()) {
1859 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1860 wxFont font = *dFont;
1861 int font_size = wxMax(10, dFont->GetPointSize());
1862 font.SetPointSize(font_size * m_displayScale);
1863 font.SetWeight(wxFONTWEIGHT_NORMAL);
1866 m_gridfont.Build(font, 1, dpi_factor);
1868 m_gridfont.SetColor(GridColor);
1873 LLBBox llbbox = vp.GetBBox();
1874 nlat = llbbox.GetMaxLat();
1875 slat = llbbox.GetMinLat();
1876 elon = llbbox.GetMaxLon();
1877 wlon = llbbox.GetMinLon();
1884 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1885 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1886 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1887 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1888 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1889 vp.m_projection_type == PROJECTION_POLAR ||
1890 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1893 if (straight_latitudes)
1896 latmargin = gridlatMajor / 2;
1898 slat = wxMax(slat, -90 + latmargin);
1899 nlat = wxMin(nlat, 90 - latmargin);
1901 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1902 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1906 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1913 float lon_step = elon - wlon;
1914 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1916 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1918 s.x = INVALID_COORD;
1919 s.y = INVALID_COORD;
1920 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1922 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1923 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1931 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1932 lat += gridlatMinor) {
1935 gldc.DrawLine(0, r.y, 10, r.y,
true);
1936 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1941 float lat_step = nlat - slat;
1942 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1944 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1946 s.x = INVALID_COORD;
1947 s.y = INVALID_COORD;
1948 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1950 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1951 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1959 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1960 lon += gridlonMinor) {
1963 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1964 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1970 glEnable(GL_TEXTURE_2D);
1972 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1973 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1976 CalcGridText(lat, gridlatMajor,
true);
1978 m_gridfont.GetTextExtent(st, 0, &iy);
1980 if (straight_latitudes) {
1985 float x = 0, y = -1;
1986 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1987 if (y < 0 || y > h) {
1989 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1992 m_gridfont.RenderString(st, x, y);
1996 double y1, y2, lat1, lon1, lat2, lon2;
2005 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2008 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2010 if (fabs(y - y1) < fabs(y - y2))
2016 error = fabs(r.m_x);
2017 if (--maxiters == 0)
break;
2018 }
while (error > 1 && error < lasterror);
2020 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2026 m_gridfont.RenderString(st, r.m_x, r.m_y);
2030 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2031 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2040 else if (xlon <= -180.0)
2043 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2045 m_gridfont.GetTextExtent(st, &ix, 0);
2047 if (straight_longitudes) {
2048 float x = -1, y = 0;
2049 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2050 if (x < 0 || x > w) {
2052 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2055 m_gridfont.RenderString(st, x, y);
2059 double x1, x2, lat1, lon1, lat2, lon2;
2067 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2070 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2072 if (fabs(x - x1) < fabs(x - x2))
2078 error = fabs(r.m_y);
2079 }
while (error > 1 && error < lasterror);
2081 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2086 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2088 m_gridfont.RenderString(st, r.m_x, r.m_y);
2092 glDisable(GL_TEXTURE_2D);
2093 glDisable(GL_BLEND);
2098 if (!emboss)
return;
2100 int w = emboss->width, h = emboss->height;
2102 glEnable(GL_TEXTURE_2D);
2105 if (!emboss->gltexind) {
2107 emboss->glwidth = NextPow2(emboss->width);
2108 emboss->glheight = NextPow2(emboss->height);
2111 int size = emboss->glwidth * emboss->glheight;
2112 char *data =
new char[2 * size];
2113 for (
int i = 0; i < h; i++) {
2114 for (
int j = 0; j < emboss->glwidth; j++) {
2116 data[2 * ((i * emboss->glwidth) + j)] =
2117 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2118 data[2 * ((i * emboss->glwidth) + j) + 1] =
2119 (char)abs((emboss->pmap[(i * w) + j]));
2124 glGenTextures(1, &emboss->gltexind);
2125 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2126 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2127 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2135 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2139 int x = emboss->x, y = emboss->y;
2141 float wp = (float)w / emboss->glwidth;
2142 float hp = (float)h / emboss->glheight;
2168 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2170 glDisable(GL_BLEND);
2171 glDisable(GL_TEXTURE_2D);
2174void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2175 if (!m_pParentCanvas->GetVP().IsValid())
return;
2176 wxPoint GPSOffsetPixels(0, 0);
2177 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2180 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2181 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2185 double shift_dx = 0;
2186 double shift_dy = 0;
2187 bool dynamic = m_pParentCanvas->m_animationActive ||
2188 m_pParentCanvas->m_MouseDragging ||
2189 m_pParentCanvas->m_chart_drag_inertia_active;
2190 if (m_pParentCanvas->m_bFollow && !dynamic) {
2191 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2192 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2193 if (m_pParentCanvas->m_bLookAhead) {
2199 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2200 angle += m_pParentCanvas->GetVPRotation();
2201 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2203 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2204 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2206 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2211 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2212 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2219 lShipMidPoint = lGPSPoint;
2223 float icon_hdt = pCog;
2224 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2227 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2231 double osd_head_lat, osd_head_lon;
2232 wxPoint2DDouble osd_head_point;
2234 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2238 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2240 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2241 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2242 icon_rad += (float)PI;
2246 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2250 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2256 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2257 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2258 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2263 float scale_factor = 1.0;
2268 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2269 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2270 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2272 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2274 float nominal_ownship_size_pixels =
2276 nominal_ownship_size_mm);
2278 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2280 wxPen ppSmallScaleShip;
2281 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2283 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2286 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2287 dc.SetPen(ppSmallScaleShip);
2289 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2292 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2293 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2294 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2295 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2298 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2299 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2302 int draw_color = SHIP_INVALID;
2303 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2304 draw_color = SHIP_NORMAL;
2305 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2306 draw_color = SHIP_LOWACCURACY;
2314 ownship_color = draw_color;
2316 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2318 glGenTextures(1, &ownship_tex);
2319 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2321 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2325 if (m_pParentCanvas->m_pos_image_user) {
2326 switch (draw_color) {
2328 image = *m_pParentCanvas->m_pos_image_user_grey;
2331 image = *m_pParentCanvas->m_pos_image_user;
2333 case SHIP_LOWACCURACY:
2334 image = *m_pParentCanvas->m_pos_image_user_yellow;
2338 switch (draw_color) {
2340 image = *m_pParentCanvas->m_pos_image_grey;
2343 image = *m_pParentCanvas->m_pos_image_red;
2345 case SHIP_LOWACCURACY:
2346 image = *m_pParentCanvas->m_pos_image_yellow;
2351 int w = image.GetWidth(), h = image.GetHeight();
2352 int glw = NextPow2(w), glh = NextPow2(h);
2353 ownship_size = wxSize(w, h);
2354 ownship_tex_size = wxSize(glw, glh);
2356 unsigned char *d = image.GetData();
2357 unsigned char *a = image.GetAlpha();
2358 unsigned char *e =
new unsigned char[4 * w * h];
2361 for (
int p = 0; p < w * h; p++) {
2362 e[4 * p + 0] = d[3 * p + 0];
2363 e[4 * p + 1] = d[3 * p + 1];
2364 e[4 * p + 2] = d[3 * p + 2];
2365 e[4 * p + 3] = a[p];
2368 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2369 GL_UNSIGNED_BYTE, 0);
2371 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2377#ifndef USE_ANDROID_GLES2
2378 if (m_pParentCanvas->m_pos_image_user)
2379 glColor4ub(255, 255, 255, 255);
2380 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2381 glColor4ub(255, 0, 0, 255);
2382 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2383 glColor4ub(255, 255, 0, 255);
2385 glColor4ub(128, 128, 128, 255);
2387 float scale_factor_y = 1.0;
2388 float scale_factor_x = 1.0;
2390 int ownShipWidth = 22;
2391 int ownShipLength = 84;
2392 lShipMidPoint = lGPSPoint;
2395 if (g_OwnShipIconType != 0)
2396 m_pParentCanvas->ComputeShipScaleFactor(
2397 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2398 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2403 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2404 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2405 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2409 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2410 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2414 float gps_circle_radius = 3.0;
2416 if (g_OwnShipIconType == 0) {
2418 glEnable(GL_TEXTURE_2D);
2419 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2428 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2429 if (m_pParentCanvas->m_pos_image_user)
2430 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2432 float nominal_ownship_size_mm =
2433 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2435 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2436 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2438 float nominal_ownship_size_pixels =
2439 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2441 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2442 nominal_ownship_size_pixels = wxMax(
2443 20.0, nominal_ownship_size_pixels);
2446 float h = nominal_ownship_size_pixels * scale_factor_y;
2447 float w = nominal_ownship_size_pixels * scale_factor_x *
2448 ownship_size.x / ownship_size.y;
2449 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2450 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2456 gps_circle_radius = w / 5;
2458 float uv[8], coords[8];
2477 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2478 lShipMidPoint.m_x, lShipMidPoint.m_y,
2480 glDisable(GL_TEXTURE_2D);
2481 }
else if (g_OwnShipIconType == 1) {
2483 glEnable(GL_TEXTURE_2D);
2484 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2486 float nominal_ownship_size_pixels_y = 84;
2487 float nominal_ownship_size_pixels_x = 22;
2489 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2490 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2492 float u = (float)ownship_size.x / ownship_tex_size.x,
2493 v = (
float)ownship_size.y / ownship_tex_size.y;
2496 gps_circle_radius = w / 5;
2498 float uv[8], coords[8];
2517 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2518 lShipMidPoint.m_x, lShipMidPoint.m_y,
2521 glDisable(GL_TEXTURE_2D);
2522 }
else if (g_OwnShipIconType == 2) {
2530 wxPoint shipPoints[6];
2532 wxColour colour = m_pParentCanvas->ShipColor();
2533 wxPen ppPen(*wxBLACK, 1);
2534 wxBrush ppBrush(colour);
2536 dc.SetBrush(ppBrush);
2538 shipPoints[0].x = 0 * scale_factor_x;
2539 shipPoints[0].y = -28 * scale_factor_y;
2540 shipPoints[1].x = 11 * scale_factor_x;
2541 shipPoints[1].y = -28 * scale_factor_y;
2542 shipPoints[2].x = 11 * scale_factor_x;
2543 shipPoints[2].y = 42 * scale_factor_y;
2544 shipPoints[3].x = 0 * scale_factor_x;
2545 shipPoints[3].y = 42 * scale_factor_y;
2546 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2549 shipPoints[0].x = 0 * scale_factor_x;
2550 shipPoints[0].y = -42 * scale_factor_y;
2551 shipPoints[1].x = 5 * scale_factor_x;
2552 shipPoints[1].y = -42 * scale_factor_y;
2553 shipPoints[2].x = 11 * scale_factor_x;
2554 shipPoints[2].y = -28 * scale_factor_y;
2555 shipPoints[3].x = 0 * scale_factor_x;
2556 shipPoints[3].y = -28 * scale_factor_y;
2557 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2560 shipPoints[0].x = 0 * scale_factor_x;
2561 shipPoints[0].y = -28 * scale_factor_y;
2562 shipPoints[1].x = -11 * scale_factor_x;
2563 shipPoints[1].y = -28 * scale_factor_y;
2564 shipPoints[2].x = -11 * scale_factor_x;
2565 shipPoints[2].y = 42 * scale_factor_y;
2566 shipPoints[3].x = 0 * scale_factor_x;
2567 shipPoints[3].y = 42 * scale_factor_y;
2568 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2571 shipPoints[0].x = 0 * scale_factor_x;
2572 shipPoints[0].y = -42 * scale_factor_y;
2573 shipPoints[1].x = -5 * scale_factor_x;
2574 shipPoints[1].y = -42 * scale_factor_y;
2575 shipPoints[2].x = -11 * scale_factor_x;
2576 shipPoints[2].y = -28 * scale_factor_y;
2577 shipPoints[3].x = 0 * scale_factor_x;
2578 shipPoints[3].y = -28 * scale_factor_y;
2579 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2583 double p1x = -11 * scale_factor_x;
2584 double p2x = 11 * scale_factor_x;
2588 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2590 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2592 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2594 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2595 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2596 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2600 p1y = -42 * scale_factor_y;
2601 p2y = 42 * scale_factor_y;
2602 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2603 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2604 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2605 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2606 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2607 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2610 img_height = ownShipLength * scale_factor_y;
2613 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2615 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2617 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2619 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2623 glDisable(GL_LINE_SMOOTH);
2624 glDisable(GL_POLYGON_SMOOTH);
2625 glDisable(GL_BLEND);
2628 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2632void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2633 ViewPort &vp = m_pParentCanvas->GetVP();
2656 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2658 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2659 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2661 m_pParentCanvas->AlertDraw(dc);
2663 m_pParentCanvas->RenderVisibleSectorLights(dc);
2665 m_pParentCanvas->RenderRouteLegs(dc);
2666 m_pParentCanvas->RenderShipToActive(dc,
true);
2667 m_pParentCanvas->ScaleBarDraw(dc);
2668 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2669 m_pParentCanvas->extendedSectorLegs);
2676void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2677 if (m_pParentCanvas->GetPiano()) {
2678 int canvas_height = GetClientSize().y;
2679 canvas_height *= m_displayScale;
2681 m_pParentCanvas->GetPiano()->DrawGL(
2682 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2686void glChartCanvas::DrawQuiting() {
2687#ifndef USE_ANDROID_GLES2
2688 GLubyte pattern[8][8];
2689 for (
int y = 0; y < 8; y++)
2690 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2693 glEnable(GL_TEXTURE_2D);
2694 glBindTexture(GL_TEXTURE_2D, 0);
2696 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2697 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2698 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2700 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2704 float x = GetSize().x, y = GetSize().y;
2705 float u = x / 8, v = y / 8;
2718 glDisable(GL_TEXTURE_2D);
2719 glDisable(GL_BLEND);
2723void glChartCanvas::DrawCloseMessage(wxString msg) {
2724#ifndef USE_ANDROID_GLES2
2728 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2732 texfont.Build(*pfont, 1, 1);
2734 texfont.GetTextExtent(msg, &w, &h);
2736 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2737 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2739 glColor3ub(243, 229, 47);
2743 glVertex2i(xp + w, yp);
2744 glVertex2i(xp + w, yp + h);
2745 glVertex2i(xp, yp + h);
2750 glColor3ub(0, 0, 0);
2751 glEnable(GL_TEXTURE_2D);
2752 texfont.RenderString(msg, xp, yp);
2753 glDisable(GL_TEXTURE_2D);
2754 glDisable(GL_BLEND);
2761static std::list<double *> combine_work_data;
2762static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2763 GLfloat weight[4], GLdouble **dataOut) {
2764 double *vertex =
new double[3];
2765 combine_work_data.push_back(vertex);
2766 memcpy(vertex, coords, 3 * (
sizeof *coords));
2770#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2771void vertexCallbackD_GLSL(GLvoid *vertex) {
2773 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2774 int new_buf_len = s_tess_buf_len + 100;
2775 GLfloat *tmp = s_tess_work_buf;
2778 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2779 if (NULL == s_tess_work_buf) {
2783 s_tess_buf_len = new_buf_len;
2786 GLdouble *pointer = (GLdouble *)vertex;
2788 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2789 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2794void beginCallbackD_GLSL(GLenum mode) {
2795 s_tess_vertex_idx_this = s_tess_vertex_idx;
2800void endCallbackD_GLSL() {
2804 shader->SetUniformMatrix4fv(
"MVMatrix",
2805 (GLfloat *)s_tessVP.vp_matrix_transform);
2807 mat4x4 identityMatrix;
2808 mat4x4_identity(identityMatrix);
2809 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2813 colorv[0] = s_regionColor.Red() / float(256);
2814 colorv[1] = s_regionColor.Green() / float(256);
2815 colorv[2] = s_regionColor.Blue() / float(256);
2816 colorv[3] = s_regionColor.Alpha() / float(256);
2817 shader->SetUniform4fv(
"color", colorv);
2819 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2820 shader->SetAttributePointerf(
"position", bufPt);
2822 glDrawArrays(s_tess_mode, 0, s_nvertex);
2827void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2829void beginCallbackD(GLenum mode) { glBegin(mode); }
2831void endCallbackD() { glEnd(); }
2835void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2836 float lat_dist, lon_dist;
2837 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2839 GLUtesselator *tobj = gluNewTess();
2840 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2842#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2843 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2844 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2845 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2846 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2850 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2851 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2852 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2853 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2856 gluTessNormal(tobj, 0, 0, 1);
2858 gluTessBeginPolygon(tobj, NULL);
2859 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2860 i != region.contours.end(); i++) {
2861 gluTessBeginContour(tobj);
2862 contour_pt l = *i->rbegin();
2864 bool sml_valid =
false;
2865 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2866 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2867 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2868 int splits = wxMax(lat_splits, lon_splits) + 1;
2874 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2875 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2878 for (
int i = 0; i < splits; i++) {
2880 if (i == splits - 1)
2881 lat = j->y, lon = j->x;
2883 double d = (double)(i + 1) / splits;
2884 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2888 if (std::isnan(q.m_x))
continue;
2890 double *p =
new double[6];
2895 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2900 gluTessVertex(tobj, p, p);
2901 combine_work_data.push_back(p);
2905 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2907 gluTessEndContour(tobj);
2909 gluTessEndPolygon(tobj);
2911 gluDeleteTess(tobj);
2913 for (std::list<double *>::iterator i = combine_work_data.begin();
2914 i != combine_work_data.end(); i++)
2916 combine_work_data.clear();
2921void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2922 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2924 if (s_b_useStencil) {
2926 glEnable(GL_STENCIL_TEST);
2928 glClear(GL_STENCIL_BUFFER_BIT);
2932 glStencilFunc(GL_ALWAYS, 1, 1);
2933 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2936#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2940 glEnable(GL_DEPTH_TEST);
2941 glDepthFunc(GL_ALWAYS);
2942 glDepthMask(GL_TRUE);
2944 glClear(GL_DEPTH_BUFFER_BIT);
2957 glTranslatef(0, 0, .5);
2961 s_regionColor = wxColor(0, 0, 0, 255);
2962 DrawRegion(vp, region);
2964 if (s_b_useStencil) {
2967 glStencilFunc(GL_EQUAL, 1, 1);
2968 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2971#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2973 glDepthFunc(GL_GREATER);
2974 glDepthMask(GL_FALSE);
2975 glTranslatef(0, 0, -.5);
2978 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2981void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2985 if (s_b_useStencil && s_b_useScissorTest) {
2987 if (rect != vp_rect) {
2988 glEnable(GL_SCISSOR_TEST);
2989 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2992#ifndef USE_ANDROID_GLES2
2998void glChartCanvas::DisableClipRegion() {
2999 glDisable(GL_SCISSOR_TEST);
3000 glDisable(GL_STENCIL_TEST);
3001 glDisable(GL_DEPTH_TEST);
3004void glChartCanvas::Invalidate() {
3006 m_cache_vp.Invalidate();
3012 if (!pBSBChart)
return;
3018 wxString key = chart->GetHashKey();
3022 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3025 if (ittf == hash.end()) {
3027 hash[key]->SetHashKey(key);
3030 pTexFact = hash[key];
3031 pTexFact->SetLRUTime(++m_LRUtime);
3036 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3037 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3044 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3045 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3046 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3047 base_level = log(scalefactor) / log(2.0);
3056 glEnable(GL_TEXTURE_2D);
3057#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3058 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3060 glEnableClientState(GL_VERTEX_ARRAY);
3061 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3066 pTexFact->GetCenter(lat, lon);
3067 MultMatrixViewPort(vp, lat, lon);
3071 LLBBox box = region.GetBox();
3074 if (g_memCacheLimit > 0) {
3079 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3080 for (
int i = 0; i < numtiles; i++) {
3082 if (region.IntersectOut(tile->box)) {
3085 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3086 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3088 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3089 global_color_scheme, mem_used);
3093 coords = tile->m_coords;
3095 coords =
new float[2 * tile->m_ncoords];
3096 for (
int i = 0; i < tile->m_ncoords; i++) {
3098 tile->m_coords[2 * i + 1]);
3099 coords[2 * i + 0] = p.m_x;
3100 coords[2 * i + 1] = p.m_y;
3104#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3105 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3106 m_pParentCanvas->GetpVP());
3109 glDisable(GL_TEXTURE_2D);
3113 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3114 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3115 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3117 if (!texture) glEnable(GL_TEXTURE_2D);
3119 if (!use_norm_vp)
delete[] coords;
3123 glDisable(GL_TEXTURE_2D);
3125#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3126 if (use_norm_vp) glPopMatrix();
3128 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3129 glDisableClientState(GL_VERTEX_ARRAY);
3133void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3135 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3136 m_pParentCanvas->m_pQuilt->IsBusy())
3140 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3142 printf(
" Chart NULL\n");
3143 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3153 LLRegion region = vp.GetLLRegion(rect_region);
3155 LLRegion rendered_region;
3161 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3169 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3171 LLRegion get_region = pqp->ActiveRegion;
3172 bool b_rendered =
false;
3174 if (!pqp->b_overlay) {
3175 get_region.Intersect(region);
3176 if (!get_region.Empty()) {
3177 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3180 SetClipRegion(vp, get_region );
3181 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3182 DisableClipRegion();
3185 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3186 SetClipRegion(vp, pqp->ActiveRegion );
3187 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3189 DisableClipRegion();
3192 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3193 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3194 RenderNoDTA(vp, get_region);
3195 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3200 if (Chs57->m_RAZBuilt) {
3201 RenderNoDTA(vp, get_region);
3202 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3203 rect_region, get_region);
3204 DisableClipRegion();
3209 const LLRegion &oregion = get_region;
3210 LLBBox box = oregion.GetBox();
3221 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3224 ViewPort cvp = ClippedViewport(vp, get_region);
3225 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3226 SetClipRegion(cvp, get_region);
3227 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3228 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3229 RenderWorldChart(gldc, cvp, srect, world);
3230 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3231 global_color_scheme);
3232 DisableClipRegion();
3239 SetClipRegion(vp, get_region);
3240 RenderNoDTA(vp, get_region);
3241 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3243 DisableClipRegion();
3246 SetClipRegion(vp, get_region);
3247 RenderNoDTA(vp, get_region);
3248 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3250 DisableClipRegion();
3266 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3270 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3271 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3273 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3274 if (pqp->b_Valid && pqp->b_overlay &&
3275 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3276 LLRegion get_region = pqp->ActiveRegion;
3278 get_region.Intersect(region);
3279 if (!get_region.Empty()) {
3282 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3287 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3294 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3299 ViewPort vph = m_pParentCanvas->GetVP();
3300 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3303 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3305 if (!hiregion.Empty()) {
3309 switch (global_color_scheme) {
3310 case GLOBAL_COLOR_SCHEME_DAY:
3313 case GLOBAL_COLOR_SCHEME_DUSK:
3316 case GLOBAL_COLOR_SCHEME_NIGHT:
3324#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3326 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3328 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3331 DrawRegion(vp, hiregion);
3333 glDisable(GL_BLEND);
3338 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3340 if (!hiregion.Empty()) {
3344 switch (global_color_scheme) {
3345 case GLOBAL_COLOR_SCHEME_DAY:
3348 case GLOBAL_COLOR_SCHEME_DUSK:
3351 case GLOBAL_COLOR_SCHEME_NIGHT:
3360#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3362 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3364 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3367 DrawRegion(vp, hiregion);
3369 glDisable(GL_BLEND);
3373 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3376void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3378 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3379 m_pParentCanvas->m_pQuilt->IsBusy())
3383 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3385 LLRegion region = vp.GetLLRegion(rect_region);
3387 LLRegion rendered_region;
3389 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3391 LLRegion get_region = pqp->ActiveRegion;
3393 if (!pqp->b_overlay) {
3394 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3397 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3402 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3409 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3437void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3438 ViewPort &vp = m_pParentCanvas->VPoint;
3446 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3447 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3450 LLRegion chart_region;
3452 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3453 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3454 CHART_FAMILY_RASTER) {
3462 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3463 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3464 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3466 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3470 for (
int i = 1; i < 6; i += 2)
3471 if (fabs(ll[i] - ll[i + 2]) > 180) {
3473 for (
int i = 1; i < 8; i += 2)
3474 if (ll[i] < 0) ll[i] += 360;
3478 chart_region = LLRegion(4, ll);
3481 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3483 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3484 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3485 chart_region = LLRegion(4, ll);
3488 chart_region = vp.b_quilt
3489 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3490 : m_pParentCanvas->m_singleChart->GetValidRegion();
3492 bool world_view =
false;
3494 wxRect rect = upd.GetRect();
3495 LLRegion background_region = vp.GetLLRegion(rect);
3498 background_region.Subtract(chart_region);
3500 if (!background_region.Empty()) {
3501 ViewPort cvp = ClippedViewport(vp, background_region);
3502 SetClipRect(cvp, rect,
false);
3503 RenderWorldChart(dc, cvp, rect, world_view);
3504 DisableClipRegion();
3509 RenderQuiltViewGL(vp, rect_region);
3512 LLRegion region = vp.GetLLRegion(rect_region);
3513 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3514 CHART_FAMILY_RASTER) {
3515 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3516 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3517 *m_pcontext, vp, rect_region, region);
3519 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3520 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3521 CHART_FAMILY_VECTOR) {
3522 chart_region.Intersect(region);
3523 RenderNoDTA(vp, chart_region);
3524 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3525 rect_region, region);
3531void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3533 wxColour color = GetGlobalColor(
"NODTA");
3534#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3536 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3538 glColor4ub(163, 180, 183, transparency);
3541 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3545 s_regionColor = color;
3548 DrawRegion(vp, region);
3552void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3555 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3557 glEnable(GL_SCISSOR_TEST);
3558 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3564 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3565#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3567 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3571 colorv[0] = water.Red() / float(256);
3572 colorv[1] = water.Green() / float(256);
3573 colorv[2] = water.Blue() / float(256);
3575 shader->SetUniform4fv(
"color", colorv);
3586 shader->SetAttributePointerf(
"position", pf);
3588 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3600 glDisable(GL_SCISSOR_TEST);
3608void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3609 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3611 DrawStaticRoutesTracksAndWaypoints(vp);
3613 DisableClipRegion();
3616void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3618 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3622 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3623 if (!bmp.Ok())
return;
3625 wxImage image = bmp.ConvertToImage();
3626 int w = image.GetWidth(), h = image.GetHeight();
3629 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3630 tex_w = w, tex_h = h;
3632 tex_w = NextPow2(w), tex_h = NextPow2(h);
3634 m_tideTexWidth = tex_w;
3635 m_tideTexHeight = tex_h;
3637 unsigned char *d = image.GetData();
3638 unsigned char *a = image.GetAlpha();
3640 unsigned char mr, mg, mb;
3641 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3643 unsigned char *e =
new unsigned char[4 * w * h];
3645 for (
int y = 0; y < h; y++)
3646 for (
int x = 0; x < w; x++) {
3647 unsigned char r, g, b;
3648 int off = (y * w + x);
3658 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3662 glGenTextures(1, &m_tideTex);
3664 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3666 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3668 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3669 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3670 GL_UNSIGNED_BYTE, e);
3672 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3673 GL_UNSIGNED_BYTE, 0);
3674 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3683 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3684 glEnable(GL_TEXTURE_2D);
3687#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3689 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3693 if ((type ==
't') || (type ==
'T'))
3698 if (BBox.Contains(lat, lon)) {
3707 scale *= getAndroidDisplayDensity();
3709 double width2 =
scale * m_tideTexWidth / 2;
3710 double height2 =
scale * m_tideTexHeight / 2;
3725 coords[0] = xp - width2;
3726 coords[1] = yp - height2;
3727 coords[2] = xp - width2;
3728 coords[3] = yp + height2;
3729 coords[4] = xp + width2;
3730 coords[5] = yp + height2;
3731 coords[6] = xp + width2;
3732 coords[7] = yp - height2;
3734 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3741 glDisable(GL_TEXTURE_2D);
3742 glDisable(GL_BLEND);
3743 glBindTexture(GL_TEXTURE_2D, 0);
3745 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3748void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3749 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3752void glChartCanvas::SetColorScheme(ColorScheme cs) {
3753 if (!m_bsetup)
return;
3755 glDeleteTextures(1, &m_tideTex);
3756 glDeleteTextures(1, &m_currentTex);
3762void glChartCanvas::RenderGLAlertMessage() {
3763 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3764 wxString msg = m_pParentCanvas->GetAlertString();
3767 m_gldc.SetFont(*pfont);
3771 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3778 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3779 int xp = sbr.x + sbr.width + 5;
3781 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3782 m_gldc.SetPen(ppPen1);
3783 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3785 m_gldc.DrawRectangle(xp, yp, w, h);
3787 m_gldc.DrawText(msg, xp, yp);
3791unsigned long quiltHash;
3793extern wxLongLong s_t0;
3796void glChartCanvas::Render() {
3797 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3798 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3799 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3804 if (!g_PrintingInProgress)
return;
3807 if (!g_true_zoom && m_binPinch)
return;
3809 if (m_binPinch) printf(
" %ld Render Start\n", m_glstopwatch.Time());
3810 long render_start_time = m_glstopwatch.Time();
3812#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3813 loadShaders(GetCanvasIndex());
3814 configureShaders(m_pParentCanvas->VPoint);
3817#ifdef USE_ANDROID_GLES2
3821 if (m_binPinch)
return;
3830 bool recompose =
false;
3831 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3832 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3833 if (m_pParentCanvas->VPoint.IsValid()) {
3834 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3835 m_pParentCanvas->UpdateCanvasControlBar();
3844 if (sw.GetTime() > 2000) {
3850 s_tess_vertex_idx = 0;
3851 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3852 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3858 m_displayScale = GetContentScaleFactor();
3862 m_last_render_time = wxDateTime::Now().GetTicks();
3866 if (g_GLOptions.m_bTextureCompression &&
3867 !g_GLOptions.m_bTextureCompressionCaching)
3872 int gl_width, gl_height;
3873 gl_width = m_pParentCanvas->VPoint.
pix_width;
3874 gl_height = m_pParentCanvas->VPoint.
pix_height;
3877 m_glcanvas_width = gl_width;
3878 m_glcanvas_height = gl_height;
3882 if (gl_height & 1) {
3884 ViewPort *vp = m_pParentCanvas->GetpVP();
3891 ViewPort *vp = m_pParentCanvas->GetpVP();
3899 ViewPort *vp = m_pParentCanvas->GetpVP();
3902 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3905 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3913 ViewPort VPoint = m_pParentCanvas->VPoint;
3915 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3916 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3919#if !defined(USE_ANDROID_GLES2)
3920 glMatrixMode(GL_PROJECTION);
3923 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3924 glMatrixMode(GL_MODELVIEW);
3928 if (s_b_useStencil) {
3929 glEnable(GL_STENCIL_TEST);
3930 glStencilMask(0xff);
3931 glClear(GL_STENCIL_BUFFER_BIT);
3932 glDisable(GL_STENCIL_TEST);
3938 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3939 if (g_GLOptions.m_GLPolygonSmoothing)
3940 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3941 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3953 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3954 bool useFBO =
false;
3960 if (m_b_BuiltFBO && !bpost_hilite
3965 bool b_newview =
true;
3966 bool b_full =
false;
3974 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3978#ifdef USE_ANDROID_GLES2
3979 if (recompose) b_newview =
true;
3991 if (VPoint.b_quilt) {
3992 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3993 if (!chart) b_full =
true;
4002 bool accelerated_pan =
false;
4012 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4013 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4014 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4016 wxPoint2DDouble c_old =
4019 wxPoint2DDouble c_new =
4023 dy = wxRound(c_new.m_y - c_old.m_y);
4024 dx = wxRound(c_new.m_x - c_old.m_x);
4034 double deltax = c_new.m_x - c_old.m_x;
4035 double deltay = c_new.m_y - c_old.m_y;
4037 bool b_whole_pixel =
true;
4038 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4039 b_whole_pixel =
false;
4041 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4042 abs(dy) < m_cache_tex_y &&
4043 (abs(dx) > 0 || (abs(dy) > 0));
4052 if (m_displayScale > 1) accelerated_pan =
false;
4057 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4060#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4063 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4069 if (b_full) accelerated_pan =
false;
4071 if (accelerated_pan) {
4072 if ((dx != 0) || (dy != 0)) {
4084 if (dy > 0 && dy < gl_height)
4085 update_region.Union(
4086 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4088 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4090 if (dx > 0 && dx < gl_width)
4091 update_region.Union(
4092 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4094 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4096 m_cache_page = !m_cache_page;
4099 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4100 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4112 RenderCharts(m_gldc, update_region);
4116 glDisable(g_texture_rectangle_format);
4121 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4122 glEnable(GL_TEXTURE_2D);
4126 float x1, x2, y1, y2;
4139 float tx1, tx2, ty1, ty2;
4145 tx2 = sx / (float)m_cache_tex_x;
4147 ty2 = sy / (float)m_cache_tex_y;
4164 coords[2] = -dx + sx;
4166 coords[4] = -dx + sx;
4167 coords[5] = dy + sy;
4169 coords[7] = dy + sy;
4172 ptexture_2D_shader_program[GetCanvasIndex()];
4176 shader->SetUniform1i(
"uTex", 0);
4180 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4181 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4182 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4184 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4206 shader->SetAttributePointerf(
"aPos", co1);
4207 shader->SetAttributePointerf(
"aUV", tco1);
4209 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4212 shader->SetUniformMatrix4fv(
"MVMatrix",
4213 (GLfloat *)VPoint.vp_matrix_transform);
4216 glBindTexture(g_texture_rectangle_format, 0);
4218 glDisable(g_texture_rectangle_format);
4226 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4227 g_texture_rectangle_format,
4228 m_cache_tex[!m_cache_page], 0);
4239 wxColour color = GetGlobalColor(
"NODTA");
4240 glClearColor(color.Red() / 256., color.Green() / 256.,
4241 color.Blue() / 256., 1.0);
4242 glClear(GL_COLOR_BUFFER_BIT);
4248 RenderCharts(m_gldc, rscreen_region);
4253 m_cache_page = !m_cache_page;
4258 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4269 glMatrixMode(GL_PROJECTION);
4272 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4273 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4275 glMatrixMode(GL_MODELVIEW);
4279 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4280 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4282 glGetIntegerv(GL_VIEWPORT, viewport);
4283 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4284 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4293 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4294 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4295 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4297 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4301 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4302 glEnable(g_texture_rectangle_format);
4304 float tx, ty, tx0, ty0, divx, divy;
4307 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4310 divx = m_cache_tex_x;
4311 divy = m_cache_tex_y;
4314 tx0 = m_fbo_offsetx / divx;
4315 ty0 = m_fbo_offsety / divy;
4316 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4317 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4342 wxColour color = GetGlobalColor(
"NODTA");
4343 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4345 glClear(GL_COLOR_BUFFER_BIT);
4347 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4350 glDisable(g_texture_rectangle_format);
4352 m_cache_vp = VPoint;
4353 m_cache_vp.Validate();
4355 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4357 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4361 RenderCharts(m_gldc, screen_region);
4365 printf(
" Render Charts Done %ld\n",
4366 m_glstopwatch.Time() - render_start_time);
4370 RenderS57TextOverlay(VPoint);
4371 RenderMBTilesOverlay(VPoint);
4377 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4382 wxRect rt = upd.GetRect();
4383 LLRegion region = VPoint.GetLLRegion(rt);
4384 ViewPort cvp = ClippedViewport(VPoint, region);
4385 DrawGroundedOverlayObjects(gldc, cvp);
4388 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4389 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4390 LLBBox screenBox = screenLLRegion.GetBox();
4392 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4395 if (m_pParentCanvas->m_bShowTide) {
4396 m_pParentCanvas->RebuildTideSelectList(screenBox);
4397 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4400 if (m_pParentCanvas->m_bShowCurrent) {
4401 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4402 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4408 if (m_pParentCanvas->m_show_focus_bar &&
4409 (g_canvasConfig != 0)) {
4410 if (m_pParentCanvas == wxWindow::FindFocus()) {
4413 wxColour colour = GetGlobalColor(
"BLUE4");
4414 wxPen ppBlue(colour, 1);
4415 wxBrush ppBrush(colour);
4416 gldc.SetPen(ppBlue);
4417 gldc.SetBrush(ppBrush);
4418 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4419 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4420 wxPoint barPoints[4];
4423 barPoints[1].x = xw;
4425 barPoints[2].x = xw;
4426 barPoints[2].y = rect_pix;
4428 barPoints[3].y = rect_pix;
4430 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4434 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4438 DrawFloatingOverlayObjects(m_gldc);
4440#ifndef USE_ANDROID_GLES2
4443 glMatrixMode(GL_PROJECTION);
4446 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4447 glMatrixMode(GL_MODELVIEW);
4452 if (!g_bhide_depth_units)
4453 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4454 if (!g_bhide_overzoom_flag)
4455 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4458 ViewPort &vp = m_pParentCanvas->GetVP();
4463 if (!g_PrintingInProgress) {
4464 if (m_pParentCanvas->m_pTrackRolloverWin)
4465 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4467 if (m_pParentCanvas->m_pRouteRolloverWin)
4468 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4470 if (m_pParentCanvas->m_pAISRolloverWin)
4471 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4473 if (m_pParentCanvas->GetMUIBar())
4474 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4488 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4489 int x, y, width, height;
4490 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4491 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4492 wxBitmap bmp(width, height, -1);
4495 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4498 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4499 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4503 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4504 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4506 wxStringTokenizer tkz(s,
"\n");
4509 while (tkz.HasMoreTokens()) {
4510 token = tkz.GetNextToken();
4511 dc.DrawText(token, xt, yt);
4514 dc.SelectObject(wxNullBitmap);
4516 m_gldc.DrawBitmap(bmp, x, y,
false);
4522 if (g_bShowChartBar) DrawChartBar(m_gldc);
4524 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4526 m_pParentCanvas->m_Compass->Paint(gldc);
4528 if (m_pParentCanvas->IsPrimaryCanvas()) {
4529 auto ¬eman = NotificationManager::GetInstance();
4530 if (noteman.GetNotificationCount()) {
4531 m_pParentCanvas->m_notification_button->SetIconSeverity(
4532 noteman.GetMaxSeverity());
4533 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4534 m_pParentCanvas->m_notification_button->Show(
true);
4535 m_pParentCanvas->m_notification_button->Paint(gldc);
4537 m_pParentCanvas->m_notification_button->Show(
false);
4540 RenderGLAlertMessage();
4543 ViewPort &vp = m_pParentCanvas->GetVP();
4547 glActiveTexture(GL_TEXTURE0);
4551 if (g_bquiting) DrawQuiting();
4552 if (g_bcompression_wait)
4553 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4558 if (g_b_needFinish) glFinish();
4565 m_pParentCanvas->PaintCleanup();
4566 m_bforcefull =
false;
4569 printf(
" Render Finished: %ld\n",
4570 m_glstopwatch.Time() - render_start_time);
4575void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4578 if (VPoint.b_quilt) {
4579 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4580 ps52plib->GetShowS57Text()) {
4581 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4582 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4587 ChPI->ClearPLIBTextList();
4589 ps52plib->ClearTextList();
4599 RenderQuiltViewGLText(vpx, screen_region);
4604void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4607 LLRegion &screenLLRegion) {
4612 if (chart == NULL)
return;
4619 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4621 wxFileName tileFile(chart->GetFullPath());
4623 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4625 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4626 (tileSizeMB.GetLo() > 5000)) {
4629 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4630 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4631 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4638 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4642 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4645 std::vector<int> piano_active_array_tiles =
4646 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4647 bool bfound =
false;
4649 if (std::find(piano_active_array_tiles.begin(),
4650 piano_active_array_tiles.end(),
4651 dbIndex) != piano_active_array_tiles.end()) {
4656 piano_active_array_tiles.push_back(dbIndex);
4657 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4661void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4663 std::vector<int> stackIndexArray =
4664 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4665 unsigned int im = stackIndexArray.size();
4668 if (VPoint.b_quilt && im > 0) {
4669 bool regionVPBuilt =
false;
4671 LLRegion screenLLRegion;
4675 std::vector<int> tiles_to_show;
4676 for (
unsigned int is = 0; is < im; is++) {
4678 ChartData->GetChartTableEntry(stackIndexArray[is]);
4679 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4680 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4682 std::vector<int> piano_active_array_tiles =
4683 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4684 bool bfound =
false;
4686 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4687 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4688 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4696 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4697 piano_active_array_tiles);
4702 tiles_to_show.push_back(stackIndexArray[is]);
4703 if (!regionVPBuilt) {
4706 screenLLRegion = VPoint.GetLLRegion(screen_region);
4707 screenBox = screenLLRegion.GetBox();
4715 regionVPBuilt =
true;
4725 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4726 rit != tiles_to_show.rend(); ++rit) {
4727 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4729 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4730 rit != tiles_to_show.rend(); ++rit) {
4731 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4735 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4737 if (!hiregion.Empty()) {
4741 switch (global_color_scheme) {
4742 case GLOBAL_COLOR_SCHEME_DAY:
4745 case GLOBAL_COLOR_SCHEME_DUSK:
4748 case GLOBAL_COLOR_SCHEME_NIGHT:
4756#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4757 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4759 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4762 DrawRegion(VPoint, hiregion);
4764 glDisable(GL_BLEND);
4770void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4774 GetClientSize(&w, &h);
4776 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4777#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4778 glMatrixMode(GL_PROJECTION);
4781 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4782 glMatrixMode(GL_MODELVIEW);
4786 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4788 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4790 bool world_view =
false;
4791 RenderWorldChart(dc, cvp, rtex, world_view);
4798 glViewport(0, 0, (GLint)w, (GLint)h);
4799#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4800 glMatrixMode(GL_PROJECTION);
4803 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4804 glMatrixMode(GL_MODELVIEW);
4810void glChartCanvas::FastPan(
int dx,
int dy) {
4811#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4815void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4817 SetCurrent(*m_pcontext);
4818 float sx = GetSize().x;
4819 float sy = GetSize().y;
4820 glClear(GL_COLOR_BUFFER_BIT);
4823 GetClientSize(&w, &h);
4825 if (s_b_useStencil) {
4826 glEnable(GL_STENCIL_TEST);
4827 glStencilMask(0xff);
4828 glClear(GL_STENCIL_BUFFER_BIT);
4829 glDisable(GL_STENCIL_TEST);
4845 float sxfactor = sx / swidth;
4846 float syfactor = sy / sheight;
4848 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4849 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4850 sx * sx / swidth * 2, sy * sy / sheight * 2);
4851 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4852 glEnable(g_texture_rectangle_format);
4877 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4878 glBindTexture(g_texture_rectangle_format, 0);
4884 float tx, ty, tx0, ty0;
4894 glBindTexture(g_texture_rectangle_format, 0);
4897 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4898 glEnable(g_texture_rectangle_format);
4904 uv[0] = tx0 / m_cache_tex_x;
4905 uv[1] = ty / m_cache_tex_y;
4906 uv[2] = tx / m_cache_tex_x;
4907 uv[3] = ty / m_cache_tex_y;
4908 uv[4] = tx / m_cache_tex_x;
4909 uv[5] = ty0 / m_cache_tex_y;
4910 uv[6] = tx0 / m_cache_tex_x;
4911 uv[7] = ty0 / m_cache_tex_y;
4923 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4924 sx * sx / swidth, sy * sy / sheight);
4926 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4928 glDisable(g_texture_rectangle_format);
4929 glBindTexture(g_texture_rectangle_format, 0);
4936 wxColour color = GetGlobalColor(
"GREY1");
4937 float ht = -offset_y * (sy / sheight);
4938 wxRect r(0, sy - ht, w, ht);
4939 RenderColorRect(r, color);
4942 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4943 RenderColorRect(rt, color);
4946 float w1 = -offset_x * sx / swidth;
4947 wxRect rl(0, 0, w1, sy);
4948 RenderColorRect(rl, color);
4951 float px = w1 + sx * sx / swidth;
4952 wxRect rr(px, 0, sx - px, sy);
4953 RenderColorRect(rr, color);
4962void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4965 if (m_nRun < m_nTotal) {
4966 m_runoffsetx += m_offsetxStep;
4967 if (m_offsetxStep > 0)
4968 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4970 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4972 m_runoffsety += m_offsetyStep;
4973 if (m_offsetyStep > 0)
4974 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4976 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4978 m_runswidth += m_swidthStep;
4979 if (m_swidthStep > 0)
4980 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4982 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4984 m_runsheight += m_sheightStep;
4985 if (m_sheightStep > 0)
4986 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4988 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4993 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4999 if (m_zoomFinaldx || m_zoomFinaldy) {
5000 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5003 m_zoomFinal =
false;
5007void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5009 int sx = GetSize().x;
5010 int sy = GetSize().y;
5012 m_lastfbo_offsetx = m_fbo_offsetx;
5013 m_lastfbo_offsety = m_fbo_offsety;
5014 m_lastfbo_swidth = m_fbo_swidth;
5015 m_lastfbo_sheight = m_fbo_sheight;
5017 float curr_fbo_offset_x = m_fbo_offsetx;
5018 float curr_fbo_offset_y = m_fbo_offsety;
5019 float curr_fbo_swidth = m_fbo_swidth;
5020 float curr_fbo_sheight = m_fbo_sheight;
5022 float fx = (float)cp_x / sx;
5023 float fy = 1.0 - (float)cp_y / sy;
5025 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5026 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5028 m_fbo_swidth = curr_fbo_swidth / factor;
5029 m_fbo_sheight = curr_fbo_sheight / factor;
5031 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5032 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5034 m_fbo_offsetx += post_x;
5035 m_fbo_offsety += post_y;
5046 float perStep = m_nStep / m_nTotal;
5048 if (zoomTimer.IsRunning()) {
5049 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5050 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5051 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5052 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5055 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5056 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5057 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5058 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5060 m_runoffsetx = m_lastfbo_offsetx;
5061 m_runoffsety = m_lastfbo_offsety;
5062 m_runswidth = m_lastfbo_swidth;
5063 m_runsheight = m_lastfbo_sheight;
5066 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5067 m_zoomFinal =
false;
5073void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5077 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5080 if (m_binPinch)
return;
5081 if (m_bpinchGuard)
return;
5083 int x =
event.GetOffset().x;
5084 int y =
event.GetOffset().y;
5086 int lx =
event.GetLastOffset().x;
5087 int ly =
event.GetLastOffset().y;
5092 switch (event.GetState()) {
5093 case GestureStarted:
5094 if (m_binPan)
break;
5098 m_binGesture =
true;
5102 case GestureUpdated:
5107 m_pParentCanvas->FreezePiano();
5109 m_pParentCanvas->ThawPiano();
5120 case GestureFinished:
5123 m_pParentCanvas->UpdateCanvasControlBar();
5126 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5130 case GestureCanceled:
5132 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5139 m_bgestureGuard =
true;
5140 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5141 m_bforcefull =
false;
5146float zoom_inc = 1.0;
5148void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5149 float zoom_gain = 1.0;
5150 float zout_gain = 1.0;
5153 float total_zoom_val;
5155 float max_zoom_scale = 1000.;
5156 float min_zoom_scale = 2e8;
5158 if (event.GetScaleFactor() > 1)
5159 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5161 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5163 if (event.GetTotalScaleFactor() > 1)
5164 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5167 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5169 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5172 float max_zoom_scale = 1000.;
5173 if( cc1->GetVP().b_quilt) {
5174 int ref_index = cc1->GetQuiltRefChartdbIndex();
5181 float min_zoom_scale = 2e8;
5185 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5187 double projected_scale =
5188 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5190 switch (event.GetState()) {
5191 case GestureStarted:
5192 m_first_zout =
false;
5196 m_binGesture =
true;
5198 m_pinchStart =
event.GetCenterPoint();
5199 m_lpinchPoint = m_pinchStart;
5202 event.GetCenterPoint().y, m_pinchlat,
5207 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5208 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5211 SetCurrent(*m_pcontext);
5217 case GestureUpdated:
5219 if (projected_scale < min_zoom_scale) {
5220 wxPoint pinchPoint =
event.GetCenterPoint();
5222 float dx = pinchPoint.x - m_lpinchPoint.x;
5223 float dy = pinchPoint.y - m_lpinchPoint.y;
5225 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5226 -dx / total_zoom_val, dy / total_zoom_val);
5228 m_lpinchPoint = pinchPoint;
5232 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5233 wxPoint pinchPoint =
event.GetCenterPoint();
5235 float dx = pinchPoint.x - m_lpinchPoint.x;
5236 float dy = pinchPoint.y - m_lpinchPoint.y;
5238 if ((projected_scale > max_zoom_scale) &&
5239 (projected_scale < min_zoom_scale))
5240 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5241 -dx / total_zoom_val, dy / total_zoom_val);
5243 m_lpinchPoint = pinchPoint;
5246 m_first_zout =
true;
5247 zoom_inc *= zoom_val;
5248 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5249 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5253 wxPoint pinchPoint =
event.GetCenterPoint();
5254 float dx = pinchPoint.x - m_lpinchPoint.x;
5255 float dy = pinchPoint.y - m_lpinchPoint.y;
5257 m_lpinchPoint = pinchPoint;
5268 case GestureFinished: {
5272 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5273 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5277 float tzoom = total_zoom_val;
5279 if (projected_scale >= min_zoom_scale)
5280 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5282 if (projected_scale < max_zoom_scale)
5283 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5285 dx = (cc_x - m_cc_x) * tzoom;
5286 dy = -(cc_y - m_cc_y) * tzoom;
5288 if (zoomTimer.IsRunning()) {
5291 m_zoomFinalZoom = tzoom;
5297 double final_projected_scale =
5301 if (final_projected_scale < min_zoom_scale) {
5305 m_pParentCanvas->m_pQuilt->Invalidate();
5306 m_bforcefull =
true;
5313 m_pParentCanvas->m_pQuilt->Invalidate();
5314 m_bforcefull =
true;
5326 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5330 case GestureCanceled:
5332 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5339 m_bgestureGuard =
true;
5341 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5344void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5354 m_bgestureGuard =
false;
5355 m_bpinchGuard =
false;
5356 m_binGesture =
false;
5357 m_bforcefull =
false;
5360void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5364 m_binGesture =
false;
5365 m_bforcefull =
false;
5369#ifdef HAVE_WX_GESTURE_EVENTS
5371void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5374 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5377 if (m_binPinch)
return;
5378 if (m_bpinchGuard)
return;
5380 int dx =
event.GetDelta().x;
5381 int dy =
event.GetDelta().y;
5383 if (event.IsGestureStart()) {
5384 if (m_binPan)
return;
5388 m_binGesture =
true;
5392 else if (event.IsGestureEnd()) {
5394 m_pParentCanvas->UpdateCanvasControlBar();
5396 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5404 m_pParentCanvas->FreezePiano();
5406 m_pParentCanvas->ThawPiano();
5417 m_bgestureGuard =
true;
5418 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5419 m_bforcefull =
false;
5423void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5425 float zoom_gain = 1.0;
5426 float zout_gain = 1.0;
5428 float last_zoom_val = m_step_zoom_val;
5430 float max_zoom_scale = 1000.;
5431 float min_zoom_scale = 2e8;
5433 if (event.GetZoomFactor() > 1)
5434 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5436 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5438 float inc_zoom_val =
5439 m_total_zoom_val / last_zoom_val;
5443 if (event.IsGestureStart()) {
5444 m_glstopwatch.Start();
5445 printf(
"\nStart--------------\n");
5447 m_pParentCanvas->m_inPinch =
true;
5450 m_binGesture =
true;
5451 m_pinchStart =
event.GetPosition();
5452 m_lpinchPoint = m_pinchStart;
5453 m_total_zoom_val = 1.0;
5454 m_final_zoom_val = 1.0;
5455 m_step_zoom_val = 1.0;
5459 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5463 if (event.IsGestureEnd()) {
5465 if (!m_binGesture)
return;
5466 printf(
"EndZoom--------------\n");
5473 m_final_zoom_val = 1.0;
5474 m_total_zoom_val = 1.0;
5475 m_step_zoom_val = 1.0;
5477 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5484 float zoom_step = 5;
5485 float zoom_trigger = 0.05;
5486 if (projected_scale > 1e5)
5488 else if (projected_scale < 3e4)
5491 if (inc_zoom_val != 1.0) {
5492 if (inc_zoom_val > 1 + zoom_step) {
5493 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5494 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5496 SetCurrent(*m_pcontext);
5499 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5500 m_step_zoom_val = m_total_zoom_val;
5501 printf(
" Zoom: %6g\n", inc_zoom_val);
5506 bool b_allow_ztp =
true;
5507 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5508 b_allow_ztp =
false;
5510 if (g_bEnableZoomToCursor && b_allow_ztp) {
5516 int dx = r.x -
event.GetPosition().x;
5517 int dy = r.y -
event.GetPosition().y;
5521 SetCurrent(*m_pcontext);
5530 float zoom_gain = 1.0;
5531 float zout_gain = 1.0;
5533 float last_zoom_val = m_total_zoom_val;
5535 float max_zoom_scale = 1000.;
5536 float min_zoom_scale = 2e8;
5538 if (event.GetZoomFactor() > 1)
5539 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5541 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5543 float inc_zoom_val =
5544 m_total_zoom_val / last_zoom_val;
5546 double projected_scale =
5547 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5549 if (event.IsGestureStart()) {
5551 m_first_zout =
false;
5555 m_binGesture =
true;
5556 m_pinchStart =
event.GetPosition();
5557 m_lpinchPoint = m_pinchStart;
5558 m_total_zoom_val = 1.0;
5559 m_final_zoom_val = 1.0;
5562 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5566 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5567 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5570 SetCurrent(*m_pcontext);
5573 ViewPort vpr = m_pParentCanvas->VPoint;
5575 GetTouchBackingBitmap(vpr);
5580 if (event.IsGestureEnd()) {
5586 if (!m_binGesture)
return;
5588 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5589 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5593 float tzoom = m_final_zoom_val;
5595 dx = (cc_x - m_cc_x) * tzoom;
5596 dy = -(cc_y - m_cc_y) * tzoom;
5598 if (zoomTimer.IsRunning()) {
5601 m_zoomFinalZoom = tzoom;
5607 double final_projected_scale =
5611 if (final_projected_scale < min_zoom_scale) {
5615 m_pParentCanvas->m_pQuilt->Invalidate();
5616 m_bforcefull =
true;
5623 m_pParentCanvas->m_pQuilt->Invalidate();
5624 m_bforcefull =
true;
5629 m_final_zoom_val = 1.0;
5630 m_total_zoom_val = 1.0;
5631 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5636 if (projected_scale < min_zoom_scale) {
5637 wxPoint pinchPoint =
event.GetPosition();
5639 float dx = pinchPoint.x - m_lpinchPoint.x;
5640 float dy = pinchPoint.y - m_lpinchPoint.y;
5642 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5643 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5645 m_lpinchPoint = pinchPoint;
5646 m_final_zoom_val *= inc_zoom_val;
5650 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5651 wxPoint pinchPoint =
event.GetPosition();
5653 float dx = pinchPoint.x - m_lpinchPoint.x;
5654 float dy = pinchPoint.y - m_lpinchPoint.y;
5656 if ((projected_scale > max_zoom_scale) &&
5657 (projected_scale < min_zoom_scale))
5658 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5659 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5661 m_lpinchPoint = pinchPoint;
5662 m_final_zoom_val *= inc_zoom_val;
5665 m_first_zout =
true;
5666 m_zoom_inc *= inc_zoom_val;
5667 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5668 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5672 wxPoint pinchPoint =
event.GetPosition();
5673 float dx = pinchPoint.x - m_lpinchPoint.x;
5674 float dy = pinchPoint.y - m_lpinchPoint.y;
5676 m_lpinchPoint = pinchPoint;
5680 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5683 m_bgestureGuard =
true;
5684 m_bpinchGuard =
true;
5687void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5696 m_bgestureGuard =
false;
5697 m_bpinchGuard =
false;
5698 m_binGesture =
false;
5699 m_bforcefull =
false;
5702void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5706 m_binGesture =
false;
5707 m_bforcefull =
false;
5709 m_pParentCanvas->m_inPinch =
false;
5710 printf(
"******Finish\n");
5716void glChartCanvas::configureShaders(
ViewPort &vp) {
5717#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5723 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5725 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5726 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5747 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5749 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5750 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5762 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5764 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5765 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5768 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5770 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5771 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5779 shader = pAALine_shader_program[GetCanvasIndex()];
5781 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5784 shader = pring_shader_program[GetCanvasIndex()];
5786 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5787 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5791 if (texture_2DA_shader_program) {
5792 glUseProgram(texture_2DA_shader_program);
5793 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5794 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5795 (
const GLfloat *)pvp->vp_matrix_transform);
5797 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5798 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5806void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5809#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5810 int nl = nVertex / 4;
5812 float *luv = uvCoords;
5815 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5823 glEnableClientState(GL_VERTEX_ARRAY);
5824 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5826 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5827 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5828 glDrawArrays(GL_QUADS, 0, 4);
5835void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5836 float *uvCoords,
ViewPort *vp,
float dx,
5837 float dy,
float angle_rad) {
5838#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5840 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5841 if (!shader)
return;
5846 shader->SetUniform1i(
"uTex", 0);
5851 mat4x4_rotate_Z(Q, I, angle_rad);
5857 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5862 shader->SetAttributePointerf(
"aPos", co1);
5863 shader->SetAttributePointerf(
"aUV", tco1);
5870 GLushort indices1[] = {0,1,3,2};
5871 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5883 tco1[0] = uvCoords[0];
5884 tco1[1] = uvCoords[1];
5885 tco1[2] = uvCoords[2];
5886 tco1[3] = uvCoords[3];
5887 tco1[4] = uvCoords[6];
5888 tco1[5] = uvCoords[7];
5889 tco1[6] = uvCoords[4];
5890 tco1[7] = uvCoords[5];
5895 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5907void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5908#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5910 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5913 shader->SetUniformMatrix4fv(
5914 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5917 colorv[0] = color.Red() / float(256);
5918 colorv[1] = color.Green() / float(256);
5919 colorv[2] = color.Blue() / float(256);
5921 shader->SetUniform4fv(
"color", colorv);
5924 pf[0] = r.x + r.width;
5928 pf[4] = r.x + r.width;
5929 pf[5] = r.y + r.height;
5931 pf[7] = r.y + r.height;
5932 shader->SetAttributePointerf(
"position", pf);
5934 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5942void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5943#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5945 ViewPort VPoint = m_pParentCanvas->VPoint;
5949 GetClientSize(&w, &h);
5950 int sx = GetSize().x;
5951 int sy = GetSize().y;
5955 glViewport(0, 0, (GLint)w, (GLint)h);
5957 if (s_b_useStencil) {
5958 glEnable(GL_STENCIL_TEST);
5959 glStencilMask(0xff);
5960 glClear(GL_STENCIL_BUFFER_BIT);
5961 glDisable(GL_STENCIL_TEST);
5965 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5970 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5971 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5972 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5975 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5977 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5978 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5986 if (bRenderCharts) RenderCharts(gldc, screen_region);
5988 if (bRenderOverlays) {
5989 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5990 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5996 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5999 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
6000 DrawDynamicRoutesTracksAndWaypoints(VPoint);
6001 DrawFloatingOverlayObjects(m_gldc);
6005 glBindFramebuffer(GL_FRAMEBUFFER, 0);
6010wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
6012 wxMemoryDC tdc(tbm);
6013 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6021 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6022 dc.SetPen(*wxTRANSPARENT_PEN);
6025 tdc.SelectObject(wxNullBitmap);
6026 m_touch_backing_bitmap = tbm;
6027 CreateBackingTexture();
6029 return m_touch_backing_bitmap;
6032void glChartCanvas::CreateBackingTexture() {
6033 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6034 unsigned char *imgdata = image.GetData();
6035 unsigned char *imgalpha = image.GetAlpha();
6036 m_tex_w = image.GetWidth();
6037 m_tex_h = image.GetHeight();
6038 m_image_width = m_tex_w;
6039 m_image_height = m_tex_h;
6041 GLuint format = GL_RGBA;
6042 GLuint internalformat = g_texture_rectangle_format;
6044 internalformat = GL_RGBA;
6049 unsigned char *teximage =
6050 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6052 for (
int i = 0; i < m_image_height; i++) {
6053 for (
int j = 0; j < m_image_width; j++) {
6054 int s = (i * 3 * m_image_width) + (j * 3);
6055 int d = (i * stride * m_tex_w) + (j * stride);
6057 teximage[d + 0] = imgdata[s + 0];
6058 teximage[d + 1] = imgdata[s + 1];
6059 teximage[d + 2] = imgdata[s + 2];
6060 teximage[d + 3] = 255;
6064 glGenTextures(1, &m_TouchBackingTexture);
6065 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6067 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6068 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6069 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6071 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6073 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6074 GL_UNSIGNED_BYTE, teximage);
6077 glBindTexture(GL_TEXTURE_2D, 0);
Wrapper for creating a ChartCtx based on global vars.
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
Represents an active track that is currently being recorded.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
float GetVPChartScale()
Return the ViewPort chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
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.