33#ifndef __OCPN__ANDROID__
47#include <wx/glcanvas.h>
50#include <wx/graphics.h>
51#include <wx/dcclient.h>
57#include "pi_shaders.h"
58#ifdef USE_ANDROID_GLES2
62#ifdef __OCPN__ANDROID__
66extern float g_piGLMinSymbolLineWidth;
67wxArrayPtrVoid pi_gTesselatorVertices;
69#ifdef USE_ANDROID_GLES2
70extern GLint GRIBpi_color_tri_shader_program;
71extern GLint pi_circle_filled_shader_program;
72extern GLint texture_2D_shader_program;
75int NextPow2(
int size) {
88pi_ocpnDC::pi_ocpnDC(wxGLCanvas &canvas)
95#if wxUSE_GRAPHICS_CONTEXT
98 m_textforegroundcolour = wxColour(0, 0, 0);
102 s_odc_tess_work_buf =
nullptr;
104#ifdef USE_ANDROID_GLES2
105 s_odc_tess_vertex_idx = 0;
106 s_odc_tess_vertex_idx_this = 0;
107 s_odc_tess_buf_len = 0;
109 s_odc_tess_work_buf = (GLfloat *)malloc(100 *
sizeof(GLfloat));
110 s_odc_tess_buf_len = 100;
117pi_ocpnDC::pi_ocpnDC(wxDC &pdc)
121 m_brush(wxNullBrush),
123#if wxUSE_GRAPHICS_CONTEXT
125 auto pmdc =
dynamic_cast<wxMemoryDC *
>(dc);
127 pgc = wxGraphicsContext::Create(*pmdc);
129 auto pcdc =
dynamic_cast<wxClientDC *
>(dc);
130 if (pcdc) pgc = wxGraphicsContext::Create(*pcdc);
133 m_textforegroundcolour = wxColour(0, 0, 0);
138 s_odc_tess_work_buf =
nullptr;
142pi_ocpnDC::pi_ocpnDC()
146 m_brush(wxNullBrush),
148#if wxUSE_GRAPHICS_CONTEXT
151 m_textforegroundcolour = wxColour(0, 0, 0);
156 s_odc_tess_work_buf =
nullptr;
162pi_ocpnDC::~pi_ocpnDC() {
163#if wxUSE_GRAPHICS_CONTEXT
168 free(s_odc_tess_work_buf);
181void pi_ocpnDC::Clear() {
186 wxBrush tmpBrush = m_brush;
188 SetBrush(wxBrush(glcanvas->GetBackgroundColour()));
189 glcanvas->GetSize(&w, &h);
190 DrawRectangle(0, 0, w, h);
196void pi_ocpnDC::SetBackground(
const wxBrush &brush) {
198 dc->SetBackground(brush);
201 glcanvas->SetBackgroundColour(brush.GetColour());
206void pi_ocpnDC::SetPen(
const wxPen &pen) {
208 if (pen == wxNullPen)
209 dc->SetPen(*wxTRANSPARENT_PEN);
216void pi_ocpnDC::SetBrush(
const wxBrush &brush) {
223void pi_ocpnDC::SetTextForeground(
const wxColour &colour) {
225 dc->SetTextForeground(colour);
227 m_textforegroundcolour = colour;
230void pi_ocpnDC::SetFont(
const wxFont &font) {
237const wxPen &pi_ocpnDC::GetPen()
const {
238 if (dc)
return dc->GetPen();
242const wxBrush &pi_ocpnDC::GetBrush()
const {
243 if (dc)
return dc->GetBrush();
247const wxFont &pi_ocpnDC::GetFont()
const {
248 if (dc)
return dc->GetFont();
252void pi_ocpnDC::GetSize(wxCoord *width, wxCoord *height)
const {
254 dc->GetSize(width, height);
257 glcanvas->GetSize(width, height);
262void pi_ocpnDC::SetGLAttrs(
bool highQuality) {
267 glEnable(GL_LINE_SMOOTH);
268 glEnable(GL_POLYGON_SMOOTH);
271 glDisable(GL_LINE_SMOOTH);
272 glDisable(GL_POLYGON_SMOOTH);
278void pi_ocpnDC::SetGLStipple()
const {
281#ifndef USE_ANDROID_GLES2
282 switch (m_pen.GetStyle()) {
283 case wxPENSTYLE_DOT: {
284 glLineStipple(1, 0x3333);
285 glEnable(GL_LINE_STIPPLE);
288 case wxPENSTYLE_LONG_DASH: {
289 glLineStipple(1, 0xFFF8);
290 glEnable(GL_LINE_STIPPLE);
293 case wxPENSTYLE_SHORT_DASH: {
294 glLineStipple(1, 0x3F3F);
295 glEnable(GL_LINE_STIPPLE);
298 case wxPENSTYLE_DOT_DASH: {
299 glLineStipple(1, 0x8FF1);
300 glEnable(GL_LINE_STIPPLE);
312void piDrawEndCap(
float x1,
float y1,
float t1,
float angle) {
313#ifndef USE_ANDROID_GLES2
314 const int steps = 16;
317 for (
int i = 0; i <= steps; i++) {
318 float a = angle + M_PI / 2 + M_PI / steps * i;
320 float xb = x1 + t1 / 2 * cos(a);
321 float yb = y1 + t1 / 2 * sin(a);
336void piDrawGLThickLine(
float x1,
float y1,
float x2,
float y2, wxPen pen,
340 float angle = atan2f(y2 - y1, x2 - x1);
341 float t1 = pen.GetWidth();
342 float t2sina1 = t1 / 2 * sinf(angle);
343 float t2cosa1 = t1 / 2 * cosf(angle);
345#ifndef USE_ANDROID_GLES2
346 glBegin(GL_TRIANGLES);
351 int n_dashes = pen.GetDashes(&dashes);
353 float lpix = sqrtf(powf((
float)(x1 - x2), 2) + powf((
float)(y1 - y2), 2));
357 float ldraw = t1 * dashes[0];
358 float lspace = t1 * dashes[1];
360 while (lrun < lpix) {
362 float xb = xa + ldraw * cosf(angle);
363 float yb = ya + ldraw * sinf(angle);
365 if ((lrun + ldraw) >= lpix)
371 glVertex2f(xa + t2sina1, ya - t2cosa1);
372 glVertex2f(xb + t2sina1, yb - t2cosa1);
373 glVertex2f(xb - t2sina1, yb + t2cosa1);
375 glVertex2f(xb - t2sina1, yb + t2cosa1);
376 glVertex2f(xa - t2sina1, ya + t2cosa1);
377 glVertex2f(xa + t2sina1, ya - t2cosa1);
384 xb = xa + lspace * cos(angle);
385 yb = ya + lspace * sin(angle);
392 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
393 glVertex2f(x2 + t2sina1, y2 - t2cosa1);
394 glVertex2f(x2 - t2sina1, y2 + t2cosa1);
396 glVertex2f(x2 - t2sina1, y2 + t2cosa1);
397 glVertex2f(x1 - t2sina1, y1 + t2cosa1);
398 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
402 if (pen.GetCap() == wxCAP_ROUND) {
403 piDrawEndCap(x1, y1, t1, angle);
404 piDrawEndCap(x2, y2, t1, angle + M_PI);
414 int n_dashes = pen.GetDashes(&dashes);
416 float lpix = sqrtf(powf((
float)(x1 - x2), 2) + powf((
float)(y1 - y2), 2));
420 float ldraw = t1 * dashes[0];
421 float lspace = t1 * dashes[1];
423 glUseProgram(GRIBpi_color_tri_shader_program);
428 glBindBuffer(GL_ARRAY_BUFFER, 0);
429 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
432 glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
433 glEnableVertexAttribArray(pos);
434 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), vert);
440 GLint matloc = glGetUniformLocation(GRIBpi_color_tri_shader_program,
442 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
444 wxColor c = pen.GetColour();
446 colorv[0] = c.Red() / float(256);
447 colorv[1] = c.Green() / float(256);
448 colorv[2] = c.Blue() / float(256);
449 colorv[3] = c.Alpha() / float(256);
452 glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
453 glUniform4fv(colloc, 1, colorv);
455 while (lrun < lpix) {
457 float xb = xa + ldraw * cosf(angle);
458 float yb = ya + ldraw * sinf(angle);
460 if ((lrun + ldraw) >= lpix)
466 vert[0] = xa + t2sina1;
467 vert[1] = ya - t2cosa1;
468 vert[2] = xb + t2sina1;
469 vert[3] = yb - t2cosa1;
470 vert[4] = xb - t2sina1;
471 vert[5] = yb + t2cosa1;
472 vert[6] = xb - t2sina1;
473 vert[7] = yb + t2cosa1;
474 vert[8] = xa - t2sina1;
475 vert[9] = ya + t2cosa1;
476 vert[10] = xa + t2sina1;
477 vert[11] = ya - t2cosa1;
479 glDrawArrays(GL_TRIANGLES, 0, 6);
486 xb = xa + lspace * cos(angle);
487 yb = ya + lspace * sin(angle);
495 vert[0] = x1 + t2sina1;
496 vert[1] = y1 - t2cosa1;
497 vert[2] = x2 + t2sina1;
498 vert[3] = y2 - t2cosa1;
499 vert[4] = x2 - t2sina1;
500 vert[5] = y2 + t2cosa1;
501 vert[6] = x2 - t2sina1;
502 vert[7] = y2 + t2cosa1;
503 vert[8] = x1 - t2sina1;
504 vert[9] = y1 + t2cosa1;
505 vert[10] = x1 + t2sina1;
506 vert[11] = y1 - t2cosa1;
508 glUseProgram(GRIBpi_color_tri_shader_program);
511 glBindBuffer(GL_ARRAY_BUFFER, 0);
512 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
515 glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
516 glEnableVertexAttribArray(pos);
517 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), vert);
523 GLint matloc = glGetUniformLocation(GRIBpi_color_tri_shader_program,
525 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
527 wxColor c = pen.GetColour();
529 colorv[0] = c.Red() / float(256);
530 colorv[1] = c.Green() / float(256);
531 colorv[2] = c.Blue() / float(256);
532 colorv[3] = c.Alpha() / float(256);
535 glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
536 glUniform4fv(colloc, 1, colorv);
538 glDrawArrays(GL_TRIANGLES, 0, 6);
539 glDisableVertexAttribArray(pos);
556void pi_ocpnDC::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
558 if (dc) dc->DrawLine(x1, y1, x2, y2);
560 else if (ConfigurePen()) {
561 bool b_draw_thick =
false;
563 float pen_width = wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth());
571 glEnable(GL_LINE_SMOOTH);
574 if (pen_width > 1.0) {
576 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
577 if (glGetError()) glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
578 if (pen_width > parms[1])
581 glLineWidth(pen_width);
583 glLineWidth(pen_width);
587 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
588 if (pen_width > parms[1])
591 glLineWidth(pen_width);
593 glLineWidth(pen_width);
598 piDrawGLThickLine(x1, y1, x2, y2, m_pen, b_hiqual);
600 glUseProgram(GRIBpi_color_tri_shader_program);
604 glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
605 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float),
607 glEnableVertexAttribArray(pos);
615 colorv[0] = m_pen.GetColour().Red() / float(256);
616 colorv[1] = m_pen.GetColour().Green() / float(256);
617 colorv[2] = m_pen.GetColour().Blue() / float(256);
621 glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
622 glUniform4fv(colloc, 1, colorv);
625 int n_dashes = m_pen.GetDashes(&dashes);
627 float angle = atan2f((
float)(y2 - y1), (
float)(x2 - x1));
628 float cosa = cosf(angle);
629 float sina = sinf(angle);
630 float t1 = m_pen.GetWidth();
632 float lpix = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
636 float ldraw = t1 * dashes[0];
637 float lspace = t1 * dashes[1];
639 ldraw = wxMax(ldraw, 4.0);
640 lspace = wxMax(lspace, 4.0);
641 lpix = wxMin(lpix, 2000.0);
643 while (lrun < lpix) {
645 float xb = xa + ldraw * cosa;
646 float yb = ya + ldraw * sina;
648 if ((lrun + ldraw) >= lpix)
659 glDrawArrays(GL_LINES, 0, 2);
660 glDisableVertexAttribArray(pos);
662 xa = xa + (lspace + ldraw) * cosa;
663 ya = ya + (lspace + ldraw) * sina;
664 lrun += lspace + ldraw;
673 glDrawArrays(GL_LINES, 0, 2);
674 glDisableVertexAttribArray(pos);
682 piDrawGLThickLine(x1, y1, x2, y2, m_pen, b_hiqual);
685 int n_dashes = m_pen.GetDashes(&dashes);
687 float angle = atan2f((
float)(y2 - y1), (
float)(x2 - x1));
688 float cosa = cosf(angle);
689 float sina = sinf(angle);
690 float t1 = m_pen.GetWidth();
692 float lpix = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
696 float ldraw = t1 * dashes[0];
697 float lspace = t1 * dashes[1];
699 ldraw = wxMax(ldraw, 4.0);
700 lspace = wxMax(lspace, 4.0);
701 lpix = wxMin(lpix, 2000.0);
704 while (lrun < lpix) {
706 float xb = xa + ldraw * cosa;
707 float yb = ya + ldraw * sina;
709 if ((lrun + ldraw) >= lpix)
718 xa = xa + (lspace + ldraw) * cosa;
719 ya = ya + (lspace + ldraw) * sina;
720 lrun += lspace + ldraw;
732 glDisable(GL_LINE_STIPPLE);
735 glDisable(GL_LINE_SMOOTH);
743void piDrawGLThickLines(
int n, wxPoint points[], wxCoord xoffset,
744 wxCoord yoffset, wxPen pen,
bool b_hiqual) {
748#ifdef USE_ANDROID_GLES2
749 wxPoint p0 = points[0];
750 for (
int i = 1; i < n; i++) {
751 piDrawGLThickLine(p0.x + xoffset, p0.y + yoffset, points[i].x + xoffset,
752 points[i].y + yoffset, pen, b_hiqual);
760 if (pen.GetDashes(&dashes)) {
761 wxPoint p0 = points[0];
762 for (
int i = 1; i < n; i++) {
763 piDrawGLThickLine(p0.x + xoffset, p0.y + yoffset, points[i].x + xoffset,
764 points[i].y + yoffset, pen, b_hiqual);
771 wxPoint *cpoints =
new wxPoint[n];
772 cpoints[0] = points[0];
774 for (
int i = 1; i < n; i++) {
775 if (points[i].x != points[i - 1].x || points[i].y != points[i - 1].y)
776 cpoints[c++] = points[i];
783 float t1 = pen.GetWidth();
785 float x0 = cpoints[0].x, y0 = cpoints[0].y, x1 = cpoints[1].x,
787 float a0 = atan2f(y1 - y0, x1 - x0);
791 glBegin(GL_TRIANGLES);
793 float t2sina0 = t1 / 2 * sinf(a0);
794 float t2cosa0 = t1 / 2 * cosf(a0);
796 for (
int i = 1; i < c; i++) {
801 x2 = cpoints[i + 1].x, y2 = cpoints[i + 1].y;
802 a1 = atan2f(y2 - y1, x2 - x1);
808 float aa = (a0 + a1) / 2;
809 float diff = fabsf(a0 - a1);
810 if (diff > M_PI) diff -= 2 * (float)M_PI;
811 float rad = t1 / 2 / wxMax(cosf(diff / 2), .4);
813 float t2sina1 = rad * sinf(aa);
814 float t2cosa1 = rad * cosf(aa);
816 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
817 glVertex2f(x1 - t2sina1, y1 + t2cosa1);
818 glVertex2f(x0 + t2sina0, y0 - t2cosa0);
820 glVertex2f(x0 - t2sina0, y0 + t2cosa0);
821 glVertex2f(x0 + t2sina0, y0 - t2cosa0);
823 float dot = t2sina0 * t2sina1 + t2cosa0 * t2cosa1;
825 glVertex2f(x1 - t2sina1, y1 + t2cosa1);
827 glVertex2f(x1 + t2sina1, y1 - t2cosa1);
832 t2sina0 = t2sina1, t2cosa0 = t2cosa1;
835 if (pen.GetCap() == wxCAP_ROUND) {
836 piDrawEndCap(x0, y0, t1, a0);
837 piDrawEndCap(x0, y0, t1, a0 + M_PI);
849void pi_ocpnDC::DrawLines(
int n, wxPoint points[], wxCoord xoffset,
850 wxCoord yoffset,
bool b_hiqual) {
851 if (dc) dc->DrawLines(n, points, xoffset, yoffset);
853 else if (ConfigurePen()) {
858 SetGLAttrs(b_hiqual);
860 bool b_draw_thick =
false;
862 glDisable(GL_LINE_STIPPLE);
868 if (m_pen.GetWidth() > 1) {
870 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
871 if (glGetError()) glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
873 if (m_pen.GetWidth() > parms[1])
876 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
878 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
880 if (m_pen.GetWidth() > 1) {
882 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
883 if (m_pen.GetWidth() > parms[1])
886 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
888 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
892 piDrawGLThickLines(n, points, xoffset, yoffset, m_pen, b_hiqual);
895 glDisable(GL_LINE_STIPPLE);
896 glDisable(GL_POLYGON_SMOOTH);
905 glBegin(GL_LINE_STRIP);
906 for (
int i = 0; i < n; i++)
907 glVertex2i(points[i].x + xoffset, points[i].y + yoffset);
913 if (workBufSize < (
size_t)n * 2) {
914 workBuf = (
float *)realloc(workBuf, (n * 4) *
sizeof(float));
918 for (
int i = 0; i < n; i++) {
919 workBuf[i * 2] = points[i].x + xoffset;
920 workBuf[(i * 2) + 1] = points[i].y + yoffset;
923 glUseProgram(GRIBpi_color_tri_shader_program);
926 glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
927 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float),
929 glEnableVertexAttribArray(pos);
936 colorv[0] = m_pen.GetColour().Red() / float(256);
937 colorv[1] = m_pen.GetColour().Green() / float(256);
938 colorv[2] = m_pen.GetColour().Blue() / float(256);
939 colorv[3] = m_pen.GetColour().Alpha() / float(256);
943 glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
944 glUniform4fv(colloc, 1, colorv);
946 glDrawArrays(GL_LINE_STRIP, 0, n);
947 glDisableVertexAttribArray(pos);
954 glDisable(GL_LINE_STIPPLE);
955 glDisable(GL_POLYGON_SMOOTH);
962void pi_ocpnDC::StrokeLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) {
963#if wxUSE_GRAPHICS_CONTEXT
965 pgc->SetPen(dc->GetPen());
966 pgc->StrokeLine(x1, y1, x2, y2);
968 dc->CalcBoundingBox(x1, y1);
969 dc->CalcBoundingBox(x2, y2);
972 DrawLine(x1, y1, x2, y2,
true);
975void pi_ocpnDC::StrokeLines(
int n, wxPoint *points) {
979#if wxUSE_GRAPHICS_CONTEXT
981 wxPoint2DDouble *dPoints =
982 (wxPoint2DDouble *)malloc(n *
sizeof(wxPoint2DDouble));
983 for (
int i = 0; i < n; i++) {
984 dPoints[i].m_x = points[i].x;
985 dPoints[i].m_y = points[i].y;
987 pgc->SetPen(dc->GetPen());
988 pgc->StrokeLines(n, dPoints);
992 DrawLines(n, points, 0, 0,
true);
995void pi_ocpnDC::DrawGLLineArray(
int n,
float *vertex_array,
float *color_array,
996 unsigned char *color_array_ub,
bool b_hiqual) {
1000 if (ConfigurePen()) {
1005 SetGLAttrs(b_hiqual);
1007 bool b_draw_thick =
false;
1009 glDisable(GL_LINE_STIPPLE);
1015 if (m_pen.GetWidth() > 1) {
1021 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
1023 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
1025 if (m_pen.GetWidth() > 1) {
1028 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, m_pen.GetWidth()));
1030 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, 1));
1035 glEnableClientState(GL_VERTEX_ARRAY);
1036 glEnableClientState(GL_COLOR_ARRAY);
1038 glColorPointer(4, GL_UNSIGNED_BYTE, 4 *
sizeof(
unsigned char),
1040 glVertexPointer(2, GL_FLOAT, 2 *
sizeof(
float), vertex_array);
1041 glDrawArrays(GL_LINES, 0, n);
1043 glDisableClientState(GL_VERTEX_ARRAY);
1044 glDisableClientState(GL_COLOR_ARRAY);
1053 glUseProgram(GRIBpi_colorv_tri_shader_program);
1056 glGetAttribLocation(GRIBpi_colorv_tri_shader_program,
"position");
1057 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float),
1059 glEnableVertexAttribArray(pos);
1062 glGetAttribLocation(GRIBpi_colorv_tri_shader_program,
"colorv");
1063 glVertexAttribPointer(colloc, 4, GL_FLOAT, GL_FALSE, 4 *
sizeof(
float),
1065 glEnableVertexAttribArray(colloc);
1067 glDrawArrays(GL_LINES, 0, n);
1068 glDisableVertexAttribArray(pos);
1069 glDisableVertexAttribArray(colloc);
1076 glDisable(GL_LINE_STIPPLE);
1077 glDisable(GL_POLYGON_SMOOTH);
1078 glDisable(GL_BLEND);
1084void pi_ocpnDC::DrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
1085 if (dc) dc->DrawRectangle(x, y, w, h);
1089 if (ConfigureBrush()) {
1092 glVertex2i(x + w, y);
1093 glVertex2i(x + w, y + h);
1094 glVertex2i(x, y + h);
1098 if (ConfigurePen()) {
1099 glBegin(GL_LINE_LOOP);
1101 glVertex2i(x + w, y);
1102 glVertex2i(x + w, y + h);
1103 glVertex2i(x, y + h);
1107 DrawRoundedRectangle(x, y, w, h, 0);
1115static void drawrrhelper(wxCoord x0, wxCoord y0, wxCoord r,
int quadrant,
1118#ifndef USE_ANDROID_GLES2
1119 float step = 1.0 / steps, rs = 2.0 * r * step, rss = rs * step, x, y, dx, dy,
1123 x = r, y = 0, dx = 0, dy = -rs, ddx = -rss, ddy = rss;
1126 x = 0, y = -r, dx = -rs, dy = 0, ddx = rss, ddy = rss;
1129 x = -r, y = 0, dx = 0, dy = rs, ddx = rss, ddy = -rss;
1132 x = 0, y = r, dx = rs, dy = 0, ddx = -rss, ddy = -rss;
1138 for (
int i = 0; i < steps; i++) {
1139 glVertex2i(x0 + floor(x), y0 + floor(y));
1140 x += dx + ddx / 2, y += dy + ddy / 2;
1141 dx += ddx, dy += ddy;
1143 glVertex2i(x0 + floor(x), y0 + floor(y));
1148void pi_ocpnDC::drawrrhelperGLES2(wxCoord x0, wxCoord y0, wxCoord r,
1149 int quadrant,
int steps) {
1151 float step = 1.0 / steps, rs = 2.0 * r * step, rss = rs * step, x, y, dx, dy,
1155 x = r, y = 0, dx = 0, dy = -rs, ddx = -rss, ddy = rss;
1158 x = 0, y = -r, dx = -rs, dy = 0, ddx = rss, ddy = rss;
1161 x = -r, y = 0, dx = 0, dy = rs, ddx = rss, ddy = -rss;
1164 x = 0, y = r, dx = rs, dy = 0, ddx = -rss, ddy = -rss;
1170 for (
int i = 0; i < steps; i++) {
1171 workBuf[workBufIndex++] = x0 + floor(x);
1172 workBuf[workBufIndex++] = y0 + floor(y);
1174 x += dx + ddx / 2, y += dy + ddy / 2;
1175 dx += ddx, dy += ddy;
1178 workBuf[workBufIndex++] = x0 + floor(x);
1179 workBuf[workBufIndex++] = y0 + floor(y);
1183void pi_ocpnDC::DrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1185 if (dc) dc->DrawRoundedRectangle(x, y, w, h, r);
1189 int steps = ceil(sqrt((
float)r));
1191 wxCoord x1 = x + r, x2 = x + w - r;
1192 wxCoord y1 = y + r, y2 = y + h - r;
1197 size_t bufReq = steps * 8 * 2 *
sizeof(float);
1199 if (workBufSize < bufReq) {
1200 workBuf = (
float *)realloc(workBuf, bufReq);
1201 workBufSize = bufReq;
1205 drawrrhelperGLES2(x2, y1, r, 0, steps);
1206 drawrrhelperGLES2(x1, y1, r, 1, steps);
1207 drawrrhelperGLES2(x1, y2, r, 2, steps);
1208 drawrrhelperGLES2(x2, y2, r, 3, steps);
1210 glUseProgram(GRIBpi_color_tri_shader_program);
1214 glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
1217 glBindBuffer(GL_ARRAY_BUFFER, 0);
1218 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1220 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, workBuf);
1221 glEnableVertexAttribArray(mPosAttrib);
1225 bcolorv[0] = m_brush.GetColour().Red() / float(256);
1226 bcolorv[1] = m_brush.GetColour().Green() / float(256);
1227 bcolorv[2] = m_brush.GetColour().Blue() / float(256);
1228 bcolorv[3] = m_brush.GetColour().Alpha() / float(256);
1231 glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
1232 glUniform4fv(bcolloc, 1, bcolorv);
1241 mat4x4_rotate_Z(Q, I, angle);
1247 GLint matloc = glGetUniformLocation(GRIBpi_color_tri_shader_program,
1249 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)Q);
1252 glDrawArrays(GL_TRIANGLE_FAN, 0, workBufIndex / 2);
1253 glDisableVertexAttribArray(mPosAttrib);
1257 mat4x4_identity(IM);
1258 GLint matlocf = glGetUniformLocation(GRIBpi_color_tri_shader_program,
1260 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
1264 if (ConfigureBrush()) {
1265 glBegin(GL_TRIANGLE_FAN);
1266 drawrrhelper(x2, y1, r, 0, steps);
1267 drawrrhelper(x1, y1, r, 1, steps);
1268 drawrrhelper(x1, y2, r, 2, steps);
1269 drawrrhelper(x2, y2, r, 3, steps);
1273 if (ConfigurePen()) {
1274 glBegin(GL_LINE_LOOP);
1275 drawrrhelper(x2, y1, r, 0, steps);
1276 drawrrhelper(x1, y1, r, 1, steps);
1277 drawrrhelper(x1, y2, r, 2, steps);
1278 drawrrhelper(x2, y2, r, 3, steps);
1286void pi_ocpnDC::DrawCircle(wxCoord x, wxCoord y, wxCoord radius) {
1287#ifdef USE_ANDROID_GLES2
1293 coords[0] = x - radius;
1294 coords[1] = y + radius;
1295 coords[2] = x + radius;
1296 coords[3] = y + radius;
1297 coords[4] = x - radius;
1298 coords[5] = y - radius;
1299 coords[6] = x + radius;
1300 coords[7] = y - radius;
1302 glUseProgram(pi_circle_filled_shader_program);
1306 glGetAttribLocation(pi_circle_filled_shader_program,
"aPos");
1309 glBindBuffer(GL_ARRAY_BUFFER, 0);
1310 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1312 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
1313 glEnableVertexAttribArray(mPosAttrib);
1317 glGetUniformLocation(pi_circle_filled_shader_program,
"circle_radius");
1318 glUniform1f(radiusloc, radius);
1322 glGetUniformLocation(pi_circle_filled_shader_program,
"circle_center");
1325 ctrv[1] = m_vpSize.y - y;
1326 glUniform2fv(centerloc, 1, ctrv);
1330 colorv[0] = m_brush.GetColour().Red() / float(256);
1331 colorv[1] = m_brush.GetColour().Green() / float(256);
1332 colorv[2] = m_brush.GetColour().Blue() / float(256);
1333 colorv[3] = (m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT) ? 0.0 : 1.0;
1336 glGetUniformLocation(pi_circle_filled_shader_program,
"circle_color");
1337 glUniform4fv(colloc, 1, colorv);
1341 bcolorv[0] = m_pen.GetColour().Red() / float(256);
1342 bcolorv[1] = m_pen.GetColour().Green() / float(256);
1343 bcolorv[2] = m_pen.GetColour().Blue() / float(256);
1344 bcolorv[3] = m_pen.GetColour().Alpha() / float(256);
1347 glGetUniformLocation(pi_circle_filled_shader_program,
"border_color");
1348 glUniform4fv(bcolloc, 1, bcolorv);
1351 GLint borderWidthloc =
1352 glGetUniformLocation(pi_circle_filled_shader_program,
"border_width");
1353 glUniform1f(borderWidthloc, m_pen.GetWidth());
1361 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1362 glDisableVertexAttribArray(mPosAttrib);
1365 glDisable(GL_BLEND);
1368 DrawEllipse(x - radius, y - radius, 2 * radius, 2 * radius);
1372void pi_ocpnDC::StrokeCircle(wxCoord x, wxCoord y, wxCoord radius) {
1373#if wxUSE_GRAPHICS_CONTEXT
1375 wxGraphicsPath gpath = pgc->CreatePath();
1376 gpath.AddCircle(x, y, radius);
1378 pgc->SetPen(GetPen());
1379 pgc->SetBrush(GetBrush());
1380 pgc->DrawPath(gpath);
1383 dc->CalcBoundingBox(x + radius + 2, y + radius + 2);
1384 dc->CalcBoundingBox(x - radius - 2, y - radius - 2);
1387 DrawCircle(x, y, radius);
1390void pi_ocpnDC::DrawEllipse(wxCoord x, wxCoord y, wxCoord width,
1392 if (dc) dc->DrawEllipse(x, y, width, height);
1395 float r1 = width / 2, r2 = height / 2;
1396 float cx = x + r1, cy = y + r2;
1402 float steps = floorf(
1403 wxMax(sqrtf(sqrtf((
float)(width * width + height * height))), 1) *
1406#ifndef USE_ANDROID_GLES2
1407 if (ConfigureBrush()) {
1408 glBegin(GL_TRIANGLE_FAN);
1410 for (
float a = 0; a <= 2 * M_PI + M_PI / steps; a += 2 * M_PI / steps)
1411 glVertex2f(cx + r1 * sinf(a), cy + r2 * cosf(a));
1415 if (ConfigurePen()) {
1416 glBegin(GL_LINE_LOOP);
1417 for (
float a = 0; a < 2 * M_PI - M_PI / steps; a += 2 * M_PI / steps)
1418 glVertex2f(cx + r1 * sinf(a), cy + r2 * cosf(a));
1423 glDisable(GL_BLEND);
1428void pi_ocpnDC::DrawPolygon(
int n, wxPoint points[], wxCoord xoffset,
1429 wxCoord yoffset,
float scale,
float angle) {
1430 if (dc) dc->DrawPolygon(n, points, xoffset, yoffset);
1440#ifdef USE_ANDROID_GLES2
1445 DrawPolygonTessellated(n, points, xoffset, yoffset);
1449 if (workBufSize < (
size_t)n * 2) {
1450 workBuf = (
float *)realloc(workBuf, (n * 4) *
sizeof(float));
1451 workBufSize = n * 4;
1454 for (
int i = 0; i < n; i++) {
1455 workBuf[i * 2] = (points[i].x *
scale);
1456 workBuf[i * 2 + 1] = (points[i].y *
scale);
1459 glUseProgram(GRIBpi_color_tri_shader_program);
1463 glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
1466 glBindBuffer(GL_ARRAY_BUFFER, 0);
1467 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1469 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, workBuf);
1470 glEnableVertexAttribArray(mPosAttrib);
1474 bcolorv[0] = m_pen.GetColour().Red() / float(256);
1475 bcolorv[1] = m_pen.GetColour().Green() / float(256);
1476 bcolorv[2] = m_pen.GetColour().Blue() / float(256);
1477 bcolorv[3] = m_pen.GetColour().Alpha() / float(256);
1480 glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
1481 glUniform4fv(bcolloc, 1, bcolorv);
1486 mat4x4_rotate_Z(Q, I, angle);
1492 GLint matloc = glGetUniformLocation(GRIBpi_color_tri_shader_program,
1494 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)Q);
1497 glDrawArrays(GL_LINE_LOOP, 0, n);
1500 bcolorv[0] = m_brush.GetColour().Red() / float(256);
1501 bcolorv[1] = m_brush.GetColour().Green() / float(256);
1502 bcolorv[2] = m_brush.GetColour().Blue() / float(256);
1503 bcolorv[3] = m_brush.GetColour().Alpha() / float(256);
1505 glUniform4fv(bcolloc, 1, bcolorv);
1510 float x1 = workBuf[4];
1511 float y1 = workBuf[5];
1512 workBuf[4] = workBuf[6];
1513 workBuf[5] = workBuf[7];
1517 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1518 }
else if (n == 3) {
1519 glDrawArrays(GL_TRIANGLES, 0, 3);
1522 glDisableVertexAttribArray(mPosAttrib);
1526 mat4x4_identity(IM);
1527 GLint matlocf = glGetUniformLocation(GRIBpi_color_tri_shader_program,
1529 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
1536 if (ConfigureBrush()) {
1537 glEnable(GL_POLYGON_SMOOTH);
1538 glBegin(GL_POLYGON);
1539 for (
int i = 0; i < n; i++)
1540 glVertex2f((points[i].x *
scale) + xoffset,
1541 (points[i].y *
scale) + yoffset);
1543 glDisable(GL_POLYGON_SMOOTH);
1546 if (ConfigurePen()) {
1547 glEnable(GL_LINE_SMOOTH);
1548 glBegin(GL_LINE_LOOP);
1549 for (
int i = 0; i < n; i++)
1550 glVertex2f((points[i].x *
scale) + xoffset,
1551 (points[i].y *
scale) + yoffset);
1553 glDisable(GL_LINE_SMOOTH);
1579void APIENTRY pi_ocpnDCcombineCallback(GLdouble coords[3],
1580 GLdouble *vertex_data[4],
1581 GLfloat weight[4], GLdouble **dataOut) {
1584 vertex =
new GLvertex();
1585 pi_gTesselatorVertices.Add(vertex);
1587 vertex->info.x = coords[0];
1588 vertex->info.y = coords[1];
1589 vertex->info.z = coords[2];
1591 for (
int i = 3; i < 6; i++) {
1593 weight[0] * vertex_data[0][i] + weight[1] * vertex_data[1][i];
1596 *dataOut = &(vertex->data[0]);
1599void APIENTRY ocpnDCvertexCallback(GLvoid *arg) {
1601 vertex = (GLvertex *)arg;
1602 glVertex2f((
float)vertex->info.x, (
float)vertex->info.y);
1605void APIENTRY ocpnDCerrorCallback(GLenum errorCode) {
1606 const GLubyte *estring;
1607 estring = gluErrorString(errorCode);
1611void APIENTRY ocpnDCbeginCallback(GLenum type) { glBegin(type); }
1613void APIENTRY ocpnDCendCallback() { glEnd(); }
1620static std::list<double *> odc_combine_work_data;
1621static void pi_odc_combineCallbackD(GLdouble coords[3],
1622 GLdouble *vertex_data[4], GLfloat weight[4],
1623 GLdouble **dataOut,
void *data) {
1630void pi_odc_vertexCallbackD_GLSL(GLvoid *vertex,
void *data) {
1634 if (pDC->s_odc_tess_vertex_idx > pDC->s_odc_tess_buf_len - 8) {
1635 int new_buf_len = pDC->s_odc_tess_buf_len + 100;
1636 GLfloat *tmp = pDC->s_odc_tess_work_buf;
1638 pDC->s_odc_tess_work_buf = (GLfloat *)realloc(
1639 pDC->s_odc_tess_work_buf, new_buf_len *
sizeof(GLfloat));
1640 if (
nullptr == pDC->s_odc_tess_work_buf) {
1644 pDC->s_odc_tess_buf_len = new_buf_len;
1647 GLdouble *pointer = (GLdouble *)vertex;
1649 pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx++] = (float)pointer[0];
1650 pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx++] = (float)pointer[1];
1652 pDC->s_odc_nvertex++;
1655void pi_odc_beginCallbackD_GLSL(GLenum mode,
void *data) {
1657 pDC->s_odc_tess_vertex_idx_this = pDC->s_odc_tess_vertex_idx;
1658 pDC->s_odc_tess_mode = mode;
1659 pDC->s_odc_nvertex = 0;
1662void pi_odc_endCallbackD_GLSL(
void *data) {
1668 glUseProgram(GRIBpi_color_tri_shader_program);
1671 glBindBuffer(GL_ARRAY_BUFFER, 0);
1672 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1674 float *bufPt = &(pDC->s_odc_tess_work_buf[pDC->s_odc_tess_vertex_idx_this]);
1675 GLint pos = glGetAttribLocation(GRIBpi_color_tri_shader_program,
"position");
1676 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), bufPt);
1677 glEnableVertexAttribArray(pos);
1685 wxColour c = pDC->GetBrush().GetColour();
1687 colorv[0] = c.Red() / float(256);
1688 colorv[1] = c.Green() / float(256);
1689 colorv[2] = c.Blue() / float(256);
1690 colorv[3] = c.Alpha() / float(256);
1692 GLint colloc = glGetUniformLocation(GRIBpi_color_tri_shader_program,
"color");
1693 glUniform4fv(colloc, 1, colorv);
1695 glDrawArrays(pDC->s_odc_tess_mode, 0, pDC->s_odc_nvertex);
1697 glDisableVertexAttribArray(pos);
1706void pi_ocpnDC::DrawPolygonTessellated(
int n, wxPoint points[], wxCoord xoffset,
1708 if (dc) dc->DrawPolygon(n, points, xoffset, yoffset);
1711#if !defined(ocpnUSE_GLES) || \
1712 defined(USE_ANDROID_GLES2)
1716 DrawPolygon(n, points, xoffset, yoffset);
1721 m_tobj = gluNewTess();
1722 s_odc_tess_vertex_idx = 0;
1724 gluTessCallback(m_tobj, GLU_TESS_VERTEX_DATA,
1725 (_GLUfuncptr)&pi_odc_vertexCallbackD_GLSL);
1726 gluTessCallback(m_tobj, GLU_TESS_BEGIN_DATA,
1727 (_GLUfuncptr)&pi_odc_beginCallbackD_GLSL);
1728 gluTessCallback(m_tobj, GLU_TESS_END_DATA,
1729 (_GLUfuncptr)&pi_odc_endCallbackD_GLSL);
1730 gluTessCallback(m_tobj, GLU_TESS_COMBINE_DATA,
1731 (_GLUfuncptr)&pi_odc_combineCallbackD);
1734 gluTessNormal(m_tobj, 0, 0, 1);
1735 gluTessProperty(m_tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
1737 if (ConfigureBrush()) {
1738 gluTessBeginPolygon(m_tobj,
this);
1739 gluTessBeginContour(m_tobj);
1741 for (
int i = 0; i < n; i++) {
1742 double *p =
new double[6];
1743 p[0] = points[i].x, p[1] = points[i].y, p[2] = 0;
1744 gluTessVertex(m_tobj, p, p);
1747 gluTessEndContour(m_tobj);
1748 gluTessEndPolygon(m_tobj);
1751 gluDeleteTess(m_tobj);
1760 static GLUtesselator *tobj =
nullptr;
1761 if (!tobj) tobj = gluNewTess();
1763 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&ocpnDCvertexCallback);
1764 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&ocpnDCbeginCallback);
1765 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&ocpnDCendCallback);
1766 gluTessCallback(tobj, GLU_TESS_COMBINE,
1767 (_GLUfuncptr)&pi_ocpnDCcombineCallback);
1768 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)&ocpnDCerrorCallback);
1770 gluTessNormal(tobj, 0, 0, 1);
1771 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
1773 if (ConfigureBrush()) {
1774 gluTessBeginPolygon(tobj,
nullptr);
1775 gluTessBeginContour(tobj);
1777 for (
int i = 0; i < n; i++) {
1778 GLvertex *vertex =
new GLvertex();
1779 pi_gTesselatorVertices.Add(vertex);
1780 vertex->info.x = (GLdouble)points[i].x;
1781 vertex->info.y = (GLdouble)points[i].y;
1782 vertex->info.z = (GLdouble)0.0;
1783 vertex->info.r = (GLdouble)0.0;
1784 vertex->info.g = (GLdouble)0.0;
1785 vertex->info.b = (GLdouble)0.0;
1786 gluTessVertex(tobj, (GLdouble *)vertex, (GLdouble *)vertex);
1788 gluTessEndContour(tobj);
1789 gluTessEndPolygon(tobj);
1792 for (
unsigned int i = 0; i < pi_gTesselatorVertices.Count(); i++)
1793 delete (GLvertex *)pi_gTesselatorVertices.Item(i);
1794 pi_gTesselatorVertices.Clear();
1796 gluDeleteTess(tobj);
1802void pi_ocpnDC::StrokePolygon(
int n, wxPoint points[], wxCoord xoffset,
1803 wxCoord yoffset,
float scale) {
1804#if wxUSE_GRAPHICS_CONTEXT
1806 wxGraphicsPath gpath = pgc->CreatePath();
1807 gpath.MoveToPoint(points[0].x + xoffset, points[0].y + yoffset);
1808 for (
int i = 1; i < n; i++)
1809 gpath.AddLineToPoint(points[i].x + xoffset, points[i].y + yoffset);
1810 gpath.AddLineToPoint(points[0].x + xoffset, points[0].y + yoffset);
1812 pgc->SetPen(GetPen());
1813 pgc->SetBrush(GetBrush());
1814 pgc->DrawPath(gpath);
1816 for (
int i = 0; i < n; i++)
1817 dc->CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
1820 DrawPolygon(n, points, xoffset, yoffset,
scale);
1823void pi_ocpnDC::DrawBitmap(
const wxBitmap &bitmap, wxCoord x, wxCoord y,
1826 if (x < 0 || y < 0) {
1827 int dx = (x < 0 ? -x : 0);
1828 int dy = (y < 0 ? -y : 0);
1829 int w = bitmap.GetWidth() - dx;
1830 int h = bitmap.GetHeight() - dy;
1832 if (w <= 0 || h <= 0)
return;
1833 wxBitmap newBitmap = bitmap.GetSubBitmap(wxRect(dx, dy, w, h));
1840 if (dc) dc->DrawBitmap(bmp, x, y, usemask);
1848#ifndef USE_ANDROID_GLES2
1849 wxImage image = bmp.ConvertToImage();
1850 int w = image.GetWidth(), h = image.GetHeight();
1853 unsigned char *d = image.GetData();
1854 unsigned char *a = image.GetAlpha();
1856 unsigned char mr, mg, mb;
1857 if (!image.GetOrFindMaskColour(&mr, &mg, &mb) && !a) {
1858 printf(
"trying to use mask to draw a bitmap without alpha or mask\n");
1862 if (image.HasMask()) a = 0;
1865 unsigned char *e =
new unsigned char[4 * w * h];
1867 for (
int y = 0; y < h; y++)
1868 for (
int x = 0; x < w; x++) {
1869 unsigned char r, g, b;
1870 int off = (y * image.GetWidth() + x);
1880 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
1886 glColor4f(1, 1, 1, 1);
1887 GLDrawBlendData(x, y, w, h, GL_RGBA, e);
1890 glRasterPos2i(x, y);
1892 if (image.GetData())
1893 glDrawPixels(w, h, GL_RGB, GL_UNSIGNED_BYTE, image.GetData());
1902void pi_ocpnDC::DrawText(
const wxString &text, wxCoord x, wxCoord y) {
1903 if (dc) dc->DrawText(text, x, y);
1910 m_texfont.Build(m_font);
1911 m_texfont.GetTextExtent(text, &w, &h);
1915 glEnable(GL_TEXTURE_2D);
1916 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1917 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1921 glTranslatef(x, y, 0);
1923 glColor3ub(m_textforegroundcolour.Red(), m_textforegroundcolour.Green(),
1924 m_textforegroundcolour.Blue());
1926 m_texfont.RenderString(text);
1929 m_texfont.RenderString(text, x, y);
1931 glDisable(GL_TEXTURE_2D);
1932 glDisable(GL_BLEND);
1936 sdc.SetFont(m_font);
1937 sdc.GetMultiLineTextExtent(text, &w, &h,
nullptr,
1940 sdc.GetTextExtent(
"W", &ww, &hw);
1951 temp_dc.SelectObject(bmp);
1954 temp_dc.SetBackground(wxBrush(wxColour(0, 0, 0)));
1958 temp_dc.SetFont(m_font);
1959 temp_dc.SetTextForeground(wxColour(255, 255, 255));
1960 temp_dc.DrawText(text, 0, 0);
1961 temp_dc.SelectObject(wxNullBitmap);
1965 wxImage image = bmp.ConvertToImage();
1968 int dx = (x < 0 ? -x : 0);
1969 int dy = (y < 0 ? -y : 0);
1970 w = bmp.GetWidth() - dx;
1971 h = bmp.GetHeight() - dy;
1973 if (w <= 0 || h <= 0)
return;
1974 image = image.GetSubImage(wxRect(dx, dy, w, h));
1979 unsigned char *data =
new unsigned char[w * h * 4];
1980 unsigned char *im = image.GetData();
1983 unsigned int r = m_textforegroundcolour.Red();
1984 unsigned int g = m_textforegroundcolour.Green();
1985 unsigned int b = m_textforegroundcolour.Blue();
1986 for (
int i = 0; i < h; i++) {
1987 for (
int j = 0; j < w; j++) {
1988 unsigned int index = ((i * w) + j) * 4;
1990 data[index + 1] = g;
1991 data[index + 2] = b;
1992 data[index + 3] = im[((i * w) + j) * 3];
1997 glColor4ub( 255, 255, 255, 255 );
1998 glEnable( GL_BLEND );
1999 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
2000 glRasterPos2i( x, y );
2001 glPixelZoom( 1, -1 );
2002 glDrawPixels( w, h, GL_RGBA, GL_UNSIGNED_BYTE, data );
2003 glPixelZoom( 1, 1 );
2004 glDisable( GL_BLEND );
2006 unsigned int texobj;
2008 glGenTextures(1, &texobj);
2009 glBindTexture(GL_TEXTURE_2D, texobj);
2011 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2012 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2014 int TextureWidth = NextPow2(w);
2015 int TextureHeight = NextPow2(h);
2016 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TextureWidth, TextureHeight, 0,
2017 GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
2018 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
2021 glEnable(GL_TEXTURE_2D);
2023 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2025 float u = (float)w / TextureWidth, v = (
float)h / TextureHeight;
2028 glColor3ub(0, 0, 0);
2034 glVertex2f(x + w, y);
2036 glVertex2f(x + w, y + h);
2038 glVertex2f(x, y + h);
2064 glUseProgram(pi_texture_2D_shader_program);
2068 glGetAttribLocation(pi_texture_2D_shader_program,
"aPos");
2070 glGetAttribLocation(pi_texture_2D_shader_program,
"aUV");
2073 GLint texUni = glGetUniformLocation(pi_texture_2D_shader_program,
"uTex");
2074 glUniform1i(texUni, 0);
2077 glBindBuffer(GL_ARRAY_BUFFER, 0);
2078 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2082 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
2084 glEnableVertexAttribArray(mPosAttrib);
2087 glVertexAttribPointer(mUvAttrib, 2, GL_FLOAT, GL_FALSE, 0, uv);
2089 glEnableVertexAttribArray(mUvAttrib);
2095 mat4x4_rotate_Z(Q, I, angle);
2102 glGetUniformLocation(pi_texture_2D_shader_program,
"TransformMatrix");
2103 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)Q);
2106 glActiveTexture(GL_TEXTURE0);
2111 GLushort indices1[] = {0,1,3,2};
2112 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
2135 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, co1);
2136 glVertexAttribPointer(mUvAttrib, 2, GL_FLOAT, GL_FALSE, 0, tco1);
2138 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2139 glDisableVertexAttribArray(mPosAttrib);
2140 glDisableVertexAttribArray(mUvAttrib);
2147 glDisable(GL_BLEND);
2148 glDisable(GL_TEXTURE_2D);
2150 glDeleteTextures(1, &texobj);
2158void pi_ocpnDC::GetTextExtent(
const wxString &
string, wxCoord *w, wxCoord *h,
2159 wxCoord *descent, wxCoord *externalLeading,
2167 dc->GetMultiLineTextExtent(
string, w, h,
nullptr, font);
2170 if (font) f = *font;
2175 m_texfont.GetTextExtent(
string, w, h);
2178 temp_dc.GetMultiLineTextExtent(
string, w, h,
nullptr, &f);
2184 temp_dc.GetMultiLineTextExtent(
string, w, h,
nullptr, &f);
2192 if (w && (*w > 2000)) *w = 2000;
2193 if (h && (*h > 500)) *h = 500;
2196void pi_ocpnDC::ResetBoundingBox() {
2197 if (dc) dc->ResetBoundingBox();
2200void pi_ocpnDC::CalcBoundingBox(wxCoord x, wxCoord y) {
2201 if (dc) dc->CalcBoundingBox(x, y);
2204bool pi_ocpnDC::ConfigurePen() {
2205 if (!m_pen.IsOk())
return false;
2206 if (m_pen == *wxTRANSPARENT_PEN)
return false;
2208 wxColour c = m_pen.GetColour();
2209 int width = m_pen.GetWidth();
2211 glColor4ub(c.Red(), c.Green(), c.Blue(), c.Alpha());
2212 glLineWidth(wxMax(g_piGLMinSymbolLineWidth, width));
2217bool pi_ocpnDC::ConfigureBrush() {
2218 if (m_brush == wxNullBrush || m_brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT)
2221 wxColour c = m_brush.GetColour();
2222 glColor4ub(c.Red(), c.Green(), c.Blue(), c.Alpha());
2227void pi_ocpnDC::GLDrawBlendData(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
2228 int format,
const unsigned char *data) {
2230#ifndef USE_ANDROID_GLES2
2232 glRasterPos2i(x, y);
2234 glDrawPixels(w, h, format, GL_UNSIGNED_BYTE, data);
2236 glDisable(GL_BLEND);
Contains view parameters and status information for a chart display viewport.
int pix_width
Viewport width in pixels.
int pix_height
Viewport height in pixels.
PlugIn Object Definition/API.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
OpenGL Platform Abstraction Layer.