1 /******************************************************/
2 /* Apply mapping and shading on the whole input image */
3 /******************************************************/
4 
5 #include "config.h"
6 
7 #include <string.h>
8 
9 #include <gtk/gtk.h>
10 
11 #include <libgimp/gimp.h>
12 #include <libgimp/gimpui.h>
13 
14 #include "map-object-main.h"
15 #include "map-object-image.h"
16 #include "map-object-shade.h"
17 #include "map-object-apply.h"
18 
19 #include "libgimp/stdplugins-intl.h"
20 
21 
22 /*************/
23 /* Main loop */
24 /*************/
25 
26 gdouble       imat[4][4];
27 gfloat        rotmat[16];
28 static gfloat a[16], b[16];
29 
30 void
init_compute(void)31 init_compute (void)
32 {
33   gint i;
34 
35   switch (mapvals.maptype)
36     {
37       case MAP_SPHERE:
38 
39         /* Rotate the equator/northpole axis */
40         /* ================================= */
41 
42         gimp_vector3_set (&mapvals.firstaxis,  0.0, 0.0, -1.0);
43         gimp_vector3_set (&mapvals.secondaxis, 0.0, 1.0,  0.0);
44 
45         gimp_vector3_rotate (&mapvals.firstaxis,
46                              gimp_deg_to_rad (mapvals.alpha),
47                              gimp_deg_to_rad (mapvals.beta),
48                              gimp_deg_to_rad (mapvals.gamma));
49         gimp_vector3_rotate (&mapvals.secondaxis,
50                              gimp_deg_to_rad (mapvals.alpha),
51                              gimp_deg_to_rad (mapvals.beta),
52                              gimp_deg_to_rad (mapvals.gamma));
53 
54         /* Compute the 2D bounding box of the sphere spanned by the axis */
55         /* ============================================================= */
56 
57         compute_bounding_box ();
58 
59         get_ray_color = get_ray_color_sphere;
60 
61         break;
62 
63       case MAP_PLANE:
64 
65         /* Rotate the plane axis */
66         /* ===================== */
67 
68         gimp_vector3_set (&mapvals.firstaxis,  1.0, 0.0, 0.0);
69         gimp_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
70         gimp_vector3_set (&mapvals.normal,     0.0, 0.0, 1.0);
71 
72         gimp_vector3_rotate (&mapvals.firstaxis,
73                              gimp_deg_to_rad (mapvals.alpha),
74                              gimp_deg_to_rad (mapvals.beta),
75                              gimp_deg_to_rad (mapvals.gamma));
76         gimp_vector3_rotate (&mapvals.secondaxis,
77                              gimp_deg_to_rad (mapvals.alpha),
78                              gimp_deg_to_rad (mapvals.beta),
79                              gimp_deg_to_rad (mapvals.gamma));
80 
81         mapvals.normal = gimp_vector3_cross_product (&mapvals.firstaxis,
82                                                      &mapvals.secondaxis);
83 
84         if (mapvals.normal.z < 0.0)
85           gimp_vector3_mul (&mapvals.normal, -1.0);
86 
87         /* Initialize intersection matrix */
88         /* ============================== */
89 
90         imat[0][1] = -mapvals.firstaxis.x;
91         imat[1][1] = -mapvals.firstaxis.y;
92         imat[2][1] = -mapvals.firstaxis.z;
93 
94         imat[0][2] = -mapvals.secondaxis.x;
95         imat[1][2] = -mapvals.secondaxis.y;
96         imat[2][2] = -mapvals.secondaxis.z;
97 
98         imat[0][3] = mapvals.position.x - mapvals.viewpoint.x;
99         imat[1][3] = mapvals.position.y - mapvals.viewpoint.y;
100         imat[2][3] = mapvals.position.z - mapvals.viewpoint.z;
101 
102         get_ray_color = get_ray_color_plane;
103 
104         break;
105 
106       case MAP_BOX:
107         get_ray_color = get_ray_color_box;
108 
109         gimp_vector3_set (&mapvals.firstaxis,  1.0, 0.0, 0.0);
110         gimp_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
111         gimp_vector3_set (&mapvals.normal,     0.0, 0.0, 1.0);
112 
113         ident_mat (rotmat);
114 
115         rotatemat (mapvals.alpha, &mapvals.firstaxis, a);
116 
117         matmul (a, rotmat, b);
118 
119         memcpy (rotmat, b, sizeof (gfloat) * 16);
120 
121         rotatemat (mapvals.beta, &mapvals.secondaxis, a);
122         matmul (a, rotmat, b);
123 
124         memcpy (rotmat, b, sizeof (gfloat) * 16);
125 
126         rotatemat (mapvals.gamma, &mapvals.normal, a);
127         matmul (a, rotmat, b);
128 
129         memcpy (rotmat, b, sizeof (gfloat) * 16);
130 
131         /* Set up pixel regions for the box face images */
132         /* ============================================ */
133 
134         for (i = 0; i < 6; i++)
135           {
136             box_drawable_ids[i] = mapvals.boxmap_id[i];
137 
138             box_buffers[i] = gimp_drawable_get_buffer (box_drawable_ids[i]);
139           }
140 
141         break;
142 
143       case MAP_CYLINDER:
144         get_ray_color = get_ray_color_cylinder;
145 
146         gimp_vector3_set (&mapvals.firstaxis,  1.0, 0.0, 0.0);
147         gimp_vector3_set (&mapvals.secondaxis, 0.0, 1.0, 0.0);
148         gimp_vector3_set (&mapvals.normal,     0.0, 0.0, 1.0);
149 
150         ident_mat (rotmat);
151 
152         rotatemat (mapvals.alpha, &mapvals.firstaxis, a);
153 
154         matmul (a, rotmat, b);
155 
156         memcpy (rotmat, b, sizeof (gfloat) * 16);
157 
158         rotatemat (mapvals.beta, &mapvals.secondaxis, a);
159         matmul (a, rotmat, b);
160 
161         memcpy (rotmat, b, sizeof (gfloat) * 16);
162 
163         rotatemat (mapvals.gamma, &mapvals.normal, a);
164         matmul (a, rotmat, b);
165 
166         memcpy (rotmat, b, sizeof (gfloat) * 16);
167 
168         /* Set up pixel regions for the cylinder cap images */
169         /* ================================================ */
170 
171         for (i = 0; i < 2; i++)
172           {
173             cylinder_drawable_ids[i] = mapvals.cylindermap_id[i];
174 
175             cylinder_buffers[i] = gimp_drawable_get_buffer (cylinder_drawable_ids[i]);
176           }
177         break;
178     }
179 
180   max_depth = (gint) mapvals.maxdepth;
181 }
182 
183 static void
render(gdouble x,gdouble y,GimpRGB * col,gpointer data)184 render (gdouble   x,
185         gdouble   y,
186         GimpRGB  *col,
187         gpointer  data)
188 {
189   GimpVector3 pos;
190 
191   pos.x = x / (gdouble) width;
192   pos.y = y / (gdouble) height;
193   pos.z = 0.0;
194 
195   *col = get_ray_color (&pos);
196 }
197 
198 static void
show_progress(gint min,gint max,gint curr,gpointer data)199 show_progress (gint     min,
200                gint     max,
201                gint     curr,
202                gpointer data)
203 {
204   gimp_progress_update ((gdouble) curr / (gdouble) max);
205 }
206 
207 /**************************************************/
208 /* Performs map-to-sphere on the whole input image */
209 /* and updates or creates a new GIMP image.       */
210 /**************************************************/
211 
212 void
compute_image(void)213 compute_image (void)
214 {
215   gint         xcount, ycount;
216   GimpRGB      color;
217   glong        progress_counter = 0;
218   GimpVector3  p;
219   gint32       new_image_id = -1;
220   gint32       new_layer_id = -1;
221   gboolean     insert_layer = FALSE;
222 
223   init_compute ();
224 
225   if (mapvals.create_new_image)
226     {
227       new_image_id = gimp_image_new (width, height, GIMP_RGB);
228     }
229   else
230     {
231       new_image_id = image_id;
232     }
233 
234   gimp_image_undo_group_start (new_image_id);
235 
236   if (mapvals.create_new_image ||
237       mapvals.create_new_layer ||
238       (mapvals.transparent_background &&
239        ! gimp_drawable_has_alpha (output_drawable_id)))
240     {
241       gchar *layername[] = {_("Map to plane"),
242                             _("Map to sphere"),
243                             _("Map to box"),
244                             _("Map to cylinder"),
245                             _("Background")};
246 
247       new_layer_id = gimp_layer_new (new_image_id,
248                                      layername[mapvals.create_new_image ? 4 :
249                                                mapvals.maptype],
250                                      width, height,
251                                      mapvals.transparent_background ?
252                                      GIMP_RGBA_IMAGE :
253                                      GIMP_RGB_IMAGE,
254                                      100.0,
255                                      gimp_image_get_default_new_layer_mode (new_image_id));
256 
257       insert_layer = TRUE;
258       output_drawable_id = new_layer_id;
259     }
260 
261   dest_buffer = gimp_drawable_get_shadow_buffer (output_drawable_id);
262 
263   switch (mapvals.maptype)
264     {
265       case MAP_PLANE:
266         gimp_progress_init (_("Map to plane"));
267         break;
268       case MAP_SPHERE:
269         gimp_progress_init (_("Map to sphere"));
270         break;
271       case MAP_BOX:
272         gimp_progress_init (_("Map to box"));
273         break;
274       case MAP_CYLINDER:
275         gimp_progress_init (_("Map to cylinder"));
276         break;
277     }
278 
279   if (! mapvals.antialiasing)
280     {
281       for (ycount = 0; ycount < height; ycount++)
282         {
283           for (xcount = 0; xcount < width; xcount++)
284             {
285               p = int_to_pos (xcount, ycount);
286               color = (* get_ray_color) (&p);
287               poke (xcount, ycount, &color, NULL);
288 
289               progress_counter++;
290             }
291 
292           gimp_progress_update ((gdouble) progress_counter /
293                                 (gdouble) maxcounter);
294         }
295     }
296   else
297     {
298       gimp_adaptive_supersample_area (0, 0,
299                                       width - 1, height - 1,
300                                       max_depth,
301                                       mapvals.pixelthreshold,
302                                       render,
303                                       NULL,
304                                       poke,
305                                       NULL,
306                                       show_progress,
307                                       NULL);
308     }
309 
310   gimp_progress_update (1.0);
311 
312   g_object_unref (source_buffer);
313   g_object_unref (dest_buffer);
314 
315   if (insert_layer)
316     gimp_image_insert_layer (new_image_id, new_layer_id, -1, 0);
317 
318   gimp_drawable_merge_shadow (output_drawable_id, TRUE);
319   gimp_drawable_update (output_drawable_id, 0, 0, width, height);
320 
321   if (new_image_id != image_id)
322     {
323       gimp_display_new (new_image_id);
324       gimp_displays_flush ();
325     }
326 
327   gimp_image_undo_group_end (new_image_id);
328 }
329