map-object-preview.c 21.1 KB
Newer Older
1 2 3 4
/*************************************************/
/* Compute a preview image and preview wireframe */
/*************************************************/

Michael Natterer's avatar
Michael Natterer committed
5 6
#include "config.h"

7 8 9
#include <gtk/gtk.h>

#include <libgimp/gimp.h>
Sven Neumann's avatar
Sven Neumann committed
10
#include <libgimp/gimpui.h>
11

12 13 14 15 16 17 18
#include "map-object-main.h"
#include "map-object-ui.h"
#include "map-object-image.h"
#include "map-object-apply.h"
#include "map-object-shade.h"
#include "map-object-preview.h"

19 20

gdouble mat[3][4];
21
gint    lightx, lighty;
22

23 24 25
/* Protos */
/* ====== */

26 27 28 29 30 31
static void compute_preview         (gint x,
                                     gint y,
                                     gint w,
                                     gint h,
                                     gint pw,
                                     gint ph);
32 33
static void draw_light_marker       (cairo_t *cr,
                                     gint xpos,
34
                                     gint ypos);
35
static void draw_line               (cairo_t    *cr,
36 37 38 39 40 41 42 43 44 45
                                     gint        startx,
                                     gint        starty,
                                     gint        pw,
                                     gint        ph,
                                     gdouble     cx1,
                                     gdouble     cy1,
                                     gdouble     cx2,
                                     gdouble     cy2,
                                     GimpVector3 a,
                                     GimpVector3 b);
46 47 48 49 50 51 52 53
static void draw_wireframe          (cairo_t *cr,
                                     gint startx,
                                     gint starty,
                                     gint pw,
                                     gint ph);
static void draw_preview_wireframe  (cairo_t *cr);
static void draw_wireframe_plane    (cairo_t *cr,
                                     gint        startx,
54 55 56
                                     gint        starty,
                                     gint        pw,
                                     gint        ph);
57 58
static void draw_wireframe_sphere   (cairo_t *cr,
                                     gint        startx,
59 60 61
                                     gint        starty,
                                     gint        pw,
                                     gint        ph);
62 63
static void draw_wireframe_box      (cairo_t *cr,
                                     gint        startx,
64 65 66
                                     gint        starty,
                                     gint        pw,
                                     gint        ph);
67 68
static void draw_wireframe_cylinder (cairo_t *cr,
                                     gint        startx,
69 70 71
                                     gint        starty,
                                     gint        pw,
                                     gint        ph);
Michael Natterer's avatar
Michael Natterer committed
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
79
compute_preview (gint x,
80 81 82 83 84
                 gint y,
                 gint w,
                 gint h,
                 gint pw,
                 gint ph)
85
{
Michael Natterer's avatar
Michael Natterer committed
86 87 88 89 90
  gdouble      xpostab[PREVIEW_WIDTH];
  gdouble      ypostab[PREVIEW_HEIGHT];
  gdouble      realw;
  gdouble      realh;
  GimpVector3  p1, p2;
91 92
  GimpRGB      color;
  GimpRGB      lightcheck, darkcheck;
Michael Natterer's avatar
Michael Natterer committed
93
  gint         xcnt, ycnt, f1, f2;
94
  guchar       r, g, b;
Michael Natterer's avatar
Michael Natterer committed
95 96 97 98
  glong        index = 0;

  init_compute ();

99 100 101
  if (! preview_surface)
    return;

Michael Natterer's avatar
Michael Natterer committed
102 103
  p1 = int_to_pos (x, y);
  p2 = int_to_pos (x + w, y + h);
104 105 106 107

  /* First, compute the linear mapping (x,y,x+w,y+h) to (0,0,pw,ph) */
  /* ============================================================== */

Michael Natterer's avatar
Michael Natterer committed
108 109 110 111 112 113 114 115
  realw = (p2.x - p1.x);
  realh = (p2.y - p1.y);

  for (xcnt = 0; xcnt < pw; xcnt++)
    xpostab[xcnt] = p1.x + realw * ((gdouble) xcnt / (gdouble) pw);

  for (ycnt = 0; ycnt < ph; ycnt++)
    ypostab[ycnt] = p1.y + realh * ((gdouble) ycnt / (gdouble) ph);
116 117 118 119

  /* Compute preview using the offset tables */
  /* ======================================= */

Michael Natterer's avatar
Michael Natterer committed
120 121
  if (mapvals.transparent_background == TRUE)
    {
122
      gimp_rgba_set (&background, 0.0, 0.0, 0.0, 0.0);
Michael Natterer's avatar
Michael Natterer committed
123
    }
124 125
  else
    {
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);
Michael Natterer's avatar
Michael Natterer committed
134
  gimp_vector3_set (&p2, -1.0, -1.0, 0.0);
135

136 137
  cairo_surface_flush (preview_surface);

Michael Natterer's avatar
Michael Natterer committed
138
  for (ycnt = 0; ycnt < ph; ycnt++)
139
    {
140
      index = ycnt * preview_rgb_stride;
Michael Natterer's avatar
Michael Natterer committed
141
      for (xcnt = 0; xcnt < pw; xcnt++)
142
        {
Michael Natterer's avatar
Michael Natterer committed
143 144
          p1.x = xpostab[xcnt];
          p1.y = ypostab[ycnt];
145

Michael Natterer's avatar
Michael Natterer committed
146 147 148 149
          p2 = p1;
          color = (* get_ray_color) (&p1);

          if (color.a < 1.0)
150
            {
Michael Natterer's avatar
Michael Natterer committed
151 152 153
              f1 = ((xcnt % 32) < 16);
              f2 = ((ycnt % 32) < 16);
              f1 = f1 ^ f2;
154 155 156

              if (f1)
                {
Michael Natterer's avatar
Michael Natterer committed
157
                  if (color.a == 0.0)
158
                    color = lightcheck;
159
                  else
160 161
                    gimp_rgb_composite (&color, &lightcheck,
                                        GIMP_RGB_COMPOSITE_BEHIND);
162
                 }
163 164
              else
                {
Michael Natterer's avatar
Michael Natterer committed
165
                  if (color.a == 0.0)
166
                    color = darkcheck;
167
                  else
168 169
                    gimp_rgb_composite (&color, &darkcheck,
                                        GIMP_RGB_COMPOSITE_BEHIND);
170 171 172
                }
            }

173
          gimp_rgb_get_uchar (&color, &r, &g, &b);
174 175
          GIMP_CAIRO_RGB24_SET_PIXEL((preview_rgb_data + index), r, g, b);
          index += 4;
176 177
        }
    }
178
  cairo_surface_mark_dirty (preview_surface);
179 180 181 182 183 184 185
}

/*************************************************/
/* Check if the given position is within the     */
/* light marker. Return TRUE if so, FALSE if not */
/*************************************************/

186 187
gint
check_light_hit (gint xpos,
188
                 gint ypos)
189
{
Michael Natterer's avatar
Michael Natterer committed
190 191 192
  gdouble dx, dy, r;

  if (mapvals.lightsource.type == POINT_LIGHT)
193
    {
Michael Natterer's avatar
Michael Natterer committed
194 195 196 197 198 199
      dx = (gdouble) lightx - xpos;
      dy = (gdouble) lighty - ypos;
      r  = sqrt (dx * dx + dy * dy) + 0.5;

      if ((gint) r > 7)
        return FALSE;
200
      else
Michael Natterer's avatar
Michael Natterer committed
201
        return TRUE;
202
    }
Michael Natterer's avatar
Michael Natterer committed
203 204

  return FALSE;
205 206 207 208 209 210
}

/****************************************/
/* Draw a marker to show light position */
/****************************************/

211
static void
212 213
draw_light_marker (cairo_t *cr,
                   gint xpos,
214
                   gint ypos)
215
{
216
  GdkRGBA color;
217

218 219 220 221
  if (mapvals.lightsource.type != POINT_LIGHT)
    return;

  cairo_set_line_width (cr, 1.0);
222

223 224 225 226 227
  color.red   = 0.0;
  color.green = 0.2;
  color.blue  = 1.0;
  color.alpha = 1.0;
  gdk_cairo_set_source_rgba (cr, &color);
228

229 230
  lightx = xpos;
  lighty = ypos;
231

232
  cairo_arc (cr, lightx, lighty, 7, 0, 2 * G_PI);
233
  cairo_fill (cr);
234 235
}

236
static void
237 238
draw_lights (cairo_t *cr,
             gint startx,
239 240 241
             gint starty,
             gint pw,
             gint ph)
242
{
Michael Natterer's avatar
Michael Natterer committed
243 244
  gdouble dxpos, dypos;
  gint    xpos, ypos;
245

Michael Natterer's avatar
Michael Natterer committed
246
  gimp_vector_3d_to_2d (startx, starty, pw, ph,
247 248
                        &dxpos, &dypos, &mapvals.viewpoint,
                        &mapvals.lightsource.position);
Michael Natterer's avatar
Michael Natterer committed
249 250 251
  xpos = RINT (dxpos);
  ypos = RINT (dypos);

252 253
  if (xpos >= 0 && xpos <= PREVIEW_WIDTH &&
      ypos >= 0 && ypos <= PREVIEW_HEIGHT)
254
    {
255
      draw_light_marker (cr, xpos, ypos);
256
    }
257 258 259 260 261 262
}

/*************************************************/
/* Update light position given new screen coords */
/*************************************************/

263 264
void
update_light (gint xpos,
265
              gint ypos)
266
{
Sven Neumann's avatar
Sven Neumann committed
267
  gint    startx, starty, pw, ph;
268

269 270
  pw     = PREVIEW_WIDTH * mapvals.zoom;
  ph     = PREVIEW_HEIGHT * mapvals.zoom;
Sven Neumann's avatar
Sven Neumann committed
271 272
  startx = (PREVIEW_WIDTH  - pw) / 2;
  starty = (PREVIEW_HEIGHT - ph) / 2;
Michael Natterer's avatar
Michael Natterer committed
273 274

  gimp_vector_2d_to_3d (startx, starty, pw, ph, xpos, ypos,
275
                        &mapvals.viewpoint, &mapvals.lightsource.position);
276 277

  gtk_widget_queue_draw (previewarea);
278 279
}

280 281 282
/**************************/
/* Compute preview image. */
/**************************/
283

284
void
285 286 287 288
compute_preview_image (void)
{
  GdkDisplay *display = gtk_widget_get_display (previewarea);
  GdkCursor  *cursor;
289
  gint        pw, ph;
290 291 292 293 294 295

  pw = PREVIEW_WIDTH * mapvals.zoom;
  ph = PREVIEW_HEIGHT * mapvals.zoom;

  cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
  gdk_window_set_cursor (gtk_widget_get_window (previewarea), cursor);
296
  g_object_unref (cursor);
297 298 299 300 301

  compute_preview (0, 0, width - 1, height - 1, pw, ph);

  cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
  gdk_window_set_cursor(gtk_widget_get_window (previewarea), cursor);
302
  g_object_unref (cursor);
303 304
}

305
gboolean
306 307
preview_draw (GtkWidget *widget,
              cairo_t   *cr)
308
{
309
  gint startx, starty, pw, ph;
310

311 312
  pw = PREVIEW_WIDTH * mapvals.zoom;
  ph = PREVIEW_HEIGHT * mapvals.zoom;
Sven Neumann's avatar
Sven Neumann committed
313 314
  startx = (PREVIEW_WIDTH - pw) / 2;
  starty = (PREVIEW_HEIGHT - ph) / 2;
315

316 317 318
  cairo_set_source_surface (cr, preview_surface, startx, starty);
  cairo_rectangle (cr, startx, starty, pw, ph);
  cairo_clip (cr);
319

320
  cairo_paint (cr);
321

322 323
  cairo_reset_clip (cr);

324
  if (mapvals.showgrid)
325 326 327 328
    draw_preview_wireframe (cr);

  cairo_reset_clip (cr);
  draw_lights (cr, startx, starty, pw, ph);
Michael Natterer's avatar
Michael Natterer committed
329

330
  return FALSE;
331
}
332 333 334 335 336 337

/**************************/
/* Draw preview wireframe */
/**************************/

void
338
draw_preview_wireframe (cairo_t *cr)
339 340 341 342 343 344 345 346
{
  gint      startx, starty, pw, ph;

  pw     = PREVIEW_WIDTH  * mapvals.zoom;
  ph     = PREVIEW_HEIGHT * mapvals.zoom;
  startx = (PREVIEW_WIDTH  - pw) / 2;
  starty = (PREVIEW_HEIGHT - ph) / 2;

347
  draw_wireframe (cr, startx, starty, pw, ph);
348 349 350 351 352 353 354
}

/****************************/
/* Draw a wireframe preview */
/****************************/

void
355 356
draw_wireframe (cairo_t *cr,
                gint startx,
357 358 359
                gint starty,
                gint pw,
                gint ph)
360
{
361
  cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
362 363 364
  switch (mapvals.maptype)
    {
    case MAP_PLANE:
365
      draw_wireframe_plane (cr, startx, starty, pw, ph);
366 367
      break;
    case MAP_SPHERE:
368
      draw_wireframe_sphere (cr, startx, starty, pw, ph);
369 370
      break;
    case MAP_BOX:
371
      draw_wireframe_box (cr, startx, starty, pw, ph);
372 373
      break;
    case MAP_CYLINDER:
374
      draw_wireframe_cylinder (cr, startx, starty, pw, ph);
375 376 377 378 379
      break;
    }
}

static void
380 381
draw_wireframe_plane (cairo_t *cr,
                      gint startx,
382 383 384
                      gint starty,
                      gint pw,
                      gint ph)
385 386 387
{
  GimpVector3 v1, v2, a, b, c, d, dir1, dir2;
  gint        cnt;
388
  gdouble     x1, y1, x2, y2, fac;
389 390 391 392 393 394 395 396 397 398 399

  cairo_rectangle (cr, startx, starty, pw, ph);
  cairo_clip (cr);

  /* Find rotated box corners */
  /* ======================== */

  gimp_vector3_set (&v1, 0.5, 0.0, 0.0);
  gimp_vector3_set (&v2, 0.0, 0.5, 0.0);

  gimp_vector3_rotate (&v1,
400 401 402
                       gimp_deg_to_rad (mapvals.alpha),
                       gimp_deg_to_rad (mapvals.beta),
                       gimp_deg_to_rad (mapvals.gamma));
403 404

  gimp_vector3_rotate (&v2,
405 406 407
                       gimp_deg_to_rad (mapvals.alpha),
                       gimp_deg_to_rad (mapvals.beta),
                       gimp_deg_to_rad (mapvals.gamma));
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427

  dir1 = v1; gimp_vector3_normalize (&dir1);
  dir2 = v2; gimp_vector3_normalize (&dir2);

  fac = 1.0 / (gdouble) WIRESIZE;

  gimp_vector3_mul (&dir1, fac);
  gimp_vector3_mul (&dir2, fac);

  gimp_vector3_add (&a, &mapvals.position, &v1);
  gimp_vector3_sub (&b, &a, &v2);
  gimp_vector3_add (&a, &a, &v2);
  gimp_vector3_sub (&d, &mapvals.position, &v1);
  gimp_vector3_sub (&d, &d, &v2);

  c = b;

  for (cnt = 0; cnt <= WIRESIZE; cnt++)
    {
      gimp_vector_3d_to_2d (startx, starty, pw, ph,
428
                            &x1, &y1, &mapvals.viewpoint, &a);
429
      gimp_vector_3d_to_2d (startx, starty, pw, ph,
430
                            &x2, &y2, &mapvals.viewpoint, &b);
431

432 433
      cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
      cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
434 435

      gimp_vector_3d_to_2d (startx, starty, pw, ph,
436
                            &x1, &y1, &mapvals.viewpoint, &c);
437
      gimp_vector_3d_to_2d (startx, starty, pw, ph,
438
                            &x2, &y2, &mapvals.viewpoint, &d);
439

440 441
      cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
      cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

      gimp_vector3_sub (&a, &a, &dir1);
      gimp_vector3_sub (&b, &b, &dir1);
      gimp_vector3_add (&c, &c, &dir2);
      gimp_vector3_add (&d, &d, &dir2);
    }

  cairo_set_line_width (cr, 3.0);
  cairo_stroke_preserve (cr);
  cairo_set_line_width (cr, 1.0);
  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
  cairo_stroke (cr);
}

static void
457 458
draw_wireframe_sphere (cairo_t *cr,
                       gint startx,
459 460 461
                       gint starty,
                       gint pw,
                       gint ph)
462 463 464
{
  GimpVector3 p[2 * (WIRESIZE + 5)];
  gint        cnt, cnt2;
465
  gdouble     x1, y1, x2, y2, twopifac;
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

  cairo_rectangle (cr, startx, starty, pw, ph);
  cairo_clip (cr);

  /* Compute wireframe points */
  /* ======================== */

  twopifac = (2.0 * G_PI) / WIRESIZE;

  for (cnt = 0; cnt < WIRESIZE; cnt++)
    {
      p[cnt].x = mapvals.radius * cos ((gdouble) cnt * twopifac);
      p[cnt].y = 0.0;
      p[cnt].z = mapvals.radius * sin ((gdouble) cnt * twopifac);
      gimp_vector3_rotate (&p[cnt],
481 482 483
                           gimp_deg_to_rad (mapvals.alpha),
                           gimp_deg_to_rad (mapvals.beta),
                           gimp_deg_to_rad (mapvals.gamma));
484 485 486 487 488 489 490 491 492 493 494
      gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position);
    }

  p[cnt] = p[0];

  for (cnt = WIRESIZE + 1; cnt < 2 * WIRESIZE + 1; cnt++)
    {
      p[cnt].x = mapvals.radius * cos ((gdouble) (cnt-(WIRESIZE+1))*twopifac);
      p[cnt].y = mapvals.radius * sin ((gdouble) (cnt-(WIRESIZE+1))*twopifac);
      p[cnt].z = 0.0;
      gimp_vector3_rotate (&p[cnt],
495 496 497
                           gimp_deg_to_rad (mapvals.alpha),
                           gimp_deg_to_rad (mapvals.beta),
                           gimp_deg_to_rad (mapvals.gamma));
498 499 500 501 502 503 504 505 506 507 508 509
      gimp_vector3_add (&p[cnt], &p[cnt], &mapvals.position);
    }

  p[cnt] = p[WIRESIZE+1];
  cnt++;
  cnt2 = cnt;

  /* Find rotated axis */
  /* ================= */

  gimp_vector3_set (&p[cnt], 0.0, -0.35, 0.0);
  gimp_vector3_rotate (&p[cnt],
510 511 512
                       gimp_deg_to_rad (mapvals.alpha),
                       gimp_deg_to_rad (mapvals.beta),
                       gimp_deg_to_rad (mapvals.gamma));
513 514 515 516
  p[cnt+1] = mapvals.position;

  gimp_vector3_set (&p[cnt+2], 0.0, 0.0, -0.35);
  gimp_vector3_rotate (&p[cnt+2],
517 518 519
                       gimp_deg_to_rad (mapvals.alpha),
                       gimp_deg_to_rad (mapvals.beta),
                       gimp_deg_to_rad (mapvals.gamma));
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
  p[cnt+3] = mapvals.position;

  p[cnt + 4] = p[cnt];
  gimp_vector3_mul (&p[cnt + 4], -1.0);
  p[cnt + 5] = p[cnt + 1];

  gimp_vector3_add (&p[cnt],     &p[cnt],     &mapvals.position);
  gimp_vector3_add (&p[cnt + 2], &p[cnt + 2], &mapvals.position);
  gimp_vector3_add (&p[cnt + 4], &p[cnt + 4], &mapvals.position);

  /* Draw the circles (equator and zero meridian) */
  /* ============================================ */

  for (cnt = 0; cnt < cnt2 - 1; cnt++)
    {
      if (p[cnt].z > mapvals.position.z && p[cnt + 1].z > mapvals.position.z)
        {
          gimp_vector_3d_to_2d (startx, starty, pw, ph,
538
                                &x1, &y1, &mapvals.viewpoint, &p[cnt]);
539
          gimp_vector_3d_to_2d (startx, starty, pw, ph,
540
                                &x2, &y2, &mapvals.viewpoint, &p[cnt + 1]);
541

542 543
          cairo_move_to (cr, (gint) (x1 + 0.5) + 0.5, (gint) (y1 + 0.5) + 0.5);
          cairo_line_to (cr, (gint) (x2 + 0.5) + 0.5, (gint) (y2 + 0.5) + 0.5);
544 545 546 547 548 549 550 551 552
        }
    }

  /* Draw the axis (pole to pole and center to zero meridian) */
  /* ======================================================== */

  for (cnt = 0; cnt < 3; cnt++)
    {
      gimp_vector_3d_to_2d (startx, starty, pw, ph,
553
                            &x1, &y1, &mapvals.viewpoint, &p[cnt2]);
554
      gimp_vector_3d_to_2d (startx, starty, pw, ph,
555
                            &x2, &y2, &mapvals.viewpoint, &p[cnt2 + 1]);
556

557 558
      cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
      cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
559 560 561 562 563 564 565 566 567 568 569 570 571

      cnt2 += 2;
    }

  cairo_set_line_width (cr, 3.0);
  cairo_stroke_preserve (cr);
  cairo_set_line_width (cr, 1.0);
  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
  cairo_stroke (cr);
}

static void
draw_line (cairo_t    *cr,
572 573 574 575 576 577 578 579 580 581
           gint        startx,
           gint        starty,
           gint        pw,
           gint        ph,
           gdouble     cx1,
           gdouble     cy1,
           gdouble     cx2,
           gdouble     cy2,
           GimpVector3 a,
           GimpVector3 b)
582 583 584 585
{
  gdouble x1, y1, x2, y2;

  gimp_vector_3d_to_2d (startx, starty, pw, ph,
586
                        &x1, &y1, &mapvals.viewpoint, &a);
587
  gimp_vector_3d_to_2d (startx, starty, pw, ph,
588
                        &x2, &y2, &mapvals.viewpoint, &b);
589

590 591
  cairo_move_to (cr, RINT (x1) + 0.5, RINT (y1) + 0.5);
  cairo_line_to (cr, RINT (x2) + 0.5, RINT (y2) + 0.5);
592 593 594
}

static void
595 596
draw_wireframe_box (cairo_t *cr,
                    gint startx,
597 598 599
                    gint starty,
                    gint pw,
                    gint ph)
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
{
  GimpVector3 p[8], tmp, scale;
  gint        i;
  gdouble     cx1, cy1, cx2, cy2;

  cairo_rectangle (cr, startx, starty, pw, ph);
  cairo_clip (cr);

  /* Compute wireframe points */
  /* ======================== */

  init_compute ();

  scale = mapvals.scale;
  gimp_vector3_mul (&scale, 0.5);

  gimp_vector3_set (&p[0], -scale.x, -scale.y, scale.z);
  gimp_vector3_set (&p[1],  scale.x, -scale.y, scale.z);
  gimp_vector3_set (&p[2],  scale.x,  scale.y, scale.z);
  gimp_vector3_set (&p[3], -scale.x,  scale.y, scale.z);

  gimp_vector3_set (&p[4], -scale.x, -scale.y, -scale.z);
  gimp_vector3_set (&p[5],  scale.x, -scale.y, -scale.z);
  gimp_vector3_set (&p[6],  scale.x,  scale.y, -scale.z);
  gimp_vector3_set (&p[7], -scale.x,  scale.y, -scale.z);

  /* Rotate and translate points */
  /* =========================== */

  for (i = 0; i < 8; i++)
    {
      vecmulmat (&tmp, &p[i], rotmat);
      gimp_vector3_add (&p[i], &tmp, &mapvals.position);
    }

  /* Draw the box */
  /* ============ */

  cx1 = (gdouble) startx;
  cy1 = (gdouble) starty;
  cx2 = cx1 + (gdouble) pw;
  cy2 = cy1 + (gdouble) ph;

  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[1]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[2]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[3]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[0]);

  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[4],p[5]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[5],p[6]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[6],p[7]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[4]);

  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[4]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[5]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[6]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[7]);

  cairo_set_line_width (cr, 3.0);
  cairo_stroke_preserve (cr);
  cairo_set_line_width (cr, 1.0);
  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
  cairo_stroke (cr);
}

static void
666 667
draw_wireframe_cylinder (cairo_t *cr,
                         gint startx,
668 669 670
                         gint starty,
                         gint pw,
                         gint ph)
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
{
  GimpVector3 p[2*8], a, axis, scale;
  gint        i;
  gdouble     cx1, cy1, cx2, cy2;
  gfloat      m[16], l, angle;

  cairo_rectangle (cr, startx, starty, pw, ph);
  cairo_clip (cr);

  /* Compute wireframe points */
  /* ======================== */

  init_compute ();

  scale = mapvals.scale;
  gimp_vector3_mul (&scale, 0.5);

  l = mapvals.cylinder_length / 2.0;
  angle = 0;

  gimp_vector3_set (&axis, 0.0, 1.0, 0.0);

  for (i = 0; i < 8; i++)
    {
      rotatemat (angle, &axis, m);

      gimp_vector3_set (&a, mapvals.cylinder_radius, 0.0, 0.0);

      vecmulmat (&p[i], &a, m);

      p[i+8] = p[i];

      p[i].y   += l;
      p[i+8].y -= l;

      angle += 360.0 / 8.0;
    }

  /* Rotate and translate points */
  /* =========================== */

  for (i = 0; i < 16; i++)
    {
      vecmulmat (&a, &p[i], rotmat);
      gimp_vector3_add (&p[i], &a, &mapvals.position);
    }

  /* Draw the box */
  /* ============ */

  cx1 = (gdouble) startx;
  cy1 = (gdouble) starty;
  cx2 = cx1 + (gdouble) pw;
  cy2 = cy1 + (gdouble) ph;

  for (i = 0; i < 7; i++)
    {
      draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+1]);
      draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i+8],p[i+9]);
      draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+8]);
    }

  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[0]);
  draw_line (cr, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[15],p[8]);

  cairo_set_line_width (cr, 3.0);
  cairo_stroke_preserve (cr);
  cairo_set_line_width (cr, 1.0);
  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
  cairo_stroke (cr);
}