]> git.mxchange.org Git - simgear.git/blob - simgear/screen/jpgfactory.cxx
Comment out GLX code for MacOS and (hopefully) add some MacOS AGL compattible code...
[simgear.git] / simgear / screen / jpgfactory.cxx
1 // jpgfactory.cxx -- jpeg frontend for TR library
2 //
3 // Written by Norman Vine, started August 2001.
4 //
5 // Copyright (C) 2001  Norman Vine - nhv@yahoo.com
6 //
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.
11 //
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.
16 //
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id:
22
23
24 #ifdef HAVE_WINDOWS_H
25 #  include <windows.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30
31 #include <plib/ssg.h>
32
33 #include "jpgfactory.hxx"
34    
35
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39
40 static void init_destination (j_compress_ptr cinfo);
41 static void term_destination (j_compress_ptr cinfo);
42 static boolean empty_output_buffer (j_compress_ptr cinfo);
43
44 #ifdef __cplusplus
45 }
46 #endif
47
48
49 typedef struct {
50     struct jpeg_destination_mgr pub; /* public fields */
51     unsigned char * outfile; /* target stream */
52     JOCTET * buffer;         /* start of buffer */
53     int numbytes;            /* num bytes used */
54     int maxsize;             /* size of outfile */
55     int error;               /* error flag */
56 } my_destination_mgr;
57
58 typedef my_destination_mgr * my_dest_ptr;
59
60 void (*jpgRenderFrame)(void) = NULL;
61
62 trJpgFactory::trJpgFactory() {
63     imageWidth = imageHeight = 0;
64     tile       = NULL;
65     buffer     = NULL;
66     IMAGE      = NULL;
67     tr         = NULL;
68     cinfo.dest = NULL;
69 }
70
71 trJpgFactory::~trJpgFactory() {
72     destroy();
73 }
74
75 /*
76  * deallocate our dynamic parts
77  */
78
79 void trJpgFactory::destroy( int error )
80 {
81     if( error )
82         printf( "!! Malloc Failure trJpgFactory ( %d )!!\n",
83                 error );
84
85     if( cinfo.dest )  jpeg_destroy_compress(&cinfo);
86     if( tr )          trDelete(tr);
87     if( IMAGE )       delete [] IMAGE;
88     if( buffer )      delete [] buffer;
89     if( tile )        delete [] tile;
90 }
91
92 /*
93  * allocate and initialize the jpeg compress struct
94  * application needs to dealocate this
95  */
96
97 int trJpgFactory::jpeg_init()
98 {
99     j_compress_ptr cinfoPtr = &cinfo;
100
101     cinfoPtr->err = jpeg_std_error(&jerr);
102     jpeg_create_compress(cinfoPtr);
103
104     /* following taken from jpeg library exaample code */
105     cinfoPtr->dest = (struct jpeg_destination_mgr *)
106                      (*cinfoPtr->mem->alloc_small)
107                      ((j_common_ptr)cinfoPtr,
108                       JPOOL_PERMANENT,
109                       sizeof(my_destination_mgr));
110
111     my_dest_ptr dest = (my_dest_ptr)cinfoPtr->dest;
112
113     if( !dest ) {
114         destroy(5);
115         return 5;
116     }
117
118     dest->pub.init_destination    = init_destination;
119     dest->pub.empty_output_buffer = empty_output_buffer;
120     dest->pub.term_destination    = term_destination;
121     dest->outfile  = NULL;
122     dest->numbytes = 0;
123     dest->maxsize  = 0;
124
125     cinfoPtr->image_width      = imageWidth;
126     cinfoPtr->image_height     = imageHeight;
127     cinfoPtr->input_components = 3;
128     cinfoPtr->in_color_space   = JCS_RGB;
129     jpeg_set_defaults(cinfoPtr);
130     jpeg_set_quality(cinfoPtr, (100 * 90) >> 8, TRUE);
131
132     return 0;
133 }
134
135
136 /*
137  * may also be used as reinit() to change image size
138  */
139
140 int trJpgFactory::init(int width, int height )
141 {
142     destroy();
143
144     if( width <= 0 || height <= 0 ) {
145         imageWidth  = DEFAULT_XS;
146         imageHeight = DEFAULT_YS;
147     } else {
148         imageWidth  = width;
149         imageHeight = height;
150     }
151
152     int bufsize = imageWidth * imageHeight * 3 * sizeof(GLubyte);
153
154     /* allocate buffer large enough to store one tile */
155     tile = new GLubyte[bufsize];
156     if (!tile) {
157         destroy(1);
158         return 1;
159     }
160
161     /* allocate buffer to hold a row of tiles */
162     buffer = new GLubyte[ bufsize ];
163     if (!buffer) {
164         destroy(2);
165         return 2;
166     }
167
168     /* this should be big enough */
169     IMAGESIZE = bufsize + 1024;
170     IMAGE = new unsigned char[ IMAGESIZE ];
171     if( !IMAGE ) {
172         destroy(3);
173         return 3;
174     }
175
176     tr = trNew();
177     if( !tr ) {
178         destroy(4);
179         return 4;
180     }
181     
182     trRowOrder(tr, TR_TOP_TO_BOTTOM);
183     trTileSize(tr, imageWidth, imageHeight, 0);
184     trImageSize(tr, imageWidth, imageHeight);
185     trTileBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, tile);
186
187     return jpeg_init();
188 }
189
190 /*
191  *compress the image
192  */
193
194 int trJpgFactory::compress()
195 {
196     JSAMPROW  row_pointer[1];
197     int       row_stride;
198
199     /* to keep track of jpeg library routines */
200     my_dest_ptr dest = (my_dest_ptr) cinfo.dest;
201
202     //printf("\tjpeg_start_compress(&cinfo, TRUE)\n");
203     jpeg_start_compress(&cinfo, TRUE);
204     if( !dest->error ) {
205         dest->outfile = IMAGE;
206         dest->maxsize = IMAGESIZE;
207         row_stride    = cinfo.image_width * 3;
208
209         while( cinfo.next_scanline < cinfo.image_height &&
210                !dest->error )
211         {
212             row_pointer[0] = buffer + (cinfo.next_scanline * row_stride);
213             jpeg_write_scanlines(&cinfo, row_pointer, 1);
214         }
215     }
216     if( !dest->error ) {
217         // printf("\n\tBEFORE: jpeg_finish_compress(&cinfo)\n");
218         jpeg_finish_compress(&cinfo);
219         // printf("\tAFTER: jpeg_finish_compress(&cinfo)\n");
220     } else {
221         printf("INTERNAL JPEG_FACTORY ERROR\n");
222         jpeg_abort_compress(&cinfo);
223         /* OK - I am paranoid */
224         dest->numbytes = 0;
225     }
226     return dest->numbytes;
227 }
228
229 /*
230  * Makes the image then calls compress()
231  */
232
233 int trJpgFactory::render()
234 {
235     if( !tr || !jpgRenderFrame ) {
236         printf("!! NO tr !!\n   trJpgFactory::render()\n");
237         return 0;
238     }
239
240     // Make sure we have SSG projection primed for current view
241     glMatrixMode(GL_MODELVIEW);
242     glLoadIdentity();
243
244     sgFrustum *frustum = ssgGetFrustum();
245     trFrustum(tr,
246               frustum->getLeft(), frustum->getRight(),
247               frustum->getBot(),  frustum->getTop(), 
248               frustum->getNear(), frustum->getFar());
249
250     /* just to be safe... */
251     glPixelStorei(GL_PACK_ALIGNMENT, 1);
252
253     // printf("\ttrBeginTile(tr)\n");
254     trBeginTile(tr);
255     jpgRenderFrame();
256     trEndTile(tr);
257
258     /* just to be safe */
259     int curTileHeight = trGet(tr, TR_CURRENT_TILE_HEIGHT);
260     int curTileWidth  = trGet(tr, TR_CURRENT_TILE_WIDTH);
261
262     /* reverse image top to bottom */
263     int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
264     int bytesPerTileRow  = imageWidth * 3*sizeof(GLubyte);
265     int bytesPerCurrentTileRow = (curTileWidth) * 3*sizeof(GLubyte);
266     int i;
267     for (i=0;i<imageHeight;i++) {
268         memcpy(buffer + (curTileHeight-1-i) * bytesPerImageRow, /* Dest */
269                tile + i*bytesPerTileRow,              /* Src */
270                bytesPerCurrentTileRow);               /* Byte count*/
271     }
272
273     //  printf("exit trJpgFactory::render()\n");
274     return  compress();
275 }
276
277
278 #define OUTPUT_BUF_SIZE  4096
279
280 #ifdef __cplusplus
281 extern "C" {
282 #endif
283
284 /*
285  * Initialize destination --- called by jpeg_start_compress
286  * before any data is actually written.
287  */
288
289 static void init_destination (j_compress_ptr cinfo)
290 {
291     // printf("enter init_destination()\n");
292     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
293
294     /* following taken from jpeg library exaample code
295      * Allocate the output buffer ---
296      * it automaically will be released when done with image */
297         
298     dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small)
299                    ((j_common_ptr)cinfo, JPOOL_IMAGE,
300                     OUTPUT_BUF_SIZE * sizeof(JOCTET) );
301
302     if( !dest->buffer ) {
303         printf("MALLOC FAILED jpegFactory init_destination()\n");
304         dest->error = TRUE;
305     } else {
306         dest->error = FALSE;
307     }
308     dest->pub.next_output_byte = dest->buffer;
309     dest->pub.free_in_buffer   = OUTPUT_BUF_SIZE;
310     dest->numbytes = 0;
311 }
312
313 /*
314  * Empty the output buffer --- called whenever buffer fills up.
315  */
316
317 static boolean empty_output_buffer (j_compress_ptr cinfo)
318 {
319     // printf("enter empty_output_buffer(%d)\n", OUTPUT_BUF_SIZE);
320     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
321
322     if( (!dest->error) &&
323           ((dest->numbytes + OUTPUT_BUF_SIZE) < dest->maxsize) )
324     {
325         memcpy( dest->outfile+dest->numbytes, dest->buffer, (size_t)OUTPUT_BUF_SIZE);
326
327         dest->pub.next_output_byte = dest->buffer;
328         dest->pub.free_in_buffer   = OUTPUT_BUF_SIZE;
329
330         dest->numbytes += OUTPUT_BUF_SIZE;
331     } else {
332         printf("BUFFER OVERFLOW jpegFactory empty_output_buffer()\n");
333         dest->numbytes = 0;
334         dest->error    = TRUE;
335     }
336     return TRUE;
337 }
338
339 /*
340  * Terminate destination --- called by jpeg_finish_compress
341  * after all data has been written.  Usually needs to flush buffer.
342  *
343  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
344  * application must deal with any cleanup that should happen even
345  * for error exit.
346  */
347
348 static void term_destination (j_compress_ptr cinfo)
349 {
350     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
351
352     size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
353
354     if( (!dest->error) &&
355           ((dest->numbytes + datacount) < (unsigned int)dest->maxsize) )
356     {
357         memcpy( dest->outfile+dest->numbytes, dest->buffer, datacount);
358         dest->numbytes += datacount;
359     } else {
360         printf("BUFFER OVERFLOW jpegFactory term_destination()\n");
361         dest->numbytes = 0;
362         dest->error = TRUE;
363     }
364     // printf(" term_destination(%d) total %d\n", datacount, dest->numbytes );
365 }
366
367 #ifdef __cplusplus
368 }
369 #endif
370