src/Makefile: Updated..
[libopano.git] / src / viewer.c
1 /* Panorama_Tools       -       Generate, Edit and Convert Panoramic Images
2    Copyright (C) 1998,1999,2000 - Helmut Dersch  der@fh-furtwangen.de
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /*------------------------------------------------------------*/
19
20 #include <X11/X.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xutil.h>
23 #include <X11/cursorfont.h>
24 #include <X11/keysym.h>
25 #include <X11/Xatom.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <stdint.h>
29
30 #include "filter.h"
31 #include "panolib.h"
32 #include "utils_image.h"
33
34 #define DEF_VIEW_WIDTH  400
35 #define DEF_VIEW_HEIGHT 300
36
37 char text[] = "PTViewer";
38
39 Display         *disp_g;
40 Window          window_g;
41 int             screen_g;
42 GC              gc;
43 Visual          *visual_g;
44 unsigned int    depth_g;
45
46
47 static int copy_rgb_to_zpixmap (XImage *dest, const ui_image_t *src)
48 {
49         uint32_t *src_data;
50
51         uint32_t src_r;
52         uint32_t src_g;
53         uint32_t src_b;
54
55         uint32_t dest_r;
56         uint32_t dest_g;
57         uint32_t dest_b;
58         uint32_t dest_pixel_value;
59
60         uint32_t x;
61         uint32_t y;
62         uint32_t pixel;
63
64         uint32_t dest_r_maxval;
65         uint32_t dest_g_maxval;
66         uint32_t dest_b_maxval;
67
68         uint32_t dest_r_offset;
69         uint32_t dest_g_offset;
70         uint32_t dest_b_offset;
71
72         dest_r_offset = 0;
73         dest_g_offset = 0;
74         dest_b_offset = 0;
75         dest_r_maxval = dest->red_mask;
76         dest_g_maxval = dest->green_mask;
77         dest_b_maxval = dest->blue_mask;
78         for (x = 0; x < dest->depth; x++)
79         {
80                 if ((dest_r_maxval & 0x01) == 0)
81                 {
82                         dest_r_offset++;
83                         dest_r_maxval >>= 1;
84                 }
85                 if ((dest_g_maxval & 0x01) == 0)
86                 {
87                         dest_g_offset++;
88                         dest_g_maxval >>= 1;
89                 }
90                 if ((dest_b_maxval & 0x01) == 0)
91                 {
92                         dest_b_offset++;
93                         dest_b_maxval >>= 1;
94                 }
95         }
96
97         src_data = (uint32_t *) *src->data;
98
99         pixel = 0;
100         for (y = 0; y < dest->height; y++)
101         {
102                 for (x = 0; x < dest->width; x++, pixel++)
103                 {
104                         int32_t bytenum;
105
106                         src_r = src->data[0][pixel];
107                         src_g = src->data[1][pixel];
108                         src_b = src->data[2][pixel];
109
110                         dest_r = dest_r_maxval * src_r / 255;
111                         dest_g = dest_g_maxval * src_g / 255;
112                         dest_b = dest_b_maxval * src_b / 255;
113
114                         dest_pixel_value = 0
115                                 | ((dest_r << dest_r_offset) & dest->red_mask)
116                                 | ((dest_g << dest_g_offset) & dest->green_mask)
117                                 | ((dest_b << dest_b_offset) & dest->blue_mask);
118
119                         for (bytenum = 0; bytenum < (dest->depth / 8); bytenum++)
120                         {
121                                 dest->data[(pixel * dest->bits_per_pixel / 8) + bytenum] = 
122                                         (dest_pixel_value >> (dest->bits_per_pixel - (8 * (bytenum + 1)))) & 0xFF;
123                         }
124                 }
125         }
126
127         return (0);
128 } /* int copy_rgb_to_zpixmap */
129
130 static int draw_window (const ui_image_t *img)
131 {
132   static XImage *ximage = NULL;
133
134   if ((ximage != NULL) && ((img->width != ximage->width) || (img->height != ximage->height)))
135   {
136     free (ximage->data);
137     ximage->data = NULL;
138     XDestroyImage (ximage);
139     ximage = NULL;
140   }
141
142   if (ximage == NULL)
143   {
144     ximage = XCreateImage(disp_g, visual_g, depth_g, ZPixmap, 0,
145         NULL, img->width, img->height,
146         8, 0);
147     if (ximage == NULL)
148       return (-1);
149
150     ximage->byte_order= MSBFirst;
151
152     ximage->data = (char *) malloc (img->width * img->height * depth_g / 8);
153     if (ximage->data == NULL)
154     {
155       XDestroyImage (ximage);
156       ximage = NULL;
157       return (-1);
158     }
159   }
160
161   copy_rgb_to_zpixmap (ximage, img);
162   XPutImage(disp_g, window_g, gc, ximage, 0, 0,
163       0, 0, ximage->width, ximage->height);
164
165   return (0);
166 } /* int draw_window */
167
168 #define ZOOM_SPEED 1.03
169
170 static void zoom_in (double *fov)
171 {
172   *fov = *fov / ZOOM_SPEED;
173   if (*fov < 10.5)
174     *fov = 10.5;
175 } /* void zoom_in */
176
177 static void zoom_out (double *fov)
178 {
179   *fov = *fov * ZOOM_SPEED;
180   if (*fov > 165.0)
181     *fov = 165.0;
182 } /* void zoom_out */
183
184 int main( int argc, char** argv )
185 {
186   unsigned long color_fg, color_bg;
187   int done;
188   static Atom                   proto_atom= None, delete_atom= None;
189
190   long event_mask;
191
192   double fov = 70.0;
193   double yaw = 0.0;
194   double pitch = 0.0;
195
196   /* Detect mouse movement direction */
197   unsigned int btn_current_pressed = 0;
198   int btn_reference_pos_x = 0;
199   int btn_reference_pos_y = 0;
200   int btn_current_pos_x = 0;
201   int btn_current_pos_y = 0;
202
203   ui_image_t *pano;
204   ui_image_t *view;
205
206
207   // Set up display
208   disp_g   = XOpenDisplay("");
209   screen_g = DefaultScreen(disp_g);
210   depth_g  = DefaultDepth(disp_g, screen_g);
211
212   color_bg = WhitePixel(disp_g,screen_g);
213   color_fg = BlackPixel(disp_g,screen_g);
214
215   // Load panoramic image       
216   if( argc < 2 )
217   {
218     PrintError("No image file supplied");
219     exit(0);
220   }
221
222   if( strcmp( argv[1], "-h" ) == 0 ) /* FIXME: Use getopt */
223   {
224     PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
225     exit(0);
226   }
227
228   pano = ui_create_file (argv[1]);
229   if (pano == NULL)
230   {
231     PrintError ("Unable to read pano file.");
232     exit (0);
233   }
234
235   printf ("Panorama `%s', %ux%u pixels, loaded.\n",
236       argv[1], pano->width, pano->height);
237
238   view = ui_create (DEF_VIEW_WIDTH, DEF_VIEW_HEIGHT); /* FIXME: Possibly chose another size */
239   if (view == NULL)
240   {
241     PrintError ("Unable to create view.");
242     exit (0);
243   }
244
245   window_g = XCreateSimpleWindow(disp_g,
246       DefaultRootWindow(disp_g),
247       0, 0, /* Position */
248       view->width, view->height,
249       5,
250       color_fg, color_bg);
251
252   {
253     XSizeHints hint;
254
255     memset (&hint, '\0', sizeof (hint));
256     hint.width  = view->width;
257     hint.height = view->height;
258     hint.flags = PSize;
259
260     XSetStandardProperties(disp_g,
261         window_g,
262         text,
263         text,
264         None,
265         argv,
266         argc,
267         &hint);
268   }
269
270   gc = XCreateGC(disp_g,window_g,0,0);
271   XSetBackground(disp_g,gc,color_bg);
272   XSetForeground(disp_g,gc,color_fg);
273
274   event_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
275     | KeyPressMask | KeyReleaseMask | StructureNotifyMask
276     | EnterWindowMask | LeaveWindowMask| ExposureMask;
277
278   XSelectInput(disp_g, window_g, event_mask);
279   XMapRaised(disp_g,window_g);
280
281   proto_atom    = XInternAtom(disp_g, "WM_PROTOCOLS", False);
282   delete_atom = XInternAtom(disp_g, "WM_DELETE_WINDOW", False);
283   if ((proto_atom != None) && (delete_atom != None))
284     XChangeProperty(disp_g, window_g, proto_atom, XA_ATOM, 32,
285         PropModeReplace, (unsigned char *)&delete_atom,
286         1);
287   visual_g  = DefaultVisual(disp_g, screen_g);
288
289   pl_extract_view (view, pano, pitch, yaw, fov, BILINEAR);
290   draw_window (view);
291
292   done = 0;
293   while (done == 0)
294   {
295     int isChanged = 0;
296     XEvent event;
297
298     memset (&event, '\0', sizeof (event));
299
300     if (btn_current_pressed == 0)
301     {
302       /* No button is pressed -> block */
303       XMaskEvent (disp_g, event_mask, &event);
304     }
305     else
306     {
307       /* A button is pressed -> do not block */
308       XCheckMaskEvent (disp_g, event_mask, &event);
309     }
310
311     switch (event.type)
312     {
313       case 0: /* XCheckMaskEvent didn't return an event */
314         break;
315
316       case Expose:
317         {
318           XExposeEvent *eev = (XExposeEvent *) &event;
319
320           while (eev->count != 0)
321           {
322             if (!XCheckTypedEvent (disp_g, Expose, &event))
323             {
324               eev = NULL;
325               break;
326             }
327             /* do nothing */
328           }
329
330           if (eev != NULL)
331             isChanged = 1;
332         }
333         break;
334
335       case EnterNotify:
336         break;
337
338       case LeaveNotify:
339         break;
340
341       case ConfigureNotify:
342         {
343           XConfigureEvent *cev = (XConfigureEvent *) &event;
344
345           ui_destroy (view);
346           view = ui_create (cev->width, cev->height);
347           isChanged = 1;
348         }
349         break;
350
351       case KeyPress:
352         {
353           XKeyEvent *kev = (XKeyEvent *) &event;
354           char buffer[64];
355           int buffer_len = sizeof (buffer);
356           KeySym ks;
357
358           buffer_len = XLookupString(kev, buffer, sizeof (buffer), &ks, NULL);
359
360           if (buffer_len >= sizeof (buffer))
361             buffer_len = sizeof (buffer) - 1;
362           buffer[buffer_len] = '\0';
363
364           switch (ks)
365           {
366             case XK_Shift_L:
367             case XK_Shift_R:
368               zoom_in (&fov);
369               isChanged = 1;
370               break;
371
372             case XK_Control_L:
373             case XK_Control_R:
374               zoom_out (&fov);
375               isChanged = 1;
376               break;
377
378             case XK_Up:
379               pitch += 5.0;
380               if (pitch > 90.0)
381                 pitch = 90.0;
382               isChanged = 1;
383               break;
384
385             case XK_Down:
386               pitch -= 5.0;
387               if (pitch < -90.0)
388                 pitch = -90.0;
389               isChanged = 1;
390               break;
391
392             case XK_Right:
393               yaw += 5.0;
394               if (yaw > 180.0)
395                 yaw -= 360.0;
396               isChanged = 1;
397               break;
398
399             case XK_Left:
400               yaw -= 5.0;
401               if (yaw <= -180.0)
402                 yaw += 360.0;
403               isChanged = 1;
404               break;
405
406             case XK_q:
407               done++;
408               break;
409
410             default:
411               printf ("Unhandeled KeySym 0x%02llx, buffer = %s\n", (uint64_t) ks, buffer);
412           }
413         }
414         break;
415
416 #if 0
417       case KeyRelease:
418         printf ("Ignoring KeyRelease event.\n");
419         break;
420 #endif
421
422       case ButtonPress:
423       /* case ButtonRelease: */
424         {
425           XButtonEvent *bev = (XButtonEvent *) &event;
426
427           btn_current_pressed = bev->button;
428           btn_current_pos_x = btn_reference_pos_x = bev->x;
429           btn_current_pos_y = btn_reference_pos_y = bev->y;
430         }
431         break;
432
433       case ButtonRelease:
434         btn_current_pressed = 0;
435         /* Re-draw the image (when no button is pressed better interpolation is
436          * used. */
437         isChanged = 1;
438         break;
439
440       case MotionNotify:
441         {
442           XMotionEvent *mev = (XMotionEvent *) &event;
443
444           do
445           {
446             btn_current_pos_x = mev->x;
447             btn_current_pos_y = mev->y;
448           }
449           while (XCheckTypedEvent (disp_g, MotionNotify, &event));
450         }
451         break;
452
453       default:
454         printf ("Unhandled event type: 0x%02x\n",
455             event.type);
456     } /* switch (event.type) */
457
458     /*
459      * Check for pressed buttons and change view accordingly
460      */
461     if (btn_current_pressed == Button1)
462     {
463       double yaw_diff = (btn_current_pos_x - btn_reference_pos_x) / 24.0;
464       if (yaw_diff > 90.0)
465         yaw_diff = 90.0;
466       else if (yaw_diff < -90.0)
467         yaw_diff = -90.0;
468
469       yaw += yaw_diff;
470       if (yaw > 180.0)
471         yaw -= 360.0;
472       else if (yaw <= -180.0)
473         yaw += 360.0;
474
475       pitch -= (btn_current_pos_y - btn_reference_pos_y) / 24.0;
476       if (pitch > 90.0)
477         pitch = 90.0;
478       else if (pitch < -90.0)
479         pitch = -90.0;
480
481       isChanged = 1;
482     }
483     else if (btn_current_pressed == Button3)
484     {
485       double zoom_diff = (btn_current_pos_y - btn_reference_pos_y) / 64.0;
486       double zoom_ratio = pow (ZOOM_SPEED, zoom_diff);
487
488       fov *= zoom_ratio;
489       if (fov < 10.5)
490         fov = 10.5;
491       else if (fov > 165.0)
492         fov = 165.0;
493
494       isChanged = 1;
495     }
496
497     if (isChanged != 0)
498     {
499       pl_extract_view (view, pano, pitch, yaw, fov,
500           (btn_current_pressed == 0) ? BILINEAR : NNEIGHBOUR);
501       draw_window (view);
502     }
503   } /* while (done == 0) */
504
505   XFreeGC(disp_g,gc);
506   XDestroyWindow(disp_g, window_g);
507   XCloseDisplay(disp_g);
508
509   return (0);
510 } /* int main */
511         
512
513
514
515
516
517 // Error reporting
518
519 void  PrintError( char* fmt, ...)
520 {
521         va_list ap;
522         char message[257];
523         
524         va_start(ap, fmt);
525         vsprintf(message, fmt, ap);
526         va_end(ap);
527         
528         printf("%s\n", message);
529 }
530
531 void**  mymalloc( long numBytes )                                       // Memory allocation, use Handles
532 {
533         char **mem;
534         
535         mem = (char**)malloc( sizeof(char*) );                  // Allocate memory for pointer
536         if(mem == NULL)
537                 return (void**)NULL;
538         else
539         {
540                 (*mem) = (char*) malloc( numBytes );            // Allocate numBytes
541                 if( *mem == NULL )
542                 {
543                         free( mem );
544                         return (void**)NULL;
545                 }
546                 else
547                         return (void**)mem;
548         }
549 }
550
551 void    myfree( void** Hdl )                                            // free Memory, use Handles
552 {
553         free( (char*) *Hdl );
554         free( (char**) Hdl );
555 }               
556
557
558 void SetImageDefaults(Image *im)
559 {
560         im->data                        = NULL;
561         im->bytesPerLine        = 0;
562         im->width                       = 0;
563         im->height                      = 0;
564         im->dataSize            = 0;
565         im->bitsPerPixel        = 0;
566         im->format                      = 0;
567         im->dataformat          = _RGB;
568         im->hfov                        = 0.0;
569         im->yaw                         = 0.0;
570         im->pitch                       = 0.0;
571         im->roll                        = 0.0;
572 //      SetCorrectDefaults( &(im->cP) );
573         *(im->name)                     = 0;
574 }
575
576 // expand image from 3 to 4 bits per pixel. No pad bytes allowed.
577 // Memory must be allocated
578 void ThreeToFourBPP( Image *im )
579 {
580         register int x,y,c1,c2;
581
582         if( im->bitsPerPixel == 32 || im->bitsPerPixel == 64) // Nothing to do
583                 return;
584         
585         
586         
587         if( im->bitsPerPixel == 24 )    // Convert to 4byte / pixel
588         {
589                 for( y = im->height-1; y>=0; y--)
590                 {
591                         for( x= im->width-1; x>=0; x--)
592                         {
593                                 c1 = (y * im->width + x) * 4;
594                                 c2 = y * im->bytesPerLine + x * 3;
595                                 (*(im->data))[c1++] = UCHAR_MAX;
596                                 (*(im->data))[c1++] = (*(im->data))[c2++];
597                                 (*(im->data))[c1++] = (*(im->data))[c2++];
598                                 (*(im->data))[c1++] = (*(im->data))[c2++];
599                         }
600                 }
601                 im->bitsPerPixel = 32;
602                 im->bytesPerLine = im->width * 4;
603         }
604         else if( im->bitsPerPixel == 48 ) // Convert to 8byte / pixel
605         {
606                 for( y = im->height-1; y>=0; y--)
607                 {
608                         for( x= im->width-1; x>=0; x--)
609                         {
610                                 c1 = (y * im->width + x) * 4;
611                                 c2 = y * im->bytesPerLine/2 + x * 3;
612                                 ((USHORT*)(*(im->data)))[c1++] = USHRT_MAX;
613                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
614                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
615                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
616                         }
617                 }
618                 im->bitsPerPixel = 64;
619                 im->bytesPerLine = im->width * 8;
620         }
621         im->dataSize = im->height * im->bytesPerLine;
622 }
623
624 /*
625  * vim: set shiftwidth=2 tabstop=8 softtabstop=2 :
626  */