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 );
38 void DrawView(int InterPolator);
40 int readJPEG ( Image *im, fullPath *sfile );
43 int zooming_in = FALSE;
44 int zooming_out = FALSE;
46 #define VIEW_WIDTH 400
47 #define VIEW_HEIGHT 300
50 char text[] = "PTViewer";
56 XImage *ximage = NULL;
63 int main( int argc, char** argv )
74 XConfigureEvent configure;
77 XResizeRequestEvent resize;
78 XClientMessageEvent message;
81 static Atom proto_atom= None, delete_atom= None;
88 disp = XOpenDisplay("");
89 screen = DefaultScreen(disp);
90 depth = DefaultDepth(disp, screen);
94 PrintError("Depth = %d, must be 24 pixels", (int)depth);
96 bg = WhitePixel(disp,screen);
97 fg = BlackPixel(disp,screen);
99 // Load panoramic image
102 PrintError("No image file supplied");
106 if( strcmp( argv[1], "-h" ) == 0 )
108 PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
111 if( readJPEG( &pano, (fullPath*)argv[1] ) != 0 )
113 PrintError("Could not read panoramic image");
117 pano.format = _equirectangular;
119 // Initialize Look-up tables
121 if( SetUpAtan() || SetUpSqrt() || SetUpMweights() )
123 PrintError("Could not set up LU Tables");
127 // Set up viewer window
129 SetImageDefaults( &view );
132 view.width = VIEW_WIDTH;
133 view.height = VIEW_HEIGHT;
134 view.bitsPerPixel = 32;
135 view.bytesPerLine = view.width * view.bitsPerPixel / 8;
136 view.dataSize = view.bytesPerLine * view.height;
138 view.data = (unsigned char**)mymalloc( view.dataSize );
139 if(view.data == NULL)
141 PrintError("Not enough memory");
148 hint.width = view.width;
149 hint.height = view.height;
150 hint.flags=PPosition | PSize;
152 win = XCreateSimpleWindow(disp,
153 DefaultRootWindow(disp),
162 XSetStandardProperties(disp,
170 gc = XCreateGC(disp,win,0,0);
171 XSetBackground(disp,gc,bg);
172 XSetForeground(disp,gc,fg);
176 ButtonPressMask | ButtonReleaseMask | Button1MotionMask | KeyPressMask | KeyReleaseMask |
177 StructureNotifyMask | EnterWindowMask | LeaveWindowMask| ExposureMask);
178 XMapRaised(disp,win);
180 proto_atom = XInternAtom(disp, "WM_PROTOCOLS", False);
181 delete_atom = XInternAtom(disp, "WM_DELETE_WINDOW", False);
182 if ((proto_atom != None) && (delete_atom != None))
183 XChangeProperty(disp, win, proto_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&delete_atom, 1);
187 visual = DefaultVisual(disp, screen);
189 ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
190 NULL, view.width, view.height,
192 memset( *(view.data), 0, view.dataSize);
193 ximage->data = (char *)*(view.data);
194 ximage->byte_order= MSBFirst;
205 if( XCheckTypedEvent(disp, Expose, (XEvent*)&event) ) DrawWindow();
207 if( XCheckTypedEvent(disp, KeyPress, (XEvent*)&event) )
211 XComposeStatus status;
212 int nkey = XLookupString(&event.key,buf,128,&ks,&status);
219 case XK_Shift_R: zooming_in = TRUE;
223 case XK_Control_R: zooming_out = TRUE;
227 else if( nkey == 1 && buf[0] == 'q')
233 if( XCheckTypedEvent(disp, KeyRelease, (XEvent*)&event) )
237 XComposeStatus status;
239 if (XLookupString(&event.key,buf,128,&ks,&status) == 0)
244 case XK_Shift_R: zooming_in = FALSE;
249 case XK_Control_R: zooming_out = FALSE;
258 if( XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) )
260 newposx = event.button.x;
261 newposy = event.button.y;
262 while (XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) == True)
264 newposx= event.button.x;
265 newposy= event.button.y;
269 if( XCheckTypedEvent(disp, ButtonPress, (XEvent*)&event) )
271 if (event.button.button == 1)
274 oldposx = newposx = event.button.x;
275 oldposy = newposy = event.button.y;
279 if( XCheckTypedEvent(disp, ButtonRelease, (XEvent*)&event) )
281 if (event.button.button == 1)
289 if( XCheckTypedEvent(disp, DestroyNotify, (XEvent*)&event) )
292 if( XCheckTypedEvent(disp,ClientMessage , (XEvent*)&event) )
294 if ((event.message.window == win) && (event.message.data.l[0] == delete_atom))
304 yaw = view.yaw + (newposx - oldposx)/20.0;
307 pitch = view.pitch - (newposy - oldposy)/20.0;
308 if( pitch > 90.0 ) pitch = 90.0;
309 if( pitch < -90.0 ) pitch = -90.0;
311 if( pitch != view.pitch || yaw != view.yaw )
318 if( zooming_in && view.hfov > 10.5)
323 if( zooming_out && view.hfov < 165.0)
328 if( zooming_in || zooming_out || panning )
340 XDestroyWindow(disp, win);
353 void PrintError( char* fmt, ...)
359 vsprintf(message, fmt, ap);
362 printf("%s\n", message);
365 void** mymalloc( long numBytes ) // Memory allocation, use Handles
369 mem = (char**)malloc( sizeof(char*) ); // Allocate memory for pointer
374 (*mem) = (char*) malloc( numBytes ); // Allocate numBytes
385 void myfree( void** Hdl ) // free Memory, use Handles
387 free( (char*) *Hdl );
388 free( (char**) Hdl );
392 void SetImageDefaults(Image *im)
395 im->bytesPerLine = 0;
399 im->bitsPerPixel = 0;
401 im->dataformat = _RGB;
406 // SetCorrectDefaults( &(im->cP) );
410 // expand image from 3 to 4 bits per pixel. No pad bytes allowed.
411 // Memory must be allocated
412 void ThreeToFourBPP( Image *im )
414 register int x,y,c1,c2;
416 if( im->bitsPerPixel == 32 || im->bitsPerPixel == 64) // Nothing to do
421 if( im->bitsPerPixel == 24 ) // Convert to 4byte / pixel
423 for( y = im->height-1; y>=0; y--)
425 for( x= im->width-1; x>=0; x--)
427 c1 = (y * im->width + x) * 4;
428 c2 = y * im->bytesPerLine + x * 3;
429 (*(im->data))[c1++] = UCHAR_MAX;
430 (*(im->data))[c1++] = (*(im->data))[c2++];
431 (*(im->data))[c1++] = (*(im->data))[c2++];
432 (*(im->data))[c1++] = (*(im->data))[c2++];
435 im->bitsPerPixel = 32;
436 im->bytesPerLine = im->width * 4;
438 else if( im->bitsPerPixel == 48 ) // Convert to 8byte / pixel
440 for( y = im->height-1; y>=0; y--)
442 for( x= im->width-1; x>=0; x--)
444 c1 = (y * im->width + x) * 4;
445 c2 = y * im->bytesPerLine/2 + x * 3;
446 ((USHORT*)(*(im->data)))[c1++] = USHRT_MAX;
447 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
448 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
449 ((USHORT*)(*(im->data)))[c1++] = ((USHORT*)(*(im->data)))[c2++];
452 im->bitsPerPixel = 64;
453 im->bytesPerLine = im->width * 8;
455 im->dataSize = im->height * im->bytesPerLine;
458 static int copy_rgb_to_zpixmap (XImage *dest, const Image *src)
469 uint32_t dest_pixel_value;
475 uint32_t dest_r_maxval;
476 uint32_t dest_g_maxval;
477 uint32_t dest_b_maxval;
479 uint32_t dest_r_offset;
480 uint32_t dest_g_offset;
481 uint32_t dest_b_offset;
486 dest_r_maxval = dest->red_mask;
487 dest_g_maxval = dest->green_mask;
488 dest_b_maxval = dest->blue_mask;
489 for (x = 0; x < dest->depth; x++)
491 if ((dest_r_maxval & 0x01) == 0)
496 if ((dest_g_maxval & 0x01) == 0)
501 if ((dest_b_maxval & 0x01) == 0)
508 src_data = (uint32_t *) *src->data;
511 for (y = 0; y < dest->height; y++)
513 for (x = 0; x < dest->width; x++, pixel++)
517 src_r = (src_data[pixel] >> 8) & 0xFF;
518 src_g = (src_data[pixel] >> 16) & 0xFF;
519 src_b = (src_data[pixel] >> 24) & 0xFF;
521 dest_r = dest_r_maxval * src_r / 0xFF;
522 dest_g = dest_g_maxval * src_g / 0xFF;
523 dest_b = dest_b_maxval * src_b / 0xFF;
526 | ((dest_r << dest_r_offset) & dest->red_mask)
527 | ((dest_g << dest_g_offset) & dest->green_mask)
528 | ((dest_b << dest_b_offset) & dest->blue_mask);
530 if ((y == 150) && (x == 200))
531 printf ("[200x150] RGB(%u,%u,%u) -> RGB(%u,%u,%u) -> 0x%04x\n",
533 dest_r, dest_g, dest_b,
535 for (bytenum = 0; bytenum < (dest->depth / 8); bytenum++)
537 int offset = (pixel * dest->bits_per_pixel / 8) + bytenum;
538 dest->data[(pixel * dest->bits_per_pixel / 8) + bytenum] =
539 (dest_pixel_value >> (dest->bits_per_pixel - (8 * (bytenum + 1)))) & 0xFF;
540 if ((y == 150) && (x == 200))
541 printf ("Setting byte #%i to 0x%02x\n",
542 offset, dest->data[offset]);
548 } /* int copy_rgb_to_zpixmap */
552 XWindowAttributes xa;
554 XGetWindowAttributes( disp, win, &xa );
556 if( xa.width != view.width || xa.height != view.height )
558 myfree((void**)view.data);
559 view.width = xa.width;
560 view.height = xa.height;
561 view.bytesPerLine = view.width * view.bitsPerPixel / 8;
562 view.dataSize = view.bytesPerLine * view.height;
564 view.data = (unsigned char**)mymalloc( view.dataSize );
565 if(view.data == NULL)
567 PrintError("Not enough memory");
571 ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
572 NULL, view.width, view.height,
574 ximage->data = (char *)*(view.data);
575 ximage->byte_order= MSBFirst;
579 if( panning || zooming_in || zooming_out)
585 ximage->data = (char *) malloc (view.dataSize);
586 if (ximage->data == NULL)
588 memcpy (ximage->data, *(view.data), view.dataSize);
590 copy_rgb_to_zpixmap (ximage, &view);
592 XPutImage(disp, win, gc, ximage, 0, 0, 0, 0, view.width, view.height);
598 void DrawView(int InterPolator)
602 Tr.interpolator = InterPolator;
607 PV_ExtractStill( &Tr );