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) {
498 ViewPort *vp = m_pParentCanvas->GetpVP();
499 vp->SetVPTransformMatrix();
502 if (!m_bsetup)
return;
504 if (!IsShown())
return;
506 SetCurrent(*m_pcontext);
510 SetSize(GetSize().x, GetSize().y);
518 if (m_pcontext && IsShown()) {
519 SetCurrent(*m_pcontext);
522 wxLogDebug(
"BuildFBO 3");
526void glChartCanvas::MouseEvent(wxMouseEvent &event) {
527 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
533 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
535 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
538 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
542 if (m_bgestureGuard) {
543 m_pParentCanvas->r_rband.x = 0;
553 if (event.LeftUp()) {
555 if ((abs(panx) > 2) || (abs(pany) > 2)) {
558 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
565 if (!event.LeftDClick()) {
570 if (m_binPan && event.RightDown()) {
571 qDebug() <<
"Skip right on pan";
574 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
576 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
577 if (!m_bgestureGuard)
587#ifndef GL_MAX_RENDERBUFFER_SIZE
588#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
591#ifndef USE_ANDROID_GLES2
592bool glChartCanvas::buildFBOSize(
int fboSize) {
594 if (IsShown()) SetCurrent(*m_pcontext);
597 glDeleteTextures(2, m_cache_tex);
598 glDeleteFramebuffers(1, &m_fb0);
599 glDeleteRenderbuffers(1, &m_renderbuffer);
600 m_b_BuiltFBO =
false;
603 if (m_b_DisableFBO)
return false;
607 int rb_x = GetSize().x;
608 int rb_y = GetSize().y;
610 while (i < rb_x) i <<= 1;
614 while (i < rb_y) i <<= 1;
617 m_cache_tex_x = wxMax(rb_x, rb_y);
618 m_cache_tex_y = wxMax(rb_x, rb_y);
621 m_cache_tex_x = GetSize().x * m_displayScale;
622 m_cache_tex_y = GetSize().y * m_displayScale;
625 int err = GL_NO_ERROR;
627 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
630 if (err == GL_INVALID_ENUM) {
631 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
635 if (err == GL_NO_ERROR) {
636 if (fboSize > params) {
638 " OpenGL-> Requested Framebuffer size exceeds "
639 "GL_MAX_RENDERBUFFER_SIZE");
644 glGenFramebuffers(1, &m_fb0);
648 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
653 glGenRenderbuffers(1, &m_renderbuffer);
657 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
662 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
666 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
672 glGenTextures(2, m_cache_tex);
673 for (
int i = 0; i < 2; i++) {
674 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
675 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
677 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
679 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
680 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
683 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
685 if (m_b_useFBOStencil) {
687 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
688 m_cache_tex_x, m_cache_tex_y);
690 int err = glGetError();
693 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
697 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
698 GL_RENDERBUFFER_EXT, m_renderbuffer);
702 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
707 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
708 GL_RENDERBUFFER_EXT, m_renderbuffer);
712 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
718 GLenum depth_format = GL_DEPTH_COMPONENT24;
723 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
727 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
729 int err = glGetError();
732 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
738 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
739 GL_RENDERBUFFER_EXT, m_renderbuffer);
744 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
751 glBindTexture(GL_TEXTURE_2D, 0);
752 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
755 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
757 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
758 g_texture_rectangle_format, m_cache_tex[0], 0);
760 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
762 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
764 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
766 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
776#ifdef USE_ANDROID_GLES2
777bool glChartCanvas::buildFBOSize(
int fboSize) {
781 int rb_x = GetSize().x;
782 int rb_y = GetSize().y;
784 while (i < rb_x) i <<= 1;
788 while (i < rb_y) i <<= 1;
791 m_cache_tex_x = wxMax(rb_x, rb_y);
792 m_cache_tex_y = wxMax(rb_x, rb_y);
796 int err = GL_NO_ERROR;
798 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
801 if (err == GL_INVALID_ENUM) {
802 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
806 if (err == GL_NO_ERROR) {
807 if (fboSize > params) {
809 " OpenGL-> Requested Framebuffer size exceeds "
810 "GL_MAX_RENDERBUFFER_SIZE");
815 glGenFramebuffers(1, &m_fb0);
819 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
824 glGenRenderbuffers(1, &m_renderbuffer);
828 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
833 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
837 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
843 glGenTextures(2, m_cache_tex);
844 for (
int i = 0; i < 2; i++) {
845 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
846 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
848 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
850 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
851 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
854 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
857 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
863 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
867 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
868 GL_RENDERBUFFER, m_renderbuffer);
872 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
877 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
878 GL_RENDERBUFFER, m_renderbuffer);
882 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
887 glBindTexture(GL_TEXTURE_2D, 0);
888 glBindFramebuffer(GL_FRAMEBUFFER, 0);
891 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
893 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
894 g_texture_rectangle_format, m_cache_tex[0], 0);
896 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
898 glBindFramebuffer(GL_FRAMEBUFFER, 0);
900 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
902 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
912void glChartCanvas::BuildFBO() {
913 if (g_b_needFinish) glFinish();
917 glDeleteTextures(2, m_cache_tex);
918 glDeleteFramebuffers(1, &m_fb0);
919 glDeleteRenderbuffers(1, &m_renderbuffer);
920 m_b_BuiltFBO =
false;
923 if (m_b_DisableFBO)
return;
926 int gl_width, gl_height;
927 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
928 int initialSize = NextPow2(gl_width * m_displayScale);
933 wxString info = androidGetDeviceInfo();
935 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
938 if (!buildFBOSize(initialSize)) {
939 glDeleteTextures(2, m_cache_tex);
940 glDeleteFramebuffers(1, &m_fb0);
941 glDeleteRenderbuffers(1, &m_renderbuffer);
943 if (!buildFBOSize(1024)) {
944 wxLogMessage(
"BuildFBO C");
946 m_b_DisableFBO =
true;
947 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
948 m_b_BuiltFBO =
false;
957 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
969void glChartCanvas::SetupOpenGL() {
970 if (IsShown()) SetCurrent(*m_pcontext);
972 char *str = (
char *)glGetString(GL_RENDERER);
975 wxLogMessage(
"Failed to initialize OpenGL");
979 char render_string[80];
980 strncpy(render_string, str, 79);
981 m_renderer = wxString(render_string, wxConvUTF8);
984 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
985 msg.Printf(
"OpenGL-> Renderer String: ");
989 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
991 char version_string[80];
992 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
993 msg.Printf(
"OpenGL-> Version reported: ");
994 m_version = wxString(version_string, wxConvUTF8);
998 char GLSL_version_string[80];
999 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1001 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1002 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1003 msg += m_GLSLversion;
1008 GLenum err = glewInit();
1009#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1010 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1015 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1018 wxLogMessage(
"GLEW init success!n");
1023 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1024 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1028#ifndef USE_ANDROID_GLES2
1029 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1031 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1033 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1034 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1041 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1043 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1045 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1048 s_b_useScissorTest =
true;
1050 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1051 s_b_useScissorTest =
false;
1053 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1054 s_b_useScissorTest =
false;
1056 bool bad_stencil_code =
false;
1059 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1060 bad_stencil_code =
true;
1063 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1066 glEnable(GL_STENCIL_TEST);
1067 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1069 glGetIntegerv(GL_STENCIL_BITS, &sb);
1072 glDisable(GL_STENCIL_TEST);
1074 s_b_useStencil =
false;
1075 if (stencil && (sb == 8)) s_b_useStencil =
true;
1077 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1078 g_texture_rectangle_format = GL_TEXTURE_2D;
1079 else if (QueryExtension(
"GL_OES_texture_npot"))
1080 g_texture_rectangle_format = GL_TEXTURE_2D;
1081 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1082 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1083 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1084 g_texture_rectangle_format));
1087 g_texture_rectangle_format = GL_TEXTURE_2D;
1091 g_b_EnableVBO =
true;
1094 g_b_EnableVBO =
false;
1098 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1100 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1104 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1106 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1109#ifndef USE_ANDROID_GLES2
1111 if (bad_stencil_code) s_b_useStencil =
false;
1125 if (m_displayScale > 1) m_b_DisableFBO =
true;
1134 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1136 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1137 g_texture_rectangle_format, m_cache_tex[0], 0);
1139 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1140 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1142 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1144 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1146 m_b_DisableFBO =
true;
1152 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1156 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1158#ifdef USE_ANDROID_GLES2
1159 s_b_useStencilAP = s_b_useStencil;
1166 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1168 if (m_b_useFBOStencil)
1169 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1171 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1173 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1176 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1178 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1180 if (s_b_useScissorTest && s_b_useStencil)
1181 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1184 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1186 MipMap_ResolveRoutines();
1190 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1191 g_GLMinCartographicLineWidth);
1192 wxLogMessage(lwmsg);
1193 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1194 g_GLMinSymbolLineWidth);
1195 wxLogMessage(lwmsg);
1198 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1200#ifdef USE_ANDROID_GLES2
1201 g_GLOptions.m_bUseAcceleratedPanning =
true;
1207 int tex_dim = g_GLOptions.m_iTextureDimension;
1208 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1217 s_b_useFBO = m_b_BuiltFBO;
1221 ps52plib->SetGLOptions(
1222 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1223 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1224 g_GLMinSymbolLineWidth);
1228 SendJSONConfigMessage();
1231void glChartCanvas::SendJSONConfigMessage() {
1234 v[
"setupComplete"] = m_bsetup;
1235 v[
"useStencil"] = s_b_useStencil;
1236 v[
"useStencilAP"] = s_b_useStencilAP;
1237 v[
"useScissorTest"] = s_b_useScissorTest;
1238 v[
"useFBO"] = s_b_useFBO;
1239 v[
"useVBO"] = g_b_EnableVBO;
1240 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1241 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1242 SendJSONMessageToAllPlugins(msg_id, v);
1245void glChartCanvas::SetupCompression() {
1246 int dim = g_GLOptions.m_iTextureDimension;
1249 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1250 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1251 goto no_compression;
1255 g_uncompressed_tile_size = dim * dim * 4;
1256 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1262 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1265 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1275 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1276 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1279 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1280 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1285 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1286 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1289 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1291 wxLogMessage(
"OpenGL-> No Useable compression format found");
1292 goto no_compression;
1297 g_tile_size = 512 * 512 / 2;
1301 glGenTextures(1, &texture);
1302 glBindTexture(GL_TEXTURE_2D, texture);
1304 GL_UNSIGNED_BYTE, NULL);
1305 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1307 glDeleteTextures(1, &texture);
1311 if (g_tile_size == 0)
goto no_compression;
1313 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1315 g_uncompressed_tile_size / g_tile_size));
1319 g_GLOptions.m_bTextureCompression =
false;
1321 g_tile_size = g_uncompressed_tile_size;
1322 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1325void glChartCanvas::OnPaint(wxPaintEvent &event) {
1327 if (!m_pcontext)
return;
1336 if (IsShown()) SetCurrent(*m_pcontext);
1341 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1349 if (!m_b_paint_enable)
return;
1352 if (m_in_glpaint)
return;
1355 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1378bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1380#ifndef USE_ANDROID_GLES2
1381 return vp.m_projection_type == PROJECTION_MERCATOR ||
1382 vp.m_projection_type == PROJECTION_POLAR ||
1383 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1397#define NORM_FACTOR 4096.0
1398void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1399#ifndef USE_ANDROID_GLES2
1401 wxPoint2DDouble point;
1403 switch (vp.m_projection_type) {
1404 case PROJECTION_MERCATOR:
1405 case PROJECTION_EQUIRECTANGULAR:
1406 case PROJECTION_WEB_MERCATOR:
1409 glTranslated(point.m_x, point.m_y, 0);
1414 case PROJECTION_POLAR:
1418 glTranslated(point.m_x, point.m_y, 0);
1419 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1426 printf(
"ERROR: Unhandled projection\n");
1431 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1439 switch (vp.m_projection_type) {
1440 case PROJECTION_MERCATOR:
1441 case PROJECTION_EQUIRECTANGULAR:
1442 case PROJECTION_WEB_MERCATOR:
1446 case PROJECTION_POLAR:
1451 printf(
"ERROR: Unhandled projection\n");
1460bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1461 return vp.m_projection_type == PROJECTION_MERCATOR ||
1462 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1463 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1467 const LLRegion ®ion) {
1468 if (!CanClipViewport(vp))
return vp;
1471 LLBBox bbox = region.GetBox();
1473 if (!bbox.GetValid())
return vp;
1481 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1482 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1483 bbox.GetMaxLon() + 360);
1484 cvp.SetBBoxDirect(bbox);
1485 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1486 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1487 bbox.GetMaxLon() - 360);
1488 cvp.SetBBoxDirect(bbox);
1490 cvp.SetBBoxDirect(bbox);
1495void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1496 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1502 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1504 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1508 if (!pRouteDraw)
continue;
1511 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1514 if (pRouteDraw->m_bIsBeingEdited)
continue;
1516 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1521 if (vp.GetBBox().GetValid() && pWayPointMan) {
1522 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1523 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1524 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1530void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1535 if (pActiveTrack && pActiveTrack->IsRunning())
1536 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1542 if (!pRouteDraw)
continue;
1545 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1548 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1551 if (pRouteDraw->IsSelected()) drawit++;
1554 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1555 if (!vp_box.IntersectOut(test_box))
1556 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1562 if (vp.GetBBox().GetValid() && pWayPointMan) {
1563 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
1564 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1571static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1575 switch (vp.m_projection_type) {
1576 case PROJECTION_TRANSVERSE_MERCATOR:
1577 lat_dist = 4, lon_dist = 1;
1579 case PROJECTION_POLYCONIC:
1580 lat_dist = 2, lon_dist = 1;
1582 case PROJECTION_ORTHOGRAPHIC:
1583 lat_dist = 2, lon_dist = 2;
1585 case PROJECTION_POLAR:
1586 lat_dist = 180, lon_dist = 1;
1588 case PROJECTION_STEREOGRAPHIC:
1589 case PROJECTION_GNOMONIC:
1590 lat_dist = 2, lon_dist = 1;
1592 case PROJECTION_EQUIRECTANGULAR:
1595 lat_dist = 2, lon_dist = 360;
1598 lat_dist = 180, lon_dist = 360;
1602void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1603 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1609 ChartData->GetDBBoundingBox(dbIndex, box);
1610 if (!box.GetValid())
return;
1614 if (box.GetLonRange() == 360)
return;
1616 LLBBox vpbox = vp.GetBBox();
1618 double lon_bias = 0;
1620 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1623 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1624 color = GetGlobalColor(
"YELO1");
1625 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1626 color = GetGlobalColor(
"GREEN2");
1628 color = GetGlobalColor(
"UINFR");
1630#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1631 float plylat, plylon;
1633 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1635 glColor3ub(color.Red(), color.Green(), color.Blue());
1636 glLineWidth(g_GLMinSymbolLineWidth);
1638 float lat_dist, lon_dist;
1639 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1642 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1646 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1648 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1650 bool begin =
false, sml_valid =
false;
1652 float lastplylat = 0.0;
1653 float lastplylon = 0.0;
1655 int modulo = (nPly == 0) ? 1 : nPly;
1656 for (
int i = 0; i < nPly + 1; i++) {
1658 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1660 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1664 if (lastplylon - plylon > 180)
1666 else if (lastplylon - plylon < -180)
1673 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1674 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1675 splits = wxMax(lat_splits, lon_splits) + 1;
1682 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1683 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1686 for (
double c = 0; c < splits; c++) {
1688 if (c == splits - 1)
1689 lat = plylat, lon = plylon;
1691 double d = (double)(c + 1) / splits;
1692 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1698 if (!std::isnan(s.m_x)) {
1701 glBegin(GL_LINE_STRIP);
1703 glVertex2f(s.m_x, s.m_y);
1709 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1710 lastplylat = plylat, lastplylon = plylon;
1715 }
while (++j < nAuxPlyEntries);
1717 glDisable(GL_LINE_SMOOTH);
1721 double nominal_line_width_pix =
1722 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1724 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1725 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1728 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1729 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1733 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1736 float plylat1, plylon1;
1740 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1741 if (0 == nAuxPlyEntries)
1744 std::vector<int> points_vector;
1746 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1747 int nPly = vec.size() / 2;
1749 if (nPly == 0)
return;
1751 for (
int i = 0; i < nPly; i++) {
1752 plylon1 = vec[i * 2];
1753 plylat1 = vec[i * 2 + 1];
1759 points_vector.push_back(pixx1);
1760 points_vector.push_back(pixy1);
1763 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1764 plylon1 += lon_bias;
1770 points_vector.push_back(pixx1);
1771 points_vector.push_back(pixy1);
1773 if (points_vector.size()) {
1774 std::vector<int>::iterator it = points_vector.begin();
1775 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1783 for (
int j = 0; j < nAuxPlyEntries; j++) {
1784 std::vector<int> points_vector;
1786 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1787 int nAuxPly = vec.size() / 2;
1789 if (nAuxPly == 0)
continue;
1791 for (
int i = 0; i < nAuxPly; i++) {
1792 plylon1 = vec[i * 2];
1793 plylat1 = vec[i * 2 + 1];
1799 points_vector.push_back(pixx1);
1800 points_vector.push_back(pixy1);
1807 points_vector.push_back(pixx1);
1808 points_vector.push_back(pixy1);
1810 if (points_vector.size()) {
1811 std::vector<int>::iterator it = points_vector.begin();
1812 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1820extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1821 float &MinorSpacing);
1822extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1823void glChartCanvas::GridDraw() {
1824 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1826 ViewPort &vp = m_pParentCanvas->GetVP();
1828 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1832 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1834 double nlat, elon, slat, wlon;
1836 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1839 wxColour GridColor = GetGlobalColor(
"SNDG1");
1841 if (!m_gridfont.IsBuilt()) {
1843 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1844 wxFont font = *dFont;
1847 int font_size = wxMax(10, dFont->GetPointSize());
1848 font.SetPointSize(font_size);
1849 font.SetWeight(wxFONTWEIGHT_NORMAL);
1852 m_gridfont.Build(font, m_displayScale, dpi_factor);
1854 m_gridfont.SetColor(GridColor);
1859 LLBBox llbbox = vp.GetBBox();
1860 nlat = llbbox.GetMaxLat();
1861 slat = llbbox.GetMinLat();
1862 elon = llbbox.GetMaxLon();
1863 wlon = llbbox.GetMinLon();
1870 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1871 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1872 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1873 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1874 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1875 vp.m_projection_type == PROJECTION_POLAR ||
1876 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1879 if (straight_latitudes)
1882 latmargin = gridlatMajor / 2;
1884 slat = wxMax(slat, -90 + latmargin);
1885 nlat = wxMin(nlat, 90 - latmargin);
1887 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1888 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1892 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1899 float lon_step = elon - wlon;
1900 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1902 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1904 s.x = INVALID_COORD;
1905 s.y = INVALID_COORD;
1906 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1908 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1909 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1917 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1918 lat += gridlatMinor) {
1921 gldc.DrawLine(0, r.y, 10, r.y,
true);
1922 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1927 float lat_step = nlat - slat;
1928 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1930 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1932 s.x = INVALID_COORD;
1933 s.y = INVALID_COORD;
1934 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1936 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1937 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1945 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1946 lon += gridlonMinor) {
1949 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1950 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1956 glEnable(GL_TEXTURE_2D);
1958 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1959 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1962 CalcGridText(lat, gridlatMajor,
true);
1964 m_gridfont.GetTextExtent(st, 0, &iy);
1966 if (straight_latitudes) {
1971 float x = 0, y = -1;
1972 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1973 if (y < 0 || y > h) {
1975 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
1978 m_gridfont.RenderString(st, x, y);
1982 double y1, y2, lat1, lon1, lat2, lon2;
1991 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
1994 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
1996 if (fabs(y - y1) < fabs(y - y2))
2002 error = fabs(r.m_x);
2003 if (--maxiters == 0)
break;
2004 }
while (error > 1 && error < lasterror);
2006 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2012 m_gridfont.RenderString(st, r.m_x, r.m_y);
2016 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2017 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2026 else if (xlon <= -180.0)
2029 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2031 m_gridfont.GetTextExtent(st, &ix, 0);
2033 if (straight_longitudes) {
2034 float x = -1, y = 0;
2035 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2036 if (x < 0 || x > w) {
2038 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2041 m_gridfont.RenderString(st, x, y);
2045 double x1, x2, lat1, lon1, lat2, lon2;
2053 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2056 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2058 if (fabs(x - x1) < fabs(x - x2))
2064 error = fabs(r.m_y);
2065 }
while (error > 1 && error < lasterror);
2067 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2072 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2074 m_gridfont.RenderString(st, r.m_x, r.m_y);
2078 glDisable(GL_TEXTURE_2D);
2079 glDisable(GL_BLEND);
2084 if (!emboss)
return;
2086 int w = emboss->width, h = emboss->height;
2088 glEnable(GL_TEXTURE_2D);
2091 if (!emboss->gltexind) {
2093 emboss->glwidth = NextPow2(emboss->width);
2094 emboss->glheight = NextPow2(emboss->height);
2097 int size = emboss->glwidth * emboss->glheight;
2098 char *data =
new char[2 * size];
2099 for (
int i = 0; i < h; i++) {
2100 for (
int j = 0; j < emboss->glwidth; j++) {
2102 data[2 * ((i * emboss->glwidth) + j)] =
2103 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2104 data[2 * ((i * emboss->glwidth) + j) + 1] =
2105 (char)abs((emboss->pmap[(i * w) + j]));
2110 glGenTextures(1, &emboss->gltexind);
2111 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2112 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2113 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2121 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2125 int x = emboss->x, y = emboss->y;
2127 float wp = (float)w / emboss->glwidth;
2128 float hp = (float)h / emboss->glheight;
2154 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2156 glDisable(GL_BLEND);
2157 glDisable(GL_TEXTURE_2D);
2160void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2161 if (!m_pParentCanvas->GetVP().IsValid())
return;
2162 wxPoint GPSOffsetPixels(0, 0);
2163 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2166 float pCog = std::isnan(
gCog) ? 0 :
gCog;
2167 float pSog = std::isnan(
gSog) ? 0 :
gSog;
2171 double shift_dx = 0;
2172 double shift_dy = 0;
2173 bool dynamic = m_pParentCanvas->m_animationActive ||
2174 m_pParentCanvas->m_MouseDragging ||
2175 m_pParentCanvas->m_chart_drag_inertia_active;
2176 if (m_pParentCanvas->m_bFollow && !dynamic) {
2177 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2178 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2179 if (m_pParentCanvas->m_bLookAhead) {
2185 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2186 angle += m_pParentCanvas->GetVPRotation();
2187 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2189 lGPSPoint.m_x -= shift_dx / cos(
gLat * PI / 180.);
2190 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2192 lGPSPoint.m_y += shift_dy / cos(
gLat * PI / 180.);
2197 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2198 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2205 lShipMidPoint = lGPSPoint;
2209 float icon_hdt = pCog;
2210 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
2213 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2217 double osd_head_lat, osd_head_lon;
2218 wxPoint2DDouble osd_head_point;
2220 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2224 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2226 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2227 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2228 icon_rad += (float)PI;
2232 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2236 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2242 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2243 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2244 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2249 float scale_factor = 1.0;
2254 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2255 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2256 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2258 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2260 float nominal_ownship_size_pixels =
2262 nominal_ownship_size_mm);
2264 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2266 wxPen ppSmallScaleShip;
2267 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2269 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2272 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2273 dc.SetPen(ppSmallScaleShip);
2275 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2278 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2279 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2280 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2281 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2284 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2285 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2288 int draw_color = SHIP_INVALID;
2289 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2290 draw_color = SHIP_NORMAL;
2291 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2292 draw_color = SHIP_LOWACCURACY;
2300 ownship_color = draw_color;
2302 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2304 glGenTextures(1, &ownship_tex);
2305 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2307 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2308 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2311 if (m_pParentCanvas->m_pos_image_user) {
2312 switch (draw_color) {
2314 image = *m_pParentCanvas->m_pos_image_user_grey;
2317 image = *m_pParentCanvas->m_pos_image_user;
2319 case SHIP_LOWACCURACY:
2320 image = *m_pParentCanvas->m_pos_image_user_yellow;
2324 switch (draw_color) {
2326 image = *m_pParentCanvas->m_pos_image_grey;
2329 image = *m_pParentCanvas->m_pos_image_red;
2331 case SHIP_LOWACCURACY:
2332 image = *m_pParentCanvas->m_pos_image_yellow;
2337 int w = image.GetWidth(), h = image.GetHeight();
2338 int glw = NextPow2(w), glh = NextPow2(h);
2339 ownship_size = wxSize(w, h);
2340 ownship_tex_size = wxSize(glw, glh);
2342 unsigned char *d = image.GetData();
2343 unsigned char *a = image.GetAlpha();
2344 unsigned char *e =
new unsigned char[4 * w * h];
2347 for (
int p = 0; p < w * h; p++) {
2348 e[4 * p + 0] = d[3 * p + 0];
2349 e[4 * p + 1] = d[3 * p + 1];
2350 e[4 * p + 2] = d[3 * p + 2];
2351 e[4 * p + 3] = a[p];
2354 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2355 GL_UNSIGNED_BYTE, 0);
2357 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2363#ifndef USE_ANDROID_GLES2
2364 if (m_pParentCanvas->m_pos_image_user)
2365 glColor4ub(255, 255, 255, 255);
2366 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2367 glColor4ub(255, 0, 0, 255);
2368 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2369 glColor4ub(255, 255, 0, 255);
2371 glColor4ub(128, 128, 128, 255);
2373 float scale_factor_y = 1.0;
2374 float scale_factor_x = 1.0;
2376 int ownShipWidth = 22;
2377 int ownShipLength = 84;
2378 lShipMidPoint = lGPSPoint;
2381 if (g_OwnShipIconType != 0)
2382 m_pParentCanvas->ComputeShipScaleFactor(
2383 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2384 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2389 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2390 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2391 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2395 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2396 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2400 float gps_circle_radius = 3.0;
2402 if (g_OwnShipIconType == 0) {
2404 glEnable(GL_TEXTURE_2D);
2405 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2414 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2415 if (m_pParentCanvas->m_pos_image_user)
2416 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2418 float nominal_ownship_size_mm =
2419 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2421 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2422 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2424 float nominal_ownship_size_pixels =
2425 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2427 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2428 nominal_ownship_size_pixels = wxMax(
2429 20.0, nominal_ownship_size_pixels);
2432 float h = nominal_ownship_size_pixels * scale_factor_y;
2433 float w = nominal_ownship_size_pixels * scale_factor_x *
2434 ownship_size.x / ownship_size.y;
2435 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2436 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2442 gps_circle_radius = w / 5;
2444 float uv[8], coords[8];
2463 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2464 lShipMidPoint.m_x, lShipMidPoint.m_y,
2466 glDisable(GL_TEXTURE_2D);
2467 }
else if (g_OwnShipIconType == 1) {
2469 glEnable(GL_TEXTURE_2D);
2470 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2472 float nominal_ownship_size_pixels_y = 84;
2473 float nominal_ownship_size_pixels_x = 22;
2475 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2476 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2478 float u = (float)ownship_size.x / ownship_tex_size.x,
2479 v = (
float)ownship_size.y / ownship_tex_size.y;
2482 gps_circle_radius = w / 5;
2484 float uv[8], coords[8];
2503 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2504 lShipMidPoint.m_x, lShipMidPoint.m_y,
2507 glDisable(GL_TEXTURE_2D);
2508 }
else if (g_OwnShipIconType == 2) {
2516 wxPoint shipPoints[6];
2518 wxColour colour = m_pParentCanvas->ShipColor();
2519 wxPen ppPen(*wxBLACK, 1);
2520 wxBrush ppBrush(colour);
2522 dc.SetBrush(ppBrush);
2524 shipPoints[0].x = 0 * scale_factor_x;
2525 shipPoints[0].y = -28 * scale_factor_y;
2526 shipPoints[1].x = 11 * scale_factor_x;
2527 shipPoints[1].y = -28 * scale_factor_y;
2528 shipPoints[2].x = 11 * scale_factor_x;
2529 shipPoints[2].y = 42 * scale_factor_y;
2530 shipPoints[3].x = 0 * scale_factor_x;
2531 shipPoints[3].y = 42 * scale_factor_y;
2532 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2535 shipPoints[0].x = 0 * scale_factor_x;
2536 shipPoints[0].y = -42 * scale_factor_y;
2537 shipPoints[1].x = 5 * scale_factor_x;
2538 shipPoints[1].y = -42 * scale_factor_y;
2539 shipPoints[2].x = 11 * scale_factor_x;
2540 shipPoints[2].y = -28 * scale_factor_y;
2541 shipPoints[3].x = 0 * scale_factor_x;
2542 shipPoints[3].y = -28 * scale_factor_y;
2543 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2546 shipPoints[0].x = 0 * scale_factor_x;
2547 shipPoints[0].y = -28 * scale_factor_y;
2548 shipPoints[1].x = -11 * scale_factor_x;
2549 shipPoints[1].y = -28 * scale_factor_y;
2550 shipPoints[2].x = -11 * scale_factor_x;
2551 shipPoints[2].y = 42 * scale_factor_y;
2552 shipPoints[3].x = 0 * scale_factor_x;
2553 shipPoints[3].y = 42 * scale_factor_y;
2554 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2557 shipPoints[0].x = 0 * scale_factor_x;
2558 shipPoints[0].y = -42 * scale_factor_y;
2559 shipPoints[1].x = -5 * scale_factor_x;
2560 shipPoints[1].y = -42 * scale_factor_y;
2561 shipPoints[2].x = -11 * scale_factor_x;
2562 shipPoints[2].y = -28 * scale_factor_y;
2563 shipPoints[3].x = 0 * scale_factor_x;
2564 shipPoints[3].y = -28 * scale_factor_y;
2565 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2569 double p1x = -11 * scale_factor_x;
2570 double p2x = 11 * scale_factor_x;
2574 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2576 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2578 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2580 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2581 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2582 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2586 p1y = -42 * scale_factor_y;
2587 p2y = 42 * scale_factor_y;
2588 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2589 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2590 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2591 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2592 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2593 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2596 img_height = ownShipLength * scale_factor_y;
2599 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2601 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2603 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2605 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2609 glDisable(GL_LINE_SMOOTH);
2610 glDisable(GL_POLYGON_SMOOTH);
2611 glDisable(GL_BLEND);
2614 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2618void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2619 ViewPort &vp = m_pParentCanvas->GetVP();
2642 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2644 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2645 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2647 m_pParentCanvas->AlertDraw(dc);
2649 m_pParentCanvas->RenderVisibleSectorLights(dc);
2651 m_pParentCanvas->RenderRouteLegs(dc);
2652 m_pParentCanvas->RenderShipToActive(dc,
true);
2653 m_pParentCanvas->ScaleBarDraw(dc);
2654 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2655 m_pParentCanvas->extendedSectorLegs);
2662void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2663 if (m_pParentCanvas->GetPiano()) {
2664 int canvas_height = GetClientSize().y;
2665 canvas_height *= m_displayScale;
2667 m_pParentCanvas->GetPiano()->DrawGL(
2668 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2672void glChartCanvas::DrawQuiting() {
2673#ifndef USE_ANDROID_GLES2
2674 GLubyte pattern[8][8];
2675 for (
int y = 0; y < 8; y++)
2676 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2679 glEnable(GL_TEXTURE_2D);
2680 glBindTexture(GL_TEXTURE_2D, 0);
2682 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2686 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2690 float x = GetSize().x, y = GetSize().y;
2691 float u = x / 8, v = y / 8;
2704 glDisable(GL_TEXTURE_2D);
2705 glDisable(GL_BLEND);
2709void glChartCanvas::DrawCloseMessage(wxString msg) {
2710#ifndef USE_ANDROID_GLES2
2714 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2718 texfont.Build(*pfont, 1, 1);
2720 texfont.GetTextExtent(msg, &w, &h);
2722 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2723 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2725 glColor3ub(243, 229, 47);
2729 glVertex2i(xp + w, yp);
2730 glVertex2i(xp + w, yp + h);
2731 glVertex2i(xp, yp + h);
2736 glColor3ub(0, 0, 0);
2737 glEnable(GL_TEXTURE_2D);
2738 texfont.RenderString(msg, xp, yp);
2739 glDisable(GL_TEXTURE_2D);
2740 glDisable(GL_BLEND);
2747static std::list<double *> combine_work_data;
2748static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2749 GLfloat weight[4], GLdouble **dataOut) {
2750 double *vertex =
new double[3];
2751 combine_work_data.push_back(vertex);
2752 memcpy(vertex, coords, 3 * (
sizeof *coords));
2756#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2757void vertexCallbackD_GLSL(GLvoid *vertex) {
2759 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2760 int new_buf_len = s_tess_buf_len + 100;
2761 GLfloat *tmp = s_tess_work_buf;
2764 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2765 if (NULL == s_tess_work_buf) {
2769 s_tess_buf_len = new_buf_len;
2772 GLdouble *pointer = (GLdouble *)vertex;
2774 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2775 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2780void beginCallbackD_GLSL(GLenum mode) {
2781 s_tess_vertex_idx_this = s_tess_vertex_idx;
2786void endCallbackD_GLSL() {
2790 shader->SetUniformMatrix4fv(
"MVMatrix",
2791 (GLfloat *)s_tessVP.vp_matrix_transform);
2793 mat4x4 identityMatrix;
2794 mat4x4_identity(identityMatrix);
2795 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2799 colorv[0] = s_regionColor.Red() / float(256);
2800 colorv[1] = s_regionColor.Green() / float(256);
2801 colorv[2] = s_regionColor.Blue() / float(256);
2802 colorv[3] = s_regionColor.Alpha() / float(256);
2803 shader->SetUniform4fv(
"color", colorv);
2805 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2806 shader->SetAttributePointerf(
"position", bufPt);
2808 glDrawArrays(s_tess_mode, 0, s_nvertex);
2813void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2815void beginCallbackD(GLenum mode) { glBegin(mode); }
2817void endCallbackD() { glEnd(); }
2821void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2822 float lat_dist, lon_dist;
2823 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2825 GLUtesselator *tobj = gluNewTess();
2826 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2828#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2829 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2830 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2831 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2832 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2836 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2837 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2838 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2839 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2842 gluTessNormal(tobj, 0, 0, 1);
2844 gluTessBeginPolygon(tobj, NULL);
2845 for (
auto i = region.contours.begin(); i != region.contours.end(); i++) {
2846 gluTessBeginContour(tobj);
2847 contour_pt l = *i->rbegin();
2849 bool sml_valid =
false;
2850 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2851 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2852 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2853 int splits = wxMax(lat_splits, lon_splits) + 1;
2859 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2860 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2863 for (
int i = 0; i < splits; i++) {
2865 if (i == splits - 1)
2866 lat = j->y, lon = j->x;
2868 double d = (double)(i + 1) / splits;
2869 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2873 if (std::isnan(q.m_x))
continue;
2875 double *p =
new double[6];
2880 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2885 gluTessVertex(tobj, p, p);
2886 combine_work_data.push_back(p);
2890 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2892 gluTessEndContour(tobj);
2894 gluTessEndPolygon(tobj);
2896 gluDeleteTess(tobj);
2898 for (std::list<double *>::iterator i = combine_work_data.begin();
2899 i != combine_work_data.end(); i++)
2901 combine_work_data.clear();
2906void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2907 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2909 if (s_b_useStencil) {
2911 glEnable(GL_STENCIL_TEST);
2913 glClear(GL_STENCIL_BUFFER_BIT);
2917 glStencilFunc(GL_ALWAYS, 1, 1);
2918 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2921#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2925 glEnable(GL_DEPTH_TEST);
2926 glDepthFunc(GL_ALWAYS);
2927 glDepthMask(GL_TRUE);
2929 glClear(GL_DEPTH_BUFFER_BIT);
2942 glTranslatef(0, 0, .5);
2946 s_regionColor = wxColor(0, 0, 0, 255);
2947 DrawRegion(vp, region);
2949 if (s_b_useStencil) {
2952 glStencilFunc(GL_EQUAL, 1, 1);
2953 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2956#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2958 glDepthFunc(GL_GREATER);
2959 glDepthMask(GL_FALSE);
2960 glTranslatef(0, 0, -.5);
2963 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2966void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2970 if (s_b_useStencil && s_b_useScissorTest) {
2972 if (rect != vp_rect) {
2973 glEnable(GL_SCISSOR_TEST);
2974 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
2977#ifndef USE_ANDROID_GLES2
2983void glChartCanvas::DisableClipRegion() {
2984 glDisable(GL_SCISSOR_TEST);
2985 glDisable(GL_STENCIL_TEST);
2986 glDisable(GL_DEPTH_TEST);
2989void glChartCanvas::Invalidate() {
2991 m_cache_vp.Invalidate();
2997 if (!pBSBChart)
return;
3003 wxString key = chart->GetHashKey();
3007 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3010 if (ittf == hash.end()) {
3012 hash[key]->SetHashKey(key);
3015 pTexFact = hash[key];
3016 pTexFact->SetLRUTime(++m_LRUtime);
3021 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3022 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3029 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3030 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3031 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3032 base_level = log(scalefactor) / log(2.0);
3041 glEnable(GL_TEXTURE_2D);
3042#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3043 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3045 glEnableClientState(GL_VERTEX_ARRAY);
3046 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3051 pTexFact->GetCenter(lat, lon);
3052 MultMatrixViewPort(vp, lat, lon);
3056 LLBBox box = region.GetBox();
3059 if (g_memCacheLimit > 0) {
3064 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3065 for (
int i = 0; i < numtiles; i++) {
3067 if (region.IntersectOut(tile->box)) {
3070 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3071 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3073 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3074 global_color_scheme, mem_used);
3078 coords = tile->m_coords;
3080 coords =
new float[2 * tile->m_ncoords];
3081 for (
int i = 0; i < tile->m_ncoords; i++) {
3083 tile->m_coords[2 * i + 1]);
3084 coords[2 * i + 0] = p.m_x;
3085 coords[2 * i + 1] = p.m_y;
3089#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3090 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3091 m_pParentCanvas->GetpVP());
3094 glDisable(GL_TEXTURE_2D);
3098 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3099 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3100 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3102 if (!texture) glEnable(GL_TEXTURE_2D);
3104 if (!use_norm_vp)
delete[] coords;
3108 glDisable(GL_TEXTURE_2D);
3110#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3111 if (use_norm_vp) glPopMatrix();
3113 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3114 glDisableClientState(GL_VERTEX_ARRAY);
3118void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3120 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3121 m_pParentCanvas->m_pQuilt->IsBusy())
3125 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3127 printf(
" Chart NULL\n");
3128 chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3138 LLRegion region = vp.GetLLRegion(rect_region);
3140 LLRegion rendered_region;
3146 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3154 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3156 LLRegion get_region = pqp->ActiveRegion;
3157 bool b_rendered =
false;
3159 if (!pqp->b_overlay) {
3160 get_region.Intersect(region);
3161 if (!get_region.Empty()) {
3162 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3165 SetClipRegion(vp, get_region );
3166 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3167 DisableClipRegion();
3170 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3171 SetClipRegion(vp, pqp->ActiveRegion );
3172 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3174 DisableClipRegion();
3177 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3178 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3179 RenderNoDTA(vp, get_region);
3180 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3185 if (Chs57->m_RAZBuilt) {
3186 RenderNoDTA(vp, get_region);
3187 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3188 rect_region, get_region);
3189 DisableClipRegion();
3194 const LLRegion &oregion = get_region;
3195 LLBBox box = oregion.GetBox();
3206 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3209 ViewPort cvp = ClippedViewport(vp, get_region);
3210 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3211 SetClipRegion(cvp, get_region);
3212 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3213 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3214 RenderWorldChart(gldc, cvp, srect, world);
3215 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3216 global_color_scheme);
3217 DisableClipRegion();
3224 SetClipRegion(vp, get_region);
3225 RenderNoDTA(vp, get_region);
3226 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3228 DisableClipRegion();
3231 SetClipRegion(vp, get_region);
3232 RenderNoDTA(vp, get_region);
3233 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3235 DisableClipRegion();
3251 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3255 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3256 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3258 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3259 if (pqp->b_Valid && pqp->b_overlay &&
3260 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3261 LLRegion get_region = pqp->ActiveRegion;
3263 get_region.Intersect(region);
3264 if (!get_region.Empty()) {
3267 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3272 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3279 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3284 ViewPort vph = m_pParentCanvas->GetVP();
3285 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3288 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3290 if (!hiregion.Empty()) {
3294 switch (global_color_scheme) {
3295 case GLOBAL_COLOR_SCHEME_DAY:
3298 case GLOBAL_COLOR_SCHEME_DUSK:
3301 case GLOBAL_COLOR_SCHEME_NIGHT:
3309#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3311 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3313 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3316 DrawRegion(vp, hiregion);
3318 glDisable(GL_BLEND);
3323 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3325 if (!hiregion.Empty()) {
3329 switch (global_color_scheme) {
3330 case GLOBAL_COLOR_SCHEME_DAY:
3333 case GLOBAL_COLOR_SCHEME_DUSK:
3336 case GLOBAL_COLOR_SCHEME_NIGHT:
3345#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3347 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3349 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3352 DrawRegion(vp, hiregion);
3354 glDisable(GL_BLEND);
3358 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3361void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3363 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3364 m_pParentCanvas->m_pQuilt->IsBusy())
3368 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3370 LLRegion region = vp.GetLLRegion(rect_region);
3372 LLRegion rendered_region;
3374 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3376 LLRegion get_region = pqp->ActiveRegion;
3378 if (!pqp->b_overlay) {
3379 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3382 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3387 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3394 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3422void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3423 ViewPort &vp = m_pParentCanvas->VPoint;
3431 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3432 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3435 LLRegion chart_region;
3437 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3438 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3439 CHART_FAMILY_RASTER) {
3447 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3448 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3449 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3451 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3455 for (
int i = 1; i < 6; i += 2)
3456 if (fabs(ll[i] - ll[i + 2]) > 180) {
3458 for (
int i = 1; i < 8; i += 2)
3459 if (ll[i] < 0) ll[i] += 360;
3463 chart_region = LLRegion(4, ll);
3466 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3468 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3469 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3470 chart_region = LLRegion(4, ll);
3473 chart_region = vp.b_quilt
3474 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3475 : m_pParentCanvas->m_singleChart->GetValidRegion();
3477 bool world_view =
false;
3479 wxRect rect = upd.GetRect();
3480 LLRegion background_region = vp.GetLLRegion(rect);
3483 background_region.Subtract(chart_region);
3485 if (!background_region.Empty()) {
3486 ViewPort cvp = ClippedViewport(vp, background_region);
3487 SetClipRect(cvp, rect,
false);
3488 RenderWorldChart(dc, cvp, rect, world_view);
3489 DisableClipRegion();
3494 RenderQuiltViewGL(vp, rect_region);
3497 LLRegion region = vp.GetLLRegion(rect_region);
3498 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3499 CHART_FAMILY_RASTER) {
3500 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3501 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3502 *m_pcontext, vp, rect_region, region);
3504 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3505 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3506 CHART_FAMILY_VECTOR) {
3507 chart_region.Intersect(region);
3508 RenderNoDTA(vp, chart_region);
3509 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3510 rect_region, region);
3516void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3518 wxColour color = GetGlobalColor(
"NODTA");
3519#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3521 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3523 glColor4ub(163, 180, 183, transparency);
3526 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3530 s_regionColor = color;
3533 DrawRegion(vp, region);
3537void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3540 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3542 glEnable(GL_SCISSOR_TEST);
3543 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3549 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3550#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3552 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3556 colorv[0] = water.Red() / float(256);
3557 colorv[1] = water.Green() / float(256);
3558 colorv[2] = water.Blue() / float(256);
3560 shader->SetUniform4fv(
"color", colorv);
3571 shader->SetAttributePointerf(
"position", pf);
3573 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3585 glDisable(GL_SCISSOR_TEST);
3593void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3594 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3596 DrawStaticRoutesTracksAndWaypoints(vp);
3598 DisableClipRegion();
3601void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3603 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3607 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3608 if (!bmp.Ok())
return;
3610 wxImage image = bmp.ConvertToImage();
3611 int w = image.GetWidth(), h = image.GetHeight();
3614 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3615 tex_w = w, tex_h = h;
3617 tex_w = NextPow2(w), tex_h = NextPow2(h);
3619 m_tideTexWidth = tex_w;
3620 m_tideTexHeight = tex_h;
3622 unsigned char *d = image.GetData();
3623 unsigned char *a = image.GetAlpha();
3625 unsigned char mr, mg, mb;
3626 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3628 unsigned char *e =
new unsigned char[4 * w * h];
3630 for (
int y = 0; y < h; y++)
3631 for (
int x = 0; x < w; x++) {
3632 unsigned char r, g, b;
3633 int off = (y * w + x);
3643 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3647 glGenTextures(1, &m_tideTex);
3649 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3650 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3651 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3653 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3654 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3655 GL_UNSIGNED_BYTE, e);
3657 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3658 GL_UNSIGNED_BYTE, 0);
3659 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3668 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3669 glEnable(GL_TEXTURE_2D);
3672#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3674 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
3678 if ((type ==
't') || (type ==
'T'))
3683 if (BBox.Contains(lat, lon)) {
3692 scale *= getAndroidDisplayDensity();
3694 double width2 =
scale * m_tideTexWidth / 2;
3695 double height2 =
scale * m_tideTexHeight / 2;
3710 coords[0] = xp - width2;
3711 coords[1] = yp - height2;
3712 coords[2] = xp - width2;
3713 coords[3] = yp + height2;
3714 coords[4] = xp + width2;
3715 coords[5] = yp + height2;
3716 coords[6] = xp + width2;
3717 coords[7] = yp - height2;
3719 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3726 glDisable(GL_TEXTURE_2D);
3727 glDisable(GL_BLEND);
3728 glBindTexture(GL_TEXTURE_2D, 0);
3730 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3733void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3734 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3737void glChartCanvas::SetColorScheme(ColorScheme cs) {
3738 if (!m_bsetup)
return;
3740 glDeleteTextures(1, &m_tideTex);
3741 glDeleteTextures(1, &m_currentTex);
3747void glChartCanvas::RenderGLAlertMessage() {
3748 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3749 wxString msg = m_pParentCanvas->GetAlertString();
3752 m_gldc.SetFont(*pfont);
3756 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3763 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3764 int xp = sbr.x + sbr.width + 5;
3766 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3767 m_gldc.SetPen(ppPen1);
3768 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3770 m_gldc.DrawRectangle(xp, yp, w, h);
3772 m_gldc.DrawText(msg, xp, yp);
3776unsigned long quiltHash;
3778extern wxLongLong s_t0;
3781void glChartCanvas::Render() {
3782 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3783 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3784 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3789 if (!g_PrintingInProgress)
return;
3792 if (!g_true_zoom && m_binPinch)
return;
3795 long render_start_time = m_glstopwatch.Time();
3797#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3798 loadShaders(GetCanvasIndex());
3799 configureShaders(m_pParentCanvas->VPoint);
3802#ifdef USE_ANDROID_GLES2
3806 if (m_binPinch)
return;
3815 bool recompose =
false;
3816 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3817 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3818 if (m_pParentCanvas->VPoint.IsValid()) {
3819 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3820 m_pParentCanvas->UpdateCanvasControlBar();
3829 if (sw.GetTime() > 2000) {
3835 s_tess_vertex_idx = 0;
3836 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3837 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3843 m_displayScale = GetContentScaleFactor();
3847 m_last_render_time = wxDateTime::Now().GetTicks();
3851 if (g_GLOptions.m_bTextureCompression &&
3852 !g_GLOptions.m_bTextureCompressionCaching)
3857 int gl_width, gl_height;
3858 gl_width = m_pParentCanvas->VPoint.
pix_width;
3859 gl_height = m_pParentCanvas->VPoint.
pix_height;
3862 m_glcanvas_width = gl_width;
3863 m_glcanvas_height = gl_height;
3869 ViewPort VPoint = m_pParentCanvas->VPoint;
3871 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3872 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3875#if !defined(USE_ANDROID_GLES2)
3876 glMatrixMode(GL_PROJECTION);
3879 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3880 glMatrixMode(GL_MODELVIEW);
3884 if (s_b_useStencil) {
3885 glEnable(GL_STENCIL_TEST);
3886 glStencilMask(0xff);
3887 glClear(GL_STENCIL_BUFFER_BIT);
3888 glDisable(GL_STENCIL_TEST);
3894 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3895 if (g_GLOptions.m_GLPolygonSmoothing)
3896 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3897 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3909 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3910 bool useFBO =
false;
3916 if (m_b_BuiltFBO && !bpost_hilite
3921 bool b_newview =
true;
3922 bool b_full =
false;
3930 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3934#ifdef USE_ANDROID_GLES2
3935 if (recompose) b_newview =
true;
3947 if (VPoint.b_quilt) {
3948 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3949 if (!chart) b_full =
true;
3958 bool accelerated_pan =
false;
3968 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
3969 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
3970 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
3972 wxPoint2DDouble c_old =
3975 wxPoint2DDouble c_new =
3979 dy = wxRound(c_new.m_y - c_old.m_y);
3980 dx = wxRound(c_new.m_x - c_old.m_x);
3990 double deltax = c_new.m_x - c_old.m_x;
3991 double deltay = c_new.m_y - c_old.m_y;
3993 bool b_whole_pixel =
true;
3994 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
3995 b_whole_pixel =
false;
3997 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
3998 abs(dy) < m_cache_tex_y &&
3999 (abs(dx) > 0 || (abs(dy) > 0));
4008 if (m_displayScale > 1) accelerated_pan =
false;
4013 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4016#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4019 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4025 if (b_full) accelerated_pan =
false;
4027 if (accelerated_pan) {
4028 if ((dx != 0) || (dy != 0)) {
4040 if (dy > 0 && dy < gl_height)
4041 update_region.Union(
4042 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4044 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4046 if (dx > 0 && dx < gl_width)
4047 update_region.Union(
4048 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4050 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4052 m_cache_page = !m_cache_page;
4055 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4056 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4068 RenderCharts(m_gldc, update_region);
4072 glDisable(g_texture_rectangle_format);
4077 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4078 glEnable(GL_TEXTURE_2D);
4082 float x1, x2, y1, y2;
4095 float tx1, tx2, ty1, ty2;
4101 tx2 = sx / (float)m_cache_tex_x;
4103 ty2 = sy / (float)m_cache_tex_y;
4120 coords[2] = -dx + sx;
4122 coords[4] = -dx + sx;
4123 coords[5] = dy + sy;
4125 coords[7] = dy + sy;
4128 ptexture_2D_shader_program[GetCanvasIndex()];
4132 shader->SetUniform1i(
"uTex", 0);
4136 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4137 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4138 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4140 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4162 shader->SetAttributePointerf(
"aPos", co1);
4163 shader->SetAttributePointerf(
"aUV", tco1);
4165 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4168 shader->SetUniformMatrix4fv(
"MVMatrix",
4169 (GLfloat *)VPoint.vp_matrix_transform);
4172 glBindTexture(g_texture_rectangle_format, 0);
4174 glDisable(g_texture_rectangle_format);
4182 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4183 g_texture_rectangle_format,
4184 m_cache_tex[!m_cache_page], 0);
4195 wxColour color = GetGlobalColor(
"NODTA");
4196 glClearColor(color.Red() / 256., color.Green() / 256.,
4197 color.Blue() / 256., 1.0);
4198 glClear(GL_COLOR_BUFFER_BIT);
4204 RenderCharts(m_gldc, rscreen_region);
4209 m_cache_page = !m_cache_page;
4214 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4225 glMatrixMode(GL_PROJECTION);
4228 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4229 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4231 glMatrixMode(GL_MODELVIEW);
4235 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4236 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4238 glGetIntegerv(GL_VIEWPORT, viewport);
4239 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4240 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4249 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4250 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4251 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4253 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4257 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4258 glEnable(g_texture_rectangle_format);
4260 float tx, ty, tx0, ty0, divx, divy;
4263 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4266 divx = m_cache_tex_x;
4267 divy = m_cache_tex_y;
4270 tx0 = m_fbo_offsetx / divx;
4271 ty0 = m_fbo_offsety / divy;
4272 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4273 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4298 wxColour color = GetGlobalColor(
"NODTA");
4299 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4301 glClear(GL_COLOR_BUFFER_BIT);
4303 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4306 glDisable(g_texture_rectangle_format);
4308 m_cache_vp = VPoint;
4309 m_cache_vp.Validate();
4311 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4313 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4317 RenderCharts(m_gldc, screen_region);
4326 RenderS57TextOverlay(VPoint);
4327 RenderMBTilesOverlay(VPoint);
4333 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4338 wxRect rt = upd.GetRect();
4339 LLRegion region = VPoint.GetLLRegion(rt);
4340 ViewPort cvp = ClippedViewport(VPoint, region);
4341 DrawGroundedOverlayObjects(gldc, cvp);
4344 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4345 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4346 LLBBox screenBox = screenLLRegion.GetBox();
4348 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4351 if (m_pParentCanvas->m_bShowTide) {
4352 m_pParentCanvas->RebuildTideSelectList(screenBox);
4353 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4356 if (m_pParentCanvas->m_bShowCurrent) {
4357 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4358 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4364 if (m_pParentCanvas->m_show_focus_bar &&
4365 (g_canvasConfig != 0)) {
4366 if (m_pParentCanvas == wxWindow::FindFocus()) {
4369 wxColour colour = GetGlobalColor(
"BLUE4");
4370 wxPen ppBlue(colour, 1);
4371 wxBrush ppBrush(colour);
4372 gldc.SetPen(ppBlue);
4373 gldc.SetBrush(ppBrush);
4374 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4375 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4376 wxPoint barPoints[4];
4379 barPoints[1].x = xw;
4381 barPoints[2].x = xw;
4382 barPoints[2].y = rect_pix;
4384 barPoints[3].y = rect_pix;
4386 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4390 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4394 DrawFloatingOverlayObjects(m_gldc);
4396#ifndef USE_ANDROID_GLES2
4399 glMatrixMode(GL_PROJECTION);
4402 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4403 glMatrixMode(GL_MODELVIEW);
4408 if (!g_bhide_depth_units)
4409 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4410 if (!g_bhide_overzoom_flag)
4411 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4414 ViewPort &vp = m_pParentCanvas->GetVP();
4419 if (!g_PrintingInProgress) {
4420 if (m_pParentCanvas->m_pTrackRolloverWin)
4421 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4423 if (m_pParentCanvas->m_pRouteRolloverWin)
4424 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4426 if (m_pParentCanvas->m_pAISRolloverWin)
4427 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4429 if (m_pParentCanvas->GetMUIBar())
4430 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4444 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4445 int x, y, width, height;
4446 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4447 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4448 wxBitmap bmp(width, height, -1);
4451 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4454 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4455 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4459 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4460 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4462 wxStringTokenizer tkz(s,
"\n");
4465 while (tkz.HasMoreTokens()) {
4466 token = tkz.GetNextToken();
4467 dc.DrawText(token, xt, yt);
4470 dc.SelectObject(wxNullBitmap);
4472 m_gldc.DrawBitmap(bmp, x, y,
false);
4478 if (g_bShowChartBar) DrawChartBar(m_gldc);
4480 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4482 m_pParentCanvas->m_Compass->Paint(gldc);
4484 if (m_pParentCanvas->IsPrimaryCanvas() &&
4485 m_pParentCanvas->m_notification_button) {
4486 auto ¬eman = NotificationManager::GetInstance();
4487 if (noteman.GetNotificationCount()) {
4488 m_pParentCanvas->m_notification_button->SetIconSeverity(
4489 noteman.GetMaxSeverity());
4490 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4491 m_pParentCanvas->m_notification_button->Show(
true);
4492 m_pParentCanvas->m_notification_button->Paint(gldc);
4494 m_pParentCanvas->m_notification_button->Show(
false);
4497 RenderGLAlertMessage();
4500 ViewPort &vp = m_pParentCanvas->GetVP();
4504 glActiveTexture(GL_TEXTURE0);
4508 if (g_bquiting) DrawQuiting();
4509 if (g_bcompression_wait)
4510 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4520 m_pParentCanvas->PaintCleanup();
4521 m_bforcefull =
false;
4530void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4533 if (VPoint.b_quilt) {
4534 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4535 ps52plib->GetShowS57Text()) {
4536 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4537 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4542 ChPI->ClearPLIBTextList();
4544 ps52plib->ClearTextList();
4554 RenderQuiltViewGLText(vpx, screen_region);
4559void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4562 LLRegion &screenLLRegion) {
4567 if (chart == NULL)
return;
4574 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4576 wxFileName tileFile(chart->GetFullPath());
4578 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4581 bool isBasemap = tileFile.GetPath().Lower().Contains(
"basemap");
4587 (double)chart->GetNativeScale();
4589 if (zoom_ratio > g_tile_basemap_zoom_factor)
return;
4592 if (!isBasemap && (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4593 (tileSizeMB.GetLo() > 5000))) {
4596 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4597 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4598 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4605 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4609 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4612 std::vector<int> piano_active_array_tiles =
4613 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4614 bool bfound =
false;
4616 if (std::find(piano_active_array_tiles.begin(),
4617 piano_active_array_tiles.end(),
4618 dbIndex) != piano_active_array_tiles.end()) {
4623 piano_active_array_tiles.push_back(dbIndex);
4624 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4628void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4630 std::vector<int> stackIndexArray =
4631 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4632 unsigned int im = stackIndexArray.size();
4635 if (VPoint.b_quilt && im > 0) {
4636 bool regionVPBuilt =
false;
4638 LLRegion screenLLRegion;
4642 std::vector<int> tiles_to_show;
4643 for (
unsigned int is = 0; is < im; is++) {
4645 ChartData->GetChartTableEntry(stackIndexArray[is]);
4646 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4647 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4649 std::vector<int> piano_active_array_tiles =
4650 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4651 bool bfound =
false;
4653 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4654 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4655 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4663 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4664 piano_active_array_tiles);
4669 tiles_to_show.push_back(stackIndexArray[is]);
4670 if (!regionVPBuilt) {
4673 screenLLRegion = VPoint.GetLLRegion(screen_region);
4674 screenBox = screenLLRegion.GetBox();
4682 regionVPBuilt =
true;
4692 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4693 rit != tiles_to_show.rend(); ++rit) {
4694 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4696 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4697 rit != tiles_to_show.rend(); ++rit) {
4698 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4702 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4704 if (!hiregion.Empty()) {
4708 switch (global_color_scheme) {
4709 case GLOBAL_COLOR_SCHEME_DAY:
4712 case GLOBAL_COLOR_SCHEME_DUSK:
4715 case GLOBAL_COLOR_SCHEME_NIGHT:
4723#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4724 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4726 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4729 DrawRegion(VPoint, hiregion);
4731 glDisable(GL_BLEND);
4737void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4741 GetClientSize(&w, &h);
4743 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4744#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4745 glMatrixMode(GL_PROJECTION);
4748 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4749 glMatrixMode(GL_MODELVIEW);
4753 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4755 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4757 bool world_view =
false;
4758 RenderWorldChart(dc, cvp, rtex, world_view);
4765 glViewport(0, 0, (GLint)w, (GLint)h);
4766#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4767 glMatrixMode(GL_PROJECTION);
4770 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4771 glMatrixMode(GL_MODELVIEW);
4777void glChartCanvas::FastPan(
int dx,
int dy) {
4778#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4782void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4784 if (IsShown()) SetCurrent(*m_pcontext);
4785 float sx = GetSize().x;
4786 float sy = GetSize().y;
4787 glClear(GL_COLOR_BUFFER_BIT);
4790 GetClientSize(&w, &h);
4792 if (s_b_useStencil) {
4793 glEnable(GL_STENCIL_TEST);
4794 glStencilMask(0xff);
4795 glClear(GL_STENCIL_BUFFER_BIT);
4796 glDisable(GL_STENCIL_TEST);
4812 float sxfactor = sx / swidth;
4813 float syfactor = sy / sheight;
4815 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4816 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4817 sx * sx / swidth * 2, sy * sy / sheight * 2);
4818 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4819 glEnable(g_texture_rectangle_format);
4844 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4845 glBindTexture(g_texture_rectangle_format, 0);
4851 float tx, ty, tx0, ty0;
4861 glBindTexture(g_texture_rectangle_format, 0);
4864 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4865 glEnable(g_texture_rectangle_format);
4871 uv[0] = tx0 / m_cache_tex_x;
4872 uv[1] = ty / m_cache_tex_y;
4873 uv[2] = tx / m_cache_tex_x;
4874 uv[3] = ty / m_cache_tex_y;
4875 uv[4] = tx / m_cache_tex_x;
4876 uv[5] = ty0 / m_cache_tex_y;
4877 uv[6] = tx0 / m_cache_tex_x;
4878 uv[7] = ty0 / m_cache_tex_y;
4890 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4891 sx * sx / swidth, sy * sy / sheight);
4893 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4895 glDisable(g_texture_rectangle_format);
4896 glBindTexture(g_texture_rectangle_format, 0);
4903 wxColour color = GetGlobalColor(
"GREY1");
4904 float ht = -offset_y * (sy / sheight);
4905 wxRect r(0, sy - ht, w, ht);
4906 RenderColorRect(r, color);
4909 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4910 RenderColorRect(rt, color);
4913 float w1 = -offset_x * sx / swidth;
4914 wxRect rl(0, 0, w1, sy);
4915 RenderColorRect(rl, color);
4918 float px = w1 + sx * sx / swidth;
4919 wxRect rr(px, 0, sx - px, sy);
4920 RenderColorRect(rr, color);
4929void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4932 if (m_nRun < m_nTotal) {
4933 m_runoffsetx += m_offsetxStep;
4934 if (m_offsetxStep > 0)
4935 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4937 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4939 m_runoffsety += m_offsetyStep;
4940 if (m_offsetyStep > 0)
4941 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4943 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4945 m_runswidth += m_swidthStep;
4946 if (m_swidthStep > 0)
4947 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4949 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4951 m_runsheight += m_sheightStep;
4952 if (m_sheightStep > 0)
4953 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4955 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4960 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4966 if (m_zoomFinaldx || m_zoomFinaldy) {
4967 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
4970 m_zoomFinal =
false;
4974void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
4976 int sx = GetSize().x;
4977 int sy = GetSize().y;
4979 m_lastfbo_offsetx = m_fbo_offsetx;
4980 m_lastfbo_offsety = m_fbo_offsety;
4981 m_lastfbo_swidth = m_fbo_swidth;
4982 m_lastfbo_sheight = m_fbo_sheight;
4984 float curr_fbo_offset_x = m_fbo_offsetx;
4985 float curr_fbo_offset_y = m_fbo_offsety;
4986 float curr_fbo_swidth = m_fbo_swidth;
4987 float curr_fbo_sheight = m_fbo_sheight;
4989 float fx = (float)cp_x / sx;
4990 float fy = 1.0 - (float)cp_y / sy;
4992 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
4993 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
4995 m_fbo_swidth = curr_fbo_swidth / factor;
4996 m_fbo_sheight = curr_fbo_sheight / factor;
4998 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
4999 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5001 m_fbo_offsetx += post_x;
5002 m_fbo_offsety += post_y;
5013 float perStep = m_nStep / m_nTotal;
5015 if (zoomTimer.IsRunning()) {
5016 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5017 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5018 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5019 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5022 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5023 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5024 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5025 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5027 m_runoffsetx = m_lastfbo_offsetx;
5028 m_runoffsety = m_lastfbo_offsety;
5029 m_runswidth = m_lastfbo_swidth;
5030 m_runsheight = m_lastfbo_sheight;
5033 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5034 m_zoomFinal =
false;
5040void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5044 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5047 if (m_binPinch)
return;
5048 if (m_bpinchGuard)
return;
5050 int x =
event.GetOffset().x;
5051 int y =
event.GetOffset().y;
5053 int lx =
event.GetLastOffset().x;
5054 int ly =
event.GetLastOffset().y;
5059 switch (event.GetState()) {
5060 case GestureStarted:
5061 if (m_binPan)
break;
5065 m_binGesture =
true;
5069 case GestureUpdated:
5074 m_pParentCanvas->FreezePiano();
5076 m_pParentCanvas->ThawPiano();
5087 case GestureFinished:
5090 m_pParentCanvas->UpdateCanvasControlBar();
5093 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5097 case GestureCanceled:
5099 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5106 m_bgestureGuard =
true;
5107 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5108 m_bforcefull =
false;
5113float zoom_inc = 1.0;
5115void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5116 float zoom_gain = 1.0;
5117 float zout_gain = 1.0;
5120 float total_zoom_val;
5122 float max_zoom_scale = 1000.;
5123 float min_zoom_scale = 2e8;
5125 if (event.GetScaleFactor() > 1)
5126 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5128 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5130 if (event.GetTotalScaleFactor() > 1)
5131 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5134 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5136 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5139 float max_zoom_scale = 1000.;
5140 if( cc1->GetVP().b_quilt) {
5141 int ref_index = cc1->GetQuiltRefChartdbIndex();
5148 float min_zoom_scale = 2e8;
5152 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5154 double projected_scale =
5155 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5157 switch (event.GetState()) {
5158 case GestureStarted:
5159 m_first_zout =
false;
5163 m_binGesture =
true;
5165 m_pinchStart =
event.GetCenterPoint();
5166 m_lpinchPoint = m_pinchStart;
5169 event.GetCenterPoint().y, m_pinchlat,
5174 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5175 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5178 if (IsShown()) SetCurrent(*m_pcontext);
5184 case GestureUpdated:
5186 if (projected_scale < min_zoom_scale) {
5187 wxPoint pinchPoint =
event.GetCenterPoint();
5189 float dx = pinchPoint.x - m_lpinchPoint.x;
5190 float dy = pinchPoint.y - m_lpinchPoint.y;
5192 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5193 -dx / total_zoom_val, dy / total_zoom_val);
5195 m_lpinchPoint = pinchPoint;
5199 if (1 || ((total_zoom_val > 1) && !m_first_zout)) {
5200 wxPoint pinchPoint =
event.GetCenterPoint();
5202 float dx = pinchPoint.x - m_lpinchPoint.x;
5203 float dy = pinchPoint.y - m_lpinchPoint.y;
5205 if ((projected_scale > max_zoom_scale) &&
5206 (projected_scale < min_zoom_scale))
5207 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5208 -dx / total_zoom_val, dy / total_zoom_val);
5210 m_lpinchPoint = pinchPoint;
5213 m_first_zout =
true;
5214 zoom_inc *= zoom_val;
5215 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5216 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5220 wxPoint pinchPoint =
event.GetCenterPoint();
5221 float dx = pinchPoint.x - m_lpinchPoint.x;
5222 float dy = pinchPoint.y - m_lpinchPoint.y;
5224 m_lpinchPoint = pinchPoint;
5235 case GestureFinished: {
5239 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5240 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5244 float tzoom = total_zoom_val;
5246 if (projected_scale >= min_zoom_scale)
5247 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5249 if (projected_scale < max_zoom_scale)
5250 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5252 dx = (cc_x - m_cc_x) * tzoom;
5253 dy = -(cc_y - m_cc_y) * tzoom;
5255 if (zoomTimer.IsRunning()) {
5258 m_zoomFinalZoom = tzoom;
5264 double final_projected_scale =
5268 if (final_projected_scale < min_zoom_scale) {
5272 m_pParentCanvas->m_pQuilt->Invalidate();
5273 m_bforcefull =
true;
5280 m_pParentCanvas->m_pQuilt->Invalidate();
5281 m_bforcefull =
true;
5293 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5297 case GestureCanceled:
5299 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5306 m_bgestureGuard =
true;
5308 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5311void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5321 m_bgestureGuard =
false;
5322 m_bpinchGuard =
false;
5323 m_binGesture =
false;
5324 m_bforcefull =
false;
5327void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5331 m_binGesture =
false;
5332 m_bforcefull =
false;
5336#ifdef HAVE_WX_GESTURE_EVENTS
5338void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5341 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5344 if (m_binPinch)
return;
5345 if (m_bpinchGuard)
return;
5347 int dx =
event.GetDelta().x;
5348 int dy =
event.GetDelta().y;
5350 if (event.IsGestureStart()) {
5351 if (m_binPan)
return;
5355 m_binGesture =
true;
5359 else if (event.IsGestureEnd()) {
5361 m_pParentCanvas->UpdateCanvasControlBar();
5363 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5371 m_pParentCanvas->FreezePiano();
5373 m_pParentCanvas->ThawPiano();
5384 m_bgestureGuard =
true;
5385 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5386 m_bforcefull =
false;
5390void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5392 float zoom_gain = 1.0;
5393 float zout_gain = 1.0;
5395 float last_zoom_val = m_step_zoom_val;
5397 float max_zoom_scale = 1000.;
5398 float min_zoom_scale = 2e8;
5400 if (event.GetZoomFactor() > 1)
5401 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5403 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5405 float inc_zoom_val =
5406 m_total_zoom_val / last_zoom_val;
5410 if (event.IsGestureStart()) {
5411 m_glstopwatch.Start();
5412 printf(
"\nStart--------------\n");
5414 m_pParentCanvas->m_inPinch =
true;
5417 m_binGesture =
true;
5418 m_pinchStart =
event.GetPosition();
5419 m_lpinchPoint = m_pinchStart;
5420 m_total_zoom_val = 1.0;
5421 m_final_zoom_val = 1.0;
5422 m_step_zoom_val = 1.0;
5426 event.GetPosition().x, event.GetPosition().y, m_pinchlat, m_pinchlon);
5430 if (event.IsGestureEnd()) {
5432 if (!m_binGesture)
return;
5433 printf(
"EndZoom--------------\n");
5440 m_final_zoom_val = 1.0;
5441 m_total_zoom_val = 1.0;
5442 m_step_zoom_val = 1.0;
5444 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5451 float zoom_step = 5;
5452 float zoom_trigger = 0.05;
5453 if (projected_scale > 1e5)
5455 else if (projected_scale < 3e4)
5458 if (inc_zoom_val != 1.0) {
5459 if (inc_zoom_val > 1 + zoom_step) {
5460 m_step_zoom_val = m_step_zoom_val * (1 + zoom_step);
5461 printf(
" Partial zoom: %6g\n", 1 + zoom_step);
5463 if (IsShown()) SetCurrent(*m_pcontext);
5466 if (fabs(inc_zoom_val - 1.) > zoom_trigger) {
5467 m_step_zoom_val = m_total_zoom_val;
5468 printf(
" Zoom: %6g\n", inc_zoom_val);
5473 bool b_allow_ztp =
true;
5474 if (m_pParentCanvas->m_bFollow && m_pParentCanvas->m_bLookAhead)
5475 b_allow_ztp =
false;
5477 if (g_bEnableZoomToCursor && b_allow_ztp) {
5483 int dx = r.x -
event.GetPosition().x;
5484 int dy = r.y -
event.GetPosition().y;
5488 if (IsShown()) SetCurrent(*m_pcontext);
5497 float zoom_gain = 1.0;
5498 float zout_gain = 1.0;
5500 float last_zoom_val = m_total_zoom_val;
5502 float max_zoom_scale = 1000.;
5503 float min_zoom_scale = 2e8;
5505 if (event.GetZoomFactor() > 1)
5506 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5508 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5510 float inc_zoom_val =
5511 m_total_zoom_val / last_zoom_val;
5513 double projected_scale =
5514 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5516 if (event.IsGestureStart()) {
5518 m_first_zout =
false;
5522 m_binGesture =
true;
5523 m_pinchStart =
event.GetPosition();
5524 m_lpinchPoint = m_pinchStart;
5525 m_total_zoom_val = 1.0;
5526 m_final_zoom_val = 1.0;
5529 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5533 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5534 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5537 if (IsShown()) SetCurrent(*m_pcontext);
5540 ViewPort vpr = m_pParentCanvas->VPoint;
5542 GetTouchBackingBitmap(vpr);
5547 if (event.IsGestureEnd()) {
5553 if (!m_binGesture)
return;
5555 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5556 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5560 float tzoom = m_final_zoom_val;
5562 dx = (cc_x - m_cc_x) * tzoom;
5563 dy = -(cc_y - m_cc_y) * tzoom;
5565 if (zoomTimer.IsRunning()) {
5568 m_zoomFinalZoom = tzoom;
5574 double final_projected_scale =
5578 if (final_projected_scale < min_zoom_scale) {
5582 m_pParentCanvas->m_pQuilt->Invalidate();
5583 m_bforcefull =
true;
5590 m_pParentCanvas->m_pQuilt->Invalidate();
5591 m_bforcefull =
true;
5596 m_final_zoom_val = 1.0;
5597 m_total_zoom_val = 1.0;
5598 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5603 if (projected_scale < min_zoom_scale) {
5604 wxPoint pinchPoint =
event.GetPosition();
5606 float dx = pinchPoint.x - m_lpinchPoint.x;
5607 float dy = pinchPoint.y - m_lpinchPoint.y;
5609 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5610 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5612 m_lpinchPoint = pinchPoint;
5613 m_final_zoom_val *= inc_zoom_val;
5617 if (1 || ((m_total_zoom_val > 1) && !m_first_zout)) {
5618 wxPoint pinchPoint =
event.GetPosition();
5620 float dx = pinchPoint.x - m_lpinchPoint.x;
5621 float dy = pinchPoint.y - m_lpinchPoint.y;
5623 if ((projected_scale > max_zoom_scale) &&
5624 (projected_scale < min_zoom_scale))
5625 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5626 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5628 m_lpinchPoint = pinchPoint;
5629 m_final_zoom_val *= inc_zoom_val;
5632 m_first_zout =
true;
5633 m_zoom_inc *= inc_zoom_val;
5634 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5635 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5639 wxPoint pinchPoint =
event.GetPosition();
5640 float dx = pinchPoint.x - m_lpinchPoint.x;
5641 float dy = pinchPoint.y - m_lpinchPoint.y;
5643 m_lpinchPoint = pinchPoint;
5647 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5650 m_bgestureGuard =
true;
5651 m_bpinchGuard =
true;
5654void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5663 m_bgestureGuard =
false;
5664 m_bpinchGuard =
false;
5665 m_binGesture =
false;
5666 m_bforcefull =
false;
5669void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5673 m_binGesture =
false;
5674 m_bforcefull =
false;
5676 m_pParentCanvas->m_inPinch =
false;
5677 printf(
"******Finish\n");
5683void glChartCanvas::configureShaders(
ViewPort &vp) {
5684#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5690 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5692 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5693 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5714 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5716 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5717 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5729 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5731 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5732 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5735 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5737 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5738 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5746 shader = pAALine_shader_program[GetCanvasIndex()];
5748 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5751 shader = pring_shader_program[GetCanvasIndex()];
5753 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5754 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5758 if (texture_2DA_shader_program) {
5759 glUseProgram(texture_2DA_shader_program);
5760 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5761 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5762 (
const GLfloat *)pvp->vp_matrix_transform);
5764 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5765 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5773void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5776#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5777 int nl = nVertex / 4;
5779 float *luv = uvCoords;
5782 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5790 glEnableClientState(GL_VERTEX_ARRAY);
5791 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5793 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5794 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5795 glDrawArrays(GL_QUADS, 0, 4);
5802void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5803 float *uvCoords,
ViewPort *vp,
float dx,
5804 float dy,
float angle_rad) {
5805#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5807 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5808 if (!shader)
return;
5813 shader->SetUniform1i(
"uTex", 0);
5818 mat4x4_rotate_Z(Q, I, angle_rad);
5824 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5829 shader->SetAttributePointerf(
"aPos", co1);
5830 shader->SetAttributePointerf(
"aUV", tco1);
5837 GLushort indices1[] = {0,1,3,2};
5838 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5850 tco1[0] = uvCoords[0];
5851 tco1[1] = uvCoords[1];
5852 tco1[2] = uvCoords[2];
5853 tco1[3] = uvCoords[3];
5854 tco1[4] = uvCoords[6];
5855 tco1[5] = uvCoords[7];
5856 tco1[6] = uvCoords[4];
5857 tco1[7] = uvCoords[5];
5862 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5874void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5875#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5877 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5880 shader->SetUniformMatrix4fv(
5881 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5884 colorv[0] = color.Red() / float(256);
5885 colorv[1] = color.Green() / float(256);
5886 colorv[2] = color.Blue() / float(256);
5888 shader->SetUniform4fv(
"color", colorv);
5891 pf[0] = r.x + r.width;
5895 pf[4] = r.x + r.width;
5896 pf[5] = r.y + r.height;
5898 pf[7] = r.y + r.height;
5899 shader->SetAttributePointerf(
"position", pf);
5901 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5909void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5910#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5912 ViewPort VPoint = m_pParentCanvas->VPoint;
5916 GetClientSize(&w, &h);
5917 int sx = GetSize().x;
5918 int sy = GetSize().y;
5922 glViewport(0, 0, (GLint)w, (GLint)h);
5924 if (s_b_useStencil) {
5925 glEnable(GL_STENCIL_TEST);
5926 glStencilMask(0xff);
5927 glClear(GL_STENCIL_BUFFER_BIT);
5928 glDisable(GL_STENCIL_TEST);
5932 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5937 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5938 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5939 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5942 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5944 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5945 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5953 if (bRenderCharts) RenderCharts(gldc, screen_region);
5955 if (bRenderOverlays) {
5956 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5957 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5963 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5966 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5967 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5968 DrawFloatingOverlayObjects(m_gldc);
5972 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5977wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5979 wxMemoryDC tdc(tbm);
5980 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5988 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5989 dc.SetPen(*wxTRANSPARENT_PEN);
5992 tdc.SelectObject(wxNullBitmap);
5993 m_touch_backing_bitmap = tbm;
5994 CreateBackingTexture();
5996 return m_touch_backing_bitmap;
5999void glChartCanvas::CreateBackingTexture() {
6000 wxImage image = m_touch_backing_bitmap.ConvertToImage();
6001 unsigned char *imgdata = image.GetData();
6002 unsigned char *imgalpha = image.GetAlpha();
6003 m_tex_w = image.GetWidth();
6004 m_tex_h = image.GetHeight();
6005 m_image_width = m_tex_w;
6006 m_image_height = m_tex_h;
6008 GLuint format = GL_RGBA;
6009 GLuint internalformat = g_texture_rectangle_format;
6011 internalformat = GL_RGBA;
6016 unsigned char *teximage =
6017 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
6019 for (
int i = 0; i < m_image_height; i++) {
6020 for (
int j = 0; j < m_image_width; j++) {
6021 int s = (i * 3 * m_image_width) + (j * 3);
6022 int d = (i * stride * m_tex_w) + (j * stride);
6024 teximage[d + 0] = imgdata[s + 0];
6025 teximage[d + 1] = imgdata[s + 1];
6026 teximage[d + 2] = imgdata[s + 2];
6027 teximage[d + 3] = 255;
6031 glGenTextures(1, &m_TouchBackingTexture);
6032 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6034 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6035 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6036 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6038 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6040 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6041 GL_UNSIGNED_BYTE, teximage);
6044 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.