sphere-designer.c 76.1 KB
Newer Older
Michael Natterer's avatar
Michael Natterer committed
1
/*
2
 * GIMP - The GNU Image Manipulation Program
Michael Natterer's avatar
Michael Natterer committed
3 4
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8 9 10 11 12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 18 19
 */

/*
Michael Natterer's avatar
Michael Natterer committed
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
 * SphereDesigner v0.4 - creates textured spheres
 * by Vidar Madsen <vidar@prosalg.no>
 *
 * Status: Last updated 1999-09-11
 *
 * Known issues:
 * - Might crash if you click OK or Cancel before first preview is rendered
 * - Phong might look weird with transparent textures
 *
 * Todo:
 * - Saving / Loading of presets needs an overhaul
 * - Antialiasing
 * - Global controls: Gamma, ++
 * - Beautification of GUI
 * - Clean up messy source (lots of Glade remnants)
 * - (Probably more. ;-)
 */

#include "config.h"

#include <string.h>
41 42
#include <errno.h>

43
#include <glib/gstdio.h>
Michael Natterer's avatar
Michael Natterer committed
44 45 46 47 48 49 50

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

#include "libgimp/stdplugins-intl.h"


51
#define PLUG_IN_PROC   "plug-in-spheredesigner"
52
#define PLUG_IN_BINARY "sphere-designer"
53
#define PLUG_IN_ROLE   "gimp-sphere-designer"
54

55 56
#define RESPONSE_RESET 1

Michael Natterer's avatar
Michael Natterer committed
57 58 59 60 61 62 63 64 65 66 67 68
#define PREVIEWSIZE 150

/* These must be adjusted as more functionality is added */
#define MAXOBJECT 5
#define MAXLIGHT 5
#define MAXTEXTURE 20
#define MAXTEXTUREPEROBJ 20
#define MAXNORMAL 20
#define MAXNORMALPEROBJ 20
#define MAXATMOS 1
#define MAXCOLPERGRADIENT 5

69
static void query (void);
70
static void run   (const gchar      *name,
71 72 73 74
                   gint              nparams,
                   const GimpParam  *param,
                   gint             *nreturn_vals,
                   GimpParam       **return_vals);
Michael Natterer's avatar
Michael Natterer committed
75

76
const GimpPlugInInfo PLUG_IN_INFO =
Michael Natterer's avatar
Michael Natterer committed
77
{
78
  NULL,   /* init_proc  */
79 80
  NULL,   /* quit_proc  */
  query,  /* query_proc */
81
  run,    /* run_proc   */
Michael Natterer's avatar
Michael Natterer committed
82 83
};

84 85 86 87 88 89 90 91
enum
{
  TRIANGLE,
  DISC,
  PLANE,
  SPHERE,
  CYLINDER,
  LIGHT
Michael Natterer's avatar
Michael Natterer committed
92 93
};

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
enum
{
  SOLID,
  CHECKER,
  MARBLE,
  LIZARD,
  IMAGE,
  PHONG,
  REFLECTION,
  REFRACTION,
  PERLIN,
  WOOD,
  TRANSPARENT,
  SPIRAL,
  SPOTS,
  SMOKE
Michael Natterer's avatar
Michael Natterer committed
110 111
};

112 113 114 115 116
enum
{
  PERSPECTIVE,
  ORTHOGONAL,
  FISHEYE
Michael Natterer's avatar
Michael Natterer committed
117 118
};

119 120
enum
{
Michael Natterer's avatar
Michael Natterer committed
121 122 123
  FOG
};

124 125 126 127 128 129 130 131
enum
{
  TYPE,
  TEXTURE,
  NUM_COLUMNS
};


Michael Natterer's avatar
Michael Natterer committed
132 133 134 135 136 137 138 139 140
/* World-flags */
#define SMARTAMBIENT 0x00000001

/* Object-flags */
#define NOSHADOW   0x00000001

/* Texture-flags */
#define GRADIENT   0x00000001

141 142 143 144
typedef struct
{
  gshort  xsize, ysize;
  guchar *rgb;
Michael Natterer's avatar
Michael Natterer committed
145 146
} image;

147 148
typedef struct
{
149 150 151
  gshort        numcol;
  gdouble       pos[MAXCOLPERGRADIENT];
  GimpVector4   color[MAXCOLPERGRADIENT];
Michael Natterer's avatar
Michael Natterer committed
152 153
} gradient;

154 155
typedef struct
{
156 157 158
  gint          majtype;
  gint          type;
  gulong        flags;
159
  GimpVector4   color1, color2;
160
  gradient      gradient;
161
  GimpVector4   ambient, diffuse;
162 163 164
  gdouble       oscale;
  GimpVector4   scale, translate, rotate;
  image         image;
165 166 167
  GimpVector4   reflection;
  GimpVector4   refraction;
  GimpVector4   transparent;
168
  gdouble       ior;
169
  GimpVector4   phongcolor;
170 171 172
  gdouble       phongsize;
  gdouble       amount;
  gdouble       exp;
173
  GimpVector4   turbulence;
Michael Natterer's avatar
Michael Natterer committed
174 175
} texture;

176 177 178 179
typedef struct
{
  gshort  type;
  gdouble density;
180
  GimpVector4  color;
181
  gdouble turbulence;
Michael Natterer's avatar
Michael Natterer committed
182 183
} atmos;

184 185 186 187 188
typedef struct
{
  gshort  type;
  gulong  flags;
  gshort  numtexture;
Michael Natterer's avatar
Michael Natterer committed
189
  texture texture[MAXTEXTUREPEROBJ];
190
  gshort  numnormal;
Michael Natterer's avatar
Michael Natterer committed
191 192 193
  texture normal[MAXNORMALPEROBJ];
} common;

194 195
typedef struct
{
Michael Natterer's avatar
Michael Natterer committed
196
  common com;
197
  GimpVector4 a, b, c;
Michael Natterer's avatar
Michael Natterer committed
198 199
} triangle;

200 201
typedef struct
{
202 203 204
  common        com;
  GimpVector4   a;
  gdouble       b, r;
Michael Natterer's avatar
Michael Natterer committed
205 206
} disc;

207 208
typedef struct
{
209 210 211
  common        com;
  GimpVector4   a;
  gdouble       r;
Michael Natterer's avatar
Michael Natterer committed
212 213
} sphere;

214 215
typedef struct
{
216 217
  common        com;
  GimpVector4   a, b, c;
Michael Natterer's avatar
Michael Natterer committed
218 219
} cylinder;

220 221
typedef struct
{
222 223 224
  common        com;
  GimpVector4   a;
  gdouble       b;
Michael Natterer's avatar
Michael Natterer committed
225 226
} plane;

227 228
typedef struct
{
229 230 231
  common        com;
  GimpVector4   color;
  GimpVector4   a;
Michael Natterer's avatar
Michael Natterer committed
232 233
} light;

234 235
typedef struct
{
236 237 238
  GimpVector4   v1, v2;
  gshort        inside;
  gdouble       ior;
Michael Natterer's avatar
Michael Natterer committed
239 240
} ray;

241 242 243
typedef union
{
  common   com;
Michael Natterer's avatar
Michael Natterer committed
244
  triangle tri;
245 246 247
  disc     disc;
  plane    plane;
  sphere   sphere;
Michael Natterer's avatar
Michael Natterer committed
248 249 250 251
  cylinder cylinder;
} object;


252 253 254 255 256 257 258
struct world_t
{
  gint    numobj;
  object  obj[MAXOBJECT];
  gint    numlight;
  light   light[MAXLIGHT];
  gint    numtexture;
Michael Natterer's avatar
Michael Natterer committed
259
  texture texture[MAXTEXTURE];
260 261 262 263 264
  gulong  flags;
  gshort  quality;
  gdouble smartambient;
  gshort  numatmos;
  atmos   atmos[MAXATMOS];
Michael Natterer's avatar
Michael Natterer committed
265 266
};

267 268
struct camera_t
{
269
  GimpVector4 location, lookat, up, right;
270
  short  type;
Michael Natterer's avatar
Michael Natterer committed
271 272 273
  double fov, tilt;
};

274
static GtkWidget *drawarea = NULL;
Michael Natterer's avatar
Michael Natterer committed
275

276 277 278
static guchar          *img;
static gint             img_stride;
static cairo_surface_t *buffer;
Michael Natterer's avatar
Michael Natterer committed
279

280
static guint  idle_id = 0;
Michael Natterer's avatar
Michael Natterer committed
281

282
static sphere s;
Michael Natterer's avatar
Michael Natterer committed
283

284 285 286 287 288
struct textures_t
{
  gint   index;
  gchar *s;
  glong  n;
Michael Natterer's avatar
Michael Natterer committed
289 290
};

291
static struct textures_t textures[] =
292 293 294 295 296 297 298 299 300 301 302
{
  { 0, N_("Solid"),   SOLID   },
  { 1, N_("Checker"), CHECKER },
  { 2, N_("Marble"),  MARBLE  },
  { 3, N_("Lizard"),  LIZARD  },
  { 4, N_("Phong"),   PHONG   },
  { 5, N_("Noise"),   PERLIN  },
  { 6, N_("Wood"),    WOOD    },
  { 7, N_("Spiral"),  SPIRAL  },
  { 8, N_("Spots"),   SPOTS   },
  { 0, NULL,          0       }
Michael Natterer's avatar
Michael Natterer committed
303 304
};

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
static inline void vset        (GimpVector4          *v,
                                gdouble               a,
                                gdouble               b,
                                gdouble               c);
static void      restartrender (void);
static void      drawcolor1    (GtkWidget            *widget);
static void      drawcolor2    (GtkWidget            *widget);
static gboolean  render        (void);
static void      realrender    (GimpDrawable         *drawable);
static void      fileselect    (GtkFileChooserAction  action,
                                GtkWidget            *parent);
static gint      traceray      (ray                  *r,
                                GimpVector4          *col,
                                gint                  level,
                                gdouble               imp);
static gdouble   turbulence    (gdouble              *point,
                                gdouble               lofreq,
                                gdouble               hifreq);
Sven Neumann's avatar
Sven Neumann committed
323 324 325


#define COLORBUTTONWIDTH  30
Michael Natterer's avatar
Michael Natterer committed
326 327
#define COLORBUTTONHEIGHT 20

328
static GtkTreeView *texturelist = NULL;
Sven Neumann's avatar
Sven Neumann committed
329

330 331 332 333 334 335 336 337 338
static GtkObject *scalexscale, *scaleyscale, *scalezscale;
static GtkObject *rotxscale, *rotyscale, *rotzscale;
static GtkObject *posxscale, *posyscale, *poszscale;
static GtkObject *scalescale;
static GtkObject *turbulencescale;
static GtkObject *amountscale;
static GtkObject *expscale;
static GtkWidget *typemenu;
static GtkWidget *texturemenu;
Michael Natterer's avatar
Michael Natterer committed
339 340 341 342 343

#define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])

#define B 256

Sven Neumann's avatar
Sven Neumann committed
344 345 346 347 348
static gint      p[B + B + 2];
static gdouble   g[B + B + 2][3];
static gboolean  start = TRUE;
static GRand    *gr;

Michael Natterer's avatar
Michael Natterer committed
349

350 351
static void
init (void)
Michael Natterer's avatar
Michael Natterer committed
352
{
353 354
  gint i, j, k;
  gdouble v[3], s;
Michael Natterer's avatar
Michael Natterer committed
355

356
  /* Create an array of random gradient vectors uniformly on the unit sphere */
Michael Natterer's avatar
Michael Natterer committed
357

358
  gr = g_rand_new ();
359
  g_rand_set_seed (gr, 1);    /* Use static seed, to get reproducible results */
360 361 362 363

  for (i = 0; i < B; i++)
    {
      do
364 365 366 367 368 369
        {                     /* Choose uniformly in a cube */
          for (j = 0; j < 3; j++)
            v[j] = g_rand_double_range (gr, -1, 1);
          s = DOT (v, v);
        }
      while (s > 1.0);        /* If not in sphere try again */
370
      s = sqrt (s);
Sven Neumann's avatar
Sven Neumann committed
371
      for (j = 0; j < 3; j++) /* Else normalize */
372
        g[i][j] = v[j] / s;
373
    }
Michael Natterer's avatar
Michael Natterer committed
374 375 376

/* Create a pseudorandom permutation of [1..B] */

377
  for (i = 0; i < B; i++)
Michael Natterer's avatar
Michael Natterer committed
378
    p[i] = i;
379 380 381 382 383 384
  for (i = B; i > 0; i -= 2)
    {
      k = p[i];
      p[i] = p[j = g_rand_int_range (gr, 0, B)];
      p[j] = k;
    }
Michael Natterer's avatar
Michael Natterer committed
385

Sven Neumann's avatar
Sven Neumann committed
386
  /* Extend g and p arrays to allow for faster indexing */
Michael Natterer's avatar
Michael Natterer committed
387

388 389 390 391
  for (i = 0; i < B + 2; i++)
    {
      p[B + i] = p[i];
      for (j = 0; j < 3; j++)
392
        g[B + i][j] = g[i][j];
393
    }
394
  g_rand_free (gr);
Michael Natterer's avatar
Michael Natterer committed
395 396 397 398 399 400 401 402 403
}

#define setup(i,b0,b1,r0,r1) \
        t = vec[i] + 10000.; \
        b0 = ((int)t) & (B-1); \
        b1 = (b0+1) & (B-1); \
        r0 = t - (int)t; \
        r1 = r0 - 1.;

404

Sven Neumann's avatar
Sven Neumann committed
405
static gdouble
406
noise3 (gdouble * vec)
Michael Natterer's avatar
Michael Natterer committed
407
{
Sven Neumann's avatar
Sven Neumann committed
408
  gint    bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
409
  gdouble rx0, rx1, ry0, ry1, rz0, rz1, *q, sx, sy, sz, a, b, c, d, t, u, v;
Sven Neumann's avatar
Sven Neumann committed
410
  gint    i, j;
Michael Natterer's avatar
Michael Natterer committed
411

412 413
  if (start)
    {
Sven Neumann's avatar
Sven Neumann committed
414
      start = FALSE;
415 416
      init ();
    }
Michael Natterer's avatar
Michael Natterer committed
417

418 419 420 421 422 423 424 425 426 427 428
  setup (0, bx0, bx1, rx0, rx1);
  setup (1, by0, by1, ry0, ry1);
  setup (2, bz0, bz1, rz0, rz1);

  i = p[bx0];
  j = p[bx1];

  b00 = p[i + by0];
  b10 = p[j + by0];
  b01 = p[i + by1];
  b11 = p[j + by1];
Michael Natterer's avatar
Michael Natterer committed
429 430 431 432 433 434 435

#define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )

#define surve(t) ( t * t * (3. - 2. * t) )

#define lerp(t, a, b) ( a + t * (b - a) )

436 437 438
  sx = surve (rx0);
  sy = surve (ry0);
  sz = surve (rz0);
Michael Natterer's avatar
Michael Natterer committed
439 440


441 442 443 444 445
  q = g[b00 + bz0];
  u = at (rx0, ry0, rz0);
  q = g[b10 + bz0];
  v = at (rx1, ry0, rz0);
  a = lerp (sx, u, v);
Michael Natterer's avatar
Michael Natterer committed
446

447 448 449 450 451
  q = g[b01 + bz0];
  u = at (rx0, ry1, rz0);
  q = g[b11 + bz0];
  v = at (rx1, ry1, rz0);
  b = lerp (sx, u, v);
Michael Natterer's avatar
Michael Natterer committed
452

453
  c = lerp (sy, a, b);          /* interpolate in y at lo x */
Michael Natterer's avatar
Michael Natterer committed
454

455 456 457 458 459
  q = g[b00 + bz1];
  u = at (rx0, ry0, rz1);
  q = g[b10 + bz1];
  v = at (rx1, ry0, rz1);
  a = lerp (sx, u, v);
Michael Natterer's avatar
Michael Natterer committed
460

461 462 463 464 465
  q = g[b01 + bz1];
  u = at (rx0, ry1, rz1);
  q = g[b11 + bz1];
  v = at (rx1, ry1, rz1);
  b = lerp (sx, u, v);
Michael Natterer's avatar
Michael Natterer committed
466

467
  d = lerp (sy, a, b);          /* interpolate in y at hi x */
Michael Natterer's avatar
Michael Natterer committed
468

469
  return 1.5 * lerp (sz, c, d); /* interpolate in z */
Michael Natterer's avatar
Michael Natterer committed
470 471
}

472 473
static double
turbulence (gdouble * point, gdouble lofreq, gdouble hifreq)
Michael Natterer's avatar
Michael Natterer committed
474
{
475
  gdouble freq, t, p[3];
Michael Natterer's avatar
Michael Natterer committed
476 477 478 479 480 481

  p[0] = point[0] + 123.456;
  p[1] = point[1] + 234.567;
  p[2] = point[2] + 345.678;

  t = 0;
482 483 484 485 486 487 488
  for (freq = lofreq; freq < hifreq; freq *= 2.)
    {
      t += noise3 (p) / freq;
      p[0] *= 2.;
      p[1] *= 2.;
      p[2] *= 2.;
    }
489
  return t - 0.3;               /* readjust to make mean value = 0.0 */
Michael Natterer's avatar
Michael Natterer committed
490 491
}

492
static struct world_t  world;
Michael Natterer's avatar
Michael Natterer committed
493

494
static inline void
495
vcopy (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
496
{
497
  *a = *b;
Michael Natterer's avatar
Michael Natterer committed
498 499
}

500
static inline void
501
vcross (GimpVector4 *r, GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
502
{
503 504 505
  r->x = a->y * b->z - a->z * b->y;
  r->y = -(a->x * b->z - a->z * b->x);
  r->z = a->x * b->y - a->y * b->x;
Michael Natterer's avatar
Michael Natterer committed
506 507
}

508
static inline gdouble
509
vdot (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
510
{
511
  return a->x * b->x + a->y * b->y + a->z * b->z;
Michael Natterer's avatar
Michael Natterer committed
512 513
}

Sven Neumann's avatar
Sven Neumann committed
514
static inline gdouble
515
vdist (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
516
{
517 518
  gdouble x, y, z;

Michael Natterer's avatar
Michael Natterer committed
519 520 521
  x = a->x - b->x;
  y = a->y - b->y;
  z = a->z - b->z;
522 523

  return sqrt (x * x + y * y + z * z);
Michael Natterer's avatar
Michael Natterer committed
524 525
}

526 527 528 529 530 531 532 533 534 535 536 537
static inline gdouble
vdist2 (GimpVector4 *a, GimpVector4 *b)
{
  gdouble x, y, z;

  x = a->x - b->x;
  y = a->y - b->y;
  z = a->z - b->z;

  return x * x + y * y + z * z;
}

Sven Neumann's avatar
Sven Neumann committed
538
static inline gdouble
539
vlen (GimpVector4 *a)
Michael Natterer's avatar
Michael Natterer committed
540
{
541
  return sqrt (a->x * a->x + a->y * a->y + a->z * a->z);
Michael Natterer's avatar
Michael Natterer committed
542 543
}

544
static inline void
545
vnorm (GimpVector4 *a, gdouble v)
Michael Natterer's avatar
Michael Natterer committed
546
{
547 548
  gdouble d;

549
  d = vlen (a);
550 551 552
  a->x *= v / d;
  a->y *= v / d;
  a->z *= v / d;
Michael Natterer's avatar
Michael Natterer committed
553 554
}

555
static inline void
556
vrotate (GimpVector4 *axis, gdouble ang, GimpVector4 *vector)
Michael Natterer's avatar
Michael Natterer committed
557
{
558
  gdouble rad = ang / 180.0 * G_PI;
Sven Neumann's avatar
Sven Neumann committed
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
  gdouble ax  = vector->x;
  gdouble ay  = vector->y;
  gdouble az  = vector->z;
  gdouble x   = axis->x;
  gdouble y   = axis->y;
  gdouble z   = axis->z;
  gdouble c   = cos (rad);
  gdouble s   = sin (rad);
  gdouble c1  = 1.0 - c;
  gdouble xx  = c1 * x * x;
  gdouble yy  = c1 * y * y;
  gdouble zz  = c1 * z * z;
  gdouble xy  = c1 * x * y;
  gdouble xz  = c1 * x * z;
  gdouble yz  = c1 * y * z;
  gdouble sx  = s * x;
  gdouble sy  = s * y;
  gdouble sz  = s * z;
577 578 579 580

  vector->x = (xx + c) * ax + (xy + sz) * ay + (xz - sy) * az;
  vector->y = (xy - sz) * ax + (yy + c) * ay + (yz + sx) * az;
  vector->z = (xz + sy) * ax + (yz - sx) * ay + (zz + c) * az;
Michael Natterer's avatar
Michael Natterer committed
581 582
}

583
static inline void
584
vset (GimpVector4 *v, gdouble a, gdouble b, gdouble c)
Michael Natterer's avatar
Michael Natterer committed
585 586 587 588 589 590 591
{
  v->x = a;
  v->y = b;
  v->z = c;
  v->w = 1.0;
}

592
static inline void
593
vcset (GimpVector4 *v, gdouble a, gdouble b, gdouble c, gdouble d)
Michael Natterer's avatar
Michael Natterer committed
594 595 596 597 598 599 600
{
  v->x = a;
  v->y = b;
  v->z = c;
  v->w = d;
}

601
static inline void
602
vvrotate (GimpVector4 *p, GimpVector4 *rot)
Michael Natterer's avatar
Michael Natterer committed
603
{
604
  GimpVector4 axis;
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623

  if (rot->x != 0.0)
    {
      vset (&axis, 1, 0, 0);
      vrotate (&axis, rot->x, p);
    }
  if (rot->y != 0.0)
    {
      vset (&axis, 0, 1, 0);
      vrotate (&axis, rot->y, p);
    }
  if (rot->z != 0.0)
    {
      vset (&axis, 0, 0, 1);
      vrotate (&axis, rot->z, p);
    }
}

static inline void
624
vsub (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
625 626 627 628 629 630 631
{
  a->x -= b->x;
  a->y -= b->y;
  a->z -= b->z;
  a->w -= b->w;
}

632
static inline void
633
vadd (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
634 635 636 637 638 639 640
{
  a->x += b->x;
  a->y += b->y;
  a->z += b->z;
  a->w += b->w;
}

641
static inline void
642
vneg (GimpVector4 *a)
Michael Natterer's avatar
Michael Natterer committed
643 644 645 646 647 648 649
{
  a->x = -a->x;
  a->y = -a->y;
  a->z = -a->z;
  a->w = -a->w;
}

650
static inline void
651
vmul (GimpVector4 *v, gdouble a)
Michael Natterer's avatar
Michael Natterer committed
652 653 654 655 656 657 658
{
  v->x *= a;
  v->y *= a;
  v->z *= a;
  v->w *= a;
}

659
static inline void
660
vvmul (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
661 662 663 664 665 666 667
{
  a->x *= b->x;
  a->y *= b->y;
  a->z *= b->z;
  a->w *= b->w;
}

668
static inline void
669
vvdiv (GimpVector4 *a, GimpVector4 *b)
Michael Natterer's avatar
Michael Natterer committed
670 671 672 673 674 675
{
  a->x /= b->x;
  a->y /= b->y;
  a->z /= b->z;
}

676
static void
677
vmix (GimpVector4 *r, GimpVector4 *a, GimpVector4 *b, gdouble v)
Michael Natterer's avatar
Michael Natterer committed
678
{
679 680
  gdouble i = 1.0 - v;

Michael Natterer's avatar
Michael Natterer committed
681 682 683 684 685 686
  r->x = a->x * v + b->x * i;
  r->y = a->y * v + b->y * i;
  r->z = a->z * v + b->z * i;
  r->w = a->w * v + b->w * i;
}

687
static double
688
vmax (GimpVector4 *a)
Michael Natterer's avatar
Michael Natterer committed
689
{
690 691 692 693 694 695 696 697 698
  gdouble max = fabs (a->x);

  if (fabs (a->y) > max)
    max = fabs (a->y);
  if (fabs (a->z) > max)
    max = fabs (a->z);
  if (fabs (a->w) > max)
    max = fabs (a->w);

Michael Natterer's avatar
Michael Natterer committed
699 700 701
  return max;
}

702 703
#if 0
static void
704
vavg (GimpVector4 * a)
Michael Natterer's avatar
Michael Natterer committed
705
{
706 707 708
  gdouble s;

  s = (a->x + a->y + a->z) / 3.0;
Michael Natterer's avatar
Michael Natterer committed
709 710
  a->x = a->y = a->z = s;
}
711
#endif
Michael Natterer's avatar
Michael Natterer committed
712

713
static void
714
trianglenormal (GimpVector4 * n, gdouble *t, triangle * tri)
Michael Natterer's avatar
Michael Natterer committed
715 716
{
  triangle tmp;
717 718 719 720 721 722 723 724
  vcopy (&tmp.b, &tri->b);
  vcopy (&tmp.c, &tri->c);
  vsub (&tmp.b, &tri->a);
  vsub (&tmp.c, &tri->a);
  vset (&tmp.a, 0, 0, 0);
  vcross (n, &tmp.b, &tmp.c);
  if (t)
    *t = vdot (&tmp.b, &tmp.c);
Michael Natterer's avatar
Michael Natterer committed
725 726
}

727 728
static gdouble
checkdisc (ray * r, disc * disc)
Michael Natterer's avatar
Michael Natterer committed
729
{
730
  GimpVector4 p, *v = &disc->a;
731
  gdouble t, d2;
732
  gdouble i, j, k;
Michael Natterer's avatar
Michael Natterer committed
733 734 735 736 737 738 739 740 741 742 743 744

  i = r->v2.x - r->v1.x;
  j = r->v2.y - r->v1.y;
  k = r->v2.z - r->v1.z;

  t = -(v->x * r->v1.x + v->y * r->v1.y + v->z * r->v1.z - disc->b) /
    (v->x * i + v->y * j + v->z * k);

  p.x = r->v1.x + i * t;
  p.y = r->v1.y + j * t;
  p.z = r->v1.z + k * t;

745
  d2 = vdist2 (&p, v);
Michael Natterer's avatar
Michael Natterer committed
746

747
  if (d2 > disc->r * disc->r)
748
    t = 0.0;
Michael Natterer's avatar
Michael Natterer committed
749 750 751 752

  return t;
}

753 754
static gdouble
checksphere (ray * r, sphere * sphere)
Michael Natterer's avatar
Michael Natterer committed
755
{
756
  GimpVector4 cendir, rdir;
757 758 759
  gdouble dirproj, cdlensq;
  gdouble linear, constant, rsq, quadratic, discriminant;
  gdouble smallzero, solmin, solmax, tolerance = 0.001;
Michael Natterer's avatar
Michael Natterer committed
760

761 762
  vcopy (&rdir, &r->v2);
  vsub (&rdir, &r->v1);
Michael Natterer's avatar
Michael Natterer committed
763 764 765

  rsq = sphere->r * sphere->r;

766 767 768 769
  vcopy (&cendir, &r->v1);
  vsub (&cendir, &sphere->a);
  dirproj = vdot (&rdir, &cendir);
  cdlensq = vdot (&cendir, &cendir);
Michael Natterer's avatar
Michael Natterer committed
770

771
  if ((cdlensq >= rsq) && (dirproj > 0.0))
Michael Natterer's avatar
Michael Natterer committed
772 773 774 775
    return 0.0;

  linear = 2.0 * dirproj;
  constant = cdlensq - rsq;
776
  quadratic = vdot (&rdir, &rdir);
Michael Natterer's avatar
Michael Natterer committed
777 778

  smallzero = (constant / linear);
779 780 781 782 783
  if ((smallzero < tolerance) && (smallzero > -tolerance))
    {
      solmin = -linear / quadratic;

      if (solmin > tolerance)
784 785 786 787 788 789 790
        {
          return solmin;
          /*
           *hits = solmin;
           return 1;
           */
        }
791
      else
792
        return 0.0;
793
    }
Michael Natterer's avatar
Michael Natterer committed
794
  discriminant = linear * linear - 4.0 * quadratic * constant;
795
  if (discriminant < 0.0)
Michael Natterer's avatar
Michael Natterer committed
796 797
    return 0.0;
  quadratic *= 2.0;
798
  discriminant = sqrt (discriminant);
Michael Natterer's avatar
Michael Natterer committed
799 800 801 802 803
  solmax = (-linear + discriminant) / (quadratic);
  solmin = (-linear - discriminant) / (quadratic);

  if (solmax < tolerance)
    return 0.0;
804 805 806 807 808

  if (solmin < tolerance)
    {
      return solmax;
      /*
Sven Neumann's avatar
Sven Neumann committed
809 810
       * hits = solmax;
       * return 1;
811 812 813 814 815 816
       */
    }
  else
    {
      return solmin;
      /*
Sven Neumann's avatar
Sven Neumann committed
817 818 819
       * hits++ = solmin;
       * hits = solmax;
       * return 2;
820 821
       */
    }
Michael Natterer's avatar
Michael Natterer committed
822 823
}

824 825
static gdouble
checkcylinder (ray * r, cylinder * cylinder)
Michael Natterer's avatar
Michael Natterer committed
826
{
Sven Neumann's avatar
Sven Neumann committed
827 828
  /* FIXME */
  return 0.0;
Michael Natterer's avatar
Michael Natterer committed
829 830 831
}


832 833
static gdouble
checkplane (ray * r, plane * plane)
Michael Natterer's avatar
Michael Natterer committed
834
{
835
  GimpVector4 *v = &plane->a;
836 837
  gdouble t;
  gdouble i, j, k;
Michael Natterer's avatar
Michael Natterer committed
838 839 840 841 842 843 844 845 846 847 848

  i = r->v2.x - r->v1.x;
  j = r->v2.y - r->v1.y;
  k = r->v2.z - r->v1.z;

  t = -(v->x * r->v1.x + v->y * r->v1.y + v->z * r->v1.z - plane->b) /
    (v->x * i + v->y * j + v->z * k);

  return t;
}

849 850
static gdouble
checktri (ray * r, triangle * tri)
Michael Natterer's avatar
Michael Natterer committed
851
{
852 853
  GimpVector4  ed1, ed2;
  GimpVector4  tvec, pvec, qvec;
854
  gdouble det, idet, t, u, v;
855
  GimpVector4 *orig, dir;
Michael Natterer's avatar
Michael Natterer committed
856 857

  orig = &r->v1;
858
  dir = r->v2;
859
  vsub (&dir, orig);
Michael Natterer's avatar
Michael Natterer committed
860 861 862 863 864 865 866

  ed1.x = tri->c.x - tri->a.x;
  ed1.y = tri->c.y - tri->a.y;
  ed1.z = tri->c.z - tri->a.z;
  ed2.x = tri->b.x - tri->a.x;
  ed2.y = tri->b.y - tri->a.y;
  ed2.z = tri->b.z - tri->a.z;
867 868
  vcross (&pvec, &dir, &ed2);
  det = vdot (&ed1, &pvec);
Michael Natterer's avatar
Michael Natterer committed
869 870 871 872 873 874

  idet = 1.0 / det;

  tvec.x = orig->x;
  tvec.y = orig->y;
  tvec.z = orig->z;
875 876
  vsub (&tvec, &tri->a);
  u = vdot (&tvec, &pvec) * idet;
Michael Natterer's avatar
Michael Natterer committed
877

878 879 880 881
  if (u < 0.0)
    return 0;
  if (u > 1.0)
    return 0;
Michael Natterer's avatar
Michael Natterer committed
882

883 884
  vcross (&qvec, &tvec, &ed1);
  v = vdot (&dir, &qvec) * idet;
Michael Natterer's avatar
Michael Natterer committed
885

886 887 888 889
  if ((v < 0.0) || (u + v > 1.0))
    return 0;

  t = vdot (&ed2, &qvec) * idet;
Michael Natterer's avatar
Michael Natterer committed
890 891 892 893

  return t;
}

894
static void
895
transformpoint (GimpVector4 * p, texture * t)
Michael Natterer's avatar
Michael Natterer committed
896
{
897
  gdouble point[3], f;
Michael Natterer's avatar
Michael Natterer committed
898

899 900 901
  if ((t->rotate.x != 0.0) || (t->rotate.y != 0.0) || (t->rotate.z != 0.0))
    vvrotate (p, &t->rotate);
  vvdiv (p, &t->scale);
Michael Natterer's avatar
Michael Natterer committed
902

903
  vsub (p, &t->translate);
Michael Natterer's avatar
Michael Natterer committed
904

905 906 907 908 909 910 911 912 913 914 915
  if ((t->turbulence.x != 0.0) || (t->turbulence.y != 0.0) ||
      (t->turbulence.z != 0.0))
    {
      point[0] = p->x;
      point[1] = p->y;
      point[2] = p->z;
      f = turbulence (point, 1, 256);
      p->x += t->turbulence.x * f;
      p->y += t->turbulence.y * f;
      p->z += t->turbulence.z * f;
    }
Michael Natterer's avatar
Michael Natterer committed
916 917
}

918
static void
919
checker (GimpVector4 *q, GimpVector4 *col, texture *t)
Michael Natterer's avatar
Michael Natterer committed
920
{
Sven Neumann's avatar
Sven Neumann committed
921
  gint   c = 0;
922
  GimpVector4 p;
Michael Natterer's avatar
Michael Natterer committed
923

924
  p = *q;
925
  transformpoint (&p, t);
Michael Natterer's avatar
Michael Natterer committed
926

927
  vmul (&p, 0.25);
Michael Natterer's avatar
Michael Natterer committed
928 929 930 931 932

  p.x += 0.00001;
  p.y += 0.00001;
  p.z += 0.00001;

933 934 935 936 937 938 939 940 941 942 943 944 945 946
  if (p.x < 0.0)
    p.x = 0.5 - p.x;
  if (p.y < 0.0)
    p.y = 0.5 - p.y;
  if (p.z < 0.0)
    p.z = 0.5 - p.z;

  if ((p.x - (gint) p.x) < 0.5)
    c ^= 1;
  if ((p.y - (gint) p.y) < 0.5)
    c ^= 1;
  if ((p.z - (gint) p.z) < 0.5)
    c ^= 1;

947
  *col = (c) ? t->color1 : t->color2;
Michael Natterer's avatar
Michael Natterer committed
948 949
}

950
static void
951
gradcolor (GimpVector4 *col, gradient *t, gdouble val)
Michael Natterer's avatar
Michael Natterer committed
952
{
953 954
  gint    i;
  gdouble d;
955 956 957
  GimpVector4  tmpcol;

  val = CLAMP (val, 0.0, 1.0);
Michael Natterer's avatar
Michael Natterer committed
958

959 960 961
  for (i = 0; i < t->numcol; i++)
    {
      if (t->pos[i] == val)
962 963 964 965
        {
          *col = t->color[i];
          return;
        }
966
      if (t->pos[i] > val)
967 968 969 970 971 972 973 974 975 976
        {
          d = (val - t->pos[i - 1]) / (t->pos[i] - t->pos[i - 1]);
          vcopy (&tmpcol, &t->color[i]);
          vmul (&tmpcol, d);
          vcopy (col, &tmpcol);
          vcopy (&tmpcol, &t->color[i - 1]);
          vmul (&tmpcol, 1.0 - d);
          vadd (col, &tmpcol);
          return;
        }
Michael Natterer's avatar
Michael Natterer committed
977
    }
978
  g_printerr ("Error in gradient!\n");
979
  vset (col, 0, 1, 0);
Michael Natterer's avatar
Michael Natterer committed
980 981
}

982
static void
983
marble (GimpVector4 *q, GimpVector4 *col, texture *t)
Michael Natterer's avatar
Michael Natterer committed
984
{
985
  gdouble f;
986
  GimpVector4 p;
Michael Natterer's avatar
Michael Natterer committed
987

988
  p = *q;
989
  transformpoint (&p, t);
Michael Natterer's avatar
Michael Natterer committed
990

991 992
  f = sin (p.x * 4) / 2 + 0.5;
  f = pow (f, t->exp);
Michael Natterer's avatar
Michael Natterer committed
993

994 995
  if (t->flags & GRADIENT)
    gradcolor (col, &t->gradient, f);
Michael Natterer's avatar
Michael Natterer committed
996
  else
997
    vmix (col, &t->color1, &t->color2, f);
Michael Natterer's avatar
Michael Natterer committed
998 999
}

1000
static void
1001
lizard (GimpVector4 *q, GimpVector4 *col, texture *t)
Michael Natterer's avatar
Michael Natterer committed
1002
{
1003
  gdouble f;
1004
  GimpVector4 p;
Michael Natterer's avatar
Michael Natterer committed
1005

1006
  p = *q;
1007
  transformpoint (&p, t);
Michael Natterer's avatar
Michael Natterer committed
1008

1009 1010 1011
  f = fabs (sin (p.x * 4));
  f += fabs (sin (p.y * 4));
  f += fabs (sin (p.z * 4));
Michael Natterer's avatar
Michael Natterer committed
1012
  f /= 3.0;
1013
  f = pow (f, t->exp);
Michael Natterer's avatar
Michael Natterer committed
1014

1015 1016
  if (t->flags & GRADIENT)
    gradcolor (col, &t->gradient, f);
Michael Natterer's avatar
Michael Natterer committed
1017
  else
1018
    vmix (col, &t->color1, &t->color2, f);
Michael Natterer's avatar
Michael Natterer committed
1019 1020
}

1021
static void
1022
wood (GimpVector4 *q, GimpVector4 *col, texture *t)
Michael Natterer's avatar
Michael Natterer committed
1023
{
1024
  gdouble f;
1025
  GimpVector4 p;
Michael Natterer's avatar
Michael Natterer committed
1026

1027
  p = *q;
1028
  transformpoint (&p, t);
Michael Natterer's avatar
Michael Natterer committed
1029

1030 1031
  f = fabs (p.x);
  f = f - (int) f;
Michael Natterer's avatar
Michael Natterer committed
1032

1033
  f = pow (f, t->exp);
Michael Natterer's avatar
Michael Natterer committed
1034

1035 1036
  if (t->flags & GRADIENT)
    gradcolor (col, &t->gradient, f);
Michael Natterer's avatar
Michael Natterer committed
1037
  else
1038
    vmix (col, &t->color1, &t->color2, f);
Michael Natterer's avatar
Michael Natterer committed
1039 1040
}

1041
static void
1042
spiral (GimpVector4 *q, GimpVector4 *col, texture *t)
Michael Natterer's avatar
Michael Natterer committed
1043
{
1044
  gdouble f;
1045
  GimpVector4 p;
Michael Natterer's avatar
Michael Natterer committed
1046

1047
  p = *q;
1048
  transformpoint (&p, t);
Michael Natterer's avatar
Michael Natterer committed
1049

1050 1051
  f = fabs (atan2 (p.x, p.z) / G_PI / 2 + p.y + 99999);
  f = f - (int) f;
Michael Natterer's avatar
Michael Natterer committed
1052

1053
  f = pow (f, t->exp);
Michael Natterer's avatar
Michael Natterer committed
1054

1055 1056
  if (t->flags & GRADIENT)
    gradcolor (col, &t->gradient, f);
Michael Natterer's avatar
Michael Natterer committed
1057
  else
1058
    vmix (col, &t->color1, &t->color2, f);
Michael Natterer's avatar
Michael Natterer committed
1059 1060
}

1061
static void
1062
spots (GimpVector4 *q, GimpVector4 *col, texture *t)
Michael Natterer's avatar
Michael Natterer committed
1063
{
1064
  gdouble f;
1065
  GimpVector4 p, r;
Michael Natterer's avatar
Michael Natterer committed
1066

1067
  p = *q;