Huge change, and it's almost working, too :)
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 18 Aug 2007 01:13:54 +0000 (03:13 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 18 Aug 2007 01:13:54 +0000 (03:13 +0200)
- Use ImageMagick to access image files. libjpeg is just too troublesome
- Much cleaned up panolib.c and viewer.c, though not done yet.
- Probably a lot more I forgot for now :/

src/panolib.c
src/panolib.h [new file with mode: 0644]
src/utils_image.c [new file with mode: 0644]
src/utils_image.h [new file with mode: 0644]
src/viewer.c

index 8b9f30b..425a839 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "filter.h"
 #include "utils_math.h"
+#include "utils_image.h"
 
 #define DEG_TO_RAD(x) ((x) * 2.0 * M_PI / 360.0 )
 
 #define NATAN 2048
 #define NSQRT 2048
 
-int *atan_LU;
-int *sqrt_LU;
-
-
-void   matrix_matrix_mult      ( double m1[3][3],double m2[3][3],double result[3][3]);
-void   PV_transForm( TrformStr *TrPtr, double dist_r, double dist_e, int mt[3][3]);
-int    PV_sqrt( int x1, int x2 );
-
-
-/*
- * Extract image from pano in TrPtr->src using parameters in prefs (ignore
- * image parameters in TrPtr)
- */
-void PV_ExtractStill( TrformStr *TrPtr )
+static void matrix_matrix_mult( double m1[3][3],double m2[3][3],double result[3][3])
 {
-       /* field of view in rad */
-       double a;
-       double b;
-
-       double      p[2];
-       double          mt[3][3];
-       int             mi[3][3],i,k;
-
-       a =      DEG_TO_RAD( TrPtr->dest->hfov );       // field of view in rad         
-       b =      DEG_TO_RAD( TrPtr->src->hfov );
+       int i,k;
+       
+       for(i=0;i<3;i++)
+               for(k=0; k<3; k++)
+                       result[i][k] = m1[i][0] * m2[0][k] + m1[i][1] * m2[1][k] + m1[i][2] * m2[2][k];
+} /* void matrix_matrix_mult */
 
-       /* Set up the transformation matrix `mt' using Euler angles (somehow..) */
-       SetMatrix (DEG_TO_RAD (TrPtr->dest->pitch), /* alpha */
-                       DEG_TO_RAD (TrPtr->dest->yaw), /* beta */
-                       0.0, /* gamma */
-                       mt, /* output */
-                       1);
+/* Set matrix elements based on Euler angles a, b, c */
+static void set_transformation_matrix (double m[3][3],
+               double a, double b, double c)
+{
+       double mx[3][3], my[3][3], mz[3][3], dummy[3][3];
+       
 
+       // Calculate Matrices;
 
-       p[0] = (double)TrPtr->dest->width/ (2.0 * tan( a / 2.0 ) );
-       p[1] = (double) TrPtr->src->width / b;
+       mx[0][0] = 1.0 ;                                mx[0][1] = 0.0 ;                                mx[0][2] = 0.0;
+       mx[1][0] = 0.0 ;                                mx[1][1] = cos(a) ;                     mx[1][2] = sin(a);
+       mx[2][0] = 0.0 ;                                mx[2][1] =-mx[1][2] ;                   mx[2][2] = mx[1][1];
        
-       for(i=0; i<3; i++){
-               for(k=0; k<3; k++){
-                       mi[i][k] = 256 * mt[i][k];
-               }
-       }
+       my[0][0] = cos(b);                              my[0][1] = 0.0 ;                                my[0][2] =-sin(b);
+       my[1][0] = 0.0 ;                                my[1][1] = 1.0 ;                                my[1][2] = 0.0;
+       my[2][0] = -my[0][2];                   my[2][1] = 0.0 ;                                my[2][2] = my[0][0];
+       
+       mz[0][0] = cos(c) ;                     mz[0][1] = sin(c) ;                     mz[0][2] = 0.0;
+       mz[1][0] =-mz[0][1] ;                   mz[1][1] = mz[0][0] ;                   mz[1][2] = 0.0;
+       mz[2][0] = 0.0 ;                                mz[2][1] = 0.0 ;                                mz[2][2] = 1.0;
 
+       /* Calculate `m = mz * mx * my' */
 
-       PV_transForm( TrPtr, p[0], p[1], mi);
-       return;
-}
+       matrix_matrix_mult( mz, mx,     dummy);
+       matrix_matrix_mult( dummy, my, m);
+} /* void SetMatrix */
 
+/*
+ * Extract image from pano in TrPtr->src using parameters in prefs (ignore
+ * image parameters in TrPtr)
+ */
 typedef enum interpolator_e
 {
        NNEIGHBOUR,
        BILINEAR
 } interpolator_t;
 
-static int copy_pixel (Image *dest, Image *src,
+static int copy_pixel (ui_image_t *dest, const ui_image_t *src,
                int x_dest, int y_dest,
                double x_src_fp, double y_src_fp,
                interpolator_t interp)
 {
-       uint32_t pixel_value;
-       uint32_t *src_data  = (uint32_t *) (*src->data);
-       uint32_t *dest_data = (uint32_t *) (*dest->data);
+       uint32_t pixel_dest = (y_dest * dest->width) + x_dest;
 
        interp = NNEIGHBOUR;
 
@@ -102,12 +93,20 @@ static int copy_pixel (Image *dest, Image *src,
 
                if ((x_src < 0) || (x_src >= src->width)
                                || (y_src < 0) || (y_src >= src->height))
-                       pixel_value = 0x000000FF;
+               {
+                       dest->data[0][pixel_dest] = 0;
+                       dest->data[1][pixel_dest] = 0;
+                       dest->data[2][pixel_dest] = 0;
+               }
                else
-                       pixel_value = src_data[(y_src * src->width) + x_src];
-       }
+               {
+                       uint32_t pixel_src = (y_src * src->width) + x_src;
 
-       dest_data[(y_dest * dest->width) + x_dest] = pixel_value;
+                       dest->data[0][pixel_dest] = src->data[0][pixel_src];
+                       dest->data[1][pixel_dest] = src->data[1][pixel_src];
+                       dest->data[2][pixel_dest] = src->data[2][pixel_src];
+               }
+       }
 
        return (0);
 } /* int copy_pixel */
@@ -117,33 +116,37 @@ static int copy_pixel (Image *dest, Image *src,
 //    determined. If successful, TrPtr->success = 1. Memory for destination image
 //    must have been allocated and locked!
 
-void PV_transForm( TrformStr *TrPtr, double dist_r, double dist_e, int mt[3][3])
+int pl_extract_view (ui_image_t *view, const ui_image_t *pano,
+               double pitch, double yaw, double fov)
 {
-       int x_dest, y_dest;                     // Loop through destination image
-       unsigned char           *dest,*src;// Source and destination image data
-
-       // Variables used to convert screen coordinates to cartesian coordinates
+       int x_dest, y_dest; // Loop through destination image
 
-               
-       int                             dest_width_left = TrPtr->dest->width  / 2 ;  
-       int                             dest_height_top = TrPtr->dest->height / 2 ;
-       int                             src_width_left =  TrPtr->src->width   / 2 ;
-       int                             src_height_top =  TrPtr->src->height  / 2 ;
+       int dest_width_left = view->width  / 2 ;  
+       int dest_height_top = view->height / 2 ;
+       int src_width_left =  pano->width   / 2 ;
+       int src_height_top =  pano->height  / 2 ;
        
-       int                             v[3];
-       int                                     x_min, x_max, y_min, y_max;
+       double v[3];
+       int     x_min, x_max, y_min, y_max;
 
-       int                                     dr1, dr2, dr3;
+       /* The transformation matrix */
+       double tm[3][3];
 
-       dr1 = mt[2][0] * dist_r;
-       dr2 = mt[2][1] * dist_r;
-       dr3 = mt[2][2] * dist_r;
-       
-       dest = *TrPtr->dest->data;
-       src  = *TrPtr->src->data; // is locked
+       double dist_r;
+       double dist_e;
 
-       x_min = -dest_width_left; x_max = TrPtr->dest->width - dest_width_left;
-       y_min = -dest_height_top; y_max = TrPtr->dest->height - dest_height_top;
+       { /* What the fuck does this? -octo */
+               double a = DEG_TO_RAD (fov);
+               double b = 2.0 * M_PI; /* DEG_TO_RAD (360.0) */
+
+               dist_r = ((double) view->width) / (2.0 * tan (a / 2.0));
+               dist_e = ((double) pano->width) / b;
+       }
+
+       set_transformation_matrix (tm, DEG_TO_RAD (pitch), DEG_TO_RAD (yaw), 0.0);
+
+       x_min = -dest_width_left; x_max = view->width - dest_width_left;
+       y_min = -dest_height_top; y_max = view->height - dest_height_top;
 
        for(y_dest = y_min; y_dest < y_max; y_dest++)
        {
@@ -152,24 +155,21 @@ void PV_transForm( TrformStr *TrPtr, double dist_r, double dist_e, int mt[3][3])
                        double x_src_fp;
                        double y_src_fp;
 
-                       v[0] = mt[0][0] * x_dest + mt[1][0] * y_dest + dr1;
-                       v[1] = mt[0][1] * x_dest + mt[1][1] * y_dest + dr2;
-                       v[2] = mt[0][2] * x_dest + mt[1][2] * y_dest + dr3;
-
-                       v[0] = v[0] >> 8; v[2] = v[2] >> 8;
-                       v[1] = v[1] >> 8;
+                       v[0] = tm[0][0] * x_dest + tm[1][0] * y_dest + tm[2][0] * dist_r;
+                       v[1] = tm[0][1] * x_dest + tm[1][1] * y_dest + tm[2][1] * dist_r;
+                       v[2] = tm[0][2] * x_dest + tm[1][2] * y_dest + tm[2][2] * dist_r;
 
                        x_src_fp = dist_e * atan2 (v[0], v[2]);
                        y_src_fp = dist_e * atan2 (v[1], sqrt (v[2] * v[2] + v[0] * v[0]));
 
-                       copy_pixel (TrPtr->dest, TrPtr->src,
+                       copy_pixel (view, pano,
                                        dest_width_left + x_dest, dest_height_top + y_dest,
                                        src_width_left + x_src_fp, src_height_top + y_src_fp,
                                        NNEIGHBOUR);
                }
        }
        
-       return;
+       return (0);
 }
 
 #if 0
@@ -187,45 +187,6 @@ void matrix_inv_mult( double m[3][3], double vector[3] )
 }
 #endif
 
-// Set matrix elements based on Euler angles a, b, c
-
-void SetMatrix( double a, double b, double c , double m[3][3], int cl )
-{
-       double mx[3][3], my[3][3], mz[3][3], dummy[3][3];
-       
-
-       // Calculate Matrices;
-
-       mx[0][0] = 1.0 ;                                mx[0][1] = 0.0 ;                                mx[0][2] = 0.0;
-       mx[1][0] = 0.0 ;                                mx[1][1] = cos(a) ;                     mx[1][2] = sin(a);
-       mx[2][0] = 0.0 ;                                mx[2][1] =-mx[1][2] ;                   mx[2][2] = mx[1][1];
-       
-       my[0][0] = cos(b);                              my[0][1] = 0.0 ;                                my[0][2] =-sin(b);
-       my[1][0] = 0.0 ;                                my[1][1] = 1.0 ;                                my[1][2] = 0.0;
-       my[2][0] = -my[0][2];                   my[2][1] = 0.0 ;                                my[2][2] = my[0][0];
-       
-       mz[0][0] = cos(c) ;                     mz[0][1] = sin(c) ;                     mz[0][2] = 0.0;
-       mz[1][0] =-mz[0][1] ;                   mz[1][1] = mz[0][0] ;                   mz[1][2] = 0.0;
-       mz[2][0] = 0.0 ;                                mz[2][1] = 0.0 ;                                mz[2][2] = 1.0;
-
-       /* Calculate `m = mz * mx * my' */
-
-       if( cl )
-               matrix_matrix_mult( mz, mx,     dummy);
-       else
-               matrix_matrix_mult( mx, mz,     dummy);
-       matrix_matrix_mult( dummy, my, m);
-} /* void SetMatrix */
-
-void matrix_matrix_mult( double m1[3][3],double m2[3][3],double result[3][3])
-{
-       register int i,k;
-       
-       for(i=0;i<3;i++)
-               for(k=0; k<3; k++)
-                       result[i][k] = m1[i][0] * m2[0][k] + m1[i][1] * m2[1][k] + m1[i][2] * m2[2][k];
-} /* void matrix_matrix_mult */
-
 #define ID_0 0xff
 #define ID_1 0xd8
 #define ID_2 0xff
diff --git a/src/panolib.h b/src/panolib.h
new file mode 100644 (file)
index 0000000..98af710
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc., 51
+ *  Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ **/
+
+#ifndef PANOLIB_H
+#define PANOLIB_H 1
+
+#include "utils_image.h"
+
+int pl_extract_view (ui_image_t *view, const ui_image_t *pano,
+               double pitch, double yaw, double fov);
+
+#endif /* PANOLIB_H */
diff --git a/src/utils_image.c b/src/utils_image.c
new file mode 100644 (file)
index 0000000..fe4f1a7
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *  Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc., 51
+ *  Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ **/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <wand/magick-wand.h>
+
+#include "utils_image.h"
+
+ui_image_t *ui_create (uint32_t width, uint32_t height)
+{
+  ui_image_t *img = NULL;
+
+  img = (ui_image_t *) malloc (sizeof (ui_image_t));
+  if (img == NULL)
+    return (NULL);
+  memset (img, '\0', sizeof (ui_image_t));
+
+  img->width = width;
+  img->height = height;
+  img->type = UIT_RGB;
+
+  img->data = (uint8_t **) malloc (3 * sizeof (uint8_t *));
+  if (img->data == NULL)
+  {
+    free (img);
+    return (NULL);
+  }
+
+  /* FIXME: s/4/3 when bug is fixed! */
+  fprintf (stderr, "Theres still a bug in %s, line %i!\n",
+      __FILE__, __LINE__);
+  img->data[0] = (uint8_t *) malloc (4 * width * height * sizeof (uint8_t));
+  if (img->data[0] == NULL)
+  {
+    free (img->data);
+    free (img);
+    return (NULL);
+  }
+  memset (img->data[0], '\0', 3 * width * height * sizeof (uint8_t));
+  /* FIXME: Remove +16 */
+  img->data[1] = img->data[0] + (width * height);
+  img->data[2] = img->data[1] + (width * height);
+
+  return (img);
+} /* ui_image_t *ui_create */
+
+ui_image_t *ui_create_file (const char *file)
+{
+  MagickWand *mwand; 
+  MagickBooleanType status;
+
+  ui_image_t *img = NULL;
+
+  uint32_t width;
+  uint32_t height;
+  int i;
+
+  mwand = NewMagickWand ();
+  if (mwand == NULL)
+    return (NULL);
+
+  status = MagickReadImage (mwand, file);
+  if (status == MagickFalse)
+  {
+    DestroyMagickWand (mwand);
+    return (NULL);
+  }
+
+  width = (uint32_t) MagickGetImageWidth (mwand);
+  height = (uint32_t) MagickGetImageHeight (mwand);
+
+  img = ui_create (width, height);
+  if (img == NULL)
+  {
+    DestroyMagickWand (mwand);
+    return (NULL);
+  }
+
+  for (i = 0; i < 3; i++)
+  {
+    char *map;
+
+    switch (i)
+    {
+      case 0: map = "R"; break;
+      case 1: map = "G"; break;
+      case 2: map = "B"; break;
+      default: map = "*invalid*";
+    };
+
+    status = MagickGetImagePixels (mwand,
+       0, 0,
+       img->width, img->height,
+       map, CharPixel, (void *) img->data[i]);
+    if (status == MagickFalse)
+      break;
+  } /* for (i = 0, 1, 2) */
+  if (status == MagickFalse)
+  {
+    ui_destroy (img);
+    img = NULL;
+  }
+
+  DestroyMagickWand (mwand);
+  
+  return (img);
+} /* ui_image_t *ui_create_file */
+
+void ui_destroy (ui_image_t *img)
+{
+  if (img != NULL)
+  {
+    if (img->data != NULL)
+    {
+      if (img->data[0] != NULL)
+       free (img->data[0]);
+      free (img->data);
+    }
+    free (img);
+  }
+} /* void ui_destroy */
+
+/*
+ * vim: set tabstop=8 softtabstop=2 shiftwidth=2 :
+ */
diff --git a/src/utils_image.h b/src/utils_image.h
new file mode 100644 (file)
index 0000000..7c41848
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc., 51
+ *  Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ **/
+
+#ifndef UTILS_IMAGE_H
+#define UTILS_IMAGE_H 1
+
+#include <stdint.h>
+
+enum ui_image_type
+{
+       UIT_BW,
+       UIT_RGB
+};
+
+struct ui_image_s
+{
+       uint32_t width;
+       uint32_t height;
+
+       uint8_t **data;
+       enum ui_image_type type;
+};
+typedef struct ui_image_s ui_image_t;
+
+ui_image_t *ui_create (uint32_t width, uint32_t height);
+ui_image_t *ui_create_file (const char *file);
+void ui_destroy (ui_image_t *);
+
+#endif /* UTILS_IMAGE_H */
+
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 :
+ */