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;
3888 ViewPort VPoint = m_pParentCanvas->VPoint;
3890 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3891 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3894#if !defined(USE_ANDROID_GLES2)
3895 glMatrixMode(GL_PROJECTION);
3898 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3899 glMatrixMode(GL_MODELVIEW);
3903 if (s_b_useStencil) {
3904 glEnable(GL_STENCIL_TEST);
3905 glStencilMask(0xff);
3906 glClear(GL_STENCIL_BUFFER_BIT);
3907 glDisable(GL_STENCIL_TEST);
3913 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3914 if (g_GLOptions.m_GLPolygonSmoothing)
3915 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3916 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3928 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3929 bool useFBO =
false;
3935 if (m_b_BuiltFBO && !bpost_hilite
3940 bool b_newview =
true;
3941 bool b_full =
false;
3949 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3953#ifdef USE_ANDROID_GLES2
3954 if (recompose) b_newview =
true;
3966 if (VPoint.b_quilt) {
3967 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3968 if (!chart) b_full =
true;
3977 bool accelerated_pan =
false;
3987 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
3988 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
3989 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
3991 wxPoint2DDouble c_old =
3994 wxPoint2DDouble c_new =
3998 dy = wxRound(c_new.m_y - c_old.m_y);
3999 dx = wxRound(c_new.m_x - c_old.m_x);
4009 double deltax = c_new.m_x - c_old.m_x;
4010 double deltay = c_new.m_y - c_old.m_y;
4012 bool b_whole_pixel =
true;
4013 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4014 b_whole_pixel =
false;
4016 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4017 abs(dy) < m_cache_tex_y &&
4018 (abs(dx) > 0 || (abs(dy) > 0));
4027 if (m_displayScale > 1) accelerated_pan =
false;
4032 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4035#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4038 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4044 if (b_full) accelerated_pan =
false;
4046 if (accelerated_pan) {
4047 if ((dx != 0) || (dy != 0)) {
4059 if (dy > 0 && dy < gl_height)
4060 update_region.Union(
4061 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4063 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4065 if (dx > 0 && dx < gl_width)
4066 update_region.Union(
4067 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4069 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4071 m_cache_page = !m_cache_page;
4074 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4075 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4087 RenderCharts(m_gldc, update_region);
4091 glDisable(g_texture_rectangle_format);
4096 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4097 glEnable(GL_TEXTURE_2D);
4101 float x1, x2, y1, y2;
4114 float tx1, tx2, ty1, ty2;
4120 tx2 = sx / (float)m_cache_tex_x;
4122 ty2 = sy / (float)m_cache_tex_y;
4139 coords[2] = -dx + sx;
4141 coords[4] = -dx + sx;
4142 coords[5] = dy + sy;
4144 coords[7] = dy + sy;
4147 ptexture_2D_shader_program[GetCanvasIndex()];
4151 shader->SetUniform1i(
"uTex", 0);
4155 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4156 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4157 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4159 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4181 shader->SetAttributePointerf(
"aPos", co1);
4182 shader->SetAttributePointerf(
"aUV", tco1);
4184 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4187 shader->SetUniformMatrix4fv(
"MVMatrix",
4188 (GLfloat *)VPoint.vp_matrix_transform);
4191 glBindTexture(g_texture_rectangle_format, 0);
4193 glDisable(g_texture_rectangle_format);
4201 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4202 g_texture_rectangle_format,
4203 m_cache_tex[!m_cache_page], 0);
4214 wxColour color = GetGlobalColor(
"NODTA");
4215 glClearColor(color.Red() / 256., color.Green() / 256.,
4216 color.Blue() / 256., 1.0);
4217 glClear(GL_COLOR_BUFFER_BIT);
4223 RenderCharts(m_gldc, rscreen_region);
4228 m_cache_page = !m_cache_page;
4233 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4244 glMatrixMode(GL_PROJECTION);
4247 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4248 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4250 glMatrixMode(GL_MODELVIEW);
4254 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4255 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4257 glGetIntegerv(GL_VIEWPORT, viewport);
4258 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4259 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4268 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4269 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4270 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4272 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4276 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4277 glEnable(g_texture_rectangle_format);
4279 float tx, ty, tx0, ty0, divx, divy;
4282 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4285 divx = m_cache_tex_x;
4286 divy = m_cache_tex_y;
4289 tx0 = m_fbo_offsetx / divx;
4290 ty0 = m_fbo_offsety / divy;
4291 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4292 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4317 wxColour color = GetGlobalColor(
"NODTA");
4318 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4320 glClear(GL_COLOR_BUFFER_BIT);
4322 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4325 glDisable(g_texture_rectangle_format);
4327 m_cache_vp = VPoint;
4328 m_cache_vp.Validate();
4330 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4332 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4336 RenderCharts(m_gldc, screen_region);
4345 RenderS57TextOverlay(VPoint);
4346 RenderMBTilesOverlay(VPoint);
4352 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4357 wxRect rt = upd.GetRect();
4358 LLRegion region = VPoint.GetLLRegion(rt);
4359 ViewPort cvp = ClippedViewport(VPoint, region);
4360 DrawGroundedOverlayObjects(gldc, cvp);
4363 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4364 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4365 LLBBox screenBox = screenLLRegion.GetBox();
4367 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4370 if (m_pParentCanvas->m_bShowTide) {
4371 m_pParentCanvas->RebuildTideSelectList(screenBox);
4372 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4375 if (m_pParentCanvas->m_bShowCurrent) {
4376 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4377 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4383 if (m_pParentCanvas->m_show_focus_bar &&
4384 (g_canvasConfig != 0)) {
4385 if (m_pParentCanvas == wxWindow::FindFocus()) {
4388 wxColour colour = GetGlobalColor(
"BLUE4");
4389 wxPen ppBlue(colour, 1);
4390 wxBrush ppBrush(colour);
4391 gldc.SetPen(ppBlue);
4392 gldc.SetBrush(ppBrush);
4393 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4394 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4395 wxPoint barPoints[4];
4398 barPoints[1].x = xw;
4400 barPoints[2].x = xw;
4401 barPoints[2].y = rect_pix;
4403 barPoints[3].y = rect_pix;
4405 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4409 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4413 DrawFloatingOverlayObjects(m_gldc);
4415#ifndef USE_ANDROID_GLES2
4418 glMatrixMode(GL_PROJECTION);
4421 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4422 glMatrixMode(GL_MODELVIEW);
4427 if (!g_bhide_depth_units)
4428 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4429 if (!g_bhide_overzoom_flag)
4430 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4433 ViewPort &vp = m_pParentCanvas->GetVP();
4438 if (!g_PrintingInProgress) {
4439 if (m_pParentCanvas->m_pTrackRolloverWin)
4440 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4442 if (m_pParentCanvas->m_pRouteRolloverWin)
4443 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4445 if (m_pParentCanvas->m_pAISRolloverWin)
4446 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4448 if (m_pParentCanvas->GetMUIBar())
4449 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4463 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4464 int x, y, width, height;
4465 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4466 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4467 wxBitmap bmp(width, height, -1);
4470 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4473 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4474 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4478 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4479 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4481 wxStringTokenizer tkz(s,
"\n");
4484 while (tkz.HasMoreTokens()) {
4485 token = tkz.GetNextToken();
4486 dc.DrawText(token, xt, yt);
4489 dc.SelectObject(wxNullBitmap);
4491 m_gldc.DrawBitmap(bmp, x, y,
false);
4497 if (g_bShowChartBar) DrawChartBar(m_gldc);
4499 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4501 m_pParentCanvas->m_Compass->Paint(gldc);
4503 if (m_pParentCanvas->IsPrimaryCanvas() &&
4504 m_pParentCanvas->m_notification_button) {
4505 auto ¬eman = NotificationManager::GetInstance();
4506 if (noteman.GetNotificationCount()) {
4507 m_pParentCanvas->m_notification_button->SetIconSeverity(
4508 noteman.GetMaxSeverity());
4509 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4510 m_pParentCanvas->m_notification_button->Show(
true);
4511 m_pParentCanvas->m_notification_button->Paint(gldc);
4513 m_pParentCanvas->m_notification_button->Show(
false);
4516 RenderGLAlertMessage();
4519 ViewPort &vp = m_pParentCanvas->GetVP();
4523 glActiveTexture(GL_TEXTURE0);
4527 if (g_bquiting) DrawQuiting();
4528 if (g_bcompression_wait)
4529 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4539 m_pParentCanvas->PaintCleanup();
4540 m_bforcefull =
false;
4549void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4552 if (VPoint.b_quilt) {
4553 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4554 ps52plib->GetShowS57Text()) {
4555 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4556 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4561 ChPI->ClearPLIBTextList();
4563 ps52plib->ClearTextList();
4573 RenderQuiltViewGLText(vpx, screen_region);
4578void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4581 LLRegion &screenLLRegion) {
4586 if (chart == NULL)
return;
4593 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4595 wxFileName tileFile(chart->GetFullPath());
4597 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4600 bool isBasemap = tileFile.GetPath().Lower().Contains(
"basemap");
4606 (double)chart->GetNativeScale();
4608 if (zoom_ratio > g_tile_basemap_zoom_factor)
return;
4611 if (!isBasemap && (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4612 (tileSizeMB.GetLo() > 5000))) {
4615 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4616 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4617 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4624 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4628 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4631 std::vector<int> piano_active_array_tiles =
4632 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4633 bool bfound =
false;
4635 if (std::find(piano_active_array_tiles.begin(),
4636 piano_active_array_tiles.end(),
4637 dbIndex) != piano_active_array_tiles.end()) {
4642 piano_active_array_tiles.push_back(dbIndex);
4643 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4647void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4649 std::vector<int> stackIndexArray =
4650 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4651 unsigned int im = stackIndexArray.size();
4654 if (VPoint.b_quilt && im > 0) {
4655 bool regionVPBuilt =
false;
4657 LLRegion screenLLRegion;
4661 std::vector<int> tiles_to_show;
4662 for (
unsigned int is = 0; is < im; is++) {
4664 ChartData->GetChartTableEntry(stackIndexArray[is]);
4665 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4666 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4668 std::vector<int> piano_active_array_tiles =
4669 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4670 bool bfound =
false;
4672 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4673 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4674 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4682 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4683 piano_active_array_tiles);
4688 tiles_to_show.push_back(stackIndexArray[is]);
4689 if (!regionVPBuilt) {
4692 screenLLRegion = VPoint.GetLLRegion(screen_region);
4693 screenBox = screenLLRegion.GetBox();
4701 regionVPBuilt =
true;
4711 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4712 rit != tiles_to_show.rend(); ++rit) {
4713 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4715 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4716 rit != tiles_to_show.rend(); ++rit) {
4717 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4721 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4723 if (!hiregion.Empty()) {
4727 switch (global_color_scheme) {
4728 case GLOBAL_COLOR_SCHEME_DAY:
4731 case GLOBAL_COLOR_SCHEME_DUSK:
4734 case GLOBAL_COLOR_SCHEME_NIGHT:
4742#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4743 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4745 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4748 DrawRegion(VPoint, hiregion);
4750 glDisable(GL_BLEND);
4756void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4760 GetClientSize(&w, &h);
4762 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4763#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4764 glMatrixMode(GL_PROJECTION);
4767 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4768 glMatrixMode(GL_MODELVIEW);
4772 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4774 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4776 bool world_view =
false;
4777 RenderWorldChart(dc, cvp, rtex, world_view);
4784 glViewport(0, 0, (GLint)w, (GLint)h);
4785#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4786 glMatrixMode(GL_PROJECTION);
4789 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4790 glMatrixMode(GL_MODELVIEW);
4796void glChartCanvas::FastPan(
int dx,
int dy) {
4797#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4801void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4803 if (IsShown()) SetCurrent(*m_pcontext);
4804 float sx = GetSize().x;
4805 float sy = GetSize().y;
4806 glClear(GL_COLOR_BUFFER_BIT);
4809 GetClientSize(&w, &h);
4811 if (s_b_useStencil) {
4812 glEnable(GL_STENCIL_TEST);
4813 glStencilMask(0xff);
4814 glClear(GL_STENCIL_BUFFER_BIT);
4815 glDisable(GL_STENCIL_TEST);
4831 float sxfactor = sx / swidth;
4832 float syfactor = sy / sheight;
4834 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4835 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4836 sx * sx / swidth * 2, sy * sy / sheight * 2);
4837 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4838 glEnable(g_texture_rectangle_format);
4863 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4864 glBindTexture(g_texture_rectangle_format, 0);
4870 float tx, ty, tx0, ty0;
4880 glBindTexture(g_texture_rectangle_format, 0);
4883 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4884 glEnable(g_texture_rectangle_format);
4890 uv[0] = tx0 / m_cache_tex_x;
4891 uv[1] = ty / m_cache_tex_y;
4892 uv[2] = tx / m_cache_tex_x;
4893 uv[3] = ty / m_cache_tex_y;
4894 uv[4] = tx / m_cache_tex_x;
4895 uv[5] = ty0 / m_cache_tex_y;
4896 uv[6] = tx0 / m_cache_tex_x;
4897 uv[7] = ty0 / m_cache_tex_y;
4909 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4910 sx * sx / swidth, sy * sy / sheight);
4912 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4914 glDisable(g_texture_rectangle_format);
4915 glBindTexture(g_texture_rectangle_format, 0);
4922 wxColour color = GetGlobalColor(
"GREY1");
4923 float ht = -offset_y * (sy / sheight);
4924 wxRect r(0, sy - ht, w, ht);
4925 RenderColorRect(r, color);
4928 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4929 RenderColorRect(rt, color);
4932 float w1 = -offset_x * sx / swidth;
4933 wxRect rl(0, 0, w1, sy);
4934 RenderColorRect(rl, color);
4937 float px = w1 + sx * sx / swidth;
4938 wxRect rr(px, 0, sx - px, sy);
4939 RenderColorRect(rr, color);
4948void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4951 if (m_nRun < m_nTotal) {
4952 m_runoffsetx += m_offsetxStep;
4953 if (m_offsetxStep > 0)
4954 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4956 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4958 m_runoffsety += m_offsetyStep;
4959 if (m_offsetyStep > 0)
4960 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4962 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4964 m_runswidth += m_swidthStep;
4965 if (m_swidthStep > 0)
4966 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4968 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4970 m_runsheight += m_sheightStep;
4971 if (m_sheightStep > 0)
4972 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4974 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4979 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4985 if (m_zoomFinaldx || m_zoomFinaldy) {
4986 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
4989 m_zoomFinal =
false;
4993void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
4995 int sx = GetSize().x;
4996 int sy = GetSize().y;
4998 m_lastfbo_offsetx = m_fbo_offsetx;
4999 m_lastfbo_offsety = m_fbo_offsety;
5000 m_lastfbo_swidth = m_fbo_swidth;
5001 m_lastfbo_sheight = m_fbo_sheight;
5003 float curr_fbo_offset_x = m_fbo_offsetx;
5004 float curr_fbo_offset_y = m_fbo_offsety;
5005 float curr_fbo_swidth = m_fbo_swidth;
5006 float curr_fbo_sheight = m_fbo_sheight;
5008 float fx = (float)cp_x / sx;
5009 float fy = 1.0 - (float)cp_y / sy;
5011 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5012 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5014 m_fbo_swidth = curr_fbo_swidth / factor;
5015 m_fbo_sheight = curr_fbo_sheight / factor;
5017 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5018 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5020 m_fbo_offsetx += post_x;
5021 m_fbo_offsety += post_y;
5032 float perStep = m_nStep / m_nTotal;
5034 if (zoomTimer.IsRunning()) {
5035 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5036 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5037 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5038 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5041 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5042 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5043 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5044 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5046 m_runoffsetx = m_lastfbo_offsetx;
5047 m_runoffsety = m_lastfbo_offsety;
5048 m_runswidth = m_lastfbo_swidth;
5049 m_runsheight = m_lastfbo_sheight;
5052 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5053 m_zoomFinal =
false;
5059void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5063 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5066 if (m_binPinch)
return;
5067 if (m_bpinchGuard)
return;
5069 int x =
event.GetOffset().x;
5070 int y =
event.GetOffset().y;
5072 int lx =
event.GetLastOffset().x;
5073 int ly =
event.GetLastOffset().y;
5078 switch (event.GetState()) {
5079 case GestureStarted:
5080 if (m_binPan)
break;
5084 m_binGesture =
true;
5088 case GestureUpdated:
5093 m_pParentCanvas->FreezePiano();
5095 m_pParentCanvas->ThawPiano();
5106 case GestureFinished:
5109 m_pParentCanvas->UpdateCanvasControlBar();
5112 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5116 case GestureCanceled:
5118 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5125 m_bgestureGuard =
true;
5126 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5127 m_bforcefull =
false;
5132float zoom_inc = 1.0;
5134void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5135 float zoom_gain = 1.0;
5136 float zout_gain = 1.0;
5139 float total_zoom_val;
5141 float max_zoom_scale = 1000.;
5142 float min_zoom_scale = 2e8;
5144 if (event.GetScaleFactor() > 1)
5145 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5147 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5149 if (event.GetTotalScaleFactor() > 1)
5150 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5153 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5155 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5158 float max_zoom_scale = 1000.;
5159 if( cc1->GetVP().b_quilt) {
5160 int ref_index = cc1->GetQuiltRefChartdbIndex();
5167 float min_zoom_scale = 2e8;
5171 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5173 double projected_scale =
5174 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5176 switch (event.GetState()) {
5177 case GestureStarted:
5178 m_first_zout =
false;
5182 m_binGesture =
true;
5184 m_pinchStart =
event.GetCenterPoint();
5185 m_lpinchPoint = m_pinchStart;
5188 event.GetCenterPoint().y, m_pinchlat,
5193 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5194 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5197 if (IsShown()) SetCurrent(*m_pcontext);
5203 case GestureUpdated:
5205 if (projected_scale < min_zoom_scale) {
5206 wxPoint pinchPoint =
event.GetCenterPoint();
5208 float dx = pinchPoint.x - m_lpinchPoint.x;
5209 float dy = pinchPoint.y - m_lpinchPoint.y;
5211 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5212 -dx / total_zoom_val, dy / total_zoom_val);
5214 m_lpinchPoint = pinchPoint;
5218 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5219 wxPoint pinchPoint =
event.GetCenterPoint();
5221 float dx = pinchPoint.x - m_lpinchPoint.x;
5222 float dy = pinchPoint.y - m_lpinchPoint.y;
5224 if ((projected_scale > max_zoom_scale) &&
5225 (projected_scale < min_zoom_scale))
5226 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5227 -dx / total_zoom_val, dy / total_zoom_val);
5229 m_lpinchPoint = pinchPoint;
5232 m_first_zout =
true;
5233 zoom_inc *= zoom_val;
5234 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5235 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5239 wxPoint pinchPoint =
event.GetCenterPoint();
5240 float dx = pinchPoint.x - m_lpinchPoint.x;
5241 float dy = pinchPoint.y - m_lpinchPoint.y;
5243 m_lpinchPoint = pinchPoint;
5254 case GestureFinished: {
5258 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5259 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5263 float tzoom = total_zoom_val;
5265 if (projected_scale >= min_zoom_scale)
5266 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5268 if (projected_scale < max_zoom_scale)
5269 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5271 dx = (cc_x - m_cc_x) * tzoom;
5272 dy = -(cc_y - m_cc_y) * tzoom;
5274 if (zoomTimer.IsRunning()) {
5277 m_zoomFinalZoom = tzoom;
5283 double final_projected_scale =
5287 if (final_projected_scale < min_zoom_scale) {
5291 m_pParentCanvas->m_pQuilt->Invalidate();
5292 m_bforcefull =
true;
5299 m_pParentCanvas->m_pQuilt->Invalidate();
5300 m_bforcefull =
true;
5312 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5316 case GestureCanceled:
5318 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5325 m_bgestureGuard =
true;
5327 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5330void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5340 m_bgestureGuard =
false;
5341 m_bpinchGuard =
false;
5342 m_binGesture =
false;
5343 m_bforcefull =
false;
5346void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5350 m_binGesture =
false;
5351 m_bforcefull =
false;
5355#ifdef HAVE_WX_GESTURE_EVENTS
5357void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5360 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5363 if (m_binPinch)
return;
5364 if (m_bpinchGuard)
return;
5366 int dx =
event.GetDelta().x;
5367 int dy =
event.GetDelta().y;
5369 if (event.IsGestureStart()) {
5370 if (m_binPan)
return;
5374 m_binGesture =
true;
5378 else if (event.IsGestureEnd()) {
5380 m_pParentCanvas->UpdateCanvasControlBar();
5382 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5390 m_pParentCanvas->FreezePiano();
5392 m_pParentCanvas->ThawPiano();
5403 m_bgestureGuard =
true;
5404 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5405 m_bforcefull =
false;
5409void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5411 float zoom_gain = 1.0;
5412 float zout_gain = 1.0;
5414 float last_zoom_val = m_step_zoom_val;
5416 float max_zoom_scale = 1000.;
5417 float min_zoom_scale = 2e8;
5419 if (event.GetZoomFactor() > 1)
5420 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5422 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5424 float inc_zoom_val =
5425 m_total_zoom_val / last_zoom_val;
5429 if (event.IsGestureStart()) {
5430 m_glstopwatch.Start();
5431 printf(
"\nStart--------------\n");
5433 m_pParentCanvas->m_inPinch =
true;
5436 m_binGesture =
true;
5437 m_pinchStart =
event.GetPosition();
5438 m_lpinchPoint = m_pinchStart;
5439 m_total_zoom_val = 1.0;
5440 m_final_zoom_val = 1.0;
5441 m_step_zoom_val = 1.0;
5445 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5449 if (event.IsGestureEnd()) {
5451 if (!m_binGesture)
return;
5452 printf(
"EndZoom--------------\n");
5459 m_final_zoom_val = 1.0;
5460 m_total_zoom_val = 1.0;
5461 m_step_zoom_val = 1.0;
5463 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5470 float zoom_step = 5;
5471 float zoom_trigger = 0.05;
5472 if (projected_scale > 1e5)
5474 else if (projected_scale < 3e4)
5477 if (inc_zoom_val != 1.0) {
5478 if (inc_zoom_val > 1 + zoom_step) {
5479 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5480 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5482 if (IsShown()) SetCurrent(*m_pcontext);
5485 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5486 m_step_zoom_val = m_total_zoom_val;
5487 printf(
" Zoom: %6g\n", inc_zoom_val);
5492 bool b_allow_ztp =
true;
5493 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5494 b_allow_ztp =
false;
5496 if (g_bEnableZoomToCursor && b_allow_ztp) {
5502 int dx = r.x -
event.GetPosition().x;
5503 int dy = r.y -
event.GetPosition().y;
5507 if (IsShown()) SetCurrent(*m_pcontext);
5516 float zoom_gain = 1.0;
5517 float zout_gain = 1.0;
5519 float last_zoom_val = m_total_zoom_val;
5521 float max_zoom_scale = 1000.;
5522 float min_zoom_scale = 2e8;
5524 if (event.GetZoomFactor() > 1)
5525 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5527 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5529 float inc_zoom_val =
5530 m_total_zoom_val / last_zoom_val;
5532 double projected_scale =
5533 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5535 if (event.IsGestureStart()) {
5537 m_first_zout =
false;
5541 m_binGesture =
true;
5542 m_pinchStart =
event.GetPosition();
5543 m_lpinchPoint = m_pinchStart;
5544 m_total_zoom_val = 1.0;
5545 m_final_zoom_val = 1.0;
5548 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5552 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5553 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5556 if (IsShown()) SetCurrent(*m_pcontext);
5559 ViewPort vpr = m_pParentCanvas->VPoint;
5561 GetTouchBackingBitmap(vpr);
5566 if (event.IsGestureEnd()) {
5572 if (!m_binGesture)
return;
5574 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5575 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5579 float tzoom = m_final_zoom_val;
5581 dx = (cc_x - m_cc_x) * tzoom;
5582 dy = -(cc_y - m_cc_y) * tzoom;
5584 if (zoomTimer.IsRunning()) {
5587 m_zoomFinalZoom = tzoom;
5593 double final_projected_scale =
5597 if (final_projected_scale < min_zoom_scale) {
5601 m_pParentCanvas->m_pQuilt->Invalidate();
5602 m_bforcefull =
true;
5609 m_pParentCanvas->m_pQuilt->Invalidate();
5610 m_bforcefull =
true;
5615 m_final_zoom_val = 1.0;
5616 m_total_zoom_val = 1.0;
5617 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5622 if (projected_scale < min_zoom_scale) {
5623 wxPoint pinchPoint =
event.GetPosition();
5625 float dx = pinchPoint.x - m_lpinchPoint.x;
5626 float dy = pinchPoint.y - m_lpinchPoint.y;
5628 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5629 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5631 m_lpinchPoint = pinchPoint;
5632 m_final_zoom_val *= inc_zoom_val;
5636 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5637 wxPoint pinchPoint =
event.GetPosition();
5639 float dx = pinchPoint.x - m_lpinchPoint.x;
5640 float dy = pinchPoint.y - m_lpinchPoint.y;
5642 if ((projected_scale > max_zoom_scale) &&
5643 (projected_scale < min_zoom_scale))
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;
5651 m_first_zout =
true;
5652 m_zoom_inc *= inc_zoom_val;
5653 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5654 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5658 wxPoint pinchPoint =
event.GetPosition();
5659 float dx = pinchPoint.x - m_lpinchPoint.x;
5660 float dy = pinchPoint.y - m_lpinchPoint.y;
5662 m_lpinchPoint = pinchPoint;
5666 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5669 m_bgestureGuard =
true;
5670 m_bpinchGuard =
true;
5673void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5682 m_bgestureGuard =
false;
5683 m_bpinchGuard =
false;
5684 m_binGesture =
false;
5685 m_bforcefull =
false;
5688void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5692 m_binGesture =
false;
5693 m_bforcefull =
false;
5695 m_pParentCanvas->m_inPinch =
false;
5696 printf(
"******Finish\n");
5702void glChartCanvas::configureShaders(
ViewPort &vp) {
5703#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5709 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5711 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5712 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5733 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5735 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5736 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5748 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5750 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5751 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5754 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5756 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5757 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5765 shader = pAALine_shader_program[GetCanvasIndex()];
5767 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5770 shader = pring_shader_program[GetCanvasIndex()];
5772 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5773 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5777 if (texture_2DA_shader_program) {
5778 glUseProgram(texture_2DA_shader_program);
5779 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5780 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5781 (
const GLfloat *)pvp->vp_matrix_transform);
5783 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5784 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5792void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5795#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5796 int nl = nVertex / 4;
5798 float *luv = uvCoords;
5801 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5809 glEnableClientState(GL_VERTEX_ARRAY);
5810 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5812 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5813 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5814 glDrawArrays(GL_QUADS, 0, 4);
5821void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5822 float *uvCoords,
ViewPort *vp,
float dx,
5823 float dy,
float angle_rad) {
5824#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5826 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5827 if (!shader)
return;
5832 shader->SetUniform1i(
"uTex", 0);
5837 mat4x4_rotate_Z(Q, I, angle_rad);
5843 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5848 shader->SetAttributePointerf(
"aPos", co1);
5849 shader->SetAttributePointerf(
"aUV", tco1);
5856 GLushort indices1[] = {0,1,3,2};
5857 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5869 tco1[0] = uvCoords[0];
5870 tco1[1] = uvCoords[1];
5871 tco1[2] = uvCoords[2];
5872 tco1[3] = uvCoords[3];
5873 tco1[4] = uvCoords[6];
5874 tco1[5] = uvCoords[7];
5875 tco1[6] = uvCoords[4];
5876 tco1[7] = uvCoords[5];
5881 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5893void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5894#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5896 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5899 shader->SetUniformMatrix4fv(
5900 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5903 colorv[0] = color.Red() / float(256);
5904 colorv[1] = color.Green() / float(256);
5905 colorv[2] = color.Blue() / float(256);
5907 shader->SetUniform4fv(
"color", colorv);
5910 pf[0] = r.x + r.width;
5914 pf[4] = r.x + r.width;
5915 pf[5] = r.y + r.height;
5917 pf[7] = r.y + r.height;
5918 shader->SetAttributePointerf(
"position", pf);
5920 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5928void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5929#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5931 ViewPort VPoint = m_pParentCanvas->VPoint;
5935 GetClientSize(&w, &h);
5936 int sx = GetSize().x;
5937 int sy = GetSize().y;
5941 glViewport(0, 0, (GLint)w, (GLint)h);
5943 if (s_b_useStencil) {
5944 glEnable(GL_STENCIL_TEST);
5945 glStencilMask(0xff);
5946 glClear(GL_STENCIL_BUFFER_BIT);
5947 glDisable(GL_STENCIL_TEST);
5951 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5956 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5957 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5958 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5961 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5963 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5964 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5972 if (bRenderCharts) RenderCharts(gldc, screen_region);
5974 if (bRenderOverlays) {
5975 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5976 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5982 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5985 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5986 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5987 DrawFloatingOverlayObjects(m_gldc);
5991 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5996wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5998 wxMemoryDC tdc(tbm);
5999 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
6007 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
6008 dc.SetPen(*wxTRANSPARENT_PEN);
6011 tdc.SelectObject(wxNullBitmap);
6012 m_touch_backing_bitmap = tbm;
6013 CreateBackingTexture();
6015 return m_touch_backing_bitmap;
6018void glChartCanvas::CreateBackingTexture() {
6019 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6020 unsigned char *imgdata = image.GetData();
6021 unsigned char *imgalpha = image.GetAlpha();
6022 m_tex_w = image.GetWidth();
6023 m_tex_h = image.GetHeight();
6024 m_image_width = m_tex_w;
6025 m_image_height = m_tex_h;
6027 GLuint format = GL_RGBA;
6028 GLuint internalformat = g_texture_rectangle_format;
6030 internalformat = GL_RGBA;
6035 unsigned char *teximage =
6036 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6038 for (
int i = 0; i < m_image_height; i++) {
6039 for (
int j = 0; j < m_image_width; j++) {
6040 int s = (i * 3 * m_image_width) + (j * 3);
6041 int d = (i * stride * m_tex_w) + (j * stride);
6043 teximage[d + 0] = imgdata[s + 0];
6044 teximage[d + 1] = imgdata[s + 1];
6045 teximage[d + 2] = imgdata[s + 2];
6046 teximage[d + 3] = 255;
6050 glGenTextures(1, &m_TouchBackingTexture);
6051 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6053 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6054 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6055 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6057 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6059 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6060 GL_UNSIGNED_BYTE, teximage);
6063 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.