1 /* Panorama_Tools - Generate, Edit and Convert Panoramic Images
2 Copyright (C) 1998,1999,2000 - Helmut Dersch der@fh-furtwangen.de
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)
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.
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. */
18 /*------------------------------------------------------------*/
22 #include <X11/Xutil.h>
23 #include <X11/cursorfont.h>
24 #include <X11/keysym.h>
25 #include <X11/Xatom.h>
31 void PV_ExtractStill( TrformStr *TrPtr );
32 void PV_SetInvMakeParams( struct fDesc *stack, struct MakeParams *mp, Image *im , Image *pn );
35 void DrawView(int InterPolator);
37 int readJPEG ( Image *im, fullPath *sfile );
40 int zooming_in = FALSE;
41 int zooming_out = FALSE;
43 #define VIEW_WIDTH 400
44 #define VIEW_HEIGHT 300
47 char text[] = "PTViewer";
53 XImage *ximage = NULL;
60 int main( int argc, char** argv )
71 XConfigureEvent configure;
74 XResizeRequestEvent resize;
75 XClientMessageEvent message;
78 static Atom proto_atom= None, delete_atom= None;
85 disp = XOpenDisplay("");
86 screen = DefaultScreen(disp);
87 depth = DefaultDepth(disp, screen);
91 PrintError("Depth = %d, must be 24 pixels", (int)depth);
93 bg = WhitePixel(disp,screen);
94 fg = BlackPixel(disp,screen);
96 // Load panoramic image
99 PrintError("No image file supplied");
103 if( strcmp( argv[1], "-h" ) == 0 )
105 PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
108 if( readJPEG( &pano, (fullPath*)argv[1] ) != 0 )
110 PrintError("Could not read panoramic image");
114 pano.format = _equirectangular;
116 // Set up viewer window
118 SetImageDefaults( &view );
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;
127 view.data = (unsigned char**)mymalloc( view.dataSize );
128 if(view.data == NULL)
130 PrintError("Not enough memory");
137 hint.width = view.width;
138 hint.height = view.height;
139 hint.flags=PPosition | PSize;
141 win = XCreateSimpleWindow(disp,
142 DefaultRootWindow(disp),
151 XSetStandardProperties(disp,
159 gc = XCreateGC(disp,win,0,0);
160 XSetBackground(disp,gc,bg);
161 XSetForeground(disp,gc,fg);
165 ButtonPressMask | ButtonReleaseMask | Button1MotionMask | KeyPressMask | KeyReleaseMask |
166 StructureNotifyMask | EnterWindowMask | LeaveWindowMask| ExposureMask);
167 XMapRaised(disp,win);
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);
176 visual = DefaultVisual(disp, screen);
178 ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
179 NULL, view.width, view.height,
181 memset( *(view.data), 0, view.dataSize);
182 ximage->data = (char *)*(view.data);
183 ximage->byte_order= MSBFirst;
194 if( XCheckTypedEvent(disp, Expose, (XEvent*)&event) ) DrawWindow();
196 if( XCheckTypedEvent(disp, KeyPress, (XEvent*)&event) )
200 XComposeStatus status;
201 int nkey = XLookupString(&event.key,buf,128,&ks,&status);
208 case XK_Shift_R: zooming_in = TRUE;
212 case XK_Control_R: zooming_out = TRUE;
216 else if( nkey == 1 && buf[0] == 'q')
222 if( XCheckTypedEvent(disp, KeyRelease, (XEvent*)&event) )
226 XComposeStatus status;
228 if (XLookupString(&event.key,buf,128,&ks,&status) == 0)
233 case XK_Shift_R: zooming_in = FALSE;
238 case XK_Control_R: zooming_out = FALSE;
247 if( XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) )
249 newposx = event.button.x;
250 newposy = event.button.y;
251 while (XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) == True)
253 newposx= event.button.x;
254 newposy= event.button.y;
258 if( XCheckTypedEvent(disp, ButtonPress, (XEvent*)&event) )
260 if (event.button.button == 1)
263 oldposx = newposx = event.button.x;
264 oldposy = newposy = event.button.y;
268 if( XCheckTypedEvent(disp, ButtonRelease, (XEvent*)&event) )
270 if (event.button.button == 1)
278 if( XCheckTypedEvent(disp, DestroyNotify, (XEvent*)&event) )
281 if( XCheckTypedEvent(disp,ClientMessage , (XEvent*)&event) )
283 if ((event.message.window == win) && (event.message.data.l[0] == delete_atom))
293 yaw = view.yaw + (newposx - oldposx)/20.0;
296 pitch = view.pitch - (newposy - oldposy)/20.0;
297 if( pitch > 90.0 ) pitch = 90.0;
298 if( pitch < -90.0 ) pitch = -90.0;
300 if( pitch != view.pitch || yaw != view.yaw )
307 if( zooming_in && view.hfov > 10.5)
312 if( zooming_out && view.hfov < 165.0)
317 if( zooming_in || zooming_out || panning )
329 XDestroyWindow(disp, win);
342 void PrintError( char* fmt, ...)
348 vsprintf(message, fmt, ap);
351 printf("%s\n", message);
354 void** mymalloc( long numBytes ) // Memory allocation, use Handles
358 mem = (char**)malloc( sizeof(char*) ); // Allocate memory for pointer
363 (*mem) = (char*) malloc( numBytes ); // Allocate numBytes
374 void myfree( void** Hdl ) // free Memory, use Handles
376 free( (char*) *Hdl );
377 free( (char**) Hdl );
381 void SetImageDefaults(Image *im)
384 im->bytesPerLine = 0;
388 im->bitsPerPixel = 0;
390 im->dataformat = _RGB;
395 // SetCorrectDefaults( &(im->cP) );
399 // expand image from 3 to 4 bits per pixel. No pad bytes allowed.
400 // Memory must be allocated
401 void ThreeToFourBPP( Image *im )
403 register int x,y,c1,c2;
405 if( im->bitsPerPixel == 32 || im->bitsPerPixel == 64) // Nothing to do
410 if( im->bitsPerPixel == 24 ) // Convert to 4byte / pixel
412 for( y = im->height-1; y>=0; y--)
414 for( x= im->width-1; x>=0; x--)
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++];
424 im->bitsPerPixel = 32;
425 im->bytesPerLine = im->width * 4;
427 else if( im->bitsPerPixel == 48 ) // Convert to 8byte / pixel
429 for( y = im->height-1; y>=0; y--)
431 for( x= im->width-1; x>=0; x--)
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++];
441 im->bitsPerPixel = 64;
442 im->bytesPerLine = im->width * 8;
444 im->dataSize = im->height * im->bytesPerLine;
447 static int copy_rgb_to_zpixmap (XImage *dest, const Image *src)
458 uint32_t dest_pixel_value;
464 uint32_t dest_r_maxval;
465 uint32_t dest_g_maxval;
466 uint32_t dest_b_maxval;
468 uint32_t dest_r_offset;
469 uint32_t dest_g_offset;
470 uint32_t dest_b_offset;
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++)
480 if ((dest_r_maxval & 0x01) == 0)
485 if ((dest_g_maxval & 0x01) == 0)
490 if ((dest_b_maxval & 0x01) == 0)
497 src_data = (uint32_t *) *src->data;
500 for (y = 0; y < dest->height; y++)
502 for (x = 0; x < dest->width; x++, pixel++)
506 src_r = (src_data[pixel] >> 8) & 0xFF;
507 src_g = (src_data[pixel] >> 16) & 0xFF;
508 src_b = (src_data[pixel] >> 24) & 0xFF;
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;
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);
519 for (bytenum = 0; bytenum < (dest->depth / 8); bytenum++)
521 dest->data[(pixel * dest->bits_per_pixel / 8) + bytenum] =
522 (dest_pixel_value >> (dest->bits_per_pixel - (8 * (bytenum + 1)))) & 0xFF;
528 } /* int copy_rgb_to_zpixmap */
532 XWindowAttributes xa;
534 XGetWindowAttributes( disp, win, &xa );
536 if( xa.width != view.width || xa.height != view.height )
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;
544 view.data = (unsigned char**)mymalloc( view.dataSize );
545 if(view.data == NULL)
547 PrintError("Not enough memory");
551 ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
552 NULL, view.width, view.height,
554 ximage->data = (char *)*(view.data);
555 ximage->byte_order= MSBFirst;
559 if( panning || zooming_in || zooming_out)
565 ximage->data = (char *) malloc (view.dataSize);
566 if (ximage->data == NULL)
568 memcpy (ximage->data, *(view.data), view.dataSize);
570 copy_rgb_to_zpixmap (ximage, &view);
572 XPutImage(disp, win, gc, ximage, 0, 0, 0, 0, view.width, view.height);
578 void DrawView(int InterPolator)
582 Tr.interpolator = InterPolator;
587 PV_ExtractStill( &Tr );