16 #ifdef HAVE_SOFTIMAGE_PIC
27 static const float imageVersionNumber = 3.0;
28 static const int imageCommentLength = 80;
29 static const char imageComment[imageCommentLength+1] =
30 "Written by pnmimage.";
33 #define UNCOMPRESSED 0x00
34 #define MIXED_RUN_LENGTH 0x02
37 #define RGB_CHANNEL 0xe0
38 #define ALPHA_CHANNEL 0x10
41 #define SOFTIMAGE_MAGIC1 0x5380
42 #define SOFTIMAGE_MAGIC2 0xf634
44 static const char *
const extensions_softimage[] = {
47 static const int num_extensions_softimage =
sizeof(extensions_softimage) /
sizeof(
const char *);
52 read_float(istream *file) {
55 if (pm_readbiglong(file, &l)==0) {
63 read_ushort_SI(istream *file) {
65 return pm_readbigshort(file, (
short *)&x)==0 ? x : 0;
69 read_uchar_SI(istream *file) {
72 return (x!=EOF) ? (
unsigned char)x : 0;
76 write_ushort_SI(ostream *file,
unsigned short x) {
77 pm_writebigshort(file, (
short)x);
81 write_uchar_SI(ostream *file,
unsigned char x) {
86 write_float(ostream *file,
float x) {
87 pm_writebiglong(file, *(
long *)&x);
91 read_channel_pkt(istream *file,
92 int &chained,
int &size,
int &type,
int &channel) {
93 chained = read_uchar_SI(file);
94 size = read_uchar_SI(file);
95 type = read_uchar_SI(file);
96 channel = read_uchar_SI(file);
98 if (file->eof() || file->fail()) {
103 pnmimage_soft_cat.error()
104 <<
"Don't know how to interpret " << size <<
" bits per pixel!\n";
112 read_rgb(
xel *row_data, xelval *, istream *file,
int x,
int repeat) {
113 xelval red, grn, blu;
114 red = read_uchar_SI(file);
115 grn = read_uchar_SI(file);
116 blu = read_uchar_SI(file);
119 PPM_ASSIGN(row_data[x], red, grn, blu);
126 read_alpha(
xel *, xelval *alpha_data, istream *file,
int x,
int repeat) {
127 xelval alpha = read_uchar_SI(file);
130 alpha_data[x] = alpha;
137 read_rgba(
xel *row_data, xelval *alpha_data, istream *file,
int x,
int repeat) {
138 xelval red, grn, blu, alpha;
139 red = read_uchar_SI(file);
140 grn = read_uchar_SI(file);
141 blu = read_uchar_SI(file);
142 alpha = read_uchar_SI(file);
145 PPM_ASSIGN(row_data[x], red, grn, blu);
146 alpha_data[x] = alpha;
154 read_scanline(
xel *row_data, xelval *alpha_data,
int cols, istream *file,
155 void (*read_data)(
xel *row_data, xelval *alpha_data, istream *file,
158 if (ctype==UNCOMPRESSED) {
159 for (
int x = 0; x<cols; x++) {
160 read_data(row_data, alpha_data, file, x, 1);
169 num = read_uchar_SI(file);
178 read_data(row_data, alpha_data, file, x, 1);
179 if (file->eof() || file->fail()) {
188 num = read_ushort_SI(file);
195 read_data(row_data, alpha_data, file, x, num);
196 if (file->eof() || file->fail()) {
210 PNMFileTypeSoftImage::
211 PNMFileTypeSoftImage() {
217 string PNMFileTypeSoftImage::
226 int PNMFileTypeSoftImage::
227 get_num_extensions()
const {
228 return num_extensions_softimage;
235 string PNMFileTypeSoftImage::
236 get_extension(
int n)
const {
237 nassertr(n >= 0 && n < num_extensions_softimage,
string());
238 return extensions_softimage[n];
245 string PNMFileTypeSoftImage::
246 get_suggested_extension()
const {
254 bool PNMFileTypeSoftImage::
255 has_magic_number()
const {
264 bool PNMFileTypeSoftImage::
265 matches_magic_number(
const string &magic_number)
const {
266 nassertr(magic_number.size() >= 2,
false);
268 ((
unsigned char)magic_number[0] << 8) |
269 ((
unsigned char)magic_number[1]);
270 return (mn == SOFTIMAGE_MAGIC1);
279 make_reader(istream *file,
bool owns_file,
const string &magic_number) {
281 return new Reader(
this, file, owns_file, magic_number);
290 make_writer(ostream *file,
bool owns_file) {
292 return new Writer(
this, file, owns_file);
299 PNMFileTypeSoftImage::Reader::
300 Reader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number) :
305 if (pnmimage_soft_cat.is_debug()) {
306 pnmimage_soft_cat.debug()
307 <<
"SoftImage image file appears to be empty.\n";
314 ((
unsigned char)magic_number[0] << 8) |
315 ((
unsigned char)magic_number[1]);
317 ((
unsigned char)magic_number[2] << 8) |
318 ((
unsigned char)magic_number[3]);
320 if (magic1 != SOFTIMAGE_MAGIC1 || magic2 != SOFTIMAGE_MAGIC2) {
329 _file->seekg(imageCommentLength, std::ios::cur);
332 _file->read(pict_id, 4);
333 if (_file->gcount() < 4) {
338 if (memcmp(pict_id,
"PICT", 4)!=0) {
343 _x_size = read_ushort_SI(_file);
344 _y_size = read_ushort_SI(_file);
347 read_ushort_SI(_file);
348 read_ushort_SI(_file);
350 int chained, size, channel;
351 if (!read_channel_pkt(_file, chained, size, rgb_ctype, channel)) {
356 soft_color = unknown;
358 if (channel == (RGB_CHANNEL | ALPHA_CHANNEL)) {
362 }
else if (channel == RGB_CHANNEL) {
367 if (!read_channel_pkt(_file, chained, size, alpha_ctype, channel)) {
372 if (channel == ALPHA_CHANNEL) {
379 switch (soft_color) {
390 pnmimage_soft_cat.error()
391 <<
"Image is not RGB or RGBA!\n";
397 pnmimage_soft_cat.error()
398 <<
"Unexpected additional channels in image file.\n";
405 if (pnmimage_soft_cat.is_debug()) {
406 pnmimage_soft_cat.debug()
407 <<
"Reading SoftImage " << *
this <<
"\n";
418 bool PNMFileTypeSoftImage::Reader::
419 supports_read_row()
const {
429 bool PNMFileTypeSoftImage::Reader::
430 read_row(
xel *row_data, xelval *alpha_data,
int x_size,
int) {
434 switch (soft_color) {
436 if (!read_scanline(row_data, alpha_data, x_size, _file,
437 read_rgb, rgb_ctype)) {
443 if (!read_scanline(row_data, alpha_data, x_size, _file,
444 read_rgba, rgb_ctype)) {
450 if (!read_scanline(row_data, alpha_data, x_size, _file,
451 read_rgb, rgb_ctype)) {
454 if (!read_scanline(row_data, alpha_data, x_size, _file,
455 read_alpha, alpha_ctype)) {
469 write_channel_pkt(ostream *file,
470 int chained,
int size,
int type,
int channel) {
471 write_uchar_SI(file, chained);
472 write_uchar_SI(file, size);
473 write_uchar_SI(file, type);
474 write_uchar_SI(file, channel);
478 write_rgb(
xel *row_data, xelval *, ostream *file,
int x) {
479 write_uchar_SI(file, PPM_GETR(row_data[x]));
480 write_uchar_SI(file, PPM_GETG(row_data[x]));
481 write_uchar_SI(file, PPM_GETB(row_data[x]));
485 compare_rgb(
xel *row_data, xelval *,
int x1,
int x2) {
486 return PPM_EQUAL(row_data[x1], row_data[x2]);
490 write_gray(
xel *row_data, xelval *, ostream *file,
int x) {
491 write_uchar_SI(file, PPM_GETB(row_data[x]));
492 write_uchar_SI(file, PPM_GETB(row_data[x]));
493 write_uchar_SI(file, PPM_GETB(row_data[x]));
497 compare_gray(
xel *row_data, xelval *,
int x1,
int x2) {
498 return (PPM_GETB(row_data[x1])==PPM_GETB(row_data[x2]));
502 write_alpha(
xel *, xelval *alpha_data, ostream *file,
int x) {
503 write_uchar_SI(file, alpha_data[x]);
507 compare_alpha(
xel *, xelval *alpha_data,
int x1,
int x2) {
508 return (alpha_data[x1]==alpha_data[x2]);
512 write_diff(
xel *row_data, xelval *alpha_data, ostream *file,
513 void (*write_data)(
xel *row_data, xelval *alpha_data, ostream *file,
515 int tox,
int length) {
517 nassertv(length<=128);
519 write_uchar_SI(file, length-1);
522 write_data(row_data, alpha_data, file, tox-length);
528 write_same(
xel *row_data, xelval *alpha_data, ostream *file,
529 void (*write_data)(
xel *row_data, xelval *alpha_data, ostream *file,
531 int tox,
int length) {
533 write_diff(row_data, alpha_data, file, write_data, tox, length);
535 }
else if (length>0) {
537 write_uchar_SI(file, length+127);
539 write_uchar_SI(file, 128);
540 write_ushort_SI(file, length);
542 write_data(row_data, alpha_data, file, tox);
548 write_scanline(
xel *row_data, xelval *alpha_data,
int cols, ostream *file,
549 int (*compare_data)(
xel *row_data, xelval *alpha_data,
551 void (*write_data)(
xel *row_data, xelval *alpha_data,
552 ostream *file,
int x)) {
567 if (!compare_data(row_data, alpha_data, x, x-run_length)) {
570 if (run_length <= 1) {
581 write_same(row_data, alpha_data, file, write_data, x-1, run_length);
592 if (run_length>128) {
596 int excess = run_length - 128;
597 write_diff(row_data, alpha_data, file, write_data, x-excess-1, 128);
600 }
else if (run_length > 2 &&
601 compare_data(row_data, alpha_data, x, x-1) &&
602 compare_data(row_data, alpha_data, x, x-2)) {
607 write_diff(row_data, alpha_data, file, write_data, x-3, run_length-2);
621 write_same(row_data, alpha_data, file, write_data, cols-1, run_length);
625 if (run_length>128) {
626 int excess = run_length - 128;
627 write_diff(row_data, alpha_data, file, write_data, cols-excess-1, 128);
631 write_diff(row_data, alpha_data, file, write_data, cols-1, run_length);
639 PNMFileTypeSoftImage::Writer::
640 Writer(
PNMFileType *type, ostream *file,
bool owns_file) :
651 bool PNMFileTypeSoftImage::Writer::
652 supports_write_row()
const {
666 bool PNMFileTypeSoftImage::Writer::
668 write_ushort_SI(_file, SOFTIMAGE_MAGIC1);
669 write_ushort_SI(_file, SOFTIMAGE_MAGIC2);
670 write_float(_file, imageVersionNumber);
672 _file->write(imageComment, imageCommentLength);
673 _file->write(
"PICT", 4);
675 write_ushort_SI(_file, _x_size);
676 write_ushort_SI(_file, _y_size);
678 write_float(_file, 1.0);
679 write_ushort_SI(_file, 3);
680 write_ushort_SI(_file, 0);
686 write_channel_pkt(_file, 1, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
687 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, ALPHA_CHANNEL);
689 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
706 bool PNMFileTypeSoftImage::Writer::
707 write_row(
xel *row_data, xelval *alpha_data) {
708 if (is_grayscale()) {
709 write_scanline(row_data, alpha_data, _x_size, _file, compare_gray, write_gray);
712 write_scanline(row_data, alpha_data, _x_size, _file, compare_rgb, write_rgb);
716 write_scanline(row_data, alpha_data, _x_size, _file, compare_alpha, write_alpha);
719 return !_file->fail();
727 void PNMFileTypeSoftImage::
728 register_with_read_factory() {
730 register_factory(get_class_type(), make_PNMFileTypeSoftImage);
746 #endif // HAVE_SOFTIMAGE_PIC