42#include <wx/glcanvas.h>
45#include <wx/graphics.h>
46#include <wx/dcclient.h>
52#ifdef __OCPN__ANDROID__
54#include "GL/gl_private.h"
60#ifdef USE_ANDROID_GLES2
61#include "pi_shaders.h"
65#ifdef __OCPN__ANDROID__
69extern float g_piGLMinSymbolLineWidth;
70wxArrayPtrVoid pi_gTesselatorVertices;
72#ifdef USE_ANDROID_GLES2
73extern GLint pi_color_tri_shader_program;
74extern GLint pi_circle_filled_shader_program;
77int NextPow2(
int size) {
90pi_ocpnDC::pi_ocpnDC(wxGLCanvas &canvas)
91 : glcanvas(&canvas), dc(NULL), m_pen(wxNullPen), m_brush(wxNullBrush) {
92#if wxUSE_GRAPHICS_CONTEXT
96 m_textforegroundcolour = wxColour(0, 0, 0);
98 m_buseTex = GetLocaleCanonicalName().IsSameAs(_T(
"en_US"));
101 s_odc_tess_work_buf = NULL;
103#ifdef USE_ANDROID_GLES2
104 s_odc_tess_vertex_idx = 0;
105 s_odc_tess_vertex_idx_this = 0;
106 s_odc_tess_buf_len = 0;
108 s_odc_tess_work_buf = (GLfloat *)malloc(100 *
sizeof(GLfloat));
109 s_odc_tess_buf_len = 100;
116pi_ocpnDC::pi_ocpnDC(wxDC &pdc)
117 : glcanvas(NULL), dc(&pdc), m_pen(wxNullPen), m_brush(wxNullBrush) {
118#if wxUSE_GRAPHICS_CONTEXT
120 auto pmdc =
dynamic_cast<wxMemoryDC *
>(dc);
122 pgc = wxGraphicsContext::Create(*pmdc);
124 auto pcdc =
dynamic_cast<wxClientDC *
>(dc);
125 if (pcdc) pgc = wxGraphicsContext::Create(*pcdc);
128 m_textforegroundcolour = wxColour(0, 0, 0);
129 m_buseTex = GetLocaleCanonicalName().IsSameAs(_T(
"en_US"));
132 s_odc_tess_work_buf = NULL;
135pi_ocpnDC::pi_ocpnDC()
136 : glcanvas(NULL), dc(NULL), m_pen(wxNullPen), m_brush(wxNullBrush) {
137#if wxUSE_GRAPHICS_CONTEXT
140 m_buseTex = GetLocaleCanonicalName().IsSameAs(_T(
"en_US"));
143 s_odc_tess_work_buf = NULL;
145#ifdef USE_ANDROID_GLES2
150pi_ocpnDC::~pi_ocpnDC() {
151#if wxUSE_GRAPHICS_CONTEXT
156 free(s_odc_tess_work_buf);
160#ifdef USE_ANDROID_GLES2
161 configureShaders(vp->pix_width, vp->pix_height);
163 m_vpSize = wxSize(vp->pix_width, vp->pix_height);
166void pi_ocpnDC::Clear() {
171 wxBrush tmpBrush = m_brush;
173 SetBrush(wxBrush(glcanvas->GetBackgroundColour()));
174 glcanvas->GetSize(&w, &h);
175 DrawRectangle(0, 0, w, h);
181void pi_ocpnDC::SetBackground(
const wxBrush &brush) {
183 dc->SetBackground(brush);
186 glcanvas->SetBackgroundColour(brush.GetColour());
191void pi_ocpnDC::SetPen(
const wxPen &pen) {
193 if (pen == wxNullPen)
194 dc->SetPen(*wxTRANSPARENT_PEN);
201void pi_ocpnDC::SetBrush(
const wxBrush &brush) {
208void pi_ocpnDC::SetTextForeground(
const wxColour &colour) {
210 dc->SetTextForeground(colour);
212 m_textforegroundcolour = colour;
215void pi_ocpnDC::SetFont(
const wxFont &font) {
222const wxPen &pi_ocpnDC::GetPen()
const {
223 if (dc)
return dc->GetPen();
227const wxBrush &pi_ocpnDC::GetBrush()
const {
228 if (dc)
return dc->GetBrush();
232const wxFont &pi_ocpnDC::GetFont()
const {
233 if (dc)
return dc->GetFont();
237void pi_ocpnDC::GetSize(wxCoord *width, wxCoord *height)
const {
239 dc->GetSize(width, height);
242 glcanvas->GetSize(width, height);
247void pi_ocpnDC::SetGLAttrs(
bool highQuality) {
252 glEnable(GL_LINE_SMOOTH);
253 glEnable(GL_POLYGON_SMOOTH);
256 glDisable(GL_LINE_SMOOTH);
257 glDisable(GL_POLYGON_SMOOTH);
263void pi_ocpnDC::SetGLStipple()
const {
266#ifndef USE_ANDROID_GLES2
267 switch (m_pen.GetStyle()) {
268 case wxPENSTYLE_DOT: {
269 glLineStipple(1, 0x3333);
270 glEnable(GL_LINE_STIPPLE);
273 case wxPENSTYLE_LONG_DASH: {
274 glLineStipple(1, 0xFFF8);
275 glEnable(GL_LINE_STIPPLE);
278 case wxPENSTYLE_SHORT_DASH: {
279 glLineStipple(1, 0x3F3F);
280 glEnable(GL_LINE_STIPPLE);
283 case wxPENSTYLE_DOT_DASH: {
284 glLineStipple(1, 0x8FF1);
285 glEnable(GL_LINE_STIPPLE);
297void piDrawEndCap(
float x1,
float y1,
float t1,
float angle) {
298#ifndef USE_ANDROID_GLES2
299 const int steps = 16;
302 for (
int i = 0; i <= steps; i++) {
303 float a = angle + M_PI / 2 + M_PI / steps * i;
305 float xb = x1 + t1 / 2 * cos(a);
306 float yb = y1 + t1 / 2 * sin(a);
321void piDrawGLThickLine(
float x1,
float y1,
float x2,
float y2, wxPen pen,
325 float angle = atan2f(y2 - y1, x2 - x1);
326 float t1 = pen.GetWidth();
327 float t2sina1 = t1 / 2 * sinf(angle);
328 float t2cosa1 = t1 / 2 * cosf(angle);
330#ifndef USE_ANDROID_GLES2
331 glBegin(GL_TRIANGLES);
336 int n_dashes = pen.GetDashes(&dashes);
338 float lpix = sqrtf(powf((
float)(x1 - x2), 2) + powf((
float)(y1 - y2), 2));
342 float ldraw = t1 * dashes[0];
343 float lspace = t1 * dashes[1];
345 while (lrun < lpix) {
347 float xb = xa + ldraw * cosf(angle);
348 float yb = ya + ldraw * sinf(angle);
350 if ((lrun + ldraw) >= lpix)
356 glVertex2f(xa + t2sina1, ya - t2cosa1);
357 glVertex2f(xb + t2sina1, yb - t2cosa1);
358 glVertex2f(xb - t2sina1, yb + t2cosa1);
360 glVertex2f(xb - t2sina1, yb + t2cosa1);
361 glVertex2f(xa - t2sina1, ya + t2cosa1);
362 glVertex2f(xa + t2sina1, ya - t2cosa1);
369 xb = xa + lspace * cos(angle);
370 yb = ya + lspace * sin(angle);
377 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
378 glVertex2f(x2 + t2sina1, y2 - t2cosa1);
379 glVertex2f(x2 - t2sina1, y2 + t2cosa1);
381 glVertex2f(x2 - t2sina1, y2 + t2cosa1);
382 glVertex2f(x1 - t2sina1, y1 + t2cosa1);
383 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
387 if (pen.GetCap() == wxCAP_ROUND) {
388 piDrawEndCap(x1, y1, t1, angle);
389 piDrawEndCap(x2, y2, t1, angle + M_PI);
399 int n_dashes = pen.GetDashes(&dashes);
401 float lpix = sqrtf(powf((
float)(x1 - x2), 2) + powf((
float)(y1 - y2), 2));
405 float ldraw = t1 * dashes[0];
406 float lspace = t1 * dashes[1];
408 glUseProgram(pi_color_tri_shader_program);
413 glBindBuffer(GL_ARRAY_BUFFER, 0);
414 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
416 GLint pos = glGetAttribLocation(pi_color_tri_shader_program,
"position");
417 glEnableVertexAttribArray(pos);
418 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), vert);
425 glGetUniformLocation(pi_color_tri_shader_program,
"TransformMatrix");
426 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
428 wxColor c = pen.GetColour();
430 colorv[0] = c.Red() / float(256);
431 colorv[1] = c.Green() / float(256);
432 colorv[2] = c.Blue() / float(256);
433 colorv[3] = c.Alpha() / float(256);
435 GLint colloc = glGetUniformLocation(pi_color_tri_shader_program,
"color");
436 glUniform4fv(colloc, 1, colorv);
438 while (lrun < lpix) {
440 float xb = xa + ldraw * cosf(angle);
441 float yb = ya + ldraw * sinf(angle);
443 if ((lrun + ldraw) >= lpix)
449 vert[0] = xa + t2sina1;
450 vert[1] = ya - t2cosa1;
451 vert[2] = xb + t2sina1;
452 vert[3] = yb - t2cosa1;
453 vert[4] = xb - t2sina1;
454 vert[5] = yb + t2cosa1;
455 vert[6] = xb - t2sina1;
456 vert[7] = yb + t2cosa1;
457 vert[8] = xa - t2sina1;
458 vert[9] = ya + t2cosa1;
459 vert[10] = xa + t2sina1;
460 vert[11] = ya - t2cosa1;
462 glDrawArrays(GL_TRIANGLES, 0, 6);
469 xb = xa + lspace * cos(angle);
470 yb = ya + lspace * sin(angle);
478 vert[0] = x1 + t2sina1;
479 vert[1] = y1 - t2cosa1;
480 vert[2] = x2 + t2sina1;
481 vert[3] = y2 - t2cosa1;
482 vert[4] = x2 - t2sina1;
483 vert[5] = y2 + t2cosa1;
484 vert[6] = x2 - t2sina1;
485 vert[7] = y2 + t2cosa1;
486 vert[8] = x1 - t2sina1;
487 vert[9] = y1 + t2cosa1;
488 vert[10] = x1 + t2sina1;
489 vert[11] = y1 - t2cosa1;
491 glUseProgram(pi_color_tri_shader_program);
494 glBindBuffer(GL_ARRAY_BUFFER, 0);
495 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
497 GLint pos = glGetAttribLocation(pi_color_tri_shader_program,
"position");
498 glEnableVertexAttribArray(pos);
499 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), vert);
506 glGetUniformLocation(pi_color_tri_shader_program,
"TransformMatrix");
507 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
509 wxColor c = pen.GetColour();
511 colorv[0] = c.Red() / float(256);
512 colorv[1] = c.Green() / float(256);
513 colorv[2] = c.Blue() / float(256);
514 colorv[3] = c.Alpha() / float(256);
516 GLint colloc = glGetUniformLocation(pi_color_tri_shader_program,
"color");
517 glUniform4fv(colloc, 1, colorv);
519 glDrawArrays(GL_TRIANGLES, 0, 6);
536void pi_ocpnDC::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
538 if (dc) dc->DrawLine(x1, y1, x2, y2);
540 else if (ConfigurePen()) {
541 bool b_draw_thick =
false;
543 float pen_width = wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth());
551 glEnable(GL_LINE_SMOOTH);
554 if (pen_width > 1.0) {
556 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
557 if (glGetError()) glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
558 if (pen_width > parms[1])
561 glLineWidth(pen_width);
563 glLineWidth(pen_width);
567 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
568 if (pen_width > parms[1])
571 glLineWidth(pen_width);
573 glLineWidth(pen_width);
576#ifdef USE_ANDROID_GLES2
578 piDrawGLThickLine(x1, y1, x2, y2, m_pen, b_hiqual);
580 glUseProgram(pi_color_tri_shader_program);
583 GLint pos = glGetAttribLocation(pi_color_tri_shader_program,
"position");
584 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float),
586 glEnableVertexAttribArray(pos);
594 colorv[0] = m_pen.GetColour().Red() / float(256);
595 colorv[1] = m_pen.GetColour().Green() / float(256);
596 colorv[2] = m_pen.GetColour().Blue() / float(256);
599 GLint colloc = glGetUniformLocation(pi_color_tri_shader_program,
"color");
600 glUniform4fv(colloc, 1, colorv);
603 int n_dashes = m_pen.GetDashes(&dashes);
605 float angle = atan2f((
float)(y2 - y1), (
float)(x2 - x1));
606 float cosa = cosf(angle);
607 float sina = sinf(angle);
608 float t1 = m_pen.GetWidth();
610 float lpix = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
614 float ldraw = t1 * dashes[0];
615 float lspace = t1 * dashes[1];
617 ldraw = wxMax(ldraw, 4.0);
618 lspace = wxMax(lspace, 4.0);
619 lpix = wxMin(lpix, 2000.0);
621 while (lrun < lpix) {
623 float xb = xa + ldraw * cosa;
624 float yb = ya + ldraw * sina;
626 if ((lrun + ldraw) >= lpix)
637 glDrawArrays(GL_LINES, 0, 2);
639 xa = xa + (lspace + ldraw) * cosa;
640 ya = ya + (lspace + ldraw) * sina;
641 lrun += lspace + ldraw;
650 glDrawArrays(GL_LINES, 0, 2);
656 piDrawGLThickLine(x1, y1, x2, y2, m_pen, b_hiqual);
659 int n_dashes = m_pen.GetDashes(&dashes);
661 float angle = atan2f((
float)(y2 - y1), (
float)(x2 - x1));
662 float cosa = cosf(angle);
663 float sina = sinf(angle);
664 float t1 = m_pen.GetWidth();
666 float lpix = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
670 float ldraw = t1 * dashes[0];
671 float lspace = t1 * dashes[1];
673 ldraw = wxMax(ldraw, 4.0);
674 lspace = wxMax(lspace, 4.0);
675 lpix = wxMin(lpix, 2000.0);
678 while (lrun < lpix) {
680 float xb = xa + ldraw * cosa;
681 float yb = ya + ldraw * sina;
683 if ((lrun + ldraw) >= lpix)
692 xa = xa + (lspace + ldraw) * cosa;
693 ya = ya + (lspace + ldraw) * sina;
694 lrun += lspace + ldraw;
706 glDisable(GL_LINE_STIPPLE);
709 glDisable(GL_LINE_SMOOTH);
717void piDrawGLThickLines(
int n, wxPoint points[], wxCoord xoffset,
718 wxCoord yoffset, wxPen pen,
bool b_hiqual) {
722#ifdef USE_ANDROID_GLES2
723 wxPoint p0 = points[0];
724 for (
int i = 1; i < n; i++) {
725 piDrawGLThickLine(p0.x + xoffset, p0.y + yoffset, points[i].x + xoffset,
726 points[i].y + yoffset, pen, b_hiqual);
734 if (pen.GetDashes(&dashes)) {
735 wxPoint p0 = points[0];
736 for (
int i = 1; i < n; i++) {
737 piDrawGLThickLine(p0.x + xoffset, p0.y + yoffset, points[i].x + xoffset,
738 points[i].y + yoffset, pen, b_hiqual);
745 wxPoint *cpoints =
new wxPoint[n];
746 cpoints[0] = points[0];
748 for (
int i = 1; i < n; i++) {
749 if (points[i].x != points[i - 1].x || points[i].y != points[i - 1].y)
750 cpoints[c++] = points[i];
757 float t1 = pen.GetWidth();
759 float x0 = cpoints[0].x, y0 = cpoints[0].y, x1 = cpoints[1].x,
761 float a0 = atan2f(y1 - y0, x1 - x0);
765 glBegin(GL_TRIANGLES);
767 float t2sina0 = t1 / 2 * sinf(a0);
768 float t2cosa0 = t1 / 2 * cosf(a0);
770 for (
int i = 1; i < c; i++) {
775 x2 = cpoints[i + 1].x, y2 = cpoints[i + 1].y;
776 a1 = atan2f(y2 - y1, x2 - x1);
782 float aa = (a0 + a1) / 2;
783 float diff = fabsf(a0 - a1);
784 if (diff > M_PI) diff -= 2 * (float)M_PI;
785 float rad = t1 / 2 / wxMax(cosf(diff / 2), .4);
787 float t2sina1 = rad * sinf(aa);
788 float t2cosa1 = rad * cosf(aa);
790 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
791 glVertex2f(x1 - t2sina1, y1 + t2cosa1);
792 glVertex2f(x0 + t2sina0, y0 - t2cosa0);
794 glVertex2f(x0 - t2sina0, y0 + t2cosa0);
795 glVertex2f(x0 + t2sina0, y0 - t2cosa0);
797 float dot = t2sina0 * t2sina1 + t2cosa0 * t2cosa1;
799 glVertex2f(x1 - t2sina1, y1 + t2cosa1);
801 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
806 t2sina0 = t2sina1, t2cosa0 = t2cosa1;
809 if (pen.GetCap() == wxCAP_ROUND) {
810 piDrawEndCap(x0, y0, t1, a0);
811 piDrawEndCap(x0, y0, t1, a0 + M_PI);
823void pi_ocpnDC::DrawLines(
int n, wxPoint points[], wxCoord xoffset,
824 wxCoord yoffset,
bool b_hiqual) {
825 if (dc) dc->DrawLines(n, points, xoffset, yoffset);
827 else if (ConfigurePen()) {
832 SetGLAttrs(b_hiqual);
834 bool b_draw_thick =
false;
836 glDisable(GL_LINE_STIPPLE);
842 if (m_pen.GetWidth() > 1) {
844 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
845 if (glGetError()) glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
847 if (m_pen.GetWidth() > parms[1])
850 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
852 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
854 if (m_pen.GetWidth() > 1) {
856 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
857 if (m_pen.GetWidth() > parms[1])
860 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
862 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
866 piDrawGLThickLines(n, points, xoffset, yoffset, m_pen, b_hiqual);
869 glDisable(GL_LINE_STIPPLE);
870 glDisable(GL_POLYGON_SMOOTH);
877#ifndef USE_ANDROID_GLES2
879 glBegin(GL_LINE_STRIP);
880 for (
int i = 0; i < n; i++)
881 glVertex2i(points[i].x + xoffset, points[i].y + yoffset);
887 if (workBufSize < (
size_t)n * 2) {
888 workBuf = (
float *)realloc(workBuf, (n * 4) *
sizeof(float));
892 for (
int i = 0; i < n; i++) {
893 workBuf[i * 2] = points[i].x + xoffset;
894 workBuf[(i * 2) + 1] = points[i].y + yoffset;
897 glUseProgram(pi_color_tri_shader_program);
899 GLint pos = glGetAttribLocation(pi_color_tri_shader_program,
"position");
900 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float),
902 glEnableVertexAttribArray(pos);
909 colorv[0] = m_pen.GetColour().Red() / float(256);
910 colorv[1] = m_pen.GetColour().Green() / float(256);
911 colorv[2] = m_pen.GetColour().Blue() / float(256);
912 colorv[3] = m_pen.GetColour().Alpha() / float(256);
915 GLint colloc = glGetUniformLocation(pi_color_tri_shader_program,
"color");
916 glUniform4fv(colloc, 1, colorv);
918 glDrawArrays(GL_LINE_STRIP, 0, n);
923 glDisable(GL_LINE_STIPPLE);
924 glDisable(GL_POLYGON_SMOOTH);
931void pi_ocpnDC::StrokeLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) {
932#if wxUSE_GRAPHICS_CONTEXT
934 pgc->SetPen(dc->GetPen());
935 pgc->StrokeLine(x1, y1, x2, y2);
937 dc->CalcBoundingBox(x1, y1);
938 dc->CalcBoundingBox(x2, y2);
941 DrawLine(x1, y1, x2, y2,
true);
944void pi_ocpnDC::StrokeLines(
int n, wxPoint *points) {
948#if wxUSE_GRAPHICS_CONTEXT
950 wxPoint2DDouble *dPoints =
951 (wxPoint2DDouble *)malloc(n *
sizeof(wxPoint2DDouble));
952 for (
int i = 0; i < n; i++) {
953 dPoints[i].m_x = points[i].x;
954 dPoints[i].m_y = points[i].y;
956 pgc->SetPen(dc->GetPen());
957 pgc->StrokeLines(n, dPoints);
961 DrawLines(n, points, 0, 0,
true);
964void pi_ocpnDC::DrawGLLineArray(
int n,
float *vertex_array,
float *color_array,
967 if (ConfigurePen()) {
972 SetGLAttrs(b_hiqual);
974 bool b_draw_thick =
false;
976 glDisable(GL_LINE_STIPPLE);
982 if (m_pen.GetWidth() > 1) {
988 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
990 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
992 if (m_pen.GetWidth() > 1) {
995 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
997 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
1000#ifndef USE_ANDROID_GLES2
1010 glUseProgram(pi_colorv_tri_shader_program);
1012 GLint pos = glGetAttribLocation(pi_colorv_tri_shader_program,
"position");
1013 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float),
1015 glEnableVertexAttribArray(pos);
1017 GLint colloc = glGetAttribLocation(pi_colorv_tri_shader_program,
"colorv");
1018 glVertexAttribPointer(colloc, 4, GL_FLOAT, GL_FALSE, 4 *
sizeof(
float),
1020 glEnableVertexAttribArray(colloc);
1022 glDrawArrays(GL_LINES, 0, n);
1027 glDisable(GL_LINE_STIPPLE);
1028 glDisable(GL_POLYGON_SMOOTH);
1029 glDisable(GL_BLEND);
1035void pi_ocpnDC::DrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
1036 if (dc) dc->DrawRectangle(x, y, w, h);
1039#ifndef USE_ANDROID_GLES2
1040 if (ConfigureBrush()) {
1043 glVertex2i(x + w, y);
1044 glVertex2i(x + w, y + h);
1045 glVertex2i(x, y + h);
1049 if (ConfigurePen()) {
1050 glBegin(GL_LINE_LOOP);
1052 glVertex2i(x + w, y);
1053 glVertex2i(x + w, y + h);
1054 glVertex2i(x, y + h);
1063static void drawrrhelper(wxCoord x0, wxCoord y0, wxCoord r,
int quadrant,
1066#ifndef USE_ANDROID_GLES2
1067 float step = 1.0 / steps, rs = 2.0 * r * step, rss = rs * step, x, y, dx, dy,
1071 x = r, y = 0, dx = 0, dy = -rs, ddx = -rss, ddy = rss;
1074 x = 0, y = -r, dx = -rs, dy = 0, ddx = rss, ddy = rss;
1077 x = -r, y = 0, dx = 0, dy = rs, ddx = rss, ddy = -rss;
1080 x = 0, y = r, dx = rs, dy = 0, ddx = -rss, ddy = -rss;
1086 for (
int i = 0; i < steps; i++) {
1087 glVertex2i(x0 + floor(x), y0 + floor(y));
1088 x += dx + ddx / 2, y += dy + ddy / 2;
1089 dx += ddx, dy += ddy;
1091 glVertex2i(x0 + floor(x), y0 + floor(y));
1096void pi_ocpnDC::drawrrhelperGLES2(wxCoord x0, wxCoord y0, wxCoord r,
1097 int quadrant,
int steps) {
1099 float step = 1.0 / steps, rs = 2.0 * r * step, rss = rs * step, x, y, dx, dy,
1103 x = r, y = 0, dx = 0, dy = -rs, ddx = -rss, ddy = rss;
1106 x = 0, y = -r, dx = -rs, dy = 0, ddx = rss, ddy = rss;
1109 x = -r, y = 0, dx = 0, dy = rs, ddx = rss, ddy = -rss;
1112 x = 0, y = r, dx = rs, dy = 0, ddx = -rss, ddy = -rss;
1118 for (
int i = 0; i < steps; i++) {
1119 workBuf[workBufIndex++] = x0 + floor(x);
1120 workBuf[workBufIndex++] = y0 + floor(y);
1122 x += dx + ddx / 2, y += dy + ddy / 2;
1123 dx += ddx, dy += ddy;
1126 workBuf[workBufIndex++] = x0 + floor(x);
1127 workBuf[workBufIndex++] = y0 + floor(y);
1131void pi_ocpnDC::DrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1133 if (dc) dc->DrawRoundedRectangle(x, y, w, h, r);
1137 int steps = ceil(sqrt((
float)r));
1139 wxCoord x1 = x + r, x2 = x + w - r;
1140 wxCoord y1 = y + r, y2 = y + h - r;
1142#ifdef USE_ANDROID_GLES2
1145 size_t bufReq = steps * 8 * 2 *
sizeof(float);
1147 if (workBufSize < bufReq) {
1148 workBuf = (
float *)realloc(workBuf, bufReq);
1149 workBufSize = bufReq;
1153 drawrrhelperGLES2(x2, y1, r, 0, steps);
1154 drawrrhelperGLES2(x1, y1, r, 1, steps);
1155 drawrrhelperGLES2(x1, y2, r, 2, steps);
1156 drawrrhelperGLES2(x2, y2, r, 3, steps);
1158 glUseProgram(pi_color_tri_shader_program);
1162 glGetAttribLocation(pi_color_tri_shader_program,
"position");
1165 glBindBuffer(GL_ARRAY_BUFFER, 0);
1166 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1168 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, workBuf);
1169 glEnableVertexAttribArray(mPosAttrib);
1173 bcolorv[0] = m_brush.GetColour().Red() / float(256);
1174 bcolorv[1] = m_brush.GetColour().Green() / float(256);
1175 bcolorv[2] = m_brush.GetColour().Blue() / float(256);
1176 bcolorv[3] = m_brush.GetColour().Alpha() / float(256);
1178 GLint bcolloc = glGetUniformLocation(pi_color_tri_shader_program,
"color");
1179 glUniform4fv(bcolloc, 1, bcolorv);
1188 mat4x4_rotate_Z(Q, I, angle);
1195 glGetUniformLocation(pi_color_tri_shader_program,
"TransformMatrix");
1196 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)Q);
1199 glDrawArrays(GL_TRIANGLE_FAN, 0, workBufIndex / 2);
1203 mat4x4_identity(IM);
1205 glGetUniformLocation(pi_color_tri_shader_program,
"TransformMatrix");
1206 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
1209 if (ConfigureBrush()) {
1210 glBegin(GL_TRIANGLE_FAN);
1211 drawrrhelper(x2, y1, r, 0, steps);
1212 drawrrhelper(x1, y1, r, 1, steps);
1213 drawrrhelper(x1, y2, r, 2, steps);
1214 drawrrhelper(x2, y2, r, 3, steps);
1218 if (ConfigurePen()) {
1219 glBegin(GL_LINE_LOOP);
1220 drawrrhelper(x2, y1, r, 0, steps);
1221 drawrrhelper(x1, y1, r, 1, steps);
1222 drawrrhelper(x1, y2, r, 2, steps);
1223 drawrrhelper(x2, y2, r, 3, steps);
1231void pi_ocpnDC::DrawCircle(wxCoord x, wxCoord y, wxCoord radius) {
1232#ifdef USE_ANDROID_GLES2
1238 coords[0] = x - radius;
1239 coords[1] = y + radius;
1240 coords[2] = x + radius;
1241 coords[3] = y + radius;
1242 coords[4] = x - radius;
1243 coords[5] = y - radius;
1244 coords[6] = x + radius;
1245 coords[7] = y - radius;
1247 glUseProgram(pi_circle_filled_shader_program);
1251 glGetAttribLocation(pi_circle_filled_shader_program,
"aPos");
1254 glBindBuffer(GL_ARRAY_BUFFER, 0);
1255 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1257 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
1258 glEnableVertexAttribArray(mPosAttrib);
1262 glGetUniformLocation(pi_circle_filled_shader_program,
"circle_radius");
1263 glUniform1f(radiusloc, radius);
1267 glGetUniformLocation(pi_circle_filled_shader_program,
"circle_center");
1270 ctrv[1] = m_vpSize.y - y;
1271 glUniform2fv(centerloc, 1, ctrv);
1275 colorv[0] = m_brush.GetColour().Red() / float(256);
1276 colorv[1] = m_brush.GetColour().Green() / float(256);
1277 colorv[2] = m_brush.GetColour().Blue() / float(256);
1278 colorv[3] = (m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT) ? 0.0 : 1.0;
1281 glGetUniformLocation(pi_circle_filled_shader_program,
"circle_color");
1282 glUniform4fv(colloc, 1, colorv);
1286 bcolorv[0] = m_pen.GetColour().Red() / float(256);
1287 bcolorv[1] = m_pen.GetColour().Green() / float(256);
1288 bcolorv[2] = m_pen.GetColour().Blue() / float(256);
1289 bcolorv[3] = m_pen.GetColour().Alpha() / float(256);
1292 glGetUniformLocation(pi_circle_filled_shader_program,
"border_color");
1293 glUniform4fv(bcolloc, 1, bcolorv);
1296 GLint borderWidthloc =
1297 glGetUniformLocation(pi_circle_filled_shader_program,
"border_width");
1298 glUniform1f(borderWidthloc, m_pen.GetWidth());
1306 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1309 glDisable(GL_BLEND);
1312 DrawEllipse(x - radius, y - radius, 2 * radius, 2 * radius);
1316void pi_ocpnDC::StrokeCircle(wxCoord x, wxCoord y, wxCoord radius) {
1317#if wxUSE_GRAPHICS_CONTEXT
1319 wxGraphicsPath gpath = pgc->CreatePath();
1320 gpath.AddCircle(x, y, radius);
1322 pgc->SetPen(GetPen());
1323 pgc->SetBrush(GetBrush());
1324 pgc->DrawPath(gpath);
1327 dc->CalcBoundingBox(x + radius + 2, y + radius + 2);
1328 dc->CalcBoundingBox(x - radius - 2, y - radius - 2);
1331 DrawCircle(x, y, radius);
1334void pi_ocpnDC::DrawEllipse(wxCoord x, wxCoord y, wxCoord width,
1336 if (dc) dc->DrawEllipse(x, y, width, height);
1339 float r1 = width / 2, r2 = height / 2;
1340 float cx = x + r1, cy = y + r2;
1346 float steps = floorf(
1347 wxMax(sqrtf(sqrtf((
float)(width * width + height * height))), 1) *
1350#ifndef USE_ANDROID_GLES2
1351 if (ConfigureBrush()) {
1352 glBegin(GL_TRIANGLE_FAN);
1354 for (
float a = 0; a <= 2 * M_PI + M_PI / steps; a += 2 * M_PI / steps)
1355 glVertex2f(cx + r1 * sinf(a), cy + r2 * cosf(a));
1359 if (ConfigurePen()) {
1360 glBegin(GL_LINE_LOOP);
1361 for (
float a = 0; a < 2 * M_PI - M_PI / steps; a += 2 * M_PI / steps)
1362 glVertex2f(cx + r1 * sinf(a), cy + r2 * cosf(a));
1367 glDisable(GL_BLEND);
1372void pi_ocpnDC::DrawPolygon(
int n, wxPoint points[], wxCoord xoffset,
1373 wxCoord yoffset,
float scale,
float angle) {
1374 if (dc) dc->DrawPolygon(n, points, xoffset, yoffset);
1384#ifdef USE_ANDROID_GLES2
1389 DrawPolygonTessellated(n, points, xoffset, yoffset);
1393 if (workBufSize < (
size_t)n * 2) {
1394 workBuf = (
float *)realloc(workBuf, (n * 4) *
sizeof(float));
1395 workBufSize = n * 4;
1398 for (
int i = 0; i < n; i++) {
1399 workBuf[i * 2] = (points[i].x *
scale);
1400 workBuf[i * 2 + 1] = (points[i].y *
scale);
1403 glUseProgram(pi_color_tri_shader_program);
1407 glGetAttribLocation(pi_color_tri_shader_program,
"position");
1410 glBindBuffer(GL_ARRAY_BUFFER, 0);
1411 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1413 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, workBuf);
1414 glEnableVertexAttribArray(mPosAttrib);
1418 bcolorv[0] = m_pen.GetColour().Red() / float(256);
1419 bcolorv[1] = m_pen.GetColour().Green() / float(256);
1420 bcolorv[2] = m_pen.GetColour().Blue() / float(256);
1421 bcolorv[3] = m_pen.GetColour().Alpha() / float(256);
1424 glGetUniformLocation(pi_color_tri_shader_program,
"color");
1425 glUniform4fv(bcolloc, 1, bcolorv);
1430 mat4x4_rotate_Z(Q, I, angle);
1437 glGetUniformLocation(pi_color_tri_shader_program,
"TransformMatrix");
1438 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)Q);
1441 glDrawArrays(GL_LINE_LOOP, 0, n);
1444 bcolorv[0] = m_brush.GetColour().Red() / float(256);
1445 bcolorv[1] = m_brush.GetColour().Green() / float(256);
1446 bcolorv[2] = m_brush.GetColour().Blue() / float(256);
1447 bcolorv[3] = m_brush.GetColour().Alpha() / float(256);
1449 glUniform4fv(bcolloc, 1, bcolorv);
1454 float x1 = workBuf[4];
1455 float y1 = workBuf[5];
1456 workBuf[4] = workBuf[6];
1457 workBuf[5] = workBuf[7];
1461 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1462 }
else if (n == 3) {
1463 glDrawArrays(GL_TRIANGLES, 0, 3);
1468 mat4x4_identity(IM);
1470 glGetUniformLocation(pi_color_tri_shader_program,
"TransformMatrix");
1471 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
1476 if (ConfigureBrush()) {
1477 glEnable(GL_POLYGON_SMOOTH);
1478 glBegin(GL_POLYGON);
1479 for (
int i = 0; i < n; i++)
1480 glVertex2f((points[i].x *
scale) + xoffset,
1481 (points[i].y *
scale) + yoffset);
1483 glDisable(GL_POLYGON_SMOOTH);
1486 if (ConfigurePen()) {
1487 glEnable(GL_LINE_SMOOTH);
1488 glBegin(GL_LINE_LOOP);
1489 for (
int i = 0; i < n; i++)
1490 glVertex2f((points[i].x *
scale) + xoffset,
1491 (points[i].y *
scale) + yoffset);
1493 glDisable(GL_LINE_SMOOTH);
1518#ifndef USE_ANDROID_GLES2
1526void APIENTRY pi_ocpnDCcombineCallback(GLdouble coords[3],
1527 GLdouble *vertex_data[4],
1528 GLfloat weight[4], GLdouble **dataOut) {
1531 vertex =
new GLvertex();
1532 pi_gTesselatorVertices.Add(vertex);
1534 vertex->info.x = coords[0];
1535 vertex->info.y = coords[1];
1536 vertex->info.z = coords[2];
1538 for (
int i = 3; i < 6; i++) {
1540 weight[0] * vertex_data[0][i] + weight[1] * vertex_data[1][i];
1543 *dataOut = &(vertex->data[0]);
1546void APIENTRY ocpnDCvertexCallback(GLvoid *arg) {
1548 vertex = (GLvertex *)arg;
1549 glVertex2f((
float)vertex->info.x, (
float)vertex->info.y);
1552void APIENTRY ocpnDCerrorCallback(GLenum errorCode) {
1553 const GLubyte *estring;
1554 estring = gluErrorString(errorCode);
1558void APIENTRY ocpnDCbeginCallback(GLenum type) { glBegin(type); }
1560void APIENTRY ocpnDCendCallback() { glEnd(); }
1565#ifdef USE_ANDROID_GLES2
1567static std::list<double *> odc_combine_work_data;
1568static void pi_odc_combineCallbackD(GLdouble coords[3],
1569 GLdouble *vertex_data[4], GLfloat weight[4],
1570 GLdouble **dataOut,
void *data) {
1577void pi_odc_vertexCallbackD_GLSL(GLvoid *vertex,
void *data) {
1581 if (pDC->s_odc_tess_vertex_idx > pDC->s_odc_tess_buf_len - 8) {
1582 int new_buf_len = pDC->s_odc_tess_buf_len + 100;
1583 GLfloat *tmp = pDC->s_odc_tess_work_buf;
1585 pDC->s_odc_tess_work_buf = (GLfloat *)realloc(
1586 pDC->s_odc_tess_work_buf, new_buf_len *
sizeof(GLfloat));
1587 if (NULL == pDC->s_odc_tess_work_buf) {
1591 pDC->s_odc_tess_buf_len = new_buf_len;
1594 GLdouble *pointer = (GLdouble *)vertex;
1596 pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx++] = (float)pointer[0];
1597 pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx++] = (float)pointer[1];
1599 pDC->s_odc_nvertex++;
1602void pi_odc_beginCallbackD_GLSL(GLenum mode,
void *data) {
1604 pDC->s_odc_tess_vertex_idx_this = pDC->s_odc_tess_vertex_idx;
1605 pDC->s_odc_tess_mode = mode;
1606 pDC->s_odc_nvertex = 0;
1609void pi_odc_endCallbackD_GLSL(
void *data) {
1615 glUseProgram(pi_color_tri_shader_program);
1618 glBindBuffer(GL_ARRAY_BUFFER, 0);
1619 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1621 float *bufPt = &(pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx_this]);
1622 GLint pos = glGetAttribLocation(pi_color_tri_shader_program,
"position");
1623 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), bufPt);
1624 glEnableVertexAttribArray(pos);
1632 wxColour c = pDC->GetBrush().GetColour();
1634 colorv[0] = c.Red() / float(256);
1635 colorv[1] = c.Green() / float(256);
1636 colorv[2] = c.Blue() / float(256);
1637 colorv[3] = c.Alpha() / float(256);
1639 GLint colloc = glGetUniformLocation(pi_color_tri_shader_program,
"color");
1640 glUniform4fv(colloc, 1, colorv);
1642 glDrawArrays(pDC->s_odc_tess_mode, 0, pDC->s_odc_nvertex);
1649void pi_ocpnDC::DrawPolygonTessellated(
int n, wxPoint points[], wxCoord xoffset,
1651 if (dc) dc->DrawPolygon(n, points, xoffset, yoffset);
1654#if !defined(ocpnUSE_GLES) || \
1655 defined(USE_ANDROID_GLES2)
1659 DrawPolygon(n, points, xoffset, yoffset);
1663#ifdef USE_ANDROID_GLES2
1664 m_tobj = gluNewTess();
1665 s_odc_tess_vertex_idx = 0;
1667 gluTessCallback(m_tobj, GLU_TESS_VERTEX_DATA,
1668 (_GLUfuncptr)&pi_odc_vertexCallbackD_GLSL);
1669 gluTessCallback(m_tobj, GLU_TESS_BEGIN_DATA,
1670 (_GLUfuncptr)&pi_odc_beginCallbackD_GLSL);
1671 gluTessCallback(m_tobj, GLU_TESS_END_DATA,
1672 (_GLUfuncptr)&pi_odc_endCallbackD_GLSL);
1673 gluTessCallback(m_tobj, GLU_TESS_COMBINE_DATA,
1674 (_GLUfuncptr)&pi_odc_combineCallbackD);
1677 gluTessNormal(m_tobj, 0, 0, 1);
1678 gluTessProperty(m_tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
1680 if (ConfigureBrush()) {
1681 gluTessBeginPolygon(m_tobj,
this);
1682 gluTessBeginContour(m_tobj);
1684 for (
int i = 0; i < n; i++) {
1685 double *p =
new double[6];
1686 p[0] = points[i].x, p[1] = points[i].y, p[2] = 0;
1687 gluTessVertex(m_tobj, p, p);
1690 gluTessEndContour(m_tobj);
1691 gluTessEndPolygon(m_tobj);
1694 gluDeleteTess(m_tobj);
1703 static GLUtesselator *tobj = NULL;
1704 if (!tobj) tobj = gluNewTess();
1706 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&ocpnDCvertexCallback);
1707 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&ocpnDCbeginCallback);
1708 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&ocpnDCendCallback);
1709 gluTessCallback(tobj, GLU_TESS_COMBINE,
1710 (_GLUfuncptr)&pi_ocpnDCcombineCallback);
1711 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)&ocpnDCerrorCallback);
1713 gluTessNormal(tobj, 0, 0, 1);
1714 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
1716 if (ConfigureBrush()) {
1717 gluTessBeginPolygon(tobj, NULL);
1718 gluTessBeginContour(tobj);
1720 for (
int i = 0; i < n; i++) {
1721 GLvertex *vertex =
new GLvertex();
1722 pi_gTesselatorVertices.Add(vertex);
1723 vertex->info.x = (GLdouble)points[i].x;
1724 vertex->info.y = (GLdouble)points[i].y;
1725 vertex->info.z = (GLdouble)0.0;
1726 vertex->info.r = (GLdouble)0.0;
1727 vertex->info.g = (GLdouble)0.0;
1728 vertex->info.b = (GLdouble)0.0;
1729 gluTessVertex(tobj, (GLdouble *)vertex, (GLdouble *)vertex);
1731 gluTessEndContour(tobj);
1732 gluTessEndPolygon(tobj);
1735 for (
unsigned int i = 0; i < pi_gTesselatorVertices.Count(); i++)
1736 delete (GLvertex *)pi_gTesselatorVertices.Item(i);
1737 pi_gTesselatorVertices.Clear();
1739 gluDeleteTess(tobj);
1745void pi_ocpnDC::StrokePolygon(
int n, wxPoint points[], wxCoord xoffset,
1746 wxCoord yoffset,
float scale) {
1747#if wxUSE_GRAPHICS_CONTEXT
1749 wxGraphicsPath gpath = pgc->CreatePath();
1750 gpath.MoveToPoint(points[0].x + xoffset, points[0].y + yoffset);
1751 for (
int i = 1; i < n; i++)
1752 gpath.AddLineToPoint(points[i].x + xoffset, points[i].y + yoffset);
1753 gpath.AddLineToPoint(points[0].x + xoffset, points[0].y + yoffset);
1755 pgc->SetPen(GetPen());
1756 pgc->SetBrush(GetBrush());
1757 pgc->DrawPath(gpath);
1759 for (
int i = 0; i < n; i++)
1760 dc->CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
1763 DrawPolygon(n, points, xoffset, yoffset,
scale);
1766void pi_ocpnDC::DrawBitmap(
const wxBitmap &bitmap, wxCoord x, wxCoord y,
1769 if (x < 0 || y < 0) {
1770 int dx = (x < 0 ? -x : 0);
1771 int dy = (y < 0 ? -y : 0);
1772 int w = bitmap.GetWidth() - dx;
1773 int h = bitmap.GetHeight() - dy;
1775 if (w <= 0 || h <= 0)
return;
1776 wxBitmap newBitmap = bitmap.GetSubBitmap(wxRect(dx, dy, w, h));
1783 if (dc) dc->DrawBitmap(bmp, x, y, usemask);
1791#ifndef USE_ANDROID_GLES2
1792 wxImage image = bmp.ConvertToImage();
1793 int w = image.GetWidth(), h = image.GetHeight();
1796 unsigned char *d = image.GetData();
1797 unsigned char *a = image.GetAlpha();
1799 unsigned char mr, mg, mb;
1800 if (!image.GetOrFindMaskColour(&mr, &mg, &mb) && !a) {
1801 printf(
"trying to use mask to draw a bitmap without alpha or mask\n");
1805 if (image.HasMask()) a = 0;
1808 unsigned char *e =
new unsigned char[4 * w * h];
1810 for (
int y = 0; y < h; y++)
1811 for (
int x = 0; x < w; x++) {
1812 unsigned char r, g, b;
1813 int off = (y * image.GetWidth() + x);
1823 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
1829 glColor4f(1, 1, 1, 1);
1830 GLDrawBlendData(x, y, w, h, GL_RGBA, e);
1833 glRasterPos2i(x, y);
1835 if (image.GetData())
1836 glDrawPixels(w, h, GL_RGB, GL_UNSIGNED_BYTE, image.GetData());
1845void pi_ocpnDC::DrawText(
const wxString &text, wxCoord x, wxCoord y) {
1846 if (dc) dc->DrawText(text, x, y);
1853 m_texfont.Build(m_font);
1854 m_texfont.GetTextExtent(text, &w, &h);
1858 glEnable(GL_TEXTURE_2D);
1859 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1861#ifndef USE_ANDROID_GLES2
1862 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1864 glTranslatef(x, y, 0);
1866 glColor3ub(m_textforegroundcolour.Red(), m_textforegroundcolour.Green(),
1867 m_textforegroundcolour.Blue());
1869 m_texfont.RenderString(text);
1872 m_texfont.RenderString(text, x, y);
1874 glDisable(GL_TEXTURE_2D);
1875 glDisable(GL_BLEND);
1879 sdc.SetFont(m_font);
1880 sdc.GetTextExtent(text, &w, &h, NULL, NULL, &m_font);
1885 temp_dc.SelectObject(bmp);
1888 temp_dc.SetBackground(wxBrush(wxColour(0, 0, 0)));
1892 temp_dc.SetFont(m_font);
1893 temp_dc.SetTextForeground(wxColour(255, 255, 255));
1894 temp_dc.DrawText(text, 0, 0);
1895 temp_dc.SelectObject(wxNullBitmap);
1899 wxImage image = bmp.ConvertToImage();
1902 int dx = (x < 0 ? -x : 0);
1903 int dy = (y < 0 ? -y : 0);
1904 w = bmp.GetWidth() - dx;
1905 h = bmp.GetHeight() - dy;
1907 if (w <= 0 || h <= 0)
return;
1908 image = image.GetSubImage(wxRect(dx, dy, w, h));
1913 unsigned char *data =
new unsigned char[w * h * 4];
1914 unsigned char *im = image.GetData();
1917 unsigned int r = m_textforegroundcolour.Red();
1918 unsigned int g = m_textforegroundcolour.Green();
1919 unsigned int b = m_textforegroundcolour.Blue();
1920 for (
int i = 0; i < h; i++) {
1921 for (
int j = 0; j < w; j++) {
1922 unsigned int index = ((i * w) + j) * 4;
1924 data[index + 1] = g;
1925 data[index + 2] = b;
1926 data[index + 3] = im[((i * w) + j) * 3];
1931 glColor4ub( 255, 255, 255, 255 );
1932 glEnable( GL_BLEND );
1933 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1934 glRasterPos2i( x, y );
1935 glPixelZoom( 1, -1 );
1936 glDrawPixels( w, h, GL_RGBA, GL_UNSIGNED_BYTE, data );
1937 glPixelZoom( 1, 1 );
1938 glDisable( GL_BLEND );
1940 unsigned int texobj;
1942 glGenTextures(1, &texobj);
1943 glBindTexture(GL_TEXTURE_2D, texobj);
1945 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1946 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1948 int TextureWidth = NextPow2(w);
1949 int TextureHeight = NextPow2(h);
1950 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TextureWidth, TextureHeight, 0,
1951 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1952 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
1955 glEnable(GL_TEXTURE_2D);
1957 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1959#ifndef USE_ANDROID_GLES2
1960 glColor3ub(0, 0, 0);
1962 float u = (float)w / TextureWidth, v = (
float)h / TextureHeight;
1967 glVertex2f(x + w, y);
1969 glVertex2f(x + w, y + h);
1971 glVertex2f(x, y + h);
1975 glDisable(GL_BLEND);
1976 glDisable(GL_TEXTURE_2D);
1978 glDeleteTextures(1, &texobj);
1986void pi_ocpnDC::GetTextExtent(
const wxString &
string, wxCoord *w, wxCoord *h,
1987 wxCoord *descent, wxCoord *externalLeading,
1994 dc->GetTextExtent(
string, w, h, descent, externalLeading, font);
1997 if (font) f = *font;
2002 m_texfont.GetTextExtent(
string, w, h);
2005 temp_dc.GetTextExtent(
string, w, h, descent, externalLeading, &f);
2009 temp_dc.GetTextExtent(
string, w, h, descent, externalLeading, &f);
2015 if (w && (*w > 2000)) *w = 2000;
2016 if (h && (*h > 500)) *h = 500;
2019void pi_ocpnDC::ResetBoundingBox() {
2020 if (dc) dc->ResetBoundingBox();
2023void pi_ocpnDC::CalcBoundingBox(wxCoord x, wxCoord y) {
2024 if (dc) dc->CalcBoundingBox(x, y);
2027bool pi_ocpnDC::ConfigurePen() {
2028 if (!m_pen.IsOk())
return false;
2029 if (m_pen == *wxTRANSPARENT_PEN)
return false;
2031 wxColour c = m_pen.GetColour();
2032 int width = m_pen.GetWidth();
2034#ifndef USE_ANDROID_GLES2
2035 glColor4ub(c.Red(), c.Green(), c.Blue(), c.Alpha());
2036 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, width));
2042bool pi_ocpnDC::ConfigureBrush() {
2043 if (m_brush == wxNullBrush || m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT)
2046#ifndef USE_ANDROID_GLES2
2047 wxColour c = m_brush.GetColour();
2048 glColor4ub(c.Red(), c.Green(), c.Blue(), c.Alpha());
2054void pi_ocpnDC::GLDrawBlendData(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
2055 int format,
const unsigned char *data) {
2057#ifndef USE_ANDROID_GLES2
2059 glRasterPos2i(x, y);
2061 glDrawPixels(w, h, format, GL_UNSIGNED_BYTE, data);
2063 glDisable(GL_BLEND);
PlugIn Object Definition/API.