home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 February / CMCD0205.ISO / Linux / gimp-2.2.0.tar.gz / gimp-2.2.0.tar / gimp-2.2.0 / plug-ins / MapObject / mapobject_preview.c < prev    next >
C/C++ Source or Header  |  2004-09-22  |  26KB  |  989 lines

  1. /*************************************************/
  2. /* Compute a preview image and preview wireframe */
  3. /*************************************************/
  4.  
  5. #include "config.h"
  6.  
  7. #include <gtk/gtk.h>
  8.  
  9. #include <libgimp/gimp.h>
  10.  
  11. #include "mapobject_main.h"
  12. #include "mapobject_ui.h"
  13. #include "mapobject_image.h"
  14. #include "mapobject_apply.h"
  15. #include "mapobject_shade.h"
  16. #include "mapobject_preview.h"
  17.  
  18. line    linetab[WIRESIZE*2+8];
  19. gdouble mat[3][4];
  20.  
  21. gint       lightx, lighty;
  22. BackBuffer backbuf = { 0, 0, 0, 0, NULL };
  23.  
  24. /* Protos */
  25. /* ====== */
  26.  
  27. static void draw_light_marker       (gint        xpos,
  28.                      gint        ypos);
  29. static void clear_light_marker      (void);
  30.  
  31. static gint draw_line               (gint        n,
  32.                      gint        startx,
  33.                      gint        starty,
  34.                      gint        pw,
  35.                      gint        ph,
  36.                      gdouble     cx1,
  37.                      gdouble     cy1,
  38.                      gdouble     cx2,
  39.                      gdouble     cy2,
  40.                      GimpVector3 a,
  41.                      GimpVector3 b);
  42.  
  43. static void draw_wireframe_plane    (gint        startx,
  44.                      gint        starty,
  45.                      gint        pw,
  46.                      gint        ph);
  47. static void draw_wireframe_sphere   (gint        startx,
  48.                      gint        starty,
  49.                      gint        pw,
  50.                      gint        ph);
  51. static void draw_wireframe_box      (gint        startx,
  52.                      gint        starty,
  53.                      gint        pw,
  54.                      gint        ph);
  55. static void draw_wireframe_cylinder (gint        startx,
  56.                      gint        starty,
  57.                      gint        pw,
  58.                      gint        ph);
  59.  
  60. /*************************************************/
  61. /* Quick and dirty (and slow) line clip routine. */
  62. /* The function returns FALSE if the line isn't  */
  63. /* visible according to the limits given.        */
  64. /*************************************************/
  65.  
  66. static gboolean
  67. clip_line (gdouble *x1,
  68.        gdouble *y1,
  69.        gdouble *x2,
  70.        gdouble *y2,
  71.        gdouble  minx,
  72.        gdouble  miny,
  73.        gdouble  maxx,
  74.        gdouble  maxy)
  75. {
  76.   gdouble tmp;
  77.  
  78.   g_assert (x1 != NULL);
  79.   g_assert (y1 != NULL);
  80.   g_assert (x2 != NULL);
  81.   g_assert (y2 != NULL);
  82.  
  83.   /* First, check if line is visible at all */
  84.   /* ====================================== */
  85.  
  86.   if (*x1 < minx && *x2 < minx) return FALSE;
  87.   if (*x1 > maxx && *x2 > maxx) return FALSE;
  88.   if (*y1 < miny && *y2 < miny) return FALSE;
  89.   if (*y1 > maxy && *y2 > maxy) return FALSE;
  90.  
  91.   /* Check for intersection with the four edges. Sort on x first. */
  92.   /* ============================================================ */
  93.  
  94.   if (*x2 < *x1)
  95.     {
  96.       tmp = *x1;
  97.       *x1 = *x2;
  98.       *x2 = tmp;
  99.       tmp = *y1;
  100.       *y1 = *y2;
  101.       *y2 = tmp;
  102.     }
  103.  
  104.   if (*x1 < minx)
  105.     {
  106.       if (*y1 < *y2) *y1 = *y1 + (minx - *x1) * ((*y2 - *y1) / (*x2 - *x1));
  107.       else           *y1 = *y1 - (minx - *x1) * ((*y1 - *y2) / (*x2 - *x1));
  108.  
  109.       *x1 = minx;
  110.     }
  111.  
  112.   if (*x2 > maxx)
  113.     {
  114.       if (*y1 < *y2) *y2 = *y2 - (*x2 - maxx) * ((*y2 - *y1) / (*x2 - *x1));
  115.       else           *y2 = *y2 + (*x2 - maxx) * ((*y1 - *y2) / (*x2 - *x1));
  116.  
  117.       *x2 = maxx;
  118.     }
  119.  
  120.   if (*y1 < miny)
  121.     {
  122.       *x1 = *x1 + (miny - *y1) * ((*x2 - *x1) / (*y2 - *y1));
  123.       *y1 = miny;
  124.     }
  125.  
  126.   if (*y2 < miny)
  127.     {
  128.       *x2 = *x2 - (miny - *y2) * ((*x2 - *x1) / (*y1 - *y2));
  129.       *y2 = miny;
  130.     }
  131.  
  132.   if (*y1 > maxy)
  133.     {
  134.       *x1 = *x1 + (*y1 - maxy) * ((*x2 - *x1) / (*y1 - *y2));
  135.       *y1 = maxy;
  136.     }
  137.  
  138.   if (*y2 > maxy)
  139.     {
  140.       *x2 = *x2 - (*y2 - maxy) * ((*x2 - *x1) / (*y2 - *y1));
  141.       *y2 = maxy;
  142.     }
  143.  
  144.   return TRUE;
  145. }
  146.  
  147. /**************************************************************/
  148. /* Computes a preview of the rectangle starting at (x,y) with */
  149. /* dimensions (w,h), placing the result in preview_RGB_data.  */
  150. /**************************************************************/
  151.  
  152. void
  153. compute_preview (gint x,
  154.          gint y,
  155.          gint w,
  156.          gint h,
  157.          gint pw,
  158.          gint ph)
  159. {
  160.   gdouble      xpostab[PREVIEW_WIDTH];
  161.   gdouble      ypostab[PREVIEW_HEIGHT];
  162.   gdouble      realw;
  163.   gdouble      realh;
  164.   GimpVector3  p1, p2;
  165.   GimpRGB      color;
  166.   GimpRGB      lightcheck, darkcheck;
  167.   gint         xcnt, ycnt, f1, f2;
  168.   glong        index = 0;
  169.  
  170.   init_compute ();
  171.  
  172.   p1 = int_to_pos (x, y);
  173.   p2 = int_to_pos (x + w, y + h);
  174.  
  175.   /* First, compute the linear mapping (x,y,x+w,y+h) to (0,0,pw,ph) */
  176.   /* ============================================================== */
  177.  
  178.   realw = (p2.x - p1.x);
  179.   realh = (p2.y - p1.y);
  180.  
  181.   for (xcnt = 0; xcnt < pw; xcnt++)
  182.     xpostab[xcnt] = p1.x + realw * ((gdouble) xcnt / (gdouble) pw);
  183.  
  184.   for (ycnt = 0; ycnt < ph; ycnt++)
  185.     ypostab[ycnt] = p1.y + realh * ((gdouble) ycnt / (gdouble) ph);
  186.  
  187.   /* Compute preview using the offset tables */
  188.   /* ======================================= */
  189.  
  190.   if (mapvals.transparent_background == TRUE)
  191.     {
  192.       gimp_rgba_set (&background, 0.0, 0.0, 0.0, 0.0);
  193.     }
  194.   else
  195.     {
  196.       gimp_context_get_background (&background);
  197.       gimp_rgb_set_alpha (&background, 1.0);
  198.     }
  199.  
  200.   gimp_rgba_set (&lightcheck,
  201.          GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, 1.0);
  202.   gimp_rgba_set (&darkcheck,
  203.          GIMP_CHECK_DARK, GIMP_CHECK_DARK, GIMP_CHECK_DARK, 1.0);
  204.   gimp_vector3_set (&p2, -1.0, -1.0, 0.0);
  205.  
  206.   for (ycnt = 0; ycnt < ph; ycnt++)
  207.     {
  208.       for (xcnt = 0; xcnt < pw; xcnt++)
  209.         {
  210.           p1.x = xpostab[xcnt];
  211.           p1.y = ypostab[ycnt];
  212.  
  213.           p2 = p1;
  214.           color = (* get_ray_color) (&p1);
  215.  
  216.           if (color.a < 1.0)
  217.             {
  218.               f1 = ((xcnt % 32) < 16);
  219.               f2 = ((ycnt % 32) < 16);
  220.               f1 = f1 ^ f2;
  221.  
  222.               if (f1)
  223.                 {
  224.                   if (color.a == 0.0)
  225.             color = lightcheck;
  226.                   else
  227.             gimp_rgb_composite (&color, &lightcheck,
  228.                     GIMP_RGB_COMPOSITE_BEHIND);
  229.                  }
  230.               else
  231.                 {
  232.                   if (color.a == 0.0)
  233.             color = darkcheck;
  234.                   else
  235.             gimp_rgb_composite (&color, &darkcheck,
  236.                     GIMP_RGB_COMPOSITE_BEHIND);
  237.                 }
  238.             }
  239.  
  240.       gimp_rgb_get_uchar (&color,
  241.                   preview_rgb_data + index,
  242.                   preview_rgb_data + index + 1,
  243.                   preview_rgb_data + index + 2);
  244.       index += 3;
  245.         }
  246.     }
  247. }
  248.  
  249. /*************************************************/
  250. /* Check if the given position is within the     */
  251. /* light marker. Return TRUE if so, FALSE if not */
  252. /*************************************************/
  253.  
  254. gint
  255. check_light_hit (gint xpos,
  256.          gint ypos)
  257. {
  258.   gdouble dx, dy, r;
  259.  
  260.   if (mapvals.lightsource.type == POINT_LIGHT)
  261.     {
  262.       dx = (gdouble) lightx - xpos;
  263.       dy = (gdouble) lighty - ypos;
  264.       r  = sqrt (dx * dx + dy * dy) + 0.5;
  265.  
  266.       if ((gint) r > 7)
  267.         return FALSE;
  268.       else
  269.         return TRUE;
  270.     }
  271.  
  272.   return FALSE;
  273. }
  274.  
  275. /****************************************/
  276. /* Draw a marker to show light position */
  277. /****************************************/
  278.  
  279. static void
  280. draw_light_marker (gint xpos,
  281.            gint ypos)
  282. {
  283.   GdkColor  color;
  284.  
  285.   color.red   = 0x0;
  286.   color.green = 0x0;
  287.   color.blue  = 0x0;
  288.   gdk_gc_set_rgb_bg_color (gc, &color);
  289.  
  290.   color.red   = 0x0;
  291.   color.green = 0x4000;
  292.   color.blue  = 0xFFFF;
  293.   gdk_gc_set_rgb_fg_color (gc, &color);
  294.  
  295.   gdk_gc_set_function (gc, GDK_COPY);
  296.  
  297.   if (mapvals.lightsource.type == POINT_LIGHT)
  298.     {
  299.       lightx = xpos;
  300.       lighty = ypos;
  301.  
  302.       /* Save background */
  303.       /* =============== */
  304.  
  305.       backbuf.x = lightx - 7;
  306.       backbuf.y = lighty - 7;
  307.       backbuf.w = 14;
  308.       backbuf.h = 14;
  309.  
  310.       /* X doesn't like images that's outside a window, make sure */
  311.       /* we get the backbuffer image from within the boundaries   */
  312.       /* ======================================================== */
  313.  
  314.       if (backbuf.x < 0)
  315.         backbuf.x = 0;
  316.       else if ((backbuf.x + backbuf.w) > PREVIEW_WIDTH)
  317.         backbuf.w = (PREVIEW_WIDTH - backbuf.x);
  318.       if (backbuf.y < 0)
  319.         backbuf.y = 0;
  320.       else if ((backbuf.y + backbuf.h) > PREVIEW_HEIGHT)
  321.         backbuf.h = (PREVIEW_WIDTH - backbuf.y);
  322.  
  323.       backbuf.image = gdk_drawable_get_image (previewarea->window,
  324.                                               backbuf.x, backbuf.y,
  325.                                               backbuf.w, backbuf.h);
  326.  
  327.       gdk_draw_arc (previewarea->window, gc,
  328.             TRUE,
  329.             lightx - 7, lighty - 7, 14, 14,
  330.             0, 360 * 64);
  331.     }
  332. }
  333.  
  334. static void
  335. clear_light_marker (void)
  336. {
  337.   /* Restore background if it has been saved */
  338.   /* ======================================= */
  339.  
  340.   if (backbuf.image != NULL)
  341.     {
  342.       GdkColor  color;
  343.  
  344.       color.red   = 0x0;
  345.       color.green = 0x0;
  346.       color.blue  = 0x0;
  347.       gdk_gc_set_rgb_bg_color (gc, &color);
  348.  
  349.       color.red   = 0xFFFF;
  350.       color.green = 0xFFFF;
  351.       color.blue  = 0xFFFF;
  352.       gdk_gc_set_rgb_fg_color (gc, &color);
  353.  
  354.       gdk_gc_set_function (gc, GDK_COPY);
  355.  
  356.       gdk_draw_image (previewarea->window, gc,
  357.               backbuf.image,
  358.               0, 0,
  359.               backbuf.x, backbuf.y,
  360.               backbuf.w, backbuf.h);
  361.  
  362.       g_object_unref (backbuf.image);
  363.       backbuf.image = NULL;
  364.     }
  365. }
  366.  
  367. static void
  368. draw_lights (gint startx,
  369.          gint starty,
  370.          gint pw,
  371.          gint ph)
  372. {
  373.   gdouble dxpos, dypos;
  374.   gint    xpos, ypos;
  375.  
  376.   clear_light_marker ();
  377.  
  378.   gimp_vector_3d_to_2d (startx, starty, pw, ph,
  379.             &dxpos, &dypos, &mapvals.viewpoint,
  380.             &mapvals.lightsource.position);
  381.   xpos = RINT (dxpos);
  382.   ypos = RINT (dypos);
  383.  
  384.   if (xpos >= 0 && xpos <= PREVIEW_WIDTH &&
  385.       ypos >= 0 && ypos <= PREVIEW_HEIGHT)
  386.     draw_light_marker (xpos, ypos);
  387. }
  388.  
  389. /*************************************************/
  390. /* Update light position given new screen coords */
  391. /*************************************************/
  392.  
  393. void
  394. update_light (gint xpos,
  395.           gint ypos)
  396. {
  397.   gint startx, starty, pw, ph;
  398.  
  399.   pw     = PREVIEW_WIDTH  >> mapvals.preview_zoom_factor;
  400.   ph     = PREVIEW_HEIGHT >> mapvals.preview_zoom_factor;
  401.   startx = (PREVIEW_WIDTH  - pw) >> 1;
  402.   starty = (PREVIEW_HEIGHT - ph) >> 1;
  403.  
  404.   gimp_vector_2d_to_3d (startx, starty, pw, ph, xpos, ypos,
  405.             &mapvals.viewpoint, &mapvals.lightsource.position);
  406.   draw_lights (startx, starty,pw, ph);
  407. }
  408.  
  409. /******************************************************************/
  410. /* Draw preview image. if DoCompute is TRUE then recompute image. */
  411. /******************************************************************/
  412.  
  413. void
  414. draw_preview_image (gint docompute)
  415. {
  416.   gint startx, starty, pw, ph;
  417.   GdkColor  color;
  418.  
  419.   color.red   = 0x0;
  420.   color.green = 0x0;
  421.   color.blue  = 0x0;
  422.   gdk_gc_set_rgb_bg_color (gc, &color);
  423.  
  424.   color.red   = 0xFFFF;
  425.   color.green = 0xFFFF;
  426.   color.blue  = 0xFFFF;
  427.   gdk_gc_set_rgb_fg_color (gc, &color);
  428.  
  429.   gdk_gc_set_function (gc, GDK_COPY);
  430.   linetab[0].x1 = -1;
  431.  
  432.   pw = PREVIEW_WIDTH >> mapvals.preview_zoom_factor;
  433.   ph = PREVIEW_HEIGHT >> mapvals.preview_zoom_factor;
  434.   startx = (PREVIEW_WIDTH - pw) >> 1;
  435.   starty = (PREVIEW_HEIGHT - ph) >> 1;
  436.  
  437.   if (docompute == TRUE)
  438.     {
  439.       GdkDisplay *display = gtk_widget_get_display (previewarea);
  440.       GdkCursor  *cursor;
  441.  
  442.       cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
  443.       gdk_window_set_cursor (previewarea->window, cursor);
  444.       gdk_cursor_unref (cursor);
  445.  
  446.       compute_preview (0, 0, width - 1, height - 1, pw, ph);
  447.  
  448.       cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
  449.       gdk_window_set_cursor(previewarea->window, cursor);
  450.       gdk_cursor_unref (cursor);
  451.  
  452.       clear_light_marker ();
  453.     }
  454.  
  455.   if (pw != PREVIEW_WIDTH || ph != PREVIEW_HEIGHT)
  456.     gdk_window_clear (previewarea->window);
  457.  
  458.   gdk_draw_rgb_image (previewarea->window, gc,
  459.                       startx, starty, pw, ph,
  460.                       GDK_RGB_DITHER_MAX,
  461.                       preview_rgb_data, 3 * pw);
  462.  
  463.   draw_lights (startx, starty, pw, ph);
  464. }
  465.  
  466. /**************************/
  467. /* Draw preview wireframe */
  468. /**************************/
  469.  
  470. void
  471. draw_preview_wireframe (void)
  472. {
  473.   gint startx, starty, pw, ph;
  474.   GdkColor  color;
  475.  
  476.   color.red   = 0x0;
  477.   color.green = 0x0;
  478.   color.blue  = 0x0;
  479.   gdk_gc_set_rgb_bg_color (gc, &color);
  480.  
  481.   color.red   = 0xFFFF;
  482.   color.green = 0xFFFF;
  483.   color.blue  = 0xFFFF;
  484.   gdk_gc_set_rgb_fg_color (gc, &color);
  485.  
  486.   gdk_gc_set_function (gc, GDK_INVERT);
  487.  
  488.   pw     = PREVIEW_WIDTH  >> mapvals.preview_zoom_factor;
  489.   ph     = PREVIEW_HEIGHT >> mapvals.preview_zoom_factor;
  490.   startx = (PREVIEW_WIDTH  - pw) >> 1;
  491.   starty = (PREVIEW_HEIGHT - ph) >> 1;
  492.  
  493.   clear_wireframe ();
  494.   draw_wireframe (startx, starty, pw, ph);
  495. }
  496.  
  497. /****************************/
  498. /* Draw a wireframe preview */
  499. /****************************/
  500.  
  501. void
  502. draw_wireframe (gint startx,
  503.         gint starty,
  504.         gint pw,
  505.         gint ph)
  506. {
  507.   switch (mapvals.maptype)
  508.     {
  509.     case MAP_PLANE:
  510.       draw_wireframe_plane (startx, starty, pw, ph);
  511.       break;
  512.     case MAP_SPHERE:
  513.       draw_wireframe_sphere (startx, starty, pw, ph);
  514.       break;
  515.     case MAP_BOX:
  516.       draw_wireframe_box (startx, starty, pw, ph);
  517.       break;
  518.     case MAP_CYLINDER:
  519.       draw_wireframe_cylinder (startx, starty, pw, ph);
  520.       break;
  521.     }
  522. }
  523.  
  524. static void
  525. draw_wireframe_plane (gint startx,
  526.               gint starty,
  527.               gint pw,
  528.               gint ph)
  529. {
  530.   GimpVector3 v1, v2, a, b, c, d, dir1, dir2;
  531.   gint        cnt, n = 0;
  532.   gdouble     x1, y1, x2, y2, cx1, cy1, cx2, cy2, fac;
  533.  
  534.   /* Find rotated box corners */
  535.   /* ======================== */
  536.  
  537.   gimp_vector3_set (&v1, 0.5, 0.0, 0.0);
  538.   gimp_vector3_set (&v2, 0.0, 0.5, 0.0);
  539.  
  540.   gimp_vector3_rotate (&v1,
  541.                gimp_deg_to_rad (mapvals.alpha),
  542.                gimp_deg_to_rad (mapvals.beta),
  543.                gimp_deg_to_rad (mapvals.gamma));
  544.  
  545.   gimp_vector3_rotate (&v2,
  546.                gimp_deg_to_rad (mapvals.alpha),
  547.                gimp_deg_to_rad (mapvals.beta),
  548.                gimp_deg_to_rad (mapvals.gamma));
  549.  
  550.   dir1 = v1; gimp_vector3_normalize (&dir1);
  551.   dir2 = v2; gimp_vector3_normalize (&dir2);
  552.  
  553.   fac = 1.0 / (gdouble) WIRESIZE;
  554.  
  555.   gimp_vector3_mul (&dir1, fac);
  556.   gimp_vector3_mul (&dir2, fac);
  557.  
  558.   gimp_vector3_add (&a, &mapvals.position, &v1);
  559.   gimp_vector3_sub (&b, &a, &v2);
  560.   gimp_vector3_add (&a, &a, &v2);
  561.   gimp_vector3_sub (&d, &mapvals.position, &v1);
  562.   gimp_vector3_sub (&d, &d, &v2);
  563.  
  564.   c = b;
  565.  
  566.   cx1 = (gdouble) startx;
  567.   cy1 = (gdouble) starty;
  568.   cx2 = cx1 + (gdouble) pw;
  569.   cy2 = cy1 + (gdouble) ph;
  570.  
  571.   for (cnt = 0; cnt <= WIRESIZE; cnt++)
  572.     {
  573.       gimp_vector_3d_to_2d (startx, starty, pw, ph,
  574.                 &x1, &y1, &mapvals.viewpoint, &a);
  575.       gimp_vector_3d_to_2d (startx, starty, pw, ph,
  576.                 &x2, &y2, &mapvals.viewpoint, &b);
  577.  
  578.       if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE)
  579.         {
  580.           linetab[n].x1 = RINT (x1);
  581.           linetab[n].y1 = RINT (y1);
  582.           linetab[n].x2 = RINT (x2);
  583.           linetab[n].y2 = RINT (y2);
  584.           linetab[n].linewidth = 1;
  585.           linetab[n].linestyle = GDK_LINE_SOLID;
  586.           gdk_gc_set_line_attributes (gc,
  587.                       linetab[n].linewidth,
  588.                       linetab[n].linestyle,
  589.                       GDK_CAP_NOT_LAST,
  590.                       GDK_JOIN_MITER);
  591.           gdk_draw_line (previewarea->window, gc,
  592.              linetab[n].x1, linetab[n].y1,
  593.              linetab[n].x2, linetab[n].y2);
  594.           n++;
  595.         }
  596.  
  597.       gimp_vector_3d_to_2d (startx, starty, pw, ph,
  598.                 &x1, &y1, &mapvals.viewpoint, &c);
  599.       gimp_vector_3d_to_2d (startx, starty, pw, ph,
  600.                 &x2, &y2, &mapvals.viewpoint, &d);
  601.  
  602.       if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE)
  603.         {
  604.           linetab[n].x1 = RINT (x1);
  605.           linetab[n].y1 = RINT (y1);
  606.           linetab[n].x2 = RINT (x2);
  607.           linetab[n].y2 = RINT (y2);
  608.           linetab[n].linewidth = 1;
  609.           linetab[n].linestyle = GDK_LINE_SOLID;
  610.           gdk_gc_set_line_attributes (gc,
  611.                       linetab[n].linewidth,
  612.                       linetab[n].linestyle,
  613.                       GDK_CAP_NOT_LAST,
  614.                       GDK_JOIN_MITER);
  615.           gdk_draw_line (previewarea->window, gc,
  616.              linetab[n].x1, linetab[n].y1,
  617.              linetab[n].x2, linetab[n].y2);
  618.           n++;
  619.         }
  620.  
  621.       gimp_vector3_sub (&a, &a, &dir1);
  622.       gimp_vector3_sub (&b, &b, &dir1);
  623.       gimp_vector3_add (&c, &c, &dir2);
  624.       gimp_vector3_add (&d, &d, &dir2);
  625.     }
  626.  
  627.   /* Mark end of lines */
  628.   /* ================= */
  629.  
  630.   linetab[n].x1 = -1;
  631. }
  632.  
  633. static void
  634. draw_wireframe_sphere (gint startx,
  635.                gint starty,
  636.                gint pw,
  637.                gint ph)
  638. {
  639.   GimpVector3 p[2 * (WIRESIZE + 5)];
  640.   gint        cnt, cnt2, n = 0;
  641.   gdouble     x1, y1, x2, y2, twopifac, cx1, cy1, cx2, cy2;
  642.  
  643.   /* Compute wireframe points */
  644.   /* ======================== */
  645.  
  646.   twopifac = (2.0 * G_PI) / WIRESIZE;
  647.  
  648.   for (cnt = 0; cnt < WIRESIZE; cnt++)
  649.     {
  650.       p[cnt].x = mapvals.radius * cos ((gdouble) cnt * twopifac);
  651.       p[cnt].y = 0.0;
  652.       p[cnt].z = mapvals.radius * sin ((gdouble) cnt * twopifac);
  653.       gimp_vector3_rotate (&p[cnt],
  654.                gimp_deg_to_rad (mapvals.alpha),
  655.                gimp_deg_to_rad (mapvals.beta),
  656.                gimp_deg_to_rad (mapvals.gamma));
  657.       gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position);
  658.     }
  659.  
  660.   p[cnt] = p[0];
  661.  
  662.   for (cnt = WIRESIZE + 1; cnt < 2 * WIRESIZE + 1; cnt++)
  663.     {
  664.       p[cnt].x = mapvals.radius * cos ((gdouble) (cnt-(WIRESIZE+1))*twopifac);
  665.       p[cnt].y = mapvals.radius * sin ((gdouble) (cnt-(WIRESIZE+1))*twopifac);
  666.       p[cnt].z = 0.0;
  667.       gimp_vector3_rotate (&p[cnt],
  668.                gimp_deg_to_rad (mapvals.alpha),
  669.                gimp_deg_to_rad (mapvals.beta),
  670.                gimp_deg_to_rad (mapvals.gamma));
  671.       gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position);
  672.     }
  673.  
  674.   p[cnt] = p[WIRESIZE+1];
  675.   cnt++;
  676.   cnt2 = cnt;
  677.  
  678.   /* Find rotated axis */
  679.   /* ================= */
  680.  
  681.   gimp_vector3_set (&p[cnt], 0.0, -0.35, 0.0);
  682.   gimp_vector3_rotate (&p[cnt],
  683.                gimp_deg_to_rad (mapvals.alpha),
  684.                gimp_deg_to_rad (mapvals.beta),
  685.                gimp_deg_to_rad (mapvals.gamma));
  686.   p[cnt+1] = mapvals.position;
  687.  
  688.   gimp_vector3_set (&p[cnt+2], 0.0, 0.0, -0.35);
  689.   gimp_vector3_rotate (&p[cnt+2],
  690.                gimp_deg_to_rad (mapvals.alpha),
  691.                gimp_deg_to_rad (mapvals.beta),
  692.                gimp_deg_to_rad (mapvals.gamma));
  693.   p[cnt+3] = mapvals.position;
  694.  
  695.   p[cnt + 4] = p[cnt];
  696.   gimp_vector3_mul (&p[cnt + 4], -1.0);
  697.   p[cnt + 5] = p[cnt + 1];
  698.  
  699.   gimp_vector3_add (&p[cnt],     &p[cnt],     &mapvals.position);
  700.   gimp_vector3_add (&p[cnt + 2], &p[cnt + 2], &mapvals.position);
  701.   gimp_vector3_add (&p[cnt + 4], &p[cnt + 4], &mapvals.position);
  702.  
  703.   /* Draw the circles (equator and zero meridian) */
  704.   /* ============================================ */
  705.  
  706.   cx1 = (gdouble) startx;
  707.   cy1 = (gdouble) starty;
  708.   cx2 = cx1 + (gdouble) pw;
  709.   cy2 = cy1 + (gdouble) ph;
  710.  
  711.   for (cnt = 0; cnt < cnt2 - 1; cnt++)
  712.     {
  713.       if (p[cnt].z > mapvals.position.z && p[cnt + 1].z > mapvals.position.z)
  714.         {
  715.           gimp_vector_3d_to_2d (startx, starty, pw, ph,
  716.                 &x1, &y1, &mapvals.viewpoint, &p[cnt]);
  717.           gimp_vector_3d_to_2d (startx, starty, pw, ph,
  718.                 &x2, &y2, &mapvals.viewpoint, &p[cnt + 1]);
  719.  
  720.           if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE)
  721.             {
  722.               linetab[n].x1 = (gint) (x1 + 0.5);
  723.               linetab[n].y1 = (gint) (y1 + 0.5);
  724.               linetab[n].x2 = (gint) (x2 + 0.5);
  725.               linetab[n].y2 = (gint) (y2 + 0.5);
  726.               linetab[n].linewidth = 3;
  727.               linetab[n].linestyle = GDK_LINE_SOLID;
  728.               gdk_gc_set_line_attributes (gc,
  729.                       linetab[n].linewidth,
  730.                       linetab[n].linestyle,
  731.                       GDK_CAP_NOT_LAST,
  732.                       GDK_JOIN_MITER);
  733.               gdk_draw_line (previewarea->window, gc,
  734.                  linetab[n].x1, linetab[n].y1,
  735.                  linetab[n].x2, linetab[n].y2);
  736.               n++;
  737.             }
  738.         }
  739.     }
  740.  
  741.   /* Draw the axis (pole to pole and center to zero meridian) */
  742.   /* ======================================================== */
  743.  
  744.   for (cnt = 0; cnt < 3; cnt++)
  745.     {
  746.       gimp_vector_3d_to_2d (startx, starty, pw, ph,
  747.                 &x1, &y1, &mapvals.viewpoint, &p[cnt2]);
  748.       gimp_vector_3d_to_2d (startx, starty, pw, ph,
  749.                 &x2, &y2, &mapvals.viewpoint, &p[cnt2 + 1]);
  750.  
  751.       if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE)
  752.         {
  753.           linetab[n].x1 = RINT (x1);
  754.           linetab[n].y1 = RINT (y1);
  755.           linetab[n].x2 = RINT (x2);
  756.           linetab[n].y2 = RINT (y2);
  757.  
  758.           if (p[cnt2].z < mapvals.position.z || p[cnt2+1].z < mapvals.position.z)
  759.             {
  760.               linetab[n].linewidth = 1;
  761.               linetab[n].linestyle = GDK_LINE_DOUBLE_DASH;
  762.             }
  763.           else
  764.             {
  765.               linetab[n].linewidth = 3;
  766.               linetab[n].linestyle = GDK_LINE_SOLID;
  767.             }
  768.  
  769.           gdk_gc_set_line_attributes (gc,
  770.                       linetab[n].linewidth,
  771.                       linetab[n].linestyle,
  772.                       GDK_CAP_NOT_LAST,
  773.                       GDK_JOIN_MITER);
  774.           gdk_draw_line (previewarea->window, gc,
  775.              linetab[n].x1, linetab[n].y1,
  776.              linetab[n].x2, linetab[n].y2);
  777.           n++;
  778.         }
  779.  
  780.       cnt2 += 2;
  781.     }
  782.  
  783.   /* Mark end of lines */
  784.   /* ================= */
  785.  
  786.   linetab[n].x1 = -1;
  787. }
  788.  
  789. static gint
  790. draw_line (gint        n,
  791.        gint        startx,
  792.        gint        starty,
  793.        gint        pw,
  794.        gint        ph,
  795.        gdouble     cx1,
  796.        gdouble     cy1,
  797.        gdouble     cx2,
  798.        gdouble     cy2,
  799.        GimpVector3 a,
  800.        GimpVector3 b)
  801. {
  802.   gdouble x1, y1, x2, y2;
  803.   gint    i = n;
  804.  
  805.   gimp_vector_3d_to_2d (startx, starty, pw, ph,
  806.             &x1, &y1, &mapvals.viewpoint, &a);
  807.   gimp_vector_3d_to_2d (startx, starty, pw, ph,
  808.             &x2, &y2, &mapvals.viewpoint, &b);
  809.  
  810.   if (clip_line (&x1, &y1, &x2, &y2, cx1, cy1, cx2, cy2) == TRUE)
  811.     {
  812.       linetab[i].x1 = RINT (x1);
  813.       linetab[i].y1 = RINT (y1);
  814.       linetab[i].x2 = RINT (x2);
  815.       linetab[i].y2 = RINT (y2);
  816.       linetab[i].linewidth = 3;
  817.       linetab[i].linestyle = GDK_LINE_SOLID;
  818.       gdk_gc_set_line_attributes (gc,
  819.                   linetab[i].linewidth,
  820.                   linetab[i].linestyle,
  821.                   GDK_CAP_NOT_LAST,
  822.                   GDK_JOIN_MITER);
  823.       gdk_draw_line (previewarea->window, gc,
  824.              linetab[i].x1, linetab[i].y1,
  825.              linetab[i].x2, linetab[i].y2);
  826.       i++;
  827.     }
  828.  
  829.   return i;
  830. }
  831.  
  832. static void
  833. draw_wireframe_box (gint startx,
  834.             gint starty,
  835.             gint pw,
  836.             gint ph)
  837. {
  838.   GimpVector3 p[8], tmp, scale;
  839.   gint        n = 0, i;
  840.   gdouble     cx1, cy1, cx2, cy2;
  841.  
  842.   /* Compute wireframe points */
  843.   /* ======================== */
  844.  
  845.   init_compute ();
  846.  
  847.   scale = mapvals.scale;
  848.   gimp_vector3_mul (&scale, 0.5);
  849.  
  850.   gimp_vector3_set (&p[0], -scale.x, -scale.y, scale.z);
  851.   gimp_vector3_set (&p[1],  scale.x, -scale.y, scale.z);
  852.   gimp_vector3_set (&p[2],  scale.x,  scale.y, scale.z);
  853.   gimp_vector3_set (&p[3], -scale.x,  scale.y, scale.z);
  854.  
  855.   gimp_vector3_set (&p[4], -scale.x, -scale.y, -scale.z);
  856.   gimp_vector3_set (&p[5],  scale.x, -scale.y, -scale.z);
  857.   gimp_vector3_set (&p[6],  scale.x,  scale.y, -scale.z);
  858.   gimp_vector3_set (&p[7], -scale.x,  scale.y, -scale.z);
  859.  
  860.   /* Rotate and translate points */
  861.   /* =========================== */
  862.  
  863.   for (i = 0; i < 8; i++)
  864.     {
  865.       vecmulmat (&tmp, &p[i], rotmat);
  866.       gimp_vector3_add (&p[i], &tmp, &mapvals.position);
  867.     }
  868.  
  869.   /* Draw the box */
  870.   /* ============ */
  871.  
  872.   cx1 = (gdouble) startx;
  873.   cy1 = (gdouble) starty;
  874.   cx2 = cx1 + (gdouble) pw;
  875.   cy2 = cy1 + (gdouble) ph;
  876.  
  877.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[1]);
  878.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[2]);
  879.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[3]);
  880.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[0]);
  881.  
  882.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[4],p[5]);
  883.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[5],p[6]);
  884.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[6],p[7]);
  885.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[4]);
  886.  
  887.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[4]);
  888.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[5]);
  889.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[6]);
  890.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[7]);
  891.  
  892.   /* Mark end of lines */
  893.   /* ================= */
  894.  
  895.   linetab[n].x1 = -1;
  896. }
  897.  
  898. static void
  899. draw_wireframe_cylinder (gint startx,
  900.              gint starty,
  901.              gint pw,
  902.              gint ph)
  903. {
  904.   GimpVector3 p[2*8], a, axis, scale;
  905.   gint        n = 0, i;
  906.   gdouble     cx1, cy1, cx2, cy2;
  907.   gfloat      m[16], l, angle;
  908.  
  909.   /* Compute wireframe points */
  910.   /* ======================== */
  911.  
  912.   init_compute ();
  913.  
  914.   scale = mapvals.scale;
  915.   gimp_vector3_mul (&scale, 0.5);
  916.  
  917.   l = mapvals.cylinder_length / 2.0;
  918.   angle = 0;
  919.  
  920.   gimp_vector3_set (&axis, 0.0, 1.0, 0.0);
  921.  
  922.   for (i = 0; i < 8; i++)
  923.     {
  924.       rotatemat (angle, &axis, m);
  925.  
  926.       gimp_vector3_set (&a, mapvals.cylinder_radius, 0.0, 0.0);
  927.  
  928.       vecmulmat (&p[i], &a, m);
  929.  
  930.       p[i+8] = p[i];
  931.  
  932.       p[i].y   += l;
  933.       p[i+8].y -= l;
  934.  
  935.       angle += 360.0 / 8.0;
  936.     }
  937.  
  938.   /* Rotate and translate points */
  939.   /* =========================== */
  940.  
  941.   for (i = 0; i < 16; i++)
  942.     {
  943.       vecmulmat (&a, &p[i], rotmat);
  944.       gimp_vector3_add (&p[i], &a, &mapvals.position);
  945.     }
  946.  
  947.   /* Draw the box */
  948.   /* ============ */
  949.  
  950.   cx1 = (gdouble) startx;
  951.   cy1 = (gdouble) starty;
  952.   cx2 = cx1 + (gdouble) pw;
  953.   cy2 = cy1 + (gdouble) ph;
  954.  
  955.   for (i = 0; i < 7; i++)
  956.     {
  957.       n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+1]);
  958.       n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i+8],p[i+9]);
  959.       n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+8]);
  960.     }
  961.  
  962.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[0]);
  963.   n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[15],p[8]);
  964.  
  965.   /* Mark end of lines */
  966.   /* ================= */
  967.  
  968.   linetab[n].x1 = -1;
  969. }
  970.  
  971. void
  972. clear_wireframe (void)
  973. {
  974.   gint n = 0;
  975.  
  976.   while (linetab[n].x1 != -1)
  977.     {
  978.       gdk_gc_set_line_attributes (gc,
  979.                   linetab[n].linewidth,
  980.                   linetab[n].linestyle,
  981.                   GDK_CAP_NOT_LAST,
  982.                   GDK_JOIN_MITER);
  983.       gdk_draw_line (previewarea->window, gc,
  984.              linetab[n].x1, linetab[n].y1,
  985.              linetab[n].x2, linetab[n].y2);
  986.       n++;
  987.     }
  988. }
  989.