1 /*
2 * GIMP - The GNU Image Manipulation Program
3 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
4 *
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 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * SphereDesigner v0.4 - creates textured spheres
21 * by Vidar Madsen <vidar@prosalg.no>
22 *
23 * Status: Last updated 1999-09-11
24 *
25 * Known issues:
26 * - Might crash if you click OK or Cancel before first preview is rendered
27 * - Phong might look weird with transparent textures
28 *
29 * Todo:
30 * - Saving / Loading of presets needs an overhaul
31 * - Antialiasing
32 * - Global controls: Gamma, ++
33 * - Beautification of GUI
34 * - Clean up messy source (lots of Glade remnants)
35 * - (Probably more. ;-)
36 */
37
38 #include "config.h"
39
40 #include <string.h>
41 #include <errno.h>
42
43 #include <glib/gstdio.h>
44
45 #include <libgimp/gimp.h>
46 #include <libgimp/gimpui.h>
47
48 #include "libgimp/stdplugins-intl.h"
49
50
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 #define RESPONSE_RESET 1
56
57 #define PREVIEWSIZE 150
58
59 /* These must be adjusted as more functionality is added */
60 #define MAXOBJECT 5
61 #define MAXLIGHT 5
62 #define MAXTEXTURE 20
63 #define MAXTEXTUREPEROBJ 20
64 #define MAXNORMAL 20
65 #define MAXNORMALPEROBJ 20
66 #define MAXATMOS 1
67 #define MAXCOLPERGRADIENT 5
68
69 static void query (void);
70 static void run (const gchar *name,
71 gint nparams,
72 const GimpParam *param,
73 gint *nreturn_vals,
74 GimpParam **return_vals);
75
76 const GimpPlugInInfo PLUG_IN_INFO =
77 {
78 NULL, /* init_proc */
79 NULL, /* quit_proc */
80 query, /* query_proc */
81 run, /* run_proc */
82 };
83
84 enum
85 {
86 TRIANGLE,
87 DISC,
88 PLANE,
89 SPHERE,
90 CYLINDER,
91 LIGHT
92 };
93
94 enum
95 {
96 SOLID,
97 CHECKER,
98 MARBLE,
99 LIZARD,
100 IMAGE,
101 PHONG,
102 REFLECTION,
103 REFRACTION,
104 PERLIN,
105 WOOD,
106 TRANSPARENT,
107 SPIRAL,
108 SPOTS,
109 SMOKE
110 };
111
112 enum
113 {
114 PERSPECTIVE,
115 ORTHOGONAL,
116 FISHEYE
117 };
118
119 enum
120 {
121 FOG
122 };
123
124 enum
125 {
126 TYPE,
127 TEXTURE,
128 NUM_COLUMNS
129 };
130
131
132 /* World-flags */
133 #define SMARTAMBIENT 0x00000001
134
135 /* Object-flags */
136 #define NOSHADOW 0x00000001
137
138 /* Texture-flags */
139 #define GRADIENT 0x00000001
140
141 typedef struct
142 {
143 gshort xsize, ysize;
144 guchar *rgb;
145 } image;
146
147 typedef struct
148 {
149 gshort numcol;
150 gdouble pos[MAXCOLPERGRADIENT];
151 GimpVector4 color[MAXCOLPERGRADIENT];
152 } gradient;
153
154 typedef struct
155 {
156 gint majtype;
157 gint type;
158 gulong flags;
159 GimpVector4 color1, color2;
160 gradient gradient;
161 GimpVector4 ambient, diffuse;
162 gdouble oscale;
163 GimpVector4 scale, translate, rotate;
164 image image;
165 GimpVector4 reflection;
166 GimpVector4 refraction;
167 GimpVector4 transparent;
168 gdouble ior;
169 GimpVector4 phongcolor;
170 gdouble phongsize;
171 gdouble amount;
172 gdouble exp;
173 GimpVector4 turbulence;
174 } texture;
175
176 typedef struct
177 {
178 gshort type;
179 gdouble density;
180 GimpVector4 color;
181 gdouble turbulence;
182 } atmos;
183
184 typedef struct
185 {
186 gshort type;
187 gulong flags;
188 gshort numtexture;
189 texture texture[MAXTEXTUREPEROBJ];
190 gshort numnormal;
191 texture normal[MAXNORMALPEROBJ];
192 } common;
193
194 typedef struct
195 {
196 common com;
197 GimpVector4 a, b, c;
198 } triangle;
199
200 typedef struct
201 {
202 common com;
203 GimpVector4 a;
204 gdouble b, r;
205 } disc;
206
207 typedef struct
208 {
209 common com;
210 GimpVector4 a;
211 gdouble r;
212 } sphere;
213
214 typedef struct
215 {
216 common com;
217 GimpVector4 a, b, c;
218 } cylinder;
219
220 typedef struct
221 {
222 common com;
223 GimpVector4 a;
224 gdouble b;
225 } plane;
226
227 typedef struct
228 {
229 common com;
230 GimpVector4 color;
231 GimpVector4 a;
232 } light;
233
234 typedef struct
235 {
236 GimpVector4 v1, v2;
237 gshort inside;
238 gdouble ior;
239 } ray;
240
241 typedef union
242 {
243 common com;
244 triangle tri;
245 disc disc;
246 plane plane;
247 sphere sphere;
248 cylinder cylinder;
249 } object;
250
251
252 struct world_t
253 {
254 gint numobj;
255 object obj[MAXOBJECT];
256 gint numlight;
257 light light[MAXLIGHT];
258 gint numtexture;
259 texture texture[MAXTEXTURE];
260 gulong flags;
261 gshort quality;
262 gdouble smartambient;
263 gshort numatmos;
264 atmos atmos[MAXATMOS];
265 };
266
267 struct camera_t
268 {
269 GimpVector4 location, lookat, up, right;
270 short type;
271 double fov, tilt;
272 };
273
274 static GtkWidget *drawarea = NULL;
275
276 static guchar *img;
277 static gint img_stride;
278 static cairo_surface_t *buffer;
279
280 static guint idle_id = 0;
281
282 static sphere s;
283
284 struct textures_t
285 {
286 gint index;
287 gchar *s;
288 glong n;
289 };
290
291 static struct textures_t textures[] =
292 {
293 { 0, N_("Solid"), SOLID },
294 { 1, N_("Checker"), CHECKER },
295 { 2, N_("Marble"), MARBLE },
296 { 3, N_("Lizard"), LIZARD },
297 { 4, N_("Phong"), PHONG },
298 { 5, N_("Noise"), PERLIN },
299 { 6, N_("Wood"), WOOD },
300 { 7, N_("Spiral"), SPIRAL },
301 { 8, N_("Spots"), SPOTS },
302 { 0, NULL, 0 }
303 };
304
305 static inline void vset (GimpVector4 *v,
306 gdouble a,
307 gdouble b,
308 gdouble c);
309 static void restartrender (void);
310 static void drawcolor1 (GtkWidget *widget);
311 static void drawcolor2 (GtkWidget *widget);
312 static gboolean render (void);
313 static void realrender (gint32 drawable_ID);
314 static void fileselect (GtkFileChooserAction action,
315 GtkWidget *parent);
316 static gint traceray (ray *r,
317 GimpVector4 *col,
318 gint level,
319 gdouble imp);
320 static gdouble turbulence (gdouble *point,
321 gdouble lofreq,
322 gdouble hifreq);
323
324
325 #define COLORBUTTONWIDTH 30
326 #define COLORBUTTONHEIGHT 20
327
328 static GtkTreeView *texturelist = NULL;
329
330 static GtkObject *scalexscale, *scaleyscale, *scalezscale;
331 static GtkObject *rotxscale, *rotyscale, *rotzscale;
332 static GtkObject *posxscale, *posyscale, *poszscale;
333 static GtkObject *scalescale;
334 static GtkObject *turbulencescale;
335 static GtkObject *amountscale;
336 static GtkObject *expscale;
337 static GtkWidget *typemenu;
338 static GtkWidget *texturemenu;
339
340 #define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
341
342 #define B 256
343
344 static gint p[B + B + 2];
345 static gdouble g[B + B + 2][3];
346 static gboolean start = TRUE;
347 static GRand *gr;
348
349
350 static void
init(void)351 init (void)
352 {
353 gint i, j, k;
354 gdouble v[3], s;
355
356 /* Create an array of random gradient vectors uniformly on the unit sphere */
357
358 gr = g_rand_new ();
359 g_rand_set_seed (gr, 1); /* Use static seed, to get reproducible results */
360
361 for (i = 0; i < B; i++)
362 {
363 do
364 { /* Choose uniformly in a cube */
365 for (j = 0; j < 3; j++)
366 v[j] = g_rand_double_range (gr, -1, 1);
367 s = DOT (v, v);
368 }
369 while (s > 1.0); /* If not in sphere try again */
370 s = sqrt (s);
371 for (j = 0; j < 3; j++) /* Else normalize */
372 g[i][j] = v[j] / s;
373 }
374
375 /* Create a pseudorandom permutation of [1..B] */
376
377 for (i = 0; i < B; i++)
378 p[i] = i;
379 for (i = B; i > 0; i -= 2)
380 {
381 k = p[i];
382 p[i] = p[j = g_rand_int_range (gr, 0, B)];
383 p[j] = k;
384 }
385
386 /* Extend g and p arrays to allow for faster indexing */
387
388 for (i = 0; i < B + 2; i++)
389 {
390 p[B + i] = p[i];
391 for (j = 0; j < 3; j++)
392 g[B + i][j] = g[i][j];
393 }
394 g_rand_free (gr);
395 }
396
397 #define setup(i,b0,b1,r0,r1) \
398 t = vec[i] + 10000.; \
399 b0 = ((int)t) & (B-1); \
400 b1 = (b0+1) & (B-1); \
401 r0 = t - (int)t; \
402 r1 = r0 - 1.;
403
404
405 static gdouble
noise3(gdouble * vec)406 noise3 (gdouble * vec)
407 {
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;
410 gint i, j;
411
412 if (start)
413 {
414 start = FALSE;
415 init ();
416 }
417
418 setup (0, bx0, bx1, rx0, rx1);
419 setup (1, by0, by1, ry0, ry1);
420 setup (2, bz0, bz1, rz0, rz1);
421
422 i = p[bx0];
423 j = p[bx1];
424
425 b00 = p[i + by0];
426 b10 = p[j + by0];
427 b01 = p[i + by1];
428 b11 = p[j + by1];
429
430 #define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
431
432 #define surve(t) ( t * t * (3. - 2. * t) )
433
434 #define lerp(t, a, b) ( a + t * (b - a) )
435
436 sx = surve (rx0);
437 sy = surve (ry0);
438 sz = surve (rz0);
439
440
441 q = g[b00 + bz0];
442 u = at (rx0, ry0, rz0);
443 q = g[b10 + bz0];
444 v = at (rx1, ry0, rz0);
445 a = lerp (sx, u, v);
446
447 q = g[b01 + bz0];
448 u = at (rx0, ry1, rz0);
449 q = g[b11 + bz0];
450 v = at (rx1, ry1, rz0);
451 b = lerp (sx, u, v);
452
453 c = lerp (sy, a, b); /* interpolate in y at lo x */
454
455 q = g[b00 + bz1];
456 u = at (rx0, ry0, rz1);
457 q = g[b10 + bz1];
458 v = at (rx1, ry0, rz1);
459 a = lerp (sx, u, v);
460
461 q = g[b01 + bz1];
462 u = at (rx0, ry1, rz1);
463 q = g[b11 + bz1];
464 v = at (rx1, ry1, rz1);
465 b = lerp (sx, u, v);
466
467 d = lerp (sy, a, b); /* interpolate in y at hi x */
468
469 return 1.5 * lerp (sz, c, d); /* interpolate in z */
470 }
471
472 static double
turbulence(gdouble * point,gdouble lofreq,gdouble hifreq)473 turbulence (gdouble * point, gdouble lofreq, gdouble hifreq)
474 {
475 gdouble freq, t, p[3];
476
477 p[0] = point[0] + 123.456;
478 p[1] = point[1] + 234.567;
479 p[2] = point[2] + 345.678;
480
481 t = 0;
482 for (freq = lofreq; freq < hifreq; freq *= 2.)
483 {
484 t += noise3 (p) / freq;
485 p[0] *= 2.;
486 p[1] *= 2.;
487 p[2] *= 2.;
488 }
489 return t - 0.3; /* readjust to make mean value = 0.0 */
490 }
491
492 static struct world_t world;
493
494 static inline void
vcopy(GimpVector4 * a,GimpVector4 * b)495 vcopy (GimpVector4 *a, GimpVector4 *b)
496 {
497 *a = *b;
498 }
499
500 static inline void
vcross(GimpVector4 * r,GimpVector4 * a,GimpVector4 * b)501 vcross (GimpVector4 *r, GimpVector4 *a, GimpVector4 *b)
502 {
503 r->x = a->y * b->z - a->z * b->y;
504 r->y = -(a->x * b->z - a->z * b->x);
505 r->z = a->x * b->y - a->y * b->x;
506 }
507
508 static inline gdouble
vdot(GimpVector4 * a,GimpVector4 * b)509 vdot (GimpVector4 *a, GimpVector4 *b)
510 {
511 return a->x * b->x + a->y * b->y + a->z * b->z;
512 }
513
514 static inline gdouble
vdist(GimpVector4 * a,GimpVector4 * b)515 vdist (GimpVector4 *a, GimpVector4 *b)
516 {
517 gdouble x, y, z;
518
519 x = a->x - b->x;
520 y = a->y - b->y;
521 z = a->z - b->z;
522
523 return sqrt (x * x + y * y + z * z);
524 }
525
526 static inline gdouble
vdist2(GimpVector4 * a,GimpVector4 * b)527 vdist2 (GimpVector4 *a, GimpVector4 *b)
528 {
529 gdouble x, y, z;
530
531 x = a->x - b->x;
532 y = a->y - b->y;
533 z = a->z - b->z;
534
535 return x * x + y * y + z * z;
536 }
537
538 static inline gdouble
vlen(GimpVector4 * a)539 vlen (GimpVector4 *a)
540 {
541 return sqrt (a->x * a->x + a->y * a->y + a->z * a->z);
542 }
543
544 static inline void
vnorm(GimpVector4 * a,gdouble v)545 vnorm (GimpVector4 *a, gdouble v)
546 {
547 gdouble d;
548
549 d = vlen (a);
550 a->x *= v / d;
551 a->y *= v / d;
552 a->z *= v / d;
553 }
554
555 static inline void
vrotate(GimpVector4 * axis,gdouble ang,GimpVector4 * vector)556 vrotate (GimpVector4 *axis, gdouble ang, GimpVector4 *vector)
557 {
558 gdouble rad = ang / 180.0 * G_PI;
559 gdouble ax = vector->x;
560 gdouble ay = vector->y;
561 gdouble az = vector->z;
562 gdouble x = axis->x;
563 gdouble y = axis->y;
564 gdouble z = axis->z;
565 gdouble c = cos (rad);
566 gdouble s = sin (rad);
567 gdouble c1 = 1.0 - c;
568 gdouble xx = c1 * x * x;
569 gdouble yy = c1 * y * y;
570 gdouble zz = c1 * z * z;
571 gdouble xy = c1 * x * y;
572 gdouble xz = c1 * x * z;
573 gdouble yz = c1 * y * z;
574 gdouble sx = s * x;
575 gdouble sy = s * y;
576 gdouble sz = s * z;
577
578 vector->x = (xx + c) * ax + (xy + sz) * ay + (xz - sy) * az;
579 vector->y = (xy - sz) * ax + (yy + c) * ay + (yz + sx) * az;
580 vector->z = (xz + sy) * ax + (yz - sx) * ay + (zz + c) * az;
581 }
582
583 static inline void
vset(GimpVector4 * v,gdouble a,gdouble b,gdouble c)584 vset (GimpVector4 *v, gdouble a, gdouble b, gdouble c)
585 {
586 v->x = a;
587 v->y = b;
588 v->z = c;
589 v->w = 1.0;
590 }
591
592 static inline void
vcset(GimpVector4 * v,gdouble a,gdouble b,gdouble c,gdouble d)593 vcset (GimpVector4 *v, gdouble a, gdouble b, gdouble c, gdouble d)
594 {
595 v->x = a;
596 v->y = b;
597 v->z = c;
598 v->w = d;
599 }
600
601 static inline void
vvrotate(GimpVector4 * p,GimpVector4 * rot)602 vvrotate (GimpVector4 *p, GimpVector4 *rot)
603 {
604 GimpVector4 axis;
605
606 if (rot->x != 0.0)
607 {
608 vset (&axis, 1, 0, 0);
609 vrotate (&axis, rot->x, p);
610 }
611 if (rot->y != 0.0)
612 {
613 vset (&axis, 0, 1, 0);
614 vrotate (&axis, rot->y, p);
615 }
616 if (rot->z != 0.0)
617 {
618 vset (&axis, 0, 0, 1);
619 vrotate (&axis, rot->z, p);
620 }
621 }
622
623 static inline void
vsub(GimpVector4 * a,GimpVector4 * b)624 vsub (GimpVector4 *a, GimpVector4 *b)
625 {
626 a->x -= b->x;
627 a->y -= b->y;
628 a->z -= b->z;
629 a->w -= b->w;
630 }
631
632 static inline void
vadd(GimpVector4 * a,GimpVector4 * b)633 vadd (GimpVector4 *a, GimpVector4 *b)
634 {
635 a->x += b->x;
636 a->y += b->y;
637 a->z += b->z;
638 a->w += b->w;
639 }
640
641 static inline void
vneg(GimpVector4 * a)642 vneg (GimpVector4 *a)
643 {
644 a->x = -a->x;
645 a->y = -a->y;
646 a->z = -a->z;
647 a->w = -a->w;
648 }
649
650 static inline void
vmul(GimpVector4 * v,gdouble a)651 vmul (GimpVector4 *v, gdouble a)
652 {
653 v->x *= a;
654 v->y *= a;
655 v->z *= a;
656 v->w *= a;
657 }
658
659 static inline void
vvmul(GimpVector4 * a,GimpVector4 * b)660 vvmul (GimpVector4 *a, GimpVector4 *b)
661 {
662 a->x *= b->x;
663 a->y *= b->y;
664 a->z *= b->z;
665 a->w *= b->w;
666 }
667
668 static inline void
vvdiv(GimpVector4 * a,GimpVector4 * b)669 vvdiv (GimpVector4 *a, GimpVector4 *b)
670 {
671 a->x /= b->x;
672 a->y /= b->y;
673 a->z /= b->z;
674 }
675
676 static void
vmix(GimpVector4 * r,GimpVector4 * a,GimpVector4 * b,gdouble v)677 vmix (GimpVector4 *r, GimpVector4 *a, GimpVector4 *b, gdouble v)
678 {
679 gdouble i = 1.0 - v;
680
681 r->x = a->x * v + b->x * i;
682 r->y = a->y * v + b->y * i;
683 r->z = a->z * v + b->z * i;
684 r->w = a->w * v + b->w * i;
685 }
686
687 static double
vmax(GimpVector4 * a)688 vmax (GimpVector4 *a)
689 {
690 gdouble max = fabs (a->x);
691
692 if (fabs (a->y) > max)
693 max = fabs (a->y);
694 if (fabs (a->z) > max)
695 max = fabs (a->z);
696 if (fabs (a->w) > max)
697 max = fabs (a->w);
698
699 return max;
700 }
701
702 #if 0
703 static void
704 vavg (GimpVector4 * a)
705 {
706 gdouble s;
707
708 s = (a->x + a->y + a->z) / 3.0;
709 a->x = a->y = a->z = s;
710 }
711 #endif
712
713 static void
trianglenormal(GimpVector4 * n,gdouble * t,triangle * tri)714 trianglenormal (GimpVector4 * n, gdouble *t, triangle * tri)
715 {
716 triangle tmp;
717 vcopy (&tmp.b, &tri->b);
718 vcopy (&tmp.c, &tri->c);
719 vsub (&tmp.b, &tri->a);
720 vsub (&tmp.c, &tri->a);
721 vset (&tmp.a, 0, 0, 0);
722 vcross (n, &tmp.b, &tmp.c);
723 if (t)
724 *t = vdot (&tmp.b, &tmp.c);
725 }
726
727 static gdouble
checkdisc(ray * r,disc * disc)728 checkdisc (ray * r, disc * disc)
729 {
730 GimpVector4 p, *v = &disc->a;
731 gdouble t, d2;
732 gdouble i, j, k;
733
734 i = r->v2.x - r->v1.x;
735 j = r->v2.y - r->v1.y;
736 k = r->v2.z - r->v1.z;
737
738 t = -(v->x * r->v1.x + v->y * r->v1.y + v->z * r->v1.z - disc->b) /
739 (v->x * i + v->y * j + v->z * k);
740
741 p.x = r->v1.x + i * t;
742 p.y = r->v1.y + j * t;
743 p.z = r->v1.z + k * t;
744
745 d2 = vdist2 (&p, v);
746
747 if (d2 > disc->r * disc->r)
748 t = 0.0;
749
750 return t;
751 }
752
753 static gdouble
checksphere(ray * r,sphere * sphere)754 checksphere (ray * r, sphere * sphere)
755 {
756 GimpVector4 cendir, rdir;
757 gdouble dirproj, cdlensq;
758 gdouble linear, constant, rsq, quadratic, discriminant;
759 gdouble smallzero, solmin, solmax, tolerance = 0.001;
760
761 vcopy (&rdir, &r->v2);
762 vsub (&rdir, &r->v1);
763
764 rsq = sphere->r * sphere->r;
765
766 vcopy (&cendir, &r->v1);
767 vsub (&cendir, &sphere->a);
768 dirproj = vdot (&rdir, &cendir);
769 cdlensq = vdot (&cendir, &cendir);
770
771 if ((cdlensq >= rsq) && (dirproj > 0.0))
772 return 0.0;
773
774 linear = 2.0 * dirproj;
775 constant = cdlensq - rsq;
776 quadratic = vdot (&rdir, &rdir);
777
778 smallzero = (constant / linear);
779 if ((smallzero < tolerance) && (smallzero > -tolerance))
780 {
781 solmin = -linear / quadratic;
782
783 if (solmin > tolerance)
784 {
785 return solmin;
786 /*
787 *hits = solmin;
788 return 1;
789 */
790 }
791 else
792 return 0.0;
793 }
794 discriminant = linear * linear - 4.0 * quadratic * constant;
795 if (discriminant < 0.0)
796 return 0.0;
797 quadratic *= 2.0;
798 discriminant = sqrt (discriminant);
799 solmax = (-linear + discriminant) / (quadratic);
800 solmin = (-linear - discriminant) / (quadratic);
801
802 if (solmax < tolerance)
803 return 0.0;
804
805 if (solmin < tolerance)
806 {
807 return solmax;
808 /*
809 * hits = solmax;
810 * return 1;
811 */
812 }
813 else
814 {
815 return solmin;
816 /*
817 * hits++ = solmin;
818 * hits = solmax;
819 * return 2;
820 */
821 }
822 }
823
824 static gdouble
checkcylinder(ray * r,cylinder * cylinder)825 checkcylinder (ray * r, cylinder * cylinder)
826 {
827 /* FIXME */
828 return 0.0;
829 }
830
831
832 static gdouble
checkplane(ray * r,plane * plane)833 checkplane (ray * r, plane * plane)
834 {
835 GimpVector4 *v = &plane->a;
836 gdouble t;
837 gdouble i, j, k;
838
839 i = r->v2.x - r->v1.x;
840 j = r->v2.y - r->v1.y;
841 k = r->v2.z - r->v1.z;
842
843 t = -(v->x * r->v1.x + v->y * r->v1.y + v->z * r->v1.z - plane->b) /
844 (v->x * i + v->y * j + v->z * k);
845
846 return t;
847 }
848
849 static gdouble
checktri(ray * r,triangle * tri)850 checktri (ray * r, triangle * tri)
851 {
852 GimpVector4 ed1, ed2;
853 GimpVector4 tvec, pvec, qvec;
854 gdouble det, idet, t, u, v;
855 GimpVector4 *orig, dir;
856
857 orig = &r->v1;
858 dir = r->v2;
859 vsub (&dir, orig);
860
861 ed1.x = tri->c.x - tri->a.x;
862 ed1.y = tri->c.y - tri->a.y;
863 ed1.z = tri->c.z - tri->a.z;
864 ed2.x = tri->b.x - tri->a.x;
865 ed2.y = tri->b.y - tri->a.y;
866 ed2.z = tri->b.z - tri->a.z;
867 vcross (&pvec, &dir, &ed2);
868 det = vdot (&ed1, &pvec);
869
870 idet = 1.0 / det;
871
872 tvec.x = orig->x;
873 tvec.y = orig->y;
874 tvec.z = orig->z;
875 vsub (&tvec, &tri->a);
876 u = vdot (&tvec, &pvec) * idet;
877
878 if (u < 0.0)
879 return 0;
880 if (u > 1.0)
881 return 0;
882
883 vcross (&qvec, &tvec, &ed1);
884 v = vdot (&dir, &qvec) * idet;
885
886 if ((v < 0.0) || (u + v > 1.0))
887 return 0;
888
889 t = vdot (&ed2, &qvec) * idet;
890
891 return t;
892 }
893
894 static void
transformpoint(GimpVector4 * p,texture * t)895 transformpoint (GimpVector4 * p, texture * t)
896 {
897 gdouble point[3], f;
898
899 if ((t->rotate.x != 0.0) || (t->rotate.y != 0.0) || (t->rotate.z != 0.0))
900 vvrotate (p, &t->rotate);
901 vvdiv (p, &t->scale);
902
903 vsub (p, &t->translate);
904
905 if ((t->turbulence.x != 0.0) || (t->turbulence.y != 0.0) ||
906 (t->turbulence.z != 0.0))
907 {
908 point[0] = p->x;
909 point[1] = p->y;
910 point[2] = p->z;
911 f = turbulence (point, 1, 256);
912 p->x += t->turbulence.x * f;
913 p->y += t->turbulence.y * f;
914 p->z += t->turbulence.z * f;
915 }
916 }
917
918 static void
checker(GimpVector4 * q,GimpVector4 * col,texture * t)919 checker (GimpVector4 *q, GimpVector4 *col, texture *t)
920 {
921 gint c = 0;
922 GimpVector4 p;
923
924 p = *q;
925 transformpoint (&p, t);
926
927 vmul (&p, 0.25);
928
929 p.x += 0.00001;
930 p.y += 0.00001;
931 p.z += 0.00001;
932
933 if (p.x < 0.0)
934 p.x = 0.5 - p.x;
935 if (p.y < 0.0)
936 p.y = 0.5 - p.y;
937 if (p.z < 0.0)
938 p.z = 0.5 - p.z;
939
940 if ((p.x - (gint) p.x) < 0.5)
941 c ^= 1;
942 if ((p.y - (gint) p.y) < 0.5)
943 c ^= 1;
944 if ((p.z - (gint) p.z) < 0.5)
945 c ^= 1;
946
947 *col = (c) ? t->color1 : t->color2;
948 }
949
950 static void
gradcolor(GimpVector4 * col,gradient * t,gdouble val)951 gradcolor (GimpVector4 *col, gradient *t, gdouble val)
952 {
953 gint i;
954 gdouble d;
955 GimpVector4 tmpcol;
956
957 val = CLAMP (val, 0.0, 1.0);
958
959 for (i = 0; i < t->numcol; i++)
960 {
961 if (t->pos[i] == val)
962 {
963 *col = t->color[i];
964 return;
965 }
966 if (t->pos[i] > val)
967 {
968 d = (val - t->pos[i - 1]) / (t->pos[i] - t->pos[i - 1]);
969 vcopy (&tmpcol, &t->color[i]);
970 vmul (&tmpcol, d);
971 vcopy (col, &tmpcol);
972 vcopy (&tmpcol, &t->color[i - 1]);
973 vmul (&tmpcol, 1.0 - d);
974 vadd (col, &tmpcol);
975 return;
976 }
977 }
978 g_printerr ("Error in gradient!\n");
979 vset (col, 0, 1, 0);
980 }
981
982 static void
marble(GimpVector4 * q,GimpVector4 * col,texture * t)983 marble (GimpVector4 *q, GimpVector4 *col, texture *t)
984 {
985 gdouble f;
986 GimpVector4 p;
987
988 p = *q;
989 transformpoint (&p, t);
990
991 f = sin (p.x * 4) / 2 + 0.5;
992 f = pow (f, t->exp);
993
994 if (t->flags & GRADIENT)
995 gradcolor (col, &t->gradient, f);
996 else
997 vmix (col, &t->color1, &t->color2, f);
998 }
999
1000 static void
lizard(GimpVector4 * q,GimpVector4 * col,texture * t)1001 lizard (GimpVector4 *q, GimpVector4 *col, texture *t)
1002 {
1003 gdouble f;
1004 GimpVector4 p;
1005
1006 p = *q;
1007 transformpoint (&p, t);
1008
1009 f = fabs (sin (p.x * 4));
1010 f += fabs (sin (p.y * 4));
1011 f += fabs (sin (p.z * 4));
1012 f /= 3.0;
1013 f = pow (f, t->exp);
1014
1015 if (t->flags & GRADIENT)
1016 gradcolor (col, &t->gradient, f);
1017 else
1018 vmix (col, &t->color1, &t->color2, f);
1019 }
1020
1021 static void
wood(GimpVector4 * q,GimpVector4 * col,texture * t)1022 wood (GimpVector4 *q, GimpVector4 *col, texture *t)
1023 {
1024 gdouble f;
1025 GimpVector4 p;
1026
1027 p = *q;
1028 transformpoint (&p, t);
1029
1030 f = fabs (p.x);
1031 f = f - (int) f;
1032
1033 f = pow (f, t->exp);
1034
1035 if (t->flags & GRADIENT)
1036 gradcolor (col, &t->gradient, f);
1037 else
1038 vmix (col, &t->color1, &t->color2, f);
1039 }
1040
1041 static void
spiral(GimpVector4 * q,GimpVector4 * col,texture * t)1042 spiral (GimpVector4 *q, GimpVector4 *col, texture *t)
1043 {
1044 gdouble f;
1045 GimpVector4 p;
1046
1047 p = *q;
1048 transformpoint (&p, t);
1049
1050 f = fabs (atan2 (p.x, p.z) / G_PI / 2 + p.y + 99999);
1051 f = f - (int) f;
1052
1053 f = pow (f, t->exp);
1054
1055 if (t->flags & GRADIENT)
1056 gradcolor (col, &t->gradient, f);
1057 else
1058 vmix (col, &t->color1, &t->color2, f);
1059 }
1060
1061 static void
spots(GimpVector4 * q,GimpVector4 * col,texture * t)1062 spots (GimpVector4 *q, GimpVector4 *col, texture *t)
1063 {
1064 gdouble f;
1065 GimpVector4 p, r;
1066
1067 p = *q;
1068 transformpoint (&p, t);
1069
1070 p.x += 10000.0;
1071 p.y += 10000.0;
1072 p.z += 10000.0;
1073
1074 vset (&r, (gint) (p.x + 0.5), (gint) (p.y + 0.5), (gint) (p.z + 0.5));
1075 f = vdist (&p, &r);
1076 f = cos (f * G_PI);
1077 f = CLAMP (f, 0.0, 1.0);
1078 f = pow (f, t->exp);
1079
1080 if (t->flags & GRADIENT)
1081 gradcolor (col, &t->gradient, f);
1082 else
1083 vmix (col, &t->color1, &t->color2, f);
1084 }
1085
1086 static void
perlin(GimpVector4 * q,GimpVector4 * col,texture * t)1087 perlin (GimpVector4 * q, GimpVector4 * col, texture * t)
1088 {
1089 gdouble f, point[3];
1090 GimpVector4 p;
1091
1092 p = *q;
1093 transformpoint (&p, t);
1094
1095 point[0] = p.x;
1096 point[1] = p.y;
1097 point[2] = p.z;
1098
1099 f = turbulence (point, 1, 256) * 0.3 + 0.5;
1100
1101 f = pow (f, t->exp);
1102
1103 if (t->flags & GRADIENT)
1104 gradcolor (col, &t->gradient, f);
1105 else
1106 vmix (col, &t->color1, &t->color2, f);
1107 }
1108
1109 static void
imagepixel(GimpVector4 * q,GimpVector4 * col,texture * t)1110 imagepixel (GimpVector4 * q, GimpVector4 * col, texture * t)
1111 {
1112 GimpVector4 p;
1113 gint x, y;
1114 guchar *rgb;
1115
1116 p = *q;
1117 transformpoint (&p, t);
1118
1119 x = (p.x * t->image.xsize);
1120 y = (p.y * t->image.ysize);
1121
1122 x = (x % t->image.xsize + t->image.xsize) % t->image.xsize;
1123 y = (y % t->image.ysize + t->image.ysize) % t->image.ysize;
1124
1125 rgb = &t->image.rgb[x * 3 + (t->image.ysize - 1 - y) * t->image.xsize * 3];
1126 vset (col, rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0);
1127 }
1128
1129 static void
objcolor(GimpVector4 * col,GimpVector4 * p,common * obj)1130 objcolor (GimpVector4 *col, GimpVector4 *p, common *obj)
1131 {
1132 gint i;
1133 texture *t;
1134 GimpVector4 tmpcol;
1135
1136 vcset (col, 0, 0, 0, 0);
1137
1138 for (i = 0; i < obj->numtexture; i++)
1139 {
1140 t = &obj->texture[i];
1141
1142 if (world.quality < 1)
1143 {
1144 vadd (col, &t->color1);
1145 continue;
1146 }
1147
1148 vset (&tmpcol, 0, 0, 0);
1149 switch (t->type)
1150 {
1151 case SOLID:
1152 vcopy (&tmpcol, &t->color1);
1153 break;
1154 case CHECKER:
1155 checker (p, &tmpcol, t);
1156 break;
1157 case MARBLE:
1158 marble (p, &tmpcol, t);
1159 break;
1160 case LIZARD:
1161 lizard (p, &tmpcol, t);
1162 break;
1163 case PERLIN:
1164 perlin (p, &tmpcol, t);
1165 break;
1166 case WOOD:
1167 wood (p, &tmpcol, t);
1168 break;
1169 case SPIRAL:
1170 spiral (p, &tmpcol, t);
1171 break;
1172 case SPOTS:
1173 spots (p, &tmpcol, t);
1174 break;
1175 case IMAGE:
1176 imagepixel (p, &tmpcol, t);
1177 break;
1178 case PHONG:
1179 case REFRACTION:
1180 case REFLECTION:
1181 case TRANSPARENT:
1182 case SMOKE:
1183 /* Silently ignore non-color textures */
1184 continue;
1185 break;
1186 default:
1187 g_printerr ("Warning: unknown texture %d\n", t->type);
1188 break;
1189 }
1190 vmul (&tmpcol, t->amount);
1191 vadd (col, &tmpcol);
1192 }
1193 if (!i)
1194 {
1195 g_printerr ("Warning: object %p has no textures\n", obj);
1196 }
1197 }
1198
1199 static void
objnormal(GimpVector4 * res,common * obj,GimpVector4 * p)1200 objnormal (GimpVector4 *res, common *obj, GimpVector4 *p)
1201 {
1202 gint i;
1203
1204 switch (obj->type)
1205 {
1206 case TRIANGLE:
1207 trianglenormal (res, NULL, (triangle *) obj);
1208 break;
1209 case DISC:
1210 vcopy (res, &((disc *) obj)->a);
1211 break;
1212 case PLANE:
1213 vcopy (res, &((plane *) obj)->a);
1214 break;
1215 case SPHERE:
1216 vcopy (res, &((sphere *) obj)->a);
1217 vsub (res, p);
1218 break;
1219 case CYLINDER:
1220 vset (res, 1, 1, 1); /* fixme */
1221 break;
1222 default:
1223 g_error ("objnormal(): Unsupported object type!?\n");
1224 }
1225 vnorm (res, 1.0);
1226
1227 for (i = 0; i < obj->numnormal; i++)
1228 {
1229 gint k;
1230 GimpVector4 tmpcol[6];
1231 GimpVector4 q[6], nres;
1232 texture *t = &obj->normal[i];
1233 gdouble nstep = 0.1;
1234
1235 vset (&nres, 0, 0, 0);
1236 for (k = 0; k < 6; k++)
1237 {
1238 vcopy (&q[k], p);
1239 }
1240 q[0].x += nstep;
1241 q[1].x -= nstep;
1242 q[2].y += nstep;
1243 q[3].y -= nstep;
1244 q[4].z += nstep;
1245 q[5].z -= nstep;
1246
1247 switch (t->type)
1248 {
1249 case MARBLE:
1250 for (k = 0; k < 6; k++)
1251 marble (&q[k], &tmpcol[k], t);
1252 break;
1253 case LIZARD:
1254 for (k = 0; k < 6; k++)
1255 lizard (&q[k], &tmpcol[k], t);
1256 break;
1257 case PERLIN:
1258 for (k = 0; k < 6; k++)
1259 perlin (&q[k], &tmpcol[k], t);
1260 break;
1261 case WOOD:
1262 for (k = 0; k < 6; k++)
1263 wood (&q[k], &tmpcol[k], t);
1264 break;
1265 case SPIRAL:
1266 for (k = 0; k < 6; k++)
1267 spiral (&q[k], &tmpcol[k], t);
1268 break;
1269 case SPOTS:
1270 for (k = 0; k < 6; k++)
1271 spots (&q[k], &tmpcol[k], t);
1272 break;
1273 case IMAGE:
1274 for (k = 0; k < 6; k++)
1275 imagepixel (&q[k], &tmpcol[k], t);
1276 break;
1277 case CHECKER:
1278 case SOLID:
1279 case PHONG:
1280 case REFRACTION:
1281 case REFLECTION:
1282 case TRANSPARENT:
1283 case SMOKE:
1284 continue;
1285 break;
1286 default:
1287 g_printerr ("Warning: unknown texture %d\n", t->type);
1288 break;
1289 }
1290
1291 nres.x = tmpcol[0].x - tmpcol[1].x;
1292 nres.y = tmpcol[2].x - tmpcol[3].x;
1293 nres.z = tmpcol[4].x - tmpcol[5].x;
1294 vadd (&nres, res);
1295 vnorm (&nres, 1.0);
1296 vmul (&nres, t->amount);
1297 vadd (res, &nres);
1298 vnorm (res, 1.0);
1299 }
1300 }
1301
1302 /*
1303 Quality:
1304 0 = Color only
1305 1 = Textures
1306 2 = Light + Normals
1307 3 = Shadows
1308 4 = Phong
1309 5 = Reflection + Refraction
1310 */
1311
1312 static void
calclight(GimpVector4 * col,GimpVector4 * point,common * obj)1313 calclight (GimpVector4 * col, GimpVector4 * point, common * obj)
1314 {
1315 gint i, j;
1316 ray r;
1317 gdouble b, a;
1318 GimpVector4 lcol;
1319 GimpVector4 norm;
1320 GimpVector4 pcol;
1321
1322 vcset (col, 0, 0, 0, 0);
1323
1324 objcolor (&pcol, point, obj);
1325 a = pcol.w;
1326
1327 if (world.quality < 2)
1328 {
1329 vcopy (col, &pcol);
1330 return;
1331 }
1332
1333 for (i = 0; i < obj->numtexture; i++)
1334 {
1335 if (obj->texture[i].type == PHONG)
1336 continue;
1337 if (obj->texture[i].type == REFLECTION)
1338 continue;
1339 if (obj->texture[i].type == REFRACTION)
1340 continue;
1341 if (obj->texture[i].type == TRANSPARENT)
1342 continue;
1343 if (obj->texture[i].type == SMOKE)
1344 continue;
1345 vcopy (&lcol, &pcol);
1346 vvmul (&lcol, &obj->texture[i].ambient);
1347 vadd (col, &lcol);
1348 }
1349
1350 objnormal (&norm, obj, point);
1351 vnorm (&norm, 1.0);
1352
1353 r.inside = -1;
1354 r.ior = 1.0;
1355
1356 for (i = 0; i < world.numlight; i++)
1357 {
1358 vcopy (&r.v1, point);
1359 vcopy (&r.v2, &world.light[i].a);
1360 vmix (&r.v1, &r.v1, &r.v2, 0.9999);
1361
1362 vsub (&r.v1, &r.v2);
1363 vnorm (&r.v1, 1.0);
1364 b = vdot (&r.v1, &norm);
1365
1366 if (b < 0.0)
1367 continue;
1368
1369 for (j = 0; j < obj->numtexture; j++)
1370 {
1371 if (obj->texture[j].type == PHONG)
1372 continue;
1373 if (obj->texture[j].type == REFLECTION)
1374 continue;
1375 if (obj->texture[j].type == REFRACTION)
1376 continue;
1377 if (obj->texture[j].type == TRANSPARENT)
1378 continue;
1379 if (obj->texture[j].type == SMOKE)
1380 continue;
1381 vcopy (&lcol, &pcol);
1382 vvmul (&lcol, &world.light[i].color);
1383 vvmul (&lcol, &obj->texture[j].diffuse);
1384 vmul (&lcol, b);
1385 vadd (col, &lcol);
1386 }
1387 }
1388 col->w = a;
1389 }
1390
1391 static void
calcphong(common * obj,ray * r2,GimpVector4 * col)1392 calcphong (common * obj, ray * r2, GimpVector4 * col)
1393 {
1394 gint i, j;
1395 ray r;
1396 gdouble b;
1397 GimpVector4 lcol;
1398 GimpVector4 norm;
1399 GimpVector4 pcol;
1400 gdouble ps;
1401
1402 vcopy (&pcol, col);
1403
1404 vcopy (&norm, &r2->v2);
1405 vsub (&norm, &r2->v1);
1406 vnorm (&norm, 1.0);
1407
1408 r.inside = -1;
1409 r.ior = 1.0;
1410
1411 for (i = 0; i < world.numlight; i++)
1412 {
1413 vcopy (&r.v1, &r2->v1);
1414 vcopy (&r.v2, &world.light[i].a);
1415 vmix (&r.v1, &r.v1, &r.v2, 0.9999);
1416
1417 if (traceray (&r, NULL, -1, 1.0))
1418 continue;
1419
1420 /* OK, light is visible */
1421
1422 vsub (&r.v1, &r.v2);
1423 vnorm (&r.v1, 1.0);
1424 b = -vdot (&r.v1, &norm);
1425
1426 for (j = 0; j < obj->numtexture; j++)
1427 {
1428 if (obj->texture[j].type != PHONG)
1429 continue;
1430
1431 ps = obj->texture[j].phongsize;
1432
1433 if (b < (1 - ps))
1434 continue;
1435 ps = (b - (1 - ps)) / ps;
1436
1437 vcopy (&lcol, &obj->texture[j].phongcolor);
1438 vvmul (&lcol, &world.light[i].color);
1439 vmul (&lcol, ps);
1440 vadd (col, &lcol);
1441 }
1442 }
1443 }
1444
1445 static int
traceray(ray * r,GimpVector4 * col,gint level,gdouble imp)1446 traceray (ray * r, GimpVector4 * col, gint level, gdouble imp)
1447 {
1448 gint i, b = -1;
1449 gdouble t = -1.0, min = 0.0;
1450 common *obj, *bobj = NULL;
1451 gint hits = 0;
1452 GimpVector4 p;
1453
1454 if ((level == 0) || (imp < 0.005))
1455 {
1456 vset (col, 0, 1, 0);
1457 return 0;
1458 }
1459
1460 for (i = 0; i < world.numobj; i++)
1461 {
1462 obj = (common *) & world.obj[i];
1463 switch (obj->type)
1464 {
1465 case TRIANGLE:
1466 t = checktri (r, (triangle *) & world.obj[i]);
1467 break;
1468 case DISC:
1469 t = checkdisc (r, (disc *) & world.obj[i]);
1470 break;
1471 case PLANE:
1472 t = checkplane (r, (plane *) & world.obj[i]);
1473 break;
1474 case SPHERE:
1475 t = checksphere (r, (sphere *) & world.obj[i]);
1476 break;
1477 case CYLINDER:
1478 t = checkcylinder (r, (cylinder *) & world.obj[i]);
1479 break;
1480 default:
1481 g_error ("Illegal object!!\n");
1482 }
1483 if (t <= 0.0)
1484 continue;
1485
1486 if (!(obj->flags & NOSHADOW) && (level == -1))
1487 {
1488 return i + 1;
1489 }
1490
1491 hits++;
1492 if ((!bobj) || (t < min))
1493 {
1494
1495 min = t;
1496 b = i;
1497 bobj = obj;
1498 }
1499 }
1500 if (level == -1)
1501 return 0;
1502
1503 if (bobj)
1504 {
1505 p.x = r->v1.x + (r->v2.x - r->v1.x) * min;
1506 p.y = r->v1.y + (r->v2.y - r->v1.y) * min;
1507 p.z = r->v1.z + (r->v2.z - r->v1.z) * min;
1508
1509 calclight (col, &p, bobj);
1510
1511 if (world.flags & SMARTAMBIENT)
1512 {
1513 gdouble ambient = 0.3 * exp (-min / world.smartambient);
1514 GimpVector4 lcol;
1515 objcolor (&lcol, &p, bobj);
1516 vmul (&lcol, ambient);
1517 vadd (col, &lcol);
1518 }
1519
1520 for (i = 0; i < bobj->numtexture; i++)
1521 {
1522
1523 if ((world.quality >= 4)
1524 && ((bobj->texture[i].type == REFLECTION)
1525 || (bobj->texture[i].type == PHONG)))
1526 {
1527
1528 GimpVector4 refcol, norm, ocol;
1529 ray ref;
1530
1531 objcolor (&ocol, &p, bobj);
1532
1533 vcopy (&ref.v1, &p);
1534 vcopy (&ref.v2, &r->v1);
1535 ref.inside = r->inside;
1536 ref.ior = r->ior;
1537
1538 vmix (&ref.v1, &ref.v1, &ref.v2, 0.9999); /* push it a tad */
1539
1540 vsub (&ref.v2, &p);
1541 objnormal (&norm, bobj, &p);
1542 vnorm (&norm, 1.0);
1543 vrotate (&norm, 180.0, &ref.v2);
1544
1545 vmul (&norm, -0.0001); /* push it a tad */
1546 vadd (&ref.v1, &norm);
1547
1548 vnorm (&ref.v2, 1.0);
1549 vadd (&ref.v2, &p);
1550
1551 if ((world.quality >= 5)
1552 && (bobj->texture[i].type == REFLECTION))
1553 {
1554 traceray (&ref, &refcol, level - 1,
1555 imp * vmax (&bobj->texture[i].reflection));
1556 vvmul (&refcol, &bobj->texture[i].reflection);
1557 refcol.w = ocol.w;
1558 vadd (col, &refcol);
1559 }
1560 if (bobj->texture[i].type == PHONG)
1561 {
1562 vcset (&refcol, 0, 0, 0, 0);
1563 calcphong (bobj, &ref, &refcol);
1564 refcol.w = ocol.w;
1565 vadd (col, &refcol);
1566 }
1567
1568 }
1569
1570 if ((world.quality >= 5) && (col->w < 1.0))
1571 {
1572 GimpVector4 refcol;
1573 ray ref;
1574
1575 vcopy (&ref.v1, &p);
1576 vcopy (&ref.v2, &p);
1577 vsub (&ref.v2, &r->v1);
1578 vnorm (&ref.v2, 1.0);
1579 vadd (&ref.v2, &p);
1580
1581 vmix (&ref.v1, &ref.v1, &ref.v2, 0.999); /* push it a tad */
1582 traceray (&ref, &refcol, level - 1, imp * (1.0 - col->w));
1583 vmul (&refcol, (1.0 - col->w));
1584 vadd (col, &refcol);
1585 }
1586
1587 if ((world.quality >= 5) && (bobj->texture[i].type == TRANSPARENT))
1588 {
1589 GimpVector4 refcol;
1590 ray ref;
1591
1592 vcopy (&ref.v1, &p);
1593 vcopy (&ref.v2, &p);
1594 vsub (&ref.v2, &r->v1);
1595 vnorm (&ref.v2, 1.0);
1596 vadd (&ref.v2, &p);
1597
1598 vmix (&ref.v1, &ref.v1, &ref.v2, 0.999); /* push it a tad */
1599
1600 traceray (&ref, &refcol, level - 1,
1601 imp * vmax (&bobj->texture[i].transparent));
1602 vvmul (&refcol, &bobj->texture[i].transparent);
1603
1604 vadd (col, &refcol);
1605 }
1606
1607 if ((world.quality >= 5) && (bobj->texture[i].type == SMOKE))
1608 {
1609 GimpVector4 smcol, raydir, norm;
1610 double tran;
1611 ray ref;
1612
1613 vcopy (&ref.v1, &p);
1614 vcopy (&ref.v2, &p);
1615 vsub (&ref.v2, &r->v1);
1616 vnorm (&ref.v2, 1.0);
1617 vadd (&ref.v2, &p);
1618
1619 objnormal (&norm, bobj, &p);
1620 vcopy (&raydir, &r->v2);
1621 vsub (&raydir, &r->v1);
1622 vnorm (&raydir, 1.0);
1623 tran = vdot (&norm, &raydir);
1624 if (tran < 0.0)
1625 continue;
1626 tran *= tran;
1627 vcopy (&smcol, &bobj->texture[i].color1);
1628 vmul (&smcol, tran);
1629 vadd (col, &smcol);
1630 }
1631
1632 if ((world.quality >= 5) && (bobj->texture[i].type == REFRACTION))
1633 {
1634 GimpVector4 refcol, norm, tmpv;
1635 ray ref;
1636 double c1, c2, n1, n2, n;
1637
1638 vcopy (&ref.v1, &p);
1639 vcopy (&ref.v2, &p);
1640 vsub (&ref.v2, &r->v1);
1641 vadd (&ref.v2, &r->v2);
1642
1643 vmix (&ref.v1, &ref.v1, &ref.v2, 0.999); /* push it a tad */
1644
1645 vsub (&ref.v2, &p);
1646 objnormal (&norm, bobj, &p);
1647
1648 if (r->inside == b)
1649 {
1650 ref.inside = -1;
1651 ref.ior = 1.0;
1652 }
1653 else
1654 {
1655 ref.inside = b;
1656 ref.ior = bobj->texture[i].ior;
1657 }
1658
1659 c1 = vdot (&norm, &ref.v2);
1660
1661 if (ref.inside < 0)
1662 c1 = -c1;
1663
1664 n1 = r->ior; /* IOR of current media */
1665 n2 = ref.ior; /* IOR of new media */
1666 n = n1 / n2;
1667 c2 = 1.0 - n * n * (1.0 - c1 * c1);
1668
1669 if (c2 < 0.0)
1670 {
1671 /* FIXME: Internal reflection should occur */
1672 c2 = sqrt (-c2);
1673
1674 }
1675 else
1676 {
1677 c2 = sqrt (c2);
1678 }
1679
1680 vmul (&ref.v2, n);
1681 vcopy (&tmpv, &norm);
1682 vmul (&tmpv, n * c1 - c2);
1683 vadd (&ref.v2, &tmpv);
1684
1685 vnorm (&ref.v2, 1.0);
1686 vadd (&ref.v2, &p);
1687
1688 traceray (&ref, &refcol, level - 1,
1689 imp * vmax (&bobj->texture[i].refraction));
1690
1691 vvmul (&refcol, &bobj->texture[i].refraction);
1692 vadd (col, &refcol);
1693 }
1694 }
1695 }
1696 else
1697 {
1698 vcset (col, 0, 0, 0, 0);
1699 min = 10000.0;
1700 vcset (&p, 0, 0, 0, 0);
1701 }
1702
1703 for (i = 0; i < world.numatmos; i++)
1704 {
1705 GimpVector4 tmpcol;
1706 if (world.atmos[i].type == FOG)
1707 {
1708 gdouble v, pt[3];
1709 pt[0] = p.x;
1710 pt[1] = p.y;
1711 pt[2] = p.z;
1712 if ((v = world.atmos[i].turbulence) > 0.0)
1713 v = turbulence (pt, 1, 256) * world.atmos[i].turbulence;
1714 v = exp (-(min + v) / world.atmos[i].density);
1715 vmul (col, v);
1716 vcopy (&tmpcol, &world.atmos[i].color);
1717 vmul (&tmpcol, 1.0 - v);
1718 vadd (col, &tmpcol);
1719 }
1720 }
1721
1722 return hits;
1723 }
1724
1725 static void
setdefaults(texture * t)1726 setdefaults (texture * t)
1727 {
1728 memset (t, 0, sizeof (texture));
1729 t->type = SOLID;
1730 vcset (&t->color1, 1, 1, 1, 1);
1731 vcset (&t->color2, 0, 0, 0, 1);
1732 vcset (&t->diffuse, 1, 1, 1, 1);
1733 vcset (&t->ambient, 0, 0, 0, 1);
1734 vset (&t->scale, 1, 1, 1);
1735 vset (&t->rotate, 0, 0, 0);
1736 vset (&t->translate, 0, 0, 0);
1737 t->oscale = 1.0;
1738 t->amount = 1.0;
1739 t->exp = 1.0;
1740 }
1741
1742 static gchar *
mklabel(texture * t)1743 mklabel (texture * t)
1744 {
1745 struct textures_t *l;
1746 static gchar tmps[100];
1747
1748 if (t->majtype == 0)
1749 strcpy (tmps, _("Texture"));
1750 else if (t->majtype == 1)
1751 strcpy (tmps, _("Bumpmap"));
1752 else if (t->majtype == 2)
1753 strcpy (tmps, _("Light"));
1754 else
1755 strcpy (tmps, "<unknown>");
1756 if ((t->majtype == 0) || (t->majtype == 1))
1757 {
1758 strcat (tmps, " / ");
1759 l = textures;
1760 while (l->s)
1761 {
1762 if (t->type == l->n)
1763 {
1764 strcat (tmps, gettext (l->s));
1765 break;
1766 }
1767 l++;
1768 }
1769 }
1770 return tmps;
1771 }
1772
1773 static texture *
currenttexture(void)1774 currenttexture (void)
1775 {
1776 GtkTreeSelection *sel;
1777 GtkTreeIter iter;
1778 texture *t = NULL;
1779
1780 sel = gtk_tree_view_get_selection (texturelist);
1781
1782 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1783 {
1784 gtk_tree_model_get (gtk_tree_view_get_model (texturelist), &iter,
1785 TEXTURE, &t,
1786 -1);
1787 }
1788
1789 return t;
1790 }
1791
1792 static void
relabel(void)1793 relabel (void)
1794 {
1795 GtkTreeModel *model;
1796 GtkTreeSelection *sel;
1797 GtkTreeIter iter;
1798 texture *t = NULL;
1799
1800 sel = gtk_tree_view_get_selection (texturelist);
1801
1802 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1803 {
1804 model = gtk_tree_view_get_model (texturelist);
1805
1806 gtk_tree_model_get (model, &iter,
1807 TEXTURE, &t,
1808 -1);
1809 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1810 TYPE, mklabel (t),
1811 -1);
1812 }
1813 }
1814
1815 static gboolean noupdate = FALSE;
1816
1817 static void
setvals(texture * t)1818 setvals (texture *t)
1819 {
1820 struct textures_t *l;
1821
1822 if (!t)
1823 return;
1824
1825 noupdate = TRUE;
1826 gtk_adjustment_set_value (GTK_ADJUSTMENT (amountscale), t->amount);
1827
1828 gtk_adjustment_set_value (GTK_ADJUSTMENT (scalescale), t->oscale);
1829
1830 gtk_adjustment_set_value (GTK_ADJUSTMENT (scalexscale), t->scale.x);
1831 gtk_adjustment_set_value (GTK_ADJUSTMENT (scaleyscale), t->scale.y);
1832 gtk_adjustment_set_value (GTK_ADJUSTMENT (scalezscale), t->scale.z);
1833
1834 gtk_adjustment_set_value (GTK_ADJUSTMENT (rotxscale), t->rotate.x);
1835 gtk_adjustment_set_value (GTK_ADJUSTMENT (rotyscale), t->rotate.y);
1836 gtk_adjustment_set_value (GTK_ADJUSTMENT (rotzscale), t->rotate.z);
1837
1838 gtk_adjustment_set_value (GTK_ADJUSTMENT (posxscale), t->translate.x);
1839 gtk_adjustment_set_value (GTK_ADJUSTMENT (posyscale), t->translate.y);
1840 gtk_adjustment_set_value (GTK_ADJUSTMENT (poszscale), t->translate.z);
1841
1842 gtk_adjustment_set_value (GTK_ADJUSTMENT (turbulencescale),
1843 t->turbulence.x);
1844 gtk_adjustment_set_value (GTK_ADJUSTMENT (expscale), t->exp);
1845
1846 drawcolor1 (NULL);
1847 drawcolor2 (NULL);
1848
1849 l = textures;
1850 while (l->s)
1851 {
1852 if (l->n == t->type)
1853 {
1854 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (texturemenu),
1855 l->index);
1856 break;
1857 }
1858 l++;
1859 }
1860
1861 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (typemenu), t->majtype);
1862
1863 noupdate = FALSE;
1864 }
1865
1866 static void
selectitem(GtkTreeSelection * treeselection,gpointer data)1867 selectitem (GtkTreeSelection *treeselection,
1868 gpointer data)
1869 {
1870 setvals (currenttexture ());
1871 }
1872
1873 static void
addtexture(void)1874 addtexture (void)
1875 {
1876 GtkListStore *list_store;
1877 GtkTreeIter iter;
1878 gint n = s.com.numtexture;
1879
1880 if (n == MAXTEXTUREPEROBJ - 1)
1881 return;
1882
1883 setdefaults (&s.com.texture[n]);
1884
1885 list_store = GTK_LIST_STORE (gtk_tree_view_get_model (texturelist));
1886
1887 gtk_list_store_append (list_store, &iter);
1888 gtk_list_store_set (list_store, &iter,
1889 TYPE, mklabel (&s.com.texture[n]),
1890 TEXTURE, &s.com.texture[n],
1891 -1);
1892 gtk_tree_selection_select_iter (gtk_tree_view_get_selection (texturelist),
1893 &iter);
1894
1895 s.com.numtexture++;
1896
1897 restartrender ();
1898 }
1899
1900 static void
duptexture(void)1901 duptexture (void)
1902 {
1903 GtkListStore *list_store;
1904 GtkTreeIter iter;
1905 texture *t = currenttexture ();
1906 gint n = s.com.numtexture;
1907
1908 if (n == MAXTEXTUREPEROBJ - 1)
1909 return;
1910 if (!t)
1911 return;
1912
1913 s.com.texture[n] = *t;
1914
1915 list_store = GTK_LIST_STORE (gtk_tree_view_get_model (texturelist));
1916
1917 gtk_list_store_append (list_store, &iter);
1918 gtk_list_store_set (list_store, &iter,
1919 TYPE, mklabel (&s.com.texture[n]),
1920 TEXTURE, &s.com.texture[n],
1921 -1);
1922 gtk_tree_selection_select_iter (gtk_tree_view_get_selection (texturelist),
1923 &iter);
1924
1925 s.com.numtexture++;
1926
1927 restartrender ();
1928 }
1929
1930 static void
rebuildlist(void)1931 rebuildlist (void)
1932 {
1933 GtkListStore *list_store;
1934 GtkTreeSelection *sel;
1935 GtkTreeIter iter;
1936 gint n;
1937
1938 sel = gtk_tree_view_get_selection (texturelist);
1939
1940 for (n = 0; n < s.com.numtexture; n++)
1941 {
1942 if (s.com.numtexture && (s.com.texture[n].majtype < 0))
1943 {
1944 gint i;
1945
1946 for (i = n; i < s.com.numtexture - 1; i++)
1947 s.com.texture[i] = s.com.texture[i + 1];
1948
1949 s.com.numtexture--;
1950 n--;
1951 }
1952 }
1953
1954 list_store = GTK_LIST_STORE (gtk_tree_view_get_model (texturelist));
1955
1956 for (n = 0; n < s.com.numtexture; n++)
1957 {
1958 gtk_list_store_append (list_store, &iter);
1959 gtk_list_store_set (list_store, &iter,
1960 TYPE, mklabel (&s.com.texture[n]),
1961 TEXTURE, &s.com.texture[n],
1962 -1);
1963 }
1964
1965 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter))
1966 gtk_tree_selection_select_iter (sel, &iter);
1967
1968 restartrender ();
1969 }
1970
1971 static void
deltexture(void)1972 deltexture (void)
1973 {
1974 GtkTreeSelection *sel;
1975 GtkTreeModel *model;
1976 GtkTreeIter iter;
1977 texture *t = NULL;
1978
1979 sel = gtk_tree_view_get_selection (texturelist);
1980
1981 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1982 {
1983 model = gtk_tree_view_get_model (texturelist);
1984
1985 gtk_tree_model_get (model, &iter,
1986 TEXTURE, &t,
1987 -1);
1988 t->majtype = -1;
1989 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1990 }
1991
1992 restartrender ();
1993 }
1994
1995 static void
loadit(const gchar * fn)1996 loadit (const gchar * fn)
1997 {
1998 FILE *f;
1999 gchar endbuf[21 * (G_ASCII_DTOSTR_BUF_SIZE + 1)];
2000 gchar *end = endbuf;
2001 gchar line[1024];
2002 gchar fmt_str[16];
2003 gint i;
2004 texture *t;
2005 gint majtype, type;
2006
2007 f = g_fopen (fn, "rt");
2008 if (! f)
2009 {
2010 g_message (_("Could not open '%s' for reading: %s"),
2011 gimp_filename_to_utf8 (fn), g_strerror (errno));
2012 return;
2013 }
2014
2015 if (2 != fscanf (f, "%d %d", &majtype, &type) || majtype < 0 || majtype > 2)
2016 {
2017 g_message (_("File '%s' is not a valid save file."),
2018 gimp_filename_to_utf8 (fn));
2019 fclose (f);
2020 return;
2021 }
2022
2023 rewind (f);
2024
2025 s.com.numtexture = 0;
2026
2027 snprintf (fmt_str, sizeof (fmt_str), "%%d %%d %%%" G_GSIZE_FORMAT "s", sizeof (endbuf) - 1);
2028
2029 while (!feof (f))
2030 {
2031
2032 if (!fgets (line, 1023, f))
2033 break;
2034
2035 i = s.com.numtexture;
2036 t = &s.com.texture[i];
2037 setdefaults (t);
2038
2039 if (sscanf (line, fmt_str, &t->majtype, &t->type, end) != 3)
2040 t->color1.x = g_ascii_strtod (end, &end);
2041 if (end && errno != ERANGE)
2042 t->color1.y = g_ascii_strtod (end, &end);
2043 if (end && errno != ERANGE)
2044 t->color1.z = g_ascii_strtod (end, &end);
2045 if (end && errno != ERANGE)
2046 t->color1.w = g_ascii_strtod (end, &end);
2047 if (end && errno != ERANGE)
2048 t->color2.x = g_ascii_strtod (end, &end);
2049 if (end && errno != ERANGE)
2050 t->color2.y = g_ascii_strtod (end, &end);
2051 if (end && errno != ERANGE)
2052 t->color2.z = g_ascii_strtod (end, &end);
2053 if (end && errno != ERANGE)
2054 t->color2.w = g_ascii_strtod (end, &end);
2055 if (end && errno != ERANGE)
2056 t->oscale = g_ascii_strtod (end, &end);
2057 if (end && errno != ERANGE)
2058 t->turbulence.x = g_ascii_strtod (end, &end);
2059 if (end && errno != ERANGE)
2060 t->amount = g_ascii_strtod (end, &end);
2061 if (end && errno != ERANGE)
2062 t->exp = g_ascii_strtod (end, &end);
2063 if (end && errno != ERANGE)
2064 t->scale.x = g_ascii_strtod (end, &end);
2065 if (end && errno != ERANGE)
2066 t->scale.y = g_ascii_strtod (end, &end);
2067 if (end && errno != ERANGE)
2068 t->scale.z = g_ascii_strtod (end, &end);
2069 if (end && errno != ERANGE)
2070 t->rotate.x = g_ascii_strtod (end, &end);
2071 if (end && errno != ERANGE)
2072 t->rotate.y = g_ascii_strtod (end, &end);
2073 if (end && errno != ERANGE)
2074 t->rotate.z = g_ascii_strtod (end, &end);
2075 if (end && errno != ERANGE)
2076 t->translate.x = g_ascii_strtod (end, &end);
2077 if (end && errno != ERANGE)
2078 t->translate.y = g_ascii_strtod (end, &end);
2079 if (end && errno != ERANGE)
2080 t->translate.z = g_ascii_strtod (end, &end);
2081
2082 s.com.numtexture++;
2083 }
2084
2085 fclose (f);
2086 }
2087
2088 static void
loadpreset_response(GtkWidget * dialog,gint response_id,gpointer data)2089 loadpreset_response (GtkWidget *dialog,
2090 gint response_id,
2091 gpointer data)
2092 {
2093 if (response_id == GTK_RESPONSE_OK)
2094 {
2095 GtkTreeModel *model = gtk_tree_view_get_model (texturelist);
2096 gchar *name;
2097
2098 name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
2099
2100 gtk_list_store_clear (GTK_LIST_STORE (model));
2101
2102 loadit (name);
2103 g_free (name);
2104
2105 rebuildlist ();
2106 }
2107
2108 gtk_widget_hide (dialog);
2109 }
2110
2111 static void
saveit(const gchar * fn)2112 saveit (const gchar *fn)
2113 {
2114 gint i;
2115 FILE *f;
2116 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
2117
2118 f = g_fopen (fn, "wt");
2119 if (!f)
2120 {
2121 g_message (_("Could not open '%s' for writing: %s"),
2122 gimp_filename_to_utf8 (fn), g_strerror (errno));
2123 return;
2124 }
2125
2126 for (i = 0; i < s.com.numtexture; i++)
2127 {
2128 texture *t = &s.com.texture[i];
2129
2130 if (t->majtype < 0)
2131 continue;
2132
2133 fprintf (f, "%d %d", t->majtype, t->type);
2134 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color1.x));
2135 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color1.y));
2136 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color1.z));
2137 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color1.w));
2138 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color2.x));
2139 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color2.y));
2140 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color2.z));
2141 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->color2.w));
2142 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->oscale));
2143 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->turbulence.x));
2144 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->amount));
2145 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->exp));
2146 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->scale.x));
2147 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->scale.y));
2148 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->scale.z));
2149 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->rotate.x));
2150 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->rotate.y));
2151 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->rotate.z));
2152 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->translate.x));
2153 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->translate.y));
2154 fprintf (f, " %s", g_ascii_dtostr (buf, sizeof (buf), t->translate.z));
2155 fprintf (f, "\n");
2156 }
2157
2158 fclose (f);
2159 }
2160
2161 static void
savepreset_response(GtkWidget * dialog,gint response_id,gpointer data)2162 savepreset_response (GtkWidget *dialog,
2163 gint response_id,
2164 gpointer data)
2165 {
2166 if (response_id == GTK_RESPONSE_OK)
2167 {
2168 gchar *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
2169
2170 saveit (name);
2171 g_free (name);
2172 }
2173
2174 gtk_widget_hide (dialog);
2175 }
2176
2177 static void
loadpreset(GtkWidget * widget,GtkWidget * parent)2178 loadpreset (GtkWidget *widget,
2179 GtkWidget *parent)
2180 {
2181 fileselect (GTK_FILE_CHOOSER_ACTION_OPEN, parent);
2182 }
2183
2184 static void
savepreset(GtkWidget * widget,GtkWidget * parent)2185 savepreset (GtkWidget *widget,
2186 GtkWidget *parent)
2187 {
2188 fileselect (GTK_FILE_CHOOSER_ACTION_SAVE, parent);
2189 }
2190
2191 static void
fileselect(GtkFileChooserAction action,GtkWidget * parent)2192 fileselect (GtkFileChooserAction action,
2193 GtkWidget *parent)
2194 {
2195 static GtkWidget *windows[2] = { NULL, NULL };
2196
2197 gchar *titles[] = { N_("Open File"), N_("Save File") };
2198 void *handlers[] = { loadpreset_response, savepreset_response };
2199
2200 if (! windows[action])
2201 {
2202 GtkWidget *dialog = windows[action] =
2203 gtk_file_chooser_dialog_new (gettext (titles[action]),
2204 GTK_WINDOW (parent),
2205 action,
2206
2207 _("_Cancel"), GTK_RESPONSE_CANCEL,
2208
2209 action == GTK_FILE_CHOOSER_ACTION_OPEN ?
2210 _("_Open") : _("_Save"),
2211 GTK_RESPONSE_OK,
2212
2213 NULL);
2214
2215 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
2216 GTK_RESPONSE_OK,
2217 GTK_RESPONSE_CANCEL,
2218 -1);
2219
2220 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2221
2222 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
2223 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
2224 TRUE);
2225
2226 g_signal_connect (dialog, "destroy",
2227 G_CALLBACK (gtk_widget_destroyed),
2228 &windows[action]);
2229 g_signal_connect (dialog, "response",
2230 G_CALLBACK (handlers[action]),
2231 NULL);
2232 }
2233
2234 gtk_window_present (GTK_WINDOW (windows[action]));
2235 }
2236
2237 static void
initworld(void)2238 initworld (void)
2239 {
2240 gint i;
2241
2242 memset (&world, 0, sizeof (world));
2243
2244 s.com.type = SPHERE;
2245 s.a.x = s.a.y = s.a.z = 0.0;
2246 s.r = 4.0;
2247
2248 /* not: world.obj[0] = s;
2249 * s is a sphere so error C2115: '=' : incompatible types
2250 */
2251 memcpy (&world.obj[0], &s, sizeof (s));
2252 world.numobj = 1;
2253
2254 world.obj[0].com.numtexture = 0;
2255 world.obj[0].com.numnormal = 0;
2256
2257 for (i = 0; i < s.com.numtexture; i++)
2258 {
2259 common *c = &s.com;
2260 common *d = &world.obj[0].com;
2261 texture *t = &c->texture[i];
2262 if ((t->amount <= 0.0) || (t->majtype < 0))
2263 continue;
2264 if (t->majtype == 0)
2265 { /* Normal texture */
2266 if (t->type == PHONG)
2267 {
2268 t->phongcolor = t->color1;
2269 t->phongsize = t->oscale / 25.0;
2270 }
2271 d->texture[d->numtexture] = *t;
2272 vmul (&d->texture[d->numtexture].scale,
2273 d->texture[d->numtexture].oscale);
2274 d->numtexture++;
2275 }
2276 else if (t->majtype == 1)
2277 { /* Bumpmap */
2278 d->normal[d->numnormal] = *t;
2279 vmul (&d->normal[d->numnormal].scale,
2280 d->texture[d->numnormal].oscale);
2281 d->numnormal++;
2282 }
2283 else if (t->majtype == 2)
2284 { /* Lightsource */
2285 light l;
2286 vcopy (&l.a, &t->translate);
2287 vcopy (&l.color, &t->color1);
2288 vmul (&l.color, t->amount);
2289 world.light[world.numlight] = l;
2290 world.numlight++;
2291 }
2292 }
2293
2294 world.quality = 5;
2295
2296 world.flags |= SMARTAMBIENT;
2297 world.smartambient = 40.0;
2298 }
2299
2300 static gboolean
expose_event(GtkWidget * widget,GdkEventExpose * event)2301 expose_event (GtkWidget *widget,
2302 GdkEventExpose *event)
2303 {
2304 cairo_t *cr;
2305
2306 cr = gdk_cairo_create (gtk_widget_get_window (widget));
2307
2308 gdk_cairo_region (cr, event->region);
2309 cairo_clip (cr);
2310
2311 cairo_set_source_surface (cr, buffer, 0.0, 0.0);
2312
2313 cairo_paint (cr);
2314
2315 cairo_destroy (cr);
2316
2317 return TRUE;
2318 }
2319
2320 static void
restartrender(void)2321 restartrender (void)
2322 {
2323 if (idle_id)
2324 g_source_remove (idle_id);
2325
2326 idle_id = g_idle_add ((GSourceFunc) render, NULL);
2327 }
2328
2329 static void
selecttexture(GtkWidget * widget,gpointer data)2330 selecttexture (GtkWidget *widget,
2331 gpointer data)
2332 {
2333 texture *t;
2334
2335 if (noupdate)
2336 return;
2337
2338 t = currenttexture ();
2339 if (!t)
2340 return;
2341
2342 gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &t->type);
2343
2344 relabel ();
2345 restartrender ();
2346 }
2347
2348 static void
selecttype(GtkWidget * widget,gpointer data)2349 selecttype (GtkWidget *widget,
2350 gpointer data)
2351 {
2352 texture *t;
2353
2354 if (noupdate)
2355 return;
2356
2357 t = currenttexture ();
2358 if (!t)
2359 return;
2360
2361 gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &t->majtype);
2362
2363 relabel ();
2364 restartrender ();
2365 }
2366
2367 static void
getscales(GtkWidget * widget,gpointer data)2368 getscales (GtkWidget *widget,
2369 gpointer data)
2370 {
2371 gdouble f;
2372 texture *t;
2373
2374 if (noupdate)
2375 return;
2376
2377 t = currenttexture ();
2378 if (!t)
2379 return;
2380
2381 t->amount = gtk_adjustment_get_value (GTK_ADJUSTMENT (amountscale));
2382 t->exp = gtk_adjustment_get_value (GTK_ADJUSTMENT (expscale));
2383
2384 f = gtk_adjustment_get_value (GTK_ADJUSTMENT (turbulencescale));
2385 vset (&t->turbulence, f, f, f);
2386
2387 t->oscale = gtk_adjustment_get_value (GTK_ADJUSTMENT (scalescale));
2388
2389 t->scale.x = gtk_adjustment_get_value (GTK_ADJUSTMENT (scalexscale));
2390 t->scale.y = gtk_adjustment_get_value (GTK_ADJUSTMENT (scaleyscale));
2391 t->scale.z = gtk_adjustment_get_value (GTK_ADJUSTMENT (scalezscale));
2392
2393 t->rotate.x = gtk_adjustment_get_value (GTK_ADJUSTMENT (rotxscale));
2394 t->rotate.y = gtk_adjustment_get_value (GTK_ADJUSTMENT (rotyscale));
2395 t->rotate.z = gtk_adjustment_get_value (GTK_ADJUSTMENT (rotzscale));
2396
2397 t->translate.x = gtk_adjustment_get_value (GTK_ADJUSTMENT (posxscale));
2398 t->translate.y = gtk_adjustment_get_value (GTK_ADJUSTMENT (posyscale));
2399 t->translate.z = gtk_adjustment_get_value (GTK_ADJUSTMENT (poszscale));
2400
2401 restartrender ();
2402 }
2403
2404
2405 static void
color1_changed(GimpColorButton * button)2406 color1_changed (GimpColorButton *button)
2407 {
2408 texture *t = currenttexture ();
2409
2410 if (t)
2411 {
2412 GimpRGB color;
2413
2414 gimp_color_button_get_color (button, &color);
2415
2416 t->color1.x = color.r;
2417 t->color1.y = color.g;
2418 t->color1.z = color.b;
2419 t->color1.w = color.a;
2420
2421 restartrender ();
2422 }
2423 }
2424
2425 static void
color2_changed(GimpColorButton * button)2426 color2_changed (GimpColorButton *button)
2427 {
2428 texture *t = currenttexture ();
2429
2430 if (t)
2431 {
2432 GimpRGB color;
2433
2434 gimp_color_button_get_color (button, &color);
2435
2436 t->color2.x = color.r;
2437 t->color2.y = color.g;
2438 t->color2.z = color.b;
2439 t->color2.w = color.a;
2440
2441 restartrender ();
2442 }
2443 }
2444
2445 static void
drawcolor1(GtkWidget * w)2446 drawcolor1 (GtkWidget *w)
2447 {
2448 static GtkWidget *lastw = NULL;
2449
2450 GimpRGB color;
2451 texture *t = currenttexture ();
2452
2453 if (w)
2454 lastw = w;
2455 else
2456 w = lastw;
2457
2458 if (!w)
2459 return;
2460 if (!t)
2461 return;
2462
2463 gimp_rgba_set (&color,
2464 t->color1.x, t->color1.y, t->color1.z, t->color1.w);
2465
2466 gimp_color_button_set_color (GIMP_COLOR_BUTTON (w), &color);
2467 }
2468
2469 static void
drawcolor2(GtkWidget * w)2470 drawcolor2 (GtkWidget *w)
2471 {
2472 static GtkWidget *lastw = NULL;
2473
2474 GimpRGB color;
2475 texture *t = currenttexture ();
2476
2477 if (w)
2478 lastw = w;
2479 else
2480 w = lastw;
2481
2482 if (!w)
2483 return;
2484 if (!t)
2485 return;
2486
2487 gimp_rgba_set (&color,
2488 t->color2.x, t->color2.y, t->color2.z, t->color2.w);
2489
2490 gimp_color_button_set_color (GIMP_COLOR_BUTTON (w), &color);
2491 }
2492
2493 static gboolean do_run = FALSE;
2494
2495 static void
sphere_response(GtkWidget * widget,gint response_id,gpointer data)2496 sphere_response (GtkWidget *widget,
2497 gint response_id,
2498 gpointer data)
2499 {
2500 switch (response_id)
2501 {
2502 case RESPONSE_RESET:
2503 s.com.numtexture = 3;
2504
2505 setdefaults (&s.com.texture[0]);
2506 setdefaults (&s.com.texture[1]);
2507 setdefaults (&s.com.texture[2]);
2508
2509 s.com.texture[1].majtype = 2;
2510 vset (&s.com.texture[1].color1, 1, 1, 1);
2511 vset (&s.com.texture[1].translate, -15, -15, -15);
2512
2513 s.com.texture[2].majtype = 2;
2514 vset (&s.com.texture[2].color1, 0, 0.4, 0.4);
2515 vset (&s.com.texture[2].translate, 15, 15, -15);
2516
2517 gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (texturelist)));
2518
2519 rebuildlist ();
2520 break;
2521
2522 case GTK_RESPONSE_OK:
2523 if (idle_id)
2524 {
2525 g_source_remove (idle_id);
2526 idle_id = 0;
2527 }
2528
2529 do_run = TRUE;
2530
2531 default:
2532 gtk_widget_hide (widget);
2533 gtk_main_quit ();
2534 break;
2535 }
2536 }
2537
2538 static GtkWidget *
makewindow(void)2539 makewindow (void)
2540 {
2541 GtkListStore *store;
2542 GtkTreeViewColumn *col;
2543 GtkTreeSelection *selection;
2544 GtkWidget *window;
2545 GtkWidget *main_hbox;
2546 GtkWidget *main_vbox;
2547 GtkWidget *table;
2548 GtkWidget *frame;
2549 GtkWidget *scrolled;
2550 GtkWidget *hbox;
2551 GtkWidget *vbox;
2552 GtkWidget *button;
2553 GtkWidget *list;
2554 GimpRGB rgb = { 0, 0, 0, 0 };
2555
2556 window = gimp_dialog_new (_("Sphere Designer"), PLUG_IN_ROLE,
2557 NULL, 0,
2558 gimp_standard_help_func, PLUG_IN_PROC,
2559
2560 _("_Reset"), RESPONSE_RESET,
2561 _("_Cancel"), GTK_RESPONSE_CANCEL,
2562 _("_OK"), GTK_RESPONSE_OK,
2563
2564 NULL);
2565
2566 gtk_dialog_set_alternative_button_order (GTK_DIALOG (window),
2567 RESPONSE_RESET,
2568 GTK_RESPONSE_OK,
2569 GTK_RESPONSE_CANCEL,
2570 -1);
2571
2572 gimp_window_set_transient (GTK_WINDOW (window));
2573
2574 g_signal_connect (window, "response",
2575 G_CALLBACK (sphere_response),
2576 NULL);
2577
2578 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
2579 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2580 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
2581 main_vbox, TRUE, TRUE, 0);
2582 gtk_widget_show (main_vbox);
2583
2584 main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2585 gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0);
2586 gtk_widget_show (main_hbox);
2587
2588 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
2589 gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);
2590 gtk_widget_show (vbox);
2591
2592 frame = gtk_frame_new (NULL);
2593 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
2594 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
2595 gtk_widget_show (frame);
2596
2597 drawarea = gtk_drawing_area_new ();
2598 gtk_container_add (GTK_CONTAINER (frame), drawarea);
2599 gtk_widget_set_size_request (drawarea, PREVIEWSIZE, PREVIEWSIZE);
2600 gtk_widget_show (drawarea);
2601
2602 g_signal_connect (drawarea, "expose-event",
2603 G_CALLBACK (expose_event), NULL);
2604
2605 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2606 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
2607 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2608 gtk_widget_show (hbox);
2609
2610 button = gtk_button_new_with_mnemonic (_("_Open"));
2611 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2612 gtk_widget_show (button);
2613
2614 g_signal_connect (button, "clicked",
2615 G_CALLBACK (loadpreset),
2616 window);
2617
2618 button = gtk_button_new_with_mnemonic (_("_Save"));
2619 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2620 gtk_widget_show (button);
2621
2622 g_signal_connect (button, "clicked",
2623 G_CALLBACK (savepreset),
2624 window);
2625
2626 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
2627 gtk_box_pack_end (GTK_BOX (main_hbox), vbox, TRUE, TRUE, 0);
2628 gtk_widget_show (vbox);
2629
2630 scrolled = gtk_scrolled_window_new (NULL, NULL);
2631 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
2632 GTK_SHADOW_IN);
2633 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2634 GTK_POLICY_NEVER,
2635 GTK_POLICY_AUTOMATIC);
2636 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
2637 gtk_widget_show (scrolled);
2638
2639 store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
2640 list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
2641 g_object_unref (store);
2642
2643 texturelist = GTK_TREE_VIEW (list);
2644
2645 selection = gtk_tree_view_get_selection (texturelist);
2646
2647 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
2648
2649 g_signal_connect (selection, "changed",
2650 G_CALLBACK (selectitem),
2651 NULL);
2652
2653 gtk_widget_set_size_request (list, -1, 150);
2654 gtk_container_add (GTK_CONTAINER (scrolled), list);
2655 gtk_widget_show (list);
2656
2657 col = gtk_tree_view_column_new_with_attributes (_("Layers"),
2658 gtk_cell_renderer_text_new (),
2659 "text", TYPE,
2660 NULL);
2661 gtk_tree_view_append_column (texturelist, col);
2662
2663 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2664 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
2665 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2666 gtk_widget_show (hbox);
2667
2668 button = gtk_button_new_with_mnemonic (_("_New"));
2669 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2670 g_signal_connect_swapped (button, "clicked",
2671 G_CALLBACK (addtexture), NULL);
2672 gtk_widget_show (button);
2673
2674 button = gtk_button_new_with_mnemonic (_("D_uplicate"));
2675 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2676 g_signal_connect_swapped (button, "clicked",
2677 G_CALLBACK (duptexture), NULL);
2678 gtk_widget_show (button);
2679
2680 button = gtk_button_new_with_mnemonic (_("_Delete"));
2681 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2682 g_signal_connect_swapped (button, "clicked",
2683 G_CALLBACK (deltexture), NULL);
2684 gtk_widget_show (button);
2685
2686 main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2687 gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, FALSE, FALSE, 0);
2688 gtk_widget_show (main_hbox);
2689
2690 frame = gimp_frame_new (_("Properties"));
2691 gtk_box_pack_start (GTK_BOX (main_hbox), frame, TRUE, TRUE, 0);
2692 gtk_widget_show (frame);
2693
2694 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2695 gtk_container_add (GTK_CONTAINER (frame), vbox);
2696 gtk_widget_show (vbox);
2697
2698 table = gtk_table_new (7, 3, FALSE);
2699 gtk_table_set_col_spacings (GTK_TABLE (table), 2);
2700 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2701 gtk_table_set_row_spacing (GTK_TABLE (table), 2, 12);
2702 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2703 gtk_widget_show (table);
2704
2705 typemenu = gimp_int_combo_box_new (_("Texture"), 0,
2706 _("Bump"), 1,
2707 _("Light"), 2,
2708 NULL);
2709 gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (typemenu), 0,
2710 G_CALLBACK (selecttype),
2711 NULL);
2712
2713 gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
2714 _("Type:"), 0.0, 0.5,
2715 typemenu, 2, FALSE);
2716
2717 texturemenu = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL);
2718 {
2719 struct textures_t *t;
2720
2721 for (t = textures; t->s; t++)
2722 gimp_int_combo_box_append (GIMP_INT_COMBO_BOX (texturemenu),
2723 GIMP_INT_STORE_VALUE, t->n,
2724 GIMP_INT_STORE_LABEL, gettext (t->s),
2725 -1);
2726 }
2727
2728 gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (texturemenu), 0,
2729 G_CALLBACK (selecttexture),
2730 NULL);
2731
2732 gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
2733 _("Texture:"), 0.0, 0.5,
2734 texturemenu, 2, FALSE);
2735
2736 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2737 gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
2738 _("Colors:"), 0.0, 0.5,
2739 hbox, 2, FALSE);
2740
2741 button = gimp_color_button_new (_("Color Selection Dialog"),
2742 COLORBUTTONWIDTH, COLORBUTTONHEIGHT, &rgb,
2743 GIMP_COLOR_AREA_FLAT);
2744 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2745 gtk_widget_show (button);
2746 drawcolor1 (button);
2747
2748 g_signal_connect (button, "color-changed",
2749 G_CALLBACK (color1_changed),
2750 NULL);
2751
2752 button = gimp_color_button_new (_("Color Selection Dialog"),
2753 COLORBUTTONWIDTH, COLORBUTTONHEIGHT, &rgb,
2754 GIMP_COLOR_AREA_FLAT);
2755 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2756 gtk_widget_show (button);
2757 drawcolor2 (button);
2758
2759 g_signal_connect (button, "color-changed",
2760 G_CALLBACK (color2_changed),
2761 NULL);
2762
2763 scalescale = gimp_scale_entry_new (GTK_TABLE (table), 0, 3, _("Scale:"),
2764 100, -1, 1.0, 0.0, 10.0, 0.1, 1.0, 1,
2765 TRUE, 0.0, 0.0, NULL, NULL);
2766 g_signal_connect (scalescale, "value-changed",
2767 G_CALLBACK (getscales),
2768 NULL);
2769
2770 turbulencescale = gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
2771 _("Turbulence:"),
2772 100, -1, 1.0, 0.0, 10.0, 0.1, 1.0, 1,
2773 TRUE, 0.0, 0.0, NULL, NULL);
2774 g_signal_connect (turbulencescale, "value-changed",
2775 G_CALLBACK (getscales),
2776 NULL);
2777
2778 amountscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 5, _("Amount:"),
2779 100, -1, 1.0, 0.0, 1.0, 0.01, 0.1, 2,
2780 TRUE, 0.0, 0.0, NULL, NULL);
2781 g_signal_connect (amountscale, "value-changed",
2782 G_CALLBACK (getscales),
2783 NULL);
2784
2785 expscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 6, _("Exp.:"),
2786 100, -1, 1.0, 0.0, 1.0, 0.01, 0.1, 2,
2787 TRUE, 0.0, 0.0, NULL, NULL);
2788 g_signal_connect (expscale, "value-changed",
2789 G_CALLBACK (getscales),
2790 NULL);
2791
2792 frame = gimp_frame_new (_("Transformations"));
2793 gtk_box_pack_start (GTK_BOX (main_hbox), frame, TRUE, TRUE, 0);
2794 gtk_widget_show (frame);
2795
2796 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2797 gtk_container_add (GTK_CONTAINER (frame), vbox);
2798 gtk_widget_show (vbox);
2799
2800 table = gtk_table_new (9, 3, FALSE);
2801 gtk_table_set_col_spacings (GTK_TABLE (table), 2);
2802 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2803 gtk_table_set_row_spacing (GTK_TABLE (table), 2, 12);
2804 gtk_table_set_row_spacing (GTK_TABLE (table), 5, 12);
2805 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2806 gtk_widget_show (table);
2807
2808 scalexscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Scale X:"),
2809 100, -1, 1.0, 0.0, 10.0, 0.1, 1.0, 2,
2810 TRUE, 0.0, 0.0, NULL, NULL);
2811 g_signal_connect (scalexscale, "value-changed",
2812 G_CALLBACK (getscales),
2813 NULL);
2814
2815 scaleyscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 1, _("Scale Y:"),
2816 100, -1, 1.0, 0.0, 10.0, 0.1, 1.0, 2,
2817 TRUE, 0.0, 0.0, NULL, NULL);
2818 g_signal_connect (scaleyscale, "value-changed",
2819 G_CALLBACK (getscales),
2820 NULL);
2821 scalezscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 2, _("Scale Z:"),
2822 100, -1, 1.0, 0.0, 10.0, 0.1, 1.0, 2,
2823 TRUE, 0.0, 0.0, NULL, NULL);
2824 g_signal_connect (scalezscale, "value-changed",
2825 G_CALLBACK (getscales),
2826 NULL);
2827
2828 rotxscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 3, _("Rotate X:"),
2829 100, -1, 0.0, 0.0, 360.0, 1.0, 10.0, 1,
2830 TRUE, 0.0, 0.0, NULL, NULL);
2831 g_signal_connect (rotxscale, "value-changed",
2832 G_CALLBACK (getscales),
2833 NULL);
2834
2835 rotyscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 4, _("Rotate Y:"),
2836 100, -1, 0.0, 0.0, 360.0, 1.0, 10.0, 1,
2837 TRUE, 0.0, 0.0, NULL, NULL);
2838 g_signal_connect (rotyscale, "value-changed",
2839 G_CALLBACK (getscales),
2840 NULL);
2841
2842 rotzscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 5, _("Rotate Z:"),
2843 100, -1, 0.0, 0.0, 360.0, 1.0, 10.0, 1,
2844 TRUE, 0.0, 0.0, NULL, NULL);
2845 g_signal_connect (rotzscale, "value-changed",
2846 G_CALLBACK (getscales),
2847 NULL);
2848
2849 posxscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 6, _("Position X:"),
2850 100, -1, 0.0, -20.0, 20.0, 0.1, 1.0, 1,
2851 TRUE, 0.0, 0.0, NULL, NULL);
2852 g_signal_connect (posxscale, "value-changed",
2853 G_CALLBACK (getscales),
2854 NULL);
2855
2856 posyscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 7, _("Position Y:"),
2857 100, -1, 0.0, -20.0, 20.0, 0.1, 1.0, 1,
2858 TRUE, 0.0, 0.0, NULL, NULL);
2859 g_signal_connect (posyscale, "value-changed",
2860 G_CALLBACK (getscales),
2861 NULL);
2862
2863 poszscale = gimp_scale_entry_new (GTK_TABLE (table), 0, 8, _("Position Z:"),
2864 100, -1, 0.0, -20.0, 20.0, 0.1, 1.0, 1,
2865 TRUE, 0.0, 0.0, NULL, NULL);
2866 g_signal_connect (poszscale, "value-changed",
2867 G_CALLBACK (getscales),
2868 NULL);
2869
2870 gtk_widget_show (window);
2871
2872 return window;
2873 }
2874
2875 static guchar
pixelval(gdouble v)2876 pixelval (gdouble v)
2877 {
2878 v += 0.5;
2879 if (v < 0.0)
2880 return 0;
2881 if (v > 255.0)
2882 return 255;
2883 return v;
2884 }
2885
2886 static gboolean
render(void)2887 render (void)
2888 {
2889 GimpVector4 col;
2890 guchar *dest_row;
2891 ray r;
2892 gint x, y, p;
2893 gint tx = PREVIEWSIZE;
2894 gint ty = PREVIEWSIZE;
2895 gint bpp = 4;
2896
2897 idle_id = 0;
2898
2899 initworld ();
2900
2901 r.v1.z = -10.0;
2902 r.v2.z = 0.0;
2903
2904 if (world.obj[0].com.numtexture > 0)
2905 {
2906 cairo_surface_flush (buffer);
2907
2908 for (y = 0; y < ty; y++)
2909 {
2910 dest_row = img + y * img_stride;
2911
2912 for (x = 0; x < tx; x++)
2913 {
2914 gint g, gridsize = 16;
2915
2916 g = ((x / gridsize + y / gridsize) % 2) * 60 + 100;
2917
2918 r.v1.x = r.v2.x = 8.5 * (x / (float) (tx - 1) - 0.5);
2919 r.v1.y = r.v2.y = 8.5 * (y / (float) (ty - 1) - 0.5);
2920
2921 p = x * bpp;
2922
2923 traceray (&r, &col, 10, 1.0);
2924
2925 if (col.w < 0.0)
2926 col.w = 0.0;
2927 else if (col.w > 1.0)
2928 col.w = 1.0;
2929
2930 GIMP_CAIRO_RGB24_SET_PIXEL ((dest_row + p),
2931 pixelval (255 * col.x) * col.w + g * (1.0 - col.w),
2932 pixelval (255 * col.y) * col.w + g * (1.0 - col.w),
2933 pixelval (255 * col.z) * col.w + g * (1.0 - col.w));
2934 }
2935 }
2936
2937 cairo_surface_mark_dirty (buffer);
2938 }
2939
2940 gtk_widget_queue_draw (drawarea);
2941
2942 return FALSE;
2943 }
2944
2945 static void
realrender(gint32 drawable_ID)2946 realrender (gint32 drawable_ID)
2947 {
2948 GeglBuffer *src_buffer;
2949 GeglBuffer *dest_buffer;
2950 const Babl *format;
2951 gint x, y;
2952 ray r;
2953 GimpVector4 rcol;
2954 gint width, height;
2955 gint x1, y1;
2956 guchar *dest;
2957 gint bpp;
2958 guchar *buffer, *ibuffer;
2959
2960 initworld ();
2961
2962 r.v1.z = -10.0;
2963 r.v2.z = 0.0;
2964
2965 if (! gimp_drawable_mask_intersect (drawable_ID,
2966 &x1, &y1, &width, &height))
2967 return;
2968
2969 src_buffer = gimp_drawable_get_buffer (drawable_ID);
2970 dest_buffer = gimp_drawable_get_shadow_buffer (drawable_ID);
2971
2972 if (gimp_drawable_is_rgb (drawable_ID))
2973 {
2974 if (gimp_drawable_has_alpha (drawable_ID))
2975 format = babl_format ("R'G'B'A u8");
2976 else
2977 format = babl_format ("R'G'B' u8");
2978 }
2979 else
2980 {
2981 if (gimp_drawable_has_alpha (drawable_ID))
2982 format = babl_format ("Y'A u8");
2983 else
2984 format = babl_format ("Y' u8");
2985 }
2986
2987 bpp = babl_format_get_bytes_per_pixel (format);
2988
2989 buffer = g_malloc (width * 4);
2990 ibuffer = g_malloc (width * 4);
2991
2992 gimp_progress_init (_("Rendering sphere"));
2993
2994 for (y = 0; y < height; y++)
2995 {
2996 dest = buffer;
2997 for (x = 0; x < width; x++)
2998 {
2999 r.v1.x = r.v2.x = 8.1 * (x / (float) (width - 1) - 0.5);
3000 r.v1.y = r.v2.y = 8.1 * (y / (float) (height - 1) - 0.5);
3001
3002 traceray (&r, &rcol, 10, 1.0);
3003 dest[0] = pixelval (255 * rcol.x);
3004 dest[1] = pixelval (255 * rcol.y);
3005 dest[2] = pixelval (255 * rcol.z);
3006 dest[3] = pixelval (255 * rcol.w);
3007 dest += 4;
3008 }
3009
3010 gegl_buffer_get (src_buffer, GEGL_RECTANGLE (x1, y1 + y, width, 1), 1.0,
3011 format, ibuffer,
3012 GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
3013
3014 for (x = 0; x < width; x++)
3015 {
3016 gint k, dx = x * 4, sx = x * bpp;
3017 gfloat a = buffer[dx + 3] / 255.0;
3018
3019 for (k = 0; k < bpp; k++)
3020 {
3021 ibuffer[sx + k] =
3022 buffer[dx + k] * a + ibuffer[sx + k] * (1.0 - a);
3023 }
3024 }
3025
3026 gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (x1, y1 + y, width, 1), 0,
3027 format, ibuffer,
3028 GEGL_AUTO_ROWSTRIDE);
3029
3030 gimp_progress_update ((gdouble) y / (gdouble) height);
3031 }
3032
3033 gimp_progress_update (1.0);
3034 g_free (buffer);
3035 g_free (ibuffer);
3036
3037 g_object_unref (src_buffer);
3038 g_object_unref (dest_buffer);
3039
3040 gimp_drawable_merge_shadow (drawable_ID, TRUE);
3041 gimp_drawable_update (drawable_ID, x1, y1, width, height);
3042 }
3043
3044 static void
query(void)3045 query (void)
3046 {
3047 static const GimpParamDef args[] =
3048 {
3049 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
3050 { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
3051 { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
3052 };
3053
3054 gimp_install_procedure (PLUG_IN_PROC,
3055 N_("Create an image of a textured sphere"),
3056 "This plug-in can be used to create textured and/or "
3057 "bumpmapped spheres, and uses a small lightweight "
3058 "raytracer to perform the task with good quality",
3059 "Vidar Madsen",
3060 "Vidar Madsen",
3061 "1999",
3062 N_("Sphere _Designer..."),
3063 "RGB*, GRAY*",
3064 GIMP_PLUGIN,
3065 G_N_ELEMENTS (args), 0,
3066 args, NULL);
3067
3068 gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Render");
3069 }
3070
3071 static gboolean
sphere_main(gint32 drawable_ID)3072 sphere_main (gint32 drawable_ID)
3073 {
3074 gimp_ui_init (PLUG_IN_BINARY, TRUE);
3075
3076 img_stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, PREVIEWSIZE);
3077 img = g_malloc0 (img_stride * PREVIEWSIZE);
3078
3079 buffer = cairo_image_surface_create_for_data (img, CAIRO_FORMAT_RGB24,
3080 PREVIEWSIZE,
3081 PREVIEWSIZE,
3082 img_stride);
3083
3084 makewindow ();
3085
3086 if (s.com.numtexture == 0)
3087 {
3088 /* Setup and use default list */
3089 sphere_response (NULL, RESPONSE_RESET, NULL);
3090 }
3091 else
3092 {
3093 /* Reuse the list from a previous invocation */
3094 rebuildlist ();
3095 }
3096
3097 gtk_main ();
3098
3099 cairo_surface_destroy (buffer);
3100 g_free (img);
3101
3102 return do_run;
3103 }
3104
3105 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)3106 run (const gchar *name,
3107 gint nparams,
3108 const GimpParam *param,
3109 gint *nreturn_vals,
3110 GimpParam **return_vals)
3111 {
3112 static GimpParam values[1];
3113 GimpRunMode run_mode;
3114 gint32 drawable_ID;
3115 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
3116 gint x, y, w, h;
3117
3118 INIT_I18N ();
3119 gegl_init (NULL, NULL);
3120
3121 *nreturn_vals = 1;
3122 *return_vals = values;
3123
3124 values[0].type = GIMP_PDB_STATUS;
3125 values[0].data.d_status = status;
3126
3127 run_mode = param[0].data.d_int32;
3128 drawable_ID = param[2].data.d_drawable;
3129
3130 if (! gimp_drawable_mask_intersect (drawable_ID, &x, &y, &w, &h))
3131 {
3132 g_message (_("Region selected for plug-in is empty"));
3133 return;
3134 }
3135
3136 switch (run_mode)
3137 {
3138 case GIMP_RUN_INTERACTIVE:
3139 s.com.numtexture = 0;
3140 gimp_get_data (PLUG_IN_PROC, &s);
3141 if (! sphere_main (drawable_ID))
3142 return;
3143 break;
3144
3145 case GIMP_RUN_WITH_LAST_VALS:
3146 s.com.numtexture = 0;
3147 gimp_get_data (PLUG_IN_PROC, &s);
3148 if (s.com.numtexture == 0)
3149 return;
3150 break;
3151
3152 case GIMP_RUN_NONINTERACTIVE:
3153 default:
3154 /* Not implemented yet... */
3155 return;
3156 }
3157
3158 gimp_set_data (PLUG_IN_PROC, &s, sizeof (s));
3159
3160 realrender (drawable_ID);
3161 gimp_displays_flush ();
3162
3163 values[0].data.d_status = status;
3164 }
3165
3166 MAIN ()
3167