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