40#include <wx/arrimpl.cpp>
43#include <wx/dcmemory.h>
44#include <wx/dynarray.h>
48#include <wx/glcanvas.h>
50#include <wx/jsonval.h>
53#include <wx/progdlg.h>
54#include <wx/stopwatch.h>
56#include <wx/tokenzr.h>
60#include "model/own_ship.h"
62#include "model/route.h"
63#include "model/routeman.h"
64#include "model/track.h"
68#include "chart_ctx_factory.h"
74#include "color_handler.h"
77#include "emboss_data.h"
79#include "glChartCanvas.h"
80#include "glTexCache.h"
84#include "mipmap/mipmap.h"
86#include "OCPNPlatform.h"
88#include "pluginmanager.h"
90#include "RolloverWin.h"
92#include "route_point_gui.h"
101#include "iENCToolbar.h"
102#include "shapefile_basemap.h"
103#include "s57_ocpn_utils.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
125#if defined(__UNIX__) && !defined(__WXOSX__)
130 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
134 clock_gettime(CLOCK_REALTIME, &tp_end);
135 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
136 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
145#define printf printf2
146int __cdecl printf2(
const char *format, ...);
149#if defined(__ANDROID__)
150#include "androidUTIL.h"
151#elif defined(__WXQT__) || defined(__WXGTK__) || defined(FLATPAK)
155#ifndef GL_ETC1_RGB8_OES
156#define GL_ETC1_RGB8_OES 0x8D64
164extern "C" void glOrthof(
float left,
float right,
float bottom,
float top,
165 float near,
float far);
166#define glOrtho(a, b, c, d, e, f) \
168 glOrthof(a, b, c, d, e, f);
176#ifdef USE_ANDROID_GLES2
177#include <GLES2/gl2.h>
180#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
185extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
187extern s52plib *ps52plib;
188extern bool g_bopengl;
189extern bool g_bDebugOGL;
190extern bool g_bSoftwareGL;
193extern bool g_bShowChartBar;
195extern bool b_inCompressAllCharts;
196extern bool g_bShowCompassWin;
198extern GLenum g_texture_rectangle_format;
200extern int g_memCacheLimit;
201extern ColorScheme global_color_scheme;
202extern bool g_bquiting;
204extern int g_mipmap_max_level;
206extern int g_OwnShipIconType;
212extern RouteList *pRouteList;
213extern std::vector<Track *> g_TrackList;
214extern bool b_inCompressAllCharts;
215extern bool g_bGLexpert;
216extern bool g_bcompression_wait;
217extern float g_ShipScaleFactorExp;
219float g_GLMinCartographicLineWidth;
221extern bool g_fog_overzoom;
222extern double g_overzoom_emphasis_base;
223extern bool g_oz_vector_scale;
225extern int g_nCPUCount;
226extern bool g_running;
228extern unsigned int g_canvasConfig;
232extern bool g_PrintingInProgress;
236wxColor s_regionColor;
248#define APIENTRYP APIENTRY *
254#ifndef GL_COMPRESSED_RGB_FXT1_3DFX
255#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
258PFNGLGENFRAMEBUFFERSEXTPROC s_glGenFramebuffers;
259PFNGLGENRENDERBUFFERSEXTPROC s_glGenRenderbuffers;
260PFNGLFRAMEBUFFERTEXTURE2DEXTPROC s_glFramebufferTexture2D;
261PFNGLBINDFRAMEBUFFEREXTPROC s_glBindFramebuffer;
262PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC s_glFramebufferRenderbuffer;
263PFNGLRENDERBUFFERSTORAGEEXTPROC s_glRenderbufferStorage;
264PFNGLBINDRENDERBUFFEREXTPROC s_glBindRenderbuffer;
265PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC s_glCheckFramebufferStatus;
266PFNGLDELETEFRAMEBUFFERSEXTPROC s_glDeleteFramebuffers;
267PFNGLDELETERENDERBUFFERSEXTPROC s_glDeleteRenderbuffers;
269PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
270PFNGLGETCOMPRESSEDTEXIMAGEPROC s_glGetCompressedTexImage;
273PFNGLGENBUFFERSPROC s_glGenBuffers;
274PFNGLBINDBUFFERPROC s_glBindBuffer;
275PFNGLBUFFERDATAPROC s_glBufferData;
276PFNGLDELETEBUFFERSPROC s_glDeleteBuffers;
278#ifndef USE_ANDROID_GLES2
283typedef void(APIENTRYP PFNGLGETBUFFERPARAMETERIV)(GLenum target, GLenum value,
285PFNGLGETBUFFERPARAMETERIV s_glGetBufferParameteriv;
287#include <wx/arrimpl.cpp>
290GLuint g_raster_format = GL_RGB;
294wxStopWatch g_glstopwatch;
295double g_gl_ms_per_frame;
298int g_uncompressed_tile_size;
300extern wxProgressDialog *pprog;
301extern bool b_skipout;
302extern wxSize pprog_size;
303extern int pprog_count;
304extern int pprog_threads;
311bool glChartCanvas::s_b_useScissorTest;
312bool glChartCanvas::s_b_useStencil;
313bool glChartCanvas::s_b_useStencilAP;
314bool glChartCanvas::s_b_useFBO;
316#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
317static int s_tess_vertex_idx;
318static int s_tess_vertex_idx_this;
319static int s_tess_buf_len;
320static GLfloat *s_tess_work_buf;
323static vec4 s_tess_color;
333 while ( upd.HaveRects() )
335 wxRect rect = upd.GetRect();
336 printf(
"[(%d, %d) (%d, %d)] ", rect.x, rect.y, rect.width, rect.height);
343GLboolean QueryExtension(
const char *extName) {
354 extNameLen = strlen(extName);
356 p = (
char *)glGetString(GL_EXTENSIONS);
364 int n = strcspn(p,
" ");
365 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
373int test_attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
374 16, WX_GL_STENCIL_SIZE, 8,
377glTestCanvas::glTestCanvas(wxWindow *parent)
378 : wxGLCanvas(parent, wxID_ANY, test_attribs, wxDefaultPosition,
382int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE,
383 16, WX_GL_STENCIL_SIZE, 8,
386EVT_PAINT(glChartCanvas::OnPaint)
387EVT_ACTIVATE(glChartCanvas::OnActivate)
388EVT_SIZE(glChartCanvas::OnSize)
389EVT_MOUSE_EVENTS(glChartCanvas::MouseEvent)
393 : wxGLCanvas(parent, wxID_ANY, attribs, wxDefaultPosition, wxSize(256, 256),
394 wxFULL_REPAINT_ON_RESIZE | wxBG_STYLE_CUSTOM, _T(""))
397 m_pParentCanvas =
dynamic_cast<ChartCanvas *
>(parent);
402std::unordered_map<wxPenStyle, std::array<wxDash, 2>> glChartCanvas::dash_map =
404 {wxPENSTYLE_DOT, {1, 1}},
405 {wxPENSTYLE_LONG_DASH, {5, 5}},
406 {wxPENSTYLE_SHORT_DASH, {1, 5}},
407 {wxPENSTYLE_DOT_DASH, {5, 1}},
410void glChartCanvas::Init() {
415 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
417 m_cache_current_ch = NULL;
419 m_b_paint_enable =
true;
420 m_in_glpaint =
false;
422 m_cache_tex[0] = m_cache_tex[1] = 0;
425 m_b_BuiltFBO =
false;
426 m_b_DisableFBO =
false;
435 m_bpinchGuard =
false;
436 m_binGesture =
false;
439 m_last_render_time = -1;
446 m_gldc.SetGLCanvas(
this);
449 m_displayScale = 1.0;
450#if defined(__WXOSX__) || defined(__WXGTK3__)
452 m_displayScale = GetContentScaleFactor();
461 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPanGesture,
465 wxEVT_QT_PINCHGESTURE,
466 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::OnEvtPinchGesture,
469 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
474 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
476 onGestureFinishTimerEvent,
480 ZOOM_TIMER, wxEVT_TIMER,
481 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
484 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
485 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
486 zoomTimer.SetOwner(
this, ZOOM_TIMER);
488#ifdef USE_ANDROID_GLES2
497#ifdef HAVE_WX_GESTURE_EVENTS
499 Connect(GESTURE_EVENT_TIMER, wxEVT_TIMER,
504 Connect(GESTURE_FINISH_TIMER, wxEVT_TIMER,
506 onGestureFinishTimerEvent,
510 ZOOM_TIMER, wxEVT_TIMER,
511 (wxObjectEventFunction)(wxEventFunction)&glChartCanvas::onZoomTimerEvent,
514 m_gestureEeventTimer.SetOwner(
this, GESTURE_EVENT_TIMER);
515 m_gestureFinishTimer.SetOwner(
this, GESTURE_FINISH_TIMER);
516 zoomTimer.SetOwner(
this, ZOOM_TIMER);
521 m_bgestureGuard =
false;
522 m_total_zoom_val = 1.0;
525#ifdef HAVE_WX_GESTURE_EVENTS
526 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
527 wxLogError(
"Failed to enable touch events");
536 Bind(wxEVT_GESTURE_ZOOM, &glChartCanvas::OnEvtZoomGesture,
this);
538 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress, m_pParentCanvas);
539 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap, m_pParentCanvas);
541 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp, m_pParentCanvas);
542 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown, m_pParentCanvas);
544 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp, m_pParentCanvas);
545 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown, m_pParentCanvas);
547 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel, m_pParentCanvas);
548 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion, m_pParentCanvas);
554glChartCanvas::~glChartCanvas() {
560void glChartCanvas::FlushFBO(
void) {
561 if (m_bsetup) BuildFBO();
564void glChartCanvas::OnActivate(wxActivateEvent &event) {
565 m_pParentCanvas->OnActivate(event);
568void glChartCanvas::OnSize(wxSizeEvent &event) {
572 wxLogMessage(_T(
"Got OnSize event while NOT running"));
574 qDebug() <<
"OnSizeB";
581 if (!IsShown())
return;
583 SetCurrent(*m_pcontext);
587 SetSize(GetSize().x, GetSize().y);
595 if (m_bsetup && m_pcontext && IsShown()) {
596 SetCurrent(*m_pcontext);
602 wxLogMessage(_T(
"BuildFBO 3"));
607 ViewPort *vp = m_pParentCanvas->GetpVP();
610 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
613 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
617void glChartCanvas::MouseEvent(wxMouseEvent &event) {
618 if (m_pParentCanvas->MouseEventOverlayWindows(event))
return;
624 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
626 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid)
629 if (!g_btouch) m_pParentCanvas->SetCanvasCursor(event);
633 if (m_bgestureGuard) {
634 m_pParentCanvas->r_rband.x = 0;
644 if (event.LeftUp()) {
646 if ((abs(panx) > 2) || (abs(pany) > 2)) {
649 m_gestureEeventTimer.Start(10, wxTIMER_ONE_SHOT);
656 if (!event.LeftDClick()) {
661 if (m_binPan && event.RightDown()) {
662 qDebug() <<
"Skip right on pan";
665 bool obj_proc = m_pParentCanvas->MouseEventProcessObjects(event);
667 if (!obj_proc && !m_pParentCanvas->singleClickEventIsValid) {
668 if (!m_bgestureGuard)
678#ifndef GL_MAX_RENDERBUFFER_SIZE
679#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
682#ifndef USE_ANDROID_GLES2
683bool glChartCanvas::buildFBOSize(
int fboSize) {
685 if (IsShown()) SetCurrent(*m_pcontext);
688 glDeleteTextures(2, m_cache_tex);
689 glDeleteFramebuffers(1, &m_fb0);
690 glDeleteRenderbuffers(1, &m_renderbuffer);
691 m_b_BuiltFBO =
false;
694 if (m_b_DisableFBO)
return false;
698 int rb_x = GetSize().x;
699 int rb_y = GetSize().y;
701 while (i < rb_x) i <<= 1;
705 while (i < rb_y) i <<= 1;
708 m_cache_tex_x = wxMax(rb_x, rb_y);
709 m_cache_tex_y = wxMax(rb_x, rb_y);
712 m_cache_tex_x = GetSize().x * m_displayScale;
713 m_cache_tex_y = GetSize().y * m_displayScale;
716 int err = GL_NO_ERROR;
718 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
721 if (err == GL_INVALID_ENUM) {
722 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
726 if (err == GL_NO_ERROR) {
727 if (fboSize > params) {
729 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
730 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
735 glGenFramebuffers(1, &m_fb0);
739 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
745 glGenRenderbuffers(1, &m_renderbuffer);
749 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
755 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
759 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
766 glGenTextures(2, m_cache_tex);
767 for (
int i = 0; i < 2; i++) {
768 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
769 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
771 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
773 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
774 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
777 glBindRenderbuffer(GL_RENDERBUFFER_EXT, m_renderbuffer);
779 if (m_b_useFBOStencil) {
781 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
782 m_cache_tex_x, m_cache_tex_y);
784 int err = glGetError();
787 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
791 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
792 GL_RENDERBUFFER_EXT, m_renderbuffer);
797 _T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"), err);
801 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
802 GL_RENDERBUFFER_EXT, m_renderbuffer);
807 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"),
813 GLenum depth_format = GL_DEPTH_COMPONENT24;
818 if (!QueryExtension(
"GL_OES_depth24")) depth_format = GL_DEPTH_COMPONENT16;
822 glRenderbufferStorage(GL_RENDERBUFFER_EXT, depth_format, m_cache_tex_x,
824 int err = glGetError();
828 _T(
" OpenGL-> Framebuffer Depth Buffer Storage error: %08X"),
834 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
835 GL_RENDERBUFFER_EXT, m_renderbuffer);
841 _T(
" OpenGL-> Framebuffer Depth Buffer Attach error: %08X"), err);
847 glBindTexture(GL_TEXTURE_2D, 0);
848 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
851 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
853 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
854 g_texture_rectangle_format, m_cache_tex[0], 0);
856 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
858 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
860 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
862 msg.Printf(_T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X"),
872#ifdef USE_ANDROID_GLES2
873bool glChartCanvas::buildFBOSize(
int fboSize) {
877 int rb_x = GetSize().x;
878 int rb_y = GetSize().y;
880 while (i < rb_x) i <<= 1;
884 while (i < rb_y) i <<= 1;
887 m_cache_tex_x = wxMax(rb_x, rb_y);
888 m_cache_tex_y = wxMax(rb_x, rb_y);
892 int err = GL_NO_ERROR;
894 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, ¶ms);
897 if (err == GL_INVALID_ENUM) {
898 glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶ms);
902 if (err == GL_NO_ERROR) {
903 if (fboSize > params) {
905 _T(
" OpenGL-> Requested Framebuffer size exceeds ")
906 _T(
"GL_MAX_RENDERBUFFER_SIZE"));
911 glGenFramebuffers(1, &m_fb0);
915 msg.Printf(_T(
" OpenGL-> Framebuffer GenFramebuffers error: %08X"),
921 glGenRenderbuffers(1, &m_renderbuffer);
925 msg.Printf(_T(
" OpenGL-> Framebuffer GenRenderbuffers error: %08X"),
931 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
935 msg.Printf(_T(
" OpenGL-> Framebuffer BindFramebuffers error: %08X"),
942 glGenTextures(2, m_cache_tex);
943 for (
int i = 0; i < 2; i++) {
944 glBindTexture(g_texture_rectangle_format, m_cache_tex[i]);
945 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
947 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
949 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, m_cache_tex_x,
950 m_cache_tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
953 glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
956 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_cache_tex_x,
962 msg.Printf(_T(
" OpenGL-> glRenderbufferStorage error: %08X"), err);
966 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
967 GL_RENDERBUFFER, m_renderbuffer);
971 msg.Printf(_T(
" OpenGL-> glFramebufferRenderbuffer depth error: %08X"),
976 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
977 GL_RENDERBUFFER, m_renderbuffer);
982 _T(
" OpenGL-> glFramebufferRenderbuffer stencil error: %08X"), err);
986 glBindTexture(GL_TEXTURE_2D, 0);
987 glBindFramebuffer(GL_FRAMEBUFFER, 0);
990 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
992 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
993 g_texture_rectangle_format, m_cache_tex[0], 0);
995 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
997 glBindFramebuffer(GL_FRAMEBUFFER, 0);
999 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
1002 _T(
" OpenGL-> buildFBOSize->Framebuffer Incomplete: %08X %08X"),
1012void glChartCanvas::BuildFBO() {
1015 glDeleteTextures(2, m_cache_tex);
1016 glDeleteFramebuffers(1, &m_fb0);
1017 glDeleteRenderbuffers(1, &m_renderbuffer);
1018 m_b_BuiltFBO =
false;
1021 if (m_b_DisableFBO)
return;
1024 int gl_width, gl_height;
1025 m_pParentCanvas->GetClientSize(&gl_width, &gl_height);
1026 int initialSize = NextPow2(gl_width * m_displayScale);
1031 wxString info = androidGetDeviceInfo();
1033 if (wxNOT_FOUND != info.Find(_T(
"GT-S6312"))) initialSize = 1024;
1036 if (!buildFBOSize(initialSize)) {
1037 glDeleteTextures(2, m_cache_tex);
1038 glDeleteFramebuffers(1, &m_fb0);
1039 glDeleteRenderbuffers(1, &m_renderbuffer);
1041 if (!buildFBOSize(1024)) {
1042 wxLogMessage(_T(
"BuildFBO C"));
1044 m_b_DisableFBO =
true;
1045 wxLogMessage(_T(
"OpenGL-> FBO Framebuffer unavailable"));
1046 m_b_BuiltFBO =
false;
1055 msg.Printf(_T(
"OpenGL-> Framebuffer OK, size = %d"), m_cache_tex_x);
1062 m_b_BuiltFBO =
true;
1067void glChartCanvas::SetupOpenGL() {
1068 SetCurrent(*m_pcontext);
1070 char *str = (
char *)glGetString(GL_RENDERER);
1073 wxLogMessage(_T(
"Failed to initialize OpenGL"));
1077 char render_string[80];
1078 strncpy(render_string, str, 79);
1079 m_renderer = wxString(render_string, wxConvUTF8);
1082 if (g_bSoftwareGL) msg.Printf(_T(
"OpenGL-> Software OpenGL"));
1083 msg.Printf(_T(
"OpenGL-> Renderer String: "));
1087 if (ps52plib) ps52plib->SetGLRendererString(m_renderer);
1089 char version_string[80];
1090 strncpy(version_string, (
char *)glGetString(GL_VERSION), 79);
1091 msg.Printf(_T(
"OpenGL-> Version reported: "));
1092 m_version = wxString(version_string, wxConvUTF8);
1096 char GLSL_version_string[80];
1097 strncpy(GLSL_version_string, (
char *)glGetString(GL_SHADING_LANGUAGE_VERSION),
1099 msg.Printf(_T(
"OpenGL-> GLSL Version reported: "));
1100 m_GLSLversion = wxString(GLSL_version_string, wxConvUTF8);
1101 msg += m_GLSLversion;
1106 GLenum err = glewInit();
1107#ifdef GLEW_ERROR_NO_GLX_DISPLAY
1108 if (GLEW_OK != err && GLEW_ERROR_NO_GLX_DISPLAY != err)
1113 printf(
"GLEW init failed: %s\n", glewGetErrorString(err));
1116 wxLogMessage(
"GLEW init success!n");
1121 const GLubyte *ext_str = glGetString(GL_EXTENSIONS);
1122 m_extensions = wxString((
const char *)ext_str, wxConvUTF8);
1126#ifndef USE_ANDROID_GLES2
1127 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
1129 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
1131 g_GLMinSymbolLineWidth = wxMax(parms[0], 1);
1132 g_GLMinCartographicLineWidth = wxMax(parms[0], 1);
1139 if (m_renderer.Upper().Find(_T(
"MESA")) != wxNOT_FOUND) {
1141 glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &parf);
1143 g_GLMinSymbolLineWidth = wxMax(((
float)parms[0] + parf), 1);
1146 s_b_useScissorTest =
true;
1148 if (GetRendererString().Find(_T(
"RADEON X600")) != wxNOT_FOUND)
1149 s_b_useScissorTest =
false;
1151 if (GetRendererString().Find(_T(
"GeForce")) !=
1153 s_b_useScissorTest =
false;
1155 bool bad_stencil_code =
false;
1158 if (GetRendererString().Find(_T(
"UniChrome")) != wxNOT_FOUND)
1159 bad_stencil_code =
true;
1162 if (GetRendererString().Find(_T(
"Mali")) != wxNOT_FOUND)
1163 bad_stencil_code =
true;
1166 glEnable(GL_STENCIL_TEST);
1167 GLboolean stencil = glIsEnabled(GL_STENCIL_TEST);
1169 glGetIntegerv(GL_STENCIL_BITS, &sb);
1172 glDisable(GL_STENCIL_TEST);
1174 s_b_useStencil =
false;
1175 if (stencil && (sb == 8)) s_b_useStencil =
true;
1177 if (QueryExtension(
"GL_ARB_texture_non_power_of_two"))
1178 g_texture_rectangle_format = GL_TEXTURE_2D;
1179 else if (QueryExtension(
"GL_OES_texture_npot"))
1180 g_texture_rectangle_format = GL_TEXTURE_2D;
1181 else if (QueryExtension(
"GL_ARB_texture_rectangle"))
1182 g_texture_rectangle_format = GL_TEXTURE_RECTANGLE_ARB;
1183 wxLogMessage(wxString::Format(_T(
"OpenGL-> Texture rectangle format: %x"),
1184 g_texture_rectangle_format));
1187 g_texture_rectangle_format = GL_TEXTURE_2D;
1191 g_b_EnableVBO =
true;
1194 g_b_EnableVBO =
false;
1198 wxLogMessage(_T(
"OpenGL-> Using Vertexbuffer Objects"));
1200 wxLogMessage(_T(
"OpenGL-> Vertexbuffer Objects unavailable"));
1204 m_b_useFBOStencil = QueryExtension(
"GL_OES_packed_depth_stencil");
1206 m_b_useFBOStencil = QueryExtension(
"GL_EXT_packed_depth_stencil") == GL_TRUE;
1209#ifndef USE_ANDROID_GLES2
1211 if (bad_stencil_code) s_b_useStencil =
false;
1225 if (m_displayScale > 1) m_b_DisableFBO =
true;
1234 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
1236 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1237 g_texture_rectangle_format, m_cache_tex[0], 0);
1239 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1240 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1242 if (fb_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1244 msg.Printf(_T(
" OpenGL-> Framebuffer Incomplete: %08X"), fb_status);
1246 m_b_DisableFBO =
true;
1252 if (m_b_BuiltFBO && !m_b_useFBOStencil) s_b_useStencil =
false;
1256 s_b_useStencilAP = s_b_useStencil & !bad_stencil_code;
1258#ifdef USE_ANDROID_GLES2
1259 s_b_useStencilAP = s_b_useStencil;
1266 wxLogMessage(_T(
"OpenGL-> Using Framebuffer Objects"));
1268 if (m_b_useFBOStencil)
1269 wxLogMessage(_T(
"OpenGL-> Using FBO Stencil buffer"));
1271 wxLogMessage(_T(
"OpenGL-> FBO Stencil buffer unavailable"));
1273 wxLogMessage(_T(
"OpenGL-> Framebuffer Objects unavailable"));
1276 wxLogMessage(_T(
"OpenGL-> Using Stencil buffer clipping"));
1278 wxLogMessage(_T(
"OpenGL-> Using Depth buffer clipping"));
1280 if (s_b_useScissorTest && s_b_useStencil)
1281 wxLogMessage(_T(
"OpenGL-> Using Scissor Clipping"));
1284 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1286 MipMap_ResolveRoutines();
1290 lwmsg.Printf(_T(
"OpenGL-> Minimum cartographic line width: %4.1f"),
1291 g_GLMinCartographicLineWidth);
1292 wxLogMessage(lwmsg);
1293 lwmsg.Printf(_T(
"OpenGL-> Minimum symbol line width: %4.1f"),
1294 g_GLMinSymbolLineWidth);
1295 wxLogMessage(lwmsg);
1298 g_GLOptions.m_bUseAcceleratedPanning = !m_b_DisableFBO && m_b_BuiltFBO;
1300#ifdef USE_ANDROID_GLES2
1301 g_GLOptions.m_bUseAcceleratedPanning =
true;
1307 int tex_dim = g_GLOptions.m_iTextureDimension;
1308 for (
int dim = tex_dim; dim > 0; dim /= 2) max_level++;
1309 g_mipmap_max_level = max_level - 1;
1314 g_mipmap_max_level = 4;
1317 s_b_useFBO = m_b_BuiltFBO;
1321 ps52plib->SetGLOptions(
1322 s_b_useStencil, s_b_useStencilAP, s_b_useScissorTest, s_b_useFBO,
1323 g_b_EnableVBO, g_texture_rectangle_format, g_GLMinCartographicLineWidth,
1324 g_GLMinSymbolLineWidth);
1328 SendJSONConfigMessage();
1331void glChartCanvas::SendJSONConfigMessage() {
1334 v[_T(
"setupComplete")] = m_bsetup;
1335 v[_T(
"useStencil")] = s_b_useStencil;
1336 v[_T(
"useStencilAP")] = s_b_useStencilAP;
1337 v[_T(
"useScissorTest")] = s_b_useScissorTest;
1338 v[_T(
"useFBO")] = s_b_useFBO;
1339 v[_T(
"useVBO")] = g_b_EnableVBO;
1340 v[_T(
"TextureRectangleFormat")] = g_texture_rectangle_format;
1341 wxString msg_id(_T(
"OCPN_OPENGL_CONFIG"));
1342 SendJSONMessageToAllPlugins(msg_id, v);
1345void glChartCanvas::SetupCompression() {
1346 int dim = g_GLOptions.m_iTextureDimension;
1349 if (!::IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
1350 wxLogMessage(_T(
"OpenGL-> SSE2 Instruction set not available"));
1351 goto no_compression;
1355 g_uncompressed_tile_size = dim * dim * 4;
1356 if (!g_GLOptions.m_bTextureCompression)
goto no_compression;
1358 g_raster_format = GL_RGB;
1362 if (QueryExtension(
"GL_OES_compressed_ETC1_RGB8_texture")) {
1363 g_raster_format = GL_ETC1_RGB8_OES;
1365 wxLogMessage(_T(
"OpenGL-> Using oes etc1 compression"));
1369 if (GL_RGB == g_raster_format) {
1375 if ((QueryExtension(
"GL_EXT_texture_compression_s3tc") ||
1376 QueryExtension(
"GL_EXT_texture_compression_dxt1"))) {
1379 if (GetRendererString().Find(_T(
"Gallium")) != wxNOT_FOUND &&
1380 GetRendererString().Find(_T(
"NV")) != wxNOT_FOUND)
1381 g_raster_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
1383 g_raster_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1385 wxLogMessage(_T(
"OpenGL-> Using s3tc dxt1 compression"));
1386 }
else if (QueryExtension(
"GL_3DFX_texture_compression_FXT1")) {
1387 g_raster_format = GL_COMPRESSED_RGB_FXT1_3DFX;
1389 wxLogMessage(_T(
"OpenGL-> Using 3dfx fxt1 compression"));
1391 wxLogMessage(_T(
"OpenGL-> No Useable compression format found"));
1392 goto no_compression;
1397 g_tile_size = 512 * 512 / 2;
1401 glGenTextures(1, &texture);
1402 glBindTexture(GL_TEXTURE_2D, texture);
1403 glTexImage2D(GL_TEXTURE_2D, 0, g_raster_format, dim, dim, 0, GL_RGB,
1404 GL_UNSIGNED_BYTE, NULL);
1405 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
1407 glDeleteTextures(1, &texture);
1411 if (g_tile_size == 0)
goto no_compression;
1413 wxLogMessage(wxString::Format(
1414 _T(
"OpenGL-> Compressed tile size: %dkb (%d:1)"), g_tile_size / 1024,
1415 g_uncompressed_tile_size / g_tile_size));
1419 g_GLOptions.m_bTextureCompression =
false;
1421 g_tile_size = g_uncompressed_tile_size;
1422 wxLogMessage(wxString::Format(_T(
"OpenGL-> Not Using compression")));
1425void glChartCanvas::OnPaint(wxPaintEvent &event) {
1428 if (!m_pcontext)
return;
1436 SetCurrent(*m_pcontext);
1441 if (ps52plib) ps52plib->FlushSymbolCaches(ChartCtxFactory());
1449 if (!m_b_paint_enable)
return;
1452 if (m_in_glpaint)
return;
1455 m_pParentCanvas->UpdateCanvasS52PLIBConfig();
1478bool glChartCanvas::HasNormalizedViewPort(
const ViewPort &vp) {
1480#ifndef USE_ANDROID_GLES2
1481 return vp.m_projection_type == PROJECTION_MERCATOR ||
1482 vp.m_projection_type == PROJECTION_POLAR ||
1483 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1497#define NORM_FACTOR 4096.0
1498void glChartCanvas::MultMatrixViewPort(
ViewPort &vp,
float lat,
float lon) {
1499#ifndef USE_ANDROID_GLES2
1501 wxPoint2DDouble point;
1503 switch (vp.m_projection_type) {
1504 case PROJECTION_MERCATOR:
1505 case PROJECTION_EQUIRECTANGULAR:
1506 case PROJECTION_WEB_MERCATOR:
1509 glTranslated(point.m_x, point.m_y, 0);
1514 case PROJECTION_POLAR:
1518 glTranslated(point.m_x, point.m_y, 0);
1519 glRotatef(vp.
clon - lon, 0, 0, vp.
clat);
1526 printf(
"ERROR: Unhandled projection\n");
1531 if (rotation) glRotatef(rotation * 180 / PI, 0, 0, 1);
1539 switch (vp.m_projection_type) {
1540 case PROJECTION_MERCATOR:
1541 case PROJECTION_EQUIRECTANGULAR:
1542 case PROJECTION_WEB_MERCATOR:
1546 case PROJECTION_POLAR:
1551 printf(
"ERROR: Unhandled projection\n");
1560bool glChartCanvas::CanClipViewport(
const ViewPort &vp) {
1561 return vp.m_projection_type == PROJECTION_MERCATOR ||
1562 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1563 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1567 const LLRegion ®ion) {
1568 if (!CanClipViewport(vp))
return vp;
1571 LLBBox bbox = region.GetBox();
1573 if (!bbox.GetValid())
return vp;
1581 if (bbox.GetMaxLon() < cvp.GetBBox().GetMinLon()) {
1582 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() + 360, bbox.GetMaxLat(),
1583 bbox.GetMaxLon() + 360);
1584 cvp.SetBBoxDirect(bbox);
1585 }
else if (bbox.GetMinLon() > cvp.GetBBox().GetMaxLon()) {
1586 bbox.Set(bbox.GetMinLat(), bbox.GetMinLon() - 360, bbox.GetMaxLat(),
1587 bbox.GetMaxLon() - 360);
1588 cvp.SetBBoxDirect(bbox);
1590 cvp.SetBBoxDirect(bbox);
1595void glChartCanvas::DrawStaticRoutesTracksAndWaypoints(
ViewPort &vp) {
1596 if (!m_pParentCanvas->m_bShowNavobjects)
return;
1599 for (
Track *pTrackDraw : g_TrackList) {
1602 if (pActiveTrack && pActiveTrack->IsRunning())
continue;
1604 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1607 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1608 node = node->GetNext()) {
1609 Route *pRouteDraw = node->GetData();
1611 if (!pRouteDraw)
continue;
1614 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected())
continue;
1617 if (pRouteDraw->m_bIsBeingEdited)
continue;
1619 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1624 if (vp.GetBBox().GetValid() && pWayPointMan) {
1625 for (wxRoutePointListNode *pnode =
1626 pWayPointMan->GetWaypointList()->GetFirst();
1627 pnode; pnode = pnode->GetNext()) {
1629 if (pWP && (!pWP->m_bRPIsBeingEdited) && (!pWP->m_bIsInRoute))
1630 if (vp.GetBBox().ContainsMarge(pWP->m_lat, pWP->m_lon, .5))
1637void glChartCanvas::DrawDynamicRoutesTracksAndWaypoints(
ViewPort &vp) {
1640 for (
Track *pTrackDraw : g_TrackList) {
1642 if (pActiveTrack && pActiveTrack->IsRunning())
1643 TrackGui(*pTrackDraw).Draw(m_pParentCanvas, dc, vp, vp.GetBBox());
1647 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
1648 node = node->GetNext()) {
1649 Route *pRouteDraw = node->GetData();
1652 if (!pRouteDraw)
continue;
1655 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) drawit++;
1658 if (pRouteDraw->m_bIsBeingEdited) drawit++;
1661 if (pRouteDraw->IsSelected()) drawit++;
1664 const LLBBox &vp_box = vp.GetBBox(), &test_box = pRouteDraw->GetBBox();
1665 if (!vp_box.IntersectOut(test_box))
1666 RouteGui(*pRouteDraw).DrawGL(vp, m_pParentCanvas, dc);
1672 if (vp.GetBBox().GetValid() && pWayPointMan) {
1673 for (wxRoutePointListNode *pnode =
1674 pWayPointMan->GetWaypointList()->GetFirst();
1675 pnode; pnode = pnode->GetNext()) {
1677 if (pWP && pWP->m_bRPIsBeingEdited && !pWP->m_bIsInRoute)
1684static void GetLatLonCurveDist(
const ViewPort &vp,
float &lat_dist,
1688 switch (vp.m_projection_type) {
1689 case PROJECTION_TRANSVERSE_MERCATOR:
1690 lat_dist = 4, lon_dist = 1;
1692 case PROJECTION_POLYCONIC:
1693 lat_dist = 2, lon_dist = 1;
1695 case PROJECTION_ORTHOGRAPHIC:
1696 lat_dist = 2, lon_dist = 2;
1698 case PROJECTION_POLAR:
1699 lat_dist = 180, lon_dist = 1;
1701 case PROJECTION_STEREOGRAPHIC:
1702 case PROJECTION_GNOMONIC:
1703 lat_dist = 2, lon_dist = 1;
1705 case PROJECTION_EQUIRECTANGULAR:
1708 lat_dist = 2, lon_dist = 360;
1711 lat_dist = 180, lon_dist = 360;
1715void glChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
1716 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN &&
1717 !ChartData->IsChartAvailable(dbIndex))
1722 ChartData->GetDBBoundingBox(dbIndex, box);
1723 if (!box.GetValid())
return;
1727 if (box.GetLonRange() == 360)
return;
1729 LLBBox vpbox = vp.GetBBox();
1731 double lon_bias = 0;
1733 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
1736 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1737 color = GetGlobalColor(_T (
"YELO1" ));
1738 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1739 color = GetGlobalColor(_T (
"GREEN2" ));
1741 color = GetGlobalColor(_T (
"UINFR" ));
1743#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1744 float plylat, plylon;
1746 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
1748 glColor3ub(color.Red(), color.Green(), color.Blue());
1749 glLineWidth(g_GLMinSymbolLineWidth);
1751 float lat_dist, lon_dist;
1752 GetLatLonCurveDist(vp, lat_dist, lon_dist);
1755 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex), nPly;
1759 nPly = ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, 0, 0);
1761 nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
1763 bool begin =
false, sml_valid =
false;
1765 float lastplylat = 0.0;
1766 float lastplylon = 0.0;
1768 int modulo = (nPly == 0) ? 1 : nPly;
1769 for (
int i = 0; i < nPly + 1; i++) {
1771 ChartData->GetDBAuxPlyPoint(dbIndex, i % modulo, j, &plylat, &plylon);
1773 ChartData->GetDBPlyPoint(dbIndex, i % modulo, &plylat, &plylon);
1777 if (lastplylon - plylon > 180)
1779 else if (lastplylon - plylon < -180)
1786 int lat_splits = floor(fabs(plylat - lastplylat) / lat_dist);
1787 int lon_splits = floor(fabs(plylon - lastplylon) / lon_dist);
1788 splits = wxMax(lat_splits, lon_splits) + 1;
1795 toSM(plylat, plylon, 0, 0, smj + 0, smj + 1);
1796 if (!sml_valid) toSM(lastplylat, lastplylon, 0, 0, sml + 0, sml + 1);
1799 for (
double c = 0; c < splits; c++) {
1801 if (c == splits - 1)
1802 lat = plylat, lon = plylon;
1804 double d = (double)(c + 1) / splits;
1805 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
1811 if (!std::isnan(s.m_x)) {
1814 glBegin(GL_LINE_STRIP);
1816 glVertex2f(s.m_x, s.m_y);
1822 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
1823 lastplylat = plylat, lastplylon = plylon;
1828 }
while (++j < nAuxPlyEntries);
1830 glDisable(GL_LINE_SMOOTH);
1834 double nominal_line_width_pix =
1835 wxMax(2.0, floor(m_pParentCanvas->
GetPixPerMM() / 4));
1837 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
1838 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), nominal_line_width_pix,
1841 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
1842 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), nominal_line_width_pix,
1846 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), nominal_line_width_pix,
1849 float plylat1, plylon1;
1853 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
1854 if (0 == nAuxPlyEntries)
1857 std::vector<int> points_vector;
1859 std::vector<float> vec = ChartData->GetReducedPlyPoints(dbIndex);
1860 int nPly = vec.size() / 2;
1862 if (nPly == 0)
return;
1864 for (
int i = 0; i < nPly; i++) {
1865 plylon1 = vec[i * 2];
1866 plylat1 = vec[i * 2 + 1];
1872 points_vector.push_back(pixx1);
1873 points_vector.push_back(pixy1);
1876 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
1877 plylon1 += lon_bias;
1883 points_vector.push_back(pixx1);
1884 points_vector.push_back(pixy1);
1886 if (points_vector.size()) {
1887 std::vector<int>::iterator it = points_vector.begin();
1888 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1896 for (
int j = 0; j < nAuxPlyEntries; j++) {
1897 std::vector<int> points_vector;
1899 std::vector<float> vec = ChartData->GetReducedAuxPlyPoints(dbIndex, j);
1900 int nAuxPly = vec.size() / 2;
1902 if (nAuxPly == 0)
continue;
1904 for (
int i = 0; i < nAuxPly; i++) {
1905 plylon1 = vec[i * 2];
1906 plylat1 = vec[i * 2 + 1];
1912 points_vector.push_back(pixx1);
1913 points_vector.push_back(pixy1);
1920 points_vector.push_back(pixx1);
1921 points_vector.push_back(pixy1);
1923 if (points_vector.size()) {
1924 std::vector<int>::iterator it = points_vector.begin();
1925 dc.DrawLines(points_vector.size() / 2, (wxPoint *)&(*it), 0, 0,
true);
1933extern void CalcGridSpacing(
float WindowDegrees,
float &MajorSpacing,
1934 float &MinorSpacing);
1935extern wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix);
1936void glChartCanvas::GridDraw() {
1937 if (!m_pParentCanvas->m_bDisplayGrid)
return;
1939 ViewPort &vp = m_pParentCanvas->GetVP();
1941 if (!vp.IsValid() || !vp.GetBBox().GetValid())
return;
1945 fabs(vp.
rotation) < 0.0001 && vp.m_projection_type == PROJECTION_MERCATOR;
1947 double nlat, elon, slat, wlon;
1949 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
1952 wxColour GridColor = GetGlobalColor(_T (
"SNDG1" ));
1954 if (!m_gridfont.IsBuilt()) {
1956 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
1957 wxFont font = *dFont;
1958 int font_size = wxMax(10, dFont->GetPointSize());
1959 font.SetPointSize(font_size * m_displayScale);
1960 font.SetWeight(wxFONTWEIGHT_NORMAL);
1963 m_gridfont.Build(font, 1, dpi_factor);
1965 m_gridfont.SetColor(GridColor);
1970 LLBBox llbbox = vp.GetBBox();
1971 nlat = llbbox.GetMaxLat();
1972 slat = llbbox.GetMinLat();
1973 elon = llbbox.GetMaxLon();
1974 wlon = llbbox.GetMinLon();
1981 bool straight_latitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1982 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1983 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1984 bool straight_longitudes = vp.m_projection_type == PROJECTION_MERCATOR ||
1985 vp.m_projection_type == PROJECTION_WEB_MERCATOR ||
1986 vp.m_projection_type == PROJECTION_POLAR ||
1987 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR;
1990 if (straight_latitudes)
1993 latmargin = gridlatMajor / 2;
1995 slat = wxMax(slat, -90 + latmargin);
1996 nlat = wxMin(nlat, 90 - latmargin);
1998 float startlat = ceil(slat / gridlatMajor) * gridlatMajor;
1999 float startlon = ceil(wlon / gridlonMajor) * gridlonMajor;
2003 wxPen *pen = wxThePenList->FindOrCreatePen(GridColor, g_GLMinSymbolLineWidth,
2010 float lon_step = elon - wlon;
2011 if (!straight_latitudes) lon_step /= ceil(lon_step / curved_step);
2013 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2015 s.x = INVALID_COORD;
2016 s.y = INVALID_COORD;
2017 for (lon = wlon; lon < elon + lon_step / 2; lon += lon_step) {
2019 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2020 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2028 for (lat = ceil(slat / gridlatMinor) * gridlatMinor; lat < nlat;
2029 lat += gridlatMinor) {
2032 gldc.DrawLine(0, r.y, 10, r.y,
true);
2033 gldc.DrawLine(w - 10, r.y, w, r.y,
false);
2038 float lat_step = nlat - slat;
2039 if (!straight_longitudes) lat_step /= ceil(lat_step / curved_step);
2041 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2043 s.x = INVALID_COORD;
2044 s.y = INVALID_COORD;
2045 for (lat = slat; lat < nlat + lat_step / 2; lat += lat_step) {
2047 if (s.x != INVALID_COORD && s.y != INVALID_COORD) {
2048 gldc.DrawLine(s.x, s.y, r.x, r.y,
false);
2056 for (lon = ceil(wlon / gridlonMinor) * gridlonMinor; lon < elon;
2057 lon += gridlonMinor) {
2060 gldc.DrawLine(r.x, 0, r.x, 10,
false);
2061 gldc.DrawLine(r.x, h - 10, r.x, h,
false);
2067 glEnable(GL_TEXTURE_2D);
2069 for (lat = startlat; lat < nlat; lat += gridlatMajor) {
2070 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
2073 CalcGridText(lat, gridlatMajor,
true);
2075 m_gridfont.GetTextExtent(st, 0, &iy);
2077 if (straight_latitudes) {
2082 float x = 0, y = -1;
2083 y = (float)(r.y * s.x - s.y * r.x) / (s.x - r.x);
2084 if (y < 0 || y > h) {
2086 x = (float)(r.x * s.y - s.x * r.y + (s.x - r.x) * y) / (s.y - r.y);
2089 m_gridfont.RenderString(st, x, y);
2093 double y1, y2, lat1, lon1, lat2, lon2;
2102 double y = y1 + (lat1 - lat) * (y2 - y1) / (lat1 - lat2);
2105 lat, lon1 + (y1 - y) * (lon2 - lon1) / (y1 - y2), &r);
2107 if (fabs(y - y1) < fabs(y - y2))
2113 error = fabs(r.m_x);
2114 if (--maxiters == 0)
break;
2115 }
while (error > 1 && error < lasterror);
2117 if (error < 1 && r.m_y >= 0 && r.m_y <= vp.
pix_height - iy)
2123 m_gridfont.RenderString(st, r.m_x, r.m_y);
2127 for (lon = startlon; lon < elon; lon += gridlonMajor) {
2128 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
2137 else if (xlon <= -180.0)
2140 wxString st = CalcGridText(xlon, gridlonMajor,
false);
2142 m_gridfont.GetTextExtent(st, &ix, 0);
2144 if (straight_longitudes) {
2145 float x = -1, y = 0;
2146 x = (float)(r.x * s.y - s.x * r.y) / (s.y - r.y);
2147 if (x < 0 || x > w) {
2149 y = (float)(r.y * s.x - s.y * r.x + (s.y - r.y) * x) / (s.x - r.x);
2152 m_gridfont.RenderString(st, x, y);
2156 double x1, x2, lat1, lon1, lat2, lon2;
2164 double x = x1 + (lon1 - lon) * (x2 - x1) / (lon1 - lon2);
2167 lat1 + (x1 - x) * (lat2 - lat1) / (x1 - x2), lon, &r);
2169 if (fabs(x - x1) < fabs(x - x2))
2175 error = fabs(r.m_y);
2176 }
while (error > 1 && error < lasterror);
2178 if (error < 1 && r.m_x >= 0 && r.m_x <= vp.
pix_width - ix)
2183 wxMin(wxMax(vp.
clat, slat), nlat), lon, &r);
2185 m_gridfont.RenderString(st, r.m_x, r.m_y);
2189 glDisable(GL_TEXTURE_2D);
2190 glDisable(GL_BLEND);
2195 if (!emboss)
return;
2197 int w = emboss->width, h = emboss->height;
2199 glEnable(GL_TEXTURE_2D);
2202 if (!emboss->gltexind) {
2204 emboss->glwidth = NextPow2(emboss->width);
2205 emboss->glheight = NextPow2(emboss->height);
2208 int size = emboss->glwidth * emboss->glheight;
2209 char *data =
new char[2 * size];
2210 for (
int i = 0; i < h; i++) {
2211 for (
int j = 0; j < emboss->glwidth; j++) {
2213 data[2 * ((i * emboss->glwidth) + j)] =
2214 (char)(emboss->pmap[(i * w) + j] > 0 ? 0 : 255);
2215 data[2 * ((i * emboss->glwidth) + j) + 1] =
2216 (char)abs((emboss->pmap[(i * w) + j]));
2221 glGenTextures(1, &emboss->gltexind);
2222 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2223 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, emboss->glwidth,
2224 emboss->glheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2232 glBindTexture(GL_TEXTURE_2D, emboss->gltexind);
2236 int x = emboss->x, y = emboss->y;
2238 float wp = (float)w / emboss->glwidth;
2239 float hp = (float)h / emboss->glheight;
2265 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(), x, y, 0);
2267 glDisable(GL_BLEND);
2268 glDisable(GL_TEXTURE_2D);
2271void glChartCanvas::ShipDraw(
ocpnDC &dc) {
2272 if (!m_pParentCanvas->GetVP().IsValid())
return;
2273 wxPoint GPSOffsetPixels(0, 0);
2274 wxPoint2DDouble lGPSPoint, lShipMidPoint;
2277 float pCog = std::isnan(gCog) ? 0 : gCog;
2278 float pSog = std::isnan(gSog) ? 0 : gSog;
2284 double shift_dx = 0;
2285 double shift_dy = 0;
2286 if (m_pParentCanvas->m_bFollow && !m_pParentCanvas->m_MouseDragging) {
2287 lGPSPoint.m_x = m_pParentCanvas->GetVP().
pix_width / 2;
2288 lGPSPoint.m_y = m_pParentCanvas->GetVP().
pix_height / 2;
2289 if (m_pParentCanvas->m_bLookAhead) {
2290 double angle = m_pParentCanvas->dir_to_shift * PI / 180.;
2291 angle += m_pParentCanvas->GetVPRotation();
2292 shift_dx = m_pParentCanvas->meters_to_shift * sin(angle) *
2294 lGPSPoint.m_x -= shift_dx / cos(gLat * PI / 180.);
2295 shift_dy = m_pParentCanvas->meters_to_shift * cos(angle) *
2297 lGPSPoint.m_y += shift_dy / cos(gLat * PI / 180.);
2299 lGPSPoint.m_x -= m_pParentCanvas->m_OSoffsetx;
2300 lGPSPoint.m_y += m_pParentCanvas->m_OSoffsety;
2307 lShipMidPoint = lGPSPoint;
2311 float icon_hdt = pCog;
2312 if (!std::isnan(gHdt)) icon_hdt = gHdt;
2315 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
2319 double osd_head_lat, osd_head_lon;
2320 wxPoint2DDouble osd_head_point;
2322 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
2326 m_pParentCanvas->GetVP(), osd_head_lat, osd_head_lon, &osd_head_point);
2328 double icon_rad = atan2f((
float)(osd_head_point.m_y - lShipMidPoint.m_y),
2329 (
float)(osd_head_point.m_x - lShipMidPoint.m_x));
2330 icon_rad += (float)PI;
2334 ((icon_hdt + 90.) * PI / 180.) + m_pParentCanvas->GetVP().
rotation;
2338 BoundingBox bb_screen(0, 0, m_pParentCanvas->GetVP().
pix_width,
2344 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
2345 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
2346 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
2351 float scale_factor = 1.0;
2353 if ((g_ChartScaleFactorExp > 1.0) && (g_OwnShipIconType == 0))
2354 scale_factor = (log(g_ChartScaleFactorExp) + 1.0) * 1.1;
2356 float nominal_ownship_size_mm = m_pParentCanvas->m_display_size_mm / 44.0;
2357 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2358 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2360 scale_factor *= m_pParentCanvas->GetContentScaleFactor();
2362 float nominal_ownship_size_pixels =
2364 nominal_ownship_size_mm);
2366 float v = (nominal_ownship_size_pixels * scale_factor) / 3;
2368 wxPen ppSmallScaleShip;
2369 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2371 wxPen(GetGlobalColor(_T (
"URED" )), v / 5, wxPENSTYLE_SOLID);
2374 wxPen(GetGlobalColor(_T (
"YELO1" )), v / 5, wxPENSTYLE_SOLID);
2375 dc.SetPen(ppSmallScaleShip);
2378 wxBrush(GetGlobalColor(_T (
"URED" )), wxBRUSHSTYLE_TRANSPARENT));
2381 dc.
DrawLine((-v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y,
2382 (v * 1.2) + lShipMidPoint.m_x, lShipMidPoint.m_y);
2383 dc.
DrawLine(lShipMidPoint.m_x, (-v * 1.2) + lShipMidPoint.m_y,
2384 lShipMidPoint.m_x, (v * 1.2) + lShipMidPoint.m_y);
2387 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, v);
2388 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, 0.6 * v);
2391 int draw_color = SHIP_INVALID;
2392 if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2393 draw_color = SHIP_NORMAL;
2394 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2395 draw_color = SHIP_LOWACCURACY;
2403 ownship_color = draw_color;
2405 if (ownship_tex) glDeleteTextures(1, &ownship_tex);
2407 glGenTextures(1, &ownship_tex);
2408 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2410 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2411 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2414 if (m_pParentCanvas->m_pos_image_user) {
2415 switch (draw_color) {
2417 image = *m_pParentCanvas->m_pos_image_user_grey;
2420 image = *m_pParentCanvas->m_pos_image_user;
2422 case SHIP_LOWACCURACY:
2423 image = *m_pParentCanvas->m_pos_image_user_yellow;
2427 switch (draw_color) {
2429 image = *m_pParentCanvas->m_pos_image_grey;
2432 image = *m_pParentCanvas->m_pos_image_red;
2434 case SHIP_LOWACCURACY:
2435 image = *m_pParentCanvas->m_pos_image_yellow;
2440 int w = image.GetWidth(), h = image.GetHeight();
2441 int glw = NextPow2(w), glh = NextPow2(h);
2442 ownship_size = wxSize(w, h);
2443 ownship_tex_size = wxSize(glw, glh);
2445 unsigned char *d = image.GetData();
2446 unsigned char *a = image.GetAlpha();
2447 unsigned char *e =
new unsigned char[4 * w * h];
2450 for (
int p = 0; p < w * h; p++) {
2451 e[4 * p + 0] = d[3 * p + 0];
2452 e[4 * p + 1] = d[3 * p + 1];
2453 e[4 * p + 2] = d[3 * p + 2];
2454 e[4 * p + 3] = a[p];
2457 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glw, glh, 0, GL_RGBA,
2458 GL_UNSIGNED_BYTE, 0);
2460 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2466#ifndef USE_ANDROID_GLES2
2467 if (m_pParentCanvas->m_pos_image_user)
2468 glColor4ub(255, 255, 255, 255);
2469 else if (SHIP_NORMAL == m_pParentCanvas->m_ownship_state)
2470 glColor4ub(255, 0, 0, 255);
2471 else if (SHIP_LOWACCURACY == m_pParentCanvas->m_ownship_state)
2472 glColor4ub(255, 255, 0, 255);
2474 glColor4ub(128, 128, 128, 255);
2476 float scale_factor_y = 1.0;
2477 float scale_factor_x = 1.0;
2479 int ownShipWidth = 22;
2480 int ownShipLength = 84;
2481 lShipMidPoint = lGPSPoint;
2484 if (g_OwnShipIconType != 0)
2485 m_pParentCanvas->ComputeShipScaleFactor(
2486 icon_hdt, ownShipWidth, ownShipLength, lShipMidPoint,
2487 GPSOffsetPixels, lGPSPoint, scale_factor_x, scale_factor_y);
2492 if ((g_ShipScaleFactorExp > 1.0) && (g_OwnShipIconType == 0)) {
2493 scale_factor_x = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2494 scale_factor_y = (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
2498 scale_factor_x *= m_pParentCanvas->GetContentScaleFactor();
2499 scale_factor_y *= m_pParentCanvas->GetContentScaleFactor();
2503 float gps_circle_radius = 3.0;
2505 if (g_OwnShipIconType == 0) {
2507 glEnable(GL_TEXTURE_2D);
2508 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2517 int image_height_bitmap = m_pParentCanvas->m_pos_image_red->GetHeight();
2518 if (m_pParentCanvas->m_pos_image_user)
2519 image_height_bitmap = m_pParentCanvas->m_pos_image_user->GetHeight();
2521 float nominal_ownship_size_mm =
2522 image_height_bitmap / m_pParentCanvas->
GetPixPerMM();
2524 nominal_ownship_size_mm = wxMin(nominal_ownship_size_mm, 15.0);
2525 nominal_ownship_size_mm = wxMax(nominal_ownship_size_mm, 7.0);
2527 float nominal_ownship_size_pixels =
2528 m_pParentCanvas->
GetPixPerMM() * nominal_ownship_size_mm;
2530 if (m_pParentCanvas->GetContentScaleFactor() == 1.0) {
2531 nominal_ownship_size_pixels = wxMax(
2532 20.0, nominal_ownship_size_pixels);
2535 float h = nominal_ownship_size_pixels * scale_factor_y;
2536 float w = nominal_ownship_size_pixels * scale_factor_x *
2537 ownship_size.x / ownship_size.y;
2538 float glw = ownship_tex_size.x, glh = ownship_tex_size.y;
2539 float u = ownship_size.x / glw, v = ownship_size.y / glh;
2545 gps_circle_radius = w / 5;
2547 float uv[8], coords[8];
2566 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2567 lShipMidPoint.m_x, lShipMidPoint.m_y,
2569 glDisable(GL_TEXTURE_2D);
2570 }
else if (g_OwnShipIconType == 1) {
2572 glEnable(GL_TEXTURE_2D);
2573 glBindTexture(GL_TEXTURE_2D, ownship_tex);
2575 float nominal_ownship_size_pixels_y = 84;
2576 float nominal_ownship_size_pixels_x = 22;
2578 float h = nominal_ownship_size_pixels_y * scale_factor_y;
2579 float w = nominal_ownship_size_pixels_x * scale_factor_x;
2581 float u = (float)ownship_size.x / ownship_tex_size.x,
2582 v = (
float)ownship_size.y / ownship_tex_size.y;
2585 gps_circle_radius = w / 5;
2587 float uv[8], coords[8];
2606 RenderSingleTexture(dc, coords, uv, m_pParentCanvas->GetpVP(),
2607 lShipMidPoint.m_x, lShipMidPoint.m_y,
2610 glDisable(GL_TEXTURE_2D);
2611 }
else if (g_OwnShipIconType == 2) {
2619 wxPoint shipPoints[6];
2621 wxColour colour = m_pParentCanvas->ShipColor();
2622 wxPen ppPen(*wxBLACK, 1);
2623 wxBrush ppBrush(colour);
2625 dc.SetBrush(ppBrush);
2627 shipPoints[0].x = 0 * scale_factor_x;
2628 shipPoints[0].y = -28 * scale_factor_y;
2629 shipPoints[1].x = 11 * scale_factor_x;
2630 shipPoints[1].y = -28 * scale_factor_y;
2631 shipPoints[2].x = 11 * scale_factor_x;
2632 shipPoints[2].y = 42 * scale_factor_y;
2633 shipPoints[3].x = 0 * scale_factor_x;
2634 shipPoints[3].y = 42 * scale_factor_y;
2635 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2638 shipPoints[0].x = 0 * scale_factor_x;
2639 shipPoints[0].y = -42 * scale_factor_y;
2640 shipPoints[1].x = 5 * scale_factor_x;
2641 shipPoints[1].y = -42 * scale_factor_y;
2642 shipPoints[2].x = 11 * scale_factor_x;
2643 shipPoints[2].y = -28 * scale_factor_y;
2644 shipPoints[3].x = 0 * scale_factor_x;
2645 shipPoints[3].y = -28 * scale_factor_y;
2646 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2649 shipPoints[0].x = 0 * scale_factor_x;
2650 shipPoints[0].y = -28 * scale_factor_y;
2651 shipPoints[1].x = -11 * scale_factor_x;
2652 shipPoints[1].y = -28 * scale_factor_y;
2653 shipPoints[2].x = -11 * scale_factor_x;
2654 shipPoints[2].y = 42 * scale_factor_y;
2655 shipPoints[3].x = 0 * scale_factor_x;
2656 shipPoints[3].y = 42 * scale_factor_y;
2657 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2660 shipPoints[0].x = 0 * scale_factor_x;
2661 shipPoints[0].y = -42 * scale_factor_y;
2662 shipPoints[1].x = -5 * scale_factor_x;
2663 shipPoints[1].y = -42 * scale_factor_y;
2664 shipPoints[2].x = -11 * scale_factor_x;
2665 shipPoints[2].y = -28 * scale_factor_y;
2666 shipPoints[3].x = 0 * scale_factor_x;
2667 shipPoints[3].y = -28 * scale_factor_y;
2668 dc.DrawPolygon(4, shipPoints, lShipMidPoint.m_x, lShipMidPoint.m_y, 1,
2672 double p1x = -11 * scale_factor_x;
2673 double p2x = 11 * scale_factor_x;
2677 ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2679 ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2681 ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2683 ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2684 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2685 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2689 p1y = -42 * scale_factor_y;
2690 p2y = 42 * scale_factor_y;
2691 p1xr = ((p1x)*cos(icon_rad - PI / 2)) - ((p1y)*sin(icon_rad - PI / 2));
2692 p2xr = ((p2x)*cos(icon_rad - PI / 2)) - ((p2y)*sin(icon_rad - PI / 2));
2693 p1yr = ((p1y)*cos(icon_rad - PI / 2)) + ((p1x)*sin(icon_rad - PI / 2));
2694 p2yr = ((p2y)*cos(icon_rad - PI / 2)) + ((p2x)*sin(icon_rad - PI / 2));
2695 dc.
DrawLine(p1xr + lShipMidPoint.m_x, p1yr + lShipMidPoint.m_y,
2696 p2xr + lShipMidPoint.m_x, p2yr + lShipMidPoint.m_y);
2699 img_height = ownShipLength * scale_factor_y;
2702 if (m_pParentCanvas->m_pos_image_user) gps_circle_radius = 1;
2704 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
2706 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"CHWHT" ))));
2708 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, gps_circle_radius);
2712 glDisable(GL_LINE_SMOOTH);
2713 glDisable(GL_POLYGON_SMOOTH);
2714 glDisable(GL_BLEND);
2717 m_pParentCanvas->ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels,
2721void glChartCanvas::DrawFloatingOverlayObjects(
ocpnDC &dc) {
2722 ViewPort &vp = m_pParentCanvas->GetVP();
2727 Route *active_route = g_pRouteMan->GetpActiveRoute();
2736 g_overlayCanvas = m_pParentCanvas;
2738 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
2739 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2740 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_LEGACY);
2745 AISDrawAreaNotices(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2747 m_pParentCanvas->DrawAnchorWatchPoints(dc);
2748 AISDraw(dc, m_pParentCanvas->GetVP(), m_pParentCanvas);
2750 m_pParentCanvas->AlertDraw(dc);
2752 m_pParentCanvas->RenderVisibleSectorLights(dc);
2754 m_pParentCanvas->RenderRouteLegs(dc);
2755 m_pParentCanvas->RenderShipToActive(dc,
true);
2756 m_pParentCanvas->ScaleBarDraw(dc);
2757 s57_DrawExtendedLightSectorsGL(dc, m_pParentCanvas->VPoint,
2758 m_pParentCanvas->extendedSectorLegs);
2760 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
2761 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_SHIPS);
2765void glChartCanvas::DrawChartBar(
ocpnDC &dc) {
2766 if (m_pParentCanvas->GetPiano()) {
2767 int canvas_height = GetClientSize().y;
2768 canvas_height *= m_displayScale;
2770 m_pParentCanvas->GetPiano()->DrawGL(
2771 canvas_height - m_pParentCanvas->GetPiano()->GetHeight());
2775void glChartCanvas::DrawQuiting() {
2776#ifndef USE_ANDROID_GLES2
2777 GLubyte pattern[8][8];
2778 for (
int y = 0; y < 8; y++)
2779 for (
int x = 0; x < 8; x++) pattern[y][x] = (y == x) * 255;
2782 glEnable(GL_TEXTURE_2D);
2783 glBindTexture(GL_TEXTURE_2D, 0);
2785 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2786 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2787 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2789 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 8, 8, 0, GL_ALPHA, GL_UNSIGNED_BYTE,
2793 float x = GetSize().x, y = GetSize().y;
2794 float u = x / 8, v = y / 8;
2807 glDisable(GL_TEXTURE_2D);
2808 glDisable(GL_BLEND);
2812void glChartCanvas::DrawCloseMessage(wxString msg) {
2813#ifndef USE_ANDROID_GLES2
2817 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
2821 texfont.Build(*pfont, 1, 1);
2823 texfont.GetTextExtent(msg, &w, &h);
2825 int yp = m_pParentCanvas->GetVP().
pix_height / 2;
2826 int xp = (m_pParentCanvas->GetVP().
pix_width - w) / 2;
2828 glColor3ub(243, 229, 47);
2832 glVertex2i(xp + w, yp);
2833 glVertex2i(xp + w, yp + h);
2834 glVertex2i(xp, yp + h);
2839 glColor3ub(0, 0, 0);
2840 glEnable(GL_TEXTURE_2D);
2841 texfont.RenderString(msg, xp, yp);
2842 glDisable(GL_TEXTURE_2D);
2843 glDisable(GL_BLEND);
2850static std::list<double *> combine_work_data;
2851static void combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
2852 GLfloat weight[4], GLdouble **dataOut) {
2853 double *vertex =
new double[3];
2854 combine_work_data.push_back(vertex);
2855 memcpy(vertex, coords, 3 * (
sizeof *coords));
2859#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2860void vertexCallbackD_GLSL(GLvoid *vertex) {
2862 if (s_tess_vertex_idx > s_tess_buf_len - 8) {
2863 int new_buf_len = s_tess_buf_len + 100;
2864 GLfloat *tmp = s_tess_work_buf;
2867 (GLfloat *)realloc(s_tess_work_buf, new_buf_len *
sizeof(GLfloat));
2868 if (NULL == s_tess_work_buf) {
2872 s_tess_buf_len = new_buf_len;
2875 GLdouble *pointer = (GLdouble *)vertex;
2877 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[0];
2878 s_tess_work_buf[s_tess_vertex_idx++] = (float)pointer[1];
2883void beginCallbackD_GLSL(GLenum mode) {
2884 s_tess_vertex_idx_this = s_tess_vertex_idx;
2889void endCallbackD_GLSL() {
2893 shader->SetUniformMatrix4fv(
"MVMatrix",
2894 (GLfloat *)s_tessVP.vp_matrix_transform);
2896 mat4x4 identityMatrix;
2897 mat4x4_identity(identityMatrix);
2898 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)identityMatrix);
2902 colorv[0] = s_regionColor.Red() / float(256);
2903 colorv[1] = s_regionColor.Green() / float(256);
2904 colorv[2] = s_regionColor.Blue() / float(256);
2905 colorv[3] = s_regionColor.Alpha() / float(256);
2906 shader->SetUniform4fv(
"color", colorv);
2908 float *bufPt = &s_tess_work_buf[s_tess_vertex_idx_this];
2909 shader->SetAttributePointerf(
"position", bufPt);
2911 glDrawArrays(s_tess_mode, 0, s_nvertex);
2916void vertexCallbackD(GLvoid *vertex) { glVertex3dv((GLdouble *)vertex); }
2918void beginCallbackD(GLenum mode) { glBegin(mode); }
2920void endCallbackD() { glEnd(); }
2924void glChartCanvas::DrawRegion(
ViewPort &vp,
const LLRegion ®ion) {
2925 float lat_dist, lon_dist;
2926 GetLatLonCurveDist(vp, lat_dist, lon_dist);
2928 GLUtesselator *tobj = gluNewTess();
2929 if (!pStaticShader) pStaticShader = GetStaticTriShader();
2931#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
2932 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD_GLSL);
2933 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD_GLSL);
2934 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD_GLSL);
2935 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2939 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&vertexCallbackD);
2940 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&beginCallbackD);
2941 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&endCallbackD);
2942 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)&combineCallbackD);
2945 gluTessNormal(tobj, 0, 0, 1);
2947 gluTessBeginPolygon(tobj, NULL);
2948 for (std::list<poly_contour>::const_iterator i = region.contours.begin();
2949 i != region.contours.end(); i++) {
2950 gluTessBeginContour(tobj);
2951 contour_pt l = *i->rbegin();
2953 bool sml_valid =
false;
2954 for (poly_contour::const_iterator j = i->begin(); j != i->end(); j++) {
2955 int lat_splits = floor(fabs(j->y - l.y) / lat_dist);
2956 int lon_splits = floor(fabs(j->x - l.x) / lon_dist);
2957 int splits = wxMax(lat_splits, lon_splits) + 1;
2963 toSM(j->y, j->x, 0, 0, smj + 0, smj + 1);
2964 if (!sml_valid) toSM(l.y, l.x, 0, 0, sml + 0, sml + 1);
2967 for (
int i = 0; i < splits; i++) {
2969 if (i == splits - 1)
2970 lat = j->y, lon = j->x;
2972 double d = (double)(i + 1) / splits;
2973 fromSM(d * smj[0] + (1 - d) * sml[0], d * smj[1] + (1 - d) * sml[1],
2977 if (std::isnan(q.m_x))
continue;
2979 double *p =
new double[6];
2984 p[0] = wxRound(q.m_x), p[1] = wxRound(q.m_y), p[2] = 0;
2989 gluTessVertex(tobj, p, p);
2990 combine_work_data.push_back(p);
2994 if ((sml_valid = splits != 1)) memcpy(sml, smj,
sizeof smj);
2996 gluTessEndContour(tobj);
2998 gluTessEndPolygon(tobj);
3000 gluDeleteTess(tobj);
3002 for (std::list<double *>::iterator i = combine_work_data.begin();
3003 i != combine_work_data.end(); i++)
3005 combine_work_data.clear();
3010void glChartCanvas::SetClipRegion(
ViewPort &vp,
const LLRegion ®ion) {
3011 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3013 if (s_b_useStencil) {
3015 glEnable(GL_STENCIL_TEST);
3017 glClear(GL_STENCIL_BUFFER_BIT);
3021 glStencilFunc(GL_ALWAYS, 1, 1);
3022 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
3025#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3029 glEnable(GL_DEPTH_TEST);
3030 glDepthFunc(GL_ALWAYS);
3031 glDepthMask(GL_TRUE);
3033 glClear(GL_DEPTH_BUFFER_BIT);
3046 glTranslatef(0, 0, .5);
3050 s_regionColor = wxColor(0, 0, 0, 255);
3051 DrawRegion(vp, region);
3053 if (s_b_useStencil) {
3056 glStencilFunc(GL_EQUAL, 1, 1);
3057 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3060#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3062 glDepthFunc(GL_GREATER);
3063 glDepthMask(GL_FALSE);
3064 glTranslatef(0, 0, -.5);
3067 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3070void glChartCanvas::SetClipRect(
const ViewPort &vp,
const wxRect &rect,
3074 if (s_b_useStencil && s_b_useScissorTest) {
3076 if (rect != vp_rect) {
3077 glEnable(GL_SCISSOR_TEST);
3078 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3081#ifndef USE_ANDROID_GLES2
3087void glChartCanvas::DisableClipRegion() {
3088 glDisable(GL_SCISSOR_TEST);
3089 glDisable(GL_STENCIL_TEST);
3090 glDisable(GL_DEPTH_TEST);
3093void glChartCanvas::Invalidate() {
3095 m_cache_vp.Invalidate();
3101 if (!pBSBChart)
return;
3103 if (b_inCompressAllCharts)
3107 wxString key = chart->GetHashKey();
3110 ChartPathHashTexfactType &hash = g_glTextureManager->m_chart_texfactory_hash;
3111 ChartPathHashTexfactType::iterator ittf = hash.find(key);
3114 if (ittf == hash.end()) {
3116 hash[key]->SetHashKey(key);
3119 pTexFact = hash[key];
3120 pTexFact->SetLRUTime(++m_LRUtime);
3125 glChartCanvas::HasNormalizedViewPort(vp) && pBSBChart->GetPPM() < 1;
3126 pTexFact->PrepareTiles(vp, use_norm_vp, pBSBChart);
3133 if (vp.m_projection_type == PROJECTION_MERCATOR &&
3134 chart->GetChartProjectionType() == PROJECTION_MERCATOR) {
3135 double scalefactor = pBSBChart->GetRasterScaleFactor(vp);
3136 base_level = log(scalefactor) / log(2.0);
3140 if (base_level > g_mipmap_max_level) base_level = g_mipmap_max_level;
3145 glEnable(GL_TEXTURE_2D);
3146#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3147 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3149 glEnableClientState(GL_VERTEX_ARRAY);
3150 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3155 pTexFact->GetCenter(lat, lon);
3156 MultMatrixViewPort(vp, lat, lon);
3160 LLBBox box = region.GetBox();
3163 if (g_memCacheLimit > 0) {
3165 GetMemoryStatus(0, &mem_used);
3168 glTexTile **tiles = pTexFact->GetTiles(numtiles);
3169 for (
int i = 0; i < numtiles; i++) {
3171 if (region.IntersectOut(tile->box)) {
3174 g_tex_mem_used > g_GLOptions.m_iTextureMemorySize * 1024 * 1024;
3175 if (bGLMemCrunch) pTexFact->DeleteTexture(tile->rect);
3177 bool texture = pTexFact->PrepareTexture(base_level, tile->rect,
3178 global_color_scheme, mem_used);
3182 coords = tile->m_coords;
3184 coords =
new float[2 * tile->m_ncoords];
3185 for (
int i = 0; i < tile->m_ncoords; i++) {
3187 tile->m_coords[2 * i + 1]);
3188 coords[2 * i + 0] = p.m_x;
3189 coords[2 * i + 1] = p.m_y;
3193#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3194 RenderTextures(m_gldc, coords, tile->m_texcoords, 4,
3195 m_pParentCanvas->GetpVP());
3198 glDisable(GL_TEXTURE_2D);
3202 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), tile->m_texcoords);
3203 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
3204 glDrawArrays(GL_QUADS, 0, tile->m_ncoords);
3206 if (!texture) glEnable(GL_TEXTURE_2D);
3208 if (!use_norm_vp)
delete[] coords;
3212 glDisable(GL_TEXTURE_2D);
3214#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3215 if (use_norm_vp) glPopMatrix();
3217 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3218 glDisableClientState(GL_VERTEX_ARRAY);
3222void glChartCanvas::RenderQuiltViewGL(
ViewPort &vp,
3224 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3225 m_pParentCanvas->m_pQuilt->IsBusy())
3229 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
3238 LLRegion region = vp.GetLLRegion(rect_region);
3240 LLRegion rendered_region;
3246 if (chart->GetChartFamily() != CHART_FAMILY_RASTER) {
3254 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3256 LLRegion get_region = pqp->ActiveRegion;
3257 bool b_rendered =
false;
3259 if (!pqp->b_overlay) {
3260 get_region.Intersect(region);
3261 if (!get_region.Empty()) {
3262 if (chart->GetChartFamily() == CHART_FAMILY_RASTER) {
3265 SetClipRegion(vp, get_region );
3266 RenderRasterChartRegionGL(chart, vp, pqp->ActiveRegion);
3267 DisableClipRegion();
3270 }
else if (chart->GetChartType() == CHART_TYPE_MBTILES) {
3271 SetClipRegion(vp, pqp->ActiveRegion );
3272 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3274 DisableClipRegion();
3277 }
else if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3278 if (chart->GetChartType() == CHART_TYPE_CM93COMP) {
3279 RenderNoDTA(vp, get_region);
3280 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3285 if (Chs57->m_RAZBuilt) {
3286 RenderNoDTA(vp, get_region);
3287 Chs57->RenderRegionViewOnGLNoText(*m_pcontext, vp,
3288 rect_region, get_region);
3289 DisableClipRegion();
3294 const LLRegion &oregion = get_region;
3295 LLBBox box = oregion.GetBox();
3306 wxRect srect(p1.x, p1.y, p3.x - p1.x, p4.y - p2.y);
3309 ViewPort cvp = ClippedViewport(vp, get_region);
3310 if (m_pParentCanvas->GetWorldBackgroundChart()) {
3311 SetClipRegion(cvp, get_region);
3312 m_pParentCanvas->GetWorldBackgroundChart()->SetColorsDirect(
3313 GetGlobalColor(_T (
"LANDA" )),
3314 GetGlobalColor(_T (
"DEPMS" )));
3315 RenderWorldChart(gldc, cvp, srect, world);
3316 m_pParentCanvas->GetWorldBackgroundChart()->SetColorScheme(
3317 global_color_scheme);
3318 DisableClipRegion();
3325 SetClipRegion(vp, get_region);
3326 RenderNoDTA(vp, get_region);
3327 ChPI->RenderRegionViewOnGLNoText(*m_pcontext, vp, rect_region,
3329 DisableClipRegion();
3332 SetClipRegion(vp, get_region);
3333 RenderNoDTA(vp, get_region);
3334 chart->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3336 DisableClipRegion();
3352 chart = m_pParentCanvas->m_pQuilt->GetNextChart();
3356 if (m_pParentCanvas->m_pQuilt->HasOverlays()) {
3357 ChartBase *pch = m_pParentCanvas->m_pQuilt->GetFirstChart();
3359 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3360 if (pqp->b_Valid && pqp->b_overlay &&
3361 pch->GetChartFamily() == CHART_FAMILY_VECTOR) {
3362 LLRegion get_region = pqp->ActiveRegion;
3364 get_region.Intersect(region);
3365 if (!get_region.Empty()) {
3368 Chs57->RenderOverlayRegionViewOnGL(*m_pcontext, vp, rect_region,
3373 ChPI->RenderRegionViewOnGL(*m_pcontext, vp, rect_region,
3380 pch = m_pParentCanvas->m_pQuilt->GetNextChart();
3385 ViewPort vph = m_pParentCanvas->GetVP();
3386 for (
auto &index : m_pParentCanvas->m_pQuilt->GetHiLiteIndexArray()) {
3389 m_pParentCanvas->m_pQuilt->GetChartQuiltRegion(cte, vph);
3391 if (!hiregion.Empty()) {
3395 switch (global_color_scheme) {
3396 case GLOBAL_COLOR_SCHEME_DAY:
3399 case GLOBAL_COLOR_SCHEME_DUSK:
3402 case GLOBAL_COLOR_SCHEME_NIGHT:
3410#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3412 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3414 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3417 DrawRegion(vp, hiregion);
3419 glDisable(GL_BLEND);
3424 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
3426 if (!hiregion.Empty()) {
3430 switch (global_color_scheme) {
3431 case GLOBAL_COLOR_SCHEME_DAY:
3434 case GLOBAL_COLOR_SCHEME_DUSK:
3437 case GLOBAL_COLOR_SCHEME_NIGHT:
3446#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3448 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
3450 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
3453 DrawRegion(vp, hiregion);
3455 glDisable(GL_BLEND);
3459 m_pParentCanvas->m_pQuilt->SetRenderedVP(vp);
3462void glChartCanvas::RenderQuiltViewGLText(
ViewPort &vp,
3464 if (!m_pParentCanvas->m_pQuilt->GetnCharts() ||
3465 m_pParentCanvas->m_pQuilt->IsBusy())
3469 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetLargestScaleChart();
3471 LLRegion region = vp.GetLLRegion(rect_region);
3473 LLRegion rendered_region;
3475 QuiltPatch *pqp = m_pParentCanvas->m_pQuilt->GetCurrentPatch();
3477 LLRegion get_region = pqp->ActiveRegion;
3479 if (!pqp->b_overlay) {
3480 if (chart->GetChartFamily() == CHART_FAMILY_VECTOR) {
3483 Chs57->RenderViewOnGLTextOnly(*m_pcontext, vp);
3488 ChPI->RenderRegionViewOnGLTextOnly(*m_pcontext, vp, rect_region);
3495 chart = m_pParentCanvas->m_pQuilt->GetNextSmallerScaleChart();
3523void glChartCanvas::RenderCharts(
ocpnDC &dc,
const OCPNRegion &rect_region) {
3524 ViewPort &vp = m_pParentCanvas->VPoint;
3532 m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)
3533 static_cast<cm93compchart *
>(m_pParentCanvas->m_singleChart)
3536 LLRegion chart_region;
3538 (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_PLUGIN)) {
3539 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3540 CHART_FAMILY_RASTER) {
3548 cpw->chartpix_to_latlong(0, 0, ll + 0, ll + 1);
3549 cpw->chartpix_to_latlong(0, cpw->GetSize_Y(), ll + 2, ll + 3);
3550 cpw->chartpix_to_latlong(cpw->GetSize_X(), cpw->GetSize_Y(), ll + 4,
3552 cpw->chartpix_to_latlong(cpw->GetSize_X(), 0, ll + 6, ll + 7);
3556 for (
int i = 1; i < 6; i += 2)
3557 if (fabs(ll[i] - ll[i + 2]) > 180) {
3559 for (
int i = 1; i < 8; i += 2)
3560 if (ll[i] < 0) ll[i] += 360;
3564 chart_region = LLRegion(4, ll);
3567 m_pParentCanvas->m_singleChart->GetChartExtent(&ext);
3569 double ll[8] = {ext.SLAT, ext.WLON, ext.SLAT, ext.ELON,
3570 ext.NLAT, ext.ELON, ext.NLAT, ext.WLON};
3571 chart_region = LLRegion(4, ll);
3574 chart_region = vp.b_quilt
3575 ? m_pParentCanvas->m_pQuilt->GetFullQuiltRegion()
3576 : m_pParentCanvas->m_singleChart->GetValidRegion();
3578 bool world_view =
false;
3580 wxRect rect = upd.GetRect();
3581 LLRegion background_region = vp.GetLLRegion(rect);
3584 background_region.Subtract(chart_region);
3586 if (!background_region.Empty()) {
3587 ViewPort cvp = ClippedViewport(vp, background_region);
3588 SetClipRect(cvp, rect,
false);
3589 RenderWorldChart(dc, cvp, rect, world_view);
3590 DisableClipRegion();
3595 RenderQuiltViewGL(vp, rect_region);
3597 LLRegion region = vp.GetLLRegion(rect_region);
3598 if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3599 CHART_FAMILY_RASTER) {
3600 if (m_pParentCanvas->m_singleChart->GetChartType() == CHART_TYPE_MBTILES)
3601 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(
3602 *m_pcontext, vp, rect_region, region);
3604 RenderRasterChartRegionGL(m_pParentCanvas->m_singleChart, vp, region);
3605 }
else if (m_pParentCanvas->m_singleChart->GetChartFamily() ==
3606 CHART_FAMILY_VECTOR) {
3607 chart_region.Intersect(region);
3608 RenderNoDTA(vp, chart_region);
3609 m_pParentCanvas->m_singleChart->RenderRegionViewOnGL(*m_pcontext, vp,
3610 rect_region, region);
3616void glChartCanvas::RenderNoDTA(
ViewPort &vp,
const LLRegion ®ion,
3618 wxColour color = GetGlobalColor(_T (
"NODTA" ));
3619#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3621 glColor4ub(color.Red(), color.Green(), color.Blue(), transparency);
3623 glColor4ub(163, 180, 183, transparency);
3626 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3630 s_regionColor = color;
3633 DrawRegion(vp, region);
3637void glChartCanvas::RenderWorldChart(
ocpnDC &dc,
ViewPort &vp, wxRect &rect,
3640 wxColour water = m_pParentCanvas->pWorldBackgroundChart->water;
3642 glEnable(GL_SCISSOR_TEST);
3643 glScissor(rect.x, vp.
pix_height - rect.height - rect.y, rect.width,
3649 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
3650#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3652 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
3656 colorv[0] = water.Red() / float(256);
3657 colorv[1] = water.Green() / float(256);
3658 colorv[2] = water.Blue() / float(256);
3660 shader->SetUniform4fv(
"color", colorv);
3671 shader->SetAttributePointerf(
"position", pf);
3673 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3683 gShapeBasemap.RenderViewOnDC(dc, vp);
3685 glDisable(GL_SCISSOR_TEST);
3693void glChartCanvas::DrawGroundedOverlayObjects(
ocpnDC &dc,
ViewPort &vp) {
3694 m_pParentCanvas->RenderAllChartOutlines(dc, vp);
3696 DrawStaticRoutesTracksAndWaypoints(vp);
3698 DisableClipRegion();
3701void glChartCanvas::DrawGLTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
3703 if (m_pParentCanvas->GetVP().
chart_scale > 500000) {
3707 wxBitmap bmp = m_pParentCanvas->GetTideBitmap();
3708 if (!bmp.Ok())
return;
3710 wxImage image = bmp.ConvertToImage();
3711 int w = image.GetWidth(), h = image.GetHeight();
3714 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3715 tex_w = w, tex_h = h;
3717 tex_w = NextPow2(w), tex_h = NextPow2(h);
3719 m_tideTexWidth = tex_w;
3720 m_tideTexHeight = tex_h;
3722 unsigned char *d = image.GetData();
3723 unsigned char *a = image.GetAlpha();
3725 unsigned char mr, mg, mb;
3726 if (!a) image.GetOrFindMaskColour(&mr, &mg, &mb);
3728 unsigned char *e =
new unsigned char[4 * w * h];
3730 for (
int y = 0; y < h; y++)
3731 for (
int x = 0; x < w; x++) {
3732 unsigned char r, g, b;
3733 int off = (y * w + x);
3743 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
3747 glGenTextures(1, &m_tideTex);
3749 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3750 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3751 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3753 if (g_texture_rectangle_format == GL_TEXTURE_2D)
3754 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
3755 GL_UNSIGNED_BYTE, e);
3757 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
3758 GL_UNSIGNED_BYTE, 0);
3759 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
3768 glBindTexture(GL_TEXTURE_2D, m_tideTex);
3769 glEnable(GL_TEXTURE_2D);
3772#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
3774 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
3775 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
3778 if ((type ==
't') || (type ==
'T'))
3783 if (BBox.Contains(lat, lon)) {
3792 scale *= getAndroidDisplayDensity();
3794 double width2 =
scale * m_tideTexWidth / 2;
3795 double height2 =
scale * m_tideTexHeight / 2;
3810 coords[0] = xp - width2;
3811 coords[1] = yp - height2;
3812 coords[2] = xp - width2;
3813 coords[3] = yp + height2;
3814 coords[4] = xp + width2;
3815 coords[5] = yp + height2;
3816 coords[6] = xp + width2;
3817 coords[7] = yp - height2;
3819 RenderTextures(dc, coords, uv, 4, m_pParentCanvas->GetpVP());
3826 glDisable(GL_TEXTURE_2D);
3827 glDisable(GL_BLEND);
3828 glBindTexture(GL_TEXTURE_2D, 0);
3830 m_pParentCanvas->DrawAllTidesInBBox(dc, BBox);
3833void glChartCanvas::DrawGLCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
3834 m_pParentCanvas->DrawAllCurrentsInBBox(dc, BBox);
3837void glChartCanvas::SetColorScheme(ColorScheme cs) {
3838 if (!m_bsetup)
return;
3840 glDeleteTextures(1, &m_tideTex);
3841 glDeleteTextures(1, &m_currentTex);
3847void glChartCanvas::RenderGLAlertMessage() {
3848 if (!m_pParentCanvas->GetAlertString().IsEmpty()) {
3849 wxString msg = m_pParentCanvas->GetAlertString();
3852 m_gldc.SetFont(*pfont);
3856 sdc.GetTextExtent(msg, &w, &h, NULL, NULL, pfont);
3863 wxRect sbr = m_pParentCanvas->GetScaleBarRect();
3864 int xp = sbr.x + sbr.width + 5;
3866 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
3867 m_gldc.SetPen(ppPen1);
3868 m_gldc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
3870 m_gldc.DrawRectangle(xp, yp, w, h);
3872 m_gldc.DrawText(msg, xp, yp);
3876unsigned long quiltHash;
3878extern wxLongLong s_t0;
3881void glChartCanvas::Render() {
3882 if (!m_bsetup || !m_pParentCanvas->m_pQuilt ||
3883 (m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_pQuilt) ||
3884 (!m_pParentCanvas->VPoint.b_quilt && !m_pParentCanvas->m_singleChart)) {
3889 if (!g_PrintingInProgress)
return;
3892 if (m_binPinch)
return;
3894#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
3895 loadShaders(GetCanvasIndex());
3896 configureShaders(m_pParentCanvas->VPoint);
3899#ifdef USE_ANDROID_GLES2
3903 if (m_binPinch)
return;
3912 bool recompose =
false;
3913 if (m_pParentCanvas->VPoint.b_quilt && m_pParentCanvas->m_pQuilt &&
3914 !m_pParentCanvas->m_pQuilt->IsComposed()) {
3915 if (m_pParentCanvas->VPoint.IsValid()) {
3916 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
3917 m_pParentCanvas->UpdateCanvasControlBar();
3926 if (sw.GetTime() > 2000) {
3932 s_tess_vertex_idx = 0;
3933 quiltHash = m_pParentCanvas->m_pQuilt->GetXStackHash();
3934 refChartIndex = m_pParentCanvas->m_pQuilt->GetRefChartdbIndex();
3940 m_displayScale = GetContentScaleFactor();
3944 m_last_render_time = wxDateTime::Now().GetTicks();
3948 if (g_GLOptions.m_bTextureCompression &&
3949 !g_GLOptions.m_bTextureCompressionCaching)
3950 g_glTextureManager->ClearJobList();
3954 int gl_width, gl_height;
3955 gl_width = m_pParentCanvas->VPoint.
pix_width;
3956 gl_height = m_pParentCanvas->VPoint.
pix_height;
3959 m_glcanvas_width = gl_width;
3960 m_glcanvas_height = gl_height;
3964 if (gl_height & 1) {
3966 ViewPort *vp = m_pParentCanvas->GetpVP();
3973 ViewPort *vp = m_pParentCanvas->GetpVP();
3981 ViewPort *vp = m_pParentCanvas->GetpVP();
3984 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3987 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3995 ViewPort VPoint = m_pParentCanvas->VPoint;
3997 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
3998 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
4001#if !defined(USE_ANDROID_GLES2)
4002 glMatrixMode(GL_PROJECTION);
4005 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4006 glMatrixMode(GL_MODELVIEW);
4010 if (s_b_useStencil) {
4011 glEnable(GL_STENCIL_TEST);
4012 glStencilMask(0xff);
4013 glClear(GL_STENCIL_BUFFER_BIT);
4014 glDisable(GL_STENCIL_TEST);
4020 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4021 if (g_GLOptions.m_GLPolygonSmoothing)
4022 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4023 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4030 g_glTextureManager->TextureCrunch(0.8);
4035 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
4036 bool useFBO =
false;
4042 if (m_b_BuiltFBO && !bpost_hilite
4047 bool b_newview =
true;
4048 bool b_full =
false;
4056 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
4060#ifdef USE_ANDROID_GLES2
4061 if (recompose) b_newview =
true;
4073 if (VPoint.b_quilt) {
4074 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
4075 if (!chart) b_full =
true;
4084 bool accelerated_pan =
false;
4094 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4095 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4096 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4098 wxPoint2DDouble c_old =
4101 wxPoint2DDouble c_new =
4105 dy = wxRound(c_new.m_y - c_old.m_y);
4106 dx = wxRound(c_new.m_x - c_old.m_x);
4116 double deltax = c_new.m_x - c_old.m_x;
4117 double deltay = c_new.m_y - c_old.m_y;
4119 bool b_whole_pixel =
true;
4120 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4121 b_whole_pixel =
false;
4123 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4124 abs(dy) < m_cache_tex_y &&
4125 (abs(dx) > 0 || (abs(dy) > 0));
4134 if (m_displayScale > 1) accelerated_pan =
false;
4139 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4142#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4145 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4151 if (b_full) accelerated_pan =
false;
4153 if (accelerated_pan) {
4154 if ((dx != 0) || (dy != 0)) {
4166 if (dy > 0 && dy < gl_height)
4167 update_region.Union(
4168 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4170 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4172 if (dx > 0 && dx < gl_width)
4173 update_region.Union(
4174 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4176 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4178 m_cache_page = !m_cache_page;
4181 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4182 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4194 RenderCharts(m_gldc, update_region);
4198 glDisable(g_texture_rectangle_format);
4203 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4204 glEnable(GL_TEXTURE_2D);
4208 float x1, x2, y1, y2;
4221 float tx1, tx2, ty1, ty2;
4227 tx2 = sx / (float)m_cache_tex_x;
4229 ty2 = sy / (float)m_cache_tex_y;
4246 coords[2] = -dx + sx;
4248 coords[4] = -dx + sx;
4249 coords[5] = dy + sy;
4251 coords[7] = dy + sy;
4254 ptexture_2D_shader_program[GetCanvasIndex()];
4258 shader->SetUniform1i(
"uTex", 0);
4262 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4263 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4264 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4266 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4288 shader->SetAttributePointerf(
"aPos", co1);
4289 shader->SetAttributePointerf(
"aUV", tco1);
4291 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4294 shader->SetUniformMatrix4fv(
"MVMatrix",
4295 (GLfloat *)VPoint.vp_matrix_transform);
4298 glBindTexture(g_texture_rectangle_format, 0);
4300 glDisable(g_texture_rectangle_format);
4308 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4309 g_texture_rectangle_format,
4310 m_cache_tex[!m_cache_page], 0);
4321 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4322 glClearColor(color.Red() / 256., color.Green() / 256.,
4323 color.Blue() / 256., 1.0);
4324 glClear(GL_COLOR_BUFFER_BIT);
4330 RenderCharts(m_gldc, rscreen_region);
4335 m_cache_page = !m_cache_page;
4340 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4351 glMatrixMode(GL_PROJECTION);
4354 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4355 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4357 glMatrixMode(GL_MODELVIEW);
4361 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4362 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4364 glGetIntegerv(GL_VIEWPORT, viewport);
4365 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4366 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4375 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4376 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4377 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4379 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4383 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4384 glEnable(g_texture_rectangle_format);
4386 float tx, ty, tx0, ty0, divx, divy;
4389 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4392 divx = m_cache_tex_x;
4393 divy = m_cache_tex_y;
4396 tx0 = m_fbo_offsetx / divx;
4397 ty0 = m_fbo_offsety / divy;
4398 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4399 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4424 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4425 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4427 glClear(GL_COLOR_BUFFER_BIT);
4429 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4432 glDisable(g_texture_rectangle_format);
4434 m_cache_vp = VPoint;
4435 m_cache_vp.Validate();
4437 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4439 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4443 RenderCharts(m_gldc, screen_region);
4449 RenderS57TextOverlay(VPoint);
4450 RenderMBTilesOverlay(VPoint);
4454 wxRect rt = upd.GetRect();
4455 LLRegion region = VPoint.GetLLRegion(rt);
4456 ViewPort cvp = ClippedViewport(VPoint, region);
4457 DrawGroundedOverlayObjects(gldc, cvp);
4460 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4461 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4462 LLBBox screenBox = screenLLRegion.GetBox();
4464 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4467 if (m_pParentCanvas->m_bShowTide) {
4468 m_pParentCanvas->RebuildTideSelectList(screenBox);
4469 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4472 if (m_pParentCanvas->m_bShowCurrent) {
4473 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4474 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4480 if (m_pParentCanvas->m_show_focus_bar &&
4481 (g_canvasConfig != 0)) {
4482 if (m_pParentCanvas == wxWindow::FindFocus()) {
4483 g_focusCanvas = m_pParentCanvas;
4485 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
4486 wxPen ppBlue(colour, 1);
4487 wxBrush ppBrush(colour);
4488 gldc.SetPen(ppBlue);
4489 gldc.SetBrush(ppBrush);
4490 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4491 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4492 wxPoint barPoints[4];
4495 barPoints[1].x = xw;
4497 barPoints[2].x = xw;
4498 barPoints[2].y = rect_pix;
4500 barPoints[3].y = rect_pix;
4502 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4506 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4510 DrawFloatingOverlayObjects(m_gldc);
4512#ifndef USE_ANDROID_GLES2
4515 glMatrixMode(GL_PROJECTION);
4518 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4519 glMatrixMode(GL_MODELVIEW);
4524 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4525 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4528 ViewPort &vp = m_pParentCanvas->GetVP();
4529 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4530 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4531 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_EMBOSS);
4533 if (!g_PrintingInProgress) {
4534 if (m_pParentCanvas->m_pTrackRolloverWin)
4535 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4537 if (m_pParentCanvas->m_pRouteRolloverWin)
4538 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4540 if (m_pParentCanvas->m_pAISRolloverWin)
4541 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4543 if (m_pParentCanvas->GetMUIBar())
4544 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4546 if (g_MainToolbar && m_pParentCanvas->IsPrimaryCanvas())
4547 g_MainToolbar->DrawGL(gldc, m_displayScale);
4549 if (g_iENCToolbar && m_pParentCanvas->IsPrimaryCanvas())
4550 g_iENCToolbar->DrawGL(gldc, m_displayScale);
4558 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4559 int x, y, width, height;
4560 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4561 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4562 wxBitmap bmp(width, height, -1);
4565 dc.SetBackground(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
4568 dc.SetTextBackground(GetGlobalColor(_T (
"UIBCK" )));
4569 dc.SetTextForeground(GetGlobalColor(_T (
"UITX1" )));
4573 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4574 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4576 wxStringTokenizer tkz(s, _T(
"\n"));
4579 while (tkz.HasMoreTokens()) {
4580 token = tkz.GetNextToken();
4581 dc.DrawText(token, xt, yt);
4584 dc.SelectObject(wxNullBitmap);
4586 m_gldc.DrawBitmap(bmp, x, y,
false);
4592 if (g_bShowChartBar) DrawChartBar(m_gldc);
4594 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4596 m_pParentCanvas->m_Compass->Paint(gldc);
4598 RenderGLAlertMessage();
4602 ViewPort &vp = m_pParentCanvas->GetVP();
4603 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4604 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4605 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_UI);
4606 glActiveTexture(GL_TEXTURE0);
4610 if (g_bquiting) DrawQuiting();
4611 if (g_bcompression_wait)
4612 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4617 if (g_b_needFinish) glFinish();
4621 g_glTextureManager->TextureCrunch(0.8);
4622 g_glTextureManager->FactoryCrunch(0.6);
4627 m_pParentCanvas->PaintCleanup();
4629 m_bforcefull =
false;
4634void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4637 if (VPoint.b_quilt) {
4638 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4639 ps52plib->GetShowS57Text()) {
4640 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4641 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4646 ChPI->ClearPLIBTextList();
4648 ps52plib->ClearTextList();
4658 RenderQuiltViewGLText(vpx, screen_region);
4663void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4666 LLRegion &screenLLRegion) {
4667 ChartBase *chart = ChartData->OpenChartFromDBAndLock(dbIndex, FULL_INIT);
4671 if (chart == NULL)
return;
4678 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4680 wxFileName tileFile(chart->GetFullPath());
4682 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4684 if (!ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4685 (tileSizeMB.GetLo() > 5000)) {
4688 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4689 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4690 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4697 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4701 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4704 std::vector<int> piano_active_array_tiles =
4705 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4706 bool bfound =
false;
4708 if (std::find(piano_active_array_tiles.begin(),
4709 piano_active_array_tiles.end(),
4710 dbIndex) != piano_active_array_tiles.end()) {
4715 piano_active_array_tiles.push_back(dbIndex);
4716 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4720void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4722 std::vector<int> stackIndexArray =
4723 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4724 unsigned int im = stackIndexArray.size();
4727 if (VPoint.b_quilt && im > 0) {
4728 bool regionVPBuilt =
false;
4730 LLRegion screenLLRegion;
4734 std::vector<int> tiles_to_show;
4735 for (
unsigned int is = 0; is < im; is++) {
4737 ChartData->GetChartTableEntry(stackIndexArray[is]);
4738 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4739 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4741 std::vector<int> piano_active_array_tiles =
4742 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4743 bool bfound =
false;
4745 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4746 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4747 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4755 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4756 piano_active_array_tiles);
4761 tiles_to_show.push_back(stackIndexArray[is]);
4762 if (!regionVPBuilt) {
4765 screenLLRegion = VPoint.GetLLRegion(screen_region);
4766 screenBox = screenLLRegion.GetBox();
4774 regionVPBuilt =
true;
4784 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4785 rit != tiles_to_show.rend(); ++rit) {
4786 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4788 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4789 rit != tiles_to_show.rend(); ++rit) {
4790 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4794 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4796 if (!hiregion.Empty()) {
4800 switch (global_color_scheme) {
4801 case GLOBAL_COLOR_SCHEME_DAY:
4804 case GLOBAL_COLOR_SCHEME_DUSK:
4807 case GLOBAL_COLOR_SCHEME_NIGHT:
4815#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4816 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4818 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4821 DrawRegion(VPoint, hiregion);
4823 glDisable(GL_BLEND);
4829void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4833 GetClientSize(&w, &h);
4835 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4836#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4837 glMatrixMode(GL_PROJECTION);
4840 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4841 glMatrixMode(GL_MODELVIEW);
4845 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4847 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4849 bool world_view =
false;
4850 RenderWorldChart(dc, cvp, rtex, world_view);
4851 gShapeBasemap.RenderViewOnDC(dc, cvp);
4857 glViewport(0, 0, (GLint)w, (GLint)h);
4858#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4859 glMatrixMode(GL_PROJECTION);
4862 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4863 glMatrixMode(GL_MODELVIEW);
4869void glChartCanvas::FastPan(
int dx,
int dy) {
4870#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4874void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4876 SetCurrent(*m_pcontext);
4877 float sx = GetSize().x;
4878 float sy = GetSize().y;
4879 glClear(GL_COLOR_BUFFER_BIT);
4882 GetClientSize(&w, &h);
4884 if (s_b_useStencil) {
4885 glEnable(GL_STENCIL_TEST);
4886 glStencilMask(0xff);
4887 glClear(GL_STENCIL_BUFFER_BIT);
4888 glDisable(GL_STENCIL_TEST);
4904 float sxfactor = sx / swidth;
4905 float syfactor = sy / sheight;
4907 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4908 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4909 sx * sx / swidth * 2, sy * sy / sheight * 2);
4910 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4911 glEnable(g_texture_rectangle_format);
4936 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4937 glBindTexture(g_texture_rectangle_format, 0);
4943 float tx, ty, tx0, ty0;
4953 glBindTexture(g_texture_rectangle_format, 0);
4956 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4957 glEnable(g_texture_rectangle_format);
4963 uv[0] = tx0 / m_cache_tex_x;
4964 uv[1] = ty / m_cache_tex_y;
4965 uv[2] = tx / m_cache_tex_x;
4966 uv[3] = ty / m_cache_tex_y;
4967 uv[4] = tx / m_cache_tex_x;
4968 uv[5] = ty0 / m_cache_tex_y;
4969 uv[6] = tx0 / m_cache_tex_x;
4970 uv[7] = ty0 / m_cache_tex_y;
4982 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4983 sx * sx / swidth, sy * sy / sheight);
4985 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4987 glDisable(g_texture_rectangle_format);
4988 glBindTexture(g_texture_rectangle_format, 0);
4995 wxColour color = GetGlobalColor(_T(
"GREY1"));
4996 float ht = -offset_y * (sy / sheight);
4997 wxRect r(0, sy - ht, w, ht);
4998 RenderColorRect(r, color);
5001 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
5002 RenderColorRect(rt, color);
5005 float w1 = -offset_x * sx / swidth;
5006 wxRect rl(0, 0, w1, sy);
5007 RenderColorRect(rl, color);
5010 float px = w1 + sx * sx / swidth;
5011 wxRect rr(px, 0, sx - px, sy);
5012 RenderColorRect(rr, color);
5021void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
5024 if (m_nRun < m_nTotal) {
5025 m_runoffsetx += m_offsetxStep;
5026 if (m_offsetxStep > 0)
5027 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
5029 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
5031 m_runoffsety += m_offsetyStep;
5032 if (m_offsetyStep > 0)
5033 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
5035 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
5037 m_runswidth += m_swidthStep;
5038 if (m_swidthStep > 0)
5039 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
5041 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
5043 m_runsheight += m_sheightStep;
5044 if (m_sheightStep > 0)
5045 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
5047 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
5052 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5058 if (m_zoomFinaldx || m_zoomFinaldy) {
5059 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5062 m_zoomFinal =
false;
5066void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5068 int sx = GetSize().x;
5069 int sy = GetSize().y;
5071 m_lastfbo_offsetx = m_fbo_offsetx;
5072 m_lastfbo_offsety = m_fbo_offsety;
5073 m_lastfbo_swidth = m_fbo_swidth;
5074 m_lastfbo_sheight = m_fbo_sheight;
5076 float curr_fbo_offset_x = m_fbo_offsetx;
5077 float curr_fbo_offset_y = m_fbo_offsety;
5078 float curr_fbo_swidth = m_fbo_swidth;
5079 float curr_fbo_sheight = m_fbo_sheight;
5081 float fx = (float)cp_x / sx;
5082 float fy = 1.0 - (float)cp_y / sy;
5084 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5085 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5087 m_fbo_swidth = curr_fbo_swidth / factor;
5088 m_fbo_sheight = curr_fbo_sheight / factor;
5090 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5091 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5093 m_fbo_offsetx += post_x;
5094 m_fbo_offsety += post_y;
5105 float perStep = m_nStep / m_nTotal;
5107 if (zoomTimer.IsRunning()) {
5108 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5109 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5110 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5111 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5114 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5115 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5116 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5117 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5119 m_runoffsetx = m_lastfbo_offsetx;
5120 m_runoffsety = m_lastfbo_offsety;
5121 m_runswidth = m_lastfbo_swidth;
5122 m_runsheight = m_lastfbo_sheight;
5125 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5126 m_zoomFinal =
false;
5132void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5136 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5139 if (m_binPinch)
return;
5140 if (m_bpinchGuard)
return;
5142 int x =
event.GetOffset().x;
5143 int y =
event.GetOffset().y;
5145 int lx =
event.GetLastOffset().x;
5146 int ly =
event.GetLastOffset().y;
5151 switch (event.GetState()) {
5152 case GestureStarted:
5153 if (m_binPan)
break;
5157 m_binGesture =
true;
5161 case GestureUpdated:
5166 m_pParentCanvas->FreezePiano();
5168 m_pParentCanvas->ThawPiano();
5179 case GestureFinished:
5182 m_pParentCanvas->UpdateCanvasControlBar();
5185 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5189 case GestureCanceled:
5191 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5198 m_bgestureGuard =
true;
5199 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5200 m_bforcefull =
false;
5205float zoom_inc = 1.0;
5206bool first_zout =
false;
5208void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5209 float zoom_gain = 1.0;
5210 float zout_gain = 1.0;
5213 float total_zoom_val;
5215 float max_zoom_scale = 1000.;
5216 float min_zoom_scale = 2e8;
5218 if (event.GetScaleFactor() > 1)
5219 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5221 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5223 if (event.GetTotalScaleFactor() > 1)
5224 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5227 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5229 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5232 float max_zoom_scale = 1000.;
5233 if( cc1->GetVP().b_quilt) {
5234 int ref_index = cc1->GetQuiltRefChartdbIndex();
5241 float min_zoom_scale = 2e8;
5245 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5247 double projected_scale =
5248 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5250 switch (event.GetState()) {
5251 case GestureStarted:
5256 m_binGesture =
true;
5258 m_pinchStart =
event.GetCenterPoint();
5259 m_lpinchPoint = m_pinchStart;
5262 event.GetCenterPoint().y, m_pinchlat,
5267 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5268 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5271 SetCurrent(*m_pcontext);
5277 case GestureUpdated:
5279 if (projected_scale < min_zoom_scale) {
5280 wxPoint pinchPoint =
event.GetCenterPoint();
5282 float dx = pinchPoint.x - m_lpinchPoint.x;
5283 float dy = pinchPoint.y - m_lpinchPoint.y;
5285 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5286 -dx / total_zoom_val, dy / total_zoom_val);
5288 m_lpinchPoint = pinchPoint;
5292 if (1 || ((total_zoom_val > 1) && !first_zout)) {
5293 wxPoint pinchPoint =
event.GetCenterPoint();
5295 float dx = pinchPoint.x - m_lpinchPoint.x;
5296 float dy = pinchPoint.y - m_lpinchPoint.y;
5298 if ((projected_scale > max_zoom_scale) &&
5299 (projected_scale < min_zoom_scale))
5300 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5301 -dx / total_zoom_val, dy / total_zoom_val);
5303 m_lpinchPoint = pinchPoint;
5307 zoom_inc *= zoom_val;
5308 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5309 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5313 wxPoint pinchPoint =
event.GetCenterPoint();
5314 float dx = pinchPoint.x - m_lpinchPoint.x;
5315 float dy = pinchPoint.y - m_lpinchPoint.y;
5317 m_lpinchPoint = pinchPoint;
5328 case GestureFinished: {
5332 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5333 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5337 float tzoom = total_zoom_val;
5339 if (projected_scale >= min_zoom_scale)
5340 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5342 if (projected_scale < max_zoom_scale)
5343 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5345 dx = (cc_x - m_cc_x) * tzoom;
5346 dy = -(cc_y - m_cc_y) * tzoom;
5348 if (zoomTimer.IsRunning()) {
5351 m_zoomFinalZoom = tzoom;
5357 double final_projected_scale =
5361 if (final_projected_scale < min_zoom_scale) {
5365 m_pParentCanvas->m_pQuilt->Invalidate();
5366 m_bforcefull =
true;
5373 m_pParentCanvas->m_pQuilt->Invalidate();
5374 m_bforcefull =
true;
5386 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5390 case GestureCanceled:
5392 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5399 m_bgestureGuard =
true;
5401 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5404void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5414 m_bgestureGuard =
false;
5415 m_bpinchGuard =
false;
5416 m_binGesture =
false;
5417 m_bforcefull =
false;
5420void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5424 m_binGesture =
false;
5425 m_bforcefull =
false;
5429#ifdef HAVE_WX_GESTURE_EVENTS
5431void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5435 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5438 if (m_binPinch)
return;
5439 if (m_bpinchGuard)
return;
5441 int dx =
event.GetDelta().x;
5442 int dy =
event.GetDelta().y;
5444 if (event.IsGestureStart()) {
5445 if (m_binPan)
return;
5449 m_binGesture =
true;
5453 else if (event.IsGestureEnd()) {
5455 m_pParentCanvas->UpdateCanvasControlBar();
5457 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5465 m_pParentCanvas->FreezePiano();
5467 m_pParentCanvas->ThawPiano();
5478 m_bgestureGuard =
true;
5479 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5480 m_bforcefull =
false;
5483bool first_zout =
false;
5486void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5487 float zoom_gain = 1.0;
5488 float zout_gain = 1.0;
5490 float last_zoom_val = m_total_zoom_val;
5492 float max_zoom_scale = 1000.;
5493 float min_zoom_scale = 2e8;
5495 if (event.GetZoomFactor() > 1)
5496 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5498 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5500 float inc_zoom_val =
5501 m_total_zoom_val / last_zoom_val;
5503 double projected_scale =
5504 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5506 if (event.IsGestureStart()) {
5512 m_binGesture =
true;
5513 m_pinchStart =
event.GetPosition();
5514 m_lpinchPoint = m_pinchStart;
5515 m_total_zoom_val = 1.0;
5516 m_final_zoom_val = 1.0;
5519 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5523 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5524 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5527 SetCurrent(*m_pcontext);
5530 ViewPort vpr = m_pParentCanvas->VPoint;
5532 GetTouchBackingBitmap(vpr);
5537 if (event.IsGestureEnd()) {
5543 if (!m_binGesture)
return;
5545 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5546 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5550 float tzoom = m_final_zoom_val;
5552 dx = (cc_x - m_cc_x) * tzoom;
5553 dy = -(cc_y - m_cc_y) * tzoom;
5555 if (zoomTimer.IsRunning()) {
5558 m_zoomFinalZoom = tzoom;
5564 double final_projected_scale =
5568 if (final_projected_scale < min_zoom_scale) {
5572 m_pParentCanvas->m_pQuilt->Invalidate();
5573 m_bforcefull =
true;
5580 m_pParentCanvas->m_pQuilt->Invalidate();
5581 m_bforcefull =
true;
5586 m_final_zoom_val = 1.0;
5587 m_total_zoom_val = 1.0;
5588 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5593 if (projected_scale < min_zoom_scale) {
5594 wxPoint pinchPoint =
event.GetPosition();
5596 float dx = pinchPoint.x - m_lpinchPoint.x;
5597 float dy = pinchPoint.y - m_lpinchPoint.y;
5599 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5600 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5602 m_lpinchPoint = pinchPoint;
5603 m_final_zoom_val *= inc_zoom_val;
5607 if (1 || ((m_total_zoom_val > 1) && !first_zout)) {
5608 wxPoint pinchPoint =
event.GetPosition();
5610 float dx = pinchPoint.x - m_lpinchPoint.x;
5611 float dy = pinchPoint.y - m_lpinchPoint.y;
5613 if ((projected_scale > max_zoom_scale) &&
5614 (projected_scale < min_zoom_scale))
5615 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5616 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5618 m_lpinchPoint = pinchPoint;
5619 m_final_zoom_val *= inc_zoom_val;
5623 m_zoom_inc *= inc_zoom_val;
5624 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5625 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5629 wxPoint pinchPoint =
event.GetPosition();
5630 float dx = pinchPoint.x - m_lpinchPoint.x;
5631 float dy = pinchPoint.y - m_lpinchPoint.y;
5633 m_lpinchPoint = pinchPoint;
5637 m_bgestureGuard =
true;
5638 m_bpinchGuard =
true;
5639 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5642void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5652 m_bgestureGuard =
false;
5653 m_bpinchGuard =
false;
5654 m_binGesture =
false;
5655 m_bforcefull =
false;
5658void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5662 m_binGesture =
false;
5663 m_bforcefull =
false;
5669void glChartCanvas::configureShaders(
ViewPort &vp) {
5670#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5676 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5678 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5679 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5700 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5702 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5703 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5715 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5717 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5718 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5721 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5723 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5724 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5732 shader = pAALine_shader_program[GetCanvasIndex()];
5734 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5737 shader = pring_shader_program[GetCanvasIndex()];
5739 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5740 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5744 if (texture_2DA_shader_program) {
5745 glUseProgram(texture_2DA_shader_program);
5746 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5747 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5748 (
const GLfloat *)pvp->vp_matrix_transform);
5750 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5751 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5759void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5762#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5763 int nl = nVertex / 4;
5765 float *luv = uvCoords;
5768 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5776 glEnableClientState(GL_VERTEX_ARRAY);
5777 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5779 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5780 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5781 glDrawArrays(GL_QUADS, 0, 4);
5788void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5789 float *uvCoords,
ViewPort *vp,
float dx,
5790 float dy,
float angle_rad) {
5791#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5793 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5794 if (!shader)
return;
5799 shader->SetUniform1i(
"uTex", 0);
5804 mat4x4_rotate_Z(Q, I, angle_rad);
5810 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5815 shader->SetAttributePointerf(
"aPos", co1);
5816 shader->SetAttributePointerf(
"aUV", tco1);
5823 GLushort indices1[] = {0,1,3,2};
5824 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5836 tco1[0] = uvCoords[0];
5837 tco1[1] = uvCoords[1];
5838 tco1[2] = uvCoords[2];
5839 tco1[3] = uvCoords[3];
5840 tco1[4] = uvCoords[6];
5841 tco1[5] = uvCoords[7];
5842 tco1[6] = uvCoords[4];
5843 tco1[7] = uvCoords[5];
5848 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5860void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5861#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5863 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5866 shader->SetUniformMatrix4fv(
5867 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5870 colorv[0] = color.Red() / float(256);
5871 colorv[1] = color.Green() / float(256);
5872 colorv[2] = color.Blue() / float(256);
5874 shader->SetUniform4fv(
"color", colorv);
5877 pf[0] = r.x + r.width;
5881 pf[4] = r.x + r.width;
5882 pf[5] = r.y + r.height;
5884 pf[7] = r.y + r.height;
5885 shader->SetAttributePointerf(
"position", pf);
5887 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5895void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5896#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5898 ViewPort VPoint = m_pParentCanvas->VPoint;
5902 GetClientSize(&w, &h);
5903 int sx = GetSize().x;
5904 int sy = GetSize().y;
5908 glViewport(0, 0, (GLint)w, (GLint)h);
5910 if (s_b_useStencil) {
5911 glEnable(GL_STENCIL_TEST);
5912 glStencilMask(0xff);
5913 glClear(GL_STENCIL_BUFFER_BIT);
5914 glDisable(GL_STENCIL_TEST);
5918 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5923 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5924 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5925 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5928 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5930 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5931 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5939 if (bRenderCharts) RenderCharts(gldc, screen_region);
5941 if (bRenderOverlays) {
5942 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5943 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5944 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5945 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5946 DrawFloatingOverlayObjects(m_gldc);
5950 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5955wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5957 wxMemoryDC tdc(tbm);
5958 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5966 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5967 dc.SetPen(*wxTRANSPARENT_PEN);
5969 gShapeBasemap.RenderViewOnDC(dc, tvp);
5970 tdc.SelectObject(wxNullBitmap);
5971 m_touch_backing_bitmap = tbm;
5972 CreateBackingTexture();
5974 return m_touch_backing_bitmap;
5977void glChartCanvas::CreateBackingTexture() {
5978 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5979 unsigned char *imgdata = image.GetData();
5980 unsigned char *imgalpha = image.GetAlpha();
5981 m_tex_w = image.GetWidth();
5982 m_tex_h = image.GetHeight();
5983 m_image_width = m_tex_w;
5984 m_image_height = m_tex_h;
5986 GLuint format = GL_RGBA;
5987 GLuint internalformat = g_texture_rectangle_format;
5989 internalformat = GL_RGBA;
5994 unsigned char *teximage =
5995 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
5997 for (
int i = 0; i < m_image_height; i++) {
5998 for (
int j = 0; j < m_image_width; j++) {
5999 int s = (i * 3 * m_image_width) + (j * 3);
6000 int d = (i * stride * m_tex_w) + (j * stride);
6002 teximage[d + 0] = imgdata[s + 0];
6003 teximage[d + 1] = imgdata[s + 1];
6004 teximage[d + 2] = imgdata[s + 2];
6005 teximage[d + 3] = 255;
6009 glGenTextures(1, &m_TouchBackingTexture);
6010 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6012 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6013 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6014 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6016 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6018 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6019 GL_UNSIGNED_BYTE, teximage);
6022 glBindTexture(GL_TEXTURE_2D, 0);
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.
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.
Manages the chart database and provides access to chart data.
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)
Gets a font object for a UI element.
Wrapper class for OpenGL shader programs.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
Represents a navigational route in the navigation system.
Manages a set of ShapeBaseChart objects at different resolutions.
Window for displaying chart thumbnails.
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.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
Tools to send data to plugins.
Represents an entry in the chart table, containing information about a single chart.