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;
181static wxColor s_regionColor;
182static float g_GLMinCartographicLineWidth;
188#define APIENTRYP APIENTRY *
194#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
195#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
201PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
202PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
203PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
204PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
205PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
206PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
207PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
208PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
209PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
210PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
212PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
213PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
216PFNGLGENBUFFERSPROC s_glGenBuffers;
217PFNGLBINDBUFFERPROC s_glBindBuffer;
218PFNGLBUFFERDATAPROC s_glBufferData;
219PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
221#ifndef USE_ANDROID_GLES2
226typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
228PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
231static int panx, pany;
235#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
236static int s_tess_vertex_idx;
237static int s_tess_vertex_idx_this;
238static int s_tess_buf_len;
239static GLfloat *s_tess_work_buf;
240static GLenum s_tess_mode;
245bool glChartCanvas::s_b_useScissorTest;
246bool glChartCanvas::s_b_useStencil;
247bool glChartCanvas::s_b_useStencilAP;
248bool glChartCanvas::s_b_useFBO;
255 while ( upd.HaveRects() )
257 wxRect rect = upd.GetRect();
258 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
265GLboolean QueryExtension(
const char *extName) {
276 extNameLen = strlen(extName);
278 p = (
char *)glGetString(GL_EXTENSIONS);
286 int n = strcspn(p,
" ");
287 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
295int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
296 16, WX_GL_STENCIL_SIZE, 8,
299glTestCanvas::glTestCanvas(wxWindow *parent)
300 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
304int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
305 16, WX_GL_STENCIL_SIZE, 8,
308EVT_PAINT(glChartCanvas::OnPaint)
309EVT_ACTIVATE(glChartCanvas::OnActivate)
310EVT_SIZE(glChartCanvas::OnSize)
311EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
315 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
316 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
319 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
324std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
326 {wxPENSTYLE_DOT, {1, 1}},
327 {wxPENSTYLE_LONG_DASH, {5, 5}},
328 {wxPENSTYLE_SHORT_DASH, {1, 5}},
329 {wxPENSTYLE_DOT_DASH, {5, 1}},
332void glChartCanvas::Init() {
337 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
339 m_cache_current_ch = NULL;
341 m_b_paint_enable =
true;
342 m_in_glpaint =
false;
344 m_cache_tex[0] = m_cache_tex[1] = 0;
347 m_b_BuiltFBO =
false;
348 m_b_DisableFBO =
false;
357 m_bpinchGuard =
false;
358 m_binGesture =
false;
359 m_first_zout =
false;
363 m_last_render_time = -1;
370 m_gldc.SetGLCanvas(
this);
373 m_displayScale = 1.0;
374#if defined(__WXOSX__) || defined(__WXGTK3__)
376 m_displayScale = GetContentScaleFactor();
385 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
389 wxEVT_QT_PINCHGESTURE,
390 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
393 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
398 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
400 onGestureFinishTimerEvent,
404 ZOOM_TIMER, wxEVT_TIMER,
405 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
408 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
409 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
410 zoomTimer.SetOwner(
this, ZOOM_TIMER);
412#ifdef USE_ANDROID_GLES2
421#ifdef HAVE_WX_GESTURE_EVENTS
423 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
428 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
430 onGestureFinishTimerEvent,
434 ZOOM_TIMER, wxEVT_TIMER,
435 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
438 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
439 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
440 zoomTimer.SetOwner(
this, ZOOM_TIMER);
445 m_bgestureGuard =
false;
446 m_total_zoom_val = 1.0;
447 m_step_zoom_val = 1.0;
450#ifdef HAVE_WX_GESTURE_EVENTS
451 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
452 wxLogError(
"Failed to enable touch events");
461 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
463 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
464 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
466 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
467 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
469 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
470 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
472 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
473 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
479glChartCanvas::~glChartCanvas() {
485int glChartCanvas::GetCanvasIndex() {
return m_pParentCanvas->m_canvasIndex; }
487void glChartCanvas::FlushFBO() {
488 if (m_bsetup) BuildFBO();
491void glChartCanvas::OnActivate(wxActivateEvent &event) {
492 m_pParentCanvas->OnActivate(event);
495void glChartCanvas::OnSize(wxSizeEvent &event) {
499 wxLogMessage(
"Got OnSize event while NOT running");
501 qDebug() <<
"OnSizeB";
509 if (!m_bsetup)
return;
511 if (!IsShown())
return;
513 SetCurrent(*m_pcontext);
517 SetSize(GetSize().x, GetSize().y);
525 if (m_pcontext && IsShown()) {
526 SetCurrent(*m_pcontext);
531 wxLogDebug(
"BuildFBO 3");
535 ViewPort *vp = m_pParentCanvas->GetpVP();
538 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
541 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
545void glChartCanvas::MouseEvent(wxMouseEvent &event) {
546 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
552 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
554 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
557 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
561 if (m_bgestureGuard) {
562 m_pParentCanvas->r_rband.x = 0;
572 if (event.LeftUp()) {
574 if ((abs(panx) > 2) || (abs(pany) > 2)) {
577 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
584 if (!event.LeftDClick()) {
589 if (m_binPan && event.RightDown()) {
590 qDebug() <<
"Skip right on pan";
593 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
595 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
596 if (!m_bgestureGuard)
606#ifndef GL_MAX_RENDERBUFFER_SIZE
607#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
610#ifndef USE_ANDROID_GLES2
611bool glChartCanvas::buildFBOSize(
int fboSize) {
613 if (IsShown()) SetCurrent(*m_pcontext);
616 glDeleteTextures(2, m_cache_tex);
617 glDeleteFramebuffers(1, &m_fb0);
618 glDeleteRenderbuffers(1, &m_renderbuffer);
619 m_b_BuiltFBO =
false;
622 if (m_b_DisableFBO)
return false;
626 int rb_x = GetSize().x;
627 int rb_y = GetSize().y;
629 while (i < rb_x) i <<= 1;
633 while (i < rb_y) i <<= 1;
636 m_cache_tex_x = wxMax(rb_x, rb_y);
637 m_cache_tex_y = wxMax(rb_x, rb_y);
640 m_cache_tex_x = GetSize().x * m_displayScale;
641 m_cache_tex_y = GetSize().y * m_displayScale;
644 int err = GL_NO_ERROR;
646 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
649 if (err == GL_INVALID_ENUM) {
650 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
654 if (err == GL_NO_ERROR) {
655 if (fboSize > params) {
657 " OpenGL-> Requested Framebuffer size exceeds "
658 "GL_MAX_RENDERBUFFER_SIZE");
663 glGenFramebuffers(1, &m_fb0);
667 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
672 glGenRenderbuffers(1, &m_renderbuffer);
676 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
681 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
685 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
691 glGenTextures(2, m_cache_tex);
692 for (
int i = 0; i < 2; i++) {
693 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
694 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
696 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
698 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
699 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
702 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
704 if (m_b_useFBOStencil) {
706 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
707 m_cache_tex_x, m_cache_tex_y);
709 int err = glGetError();
712 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
716 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
717 GL_RENDERBUFFER_EXT, m_renderbuffer);
721 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
726 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
727 GL_RENDERBUFFER_EXT, m_renderbuffer);
731 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
737 GLenum depth_format = GL_DEPTH_COMPONENT24;
742 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
746 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
748 int err = glGetError();
751 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
757 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
758 GL_RENDERBUFFER_EXT, m_renderbuffer);
763 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
770 glBindTexture(GL_TEXTURE_2D, 0);
771 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
774 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
776 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
777 g_texture_rectangle_format, m_cache_tex[0], 0);
779 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
781 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
783 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
785 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
795#ifdef USE_ANDROID_GLES2
796bool glChartCanvas::buildFBOSize(
int fboSize) {
800 int rb_x = GetSize().x;
801 int rb_y = GetSize().y;
803 while (i < rb_x) i <<= 1;
807 while (i < rb_y) i <<= 1;
810 m_cache_tex_x = wxMax(rb_x, rb_y);
811 m_cache_tex_y = wxMax(rb_x, rb_y);
815 int err = GL_NO_ERROR;
817 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
820 if (err == GL_INVALID_ENUM) {
821 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
825 if (err == GL_NO_ERROR) {
826 if (fboSize > params) {
828 " OpenGL-> Requested Framebuffer size exceeds "
829 "GL_MAX_RENDERBUFFER_SIZE");
834 glGenFramebuffers(1, &m_fb0);
838 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
843 glGenRenderbuffers(1, &m_renderbuffer);
847 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
852 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
856 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
862 glGenTextures(2, m_cache_tex);
863 for (
int i = 0; i < 2; i++) {
864 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
865 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
867 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
869 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
870 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
873 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
876 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
882 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
886 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
887 GL_RENDERBUFFER, m_renderbuffer);
891 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
896 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
897 GL_RENDERBUFFER, m_renderbuffer);
901 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
906 glBindTexture(GL_TEXTURE_2D, 0);
907 glBindFramebuffer(GL_FRAMEBUFFER, 0);
910 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
912 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
913 g_texture_rectangle_format, m_cache_tex[0], 0);
915 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
917 glBindFramebuffer(GL_FRAMEBUFFER, 0);
919 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
921 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
931void glChartCanvas::BuildFBO() {
932 if (g_b_needFinish) glFinish();
936 glDeleteTextures(2, m_cache_tex);
937 glDeleteFramebuffers(1, &m_fb0);
938 glDeleteRenderbuffers(1, &m_renderbuffer);
939 m_b_BuiltFBO =
false;
942 if (m_b_DisableFBO)
return;
945 int gl_width, gl_height;
946 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
947 int initialSize = NextPow2(gl_width * m_displayScale);
952 wxString info = androidGetDeviceInfo();
954 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
957 if (!buildFBOSize(initialSize)) {
958 glDeleteTextures(2, m_cache_tex);
959 glDeleteFramebuffers(1, &m_fb0);
960 glDeleteRenderbuffers(1, &m_renderbuffer);
962 if (!buildFBOSize(1024)) {
963 wxLogMessage(
"BuildFBO C");
965 m_b_DisableFBO =
true;
966 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
967 m_b_BuiltFBO =
false;
976 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
988void glChartCanvas::SetupOpenGL() {
989 if (IsShown()) SetCurrent(*m_pcontext);
991 char *str = (
char *)glGetString(GL_RENDERER);
994 wxLogMessage(
"Failed to initialize OpenGL");
998 char render_string[80];
999 strncpy(render_string, str, 79);
1000 m_renderer = wxString(render_string, wxConvUTF8);
1003 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1004 msg.Printf(
"OpenGL-> Renderer String: ");
1008 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1010 char version_string[80];
1011 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1012 msg.Printf(
"OpenGL-> Version reported: ");
1013 m_version = wxString(version_string, wxConvUTF8);
1017 char GLSL_version_string[80];
1018 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1020 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1021 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1022 msg += m_GLSLversion;
1027 GLenum err = glewInit();
1028#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1029 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1034 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1037 wxLogMessage(
"GLEW init success!n");
1042 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1043 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1047#ifndef USE_ANDROID_GLES2
1048 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1050 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1052 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1053 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1060 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1062 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1064 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1067 s_b_useScissorTest =
true;
1069 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1070 s_b_useScissorTest =
false;
1072 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1073 s_b_useScissorTest =
false;
1075 bool bad_stencil_code =
false;
1078 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1079 bad_stencil_code =
true;
1082 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1085 glEnable(GL_STENCIL_TEST);
1086 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1088 glGetIntegerv(GL_STENCIL_BITS, &sb);
1091 glDisable(GL_STENCIL_TEST);
1093 s_b_useStencil =
false;
1094 if (stencil && (sb == 8)) s_b_useStencil =
true;
1096 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1097 g_texture_rectangle_format = GL_TEXTURE_2D;
1098 else if (QueryExtension(
"GL_OES_texture_npot"))
1099 g_texture_rectangle_format = GL_TEXTURE_2D;
1100 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1101 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1102 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1103 g_texture_rectangle_format));
1106 g_texture_rectangle_format = GL_TEXTURE_2D;
1110 g_b_EnableVBO =
true;
1113 g_b_EnableVBO =
false;
1117 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1119 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1123 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1125 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1128#ifndef USE_ANDROID_GLES2
1130 if (bad_stencil_code) s_b_useStencil =
false;
1144 if (m_displayScale > 1) m_b_DisableFBO =
true;
1153 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1155 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1156 g_texture_rectangle_format, m_cache_tex[0], 0);
1158 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1159 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1161 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1163 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1165 m_b_DisableFBO =
true;
1171 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1175 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1177#ifdef USE_ANDROID_GLES2
1178 s_b_useStencilAP = s_b_useStencil;
1185 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1187 if (m_b_useFBOStencil)
1188 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1190 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1192 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1195 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1197 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1199 if (s_b_useScissorTest && s_b_useStencil)
1200 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1203 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1205 MipMap_ResolveRoutines();
1209 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1210 g_GLMinCartographicLineWidth);
1211 wxLogMessage(lwmsg);
1212 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1213 g_GLMinSymbolLineWidth);
1214 wxLogMessage(lwmsg);
1217 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1219#ifdef USE_ANDROID_GLES2
1220 g_GLOptions.m_bUseAcceleratedPanning =
true;
1226 int tex_dim = g_GLOptions.m_iTextureDimension;
1227 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1236 s_b_useFBO = m_b_BuiltFBO;
1240 ps52plib->SetGLOptions(
1241 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1242 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1243 g_GLMinSymbolLineWidth);
1247 SendJSONConfigMessage();
1250void glChartCanvas::SendJSONConfigMessage() {
1253 v[
"setupComplete"] = m_bsetup;
1254 v[
"useStencil"] = s_b_useStencil;
1255 v[
"useStencilAP"] = s_b_useStencilAP;
1256 v[
"useScissorTest"] = s_b_useScissorTest;
1257 v[
"useFBO"] = s_b_useFBO;
1258 v[
"useVBO"] = g_b_EnableVBO;
1259 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1260 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1261 SendJSONMessageToAllPlugins(msg_id, v);
1264void glChartCanvas::SetupCompression() {
1265 int dim = g_GLOptions.m_iTextureDimension;
1268 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1269 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1270 goto no_compression;
1274 g_uncompressed_tile_size = dim * dim * 4;
1275 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1281 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1284 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1294 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1295 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1298 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1299 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1304 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1305 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1308 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1310 wxLogMessage(
"OpenGL-> No Useable compression format found");
1311 goto no_compression;
1316 g_tile_size = 512 * 512 / 2;
1320 glGenTextures(1, &texture);
1321 glBindTexture(GL_TEXTURE_2D, texture);
1323 GL_UNSIGNED_BYTE, NULL);
1324 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1326 glDeleteTextures(1, &texture);
1330 if (g_tile_size == 0)
goto no_compression;
1332 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1334 g_uncompressed_tile_size / g_tile_size));
1338 g_GLOptions.m_bTextureCompression =
false;
1340 g_tile_size = g_uncompressed_tile_size;
1341 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1344void glChartCanvas::OnPaint(wxPaintEvent &event) {
1346 if (!m_pcontext)
return;
1355 if (IsShown()) SetCurrent(*m_pcontext);
1360 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1368 if (!m_b_paint_enable)
return;
1371 if (m_in_glpaint)
return;
1374 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1397bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1399#ifndef USE_ANDROID_GLES2
1400 return vp.m_projection_type == PROJECTION_MERCATOR ||
1401 vp.m_projection_type == PROJECTION_POLAR ||
1402 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1416#define NORM_FACTOR 4096.0
1417void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1418#ifndef USE_ANDROID_GLES2
1420 wxPoint2DDouble point;
1422 switch (vp.m_projection_type) {
1423 case PROJECTION_MERCATOR:
1424 case PROJECTION_EQUIRECTANGULAR:
1425 case PROJECTION_WEB_MERCATOR:
1428 glTranslated(point.m_x, point.m_y, 0);
1433 case PROJECTION_POLAR:
1437 glTranslated(point.m_x, point.m_y, 0);
1438 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1445 printf(
"ERROR: Unhandled projection\n");
1450 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1458 switch (vp.m_projection_type) {
1459 case PROJECTION_MERCATOR:
1460 case PROJECTION_EQUIRECTANGULAR:
1461 case PROJECTION_WEB_MERCATOR:
1465 case PROJECTION_POLAR:
1470 printf(
"ERROR: Unhandled projection\n");
1479bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1480 return vp.m_projection_type == PROJECTION_MERCATOR ||
1481 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1482 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1486 const LLRegion ®ion) {
1487 if (!CanClipViewport(vp))
return vp;
1490 LLBBox bbox = region.GetBox();
1492 if (!bbox.GetValid())
return vp;
1500 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1501 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1502 bbox.GetMaxLon() + 360);
1503 cvp.SetBBoxDirect(bbox);
1504 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1505 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1506 bbox.GetMaxLon() - 360);
1507 cvp.SetBBoxDirect(bbox);
1509 cvp.SetBBoxDirect(bbox);
1514void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1515 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1521 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1523 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1527 if (!pRouteDraw)
continue;
1530 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1533 if (pRouteDraw->m_bIsBeingEdited)
continue;
1535 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1540 if (vp.GetBBox().GetValid() && pWayPointMan) {
1541 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1542 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1543 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1549void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1554 if (pActiveTrack && pActiveTrack->IsRunning())
1555 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1561 if (!pRouteDraw)
continue;
1564 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1567 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1570 if (pRouteDraw->IsSelected()) drawit++;
1573 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1574 if (!vp_box.IntersectOut(test_box))
1575 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1581 if (vp.GetBBox().GetValid() && pWayPointMan) {
1582 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1583 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1590static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1594 switch (vp.m_projection_type) {
1595 case PROJECTION_TRANSVERSE_MERCATOR:
1596 lat_dist = 4, lon_dist = 1;
1598 case PROJECTION_POLYCONIC:
1599 lat_dist = 2, lon_dist = 1;
1601 case PROJECTION_ORTHOGRAPHIC:
1602 lat_dist = 2, lon_dist = 2;
1604 case PROJECTION_POLAR:
1605 lat_dist = 180, lon_dist = 1;
1607 case PROJECTION_STEREOGRAPHIC:
1608 case PROJECTION_GNOMONIC:
1609 lat_dist = 2, lon_dist = 1;
1611 case PROJECTION_EQUIRECTANGULAR:
1614 lat_dist = 2, lon_dist = 360;
1617 lat_dist = 180, lon_dist = 360;
1621void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1622 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1628 ChartData->GetDBBoundingBox(dbIndex, box);
1629 if (!box.GetValid())
return;
1633 if (box.GetLonRange() == 360)
return;
1635 LLBBox vpbox = vp.GetBBox();
1637 double lon_bias = 0;
1639 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1642 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1643 color = GetGlobalColor(
"YELO1");
1644 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1645 color = GetGlobalColor(
"GREEN2");
1647 color = GetGlobalColor(
"UINFR");
1649#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1650 float plylat, plylon;
1652 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1654 glColor3ub(color.Red(), color.Green(), color.Blue());
1655 glLineWidth(g_GLMinSymbolLineWidth);
1657 float lat_dist, lon_dist;
1658 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1661 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1665 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1667 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1669 bool begin =
false, sml_valid =
false;
1671 float lastplylat = 0.0;
1672 float lastplylon = 0.0;
1674 int modulo = (nPly == 0) ? 1 : nPly;
1675 for (
int i = 0; i < nPly + 1; i++) {
1677 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1679 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1683 if (lastplylon - plylon > 180)
1685 else if (lastplylon - plylon < -180)
1692 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1693 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1694 splits = wxMax(lat_splits, lon_splits) + 1;
1701 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1702 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1705 for (
double c = 0; c < splits; c++) {
1707 if (c == splits - 1)
1708 lat = plylat, lon = plylon;
1710 double d = (double)(c + 1) / splits;
1711 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1717 if (!std::isnan(s.m_x)) {
1720 glBegin(GL_LINE_STRIP);
1722 glVertex2f(s.m_x, s.m_y);
1728 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1729 lastplylat = plylat, lastplylon = plylon;
1734 }
while (++j < nAuxPlyEntries);
1736 glDisable(GL_LINE_SMOOTH);
1740 double nominal_line_width_pix =
1741 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1743 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1744 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1747 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1748 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1752 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1755 float plylat1, plylon1;
1759 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1760 if (0 == nAuxPlyEntries)
1763 std::vector<int> points_vector;
1765 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1766 int nPly = vec.size() / 2;
1768 if (nPly == 0)
return;
1770 for (
int i = 0; i < nPly; i++) {
1771 plylon1 = vec[i * 2];
1772 plylat1 = vec[i * 2 + 1];
1778 points_vector.push_back(pixx1);
1779 points_vector.push_back(pixy1);
1782 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1783 plylon1 += lon_bias;
1789 points_vector.push_back(pixx1);
1790 points_vector.push_back(pixy1);
1792 if (points_vector.size()) {
1793 std::vector<int>::iterator it = points_vector.begin();
1794 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1802 for (
int j = 0; j < nAuxPlyEntries; j++) {
1803 std::vector<int> points_vector;
1805 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1806 int nAuxPly = vec.size() / 2;
1808 if (nAuxPly == 0)
continue;
1810 for (
int i = 0; i < nAuxPly; i++) {
1811 plylon1 = vec[i * 2];
1812 plylat1 = vec[i * 2 + 1];
1818 points_vector.push_back(pixx1);
1819 points_vector.push_back(pixy1);
1826 points_vector.push_back(pixx1);
1827 points_vector.push_back(pixy1);
1829 if (points_vector.size()) {
1830 std::vector<int>::iterator it = points_vector.begin();
1831 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1839extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1840 float &MinorSpacing);
1841extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1842void glChartCanvas::GridDraw() {
1843 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1845 ViewPort &vp = m_pParentCanvas->GetVP();
1847 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1851 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1853 double nlat, elon, slat, wlon;
1855 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1858 wxColour GridColor = GetGlobalColor(
"SNDG1");
1860 if (!m_gridfont.IsBuilt()) {
1862 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1863 wxFont font = *dFont;
1866 int font_size = wxMax(10, dFont->GetPointSize());
1867 font.SetPointSize(font_size);
1868 font.SetWeight(wxFONTWEIGHT_NORMAL);
1871 m_gridfont.Build(font, m_displayScale, dpi_factor);
1873 m_gridfont.SetColor(GridColor);
1878 LLBBox llbbox = vp.GetBBox();
1879 nlat = llbbox.GetMaxLat();
1880 slat = llbbox.GetMinLat();
1881 elon = llbbox.GetMaxLon();
1882 wlon = llbbox.GetMinLon();
1889 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1890 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1891 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1892 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1893 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1894 vp.m_projection_type == PROJECTION_POLAR ||
1895 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1898 if (straight_latitudes)
1901 latmargin = gridlatMajor / 2;
1903 slat = wxMax(slat, -90 + latmargin);
1904 nlat = wxMin(nlat, 90 - latmargin);
1906 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1907 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1911 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1918 float lon_step = elon - wlon;
1919 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1921 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1923 s.x = INVALID_COORD;
1924 s.y = INVALID_COORD;
1925 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1927 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1928 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1936 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1937 lat += gridlatMinor) {
1940 gldc.DrawLine(0, r.y, 10, r.y,
true);
1941 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1946 float lat_step = nlat - slat;
1947 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1949 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1951 s.x = INVALID_COORD;
1952 s.y = INVALID_COORD;
1953 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1955 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1956 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1964 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1965 lon += gridlonMinor) {
1968 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1969 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1975 glEnable(GL_TEXTURE_2D);
1977 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1978 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1981 CalcGridText(lat, gridlatMajor,
true);
1983 m_gridfont.GetTextExtent(st, 0, &iy);
1985 if (straight_latitudes) {
1990 float x = 0, y = -1;
1991 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1992 if (y < 0 || y > h) {
1994 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1997 m_gridfont.RenderString(st, x, y);
2001 double y1, y2, lat1, lon1, lat2, lon2;
2010 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2013 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2015 if (fabs(y - y1) < fabs(y - y2))
2021 error = fabs(r.m_x);
2022 if (--maxiters == 0)
break;
2023 }
while (error > 1 && error < lasterror);
2025 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2031 m_gridfont.RenderString(st, r.m_x, r.m_y);
2035 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2036 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2045 else if (xlon <= -180.0)
2048 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2050 m_gridfont.GetTextExtent(st, &ix, 0);
2052 if (straight_longitudes) {
2053 float x = -1, y = 0;
2054 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2055 if (x < 0 || x > w) {
2057 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2060 m_gridfont.RenderString(st, x, y);
2064 double x1, x2, lat1, lon1, lat2, lon2;
2072 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2075 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2077 if (fabs(x - x1) < fabs(x - x2))
2083 error = fabs(r.m_y);
2084 }
while (error > 1 && error < lasterror);
2086 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2091 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2093 m_gridfont.RenderString(st, r.m_x, r.m_y);
2097 glDisable(GL_TEXTURE_2D);
2098 glDisable(GL_BLEND);
2103 if (!emboss)
return;
2105 int w = emboss->width, h = emboss->height;
2107 glEnable(GL_TEXTURE_2D);
2110 if (!emboss->gltexind) {
2112 emboss->glwidth = NextPow2(emboss->width);
2113 emboss->glheight = NextPow2(emboss->height);
2116 int size = emboss->glwidth * emboss->glheight;
2117 char *data =
new char[2 * size];
2118 for (
int i = 0; i < h; i++) {
2119 for (
int j = 0; j < emboss->glwidth; j++) {
2121 data[2 * ((i * emboss->glwidth) + j)] =
2122 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2123 data[2 * ((i * emboss->glwidth) + j) + 1] =
2124 (char)abs((emboss->pmap[(i * w) + j]));
2129 glGenTextures(1, &emboss->gltexind);
2130 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2131 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2132 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2140 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2144 int x = emboss->x, y = emboss->y;
2146 float wp = (float)w / emboss->glwidth;
2147 float hp = (float)h / emboss->glheight;
2173 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2175 glDisable(GL_BLEND);
2176 glDisable(GL_TEXTURE_2D);
2179void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2180 if (!m_pParentCanvas->GetVP().IsValid())
return;
2181 wxPoint GPSOffsetPixels(0, 0);
2182 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2185 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2186 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2190 double shift_dx = 0;
2191 double shift_dy = 0;
2192 bool dynamic = m_pParentCanvas->m_animationActive ||
2193 m_pParentCanvas->m_MouseDragging ||
2194 m_pParentCanvas->m_chart_drag_inertia_active;
2195 if (m_pParentCanvas->m_bFollow && !dynamic) {
2196 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2197 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2198 if (m_pParentCanvas->m_bLookAhead) {
2204 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2205 angle += m_pParentCanvas->GetVPRotation();
2206 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2208 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2209 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2211 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2216 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2217 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2224 lShipMidPoint = lGPSPoint;
2228 float icon_hdt = pCog;
2229 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2232 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2236 double osd_head_lat, osd_head_lon;
2237 wxPoint2DDouble osd_head_point;
2239 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2243 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2245 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2246 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2247 icon_rad += (float)PI;
2251 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2255 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2261 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2262 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2263 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2268 float scale_factor = 1.0;
2273 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2274 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2275 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2277 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2279 float nominal_ownship_size_pixels =
2281 nominal_ownship_size_mm);
2283 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2285 wxPen ppSmallScaleShip;
2286 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2288 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2291 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2292 dc.SetPen(ppSmallScaleShip);
2294 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2297 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2298 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2299 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2300 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2303 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2304 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2307 int draw_color = SHIP_INVALID;
2308 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2309 draw_color = SHIP_NORMAL;
2310 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2311 draw_color = SHIP_LOWACCURACY;
2319 ownship_color = draw_color;
2321 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2323 glGenTextures(1, &ownship_tex);
2324 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2327 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2330 if (m_pParentCanvas->m_pos_image_user) {
2331 switch (draw_color) {
2333 image = *m_pParentCanvas->m_pos_image_user_grey;
2336 image = *m_pParentCanvas->m_pos_image_user;
2338 case SHIP_LOWACCURACY:
2339 image = *m_pParentCanvas->m_pos_image_user_yellow;
2343 switch (draw_color) {
2345 image = *m_pParentCanvas->m_pos_image_grey;
2348 image = *m_pParentCanvas->m_pos_image_red;
2350 case SHIP_LOWACCURACY:
2351 image = *m_pParentCanvas->m_pos_image_yellow;
2356 int w = image.GetWidth(), h = image.GetHeight();
2357 int glw = NextPow2(w), glh = NextPow2(h);
2358 ownship_size = wxSize(w, h);
2359 ownship_tex_size = wxSize(glw, glh);
2361 unsigned char *d = image.GetData();
2362 unsigned char *a = image.GetAlpha();
2363 unsigned char *e =
new unsigned char[4 * w * h];
2366 for (
int p = 0; p < w * h; p++) {
2367 e[4 * p + 0] = d[3 * p + 0];
2368 e[4 * p + 1] = d[3 * p + 1];
2369 e[4 * p + 2] = d[3 * p + 2];
2370 e[4 * p + 3] = a[p];
2373 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2374 GL_UNSIGNED_BYTE, 0);
2376 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2382#ifndef USE_ANDROID_GLES2
2383 if (m_pParentCanvas->m_pos_image_user)
2384 glColor4ub(255, 255, 255, 255);
2385 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2386 glColor4ub(255, 0, 0, 255);
2387 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2388 glColor4ub(255, 255, 0, 255);
2390 glColor4ub(128, 128, 128, 255);
2392 float scale_factor_y = 1.0;
2393 float scale_factor_x = 1.0;
2395 int ownShipWidth = 22;
2396 int ownShipLength = 84;
2397 lShipMidPoint = lGPSPoint;
2400 if (g_OwnShipIconType != 0)
2401 m_pParentCanvas->ComputeShipScaleFactor(
2402 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2403 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2408 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2409 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2410 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2414 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2415 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2419 float gps_circle_radius = 3.0;
2421 if (g_OwnShipIconType == 0) {
2423 glEnable(GL_TEXTURE_2D);
2424 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2433 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2434 if (m_pParentCanvas->m_pos_image_user)
2435 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2437 float nominal_ownship_size_mm =
2438 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2440 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2441 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2443 float nominal_ownship_size_pixels =
2444 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2446 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2447 nominal_ownship_size_pixels = wxMax(
2448 20.0, nominal_ownship_size_pixels);
2451 float h = nominal_ownship_size_pixels * scale_factor_y;
2452 float w = nominal_ownship_size_pixels * scale_factor_x *
2453 ownship_size.x / ownship_size.y;
2454 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2455 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2461 gps_circle_radius = w / 5;
2463 float uv[8], coords[8];
2482 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2483 lShipMidPoint.m_x, lShipMidPoint.m_y,
2485 glDisable(GL_TEXTURE_2D);
2486 }
else if (g_OwnShipIconType == 1) {
2488 glEnable(GL_TEXTURE_2D);
2489 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2491 float nominal_ownship_size_pixels_y = 84;
2492 float nominal_ownship_size_pixels_x = 22;
2494 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2495 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2497 float u = (float)ownship_size.x / ownship_tex_size.x,
2498 v = (
float)ownship_size.y / ownship_tex_size.y;
2501 gps_circle_radius = w / 5;
2503 float uv[8], coords[8];
2522 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2523 lShipMidPoint.m_x, lShipMidPoint.m_y,
2526 glDisable(GL_TEXTURE_2D);
2527 }
else if (g_OwnShipIconType == 2) {
2535 wxPoint shipPoints[6];
2537 wxColour colour = m_pParentCanvas->ShipColor();
2538 wxPen ppPen(*wxBLACK, 1);
2539 wxBrush ppBrush(colour);
2541 dc.SetBrush(ppBrush);
2543 shipPoints[0].x = 0 * scale_factor_x;
2544 shipPoints[0].y = -28 * scale_factor_y;
2545 shipPoints[1].x = 11 * scale_factor_x;
2546 shipPoints[1].y = -28 * scale_factor_y;
2547 shipPoints[2].x = 11 * scale_factor_x;
2548 shipPoints[2].y = 42 * scale_factor_y;
2549 shipPoints[3].x = 0 * scale_factor_x;
2550 shipPoints[3].y = 42 * scale_factor_y;
2551 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2554 shipPoints[0].x = 0 * scale_factor_x;
2555 shipPoints[0].y = -42 * scale_factor_y;
2556 shipPoints[1].x = 5 * scale_factor_x;
2557 shipPoints[1].y = -42 * scale_factor_y;
2558 shipPoints[2].x = 11 * scale_factor_x;
2559 shipPoints[2].y = -28 * scale_factor_y;
2560 shipPoints[3].x = 0 * scale_factor_x;
2561 shipPoints[3].y = -28 * scale_factor_y;
2562 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2565 shipPoints[0].x = 0 * scale_factor_x;
2566 shipPoints[0].y = -28 * scale_factor_y;
2567 shipPoints[1].x = -11 * scale_factor_x;
2568 shipPoints[1].y = -28 * scale_factor_y;
2569 shipPoints[2].x = -11 * scale_factor_x;
2570 shipPoints[2].y = 42 * scale_factor_y;
2571 shipPoints[3].x = 0 * scale_factor_x;
2572 shipPoints[3].y = 42 * scale_factor_y;
2573 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2576 shipPoints[0].x = 0 * scale_factor_x;
2577 shipPoints[0].y = -42 * scale_factor_y;
2578 shipPoints[1].x = -5 * scale_factor_x;
2579 shipPoints[1].y = -42 * scale_factor_y;
2580 shipPoints[2].x = -11 * scale_factor_x;
2581 shipPoints[2].y = -28 * scale_factor_y;
2582 shipPoints[3].x = 0 * scale_factor_x;
2583 shipPoints[3].y = -28 * scale_factor_y;
2584 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2588 double p1x = -11 * scale_factor_x;
2589 double p2x = 11 * scale_factor_x;
2593 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2595 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2597 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2599 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2600 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2601 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2605 p1y = -42 * scale_factor_y;
2606 p2y = 42 * scale_factor_y;
2607 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2608 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2609 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2610 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2611 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2612 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2615 img_height = ownShipLength * scale_factor_y;
2618 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2620 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2622 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2624 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2628 glDisable(GL_LINE_SMOOTH);
2629 glDisable(GL_POLYGON_SMOOTH);
2630 glDisable(GL_BLEND);
2633 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2637void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2638 ViewPort &vp = m_pParentCanvas->GetVP();
2661 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2663 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2664 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2666 m_pParentCanvas->AlertDraw(dc);
2668 m_pParentCanvas->RenderVisibleSectorLights(dc);
2670 m_pParentCanvas->RenderRouteLegs(dc);
2671 m_pParentCanvas->RenderShipToActive(dc,
true);
2672 m_pParentCanvas->ScaleBarDraw(dc);
2673 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2674 m_pParentCanvas->extendedSectorLegs);
2681void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2682 if (m_pParentCanvas->GetPiano()) {
2683 int canvas_height = GetClientSize().y;
2684 canvas_height *= m_displayScale;
2686 m_pParentCanvas->GetPiano()->DrawGL(
2687 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2691void glChartCanvas::DrawQuiting() {
2692#ifndef USE_ANDROID_GLES2
2693 GLubyte pattern[8][8];
2694 for (
int y = 0; y < 8; y++)
2695 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2698 glEnable(GL_TEXTURE_2D);
2699 glBindTexture(GL_TEXTURE_2D, 0);
2701 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2702 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2703 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2705 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2709 float x = GetSize().x, y = GetSize().y;
2710 float u = x / 8, v = y / 8;
2723 glDisable(GL_TEXTURE_2D);
2724 glDisable(GL_BLEND);
2728void glChartCanvas::DrawCloseMessage(wxString msg) {
2729#ifndef USE_ANDROID_GLES2
2733 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2737 texfont.Build(*pfont, 1, 1);
2739 texfont.GetTextExtent(msg, &w, &h);
2741 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2742 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2744 glColor3ub(243, 229, 47);
2748 glVertex2i(xp + w, yp);
2749 glVertex2i(xp + w, yp + h);
2750 glVertex2i(xp, yp + h);
2755 glColor3ub(0, 0, 0);
2756 glEnable(GL_TEXTURE_2D);
2757 texfont.RenderString(msg, xp, yp);
2758 glDisable(GL_TEXTURE_2D);
2759 glDisable(GL_BLEND);
2766static std::list<double *> combine_work_data;
2767static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2768 GLfloat weight[4], GLdouble **dataOut) {
2769 double *vertex =
new double[3];
2770 combine_work_data.push_back(vertex);
2771 memcpy(vertex, coords, 3 * (
sizeof *coords));
2775#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2776void vertexCallbackD_GLSL(GLvoid *vertex) {
2778 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2779 int new_buf_len = s_tess_buf_len + 100;
2780 GLfloat *tmp = s_tess_work_buf;
2783 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2784 if (NULL == s_tess_work_buf) {
2788 s_tess_buf_len = new_buf_len;
2791 GLdouble *pointer = (GLdouble *)vertex;
2793 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2794 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2799void beginCallbackD_GLSL(GLenum mode) {
2800 s_tess_vertex_idx_this = s_tess_vertex_idx;
2805void endCallbackD_GLSL() {
2809 shader->SetUniformMatrix4fv(
"MVMatrix",
2810 (GLfloat *)s_tessVP.vp_matrix_transform);
2812 mat4x4 identityMatrix;
2813 mat4x4_identity(identityMatrix);
2814 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2818 colorv[0] = s_regionColor.Red() / float(256);
2819 colorv[1] = s_regionColor.Green() / float(256);
2820 colorv[2] = s_regionColor.Blue() / float(256);
2821 colorv[3] = s_regionColor.Alpha() / float(256);
2822 shader->SetUniform4fv(
"color", colorv);
2824 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2825 shader->SetAttributePointerf(
"position", bufPt);
2827 glDrawArrays(s_tess_mode, 0, s_nvertex);
2832void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2834void beginCallbackD(GLenum mode) { glBegin(mode); }
2836void endCallbackD() { glEnd(); }
2840void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2841 float lat_dist, lon_dist;
2842 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2844 GLUtesselator *tobj = gluNewTess();
2845 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2847#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2848 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2849 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2850 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2851 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2855 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2856 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2857 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2858 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2861 gluTessNormal(tobj, 0, 0, 1);
2863 gluTessBeginPolygon(tobj, NULL);
2864 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2865 gluTessBeginContour(tobj);
2866 contour_pt l = *i->rbegin();
2868 bool sml_valid =
false;
2869 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2870 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2871 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2872 int splits = wxMax(lat_splits, lon_splits) + 1;
2878 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2879 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2882 for (
int i = 0; i < splits; i++) {
2884 if (i == splits - 1)
2885 lat = j->y, lon = j->x;
2887 double d = (double)(i + 1) / splits;
2888 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2892 if (std::isnan(q.m_x))
continue;
2894 double *p =
new double[6];
2899 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2904 gluTessVertex(tobj, p, p);
2905 combine_work_data.push_back(p);
2909 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2911 gluTessEndContour(tobj);
2913 gluTessEndPolygon(tobj);
2915 gluDeleteTess(tobj);
2917 for (std::list<double *>::iterator i = combine_work_data.begin();
2918 i != combine_work_data.end(); i++)
2920 combine_work_data.clear();
2925void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2926 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2928 if (s_b_useStencil) {
2930 glEnable(GL_STENCIL_TEST);
2932 glClear(GL_STENCIL_BUFFER_BIT);
2936 glStencilFunc(GL_ALWAYS, 1, 1);
2937 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2940#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2944 glEnable(GL_DEPTH_TEST);
2945 glDepthFunc(GL_ALWAYS);
2946 glDepthMask(GL_TRUE);
2948 glClear(GL_DEPTH_BUFFER_BIT);
2961 glTranslatef(0, 0, .5);
2965 s_regionColor = wxColor(0, 0, 0, 255);
2966 DrawRegion(vp, region);
2968 if (s_b_useStencil) {
2971 glStencilFunc(GL_EQUAL, 1, 1);
2972 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2975#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2977 glDepthFunc(GL_GREATER);
2978 glDepthMask(GL_FALSE);
2979 glTranslatef(0, 0, -.5);
2982 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2985void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2989 if (s_b_useStencil && s_b_useScissorTest) {
2991 if (rect != vp_rect) {
2992 glEnable(GL_SCISSOR_TEST);
2993 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2996#ifndef USE_ANDROID_GLES2
3002void glChartCanvas::DisableClipRegion() {
3003 glDisable(GL_SCISSOR_TEST);
3004 glDisable(GL_STENCIL_TEST);
3005 glDisable(GL_DEPTH_TEST);
3008void glChartCanvas::Invalidate() {
3010 m_cache_vp.Invalidate();
3016 if (!pBSBChart)
return;
3022 wxString key = chart->GetHashKey();
3026 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3029 if (ittf == hash.end()) {
3031 hash[key]->SetHashKey(key);
3034 pTexFact = hash[key];
3035 pTexFact->SetLRUTime(++m_LRUtime);
3040 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3041 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3048 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3049 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3050 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3051 base_level = log(scalefactor) / log(2.0);
3060 glEnable(GL_TEXTURE_2D);
3061#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3062 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3064 glEnableClientState(GL_VERTEX_ARRAY);
3065 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3070 pTexFact->GetCenter(lat, lon);
3071 MultMatrixViewPort(vp, lat, lon);
3075 LLBBox box = region.GetBox();
3078 if (g_memCacheLimit > 0) {
3083 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3084 for (
int i = 0; i < numtiles; i++) {
3086 if (region.IntersectOut(tile->box)) {
3089 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3090 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3092 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3093 global_color_scheme, mem_used);
3097 coords = tile->m_coords;
3099 coords =
new float[2 * tile->m_ncoords];
3100 for (
int i = 0; i < tile->m_ncoords; i++) {
3102 tile->m_coords[2 * i + 1]);
3103 coords[2 * i + 0] = p.m_x;
3104 coords[2 * i + 1] = p.m_y;
3108#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3109 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3110 m_pParentCanvas->GetpVP());
3113 glDisable(GL_TEXTURE_2D);
3117 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3118 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3119 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3121 if (!texture) glEnable(GL_TEXTURE_2D);
3123 if (!use_norm_vp)
delete[] coords;
3127 glDisable(GL_TEXTURE_2D);
3129#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3130 if (use_norm_vp) glPopMatrix();
3132 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3133 glDisableClientState(GL_VERTEX_ARRAY);
3137void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3139 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3140 m_pParentCanvas->m_pQuilt->IsBusy())
3144 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3146 printf(
" Chart NULL\n");
3147 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3157 LLRegion region = vp.GetLLRegion(rect_region);
3159 LLRegion rendered_region;
3165 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3173 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3175 LLRegion get_region = pqp->ActiveRegion;
3176 bool b_rendered =
false;
3178 if (!pqp->b_overlay) {
3179 get_region.Intersect(region);
3180 if (!get_region.Empty()) {
3181 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3184 SetClipRegion(vp, get_region );
3185 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3186 DisableClipRegion();
3189 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3190 SetClipRegion(vp, pqp->ActiveRegion );
3191 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3193 DisableClipRegion();
3196 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3197 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3198 RenderNoDTA(vp, get_region);
3199 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3204 if (Chs57->m_RAZBuilt) {
3205 RenderNoDTA(vp, get_region);
3206 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3207 rect_region, get_region);
3208 DisableClipRegion();
3213 const LLRegion &oregion = get_region;
3214 LLBBox box = oregion.GetBox();
3225 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3228 ViewPort cvp = ClippedViewport(vp, get_region);
3229 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3230 SetClipRegion(cvp, get_region);
3231 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3232 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3233 RenderWorldChart(gldc, cvp, srect, world);
3234 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3235 global_color_scheme);
3236 DisableClipRegion();
3243 SetClipRegion(vp, get_region);
3244 RenderNoDTA(vp, get_region);
3245 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3247 DisableClipRegion();
3250 SetClipRegion(vp, get_region);
3251 RenderNoDTA(vp, get_region);
3252 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3254 DisableClipRegion();
3270 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3274 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3275 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3277 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3278 if (pqp->b_Valid && pqp->b_overlay &&
3279 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3280 LLRegion get_region = pqp->ActiveRegion;
3282 get_region.Intersect(region);
3283 if (!get_region.Empty()) {
3286 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3291 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3298 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3303 ViewPort vph = m_pParentCanvas->GetVP();
3304 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3307 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3309 if (!hiregion.Empty()) {
3313 switch (global_color_scheme) {
3314 case GLOBAL_COLOR_SCHEME_DAY:
3317 case GLOBAL_COLOR_SCHEME_DUSK:
3320 case GLOBAL_COLOR_SCHEME_NIGHT:
3328#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3330 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3332 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3335 DrawRegion(vp, hiregion);
3337 glDisable(GL_BLEND);
3342 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3344 if (!hiregion.Empty()) {
3348 switch (global_color_scheme) {
3349 case GLOBAL_COLOR_SCHEME_DAY:
3352 case GLOBAL_COLOR_SCHEME_DUSK:
3355 case GLOBAL_COLOR_SCHEME_NIGHT:
3364#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3366 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3368 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3371 DrawRegion(vp, hiregion);
3373 glDisable(GL_BLEND);
3377 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3380void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3382 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3383 m_pParentCanvas->m_pQuilt->IsBusy())
3387 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3389 LLRegion region = vp.GetLLRegion(rect_region);
3391 LLRegion rendered_region;
3393 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3395 LLRegion get_region = pqp->ActiveRegion;
3397 if (!pqp->b_overlay) {
3398 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3401 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3406 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3413 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3441void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3442 ViewPort &vp = m_pParentCanvas->VPoint;
3450 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3451 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3454 LLRegion chart_region;
3456 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3457 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3458 CHART_FAMILY_RASTER) {
3466 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3467 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3468 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3470 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3474 for (
int i = 1; i < 6; i += 2)
3475 if (fabs(ll[i] - ll[i + 2]) > 180) {
3477 for (
int i = 1; i < 8; i += 2)
3478 if (ll[i] < 0) ll[i] += 360;
3482 chart_region = LLRegion(4, ll);
3485 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3487 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3488 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3489 chart_region = LLRegion(4, ll);
3492 chart_region = vp.b_quilt
3493 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3494 : m_pParentCanvas->m_singleChart->GetValidRegion();
3496 bool world_view =
false;
3498 wxRect rect = upd.GetRect();
3499 LLRegion background_region = vp.GetLLRegion(rect);
3502 background_region.Subtract(chart_region);
3504 if (!background_region.Empty()) {
3505 ViewPort cvp = ClippedViewport(vp, background_region);
3506 SetClipRect(cvp, rect,
false);
3507 RenderWorldChart(dc, cvp, rect, world_view);
3508 DisableClipRegion();
3513 RenderQuiltViewGL(vp, rect_region);
3516 LLRegion region = vp.GetLLRegion(rect_region);
3517 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3518 CHART_FAMILY_RASTER) {
3519 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3520 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3521 *m_pcontext, vp, rect_region, region);
3523 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3524 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3525 CHART_FAMILY_VECTOR) {
3526 chart_region.Intersect(region);
3527 RenderNoDTA(vp, chart_region);
3528 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3529 rect_region, region);
3535void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3537 wxColour color = GetGlobalColor(
"NODTA");
3538#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3540 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3542 glColor4ub(163, 180, 183, transparency);
3545 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3549 s_regionColor = color;
3552 DrawRegion(vp, region);
3556void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3559 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3561 glEnable(GL_SCISSOR_TEST);
3562 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3568 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3569#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3571 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3575 colorv[0] = water.Red() / float(256);
3576 colorv[1] = water.Green() / float(256);
3577 colorv[2] = water.Blue() / float(256);
3579 shader->SetUniform4fv(
"color", colorv);
3590 shader->SetAttributePointerf(
"position", pf);
3592 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3604 glDisable(GL_SCISSOR_TEST);
3612void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3613 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3615 DrawStaticRoutesTracksAndWaypoints(vp);
3617 DisableClipRegion();
3620void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3622 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3626 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3627 if (!bmp.Ok())
return;
3629 wxImage image = bmp.ConvertToImage();
3630 int w = image.GetWidth(), h = image.GetHeight();
3633 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3634 tex_w = w, tex_h = h;
3636 tex_w = NextPow2(w), tex_h = NextPow2(h);
3638 m_tideTexWidth = tex_w;
3639 m_tideTexHeight = tex_h;
3641 unsigned char *d = image.GetData();
3642 unsigned char *a = image.GetAlpha();
3644 unsigned char mr, mg, mb;
3645 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3647 unsigned char *e =
new unsigned char[4 * w * h];
3649 for (
int y = 0; y < h; y++)
3650 for (
int x = 0; x < w; x++) {
3651 unsigned char r, g, b;
3652 int off = (y * w + x);
3662 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3666 glGenTextures(1, &m_tideTex);
3668 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3669 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3670 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3672 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3673 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3674 GL_UNSIGNED_BYTE, e);
3676 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3677 GL_UNSIGNED_BYTE, 0);
3678 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3687 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3688 glEnable(GL_TEXTURE_2D);
3691#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3693 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3697 if ((type ==
't') || (type ==
'T'))
3702 if (BBox.Contains(lat, lon)) {
3711 scale *= getAndroidDisplayDensity();
3713 double width2 =
scale * m_tideTexWidth / 2;
3714 double height2 =
scale * m_tideTexHeight / 2;
3729 coords[0] = xp - width2;
3730 coords[1] = yp - height2;
3731 coords[2] = xp - width2;
3732 coords[3] = yp + height2;
3733 coords[4] = xp + width2;
3734 coords[5] = yp + height2;
3735 coords[6] = xp + width2;
3736 coords[7] = yp - height2;
3738 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3745 glDisable(GL_TEXTURE_2D);
3746 glDisable(GL_BLEND);
3747 glBindTexture(GL_TEXTURE_2D, 0);
3749 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3752void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3753 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3756void glChartCanvas::SetColorScheme(ColorScheme cs) {
3757 if (!m_bsetup)
return;
3759 glDeleteTextures(1, &m_tideTex);
3760 glDeleteTextures(1, &m_currentTex);
3766void glChartCanvas::RenderGLAlertMessage() {
3767 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3768 wxString msg = m_pParentCanvas->GetAlertString();
3771 m_gldc.SetFont(*pfont);
3775 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3782 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3783 int xp = sbr.x + sbr.width + 5;
3785 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3786 m_gldc.SetPen(ppPen1);
3787 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3789 m_gldc.DrawRectangle(xp, yp, w, h);
3791 m_gldc.DrawText(msg, xp, yp);
3795unsigned long quiltHash;
3797extern wxLongLong s_t0;
3800void glChartCanvas::Render() {
3801 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3802 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3803 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3808 if (!g_PrintingInProgress)
return;
3811 if (!g_true_zoom && m_binPinch)
return;
3814 long render_start_time = m_glstopwatch.Time();
3816#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3817 loadShaders(GetCanvasIndex());
3818 configureShaders(m_pParentCanvas->VPoint);
3821#ifdef USE_ANDROID_GLES2
3825 if (m_binPinch)
return;
3834 bool recompose =
false;
3835 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3836 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3837 if (m_pParentCanvas->VPoint.IsValid()) {
3838 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3839 m_pParentCanvas->UpdateCanvasControlBar();
3848 if (sw.GetTime() > 2000) {
3854 s_tess_vertex_idx = 0;
3855 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3856 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3862 m_displayScale = GetContentScaleFactor();
3866 m_last_render_time = wxDateTime::Now().GetTicks();
3870 if (g_GLOptions.m_bTextureCompression &&
3871 !g_GLOptions.m_bTextureCompressionCaching)
3876 int gl_width, gl_height;
3877 gl_width = m_pParentCanvas->VPoint.
pix_width;
3878 gl_height = m_pParentCanvas->VPoint.
pix_height;
3881 m_glcanvas_width = gl_width;
3882 m_glcanvas_height = gl_height;
3886 if (gl_height & 1) {
3888 ViewPort *vp = m_pParentCanvas->GetpVP();
3895 ViewPort *vp = m_pParentCanvas->GetpVP();
3903 ViewPort *vp = m_pParentCanvas->GetpVP();
3906 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3909 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3917 ViewPort VPoint = m_pParentCanvas->VPoint;
3919 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3920 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3923#if !defined(USE_ANDROID_GLES2)
3924 glMatrixMode(GL_PROJECTION);
3927 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3928 glMatrixMode(GL_MODELVIEW);
3932 if (s_b_useStencil) {
3933 glEnable(GL_STENCIL_TEST);
3934 glStencilMask(0xff);
3935 glClear(GL_STENCIL_BUFFER_BIT);
3936 glDisable(GL_STENCIL_TEST);
3942 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3943 if (g_GLOptions.m_GLPolygonSmoothing)
3944 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3945 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3957 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3958 bool useFBO =
false;
3964 if (m_b_BuiltFBO && !bpost_hilite
3969 bool b_newview =
true;
3970 bool b_full =
false;
3978 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3982#ifdef USE_ANDROID_GLES2
3983 if (recompose) b_newview =
true;
3995 if (VPoint.b_quilt) {
3996 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3997 if (!chart) b_full =
true;
4006 bool accelerated_pan =
false;
4016 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4017 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4018 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4020 wxPoint2DDouble c_old =
4023 wxPoint2DDouble c_new =
4027 dy = wxRound(c_new.m_y - c_old.m_y);
4028 dx = wxRound(c_new.m_x - c_old.m_x);
4038 double deltax = c_new.m_x - c_old.m_x;
4039 double deltay = c_new.m_y - c_old.m_y;
4041 bool b_whole_pixel =
true;
4042 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4043 b_whole_pixel =
false;
4045 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4046 abs(dy) < m_cache_tex_y &&
4047 (abs(dx) > 0 || (abs(dy) > 0));
4056 if (m_displayScale > 1) accelerated_pan =
false;
4061 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4064#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4067 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4073 if (b_full) accelerated_pan =
false;
4075 if (accelerated_pan) {
4076 if ((dx != 0) || (dy != 0)) {
4088 if (dy > 0 && dy < gl_height)
4089 update_region.Union(
4090 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4092 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4094 if (dx > 0 && dx < gl_width)
4095 update_region.Union(
4096 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4098 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4100 m_cache_page = !m_cache_page;
4103 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4104 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4116 RenderCharts(m_gldc, update_region);
4120 glDisable(g_texture_rectangle_format);
4125 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4126 glEnable(GL_TEXTURE_2D);
4130 float x1, x2, y1, y2;
4143 float tx1, tx2, ty1, ty2;
4149 tx2 = sx / (float)m_cache_tex_x;
4151 ty2 = sy / (float)m_cache_tex_y;
4168 coords[2] = -dx + sx;
4170 coords[4] = -dx + sx;
4171 coords[5] = dy + sy;
4173 coords[7] = dy + sy;
4176 ptexture_2D_shader_program[GetCanvasIndex()];
4180 shader->SetUniform1i(
"uTex", 0);
4184 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4185 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4186 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4188 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4210 shader->SetAttributePointerf(
"aPos", co1);
4211 shader->SetAttributePointerf(
"aUV", tco1);
4213 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4216 shader->SetUniformMatrix4fv(
"MVMatrix",
4217 (GLfloat *)VPoint.vp_matrix_transform);
4220 glBindTexture(g_texture_rectangle_format, 0);
4222 glDisable(g_texture_rectangle_format);
4230 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4231 g_texture_rectangle_format,
4232 m_cache_tex[!m_cache_page], 0);
4243 wxColour color = GetGlobalColor(
"NODTA");
4244 glClearColor(color.Red() / 256., color.Green() / 256.,
4245 color.Blue() / 256., 1.0);
4246 glClear(GL_COLOR_BUFFER_BIT);
4252 RenderCharts(m_gldc, rscreen_region);
4257 m_cache_page = !m_cache_page;
4262 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4273 glMatrixMode(GL_PROJECTION);
4276 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4277 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4279 glMatrixMode(GL_MODELVIEW);
4283 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4284 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4286 glGetIntegerv(GL_VIEWPORT, viewport);
4287 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4288 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4297 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4298 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4299 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4301 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4305 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4306 glEnable(g_texture_rectangle_format);
4308 float tx, ty, tx0, ty0, divx, divy;
4311 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4314 divx = m_cache_tex_x;
4315 divy = m_cache_tex_y;
4318 tx0 = m_fbo_offsetx / divx;
4319 ty0 = m_fbo_offsety / divy;
4320 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4321 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4346 wxColour color = GetGlobalColor(
"NODTA");
4347 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4349 glClear(GL_COLOR_BUFFER_BIT);
4351 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4354 glDisable(g_texture_rectangle_format);
4356 m_cache_vp = VPoint;
4357 m_cache_vp.Validate();
4359 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4361 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4365 RenderCharts(m_gldc, screen_region);
4374 RenderS57TextOverlay(VPoint);
4375 RenderMBTilesOverlay(VPoint);
4381 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4386 wxRect rt = upd.GetRect();
4387 LLRegion region = VPoint.GetLLRegion(rt);
4388 ViewPort cvp = ClippedViewport(VPoint, region);
4389 DrawGroundedOverlayObjects(gldc, cvp);
4392 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4393 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4394 LLBBox screenBox = screenLLRegion.GetBox();
4396 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4399 if (m_pParentCanvas->m_bShowTide) {
4400 m_pParentCanvas->RebuildTideSelectList(screenBox);
4401 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4404 if (m_pParentCanvas->m_bShowCurrent) {
4405 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4406 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4412 if (m_pParentCanvas->m_show_focus_bar &&
4413 (g_canvasConfig != 0)) {
4414 if (m_pParentCanvas == wxWindow::FindFocus()) {
4417 wxColour colour = GetGlobalColor(
"BLUE4");
4418 wxPen ppBlue(colour, 1);
4419 wxBrush ppBrush(colour);
4420 gldc.SetPen(ppBlue);
4421 gldc.SetBrush(ppBrush);
4422 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4423 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4424 wxPoint barPoints[4];
4427 barPoints[1].x = xw;
4429 barPoints[2].x = xw;
4430 barPoints[2].y = rect_pix;
4432 barPoints[3].y = rect_pix;
4434 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4438 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4442 DrawFloatingOverlayObjects(m_gldc);
4444#ifndef USE_ANDROID_GLES2
4447 glMatrixMode(GL_PROJECTION);
4450 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4451 glMatrixMode(GL_MODELVIEW);
4456 if (!g_bhide_depth_units)
4457 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4458 if (!g_bhide_overzoom_flag)
4459 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4462 ViewPort &vp = m_pParentCanvas->GetVP();
4467 if (!g_PrintingInProgress) {
4468 if (m_pParentCanvas->m_pTrackRolloverWin)
4469 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4471 if (m_pParentCanvas->m_pRouteRolloverWin)
4472 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4474 if (m_pParentCanvas->m_pAISRolloverWin)
4475 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4477 if (m_pParentCanvas->GetMUIBar())
4478 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4492 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4493 int x, y, width, height;
4494 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4495 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4496 wxBitmap bmp(width, height, -1);
4499 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4502 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4503 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4507 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4508 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4510 wxStringTokenizer tkz(s,
"\n");
4513 while (tkz.HasMoreTokens()) {
4514 token = tkz.GetNextToken();
4515 dc.DrawText(token, xt, yt);
4518 dc.SelectObject(wxNullBitmap);
4520 m_gldc.DrawBitmap(bmp, x, y,
false);
4526 if (g_bShowChartBar) DrawChartBar(m_gldc);
4528 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4530 m_pParentCanvas->m_Compass->Paint(gldc);
4532 if (m_pParentCanvas->IsPrimaryCanvas()) {
4533 auto ¬eman = NotificationManager::GetInstance();
4534 if (noteman.GetNotificationCount()) {
4535 m_pParentCanvas->m_notification_button->SetIconSeverity(
4536 noteman.GetMaxSeverity());
4537 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4538 m_pParentCanvas->m_notification_button->Show(
true);
4539 m_pParentCanvas->m_notification_button->Paint(gldc);
4541 m_pParentCanvas->m_notification_button->Show(
false);
4544 RenderGLAlertMessage();
4547 ViewPort &vp = m_pParentCanvas->GetVP();
4551 glActiveTexture(GL_TEXTURE0);
4555 if (g_bquiting) DrawQuiting();
4556 if (g_bcompression_wait)
4557 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4567 m_pParentCanvas->PaintCleanup();
4568 m_bforcefull =
false;
4577void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4580 if (VPoint.b_quilt) {
4581 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4582 ps52plib->GetShowS57Text()) {
4583 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4584 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4589 ChPI->ClearPLIBTextList();
4591 ps52plib->ClearTextList();
4601 RenderQuiltViewGLText(vpx, screen_region);
4606void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4609 LLRegion &screenLLRegion) {
4614 if (chart == NULL)
return;
4621 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4623 wxFileName tileFile(chart->GetFullPath());
4625 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4627 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4628 (tileSizeMB.GetLo() > 5000)) {
4631 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4632 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4633 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4640 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4644 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4647 std::vector<int> piano_active_array_tiles =
4648 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4649 bool bfound =
false;
4651 if (std::find(piano_active_array_tiles.begin(),
4652 piano_active_array_tiles.end(),
4653 dbIndex) != piano_active_array_tiles.end()) {
4658 piano_active_array_tiles.push_back(dbIndex);
4659 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4663void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4665 std::vector<int> stackIndexArray =
4666 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4667 unsigned int im = stackIndexArray.size();
4670 if (VPoint.b_quilt && im > 0) {
4671 bool regionVPBuilt =
false;
4673 LLRegion screenLLRegion;
4677 std::vector<int> tiles_to_show;
4678 for (
unsigned int is = 0; is < im; is++) {
4680 ChartData->GetChartTableEntry(stackIndexArray[is]);
4681 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4682 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4684 std::vector<int> piano_active_array_tiles =
4685 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4686 bool bfound =
false;
4688 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4689 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4690 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4698 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4699 piano_active_array_tiles);
4704 tiles_to_show.push_back(stackIndexArray[is]);
4705 if (!regionVPBuilt) {
4708 screenLLRegion = VPoint.GetLLRegion(screen_region);
4709 screenBox = screenLLRegion.GetBox();
4717 regionVPBuilt =
true;
4727 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4728 rit != tiles_to_show.rend(); ++rit) {
4729 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4731 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4732 rit != tiles_to_show.rend(); ++rit) {
4733 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4737 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4739 if (!hiregion.Empty()) {
4743 switch (global_color_scheme) {
4744 case GLOBAL_COLOR_SCHEME_DAY:
4747 case GLOBAL_COLOR_SCHEME_DUSK:
4750 case GLOBAL_COLOR_SCHEME_NIGHT:
4758#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4759 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4761 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4764 DrawRegion(VPoint, hiregion);
4766 glDisable(GL_BLEND);
4772void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4776 GetClientSize(&w, &h);
4778 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4779#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4780 glMatrixMode(GL_PROJECTION);
4783 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4784 glMatrixMode(GL_MODELVIEW);
4788 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4790 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4792 bool world_view =
false;
4793 RenderWorldChart(dc, cvp, rtex, world_view);
4800 glViewport(0, 0, (GLint)w, (GLint)h);
4801#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4802 glMatrixMode(GL_PROJECTION);
4805 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4806 glMatrixMode(GL_MODELVIEW);
4812void glChartCanvas::FastPan(
int dx,
int dy) {
4813#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4817void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4819 if (IsShown()) SetCurrent(*m_pcontext);
4820 float sx = GetSize().x;
4821 float sy = GetSize().y;
4822 glClear(GL_COLOR_BUFFER_BIT);
4825 GetClientSize(&w, &h);
4827 if (s_b_useStencil) {
4828 glEnable(GL_STENCIL_TEST);
4829 glStencilMask(0xff);
4830 glClear(GL_STENCIL_BUFFER_BIT);
4831 glDisable(GL_STENCIL_TEST);
4847 float sxfactor = sx / swidth;
4848 float syfactor = sy / sheight;
4850 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4851 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4852 sx * sx / swidth * 2, sy * sy / sheight * 2);
4853 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4854 glEnable(g_texture_rectangle_format);
4879 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4880 glBindTexture(g_texture_rectangle_format, 0);
4886 float tx, ty, tx0, ty0;
4896 glBindTexture(g_texture_rectangle_format, 0);
4899 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4900 glEnable(g_texture_rectangle_format);
4906 uv[0] = tx0 / m_cache_tex_x;
4907 uv[1] = ty / m_cache_tex_y;
4908 uv[2] = tx / m_cache_tex_x;
4909 uv[3] = ty / m_cache_tex_y;
4910 uv[4] = tx / m_cache_tex_x;
4911 uv[5] = ty0 / m_cache_tex_y;
4912 uv[6] = tx0 / m_cache_tex_x;
4913 uv[7] = ty0 / m_cache_tex_y;
4925 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4926 sx * sx / swidth, sy * sy / sheight);
4928 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4930 glDisable(g_texture_rectangle_format);
4931 glBindTexture(g_texture_rectangle_format, 0);
4938 wxColour color = GetGlobalColor(
"GREY1");
4939 float ht = -offset_y * (sy / sheight);
4940 wxRect r(0, sy - ht, w, ht);
4941 RenderColorRect(r, color);
4944 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4945 RenderColorRect(rt, color);
4948 float w1 = -offset_x * sx / swidth;
4949 wxRect rl(0, 0, w1, sy);
4950 RenderColorRect(rl, color);
4953 float px = w1 + sx * sx / swidth;
4954 wxRect rr(px, 0, sx - px, sy);
4955 RenderColorRect(rr, color);
4964void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4967 if (m_nRun < m_nTotal) {
4968 m_runoffsetx += m_offsetxStep;
4969 if (m_offsetxStep > 0)
4970 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4972 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4974 m_runoffsety += m_offsetyStep;
4975 if (m_offsetyStep > 0)
4976 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4978 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4980 m_runswidth += m_swidthStep;
4981 if (m_swidthStep > 0)
4982 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4984 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4986 m_runsheight += m_sheightStep;
4987 if (m_sheightStep > 0)
4988 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4990 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4995 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5001 if (m_zoomFinaldx || m_zoomFinaldy) {
5002 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5005 m_zoomFinal =
false;
5009void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5011 int sx = GetSize().x;
5012 int sy = GetSize().y;
5014 m_lastfbo_offsetx = m_fbo_offsetx;
5015 m_lastfbo_offsety = m_fbo_offsety;
5016 m_lastfbo_swidth = m_fbo_swidth;
5017 m_lastfbo_sheight = m_fbo_sheight;
5019 float curr_fbo_offset_x = m_fbo_offsetx;
5020 float curr_fbo_offset_y = m_fbo_offsety;
5021 float curr_fbo_swidth = m_fbo_swidth;
5022 float curr_fbo_sheight = m_fbo_sheight;
5024 float fx = (float)cp_x / sx;
5025 float fy = 1.0 - (float)cp_y / sy;
5027 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5028 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5030 m_fbo_swidth = curr_fbo_swidth / factor;
5031 m_fbo_sheight = curr_fbo_sheight / factor;
5033 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5034 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5036 m_fbo_offsetx += post_x;
5037 m_fbo_offsety += post_y;
5048 float perStep = m_nStep / m_nTotal;
5050 if (zoomTimer.IsRunning()) {
5051 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5052 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5053 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5054 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5057 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5058 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5059 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5060 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5062 m_runoffsetx = m_lastfbo_offsetx;
5063 m_runoffsety = m_lastfbo_offsety;
5064 m_runswidth = m_lastfbo_swidth;
5065 m_runsheight = m_lastfbo_sheight;
5068 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5069 m_zoomFinal =
false;
5075void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5079 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5082 if (m_binPinch)
return;
5083 if (m_bpinchGuard)
return;
5085 int x =
event.GetOffset().x;
5086 int y =
event.GetOffset().y;
5088 int lx =
event.GetLastOffset().x;
5089 int ly =
event.GetLastOffset().y;
5094 switch (event.GetState()) {
5095 case GestureStarted:
5096 if (m_binPan)
break;
5100 m_binGesture =
true;
5104 case GestureUpdated:
5109 m_pParentCanvas->FreezePiano();
5111 m_pParentCanvas->ThawPiano();
5122 case GestureFinished:
5125 m_pParentCanvas->UpdateCanvasControlBar();
5128 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5132 case GestureCanceled:
5134 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5141 m_bgestureGuard =
true;
5142 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5143 m_bforcefull =
false;
5148float zoom_inc = 1.0;
5150void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5151 float zoom_gain = 1.0;
5152 float zout_gain = 1.0;
5155 float total_zoom_val;
5157 float max_zoom_scale = 1000.;
5158 float min_zoom_scale = 2e8;
5160 if (event.GetScaleFactor() > 1)
5161 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5163 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5165 if (event.GetTotalScaleFactor() > 1)
5166 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5169 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5171 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5174 float max_zoom_scale = 1000.;
5175 if( cc1->GetVP().b_quilt) {
5176 int ref_index = cc1->GetQuiltRefChartdbIndex();
5183 float min_zoom_scale = 2e8;
5187 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5189 double projected_scale =
5190 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5192 switch (event.GetState()) {
5193 case GestureStarted:
5194 m_first_zout =
false;
5198 m_binGesture =
true;
5200 m_pinchStart =
event.GetCenterPoint();
5201 m_lpinchPoint = m_pinchStart;
5204 event.GetCenterPoint().y, m_pinchlat,
5209 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5210 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5213 if (IsShown()) SetCurrent(*m_pcontext);
5219 case GestureUpdated:
5221 if (projected_scale < min_zoom_scale) {
5222 wxPoint pinchPoint =
event.GetCenterPoint();
5224 float dx = pinchPoint.x - m_lpinchPoint.x;
5225 float dy = pinchPoint.y - m_lpinchPoint.y;
5227 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5228 -dx / total_zoom_val, dy / total_zoom_val);
5230 m_lpinchPoint = pinchPoint;
5234 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5235 wxPoint pinchPoint =
event.GetCenterPoint();
5237 float dx = pinchPoint.x - m_lpinchPoint.x;
5238 float dy = pinchPoint.y - m_lpinchPoint.y;
5240 if ((projected_scale > max_zoom_scale) &&
5241 (projected_scale < min_zoom_scale))
5242 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5243 -dx / total_zoom_val, dy / total_zoom_val);
5245 m_lpinchPoint = pinchPoint;
5248 m_first_zout =
true;
5249 zoom_inc *= zoom_val;
5250 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5251 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5255 wxPoint pinchPoint =
event.GetCenterPoint();
5256 float dx = pinchPoint.x - m_lpinchPoint.x;
5257 float dy = pinchPoint.y - m_lpinchPoint.y;
5259 m_lpinchPoint = pinchPoint;
5270 case GestureFinished: {
5274 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5275 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5279 float tzoom = total_zoom_val;
5281 if (projected_scale >= min_zoom_scale)
5282 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5284 if (projected_scale < max_zoom_scale)
5285 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5287 dx = (cc_x - m_cc_x) * tzoom;
5288 dy = -(cc_y - m_cc_y) * tzoom;
5290 if (zoomTimer.IsRunning()) {
5293 m_zoomFinalZoom = tzoom;
5299 double final_projected_scale =
5303 if (final_projected_scale < min_zoom_scale) {
5307 m_pParentCanvas->m_pQuilt->Invalidate();
5308 m_bforcefull =
true;
5315 m_pParentCanvas->m_pQuilt->Invalidate();
5316 m_bforcefull =
true;
5328 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5332 case GestureCanceled:
5334 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5341 m_bgestureGuard =
true;
5343 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5346void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5356 m_bgestureGuard =
false;
5357 m_bpinchGuard =
false;
5358 m_binGesture =
false;
5359 m_bforcefull =
false;
5362void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5366 m_binGesture =
false;
5367 m_bforcefull =
false;
5371#ifdef HAVE_WX_GESTURE_EVENTS
5373void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5376 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5379 if (m_binPinch)
return;
5380 if (m_bpinchGuard)
return;
5382 int dx =
event.GetDelta().x;
5383 int dy =
event.GetDelta().y;
5385 if (event.IsGestureStart()) {
5386 if (m_binPan)
return;
5390 m_binGesture =
true;
5394 else if (event.IsGestureEnd()) {
5396 m_pParentCanvas->UpdateCanvasControlBar();
5398 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5406 m_pParentCanvas->FreezePiano();
5408 m_pParentCanvas->ThawPiano();
5419 m_bgestureGuard =
true;
5420 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5421 m_bforcefull =
false;
5425void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5427 float zoom_gain = 1.0;
5428 float zout_gain = 1.0;
5430 float last_zoom_val = m_step_zoom_val;
5432 float max_zoom_scale = 1000.;
5433 float min_zoom_scale = 2e8;
5435 if (event.GetZoomFactor() > 1)
5436 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5438 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5440 float inc_zoom_val =
5441 m_total_zoom_val / last_zoom_val;
5445 if (event.IsGestureStart()) {
5446 m_glstopwatch.Start();
5447 printf(
"\nStart--------------\n");
5449 m_pParentCanvas->m_inPinch =
true;
5452 m_binGesture =
true;
5453 m_pinchStart =
event.GetPosition();
5454 m_lpinchPoint = m_pinchStart;
5455 m_total_zoom_val = 1.0;
5456 m_final_zoom_val = 1.0;
5457 m_step_zoom_val = 1.0;
5461 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5465 if (event.IsGestureEnd()) {
5467 if (!m_binGesture)
return;
5468 printf(
"EndZoom--------------\n");
5475 m_final_zoom_val = 1.0;
5476 m_total_zoom_val = 1.0;
5477 m_step_zoom_val = 1.0;
5479 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5486 float zoom_step = 5;
5487 float zoom_trigger = 0.05;
5488 if (projected_scale > 1e5)
5490 else if (projected_scale < 3e4)
5493 if (inc_zoom_val != 1.0) {
5494 if (inc_zoom_val > 1 + zoom_step) {
5495 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5496 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5498 if (IsShown()) SetCurrent(*m_pcontext);
5501 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5502 m_step_zoom_val = m_total_zoom_val;
5503 printf(
" Zoom: %6g\n", inc_zoom_val);
5508 bool b_allow_ztp =
true;
5509 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5510 b_allow_ztp =
false;
5512 if (g_bEnableZoomToCursor && b_allow_ztp) {
5518 int dx = r.x -
event.GetPosition().x;
5519 int dy = r.y -
event.GetPosition().y;
5523 if (IsShown()) SetCurrent(*m_pcontext);
5532 float zoom_gain = 1.0;
5533 float zout_gain = 1.0;
5535 float last_zoom_val = m_total_zoom_val;
5537 float max_zoom_scale = 1000.;
5538 float min_zoom_scale = 2e8;
5540 if (event.GetZoomFactor() > 1)
5541 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5543 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5545 float inc_zoom_val =
5546 m_total_zoom_val / last_zoom_val;
5548 double projected_scale =
5549 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5551 if (event.IsGestureStart()) {
5553 m_first_zout =
false;
5557 m_binGesture =
true;
5558 m_pinchStart =
event.GetPosition();
5559 m_lpinchPoint = m_pinchStart;
5560 m_total_zoom_val = 1.0;
5561 m_final_zoom_val = 1.0;
5564 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5568 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5569 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5572 if (IsShown()) SetCurrent(*m_pcontext);
5575 ViewPort vpr = m_pParentCanvas->VPoint;
5577 GetTouchBackingBitmap(vpr);
5582 if (event.IsGestureEnd()) {
5588 if (!m_binGesture)
return;
5590 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5591 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5595 float tzoom = m_final_zoom_val;
5597 dx = (cc_x - m_cc_x) * tzoom;
5598 dy = -(cc_y - m_cc_y) * tzoom;
5600 if (zoomTimer.IsRunning()) {
5603 m_zoomFinalZoom = tzoom;
5609 double final_projected_scale =
5613 if (final_projected_scale < min_zoom_scale) {
5617 m_pParentCanvas->m_pQuilt->Invalidate();
5618 m_bforcefull =
true;
5625 m_pParentCanvas->m_pQuilt->Invalidate();
5626 m_bforcefull =
true;
5631 m_final_zoom_val = 1.0;
5632 m_total_zoom_val = 1.0;
5633 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5638 if (projected_scale < min_zoom_scale) {
5639 wxPoint pinchPoint =
event.GetPosition();
5641 float dx = pinchPoint.x - m_lpinchPoint.x;
5642 float dy = pinchPoint.y - m_lpinchPoint.y;
5644 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5645 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5647 m_lpinchPoint = pinchPoint;
5648 m_final_zoom_val *= inc_zoom_val;
5652 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5653 wxPoint pinchPoint =
event.GetPosition();
5655 float dx = pinchPoint.x - m_lpinchPoint.x;
5656 float dy = pinchPoint.y - m_lpinchPoint.y;
5658 if ((projected_scale > max_zoom_scale) &&
5659 (projected_scale < min_zoom_scale))
5660 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5661 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5663 m_lpinchPoint = pinchPoint;
5664 m_final_zoom_val *= inc_zoom_val;
5667 m_first_zout =
true;
5668 m_zoom_inc *= inc_zoom_val;
5669 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5670 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5674 wxPoint pinchPoint =
event.GetPosition();
5675 float dx = pinchPoint.x - m_lpinchPoint.x;
5676 float dy = pinchPoint.y - m_lpinchPoint.y;
5678 m_lpinchPoint = pinchPoint;
5682 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5685 m_bgestureGuard =
true;
5686 m_bpinchGuard =
true;
5689void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5698 m_bgestureGuard =
false;
5699 m_bpinchGuard =
false;
5700 m_binGesture =
false;
5701 m_bforcefull =
false;
5704void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5708 m_binGesture =
false;
5709 m_bforcefull =
false;
5711 m_pParentCanvas->m_inPinch =
false;
5712 printf(
"******Finish\n");
5718void glChartCanvas::configureShaders(
ViewPort &vp) {
5719#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5725 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5727 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5728 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5749 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5751 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5752 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5764 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5766 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5767 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5770 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5772 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5773 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5781 shader = pAALine_shader_program[GetCanvasIndex()];
5783 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5786 shader = pring_shader_program[GetCanvasIndex()];
5788 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5789 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5793 if (texture_2DA_shader_program) {
5794 glUseProgram(texture_2DA_shader_program);
5795 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5796 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5797 (
const GLfloat *)pvp->vp_matrix_transform);
5799 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5800 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5808void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5811#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5812 int nl = nVertex / 4;
5814 float *luv = uvCoords;
5817 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5825 glEnableClientState(GL_VERTEX_ARRAY);
5826 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5828 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5829 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5830 glDrawArrays(GL_QUADS, 0, 4);
5837void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5838 float *uvCoords,
ViewPort *vp,
float dx,
5839 float dy,
float angle_rad) {
5840#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5842 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5843 if (!shader)
return;
5848 shader->SetUniform1i(
"uTex", 0);
5853 mat4x4_rotate_Z(Q, I, angle_rad);
5859 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5864 shader->SetAttributePointerf(
"aPos", co1);
5865 shader->SetAttributePointerf(
"aUV", tco1);
5872 GLushort indices1[] = {0,1,3,2};
5873 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5885 tco1[0] = uvCoords[0];
5886 tco1[1] = uvCoords[1];
5887 tco1[2] = uvCoords[2];
5888 tco1[3] = uvCoords[3];
5889 tco1[4] = uvCoords[6];
5890 tco1[5] = uvCoords[7];
5891 tco1[6] = uvCoords[4];
5892 tco1[7] = uvCoords[5];
5897 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5909void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5910#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5912 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5915 shader->SetUniformMatrix4fv(
5916 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5919 colorv[0] = color.Red() / float(256);
5920 colorv[1] = color.Green() / float(256);
5921 colorv[2] = color.Blue() / float(256);
5923 shader->SetUniform4fv(
"color", colorv);
5926 pf[0] = r.x + r.width;
5930 pf[4] = r.x + r.width;
5931 pf[5] = r.y + r.height;
5933 pf[7] = r.y + r.height;
5934 shader->SetAttributePointerf(
"position", pf);
5936 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5944void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5945#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5947 ViewPort VPoint = m_pParentCanvas->VPoint;
5951 GetClientSize(&w, &h);
5952 int sx = GetSize().x;
5953 int sy = GetSize().y;
5957 glViewport(0, 0, (GLint)w, (GLint)h);
5959 if (s_b_useStencil) {
5960 glEnable(GL_STENCIL_TEST);
5961 glStencilMask(0xff);
5962 glClear(GL_STENCIL_BUFFER_BIT);
5963 glDisable(GL_STENCIL_TEST);
5967 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5972 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5973 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5974 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5977 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5979 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5980 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5988 if (bRenderCharts) RenderCharts(gldc, screen_region);
5990 if (bRenderOverlays) {
5991 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5992 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5998 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
6001 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
6002 DrawDynamicRoutesTracksAndWaypoints(VPoint);
6003 DrawFloatingOverlayObjects(m_gldc);
6007 glBindFramebuffer(GL_FRAMEBUFFER, 0);
6012wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
6014 wxMemoryDC tdc(tbm);
6015 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6023 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6024 dc.SetPen(*wxTRANSPARENT_PEN);
6027 tdc.SelectObject(wxNullBitmap);
6028 m_touch_backing_bitmap = tbm;
6029 CreateBackingTexture();
6031 return m_touch_backing_bitmap;
6034void glChartCanvas::CreateBackingTexture() {
6035 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6036 unsigned char *imgdata = image.GetData();
6037 unsigned char *imgalpha = image.GetAlpha();
6038 m_tex_w = image.GetWidth();
6039 m_tex_h = image.GetHeight();
6040 m_image_width = m_tex_w;
6041 m_image_height = m_tex_h;
6043 GLuint format = GL_RGBA;
6044 GLuint internalformat = g_texture_rectangle_format;
6046 internalformat = GL_RGBA;
6051 unsigned char *teximage =
6052 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6054 for (
int i = 0; i < m_image_height; i++) {
6055 for (
int j = 0; j < m_image_width; j++) {
6056 int s = (i * 3 * m_image_width) + (j * 3);
6057 int d = (i * stride * m_tex_w) + (j * stride);
6059 teximage[d + 0] = imgdata[s + 0];
6060 teximage[d + 1] = imgdata[s + 1];
6061 teximage[d + 2] = imgdata[s + 2];
6062 teximage[d + 3] = 255;
6066 glGenTextures(1, &m_TouchBackingTexture);
6067 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6069 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6070 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6071 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6073 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6075 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6076 GL_UNSIGNED_BYTE, teximage);
6079 glBindTexture(GL_TEXTURE_2D, 0);
Wrapper for creating a ChartCtx based on global vars.
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
Represents an active track that is currently being recorded.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
float GetVPChartScale()
Return the ViewPort chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Wrapper class for OpenGL shader programs.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
Represents a navigational route in the navigation system.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
bool m_bUseCanvasPanning
Controls OpenGL canvas hardware-accelerated panning mode.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
Class cm93chart and helpers – CM93 chart state.
Global color handling by name.
Global variables stored in configuration file.
Texture emboss effects storage.
bool g_running
Android only.
GLuint g_raster_format
Global instance.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
GLuint g_raster_format
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
bool b_inCompressAllCharts
Flag to control adaptive UI scaling.
int g_mipmap_max_level
Global instance.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
MUI (Modern User Interface) Control bar.
User notifications manager.
#define OVERLAY_CHARTS
Lowest priority for overlays to render above all basic charts.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Purpose: Track and Trackpoint drawing stuff.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
float g_ChartScaleFactorExp
Global instance.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Track and Trackpoint drawing stuff.
Geographic projection and coordinate transformations.