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