OpenCPN Partial API docs
Loading...
Searching...
No Matches
ocpndc.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2011 by Sean D'Epagnier *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include <list>
25#include <vector>
26
27#ifdef __MSVC__
28#include <winsock2.h>
29#include <windows.h>
30#endif
31
32#include <wx/wxprec.h>
33
34#ifndef WX_PRECOMP
35#include <wx/wx.h>
36#endif
37
38#include <wx/graphics.h>
39#include <wx/dcclient.h>
40
41#include "config.h"
42#include "ocpndc.h"
43
44#include "model/cutil.h"
45#include "model/config_vars.h"
46
47#include "chcanv.h"
48#include "dychart.h"
49#include "linmath.h"
50#include "ocpn_frame.h"
51#include "ocpn_plugin.h"
52
53#ifdef ocpnUSE_GL
54#include "shaders.h"
55#endif
56
57#ifdef ocpnUSE_GL
58#include "gl_chart_canvas.h"
59extern ocpnGLOptions g_GLOptions;
60#endif
61
62#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
63extern GLint color_tri_shader_program;
64extern GLint circle_filled_shader_program;
65extern GLint texture_2D_shader_program;
66#endif
67
68//----------------------------------------------------------------------------
69// constants
70//----------------------------------------------------------------------------
71#ifndef PI
72#define PI 3.1415926535897931160E0 /* pi */
73#endif
74
75//----------------------------------------------------------------------------
76static wxArrayPtrVoid gTesselatorVertices;
77
78ocpnDC::ocpnDC(glChartCanvas &canvas)
79 : m_glchartCanvas(&canvas),
80 m_glcanvas(NULL),
81 dc(NULL),
82 m_pen(wxNullPen),
83 m_brush(wxNullBrush) {
84#if wxUSE_GRAPHICS_CONTEXT
85 pgc = NULL;
86#endif
87 Init();
88#ifdef ocpnUSE_GL
89 m_canvasIndex = m_glchartCanvas->GetCanvasIndex();
90#endif
91}
92
93ocpnDC::ocpnDC(wxGLCanvas &canvas)
94 : m_glchartCanvas(NULL),
95 m_glcanvas(&canvas),
96 dc(NULL),
97 m_pen(wxNullPen),
98 m_brush(wxNullBrush) {
99#if wxUSE_GRAPHICS_CONTEXT
100 pgc = NULL;
101#endif
102 Init();
103}
104
105ocpnDC::ocpnDC(wxDC &pdc)
106 : m_glchartCanvas(NULL),
107 m_glcanvas(NULL),
108 dc(&pdc),
109 m_pen(wxNullPen),
110 m_brush(wxNullBrush) {
111#if wxUSE_GRAPHICS_CONTEXT
112 pgc = NULL;
113 auto pmdc = dynamic_cast<wxMemoryDC *>(dc);
114 if (pmdc)
115 pgc = wxGraphicsContext::Create(*pmdc);
116 else {
117 auto pcdc = dynamic_cast<wxClientDC *>(dc);
118 if (pcdc) pgc = wxGraphicsContext::Create(*pcdc);
119 }
120#endif
121
122 Init();
123}
124
125ocpnDC::ocpnDC()
126 : m_glchartCanvas(NULL),
127 m_glcanvas(NULL),
128 dc(NULL),
129 m_pen(wxNullPen),
130 m_brush(wxNullBrush) {
131#if wxUSE_GRAPHICS_CONTEXT
132 pgc = NULL;
133#endif
134 Init();
135}
136
137ocpnDC::~ocpnDC() {
138#if wxUSE_GRAPHICS_CONTEXT
139 if (pgc) delete pgc;
140#endif
141 free(workBuf);
142
143#ifdef ocpnUSE_GL
144 free(s_odc_tess_work_buf);
145
146 delete m_pcolor_tri_shader_program;
147 delete m_pAALine_shader_program;
148 delete m_pcircle_filled_shader_program;
149 delete m_ptexture_2D_shader_program;
150#endif
151}
152
153void ocpnDC::Init() {
154 m_buseTex = GetLocaleCanonicalName().IsSameAs("en_US");
155 workBuf = NULL;
156 workBufSize = 0;
157 m_dpi_factor = 1.0;
158 m_canvasIndex = 0;
159 m_textforegroundcolour = wxColour(0, 0, 0);
160#ifdef ocpnUSE_GL
161 s_odc_tess_work_buf = NULL;
162#endif
163
164#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
165 s_odc_tess_vertex_idx = 0;
166 s_odc_tess_vertex_idx_this = 0;
167 s_odc_tess_buf_len = 0;
168
169 s_odc_tess_work_buf = (GLfloat *)malloc(100 * sizeof(GLfloat));
170 s_odc_tess_buf_len = 100;
171
172 m_pcolor_tri_shader_program = NULL;
173 m_pAALine_shader_program = NULL;
174 m_pcircle_filled_shader_program = NULL;
175 m_ptexture_2D_shader_program = NULL;
176#endif
177}
178#ifdef ocpnUSE_GL
179void ocpnDC::SetGLCanvas(glChartCanvas *canvas) {
180 m_glchartCanvas = canvas;
181 m_canvasIndex = m_glchartCanvas->GetCanvasIndex();
182}
183#endif
184
185void ocpnDC::Clear() {
186 if (dc)
187 dc->Clear();
188 else {
189#ifdef ocpnUSE_GL
190 wxBrush tmpBrush = m_brush;
191 int w, h;
192 if (m_glchartCanvas) {
193 SetBrush(wxBrush(m_glchartCanvas->GetBackgroundColour()));
194 m_glchartCanvas->GetSize(&w, &h);
195 } else if (m_glcanvas) {
196 SetBrush(wxBrush(m_glcanvas->GetBackgroundColour()));
197 m_glcanvas->GetSize(&w, &h);
198 } else
199 return;
200
201 DrawRectangle(0, 0, w, h);
202 SetBrush(tmpBrush);
203#endif
204 }
205}
206
207void ocpnDC::SetBackground(const wxBrush &brush) {
208 if (dc)
209 dc->SetBackground(brush);
210 else {
211#ifdef ocpnUSE_GL
212 if (m_glchartCanvas)
213 m_glchartCanvas->SetBackgroundColour(brush.GetColour());
214 else if (m_glcanvas)
215 m_glcanvas->SetBackgroundColour(brush.GetColour());
216 else
217 return;
218#endif
219 }
220}
221
222void ocpnDC::SetPen(const wxPen &pen) {
223 if (dc) {
224 if (pen == wxNullPen)
225 dc->SetPen(*wxTRANSPARENT_PEN);
226 else
227 dc->SetPen(pen);
228 } else
229 m_pen = pen;
230}
231
232void ocpnDC::SetBrush(const wxBrush &brush) {
233 if (dc)
234 dc->SetBrush(brush);
235 else
236 m_brush = brush;
237}
238
239void ocpnDC::SetTextForeground(const wxColour &colour) {
240 if (dc)
241 dc->SetTextForeground(colour);
242 else
243 m_textforegroundcolour = colour;
244}
245
246void ocpnDC::SetFont(const wxFont &font) {
247 if (dc)
248 dc->SetFont(font);
249 else
250 m_font = font;
251}
252
253const wxPen &ocpnDC::GetPen() const {
254 if (dc) return dc->GetPen();
255 return m_pen;
256}
257
258const wxBrush &ocpnDC::GetBrush() const {
259 if (dc) return dc->GetBrush();
260 return m_brush;
261}
262
263const wxFont &ocpnDC::GetFont() const {
264 if (dc) return dc->GetFont();
265 return m_font;
266}
267
268void ocpnDC::GetSize(wxCoord *width, wxCoord *height) const {
269 if (dc)
270 dc->GetSize(width, height);
271 else {
272#ifdef ocpnUSE_GL
273 if (m_glchartCanvas) {
274 *width = m_glchartCanvas->GetGLCanvasWidth();
275 *height = m_glchartCanvas->GetGLCanvasHeight();
276 } else if (m_glcanvas) {
277 m_glcanvas->GetSize(width, height);
278 }
279#endif
280 }
281}
282
283void ocpnDC::SetGLAttrs(bool highQuality) {
284#ifdef ocpnUSE_GL
285
286 // Enable anti-aliased polys, at best quality
287 if (highQuality) {
288 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
289 if (g_GLOptions.m_GLPolygonSmoothing) glEnable(GL_POLYGON_SMOOTH);
290 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
291 glEnable(GL_BLEND);
292 } else {
293 glDisable(GL_LINE_SMOOTH);
294 glDisable(GL_POLYGON_SMOOTH);
295 glDisable(GL_BLEND);
296 }
297#endif
298}
299
300void ocpnDC::SetGLStipple() const {
301#ifdef ocpnUSE_GL
302
303#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
304 switch (m_pen.GetStyle()) {
305 case wxPENSTYLE_DOT: {
306 glLineStipple(1, 0x3333);
307 glEnable(GL_LINE_STIPPLE);
308 break;
309 }
310 case wxPENSTYLE_LONG_DASH: {
311 glLineStipple(1, 0xFFF8);
312 glEnable(GL_LINE_STIPPLE);
313 break;
314 }
315 case wxPENSTYLE_SHORT_DASH: {
316 glLineStipple(1, 0x3F3F);
317 glEnable(GL_LINE_STIPPLE);
318 break;
319 }
320 case wxPENSTYLE_DOT_DASH: {
321 glLineStipple(1, 0x8FF1);
322 glEnable(GL_LINE_STIPPLE);
323 break;
324 }
325 default:
326 break;
327 }
328#endif
329#endif
330}
331
332#ifdef ocpnUSE_GL
333/* draw a half circle using triangles */
334void DrawEndCap(float x1, float y1, float t1, float angle) {
335#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
336 const int steps = 16;
337 float xa, ya;
338 bool first = true;
339 for (int i = 0; i <= steps; i++) {
340 float a = angle + M_PI / 2 + M_PI / steps * i;
341
342 float xb = x1 + t1 / 2 * cos(a);
343 float yb = y1 + t1 / 2 * sin(a);
344 if (first)
345 first = false;
346 else {
347 glVertex2f(x1, y1);
348 glVertex2f(xa, ya);
349 glVertex2f(xb, yb);
350 }
351 xa = xb, ya = yb;
352 }
353#endif
354}
355#endif
356
357// Draws a line between (x1,y1) - (x2,y2) with a start thickness of t1
358void ocpnDC::DrawGLThickLine(float x1, float y1, float x2, float y2, wxPen pen,
359 bool b_hiqual) {
360#ifdef ocpnUSE_GL
361
362 float angle = atan2f(y2 - y1, x2 - x1);
363 float t1 = pen.GetWidth();
364 float t2sina1 = t1 / 2 * sinf(angle);
365 float t2cosa1 = t1 / 2 * cosf(angle);
366
367 // Set up the shader
368 GLShaderProgram *shader;
369 if (m_glchartCanvas) {
370 shader = pcolor_tri_shader_program[m_canvasIndex];
371 shader->Bind();
372 // Assuming here that transform matrix for this shader is preset for canvas.
373 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
374 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
375 } else {
376 shader = m_pcolor_tri_shader_program;
377 shader->Bind();
378 shader->SetUniformMatrix4fv("MVMatrix",
379 (float *)&(m_vp.vp_matrix_transform));
380 }
381
382 wxColor c = pen.GetColour();
383 float colorv[4];
384 colorv[0] = c.Red() / float(256);
385 colorv[1] = c.Green() / float(256);
386 colorv[2] = c.Blue() / float(256);
387 colorv[3] = c.Alpha() / float(256);
388 shader->SetUniform4fv("color", colorv);
389
390 float vert[12];
391 shader->SetAttributePointerf("position", vert);
392
393 // n.b. The dwxDash interpretation for GL only allows for 2 elements in
394 // the dash table. The first is assumed drawn, second is assumed space
395 wxDash *dashes;
396 int n_dashes = pen.GetDashes(&dashes);
397 if (n_dashes) {
398 float lpix = sqrtf(powf((float)(x1 - x2), 2) + powf((float)(y1 - y2), 2));
399 float lrun = 0.;
400 float xa = x1;
401 float ya = y1;
402 float ldraw = t1 * dashes[0];
403 float lspace = t1 * dashes[1];
404
405 while (lrun < lpix) {
406 // Dash
407 float xb = xa + ldraw * cosf(angle);
408 float yb = ya + ldraw * sinf(angle);
409
410 if ((lrun + ldraw) >= lpix) // last segment is partial draw
411 {
412 xb = x2;
413 yb = y2;
414 }
415
416 vert[0] = xa + t2sina1;
417 vert[1] = ya - t2cosa1;
418 vert[2] = xb + t2sina1;
419 vert[3] = yb - t2cosa1;
420 vert[4] = xb - t2sina1;
421 vert[5] = yb + t2cosa1;
422 vert[6] = xb - t2sina1;
423 vert[7] = yb + t2cosa1;
424 vert[8] = xa - t2sina1;
425 vert[9] = ya + t2cosa1;
426 vert[10] = xa + t2sina1;
427 vert[11] = ya - t2cosa1;
428
429 glDrawArrays(GL_TRIANGLES, 0, 6);
430
431 xa = xb;
432 ya = yb;
433 lrun += ldraw;
434
435 // Space
436 xb = xa + lspace * cos(angle);
437 yb = ya + lspace * sin(angle);
438
439 xa = xb;
440 ya = yb;
441 lrun += lspace;
442 }
443
444 } else {
445 vert[0] = x1 + t2sina1;
446 vert[1] = y1 - t2cosa1;
447 vert[2] = x2 + t2sina1;
448 vert[3] = y2 - t2cosa1;
449 vert[4] = x2 - t2sina1;
450 vert[5] = y2 + t2cosa1;
451 vert[6] = x2 - t2sina1;
452 vert[7] = y2 + t2cosa1;
453 vert[8] = x1 - t2sina1;
454 vert[9] = y1 + t2cosa1;
455 vert[10] = x1 + t2sina1;
456 vert[11] = y1 - t2cosa1;
457
458 glDrawArrays(GL_TRIANGLES, 0, 6);
459
460 /* wx draws a nice rounded end in dc mode, so replicate
461 * this for opengl mode, should this be done for the dashed mode
462 * case? */
463 // if(pen.GetCap() == wxCAP_ROUND) {
464 // DrawEndCap( x1, y1, t1, angle);
465 // DrawEndCap( x2, y2, t1, angle + M_PI);
466 // }
467 //
468 }
469 shader->UnBind();
470
471#endif
472}
473
474void ocpnDC::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
475 bool b_hiqual) {
476 if (dc) dc->DrawLine(x1, y1, x2, y2);
477#ifdef ocpnUSE_GL
478 else if (ConfigurePen()) {
479 bool b_draw_thick = false;
480
481 float pen_width = wxMax(g_GLMinSymbolLineWidth, m_pen.GetWidth());
482
483 // Enable anti-aliased lines, at best quality
484 if (b_hiqual) {
485 SetGLStipple();
486
487#ifndef __WXQT__
488 glEnable(GL_BLEND);
489 if (g_GLOptions.m_GLLineSmoothing) glEnable(GL_LINE_SMOOTH);
490#endif
491
492 if (pen_width > 1.0) {
493 GLint parms[2];
494 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
495 if (glGetError()) glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
496 if (pen_width > parms[1])
497 b_draw_thick = true;
498 else
499 glLineWidth(pen_width);
500 } else
501 glLineWidth(pen_width);
502 } else {
503 if (pen_width > 1) {
504 GLint parms[2];
505 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
506 if (pen_width > parms[1])
507 b_draw_thick = true;
508 else
509 glLineWidth(pen_width);
510 } else
511 glLineWidth(pen_width);
512 }
513
514#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
515 if (b_draw_thick)
516 DrawGLThickLine(x1, y1, x2, y2, m_pen, b_hiqual);
517 else {
518#if 0 // Use AA lines
519
520 GLShaderProgram *shader = pAALine_shader_program[m_canvasIndex];
521 shader->Bind();
522
523 // Assuming here that transform matrix for this shader is preset for canvas.
524 shader->SetUniformMatrix4fv("MVMatrix", (GLfloat *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
525
526 float vpx[2];
527 int width = 0;
528 int height = 0;
529 GetSize(&width, &height);
530 vpx[0] = width;
531 vpx[1] = height;
532
533 shader->SetUniform2fv("uViewPort", vpx);
534
535 float colorv[4];
536 colorv[0] = m_pen.GetColour().Red() / float(256);
537 colorv[1] = m_pen.GetColour().Green() / float(256);
538 colorv[2] = m_pen.GetColour().Blue() / float(256);
539 colorv[3] = 1.0;
540
541 shader->SetUniform4fv("color", colorv);
542
543 float fBuf[4];
544 shader->SetAttributePointerf("position", fBuf);
545
546
547 wxDash *dashes;
548 int n_dashes = m_pen.GetDashes(&dashes);
549 if (n_dashes) {
550 float angle = atan2f((float)(y2 - y1), (float)(x2 - x1));
551 float cosa = cosf(angle);
552 float sina = sinf(angle);
553 float t1 = m_pen.GetWidth();
554
555 float lpix = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
556 float lrun = 0.;
557 float xa = x1;
558 float ya = y1;
559 float ldraw = t1 * dashes[0];
560 float lspace = t1 * dashes[1];
561
562 ldraw = wxMax(ldraw, 4.0);
563 lspace = wxMax(lspace, 4.0);
564 lpix = wxMin(lpix, 2000.0);
565
566 while (lrun < lpix) {
567 // Dash
568 float xb = xa + ldraw * cosa;
569 float yb = ya + ldraw * sina;
570
571 if ((lrun + ldraw) >= lpix) // last segment is partial draw
572 {
573 xb = x2;
574 yb = y2;
575 }
576
577 fBuf[0] = xa;
578 fBuf[1] = ya;
579 fBuf[2] = xb;
580 fBuf[3] = yb;
581
582 glDrawArrays(GL_LINES, 0, 2);
583
584 xa = xa + (lspace + ldraw) * cosa;
585 ya = ya + (lspace + ldraw) * sina;
586 lrun += lspace + ldraw;
587 }
588 } else // not dashed
589 {
590 fBuf[0] = x1;
591 fBuf[1] = y1;
592 fBuf[2] = x2;
593 fBuf[3] = y2;
594
595 glDrawArrays(GL_LINES, 0, 2);
596 }
597 shader->UnBind();
598#else
599
600 GLShaderProgram *shader;
601 if (m_glchartCanvas) {
602 shader = pcolor_tri_shader_program[m_canvasIndex];
603 shader->Bind();
604 // Assuming here that transform matrix for this shader is preset for
605 // canvas.
606 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
607 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
608 } else {
609 shader = m_pcolor_tri_shader_program;
610 shader->Bind();
611 shader->SetUniformMatrix4fv("MVMatrix",
612 (float *)&(m_vp.vp_matrix_transform));
613 }
614
615 float colorv[4];
616 colorv[0] = m_pen.GetColour().Red() / float(256);
617 colorv[1] = m_pen.GetColour().Green() / float(256);
618 colorv[2] = m_pen.GetColour().Blue() / float(256);
619 colorv[3] = 1.0;
620
621 shader->SetUniform4fv("color", colorv);
622
623 glLineWidth(wxMax(g_GLMinSymbolLineWidth, m_pen.GetWidth()));
624
625 float fBuf[4];
626 shader->SetAttributePointerf("position", fBuf);
627
628 wxDash *dashes;
629 int n_dashes = m_pen.GetDashes(&dashes);
630 if (n_dashes) {
631 float angle = atan2f((float)(y2 - y1), (float)(x2 - x1));
632 float cosa = cosf(angle);
633 float sina = sinf(angle);
634 float t1 = m_pen.GetWidth();
635
636 float lpix = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
637 float lrun = 0.;
638 float xa = x1;
639 float ya = y1;
640 float ldraw = t1 * dashes[0];
641 float lspace = t1 * dashes[1];
642
643 ldraw = wxMax(ldraw, 4.0);
644 lspace = wxMax(lspace, 4.0);
645 // lpix = wxMin(lpix, 2000.0);
646
647 while (lrun < lpix) {
648 // Dash
649 float xb = xa + ldraw * cosa;
650 float yb = ya + ldraw * sina;
651
652 if ((lrun + ldraw) >= lpix) // last segment is partial draw
653 {
654 xb = x2;
655 yb = y2;
656 }
657
658 fBuf[0] = xa;
659 fBuf[1] = ya;
660 fBuf[2] = xb;
661 fBuf[3] = yb;
662
663 glDrawArrays(GL_LINES, 0, 2);
664
665 xa = xa + (lspace + ldraw) * cosa;
666 ya = ya + (lspace + ldraw) * sina;
667 lrun += lspace + ldraw;
668 }
669 } else // not dashed
670 {
671 fBuf[0] = x1;
672 fBuf[1] = y1;
673 fBuf[2] = x2;
674 fBuf[3] = y2;
675
676 glDrawArrays(GL_LINES, 0, 2);
677 }
678 shader->UnBind();
679
680#endif
681 }
682
683#else
684#endif
685 glDisable(GL_LINE_STIPPLE);
686
687 if (b_hiqual) {
688 glDisable(GL_LINE_SMOOTH);
689 glDisable(GL_BLEND);
690 }
691 }
692#endif
693}
694
695// Draws thick lines from triangles
696void ocpnDC::DrawGLThickLines(int n, wxPoint points[], wxCoord xoffset,
697 wxCoord yoffset, wxPen pen, bool b_hiqual) {
698#ifdef ocpnUSE_GL
699 if (n < 2) return;
700
701 wxPoint p0 = points[0];
702 for (int i = 1; i < n; i++) {
703 DrawGLThickLine(p0.x + xoffset, p0.y + yoffset, points[i].x + xoffset,
704 points[i].y + yoffset, pen, b_hiqual);
705 p0 = points[i];
706 }
707 return;
708#endif
709}
710
711void ocpnDC::DrawLines(int n, wxPoint points[], wxCoord xoffset,
712 wxCoord yoffset, bool b_hiqual) {
713 if (dc) dc->DrawLines(n, points, xoffset, yoffset);
714#ifdef ocpnUSE_GL
715 else if (ConfigurePen()) {
716#ifdef __WXQT__
717 SetGLAttrs(false); // Some QT platforms (Android) have trouble with
718 // GL_BLEND / GL_LINE_SMOOTH
719#else
720 SetGLAttrs(b_hiqual);
721#endif
722 bool b_draw_thick = false;
723
724 glDisable(GL_LINE_STIPPLE);
725 SetGLStipple();
726
727 // Enable anti-aliased lines, at best quality
728 if (b_hiqual) {
729 glEnable(GL_BLEND);
730 if (m_pen.GetWidth() > 1) {
731 GLint parms[2];
732 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
733 if (glGetError()) glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
734
735 if (m_pen.GetWidth() > parms[1])
736 b_draw_thick = true;
737 else
738 glLineWidth(wxMax(g_GLMinSymbolLineWidth, m_pen.GetWidth()));
739 } else
740 glLineWidth(wxMax(g_GLMinSymbolLineWidth, 1));
741 } else {
742 if (m_pen.GetWidth() > 1) {
743 GLint parms[2];
744 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
745 if (m_pen.GetWidth() > parms[1])
746 b_draw_thick = true;
747 else
748 glLineWidth(wxMax(g_GLMinSymbolLineWidth, m_pen.GetWidth()));
749 } else
750 glLineWidth(wxMax(g_GLMinSymbolLineWidth, 1));
751 }
752
753 if (b_draw_thick || m_pen.GetStyle() != wxPENSTYLE_SOLID) {
754 DrawGLThickLines(n, points, xoffset, yoffset, m_pen, b_hiqual);
755
756 if (b_hiqual) {
757 glDisable(GL_LINE_STIPPLE);
758 glDisable(GL_LINE_SMOOTH);
759 glDisable(GL_POLYGON_SMOOTH);
760 glDisable(GL_BLEND);
761 }
762
763 return;
764 }
765
766 // Grow the work buffer as necessary
767 if (workBufSize < (size_t)n * 2) {
768 workBuf = (float *)realloc(workBuf, (n * 4) * sizeof(float));
769 workBufSize = n * 4;
770 }
771
772 for (int i = 0; i < n; i++) {
773 workBuf[i * 2] = points[i].x + xoffset;
774 workBuf[(i * 2) + 1] = points[i].y + yoffset;
775 }
776
777#if 0 // Use AA lines
778 GLShaderProgram *shader = pAALine_shader_program[m_canvasIndex];
779 shader->Bind();
780
781 // Assuming here that transform matrix for this shader is preset for canvas.
782 //shader->SetUniformMatrix4fv("MVMatrix", (GLfloat *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
783
784 float vpx[2];
785 int width = 0;
786 int height = 0;
787 GetSize(&width, &height);
788 vpx[0] = width;
789 vpx[1] = height;
790
791 shader->SetUniform2fv("uViewPort", vpx);
792
793 float colorv[4];
794 colorv[0] = m_pen.GetColour().Red() / float(256);
795 colorv[1] = m_pen.GetColour().Green() / float(256);
796 colorv[2] = m_pen.GetColour().Blue() / float(256);
797 colorv[3] = 1.0;
798
799 shader->SetUniform4fv("color", colorv);
800
801 shader->SetAttributePointerf("position", workBuf);
802
803 glDrawArrays(GL_LINE_STRIP, 0, n);
804
805 shader->UnBind();
806#else
807 GLShaderProgram *shader;
808 if (m_glchartCanvas) {
809 shader = pcolor_tri_shader_program[m_canvasIndex];
810 shader->Bind();
811 // Assuming here that transform matrix for this shader is preset for
812 // canvas.
813 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
814 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
815 } else {
816 shader = m_pcolor_tri_shader_program;
817 shader->Bind();
818 shader->SetUniformMatrix4fv("MVMatrix",
819 (float *)&(m_vp.vp_matrix_transform));
820 }
821
822 float colorv[4];
823 colorv[0] = m_pen.GetColour().Red() / float(256);
824 colorv[1] = m_pen.GetColour().Green() / float(256);
825 colorv[2] = m_pen.GetColour().Blue() / float(256);
826 colorv[3] = 1.0;
827
828 shader->SetUniform4fv("color", colorv);
829
830 shader->SetAttributePointerf("position", workBuf);
831
832 glDrawArrays(GL_LINE_STRIP, 0, n);
833
834 shader->UnBind();
835
836#endif
837
838 if (b_hiqual) {
839 glDisable(GL_LINE_STIPPLE);
840 glDisable(GL_LINE_SMOOTH);
841 glDisable(GL_POLYGON_SMOOTH);
842 glDisable(GL_BLEND);
843 }
844 }
845#endif
846}
847
848void ocpnDC::StrokeLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) {
849#if wxUSE_GRAPHICS_CONTEXT
850 if (pgc && dc) {
851 pgc->SetPen(GetPen());
852 pgc->StrokeLine(x1, y1, x2, y2);
853
854 dc->CalcBoundingBox(x1, y1);
855 dc->CalcBoundingBox(x2, y2);
856 } else
857#endif
858 DrawLine(x1, y1, x2, y2, true);
859}
860
861void ocpnDC::StrokeLines(int n, wxPoint *points) {
862 if (n < 2) /* optimization and also to avoid assertion in pgc->StrokeLines */
863 return;
864
865#if wxUSE_GRAPHICS_CONTEXT
866 if (pgc) {
867 wxPoint2DDouble *dPoints =
868 (wxPoint2DDouble *)malloc(n * sizeof(wxPoint2DDouble));
869 for (int i = 0; i < n; i++) {
870 dPoints[i].m_x = points[i].x;
871 dPoints[i].m_y = points[i].y;
872 }
873 pgc->SetPen(GetPen());
874 pgc->StrokeLines(n, dPoints);
875 free(dPoints);
876 } else
877#endif
878 DrawLines(n, points, 0, 0, true);
879}
880
881void ocpnDC::DrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
882 if (dc) dc->DrawRectangle(x, y, w, h);
883#ifdef ocpnUSE_GL
884 else {
885 DrawRoundedRectangle(x, y, w, h, 0);
886 }
887#endif
888}
889
890/* draw the arc along corners */
891static void drawrrhelper(wxCoord x0, wxCoord y0, wxCoord r, int quadrant,
892 int steps) {
893#ifdef ocpnUSE_GL
894#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
895 float step = 1.0 / steps, rs = 2.0 * r * step, rss = rs * step, x, y, dx, dy,
896 ddx, ddy;
897 switch (quadrant) {
898 case 0:
899 x = r, y = 0, dx = 0, dy = -rs, ddx = -rss, ddy = rss;
900 break;
901 case 1:
902 x = 0, y = -r, dx = -rs, dy = 0, ddx = rss, ddy = rss;
903 break;
904 case 2:
905 x = -r, y = 0, dx = 0, dy = rs, ddx = rss, ddy = -rss;
906 break;
907 case 3:
908 x = 0, y = r, dx = rs, dy = 0, ddx = -rss, ddy = -rss;
909 break;
910 default:
911 return; // avoid unitialized compiler warnings
912 }
913
914 for (int i = 0; i < steps; i++) {
915 glVertex2i(x0 + floor(x), y0 + floor(y));
916 x += dx + ddx / 2, y += dy + ddy / 2;
917 dx += ddx, dy += ddy;
918 }
919 glVertex2i(x0 + floor(x), y0 + floor(y));
920#endif
921#endif
922}
923
924void ocpnDC::drawrrhelperGLES2(wxCoord x0, wxCoord y0, wxCoord r, int quadrant,
925 int steps) {
926#ifdef ocpnUSE_GL
927 if (steps == 0) return;
928
929 float step = 1.0 / steps, rs = 2.0 * r * step, rss = rs * step, x, y, dx, dy,
930 ddx, ddy;
931 switch (quadrant) {
932 case 0:
933 x = r, y = 0, dx = 0, dy = -rs, ddx = -rss, ddy = rss;
934 break;
935 case 1:
936 x = 0, y = -r, dx = -rs, dy = 0, ddx = rss, ddy = rss;
937 break;
938 case 2:
939 x = -r, y = 0, dx = 0, dy = rs, ddx = rss, ddy = -rss;
940 break;
941 case 3:
942 x = 0, y = r, dx = rs, dy = 0, ddx = -rss, ddy = -rss;
943 break;
944 default:
945 return; // avoid unitialized compiler warnings
946 }
947
948 for (int i = 0; i < steps; i++) {
949 workBuf[workBufIndex++] = x0 + floor(x);
950 workBuf[workBufIndex++] = y0 + floor(y);
951
952 x += dx + ddx / 2, y += dy + ddy / 2;
953 dx += ddx, dy += ddy;
954 }
955
956 workBuf[workBufIndex++] = x0 + floor(x);
957 workBuf[workBufIndex++] = y0 + floor(y);
958#endif
959}
960
961void ocpnDC::DrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
962 wxCoord r) {
963 if (dc) dc->DrawRoundedRectangle(x, y, w, h, r);
964#ifdef ocpnUSE_GL
965 else {
966 if (!m_glchartCanvas) return;
967
968 r++;
969 int steps = ceil(sqrt((float)r));
970
971 wxCoord x1 = x + r, x2 = x + w - r;
972 wxCoord y1 = y + r, y2 = y + h - r;
973
974 ConfigureBrush();
975 ConfigurePen();
976
977 // Grow the work buffer as necessary
978 size_t bufReq = (steps + 1) * 8 * 2; // large, to be sure
979
980 if (workBufSize < bufReq) {
981 workBuf = (float *)realloc(workBuf, bufReq * sizeof(float));
982 workBufSize = bufReq;
983 }
984 workBufIndex = 0;
985
986 if (steps) {
987 drawrrhelperGLES2(x2, y1, r, 0, steps);
988 drawrrhelperGLES2(x1, y1, r, 1, steps);
989 drawrrhelperGLES2(x1, y2, r, 2, steps);
990 drawrrhelperGLES2(x2, y2, r, 3, steps);
991 }
992
993 GLShaderProgram *shader = pcolor_tri_shader_program[m_canvasIndex];
994 shader->Bind();
995
996 float fcolorv[4];
997 fcolorv[0] = m_brush.GetColour().Red() / float(256);
998 fcolorv[1] = m_brush.GetColour().Green() / float(256);
999 fcolorv[2] = m_brush.GetColour().Blue() / float(256);
1000 fcolorv[3] = m_brush.GetColour().Alpha() / float(256);
1001 shader->SetUniform4fv("color", fcolorv);
1002
1003 float angle = 0.;
1004 float xoffset = 0;
1005 float yoffset = 0;
1006
1007 // Rotate
1008 mat4x4 I, Q;
1009 mat4x4_identity(I);
1010 mat4x4_rotate_Z(Q, I, angle);
1011
1012 // Translate
1013 Q[3][0] = xoffset;
1014 Q[3][1] = yoffset;
1015
1016 mat4x4 X;
1017 mat4x4_mul(X,
1018 (float(*)[4])m_glchartCanvas->m_pParentCanvas->GetpVP()
1019 ->vp_matrix_transform,
1020 Q);
1021 shader->SetUniformMatrix4fv("MVMatrix", (GLfloat *)X);
1022
1023 shader->SetAttributePointerf("position", workBuf);
1024
1025 // Perform the actual drawing.
1026 glDrawArrays(GL_TRIANGLE_FAN, 0, workBufIndex / 2);
1027
1028 // Border color
1029 float bcolorv[4];
1030 bcolorv[0] = m_pen.GetColour().Red() / float(256);
1031 bcolorv[1] = m_pen.GetColour().Green() / float(256);
1032 bcolorv[2] = m_pen.GetColour().Blue() / float(256);
1033 bcolorv[3] = m_pen.GetColour().Alpha() / float(256);
1034
1035 shader->SetUniform4fv("color", bcolorv);
1036
1037 // Perform the actual drawing.
1038 glDrawArrays(GL_LINE_LOOP, 0, workBufIndex / 2);
1039
1040 shader->UnBind();
1041 }
1042#endif
1043}
1044
1045void ocpnDC::DrawCircle(wxCoord x, wxCoord y, wxCoord radius) {
1046 if (dc) {
1047 dc->DrawCircle(x, y, radius);
1048 return;
1049 }
1050
1051#ifdef ocpnUSE_GL
1052 glEnable(GL_BLEND);
1053
1054 float coords[8];
1055 coords[0] = x - radius;
1056 coords[1] = y + radius;
1057 coords[2] = x + radius;
1058 coords[3] = y + radius;
1059 coords[4] = x - radius;
1060 coords[5] = y - radius;
1061 coords[6] = x + radius;
1062 coords[7] = y - radius;
1063
1064 GLShaderProgram *shader;
1065 if (m_glchartCanvas) {
1066 shader = pcircle_filled_shader_program[m_canvasIndex];
1067 shader->Bind();
1068 // Assuming here that transform matrix for this shader is preset for canvas.
1069 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
1070 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
1071 } else {
1072 shader = m_pcircle_filled_shader_program;
1073 shader->Bind();
1074 shader->SetUniformMatrix4fv("MVMatrix",
1075 (float *)&(m_vp.vp_matrix_transform));
1076 }
1077
1078 // GLShaderProgram *shader = pcircle_filled_shader_program[m_canvasIndex];
1079 // shader->Bind();
1080
1081 shader->SetUniform1f("circle_radius", radius);
1082
1083 // Circle center point
1084 float ctrv[2];
1085 ctrv[0] = x;
1086 int width, height;
1087 GetSize(&width, &height);
1088 ctrv[1] = height - y;
1089 shader->SetUniform2fv("circle_center", ctrv);
1090
1091 // Circle color
1092 float colorv[4];
1093 if (m_brush.IsOk()) {
1094 colorv[0] = m_brush.GetColour().Red() / float(256);
1095 colorv[1] = m_brush.GetColour().Green() / float(256);
1096 colorv[2] = m_brush.GetColour().Blue() / float(256);
1097 colorv[3] = (m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT) ? 0.0 : 1.0;
1098 }
1099 shader->SetUniform4fv("circle_color", colorv);
1100
1101 // Border color
1102 float bcolorv[4];
1103 if (m_pen.IsOk()) {
1104 bcolorv[0] = m_pen.GetColour().Red() / float(256);
1105 bcolorv[1] = m_pen.GetColour().Green() / float(256);
1106 bcolorv[2] = m_pen.GetColour().Blue() / float(256);
1107 bcolorv[3] = m_pen.GetColour().Alpha() / float(256);
1108 }
1109 shader->SetUniform4fv("border_color", bcolorv);
1110
1111 // Border Width
1112 if (m_pen.IsOk())
1113 shader->SetUniform1f("border_width", m_pen.GetWidth());
1114 else
1115 shader->SetUniform1f("border_width", 2);
1116
1117 shader->SetAttributePointerf("aPos", coords);
1118
1119 // Perform the actual drawing.
1120 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1121
1122 shader->UnBind();
1123#endif
1124}
1125
1126void ocpnDC::StrokeCircle(wxCoord x, wxCoord y, wxCoord radius) {
1127#if wxUSE_GRAPHICS_CONTEXT
1128 if (pgc && dc) {
1129 wxGraphicsPath gpath = pgc->CreatePath();
1130 gpath.AddCircle(x, y, radius);
1131
1132 pgc->SetPen(GetPen());
1133 pgc->SetBrush(GetBrush());
1134 pgc->DrawPath(gpath);
1135
1136 // keep dc dirty box up-to-date
1137 dc->CalcBoundingBox(x + radius + 2, y + radius + 2);
1138 dc->CalcBoundingBox(x - radius - 2, y - radius - 2);
1139 } else
1140#endif
1141 DrawCircle(x, y, radius);
1142}
1143
1144void ocpnDC::DrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) {
1145 if (dc) dc->DrawEllipse(x, y, width, height);
1146#ifdef ocpnUSE_GL
1147 else {
1148 float r1 = width / 2, r2 = height / 2;
1149 float cx = x + r1, cy = y + r2;
1150
1151 // Enable anti-aliased lines, at best quality
1152 glEnable(GL_BLEND);
1153
1154 /* formula for variable step count to produce smooth ellipse */
1155 float steps = floorf(
1156 wxMax(sqrtf(sqrtf((float)(width * width + height * height))), 1) *
1157 M_PI);
1158
1159 // FIXME (dave??) Unimplemented for GLSL and GLES2
1160 glDisable(GL_BLEND);
1161 }
1162#endif
1163}
1164
1165void ocpnDC::DrawPolygon(int n, wxPoint points[], wxCoord xoffset,
1166 wxCoord yoffset, float scale, float angle) {
1167 if (dc) dc->DrawPolygon(n, points, xoffset, yoffset);
1168#ifdef ocpnUSE_GL
1169 else {
1170#ifdef __WXQT__
1171 SetGLAttrs(false); // Some QT platforms (Android) have trouble with
1172 // GL_BLEND / GL_LINE_SMOOTH
1173#else
1174 SetGLAttrs(true);
1175#endif
1176 ConfigurePen();
1177
1178 // Prepare the line rendering shader
1179 GLShaderProgram *line_shader;
1180 float *mvmatrix;
1181
1182 if (m_glchartCanvas) {
1183 line_shader = pAALine_shader_program[m_canvasIndex];
1184 mvmatrix = (float *)&(
1185 m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
1186 } else {
1187 line_shader = m_pAALine_shader_program;
1188 mvmatrix = (float *)&(m_vp.vp_matrix_transform);
1189 }
1190
1191 {
1192 // GLShaderProgram *shader = pAALine_shader_program[m_canvasIndex];
1193 line_shader->Bind();
1194
1195 line_shader->SetUniform1f("uLineWidth", m_pen.GetWidth());
1196 line_shader->SetUniform1f("uBlendFactor", 2.0);
1197
1198 float vpx[2];
1199 int width = 0;
1200 int height = 0;
1201 GetSize(&width, &height);
1202 vpx[0] = width;
1203 vpx[1] = height;
1204
1205 line_shader->SetUniform2fv("uViewPort", vpx);
1206
1207 float colorv[4];
1208 colorv[0] = m_pen.GetColour().Red() / float(256);
1209 colorv[1] = m_pen.GetColour().Green() / float(256);
1210 colorv[2] = m_pen.GetColour().Blue() / float(256);
1211 colorv[3] = 1.0;
1212
1213 line_shader->SetUniform4fv("color", colorv);
1214
1215 // shader->SetAttributePointerf("position", workBuf);
1216
1217 // Rotate
1218 mat4x4 I, Q;
1219 mat4x4_identity(I);
1220 mat4x4_rotate_Z(Q, I, angle);
1221
1222 // Translate
1223 Q[3][0] = xoffset;
1224 Q[3][1] = yoffset;
1225
1226 mat4x4 X;
1227 mat4x4_mul(
1228 X,
1229 (float(*)[4])
1230 mvmatrix, // m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform,
1231 Q);
1232
1233 line_shader->SetUniformMatrix4fv("MVMatrix", (GLfloat *)X);
1234
1235 line_shader->UnBind();
1236 }
1237
1238 if (n > 4) {
1239 if (ConfigureBrush()) // Check for transparent brush
1240 DrawPolygonTessellated(n, points, xoffset, yoffset);
1241
1242 // Draw the polygon ouline
1243 // Grow the work buffer as necessary
1244 if (workBufSize < (size_t)n * 2) {
1245 workBuf = (float *)realloc(workBuf, (n * 4) * sizeof(float));
1246 workBufSize = n * 4;
1247 }
1248
1249 for (int i = 0; i < n; i++) {
1250 workBuf[i * 2] = (points[i].x * scale);
1251 workBuf[i * 2 + 1] = (points[i].y * scale);
1252 }
1253
1254 line_shader->Bind();
1255 line_shader->SetAttributePointerf("position", workBuf);
1256
1257 // Render the polygon outline.
1258 glDrawArrays(GL_LINE_LOOP, 0, n);
1259
1260 // Restore the default matrix
1261 // TODO This will not work for multicanvas
1262 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
1263 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
1264
1265 line_shader->UnBind();
1266
1267 } else { // n = 3 or 4, most common case for pre-tesselated shapes
1268
1269 // Grow the work buffer as necessary
1270 if (workBufSize < (size_t)n * 2) {
1271 workBuf = (float *)realloc(workBuf, (n * 4) * sizeof(float));
1272 workBufSize = n * 4;
1273 }
1274
1275 for (int i = 0; i < n; i++) {
1276 workBuf[i * 2] = (points[i].x * scale); // + xoffset;
1277 workBuf[i * 2 + 1] = (points[i].y * scale); // + yoffset;
1278 }
1279
1280 // Draw the triangle fill
1281 GLShaderProgram *shader;
1282 float *mvmatrix;
1283
1284 if (m_glchartCanvas) {
1285 shader = pcolor_tri_shader_program[m_canvasIndex];
1286 mvmatrix = (float *)&(
1287 m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
1288 } else {
1289 shader = m_pcolor_tri_shader_program;
1290 mvmatrix = (float *)&(m_vp.vp_matrix_transform);
1291 }
1292 shader->Bind();
1293
1294 // Rotate
1295 mat4x4 I, Q;
1296 mat4x4_identity(I);
1297 mat4x4_rotate_Z(Q, I, angle);
1298
1299 // Translate
1300 Q[3][0] = xoffset;
1301 Q[3][1] = yoffset;
1302 mat4x4 X;
1303 mat4x4_mul(X, (float(*)[4])mvmatrix, Q);
1304 shader->SetUniformMatrix4fv("MVMatrix", (GLfloat *)X);
1305
1306 // Fill color
1307 float bcolorv[4];
1308 bcolorv[0] = m_brush.GetColour().Red() / float(256);
1309 bcolorv[1] = m_brush.GetColour().Green() / float(256);
1310 bcolorv[2] = m_brush.GetColour().Blue() / float(256);
1311 bcolorv[3] = m_brush.GetColour().Alpha() / float(256);
1312 shader->SetUniform4fv("color", bcolorv);
1313
1314 shader->SetAttributePointerf("position", workBuf);
1315
1316 // For the simple common case of a convex rectangle...
1317 // swizzle the array points to enable GL_TRIANGLE_STRIP
1318 if (n == 4) {
1319 float x1 = workBuf[4];
1320 float y1 = workBuf[5];
1321 workBuf[4] = workBuf[6];
1322 workBuf[5] = workBuf[7];
1323 workBuf[6] = x1;
1324 workBuf[7] = y1;
1325
1326 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1327 } else if (n == 3) {
1328 glDrawArrays(GL_TRIANGLES, 0, 3);
1329 }
1330
1331 // Restore the default glCanvas matrix
1332 if (m_glchartCanvas) {
1333 shader->SetUniformMatrix4fv(
1334 "MVMatrix", (GLfloat *)m_glchartCanvas->m_pParentCanvas->GetpVP()
1335 ->vp_matrix_transform);
1336 }
1337
1338 shader->UnBind();
1339
1340 // Draw the polygon outline
1341
1342 // Reset the workbuf, corrupted in swizzle above
1343 for (int i = 0; i < n; i++) {
1344 workBuf[i * 2] = (points[i].x * scale); // + xoffset;
1345 workBuf[i * 2 + 1] = (points[i].y * scale); // + yoffset;
1346 }
1347
1348 line_shader->Bind();
1349
1350 line_shader->SetAttributePointerf("position", workBuf);
1351
1352 glDrawArrays(GL_LINE_LOOP, 0, n);
1353
1354 // Restore the default matrix
1355 // TODO This will not work for multicanvas
1356 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
1357 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
1358
1359 line_shader->UnBind();
1360 }
1361
1362 SetGLAttrs(false);
1363 }
1364#endif
1365}
1366
1367#ifdef ocpnUSE_GL
1368
1369// GL callbacks
1370
1371typedef union {
1372 GLdouble data[6];
1373 struct sGLvertex {
1374 GLdouble x;
1375 GLdouble y;
1376 GLdouble z;
1377 GLdouble r;
1378 GLdouble g;
1379 GLdouble b;
1380 } info;
1381} GLvertex;
1382
1383// GLSL callbacks
1384
1385#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
1386
1387static std::list<double *> odc_combine_work_data;
1388static void odc_combineCallbackD(GLdouble coords[3], GLdouble *vertex_data[4],
1389 GLfloat weight[4], GLdouble **dataOut,
1390 void *data) {
1391 // double *vertex = new double[3];
1392 // odc_combine_work_data.push_back(vertex);
1393 // memcpy(vertex, coords, 3*(sizeof *coords));
1394 // *dataOut = vertex;
1395}
1396
1397void odc_vertexCallbackD_GLSL(GLvoid *vertex, void *data) {
1398 ocpnDC *pDC = (ocpnDC *)data;
1399
1400 // Grow the work buffer if necessary
1401 if (pDC->s_odc_tess_vertex_idx > pDC->s_odc_tess_buf_len - 8) {
1402 int new_buf_len = pDC->s_odc_tess_buf_len + 100;
1403 GLfloat *tmp = pDC->s_odc_tess_work_buf;
1404
1405 pDC->s_odc_tess_work_buf = (GLfloat *)realloc(
1406 pDC->s_odc_tess_work_buf, new_buf_len * sizeof(GLfloat));
1407 if (NULL == pDC->s_odc_tess_work_buf) {
1408 free(tmp);
1409 tmp = NULL;
1410 } else
1411 pDC->s_odc_tess_buf_len = new_buf_len;
1412 }
1413
1414 GLdouble *pointer = (GLdouble *)vertex;
1415
1416 pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx++] = (float)pointer[0];
1417 pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx++] = (float)pointer[1];
1418
1419 pDC->s_odc_nvertex++;
1420}
1421
1422void odc_beginCallbackD_GLSL(GLenum mode, void *data) {
1423 ocpnDC *pDC = (ocpnDC *)data;
1424 pDC->s_odc_tess_vertex_idx_this = pDC->s_odc_tess_vertex_idx;
1425 pDC->s_odc_tess_mode = mode;
1426 pDC->s_odc_nvertex = 0;
1427}
1428
1429void odc_endCallbackD_GLSL(void *data) {
1430#if 1
1431 ocpnDC *pDC = (ocpnDC *)data;
1432
1433 GLShaderProgram *shader = pcolor_tri_shader_program[pDC->m_canvasIndex];
1434 shader->Bind();
1435
1436 float colorv[4];
1437 wxColour c = pDC->GetBrush().GetColour();
1438
1439 colorv[0] = c.Red() / float(256);
1440 colorv[1] = c.Green() / float(256);
1441 colorv[2] = c.Blue() / float(256);
1442 colorv[3] = c.Alpha() / float(256);
1443 shader->SetUniform4fv("color", colorv);
1444
1445 float *bufPt = &(pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx_this]);
1446 shader->SetAttributePointerf("position", bufPt);
1447
1448 glDrawArrays(pDC->s_odc_tess_mode, 0, pDC->s_odc_nvertex);
1449
1450 shader->UnBind();
1451
1452#endif
1453}
1454#endif
1455
1456#endif // #ifdef ocpnUSE_GL
1457
1458void ocpnDC::DrawPolygonTessellated(int n, wxPoint points[], wxCoord xoffset,
1459 wxCoord yoffset) {
1460 if (dc) dc->DrawPolygon(n, points, xoffset, yoffset);
1461#ifdef ocpnUSE_GL
1462 else {
1463 if (!m_glchartCanvas) return;
1464
1465#if !defined(ocpnUSE_GLES) || \
1466 defined(USE_ANDROID_GLES2) // tessalator in glues is broken
1467 if (n < 5)
1468#endif
1469 {
1470 DrawPolygon(n, points, xoffset, yoffset);
1471 return;
1472 }
1473
1474#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
1475 m_tobj = gluNewTess();
1476 s_odc_tess_vertex_idx = 0;
1477
1478 gluTessCallback(m_tobj, GLU_TESS_VERTEX_DATA,
1479 (_GLUfuncptr)&odc_vertexCallbackD_GLSL);
1480 gluTessCallback(m_tobj, GLU_TESS_BEGIN_DATA,
1481 (_GLUfuncptr)&odc_beginCallbackD_GLSL);
1482 gluTessCallback(m_tobj, GLU_TESS_END_DATA,
1483 (_GLUfuncptr)&odc_endCallbackD_GLSL);
1484 gluTessCallback(m_tobj, GLU_TESS_COMBINE_DATA,
1485 (_GLUfuncptr)&odc_combineCallbackD);
1486 // s_tessVP = vp;
1487
1488 gluTessNormal(m_tobj, 0, 0, 1);
1489 gluTessProperty(m_tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
1490
1491 if (ConfigureBrush()) {
1492 gluTessBeginPolygon(m_tobj, this);
1493 gluTessBeginContour(m_tobj);
1494
1495 ViewPort *pvp = m_glchartCanvas->m_pParentCanvas
1496 ->GetpVP(); // gFrame->GetPrimaryCanvas()->GetpVP();
1497
1498 for (int i = 0; i < n; i++) {
1499 double *p = new double[6];
1500
1501 if (fabs(pvp->rotation) > 0.01) {
1502 float cx = pvp->pix_width / 2.;
1503 float cy = pvp->pix_height / 2.;
1504 float c = cosf(pvp->rotation);
1505 float s = sinf(pvp->rotation);
1506 float xn = points[i].x - cx;
1507 float yn = points[i].y - cy;
1508 p[0] = xn * c - yn * s + cx;
1509 p[1] = xn * s + yn * c + cy;
1510 p[2] = 0;
1511 } else
1512 p[0] = points[i].x, p[1] = points[i].y, p[2] = 0;
1513
1514 gluTessVertex(m_tobj, p, p);
1515 }
1516 gluTessEndContour(m_tobj);
1517 gluTessEndPolygon(m_tobj);
1518 }
1519
1520 gluDeleteTess(m_tobj);
1521
1522 // for(std::list<double*>::iterator i =
1523 // odc_combine_work_data.begin(); i!=odc_combine_work_data.end();
1524 // i++)
1525 // delete [] *i;
1526 // odc_combine_work_data.clear();
1527 }
1528#else
1529 }
1530
1531#endif
1532#endif
1533}
1534
1535void ocpnDC::StrokePolygon(int n, wxPoint points[], wxCoord xoffset,
1536 wxCoord yoffset, float scale) {
1537#if wxUSE_GRAPHICS_CONTEXT
1538 if (pgc && dc) {
1539 wxGraphicsPath gpath = pgc->CreatePath();
1540 gpath.MoveToPoint(points[0].x * scale + xoffset,
1541 points[0].y * scale + yoffset);
1542 for (int i = 1; i < n; i++)
1543 gpath.AddLineToPoint(points[i].x * scale + xoffset,
1544 points[i].y * scale + yoffset);
1545 gpath.AddLineToPoint(points[0].x * scale + xoffset,
1546 points[0].y * scale + yoffset);
1547
1548 pgc->SetPen(GetPen());
1549 pgc->SetBrush(GetBrush());
1550 pgc->DrawPath(gpath);
1551
1552 for (int i = 0; i < n; i++)
1553 dc->CalcBoundingBox(points[i].x * scale + xoffset,
1554 points[i].y * scale + yoffset);
1555 } else
1556#endif
1557 DrawPolygon(n, points, xoffset, yoffset, scale);
1558}
1559
1560void ocpnDC::DrawBitmap(const wxBitmap &bitmap, wxCoord x, wxCoord y,
1561 bool usemask) {
1562 wxBitmap bmp;
1563 if (x < 0 || y < 0) {
1564 int dx = (x < 0 ? -x : 0);
1565 int dy = (y < 0 ? -y : 0);
1566 int w = bitmap.GetWidth() - dx;
1567 int h = bitmap.GetHeight() - dy;
1568 /* picture is out of viewport */
1569 if (w <= 0 || h <= 0) return;
1570 wxBitmap newBitmap = bitmap.GetSubBitmap(wxRect(dx, dy, w, h));
1571 x += dx;
1572 y += dy;
1573 bmp = newBitmap;
1574 } else {
1575 bmp = bitmap;
1576 }
1577 if (dc) dc->DrawBitmap(bmp, x, y, usemask);
1578#ifdef ocpnUSE_GL
1579 else {
1580#ifdef ocpnUSE_GLES // Do not attempt to do anything with glDrawPixels if using
1581 // opengles
1582 return; // this should not be hit anymore ever anyway
1583#endif
1584
1585#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1586 wxImage image = bmp.ConvertToImage();
1587 int w = image.GetWidth(), h = image.GetHeight();
1588
1589 if (usemask) {
1590 unsigned char *d = image.GetData();
1591 unsigned char *a = image.GetAlpha();
1592
1593#ifdef __WXOSX__
1594 if (image.HasMask()) a = 0;
1595#endif
1596 unsigned char mr, mg, mb;
1597 if (!a && !image.GetOrFindMaskColour(&mr, &mg, &mb)) {
1598 printf("trying to use mask to draw a bitmap without alpha or mask\n");
1599 }
1600
1601 unsigned char *e = new unsigned char[4 * w * h];
1602 if (e && d) {
1603 for (int y = 0; y < h; y++)
1604 for (int x = 0; x < w; x++) {
1605 unsigned char r, g, b;
1606 int off = (y * w + x);
1607 r = d[off * 3 + 0];
1608 g = d[off * 3 + 1];
1609 b = d[off * 3 + 2];
1610
1611 e[off * 4 + 0] = r;
1612 e[off * 4 + 1] = g;
1613 e[off * 4 + 2] = b;
1614
1615 e[off * 4 + 3] =
1616 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
1617 // e[off * 4 + 3] = ( ( r == mr ) && ( g ==
1618 // mg ) && ( b == mb ) ? 0 : 255 );
1619 }
1620 }
1621
1622 glColor4f(1, 1, 1, 1);
1623 GLDrawBlendData(x, y, w, h, GL_RGBA, e);
1624 delete[] (e);
1625 } else {
1626 glRasterPos2i(x, y);
1627 glPixelZoom(1, -1); /* draw data from top to bottom */
1628 if (image.GetData())
1629 glDrawPixels(w, h, GL_RGB, GL_UNSIGNED_BYTE, image.GetData());
1630 glPixelZoom(1, 1);
1631 }
1632#endif // GLES2
1633 }
1634#endif
1635}
1636
1637void ocpnDC::DrawText(const wxString &text, wxCoord x, wxCoord y, float angle) {
1638 if (dc) dc->DrawText(text, x, y);
1639#ifdef ocpnUSE_GL
1640 else {
1641 wxCoord w = 0;
1642 wxCoord h = 0;
1643
1644 // FIXME Dave Re-enable, and fix rotation logic.
1645 if (0 /*m_buseTex*/) {
1646 m_texfont.Build(m_font, 1.0,
1647 m_dpi_factor); // make sure the font is ready
1648 m_texfont.GetTextExtent(text, &w, &h);
1649 m_texfont.SetColor(m_textforegroundcolour);
1650
1651 if (w && h) {
1652 glEnable(GL_BLEND);
1653 glEnable(GL_TEXTURE_2D);
1654 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1655
1656 m_texfont.RenderString(text, x, y, angle);
1657
1658 glDisable(GL_TEXTURE_2D);
1659 glDisable(GL_BLEND);
1660 }
1661 } else {
1662 wxScreenDC sdc;
1663 sdc.SetFont(m_font);
1664 sdc.GetTextExtent(text, &w, &h, NULL, NULL, &m_font);
1665 if (w && h) {
1666 /* create bitmap of appropriate size and select it */
1667 wxBitmap bmp(w, h);
1668 wxMemoryDC temp_dc;
1669 temp_dc.SelectObject(bmp);
1670
1671 /* fill bitmap with black */
1672 temp_dc.SetBackground(wxBrush(wxColour(0, 0, 0)));
1673 temp_dc.Clear();
1674
1675 /* draw the text white */
1676 temp_dc.SetFont(m_font);
1677 temp_dc.SetTextForeground(wxColour(255, 255, 255));
1678 temp_dc.DrawText(text, 0, 0);
1679 temp_dc.SelectObject(wxNullBitmap);
1680
1681 /* use the data in the bitmap for alpha channel,
1682 and set the color to text foreground */
1683 wxImage image = bmp.ConvertToImage();
1684 if (x < 0 ||
1685 y < 0) { // Allow Drawing text which is offset to start off screen
1686 int dx = (x < 0 ? -x : 0);
1687 int dy = (y < 0 ? -y : 0);
1688 w = bmp.GetWidth() - dx;
1689 h = bmp.GetHeight() - dy;
1690 /* picture is out of viewport */
1691 if (w <= 0 || h <= 0) return;
1692 image = image.GetSubImage(wxRect(dx, dy, w, h));
1693 x += dx;
1694 y += dy;
1695 }
1696
1697 unsigned char *data = new unsigned char[w * h * 4];
1698 unsigned char *im = image.GetData();
1699
1700 if (im) {
1701 unsigned int r = m_textforegroundcolour.Red();
1702 unsigned int g = m_textforegroundcolour.Green();
1703 unsigned int b = m_textforegroundcolour.Blue();
1704 for (int i = 0; i < h; i++) {
1705 for (int j = 0; j < w; j++) {
1706 unsigned int index = ((i * w) + j) * 4;
1707 data[index] = r;
1708 data[index + 1] = g;
1709 data[index + 2] = b;
1710 data[index + 3] = im[((i * w) + j) * 3];
1711 }
1712 }
1713 }
1714
1715 unsigned int texobj;
1716
1717 glGenTextures(1, &texobj);
1718 glBindTexture(GL_TEXTURE_2D, texobj);
1719
1720 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1721 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1722
1723 int TextureWidth = NextPow2(w);
1724 int TextureHeight = NextPow2(h);
1725 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TextureWidth, TextureHeight, 0,
1726 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1727 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
1728 data);
1729
1730 glEnable(GL_TEXTURE_2D);
1731 glEnable(GL_BLEND);
1732 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1733
1734 float u = (float)w / TextureWidth, v = (float)h / TextureHeight;
1735
1736 float uv[8];
1737 float coords[8];
1738
1739 // normal uv
1740 uv[0] = 0;
1741 uv[1] = 0;
1742 uv[2] = u;
1743 uv[3] = 0;
1744 uv[4] = u;
1745 uv[5] = v;
1746 uv[6] = 0;
1747 uv[7] = v;
1748
1749 // pixels
1750 coords[0] = 0;
1751 coords[1] = 0;
1752 coords[2] = w;
1753 coords[3] = 0;
1754 coords[4] = w;
1755 coords[5] = h;
1756 coords[6] = 0;
1757 coords[7] = h;
1758
1759 // Set up the shader
1760 GLShaderProgram *shader;
1761 if (m_glchartCanvas) {
1762 shader = ptexture_2D_shader_program[m_canvasIndex];
1763 shader->Bind();
1764 // Assuming here that transform matrix for this shader is preset for
1765 // canvas.
1766 // shader->SetUniformMatrix4fv("MVMatrix", (GLfloat
1767 // *)m_glchartCanvas->m_pParentCanvas->GetpVP()->vp_matrix_transform);
1768 } else {
1769 shader = m_ptexture_2D_shader_program;
1770 shader->Bind();
1771 shader->SetUniformMatrix4fv("MVMatrix",
1772 (float *)&(m_vp.vp_matrix_transform));
1773 }
1774
1775 // Set up the texture sampler to texture unit 0
1776 shader->SetUniform1i("uTex", 0);
1777
1778 // Rotate
1779 mat4x4 I, Q;
1780 mat4x4_identity(I);
1781 mat4x4_rotate_Z(Q, I, 0);
1782
1783 // Translate
1784 Q[3][0] = x;
1785 Q[3][1] = y;
1786
1787 shader->SetUniformMatrix4fv("TransformMatrix", (GLfloat *)Q);
1788
1789 float co1[8];
1790 float tco1[8];
1791
1792 // Perform the actual drawing.
1793
1794 // For some reason, glDrawElements is busted on Android
1795 // So we do this a hard ugly way, drawing two triangles...
1796 co1[0] = coords[0];
1797 co1[1] = coords[1];
1798 co1[2] = coords[2];
1799 co1[3] = coords[3];
1800 co1[4] = coords[6];
1801 co1[5] = coords[7];
1802 co1[6] = coords[4];
1803 co1[7] = coords[5];
1804
1805 tco1[0] = uv[0];
1806 tco1[1] = uv[1];
1807 tco1[2] = uv[2];
1808 tco1[3] = uv[3];
1809 tco1[4] = uv[6];
1810 tco1[5] = uv[7];
1811 tco1[6] = uv[4];
1812 tco1[7] = uv[5];
1813
1814 shader->SetAttributePointerf("aPos", co1);
1815 shader->SetAttributePointerf("aUV", tco1);
1816
1817 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1818
1819 shader->UnBind();
1820
1821 glDisable(GL_BLEND);
1822 glDisable(GL_TEXTURE_2D);
1823
1824 glDeleteTextures(1, &texobj);
1825 delete[] data;
1826 }
1827 }
1828 }
1829#endif
1830}
1831
1832void ocpnDC::GetTextExtent(const wxString &string, wxCoord *w, wxCoord *h,
1833 wxCoord *descent, wxCoord *externalLeading,
1834 wxFont *font) {
1835 // Give at least reasonable results on failure.
1836 if (w) *w = 100;
1837 if (h) *h = 100;
1838
1839 if (dc)
1840 dc->GetTextExtent(string, w, h, descent, externalLeading, font);
1841 else {
1842 wxFont f = m_font;
1843 if (font) f = *font;
1844
1845 // FIXME Dave Re-enable, and fix rotation logic.
1846 if (0 /*m_buseTex*/) {
1847#ifdef ocpnUSE_GL
1848 m_texfont.Build(f, 1.0, m_dpi_factor); // make sure the font is ready
1849 m_texfont.GetTextExtent(string, w, h);
1850#else
1851 wxMemoryDC temp_dc;
1852 temp_dc.GetTextExtent(string, w, h, descent, externalLeading, &f);
1853#endif
1854 } else {
1855 wxMemoryDC temp_dc;
1856 temp_dc.GetTextExtent(string, w, h, descent, externalLeading, &f);
1857 }
1858 }
1859
1860 // Sometimes GetTextExtent returns really wrong, uninitialized results.
1861 // Dunno why....
1862 if (w && (*w > 500)) *w = 500;
1863 if (h && (*h > 500)) *h = 500;
1864}
1865
1866void ocpnDC::ResetBoundingBox() {
1867 if (dc) dc->ResetBoundingBox();
1868}
1869
1870void ocpnDC::CalcBoundingBox(wxCoord x, wxCoord y) {
1871 if (dc) dc->CalcBoundingBox(x, y);
1872}
1873
1874bool ocpnDC::ConfigurePen() {
1875 if (!m_pen.IsOk()) return false;
1876 if (m_pen == *wxTRANSPARENT_PEN) return false;
1877
1878 wxColour c = m_pen.GetColour();
1879 int width = m_pen.GetWidth();
1880#ifdef ocpnUSE_GL
1881#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1882 glColor4ub(c.Red(), c.Green(), c.Blue(), c.Alpha());
1883#endif
1884 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
1885#endif
1886 return true;
1887}
1888
1889bool ocpnDC::ConfigureBrush() {
1890 if (m_brush == wxNullBrush || m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT)
1891 return false;
1892#ifdef ocpnUSE_GL
1893 wxColour c = m_brush.GetColour();
1894#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1895 glColor4ub(c.Red(), c.Green(), c.Blue(), c.Alpha());
1896#endif
1897#endif
1898 return true;
1899}
1900
1901void ocpnDC::GLDrawBlendData(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1902 int format, const unsigned char *data) {
1903#ifdef ocpnUSE_GL
1904#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1905 glEnable(GL_BLEND);
1906 glRasterPos2i(x, y);
1907 glPixelZoom(1, -1);
1908 glDrawPixels(w, h, format, GL_UNSIGNED_BYTE, data);
1909 glPixelZoom(1, 1);
1910 glDisable(GL_BLEND);
1911#endif
1912#endif
1913}
1914
1915void ocpnDC::SetVP(ViewPort vp) {
1916 m_vp = vp;
1917
1918 // If not in DC mode, simply return
1919 if (!m_glchartCanvas && !m_glcanvas) return;
1920#ifdef ocpnUSE_GL
1921 // Otherwise, prepare local shaders
1922 m_vp.SetVPTransformMatrix();
1923
1924 BuildShaders();
1925
1926 // Program the matrix transforms for the several private shaders
1927 mat4x4 I;
1928 mat4x4_identity(I);
1929
1930 if (m_pcolor_tri_shader_program) {
1931 m_pcolor_tri_shader_program->Bind();
1932 m_pcolor_tri_shader_program->SetUniformMatrix4fv(
1933 "MVMatrix", (GLfloat *)m_vp.vp_matrix_transform);
1934 m_pcolor_tri_shader_program->SetUniformMatrix4fv("TransformMatrix",
1935 (GLfloat *)I);
1936 m_pcolor_tri_shader_program->UnBind();
1937 }
1938 if (m_pAALine_shader_program) {
1939 m_pAALine_shader_program->Bind();
1940 m_pAALine_shader_program->SetUniformMatrix4fv(
1941 "MVMatrix", (GLfloat *)m_vp.vp_matrix_transform);
1942 m_pAALine_shader_program->SetUniformMatrix4fv("TransformMatrix",
1943 (GLfloat *)I);
1944 m_pAALine_shader_program->UnBind();
1945 }
1946
1947 if (m_pcircle_filled_shader_program) {
1948 m_pcircle_filled_shader_program->Bind();
1949 m_pcircle_filled_shader_program->SetUniformMatrix4fv(
1950 "MVMatrix", (GLfloat *)m_vp.vp_matrix_transform);
1951 m_pcircle_filled_shader_program->SetUniformMatrix4fv("TransformMatrix",
1952 (GLfloat *)I);
1953 m_pcircle_filled_shader_program->UnBind();
1954 }
1955
1956 if (m_ptexture_2D_shader_program) {
1957 m_ptexture_2D_shader_program->Bind();
1958 m_ptexture_2D_shader_program->SetUniformMatrix4fv(
1959 "MVMatrix", (GLfloat *)m_vp.vp_matrix_transform);
1960 m_ptexture_2D_shader_program->SetUniformMatrix4fv("TransformMatrix",
1961 (GLfloat *)I);
1962 m_ptexture_2D_shader_program->UnBind();
1963 }
1964#endif
1965}
1966
1967#ifdef ocpnUSE_GL
1968// Private shaders, used when drawing to a context which is not a glChartCanvas
1969// (i.e. radar_pi)
1970#ifdef USE_ANDROID_GLES2
1971const GLchar *odc_preamble = "\n";
1972#else
1973const GLchar *odc_preamble =
1974 "#version 120\n"
1975 "#define precision\n"
1976 "#define lowp\n"
1977 "#define mediump\n"
1978 "#define highp\n";
1979#endif
1980
1981// Simple colored triangle shader
1982
1983static const GLchar *odc_color_tri_vertex_shader_source =
1984 "attribute vec2 position;\n"
1985 "uniform mat4 MVMatrix;\n"
1986 "uniform mat4 TransformMatrix;\n"
1987 "uniform vec4 color;\n"
1988 "varying vec4 fragColor;\n"
1989 "void main() {\n"
1990 " fragColor = color;\n"
1991 " gl_Position = MVMatrix * TransformMatrix * vec4(position, 0.0, 1.0);\n"
1992 "}\n";
1993
1994static const GLchar *odc_color_tri_fragment_shader_source =
1995 "precision lowp float;\n"
1996 "varying vec4 fragColor;\n"
1997 "void main() {\n"
1998 " gl_FragColor = fragColor;\n"
1999 "}\n";
2000
2001static const GLchar *odc_AALine_vertex_shader_source =
2002 "uniform vec2 uViewPort; //Width and Height of the viewport\n"
2003 "varying vec2 vLineCenter;\n"
2004 "attribute vec2 position;\n"
2005 "uniform mat4 MVMatrix;\n"
2006 "uniform mat4 TransformMatrix;\n"
2007 "void main()\n"
2008 "{\n"
2009 " vec4 pp = MVMatrix * vec4(position, 0.0, 1.0);\n"
2010 " gl_Position = pp;\n"
2011 " vec2 vp = uViewPort;\n"
2012 " vLineCenter = 0.5*(pp.xy + vec2(1, 1))*vp;\n"
2013 "}\n";
2014
2015static const GLchar *odc_AALine_fragment_shader_source =
2016 "precision mediump float;\n"
2017 "uniform float uLineWidth;\n"
2018 "uniform vec4 color;\n"
2019 "uniform float uBlendFactor; //1.5..2.5\n"
2020 "varying vec2 vLineCenter;\n"
2021 "void main()\n"
2022 "{\n"
2023 " vec4 col = color;\n"
2024 " float d = length(vLineCenter-gl_FragCoord.xy);\n"
2025 " float w = uLineWidth;\n"
2026 " if (d>w)\n"
2027 " col.w = 0.0;\n"
2028 " else{\n"
2029 " if(float((w/2-d)/(w/2)) < .5){\n"
2030 " //col.w *= pow(float((w-d)/w), uBlendFactor);\n"
2031 " col.w *= pow(float((w/2-d)/(w/2)), uBlendFactor);\n"
2032 " }\n"
2033 " }\n"
2034 " gl_FragColor = col;\n"
2035 "}\n";
2036
2037// Circle shader
2038static const GLchar *odc_circle_filled_vertex_shader_source =
2039 "precision highp float;\n"
2040 "attribute vec2 aPos;\n"
2041 "uniform mat4 MVMatrix;\n"
2042 "uniform mat4 TransformMatrix;\n"
2043 "void main() {\n"
2044 " gl_Position = MVMatrix * TransformMatrix * vec4(aPos, 0.0, 1.0);\n"
2045 "}\n";
2046
2047static const GLchar *odc_circle_filled_fragment_shader_source =
2048 "precision highp float;\n"
2049 "uniform float border_width;\n"
2050 "uniform float circle_radius;\n"
2051 "uniform vec4 circle_color;\n"
2052 "uniform vec4 border_color;\n"
2053 "uniform vec2 circle_center;\n"
2054 "void main(){\n"
2055 "float d = distance(gl_FragCoord.xy, circle_center);\n"
2056 "if (d < (circle_radius - border_width)) { gl_FragColor = circle_color; }\n"
2057 "else if (d < circle_radius) { gl_FragColor = border_color; }\n"
2058 "else { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); }\n"
2059 "}\n";
2060
2061// Simple 2D texture shader
2062static const GLchar *odc_texture_2D_vertex_shader_source =
2063 "attribute vec2 aPos;\n"
2064 "attribute vec2 aUV;\n"
2065 "uniform mat4 MVMatrix;\n"
2066 "uniform mat4 TransformMatrix;\n"
2067 "varying vec2 varCoord;\n"
2068 "void main() {\n"
2069 " gl_Position = MVMatrix * TransformMatrix * vec4(aPos, 0.0, 1.0);\n"
2070 " varCoord = aUV;\n"
2071 "}\n";
2072
2073static const GLchar *odc_texture_2D_fragment_shader_source =
2074 "precision lowp float;\n"
2075 "uniform sampler2D uTex;\n"
2076 "varying vec2 varCoord;\n"
2077 "void main() {\n"
2078 " gl_FragColor = texture2D(uTex, varCoord);\n"
2079 "}\n";
2080
2081#ifdef ocpnUSE_GL
2082void ocpnDC::BuildShaders() {
2083 // Simple colored triangle shader
2084 if (!m_pcolor_tri_shader_program) {
2085 GLShaderProgram *shaderProgram = new GLShaderProgram;
2086 shaderProgram->addShaderFromSource(odc_color_tri_vertex_shader_source,
2087 GL_VERTEX_SHADER);
2088 shaderProgram->addShaderFromSource(odc_color_tri_fragment_shader_source,
2089 GL_FRAGMENT_SHADER);
2090 shaderProgram->linkProgram();
2091
2092 if (shaderProgram->isOK()) m_pcolor_tri_shader_program = shaderProgram;
2093 }
2094
2095 if (!m_pAALine_shader_program) {
2096 GLShaderProgram *shaderProgram = new GLShaderProgram;
2097 shaderProgram->addShaderFromSource(odc_AALine_fragment_shader_source,
2098 GL_FRAGMENT_SHADER);
2099 shaderProgram->addShaderFromSource(odc_AALine_vertex_shader_source,
2100 GL_VERTEX_SHADER);
2101 shaderProgram->linkProgram();
2102
2103 if (shaderProgram->isOK()) m_pAALine_shader_program = shaderProgram;
2104 }
2105
2106 if (!m_pcircle_filled_shader_program) {
2107 GLShaderProgram *shaderProgram = new GLShaderProgram;
2108 shaderProgram->addShaderFromSource(odc_circle_filled_vertex_shader_source,
2109 GL_VERTEX_SHADER);
2110 shaderProgram->addShaderFromSource(odc_circle_filled_fragment_shader_source,
2111 GL_FRAGMENT_SHADER);
2112 shaderProgram->linkProgram();
2113
2114 if (shaderProgram->isOK()) m_pcircle_filled_shader_program = shaderProgram;
2115 }
2116
2117 if (!m_ptexture_2D_shader_program) {
2118 GLShaderProgram *shaderProgram = new GLShaderProgram;
2119 shaderProgram->addShaderFromSource(odc_texture_2D_vertex_shader_source,
2120 GL_VERTEX_SHADER);
2121 shaderProgram->addShaderFromSource(odc_texture_2D_fragment_shader_source,
2122 GL_FRAGMENT_SHADER);
2123 shaderProgram->linkProgram();
2124
2125 if (shaderProgram->isOK()) m_ptexture_2D_shader_program = shaderProgram;
2126 }
2127}
2128#endif
2129#endif
Generic Chart canvas base.
Wrapper class for OpenGL shader programs.
Definition shaders.h:57
ViewPort - Core geographic projection and coordinate transformation engine.
Definition viewport.h:56
int pix_height
Height of the viewport in physical pixels.
Definition viewport.h:233
double rotation
Rotation angle of the viewport in radians.
Definition viewport.h:214
int pix_width
Width of the viewport in physical pixels.
Definition viewport.h:231
OpenGL chart rendering canvas.
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:60
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.
Definition ocpndc.cpp:474
Global variables stored in configuration file.
Extern C linked utilities.
OpenGL chart rendering canvas.
OpenCPN top window.
PlugIn Object Definition/API.
wxString GetLocaleCanonicalName()
Gets system locale canonical name.
Layer to use wxDC or opengl.
OpenGL shader interface.