jpgfactory.cxx

00001 // jpgfactory.cxx -- jpeg frontend for TR library
00002 //
00003 // Written by Norman Vine, started August 2001.
00004 //
00005 // Copyright (C) 2001  Norman Vine - nhv@yahoo.com
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License as
00009 // published by the Free Software Foundation; either version 2 of the
00010 // License, or (at your option) any later version.
00011 //
00012 // This program 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 // General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with this program; if not, write to the Free Software
00019 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020 //
00021 // $Id: jpgfactory_8cxx-source.html,v 1.15 2007-12-17 15:37:04 curt Exp $
00022 
00023 
00024 #ifdef HAVE_WINDOWS_H
00025 #  include <windows.h>
00026 #endif
00027 
00028 #include <plib/ssg.h>
00029 
00030 #include "jpgfactory.hxx"
00031    
00032 
00033 #ifdef __cplusplus
00034 extern "C" {
00035 #endif
00036 
00037 static void init_destination (j_compress_ptr cinfo);
00038 static void term_destination (j_compress_ptr cinfo);
00039 static boolean empty_output_buffer (j_compress_ptr cinfo);
00040 
00041 #ifdef __cplusplus
00042 }
00043 #endif
00044 
00045 
00046 typedef struct {
00047     struct jpeg_destination_mgr pub; /* public fields */
00048     unsigned char * outfile; /* target stream */
00049     JOCTET * buffer;         /* start of buffer */
00050     int numbytes;            /* num bytes used */
00051     int maxsize;             /* size of outfile */
00052     int error;               /* error flag */
00053 } my_destination_mgr;
00054 
00055 typedef my_destination_mgr * my_dest_ptr;
00056 
00057 void (*jpgRenderFrame)(void) = NULL;
00058 
00059 trJpgFactory::trJpgFactory() {
00060     imageWidth = imageHeight = 0;
00061     tile       = NULL;
00062     buffer     = NULL;
00063     IMAGE      = NULL;
00064     tr         = NULL;
00065     cinfo.dest = NULL;
00066 }
00067 
00068 trJpgFactory::~trJpgFactory() {
00069     destroy();
00070 }
00071 
00072 /*
00073  * deallocate our dynamic parts
00074  */
00075 
00076 void trJpgFactory::destroy( int error )
00077 {
00078     if( error )
00079         printf( "!! Malloc Failure trJpgFactory ( %d )!!\n",
00080                 error );
00081 
00082     if( cinfo.dest )  jpeg_destroy_compress(&cinfo);
00083     if( tr )          trDelete(tr);
00084     if( IMAGE )       delete [] IMAGE;
00085     if( buffer )      delete [] buffer;
00086     if( tile )        delete [] tile;
00087 }
00088 
00089 /*
00090  * allocate and initialize the jpeg compress struct
00091  * application needs to dealocate this
00092  */
00093 
00094 int trJpgFactory::jpeg_init()
00095 {
00096     j_compress_ptr cinfoPtr = &cinfo;
00097 
00098     cinfoPtr->err = jpeg_std_error(&jerr);
00099     jpeg_create_compress(cinfoPtr);
00100 
00101     /* following taken from jpeg library exaample code */
00102     cinfoPtr->dest = (struct jpeg_destination_mgr *)
00103                      (*cinfoPtr->mem->alloc_small)
00104                      ((j_common_ptr)cinfoPtr,
00105                       JPOOL_PERMANENT,
00106                       sizeof(my_destination_mgr));
00107 
00108     my_dest_ptr dest = (my_dest_ptr)cinfoPtr->dest;
00109 
00110     if( !dest ) {
00111         destroy(5);
00112         return 5;
00113     }
00114 
00115     dest->pub.init_destination    = init_destination;
00116     dest->pub.empty_output_buffer = empty_output_buffer;
00117     dest->pub.term_destination    = term_destination;
00118     dest->outfile  = NULL;
00119     dest->numbytes = 0;
00120     dest->maxsize  = 0;
00121 
00122     cinfoPtr->image_width      = imageWidth;
00123     cinfoPtr->image_height     = imageHeight;
00124     cinfoPtr->input_components = 3;
00125     cinfoPtr->in_color_space   = JCS_RGB;
00126     jpeg_set_defaults(cinfoPtr);
00127     jpeg_set_quality(cinfoPtr, (100 * 90) >> 8, TRUE);
00128 
00129     return 0;
00130 }
00131 
00132 
00133 /*
00134  * may also be used as reinit() to change image size
00135  */
00136 
00137 int trJpgFactory::init(int width, int height )
00138 {
00139     destroy();
00140 
00141     if( width <= 0 || height <= 0 ) {
00142         imageWidth  = DEFAULT_XS;
00143         imageHeight = DEFAULT_YS;
00144     } else {
00145         imageWidth  = width;
00146         imageHeight = height;
00147     }
00148 
00149     int bufsize = imageWidth * imageHeight * 3 * sizeof(GLubyte);
00150 
00151     /* allocate buffer large enough to store one tile */
00152     tile = new GLubyte[bufsize];
00153     if (!tile) {
00154         destroy(1);
00155         return 1;
00156     }
00157 
00158     /* allocate buffer to hold a row of tiles */
00159     buffer = new GLubyte[ bufsize ];
00160     if (!buffer) {
00161         destroy(2);
00162         return 2;
00163     }
00164 
00165     /* this should be big enough */
00166     IMAGESIZE = bufsize + 1024;
00167     IMAGE = new unsigned char[ IMAGESIZE ];
00168     if( !IMAGE ) {
00169         destroy(3);
00170         return 3;
00171     }
00172 
00173     tr = trNew();
00174     if( !tr ) {
00175         destroy(4);
00176         return 4;
00177     }
00178     
00179     trRowOrder(tr, TR_TOP_TO_BOTTOM);
00180     trTileSize(tr, imageWidth, imageHeight, 0);
00181     trImageSize(tr, imageWidth, imageHeight);
00182     trTileBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, tile);
00183 
00184     return jpeg_init();
00185 }
00186 
00187 /*
00188  *compress the image
00189  */
00190 
00191 int trJpgFactory::compress()
00192 {
00193     JSAMPROW  row_pointer[1];
00194     int       row_stride;
00195 
00196     /* to keep track of jpeg library routines */
00197     my_dest_ptr dest = (my_dest_ptr) cinfo.dest;
00198 
00199     //printf("\tjpeg_start_compress(&cinfo, TRUE)\n");
00200     jpeg_start_compress(&cinfo, TRUE);
00201     if( !dest->error ) {
00202         dest->outfile = IMAGE;
00203         dest->maxsize = IMAGESIZE;
00204         row_stride    = cinfo.image_width * 3;
00205 
00206         while( cinfo.next_scanline < cinfo.image_height &&
00207                !dest->error )
00208         {
00209             row_pointer[0] = buffer + (cinfo.next_scanline * row_stride);
00210             jpeg_write_scanlines(&cinfo, row_pointer, 1);
00211         }
00212     }
00213     if( !dest->error ) {
00214         // printf("\n\tBEFORE: jpeg_finish_compress(&cinfo)\n");
00215         jpeg_finish_compress(&cinfo);
00216         // printf("\tAFTER: jpeg_finish_compress(&cinfo)\n");
00217     } else {
00218         printf("INTERNAL JPEG_FACTORY ERROR\n");
00219         jpeg_abort_compress(&cinfo);
00220         /* OK - I am paranoid */
00221         dest->numbytes = 0;
00222     }
00223     return dest->numbytes;
00224 }
00225 
00226 /*
00227  * Makes the image then calls compress()
00228  */
00229 
00230 int trJpgFactory::render()
00231 {
00232     if( !tr || !jpgRenderFrame ) {
00233         printf("!! NO tr !!\n   trJpgFactory::render()\n");
00234         return 0;
00235     }
00236 
00237     // Make sure we have SSG projection primed for current view
00238     glMatrixMode(GL_MODELVIEW);
00239     glLoadIdentity();
00240 
00241     sgFrustum *frustum = ssgGetFrustum();
00242     trFrustum(tr,
00243               frustum->getLeft(), frustum->getRight(),
00244               frustum->getBot(),  frustum->getTop(), 
00245               frustum->getNear(), frustum->getFar());
00246 
00247     /* just to be safe... */
00248     glPixelStorei(GL_PACK_ALIGNMENT, 1);
00249 
00250     // printf("\ttrBeginTile(tr)\n");
00251     trBeginTile(tr);
00252     jpgRenderFrame();
00253     trEndTile(tr);
00254 
00255     /* just to be safe */
00256     int curTileHeight = trGet(tr, TR_CURRENT_TILE_HEIGHT);
00257     int curTileWidth  = trGet(tr, TR_CURRENT_TILE_WIDTH);
00258 
00259     /* reverse image top to bottom */
00260     int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
00261     int bytesPerTileRow  = imageWidth * 3*sizeof(GLubyte);
00262     int bytesPerCurrentTileRow = (curTileWidth) * 3*sizeof(GLubyte);
00263     int i;
00264     for (i=0;i<imageHeight;i++) {
00265         memcpy(buffer + (curTileHeight-1-i) * bytesPerImageRow, /* Dest */
00266                tile + i*bytesPerTileRow,              /* Src */
00267                bytesPerCurrentTileRow);               /* Byte count*/
00268     }
00269 
00270     //  printf("exit trJpgFactory::render()\n");
00271     return  compress();
00272 }
00273 
00274 
00275 #define OUTPUT_BUF_SIZE  4096
00276 
00277 #ifdef __cplusplus
00278 extern "C" {
00279 #endif
00280 
00281 /*
00282  * Initialize destination --- called by jpeg_start_compress
00283  * before any data is actually written.
00284  */
00285 
00286 static void init_destination (j_compress_ptr cinfo)
00287 {
00288     // printf("enter init_destination()\n");
00289     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
00290 
00291     /* following taken from jpeg library exaample code
00292      * Allocate the output buffer ---
00293      * it automaically will be released when done with image */
00294         
00295     dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small)
00296                    ((j_common_ptr)cinfo, JPOOL_IMAGE,
00297                     OUTPUT_BUF_SIZE * sizeof(JOCTET) );
00298 
00299     if( !dest->buffer ) {
00300         printf("MALLOC FAILED jpegFactory init_destination()\n");
00301         dest->error = TRUE;
00302     } else {
00303         dest->error = FALSE;
00304     }
00305     dest->pub.next_output_byte = dest->buffer;
00306     dest->pub.free_in_buffer   = OUTPUT_BUF_SIZE;
00307     dest->numbytes = 0;
00308 }
00309 
00310 /*
00311  * Empty the output buffer --- called whenever buffer fills up.
00312  */
00313 
00314 static boolean empty_output_buffer (j_compress_ptr cinfo)
00315 {
00316     // printf("enter empty_output_buffer(%d)\n", OUTPUT_BUF_SIZE);
00317     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
00318 
00319     if( (!dest->error) &&
00320           ((dest->numbytes + OUTPUT_BUF_SIZE) < dest->maxsize) )
00321     {
00322         memcpy( dest->outfile+dest->numbytes, dest->buffer, (size_t)OUTPUT_BUF_SIZE);
00323 
00324         dest->pub.next_output_byte = dest->buffer;
00325         dest->pub.free_in_buffer   = OUTPUT_BUF_SIZE;
00326 
00327         dest->numbytes += OUTPUT_BUF_SIZE;
00328     } else {
00329         printf("BUFFER OVERFLOW jpegFactory empty_output_buffer()\n");
00330         dest->numbytes = 0;
00331         dest->error    = TRUE;
00332     }
00333     return TRUE;
00334 }
00335 
00336 /*
00337  * Terminate destination --- called by jpeg_finish_compress
00338  * after all data has been written.  Usually needs to flush buffer.
00339  *
00340  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
00341  * application must deal with any cleanup that should happen even
00342  * for error exit.
00343  */
00344 
00345 static void term_destination (j_compress_ptr cinfo)
00346 {
00347     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
00348 
00349     size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
00350 
00351     if( (!dest->error) &&
00352           ((dest->numbytes + datacount) < (unsigned int)dest->maxsize) )
00353     {
00354         memcpy( dest->outfile+dest->numbytes, dest->buffer, datacount);
00355         dest->numbytes += datacount;
00356     } else {
00357         printf("BUFFER OVERFLOW jpegFactory term_destination()\n");
00358         dest->numbytes = 0;
00359         dest->error = TRUE;
00360     }
00361     // printf(" term_destination(%d) total %d\n", datacount, dest->numbytes );
00362 }
00363 
00364 #ifdef __cplusplus
00365 }
00366 #endif
00367 

Generated on Mon Dec 17 09:30:54 2007 for SimGear by  doxygen 1.5.1