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>
59#include "model/own_ship.h"
61#include "model/route.h"
62#include "model/routeman.h"
63#include "model/track.h"
83#include "mipmap/mipmap.h"
86#include "OCPNPlatform.h"
90#include "RolloverWin.h"
92#include "route_point_gui.h"
95#include "s57_ocpn_utils.h"
96#include "shapefile_basemap.h"
102#include "track_gui.h"
105#ifdef USE_ANDROID_GLES2
106#include <GLES2/gl2.h>
112#include "androidUTIL.h"
113#elif defined(__WXQT__) || defined(__WXGTK__)
117#ifndef GL_ETC1_RGB8_OES
118#define GL_ETC1_RGB8_OES 0x8D64
121#ifndef GL_DEPTH_STENCIL_ATTACHMENT
122#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
126#define printf printf2
127int __cdecl printf2(
const char *format, ...);
130#if defined(__ANDROID__)
131#include "androidUTIL.h"
132#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
139extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
140 float near,
float far);
141#define glOrtho(a, b, c, d, e, f) \
143 glOrthof(a, b, c, d, e, f);
147#ifdef USE_ANDROID_GLES2
148#include <GLES2/gl2.h>
151#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
157#if defined(__UNIX__) && !defined(__WXOSX__)
162 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
166 clock_gettime(CLOCK_REALTIME, &tp_end);
167 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
168 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
178extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
185static bool g_b_needFinish;
187static wxColor s_regionColor;
188static float g_GLMinCartographicLineWidth;
194#define APIENTRYP APIENTRY *
200#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
201#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
207PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
208PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
209PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
210PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
211PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
212PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
213PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
214PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
215PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
216PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
218PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
219PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
222PFNGLGENBUFFERSPROC s_glGenBuffers;
223PFNGLBINDBUFFERPROC s_glBindBuffer;
224PFNGLBUFFERDATAPROC s_glBufferData;
225PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
227#ifndef USE_ANDROID_GLES2
232typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
234PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
237static int panx, pany;
239#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
240static int s_tess_vertex_idx;
241static int s_tess_vertex_idx_this;
242static int s_tess_buf_len;
243static GLfloat *s_tess_work_buf;
244static GLenum s_tess_mode;
249bool glChartCanvas::s_b_useScissorTest;
250bool glChartCanvas::s_b_useStencil;
251bool glChartCanvas::s_b_useStencilAP;
252bool glChartCanvas::s_b_useFBO;
259 while ( upd.HaveRects() )
261 wxRect rect = upd.GetRect();
262 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
269GLboolean QueryExtension(
const char *extName) {
280 extNameLen = strlen(extName);
282 p = (
char *)glGetString(GL_EXTENSIONS);
290 int n = strcspn(p,
" ");
291 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
299int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
300 16, WX_GL_STENCIL_SIZE, 8,
303glTestCanvas::glTestCanvas(wxWindow *parent)
304 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
308int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
309 16, WX_GL_STENCIL_SIZE, 8,
312EVT_PAINT(glChartCanvas::OnPaint)
313EVT_ACTIVATE(glChartCanvas::OnActivate)
314EVT_SIZE(glChartCanvas::OnSize)
315EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
319 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
320 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, "")
323 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
328std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
330 {wxPENSTYLE_DOT, {1, 1}},
331 {wxPENSTYLE_LONG_DASH, {5, 5}},
332 {wxPENSTYLE_SHORT_DASH, {1, 5}},
333 {wxPENSTYLE_DOT_DASH, {5, 1}},
336void glChartCanvas::Init() {
341 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
343 m_cache_current_ch = NULL;
345 m_b_paint_enable =
true;
346 m_in_glpaint =
false;
348 m_cache_tex[0] = m_cache_tex[1] = 0;
351 m_b_BuiltFBO =
false;
352 m_b_DisableFBO =
false;
361 m_bpinchGuard =
false;
362 m_binGesture =
false;
365 m_last_render_time = -1;
372 m_gldc.SetGLCanvas(
this);
375 m_displayScale = 1.0;
376#if defined(__WXOSX__) || defined(__WXGTK3__)
378 m_displayScale = GetContentScaleFactor();
387 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
391 wxEVT_QT_PINCHGESTURE,
392 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
395 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
400 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
402 onGestureFinishTimerEvent,
406 ZOOM_TIMER, wxEVT_TIMER,
407 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
410 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
411 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
412 zoomTimer.SetOwner(
this, ZOOM_TIMER);
414#ifdef USE_ANDROID_GLES2
423#ifdef HAVE_WX_GESTURE_EVENTS
425 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
430 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
432 onGestureFinishTimerEvent,
436 ZOOM_TIMER, wxEVT_TIMER,
437 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
440 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
441 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
442 zoomTimer.SetOwner(
this, ZOOM_TIMER);
447 m_bgestureGuard =
false;
448 m_total_zoom_val = 1.0;
451#ifdef HAVE_WX_GESTURE_EVENTS
452 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
453 wxLogError(
"Failed to enable touch events");
462 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
464 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
465 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
467 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
468 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
470 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
471 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
473 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
474 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
480glChartCanvas::~glChartCanvas() {
486void glChartCanvas::FlushFBO(
void) {
487 if (m_bsetup) BuildFBO();
490void glChartCanvas::OnActivate(wxActivateEvent &event) {
491 m_pParentCanvas->OnActivate(event);
494void glChartCanvas::OnSize(wxSizeEvent &event) {
498 wxLogMessage(
"Got OnSize event while NOT running");
500 qDebug() <<
"OnSizeB";
507 if (!IsShown())
return;
509 SetCurrent(*m_pcontext);
513 SetSize(GetSize().x, GetSize().y);
521 if (m_bsetup && m_pcontext && IsShown()) {
522 SetCurrent(*m_pcontext);
528 wxLogMessage(
"BuildFBO 3");
533 ViewPort *vp = m_pParentCanvas->GetpVP();
536 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
539 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
543void glChartCanvas::MouseEvent(wxMouseEvent &event) {
544 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
550 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
552 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
555 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
559 if (m_bgestureGuard) {
560 m_pParentCanvas->r_rband.x = 0;
570 if (event.LeftUp()) {
572 if ((abs(panx) > 2) || (abs(pany) > 2)) {
575 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
582 if (!event.LeftDClick()) {
587 if (m_binPan && event.RightDown()) {
588 qDebug() <<
"Skip right on pan";
591 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
593 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
594 if (!m_bgestureGuard)
604#ifndef GL_MAX_RENDERBUFFER_SIZE
605#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
608#ifndef USE_ANDROID_GLES2
609bool glChartCanvas::buildFBOSize(
int fboSize) {
611 if (IsShown()) SetCurrent(*m_pcontext);
614 glDeleteTextures(2, m_cache_tex);
615 glDeleteFramebuffers(1, &m_fb0);
616 glDeleteRenderbuffers(1, &m_renderbuffer);
617 m_b_BuiltFBO =
false;
620 if (m_b_DisableFBO)
return false;
624 int rb_x = GetSize().x;
625 int rb_y = GetSize().y;
627 while (i < rb_x) i <<= 1;
631 while (i < rb_y) i <<= 1;
634 m_cache_tex_x = wxMax(rb_x, rb_y);
635 m_cache_tex_y = wxMax(rb_x, rb_y);
638 m_cache_tex_x = GetSize().x * m_displayScale;
639 m_cache_tex_y = GetSize().y * m_displayScale;
642 int err = GL_NO_ERROR;
644 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
647 if (err == GL_INVALID_ENUM) {
648 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
652 if (err == GL_NO_ERROR) {
653 if (fboSize > params) {
655 " OpenGL-> Requested Framebuffer size exceeds "
656 "GL_MAX_RENDERBUFFER_SIZE");
661 glGenFramebuffers(1, &m_fb0);
665 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
670 glGenRenderbuffers(1, &m_renderbuffer);
674 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
679 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
683 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
689 glGenTextures(2, m_cache_tex);
690 for (
int i = 0; i < 2; i++) {
691 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
692 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
694 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
696 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
697 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
700 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
702 if (m_b_useFBOStencil) {
704 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
705 m_cache_tex_x, m_cache_tex_y);
707 int err = glGetError();
710 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
714 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
715 GL_RENDERBUFFER_EXT, m_renderbuffer);
719 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
724 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
725 GL_RENDERBUFFER_EXT, m_renderbuffer);
729 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
735 GLenum depth_format = GL_DEPTH_COMPONENT24;
740 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
744 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
746 int err = glGetError();
749 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X",
755 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
756 GL_RENDERBUFFER_EXT, m_renderbuffer);
761 msg.Printf(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X",
768 glBindTexture(GL_TEXTURE_2D, 0);
769 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
772 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
774 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
775 g_texture_rectangle_format, m_cache_tex[0], 0);
777 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
779 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
781 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
783 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X",
793#ifdef USE_ANDROID_GLES2
794bool glChartCanvas::buildFBOSize(
int fboSize) {
798 int rb_x = GetSize().x;
799 int rb_y = GetSize().y;
801 while (i < rb_x) i <<= 1;
805 while (i < rb_y) i <<= 1;
808 m_cache_tex_x = wxMax(rb_x, rb_y);
809 m_cache_tex_y = wxMax(rb_x, rb_y);
813 int err = GL_NO_ERROR;
815 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
818 if (err == GL_INVALID_ENUM) {
819 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
823 if (err == GL_NO_ERROR) {
824 if (fboSize > params) {
826 " OpenGL-> Requested Framebuffer size exceeds "
827 "GL_MAX_RENDERBUFFER_SIZE");
832 glGenFramebuffers(1, &m_fb0);
836 msg.Printf(
" OpenGL-> Framebuffer GenFramebuffers error: %08X", err);
841 glGenRenderbuffers(1, &m_renderbuffer);
845 msg.Printf(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X", err);
850 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
854 msg.Printf(
" OpenGL-> Framebuffer BindFramebuffers error: %08X", err);
860 glGenTextures(2, m_cache_tex);
861 for (
int i = 0; i < 2; i++) {
862 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
863 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
865 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
867 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
868 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
871 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
874 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
880 msg.Printf(
" OpenGL-> glRenderbufferStorage error: %08X", err);
884 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
885 GL_RENDERBUFFER, m_renderbuffer);
889 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X",
894 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
895 GL_RENDERBUFFER, m_renderbuffer);
899 msg.Printf(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X",
904 glBindTexture(GL_TEXTURE_2D, 0);
905 glBindFramebuffer(GL_FRAMEBUFFER, 0);
908 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
910 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
911 g_texture_rectangle_format, m_cache_tex[0], 0);
913 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
915 glBindFramebuffer(GL_FRAMEBUFFER, 0);
917 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
919 msg.Printf(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X",
929void glChartCanvas::BuildFBO() {
932 glDeleteTextures(2, m_cache_tex);
933 glDeleteFramebuffers(1, &m_fb0);
934 glDeleteRenderbuffers(1, &m_renderbuffer);
935 m_b_BuiltFBO =
false;
938 if (m_b_DisableFBO)
return;
941 int gl_width, gl_height;
942 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
943 int initialSize = NextPow2(gl_width * m_displayScale);
948 wxString info = androidGetDeviceInfo();
950 if (wxNOT_FOUND != info.Find(
"GT-S6312")) initialSize = 1024;
953 if (!buildFBOSize(initialSize)) {
954 glDeleteTextures(2, m_cache_tex);
955 glDeleteFramebuffers(1, &m_fb0);
956 glDeleteRenderbuffers(1, &m_renderbuffer);
958 if (!buildFBOSize(1024)) {
959 wxLogMessage(
"BuildFBO C");
961 m_b_DisableFBO =
true;
962 wxLogMessage(
"OpenGL-> FBO Framebuffer unavailable");
963 m_b_BuiltFBO =
false;
972 msg.Printf(
"OpenGL-> Framebuffer OK, size = %d", m_cache_tex_x);
984void glChartCanvas::SetupOpenGL() {
985 SetCurrent(*m_pcontext);
987 char *str = (
char *)glGetString(GL_RENDERER);
990 wxLogMessage(
"Failed to initialize OpenGL");
994 char render_string[80];
995 strncpy(render_string, str, 79);
996 m_renderer = wxString(render_string, wxConvUTF8);
999 if (g_bSoftwareGL) msg.Printf(
"OpenGL-> Software OpenGL");
1000 msg.Printf(
"OpenGL-> Renderer String: ");
1004 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1006 char version_string[80];
1007 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1008 msg.Printf(
"OpenGL-> Version reported: ");
1009 m_version = wxString(version_string, wxConvUTF8);
1013 char GLSL_version_string[80];
1014 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1016 msg.Printf(
"OpenGL-> GLSL Version reported: ");
1017 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1018 msg += m_GLSLversion;
1023 GLenum err = glewInit();
1024#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1025 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1030 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1033 wxLogMessage(
"GLEW init success!n");
1038 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1039 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1043#ifndef USE_ANDROID_GLES2
1044 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1046 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1048 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1049 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1056 if (m_renderer.Upper().Find(
"MESA") != wxNOT_FOUND) {
1058 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1060 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1063 s_b_useScissorTest =
true;
1065 if (GetRendererString().Find(
"RADEON X600") != wxNOT_FOUND)
1066 s_b_useScissorTest =
false;
1068 if (GetRendererString().Find(
"GeForce") != wxNOT_FOUND)
1069 s_b_useScissorTest =
false;
1071 bool bad_stencil_code =
false;
1074 if (GetRendererString().Find(
"UniChrome") != wxNOT_FOUND)
1075 bad_stencil_code =
true;
1078 if (GetRendererString().Find(
"Mali") != wxNOT_FOUND) bad_stencil_code =
true;
1081 glEnable(GL_STENCIL_TEST);
1082 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1084 glGetIntegerv(GL_STENCIL_BITS, &sb);
1087 glDisable(GL_STENCIL_TEST);
1089 s_b_useStencil =
false;
1090 if (stencil && (sb == 8)) s_b_useStencil =
true;
1092 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1093 g_texture_rectangle_format = GL_TEXTURE_2D;
1094 else if (QueryExtension(
"GL_OES_texture_npot"))
1095 g_texture_rectangle_format = GL_TEXTURE_2D;
1096 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1097 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1098 wxLogMessage(wxString::Format(
"OpenGL-> Texture rectangle format: %x",
1099 g_texture_rectangle_format));
1102 g_texture_rectangle_format = GL_TEXTURE_2D;
1106 g_b_EnableVBO =
true;
1109 g_b_EnableVBO =
false;
1113 wxLogMessage(
"OpenGL-> Using Vertexbuffer Objects");
1115 wxLogMessage(
"OpenGL-> Vertexbuffer Objects unavailable");
1119 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1121 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1124#ifndef USE_ANDROID_GLES2
1126 if (bad_stencil_code) s_b_useStencil =
false;
1140 if (m_displayScale > 1) m_b_DisableFBO =
true;
1149 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1151 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1152 g_texture_rectangle_format, m_cache_tex[0], 0);
1154 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1155 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1157 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1159 msg.Printf(
" OpenGL-> Framebuffer Incomplete: %08X", fb_status);
1161 m_b_DisableFBO =
true;
1167 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1171 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1173#ifdef USE_ANDROID_GLES2
1174 s_b_useStencilAP = s_b_useStencil;
1181 wxLogMessage(
"OpenGL-> Using Framebuffer Objects");
1183 if (m_b_useFBOStencil)
1184 wxLogMessage(
"OpenGL-> Using FBO Stencil buffer");
1186 wxLogMessage(
"OpenGL-> FBO Stencil buffer unavailable");
1188 wxLogMessage(
"OpenGL-> Framebuffer Objects unavailable");
1191 wxLogMessage(
"OpenGL-> Using Stencil buffer clipping");
1193 wxLogMessage(
"OpenGL-> Using Depth buffer clipping");
1195 if (s_b_useScissorTest && s_b_useStencil)
1196 wxLogMessage(
"OpenGL-> Using Scissor Clipping");
1199 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1201 MipMap_ResolveRoutines();
1205 lwmsg.Printf(
"OpenGL-> Minimum cartographic line width: %4.1f",
1206 g_GLMinCartographicLineWidth);
1207 wxLogMessage(lwmsg);
1208 lwmsg.Printf(
"OpenGL-> Minimum symbol line width: %4.1f",
1209 g_GLMinSymbolLineWidth);
1210 wxLogMessage(lwmsg);
1213 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1215#ifdef USE_ANDROID_GLES2
1216 g_GLOptions.m_bUseAcceleratedPanning =
true;
1222 int tex_dim = g_GLOptions.m_iTextureDimension;
1223 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1232 s_b_useFBO = m_b_BuiltFBO;
1236 ps52plib->SetGLOptions(
1237 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1238 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1239 g_GLMinSymbolLineWidth);
1243 SendJSONConfigMessage();
1246void glChartCanvas::SendJSONConfigMessage() {
1249 v[
"setupComplete"] = m_bsetup;
1250 v[
"useStencil"] = s_b_useStencil;
1251 v[
"useStencilAP"] = s_b_useStencilAP;
1252 v[
"useScissorTest"] = s_b_useScissorTest;
1253 v[
"useFBO"] = s_b_useFBO;
1254 v[
"useVBO"] = g_b_EnableVBO;
1255 v[
"TextureRectangleFormat"] = g_texture_rectangle_format;
1256 wxString msg_id(
"OCPN_OPENGL_CONFIG");
1257 SendJSONMessageToAllPlugins(msg_id, v);
1260void glChartCanvas::SetupCompression() {
1261 int dim = g_GLOptions.m_iTextureDimension;
1264 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1265 wxLogMessage(
"OpenGL-> SSE2 Instruction set not available");
1266 goto no_compression;
1270 g_uncompressed_tile_size = dim * dim * 4;
1271 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1277 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1280 wxLogMessage(
"OpenGL-> Using oes etc1 compression");
1290 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1291 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1294 if (GetRendererString().Find(
"Gallium") != wxNOT_FOUND &&
1295 GetRendererString().Find(
"NV") != wxNOT_FOUND)
1300 wxLogMessage(
"OpenGL-> Using s3tc dxt1 compression");
1301 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1304 wxLogMessage(
"OpenGL-> Using 3dfx fxt1 compression");
1306 wxLogMessage(
"OpenGL-> No Useable compression format found");
1307 goto no_compression;
1312 g_tile_size = 512 * 512 / 2;
1316 glGenTextures(1, &texture);
1317 glBindTexture(GL_TEXTURE_2D, texture);
1319 GL_UNSIGNED_BYTE, NULL);
1320 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1322 glDeleteTextures(1, &texture);
1326 if (g_tile_size == 0)
goto no_compression;
1328 wxLogMessage(wxString::Format(
"OpenGL-> Compressed tile size: %dkb (%d:1)",
1330 g_uncompressed_tile_size / g_tile_size));
1334 g_GLOptions.m_bTextureCompression =
false;
1336 g_tile_size = g_uncompressed_tile_size;
1337 wxLogMessage(wxString::Format(
"OpenGL-> Not Using compression"));
1340void glChartCanvas::OnPaint(wxPaintEvent &event) {
1343 if (!m_pcontext)
return;
1351 SetCurrent(*m_pcontext);
1356 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1364 if (!m_b_paint_enable)
return;
1367 if (m_in_glpaint)
return;
1370 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1393bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1395#ifndef USE_ANDROID_GLES2
1396 return vp.m_projection_type == PROJECTION_MERCATOR ||
1397 vp.m_projection_type == PROJECTION_POLAR ||
1398 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1412#define NORM_FACTOR 4096.0
1413void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1414#ifndef USE_ANDROID_GLES2
1416 wxPoint2DDouble point;
1418 switch (vp.m_projection_type) {
1419 case PROJECTION_MERCATOR:
1420 case PROJECTION_EQUIRECTANGULAR:
1421 case PROJECTION_WEB_MERCATOR:
1424 glTranslated(point.m_x, point.m_y, 0);
1429 case PROJECTION_POLAR:
1433 glTranslated(point.m_x, point.m_y, 0);
1434 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1441 printf(
"ERROR: Unhandled projection\n");
1446 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1454 switch (vp.m_projection_type) {
1455 case PROJECTION_MERCATOR:
1456 case PROJECTION_EQUIRECTANGULAR:
1457 case PROJECTION_WEB_MERCATOR:
1461 case PROJECTION_POLAR:
1466 printf(
"ERROR: Unhandled projection\n");
1475bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1476 return vp.m_projection_type == PROJECTION_MERCATOR ||
1477 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1478 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1482 const LLRegion ®ion) {
1483 if (!CanClipViewport(vp))
return vp;
1486 LLBBox bbox = region.GetBox();
1488 if (!bbox.GetValid())
return vp;
1496 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1497 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1498 bbox.GetMaxLon() + 360);
1499 cvp.SetBBoxDirect(bbox);
1500 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1501 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1502 bbox.GetMaxLon() - 360);
1503 cvp.SetBBoxDirect(bbox);
1505 cvp.SetBBoxDirect(bbox);
1510void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1511 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1514 for (
Track *pTrackDraw : g_TrackList) {
1517 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1519 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1522 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1523 node = node->GetNext()) {
1524 Route *pRouteDraw = node->GetData();
1526 if (!pRouteDraw)
continue;
1529 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1534 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1539 if (vp.GetBBox().GetValid() && pWayPointMan) {
1540 for (wxRoutePointListNode *pnode =
1541 pWayPointMan->GetWaypointList()->GetFirst();
1542 pnode; pnode = pnode->GetNext()) {
1545 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1552void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1555 for (
Track *pTrackDraw : g_TrackList) {
1557 if (pActiveTrack && pActiveTrack->IsRunning())
1558 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1562 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1563 node = node->GetNext()) {
1564 Route *pRouteDraw = node->GetData();
1567 if (!pRouteDraw)
continue;
1570 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1576 if (pRouteDraw->IsSelected()) drawit++;
1579 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1580 if (!vp_box.IntersectOut(test_box))
1581 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1587 if (vp.GetBBox().GetValid() && pWayPointMan) {
1588 for (wxRoutePointListNode *pnode =
1589 pWayPointMan->GetWaypointList()->GetFirst();
1590 pnode; pnode = pnode->GetNext()) {
1599static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1603 switch (vp.m_projection_type) {
1604 case PROJECTION_TRANSVERSE_MERCATOR:
1605 lat_dist = 4, lon_dist = 1;
1607 case PROJECTION_POLYCONIC:
1608 lat_dist = 2, lon_dist = 1;
1610 case PROJECTION_ORTHOGRAPHIC:
1611 lat_dist = 2, lon_dist = 2;
1613 case PROJECTION_POLAR:
1614 lat_dist = 180, lon_dist = 1;
1616 case PROJECTION_STEREOGRAPHIC:
1617 case PROJECTION_GNOMONIC:
1618 lat_dist = 2, lon_dist = 1;
1620 case PROJECTION_EQUIRECTANGULAR:
1623 lat_dist = 2, lon_dist = 360;
1626 lat_dist = 180, lon_dist = 360;
1630void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1631 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1637 ChartData->GetDBBoundingBox(dbIndex, box);
1638 if (!box.GetValid())
return;
1642 if (box.GetLonRange() == 360)
return;
1644 LLBBox vpbox = vp.GetBBox();
1646 double lon_bias = 0;
1648 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1651 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1652 color = GetGlobalColor(
"YELO1");
1653 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1654 color = GetGlobalColor(
"GREEN2");
1656 color = GetGlobalColor(
"UINFR");
1658#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1659 float plylat, plylon;
1661 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1663 glColor3ub(color.Red(), color.Green(), color.Blue());
1664 glLineWidth(g_GLMinSymbolLineWidth);
1666 float lat_dist, lon_dist;
1667 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1670 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1674 nPly =
ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1676 nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1678 bool begin =
false, sml_valid =
false;
1680 float lastplylat = 0.0;
1681 float lastplylon = 0.0;
1683 int modulo = (nPly == 0) ? 1 : nPly;
1684 for (
int i = 0; i < nPly + 1; i++) {
1686 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1688 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1692 if (lastplylon - plylon > 180)
1694 else if (lastplylon - plylon < -180)
1701 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1702 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1703 splits = wxMax(lat_splits, lon_splits) + 1;
1710 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1711 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1714 for (
double c = 0; c < splits; c++) {
1716 if (c == splits - 1)
1717 lat = plylat, lon = plylon;
1719 double d = (double)(c + 1) / splits;
1720 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1726 if (!std::isnan(s.m_x)) {
1729 glBegin(GL_LINE_STRIP);
1731 glVertex2f(s.m_x, s.m_y);
1737 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1738 lastplylat = plylat, lastplylon = plylon;
1743 }
while (++j < nAuxPlyEntries);
1745 glDisable(GL_LINE_SMOOTH);
1749 double nominal_line_width_pix =
1750 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1752 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1753 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), nominal_line_width_pix,
1756 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1757 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), nominal_line_width_pix,
1761 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), nominal_line_width_pix,
1764 float plylat1, plylon1;
1768 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
1769 if (0 == nAuxPlyEntries)
1772 std::vector<int> points_vector;
1774 std::vector<float> vec =
ChartData->GetReducedPlyPoints(dbIndex);
1775 int nPly = vec.size() / 2;
1777 if (nPly == 0)
return;
1779 for (
int i = 0; i < nPly; i++) {
1780 plylon1 = vec[i * 2];
1781 plylat1 = vec[i * 2 + 1];
1787 points_vector.push_back(pixx1);
1788 points_vector.push_back(pixy1);
1791 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1792 plylon1 += lon_bias;
1798 points_vector.push_back(pixx1);
1799 points_vector.push_back(pixy1);
1801 if (points_vector.size()) {
1802 std::vector<int>::iterator it = points_vector.begin();
1803 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1811 for (
int j = 0; j < nAuxPlyEntries; j++) {
1812 std::vector<int> points_vector;
1814 std::vector<float> vec =
ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1815 int nAuxPly = vec.size() / 2;
1817 if (nAuxPly == 0)
continue;
1819 for (
int i = 0; i < nAuxPly; i++) {
1820 plylon1 = vec[i * 2];
1821 plylat1 = vec[i * 2 + 1];
1827 points_vector.push_back(pixx1);
1828 points_vector.push_back(pixy1);
1835 points_vector.push_back(pixx1);
1836 points_vector.push_back(pixy1);
1838 if (points_vector.size()) {
1839 std::vector<int>::iterator it = points_vector.begin();
1840 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1848extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1849 float &MinorSpacing);
1850extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1851void glChartCanvas::GridDraw() {
1852 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1854 ViewPort &vp = m_pParentCanvas->GetVP();
1856 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1860 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1862 double nlat, elon, slat, wlon;
1864 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1867 wxColour GridColor = GetGlobalColor(
"SNDG1");
1869 if (!m_gridfont.IsBuilt()) {
1871 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1872 wxFont font = *dFont;
1873 int font_size = wxMax(10, dFont->GetPointSize());
1874 font.SetPointSize(font_size * m_displayScale);
1875 font.SetWeight(wxFONTWEIGHT_NORMAL);
1878 m_gridfont.Build(font, 1, dpi_factor);
1880 m_gridfont.SetColor(GridColor);
1885 LLBBox llbbox = vp.GetBBox();
1886 nlat = llbbox.GetMaxLat();
1887 slat = llbbox.GetMinLat();
1888 elon = llbbox.GetMaxLon();
1889 wlon = llbbox.GetMinLon();
1896 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1897 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1898 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1899 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1900 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1901 vp.m_projection_type == PROJECTION_POLAR ||
1902 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1905 if (straight_latitudes)
1908 latmargin = gridlatMajor / 2;
1910 slat = wxMax(slat, -90 + latmargin);
1911 nlat = wxMin(nlat, 90 - latmargin);
1913 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1914 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
1918 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
1925 float lon_step = elon - wlon;
1926 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
1928 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1930 s.x = INVALID_COORD;
1931 s.y = INVALID_COORD;
1932 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
1934 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1935 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1943 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
1944 lat += gridlatMinor) {
1947 gldc.DrawLine(0, r.y, 10, r.y,
true);
1948 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
1953 float lat_step = nlat - slat;
1954 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
1956 for (lon = startlon; lon < elon; lon += gridlonMajor) {
1958 s.x = INVALID_COORD;
1959 s.y = INVALID_COORD;
1960 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
1962 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
1963 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
1971 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
1972 lon += gridlonMinor) {
1975 gldc.DrawLine(r.x, 0, r.x, 10,
false);
1976 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
1982 glEnable(GL_TEXTURE_2D);
1984 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
1985 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
1988 CalcGridText(lat, gridlatMajor,
true);
1990 m_gridfont.GetTextExtent(st, 0, &iy);
1992 if (straight_latitudes) {
1997 float x = 0, y = -1;
1998 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
1999 if (y < 0 || y > h) {
2001 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
2004 m_gridfont.RenderString(st, x, y);
2008 double y1, y2, lat1, lon1, lat2, lon2;
2017 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2020 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2022 if (fabs(y - y1) < fabs(y - y2))
2028 error = fabs(r.m_x);
2029 if (--maxiters == 0)
break;
2030 }
while (error > 1 && error < lasterror);
2032 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2038 m_gridfont.RenderString(st, r.m_x, r.m_y);
2042 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2043 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2052 else if (xlon <= -180.0)
2055 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2057 m_gridfont.GetTextExtent(st, &ix, 0);
2059 if (straight_longitudes) {
2060 float x = -1, y = 0;
2061 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2062 if (x < 0 || x > w) {
2064 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2067 m_gridfont.RenderString(st, x, y);
2071 double x1, x2, lat1, lon1, lat2, lon2;
2079 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2082 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2084 if (fabs(x - x1) < fabs(x - x2))
2090 error = fabs(r.m_y);
2091 }
while (error > 1 && error < lasterror);
2093 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2098 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2100 m_gridfont.RenderString(st, r.m_x, r.m_y);
2104 glDisable(GL_TEXTURE_2D);
2105 glDisable(GL_BLEND);
2110 if (!emboss)
return;
2112 int w = emboss->width, h = emboss->height;
2114 glEnable(GL_TEXTURE_2D);
2117 if (!emboss->gltexind) {
2119 emboss->glwidth = NextPow2(emboss->width);
2120 emboss->glheight = NextPow2(emboss->height);
2123 int size = emboss->glwidth * emboss->glheight;
2124 char *data =
new char[2 * size];
2125 for (
int i = 0; i < h; i++) {
2126 for (
int j = 0; j < emboss->glwidth; j++) {
2128 data[2 * ((i * emboss->glwidth) + j)] =
2129 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2130 data[2 * ((i * emboss->glwidth) + j) + 1] =
2131 (char)abs((emboss->pmap[(i * w) + j]));
2136 glGenTextures(1, &emboss->gltexind);
2137 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2138 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2139 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2147 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2151 int x = emboss->x, y = emboss->y;
2153 float wp = (float)w / emboss->glwidth;
2154 float hp = (float)h / emboss->glheight;
2180 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2182 glDisable(GL_BLEND);
2183 glDisable(GL_TEXTURE_2D);
2186void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2187 if (!m_pParentCanvas->GetVP().IsValid())
return;
2188 wxPoint GPSOffsetPixels(0, 0);
2189 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2192 float pCog = std::isnan(gCog) ? 0 : gCog;
2193 float pSog = std::isnan(gSog) ? 0 : gSog;
2197 double shift_dx = 0;
2198 double shift_dy = 0;
2199 bool dynamic = m_pParentCanvas->m_animationActive ||
2200 m_pParentCanvas->m_MouseDragging ||
2201 m_pParentCanvas->m_chart_drag_inertia_active;
2202 if (m_pParentCanvas->m_bFollow && !dynamic) {
2203 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2204 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2205 if (m_pParentCanvas->m_bLookAhead) {
2211 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2212 angle += m_pParentCanvas->GetVPRotation();
2213 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2215 lGPSPoint.m_x -= shift_dx / cos(gLat * PI / 180.);
2216 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2218 lGPSPoint.m_y += shift_dy / cos(gLat * PI / 180.);
2223 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2224 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2231 lShipMidPoint = lGPSPoint;
2235 float icon_hdt = pCog;
2236 if (!std::isnan(gHdt)) icon_hdt = gHdt;
2239 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2243 double osd_head_lat, osd_head_lon;
2244 wxPoint2DDouble osd_head_point;
2246 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2250 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2252 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2253 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2254 icon_rad += (float)PI;
2258 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2262 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2268 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2269 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2270 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2275 float scale_factor = 1.0;
2277 if ((g_ChartScaleFactorExp > 1.0) && (g_OwnShipIconType == 0))
2278 scale_factor = (log(g_ChartScaleFactorExp) + 1.0) * 1.1;
2280 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2281 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2282 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2284 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2286 float nominal_ownship_size_pixels =
2288 nominal_ownship_size_mm);
2290 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2292 wxPen ppSmallScaleShip;
2293 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2295 wxPen(GetGlobalColor(
"URED"), v / 5, wxPENSTYLE_SOLID);
2298 wxPen(GetGlobalColor(
"YELO1"), v / 5, wxPENSTYLE_SOLID);
2299 dc.SetPen(ppSmallScaleShip);
2301 dc.SetBrush(wxBrush(GetGlobalColor(
"URED"), wxBRUSHSTYLE_TRANSPARENT));
2304 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2305 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2306 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2307 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2310 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2311 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2314 int draw_color = SHIP_INVALID;
2315 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2316 draw_color = SHIP_NORMAL;
2317 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2318 draw_color = SHIP_LOWACCURACY;
2326 ownship_color = draw_color;
2328 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2330 glGenTextures(1, &ownship_tex);
2331 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2334 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2337 if (m_pParentCanvas->m_pos_image_user) {
2338 switch (draw_color) {
2340 image = *m_pParentCanvas->m_pos_image_user_grey;
2343 image = *m_pParentCanvas->m_pos_image_user;
2345 case SHIP_LOWACCURACY:
2346 image = *m_pParentCanvas->m_pos_image_user_yellow;
2350 switch (draw_color) {
2352 image = *m_pParentCanvas->m_pos_image_grey;
2355 image = *m_pParentCanvas->m_pos_image_red;
2357 case SHIP_LOWACCURACY:
2358 image = *m_pParentCanvas->m_pos_image_yellow;
2363 int w = image.GetWidth(), h = image.GetHeight();
2364 int glw = NextPow2(w), glh = NextPow2(h);
2365 ownship_size = wxSize(w, h);
2366 ownship_tex_size = wxSize(glw, glh);
2368 unsigned char *d = image.GetData();
2369 unsigned char *a = image.GetAlpha();
2370 unsigned char *e =
new unsigned char[4 * w * h];
2373 for (
int p = 0; p < w * h; p++) {
2374 e[4 * p + 0] = d[3 * p + 0];
2375 e[4 * p + 1] = d[3 * p + 1];
2376 e[4 * p + 2] = d[3 * p + 2];
2377 e[4 * p + 3] = a[p];
2380 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2381 GL_UNSIGNED_BYTE, 0);
2383 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2389#ifndef USE_ANDROID_GLES2
2390 if (m_pParentCanvas->m_pos_image_user)
2391 glColor4ub(255, 255, 255, 255);
2392 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2393 glColor4ub(255, 0, 0, 255);
2394 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2395 glColor4ub(255, 255, 0, 255);
2397 glColor4ub(128, 128, 128, 255);
2399 float scale_factor_y = 1.0;
2400 float scale_factor_x = 1.0;
2402 int ownShipWidth = 22;
2403 int ownShipLength = 84;
2404 lShipMidPoint = lGPSPoint;
2407 if (g_OwnShipIconType != 0)
2408 m_pParentCanvas->ComputeShipScaleFactor(
2409 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2410 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2415 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2416 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2417 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2421 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2422 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2426 float gps_circle_radius = 3.0;
2428 if (g_OwnShipIconType == 0) {
2430 glEnable(GL_TEXTURE_2D);
2431 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2440 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2441 if (m_pParentCanvas->m_pos_image_user)
2442 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2444 float nominal_ownship_size_mm =
2445 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2447 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2448 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2450 float nominal_ownship_size_pixels =
2451 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2453 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2454 nominal_ownship_size_pixels = wxMax(
2455 20.0, nominal_ownship_size_pixels);
2458 float h = nominal_ownship_size_pixels * scale_factor_y;
2459 float w = nominal_ownship_size_pixels * scale_factor_x *
2460 ownship_size.x / ownship_size.y;
2461 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2462 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2468 gps_circle_radius = w / 5;
2470 float uv[8], coords[8];
2489 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2490 lShipMidPoint.m_x, lShipMidPoint.m_y,
2492 glDisable(GL_TEXTURE_2D);
2493 }
else if (g_OwnShipIconType == 1) {
2495 glEnable(GL_TEXTURE_2D);
2496 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2498 float nominal_ownship_size_pixels_y = 84;
2499 float nominal_ownship_size_pixels_x = 22;
2501 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2502 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2504 float u = (float)ownship_size.x / ownship_tex_size.x,
2505 v = (
float)ownship_size.y / ownship_tex_size.y;
2508 gps_circle_radius = w / 5;
2510 float uv[8], coords[8];
2529 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2530 lShipMidPoint.m_x, lShipMidPoint.m_y,
2533 glDisable(GL_TEXTURE_2D);
2534 }
else if (g_OwnShipIconType == 2) {
2542 wxPoint shipPoints[6];
2544 wxColour colour = m_pParentCanvas->ShipColor();
2545 wxPen ppPen(*wxBLACK, 1);
2546 wxBrush ppBrush(colour);
2548 dc.SetBrush(ppBrush);
2550 shipPoints[0].x = 0 * scale_factor_x;
2551 shipPoints[0].y = -28 * scale_factor_y;
2552 shipPoints[1].x = 11 * scale_factor_x;
2553 shipPoints[1].y = -28 * scale_factor_y;
2554 shipPoints[2].x = 11 * scale_factor_x;
2555 shipPoints[2].y = 42 * scale_factor_y;
2556 shipPoints[3].x = 0 * scale_factor_x;
2557 shipPoints[3].y = 42 * scale_factor_y;
2558 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2561 shipPoints[0].x = 0 * scale_factor_x;
2562 shipPoints[0].y = -42 * scale_factor_y;
2563 shipPoints[1].x = 5 * scale_factor_x;
2564 shipPoints[1].y = -42 * scale_factor_y;
2565 shipPoints[2].x = 11 * scale_factor_x;
2566 shipPoints[2].y = -28 * scale_factor_y;
2567 shipPoints[3].x = 0 * scale_factor_x;
2568 shipPoints[3].y = -28 * scale_factor_y;
2569 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2572 shipPoints[0].x = 0 * scale_factor_x;
2573 shipPoints[0].y = -28 * scale_factor_y;
2574 shipPoints[1].x = -11 * scale_factor_x;
2575 shipPoints[1].y = -28 * scale_factor_y;
2576 shipPoints[2].x = -11 * scale_factor_x;
2577 shipPoints[2].y = 42 * scale_factor_y;
2578 shipPoints[3].x = 0 * scale_factor_x;
2579 shipPoints[3].y = 42 * scale_factor_y;
2580 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2583 shipPoints[0].x = 0 * scale_factor_x;
2584 shipPoints[0].y = -42 * scale_factor_y;
2585 shipPoints[1].x = -5 * scale_factor_x;
2586 shipPoints[1].y = -42 * scale_factor_y;
2587 shipPoints[2].x = -11 * scale_factor_x;
2588 shipPoints[2].y = -28 * scale_factor_y;
2589 shipPoints[3].x = 0 * scale_factor_x;
2590 shipPoints[3].y = -28 * scale_factor_y;
2591 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2595 double p1x = -11 * scale_factor_x;
2596 double p2x = 11 * scale_factor_x;
2600 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2602 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2604 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2606 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2607 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2608 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2612 p1y = -42 * scale_factor_y;
2613 p2y = 42 * scale_factor_y;
2614 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2615 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2616 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2617 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2618 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2619 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2622 img_height = ownShipLength * scale_factor_y;
2625 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2627 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
2629 dc.SetBrush(wxBrush(GetGlobalColor(
"CHWHT")));
2631 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2635 glDisable(GL_LINE_SMOOTH);
2636 glDisable(GL_POLYGON_SMOOTH);
2637 glDisable(GL_BLEND);
2640 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2644void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2645 ViewPort &vp = m_pParentCanvas->GetVP();
2650 Route *active_route = g_pRouteMan->GetpActiveRoute();
2661 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
2662 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2668 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2670 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2671 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2673 m_pParentCanvas->AlertDraw(dc);
2675 m_pParentCanvas->RenderVisibleSectorLights(dc);
2677 m_pParentCanvas->RenderRouteLegs(dc);
2678 m_pParentCanvas->RenderShipToActive(dc,
true);
2679 m_pParentCanvas->ScaleBarDraw(dc);
2680 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2681 m_pParentCanvas->extendedSectorLegs);
2683 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2688void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2689 if (m_pParentCanvas->GetPiano()) {
2690 int canvas_height = GetClientSize().y;
2691 canvas_height *= m_displayScale;
2693 m_pParentCanvas->GetPiano()->DrawGL(
2694 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2698void glChartCanvas::DrawQuiting() {
2699#ifndef USE_ANDROID_GLES2
2700 GLubyte pattern[8][8];
2701 for (
int y = 0; y < 8; y++)
2702 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2705 glEnable(GL_TEXTURE_2D);
2706 glBindTexture(GL_TEXTURE_2D, 0);
2708 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2709 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2710 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2712 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2716 float x = GetSize().x, y = GetSize().y;
2717 float u = x / 8, v = y / 8;
2730 glDisable(GL_TEXTURE_2D);
2731 glDisable(GL_BLEND);
2735void glChartCanvas::DrawCloseMessage(wxString msg) {
2736#ifndef USE_ANDROID_GLES2
2740 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2744 texfont.Build(*pfont, 1, 1);
2746 texfont.GetTextExtent(msg, &w, &h);
2748 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2749 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2751 glColor3ub(243, 229, 47);
2755 glVertex2i(xp + w, yp);
2756 glVertex2i(xp + w, yp + h);
2757 glVertex2i(xp, yp + h);
2762 glColor3ub(0, 0, 0);
2763 glEnable(GL_TEXTURE_2D);
2764 texfont.RenderString(msg, xp, yp);
2765 glDisable(GL_TEXTURE_2D);
2766 glDisable(GL_BLEND);
2773static std::list<double *> combine_work_data;
2774static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2775 GLfloat weight[4], GLdouble **dataOut) {
2776 double *vertex =
new double[3];
2777 combine_work_data.push_back(vertex);
2778 memcpy(vertex, coords, 3 * (
sizeof *coords));
2782#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2783void vertexCallbackD_GLSL(GLvoid *vertex) {
2785 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2786 int new_buf_len = s_tess_buf_len + 100;
2787 GLfloat *tmp = s_tess_work_buf;
2790 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2791 if (NULL == s_tess_work_buf) {
2795 s_tess_buf_len = new_buf_len;
2798 GLdouble *pointer = (GLdouble *)vertex;
2800 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2801 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2806void beginCallbackD_GLSL(GLenum mode) {
2807 s_tess_vertex_idx_this = s_tess_vertex_idx;
2812void endCallbackD_GLSL() {
2816 shader->SetUniformMatrix4fv(
"MVMatrix",
2817 (GLfloat *)s_tessVP.vp_matrix_transform);
2819 mat4x4 identityMatrix;
2820 mat4x4_identity(identityMatrix);
2821 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2825 colorv[0] = s_regionColor.Red() / float(256);
2826 colorv[1] = s_regionColor.Green() / float(256);
2827 colorv[2] = s_regionColor.Blue() / float(256);
2828 colorv[3] = s_regionColor.Alpha() / float(256);
2829 shader->SetUniform4fv(
"color", colorv);
2831 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2832 shader->SetAttributePointerf(
"position", bufPt);
2834 glDrawArrays(s_tess_mode, 0, s_nvertex);
2839void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2841void beginCallbackD(GLenum mode) { glBegin(mode); }
2843void endCallbackD() { glEnd(); }
2847void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2848 float lat_dist, lon_dist;
2849 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2851 GLUtesselator *tobj = gluNewTess();
2852 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2854#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2855 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2856 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2857 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2858 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2862 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2863 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2864 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2865 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2868 gluTessNormal(tobj, 0, 0, 1);
2870 gluTessBeginPolygon(tobj, NULL);
2871 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2872 i != region.contours.end(); i++) {
2873 gluTessBeginContour(tobj);
2874 contour_pt l = *i->rbegin();
2876 bool sml_valid =
false;
2877 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2878 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2879 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2880 int splits = wxMax(lat_splits, lon_splits) + 1;
2886 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2887 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2890 for (
int i = 0; i < splits; i++) {
2892 if (i == splits - 1)
2893 lat = j->y, lon = j->x;
2895 double d = (double)(i + 1) / splits;
2896 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2900 if (std::isnan(q.m_x))
continue;
2902 double *p =
new double[6];
2907 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2912 gluTessVertex(tobj, p, p);
2913 combine_work_data.push_back(p);
2917 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2919 gluTessEndContour(tobj);
2921 gluTessEndPolygon(tobj);
2923 gluDeleteTess(tobj);
2925 for (std::list<double *>::iterator i = combine_work_data.begin();
2926 i != combine_work_data.end(); i++)
2928 combine_work_data.clear();
2933void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
2934 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2936 if (s_b_useStencil) {
2938 glEnable(GL_STENCIL_TEST);
2940 glClear(GL_STENCIL_BUFFER_BIT);
2944 glStencilFunc(GL_ALWAYS, 1, 1);
2945 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2948#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2952 glEnable(GL_DEPTH_TEST);
2953 glDepthFunc(GL_ALWAYS);
2954 glDepthMask(GL_TRUE);
2956 glClear(GL_DEPTH_BUFFER_BIT);
2969 glTranslatef(0, 0, .5);
2973 s_regionColor = wxColor(0, 0, 0, 255);
2974 DrawRegion(vp, region);
2976 if (s_b_useStencil) {
2979 glStencilFunc(GL_EQUAL, 1, 1);
2980 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2983#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
2985 glDepthFunc(GL_GREATER);
2986 glDepthMask(GL_FALSE);
2987 glTranslatef(0, 0, -.5);
2990 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2993void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
2997 if (s_b_useStencil && s_b_useScissorTest) {
2999 if (rect != vp_rect) {
3000 glEnable(GL_SCISSOR_TEST);
3001 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3004#ifndef USE_ANDROID_GLES2
3010void glChartCanvas::DisableClipRegion() {
3011 glDisable(GL_SCISSOR_TEST);
3012 glDisable(GL_STENCIL_TEST);
3013 glDisable(GL_DEPTH_TEST);
3016void glChartCanvas::Invalidate() {
3018 m_cache_vp.Invalidate();
3024 if (!pBSBChart)
return;
3026 if (b_inCompressAllCharts)
3030 wxString key = chart->GetHashKey();
3034 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3037 if (ittf == hash.end()) {
3039 hash[key]->SetHashKey(key);
3042 pTexFact = hash[key];
3043 pTexFact->SetLRUTime(++m_LRUtime);
3048 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3049 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3056 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3057 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3058 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3059 base_level = log(scalefactor) / log(2.0);
3068 glEnable(GL_TEXTURE_2D);
3069#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3070 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3072 glEnableClientState(GL_VERTEX_ARRAY);
3073 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3078 pTexFact->GetCenter(lat, lon);
3079 MultMatrixViewPort(vp, lat, lon);
3083 LLBBox box = region.GetBox();
3086 if (g_memCacheLimit > 0) {
3088 GetMemoryStatus(0, &mem_used);
3091 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3092 for (
int i = 0; i < numtiles; i++) {
3094 if (region.IntersectOut(tile->box)) {
3097 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3098 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3100 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3101 global_color_scheme, mem_used);
3105 coords = tile->m_coords;
3107 coords =
new float[2 * tile->m_ncoords];
3108 for (
int i = 0; i < tile->m_ncoords; i++) {
3110 tile->m_coords[2 * i + 1]);
3111 coords[2 * i + 0] = p.m_x;
3112 coords[2 * i + 1] = p.m_y;
3116#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3117 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3118 m_pParentCanvas->GetpVP());
3121 glDisable(GL_TEXTURE_2D);
3125 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3126 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3127 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3129 if (!texture) glEnable(GL_TEXTURE_2D);
3131 if (!use_norm_vp)
delete[] coords;
3135 glDisable(GL_TEXTURE_2D);
3137#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3138 if (use_norm_vp) glPopMatrix();
3140 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3141 glDisableClientState(GL_VERTEX_ARRAY);
3145void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3147 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3148 m_pParentCanvas->m_pQuilt->IsBusy())
3152 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3161 LLRegion region = vp.GetLLRegion(rect_region);
3163 LLRegion rendered_region;
3169 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3177 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3179 LLRegion get_region = pqp->ActiveRegion;
3180 bool b_rendered =
false;
3182 if (!pqp->b_overlay) {
3183 get_region.Intersect(region);
3184 if (!get_region.Empty()) {
3185 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3188 SetClipRegion(vp, get_region );
3189 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3190 DisableClipRegion();
3193 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3194 SetClipRegion(vp, pqp->ActiveRegion );
3195 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3197 DisableClipRegion();
3200 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3201 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3202 RenderNoDTA(vp, get_region);
3203 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3208 if (Chs57->m_RAZBuilt) {
3209 RenderNoDTA(vp, get_region);
3210 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3211 rect_region, get_region);
3212 DisableClipRegion();
3217 const LLRegion &oregion = get_region;
3218 LLBBox box = oregion.GetBox();
3229 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3232 ViewPort cvp = ClippedViewport(vp, get_region);
3233 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3234 SetClipRegion(cvp, get_region);
3235 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3236 GetGlobalColor(
"LANDA"), GetGlobalColor(
"DEPMS"));
3237 RenderWorldChart(gldc, cvp, srect, world);
3238 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3239 global_color_scheme);
3240 DisableClipRegion();
3247 SetClipRegion(vp, get_region);
3248 RenderNoDTA(vp, get_region);
3249 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3251 DisableClipRegion();
3254 SetClipRegion(vp, get_region);
3255 RenderNoDTA(vp, get_region);
3256 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3258 DisableClipRegion();
3274 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3278 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3279 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3281 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3282 if (pqp->b_Valid && pqp->b_overlay &&
3283 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3284 LLRegion get_region = pqp->ActiveRegion;
3286 get_region.Intersect(region);
3287 if (!get_region.Empty()) {
3290 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3295 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3302 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3307 ViewPort vph = m_pParentCanvas->GetVP();
3308 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3311 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3313 if (!hiregion.Empty()) {
3317 switch (global_color_scheme) {
3318 case GLOBAL_COLOR_SCHEME_DAY:
3321 case GLOBAL_COLOR_SCHEME_DUSK:
3324 case GLOBAL_COLOR_SCHEME_NIGHT:
3332#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3334 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3336 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3339 DrawRegion(vp, hiregion);
3341 glDisable(GL_BLEND);
3346 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3348 if (!hiregion.Empty()) {
3352 switch (global_color_scheme) {
3353 case GLOBAL_COLOR_SCHEME_DAY:
3356 case GLOBAL_COLOR_SCHEME_DUSK:
3359 case GLOBAL_COLOR_SCHEME_NIGHT:
3368#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3370 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3372 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3375 DrawRegion(vp, hiregion);
3377 glDisable(GL_BLEND);
3381 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3384void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3386 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3387 m_pParentCanvas->m_pQuilt->IsBusy())
3391 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3393 LLRegion region = vp.GetLLRegion(rect_region);
3395 LLRegion rendered_region;
3397 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3399 LLRegion get_region = pqp->ActiveRegion;
3401 if (!pqp->b_overlay) {
3402 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3405 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3410 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3417 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3445void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3446 ViewPort &vp = m_pParentCanvas->VPoint;
3454 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3455 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3458 LLRegion chart_region;
3460 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3461 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3462 CHART_FAMILY_RASTER) {
3470 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3471 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3472 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3474 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3478 for (
int i = 1; i < 6; i += 2)
3479 if (fabs(ll[i] - ll[i + 2]) > 180) {
3481 for (
int i = 1; i < 8; i += 2)
3482 if (ll[i] < 0) ll[i] += 360;
3486 chart_region = LLRegion(4, ll);
3489 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3491 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3492 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3493 chart_region = LLRegion(4, ll);
3496 chart_region = vp.b_quilt
3497 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3498 : m_pParentCanvas->m_singleChart->GetValidRegion();
3500 bool world_view =
false;
3502 wxRect rect = upd.GetRect();
3503 LLRegion background_region = vp.GetLLRegion(rect);
3506 background_region.Subtract(chart_region);
3508 if (!background_region.Empty()) {
3509 ViewPort cvp = ClippedViewport(vp, background_region);
3510 SetClipRect(cvp, rect,
false);
3511 RenderWorldChart(dc, cvp, rect, world_view);
3512 DisableClipRegion();
3517 RenderQuiltViewGL(vp, rect_region);
3519 LLRegion region = vp.GetLLRegion(rect_region);
3520 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3521 CHART_FAMILY_RASTER) {
3522 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3523 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3524 *m_pcontext, vp, rect_region, region);
3526 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3527 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3528 CHART_FAMILY_VECTOR) {
3529 chart_region.Intersect(region);
3530 RenderNoDTA(vp, chart_region);
3531 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3532 rect_region, region);
3538void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3540 wxColour color = GetGlobalColor(
"NODTA");
3541#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3543 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3545 glColor4ub(163, 180, 183, transparency);
3548 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3552 s_regionColor = color;
3555 DrawRegion(vp, region);
3559void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3562 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3564 glEnable(GL_SCISSOR_TEST);
3565 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3571 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3572#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3574 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3578 colorv[0] = water.Red() / float(256);
3579 colorv[1] = water.Green() / float(256);
3580 colorv[2] = water.Blue() / float(256);
3582 shader->SetUniform4fv(
"color", colorv);
3593 shader->SetAttributePointerf(
"position", pf);
3595 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3607 glDisable(GL_SCISSOR_TEST);
3615void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3616 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3618 DrawStaticRoutesTracksAndWaypoints(vp);
3620 DisableClipRegion();
3623void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3625 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3629 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3630 if (!bmp.Ok())
return;
3632 wxImage image = bmp.ConvertToImage();
3633 int w = image.GetWidth(), h = image.GetHeight();
3636 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3637 tex_w = w, tex_h = h;
3639 tex_w = NextPow2(w), tex_h = NextPow2(h);
3641 m_tideTexWidth = tex_w;
3642 m_tideTexHeight = tex_h;
3644 unsigned char *d = image.GetData();
3645 unsigned char *a = image.GetAlpha();
3647 unsigned char mr, mg, mb;
3648 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3650 unsigned char *e =
new unsigned char[4 * w * h];
3652 for (
int y = 0; y < h; y++)
3653 for (
int x = 0; x < w; x++) {
3654 unsigned char r, g, b;
3655 int off = (y * w + x);
3665 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3669 glGenTextures(1, &m_tideTex);
3671 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3672 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3673 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3675 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3676 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3677 GL_UNSIGNED_BYTE, e);
3679 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3680 GL_UNSIGNED_BYTE, 0);
3681 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3690 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3691 glEnable(GL_TEXTURE_2D);
3694#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3696 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
3697 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
3700 if ((type ==
't') || (type ==
'T'))
3705 if (BBox.Contains(lat, lon)) {
3714 scale *= getAndroidDisplayDensity();
3716 double width2 =
scale * m_tideTexWidth / 2;
3717 double height2 =
scale * m_tideTexHeight / 2;
3732 coords[0] = xp - width2;
3733 coords[1] = yp - height2;
3734 coords[2] = xp - width2;
3735 coords[3] = yp + height2;
3736 coords[4] = xp + width2;
3737 coords[5] = yp + height2;
3738 coords[6] = xp + width2;
3739 coords[7] = yp - height2;
3741 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3748 glDisable(GL_TEXTURE_2D);
3749 glDisable(GL_BLEND);
3750 glBindTexture(GL_TEXTURE_2D, 0);
3752 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3755void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3756 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3759void glChartCanvas::SetColorScheme(ColorScheme cs) {
3760 if (!m_bsetup)
return;
3762 glDeleteTextures(1, &m_tideTex);
3763 glDeleteTextures(1, &m_currentTex);
3769void glChartCanvas::RenderGLAlertMessage() {
3770 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3771 wxString msg = m_pParentCanvas->GetAlertString();
3774 m_gldc.SetFont(*pfont);
3778 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3785 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3786 int xp = sbr.x + sbr.width + 5;
3788 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
3789 m_gldc.SetPen(ppPen1);
3790 m_gldc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
3792 m_gldc.DrawRectangle(xp, yp, w, h);
3794 m_gldc.DrawText(msg, xp, yp);
3798unsigned long quiltHash;
3800extern wxLongLong s_t0;
3803void glChartCanvas::Render() {
3804 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3805 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3806 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3811 if (!g_PrintingInProgress)
return;
3814 if (m_binPinch)
return;
3816#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3817 loadShaders(GetCanvasIndex());
3818 configureShaders(m_pParentCanvas->VPoint);
3821#ifdef USE_ANDROID_GLES2
3825 if (m_binPinch)
return;
3834 bool recompose =
false;
3835 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3836 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3837 if (m_pParentCanvas->VPoint.IsValid()) {
3838 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3839 m_pParentCanvas->UpdateCanvasControlBar();
3848 if (sw.GetTime() > 2000) {
3854 s_tess_vertex_idx = 0;
3855 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3856 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3862 m_displayScale = GetContentScaleFactor();
3866 m_last_render_time = wxDateTime::Now().GetTicks();
3870 if (g_GLOptions.m_bTextureCompression &&
3871 !g_GLOptions.m_bTextureCompressionCaching)
3876 int gl_width, gl_height;
3877 gl_width = m_pParentCanvas->VPoint.
pix_width;
3878 gl_height = m_pParentCanvas->VPoint.
pix_height;
3881 m_glcanvas_width = gl_width;
3882 m_glcanvas_height = gl_height;
3886 if (gl_height & 1) {
3888 ViewPort *vp = m_pParentCanvas->GetpVP();
3895 ViewPort *vp = m_pParentCanvas->GetpVP();
3903 ViewPort *vp = m_pParentCanvas->GetpVP();
3906 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3909 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3917 ViewPort VPoint = m_pParentCanvas->VPoint;
3919 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3920 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
3923#if !defined(USE_ANDROID_GLES2)
3924 glMatrixMode(GL_PROJECTION);
3927 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
3928 glMatrixMode(GL_MODELVIEW);
3932 if (s_b_useStencil) {
3933 glEnable(GL_STENCIL_TEST);
3934 glStencilMask(0xff);
3935 glClear(GL_STENCIL_BUFFER_BIT);
3936 glDisable(GL_STENCIL_TEST);
3942 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
3943 if (g_GLOptions.m_GLPolygonSmoothing)
3944 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
3945 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3957 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
3958 bool useFBO =
false;
3964 if (m_b_BuiltFBO && !bpost_hilite
3969 bool b_newview =
true;
3970 bool b_full =
false;
3978 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
3982#ifdef USE_ANDROID_GLES2
3983 if (recompose) b_newview =
true;
3995 if (VPoint.b_quilt) {
3996 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3997 if (!chart) b_full =
true;
4006 bool accelerated_pan =
false;
4016 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4017 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4018 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4020 wxPoint2DDouble c_old =
4023 wxPoint2DDouble c_new =
4027 dy = wxRound(c_new.m_y - c_old.m_y);
4028 dx = wxRound(c_new.m_x - c_old.m_x);
4038 double deltax = c_new.m_x - c_old.m_x;
4039 double deltay = c_new.m_y - c_old.m_y;
4041 bool b_whole_pixel =
true;
4042 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4043 b_whole_pixel =
false;
4045 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4046 abs(dy) < m_cache_tex_y &&
4047 (abs(dx) > 0 || (abs(dy) > 0));
4056 if (m_displayScale > 1) accelerated_pan =
false;
4061 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4064#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4067 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4073 if (b_full) accelerated_pan =
false;
4075 if (accelerated_pan) {
4076 if ((dx != 0) || (dy != 0)) {
4088 if (dy > 0 && dy < gl_height)
4089 update_region.Union(
4090 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4092 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4094 if (dx > 0 && dx < gl_width)
4095 update_region.Union(
4096 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4098 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4100 m_cache_page = !m_cache_page;
4103 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4104 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4116 RenderCharts(m_gldc, update_region);
4120 glDisable(g_texture_rectangle_format);
4125 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4126 glEnable(GL_TEXTURE_2D);
4130 float x1, x2, y1, y2;
4143 float tx1, tx2, ty1, ty2;
4149 tx2 = sx / (float)m_cache_tex_x;
4151 ty2 = sy / (float)m_cache_tex_y;
4168 coords[2] = -dx + sx;
4170 coords[4] = -dx + sx;
4171 coords[5] = dy + sy;
4173 coords[7] = dy + sy;
4176 ptexture_2D_shader_program[GetCanvasIndex()];
4180 shader->SetUniform1i(
"uTex", 0);
4184 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4185 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4186 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4188 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4210 shader->SetAttributePointerf(
"aPos", co1);
4211 shader->SetAttributePointerf(
"aUV", tco1);
4213 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4216 shader->SetUniformMatrix4fv(
"MVMatrix",
4217 (GLfloat *)VPoint.vp_matrix_transform);
4220 glBindTexture(g_texture_rectangle_format, 0);
4222 glDisable(g_texture_rectangle_format);
4230 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4231 g_texture_rectangle_format,
4232 m_cache_tex[!m_cache_page], 0);
4243 wxColour color = GetGlobalColor(
"NODTA");
4244 glClearColor(color.Red() / 256., color.Green() / 256.,
4245 color.Blue() / 256., 1.0);
4246 glClear(GL_COLOR_BUFFER_BIT);
4252 RenderCharts(m_gldc, rscreen_region);
4257 m_cache_page = !m_cache_page;
4262 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4273 glMatrixMode(GL_PROJECTION);
4276 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4277 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4279 glMatrixMode(GL_MODELVIEW);
4283 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4284 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4286 glGetIntegerv(GL_VIEWPORT, viewport);
4287 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4288 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4297 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4298 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4299 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4301 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4305 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4306 glEnable(g_texture_rectangle_format);
4308 float tx, ty, tx0, ty0, divx, divy;
4311 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4314 divx = m_cache_tex_x;
4315 divy = m_cache_tex_y;
4318 tx0 = m_fbo_offsetx / divx;
4319 ty0 = m_fbo_offsety / divy;
4320 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4321 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4346 wxColour color = GetGlobalColor(
"NODTA");
4347 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4349 glClear(GL_COLOR_BUFFER_BIT);
4351 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4354 glDisable(g_texture_rectangle_format);
4356 m_cache_vp = VPoint;
4357 m_cache_vp.Validate();
4359 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4361 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4365 RenderCharts(m_gldc, screen_region);
4370 RenderS57TextOverlay(VPoint);
4371 RenderMBTilesOverlay(VPoint);
4375 g_pi_manager->SendViewPortToRequestingPlugIns(VPoint);
4376 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4377 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
4382 wxRect rt = upd.GetRect();
4383 LLRegion region = VPoint.GetLLRegion(rt);
4384 ViewPort cvp = ClippedViewport(VPoint, region);
4385 DrawGroundedOverlayObjects(gldc, cvp);
4388 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4389 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4390 LLBBox screenBox = screenLLRegion.GetBox();
4392 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4395 if (m_pParentCanvas->m_bShowTide) {
4396 m_pParentCanvas->RebuildTideSelectList(screenBox);
4397 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4400 if (m_pParentCanvas->m_bShowCurrent) {
4401 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4402 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4408 if (m_pParentCanvas->m_show_focus_bar &&
4409 (g_canvasConfig != 0)) {
4410 if (m_pParentCanvas == wxWindow::FindFocus()) {
4413 wxColour colour = GetGlobalColor(
"BLUE4");
4414 wxPen ppBlue(colour, 1);
4415 wxBrush ppBrush(colour);
4416 gldc.SetPen(ppBlue);
4417 gldc.SetBrush(ppBrush);
4418 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4419 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4420 wxPoint barPoints[4];
4423 barPoints[1].x = xw;
4425 barPoints[2].x = xw;
4426 barPoints[2].y = rect_pix;
4428 barPoints[3].y = rect_pix;
4430 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4434 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4438 DrawFloatingOverlayObjects(m_gldc);
4440#ifndef USE_ANDROID_GLES2
4443 glMatrixMode(GL_PROJECTION);
4446 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4447 glMatrixMode(GL_MODELVIEW);
4452 if (!g_bhide_depth_units)
4453 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4454 if (!g_bhide_overzoom_flag)
4455 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4458 ViewPort &vp = m_pParentCanvas->GetVP();
4459 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4460 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4463 if (!g_PrintingInProgress) {
4464 if (m_pParentCanvas->m_pTrackRolloverWin)
4465 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4467 if (m_pParentCanvas->m_pRouteRolloverWin)
4468 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4470 if (m_pParentCanvas->m_pAISRolloverWin)
4471 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4473 if (m_pParentCanvas->GetMUIBar())
4474 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4476 if (g_MainToolbar && m_pParentCanvas->IsPrimaryCanvas())
4477 g_MainToolbar->DrawGL(gldc, m_displayScale);
4488 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4489 int x, y, width, height;
4490 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4491 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4492 wxBitmap bmp(width, height, -1);
4495 dc.SetBackground(wxBrush(GetGlobalColor(
"UIBCK")));
4498 dc.SetTextBackground(GetGlobalColor(
"UIBCK"));
4499 dc.SetTextForeground(GetGlobalColor(
"UITX1"));
4503 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4504 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4506 wxStringTokenizer tkz(s,
"\n");
4509 while (tkz.HasMoreTokens()) {
4510 token = tkz.GetNextToken();
4511 dc.DrawText(token, xt, yt);
4514 dc.SelectObject(wxNullBitmap);
4516 m_gldc.DrawBitmap(bmp, x, y,
false);
4522 if (g_bShowChartBar) DrawChartBar(m_gldc);
4524 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4526 m_pParentCanvas->m_Compass->Paint(gldc);
4528 if (m_pParentCanvas->IsPrimaryCanvas()) {
4529 auto ¬eman = NotificationManager::GetInstance();
4530 if (noteman.GetNotificationCount()) {
4531 m_pParentCanvas->m_notification_button->SetIconSeverity(
4532 noteman.GetMaxSeverity());
4533 if (m_pParentCanvas->m_notification_button->UpdateStatus()) Refresh();
4534 m_pParentCanvas->m_notification_button->Show(
true);
4535 m_pParentCanvas->m_notification_button->Paint(gldc);
4537 m_pParentCanvas->m_notification_button->Show(
false);
4540 RenderGLAlertMessage();
4543 ViewPort &vp = m_pParentCanvas->GetVP();
4544 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4545 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4547 glActiveTexture(GL_TEXTURE0);
4551 if (g_bquiting) DrawQuiting();
4552 if (g_bcompression_wait)
4553 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4558 if (g_b_needFinish) glFinish();
4568 m_pParentCanvas->PaintCleanup();
4570 m_bforcefull =
false;
4575void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4578 if (VPoint.b_quilt) {
4579 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4580 ps52plib->GetShowS57Text()) {
4581 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4582 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4587 ChPI->ClearPLIBTextList();
4589 ps52plib->ClearTextList();
4599 RenderQuiltViewGLText(vpx, screen_region);
4604void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4607 LLRegion &screenLLRegion) {
4612 if (chart == NULL)
return;
4619 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4621 wxFileName tileFile(chart->GetFullPath());
4623 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4625 if (!
ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4626 (tileSizeMB.GetLo() > 5000)) {
4629 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4630 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4631 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4638 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4642 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4645 std::vector<int> piano_active_array_tiles =
4646 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4647 bool bfound =
false;
4649 if (std::find(piano_active_array_tiles.begin(),
4650 piano_active_array_tiles.end(),
4651 dbIndex) != piano_active_array_tiles.end()) {
4656 piano_active_array_tiles.push_back(dbIndex);
4657 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4661void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4663 std::vector<int> stackIndexArray =
4664 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4665 unsigned int im = stackIndexArray.size();
4668 if (VPoint.b_quilt && im > 0) {
4669 bool regionVPBuilt =
false;
4671 LLRegion screenLLRegion;
4675 std::vector<int> tiles_to_show;
4676 for (
unsigned int is = 0; is < im; is++) {
4678 ChartData->GetChartTableEntry(stackIndexArray[is]);
4679 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4680 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4682 std::vector<int> piano_active_array_tiles =
4683 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4684 bool bfound =
false;
4686 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4687 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4688 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4696 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4697 piano_active_array_tiles);
4702 tiles_to_show.push_back(stackIndexArray[is]);
4703 if (!regionVPBuilt) {
4706 screenLLRegion = VPoint.GetLLRegion(screen_region);
4707 screenBox = screenLLRegion.GetBox();
4715 regionVPBuilt =
true;
4725 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4726 rit != tiles_to_show.rend(); ++rit) {
4727 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4729 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4730 rit != tiles_to_show.rend(); ++rit) {
4731 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4735 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4737 if (!hiregion.Empty()) {
4741 switch (global_color_scheme) {
4742 case GLOBAL_COLOR_SCHEME_DAY:
4745 case GLOBAL_COLOR_SCHEME_DUSK:
4748 case GLOBAL_COLOR_SCHEME_NIGHT:
4756#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4757 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4759 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4762 DrawRegion(VPoint, hiregion);
4764 glDisable(GL_BLEND);
4770void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4774 GetClientSize(&w, &h);
4776 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4777#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4778 glMatrixMode(GL_PROJECTION);
4781 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4782 glMatrixMode(GL_MODELVIEW);
4786 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4788 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4790 bool world_view =
false;
4791 RenderWorldChart(dc, cvp, rtex, world_view);
4798 glViewport(0, 0, (GLint)w, (GLint)h);
4799#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4800 glMatrixMode(GL_PROJECTION);
4803 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4804 glMatrixMode(GL_MODELVIEW);
4810void glChartCanvas::FastPan(
int dx,
int dy) {
4811#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4815void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4817 SetCurrent(*m_pcontext);
4818 float sx = GetSize().x;
4819 float sy = GetSize().y;
4820 glClear(GL_COLOR_BUFFER_BIT);
4823 GetClientSize(&w, &h);
4825 if (s_b_useStencil) {
4826 glEnable(GL_STENCIL_TEST);
4827 glStencilMask(0xff);
4828 glClear(GL_STENCIL_BUFFER_BIT);
4829 glDisable(GL_STENCIL_TEST);
4845 float sxfactor = sx / swidth;
4846 float syfactor = sy / sheight;
4848 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4849 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4850 sx * sx / swidth * 2, sy * sy / sheight * 2);
4851 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4852 glEnable(g_texture_rectangle_format);
4877 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4878 glBindTexture(g_texture_rectangle_format, 0);
4884 float tx, ty, tx0, ty0;
4894 glBindTexture(g_texture_rectangle_format, 0);
4897 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4898 glEnable(g_texture_rectangle_format);
4904 uv[0] = tx0 / m_cache_tex_x;
4905 uv[1] = ty / m_cache_tex_y;
4906 uv[2] = tx / m_cache_tex_x;
4907 uv[3] = ty / m_cache_tex_y;
4908 uv[4] = tx / m_cache_tex_x;
4909 uv[5] = ty0 / m_cache_tex_y;
4910 uv[6] = tx0 / m_cache_tex_x;
4911 uv[7] = ty0 / m_cache_tex_y;
4923 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4924 sx * sx / swidth, sy * sy / sheight);
4926 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4928 glDisable(g_texture_rectangle_format);
4929 glBindTexture(g_texture_rectangle_format, 0);
4936 wxColour color = GetGlobalColor(
"GREY1");
4937 float ht = -offset_y * (sy / sheight);
4938 wxRect r(0, sy - ht, w, ht);
4939 RenderColorRect(r, color);
4942 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
4943 RenderColorRect(rt, color);
4946 float w1 = -offset_x * sx / swidth;
4947 wxRect rl(0, 0, w1, sy);
4948 RenderColorRect(rl, color);
4951 float px = w1 + sx * sx / swidth;
4952 wxRect rr(px, 0, sx - px, sy);
4953 RenderColorRect(rr, color);
4962void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
4965 if (m_nRun < m_nTotal) {
4966 m_runoffsetx += m_offsetxStep;
4967 if (m_offsetxStep > 0)
4968 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
4970 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
4972 m_runoffsety += m_offsetyStep;
4973 if (m_offsetyStep > 0)
4974 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
4976 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
4978 m_runswidth += m_swidthStep;
4979 if (m_swidthStep > 0)
4980 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
4982 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
4984 m_runsheight += m_sheightStep;
4985 if (m_sheightStep > 0)
4986 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
4988 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
4993 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
4999 if (m_zoomFinaldx || m_zoomFinaldy) {
5000 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5003 m_zoomFinal =
false;
5007void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5009 int sx = GetSize().x;
5010 int sy = GetSize().y;
5012 m_lastfbo_offsetx = m_fbo_offsetx;
5013 m_lastfbo_offsety = m_fbo_offsety;
5014 m_lastfbo_swidth = m_fbo_swidth;
5015 m_lastfbo_sheight = m_fbo_sheight;
5017 float curr_fbo_offset_x = m_fbo_offsetx;
5018 float curr_fbo_offset_y = m_fbo_offsety;
5019 float curr_fbo_swidth = m_fbo_swidth;
5020 float curr_fbo_sheight = m_fbo_sheight;
5022 float fx = (float)cp_x / sx;
5023 float fy = 1.0 - (float)cp_y / sy;
5025 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5026 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5028 m_fbo_swidth = curr_fbo_swidth / factor;
5029 m_fbo_sheight = curr_fbo_sheight / factor;
5031 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5032 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5034 m_fbo_offsetx += post_x;
5035 m_fbo_offsety += post_y;
5046 float perStep = m_nStep / m_nTotal;
5048 if (zoomTimer.IsRunning()) {
5049 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5050 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5051 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5052 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5055 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5056 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5057 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5058 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5060 m_runoffsetx = m_lastfbo_offsetx;
5061 m_runoffsety = m_lastfbo_offsety;
5062 m_runswidth = m_lastfbo_swidth;
5063 m_runsheight = m_lastfbo_sheight;
5066 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5067 m_zoomFinal =
false;
5073void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5077 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5080 if (m_binPinch)
return;
5081 if (m_bpinchGuard)
return;
5083 int x =
event.GetOffset().x;
5084 int y =
event.GetOffset().y;
5086 int lx =
event.GetLastOffset().x;
5087 int ly =
event.GetLastOffset().y;
5092 switch (event.GetState()) {
5093 case GestureStarted:
5094 if (m_binPan)
break;
5098 m_binGesture =
true;
5102 case GestureUpdated:
5107 m_pParentCanvas->FreezePiano();
5109 m_pParentCanvas->ThawPiano();
5120 case GestureFinished:
5123 m_pParentCanvas->UpdateCanvasControlBar();
5126 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5130 case GestureCanceled:
5132 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5139 m_bgestureGuard =
true;
5140 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5141 m_bforcefull =
false;
5146float zoom_inc = 1.0;
5147bool first_zout =
false;
5149void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5150 float zoom_gain = 1.0;
5151 float zout_gain = 1.0;
5154 float total_zoom_val;
5156 float max_zoom_scale = 1000.;
5157 float min_zoom_scale = 2e8;
5159 if (event.GetScaleFactor() > 1)
5160 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5162 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5164 if (event.GetTotalScaleFactor() > 1)
5165 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5168 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5170 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5173 float max_zoom_scale = 1000.;
5174 if( cc1->GetVP().b_quilt) {
5175 int ref_index = cc1->GetQuiltRefChartdbIndex();
5182 float min_zoom_scale = 2e8;
5186 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5188 double projected_scale =
5189 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5191 switch (event.GetState()) {
5192 case GestureStarted:
5197 m_binGesture =
true;
5199 m_pinchStart =
event.GetCenterPoint();
5200 m_lpinchPoint = m_pinchStart;
5203 event.GetCenterPoint().y, m_pinchlat,
5208 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5209 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5212 SetCurrent(*m_pcontext);
5218 case GestureUpdated:
5220 if (projected_scale < min_zoom_scale) {
5221 wxPoint pinchPoint =
event.GetCenterPoint();
5223 float dx = pinchPoint.x - m_lpinchPoint.x;
5224 float dy = pinchPoint.y - m_lpinchPoint.y;
5226 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5227 -dx / total_zoom_val, dy / total_zoom_val);
5229 m_lpinchPoint = pinchPoint;
5233 if (1 || ((total_zoom_val > 1) && !first_zout)) {
5234 wxPoint pinchPoint =
event.GetCenterPoint();
5236 float dx = pinchPoint.x - m_lpinchPoint.x;
5237 float dy = pinchPoint.y - m_lpinchPoint.y;
5239 if ((projected_scale > max_zoom_scale) &&
5240 (projected_scale < min_zoom_scale))
5241 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5242 -dx / total_zoom_val, dy / total_zoom_val);
5244 m_lpinchPoint = pinchPoint;
5248 zoom_inc *= zoom_val;
5249 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5250 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5254 wxPoint pinchPoint =
event.GetCenterPoint();
5255 float dx = pinchPoint.x - m_lpinchPoint.x;
5256 float dy = pinchPoint.y - m_lpinchPoint.y;
5258 m_lpinchPoint = pinchPoint;
5269 case GestureFinished: {
5273 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5274 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5278 float tzoom = total_zoom_val;
5280 if (projected_scale >= min_zoom_scale)
5281 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5283 if (projected_scale < max_zoom_scale)
5284 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5286 dx = (cc_x - m_cc_x) * tzoom;
5287 dy = -(cc_y - m_cc_y) * tzoom;
5289 if (zoomTimer.IsRunning()) {
5292 m_zoomFinalZoom = tzoom;
5298 double final_projected_scale =
5302 if (final_projected_scale < min_zoom_scale) {
5306 m_pParentCanvas->m_pQuilt->Invalidate();
5307 m_bforcefull =
true;
5314 m_pParentCanvas->m_pQuilt->Invalidate();
5315 m_bforcefull =
true;
5327 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5331 case GestureCanceled:
5333 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5340 m_bgestureGuard =
true;
5342 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5345void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5355 m_bgestureGuard =
false;
5356 m_bpinchGuard =
false;
5357 m_binGesture =
false;
5358 m_bforcefull =
false;
5361void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5365 m_binGesture =
false;
5366 m_bforcefull =
false;
5370#ifdef HAVE_WX_GESTURE_EVENTS
5372void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5376 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5379 if (m_binPinch)
return;
5380 if (m_bpinchGuard)
return;
5382 int dx =
event.GetDelta().x;
5383 int dy =
event.GetDelta().y;
5385 if (event.IsGestureStart()) {
5386 if (m_binPan)
return;
5390 m_binGesture =
true;
5394 else if (event.IsGestureEnd()) {
5396 m_pParentCanvas->UpdateCanvasControlBar();
5398 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5406 m_pParentCanvas->FreezePiano();
5408 m_pParentCanvas->ThawPiano();
5419 m_bgestureGuard =
true;
5420 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5421 m_bforcefull =
false;
5424bool first_zout =
false;
5427void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5428 float zoom_gain = 1.0;
5429 float zout_gain = 1.0;
5431 float last_zoom_val = m_total_zoom_val;
5433 float max_zoom_scale = 1000.;
5434 float min_zoom_scale = 2e8;
5436 if (event.GetZoomFactor() > 1)
5437 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5439 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5441 float inc_zoom_val =
5442 m_total_zoom_val / last_zoom_val;
5444 double projected_scale =
5445 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5447 if (event.IsGestureStart()) {
5453 m_binGesture =
true;
5454 m_pinchStart =
event.GetPosition();
5455 m_lpinchPoint = m_pinchStart;
5456 m_total_zoom_val = 1.0;
5457 m_final_zoom_val = 1.0;
5460 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5464 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5465 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5468 SetCurrent(*m_pcontext);
5471 ViewPort vpr = m_pParentCanvas->VPoint;
5473 GetTouchBackingBitmap(vpr);
5478 if (event.IsGestureEnd()) {
5484 if (!m_binGesture)
return;
5486 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5487 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5491 float tzoom = m_final_zoom_val;
5493 dx = (cc_x - m_cc_x) * tzoom;
5494 dy = -(cc_y - m_cc_y) * tzoom;
5496 if (zoomTimer.IsRunning()) {
5499 m_zoomFinalZoom = tzoom;
5505 double final_projected_scale =
5509 if (final_projected_scale < min_zoom_scale) {
5513 m_pParentCanvas->m_pQuilt->Invalidate();
5514 m_bforcefull =
true;
5521 m_pParentCanvas->m_pQuilt->Invalidate();
5522 m_bforcefull =
true;
5527 m_final_zoom_val = 1.0;
5528 m_total_zoom_val = 1.0;
5529 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5534 if (projected_scale < min_zoom_scale) {
5535 wxPoint pinchPoint =
event.GetPosition();
5537 float dx = pinchPoint.x - m_lpinchPoint.x;
5538 float dy = pinchPoint.y - m_lpinchPoint.y;
5540 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5541 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5543 m_lpinchPoint = pinchPoint;
5544 m_final_zoom_val *= inc_zoom_val;
5548 if (1 || ((m_total_zoom_val > 1) && !first_zout)) {
5549 wxPoint pinchPoint =
event.GetPosition();
5551 float dx = pinchPoint.x - m_lpinchPoint.x;
5552 float dy = pinchPoint.y - m_lpinchPoint.y;
5554 if ((projected_scale > max_zoom_scale) &&
5555 (projected_scale < min_zoom_scale))
5556 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5557 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5559 m_lpinchPoint = pinchPoint;
5560 m_final_zoom_val *= inc_zoom_val;
5564 m_zoom_inc *= inc_zoom_val;
5565 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5566 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5570 wxPoint pinchPoint =
event.GetPosition();
5571 float dx = pinchPoint.x - m_lpinchPoint.x;
5572 float dy = pinchPoint.y - m_lpinchPoint.y;
5574 m_lpinchPoint = pinchPoint;
5578 m_bgestureGuard =
true;
5579 m_bpinchGuard =
true;
5580 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5583void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5593 m_bgestureGuard =
false;
5594 m_bpinchGuard =
false;
5595 m_binGesture =
false;
5596 m_bforcefull =
false;
5599void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5603 m_binGesture =
false;
5604 m_bforcefull =
false;
5610void glChartCanvas::configureShaders(
ViewPort &vp) {
5611#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5617 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5619 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5620 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5641 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5643 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5644 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5656 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5658 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5659 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5662 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5664 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5665 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5673 shader = pAALine_shader_program[GetCanvasIndex()];
5675 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5678 shader = pring_shader_program[GetCanvasIndex()];
5680 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5681 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5685 if (texture_2DA_shader_program) {
5686 glUseProgram(texture_2DA_shader_program);
5687 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5688 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5689 (
const GLfloat *)pvp->vp_matrix_transform);
5691 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5692 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5700void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5703#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5704 int nl = nVertex / 4;
5706 float *luv = uvCoords;
5709 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5717 glEnableClientState(GL_VERTEX_ARRAY);
5718 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5720 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5721 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5722 glDrawArrays(GL_QUADS, 0, 4);
5729void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5730 float *uvCoords,
ViewPort *vp,
float dx,
5731 float dy,
float angle_rad) {
5732#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5734 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5735 if (!shader)
return;
5740 shader->SetUniform1i(
"uTex", 0);
5745 mat4x4_rotate_Z(Q, I, angle_rad);
5751 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5756 shader->SetAttributePointerf(
"aPos", co1);
5757 shader->SetAttributePointerf(
"aUV", tco1);
5764 GLushort indices1[] = {0,1,3,2};
5765 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5777 tco1[0] = uvCoords[0];
5778 tco1[1] = uvCoords[1];
5779 tco1[2] = uvCoords[2];
5780 tco1[3] = uvCoords[3];
5781 tco1[4] = uvCoords[6];
5782 tco1[5] = uvCoords[7];
5783 tco1[6] = uvCoords[4];
5784 tco1[7] = uvCoords[5];
5789 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5801void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5802#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5804 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5807 shader->SetUniformMatrix4fv(
5808 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5811 colorv[0] = color.Red() / float(256);
5812 colorv[1] = color.Green() / float(256);
5813 colorv[2] = color.Blue() / float(256);
5815 shader->SetUniform4fv(
"color", colorv);
5818 pf[0] = r.x + r.width;
5822 pf[4] = r.x + r.width;
5823 pf[5] = r.y + r.height;
5825 pf[7] = r.y + r.height;
5826 shader->SetAttributePointerf(
"position", pf);
5828 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5836void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5837#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5839 ViewPort VPoint = m_pParentCanvas->VPoint;
5843 GetClientSize(&w, &h);
5844 int sx = GetSize().x;
5845 int sy = GetSize().y;
5849 glViewport(0, 0, (GLint)w, (GLint)h);
5851 if (s_b_useStencil) {
5852 glEnable(GL_STENCIL_TEST);
5853 glStencilMask(0xff);
5854 glClear(GL_STENCIL_BUFFER_BIT);
5855 glDisable(GL_STENCIL_TEST);
5859 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5864 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5865 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5866 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5869 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5871 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5872 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5880 if (bRenderCharts) RenderCharts(gldc, screen_region);
5882 if (bRenderOverlays) {
5883 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5884 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5888 g_pi_manager->SendViewPortToRequestingPlugIns(VPoint);
5889 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
5890 m_pcontext, VPoint, m_pParentCanvas->m_canvasIndex,
OVERLAY_CHARTS);
5893 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5894 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5895 DrawFloatingOverlayObjects(m_gldc);
5899 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5904wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5906 wxMemoryDC tdc(tbm);
5907 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5915 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5916 dc.SetPen(*wxTRANSPARENT_PEN);
5919 tdc.SelectObject(wxNullBitmap);
5920 m_touch_backing_bitmap = tbm;
5921 CreateBackingTexture();
5923 return m_touch_backing_bitmap;
5926void glChartCanvas::CreateBackingTexture() {
5927 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5928 unsigned char *imgdata = image.GetData();
5929 unsigned char *imgalpha = image.GetAlpha();
5930 m_tex_w = image.GetWidth();
5931 m_tex_h = image.GetHeight();
5932 m_image_width = m_tex_w;
5933 m_image_height = m_tex_h;
5935 GLuint format = GL_RGBA;
5936 GLuint internalformat = g_texture_rectangle_format;
5938 internalformat = GL_RGBA;
5943 unsigned char *teximage =
5944 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
5946 for (
int i = 0; i < m_image_height; i++) {
5947 for (
int j = 0; j < m_image_width; j++) {
5948 int s = (i * 3 * m_image_width) + (j * 3);
5949 int d = (i * stride * m_tex_w) + (j * stride);
5951 teximage[d + 0] = imgdata[s + 0];
5952 teximage[d + 1] = imgdata[s + 1];
5953 teximage[d + 2] = imgdata[s + 2];
5954 teximage[d + 3] = 255;
5958 glGenTextures(1, &m_TouchBackingTexture);
5959 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
5961 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5962 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5963 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
5965 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5967 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
5968 GL_UNSIGNED_BYTE, teximage);
5971 glBindTexture(GL_TEXTURE_2D, 0);
Wrapper for creating a ChartCtx based on global vars.
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
Represents an active track that is currently being recorded.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
float GetVPChartScale()
Return the ViewPort chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Wrapper class for OpenGL shader programs.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
Represents a navigational route in the navigation system.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
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.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
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.
int g_mipmap_max_level
Global instance.
Miscellaneous globals primarely used by gui layer.
Class NotificationManager.
#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.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
ShapeBaseChartSet gShapeBasemap
global instance
Tools to send data to plugins.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents an entry in the chart table, containing information about a single chart.