GimpRGB get_ray_color_box (GimpVector3 *pos) { GimpVector3 lvp, ldir, vp, p, dir, ns, nn; GimpRGB color, color2; gfloat m[16]; gint i; FaceIntersectInfo face_intersect[2]; color = background; vp = mapvals.viewpoint; p = *pos; /* Translate viewpoint so that the box has its origin */ /* at its lower left corner. */ /* ================================================== */ vp.x = vp.x - mapvals.position.x; vp.y = vp.y - mapvals.position.y; vp.z = vp.z - mapvals.position.z; p.x = p.x - mapvals.position.x; p.y = p.y - mapvals.position.y; p.z = p.z - mapvals.position.z; /* Compute direction */ /* ================= */ gimp_vector3_sub (&dir, &p, &vp); gimp_vector3_normalize (&dir); /* Compute inverse of rotation matrix and apply it to */ /* the viewpoint and direction. This transforms the */ /* observer into the local coordinate system of the box */ /* ==================================================== */ memcpy (m, rotmat, sizeof (gfloat) * 16); transpose_mat (m); vecmulmat (&lvp, &vp, m); vecmulmat (&ldir, &dir, m); /* Ok. Now the observer is in the space where the box is located */ /* with its lower left corner at the origin and its axis aligned */ /* to the cartesian basis. Check if the transformed ray hits it. */ /* ============================================================= */ face_intersect[0].t = 1000000.0; face_intersect[1].t = 1000000.0; if (intersect_box (mapvals.scale, lvp, ldir, face_intersect) == TRUE) { /* We've hit the box. Transform the hit points and */ /* normals back into the world coordinate system */ /* =============================================== */ for (i = 0; i < 2; i++) { vecmulmat (&ns, &face_intersect[i].s, rotmat); vecmulmat (&nn, &face_intersect[i].n, rotmat); ns.x = ns.x + mapvals.position.x; ns.y = ns.y + mapvals.position.y; ns.z = ns.z + mapvals.position.z; face_intersect[i].s = ns; face_intersect[i].n = nn; } color = get_box_image_color (face_intersect[0].face, face_intersect[0].u, face_intersect[0].v); /* Check for total transparency... */ /* =============================== */ if (color.a < 1.0) { /* Hey, we can see through here! */ /* Lets see what's on the other side.. */ /* =================================== */ color = phong_shade (&face_intersect[0].s, &mapvals.viewpoint, &face_intersect[0].n, &mapvals.lightsource.position, &color, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color); color2 = get_box_image_color (face_intersect[1].face, face_intersect[1].u, face_intersect[1].v); /* Make the normal point inwards */ /* ============================= */ gimp_vector3_mul (&face_intersect[1].n, -1.0); color2 = phong_shade (&face_intersect[1].s, &mapvals.viewpoint, &face_intersect[1].n, &mapvals.lightsource.position, &color2, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color2); if (mapvals.transparent_background == FALSE && color2.a < 1.0) { gimp_rgb_composite (&color2, &background, GIMP_RGB_COMPOSITE_BEHIND); } /* Compute a mix of the first and second colors */ /* ============================================ */ gimp_rgb_composite (&color, &color2, GIMP_RGB_COMPOSITE_NORMAL); gimp_rgb_clamp (&color); } else if (color.a != 0.0 && mapvals.lightsource.type != NO_LIGHT) { color = phong_shade (&face_intersect[0].s, &mapvals.viewpoint, &face_intersect[0].n, &mapvals.lightsource.position, &color, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color); } } else { if (mapvals.transparent_background == TRUE) gimp_rgb_set_alpha (&color, 0.0); } return color; }
static void draw_wireframe_cylinder (gint startx, gint starty, gint pw, gint ph) { GimpVector3 p[2*8], a, axis, scale; gint n = 0, i; gdouble cx1, cy1, cx2, cy2; gfloat m[16], l, angle; /* Compute wireframe points */ /* ======================== */ init_compute (); scale = mapvals.scale; gimp_vector3_mul (&scale, 0.5); l = mapvals.cylinder_length / 2.0; angle = 0; gimp_vector3_set (&axis, 0.0, 1.0, 0.0); for (i = 0; i < 8; i++) { rotatemat (angle, &axis, m); gimp_vector3_set (&a, mapvals.cylinder_radius, 0.0, 0.0); vecmulmat (&p[i], &a, m); p[i+8] = p[i]; p[i].y += l; p[i+8].y -= l; angle += 360.0 / 8.0; } /* Rotate and translate points */ /* =========================== */ for (i = 0; i < 16; i++) { vecmulmat (&a, &p[i], rotmat); gimp_vector3_add (&p[i], &a, &mapvals.position); } /* Draw the box */ /* ============ */ cx1 = (gdouble) startx; cy1 = (gdouble) starty; cx2 = cx1 + (gdouble) pw; cy2 = cy1 + (gdouble) ph; for (i = 0; i < 7; i++) { n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+1]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i+8],p[i+9]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+8]); } n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[0]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[15],p[8]); /* Mark end of lines */ /* ================= */ linetab[n].x1 = -1; }
static gboolean intersect_box (GimpVector3 scale, GimpVector3 viewp, GimpVector3 dir, FaceIntersectInfo *face_intersect) { GimpVector3 v, d, tmp, axis[3]; FaceIntersectInfo face_tmp; gboolean result = FALSE; gfloat m[16]; gint i = 0; gimp_vector3_set (&axis[0], 1.0, 0.0, 0.0); gimp_vector3_set (&axis[1], 0.0, 1.0, 0.0); gimp_vector3_set (&axis[2], 0.0, 0.0, 1.0); /* Front side */ /* ========== */ if (intersect_rect (scale.x, scale.y, scale.z / 2.0, viewp, dir, &face_intersect[i]) == TRUE) { face_intersect[i].face = 0; gimp_vector3_set (&face_intersect[i++].n, 0.0, 0.0, 1.0); result = TRUE; } /* Back side */ /* ========= */ if (intersect_rect (scale.x, scale.y, -scale.z / 2.0, viewp, dir, &face_intersect[i]) == TRUE) { face_intersect[i].face = 1; face_intersect[i].u = 1.0 - face_intersect[i].u; gimp_vector3_set (&face_intersect[i++].n, 0.0, 0.0, -1.0); result = TRUE; } /* Check if we've found the two possible intersection points */ /* ========================================================= */ if (i < 2) { /* Top: Rotate viewpoint and direction into rectangle's local coordinate system */ /* ============================================================================ */ rotatemat (90, &axis[0], m); vecmulmat (&v, &viewp, m); vecmulmat (&d, &dir, m); if (intersect_rect (scale.x, scale.z, scale.y / 2.0, v, d, &face_intersect[i]) == TRUE) { face_intersect[i].face = 2; transpose_mat (m); vecmulmat(&tmp, &face_intersect[i].s, m); face_intersect[i].s = tmp; gimp_vector3_set (&face_intersect[i++].n, 0.0, -1.0, 0.0); result = TRUE; } } /* Check if we've found the two possible intersection points */ /* ========================================================= */ if (i < 2) { /* Bottom: Rotate viewpoint and direction into rectangle's local coordinate system */ /* =============================================================================== */ rotatemat (90, &axis[0], m); vecmulmat (&v, &viewp, m); vecmulmat (&d, &dir, m); if (intersect_rect (scale.x, scale.z, -scale.y / 2.0, v, d, &face_intersect[i]) == TRUE) { face_intersect[i].face = 3; transpose_mat (m); vecmulmat (&tmp, &face_intersect[i].s, m); face_intersect[i].s = tmp; face_intersect[i].v = 1.0 - face_intersect[i].v; gimp_vector3_set (&face_intersect[i++].n, 0.0, 1.0, 0.0); result = TRUE; } } /* Check if we've found the two possible intersection points */ /* ========================================================= */ if (i < 2) { /* Left side: Rotate viewpoint and direction into rectangle's local coordinate system */ /* ================================================================================== */ rotatemat (90, &axis[1], m); vecmulmat (&v, &viewp, m); vecmulmat (&d, &dir, m); if (intersect_rect (scale.z, scale.y, scale.x / 2.0, v, d, &face_intersect[i]) == TRUE) { face_intersect[i].face = 4; transpose_mat (m); vecmulmat (&tmp, &face_intersect[i].s, m); face_intersect[i].s = tmp; gimp_vector3_set (&face_intersect[i++].n, 1.0, 0.0, 0.0); result = TRUE; } } /* Check if we've found the two possible intersection points */ /* ========================================================= */ if (i < 2) { /* Right side: Rotate viewpoint and direction into rectangle's local coordinate system */ /* =================================================================================== */ rotatemat (90, &axis[1], m); vecmulmat (&v, &viewp, m); vecmulmat (&d, &dir, m); if (intersect_rect (scale.z, scale.y, -scale.x / 2.0, v, d, &face_intersect[i]) == TRUE) { face_intersect[i].face = 5; transpose_mat (m); vecmulmat (&tmp, &face_intersect[i].s, m); face_intersect[i].u = 1.0 - face_intersect[i].u; gimp_vector3_set (&face_intersect[i++].n, -1.0, 0.0, 0.0); result = TRUE; } } /* Sort intersection points */ /* ======================== */ if (face_intersect[0].t > face_intersect[1].t) { face_tmp = face_intersect[0]; face_intersect[0] = face_intersect[1]; face_intersect[1] = face_tmp; } return result; }
static void draw_wireframe_box (gint startx, gint starty, gint pw, gint ph) { GimpVector3 p[8], tmp, scale; gint n = 0, i; gdouble cx1, cy1, cx2, cy2; /* Compute wireframe points */ /* ======================== */ init_compute (); scale = mapvals.scale; gimp_vector3_mul (&scale, 0.5); gimp_vector3_set (&p[0], -scale.x, -scale.y, scale.z); gimp_vector3_set (&p[1], scale.x, -scale.y, scale.z); gimp_vector3_set (&p[2], scale.x, scale.y, scale.z); gimp_vector3_set (&p[3], -scale.x, scale.y, scale.z); gimp_vector3_set (&p[4], -scale.x, -scale.y, -scale.z); gimp_vector3_set (&p[5], scale.x, -scale.y, -scale.z); gimp_vector3_set (&p[6], scale.x, scale.y, -scale.z); gimp_vector3_set (&p[7], -scale.x, scale.y, -scale.z); /* Rotate and translate points */ /* =========================== */ for (i = 0; i < 8; i++) { vecmulmat (&tmp, &p[i], rotmat); gimp_vector3_add (&p[i], &tmp, &mapvals.position); } /* Draw the box */ /* ============ */ cx1 = (gdouble) startx; cy1 = (gdouble) starty; cx2 = cx1 + (gdouble) pw; cy2 = cy1 + (gdouble) ph; n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[1]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[2]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[3]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[0]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[4],p[5]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[5],p[6]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[6],p[7]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[4]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[0],p[4]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[1],p[5]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[2],p[6]); n = draw_line (n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[3],p[7]); /* Mark end of lines */ /* ================= */ linetab[n].x1 = -1; }