Huge change, and it's almost working, too :)
[libopano.git] / src / viewer.c
index 043cef8..d7445e2 100644 (file)
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdint.h>
-#include "filter.h"
-
-void   PV_ExtractStill( TrformStr *TrPtr );
-void   PV_SetInvMakeParams( struct fDesc *stack, struct MakeParams *mp, Image *im , Image *pn );
-
-void   DrawWindow();
-void   DrawView(int InterPolator);
-
-int readJPEG ( Image *im, fullPath *sfile );
 
-int                                    panning = FALSE;
-int                                    zooming_in = FALSE;
-int                                    zooming_out = FALSE;
-
-#define VIEW_WIDTH     400
-#define VIEW_HEIGHT 300
+#include "filter.h"
+#include "panolib.h"
+#include "utils_image.h"
 
+#define DEF_VIEW_WIDTH  400
+#define DEF_VIEW_HEIGHT 300
 
 char text[] = "PTViewer";
 
-Image                  view, pano;
-Display                *disp;
-Window                         win;
-int                    screen;
-XImage                         *ximage = NULL;
-GC                             gc;
-Visual                 *visual;
-unsigned int   depth;
-int                    oldposx, oldposy;
+Display        *disp_g;
+Window                 window_g;
+int            screen_g;
+GC             gc;
+Visual         *visual_g;
+unsigned int   depth_g;
 
 
-int main( int argc, char** argv )
+static int copy_rgb_to_zpixmap (XImage *dest, const ui_image_t *src)
 {
-       XSizeHints hint;
-       unsigned long fg, bg;
-       int done;
-       union 
-       {
-       XEvent              event;
-       XAnyEvent           any;
-       XButtonEvent        button;
-       XKeyEvent           key;
-       XConfigureEvent     configure;
-       XExposeEvent        expose;
-       XMotionEvent        motion;
-       XResizeRequestEvent resize;
-       XClientMessageEvent message;
-        } event;
-       int newposx, newposy;
-       static Atom             proto_atom= None, delete_atom= None;
-
-
-       // Set up display
-       
-
-
-       disp            = XOpenDisplay("");
-       screen          = DefaultScreen(disp);
-       depth           = DefaultDepth(disp, screen);
-       
-       if( depth != 24 )
-       {
-               PrintError("Depth = %d, must be 24 pixels", (int)depth);
-       }
-       bg = WhitePixel(disp,screen);
-       fg = BlackPixel(disp,screen);
+       uint32_t *src_data;
 
-       // Load panoramic image         
-       if( argc < 2 )
-       {
-               PrintError("No image file supplied");
-               exit(0);
-       }
-       
-       if( strcmp( argv[1], "-h" ) == 0 )
-       {
-               PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
-               exit(0);
-       }
-       if( readJPEG( &pano, (fullPath*)argv[1] ) != 0 )
-       {
-               PrintError("Could not read panoramic image");
-               exit(0);
-       }
-       pano.hfov               = 360.0;
-       pano.format     = _equirectangular;
-       
-       // Set up viewer window
-
-       SetImageDefaults( &view );
-
-       view.hfov                       = 70.0;
-       view.width                      = VIEW_WIDTH;
-       view.height                     = VIEW_HEIGHT;
-       view.bitsPerPixel       = 32;
-       view.bytesPerLine       = view.width * view.bitsPerPixel / 8;
-       view.dataSize           = view.bytesPerLine * view.height;
-       view.format                     = 1;
-       view.data                       = (unsigned char**)mymalloc( view.dataSize );
-       if(view.data == NULL)
-       {
-               PrintError("Not enough memory");
-               exit(0);
-       }
+       uint32_t src_r;
+       uint32_t src_g;
+       uint32_t src_b;
 
+       uint32_t dest_r;
+       uint32_t dest_g;
+       uint32_t dest_b;
+       uint32_t dest_pixel_value;
 
-       hint.x                  = 200;
-       hint.y                  = 200;
-       hint.width              = view.width;
-       hint.height     = view.height;
-       hint.flags=PPosition | PSize;
-
-       win = XCreateSimpleWindow(disp,
-               DefaultRootWindow(disp),
-               hint.x,
-               hint.y,
-               hint.width,
-               hint.height,
-               5,
-               fg,
-               bg);
-
-       XSetStandardProperties(disp,
-               win,
-               text,
-               text,
-               None,
-               argv,
-               argc,
-               &hint);
-       gc = XCreateGC(disp,win,0,0);
-       XSetBackground(disp,gc,bg);
-       XSetForeground(disp,gc,fg);
-
-       XSelectInput(disp,
-               win,
-               ButtonPressMask | ButtonReleaseMask | Button1MotionMask | KeyPressMask | KeyReleaseMask |
-       StructureNotifyMask | EnterWindowMask | LeaveWindowMask| ExposureMask);
-       XMapRaised(disp,win);
-
-    proto_atom         = XInternAtom(disp, "WM_PROTOCOLS", False);
-    delete_atom = XInternAtom(disp, "WM_DELETE_WINDOW", False);
-    if ((proto_atom != None) && (delete_atom != None))
-               XChangeProperty(disp, win, proto_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&delete_atom, 1);
-
-
-    visual  = DefaultVisual(disp, screen);
-
-    ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
-                   NULL, view.width, view.height,
-                   8, 0);
-    memset( *(view.data), 0, view.dataSize);
-    ximage->data = (char *)*(view.data);
-    ximage->byte_order= MSBFirst;
+       uint32_t x;
+       uint32_t y;
+       uint32_t pixel;
 
+       uint32_t dest_r_maxval;
+       uint32_t dest_g_maxval;
+       uint32_t dest_b_maxval;
 
+       uint32_t dest_r_offset;
+       uint32_t dest_g_offset;
+       uint32_t dest_b_offset;
 
-       done = 0;
-       while( done==0)
+       dest_r_offset = 0;
+       dest_g_offset = 0;
+       dest_b_offset = 0;
+       dest_r_maxval = dest->red_mask;
+       dest_g_maxval = dest->green_mask;
+       dest_b_maxval = dest->blue_mask;
+       for (x = 0; x < dest->depth; x++)
        {
-               int isChanged = 0;
-               
-               // No XNextEvent 
-                               
-               if( XCheckTypedEvent(disp, Expose, (XEvent*)&event) ) DrawWindow();
-
-               if( XCheckTypedEvent(disp, KeyPress, (XEvent*)&event) )
-               {
-               char buf[128];
-               KeySym ks;
-               XComposeStatus status;
-               int nkey = XLookupString(&event.key,buf,128,&ks,&status);
-                                               
-               if( nkey == 0 )
-               {
-                       switch(ks)
-                       {
-                               case XK_Shift_L:
-                                       case XK_Shift_R: zooming_in = TRUE;
-                                       break;
-                               
-                               case XK_Control_L:
-                                       case XK_Control_R: zooming_out = TRUE;
-                               break;
-                       }
-               }
-               else if( nkey == 1 && buf[0] == 'q')
-                       done = 1;
-                                               
-               goto _EventLoop;
-       }
-
-               if( XCheckTypedEvent(disp, KeyRelease, (XEvent*)&event) ) 
-               {
-               char buf[128];
-               KeySym ks;
-               XComposeStatus status;
-
-               if (XLookupString(&event.key,buf,128,&ks,&status) == 0)
-               {
-                       switch(ks)
-                       {
-                               case XK_Shift_L:
-                       case XK_Shift_R: zooming_in = FALSE;
-                                                               view.format = 1;
-                                                               DrawWindow();
-                                                               break;
-                               case XK_Control_L: 
-                       case XK_Control_R: zooming_out = FALSE;
-                                                               view.format = 1;
-                                                               DrawWindow();
-                                                               break;
-                       }
-               }
-               goto _EventLoop;
-               }
-               if( XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) )
-               { 
-                       newposx = event.button.x;
-            newposy = event.button.y;
-               while (XCheckTypedEvent(disp, MotionNotify, (XEvent*)&event) == True) 
-               {
-                               newposx= event.button.x;
-                               newposy= event.button.y;
-               }
-               }
-                                       
-               if( XCheckTypedEvent(disp, ButtonPress, (XEvent*)&event) )
+               if ((dest_r_maxval & 0x01) == 0)
                {
-               if (event.button.button == 1) 
-               {
-                       panning = TRUE;
-                               oldposx = newposx = event.button.x;
-                               oldposy = newposy = event.button.y;
-                       }
+                       dest_r_offset++;
+                       dest_r_maxval >>= 1;
                }
-
-               if( XCheckTypedEvent(disp, ButtonRelease, (XEvent*)&event) )
+               if ((dest_g_maxval & 0x01) == 0)
                {
-               if (event.button.button == 1) 
-               {
-                               panning = FALSE;
-                               view.format = 1;
-                               DrawWindow();
-                       }
+                       dest_g_offset++;
+                       dest_g_maxval >>= 1;
                }
-               
-               if( XCheckTypedEvent(disp, DestroyNotify, (XEvent*)&event) )
-                       done = 1;
-               
-               if( XCheckTypedEvent(disp,ClientMessage , (XEvent*)&event) )
+               if ((dest_b_maxval & 0x01) == 0)
                {
-                       if ((event.message.window == win) && (event.message.data.l[0] == delete_atom)) 
-                               done = 1;
+                       dest_b_offset++;
+                       dest_b_maxval >>= 1;
                }
+       }
 
-               
-_EventLoop:                    
-               if( panning )
-               {
-                               double yaw, pitch;
-                                                                               
-                               yaw = view.yaw + (newposx - oldposx)/20.0;
-                               NORM_ANGLE( yaw );
-                                                                               
-                               pitch = view.pitch - (newposy - oldposy)/20.0;
-                               if( pitch > 90.0 ) pitch = 90.0;
-                               if( pitch < -90.0 ) pitch = -90.0;
-                                                                       
-                               if( pitch != view.pitch || yaw != view.yaw )
-                               {
-                                       view.pitch      = pitch;
-                                       view.yaw        = yaw;
-                                       isChanged = 1;
-                               }
-               }
-               if( zooming_in && view.hfov > 10.5)
-               {
-                       view.hfov /= 1.03;
-                       isChanged = 1;
-               }
-               if( zooming_out && view.hfov < 165.0)
-               {
-                       view.hfov *= 1.03;
-                       isChanged = 1;
-               }
-               if( zooming_in || zooming_out || panning )
+       src_data = (uint32_t *) *src->data;
+
+       pixel = 0;
+       for (y = 0; y < dest->height; y++)
+       {
+               for (x = 0; x < dest->width; x++, pixel++)
                {
-                       if( isChanged )
+                       int32_t bytenum;
+
+                       src_r = src->data[0][pixel];
+                       src_g = src->data[1][pixel];
+                       src_b = src->data[2][pixel];
+
+                       dest_r = dest_r_maxval * src_r / 255;
+                       dest_g = dest_g_maxval * src_g / 255;
+                       dest_b = dest_b_maxval * src_b / 255;
+
+                       dest_pixel_value = 0
+                               | ((dest_r << dest_r_offset) & dest->red_mask)
+                               | ((dest_g << dest_g_offset) & dest->green_mask)
+                               | ((dest_b << dest_b_offset) & dest->blue_mask);
+
+                       for (bytenum = 0; bytenum < (dest->depth / 8); bytenum++)
                        {
-                               view.format = 1;
-                               DrawWindow();
+                               dest->data[(pixel * dest->bits_per_pixel / 8) + bytenum] = 
+                                       (dest_pixel_value >> (dest->bits_per_pixel - (8 * (bytenum + 1)))) & 0xFF;
                        }
                }
+       }
+
+       return (0);
+} /* int copy_rgb_to_zpixmap */
+
+static int draw_window (const ui_image_t *img)
+{
+  static XImage *ximage = NULL;
+
+  if ((ximage != NULL) && ((img->width != ximage->width) || (img->height != ximage->height)))
+  {
+    free (ximage->data);
+    XDestroyImage (ximage);
+    ximage = NULL;
+  }
+
+  if (ximage == NULL)
+  {
+    char *data;
+    ximage = XCreateImage(disp_g, visual_g, depth_g, ZPixmap, 0,
+       NULL, img->width, img->height,
+       8, 0);
+    if (ximage == NULL)
+      return (-1);
+
+    ximage->byte_order= MSBFirst;
 
+    data = (char *) malloc (img->width * img->height * depth_g / 8);
+    ximage->data = data;
+    if (ximage->data == NULL)
+    {
+      XDestroyImage (ximage);
+      ximage = NULL;
+      return (-1);
+    }
+  }
 
+  copy_rgb_to_zpixmap (ximage, img);
+  XPutImage(disp_g, window_g, gc, ximage, 0, 0,
+      0, 0, ximage->width, ximage->height);
+
+  return (0);
+} /* int draw_window */
+
+#define ZOOM_SPEED 1.03
+
+static void zoom_in (double *fov)
+{
+  *fov = *fov / ZOOM_SPEED;
+  if (*fov < 10.5)
+    *fov = 10.5;
+} /* void zoom_in */
+
+static void zoom_out (double *fov)
+{
+  *fov = *fov * ZOOM_SPEED;
+  if (*fov > 165.0)
+    *fov = 165.0;
+} /* void zoom_out */
+
+int main( int argc, char** argv )
+{
+  XSizeHints hint;
+  unsigned long color_fg, color_bg;
+  int done;
+  static Atom                  proto_atom= None, delete_atom= None;
+
+  long event_mask;
+  unsigned int button_state = 0;
+
+  double fov = 70.0;
+  double yaw = 0.0;
+  double pitch = 0.0;
+
+  /* Detect mouse movement direction */
+  int pos_x_new = 0;
+  int pos_y_new = 0;
+  int pos_x_old;
+  int pos_y_old;
+
+  ui_image_t *pano;
+  ui_image_t *view;
+
+
+  // Set up display
+  disp_g   = XOpenDisplay("");
+  screen_g = DefaultScreen(disp_g);
+  depth_g  = DefaultDepth(disp_g, screen_g);
+
+  color_bg = WhitePixel(disp_g,screen_g);
+  color_fg = BlackPixel(disp_g,screen_g);
+
+  // Load panoramic image      
+  if( argc < 2 )
+  {
+    PrintError("No image file supplied");
+    exit(0);
+  }
+
+  if( strcmp( argv[1], "-h" ) == 0 ) /* FIXME: Use getopt */
+  {
+    PrintError( "%s\n %s\nUsage: PTViewer Imagefile", "PTViewer", LONGVERSION );
+    exit(0);
+  }
+
+  pano = ui_create_file (argv[1]);
+  if (pano == NULL)
+  {
+    PrintError ("Unable to read pano file.");
+    exit (0);
+  }
+
+  printf ("Panorama `%s', %ux%u pixels, loaded.\n",
+      argv[1], pano->width, pano->height);
+
+  view = ui_create (DEF_VIEW_WIDTH, DEF_VIEW_HEIGHT); /* FIXME: Possibly chose another size */
+  if (view == NULL)
+  {
+    PrintError ("Unable to create view.");
+    exit (0);
+  }
+
+  hint.width  = view->width;
+  hint.height = view->height;
+  hint.flags = PSize;
+
+  window_g = XCreateSimpleWindow(disp_g,
+      DefaultRootWindow(disp_g),
+      0, 0, /* Position */
+      view->width, view->height,
+      5,
+      color_fg, color_bg);
+
+  XSetStandardProperties(disp_g,
+      window_g,
+      text,
+      text,
+      None,
+      argv,
+      argc,
+      &hint);
+  gc = XCreateGC(disp_g,window_g,0,0);
+  XSetBackground(disp_g,gc,color_bg);
+  XSetForeground(disp_g,gc,color_fg);
+
+  event_mask = ButtonPressMask | ButtonReleaseMask | Button1MotionMask
+    | KeyPressMask | KeyReleaseMask | StructureNotifyMask
+    | EnterWindowMask | LeaveWindowMask| ExposureMask;
+
+  XSelectInput(disp_g, window_g, event_mask);
+  XMapRaised(disp_g,window_g);
+
+  proto_atom   = XInternAtom(disp_g, "WM_PROTOCOLS", False);
+  delete_atom = XInternAtom(disp_g, "WM_DELETE_WINDOW", False);
+  if ((proto_atom != None) && (delete_atom != None))
+    XChangeProperty(disp_g, window_g, proto_atom, XA_ATOM, 32,
+       PropModeReplace, (unsigned char *)&delete_atom,
+       1);
+  visual_g  = DefaultVisual(disp_g, screen_g);
+
+  pl_extract_view (view, pano, pitch, yaw, fov);
+  draw_window (view);
+
+  done = 0;
+  while (done == 0)
+  {
+    int isChanged = 0;
+    XEvent event;
+
+    XMaskEvent (disp_g, event_mask, &event);
+
+    switch (event.type)
+    {
+      case Expose:
+       draw_window (view);
+       break;
+
+      case ConfigureNotify:
+       {
+         XConfigureEvent *cev = (XConfigureEvent *) &event;
+         printf ("XConfigureEvent received: width = %i; height = %i;\n",
+             cev->width, cev->height);
+         /* TODO, FIXME: re-create `view' and `ximage' with cev->width, cev->height */
        }
-       XFreeGC(disp,gc);
-       XDestroyWindow(disp, win);
-       XCloseDisplay(disp);
+       break;
 
-       return (0);
-}
+      case KeyPress:
+       {
+         XKeyEvent *kev = (XKeyEvent *) &event;
+         KeySym ks = XLookupKeysym (kev, 0);
+
+         switch (ks)
+         {
+           case XK_Shift_L:
+           case XK_Shift_R:
+             zoom_in (&fov);
+             isChanged = 1;
+             break;
+
+           case XK_Control_L:
+           case XK_Control_R:
+             zoom_out (&fov);
+             isChanged = 1;
+             break;
+         }
+       }
+       break;
+
+      case KeyRelease:
+       printf ("Ignoring KeyRelease event.\n");
+       break;
+
+      case ButtonPress:
+      case ButtonRelease:
+       {
+         XButtonEvent *bev = (XButtonEvent *) &event;
+         button_state = bev->state;
+       }
+       break;
+
+      case MotionNotify:
+       {
+         XMotionEvent *mev = (XMotionEvent *) &event;
+
+         pos_x_old = pos_x_new;
+         pos_y_old = pos_y_new;
+         pos_x_new = mev->x;
+         pos_y_new = mev->y;
+
+         if (button_state & Button1Mask)
+         {
+           double yaw_diff = (pos_x_new - pos_x_old) / 24.0;
+           if (yaw_diff > 90.0)
+             yaw_diff = 90.0;
+           else if (yaw_diff < -90.0)
+             yaw_diff = -90.0;
+
+           yaw += yaw_diff;
+           if (yaw > 180.0)
+             yaw -= 360.0;
+           else if (yaw <= -180.0)
+             yaw += 360.0;
+
+           pitch -= (pos_y_new - pos_y_old) / 24.0;
+           if (pitch > 90.0)
+             pitch = 90.0;
+           else if (pitch < -90.0)
+             pitch = -90.0;
+
+           isChanged = 1;
+         }
+       }
+       break;
+
+      default:
+       printf ("Unhandled event type: 0x%02x\n",
+           event.type);
+    } /* switch (event.type) */
+
+    if (isChanged != 0)
+    {
+      pl_extract_view (view, pano, pitch, yaw, fov);
+      draw_window (view);
+    }
+  } /* while (done == 0) */
+
+  XFreeGC(disp_g,gc);
+  XDestroyWindow(disp_g, window_g);
+  XCloseDisplay(disp_g);
+
+  return (0);
+} /* int main */
        
 
 
@@ -444,150 +507,6 @@ void ThreeToFourBPP( Image *im )
        im->dataSize = im->height * im->bytesPerLine;
 }
 
-static int copy_rgb_to_zpixmap (XImage *dest, const Image *src)
-{
-       uint32_t *src_data;
-
-       uint32_t src_r;
-       uint32_t src_g;
-       uint32_t src_b;
-
-       uint32_t dest_r;
-       uint32_t dest_g;
-       uint32_t dest_b;
-       uint32_t dest_pixel_value;
-
-       uint32_t x;
-       uint32_t y;
-       uint32_t pixel;
-
-       uint32_t dest_r_maxval;
-       uint32_t dest_g_maxval;
-       uint32_t dest_b_maxval;
-
-       uint32_t dest_r_offset;
-       uint32_t dest_g_offset;
-       uint32_t dest_b_offset;
-
-       dest_r_offset = 0;
-       dest_g_offset = 0;
-       dest_b_offset = 0;
-       dest_r_maxval = dest->red_mask;
-       dest_g_maxval = dest->green_mask;
-       dest_b_maxval = dest->blue_mask;
-       for (x = 0; x < dest->depth; x++)
-       {
-               if ((dest_r_maxval & 0x01) == 0)
-               {
-                       dest_r_offset++;
-                       dest_r_maxval >>= 1;
-               }
-               if ((dest_g_maxval & 0x01) == 0)
-               {
-                       dest_g_offset++;
-                       dest_g_maxval >>= 1;
-               }
-               if ((dest_b_maxval & 0x01) == 0)
-               {
-                       dest_b_offset++;
-                       dest_b_maxval >>= 1;
-               }
-       }
-
-       src_data = (uint32_t *) *src->data;
-
-       pixel = 0;
-       for (y = 0; y < dest->height; y++)
-       {
-               for (x = 0; x < dest->width; x++, pixel++)
-               {
-                       int32_t bytenum;
-
-                       src_r = (src_data[pixel] >>  8) & 0xFF;
-                       src_g = (src_data[pixel] >> 16) & 0xFF;
-                       src_b = (src_data[pixel] >> 24) & 0xFF;
-
-                       dest_r = dest_r_maxval * src_r / 0xFF;
-                       dest_g = dest_g_maxval * src_g / 0xFF;
-                       dest_b = dest_b_maxval * src_b / 0xFF;
-
-                       dest_pixel_value = 0
-                               | ((dest_r << dest_r_offset) & dest->red_mask)
-                               | ((dest_g << dest_g_offset) & dest->green_mask)
-                               | ((dest_b << dest_b_offset) & dest->blue_mask);
-
-                       for (bytenum = 0; bytenum < (dest->depth / 8); bytenum++)
-                       {
-                               dest->data[(pixel * dest->bits_per_pixel / 8) + bytenum] = 
-                                       (dest_pixel_value >> (dest->bits_per_pixel - (8 * (bytenum + 1)))) & 0xFF;
-                       }
-               }
-       }
-
-       return (0);
-} /* int copy_rgb_to_zpixmap */
-
-void DrawWindow()
-{
-       XWindowAttributes xa;
-
-       XGetWindowAttributes( disp, win, &xa );
-
-       if( xa.width != view.width || xa.height != view.height )
-       {
-               myfree((void**)view.data);
-               view.width                      = xa.width;
-               view.height             = xa.height;
-               view.bytesPerLine       = view.width * view.bitsPerPixel / 8;
-               view.dataSize           = view.bytesPerLine * view.height;
-               view.format             = 1;
-               view.data               = (unsigned char**)mymalloc( view.dataSize );
-               if(view.data == NULL)
-               {
-                       PrintError("Not enough memory");
-                       exit(0);
-               }
-
-               ximage = XCreateImage(disp, visual, depth, ZPixmap, 0,
-                               NULL, view.width, view.height,
-                               8, 0);
-               ximage->data = (char *)*(view.data);
-               ximage->byte_order= MSBFirst;
-       }
-       if( view.format )
-       {
-               if( panning || zooming_in || zooming_out)
-                       DrawView(_nn);
-               else
-                       DrawView(_bilinear);
-       }
-
-       ximage->data = (char *) malloc (view.dataSize);
-       if (ximage->data == NULL)
-               return;
-       memcpy (ximage->data, *(view.data), view.dataSize);
-
-       copy_rgb_to_zpixmap (ximage, &view);
-
-       XPutImage(disp, win, gc, ximage, 0, 0, 0, 0, view.width, view.height);
-
-       free (ximage->data);
-       ximage->data = NULL;
-}
-
-void DrawView(int InterPolator)
-{
-       TrformStr                               Tr;
-                       
-       Tr.interpolator                 = InterPolator;
-
-       Tr.src                                  = &pano;
-       Tr.dest                                 = &view;        
-       
-       PV_ExtractStill( &Tr );
-       
-       view.format = 0;
-       return;
-       
-}
-               
+/*
+ * vim: set shiftwidth=2 tabstop=8 softtabstop=2 :
+ */