Removed unused code.
[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 #include "filter.h"
30
31 void    PV_ExtractStill( TrformStr *TrPtr );
32 void    PV_SetInvMakeParams( struct fDesc *stack, struct MakeParams *mp, Image *im , Image *pn );
33
34 void    DrawWindow();
35 void    DrawView(int InterPolator);
36
37 int readJPEG ( Image *im, fullPath *sfile );
38
39 int                                     panning = FALSE;
40 int                                     zooming_in = FALSE;
41 int                                     zooming_out = FALSE;
42
43 #define VIEW_WIDTH      400
44 #define VIEW_HEIGHT 300
45
46
47 char text[] = "PTViewer";
48
49 Image                   view, pano;
50 Display                 *disp;
51 Window                  win;
52 int                     screen;
53 XImage                  *ximage = NULL;
54 GC                              gc;
55 Visual                  *visual;
56 unsigned int    depth;
57 int                     oldposx, oldposy;
58
59
60 int main( int argc, char** argv )
61 {
62         XSizeHints hint;
63         unsigned long fg, bg;
64         int done;
65         union 
66         {
67         XEvent              event;
68         XAnyEvent           any;
69         XButtonEvent        button;
70         XKeyEvent           key;
71         XConfigureEvent     configure;
72         XExposeEvent        expose;
73         XMotionEvent        motion;
74         XResizeRequestEvent resize;
75         XClientMessageEvent message;
76          } event;
77         int newposx, newposy;
78         static Atom             proto_atom= None, delete_atom= None;
79
80
81         // Set up display
82         
83
84
85         disp            = XOpenDisplay("");
86         screen          = DefaultScreen(disp);
87         depth           = DefaultDepth(disp, screen);
88         
89         if( depth != 24 )
90         {
91                 PrintError("Depth = %d, must be 24 pixels", (int)depth);
92         }
93         bg = WhitePixel(disp,screen);
94         fg = BlackPixel(disp,screen);
95
96         // Load panoramic image         
97         if( argc < 2 )
98         {
99                 PrintError("No image file supplied");
100                 exit(0);
101         }
102         
103         if( strcmp( argv[1], "-h" ) == 0 )
104         {
105                 PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
106                 exit(0);
107         }
108         if( readJPEG( &pano, (fullPath*)argv[1] ) != 0 )
109         {
110                 PrintError("Could not read panoramic image");
111                 exit(0);
112         }
113         pano.hfov               = 360.0;
114         pano.format     = _equirectangular;
115         
116         // Set up viewer window
117
118         SetImageDefaults( &view );
119
120         view.hfov                       = 70.0;
121         view.width                      = VIEW_WIDTH;
122         view.height                     = VIEW_HEIGHT;
123         view.bitsPerPixel       = 32;
124         view.bytesPerLine       = view.width * view.bitsPerPixel / 8;
125         view.dataSize           = view.bytesPerLine * view.height;
126         view.format                     = 1;
127         view.data                       = (unsigned char**)mymalloc( view.dataSize );
128         if(view.data == NULL)
129         {
130                 PrintError("Not enough memory");
131                 exit(0);
132         }
133
134
135         hint.x                  = 200;
136         hint.y                  = 200;
137         hint.width              = view.width;
138         hint.height     = view.height;
139         hint.flags=PPosition | PSize;
140
141         win = XCreateSimpleWindow(disp,
142                 DefaultRootWindow(disp),
143                 hint.x,
144                 hint.y,
145                 hint.width,
146                 hint.height,
147                 5,
148                 fg,
149                 bg);
150
151         XSetStandardProperties(disp,
152                 win,
153                 text,
154                 text,
155                 None,
156                 argv,
157                 argc,
158                 &hint);
159         gc = XCreateGC(disp,win,0,0);
160         XSetBackground(disp,gc,bg);
161         XSetForeground(disp,gc,fg);
162
163         XSelectInput(disp,
164                 win,
165                 ButtonPressMask | ButtonReleaseMask | Button1MotionMask | KeyPressMask | KeyReleaseMask |
166         StructureNotifyMask | EnterWindowMask | LeaveWindowMask| ExposureMask);
167         XMapRaised(disp,win);
168
169     proto_atom  = XInternAtom(disp, "WM_PROTOCOLS", False);
170     delete_atom = XInternAtom(disp, "WM_DELETE_WINDOW", False);
171     if ((proto_atom != None) && (delete_atom != None))
172                 XChangeProperty(disp, win, proto_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&delete_atom, 1);
173  
174
175
176     visual  = DefaultVisual(disp, screen);
177
178     ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
179                     NULL, view.width, view.height,
180                     8, 0);
181     memset( *(view.data), 0, view.dataSize);
182     ximage->data = (char *)*(view.data);
183     ximage->byte_order= MSBFirst;
184
185
186
187         done = 0;
188         while( done==0)
189         {
190                 int isChanged = 0;
191                 
192                 // No XNextEvent 
193                                 
194                 if( XCheckTypedEvent(disp, Expose, (XEvent*)&event) ) DrawWindow();
195
196                 if( XCheckTypedEvent(disp, KeyPress, (XEvent*)&event) )
197                 {
198                 char buf[128];
199                 KeySym ks;
200                 XComposeStatus status;
201                 int nkey = XLookupString(&event.key,buf,128,&ks,&status);
202                                                 
203                 if( nkey == 0 )
204                 {
205                         switch(ks)
206                         {
207                                 case XK_Shift_L:
208                                         case XK_Shift_R: zooming_in = TRUE;
209                                         break;
210                                 
211                                 case XK_Control_L:
212                                         case XK_Control_R: zooming_out = TRUE;
213                                 break;
214                         }
215                 }
216                 else if( nkey == 1 && buf[0] == 'q')
217                         done = 1;
218                                                 
219                 goto _EventLoop;
220         }
221
222                 if( XCheckTypedEvent(disp, KeyRelease, (XEvent*)&event) ) 
223                 {
224                 char buf[128];
225                 KeySym ks;
226                 XComposeStatus status;
227
228                 if (XLookupString(&event.key,buf,128,&ks,&status) == 0)
229                 {
230                         switch(ks)
231                         {
232                                 case XK_Shift_L:
233                         case XK_Shift_R: zooming_in = FALSE;
234                                                                 view.format = 1;
235                                                                 DrawWindow();
236                                                                 break;
237                                 case XK_Control_L: 
238                         case XK_Control_R: zooming_out = FALSE;
239                                                                 view.format = 1;
240                                                                 DrawWindow();
241                                                                 break;
242                         }
243                 }
244                 goto _EventLoop;
245                 }
246  
247                 if( XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) )
248                 { 
249                         newposx = event.button.x;
250             newposy = event.button.y;
251                 while (XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) == True) 
252                 {
253                                 newposx= event.button.x;
254                                 newposy= event.button.y;
255                 }
256                 }
257                                         
258                 if( XCheckTypedEvent(disp, ButtonPress, (XEvent*)&event) )
259                 {
260                 if (event.button.button == 1) 
261                 {
262                         panning = TRUE;
263                                 oldposx = newposx = event.button.x;
264                                 oldposy = newposy = event.button.y;
265                         }
266                 }
267
268                 if( XCheckTypedEvent(disp, ButtonRelease, (XEvent*)&event) )
269                 {
270                 if (event.button.button == 1) 
271                 {
272                                 panning = FALSE;
273                                 view.format = 1;
274                                 DrawWindow();
275                         }
276                 }
277                 
278                 if( XCheckTypedEvent(disp, DestroyNotify, (XEvent*)&event) )
279                         done = 1;
280                 
281                 if( XCheckTypedEvent(disp,ClientMessage , (XEvent*)&event) )
282                 {
283                         if ((event.message.window == win) && (event.message.data.l[0] == delete_atom)) 
284                                 done = 1;
285                 }
286
287                 
288 _EventLoop:                     
289                 if( panning )
290                 {
291                                 double yaw, pitch;
292                                                                                 
293                                 yaw = view.yaw + (newposx - oldposx)/20.0;
294                                 NORM_ANGLE( yaw );
295                                                                                 
296                                 pitch = view.pitch - (newposy - oldposy)/20.0;
297                                 if( pitch > 90.0 ) pitch = 90.0;
298                                 if( pitch < -90.0 ) pitch = -90.0;
299                                                                         
300                                 if( pitch != view.pitch || yaw != view.yaw )
301                                 {
302                                         view.pitch      = pitch;
303                                         view.yaw        = yaw;
304                                         isChanged = 1;
305                                 }
306                 }
307                 if( zooming_in && view.hfov > 10.5)
308                 {
309                         view.hfov /= 1.03;
310                         isChanged = 1;
311                 }
312                 if( zooming_out && view.hfov < 165.0)
313                 {
314                         view.hfov *= 1.03;
315                         isChanged = 1;
316                 }
317                 if( zooming_in || zooming_out || panning )
318                 {
319                         if( isChanged )
320                         {
321                                 view.format = 1;
322                                 DrawWindow();
323                         }
324                 }
325
326
327         }
328         XFreeGC(disp,gc);
329         XDestroyWindow(disp, win);
330         XCloseDisplay(disp);
331
332         return (0);
333 }
334         
335
336
337
338
339
340 // Error reporting
341
342 void  PrintError( char* fmt, ...)
343 {
344         va_list ap;
345         char message[257];
346         
347         va_start(ap, fmt);
348         vsprintf(message, fmt, ap);
349         va_end(ap);
350         
351         printf("%s\n", message);
352 }
353
354 void**  mymalloc( long numBytes )                                       // Memory allocation, use Handles
355 {
356         char **mem;
357         
358         mem = (char**)malloc( sizeof(char*) );                  // Allocate memory for pointer
359         if(mem == NULL)
360                 return (void**)NULL;
361         else
362         {
363                 (*mem) = (char*) malloc( numBytes );            // Allocate numBytes
364                 if( *mem == NULL )
365                 {
366                         free( mem );
367                         return (void**)NULL;
368                 }
369                 else
370                         return (void**)mem;
371         }
372 }
373
374 void    myfree( void** Hdl )                                            // free Memory, use Handles
375 {
376         free( (char*) *Hdl );
377         free( (char**) Hdl );
378 }               
379
380
381 void SetImageDefaults(Image *im)
382 {
383         im->data                        = NULL;
384         im->bytesPerLine        = 0;
385         im->width                       = 0;
386         im->height                      = 0;
387         im->dataSize            = 0;
388         im->bitsPerPixel        = 0;
389         im->format                      = 0;
390         im->dataformat          = _RGB;
391         im->hfov                        = 0.0;
392         im->yaw                         = 0.0;
393         im->pitch                       = 0.0;
394         im->roll                        = 0.0;
395 //      SetCorrectDefaults( &(im->cP) );
396         *(im->name)                     = 0;
397 }
398
399 // expand image from 3 to 4 bits per pixel. No pad bytes allowed.
400 // Memory must be allocated
401 void ThreeToFourBPP( Image *im )
402 {
403         register int x,y,c1,c2;
404
405         if( im->bitsPerPixel == 32 || im->bitsPerPixel == 64) // Nothing to do
406                 return;
407         
408         
409         
410         if( im->bitsPerPixel == 24 )    // Convert to 4byte / pixel
411         {
412                 for( y = im->height-1; y>=0; y--)
413                 {
414                         for( x= im->width-1; x>=0; x--)
415                         {
416                                 c1 = (y * im->width + x) * 4;
417                                 c2 = y * im->bytesPerLine + x * 3;
418                                 (*(im->data))[c1++] = UCHAR_MAX;
419                                 (*(im->data))[c1++] = (*(im->data))[c2++];
420                                 (*(im->data))[c1++] = (*(im->data))[c2++];
421                                 (*(im->data))[c1++] = (*(im->data))[c2++];
422                         }
423                 }
424                 im->bitsPerPixel = 32;
425                 im->bytesPerLine = im->width * 4;
426         }
427         else if( im->bitsPerPixel == 48 ) // Convert to 8byte / pixel
428         {
429                 for( y = im->height-1; y>=0; y--)
430                 {
431                         for( x= im->width-1; x>=0; x--)
432                         {
433                                 c1 = (y * im->width + x) * 4;
434                                 c2 = y * im->bytesPerLine/2 + x * 3;
435                                 ((USHORT*)(*(im->data)))[c1++] = USHRT_MAX;
436                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
437                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
438                                 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
439                         }
440                 }
441                 im->bitsPerPixel = 64;
442                 im->bytesPerLine = im->width * 8;
443         }
444         im->dataSize = im->height * im->bytesPerLine;
445 }
446
447 static int copy_rgb_to_zpixmap (XImage *dest, const Image *src)
448 {
449         uint32_t *src_data;
450
451         uint32_t src_r;
452         uint32_t src_g;
453         uint32_t src_b;
454
455         uint32_t dest_r;
456         uint32_t dest_g;
457         uint32_t dest_b;
458         uint32_t dest_pixel_value;
459
460         uint32_t x;
461         uint32_t y;
462         uint32_t pixel;
463
464         uint32_t dest_r_maxval;
465         uint32_t dest_g_maxval;
466         uint32_t dest_b_maxval;
467
468         uint32_t dest_r_offset;
469         uint32_t dest_g_offset;
470         uint32_t dest_b_offset;
471
472         dest_r_offset = 0;
473         dest_g_offset = 0;
474         dest_b_offset = 0;
475         dest_r_maxval = dest->red_mask;
476         dest_g_maxval = dest->green_mask;
477         dest_b_maxval = dest->blue_mask;
478         for (x = 0; x < dest->depth; x++)
479         {
480                 if ((dest_r_maxval & 0x01) == 0)
481                 {
482                         dest_r_offset++;
483                         dest_r_maxval >>= 1;
484                 }
485                 if ((dest_g_maxval & 0x01) == 0)
486                 {
487                         dest_g_offset++;
488                         dest_g_maxval >>= 1;
489                 }
490                 if ((dest_b_maxval & 0x01) == 0)
491                 {
492                         dest_b_offset++;
493                         dest_b_maxval >>= 1;
494                 }
495         }
496
497         src_data = (uint32_t *) *src->data;
498
499         pixel = 0;
500         for (y = 0; y < dest->height; y++)
501         {
502                 for (x = 0; x < dest->width; x++, pixel++)
503                 {
504                         int32_t bytenum;
505
506                         src_r = (src_data[pixel] >>  8) & 0xFF;
507                         src_g = (src_data[pixel] >> 16) & 0xFF;
508                         src_b = (src_data[pixel] >> 24) & 0xFF;
509
510                         dest_r = dest_r_maxval * src_r / 0xFF;
511                         dest_g = dest_g_maxval * src_g / 0xFF;
512                         dest_b = dest_b_maxval * src_b / 0xFF;
513
514                         dest_pixel_value = 0
515                                 | ((dest_r << dest_r_offset) & dest->red_mask)
516                                 | ((dest_g << dest_g_offset) & dest->green_mask)
517                                 | ((dest_b << dest_b_offset) & dest->blue_mask);
518
519                         for (bytenum = 0; bytenum < (dest->depth / 8); bytenum++)
520                         {
521                                 dest->data[(pixel * dest->bits_per_pixel / 8) + bytenum] = 
522                                         (dest_pixel_value >> (dest->bits_per_pixel - (8 * (bytenum + 1)))) & 0xFF;
523                         }
524                 }
525         }
526
527         return (0);
528 } /* int copy_rgb_to_zpixmap */
529
530 void DrawWindow()
531 {
532         XWindowAttributes xa;
533
534         XGetWindowAttributes( disp, win, &xa );
535
536         if( xa.width != view.width || xa.height != view.height )
537         {
538                 myfree((void**)view.data);
539                 view.width                      = xa.width;
540                 view.height             = xa.height;
541                 view.bytesPerLine       = view.width * view.bitsPerPixel / 8;
542                 view.dataSize           = view.bytesPerLine * view.height;
543                 view.format             = 1;
544                 view.data               = (unsigned char**)mymalloc( view.dataSize );
545                 if(view.data == NULL)
546                 {
547                         PrintError("Not enough memory");
548                         exit(0);
549                 }
550
551                 ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
552                                 NULL, view.width, view.height,
553                                 8, 0);
554                 ximage->data = (char *)*(view.data);
555                 ximage->byte_order= MSBFirst;
556         }
557         if( view.format )
558         {
559                 if( panning || zooming_in || zooming_out)
560                         DrawView(_nn);
561                 else
562                         DrawView(_bilinear);
563         }
564
565         ximage->data = (char *) malloc (view.dataSize);
566         if (ximage->data == NULL)
567                 return;
568         memcpy (ximage->data, *(view.data), view.dataSize);
569
570         copy_rgb_to_zpixmap (ximage, &view);
571
572         XPutImage(disp, win, gc, ximage, 0, 0, 0, 0, view.width, view.height);
573
574         free (ximage->data);
575         ximage->data = NULL;
576 }
577
578 void DrawView(int InterPolator)
579 {
580         TrformStr                               Tr;
581                         
582         Tr.interpolator                 = InterPolator;
583
584         Tr.src                                  = &pano;
585         Tr.dest                                 = &view;        
586         
587         PV_ExtractStill( &Tr );
588         
589         view.format = 0;
590         return;
591         
592 }
593