Ticket #671: graphics_opengl.c

File graphics_opengl.c, 28.8 KB (added by tegzed, 12 years ago)

eliminated some compiler warnings

Line 
1/**
2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2010 Navit Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA  02110-1301, USA.
18 */
19
20#include <glib.h>
21#include <unistd.h>
22#include <math.h>
23#include <stdio.h>
24#include <FreeImage.h>
25
26#include "item.h"
27#include "attr.h"
28#include "config.h"
29#include "point.h"
30#include "graphics.h"
31#include "color.h"
32#include "plugin.h"
33#include "event.h"
34#include "debug.h"
35#include "callback.h"
36#include "keys.h"
37#include "window.h"
38#include "navit/font/freetype/font_freetype.h"
39#include <GL/glc.h>
40
41#if defined(WINDOWS) || defined(WIN32)
42#include <windows.h>
43# define sleep(i) Sleep(i * 1000)
44#endif
45
46#ifdef __APPLE__
47#include <GLUT/glut.h>
48#else
49#include <GL/glut.h>            /* glut.h includes gl.h and glu.h */
50#endif
51
52#define SCREEN_WIDTH 700
53#define SCREEN_HEIGHT 700
54
55
56struct graphics_gc_priv
57{
58  struct graphics_priv *gr;
59  float fr, fg, fb, fa;
60  float br, bg, bb, ba;
61  int linewidth;
62  unsigned char *dash_list;
63  int dash_count;
64  int dash_mask;
65} graphics_gc_priv;
66
67struct graphics_priv
68{
69  int button_timeout;
70  struct point p;
71  int width;
72  int height;
73  int library_init;
74  int visible;
75  int overlay_enabled;
76  int overlay_autodisabled;
77  int wraparound;
78  struct graphics_priv *parent;
79  struct graphics_priv *overlays;
80  struct graphics_priv *next;
81  struct graphics_gc_priv *background_gc;
82  enum draw_mode_num mode;
83  void (*resize_callback) (void *data, int w, int h);
84  void *resize_callback_data;
85  void (*motion_callback) (void *data, struct point * p);
86  void *motion_callback_data;
87  void (*button_callback) (void *data, int press, int button,
88                           struct point * p);
89  void *button_callback_data;
90  GLuint DLid;
91  struct callback_list *cbl;
92  struct font_freetype_methods freetype_methods;
93  struct navit *nav;
94  int timeout;
95  int delay;
96
97  struct window window;
98
99};
100
101static struct graphics_priv *graphics_priv_root;
102struct graphics_image_priv
103{
104  int w;
105  int h;
106  int hot_x;
107  int hot_y;
108  unsigned char *data;
109  char *path;
110} graphics_image_priv;
111
112/*  prototypes */
113void CALLBACK tessBeginCB (GLenum which);
114void CALLBACK tessEndCB ();
115void CALLBACK tessErrorCB (GLenum errorCode);
116void CALLBACK tessVertexCB (const GLvoid * data);
117void CALLBACK tessVertexCB2 (const GLvoid * data);
118void CALLBACK tessCombineCB (const GLdouble newVertex[3],
119                             const GLdouble * neighborVertex[4],
120                             const GLfloat neighborWeight[4],
121                             GLdouble ** outData);
122
123static struct graphics_priv *graphics_opengl_new_helper (struct
124                                                         graphics_methods
125                                                         *meth);
126void display (void);
127void resize_callback (int w, int h);
128const char *getPrimitiveType (GLenum type);
129
130static void
131graphics_destroy (struct graphics_priv *gr)
132{
133//printf ("gra destr\n");
134}
135
136/*
137static void
138font_destroy (struct graphics_font_priv *font)
139{
140//printf ("font destr\n");
141}
142*/
143
144/*
145static struct graphics_font_methods font_methods = {
146  font_destroy
147};
148*/
149
150static void
151gc_destroy (struct graphics_gc_priv *gc)
152{
153  g_free (gc);
154}
155
156static void
157gc_set_linewidth (struct graphics_gc_priv *gc, int w)
158{
159  gc->linewidth = w;
160}
161
162static void
163gc_set_dashes (struct graphics_gc_priv *gc, int width, int offset,
164               unsigned char *dash_list, int n)
165{
166  const int cOpenglMaskBits = 16;
167  gc->dash_count = n;
168  int i;
169  if (1 == n)
170    {
171      gc->dash_mask = 0;
172      for (i = 0; i < cOpenglMaskBits; ++i)
173        {
174          gc->dash_mask <<= 1;
175          gc->dash_mask |= (i / n) % 2;
176        }
177    }
178  else if (1 < n)
179    {
180      unsigned char *curr = dash_list;
181      int cnt = 0;              //dot counter
182      int dcnt = 0;             //dash element counter
183      int sum_dash = 0;
184      gc->dash_mask = 0;
185
186      for (i = 0; i < n; ++i)
187        {
188          sum_dash += dash_list[i];
189        }
190
191      //scale dashlist elements to max size
192      if (sum_dash > cOpenglMaskBits)
193        {
194          int num_error[2] = { 0, 0 };  //count elements rounded to 0 for odd(drawn) and even(masked) for compensation
195          double factor = (1.0 * cOpenglMaskBits) / sum_dash;
196          for (i = 0; i < n; ++i)
197            {                   //calculate dashlist max and largest common denomiator for scaling
198              dash_list[i] *= factor;
199              if (dash_list[i] == 0)
200                {
201                  ++dash_list[i];
202                  ++num_error[i % 2];
203                }
204              else if (0 < num_error[i % 2] && 2 < dash_list[i])
205                {
206                  ++dash_list[i];
207                  --num_error[i % 2];
208                }
209            }
210        }
211
212      //calculate mask
213      for (i = 0; i < cOpenglMaskBits; ++i)
214        {
215          gc->dash_mask <<= 1;
216          gc->dash_mask |= 1 - dcnt % 2;
217          ++cnt;
218          if (cnt == *curr)
219            {
220              cnt = 0;
221              ++curr;
222              ++dcnt;
223              if (dcnt == n)
224                {
225                  curr = dash_list;
226                }
227            }
228        }
229    }
230//printf("MASK %XH     %XH\n", gc, gc->dash_mask);
231}
232
233
234static void
235gc_set_foreground (struct graphics_gc_priv *gc, struct color *c)
236{
237  gc->fr = c->r / 65535.0;
238  gc->fg = c->g / 65535.0;
239  gc->fb = c->b / 65535.0;
240  gc->fa = c->a / 65535.0;
241}
242
243static void
244gc_set_background (struct graphics_gc_priv *gc, struct color *c)
245{
246  gc->br = c->r / 65535.0;
247  gc->bg = c->g / 65535.0;
248  gc->bb = c->b / 65535.0;
249  gc->ba = c->a / 65535.0;
250}
251
252static struct graphics_gc_methods gc_methods = {
253  gc_destroy,
254  gc_set_linewidth,
255  gc_set_dashes,
256  gc_set_foreground,
257  gc_set_background
258};
259
260static struct graphics_gc_priv *
261gc_new (struct graphics_priv *gr, struct graphics_gc_methods *meth)
262{
263  struct graphics_gc_priv *gc = g_new (struct graphics_gc_priv, 1);
264
265  *meth = gc_methods;
266  gc->gr = gr;
267  gc->linewidth = 1;
268  return gc;
269}
270
271static struct graphics_image_priv *
272image_new (struct graphics_priv *gr, struct graphics_image_methods *meth,
273           char *path, int *w, int *h, struct point *hot, int rotation)
274{
275  FIBITMAP *image;
276  RGBQUAD aPixel;
277  unsigned char *data;
278  int width, height, i, j;
279
280  if (strlen (path) < 4)
281    {
282      return NULL;
283    }
284  char *ext_str = path + strlen (path) - 3;
285  if (strstr (ext_str, "png") || strstr (path, "PNG"))
286    {
287      if ((image = FreeImage_Load (FIF_PNG, path, 0)) == NULL)
288        {
289          return NULL;
290        }
291    }
292  else if (strstr (ext_str, "xpm") || strstr (path, "XPM"))
293    {
294      if ((image = FreeImage_Load (FIF_XPM, path, 0)) == NULL)
295        {
296          return NULL;
297        }
298    }
299  else if (strstr (ext_str, "svg") || strstr (path, "SVG"))
300    {
301      char path_new[256];
302      snprintf (path_new, strlen (path) - 3, "%s", path);
303      strcat (path_new, "_48_48.png");
304
305      if ((image = FreeImage_Load (FIF_PNG, path_new, 0)) == NULL)
306        {
307          return NULL;
308        }
309    }
310  else
311    {
312      return NULL;
313    }
314  struct graphics_image_priv *gi;
315  gi = g_new0 (struct graphics_image_priv, 1);
316
317  width = FreeImage_GetWidth (image);
318  height = FreeImage_GetHeight (image);
319
320  data =
321    (unsigned char *) malloc (width*height*4);
322
323  RGBQUAD *palette = NULL;
324  if (FreeImage_GetBPP (image) == 8)
325    {
326      palette = FreeImage_GetPalette (image);
327    }
328
329  for (i = 0; i < height; i++)
330    {
331      for (j = 0; j < width; j++)
332        {
333          unsigned char idx;
334          if (FreeImage_GetBPP (image) == 8)
335            {
336              FreeImage_GetPixelIndex (image, j, height - i - 1, &idx);
337              data[4 * width * i + 4 * j + 0] =
338                palette[idx].rgbRed;
339              data[4 * width * i + 4 * j + 1] =
340                palette[idx].rgbGreen;
341              data[4 * width * i + 4 * j + 2] =
342                palette[idx].rgbBlue;
343              data[4 * width * i + 4 * j + 3] = 255;
344            }
345          else if (FreeImage_GetBPP (image) == 16
346                   || FreeImage_GetBPP (image) == 24
347                   || FreeImage_GetBPP (image) == 32)
348            {
349              FreeImage_GetPixelColor (image, j, height - i - 1, &aPixel);
350              int transparent = (aPixel.rgbRed == 0 && aPixel.rgbBlue == 0
351                                 && aPixel.rgbGreen == 0);
352              data[4 * width * i + 4 * j + 0] =
353                transparent ? 0 : (aPixel.rgbRed);
354              data[4 * width * i + 4 * j + 1] =
355                (aPixel.rgbGreen);
356              data[4 * width * i + 4 * j + 2] =
357                transparent ? 0 : (aPixel.rgbBlue);
358              data[4 * width * i + 4 * j + 3] =
359                transparent ? 0 : 255;
360
361            }
362          else if (FreeImage_GetBPP (image) == 64)
363            {
364              //FreeImage_GetPixelColor does not handle 64bits/pixel images correctly
365              return NULL;
366            }
367
368        }
369    }
370
371  FreeImage_Unload (image);
372
373  *w = width;
374  *h = height;
375  gi->w = width;
376  gi->h = height;
377  gi->hot_x = width / 2 - 1;
378  gi->hot_y = height / 2 - 1;
379  hot->x = width / 2 - 1;
380  hot->y = height / 2 - 1;
381  gi->data = data;
382  gi->path = path;
383  return gi;
384}
385
386const char *
387getPrimitiveType (GLenum type)
388{
389  char *ret="";
390
391  switch (type)
392    {
393    case 0x0000:
394      ret = "GL_POINTS";
395      break;
396    case 0x0001:
397      ret = "GL_LINES";
398      break;
399    case 0x0002:
400      ret = "GL_LINE_LOOP";
401      break;
402    case 0x0003:
403      ret = "GL_LINE_STRIP";
404      break;
405    case 0x0004:
406      ret = "GL_TRIANGLES";
407      break;
408    case 0x0005:
409      ret = "GL_TRIANGLE_STRIP";
410      break;
411    case 0x0006:
412      ret = "GL_TRIANGLE_FAN";
413      break;
414    case 0x0007:
415      ret = "GL_QUADS";
416      break;
417    case 0x0008:
418      ret = "GL_QUAD_STRIP";
419      break;
420    case 0x0009:
421      ret = "GL_POLYGON";
422      break;
423    }
424  return ret;
425}
426
427void CALLBACK
428tessBeginCB (GLenum which)
429{
430  glBegin (which);
431
432  dbg (1, "glBegin( %s );\n", getPrimitiveType (which));
433}
434
435
436
437void CALLBACK
438tessEndCB ()
439{
440  glEnd ();
441
442  dbg (1, "glEnd();\n");
443}
444
445
446
447void CALLBACK
448tessVertexCB (const GLvoid * data)
449{
450  // cast back to double type
451  const GLdouble *ptr = (const GLdouble *) data;
452
453  glVertex3dv (ptr);
454
455  dbg (1, "  glVertex3d();\n");
456}
457
458static void
459get_overlay_pos (struct graphics_priv *gr, struct point *point_out)
460{
461  if (gr->parent == NULL)
462    {
463      point_out->x = 0;
464      point_out->y = 0;
465      return;
466    }
467  point_out->x = gr->p.x;
468  if (point_out->x < 0)
469    {
470      point_out->x += gr->parent->width;
471    }
472
473  point_out->y = gr->p.y;
474  if (point_out->y < 0)
475    {
476      point_out->y += gr->parent->height;
477    }
478}
479
480static void
481draw_lines (struct graphics_priv *gr, struct graphics_gc_priv *gc,
482            struct point *p, int count)
483{
484  if (gr->parent && !gr->parent->overlay_enabled)
485    {
486      return;
487    }
488
489  glColor4f (gc->fr, gc->fg, gc->fb, gc->fa);
490  glLineWidth (gc->linewidth);
491  if (!gr->parent && 0 < gc->dash_count)
492    {
493      glLineStipple (1, gc->dash_mask);
494      glEnable (GL_LINE_STIPPLE);
495    }
496  glBegin (GL_LINE_STRIP);
497  int i;
498  for (i = 0; i < count; i++)
499    {
500      struct point p_eff;
501      //get_overlay_pos(gr, &p_eff);
502      p_eff.x = p[i].x;
503      p_eff.y = p[i].y;
504      glVertex2f (p_eff.x, p_eff.y);
505    }
506  glEnd ();
507  if (!gr->parent && 0 < gc->dash_count)
508    {
509      glDisable (GL_LINE_STIPPLE);
510    }
511}
512
513
514static void
515draw_polygon (struct graphics_priv *gr, struct graphics_gc_priv *gc,
516              struct point *p, int count)
517{
518  if (gr->parent && !gr->parent->overlay_enabled)
519    {
520      return;
521    }
522
523
524  int i;
525  GLUtesselator *tess = gluNewTess ();  // create a tessellator
526  if (!tess)
527    return;                     // failed to create tessellation object, return 0
528
529  GLdouble quad1[count][3];
530  for (i = 0; i < count; i++)
531    {
532      quad1[i][0] = (GLdouble) (p[i].x + gr->p.x);
533      quad1[i][1] = (GLdouble) (p[i].y + gr->p.y);
534      quad1[i][2] = 0;
535    }
536
537
538  // register callback functions
539  gluTessCallback (tess, GLU_TESS_BEGIN, (void (*)(void)) tessBeginCB);
540  gluTessCallback (tess, GLU_TESS_END, (void (*)(void)) tessEndCB);
541  //     gluTessCallback(tess, GLU_TESS_ERROR, (void (*)(void))tessErrorCB);
542  gluTessCallback (tess, GLU_TESS_VERTEX, (void (*)(void)) tessVertexCB);
543
544  // tessellate and compile a concave quad into display list
545  // gluTessVertex() takes 3 params: tess object, pointer to vertex coords,
546  // and pointer to vertex data to be passed to vertex callback.
547  // The second param is used only to perform tessellation, and the third
548  // param is the actual vertex data to draw. It is usually same as the second
549  // param, but It can be more than vertex coord, for example, color, normal
550  // and UV coords which are needed for actual drawing.
551  // Here, we are looking at only vertex coods, so the 2nd and 3rd params are
552  // pointing same address.
553  glColor4f (gc->fr, gc->fg, gc->fb, gc->fa);
554  gluTessBeginPolygon (tess, 0);        // with NULL data
555  gluTessBeginContour (tess);
556  for (i = 0; i < count; i++)
557    {
558      gluTessVertex (tess, quad1[i], quad1[i]);
559    }
560  gluTessEndContour (tess);
561  gluTessEndPolygon (tess);
562
563  gluDeleteTess (tess);         // delete after tessellation
564}
565
566static void
567draw_rectangle (struct graphics_priv *gr, struct graphics_gc_priv *gc,
568                struct point *p, int w, int h)
569{
570  if (gr->parent && !gr->parent->overlay_enabled)
571    {
572      return;
573    }
574
575  struct point p_eff;
576  p_eff.x = p->x;
577  p_eff.y = p->y;
578
579  glColor4f (gc->fr, gc->fg, gc->fb, gc->fa);
580  glBegin (GL_POLYGON);
581  glVertex2f (p_eff.x, p_eff.y);
582  glVertex2f (p_eff.x + w, p_eff.y);
583  glVertex2f (p_eff.x + w, p_eff.y + h);
584  glVertex2f (p_eff.x, p_eff.y + h);
585  glEnd ();
586}
587
588static void
589draw_circle (struct graphics_priv *gr, struct graphics_gc_priv *gc,
590             struct point *p, int r)
591{
592
593  if (gr->parent && !gr->parent->overlay_enabled)
594    {
595      return;
596    }
597  /* FIXME: does not quite match gtk */
598  /* hack for osd compass.. why is this needed!? */
599  if (gr->parent)
600    {
601      r = r / 2;
602    }
603
604  struct point p_eff;
605  p_eff.x = p->x;
606  p_eff.y = p->y;
607
608  GLint circle_points = 7 + r / 5;
609  glColor4f (gc->fr, gc->fg, gc->fb, gc->fa);
610  glLineWidth (gc->linewidth * 2);
611  //glBegin (GL_POLYGON);
612  glBegin (GL_LINE_LOOP);
613  int i;
614  for (i = 0; i < circle_points; ++i)
615    {
616      double angle = 2 * M_PI * i / circle_points;
617      glVertex2f (r * cos (angle) + p_eff.x, r * sin (angle) + p_eff.y);
618    }
619  glEnd ();
620}
621
622static void
623display_text_draw (struct font_freetype_text *text, struct graphics_priv *gr,
624                   struct graphics_gc_priv *fg, struct graphics_gc_priv *bg,
625                   int color, struct point *p)
626{
627  int i, x, y, stride;
628  struct font_freetype_glyph *g, **gp;
629  unsigned char *shadow, *glyph;
630  struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
631  struct color black =
632    { fg->fr * 65535, fg->fg * 65535, fg->fb * 65535, fg->fa * 65535 };
633  struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
634
635  if(bg) {
636    white.r = bg->fr;
637    white.g = bg->fg;
638    white.b = bg->fb;
639    white.a = bg->fa;
640  }
641 
642  gp = text->glyph;
643  i = text->glyph_count;
644  x = p->x << 6;
645  y = p->y << 6;
646  while (i-- > 0)
647    {
648      g = *gp++;
649      if (g->w && g->h && bg)
650        {
651          stride = (g->w + 2) * 4;
652          //shadow = g_malloc (stride * (g->h + 2));
653          if (color)
654            {
655              shadow = g_malloc (stride * (g->h + 2));
656              gr->freetype_methods.get_shadow (g, shadow, 32, stride, &white,
657                                               &transparent);
658              glPixelZoom (1.0, -1.0);
659              glRasterPos2d ((x + g->x) >> 6 , (y + g->y) >> 6 );
660              glDrawPixels (g->w+2, g->h+2, GL_BGRA, GL_UNSIGNED_BYTE, shadow);
661              g_free (shadow);
662            }
663        }
664      x += g->dx;
665      y += g->dy;
666    }
667
668  x = p->x << 6;
669  y = p->y << 6;
670  gp = text->glyph;
671  i = text->glyph_count;
672  while (i-- > 0)
673    {
674      g = *gp++;
675      if (g->w && g->h)
676        {
677          if (color)
678            {
679              stride = g->w;
680              if (bg)
681                {
682                  glyph = g_malloc (stride * g->h * 4);
683                  gr->freetype_methods.get_glyph (g, glyph, 24, stride * 4,
684                                                  &black, &white,
685                                                  &white);
686                  g_free (glyph);
687                }
688              stride *= 4;
689              glyph = g_malloc (stride * g->h);
690              gr->freetype_methods.get_glyph (g, glyph, 32, stride, &black,
691                                              &white, &transparent);
692
693              glPixelZoom (1.0, -1.0);
694              glRasterPos2d ((x + g->x) >> 6, (y + g->y) >> 6);
695              glDrawPixels (g->w, g->h, GL_BGRA, GL_UNSIGNED_BYTE, glyph);
696              g_free (glyph);
697            }
698        }
699      x += g->dx;
700      y += g->dy;
701    }
702
703
704}
705
706static void
707draw_text (struct graphics_priv *gr, struct graphics_gc_priv *fg,
708           struct graphics_gc_priv *bg, struct graphics_font_priv *font,
709           char *text, struct point *p, int dx, int dy)
710{
711  if (gr->parent && !gr->parent->overlay_enabled)
712    {
713      return;
714    }
715
716  struct font_freetype_text *t;
717  int color = 1;
718
719  if (!font)
720    {
721      dbg (0, "no font, returning\n");
722      return;
723    }
724  t =
725    gr->freetype_methods.text_new (text, (struct font_freetype_font *) font,
726                                   dx, dy);
727
728  struct point p_eff;
729  p_eff.x = p->x;
730  p_eff.y = p->y;
731
732  display_text_draw (t, gr, fg, bg, color, &p_eff);
733  gr->freetype_methods.text_destroy (t);
734}
735
736
737static void
738draw_image (struct graphics_priv *gr, struct graphics_gc_priv *fg,
739            struct point *p, struct graphics_image_priv *img)
740{
741  if (gr->parent && !gr->parent->overlay_enabled)
742    {
743      return;
744    }
745
746  if (!img || !img->data)
747    {
748      return;
749    }
750
751  struct point p_eff;
752  p_eff.x = p->x + img->hot_x;
753  p_eff.y = p->y + img->hot_y;
754
755  glColor4f (1.0, 1.0, 1.0, 1.0);
756
757  GLuint texture;
758  glGenTextures (1, &texture);
759  glBindTexture (GL_TEXTURE_2D, texture);
760
761  glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
762  glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
763
764  // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
765  // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
766  glTexImage2D (GL_TEXTURE_2D, 0, 4, img->w, img->h, 0, GL_RGBA,
767                GL_UNSIGNED_BYTE, img->data);
768
769  glEnable (GL_TEXTURE_2D);
770  glDisable (GL_LIGHTING);
771
772  glEnable (GL_BLEND);
773  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
774
775  glBegin (GL_QUADS);
776  glTexCoord2d (0, 0);
777  glVertex2d (p_eff.x - img->hot_x, p_eff.y - img->hot_y);
778
779  glTexCoord2d (1.0, 0);
780  glVertex2d (img->w + p_eff.x - img->hot_x, p_eff.y - img->hot_y);
781
782  glTexCoord2d (1.0, 1.0);
783  glVertex2d (img->w + p_eff.x - img->hot_x, img->h + p_eff.y - img->hot_y);
784
785  glTexCoord2d (0, 1.0);
786  glVertex2d (p_eff.x - img->hot_x, img->h + p_eff.y - img->hot_y);
787
788  glEnd ();
789  glDisable (GL_TEXTURE_2D);
790
791  glDeleteTextures (1, &texture);
792
793#if 0
794//pixel by pixel image output
795  int x, y;
796  for (y = 0; y < img->h; ++y)
797    {
798      for (x = 0; x < img->w; ++x)
799        {
800          glColor3f (img->data[4 * y * img->w + 4 * x + 0] / 255.0,
801                     img->data[4 * y * img->w + 4 * x + 1] / 255.0,
802                     img->data[4 * y * img->w + 4 * x + 2] / 255.0);
803          glBegin (GL_POINTS);
804          glVertex2f (p->x - img->hot_x + x, p->y - img->hot_y + y);
805          glEnd ();
806        }
807    }
808#endif
809}
810
811static void
812draw_image_warp (struct graphics_priv *gr, struct graphics_gc_priv *fg,
813                 struct point *p, int count, char *data)
814{
815}
816
817static void
818draw_restore (struct graphics_priv *gr, struct point *p, int w, int h)
819{
820//  printf ("darw_restore %X  %d %d %d %d\n", gr, p->x, p->y, w, h);
821}
822
823static void
824draw_drag (struct graphics_priv *gr, struct point *p)
825{
826
827  if (p)
828    {
829      gr->p.x = p->x;
830      gr->p.y = p->y;
831    }
832}
833
834static void
835background_gc (struct graphics_priv *gr, struct graphics_gc_priv *gc)
836{
837  gr->background_gc = gc;
838}
839
840static void
841redraw_screen (struct graphics_priv *gr)
842{
843  glCallList (gr->DLid);
844  //display overlays display list
845  struct graphics_priv *overlay;
846  overlay = gr->overlays;
847  while (gr->overlay_enabled && overlay)
848    {
849      glPushMatrix ();
850      struct point p_eff;
851      get_overlay_pos (overlay, &p_eff);
852      glTranslatef (p_eff.x, p_eff.y, 1);
853      glCallList (overlay->DLid);
854      glPopMatrix ();
855      overlay = overlay->next;
856    }
857  glutSwapBuffers ();
858}
859
860
861static void
862draw_mode (struct graphics_priv *gr, enum draw_mode_num mode)
863{
864
865
866  if (gr->parent)
867    {                           //overlay
868      if (mode == draw_mode_begin)
869        {
870          glNewList (gr->DLid, GL_COMPILE);
871        }
872
873      if (mode == draw_mode_end || mode == draw_mode_end_lazy)
874        {
875          glEndList ();
876          redraw_screen (gr->parent);
877        }
878    }
879  else
880    {                           //root graphics
881      if (mode == draw_mode_begin)
882        {
883          glNewList (gr->DLid, GL_COMPILE);
884        }
885
886      if (mode == draw_mode_end)
887        {
888          glEndList ();
889          redraw_screen (gr);
890        }
891    }
892    gr->mode = mode;
893}
894
895static struct graphics_priv *overlay_new (struct graphics_priv *gr,
896                                          struct graphics_methods *meth,
897                                          struct point *p, int w, int h,
898                                          int alpha, int wraparound);
899
900static int
901graphics_opengl_fullscreen(struct window *w, int on)
902{
903        return 1;
904}               
905
906static void
907graphics_opengl_disable_suspend(struct window *w)
908{
909}
910
911
912static void *
913get_data (struct graphics_priv *this, char *type)
914{
915  /*TODO initialize gtkglext context then type=="gtk_widget" */
916
917
918        if(strcmp(type, "window") == 0) {
919                struct window *win;
920                win=g_new(struct window, 1);
921                win->priv=this;
922                win->fullscreen=graphics_opengl_fullscreen;
923                win->disable_suspend=graphics_opengl_disable_suspend;
924                return win;
925        } else {
926                return &this->DLid;
927        }
928
929
930}
931
932static void
933image_free (struct graphics_priv *gr, struct graphics_image_priv *priv)
934{
935}
936
937static void
938overlay_disable (struct graphics_priv *gr, int disable)
939{
940  gr->overlay_enabled = !disable;
941}
942
943static void
944overlay_resize (struct graphics_priv *gr, struct point *p, int w, int h,
945                int alpha, int wraparound)
946{
947  int changed = 0;
948  int w2, h2;
949
950  if (w == 0)
951    {
952      w2 = 1;
953    }
954  else
955    {
956      w2 = w;
957    }
958
959  if (h == 0)
960    {
961      h2 = 1;
962    }
963  else
964    {
965      h2 = h;
966    }
967
968  gr->p = *p;
969  if (gr->width != w2)
970    {
971      gr->width = w2;
972      changed = 1;
973    }
974
975  if (gr->height != h2)
976    {
977      gr->height = h2;
978      changed = 1;
979    }
980
981  gr->wraparound = wraparound;
982
983  if (changed)
984    {
985      if ((w == 0) || (h == 0))
986        {
987          gr->overlay_autodisabled = 1;
988        }
989      else
990        {
991          gr->overlay_autodisabled = 0;
992        }
993
994      callback_list_call_attr_2 (gr->cbl, attr_resize,
995                                 GINT_TO_POINTER (gr->width),
996                                 GINT_TO_POINTER (gr->height));
997    }
998}
999
1000static struct graphics_methods graphics_methods = {
1001  graphics_destroy,
1002  draw_mode,
1003  draw_lines,
1004  draw_polygon,
1005  draw_rectangle,
1006  draw_circle,
1007  draw_text,
1008  draw_image,
1009  draw_image_warp,
1010  draw_restore,
1011  draw_drag,
1012  NULL,
1013  gc_new,
1014  background_gc,
1015  overlay_new,
1016  image_new,
1017  get_data,
1018  image_free,
1019  NULL,
1020  overlay_disable,
1021  overlay_resize,
1022};
1023
1024static struct graphics_priv *
1025graphics_opengl_new_helper (struct graphics_methods *meth)
1026{
1027  struct font_priv *(*font_freetype_new) (void *meth);
1028  font_freetype_new = plugin_get_font_type ("freetype");
1029
1030  if (!font_freetype_new)
1031    {
1032      return NULL;
1033    }
1034
1035  struct graphics_priv *this = g_new0 (struct graphics_priv, 1);
1036
1037  font_freetype_new (&this->freetype_methods);
1038  *meth = graphics_methods;
1039
1040  meth->font_new =
1041    (struct graphics_font_priv *
1042     (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1043         int)) this->freetype_methods.font_new;
1044  meth->get_text_bbox = this->freetype_methods.get_text_bbox;
1045
1046  return this;
1047}
1048
1049static struct graphics_priv *
1050overlay_new (struct graphics_priv *gr, struct graphics_methods *meth,
1051             struct point *p, int w, int h, int alpha, int wraparound)
1052{
1053  int w2, h2;
1054  struct graphics_priv *this = graphics_opengl_new_helper (meth);
1055  this->p = *p;
1056  this->width = w;
1057  this->height = h;
1058  this->parent = gr;
1059
1060  /* If either height or width is 0, we set it to 1 to avoid warnings, and
1061   * disable the overlay. */
1062  if (h == 0)
1063    {
1064      h2 = 1;
1065    }
1066  else
1067    {
1068      h2 = h;
1069    }
1070
1071  if (w == 0)
1072    {
1073      w2 = 1;
1074    }
1075  else
1076    {
1077      w2 = w;
1078    }
1079
1080  if ((w == 0) || (h == 0))
1081    {
1082      this->overlay_autodisabled = 1;
1083    }
1084  else
1085    {
1086      this->overlay_autodisabled = 0;
1087    }
1088  this->overlay_enabled = 1;
1089  this->overlay_autodisabled = 0;
1090
1091  this->next = gr->overlays;
1092  gr->overlays = this;
1093  this->DLid = glGenLists (1);
1094  return this;
1095}
1096
1097
1098static void
1099click_notify (int button, int state, int x, int y)
1100{
1101  if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
1102    {
1103      struct point p;
1104      p.x = x;
1105      p.y = y;
1106      callback_list_call_attr_3 (graphics_priv_root->cbl, attr_button,
1107                                 (void *) 0, 1, (void *) &p);
1108    }
1109  else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
1110    {
1111      struct point p;
1112      p.x = x;
1113      p.y = y;
1114      callback_list_call_attr_3 (graphics_priv_root->cbl, attr_button,
1115                                 (void *) 1, 1, (void *) &p);
1116    }
1117}
1118
1119static void
1120motion_notify (int x, int y)
1121{
1122  struct point p;
1123  p.x = x;
1124  p.y = y;
1125  callback_list_call_attr_1 (graphics_priv_root->cbl, attr_motion,
1126                             (void *) &p);
1127  return;
1128}
1129
1130static gboolean
1131graphics_opengl_idle (void *data)
1132{
1133  static int opengl_init_ok = 0;
1134  if (!opengl_init_ok)
1135    {
1136      callback_list_call_attr_2 (graphics_priv_root->cbl, attr_resize,
1137                                 GINT_TO_POINTER (graphics_priv_root->width),
1138                                 GINT_TO_POINTER
1139                                 (graphics_priv_root->height));
1140      opengl_init_ok = 1;
1141    }
1142  else
1143    {
1144      glutMainLoopEvent ();
1145    }
1146  return TRUE;
1147}
1148
1149static void
1150ProcessNormalKeys (unsigned char key_in, int x, int y)
1151{
1152  int key = 0;
1153  char keybuf[2];
1154
1155  switch (key_in)
1156    {
1157    case 13:
1158      key = NAVIT_KEY_RETURN;
1159      break;
1160    default:
1161      key = key_in;
1162      break;
1163    }
1164  keybuf[0] = key;
1165  keybuf[1] = '\0';
1166  callback_list_call_attr_1 (graphics_priv_root->cbl, attr_keypress,
1167                             (void *) keybuf);
1168}
1169
1170static void
1171ProcessSpecialKeys (int key_in, int x, int y)
1172{
1173  int key = 0;
1174  char keybuf[2];
1175
1176  switch (key_in)
1177    {
1178    case 102:
1179      key = NAVIT_KEY_RIGHT;
1180      break;
1181    case 100:
1182      key = NAVIT_KEY_LEFT;
1183      break;
1184    case 103:
1185      key = NAVIT_KEY_DOWN;
1186      break;
1187    case 101:
1188      key = NAVIT_KEY_UP;
1189      break;
1190    case 104:
1191      key = NAVIT_KEY_ZOOM_OUT;
1192      break;
1193    case 105:
1194      key = NAVIT_KEY_ZOOM_IN;
1195      break;
1196    default:
1197      break;
1198    }                           //switch
1199
1200  keybuf[0] = key;
1201  keybuf[1] = '\0';
1202  callback_list_call_attr_1 (graphics_priv_root->cbl, attr_keypress,
1203                             (void *) keybuf);
1204}
1205
1206void
1207resize_callback (int w, int h)
1208{
1209  glViewport (0, 0, w, h);
1210  glMatrixMode (GL_PROJECTION);
1211  glLoadIdentity ();
1212  gluOrtho2D (0.0, w, h, 0.0);
1213
1214  graphics_priv_root->width = w;
1215  graphics_priv_root->height = h;
1216
1217  callback_list_call_attr_2 (graphics_priv_root->cbl, attr_resize,
1218                             GINT_TO_POINTER (w), GINT_TO_POINTER (h));
1219}
1220
1221void
1222display (void)
1223{
1224  resize_callback (graphics_priv_root->width, graphics_priv_root->height);
1225}
1226
1227
1228static struct graphics_priv *
1229graphics_opengl_new (struct navit *nav, struct graphics_methods *meth,
1230                     struct attr **attrs, struct callback_list *cbl)
1231{
1232  struct attr *attr;
1233
1234  if (!event_request_system ("glib", "graphics_opengl_new"))
1235    return NULL;
1236
1237  struct graphics_priv *this = graphics_opengl_new_helper (meth);
1238  graphics_priv_root = this;
1239
1240  this->nav = nav;
1241  this->parent = NULL;
1242  this->overlay_enabled = 1;
1243
1244  this->width = SCREEN_WIDTH;
1245  if ((attr = attr_search (attrs, NULL, attr_w)))
1246    this->width = attr->u.num;
1247  this->height = SCREEN_HEIGHT;
1248  if ((attr = attr_search (attrs, NULL, attr_h)))
1249    this->height = attr->u.num;
1250  this->timeout = 100;
1251  if ((attr = attr_search (attrs, NULL, attr_timeout)))
1252    this->timeout = attr->u.num;
1253  this->delay = 0;
1254  if ((attr = attr_search (attrs, NULL, attr_delay)))
1255    this->delay = attr->u.num;
1256  this->cbl = cbl;
1257
1258  char *cmdline = "";
1259  int argc = 0;
1260  glutInit (&argc, &cmdline);
1261  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
1262
1263  glutInitWindowSize (this->width, this->height);
1264  glutInitWindowPosition (0, 0);
1265  glutCreateWindow ("Navit opengl window");
1266
1267  glutDisplayFunc (display);
1268  glutReshapeFunc (resize_callback);
1269  resize_callback (this->width, this->height);
1270
1271  graphics_priv_root->cbl = cbl;
1272  graphics_priv_root->width = this->width;
1273  graphics_priv_root->height = this->height;
1274
1275  glutMotionFunc (motion_notify);
1276  glutPassiveMotionFunc (motion_notify);
1277  glutMouseFunc (click_notify);
1278  glutKeyboardFunc (ProcessNormalKeys);
1279  glutSpecialFunc (ProcessSpecialKeys);
1280
1281  g_timeout_add (G_PRIORITY_DEFAULT + 10, graphics_opengl_idle, NULL);
1282
1283  this->DLid = glGenLists (1);
1284
1285  return this;
1286}
1287
1288
1289static void
1290event_opengl_main_loop_run (void)
1291{
1292  dbg (0, "enter\n");
1293}
1294
1295static void
1296event_opengl_main_loop_quit (void)
1297{
1298  dbg (0, "enter\n");
1299}
1300
1301static struct event_watch *
1302event_opengl_add_watch (void *h, enum event_watch_cond cond,
1303                        struct callback *cb)
1304{
1305  dbg (0, "enter\n");
1306  return NULL;
1307}
1308
1309static void
1310event_opengl_remove_watch (struct event_watch *ev)
1311{
1312  dbg (0, "enter\n");
1313}
1314
1315
1316static struct event_timeout *
1317event_opengl_add_timeout (int timeout, int multi, struct callback *cb)
1318{
1319  dbg (0, "enter\n");
1320  return NULL;
1321}
1322
1323static void
1324event_opengl_remove_timeout (struct event_timeout *to)
1325{
1326  dbg (0, "enter\n");
1327}
1328
1329
1330static struct event_idle *
1331event_opengl_add_idle (int priority, struct callback *cb)
1332{
1333  dbg (0, "enter\n");
1334  return NULL;
1335}
1336
1337static void
1338event_opengl_remove_idle (struct event_idle *ev)
1339{
1340  dbg (0, "enter\n");
1341}
1342
1343static void
1344event_opengl_call_callback (struct callback_list *cb)
1345{
1346  dbg (0, "enter\n");
1347}
1348
1349static struct event_methods event_opengl_methods = {
1350  event_opengl_main_loop_run,
1351  event_opengl_main_loop_quit,
1352  event_opengl_add_watch,
1353  event_opengl_remove_watch,
1354  event_opengl_add_timeout,
1355  event_opengl_remove_timeout,
1356  event_opengl_add_idle,
1357  event_opengl_remove_idle,
1358  event_opengl_call_callback,
1359};
1360
1361static struct event_priv *
1362event_opengl_new (struct event_methods *meth)
1363{
1364  *meth = event_opengl_methods;
1365  return NULL;
1366}
1367
1368void
1369plugin_init (void)
1370{
1371  plugin_register_graphics_type ("opengl", graphics_opengl_new);
1372  plugin_register_event_type ("opengl", event_opengl_new);
1373}