From: Florian Forster Date: Sat, 18 Aug 2007 01:13:54 +0000 (+0200) Subject: Huge change, and it's almost working, too :) X-Git-Url: https://git.octo.it/?p=libopano.git;a=commitdiff_plain;h=464058941615b31ff7ce83f5c4226acd412f7aec Huge change, and it's almost working, too :) - 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 :/ --- diff --git a/src/panolib.c b/src/panolib.c index 8b9f30b..425a839 100644 --- a/src/panolib.c +++ b/src/panolib.c @@ -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 ) @@ -30,68 +31,58 @@ #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 index 0000000..98af710 --- /dev/null +++ b/src/panolib.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007 Florian octo Forster + * + * 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 index 0000000..fe4f1a7 --- /dev/null +++ b/src/utils_image.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2007 Florian octo Forster + * + * 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 +#include +#include +#include +#include + +#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 index 0000000..7c41848 --- /dev/null +++ b/src/utils_image.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007 Florian octo Forster + * + * 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 + +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 */ + diff --git a/src/viewer.c b/src/viewer.c index 043cef8..d7445e2 100644 --- a/src/viewer.c +++ b/src/viewer.c @@ -26,311 +26,374 @@ #include #include #include -#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 : + */