home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / MapObject / mapobject_preview.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-23  |  24.0 KB  |  882 lines

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