PIKApp/plug-ins/map-object/map-object-apply.c

416 lines
13 KiB
C

/******************************************************/
/* Apply mapping and shading on the whole input image */
/******************************************************/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "map-object-main.h"
#include "map-object-image.h"
#include "map-object-shade.h"
#include "map-object-apply.h"
#include "libpika/stdplugins-intl.h"
/*************/
/* Main loop */
/*************/
gdouble imat[4][4];
gfloat rotmat[16];
static gfloat a[16], b[16];
void
init_compute (void)
{
gint i;
switch (mapvals.maptype)
{
case MAP_SPHERE:
/* Rotate the equator/northpole axis */
/* ================================= */
pika_vector3_set (&mapvals.firstaxis, 0.0, 0.0, -1.0);
pika_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
pika_vector3_rotate (&mapvals.firstaxis,
pika_deg_to_rad (mapvals.alpha),
pika_deg_to_rad (mapvals.beta),
pika_deg_to_rad (mapvals.gamma));
pika_vector3_rotate (&mapvals.secondaxis,
pika_deg_to_rad (mapvals.alpha),
pika_deg_to_rad (mapvals.beta),
pika_deg_to_rad (mapvals.gamma));
/* Compute the 2D bounding box of the sphere spanned by the axis */
/* ============================================================= */
compute_bounding_box ();
get_ray_color = get_ray_color_sphere;
break;
case MAP_PLANE:
/* Rotate the plane axis */
/* ===================== */
pika_vector3_set (&mapvals.firstaxis, 1.0, 0.0, 0.0);
pika_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
pika_vector3_set (&mapvals.normal, 0.0, 0.0, 1.0);
pika_vector3_rotate (&mapvals.firstaxis,
pika_deg_to_rad (mapvals.alpha),
pika_deg_to_rad (mapvals.beta),
pika_deg_to_rad (mapvals.gamma));
pika_vector3_rotate (&mapvals.secondaxis,
pika_deg_to_rad (mapvals.alpha),
pika_deg_to_rad (mapvals.beta),
pika_deg_to_rad (mapvals.gamma));
mapvals.normal = pika_vector3_cross_product (&mapvals.firstaxis,
&mapvals.secondaxis);
if (mapvals.normal.z < 0.0)
pika_vector3_mul (&mapvals.normal, -1.0);
/* Initialize intersection matrix */
/* ============================== */
imat[0][1] = -mapvals.firstaxis.x;
imat[1][1] = -mapvals.firstaxis.y;
imat[2][1] = -mapvals.firstaxis.z;
imat[0][2] = -mapvals.secondaxis.x;
imat[1][2] = -mapvals.secondaxis.y;
imat[2][2] = -mapvals.secondaxis.z;
imat[0][3] = mapvals.position.x - mapvals.viewpoint.x;
imat[1][3] = mapvals.position.y - mapvals.viewpoint.y;
imat[2][3] = mapvals.position.z - mapvals.viewpoint.z;
get_ray_color = get_ray_color_plane;
break;
case MAP_BOX:
get_ray_color = get_ray_color_box;
pika_vector3_set (&mapvals.firstaxis, 1.0, 0.0, 0.0);
pika_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
pika_vector3_set (&mapvals.normal, 0.0, 0.0, 1.0);
ident_mat (rotmat);
rotatemat (mapvals.alpha, &mapvals.firstaxis, a);
matmul (a, rotmat, b);
memcpy (rotmat, b, sizeof (gfloat) * 16);
rotatemat (mapvals.beta, &mapvals.secondaxis, a);
matmul (a, rotmat, b);
memcpy (rotmat, b, sizeof (gfloat) * 16);
rotatemat (mapvals.gamma, &mapvals.normal, a);
matmul (a, rotmat, b);
memcpy (rotmat, b, sizeof (gfloat) * 16);
/* Set up pixel regions for the box face images */
/* ============================================ */
for (i = 0; i < 6; i++)
{
box_drawables[i] = pika_drawable_get_by_id (mapvals.boxmap_id[i]);
box_buffers[i] = pika_drawable_get_buffer (box_drawables[i]);
}
break;
case MAP_CYLINDER:
get_ray_color = get_ray_color_cylinder;
pika_vector3_set (&mapvals.firstaxis, 1.0, 0.0, 0.0);
pika_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
pika_vector3_set (&mapvals.normal, 0.0, 0.0, 1.0);
ident_mat (rotmat);
rotatemat (mapvals.alpha, &mapvals.firstaxis, a);
matmul (a, rotmat, b);
memcpy (rotmat, b, sizeof (gfloat) * 16);
rotatemat (mapvals.beta, &mapvals.secondaxis, a);
matmul (a, rotmat, b);
memcpy (rotmat, b, sizeof (gfloat) * 16);
rotatemat (mapvals.gamma, &mapvals.normal, a);
matmul (a, rotmat, b);
memcpy (rotmat, b, sizeof (gfloat) * 16);
/* Set up pixel regions for the cylinder cap images */
/* ================================================ */
for (i = 0; i < 2; i++)
{
cylinder_drawables[i] = pika_drawable_get_by_id (mapvals.cylindermap_id[i]);;
cylinder_buffers[i] = pika_drawable_get_buffer (cylinder_drawables[i]);
}
break;
}
max_depth = (gint) mapvals.maxdepth;
}
static void
render (gdouble x,
gdouble y,
PikaRGB *col,
gpointer data)
{
PikaVector3 pos;
pos.x = x / (gdouble) width;
pos.y = y / (gdouble) height;
pos.z = 0.0;
*col = get_ray_color (&pos);
}
static void
show_progress (gint min,
gint max,
gint curr,
gpointer data)
{
pika_progress_update ((gdouble) curr / (gdouble) max);
}
/**************************************************/
/* Performs map-to-sphere on the whole input image */
/* and updates or creates a new PIKA image. */
/**************************************************/
void
compute_image (void)
{
gint xcount, ycount;
PikaRGB color;
glong progress_counter = 0;
PikaVector3 p;
PikaImage *new_image = NULL;
PikaLayer *new_layer = NULL;
gboolean insert_layer = FALSE;
init_compute ();
if (mapvals.create_new_image)
{
new_image = pika_image_new (width, height, PIKA_RGB);
}
else
{
new_image = image;
}
pika_image_undo_group_start (new_image);
if (mapvals.create_new_image ||
mapvals.create_new_layer ||
(mapvals.transparent_background &&
! pika_drawable_has_alpha (output_drawable)))
{
gchar *layername[] = {_("Map to plane"),
_("Map to sphere"),
_("Map to box"),
_("Map to cylinder"),
_("Background")};
new_layer = pika_layer_new (new_image,
layername[mapvals.create_new_image ? 4 :
mapvals.maptype],
width, height,
mapvals.transparent_background ?
PIKA_RGBA_IMAGE :
PIKA_RGB_IMAGE,
100.0,
pika_image_get_default_new_layer_mode (new_image));
insert_layer = TRUE;
output_drawable = PIKA_DRAWABLE (new_layer);
}
dest_buffer = pika_drawable_get_shadow_buffer (output_drawable);
switch (mapvals.maptype)
{
case MAP_PLANE:
pika_progress_init (_("Map to plane"));
break;
case MAP_SPHERE:
pika_progress_init (_("Map to sphere"));
break;
case MAP_BOX:
pika_progress_init (_("Map to box"));
break;
case MAP_CYLINDER:
pika_progress_init (_("Map to cylinder"));
break;
}
if (! mapvals.antialiasing)
{
for (ycount = 0; ycount < height; ycount++)
{
for (xcount = 0; xcount < width; xcount++)
{
p = int_to_pos (xcount, ycount);
color = (* get_ray_color) (&p);
poke (xcount, ycount, &color, NULL);
progress_counter++;
}
pika_progress_update ((gdouble) progress_counter /
(gdouble) maxcounter);
}
}
else
{
pika_adaptive_supersample_area (0, 0,
width - 1, height - 1,
max_depth,
mapvals.pixelthreshold,
render,
NULL,
poke,
NULL,
show_progress,
NULL);
}
pika_progress_update (1.0);
g_object_unref (source_buffer);
g_object_unref (dest_buffer);
if (insert_layer)
pika_image_insert_layer (new_image, new_layer, NULL, 0);
pika_drawable_merge_shadow (output_drawable, TRUE);
pika_drawable_update (output_drawable, 0, 0, width, height);
if (new_image != image)
{
pika_display_new (new_image);
pika_displays_flush ();
}
pika_image_undo_group_end (new_image);
}
void
copy_from_config (PikaProcedureConfig *config)
{
PikaDrawable *box_front = NULL;
PikaDrawable *box_back = NULL;
PikaDrawable *box_top = NULL;
PikaDrawable *box_bottom = NULL;
PikaDrawable *box_left = NULL;
PikaDrawable *box_right = NULL;
PikaDrawable *cyl_top = NULL;
PikaDrawable *cyl_bottom = NULL;
mapvals.maptype = pika_procedure_config_get_choice_id (config, "map-type");
mapvals.lightsource.type =
pika_procedure_config_get_choice_id (config, "light-type");
g_object_get (config,
"viewpoint-x", &mapvals.viewpoint.x,
"viewpoint-y", &mapvals.viewpoint.y,
"viewpoint-z", &mapvals.viewpoint.z,
"position-x", &mapvals.position.x,
"position-y", &mapvals.position.y,
"position-z", &mapvals.position.z,
"first-axis-x", &mapvals.firstaxis.x,
"first-axis-y", &mapvals.firstaxis.y,
"first-axis-z", &mapvals.firstaxis.z,
"second-axis-x", &mapvals.secondaxis.x,
"second-axis-y", &mapvals.secondaxis.y,
"second-axis-z", &mapvals.secondaxis.z,
"rotation-angle-x", &mapvals.alpha,
"rotation-angle-y", &mapvals.beta,
"rotation-angle-z", &mapvals.gamma,
"light-color", &mapvals.lightsource.color,
"light-position-x", &mapvals.lightsource.position.x,
"light-position-y", &mapvals.lightsource.position.y,
"light-position-z", &mapvals.lightsource.position.z,
"light-direction-x", &mapvals.lightsource.direction.x,
"light-direction-y", &mapvals.lightsource.direction.y,
"light-direction-z", &mapvals.lightsource.direction.z,
"ambient-intensity", &mapvals.material.ambient_int,
"diffuse-intensity", &mapvals.material.diffuse_int,
"diffuse-reflectivity", &mapvals.material.diffuse_ref,
"specular-reflectivity", &mapvals.material.specular_ref,
"highlight", &mapvals.material.highlight,
"antialiasing", &mapvals.antialiasing,
"depth", &mapvals.maxdepth,
"threshold", &mapvals.pixelthreshold,
"tiled", &mapvals.tiled,
"new-image", &mapvals.create_new_image,
"new-layer", &mapvals.create_new_layer,
"transparent-background", &mapvals.transparent_background,
"sphere-radius", &mapvals.radius,
"box-front-drawable", &box_front,
"box-back-drawable", &box_back,
"box-top-drawable", &box_top,
"box-bottom-drawable", &box_bottom,
"box-left-drawable", &box_left,
"box-right-drawable", &box_right,
"x-scale", &mapvals.scale.x,
"y-scale", &mapvals.scale.y,
"z-scale", &mapvals.scale.z,
"cyl-top-drawable", &cyl_top,
"cyl-bottom-drawable", &cyl_bottom,
"cylinder-radius", &mapvals.cylinder_radius,
"cylinder-length", &mapvals.cylinder_length,
NULL);
if (box_front)
mapvals.boxmap_id[0] = pika_item_get_id (PIKA_ITEM (box_front));
if (box_back)
mapvals.boxmap_id[1] = pika_item_get_id (PIKA_ITEM (box_back));
if (box_top)
mapvals.boxmap_id[2] = pika_item_get_id (PIKA_ITEM (box_top));
if (box_bottom)
mapvals.boxmap_id[3] = pika_item_get_id (PIKA_ITEM (box_bottom));
if (box_left)
mapvals.boxmap_id[4] = pika_item_get_id (PIKA_ITEM (box_left));
if (box_right)
mapvals.boxmap_id[5] = pika_item_get_id (PIKA_ITEM (box_right));
if (cyl_top)
mapvals.cylindermap_id[0] = pika_item_get_id (PIKA_ITEM (cyl_top));
if (cyl_bottom)
mapvals.cylindermap_id[0] = pika_item_get_id (PIKA_ITEM (cyl_bottom));
}