From 892f7f47981844cd343134eba56aa74d214300b2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 27 Apr 2001 23:19:30 +0000 Subject: [PATCH] *** empty log message *** --- panda/src/express/datagramInputFile.cxx | 4 +- panda/src/pnmimagetypes/Sources.pp | 1 + .../pnmimagetypes/config_pnmimagetypes.cxx | 13 + .../src/pnmimagetypes/config_pnmimagetypes.h | 4 + panda/src/pnmimagetypes/pnmFileTypeTGA.cxx | 918 ++++++++++++++++++ panda/src/pnmimagetypes/pnmFileTypeTGA.h | 118 +++ panda/src/pnmimagetypes/pnmFileTypeYUV.h | 2 +- 7 files changed, 1057 insertions(+), 3 deletions(-) create mode 100644 panda/src/pnmimagetypes/pnmFileTypeTGA.cxx create mode 100644 panda/src/pnmimagetypes/pnmFileTypeTGA.h diff --git a/panda/src/express/datagramInputFile.cxx b/panda/src/express/datagramInputFile.cxx index cefe3f72b7..24e745e219 100644 --- a/panda/src/express/datagramInputFile.cxx +++ b/panda/src/express/datagramInputFile.cxx @@ -13,8 +13,8 @@ // Description: Reads a sequence of bytes from the beginning of the // datagram file. This may be called any number of // times after the file has been opened and before the -// first datagram is written. It may not be called once -// the first datagram is written. +// first datagram is read. It may not be called once +// the first datagram has been read. //////////////////////////////////////////////////////////////////// bool DatagramInputFile:: read_header(string &header, size_t num_bytes) { diff --git a/panda/src/pnmimagetypes/Sources.pp b/panda/src/pnmimagetypes/Sources.pp index b99905ba2b..1f2978bb4c 100644 --- a/panda/src/pnmimagetypes/Sources.pp +++ b/panda/src/pnmimagetypes/Sources.pp @@ -16,6 +16,7 @@ pnmFileTypeSGI.cxx pnmFileTypeSGI.h pnmFileTypeSGIReader.cxx \ pnmFileTypeSGIWriter.cxx pnmFileTypeSoftImage.cxx \ pnmFileTypeSoftImage.h pnmFileTypeTIFF.cxx pnmFileTypeTIFF.h \ + pnmFileTypeTGA.cxx pnmFileTypeTGA.h \ pnmFileTypeYUV.cxx pnmFileTypeYUV.h \ color.c colrops.c resolu.c header.c diff --git a/panda/src/pnmimagetypes/config_pnmimagetypes.cxx b/panda/src/pnmimagetypes/config_pnmimagetypes.cxx index 2173a6f894..86f4af87db 100644 --- a/panda/src/pnmimagetypes/config_pnmimagetypes.cxx +++ b/panda/src/pnmimagetypes/config_pnmimagetypes.cxx @@ -9,6 +9,7 @@ #include "pnmFileTypeAlias.h" #include "pnmFileTypeRadiance.h" #include "pnmFileTypeTIFF.h" +#include "pnmFileTypeTGA.h" #include "pnmFileTypeYUV.h" #include "pnmFileTypeIMG.h" #include "pnmFileTypeSoftImage.h" @@ -29,6 +30,7 @@ NotifyCategoryDef(pnmimage_sgi, pnmimage_cat); NotifyCategoryDef(pnmimage_alias, pnmimage_cat); NotifyCategoryDef(pnmimage_radiance, pnmimage_cat); NotifyCategoryDef(pnmimage_tiff, pnmimage_cat); +NotifyCategoryDef(pnmimage_tga, pnmimage_cat); NotifyCategoryDef(pnmimage_yuv, pnmimage_cat); NotifyCategoryDef(pnmimage_img, pnmimage_cat); NotifyCategoryDef(pnmimage_soft, pnmimage_cat); @@ -47,6 +49,14 @@ const int radiance_brightness_adjustment = config_pnmimagetypes.GetInt("radiance const int yuv_xsize = config_pnmimagetypes.GetInt("yuv-xsize", 720); const int yuv_ysize = config_pnmimagetypes.GetInt("yuv-ysize", 486); +// TGA supports RLE compression, as well as colormapping and/or +// grayscale images. Set these true to enable these features, if +// possible, or false to disable them. Some programs (like xv) have +// difficulty reading these advanced TGA files. +const bool tga_rle = config_pnmimagetypes.GetBool("tga-rle", false); +const bool tga_colormap = config_pnmimagetypes.GetBool("tga-colormap", false); +const bool tga_grayscale = config_pnmimagetypes.GetBool("tga-grayscale", false); + // IMG format is just a sequential string of r, g, b bytes. However, // it may or may not include a "header" which consists of the xsize // and the ysize of the image, either as shorts or as longs. @@ -97,6 +107,7 @@ init_libpnmimagetypes() { PNMFileTypeAlias::init_type(); PNMFileTypeRadiance::init_type(); PNMFileTypeTIFF::init_type(); + PNMFileTypeTGA::init_type(); PNMFileTypeYUV::init_type(); PNMFileTypeIMG::init_type(); PNMFileTypeSoftImage::init_type(); @@ -137,6 +148,7 @@ init_libpnmimagetypes() { tr->register_type(new PNMFileTypeAlias); tr->register_type(new PNMFileTypeRadiance); tr->register_type(new PNMFileTypeTIFF); + tr->register_type(new PNMFileTypeTGA); tr->register_type(new PNMFileTypeYUV); tr->register_type(new PNMFileTypeIMG); tr->register_type(new PNMFileTypeSoftImage); @@ -151,6 +163,7 @@ init_libpnmimagetypes() { PNMFileTypeAlias::register_with_read_factory(); PNMFileTypeRadiance::register_with_read_factory(); PNMFileTypeTIFF::register_with_read_factory(); + PNMFileTypeTGA::register_with_read_factory(); PNMFileTypeYUV::register_with_read_factory(); PNMFileTypeIMG::register_with_read_factory(); PNMFileTypeSoftImage::register_with_read_factory(); diff --git a/panda/src/pnmimagetypes/config_pnmimagetypes.h b/panda/src/pnmimagetypes/config_pnmimagetypes.h index ee7636ad2f..bae342e1f4 100644 --- a/panda/src/pnmimagetypes/config_pnmimagetypes.h +++ b/panda/src/pnmimagetypes/config_pnmimagetypes.h @@ -14,6 +14,7 @@ NotifyCategoryDecl(pnmimage_sgi, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_alias, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_radiance, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_tiff, EXPCL_PANDA, EXPTP_PANDA); +NotifyCategoryDecl(pnmimage_tga, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_yuv, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_img, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_soft, EXPCL_PANDA, EXPTP_PANDA); @@ -26,6 +27,9 @@ extern const double radiance_gamma_correction; extern const int radiance_brightness_adjustment; extern const int yuv_xsize; extern const int yuv_ysize; +extern const bool tga_rle; +extern const bool tga_colormap; +extern const bool tga_grayscale; extern const int jpeg_quality; extern const int jpeg_scale_num; diff --git a/panda/src/pnmimagetypes/pnmFileTypeTGA.cxx b/panda/src/pnmimagetypes/pnmFileTypeTGA.cxx new file mode 100644 index 0000000000..00e69a9a11 --- /dev/null +++ b/panda/src/pnmimagetypes/pnmFileTypeTGA.cxx @@ -0,0 +1,918 @@ +// Filename: pnmFileTypeTGA.cxx +// Created by: drose (27Apr01) +// +//////////////////////////////////////////////////////////////////// + + +// Much code in this file is borrowed from Netpbm, specifically tgatoppm.c +// and ppmtotga.c. + +/* tgatoppm.c - read a TrueVision Targa file and write a portable pixmap +** +** Partially based on tga2rast, version 1.0, by Ian MacPhedran. +** +** Copyright (C) 1989 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/* ppmtotga.c - read a portable pixmap and produce a TrueVision Targa file +** +** Copyright (C) 1989, 1991 by Mark Shand and Jef Poskanzer +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include "pnmFileTypeTGA.h" +#include "config_pnmimagetypes.h" + +#include +#include + +#include +#include + +static const char * const extensions[] = { + "tga" +}; +static const int num_extensions = sizeof(extensions) / sizeof(const char *); + +TypeHandle PNMFileTypeTGA::_type_handle; + + +/* Header definition. */ +struct ImageHeader { + unsigned char IDLength; /* length of Identifier String */ + unsigned char CoMapType; /* 0 = no map */ + unsigned char ImgType; /* image type (see below for values) */ + unsigned char Index_lo, Index_hi; /* index of first color map entry */ + unsigned char Length_lo, Length_hi; /* number of entries in color map */ + unsigned char CoSize; /* size of color map entry (15,16,24,32) */ + unsigned char X_org_lo, X_org_hi; /* x origin of image */ + unsigned char Y_org_lo, Y_org_hi; /* y origin of image */ + unsigned char Width_lo, Width_hi; /* width of image */ + unsigned char Height_lo, Height_hi; /* height of image */ + unsigned char PixelSize; /* pixel size (8,16,24,32) */ + unsigned char AttBits; /* 4 bits, number of attribute bits per pixel */ + unsigned char Rsrvd; /* 1 bit, reserved */ + unsigned char OrgBit; /* 1 bit, origin: 0=lower left, 1=upper left */ + unsigned char IntrLve; /* 2 bits, interleaving flag */ + }; + +typedef char ImageIDField[256]; + +/* Definitions for image types. */ +#define TGA_Null 0 +#define TGA_Map 1 +#define TGA_RGB 2 +#define TGA_Mono 3 +#define TGA_RLEMap 9 +#define TGA_RLERGB 10 +#define TGA_RLEMono 11 +#define TGA_CompMap 32 +#define TGA_CompMap4 33 + +/* Definitions for interleave flag. */ +#define TGA_IL_None 0 +#define TGA_IL_Two 1 +#define TGA_IL_Four 2 + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeTGA:: +PNMFileTypeTGA() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::get_name +// Access: Public, Virtual +// Description: Returns a few words describing the file type. +//////////////////////////////////////////////////////////////////// +string PNMFileTypeTGA:: +get_name() const { + return "Targa"; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::get_num_extensions +// Access: Public, Virtual +// Description: Returns the number of different possible filename +// extensions associated with this particular file type. +//////////////////////////////////////////////////////////////////// +int PNMFileTypeTGA:: +get_num_extensions() const { + return num_extensions; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::get_extension +// Access: Public, Virtual +// Description: Returns the nth possible filename extension +// associated with this particular file type, without a +// leading dot. +//////////////////////////////////////////////////////////////////// +string PNMFileTypeTGA:: +get_extension(int n) const { + nassertr(n >= 0 && n < num_extensions, string()); + return extensions[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::get_suggested_extension +// Access: Public, Virtual +// Description: Returns a suitable filename extension (without a +// leading dot) to suggest for files of this type, or +// empty string if no suggestions are available. +//////////////////////////////////////////////////////////////////// +string PNMFileTypeTGA:: +get_suggested_extension() const { + return "tga"; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::make_reader +// Access: Public, Virtual +// Description: Allocates and returns a new PNMReader suitable for +// reading from this file type, if possible. If reading +// from this file type is not supported, returns NULL. +//////////////////////////////////////////////////////////////////// +PNMReader *PNMFileTypeTGA:: +make_reader(FILE *file, bool owns_file, const string &magic_number) { + init_pnm(); + return new Reader(this, file, owns_file, magic_number); +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::make_writer +// Access: Public, Virtual +// Description: Allocates and returns a new PNMWriter suitable for +// reading from this file type, if possible. If writing +// files of this type is not supported, returns NULL. +//////////////////////////////////////////////////////////////////// +PNMWriter *PNMFileTypeTGA:: +make_writer(FILE *file, bool owns_file) { + init_pnm(); + return new Writer(this, file, owns_file); +} + + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::Reader::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeTGA::Reader:: +Reader(PNMFileType *type, FILE *file, bool owns_file, string magic_number) : + PNMReader(type, file, owns_file) +{ + tga_head = new ImageHeader; + RLE_count = 0; + RLE_flag = 0; + + /* Read the Targa file header. */ + readtga( file, tga_head, magic_number ); + /* + { + pm_message( "IDLength = %d", (int) tga_head->IDLength ); + pm_message( "CoMapType = %d", (int) tga_head->CoMapType ); + pm_message( "ImgType = %d", (int) tga_head->ImgType ); + pm_message( "Index_lo = %d", (int) tga_head->Index_lo ); + pm_message( "Index_hi = %d", (int) tga_head->Index_hi ); + pm_message( "Length_lo = %d", (int) tga_head->Length_lo ); + pm_message( "Length_hi = %d", (int) tga_head->Length_hi ); + pm_message( "CoSize = %d", (int) tga_head->CoSize ); + pm_message( "X_org_lo = %d", (int) tga_head->X_org_lo ); + pm_message( "X_org_hi = %d", (int) tga_head->X_org_hi ); + pm_message( "Y_org_lo = %d", (int) tga_head->Y_org_lo ); + pm_message( "Y_org_hi = %d", (int) tga_head->Y_org_hi ); + pm_message( "Width_lo = %d", (int) tga_head->Width_lo ); + pm_message( "Width_hi = %d", (int) tga_head->Width_hi ); + pm_message( "Height_lo = %d", (int) tga_head->Height_lo ); + pm_message( "Height_hi = %d", (int) tga_head->Height_hi ); + pm_message( "PixelSize = %d", (int) tga_head->PixelSize ); + pm_message( "AttBits = %d", (int) tga_head->AttBits ); + pm_message( "Rsrvd = %d", (int) tga_head->Rsrvd ); + pm_message( "OrgBit = %d", (int) tga_head->OrgBit ); + pm_message( "IntrLve = %d", (int) tga_head->IntrLve ); + } + */ + rows = ( (int) tga_head->Height_lo ) + ( (int) tga_head->Height_hi ) * 256; + cols = ( (int) tga_head->Width_lo ) + ( (int) tga_head->Width_hi ) * 256; + + switch ( tga_head->ImgType ) + { + case TGA_Map: + case TGA_RGB: + case TGA_Mono: + case TGA_RLEMap: + case TGA_RLERGB: + case TGA_RLEMono: + break; + + default: + pm_error( "unknown Targa image type %d", tga_head->ImgType ); + } + + int size; + + if ( tga_head->ImgType == TGA_Map || + tga_head->ImgType == TGA_RLEMap || + tga_head->ImgType == TGA_CompMap || + tga_head->ImgType == TGA_CompMap4 ) + { /* Color-mapped image */ + if ( tga_head->CoMapType != 1 ) + pm_error( + "mapped image (type %d) with color map type != 1", + tga_head->ImgType ); + mapped = 1; + /* Figure maxval from CoSize. */ + size = tga_head->CoSize; + } + else + { /* Not colormap, so figure maxval from PixelSize. */ + mapped = 0; + size = tga_head->PixelSize; + } + + switch ( size ) { + case 8: + _num_channels = 1; + _maxval = 255; + break; + + case 24: + _num_channels = 3; + _maxval = 255; + break; + + case 32: + _num_channels = 4; + _maxval = 255; + break; + + case 15: + case 16: + _num_channels = 3; + _maxval = 31; + break; + + default: + pm_error("unknown pixel size - %d", size ); + } + + /* If required, read the color map information. */ + if ( tga_head->CoMapType != 0 ) + { + unsigned int temp1, temp2; + temp1 = tga_head->Index_lo + tga_head->Index_hi * 256; + temp2 = tga_head->Length_lo + tga_head->Length_hi * 256; + if ( ( temp1 + temp2 + 1 ) >= TGA_MAXCOLORS ) + pm_error( "too many colors - %d", ( temp1 + temp2 + 1 ) ); + for ( unsigned int i = temp1; i < ( temp1 + temp2 ); ++i ) + get_map_entry( file, &ColorMap[i], (int) tga_head->CoSize, + &AlphaMap[i]); + } + + /* Check run-length encoding. */ + if ( tga_head->ImgType == TGA_RLEMap || + tga_head->ImgType == TGA_RLERGB || + tga_head->ImgType == TGA_RLEMono ) + rlencoded = 1; + else + rlencoded = 0; + + _x_size = cols; + _y_size = rows; + _num_channels = 3; + +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::Reader::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeTGA::Reader:: +~Reader() { + delete tga_head; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::Reader::read_data +// Access: Public, Virtual +// Description: Reads in an entire image all at once, storing it in +// the pre-allocated _x_size * _y_size array and alpha +// pointers. (If the image type has no alpha channel, +// alpha is ignored.) Returns the number of rows +// correctly read. +// +// Derived classes need not override this if they +// instead provide supports_read_row() and read_row(), +// below. +//////////////////////////////////////////////////////////////////// +int PNMFileTypeTGA::Reader:: +read_data(xel *array, xelval *alpha) { + int truerow = 0; + int baserow = 0; + for ( int row = 0; row < rows; ++row ) + { + int realrow = truerow; + if ( tga_head->OrgBit == 0 ) + realrow = rows - realrow - 1; + + for ( int col = 0; col < cols; ++col ) + get_pixel( _file, &(array[realrow * cols + col]), + (int) tga_head->PixelSize, + &(alpha[realrow * cols + col]) ); + if ( tga_head->IntrLve == TGA_IL_Four ) + truerow += 4; + else if ( tga_head->IntrLve == TGA_IL_Two ) + truerow += 2; + else + ++truerow; + if ( truerow >= rows ) + truerow = ++baserow; + } + + return rows; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::Writer::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeTGA::Writer:: +Writer(PNMFileType *type, FILE *file, bool owns_file) : + PNMWriter(type, file, owns_file) +{ + tgaHeader = new ImageHeader; + chv = (colorhist_vector)0; + cht = (colorhash_table)0; + runlength = (int*)0; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::Writer::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeTGA::Writer:: +~Writer() { + delete tgaHeader; + + if (chv != (colorhist_vector)0) { + ppm_freecolorhist(chv); + } + if (cht != (colorhash_table)0) { + ppm_freecolorhash(cht); + } + if (runlength != (int *)0) { + pm_freerow((char *)runlength); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeBMP::Writer::write_data +// Access: Public, Virtual +// Description: Writes out an entire image all at once, including the +// header, based on the image data stored in the given +// _x_size * _y_size array and alpha pointers. (If the +// image type has no alpha channel, alpha is ignored.) +// Returns the number of rows correctly written. +// +// It is the user's responsibility to fill in the header +// data via calls to set_x_size(), set_num_channels(), +// etc., or copy_header_from(), before calling +// write_data(). +// +// It is important to delete the PNMWriter class after +// successfully writing the data. Failing to do this +// may result in some data not getting flushed! +// +// Derived classes need not override this if they +// instead provide supports_streaming() and write_row(), +// below. +//////////////////////////////////////////////////////////////////// +int PNMFileTypeTGA::Writer:: +write_data(xel *array, xelval *) { + // We don't presently support writing 4-channel tga files (since + // ppmtotga doesn't support this). + rle_flag = tga_rle; + + int row, col; + int i; + pixel* pP; + + cols = _x_size; + rows = _y_size; + + if (is_grayscale() && tga_grayscale) { + // We allow grayscale TGA files, and this is a grayscale image, so... + tgaHeader->ImgType = TGA_Mono; + + // There's no real point in colormapping a grayscale image. + pnmimage_tga_cat.info() + << "writing grayscale.\n"; + + } else { + // This will be an RGB image. + tgaHeader->ImgType = TGA_RGB; + + if (tga_colormap) { + // It may even be colormapped if there are few enough colors. + pnmimage_tga_cat.info() + << "computing colormap...\n"; + chv = ppm_computecolorhist(&array, cols * rows, 1, TGA_MAXCOLORS, &ncolors ); + if ( chv == (colorhist_vector) 0 ) { + pnmimage_tga_cat.info() + << "too many colors, writing RGB.\n"; + } else { + pnmimage_tga_cat.info() + << ncolors << " colors found.\n"; + tgaHeader->ImgType = TGA_Map; + } + } + } + + if ( rle_flag ) + { + switch ( tgaHeader->ImgType ) + { + case TGA_Mono: + tgaHeader->ImgType = TGA_RLEMono; + break; + case TGA_Map: + tgaHeader->ImgType = TGA_RLEMap; + break; + case TGA_RGB: + tgaHeader->ImgType = TGA_RLERGB; + break; + default: + pm_error( "can't happen" ); + } + runlength = (int*) pm_allocrow( cols, sizeof(int) ); + } + + tgaHeader->IDLength = 0; + tgaHeader->Index_lo = 0; + tgaHeader->Index_hi = 0; + if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap ) + { + /* Make a hash table for fast color lookup. */ + cht = ppm_colorhisttocolorhash( chv, ncolors ); + + tgaHeader->CoMapType = 1; + tgaHeader->Length_lo = ncolors % 256; + tgaHeader->Length_hi = ncolors / 256; + tgaHeader->CoSize = 24; + } + else + { + tgaHeader->CoMapType = 0; + tgaHeader->Length_lo = 0; + tgaHeader->Length_hi = 0; + tgaHeader->CoSize = 0; + } + if ( tgaHeader->ImgType == TGA_RGB || tgaHeader->ImgType == TGA_RLERGB ) + tgaHeader->PixelSize = 24; + else + tgaHeader->PixelSize = 8; + tgaHeader->X_org_lo = tgaHeader->X_org_hi = 0; + tgaHeader->Y_org_lo = tgaHeader->Y_org_hi = 0; + tgaHeader->Width_lo = cols % 256; + tgaHeader->Width_hi = cols / 256; + tgaHeader->Height_lo = rows % 256; + tgaHeader->Height_hi = rows / 256; + tgaHeader->AttBits = 0; + tgaHeader->Rsrvd = 0; + tgaHeader->IntrLve = 0; + tgaHeader->OrgBit = 0; + + /* Write out the Targa header. */ + writetga( tgaHeader, (char*) 0 ); + + if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap ) + { + /* Write out the Targa colormap. */ + for ( i = 0; i < ncolors; ++i ) + put_map_entry( &chv[i].color, tgaHeader->CoSize, _maxval ); + } + + /* Write out the pixels */ + for ( row = 0; row < rows; ++row ) + { + int realrow = row; + if ( tgaHeader->OrgBit == 0 ) + realrow = rows - realrow - 1; + if ( rle_flag ) + { + compute_runlengths( cols, &array[realrow * cols], runlength ); + for ( col = 0; col < cols; ) + { + if ( runlength[col] > 0 ) + { + fputc( 0x80 + runlength[col] - 1, _file ); + put_pixel(&(array[realrow * cols + col]), + tgaHeader->ImgType, _maxval, cht ); + col += runlength[col]; + } + else if ( runlength[col] < 0 ) + { + fputc( -runlength[col] - 1, _file ); + for ( i = 0; i < -runlength[col]; ++i ) + put_pixel(&(array[realrow * cols + (col + i)]), + tgaHeader->ImgType, _maxval, cht ); + col += -runlength[col]; + } + else + pm_error( "can't happen" ); + } + } + else + { + for ( col = 0, pP = &array[realrow * cols]; col < cols; ++col, ++pP ) + put_pixel( pP, tgaHeader->ImgType, _maxval, cht ); + } + } + + return rows; +} + + + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::register_with_read_factory +// Access: Public, Static +// Description: Registers the current object as something that can be +// read from a Bam file. +//////////////////////////////////////////////////////////////////// +void PNMFileTypeTGA:: +register_with_read_factory() { + BamReader::get_factory()-> + register_factory(get_class_type(), make_PNMFileTypeTGA); +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTGA::make_PNMFileTypeTGA +// Access: Protected, Static +// Description: This method is called by the BamReader when an object +// of this type is encountered in a Bam file; it should +// allocate and return a new object with all the data +// read. +// +// In the case of the PNMFileType objects, since these +// objects are all shared, we just pull the object from +// the registry. +//////////////////////////////////////////////////////////////////// +TypedWriteable *PNMFileTypeTGA:: +make_PNMFileTypeTGA(const FactoryParams ¶ms) { + return PNMFileTypeRegistry::get_ptr()->get_type_by_handle(get_class_type()); +} + +void PNMFileTypeTGA::Reader:: +readtga( FILE *ifp, struct ImageHeader *tgaP, const string &magic_number ) { + unsigned char flags; + ImageIDField junk; + + if (magic_number.length() > 0) { + tgaP->IDLength = (unsigned char)magic_number[0]; + } else { + tgaP->IDLength = getbyte( ifp ); + } + if (magic_number.length() > 1) { + tgaP->CoMapType = (unsigned char)magic_number[1]; + } else { + tgaP->CoMapType = getbyte( ifp ); + } + if (magic_number.length() > 2) { + tgaP->ImgType = (unsigned char)magic_number[2]; + } else { + tgaP->ImgType = getbyte( ifp ); + } + if (magic_number.length() > 3) { + tgaP->Index_lo = (unsigned char)magic_number[3]; + } else { + tgaP->Index_lo = getbyte( ifp ); + } + tgaP->Index_hi = getbyte( ifp ); + tgaP->Length_lo = getbyte( ifp ); + tgaP->Length_hi = getbyte( ifp ); + tgaP->CoSize = getbyte( ifp ); + tgaP->X_org_lo = getbyte( ifp ); + tgaP->X_org_hi = getbyte( ifp ); + tgaP->Y_org_lo = getbyte( ifp ); + tgaP->Y_org_hi = getbyte( ifp ); + tgaP->Width_lo = getbyte( ifp ); + tgaP->Width_hi = getbyte( ifp ); + tgaP->Height_lo = getbyte( ifp ); + tgaP->Height_hi = getbyte( ifp ); + tgaP->PixelSize = getbyte( ifp ); + flags = getbyte( ifp ); + tgaP->AttBits = flags & 0xf; + tgaP->Rsrvd = ( flags & 0x10 ) >> 4; + tgaP->OrgBit = ( flags & 0x20 ) >> 5; + tgaP->IntrLve = ( flags & 0xc0 ) >> 6; + + if ( tgaP->IDLength != 0 ) + fread( junk, 1, (int) tgaP->IDLength, ifp ); + } + +void PNMFileTypeTGA::Reader:: +get_map_entry( FILE *ifp, pixel *Value, int Size, gray *Alpha ) { + unsigned char j, k, r, g, b, a; + + /* Read appropriate number of bytes, break into rgb & put in map. */ + switch ( Size ) + { + case 8: /* Grey scale, read and triplicate. */ + r = g = b = getbyte( ifp ); + a = 0; + break; + + case 16: /* 5 bits each of red green and blue. */ + case 15: /* Watch for byte order. */ + j = getbyte( ifp ); + k = getbyte( ifp ); + r = ( k & 0x7C ) >> 2; + g = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 ); + b = j & 0x1F; + a = 0; + break; + + case 32: /* 8 bits each of blue, green, red, and alpha */ + case 24: /* 8 bits each of blue green and red. */ + b = getbyte( ifp ); + g = getbyte( ifp ); + r = getbyte( ifp ); + if ( Size == 32 ) + a = getbyte( ifp ); + else + a = 0; + break; + + default: + pm_error( "unknown colormap pixel size (#2) - %d", Size ); + } + PPM_ASSIGN( *Value, r, g, b ); + *Alpha = a; + } + + + +void PNMFileTypeTGA::Reader:: +get_pixel( FILE *ifp, pixel *dest, int Size, gray *alpha_p) { + static pixval Red, Grn, Blu; + static pixval Alpha; + unsigned char j, k; + static unsigned int l; + + /* Check if run length encoded. */ + if ( rlencoded ) + { + if ( RLE_count == 0 ) + { /* Have to restart run. */ + unsigned char i; + i = getbyte( ifp ); + RLE_flag = ( i & 0x80 ); + if ( RLE_flag == 0 ) + /* Stream of unencoded pixels. */ + RLE_count = i + 1; + else + /* Single pixel replicated. */ + RLE_count = i - 127; + /* Decrement count & get pixel. */ + --RLE_count; + } + else + { /* Have already read count & (at least) first pixel. */ + --RLE_count; + if ( RLE_flag != 0 ) + /* Replicated pixels. */ + goto PixEncode; + } + } + /* Read appropriate number of bytes, break into RGB. */ + switch ( Size ) + { + case 8: /* Grey scale, read and triplicate. */ + Red = Grn = Blu = l = getbyte( ifp ); + Alpha = 0; + break; + + case 16: /* 5 bits each of red green and blue. */ + case 15: /* Watch byte order. */ + j = getbyte( ifp ); + k = getbyte( ifp ); + l = ( (unsigned int) k << 8 ) + j; + Red = ( k & 0x7C ) >> 2; + Grn = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 ); + Blu = j & 0x1F; + Alpha = 0; + break; + + case 32: /* 8 bits each of blue, green, red, and alpha */ + case 24: /* 8 bits each of blue, green, and red. */ + Blu = getbyte( ifp ); + Grn = getbyte( ifp ); + Red = getbyte( ifp ); + if ( Size == 32 ) + Alpha = getbyte( ifp ); + else + Alpha = 0; + l = 0; + break; + + default: + pm_error( "unknown pixel size (#2) - %d", Size ); + } + +PixEncode: + if ( mapped ) { + *dest = ColorMap[l]; + if (has_alpha()) { + *alpha_p = AlphaMap[l]; + } + } else { + PPM_ASSIGN( *dest, Red, Grn, Blu ); + if (has_alpha()) { + *alpha_p = Alpha; + } + } + } + + +unsigned char PNMFileTypeTGA::Reader:: +getbyte( FILE *ifp ) { + unsigned char c; + + if ( fread( (char*) &c, 1, 1, ifp ) != 1 ) + pm_error( "EOF / read error" ); + + return c; + } + +void PNMFileTypeTGA::Writer:: +writetga( struct ImageHeader *tgaP, char *id ) + { + unsigned char flags; + + fputc( tgaP->IDLength, _file ); + fputc( tgaP->CoMapType, _file ); + fputc( tgaP->ImgType, _file ); + fputc( tgaP->Index_lo, _file ); + fputc( tgaP->Index_hi, _file ); + fputc( tgaP->Length_lo, _file ); + fputc( tgaP->Length_hi, _file ); + fputc( tgaP->CoSize, _file ); + fputc( tgaP->X_org_lo, _file ); + fputc( tgaP->X_org_hi, _file ); + fputc( tgaP->Y_org_lo, _file ); + fputc( tgaP->Y_org_hi, _file ); + fputc( tgaP->Width_lo, _file ); + fputc( tgaP->Width_hi, _file ); + fputc( tgaP->Height_lo, _file ); + fputc( tgaP->Height_hi, _file ); + fputc( tgaP->PixelSize, _file ); + flags = ( tgaP->AttBits & 0xf ) | ( ( tgaP->Rsrvd & 0x1 ) << 4 ) | + ( ( tgaP->OrgBit & 0x1 ) << 5 ) | ( ( tgaP->OrgBit & 0x3 ) << 6 ); + fputc( flags, _file ); + if ( tgaP->IDLength ) + fwrite( id, 1, (int) tgaP->IDLength, _file ); + } + +void PNMFileTypeTGA::Writer:: +put_map_entry( pixel* valueP, int size, pixval maxval ) + { + int j; + pixel p; + + switch ( size ) + { + case 8: /* Grey scale. */ + put_mono( valueP, maxval ); + break; + + case 16: /* 5 bits each of red green and blue. */ + case 15: /* Watch for byte order. */ + PPM_DEPTH( p, *valueP, maxval, 31 ); + j = (int) PPM_GETB( p ) | ( (int) PPM_GETG( p ) << 5 ) | + ( (int) PPM_GETR( p ) << 10 ); + fputc( j % 256, _file ); + fputc( j / 256, _file ); + break; + + case 32: + case 24: /* 8 bits each of blue green and red. */ + put_rgb( valueP, maxval ); + break; + + default: + pm_error( "unknown colormap pixel size (#2) - %d", size ); + } + } + +void PNMFileTypeTGA::Writer:: +compute_runlengths( int cols, pixel *pixelrow, int *runlength ) + { + int col, start; + + /* Initialize all run lengths to 0. (This is just an error check.) */ + for ( col = 0; col < cols; ++col ) + runlength[col] = 0; + + /* Find runs of identical pixels. */ + for ( col = 0; col < cols; ) + { + start = col; + do { + ++col; + } + while ( col < cols && + col - start < 128 && + PPM_EQUAL( pixelrow[col], pixelrow[start] ) ); + runlength[start] = col - start; + } + + /* Now look for runs of length-1 runs, and turn them into negative runs. */ + for ( col = 0; col < cols; ) + { + if ( runlength[col] == 1 ) + { + start = col; + while ( col < cols && + col - start < 128 && + runlength[col] == 1 ) + { + runlength[col] = 0; + ++col; + } + runlength[start] = - ( col - start ); + } + else + col += runlength[col]; + } + } + +void PNMFileTypeTGA::Writer:: +put_pixel( pixel* pP, int imgtype, pixval maxval, colorhash_table cht ) + { + switch ( imgtype ) + { + case TGA_Mono: + case TGA_RLEMono: + put_mono( pP, maxval ); + break; + case TGA_Map: + case TGA_RLEMap: + put_map( pP, cht ); + break; + case TGA_RGB: + case TGA_RLERGB: + put_rgb( pP, maxval ); + break; + default: + pm_error( "can't happen" ); + } + } + +void PNMFileTypeTGA::Writer:: +put_mono( pixel* pP, pixval maxval ) + { + pixel p; + PPM_DEPTH( p, *pP, maxval, (pixval) 255 ); + fputc( PPM_GETB( p ), _file ); + } + +void PNMFileTypeTGA::Writer:: +put_map( pixel *pP, colorhash_table cht ) + { + fputc( ppm_lookupcolor( cht, pP ), _file ); + } + +void PNMFileTypeTGA::Writer:: +put_rgb( pixel* pP, pixval maxval ) { + pixel p; + PPM_DEPTH( p, *pP, maxval, (pixval) 255 ); + fputc( PPM_GETB( p ), _file ); + if (is_grayscale()) { + fputc( PPM_GETB( p ), _file ); + fputc( PPM_GETB( p ), _file ); + } else { + fputc( PPM_GETG( p ), _file ); + fputc( PPM_GETR( p ), _file ); + } +} diff --git a/panda/src/pnmimagetypes/pnmFileTypeTGA.h b/panda/src/pnmimagetypes/pnmFileTypeTGA.h new file mode 100644 index 0000000000..aab5fc29f5 --- /dev/null +++ b/panda/src/pnmimagetypes/pnmFileTypeTGA.h @@ -0,0 +1,118 @@ +// Filename: pnmFileTypeTGA.h +// Created by: drose (27Apr01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef PNMFILETYPETGA_H +#define PNMFILETYPETGA_H + +#include + +#include +#include +#include + +extern "C" { +#include +} + +struct ImageHeader; + + +/* Max number of colors allowed for colormapped output. */ +#define TGA_MAXCOLORS 256 + +//////////////////////////////////////////////////////////////////// +// Class : PNMFileTypeTGA +// Description : For reading and writing Targa image files. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PNMFileTypeTGA : public PNMFileType { +public: + PNMFileTypeTGA(); + + virtual string get_name() const; + + virtual int get_num_extensions() const; + virtual string get_extension(int n) const; + virtual string get_suggested_extension() const; + + virtual PNMReader *make_reader(FILE *file, bool owns_file = true, + const string &magic_number = string()); + virtual PNMWriter *make_writer(FILE *file, bool owns_file = true); + +public: + class Reader : public PNMReader { + public: + Reader(PNMFileType *type, FILE *file, bool owns_file, string magic_number); + virtual ~Reader(); + + virtual int read_data(xel *array, xelval *alpha); + + private: + void readtga ( FILE* ifp, struct ImageHeader* tgaP, const string &magic_number ); + void get_map_entry ( FILE* ifp, pixel* Value, int Size, + gray* Alpha); + void get_pixel ( FILE* ifp, pixel* dest, int Size, gray* alpha_p); + unsigned char getbyte ( FILE* ifp ); + + int rows, cols, rlencoded, mapped; + struct ImageHeader *tga_head; + pixel ColorMap[TGA_MAXCOLORS]; + gray AlphaMap[TGA_MAXCOLORS]; + int RLE_count, RLE_flag; + }; + + class Writer : public PNMWriter { + public: + Writer(PNMFileType *type, FILE *file, bool owns_file); + virtual ~Writer(); + + virtual int write_data(xel *array, xelval *alpha); + + private: + void writetga ( struct ImageHeader* tgaP, char* id ); + void put_map_entry ( pixel* valueP, int size, pixval maxval ); + void compute_runlengths ( int cols, pixel* pixelrow, int* runlength ); + void put_pixel ( pixel* pP, int imgtype, pixval maxval, colorhash_table cht ); + void put_mono ( pixel* pP, pixval maxval ); + void put_map ( pixel* pP, colorhash_table cht ); + void put_rgb ( pixel* pP, pixval maxval ); + + int rle_flag; + int rows, cols; + struct ImageHeader *tgaHeader; + colorhist_vector chv; + colorhash_table cht; + int ncolors; + int *runlength; + }; + + + // The TypedWriteable interface follows. +public: + static void register_with_read_factory(); + +protected: + static TypedWriteable *make_PNMFileTypeTGA(const FactoryParams ¶ms); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + PNMFileType::init_type(); + register_type(_type_handle, "PNMFileTypeTGA", + PNMFileType::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#endif + + diff --git a/panda/src/pnmimagetypes/pnmFileTypeYUV.h b/panda/src/pnmimagetypes/pnmFileTypeYUV.h index c850e21f15..b0c03e3260 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeYUV.h +++ b/panda/src/pnmimagetypes/pnmFileTypeYUV.h @@ -14,7 +14,7 @@ //////////////////////////////////////////////////////////////////// // Class : PNMFileTypeYUV -// Description : For reading and Abekas YUV files. +// Description : For reading and writing Abekas YUV files. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA PNMFileTypeYUV : public PNMFileType { public: