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