9
#include <libgimp/gimp.h>
10
#include <libgimp/gimpui.h>
12
#include "mapobject_apply.h"
13
#include "mapobject_main.h"
14
#include "mapobject_image.h"
15
#include "mapobject_shade.h"
17
gdouble bx1, by1, bx2, by2;
18
get_ray_color_func get_ray_color;
34
phong_shade (GimpVector3 *pos,
35
GimpVector3 *viewpoint,
42
GimpRGB ambientcolor, diffusecolor, specularcolor;
44
GimpVector3 L, NN, V, N;
46
/* Compute ambient intensity */
47
/* ========================= */
50
ambientcolor = *diff_col;
51
gimp_rgb_multiply (&ambientcolor, mapvals.material.ambient_int);
53
/* Compute (N*L) term of Phong's equation */
54
/* ====================================== */
56
if (type == POINT_LIGHT)
57
gimp_vector3_sub (&L, light, pos);
61
dist = gimp_vector3_length (&L);
64
gimp_vector3_mul (&L, 1.0 / dist);
66
NL = 2.0 * gimp_vector3_inner_product (&N, &L);
70
/* Compute (R*V)^alpha term of Phong's equation */
71
/* ============================================ */
73
gimp_vector3_sub (&V, viewpoint, pos);
74
gimp_vector3_normalize (&V);
76
gimp_vector3_mul (&N, NL);
77
gimp_vector3_sub (&NN, &N, &L);
78
RV = gimp_vector3_inner_product (&NN, &V);
79
RV = pow (RV, mapvals.material.highlight);
81
/* Compute diffuse and specular intensity contribution */
82
/* =================================================== */
84
diffusecolor = *diff_col;
85
gimp_rgb_multiply (&diffusecolor, mapvals.material.diffuse_ref);
86
gimp_rgb_multiply (&diffusecolor, NL);
88
specularcolor = *spec_col;
89
gimp_rgb_multiply (&specularcolor, mapvals.material.specular_ref);
90
gimp_rgb_multiply (&specularcolor, RV);
92
gimp_rgb_add (&diffusecolor, &specularcolor);
93
gimp_rgb_multiply (&diffusecolor, mapvals.material.diffuse_int);
94
gimp_rgb_clamp (&diffusecolor);
96
gimp_rgb_add (&ambientcolor, &diffusecolor);
103
plane_intersect (GimpVector3 *dir,
109
static gdouble det, det1, det2, det3, t;
115
/* Compute determinant of the first 3x3 sub matrix (denominator) */
116
/* ============================================================= */
118
det = (imat[0][0] * imat[1][1] * imat[2][2] +
119
imat[0][1] * imat[1][2] * imat[2][0] +
120
imat[0][2] * imat[1][0] * imat[2][1] -
121
imat[0][2] * imat[1][1] * imat[2][0] -
122
imat[0][0] * imat[1][2] * imat[2][1] -
123
imat[2][2] * imat[0][1] * imat[1][0]);
125
/* If the determinant is non-zero, a intersection point exists */
126
/* =========================================================== */
130
/* Now, lets compute the numerator determinants (wow ;) */
131
/* ==================================================== */
133
det1 = (imat[0][3] * imat[1][1] * imat[2][2] +
134
imat[0][1] * imat[1][2] * imat[2][3] +
135
imat[0][2] * imat[1][3] * imat[2][1] -
136
imat[0][2] * imat[1][1] * imat[2][3] -
137
imat[1][2] * imat[2][1] * imat[0][3] -
138
imat[2][2] * imat[0][1] * imat[1][3]);
140
det2 = (imat[0][0] * imat[1][3] * imat[2][2] +
141
imat[0][3] * imat[1][2] * imat[2][0] +
142
imat[0][2] * imat[1][0] * imat[2][3] -
143
imat[0][2] * imat[1][3] * imat[2][0] -
144
imat[1][2] * imat[2][3] * imat[0][0] -
145
imat[2][2] * imat[0][3] * imat[1][0]);
147
det3 = (imat[0][0] * imat[1][1] * imat[2][3] +
148
imat[0][1] * imat[1][3] * imat[2][0] +
149
imat[0][3] * imat[1][0] * imat[2][1] -
150
imat[0][3] * imat[1][1] * imat[2][0] -
151
imat[1][3] * imat[2][1] * imat[0][0] -
152
imat[2][3] * imat[0][1] * imat[1][0]);
154
/* Now we have the simultanous solutions. Lets compute the unknowns */
155
/* (skip u&v if t is <0, this means the intersection is behind us) */
156
/* ================================================================ */
162
*u = 1.0 + ((det2 / det) - 0.5);
163
*v = 1.0 + ((det3 / det) - 0.5);
165
ipos->x = viewp->x + t * dir->x;
166
ipos->y = viewp->y + t * dir->y;
167
ipos->z = viewp->z + t * dir->z;
176
/*****************************************************************************
177
* These routines computes the color of the surface
178
* of the plane at a given point
179
*****************************************************************************/
182
get_ray_color_plane (GimpVector3 *pos)
184
GimpRGB color = background;
186
static gint inside = FALSE;
187
static GimpVector3 ray, spos;
188
static gdouble vx, vy;
190
/* Construct a line from our VP to the point */
191
/* ========================================= */
193
gimp_vector3_sub (&ray, pos, &mapvals.viewpoint);
194
gimp_vector3_normalize (&ray);
196
/* Check for intersection. This is a quasi ray-tracer. */
197
/* =================================================== */
199
if (plane_intersect (&ray, &mapvals.viewpoint, &spos, &vx, &vy) == TRUE)
201
color = get_image_color (vx, vy, &inside);
203
if (color.a != 0.0 && inside == TRUE &&
204
mapvals.lightsource.type != NO_LIGHT)
206
/* Compute shading at this point */
207
/* ============================= */
209
color = phong_shade (&spos,
212
&mapvals.lightsource.position,
214
&mapvals.lightsource.color,
215
mapvals.lightsource.type);
217
gimp_rgb_clamp (&color);
221
if (mapvals.transparent_background == FALSE && color.a < 1.0)
223
gimp_rgb_composite (&color, &background,
224
GIMP_RGB_COMPOSITE_BEHIND);
230
/***********************************************************************/
231
/* Given the NorthPole, Equator and a third vector (normal) compute */
232
/* the conversion from spherical oordinates to image space coordinates */
233
/***********************************************************************/
236
sphere_to_image (GimpVector3 *normal,
240
static gdouble alpha, fac;
241
static GimpVector3 cross_prod;
243
alpha = acos (-gimp_vector3_inner_product (&mapvals.secondaxis, normal));
247
if (*v == 0.0 || *v == 1.0)
253
fac = (gimp_vector3_inner_product (&mapvals.firstaxis, normal) /
256
/* Make sure that we map to -1.0..1.0 (take care of rounding errors) */
257
/* ================================================================= */
259
fac = CLAMP (fac, -1.0, 1.0);
261
*u = acos (fac) / (2.0 * G_PI);
263
cross_prod = gimp_vector3_cross_product (&mapvals.secondaxis,
266
if (gimp_vector3_inner_product (&cross_prod, normal) < 0.0)
271
/***************************************************/
272
/* Compute intersection point with sphere (if any) */
273
/***************************************************/
276
sphere_intersect (GimpVector3 *dir,
281
static gdouble alpha, beta, tau, s1, s2, tmp;
282
static GimpVector3 t;
284
gimp_vector3_sub (&t, &mapvals.position, viewp);
286
alpha = gimp_vector3_inner_product (dir, &t);
287
beta = gimp_vector3_inner_product (&t, &t);
289
tau = alpha * alpha - beta + mapvals.radius * mapvals.radius;
304
spos1->x = viewp->x + s1 * dir->x;
305
spos1->y = viewp->y + s1 * dir->y;
306
spos1->z = viewp->z + s1 * dir->z;
307
spos2->x = viewp->x + s2 * dir->x;
308
spos2->y = viewp->y + s2 * dir->y;
309
spos2->z = viewp->z + s2 * dir->z;
317
/*****************************************************************************
318
* These routines computes the color of the surface
319
* of the sphere at a given point
320
*****************************************************************************/
323
get_ray_color_sphere (GimpVector3 *pos)
325
GimpRGB color = background;
327
static GimpRGB color2;
328
static gint inside = FALSE;
329
static GimpVector3 normal, ray, spos1, spos2;
330
static gdouble vx, vy;
332
/* Check if ray is within the bounding box */
333
/* ======================================= */
335
if (pos->x<bx1 || pos->x>bx2 || pos->y<by1 || pos->y>by2)
338
/* Construct a line from our VP to the point */
339
/* ========================================= */
341
gimp_vector3_sub (&ray, pos, &mapvals.viewpoint);
342
gimp_vector3_normalize (&ray);
344
/* Check for intersection. This is a quasi ray-tracer. */
345
/* =================================================== */
347
if (sphere_intersect (&ray, &mapvals.viewpoint, &spos1, &spos2) == TRUE)
349
/* Compute spherical to rectangular mapping */
350
/* ======================================== */
352
gimp_vector3_sub (&normal, &spos1, &mapvals.position);
353
gimp_vector3_normalize (&normal);
354
sphere_to_image (&normal, &vx, &vy);
355
color = get_image_color (vx, vy, &inside);
357
/* Check for total transparency... */
358
/* =============================== */
362
/* Hey, we can see through here! */
363
/* Lets see what's on the other side.. */
364
/* =================================== */
366
color = phong_shade (&spos1,
369
&mapvals.lightsource.position,
371
&mapvals.lightsource.color,
372
mapvals.lightsource.type);
374
gimp_rgb_clamp (&color);
376
gimp_vector3_sub (&normal, &spos2, &mapvals.position);
377
gimp_vector3_normalize (&normal);
378
sphere_to_image (&normal, &vx, &vy);
379
color2 = get_image_color (vx, vy, &inside);
381
/* Make the normal point inwards */
382
/* ============================= */
384
gimp_vector3_mul (&normal, -1.0);
386
color2 = phong_shade (&spos2,
389
&mapvals.lightsource.position,
391
&mapvals.lightsource.color,
392
mapvals.lightsource.type);
394
gimp_rgb_clamp (&color2);
396
/* Compute a mix of the first and second colors */
397
/* ============================================ */
399
gimp_rgb_composite (&color, &color2, GIMP_RGB_COMPOSITE_NORMAL);
400
gimp_rgb_clamp (&color);
402
else if (color.a != 0.0 &&
404
mapvals.lightsource.type != NO_LIGHT)
406
/* Compute shading at this point */
407
/* ============================= */
409
color = phong_shade (&spos1,
412
&mapvals.lightsource.position,
414
&mapvals.lightsource.color,
415
mapvals.lightsource.type);
417
gimp_rgb_clamp (&color);
421
if (mapvals.transparent_background == FALSE && color.a < 1.0)
423
gimp_rgb_composite (&color, &background,
424
GIMP_RGB_COMPOSITE_BEHIND);
430
/***************************************************/
431
/* Transform the corners of the bounding box to 2D */
432
/***************************************************/
435
compute_bounding_box (void)
441
p1 = mapvals.position;
442
p1.x -= (mapvals.radius + 0.01);
443
p1.y -= (mapvals.radius + 0.01);
445
p2 = mapvals.position;
446
p2.x += (mapvals.radius + 0.01);
447
p2.y += (mapvals.radius + 0.01);
449
gimp_vector3_sub (&dir, &p1, &mapvals.viewpoint);
450
gimp_vector3_normalize (&dir);
454
t = (-1.0 * mapvals.viewpoint.z) / dir.z;
455
p1.x = (mapvals.viewpoint.x + t * dir.x);
456
p1.y = (mapvals.viewpoint.y + t * dir.y);
459
gimp_vector3_sub (&dir, &p2, &mapvals.viewpoint);
460
gimp_vector3_normalize (&dir);
464
t = (-1.0 * mapvals.viewpoint.z) / dir.z;
465
p2.x = (mapvals.viewpoint.x + t * dir.x);
466
p2.y = (mapvals.viewpoint.y + t * dir.y);
475
/* These two were taken from the Mesa source. Mesa is written */
476
/* and is (C) by Brian Paul. vecmulmat() performs a post-mul by */
477
/* a 4x4 matrix to a 1x4(3) vector. rotmat() creates a matrix */
478
/* that by post-mul will rotate a 1x4(3) vector the given angle */
479
/* about the given axis. */
480
/* ============================================================ */
483
vecmulmat (GimpVector3 *u,
487
gfloat v0=v->x, v1=v->y, v2=v->z;
488
#define M(row,col) m[col*4+row]
489
u->x = v0 * M(0,0) + v1 * M(1,0) + v2 * M(2,0) + M(3,0);
490
u->y = v0 * M(0,1) + v1 * M(1,1) + v2 * M(2,1) + M(3,1);
491
u->z = v0 * M(0,2) + v1 * M(1,2) + v2 * M(2,2) + M(3,2);
496
rotatemat (gfloat angle,
500
/* This function contributed by Erich Boleyn (erich@uruk.org) */
502
gfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
503
gfloat IdentityMat[16];
506
s = sin (angle * (G_PI / 180.0));
507
c = cos (angle * (G_PI / 180.0));
509
mag = sqrt (v->x*v->x + v->y*v->y + v->z*v->z);
513
/* generate an identity matrix and return */
515
for (cnt = 0; cnt < 16; cnt++)
516
IdentityMat[cnt] = 0.0;
518
IdentityMat[0] = 1.0;
519
IdentityMat[5] = 1.0;
520
IdentityMat[10] = 1.0;
521
IdentityMat[15] = 1.0;
523
memcpy (m, IdentityMat, sizeof (gfloat) * 16);
531
#define M(row,col) m[col*4+row]
544
M(0,0) = (one_c * xx) + c;
545
M(0,1) = (one_c * xy) - zs;
546
M(0,2) = (one_c * zx) + ys;
549
M(1,0) = (one_c * xy) + zs;
550
M(1,1) = (one_c * yy) + c;
551
M(1,2) = (one_c * yz) - xs;
554
M(2,0) = (one_c * zx) - ys;
555
M(2,1) = (one_c * yz) + xs;
556
M(2,2) = (one_c * zz) + c;
567
/* Transpose the matrix m. If m is orthogonal (like a rotation matrix), */
568
/* this is equal to the inverse of the matrix. */
569
/* ==================================================================== */
572
transpose_mat (gfloat m[16])
577
for (i = 0; i < 4; i++)
579
for (j = 0; j < i; j++)
588
/* Compute the matrix product c=a*b */
589
/* ================================ */
592
matmul (gfloat a[16],
599
#define A(row,col) a[col*4+row]
600
#define B(row,col) b[col*4+row]
601
#define C(row,col) c[col*4+row]
603
for (i = 0; i < 4; i++)
605
for (j = 0; j < 4; j++)
609
for (k = 0; k < 4; k++)
610
value += A(i,k) * B(k,j);
622
ident_mat (gfloat m[16])
626
#define M(row,col) m[col*4+row]
628
for (i = 0; i < 4; i++)
630
for (j = 0; j < 4; j++)
643
intersect_rect (gdouble u,
648
FaceIntersectInfo *face_info)
650
gboolean result = FALSE;
658
face_info->t = (w-viewp.z) / dir.z;
659
face_info->s.x = viewp.x + face_info->t * dir.x;
660
face_info->s.y = viewp.y + face_info->t * dir.y;
663
if (face_info->s.x >= -u2 && face_info->s.x <= u2 &&
664
face_info->s.y >= -v2 && face_info->s.y <= v2)
666
face_info->u = (face_info->s.x + u2) / u;
667
face_info->v = (face_info->s.y + v2) / v;
676
intersect_box (GimpVector3 scale,
679
FaceIntersectInfo *face_intersect)
681
GimpVector3 v, d, tmp, axis[3];
682
FaceIntersectInfo face_tmp;
683
gboolean result = FALSE;
687
gimp_vector3_set (&axis[0], 1.0, 0.0, 0.0);
688
gimp_vector3_set (&axis[1], 0.0, 1.0, 0.0);
689
gimp_vector3_set (&axis[2], 0.0, 0.0, 1.0);
694
if (intersect_rect (scale.x, scale.y, scale.z / 2.0,
695
viewp, dir, &face_intersect[i]) == TRUE)
697
face_intersect[i].face = 0;
698
gimp_vector3_set (&face_intersect[i++].n, 0.0, 0.0, 1.0);
705
if (intersect_rect (scale.x, scale.y, -scale.z / 2.0,
706
viewp, dir, &face_intersect[i]) == TRUE)
708
face_intersect[i].face = 1;
709
face_intersect[i].u = 1.0 - face_intersect[i].u;
710
gimp_vector3_set (&face_intersect[i++].n, 0.0, 0.0, -1.0);
714
/* Check if we've found the two possible intersection points */
715
/* ========================================================= */
719
/* Top: Rotate viewpoint and direction into rectangle's local coordinate system */
720
/* ============================================================================ */
722
rotatemat (90, &axis[0], m);
723
vecmulmat (&v, &viewp, m);
724
vecmulmat (&d, &dir, m);
726
if (intersect_rect (scale.x, scale.z, scale.y / 2.0,
727
v, d, &face_intersect[i]) == TRUE)
729
face_intersect[i].face = 2;
732
vecmulmat(&tmp, &face_intersect[i].s, m);
733
face_intersect[i].s = tmp;
735
gimp_vector3_set (&face_intersect[i++].n, 0.0, -1.0, 0.0);
740
/* Check if we've found the two possible intersection points */
741
/* ========================================================= */
745
/* Bottom: Rotate viewpoint and direction into rectangle's local coordinate system */
746
/* =============================================================================== */
748
rotatemat (90, &axis[0], m);
749
vecmulmat (&v, &viewp, m);
750
vecmulmat (&d, &dir, m);
752
if (intersect_rect (scale.x, scale.z, -scale.y / 2.0,
753
v, d, &face_intersect[i]) == TRUE)
755
face_intersect[i].face = 3;
759
vecmulmat (&tmp, &face_intersect[i].s, m);
760
face_intersect[i].s = tmp;
762
face_intersect[i].v = 1.0 - face_intersect[i].v;
764
gimp_vector3_set (&face_intersect[i++].n, 0.0, 1.0, 0.0);
770
/* Check if we've found the two possible intersection points */
771
/* ========================================================= */
775
/* Left side: Rotate viewpoint and direction into rectangle's local coordinate system */
776
/* ================================================================================== */
778
rotatemat (90, &axis[1], m);
779
vecmulmat (&v, &viewp, m);
780
vecmulmat (&d, &dir, m);
782
if (intersect_rect (scale.z, scale.y, scale.x / 2.0,
783
v, d, &face_intersect[i]) == TRUE)
785
face_intersect[i].face = 4;
788
vecmulmat (&tmp, &face_intersect[i].s, m);
789
face_intersect[i].s = tmp;
791
gimp_vector3_set (&face_intersect[i++].n, 1.0, 0.0, 0.0);
796
/* Check if we've found the two possible intersection points */
797
/* ========================================================= */
801
/* Right side: Rotate viewpoint and direction into rectangle's local coordinate system */
802
/* =================================================================================== */
804
rotatemat (90, &axis[1], m);
805
vecmulmat (&v, &viewp, m);
806
vecmulmat (&d, &dir, m);
808
if (intersect_rect (scale.z, scale.y, -scale.x / 2.0,
809
v, d, &face_intersect[i]) == TRUE)
811
face_intersect[i].face = 5;
814
vecmulmat (&tmp, &face_intersect[i].s, m);
816
face_intersect[i].u = 1.0 - face_intersect[i].u;
818
gimp_vector3_set (&face_intersect[i++].n, -1.0, 0.0, 0.0);
823
/* Sort intersection points */
824
/* ======================== */
826
if (face_intersect[0].t > face_intersect[1].t)
828
face_tmp = face_intersect[0];
829
face_intersect[0] = face_intersect[1];
830
face_intersect[1] = face_tmp;
837
get_ray_color_box (GimpVector3 *pos)
839
GimpVector3 lvp, ldir, vp, p, dir, ns, nn;
840
GimpRGB color, color2;
843
FaceIntersectInfo face_intersect[2];
846
vp = mapvals.viewpoint;
849
/* Translate viewpoint so that the box has its origin */
850
/* at its lower left corner. */
851
/* ================================================== */
853
vp.x = vp.x - mapvals.position.x;
854
vp.y = vp.y - mapvals.position.y;
855
vp.z = vp.z - mapvals.position.z;
857
p.x = p.x - mapvals.position.x;
858
p.y = p.y - mapvals.position.y;
859
p.z = p.z - mapvals.position.z;
861
/* Compute direction */
862
/* ================= */
864
gimp_vector3_sub (&dir, &p, &vp);
865
gimp_vector3_normalize (&dir);
867
/* Compute inverse of rotation matrix and apply it to */
868
/* the viewpoint and direction. This transforms the */
869
/* observer into the local coordinate system of the box */
870
/* ==================================================== */
872
memcpy (m, rotmat, sizeof (gfloat) * 16);
876
vecmulmat (&lvp, &vp, m);
877
vecmulmat (&ldir, &dir, m);
879
/* Ok. Now the observer is in the space where the box is located */
880
/* with its lower left corner at the origin and its axis aligned */
881
/* to the cartesian basis. Check if the transformed ray hits it. */
882
/* ============================================================= */
884
face_intersect[0].t = 1000000.0;
885
face_intersect[1].t = 1000000.0;
887
if (intersect_box (mapvals.scale, lvp, ldir, face_intersect) == TRUE)
889
/* We've hit the box. Transform the hit points and */
890
/* normals back into the world coordinate system */
891
/* =============================================== */
893
for (i = 0; i < 2; i++)
895
vecmulmat (&ns, &face_intersect[i].s, rotmat);
896
vecmulmat (&nn, &face_intersect[i].n, rotmat);
898
ns.x = ns.x + mapvals.position.x;
899
ns.y = ns.y + mapvals.position.y;
900
ns.z = ns.z + mapvals.position.z;
902
face_intersect[i].s = ns;
903
face_intersect[i].n = nn;
906
color = get_box_image_color (face_intersect[0].face,
908
face_intersect[0].v);
910
/* Check for total transparency... */
911
/* =============================== */
915
/* Hey, we can see through here! */
916
/* Lets see what's on the other side.. */
917
/* =================================== */
919
color = phong_shade (&face_intersect[0].s,
921
&face_intersect[0].n,
922
&mapvals.lightsource.position,
924
&mapvals.lightsource.color,
925
mapvals.lightsource.type);
927
gimp_rgb_clamp (&color);
929
color2 = get_box_image_color (face_intersect[1].face,
931
face_intersect[1].v);
933
/* Make the normal point inwards */
934
/* ============================= */
936
gimp_vector3_mul (&face_intersect[1].n, -1.0);
938
color2 = phong_shade (&face_intersect[1].s,
940
&face_intersect[1].n,
941
&mapvals.lightsource.position,
943
&mapvals.lightsource.color,
944
mapvals.lightsource.type);
946
gimp_rgb_clamp (&color2);
948
if (mapvals.transparent_background == FALSE && color2.a < 1.0)
950
gimp_rgb_composite (&color2, &background,
951
GIMP_RGB_COMPOSITE_BEHIND);
954
/* Compute a mix of the first and second colors */
955
/* ============================================ */
957
gimp_rgb_composite (&color, &color2, GIMP_RGB_COMPOSITE_NORMAL);
958
gimp_rgb_clamp (&color);
960
else if (color.a != 0.0 && mapvals.lightsource.type != NO_LIGHT)
962
color = phong_shade (&face_intersect[0].s,
964
&face_intersect[0].n,
965
&mapvals.lightsource.position,
967
&mapvals.lightsource.color,
968
mapvals.lightsource.type);
970
gimp_rgb_clamp (&color);
975
if (mapvals.transparent_background == TRUE)
976
gimp_rgb_set_alpha (&color, 0.0);
983
intersect_circle (GimpVector3 vp,
986
FaceIntersectInfo *face_info)
988
gboolean result = FALSE;
995
face_info->t = (w-vp.y)/dir.y;
996
face_info->s.x = vp.x + face_info->t*dir.x;
998
face_info->s.z = vp.z + face_info->t*dir.z;
1000
r = sqrt (sqr (face_info->s.x) + sqr (face_info->s.z));
1002
if (r <= mapvals.cylinder_radius)
1004
d = 2.0 * mapvals.cylinder_radius;
1005
face_info->u = (face_info->s.x + mapvals.cylinder_radius) / d;
1006
face_info->v = (face_info->s.z + mapvals.cylinder_radius) / d;
1017
intersect_cylinder (GimpVector3 vp,
1019
FaceIntersectInfo *face_intersect)
1021
gdouble a, b, c, d, e, f, tmp, l;
1022
gboolean result = FALSE;
1025
#define sqr(a) (a*a)
1027
a = sqr (dir.x) + sqr (dir.z);
1028
b = 2.0 * (vp.x * dir.x + vp.z * dir.z);
1029
c = sqr (vp.x) + sqr (vp.z) - sqr (mapvals.cylinder_radius);
1031
d = sqr (b) - 4.0 * a * c;
1042
face_intersect[0].t = (-b+e)/f;
1043
face_intersect[1].t = (-b-e)/f;
1045
if (face_intersect[0].t>face_intersect[1].t)
1047
tmp = face_intersect[0].t;
1048
face_intersect[0].t = face_intersect[1].t;
1049
face_intersect[1].t = tmp;
1052
for (i = 0; i < 2; i++)
1054
face_intersect[i].s.x = vp.x + face_intersect[i].t * dir.x;
1055
face_intersect[i].s.y = vp.y + face_intersect[i].t * dir.y;
1056
face_intersect[i].s.z = vp.z + face_intersect[i].t * dir.z;
1058
face_intersect[i].n = face_intersect[i].s;
1059
face_intersect[i].n.y = 0.0;
1060
gimp_vector3_normalize(&face_intersect[i].n);
1062
l = mapvals.cylinder_length/2.0;
1064
face_intersect[i].u = (atan2(face_intersect[i].s.x,face_intersect[i].s.z)+G_PI)/(2.0*G_PI);
1065
face_intersect[i].v = (face_intersect[i].s.y+l)/mapvals.cylinder_length;
1067
/* Mark hitpoint as on the cylinder hull */
1068
/* ===================================== */
1070
face_intersect[i].face = 0;
1072
/* Check if we're completely off the cylinder axis */
1073
/* =============================================== */
1075
if (face_intersect[i].s.y>l || face_intersect[i].s.y<-l)
1077
/* Check if we've hit a cap */
1078
/* ======================== */
1080
if (face_intersect[i].s.y>l)
1082
if (intersect_circle(vp,dir,l,&face_intersect[i])==FALSE)
1086
face_intersect[i].face = 2;
1087
face_intersect[i].v = 1 - face_intersect[i].v;
1088
gimp_vector3_set(&face_intersect[i].n, 0.0, 1.0, 0.0);
1093
if (intersect_circle(vp,dir,-l,&face_intersect[i])==FALSE)
1097
face_intersect[i].face = 1;
1098
gimp_vector3_set(&face_intersect[i].n, 0.0, -1.0, 0.0);
1112
get_cylinder_color (gint face,
1120
color = get_image_color (u, v, &inside);
1122
color = get_cylinder_image_color (face - 1, u, v);
1128
get_ray_color_cylinder (GimpVector3 *pos)
1130
GimpVector3 lvp, ldir, vp, p, dir, ns, nn;
1131
GimpRGB color, color2;
1134
FaceIntersectInfo face_intersect[2];
1137
vp = mapvals.viewpoint;
1140
vp.x = vp.x - mapvals.position.x;
1141
vp.y = vp.y - mapvals.position.y;
1142
vp.z = vp.z - mapvals.position.z;
1144
p.x = p.x - mapvals.position.x;
1145
p.y = p.y - mapvals.position.y;
1146
p.z = p.z - mapvals.position.z;
1148
/* Compute direction */
1149
/* ================= */
1151
gimp_vector3_sub (&dir, &p, &vp);
1152
gimp_vector3_normalize (&dir);
1154
/* Compute inverse of rotation matrix and apply it to */
1155
/* the viewpoint and direction. This transforms the */
1156
/* observer into the local coordinate system of the box */
1157
/* ==================================================== */
1159
memcpy (m, rotmat, sizeof (gfloat) * 16);
1163
vecmulmat (&lvp, &vp, m);
1164
vecmulmat (&ldir, &dir, m);
1166
if (intersect_cylinder (lvp, ldir, face_intersect) == TRUE)
1168
/* We've hit the cylinder. Transform the hit points and */
1169
/* normals back into the world coordinate system */
1170
/* ==================================================== */
1172
for (i = 0; i < 2; i++)
1174
vecmulmat (&ns, &face_intersect[i].s, rotmat);
1175
vecmulmat (&nn, &face_intersect[i].n, rotmat);
1177
ns.x = ns.x + mapvals.position.x;
1178
ns.y = ns.y + mapvals.position.y;
1179
ns.z = ns.z + mapvals.position.z;
1181
face_intersect[i].s = ns;
1182
face_intersect[i].n = nn;
1185
color = get_cylinder_color (face_intersect[0].face,
1186
face_intersect[0].u,
1187
face_intersect[0].v);
1189
/* Check for transparency... */
1190
/* ========================= */
1194
/* Hey, we can see through here! */
1195
/* Lets see what's on the other side.. */
1196
/* =================================== */
1198
color = phong_shade (&face_intersect[0].s,
1200
&face_intersect[0].n,
1201
&mapvals.lightsource.position,
1203
&mapvals.lightsource.color,
1204
mapvals.lightsource.type);
1206
gimp_rgb_clamp (&color);
1208
color2 = get_cylinder_color (face_intersect[1].face,
1209
face_intersect[1].u,
1210
face_intersect[1].v);
1212
/* Make the normal point inwards */
1213
/* ============================= */
1215
gimp_vector3_mul (&face_intersect[1].n, -1.0);
1217
color2 = phong_shade (&face_intersect[1].s,
1219
&face_intersect[1].n,
1220
&mapvals.lightsource.position,
1222
&mapvals.lightsource.color,
1223
mapvals.lightsource.type);
1225
gimp_rgb_clamp (&color2);
1227
if (mapvals.transparent_background == FALSE && color2.a < 1.0)
1229
gimp_rgb_composite (&color2, &background,
1230
GIMP_RGB_COMPOSITE_BEHIND);
1233
/* Compute a mix of the first and second colors */
1234
/* ============================================ */
1236
gimp_rgb_composite (&color, &color2, GIMP_RGB_COMPOSITE_NORMAL);
1237
gimp_rgb_clamp (&color);
1239
else if (color.a != 0.0 && mapvals.lightsource.type != NO_LIGHT)
1241
color = phong_shade (&face_intersect[0].s,
1243
&face_intersect[0].n,
1244
&mapvals.lightsource.position,
1246
&mapvals.lightsource.color,
1247
mapvals.lightsource.type);
1249
gimp_rgb_clamp (&color);
1254
if (mapvals.transparent_background == TRUE)
1255
gimp_rgb_set_alpha (&color, 0.0);