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 #include <libgimp/gimpui.h>
11 
12 #include "map-object-main.h"
13 #include "map-object-ui.h"
14 #include "map-object-image.h"
15 #include "map-object-apply.h"
16 #include "map-object-shade.h"
17 #include "map-object-preview.h"
18 
19 
20 gdouble mat[3][4];
21 gint    lightx, lighty;
22 
23 /* Protos */
24 /* ====== */
25 
26 static void compute_preview         (gint x,
27                                      gint y,
28                                      gint w,
29                                      gint h,
30                                      gint pw,
31                                      gint ph);
32 static void draw_light_marker       (cairo_t *cr,
33                                      gint xpos,
34                                      gint ypos);
35 static void draw_line               (cairo_t    *cr,
36                                      gint        startx,
37                                      gint        starty,
38                                      gint        pw,
39                                      gint        ph,
40                                      gdouble     cx1,
41                                      gdouble     cy1,
42                                      gdouble     cx2,
43                                      gdouble     cy2,
44                                      GimpVector3 a,
45                                      GimpVector3 b);
46 static void draw_wireframe          (cairo_t *cr,
47                                      gint startx,
48                                      gint starty,
49                                      gint pw,
50                                      gint ph);
51 static void draw_preview_wireframe  (cairo_t *cr);
52 static void draw_wireframe_plane    (cairo_t *cr,
53                                      gint        startx,
54                                      gint        starty,
55                                      gint        pw,
56                                      gint        ph);
57 static void draw_wireframe_sphere   (cairo_t *cr,
58                                      gint        startx,
59                                      gint        starty,
60                                      gint        pw,
61                                      gint        ph);
62 static void draw_wireframe_box      (cairo_t *cr,
63                                      gint        startx,
64                                      gint        starty,
65                                      gint        pw,
66                                      gint        ph);
67 static void draw_wireframe_cylinder (cairo_t *cr,
68                                      gint        startx,
69                                      gint        starty,
70                                      gint        pw,
71                                      gint        ph);
72 
73 /**************************************************************/
74 /* Computes a preview of the rectangle starting at (x,y) with */
75 /* dimensions (w,h), placing the result in preview_RGB_data.  */
76 /**************************************************************/
77 
78 static void
compute_preview(gint x,gint y,gint w,gint h,gint pw,gint ph)79 compute_preview (gint x,
80                  gint y,
81                  gint w,
82                  gint h,
83                  gint pw,
84                  gint ph)
85 {
86   gdouble      xpostab[PREVIEW_WIDTH];
87   gdouble      ypostab[PREVIEW_HEIGHT];
88   gdouble      realw;
89   gdouble      realh;
90   GimpVector3  p1, p2;
91   GimpRGB      color;
92   GimpRGB      lightcheck, darkcheck;
93   gint         xcnt, ycnt, f1, f2;
94   guchar       r, g, b;
95   glong        index = 0;
96 
97   init_compute ();
98 
99   if (! preview_surface)
100     return;
101 
102   p1 = int_to_pos (x, y);
103   p2 = int_to_pos (x + w, y + h);
104 
105   /* First, compute the linear mapping (x,y,x+w,y+h) to (0,0,pw,ph) */
106   /* ============================================================== */
107 
108   realw = (p2.x - p1.x);
109   realh = (p2.y - p1.y);
110 
111   for (xcnt = 0; xcnt < pw; xcnt++)
112     xpostab[xcnt] = p1.x + realw * ((gdouble) xcnt / (gdouble) pw);
113 
114   for (ycnt = 0; ycnt < ph; ycnt++)
115     ypostab[ycnt] = p1.y + realh * ((gdouble) ycnt / (gdouble) ph);
116 
117   /* Compute preview using the offset tables */
118   /* ======================================= */
119 
120   if (mapvals.transparent_background == TRUE)
121     {
122       gimp_rgba_set (&background, 0.0, 0.0, 0.0, 0.0);
123     }
124   else
125     {
126       gimp_context_get_background (&background);
127       gimp_rgb_set_alpha (&background, 1.0);
128     }
129 
130   gimp_rgba_set (&lightcheck,
131                  GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, 1.0);
132   gimp_rgba_set (&darkcheck,
133                  GIMP_CHECK_DARK, GIMP_CHECK_DARK, GIMP_CHECK_DARK, 1.0);
134   gimp_vector3_set (&p2, -1.0, -1.0, 0.0);
135 
136   cairo_surface_flush (preview_surface);
137 
138   for (ycnt = 0; ycnt < ph; ycnt++)
139     {
140       index = ycnt * preview_rgb_stride;
141       for (xcnt = 0; xcnt < pw; xcnt++)
142         {
143           p1.x = xpostab[xcnt];
144           p1.y = ypostab[ycnt];
145 
146           p2 = p1;
147           color = (* get_ray_color) (&p1);
148 
149           if (color.a < 1.0)
150             {
151               f1 = ((xcnt % 32) < 16);
152               f2 = ((ycnt % 32) < 16);
153               f1 = f1 ^ f2;
154 
155               if (f1)
156                 {
157                   if (color.a == 0.0)
158                     color = lightcheck;
159                   else
160                     gimp_rgb_composite (&color, &lightcheck,
161                                         GIMP_RGB_COMPOSITE_BEHIND);
162                  }
163               else
164                 {
165                   if (color.a == 0.0)
166                     color = darkcheck;
167                   else
168                     gimp_rgb_composite (&color, &darkcheck,
169                                         GIMP_RGB_COMPOSITE_BEHIND);
170                 }
171             }
172 
173           gimp_rgb_get_uchar (&color, &r, &g, &b);
174           GIMP_CAIRO_RGB24_SET_PIXEL((preview_rgb_data + index), r, g, b);
175           index += 4;
176         }
177     }
178   cairo_surface_mark_dirty (preview_surface);
179 }
180 
181 /*************************************************/
182 /* Check if the given position is within the     */
183 /* light marker. Return TRUE if so, FALSE if not */
184 /*************************************************/
185 
186 gint
check_light_hit(gint xpos,gint ypos)187 check_light_hit (gint xpos,
188                  gint ypos)
189 {
190   gdouble dx, dy, r;
191 
192   if (mapvals.lightsource.type == POINT_LIGHT)
193     {
194       dx = (gdouble) lightx - xpos;
195       dy = (gdouble) lighty - ypos;
196       r  = sqrt (dx * dx + dy * dy) + 0.5;
197 
198       if ((gint) r > 7)
199         return FALSE;
200       else
201         return TRUE;
202     }
203 
204   return FALSE;
205 }
206 
207 /****************************************/
208 /* Draw a marker to show light position */
209 /****************************************/
210 
211 static void
draw_light_marker(cairo_t * cr,gint xpos,gint ypos)212 draw_light_marker (cairo_t *cr,
213                    gint xpos,
214                    gint ypos)
215 {
216   GdkColor color;
217 
218   if (mapvals.lightsource.type != POINT_LIGHT)
219     return;
220 
221   cairo_set_line_width (cr, 1.0);
222 
223   color.red   = 0x0;
224   color.green = 0x4000;
225   color.blue  = 0xFFFF;
226   gdk_cairo_set_source_color (cr, &color);
227 
228   lightx = xpos;
229   lighty = ypos;
230 
231   cairo_arc (cr, lightx, lighty, 7, 0, 2 * G_PI);
232   cairo_fill (cr);
233 }
234 
235 static void
draw_lights(cairo_t * cr,gint startx,gint starty,gint pw,gint ph)236 draw_lights (cairo_t *cr,
237              gint startx,
238              gint starty,
239              gint pw,
240              gint ph)
241 {
242   gdouble dxpos, dypos;
243   gint    xpos, ypos;
244 
245   gimp_vector_3d_to_2d (startx, starty, pw, ph,
246                         &dxpos, &dypos, &mapvals.viewpoint,
247                         &mapvals.lightsource.position);
248   xpos = RINT (dxpos);
249   ypos = RINT (dypos);
250 
251   if (xpos >= 0 && xpos <= PREVIEW_WIDTH &&
252       ypos >= 0 && ypos <= PREVIEW_HEIGHT)
253     {
254       draw_light_marker (cr, xpos, ypos);
255     }
256 }
257 
258 /*************************************************/
259 /* Update light position given new screen coords */
260 /*************************************************/
261 
262 void
update_light(gint xpos,gint ypos)263 update_light (gint xpos,
264               gint ypos)
265 {
266   gint    startx, starty, pw, ph;
267 
268   pw     = PREVIEW_WIDTH * mapvals.zoom;
269   ph     = PREVIEW_HEIGHT * mapvals.zoom;
270   startx = (PREVIEW_WIDTH  - pw) / 2;
271   starty = (PREVIEW_HEIGHT - ph) / 2;
272 
273   gimp_vector_2d_to_3d (startx, starty, pw, ph, xpos, ypos,
274                         &mapvals.viewpoint, &mapvals.lightsource.position);
275 
276   gtk_widget_queue_draw (previewarea);
277 }
278 
279 /**************************/
280 /* Compute preview image. */
281 /**************************/
282 
283 void
compute_preview_image(void)284 compute_preview_image (void)
285 {
286   GdkDisplay *display = gtk_widget_get_display (previewarea);
287   GdkCursor  *cursor;
288   gint        pw, ph;
289 
290   pw = PREVIEW_WIDTH * mapvals.zoom;
291   ph = PREVIEW_HEIGHT * mapvals.zoom;
292 
293   cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
294   gdk_window_set_cursor (gtk_widget_get_window (previewarea), cursor);
295   gdk_cursor_unref (cursor);
296 
297   compute_preview (0, 0, width - 1, height - 1, pw, ph);
298 
299   cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
300   gdk_window_set_cursor(gtk_widget_get_window (previewarea), cursor);
301   gdk_cursor_unref (cursor);
302 }
303 
304 gboolean
preview_expose(GtkWidget * widget,GdkEventExpose * eevent)305 preview_expose (GtkWidget      *widget,
306                 GdkEventExpose *eevent)
307 {
308   gint startx, starty, pw, ph;
309   cairo_t *cr;
310 
311   cr = gdk_cairo_create (eevent->window);
312 
313   pw = PREVIEW_WIDTH * mapvals.zoom;
314   ph = PREVIEW_HEIGHT * mapvals.zoom;
315   startx = (PREVIEW_WIDTH - pw) / 2;
316   starty = (PREVIEW_HEIGHT - ph) / 2;
317 
318   cairo_set_source_surface (cr, preview_surface, startx, starty);
319   cairo_rectangle (cr, startx, starty, pw, ph);
320   cairo_clip (cr);
321 
322   cairo_paint (cr);
323 
324   cairo_reset_clip (cr);
325 
326   if (mapvals.showgrid)
327     draw_preview_wireframe (cr);
328 
329   cairo_reset_clip (cr);
330   draw_lights (cr, startx, starty, pw, ph);
331 
332   cairo_destroy (cr);
333 
334   return FALSE;
335 }
336 
337 /**************************/
338 /* Draw preview wireframe */
339 /**************************/
340 
341 void
draw_preview_wireframe(cairo_t * cr)342 draw_preview_wireframe (cairo_t *cr)
343 {
344   gint      startx, starty, pw, ph;
345 
346   pw     = PREVIEW_WIDTH  * mapvals.zoom;
347   ph     = PREVIEW_HEIGHT * mapvals.zoom;
348   startx = (PREVIEW_WIDTH  - pw) / 2;
349   starty = (PREVIEW_HEIGHT - ph) / 2;
350 
351   draw_wireframe (cr, startx, starty, pw, ph);
352 }
353 
354 /****************************/
355 /* Draw a wireframe preview */
356 /****************************/
357 
358 void
draw_wireframe(cairo_t * cr,gint startx,gint starty,gint pw,gint ph)359 draw_wireframe (cairo_t *cr,
360                 gint startx,
361                 gint starty,
362                 gint pw,
363                 gint ph)
364 {
365   cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
366   switch (mapvals.maptype)
367     {
368     case MAP_PLANE:
369       draw_wireframe_plane (cr, startx, starty, pw, ph);
370       break;
371     case MAP_SPHERE:
372       draw_wireframe_sphere (cr, startx, starty, pw, ph);
373       break;
374     case MAP_BOX:
375       draw_wireframe_box (cr, startx, starty, pw, ph);
376       break;
377     case MAP_CYLINDER:
378       draw_wireframe_cylinder (cr, startx, starty, pw, ph);
379       break;
380     }
381 }
382 
383 static void
draw_wireframe_plane(cairo_t * cr,gint startx,gint starty,gint pw,gint ph)384 draw_wireframe_plane (cairo_t *cr,
385                       gint startx,
386                       gint starty,
387                       gint pw,
388                       gint ph)
389 {
390   GimpVector3 v1, v2, a, b, c, d, dir1, dir2;
391   gint        cnt;
392   gdouble     x1, y1, x2, y2, fac;
393 
394   cairo_rectangle (cr, startx, starty, pw, ph);
395   cairo_clip (cr);
396 
397   /* Find rotated box corners */
398   /* ======================== */
399 
400   gimp_vector3_set (&v1, 0.5, 0.0, 0.0);
401   gimp_vector3_set (&v2, 0.0, 0.5, 0.0);
402 
403   gimp_vector3_rotate (&v1,
404                        gimp_deg_to_rad (mapvals.alpha),
405                        gimp_deg_to_rad (mapvals.beta),
406                        gimp_deg_to_rad (mapvals.gamma));
407 
408   gimp_vector3_rotate (&v2,
409                        gimp_deg_to_rad (mapvals.alpha),
410                        gimp_deg_to_rad (mapvals.beta),
411                        gimp_deg_to_rad (mapvals.gamma));
412 
413   dir1 = v1; gimp_vector3_normalize (&dir1);
414   dir2 = v2; gimp_vector3_normalize (&dir2);
415 
416   fac = 1.0 / (gdouble) WIRESIZE;
417 
418   gimp_vector3_mul (&dir1, fac);
419   gimp_vector3_mul (&dir2, fac);
420 
421   gimp_vector3_add (&a, &mapvals.position, &v1);
422   gimp_vector3_sub (&b, &a, &v2);
423   gimp_vector3_add (&a, &a, &v2);
424   gimp_vector3_sub (&d, &mapvals.position, &v1);
425   gimp_vector3_sub (&d, &d, &v2);
426 
427   c = b;
428 
429   for (cnt = 0; cnt <= WIRESIZE; cnt++)
430     {
431       gimp_vector_3d_to_2d (startx, starty, pw, ph,
432                             &x1, &y1, &mapvals.viewpoint, &a);
433       gimp_vector_3d_to_2d (startx, starty, pw, ph,
434                             &x2, &y2, &mapvals.viewpoint, &b);
435 
436       cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
437       cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
438 
439       gimp_vector_3d_to_2d (startx, starty, pw, ph,
440                             &x1, &y1, &mapvals.viewpoint, &c);
441       gimp_vector_3d_to_2d (startx, starty, pw, ph,
442                             &x2, &y2, &mapvals.viewpoint, &d);
443 
444       cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
445       cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
446 
447       gimp_vector3_sub (&a, &a, &dir1);
448       gimp_vector3_sub (&b, &b, &dir1);
449       gimp_vector3_add (&c, &c, &dir2);
450       gimp_vector3_add (&d, &d, &dir2);
451     }
452 
453   cairo_set_line_width (cr, 3.0);
454   cairo_stroke_preserve (cr);
455   cairo_set_line_width (cr, 1.0);
456   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
457   cairo_stroke (cr);
458 }
459 
460 static void
draw_wireframe_sphere(cairo_t * cr,gint startx,gint starty,gint pw,gint ph)461 draw_wireframe_sphere (cairo_t *cr,
462                        gint startx,
463                        gint starty,
464                        gint pw,
465                        gint ph)
466 {
467   GimpVector3 p[2 * (WIRESIZE + 5)];
468   gint        cnt, cnt2;
469   gdouble     x1, y1, x2, y2, twopifac;
470 
471   cairo_rectangle (cr, startx, starty, pw, ph);
472   cairo_clip (cr);
473 
474   /* Compute wireframe points */
475   /* ======================== */
476 
477   twopifac = (2.0 * G_PI) / WIRESIZE;
478 
479   for (cnt = 0; cnt < WIRESIZE; cnt++)
480     {
481       p[cnt].x = mapvals.radius * cos ((gdouble) cnt * twopifac);
482       p[cnt].y = 0.0;
483       p[cnt].z = mapvals.radius * sin ((gdouble) cnt * twopifac);
484       gimp_vector3_rotate (&p[cnt],
485                            gimp_deg_to_rad (mapvals.alpha),
486                            gimp_deg_to_rad (mapvals.beta),
487                            gimp_deg_to_rad (mapvals.gamma));
488       gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position);
489     }
490 
491   p[cnt] = p[0];
492 
493   for (cnt = WIRESIZE + 1; cnt < 2 * WIRESIZE + 1; cnt++)
494     {
495       p[cnt].x = mapvals.radius * cos ((gdouble) (cnt-(WIRESIZE+1))*twopifac);
496       p[cnt].y = mapvals.radius * sin ((gdouble) (cnt-(WIRESIZE+1))*twopifac);
497       p[cnt].z = 0.0;
498       gimp_vector3_rotate (&p[cnt],
499                            gimp_deg_to_rad (mapvals.alpha),
500                            gimp_deg_to_rad (mapvals.beta),
501                            gimp_deg_to_rad (mapvals.gamma));
502       gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position);
503     }
504 
505   p[cnt] = p[WIRESIZE+1];
506   cnt++;
507   cnt2 = cnt;
508 
509   /* Find rotated axis */
510   /* ================= */
511 
512   gimp_vector3_set (&p[cnt], 0.0, -0.35, 0.0);
513   gimp_vector3_rotate (&p[cnt],
514                        gimp_deg_to_rad (mapvals.alpha),
515                        gimp_deg_to_rad (mapvals.beta),
516                        gimp_deg_to_rad (mapvals.gamma));
517   p[cnt+1] = mapvals.position;
518 
519   gimp_vector3_set (&p[cnt+2], 0.0, 0.0, -0.35);
520   gimp_vector3_rotate (&p[cnt+2],
521                        gimp_deg_to_rad (mapvals.alpha),
522                        gimp_deg_to_rad (mapvals.beta),
523                        gimp_deg_to_rad (mapvals.gamma));
524   p[cnt+3] = mapvals.position;
525 
526   p[cnt + 4] = p[cnt];
527   gimp_vector3_mul (&p[cnt + 4], -1.0);
528   p[cnt + 5] = p[cnt + 1];
529 
530   gimp_vector3_add (&p[cnt],     &p[cnt],     &mapvals.position);
531   gimp_vector3_add (&p[cnt + 2], &p[cnt + 2], &mapvals.position);
532   gimp_vector3_add (&p[cnt + 4], &p[cnt + 4], &mapvals.position);
533 
534   /* Draw the circles (equator and zero meridian) */
535   /* ============================================ */
536 
537   for (cnt = 0; cnt < cnt2 - 1; cnt++)
538     {
539       if (p[cnt].z > mapvals.position.z && p[cnt + 1].z > mapvals.position.z)
540         {
541           gimp_vector_3d_to_2d (startx, starty, pw, ph,
542                                 &x1, &y1, &mapvals.viewpoint, &p[cnt]);
543           gimp_vector_3d_to_2d (startx, starty, pw, ph,
544                                 &x2, &y2, &mapvals.viewpoint, &p[cnt + 1]);
545 
546           cairo_move_to (cr, (gint) (x1 + 0.5) + 0.5, (gint) (y1 + 0.5) + 0.5);
547           cairo_line_to (cr, (gint) (x2 + 0.5) + 0.5, (gint) (y2 + 0.5) + 0.5);
548         }
549     }
550 
551   /* Draw the axis (pole to pole and center to zero meridian) */
552   /* ======================================================== */
553 
554   for (cnt = 0; cnt < 3; cnt++)
555     {
556       gimp_vector_3d_to_2d (startx, starty, pw, ph,
557                             &x1, &y1, &mapvals.viewpoint, &p[cnt2]);
558       gimp_vector_3d_to_2d (startx, starty, pw, ph,
559                             &x2, &y2, &mapvals.viewpoint, &p[cnt2 + 1]);
560 
561       cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
562       cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
563 
564       cnt2 += 2;
565     }
566 
567   cairo_set_line_width (cr, 3.0);
568   cairo_stroke_preserve (cr);
569   cairo_set_line_width (cr, 1.0);
570   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
571   cairo_stroke (cr);
572 }
573 
574 static void
draw_line(cairo_t * cr,gint startx,gint starty,gint pw,gint ph,gdouble cx1,gdouble cy1,gdouble cx2,gdouble cy2,GimpVector3 a,GimpVector3 b)575 draw_line (cairo_t    *cr,
576            gint        startx,
577            gint        starty,
578            gint        pw,
579            gint        ph,
580            gdouble     cx1,
581            gdouble     cy1,
582            gdouble     cx2,
583            gdouble     cy2,
584            GimpVector3 a,
585            GimpVector3 b)
586 {
587   gdouble x1, y1, x2, y2;
588 
589   gimp_vector_3d_to_2d (startx, starty, pw, ph,
590                         &x1, &y1, &mapvals.viewpoint, &a);
591   gimp_vector_3d_to_2d (startx, starty, pw, ph,
592                         &x2, &y2, &mapvals.viewpoint, &b);
593 
594   cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
595   cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
596 }
597 
598 static void
draw_wireframe_box(cairo_t * cr,gint startx,gint starty,gint pw,gint ph)599 draw_wireframe_box (cairo_t *cr,
600                     gint startx,
601                     gint starty,
602                     gint pw,
603                     gint ph)
604 {
605   GimpVector3 p[8], tmp, scale;
606   gint        i;
607   gdouble     cx1, cy1, cx2, cy2;
608 
609   cairo_rectangle (cr, startx, starty, pw, ph);
610   cairo_clip (cr);
611 
612   /* Compute wireframe points */
613   /* ======================== */
614 
615   init_compute ();
616 
617   scale = mapvals.scale;
618   gimp_vector3_mul (&scale, 0.5);
619 
620   gimp_vector3_set (&p[0], -scale.x, -scale.y, scale.z);
621   gimp_vector3_set (&p[1],  scale.x, -scale.y, scale.z);
622   gimp_vector3_set (&p[2],  scale.x,  scale.y, scale.z);
623   gimp_vector3_set (&p[3], -scale.x,  scale.y, scale.z);
624 
625   gimp_vector3_set (&p[4], -scale.x, -scale.y, -scale.z);
626   gimp_vector3_set (&p[5],  scale.x, -scale.y, -scale.z);
627   gimp_vector3_set (&p[6],  scale.x,  scale.y, -scale.z);
628   gimp_vector3_set (&p[7], -scale.x,  scale.y, -scale.z);
629 
630   /* Rotate and translate points */
631   /* =========================== */
632 
633   for (i = 0; i < 8; i++)
634     {
635       vecmulmat (&tmp, &p[i], rotmat);
636       gimp_vector3_add (&p[i], &tmp, &mapvals.position);
637     }
638 
639   /* Draw the box */
640   /* ============ */
641 
642   cx1 = (gdouble) startx;
643   cy1 = (gdouble) starty;
644   cx2 = cx1 + (gdouble) pw;
645   cy2 = cy1 + (gdouble) ph;
646 
647   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[1]);
648   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[2]);
649   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[3]);
650   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[0]);
651 
652   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[4],p[5]);
653   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[5],p[6]);
654   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[6],p[7]);
655   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[4]);
656 
657   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[4]);
658   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[5]);
659   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[6]);
660   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[7]);
661 
662   cairo_set_line_width (cr, 3.0);
663   cairo_stroke_preserve (cr);
664   cairo_set_line_width (cr, 1.0);
665   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
666   cairo_stroke (cr);
667 }
668 
669 static void
draw_wireframe_cylinder(cairo_t * cr,gint startx,gint starty,gint pw,gint ph)670 draw_wireframe_cylinder (cairo_t *cr,
671                          gint startx,
672                          gint starty,
673                          gint pw,
674                          gint ph)
675 {
676   GimpVector3 p[2*8], a, axis, scale;
677   gint        i;
678   gdouble     cx1, cy1, cx2, cy2;
679   gfloat      m[16], l, angle;
680 
681   cairo_rectangle (cr, startx, starty, pw, ph);
682   cairo_clip (cr);
683 
684   /* Compute wireframe points */
685   /* ======================== */
686 
687   init_compute ();
688 
689   scale = mapvals.scale;
690   gimp_vector3_mul (&scale, 0.5);
691 
692   l = mapvals.cylinder_length / 2.0;
693   angle = 0;
694 
695   gimp_vector3_set (&axis, 0.0, 1.0, 0.0);
696 
697   for (i = 0; i < 8; i++)
698     {
699       rotatemat (angle, &axis, m);
700 
701       gimp_vector3_set (&a, mapvals.cylinder_radius, 0.0, 0.0);
702 
703       vecmulmat (&p[i], &a, m);
704 
705       p[i+8] = p[i];
706 
707       p[i].y   += l;
708       p[i+8].y -= l;
709 
710       angle += 360.0 / 8.0;
711     }
712 
713   /* Rotate and translate points */
714   /* =========================== */
715 
716   for (i = 0; i < 16; i++)
717     {
718       vecmulmat (&a, &p[i], rotmat);
719       gimp_vector3_add (&p[i], &a, &mapvals.position);
720     }
721 
722   /* Draw the box */
723   /* ============ */
724 
725   cx1 = (gdouble) startx;
726   cy1 = (gdouble) starty;
727   cx2 = cx1 + (gdouble) pw;
728   cy2 = cy1 + (gdouble) ph;
729 
730   for (i = 0; i < 7; i++)
731     {
732       draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+1]);
733       draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i+8],p[i+9]);
734       draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+8]);
735     }
736 
737   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[0]);
738   draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[15],p[8]);
739 
740   cairo_set_line_width (cr, 3.0);
741   cairo_stroke_preserve (cr);
742   cairo_set_line_width (cr, 1.0);
743   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
744   cairo_stroke (cr);
745 }
746