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);
1962 m_gridfont.SetContentScaleFactor(OCPN_GetDisplayContentScaleFactor());
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);
3861 m_pParentCanvas->VPoint.
pix_height - GetChartbarHeight() - h - (h / 4);
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();
3956 int gl_width, gl_height;
3957 gl_width = m_pParentCanvas->VPoint.
pix_width;
3958 gl_height = m_pParentCanvas->VPoint.
pix_height;
3961 m_glcanvas_width = gl_width;
3962 m_glcanvas_height = gl_height;
3966 if (gl_height & 1) {
3968 ViewPort *vp = m_pParentCanvas->GetpVP();
3975 ViewPort *vp = m_pParentCanvas->GetpVP();
3983 ViewPort *vp = m_pParentCanvas->GetpVP();
3986 mat4x4_scale_aniso((
float(*)[4])vp->vp_matrix_transform, m,
3989 mat4x4_translate_in_place((
float(*)[4])vp->vp_matrix_transform,
3997 ViewPort VPoint = m_pParentCanvas->VPoint;
3999 OCPNRegion screen_region(wxRect(0, 0, gl_width, gl_height));
4000 glViewport(0, 0, (GLint)gl_width, (GLint)gl_height);
4003#if !defined(USE_ANDROID_GLES2)
4004 glMatrixMode(GL_PROJECTION);
4007 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4008 glMatrixMode(GL_MODELVIEW);
4012 if (s_b_useStencil) {
4013 glEnable(GL_STENCIL_TEST);
4014 glStencilMask(0xff);
4015 glClear(GL_STENCIL_BUFFER_BIT);
4016 glDisable(GL_STENCIL_TEST);
4022 if (g_GLOptions.m_GLLineSmoothing) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4023 if (g_GLOptions.m_GLPolygonSmoothing)
4024 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4025 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4032 g_glTextureManager->TextureCrunch(0.8);
4037 bool bpost_hilite = !m_pParentCanvas->m_pQuilt->GetHiliteRegion().Empty();
4038 bool useFBO =
false;
4044 if (m_b_BuiltFBO && !bpost_hilite
4049 bool b_newview =
true;
4050 bool b_full =
false;
4058 m_cache_current_ch == m_pParentCanvas->m_singleChart) {
4062#ifdef USE_ANDROID_GLES2
4063 if (recompose) b_newview =
true;
4075 if (VPoint.b_quilt) {
4076 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetFirstChart();
4077 if (!chart) b_full =
true;
4086 bool accelerated_pan =
false;
4096 if (g_GLOptions.m_bUseAcceleratedPanning && m_cache_vp.IsValid() &&
4097 (VPoint.m_projection_type == PROJECTION_MERCATOR ||
4098 VPoint.m_projection_type == PROJECTION_EQUIRECTANGULAR) &&
4100 wxPoint2DDouble c_old =
4103 wxPoint2DDouble c_new =
4107 dy = wxRound(c_new.m_y - c_old.m_y);
4108 dx = wxRound(c_new.m_x - c_old.m_x);
4118 double deltax = c_new.m_x - c_old.m_x;
4119 double deltay = c_new.m_y - c_old.m_y;
4121 bool b_whole_pixel =
true;
4122 if ((fabs(deltax - dx) > 1e-2) || (fabs(deltay - dy) > 1e-2))
4123 b_whole_pixel =
false;
4125 accelerated_pan = b_whole_pixel && abs(dx) < m_cache_tex_x &&
4126 abs(dy) < m_cache_tex_y &&
4127 (abs(dx) > 0 || (abs(dy) > 0));
4136 if (m_displayScale > 1) accelerated_pan =
false;
4141 if (fabs(VPoint.
rotation) > 0) accelerated_pan =
false;
4144#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4147 glBindFramebuffer(GL_FRAMEBUFFER, m_fb0);
4153 if (b_full) accelerated_pan =
false;
4155 if (accelerated_pan) {
4156 if ((dx != 0) || (dy != 0)) {
4168 if (dy > 0 && dy < gl_height)
4169 update_region.Union(
4170 wxRect(0, gl_height - (dy + fluff), gl_width, dy + fluff));
4172 update_region.Union(wxRect(0, 0, gl_width, -dy + fluff));
4174 if (dx > 0 && dx < gl_width)
4175 update_region.Union(
4176 wxRect(gl_width - (dx + fluff), 0, dx + fluff, gl_height));
4178 update_region.Union(wxRect(0, 0, -dx + fluff, gl_height));
4180 m_cache_page = !m_cache_page;
4183 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
4184 GL_TEXTURE_2D, m_cache_tex[m_cache_page], 0);
4196 RenderCharts(m_gldc, update_region);
4200 glDisable(g_texture_rectangle_format);
4205 glBindTexture(GL_TEXTURE_2D, m_cache_tex[!m_cache_page]);
4206 glEnable(GL_TEXTURE_2D);
4210 float x1, x2, y1, y2;
4223 float tx1, tx2, ty1, ty2;
4229 tx2 = sx / (float)m_cache_tex_x;
4231 ty2 = sy / (float)m_cache_tex_y;
4248 coords[2] = -dx + sx;
4250 coords[4] = -dx + sx;
4251 coords[5] = dy + sy;
4253 coords[7] = dy + sy;
4256 ptexture_2D_shader_program[GetCanvasIndex()];
4260 shader->SetUniform1i(
"uTex", 0);
4264 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)sx, 2.0 / (
float)sy, 1.0);
4265 mat4x4_translate_in_place(mvp, -(
float)sx / 2, -(
float)sy / 2, 0);
4266 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)mvp);
4268 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
4290 shader->SetAttributePointerf(
"aPos", co1);
4291 shader->SetAttributePointerf(
"aUV", tco1);
4293 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4296 shader->SetUniformMatrix4fv(
"MVMatrix",
4297 (GLfloat *)VPoint.vp_matrix_transform);
4300 glBindTexture(g_texture_rectangle_format, 0);
4302 glDisable(g_texture_rectangle_format);
4310 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
4311 g_texture_rectangle_format,
4312 m_cache_tex[!m_cache_page], 0);
4323 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4324 glClearColor(color.Red() / 256., color.Green() / 256.,
4325 color.Blue() / 256., 1.0);
4326 glClear(GL_COLOR_BUFFER_BIT);
4332 RenderCharts(m_gldc, rscreen_region);
4337 m_cache_page = !m_cache_page;
4342 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4353 glMatrixMode(GL_PROJECTION);
4356 gluPerspective(2 * 180 / PI * atan2((
double)gl_height, (
double)gl_width),
4357 (GLfloat)gl_width / (GLfloat)gl_height, 1, gl_width);
4359 glMatrixMode(GL_MODELVIEW);
4363 glTranslatef(-gl_width / 2, -gl_height / 2, -gl_width / 2);
4364 glRotated(VPoint.
tilt * 180 / PI, 1, 0, 0);
4366 glGetIntegerv(GL_VIEWPORT, viewport);
4367 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
4368 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
4377 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fb0);
4378 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
4379 glBlitFramebuffer(0, 0, sx, sy, 0, 0, sx*2, sy*2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4381 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4385 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4386 glEnable(g_texture_rectangle_format);
4388 float tx, ty, tx0, ty0, divx, divy;
4391 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format) {
4394 divx = m_cache_tex_x;
4395 divy = m_cache_tex_y;
4398 tx0 = m_fbo_offsetx / divx;
4399 ty0 = m_fbo_offsety / divy;
4400 tx = (m_fbo_offsetx + m_fbo_swidth) / divx;
4401 ty = (m_fbo_offsety + m_fbo_sheight) / divy;
4426 wxColour color = GetGlobalColor(_T (
"NODTA" ));
4427 glClearColor(color.Red() / 256., color.Green() / 256., color.Blue() / 256.,
4429 glClear(GL_COLOR_BUFFER_BIT);
4431 RenderTextures(gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4434 glDisable(g_texture_rectangle_format);
4436 m_cache_vp = VPoint;
4437 m_cache_vp.Validate();
4439 m_cache_current_ch = m_pParentCanvas->m_singleChart;
4441 if (VPoint.b_quilt) m_pParentCanvas->m_pQuilt->SetRenderedVP(VPoint);
4445 RenderCharts(m_gldc, screen_region);
4451 RenderS57TextOverlay(VPoint);
4452 RenderMBTilesOverlay(VPoint);
4456 wxRect rt = upd.GetRect();
4457 LLRegion region = VPoint.GetLLRegion(rt);
4458 ViewPort cvp = ClippedViewport(VPoint, region);
4459 DrawGroundedOverlayObjects(gldc, cvp);
4462 if (m_pParentCanvas->m_bShowTide || m_pParentCanvas->m_bShowCurrent) {
4463 LLRegion screenLLRegion = VPoint.GetLLRegion(screen_region);
4464 LLBBox screenBox = screenLLRegion.GetBox();
4466 screenBox.EnLarge(screenBox.GetLonRange() * 0.05);
4469 if (m_pParentCanvas->m_bShowTide) {
4470 m_pParentCanvas->RebuildTideSelectList(screenBox);
4471 DrawGLTidesInBBox(gldc, VPoint.GetBBox());
4474 if (m_pParentCanvas->m_bShowCurrent) {
4475 m_pParentCanvas->RebuildCurrentSelectList(screenBox);
4476 DrawGLCurrentsInBBox(gldc, VPoint.GetBBox());
4482 if (m_pParentCanvas->m_show_focus_bar &&
4483 (g_canvasConfig != 0)) {
4484 if (m_pParentCanvas == wxWindow::FindFocus()) {
4485 g_focusCanvas = m_pParentCanvas;
4487 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
4488 wxPen ppBlue(colour, 1);
4489 wxBrush ppBrush(colour);
4490 gldc.SetPen(ppBlue);
4491 gldc.SetBrush(ppBrush);
4492 int xw = m_pParentCanvas->GetClientSize().x * m_displayScale;
4493 float rect_pix = m_pParentCanvas->m_focus_indicator_pix * m_displayScale;
4494 wxPoint barPoints[4];
4497 barPoints[1].x = xw;
4499 barPoints[2].x = xw;
4500 barPoints[2].y = rect_pix;
4502 barPoints[3].y = rect_pix;
4504 gldc.DrawPolygon(4, barPoints, 0, 0, 1, 0);
4508 DrawDynamicRoutesTracksAndWaypoints(VPoint);
4512 DrawFloatingOverlayObjects(m_gldc);
4514#ifndef USE_ANDROID_GLES2
4517 glMatrixMode(GL_PROJECTION);
4520 glOrtho(0, (GLint)gl_width, (GLint)gl_height, 0, -1, 1);
4521 glMatrixMode(GL_MODELVIEW);
4526 DrawEmboss(m_gldc, m_pParentCanvas->EmbossDepthScale());
4527 DrawEmboss(m_gldc, m_pParentCanvas->EmbossOverzoomIndicator(gldc));
4530 ViewPort &vp = m_pParentCanvas->GetVP();
4531 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4532 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4533 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_EMBOSS);
4535 if (!g_PrintingInProgress) {
4536 if (m_pParentCanvas->m_pTrackRolloverWin)
4537 m_pParentCanvas->m_pTrackRolloverWin->Draw(gldc);
4539 if (m_pParentCanvas->m_pRouteRolloverWin)
4540 m_pParentCanvas->m_pRouteRolloverWin->Draw(gldc);
4542 if (m_pParentCanvas->m_pAISRolloverWin)
4543 m_pParentCanvas->m_pAISRolloverWin->Draw(gldc);
4545 if (m_pParentCanvas->GetMUIBar())
4546 m_pParentCanvas->GetMUIBar()->DrawGL(gldc, m_displayScale);
4548 if (g_MainToolbar && m_pParentCanvas->IsPrimaryCanvas())
4549 g_MainToolbar->DrawGL(gldc, m_displayScale);
4551 if (g_iENCToolbar && m_pParentCanvas->IsPrimaryCanvas())
4552 g_iENCToolbar->DrawGL(gldc, m_displayScale);
4560 if (m_pParentCanvas->m_pCIWin && m_pParentCanvas->m_pCIWin->IsShown()) {
4561 int x, y, width, height;
4562 m_pParentCanvas->m_pCIWin->GetClientSize(&width, &height);
4563 m_pParentCanvas->m_pCIWin->GetPosition(&x, &y);
4564 wxBitmap bmp(width, height, -1);
4567 dc.SetBackground(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
4570 dc.SetTextBackground(GetGlobalColor(_T (
"UIBCK" )));
4571 dc.SetTextForeground(GetGlobalColor(_T (
"UITX1" )));
4575 wxString s = m_pParentCanvas->m_pCIWin->GetString();
4576 int h = m_pParentCanvas->m_pCIWin->GetCharHeight();
4578 wxStringTokenizer tkz(s, _T(
"\n"));
4581 while (tkz.HasMoreTokens()) {
4582 token = tkz.GetNextToken();
4583 dc.DrawText(token, xt, yt);
4586 dc.SelectObject(wxNullBitmap);
4588 m_gldc.DrawBitmap(bmp, x, y,
false);
4594 if (g_bShowChartBar) DrawChartBar(m_gldc);
4596 if (m_pParentCanvas->m_Compass && m_pParentCanvas->m_bShowCompassWin &&
4598 m_pParentCanvas->m_Compass->Paint(gldc);
4600 RenderGLAlertMessage();
4604 ViewPort &vp = m_pParentCanvas->GetVP();
4605 g_pi_manager->SendViewPortToRequestingPlugIns(vp);
4606 g_pi_manager->RenderAllGLCanvasOverlayPlugIns(
4607 m_pcontext, vp, m_pParentCanvas->m_canvasIndex, OVERLAY_OVER_UI);
4608 glActiveTexture(GL_TEXTURE0);
4612 if (g_bquiting) DrawQuiting();
4613 if (g_bcompression_wait)
4614 DrawCloseMessage(_(
"Waiting for raster chart compression thread exit."));
4619 if (g_b_needFinish) glFinish();
4623 g_glTextureManager->TextureCrunch(0.8);
4624 g_glTextureManager->FactoryCrunch(0.6);
4629 m_pParentCanvas->PaintCleanup();
4631 m_bforcefull =
false;
4636void glChartCanvas::RenderS57TextOverlay(
ViewPort &VPoint) {
4639 if (VPoint.b_quilt) {
4640 if (m_pParentCanvas->m_pQuilt->IsQuiltVector() && ps52plib &&
4641 ps52plib->GetShowS57Text()) {
4642 ChartBase *chart = m_pParentCanvas->m_pQuilt->GetRefChart();
4643 if (chart && (chart->GetChartType() != CHART_TYPE_CM93COMP)) {
4648 ChPI->ClearPLIBTextList();
4650 ps52plib->ClearTextList();
4660 RenderQuiltViewGLText(vpx, screen_region);
4665void glChartCanvas::RenderSingleMBTileOverlay(
const int dbIndex,
bool bOverlay,
4668 LLRegion &screenLLRegion) {
4669 ChartBase *chart = ChartData->OpenChartFromDBAndLock(dbIndex, FULL_INIT);
4673 if (chart == NULL)
return;
4680 if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY)
return;
4682 wxFileName tileFile(chart->GetFullPath());
4684 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
4686 if (!ChartData->CheckAnyCanvasExclusiveTileGroup() ||
4687 (tileSizeMB.GetLo() > 5000)) {
4690 if (!m_pParentCanvas->IsTileOverlayIndexInYesShow(dbIndex)) {
4691 if (!m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4692 m_pParentCanvas->m_tile_noshow_index_array.push_back(dbIndex);
4699 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(dbIndex)) {
4703 pcmbt->RenderRegionViewOnGL(*m_pcontext, vp, screen_region, screenLLRegion);
4706 std::vector<int> piano_active_array_tiles =
4707 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4708 bool bfound =
false;
4710 if (std::find(piano_active_array_tiles.begin(),
4711 piano_active_array_tiles.end(),
4712 dbIndex) != piano_active_array_tiles.end()) {
4717 piano_active_array_tiles.push_back(dbIndex);
4718 m_pParentCanvas->m_Piano->SetActiveKeyArray(piano_active_array_tiles);
4722void glChartCanvas::RenderMBTilesOverlay(
ViewPort &VPoint) {
4724 std::vector<int> stackIndexArray =
4725 m_pParentCanvas->m_pQuilt->GetExtendedStackIndexArray();
4726 unsigned int im = stackIndexArray.size();
4729 if (VPoint.b_quilt && im > 0) {
4730 bool regionVPBuilt =
false;
4732 LLRegion screenLLRegion;
4736 std::vector<int> tiles_to_show;
4737 for (
unsigned int is = 0; is < im; is++) {
4739 ChartData->GetChartTableEntry(stackIndexArray[is]);
4740 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
4741 if (m_pParentCanvas->IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
4743 std::vector<int> piano_active_array_tiles =
4744 m_pParentCanvas->m_Piano->GetActiveKeyArray();
4745 bool bfound =
false;
4747 for (
unsigned int i = 0; i < piano_active_array_tiles.size(); i++) {
4748 if (piano_active_array_tiles[i] == stackIndexArray[is]) {
4749 piano_active_array_tiles.erase(piano_active_array_tiles.begin() +
4757 m_pParentCanvas->m_Piano->SetActiveKeyArray(
4758 piano_active_array_tiles);
4763 tiles_to_show.push_back(stackIndexArray[is]);
4764 if (!regionVPBuilt) {
4767 screenLLRegion = VPoint.GetLLRegion(screen_region);
4768 screenBox = screenLLRegion.GetBox();
4776 regionVPBuilt =
true;
4786 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4787 rit != tiles_to_show.rend(); ++rit) {
4788 RenderSingleMBTileOverlay(*rit, FALSE, vp, screen_region, screenLLRegion);
4790 for (std::vector<int>::reverse_iterator rit = tiles_to_show.rbegin();
4791 rit != tiles_to_show.rend(); ++rit) {
4792 RenderSingleMBTileOverlay(*rit, TRUE, vp, screen_region, screenLLRegion);
4796 LLRegion hiregion = m_pParentCanvas->m_pQuilt->GetHiliteRegion();
4798 if (!hiregion.Empty()) {
4802 switch (global_color_scheme) {
4803 case GLOBAL_COLOR_SCHEME_DAY:
4806 case GLOBAL_COLOR_SCHEME_DUSK:
4809 case GLOBAL_COLOR_SCHEME_NIGHT:
4817#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4818 glColor4f((
float).8, (
float).4, (
float).4, (
float)hitrans);
4820 s_regionColor = wxColor(204, 102, 102, hitrans * 256);
4823 DrawRegion(VPoint, hiregion);
4825 glDisable(GL_BLEND);
4831void glChartCanvas::RenderCanvasBackingChart(
ocpnDC &dc,
4835 GetClientSize(&w, &h);
4837 glViewport(0, 0, (GLint)m_cache_tex_x, (GLint)m_cache_tex_y);
4838#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4839 glMatrixMode(GL_PROJECTION);
4842 glOrtho(0, m_cache_tex_x, m_cache_tex_y, 0, -1, 1);
4843 glMatrixMode(GL_MODELVIEW);
4847 wxRect rtex(0, 0, m_cache_tex_x, m_cache_tex_y);
4849 m_pParentCanvas->GetVP().BuildExpandedVP(m_cache_tex_x, m_cache_tex_y);
4851 bool world_view =
false;
4852 RenderWorldChart(dc, cvp, rtex, world_view);
4853 gShapeBasemap.RenderViewOnDC(dc, cvp);
4859 glViewport(0, 0, (GLint)w, (GLint)h);
4860#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4861 glMatrixMode(GL_PROJECTION);
4864 glOrtho(0, (GLint)w, (GLint)h, 0, -1, 1);
4865 glMatrixMode(GL_MODELVIEW);
4871void glChartCanvas::FastPan(
int dx,
int dy) {
4872#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
4876void glChartCanvas::ZoomProject(
float offset_x,
float offset_y,
float swidth,
4878 SetCurrent(*m_pcontext);
4879 float sx = GetSize().x;
4880 float sy = GetSize().y;
4881 glClear(GL_COLOR_BUFFER_BIT);
4884 GetClientSize(&w, &h);
4886 if (s_b_useStencil) {
4887 glEnable(GL_STENCIL_TEST);
4888 glStencilMask(0xff);
4889 glClear(GL_STENCIL_BUFFER_BIT);
4890 glDisable(GL_STENCIL_TEST);
4906 float sxfactor = sx / swidth;
4907 float syfactor = sy / sheight;
4909 glViewport(-offset_x * sx / swidth - (sx * sxfactor / 2),
4910 -offset_y * (sy / sheight) - (sy * syfactor / 2),
4911 sx * sx / swidth * 2, sy * sy / sheight * 2);
4912 glBindTexture(g_texture_rectangle_format, m_TouchBackingTexture);
4913 glEnable(g_texture_rectangle_format);
4938 RenderTextures(m_gldc, coords, uv, 4, &m_texVP);
4939 glBindTexture(g_texture_rectangle_format, 0);
4945 float tx, ty, tx0, ty0;
4955 glBindTexture(g_texture_rectangle_format, 0);
4958 glBindTexture(g_texture_rectangle_format, m_cache_tex[m_cache_page]);
4959 glEnable(g_texture_rectangle_format);
4965 uv[0] = tx0 / m_cache_tex_x;
4966 uv[1] = ty / m_cache_tex_y;
4967 uv[2] = tx / m_cache_tex_x;
4968 uv[3] = ty / m_cache_tex_y;
4969 uv[4] = tx / m_cache_tex_x;
4970 uv[5] = ty0 / m_cache_tex_y;
4971 uv[6] = tx0 / m_cache_tex_x;
4972 uv[7] = ty0 / m_cache_tex_y;
4984 glViewport(-offset_x * sx / swidth, -offset_y * (sy / sheight),
4985 sx * sx / swidth, sy * sy / sheight);
4987 RenderTextures(m_gldc, coords, uv, 4, m_pParentCanvas->GetpVP());
4989 glDisable(g_texture_rectangle_format);
4990 glBindTexture(g_texture_rectangle_format, 0);
4997 wxColour color = GetGlobalColor(_T(
"GREY1"));
4998 float ht = -offset_y * (sy / sheight);
4999 wxRect r(0, sy - ht, w, ht);
5000 RenderColorRect(r, color);
5003 wxRect rt(0, 0, w, sy - (ht + (sy * sy / sheight)));
5004 RenderColorRect(rt, color);
5007 float w1 = -offset_x * sx / swidth;
5008 wxRect rl(0, 0, w1, sy);
5009 RenderColorRect(rl, color);
5012 float px = w1 + sx * sx / swidth;
5013 wxRect rr(px, 0, sx - px, sy);
5014 RenderColorRect(rr, color);
5023void glChartCanvas::onZoomTimerEvent(wxTimerEvent &event) {
5026 if (m_nRun < m_nTotal) {
5027 m_runoffsetx += m_offsetxStep;
5028 if (m_offsetxStep > 0)
5029 m_runoffsetx = wxMin(m_runoffsetx, m_fbo_offsetx);
5031 m_runoffsetx = wxMax(m_runoffsetx, m_fbo_offsetx);
5033 m_runoffsety += m_offsetyStep;
5034 if (m_offsetyStep > 0)
5035 m_runoffsety = wxMin(m_runoffsety, m_fbo_offsety);
5037 m_runoffsety = wxMax(m_runoffsety, m_fbo_offsety);
5039 m_runswidth += m_swidthStep;
5040 if (m_swidthStep > 0)
5041 m_runswidth = wxMin(m_runswidth, m_fbo_swidth);
5043 m_runswidth = wxMax(m_runswidth, m_fbo_swidth);
5045 m_runsheight += m_sheightStep;
5046 if (m_sheightStep > 0)
5047 m_runsheight = wxMin(m_runsheight, m_fbo_sheight);
5049 m_runsheight = wxMax(m_runsheight, m_fbo_sheight);
5054 ZoomProject(m_runoffsetx, m_runoffsety, m_runswidth, m_runsheight);
5060 if (m_zoomFinaldx || m_zoomFinaldy) {
5061 m_pParentCanvas->
PanCanvas(m_zoomFinaldx, m_zoomFinaldy);
5064 m_zoomFinal =
false;
5068void glChartCanvas::FastZoom(
float factor,
float cp_x,
float cp_y,
float post_x,
5070 int sx = GetSize().x;
5071 int sy = GetSize().y;
5073 m_lastfbo_offsetx = m_fbo_offsetx;
5074 m_lastfbo_offsety = m_fbo_offsety;
5075 m_lastfbo_swidth = m_fbo_swidth;
5076 m_lastfbo_sheight = m_fbo_sheight;
5078 float curr_fbo_offset_x = m_fbo_offsetx;
5079 float curr_fbo_offset_y = m_fbo_offsety;
5080 float curr_fbo_swidth = m_fbo_swidth;
5081 float curr_fbo_sheight = m_fbo_sheight;
5083 float fx = (float)cp_x / sx;
5084 float fy = 1.0 - (float)cp_y / sy;
5086 float fbo_ctr_x = curr_fbo_offset_x + (curr_fbo_swidth * fx);
5087 float fbo_ctr_y = curr_fbo_offset_y + (curr_fbo_sheight * fy);
5089 m_fbo_swidth = curr_fbo_swidth / factor;
5090 m_fbo_sheight = curr_fbo_sheight / factor;
5092 m_fbo_offsetx = fbo_ctr_x - (m_fbo_swidth * fx);
5093 m_fbo_offsety = fbo_ctr_y - (m_fbo_sheight * fy);
5095 m_fbo_offsetx += post_x;
5096 m_fbo_offsety += post_y;
5107 float perStep = m_nStep / m_nTotal;
5109 if (zoomTimer.IsRunning()) {
5110 m_offsetxStep = (m_fbo_offsetx - m_runoffsetx) * perStep;
5111 m_offsetyStep = (m_fbo_offsety - m_runoffsety) * perStep;
5112 m_swidthStep = (m_fbo_swidth - m_runswidth) * perStep;
5113 m_sheightStep = (m_fbo_sheight - m_runsheight) * perStep;
5116 m_offsetxStep = (m_fbo_offsetx - m_lastfbo_offsetx) * perStep;
5117 m_offsetyStep = (m_fbo_offsety - m_lastfbo_offsety) * perStep;
5118 m_swidthStep = (m_fbo_swidth - m_lastfbo_swidth) * perStep;
5119 m_sheightStep = (m_fbo_sheight - m_lastfbo_sheight) * perStep;
5121 m_runoffsetx = m_lastfbo_offsetx;
5122 m_runoffsety = m_lastfbo_offsety;
5123 m_runswidth = m_lastfbo_swidth;
5124 m_runsheight = m_lastfbo_sheight;
5127 if (!zoomTimer.IsRunning()) zoomTimer.Start(m_nStep);
5128 m_zoomFinal =
false;
5134void glChartCanvas::OnEvtPanGesture(wxQT_PanGestureEvent &event) {
5138 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5141 if (m_binPinch)
return;
5142 if (m_bpinchGuard)
return;
5144 int x =
event.GetOffset().x;
5145 int y =
event.GetOffset().y;
5147 int lx =
event.GetLastOffset().x;
5148 int ly =
event.GetLastOffset().y;
5153 switch (event.GetState()) {
5154 case GestureStarted:
5155 if (m_binPan)
break;
5159 m_binGesture =
true;
5163 case GestureUpdated:
5168 m_pParentCanvas->FreezePiano();
5170 m_pParentCanvas->ThawPiano();
5181 case GestureFinished:
5184 m_pParentCanvas->UpdateCanvasControlBar();
5187 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5191 case GestureCanceled:
5193 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5200 m_bgestureGuard =
true;
5201 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5202 m_bforcefull =
false;
5207float zoom_inc = 1.0;
5208bool first_zout =
false;
5210void glChartCanvas::OnEvtPinchGesture(wxQT_PinchGestureEvent &event) {
5211 float zoom_gain = 1.0;
5212 float zout_gain = 1.0;
5215 float total_zoom_val;
5217 float max_zoom_scale = 1000.;
5218 float min_zoom_scale = 2e8;
5220 if (event.GetScaleFactor() > 1)
5221 zoom_val = ((
event.GetScaleFactor() - 1.0) * zoom_gain) + 1.0;
5223 zoom_val = 1.0 - ((1.0 -
event.GetScaleFactor()) * zout_gain);
5225 if (event.GetTotalScaleFactor() > 1)
5226 total_zoom_val = ((event.GetTotalScaleFactor() - 1.0) * zoom_gain) + 1.0;
5229 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zout_gain);
5231 double projected_scale = cc1->GetVP().chart_scale / total_zoom_val;
5234 float max_zoom_scale = 1000.;
5235 if( cc1->GetVP().b_quilt) {
5236 int ref_index = cc1->GetQuiltRefChartdbIndex();
5243 float min_zoom_scale = 2e8;
5247 total_zoom_val = 1.0 - ((1.0 -
event.GetTotalScaleFactor()) * zoom_gain);
5249 double projected_scale =
5250 m_pParentCanvas->GetVP().
chart_scale / total_zoom_val;
5252 switch (event.GetState()) {
5253 case GestureStarted:
5258 m_binGesture =
true;
5260 m_pinchStart =
event.GetCenterPoint();
5261 m_lpinchPoint = m_pinchStart;
5264 event.GetCenterPoint().y, m_pinchlat,
5269 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5270 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5273 SetCurrent(*m_pcontext);
5279 case GestureUpdated:
5281 if (projected_scale < min_zoom_scale) {
5282 wxPoint pinchPoint =
event.GetCenterPoint();
5284 float dx = pinchPoint.x - m_lpinchPoint.x;
5285 float dy = pinchPoint.y - m_lpinchPoint.y;
5287 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5288 -dx / total_zoom_val, dy / total_zoom_val);
5290 m_lpinchPoint = pinchPoint;
5294 if (1 || ((total_zoom_val > 1) && !first_zout)) {
5295 wxPoint pinchPoint =
event.GetCenterPoint();
5297 float dx = pinchPoint.x - m_lpinchPoint.x;
5298 float dy = pinchPoint.y - m_lpinchPoint.y;
5300 if ((projected_scale > max_zoom_scale) &&
5301 (projected_scale < min_zoom_scale))
5302 FastZoom(zoom_val, m_pinchStart.x, m_pinchStart.y,
5303 -dx / total_zoom_val, dy / total_zoom_val);
5305 m_lpinchPoint = pinchPoint;
5309 zoom_inc *= zoom_val;
5310 if ((zoom_inc < 0.9) || (zoom_inc > 1.1)) {
5311 m_pParentCanvas->
ZoomCanvas(zoom_inc,
false);
5315 wxPoint pinchPoint =
event.GetCenterPoint();
5316 float dx = pinchPoint.x - m_lpinchPoint.x;
5317 float dy = pinchPoint.y - m_lpinchPoint.y;
5319 m_lpinchPoint = pinchPoint;
5330 case GestureFinished: {
5334 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5335 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5339 float tzoom = total_zoom_val;
5341 if (projected_scale >= min_zoom_scale)
5342 tzoom = m_pParentCanvas->GetVP().
chart_scale / min_zoom_scale;
5344 if (projected_scale < max_zoom_scale)
5345 tzoom = m_pParentCanvas->GetVP().
chart_scale / max_zoom_scale;
5347 dx = (cc_x - m_cc_x) * tzoom;
5348 dy = -(cc_y - m_cc_y) * tzoom;
5350 if (zoomTimer.IsRunning()) {
5353 m_zoomFinalZoom = tzoom;
5359 double final_projected_scale =
5363 if (final_projected_scale < min_zoom_scale) {
5367 m_pParentCanvas->m_pQuilt->Invalidate();
5368 m_bforcefull =
true;
5375 m_pParentCanvas->m_pQuilt->Invalidate();
5376 m_bforcefull =
true;
5388 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5392 case GestureCanceled:
5394 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5401 m_bgestureGuard =
true;
5403 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5406void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5416 m_bgestureGuard =
false;
5417 m_bpinchGuard =
false;
5418 m_binGesture =
false;
5419 m_bforcefull =
false;
5422void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5426 m_binGesture =
false;
5427 m_bforcefull =
false;
5431#ifdef HAVE_WX_GESTURE_EVENTS
5433void glChartCanvas::OnEvtPanGesture(wxPanGestureEvent &event) {
5437 if (m_pParentCanvas->isRouteEditing() || m_pParentCanvas->isMarkEditing())
5440 if (m_binPinch)
return;
5441 if (m_bpinchGuard)
return;
5443 int dx =
event.GetDelta().x;
5444 int dy =
event.GetDelta().y;
5446 if (event.IsGestureStart()) {
5447 if (m_binPan)
return;
5451 m_binGesture =
true;
5455 else if (event.IsGestureEnd()) {
5457 m_pParentCanvas->UpdateCanvasControlBar();
5459 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5467 m_pParentCanvas->FreezePiano();
5469 m_pParentCanvas->ThawPiano();
5480 m_bgestureGuard =
true;
5481 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5482 m_bforcefull =
false;
5485bool first_zout =
false;
5488void glChartCanvas::OnEvtZoomGesture(wxZoomGestureEvent &event) {
5489 float zoom_gain = 1.0;
5490 float zout_gain = 1.0;
5492 float last_zoom_val = m_total_zoom_val;
5494 float max_zoom_scale = 1000.;
5495 float min_zoom_scale = 2e8;
5497 if (event.GetZoomFactor() > 1)
5498 m_total_zoom_val = ((
event.GetZoomFactor() - 1.0) * zoom_gain) + 1.0;
5500 m_total_zoom_val = 1.0 - ((1.0 -
event.GetZoomFactor()) * zout_gain);
5502 float inc_zoom_val =
5503 m_total_zoom_val / last_zoom_val;
5505 double projected_scale =
5506 m_pParentCanvas->GetVP().
chart_scale / m_total_zoom_val;
5508 if (event.IsGestureStart()) {
5514 m_binGesture =
true;
5515 m_pinchStart =
event.GetPosition();
5516 m_lpinchPoint = m_pinchStart;
5517 m_total_zoom_val = 1.0;
5518 m_final_zoom_val = 1.0;
5521 event.GetPosition().x,
event.GetPosition().y, m_pinchlat, m_pinchlon);
5525 m_cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5526 m_cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5529 SetCurrent(*m_pcontext);
5532 ViewPort vpr = m_pParentCanvas->VPoint;
5534 GetTouchBackingBitmap(vpr);
5539 if (event.IsGestureEnd()) {
5545 if (!m_binGesture)
return;
5547 float cc_x = m_fbo_offsetx + (m_fbo_swidth / 2);
5548 float cc_y = m_fbo_offsety + (m_fbo_sheight / 2);
5552 float tzoom = m_final_zoom_val;
5554 dx = (cc_x - m_cc_x) * tzoom;
5555 dy = -(cc_y - m_cc_y) * tzoom;
5557 if (zoomTimer.IsRunning()) {
5560 m_zoomFinalZoom = tzoom;
5566 double final_projected_scale =
5570 if (final_projected_scale < min_zoom_scale) {
5574 m_pParentCanvas->m_pQuilt->Invalidate();
5575 m_bforcefull =
true;
5582 m_pParentCanvas->m_pQuilt->Invalidate();
5583 m_bforcefull =
true;
5588 m_final_zoom_val = 1.0;
5589 m_total_zoom_val = 1.0;
5590 m_gestureFinishTimer.Start(500, wxTIMER_ONE_SHOT);
5595 if (projected_scale < min_zoom_scale) {
5596 wxPoint pinchPoint =
event.GetPosition();
5598 float dx = pinchPoint.x - m_lpinchPoint.x;
5599 float dy = pinchPoint.y - m_lpinchPoint.y;
5601 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5602 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5604 m_lpinchPoint = pinchPoint;
5605 m_final_zoom_val *= inc_zoom_val;
5609 if (1 || ((m_total_zoom_val > 1) && !first_zout)) {
5610 wxPoint pinchPoint =
event.GetPosition();
5612 float dx = pinchPoint.x - m_lpinchPoint.x;
5613 float dy = pinchPoint.y - m_lpinchPoint.y;
5615 if ((projected_scale > max_zoom_scale) &&
5616 (projected_scale < min_zoom_scale))
5617 FastZoom(inc_zoom_val, m_pinchStart.x, m_pinchStart.y,
5618 -dx / m_total_zoom_val, dy / m_total_zoom_val);
5620 m_lpinchPoint = pinchPoint;
5621 m_final_zoom_val *= inc_zoom_val;
5625 m_zoom_inc *= inc_zoom_val;
5626 if ((m_zoom_inc < 0.9) || (m_zoom_inc > 1.1)) {
5627 m_pParentCanvas->
ZoomCanvas(m_zoom_inc,
false);
5631 wxPoint pinchPoint =
event.GetPosition();
5632 float dx = pinchPoint.x - m_lpinchPoint.x;
5633 float dy = pinchPoint.y - m_lpinchPoint.y;
5635 m_lpinchPoint = pinchPoint;
5639 m_bgestureGuard =
true;
5640 m_bpinchGuard =
true;
5641 m_gestureEeventTimer.Start(500, wxTIMER_ONE_SHOT);
5644void glChartCanvas::onGestureTimerEvent(wxTimerEvent &event) {
5654 m_bgestureGuard =
false;
5655 m_bpinchGuard =
false;
5656 m_binGesture =
false;
5657 m_bforcefull =
false;
5660void glChartCanvas::onGestureFinishTimerEvent(wxTimerEvent &event) {
5664 m_binGesture =
false;
5665 m_bforcefull =
false;
5671void glChartCanvas::configureShaders(
ViewPort &vp) {
5672#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5678 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5680 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5681 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5702 shader = ptexture_2D_shader_program[GetCanvasIndex()];
5704 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5705 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5717 shader = pcircle_filled_shader_program[GetCanvasIndex()];
5719 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5720 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5723 shader = ptexture_2DA_shader_program[GetCanvasIndex()];
5725 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5726 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5734 shader = pAALine_shader_program[GetCanvasIndex()];
5736 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5739 shader = pring_shader_program[GetCanvasIndex()];
5741 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)pvp->vp_matrix_transform);
5742 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)I);
5746 if (texture_2DA_shader_program) {
5747 glUseProgram(texture_2DA_shader_program);
5748 GLint matloc = glGetUniformLocation(texture_2DA_shader_program,
"MVMatrix");
5749 glUniformMatrix4fv(matloc, 1, GL_FALSE,
5750 (
const GLfloat *)pvp->vp_matrix_transform);
5752 glGetUniformLocation(texture_2DA_shader_program,
"TransformMatrix");
5753 glUniformMatrix4fv(transloc, 1, GL_FALSE, (
const GLfloat *)I);
5761void glChartCanvas::RenderTextures(
ocpnDC &dc,
float *coords,
float *uvCoords,
5764#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5765 int nl = nVertex / 4;
5767 float *luv = uvCoords;
5770 RenderSingleTexture(dc, lc, luv, vp, 0, 0, 0);
5778 glEnableClientState(GL_VERTEX_ARRAY);
5779 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5781 glTexCoordPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), uvCoords);
5782 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(GLfloat), coords);
5783 glDrawArrays(GL_QUADS, 0, 4);
5790void glChartCanvas::RenderSingleTexture(
ocpnDC &dc,
float *coords,
5791 float *uvCoords,
ViewPort *vp,
float dx,
5792 float dy,
float angle_rad) {
5793#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5795 GLShaderProgram *shader = ptexture_2D_shader_program[dc.m_canvasIndex];
5796 if (!shader)
return;
5801 shader->SetUniform1i(
"uTex", 0);
5806 mat4x4_rotate_Z(Q, I, angle_rad);
5812 shader->SetUniformMatrix4fv(
"TransformMatrix", (GLfloat *)Q);
5817 shader->SetAttributePointerf(
"aPos", co1);
5818 shader->SetAttributePointerf(
"aUV", tco1);
5825 GLushort indices1[] = {0,1,3,2};
5826 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
5838 tco1[0] = uvCoords[0];
5839 tco1[1] = uvCoords[1];
5840 tco1[2] = uvCoords[2];
5841 tco1[3] = uvCoords[3];
5842 tco1[4] = uvCoords[6];
5843 tco1[5] = uvCoords[7];
5844 tco1[6] = uvCoords[4];
5845 tco1[7] = uvCoords[5];
5850 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5862void glChartCanvas::RenderColorRect(wxRect r, wxColor &color) {
5863#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5865 GLShaderProgram *shader = pcolor_tri_shader_program[GetCanvasIndex()];
5868 shader->SetUniformMatrix4fv(
5869 "MVMatrix", (GLfloat *)m_pParentCanvas->GetpVP()->vp_matrix_transform);
5872 colorv[0] = color.Red() / float(256);
5873 colorv[1] = color.Green() / float(256);
5874 colorv[2] = color.Blue() / float(256);
5876 shader->SetUniform4fv(
"color", colorv);
5879 pf[0] = r.x + r.width;
5883 pf[4] = r.x + r.width;
5884 pf[5] = r.y + r.height;
5886 pf[7] = r.y + r.height;
5887 shader->SetAttributePointerf(
"position", pf);
5889 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5897void glChartCanvas::RenderScene(
bool bRenderCharts,
bool bRenderOverlays) {
5898#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
5900 ViewPort VPoint = m_pParentCanvas->VPoint;
5904 GetClientSize(&w, &h);
5905 int sx = GetSize().x;
5906 int sy = GetSize().y;
5910 glViewport(0, 0, (GLint)w, (GLint)h);
5912 if (s_b_useStencil) {
5913 glEnable(GL_STENCIL_TEST);
5914 glStencilMask(0xff);
5915 glClear(GL_STENCIL_BUFFER_BIT);
5916 glDisable(GL_STENCIL_TEST);
5920 m_pParentCanvas->m_pQuilt->
Compose(m_pParentCanvas->VPoint);
5925 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
5926 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
5927 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5930 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fb0);
5932 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
5933 g_texture_rectangle_format, m_cache_tex[m_cache_page],
5941 if (bRenderCharts) RenderCharts(gldc, screen_region);
5943 if (bRenderOverlays) {
5944 RenderS57TextOverlay(m_pParentCanvas->VPoint);
5945 RenderMBTilesOverlay(m_pParentCanvas->VPoint);
5946 DrawStaticRoutesTracksAndWaypoints(m_pParentCanvas->VPoint);
5947 DrawDynamicRoutesTracksAndWaypoints(VPoint);
5948 DrawFloatingOverlayObjects(m_gldc);
5952 glBindFramebuffer(GL_FRAMEBUFFER, 0);
5957wxBitmap &glChartCanvas::GetTouchBackingBitmap(
ViewPort &vp) {
5959 wxMemoryDC tdc(tbm);
5960 tdc.SetBackground(wxBrush(GetGlobalColor(
"BLUEBACK")));
5968 gShapeBasemap.SetBasemapLandColor(GetGlobalColor(
"LANDBACK"));
5969 dc.SetPen(*wxTRANSPARENT_PEN);
5971 gShapeBasemap.RenderViewOnDC(dc, tvp);
5972 tdc.SelectObject(wxNullBitmap);
5973 m_touch_backing_bitmap = tbm;
5974 CreateBackingTexture();
5976 return m_touch_backing_bitmap;
5979void glChartCanvas::CreateBackingTexture() {
5980 wxImage image = m_touch_backing_bitmap.ConvertToImage();
5981 unsigned char *imgdata = image.GetData();
5982 unsigned char *imgalpha = image.GetAlpha();
5983 m_tex_w = image.GetWidth();
5984 m_tex_h = image.GetHeight();
5985 m_image_width = m_tex_w;
5986 m_image_height = m_tex_h;
5988 GLuint format = GL_RGBA;
5989 GLuint internalformat = g_texture_rectangle_format;
5991 internalformat = GL_RGBA;
5996 unsigned char *teximage =
5997 (
unsigned char *)malloc(stride * m_tex_w * m_tex_h);
5999 for (
int i = 0; i < m_image_height; i++) {
6000 for (
int j = 0; j < m_image_width; j++) {
6001 int s = (i * 3 * m_image_width) + (j * 3);
6002 int d = (i * stride * m_tex_w) + (j * stride);
6004 teximage[d + 0] = imgdata[s + 0];
6005 teximage[d + 1] = imgdata[s + 1];
6006 teximage[d + 2] = imgdata[s + 2];
6007 teximage[d + 3] = 255;
6011 glGenTextures(1, &m_TouchBackingTexture);
6012 glBindTexture(GL_TEXTURE_2D, m_TouchBackingTexture);
6014 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6015 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6016 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
6018 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6020 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_tex_w, m_tex_h, 0, format,
6021 GL_UNSIGNED_BYTE, teximage);
6024 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.
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)
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.
Represents the view port for chart display in OpenCPN.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
bool m_bUseCanvasPanning
Controls OpenGL canvas hardware-accelerated panning mode.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Tools to send data to plugins.
Represents an entry in the chart table, containing information about a single chart.