46 #define WORSTCOMPR(x) (2*(x) + 2)
49 #define MAXVAL_BYTE 255
50 #define MAXVAL_WORD 65535
55 put_byte(ostream *out_file,
unsigned char b) {
60 put_big_short(ostream *out_file,
short s) {
61 if ( pm_writebigshort( out_file, s ) == -1 )
67 put_big_long(ostream *out_file,
long l) {
68 if ( pm_writebiglong( out_file, l ) == -1 )
74 put_short_as_byte(ostream *out_file,
short s) {
75 put_byte(out_file, (
unsigned char)s);
82 PNMFileTypeSGI::Writer::
83 Writer(
PNMFileType *type, ostream *file,
bool owns_file) :
91 PNMFileTypeSGI::Writer::
95 _file->seekp(table_start);
97 PANDA_FREE_ARRAY(table);
107 bool PNMFileTypeSGI::Writer::
108 supports_write_row()
const {
122 bool PNMFileTypeSGI::Writer::
126 switch (_num_channels) {
138 nassert_raise(
"unexpected channel count");
144 if( _maxval <= MAXVAL_BYTE ) {
146 new_maxval = MAXVAL_BYTE;
147 }
else if( _maxval <= MAXVAL_WORD ) {
149 new_maxval = MAXVAL_WORD;
154 if( sgi_storage_type != STORAGE_VERBATIM ) {
155 table = (TabEntry *)PANDA_MALLOC_ARRAY(_num_channels * _y_size *
sizeof(TabEntry));
156 memset(table, 0, _num_channels * _y_size *
sizeof(TabEntry));
159 write_rgb_header(sgi_imagename.c_str());
161 if (table!=
nullptr) {
162 table_start = _file->tellp();
169 current_row = _y_size - 1;
185 bool PNMFileTypeSGI::Writer::
186 write_row(
xel *row_data, xelval *alpha_data) {
189 build_scanline(channel, row_data, alpha_data);
192 write_channels(channel, put_short_as_byte);
194 write_channels(channel, put_big_short);
196 for (
int i = 0; i < _num_channels; i++) {
197 PANDA_FREE_ARRAY(channel[i].data);
205 void PNMFileTypeSGI::Writer::
206 write_rgb_header(
const char *imagename) {
209 put_big_short(_file, SGI_MAGIC);
210 put_byte(_file, sgi_storage_type);
211 put_byte(_file, (
char)bpc);
212 put_big_short(_file, dimensions);
213 put_big_short(_file, _x_size);
214 put_big_short(_file, _y_size);
215 put_big_short(_file, _num_channels);
216 put_big_long(_file, 0);
217 put_big_long(_file, new_maxval);
218 for( i = 0; i < 4; i++ )
220 for( i = 0; i < 79 && imagename[i] !=
'\0'; i++ )
221 put_byte(_file, imagename[i]);
224 put_big_long(_file, CMAP_NORMAL);
225 for( i = 0; i < 404; i++ )
230 void PNMFileTypeSGI::Writer::
233 int tabsize = _y_size*_num_channels;
235 for( i = 0; i < tabsize; i++ ) {
236 put_big_long(_file, table[i].start);
238 for( i = 0; i < tabsize; i++ )
239 put_big_long(_file, table[i].length);
243 void PNMFileTypeSGI::Writer::
244 write_channels(ScanLine channel[],
void (*put)(ostream *,
short)) {
247 for( i = 0; i < _num_channels; i++ ) {
248 Table(i).start = _file->tellp();
249 Table(i).length = channel[i].length * bpc;
251 for( col = 0; col < channel[i].length; col++ ) {
252 (*put)(_file, channel[i].data[col]);
258 void PNMFileTypeSGI::Writer::
259 build_scanline(ScanLine output[],
xel *row_data, xelval *alpha_data) {
263 if( sgi_storage_type != STORAGE_VERBATIM ) {
264 rletemp = (ScanElem *)alloca(WORSTCOMPR(_x_size) *
sizeof(ScanElem));
266 temp = (ScanElem *)PANDA_MALLOC_ARRAY(_x_size *
sizeof(ScanElem));
268 if( _num_channels <= 2 ) {
269 for( col = 0; col < _x_size; col++ )
270 temp[col] = (ScanElem)
271 (new_maxval * PPM_GETB(row_data[col]) / _maxval);
272 temp = compress(temp, output[0]);
274 if (_num_channels == 2) {
275 for( col = 0; col < _x_size; col++ )
276 temp[col] = (ScanElem)
277 (new_maxval * alpha_data[col] / _maxval);
278 temp = compress(temp, output[1]);
282 for( col = 0; col < _x_size; col++ )
283 temp[col] = (ScanElem)
284 (new_maxval * PPM_GETR(row_data[col]) / _maxval);
285 temp = compress(temp, output[0]);
286 for( col = 0; col < _x_size; col++ )
287 temp[col] = (ScanElem)
288 (new_maxval * PPM_GETG(row_data[col]) / _maxval);
289 temp = compress(temp, output[1]);
290 for( col = 0; col < _x_size; col++ )
291 temp[col] = (ScanElem)
292 (new_maxval * PPM_GETB(row_data[col]) / _maxval);
293 temp = compress(temp, output[2]);
294 if (_num_channels == 4) {
295 for( col = 0; col < _x_size; col++ )
296 temp[col] = (ScanElem)
297 (new_maxval * alpha_data[col] / _maxval);
298 temp = compress(temp, output[3]);
302 PANDA_FREE_ARRAY(temp);
306 PNMFileTypeSGI::Writer::ScanElem *PNMFileTypeSGI::Writer::
307 compress(ScanElem *temp, ScanLine &output) {
310 switch( sgi_storage_type ) {
311 case STORAGE_VERBATIM:
312 output.length = _x_size;
314 temp = (ScanElem *)PANDA_MALLOC_ARRAY(_x_size *
sizeof(ScanElem));
317 len = rle_compress(temp, _x_size);
319 output.data = (ScanElem *)PANDA_MALLOC_ARRAY(len *
sizeof(ScanElem));
320 memcpy(output.data, rletemp, len *
sizeof(ScanElem));
323 pm_error(
"unknown storage type - can\'t happen");
333 int PNMFileTypeSGI::Writer::
334 rle_compress(ScanElem *inbuf,
int size) {
335 int in, out, hold, count;
336 ScanElem *outbuf = rletemp;
340 if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {
341 for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
343 outbuf[out++]=(ScanElem)(count);
344 outbuf[out++]=inbuf[hold];
347 hold=out; out++; count=0;
348 while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
349 outbuf[out++]=inbuf[in++];
353 outbuf[hold]=(ScanElem)(count | 0x80);
356 outbuf[out++] = (ScanElem)0;
360 #endif // HAVE_SGI_RGB