7516db22629c70e911e4fb17827de0ffb5179812
[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     XDestroyImage (ximage);
138     ximage = NULL;
139   }
140
141   if (ximage == NULL)
142   {
143     char *data;
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     data = (char *) malloc (img->width * img->height * depth_g / 8);
153     ximage->data = data;
154     if (ximage->data == NULL)
155     {
156       XDestroyImage (ximage);
157       ximage = NULL;
158       return (-1);
159     }
160   }
161
162   copy_rgb_to_zpixmap (ximage, img);
163   XPutImage(disp_g, window_g, gc, ximage, 0, 0,
164       0, 0, ximage->width, ximage->height);
165
166   return (0);
167 } /* int draw_window */
168
169 #define ZOOM_SPEED 1.03
170
171 static void zoom_in (double *fov)
172 {
173   *fov = *fov / ZOOM_SPEED;
174   if (*fov < 10.5)
175     *fov = 10.5;
176 } /* void zoom_in */
177
178 static void zoom_out (double *fov)
179 {
180   *fov = *fov * ZOOM_SPEED;
181   if (*fov > 165.0)
182     *fov = 165.0;
183 } /* void zoom_out */
184
185 int main( int argc, char** argv )
186 {
187   unsigned long color_fg, color_bg;
188   int done;
189   static Atom                   proto_atom= None, delete_atom= None;
190
191   long event_mask;
192
193   double fov = 70.0;
194   double yaw = 0.0;
195   double pitch = 0.0;
196
197   /* Detect mouse movement direction */
198   unsigned int btn_current_pressed = 0;
199   int btn_reference_pos_x = 0;
200   int btn_reference_pos_y = 0;
201   int btn_current_pos_x = 0;
202   int btn_current_pos_y = 0;
203
204   ui_image_t *pano;
205   ui_image_t *view;
206
207
208   // Set up display
209   disp_g   = XOpenDisplay("");
210   screen_g = DefaultScreen(disp_g);
211   depth_g  = DefaultDepth(disp_g, screen_g);
212
213   color_bg = WhitePixel(disp_g,screen_g);
214   color_fg = BlackPixel(disp_g,screen_g);
215
216   // Load panoramic image       
217   if( argc < 2 )
218   {
219     PrintError("No image file supplied");
220     exit(0);
221   }
222
223   if( strcmp( argv[1], "-h" ) == 0 ) /* FIXME: Use getopt */
224   {
225     PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
226     exit(0);
227   }
228
229   pano = ui_create_file (argv[1]);
230   if (pano == NULL)
231   {
232     PrintError ("Unable to read pano file.");
233     exit (0);
234   }
235
236   printf ("Panorama `%s', %ux%u pixels, loaded.\n",
237       argv[1], pano->width, pano->height);
238
239   view = ui_create (DEF_VIEW_WIDTH, DEF_VIEW_HEIGHT); /* FIXME: Possibly chose another size */
240   if (view == NULL)
241   {
242     PrintError ("Unable to create view.");
243     exit (0);
244   }
245
246   window_g = XCreateSimpleWindow(disp_g,
247       DefaultRootWindow(disp_g),
248       0, 0, /* Position */
249       view->width, view->height,
250       5,
251       color_fg, color_bg);
252
253   {
254     XSizeHints hint;
255
256     memset (&hint, '\0', sizeof (hint));
257     hint.width  = view->width;
258     hint.height = view->height;
259     hint.flags = PSize;
260
261     XSetStandardProperties(disp_g,
262         window_g,
263         text,
264         text,
265         None,
266         argv,
267         argc,
268         &hint);
269   }
270
271   gc = XCreateGC(disp_g,window_g,0,0);
272   XSetBackground(disp_g,gc,color_bg);
273   XSetForeground(disp_g,gc,color_fg);
274
275   event_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
276     | KeyPressMask | KeyReleaseMask | StructureNotifyMask
277     | EnterWindowMask | LeaveWindowMask| ExposureMask;
278
279   XSelectInput(disp_g, window_g, event_mask);
280   XMapRaised(disp_g,window_g);
281
282   proto_atom    = XInternAtom(disp_g, "WM_PROTOCOLS", False);
283   delete_atom = XInternAtom(disp_g, "WM_DELETE_WINDOW", False);
284   if ((proto_atom != None) && (delete_atom != None))
285     XChangeProperty(disp_g, window_g, proto_atom, XA_ATOM, 32,
286         PropModeReplace, (unsigned char *)&delete_atom,
287         1);
288   visual_g  = DefaultVisual(disp_g, screen_g);
289
290   pl_extract_view (view, pano, pitch, yaw, fov);
291   draw_window (view);
292
293   done = 0;
294   while (done == 0)
295   {
296     int isChanged = 0;
297     XEvent event;
298
299     memset (&event, '\0', sizeof (event));
300
301     if (btn_current_pressed == 0)
302     {
303       /* No button is pressed -> block */
304       XMaskEvent (disp_g, event_mask, &event);
305     }
306     else
307     {
308       /* A button is pressed -> do not block */
309       XCheckMaskEvent (disp_g, event_mask, &event);
310     }
311
312     switch (event.type)
313     {
314       case 0: /* XCheckMaskEvent didn't return an event */
315         break;
316
317       case Expose:
318         {
319           XExposeEvent *eev = (XExposeEvent *) &event;
320
321           while (eev->count != 0)
322           {
323             if (!XCheckTypedEvent (disp_g, Expose, &event))
324             {
325               eev = NULL;
326               break;
327             }
328             /* do nothing */
329           }
330
331           if (eev != NULL)
332             isChanged = 1;
333         }
334         break;
335
336       case EnterNotify:
337         break;
338
339       case LeaveNotify:
340         break;
341
342       case ConfigureNotify:
343         {
344           XConfigureEvent *cev = (XConfigureEvent *) &event;
345           printf ("XConfigureEvent received: width = %i; height = %i;\n",
346               cev->width, cev->height);
347
348           ui_destroy (view);
349           view = ui_create (cev->width, cev->height);
350           isChanged = 1;
351         }
352         break;
353
354       case KeyPress:
355         {
356           XKeyEvent *kev = (XKeyEvent *) &event;
357           char buffer[64];
358           int buffer_len = sizeof (buffer);
359           KeySym ks;
360
361           buffer_len = XLookupString(kev, buffer, sizeof (buffer), &ks, NULL);
362
363           if (buffer_len >= sizeof (buffer))
364             buffer_len = sizeof (buffer) - 1;
365           buffer[buffer_len] = '\0';
366
367           switch (ks)
368           {
369             case XK_Shift_L:
370             case XK_Shift_R:
371               zoom_in (&fov);
372               isChanged = 1;
373               break;
374
375             case XK_Control_L:
376             case XK_Control_R:
377               zoom_out (&fov);
378               isChanged = 1;
379               break;
380
381             case XK_Up:
382               pitch += 5.0;
383               if (pitch > 90.0)
384                 pitch = 90.0;
385               isChanged = 1;
386               break;
387
388             case XK_Down:
389               pitch -= 5.0;
390               if (pitch < -90.0)
391                 pitch = -90.0;
392               isChanged = 1;
393               break;
394
395             case XK_Right:
396               yaw += 5.0;
397               if (yaw > 180.0)
398                 yaw -= 360.0;
399               isChanged = 1;
400               break;
401
402             case XK_Left:
403               yaw -= 5.0;
404               if (yaw <= -180.0)
405                 yaw += 360.0;
406               isChanged = 1;
407               break;
408
409             case XK_q:
410               done++;
411               break;
412
413             default:
414               printf ("Unhandeled KeySym 0x%02llx, buffer = %s\n", (uint64_t) ks, buffer);
415           }
416         }
417         break;
418
419 #if 0
420       case KeyRelease:
421         printf ("Ignoring KeyRelease event.\n");
422         break;
423 #endif
424
425       case ButtonPress:
426       /* case ButtonRelease: */
427         {
428           XButtonEvent *bev = (XButtonEvent *) &event;
429
430           btn_current_pressed = bev->button;
431           btn_current_pos_x = btn_reference_pos_x = bev->x;
432           btn_current_pos_y = btn_reference_pos_y = bev->y;
433         }
434         break;
435
436       case ButtonRelease:
437         btn_current_pressed = 0;
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       draw_window (view);
501     }
502   } /* while (done == 0) */
503
504   XFreeGC(disp_g,gc);
505   XDestroyWindow(disp_g, window_g);
506   XCloseDisplay(disp_g);
507
508   return (0);
509 } /* int main */
510         
511
512
513
514
515
516 // Error reporting
517
518 void  PrintError( char* fmt, ...)
519 {
520         va_list ap;
521         char message[257];
522         
523         va_start(ap, fmt);
524         vsprintf(message, fmt, ap);
525         va_end(ap);
526         
527         printf("%s\n", message);
528 }
529
530 void**  mymalloc( long numBytes )                                       // Memory allocation, use Handles
531 {
532         char **mem;
533         
534         mem = (char**)malloc( sizeof(char*) );                  // Allocate memory for pointer
535         if(mem == NULL)
536                 return (void**)NULL;
537         else
538         {
539                 (*mem) = (char*) malloc( numBytes );            // Allocate numBytes
540                 if( *mem == NULL )
541                 {
542                         free( mem );
543                         return (void**)NULL;
544                 }
545                 else
546                         return (void**)mem;
547         }
548 }
549
550 void    myfree( void** Hdl )                                            // free Memory, use Handles
551 {
552         free( (char*) *Hdl );
553         free( (char**) Hdl );
554 }               
555
556
557 void SetImageDefaults(Image *im)
558 {
559         im->data                        = NULL;
560         im->bytesPerLine        = 0;
561         im->width                       = 0;
562         im->height                      = 0;
563         im->dataSize            = 0;
564         im->bitsPerPixel        = 0;
565         im->format                      = 0;
566         im->dataformat          = _RGB;
567         im->hfov                        = 0.0;
568         im->yaw                         = 0.0;
569         im->pitch                       = 0.0;
570         im->roll                        = 0.0;
571 //      SetCorrectDefaults( &(im->cP) );
572         *(im->name)                     = 0;
573 }
574
575 // expand image from 3 to 4 bits per pixel. No pad bytes allowed.
576 // Memory must be allocated
577 void ThreeToFourBPP( Image *im )
578 {
579         register int x,y,c1,c2;
580
581         if( im->bitsPerPixel == 32 || im->bitsPerPixel == 64) // Nothing to do
582                 return;
583         
584         
585         
586         if( im->bitsPerPixel == 24 )    // Convert to 4byte / pixel
587         {
588                 for( y = im->height-1; y>=0; y--)
589                 {
590                         for( x= im->width-1; x>=0; x--)
591                         {
592                                 c1 = (y * im->width + x) * 4;
593                                 c2 = y * im->bytesPerLine + x * 3;
594                                 (*(im->data))[c1++] = UCHAR_MAX;
595                                 (*(im->data))[c1++] = (*(im->data))[c2++];
596                                 (*(im->data))[c1++] = (*(im->data))[c2++];
597                                 (*(im->data))[c1++] = (*(im->data))[c2++];
598                         }
599                 }
600                 im->bitsPerPixel = 32;
601                 im->bytesPerLine = im->width * 4;
602         }
603         else if( im->bitsPerPixel == 48 ) // Convert to 8byte / pixel
604         {
605                 for( y = im->height-1; y>=0; y--)
606                 {
607                         for( x= im->width-1; x>=0; x--)
608                         {
609                                 c1 = (y * im->width + x) * 4;
610                                 c2 = y * im->bytesPerLine/2 + x * 3;
611                                 ((USHORT*)(*(im->data)))[c1++] = USHRT_MAX;
612                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
613                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
614                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
615                         }
616                 }
617                 im->bitsPerPixel = 64;
618                 im->bytesPerLine = im->width * 8;
619         }
620         im->dataSize = im->height * im->bytesPerLine;
621 }
622
623 /*
624  * vim: set shiftwidth=2 tabstop=8 softtabstop=2 :
625  */