sphmap.c

Go to the documentation of this file.
00001 /*                        S P H M A P . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1986-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup sphmap */
00023 /*@{*/
00024 
00025 /** @file sphmap.c
00026  * @brief
00027  *  Common Subroutines for Spherical Data Structures/Texture Maps Subroutines
00028  *
00029  *  @author
00030  *      Phillip Dykstra
00031  *
00032  *  @par Source -
00033  *      SECAD/VLD Computing Consortium, Bldg 394
00034  *@n    The U. S. Army Ballistic Research Laboratory
00035  *@n    Aberdeen Proving Ground, Maryland  21005-5066
00036  *
00037  */
00038 
00039 
00040 #ifndef lint
00041 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/sphmap.c,v 14.11 2006/09/07 01:19:17 lbutler Exp $ (BRL)";
00042 #endif
00043 
00044 #include "common.h"
00045 
00046 
00047 
00048 #include <stdio.h>
00049 #include <math.h>
00050 #ifdef HAVE_STRING_H
00051 #include <string.h>
00052 #else
00053 #include <strings.h>
00054 #endif
00055 #include "machine.h"
00056 #include "bu.h"
00057 #include "vmath.h"
00058 #include "bn.h"
00059 #include "spm.h"
00060 
00061 /**
00062  *              S P M _ I N I T
00063  *@brief
00064  *  Return a sphere map structure initialized for N points around
00065  *  the equator.  
00066  *
00067  * Malloc the storage and fill in the pointers.
00068  *  This code leaves a ring of "triangular" pixels at the poles.
00069  *  An alternative would be to have the pole region map to a
00070  *  single pixel.
00071  *
00072  *  Returns SPM_NULL on error.
00073  */
00074 spm_map_t *
00075 spm_init(int N, int elsize)
00076 {
00077         int     i, nx, total, index;
00078         register spm_map_t *mapp;
00079 
00080         mapp = (spm_map_t *)bu_malloc( sizeof(spm_map_t), "spm_map_t");
00081         if( mapp == SPM_NULL )
00082                 return( SPM_NULL );
00083         bzero( (char *)mapp, sizeof(spm_map_t) );
00084 
00085         mapp->elsize = elsize;
00086         mapp->ny = N/2;
00087         mapp->nx = (int *) bu_malloc( (unsigned)(N/2 * sizeof(*(mapp->nx))), "sph nx" );
00088         if( mapp->nx == NULL ) {
00089                 spm_free( mapp );
00090                 return( SPM_NULL );
00091         }
00092         mapp->xbin = (unsigned char **) bu_malloc( (unsigned)(N/2 * sizeof(char *)), "sph xbin" );
00093         if( mapp->xbin == NULL ) {
00094                 spm_free( mapp );
00095                 return( SPM_NULL );
00096         }
00097 
00098         total = 0;
00099         for( i = 0; i < N/4; i++ ) {
00100                 nx = ceil( N*cos( i*bn_twopi/N ) );
00101                 if( nx > N ) nx = N;
00102                 mapp->nx[ N/4 + i ] = nx;
00103                 mapp->nx[ N/4 - i -1 ] = nx;
00104 
00105                 total += 2*nx;
00106         }
00107 
00108         mapp->_data = (unsigned char *) bu_calloc( (unsigned)total, elsize, "spm_init data" );
00109         if( mapp->_data == NULL ) {
00110                 spm_free( mapp );
00111                 return( SPM_NULL );
00112         }
00113 
00114         index = 0;
00115         for( i = 0; i < N/2; i++ ) {
00116                 mapp->xbin[i] = &((mapp->_data)[index]);
00117                 index += elsize * mapp->nx[i];
00118         }
00119         mapp->magic = SPM_MAGIC;
00120         return( mapp );
00121 }
00122 
00123 /**
00124  *              S P M _ F R E E
00125  *@brief
00126  *  Free the storage associated with a sphere structure.
00127  */
00128 void
00129 spm_free(spm_map_t *mp)
00130 {
00131         RT_CK_SPM(mp);
00132         if( mp == SPM_NULL )
00133                 return;
00134 
00135         if( mp->_data != NULL )  {
00136                 (void) bu_free( (char *)mp->_data, "sph _data" );
00137                 mp->_data = NULL;
00138         }
00139 
00140         if( mp->nx != NULL )  {
00141                 (void) bu_free( (char *)mp->nx, "sph nx" );
00142                 mp->nx = NULL;
00143         }
00144 
00145         if( mp->xbin != NULL )  {
00146                 (void) bu_free( (char *)mp->xbin, "sph xbin" );
00147                 mp->xbin = NULL;
00148         }
00149 
00150         (void) bu_free( (char *)mp, "spm_map_t" );
00151 }
00152 
00153 /*
00154  *              S P M _ R E A D
00155  *@brief
00156  *  Read the value of the pixel at the given normalized (u,v)
00157  *  coordinates.  It does NOT check the sanity of the coords.
00158  *
00159  *@n  0.0 <= u < 1.0    Left to Right
00160  *@n  0.0 <= v < 1.0    Bottom to Top
00161  */
00162 void
00163 spm_read(register spm_map_t *mapp, register unsigned char *valp, double u, double v)
00164 {
00165         int     x, y;
00166         register unsigned char *cp;
00167         register int    i;
00168 
00169         RT_CK_SPM(mapp);
00170 
00171         y = v * mapp->ny;
00172         x = u * mapp->nx[y];
00173         cp = &(mapp->xbin[y][x*mapp->elsize]);
00174 
00175         i = mapp->elsize;
00176         while( i-- > 0 ) {
00177                 *valp++ = *cp++;
00178         }
00179 }
00180 
00181 /*
00182  *              S P M _ W R I T E
00183  *@breif
00184  *  Write the value of the pixel at the given normalized (u,v)
00185  *  coordinates.  It does NOT check the sanity of the coords.
00186  *
00187  *@n  0.0 <= u < 1.0    Left to Right
00188  *@n  0.0 <= v < 1.0    Bottom to Top
00189  */
00190 void
00191 spm_write(register spm_map_t *mapp, register unsigned char *valp, double u, double v)
00192 {
00193         int     x, y;
00194         register unsigned char *cp;
00195         register int    i;
00196 
00197         RT_CK_SPM(mapp);
00198 
00199         y = v * mapp->ny;
00200         x = u * mapp->nx[y];
00201         cp = &(mapp->xbin[y][x*mapp->elsize]);
00202 
00203         i = mapp->elsize;
00204         while( i-- > 0 ) {
00205                 *cp++ = *valp++;
00206         }
00207 }
00208 
00209 /*
00210  *              S P M _ G E T
00211  *@brief
00212  *  Return a pointer to the storage element indexed by (u,v)
00213  *  coordinates.  It does NOT check the sanity of the coords.
00214  *
00215  *@n  0.0 <= u < 1.0    Left to Right
00216  *@n  0.0 <= v < 1.0    Bottom to Top
00217  */
00218 char *
00219 spm_get(register spm_map_t *mapp, double u, double v)
00220 {
00221         int     x, y;
00222         register unsigned char *cp;
00223 
00224         RT_CK_SPM(mapp);
00225 
00226         y = v * mapp->ny;
00227         x = u * mapp->nx[y];
00228         cp = &(mapp->xbin[y][x*mapp->elsize]);
00229 
00230         return( (char *)cp );
00231 }
00232 
00233 /*
00234  *              S P M _ L O A D
00235  *@brief
00236  *  Read a saved sphere map from a file ("-" for stdin) into
00237  *  the given map structure.
00238  *  This does not check for conformity of size, etc.
00239  *
00240  *  @return -1 on error, else 0.
00241  */
00242 int
00243 spm_load(spm_map_t *mapp, char *filename)
00244 {
00245         int     y, total;
00246         FILE    *fp;
00247 
00248         RT_CK_SPM(mapp);
00249 
00250         if( strcmp( filename, "-" ) == 0 )
00251                 fp = stdin;
00252         else  {
00253                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00254                 fp = fopen( filename, "r" );
00255                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00256                 if( fp == NULL )
00257                         return( -1 );
00258         }
00259 
00260         total = 0;
00261         for( y = 0; y < mapp->ny; y++ )
00262                 total += mapp->nx[y];
00263 
00264         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00265         y = fread( (char *)mapp->_data, mapp->elsize, total, fp );      /* res_syscall */
00266         (void) fclose( fp );
00267         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00268 
00269         if( y != total )
00270                 return( -1 );
00271 
00272         return( 0 );
00273 }
00274 
00275 /*
00276  *              S P M _ S A V E
00277  *@brief
00278  *  Write a loaded sphere map to the given file ("-" for stdout).
00279  *  Returns -1 on error, else 0.
00280  */
00281 int
00282 spm_save(spm_map_t *mapp, char *filename)
00283 {
00284         int     i;
00285         int     got;
00286         FILE    *fp;
00287 
00288         RT_CK_SPM(mapp);
00289 
00290         if( strcmp( filename, "-" ) == 0 )
00291                 fp = stdout;
00292         else  {
00293                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00294                 fp = fopen( filename, "w" );                    /* res_syscall */
00295                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00296                 if( fp == NULL )
00297                         return( -1 );
00298         }
00299 
00300         for( i = 0; i < mapp->ny; i++ ) {
00301                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00302                 got = fwrite( (char *)mapp->xbin[i], mapp->elsize,      /* res_syscall */
00303                     mapp->nx[i], fp );
00304                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00305                 if( got != mapp->nx[i] ) {
00306                         bu_log("spm_save(%s): write error\n", filename);
00307                         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00308                         (void) fclose( fp );
00309                         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00310                         return( -1 );
00311                 }
00312         }
00313 
00314         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00315         (void) fclose( fp );
00316         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00317 
00318         return( 0 );
00319 }
00320 
00321 /*
00322  *              S P M _ P I X _ L O A D
00323  *@brief
00324  *  Load an 'nx' by 'ny' pix file and filter it into the
00325  *  given sphere structure.
00326  *  @return -1 on error, else 0.
00327  */
00328 int
00329 spm_px_load(spm_map_t *mapp, char *filename, int nx, int ny)
00330 {
00331         int     i, j;                   /* index input file */
00332         int     x, y;                   /* index texture map */
00333         double  j_per_y, i_per_x;       /* ratios */
00334         int     nj, ni;                 /* ints of ratios */
00335         unsigned char *cp;
00336         unsigned char *buffer;
00337         unsigned long   red, green, blue;
00338         long    count;
00339         FILE    *fp;
00340 
00341         RT_CK_SPM(mapp);
00342 
00343         if( strcmp( filename, "-" ) == 0 )
00344                 fp = stdin;
00345         else  {
00346                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00347                 fp = fopen( filename, "r" );
00348                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00349                 if( fp == NULL )
00350                         return( -1 );
00351         }
00352 
00353         /* Shamelessly suck it all in */
00354         buffer = (unsigned char *)bu_malloc( (unsigned)(nx*nx*3), "spm_px_load buffer" );
00355         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00356         i = fread( (char *)buffer, 3, nx*ny, fp );      /* res_syscall */
00357         (void) fclose( fp );
00358         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00359         if( i != nx*ny )  {
00360                 bu_log("spm_px_load(%s) read error\n", filename);
00361                 return( -1 );
00362         }
00363 
00364         j_per_y = (double)ny / (double)mapp->ny;
00365         nj = (int)j_per_y;
00366         /* for each bin */
00367         for( y = 0; y < mapp->ny; y++ ) {
00368                 i_per_x = (double)nx / (double)mapp->nx[y];
00369                 ni = (int)i_per_x;
00370                 /* for each cell in bin */
00371                 for( x = 0; x < mapp->nx[y]; x++ ) {
00372                         /* Average pixels from the input file */
00373                         red = green = blue = 0;
00374                         count = 0;
00375                         for( j = y*j_per_y; j < y*j_per_y+nj; j++ ) {
00376                                 for( i = x*i_per_x; i < x*i_per_x+ni; i++ ) {
00377                                         red = red + (unsigned long)buffer[ 3*(j*nx+i) ];
00378                                         green = green + (unsigned long)buffer[ 3*(j*nx+i)+1 ];
00379                                         blue = blue + (unsigned long)buffer[ 3*(j*nx+i)+2 ];
00380                                         count++;
00381                                 }
00382                         }
00383                         /* Save the color */
00384                         cp = &(mapp->xbin[y][x*3]);
00385                         *cp++ = (unsigned char)(red/count);
00386                         *cp++ = (unsigned char)(green/count);
00387                         *cp++ = (unsigned char)(blue/count);
00388                 }
00389         }
00390         (void) bu_free( (char *)buffer, "spm buffer" );
00391 
00392         return( 0 );
00393 }
00394 
00395 /*
00396  *              S P M _ P I X _ S A V E
00397  *@brief
00398  *  Save a sphere structure as an 'nx' by 'ny' pix file.
00399  *  @return -1 on error, else 0.
00400  */
00401 int
00402 spm_px_save(spm_map_t *mapp, char *filename, int nx, int ny)
00403 {
00404         int     x, y;
00405         FILE    *fp;
00406         unsigned char pixel[3];
00407         int     got;
00408 
00409         RT_CK_SPM(mapp);
00410 
00411         if( strcmp( filename, "-" ) == 0 )
00412                 fp = stdout;
00413         else  {
00414                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00415                 fp = fopen( filename, "w" );
00416                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00417                 if( fp == NULL )
00418                         return( -1 );
00419         }
00420 
00421         for( y = 0; y < ny; y++ ) {
00422                 for( x = 0; x < nx; x++ ) {
00423                         spm_read( mapp, pixel, (double)x/(double)nx, (double)y/(double)ny );
00424                         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00425                         got = fwrite( (char *)pixel, sizeof(pixel), 1, fp );    /* res_syscall */
00426                         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00427                         if( got != 1 )  {
00428                                 bu_log("spm_px_save(%s): write error\n", filename);
00429                                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00430                                 (void) fclose( fp );
00431                                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00432                                 return( -1 );
00433                         }
00434                 }
00435         }
00436 
00437         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00438         (void) fclose( fp );
00439         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00440 
00441         return( 0 );
00442 }
00443 
00444 /*
00445  *              S P M _ D U M P
00446  *@brief
00447  *  Display a sphere structure on stderr.
00448  *  Used for debugging.
00449  */
00450 void
00451 spm_dump(spm_map_t *mp, int verbose)
00452 {
00453         int     i;
00454 
00455         RT_CK_SPM(mp);
00456 
00457         bu_log("elsize = %d\n", mp->elsize );
00458         bu_log("ny = %d\n", mp->ny );
00459         bu_log("_data = 0x%x\n", mp->_data );
00460         if( !verbose )  return;
00461         for( i = 0; i < mp->ny; i++ ) {
00462                 bu_log("  nx[%d] = %3d, xbin[%d] = 0x%x\n",
00463                         i, mp->nx[i], i, mp->xbin[i] );
00464         }
00465 }
00466 /*@}*/
00467 /*
00468  * Local Variables:
00469  * mode: C
00470  * tab-width: 8
00471  * c-basic-offset: 4
00472  * indent-tabs-mode: t
00473  * End:
00474  * ex: shiftwidth=4 tabstop=8
00475  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6