1 // jpgfactory.cxx -- jpeg frontend for TR library
3 // Written by Norman Vine, started August 2001.
5 // Copyright (C) 2001 Norman Vine - nhv@yahoo.com
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "jpgfactory.hxx"
35 static void init_destination (j_compress_ptr cinfo);
36 static void term_destination (j_compress_ptr cinfo);
37 static boolean empty_output_buffer (j_compress_ptr cinfo);
43 // OSGFIME: offscreenrendering on osg - completely new context ...
46 struct jpeg_destination_mgr pub; /* public fields */
47 unsigned char * outfile; /* target stream */
48 JOCTET * buffer; /* start of buffer */
49 int numbytes; /* num bytes used */
50 int maxsize; /* size of outfile */
51 int error; /* error flag */
54 typedef my_destination_mgr * my_dest_ptr;
56 void (*jpgRenderFrame)(void) = NULL;
58 trJpgFactory::trJpgFactory() {
59 imageWidth = imageHeight = 0;
67 trJpgFactory::~trJpgFactory() {
72 * deallocate our dynamic parts
75 void trJpgFactory::destroy( int error )
78 printf( "!! Malloc Failure trJpgFactory ( %d )!!\n",
81 if( cinfo.dest ) jpeg_destroy_compress(&cinfo);
82 if( tr ) trDelete(tr);
83 if( IMAGE ) delete [] IMAGE;
84 if( buffer ) delete [] buffer;
85 if( tile ) delete [] tile;
89 * allocate and initialize the jpeg compress struct
90 * application needs to dealocate this
93 int trJpgFactory::jpeg_init()
95 j_compress_ptr cinfoPtr = &cinfo;
97 cinfoPtr->err = jpeg_std_error(&jerr);
98 jpeg_create_compress(cinfoPtr);
100 /* following taken from jpeg library exaample code */
101 cinfoPtr->dest = (struct jpeg_destination_mgr *)
102 (*cinfoPtr->mem->alloc_small)
103 ((j_common_ptr)cinfoPtr,
105 sizeof(my_destination_mgr));
107 my_dest_ptr dest = (my_dest_ptr)cinfoPtr->dest;
114 dest->pub.init_destination = init_destination;
115 dest->pub.empty_output_buffer = empty_output_buffer;
116 dest->pub.term_destination = term_destination;
117 dest->outfile = NULL;
121 cinfoPtr->image_width = imageWidth;
122 cinfoPtr->image_height = imageHeight;
123 cinfoPtr->input_components = 3;
124 cinfoPtr->in_color_space = JCS_RGB;
125 jpeg_set_defaults(cinfoPtr);
126 jpeg_set_quality(cinfoPtr, (100 * 90) >> 8, TRUE);
133 * may also be used as reinit() to change image size
136 int trJpgFactory::init(int width, int height )
140 if( width <= 0 || height <= 0 ) {
141 imageWidth = DEFAULT_XS;
142 imageHeight = DEFAULT_YS;
145 imageHeight = height;
148 int bufsize = imageWidth * imageHeight * 3 * sizeof(GLubyte);
150 /* allocate buffer large enough to store one tile */
151 tile = new GLubyte[bufsize];
157 /* allocate buffer to hold a row of tiles */
158 buffer = new GLubyte[ bufsize ];
164 /* this should be big enough */
165 IMAGESIZE = bufsize + 1024;
166 IMAGE = new unsigned char[ IMAGESIZE ];
178 trRowOrder(tr, TR_TOP_TO_BOTTOM);
179 trTileSize(tr, imageWidth, imageHeight, 0);
180 trImageSize(tr, imageWidth, imageHeight);
181 trTileBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, tile);
190 int trJpgFactory::compress()
192 JSAMPROW row_pointer[1];
195 /* to keep track of jpeg library routines */
196 my_dest_ptr dest = (my_dest_ptr) cinfo.dest;
198 //printf("\tjpeg_start_compress(&cinfo, TRUE)\n");
199 jpeg_start_compress(&cinfo, TRUE);
201 dest->outfile = IMAGE;
202 dest->maxsize = IMAGESIZE;
203 row_stride = cinfo.image_width * 3;
205 while( cinfo.next_scanline < cinfo.image_height &&
208 row_pointer[0] = buffer + (cinfo.next_scanline * row_stride);
209 jpeg_write_scanlines(&cinfo, row_pointer, 1);
213 // printf("\n\tBEFORE: jpeg_finish_compress(&cinfo)\n");
214 jpeg_finish_compress(&cinfo);
215 // printf("\tAFTER: jpeg_finish_compress(&cinfo)\n");
217 printf("INTERNAL JPEG_FACTORY ERROR\n");
218 jpeg_abort_compress(&cinfo);
219 /* OK - I am paranoid */
222 return dest->numbytes;
226 * Makes the image then calls compress()
229 int trJpgFactory::render()
231 if( !tr || !jpgRenderFrame ) {
232 printf("!! NO tr !!\n trJpgFactory::render()\n");
236 // Make sure we have SSG projection primed for current view
237 glMatrixMode(GL_MODELVIEW);
241 // sgFrustum *frustum = ssgGetFrustum();
243 frustum->getLeft(), frustum->getRight(),
244 frustum->getBot(), frustum->getTop(),
245 frustum->getNear(), frustum->getFar());
247 /* just to be safe... */
248 glPixelStorei(GL_PACK_ALIGNMENT, 1);
250 // printf("\ttrBeginTile(tr)\n");
255 /* just to be safe */
256 int curTileHeight = trGet(tr, TR_CURRENT_TILE_HEIGHT);
257 int curTileWidth = trGet(tr, TR_CURRENT_TILE_WIDTH);
259 /* reverse image top to bottom */
260 int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
261 int bytesPerTileRow = imageWidth * 3*sizeof(GLubyte);
262 int bytesPerCurrentTileRow = (curTileWidth) * 3*sizeof(GLubyte);
264 for (i=0;i<imageHeight;i++) {
265 memcpy(buffer + (curTileHeight-1-i) * bytesPerImageRow, /* Dest */
266 tile + i*bytesPerTileRow, /* Src */
267 bytesPerCurrentTileRow); /* Byte count*/
270 // printf("exit trJpgFactory::render()\n");
275 #define OUTPUT_BUF_SIZE 4096
282 * Initialize destination --- called by jpeg_start_compress
283 * before any data is actually written.
286 static void init_destination (j_compress_ptr cinfo)
288 // printf("enter init_destination()\n");
289 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
291 /* following taken from jpeg library exaample code
292 * Allocate the output buffer ---
293 * it automaically will be released when done with image */
295 dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small)
296 ((j_common_ptr)cinfo, JPOOL_IMAGE,
297 OUTPUT_BUF_SIZE * sizeof(JOCTET) );
299 if( !dest->buffer ) {
300 printf("MALLOC FAILED jpegFactory init_destination()\n");
305 dest->pub.next_output_byte = dest->buffer;
306 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
311 * Empty the output buffer --- called whenever buffer fills up.
314 static boolean empty_output_buffer (j_compress_ptr cinfo)
316 // printf("enter empty_output_buffer(%d)\n", OUTPUT_BUF_SIZE);
317 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
319 if( (!dest->error) &&
320 ((dest->numbytes + OUTPUT_BUF_SIZE) < dest->maxsize) )
322 memcpy( dest->outfile+dest->numbytes, dest->buffer, (size_t)OUTPUT_BUF_SIZE);
324 dest->pub.next_output_byte = dest->buffer;
325 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
327 dest->numbytes += OUTPUT_BUF_SIZE;
329 printf("BUFFER OVERFLOW jpegFactory empty_output_buffer()\n");
337 * Terminate destination --- called by jpeg_finish_compress
338 * after all data has been written. Usually needs to flush buffer.
340 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
341 * application must deal with any cleanup that should happen even
345 static void term_destination (j_compress_ptr cinfo)
347 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
349 size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
351 if( (!dest->error) &&
352 ((dest->numbytes + datacount) < (unsigned int)dest->maxsize) )
354 memcpy( dest->outfile+dest->numbytes, dest->buffer, datacount);
355 dest->numbytes += datacount;
357 printf("BUFFER OVERFLOW jpegFactory term_destination()\n");
361 // printf(" term_destination(%d) total %d\n", datacount, dest->numbytes );