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