diff --git a/panda/src/framework/framework.cxx b/panda/src/framework/framework.cxx index f73a06b0b0..42d6493ba5 100644 --- a/panda/src/framework/framework.cxx +++ b/panda/src/framework/framework.cxx @@ -1067,7 +1067,7 @@ int framework_main(int argc, char *argv[]) { RenderRelation *arc = new RenderRelation(root, geomnode, 10); first_arc = arc; - Texture *tex = TexturePool::load_texture("rock-floor.rgb"); + Texture *tex = TexturePool::load_texture("rock-floor.jpg"); if (tex != (Texture *)NULL) { tex->set_minfilter(Texture::FT_linear); tex->set_magfilter(Texture::FT_linear); diff --git a/panda/src/pnmimagetypes/Sources.pp b/panda/src/pnmimagetypes/Sources.pp index 9d5a443edd..db9c94c634 100644 --- a/panda/src/pnmimagetypes/Sources.pp +++ b/panda/src/pnmimagetypes/Sources.pp @@ -1,4 +1,5 @@ #define OTHER_LIBS interrogatedb:c dconfig:c dtoolutil:c dtoolbase:c dtool:m +#define USE_JPEG yes #begin lib_target #define TARGET pnmimagetypes @@ -17,5 +18,8 @@ pnmFileTypeYUV.cxx pnmFileTypeYUV.h \ color.c colrops.c resolu.c header.c + #define IF_JPEG_SOURCES \ + pnmFileTypeJPG.cxx pnmFileTypeJPGReader.cxx pnmFileTypeJPGWriter.cxx + #end lib_target diff --git a/panda/src/pnmimagetypes/config_pnmimagetypes.cxx b/panda/src/pnmimagetypes/config_pnmimagetypes.cxx index 978417f8d9..5a5a351890 100644 --- a/panda/src/pnmimagetypes/config_pnmimagetypes.cxx +++ b/panda/src/pnmimagetypes/config_pnmimagetypes.cxx @@ -13,6 +13,9 @@ #include "pnmFileTypeIMG.h" #include "pnmFileTypeSoftImage.h" #include "pnmFileTypeBMP.h" +#ifdef HAVE_JPEG + #include "pnmFileTypeJPG.h" +#endif #include "sgi.h" #include @@ -30,6 +33,7 @@ NotifyCategoryDef(pnmimage_yuv, pnmimage_cat); NotifyCategoryDef(pnmimage_img, pnmimage_cat); NotifyCategoryDef(pnmimage_soft, pnmimage_cat); NotifyCategoryDef(pnmimage_bmp, pnmimage_cat); +NotifyCategoryDef(pnmimage_jpg, pnmimage_cat); int sgi_storage_type = STORAGE_RLE; const string sgi_imagename = config_pnmimagetypes.GetString("sgi-imagename", ""); @@ -61,6 +65,9 @@ ConfigureFn(config_pnmimagetypes) { PNMFileTypeIMG::init_type(); PNMFileTypeSoftImage::init_type(); PNMFileTypeBMP::init_type(); +#ifdef HAVE_JPEG + PNMFileTypeJPG::init_type(); +#endif string sgi_storage_type_str = config_pnmimagetypes.GetString("sgi-storage-type", "rle"); @@ -97,4 +104,7 @@ ConfigureFn(config_pnmimagetypes) { tr->register_type(new PNMFileTypeIMG); tr->register_type(new PNMFileTypeSoftImage); tr->register_type(new PNMFileTypeBMP); +#ifdef HAVE_JPEG + tr->register_type(new PNMFileTypeJPG); +#endif } diff --git a/panda/src/pnmimagetypes/config_pnmimagetypes.h b/panda/src/pnmimagetypes/config_pnmimagetypes.h index 0209cb3f0b..22099db0ee 100644 --- a/panda/src/pnmimagetypes/config_pnmimagetypes.h +++ b/panda/src/pnmimagetypes/config_pnmimagetypes.h @@ -18,6 +18,7 @@ NotifyCategoryDecl(pnmimage_yuv, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_img, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_soft, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pnmimage_bmp, EXPCL_PANDA, EXPTP_PANDA); +NotifyCategoryDecl(pnmimage_jpg, EXPCL_PANDA, EXPTP_PANDA); extern int sgi_storage_type; extern const string sgi_imagename; diff --git a/panda/src/pnmimagetypes/pnmFileTypeJPG.cxx b/panda/src/pnmimagetypes/pnmFileTypeJPG.cxx new file mode 100644 index 0000000000..5b5a2b8ed8 --- /dev/null +++ b/panda/src/pnmimagetypes/pnmFileTypeJPG.cxx @@ -0,0 +1,120 @@ +// Filename: pnmFileTypeJPG.cxx +// Created by: mike (19Jun00) +// +//////////////////////////////////////////////////////////////////// + +#include "pnmFileTypeJPG.h" +#include "config_pnmimagetypes.h" + +static const char * const extensions[] = { + "jpg" +}; +static const int num_extensions = sizeof(extensions) / sizeof(const char *); + +TypeHandle PNMFileTypeJPG::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeJPG:: +PNMFileTypeJPG() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::get_name +// Access: Public, Virtual +// Description: Returns a few words describing the file type. +//////////////////////////////////////////////////////////////////// +string PNMFileTypeJPG:: +get_name() const { + return "Jpeg"; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::get_num_extensions +// Access: Public, Virtual +// Description: Returns the number of different possible filename +// extensions associated with this particular file type. +//////////////////////////////////////////////////////////////////// +int PNMFileTypeJPG:: +get_num_extensions() const { + return num_extensions; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::get_extension +// Access: Public, Virtual +// Description: Returns the nth possible filename extension +// associated with this particular file type, without a +// leading dot. +//////////////////////////////////////////////////////////////////// +string PNMFileTypeJPG:: +get_extension(int n) const { + nassertr(n >= 0 && n < num_extensions, string()); + return extensions[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::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 PNMFileTypeJPG:: +get_suggested_extension() const { + return "bmp"; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::has_magic_number +// Access: Public, Virtual +// Description: Returns true if this particular file type uses a +// magic number to identify it, false otherwise. +//////////////////////////////////////////////////////////////////// +bool PNMFileTypeJPG:: +has_magic_number() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::matches_magic_number +// Access: Public, Virtual +// Description: Returns true if the indicated "magic number" byte +// stream (the initial few bytes read from the file) +// matches this particular file type, false otherwise. +//////////////////////////////////////////////////////////////////// +bool PNMFileTypeJPG:: +matches_magic_number(const string &magic_number) const { + nassertr(magic_number.size() >= 2, false); + return (magic_number.substr(0, 2) == "BM"); +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::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 *PNMFileTypeJPG:: +make_reader(FILE *file, bool owns_file, const string &magic_number) { + init_pnm(); + return new Reader(this, file, owns_file, magic_number); +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::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 *PNMFileTypeJPG:: +make_writer(FILE *file, bool owns_file) { + init_pnm(); + return new Writer(this, file, owns_file); +} + diff --git a/panda/src/pnmimagetypes/pnmFileTypeJPG.h b/panda/src/pnmimagetypes/pnmFileTypeJPG.h new file mode 100644 index 0000000000..ce35b95193 --- /dev/null +++ b/panda/src/pnmimagetypes/pnmFileTypeJPG.h @@ -0,0 +1,91 @@ +// Filename: pnmFileTypeJPG.h +// Created by: mike (17Jun00) +// +//////////////////////////////////////////////////////////////////// + +#ifndef PNMFILETYPEJPG_H +#define PNMFILETYPEJPG_H + +#include + +#include +#include +#include + +extern "C" { +#include +} + +//////////////////////////////////////////////////////////////////// +// Class : PNMFileTypeJPG +// Description : For reading and writing Jpeg files. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PNMFileTypeJPG : public PNMFileType { +public: + PNMFileTypeJPG(); + + 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 bool has_magic_number() const; + virtual bool matches_magic_number(const string &magic_number) 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 int read_data(xel *array, xelval *alpha); + + private: + struct jpeg_decompress_struct cinfo; + FILE *_my_file; + unsigned long pos; + + unsigned long offBits; + + unsigned short cBitCount; + int indexed; + int classv; + + pixval R[256]; /* reds */ + pixval G[256]; /* greens */ + pixval B[256]; /* blues */ + }; + + class Writer : public PNMWriter { + public: + Writer(PNMFileType *type, FILE *file, bool owns_file); + + virtual int write_data(xel *array, xelval *alpha); + }; + + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + PNMFileType::init_type(); + register_type(_type_handle, "PNMFileTypeJPG", + 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/pnmFileTypeJPGReader.cxx b/panda/src/pnmimagetypes/pnmFileTypeJPGReader.cxx new file mode 100644 index 0000000000..2fb0619d44 --- /dev/null +++ b/panda/src/pnmimagetypes/pnmFileTypeJPGReader.cxx @@ -0,0 +1,181 @@ +// Filename: pnmFileTypeJPGReader.cxx +// Created by: mike (19Jun00) +// +//////////////////////////////////////////////////////////////////// + +#include "pnmFileTypeJPG.h" +#include "config_pnmimagetypes.h" +#include + +extern "C" { +#include +#include +} + +struct my_error_mgr { + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +typedef struct my_error_mgr * my_error_ptr; + +METHODDEF(void) my_error_exit(j_common_ptr cinfo) { + my_error_ptr myerr = (my_error_ptr) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(myerr->setjmp_buffer, 1); +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::Reader::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeJPG::Reader:: +Reader(PNMFileType *type, FILE *file, bool owns_file, string magic_number) : + PNMReader(type, file, owns_file) +{ + // Put the magic number bytes back into the file + fseek(file, 0, SEEK_SET); + + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(file); + return; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, file); + + /* Step 3: read file parameters with jpeg_read_header() */ + + jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + _num_channels = cinfo.output_components; + _x_size = (int)cinfo.output_width; + _y_size = (int)cinfo.output_height; + _my_file = file; +} + + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::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 PNMFileTypeJPG::Reader:: +read_data(xel *array, xelval *) { + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + nassertr(cinfo.output_components == 1 || cinfo.output_components == 3, 0); + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + /* Make a one-row-high sample array that will go away when done with image */ + + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + //put_scanline_someplace(buffer[0], row_stride); + int x = 0; + for (int i = 0; i < cinfo.output_width; i += cinfo.output_components) { + if (cinfo.output_components == 1) { + xelval val = (uchar)buffer[i]; + PNM_ASSIGN1(array[x++], val); + } else { + xelval red, grn, blu; + red = (uchar)buffer[i]; + grn = (uchar)buffer[i+1]; + blu = (uchar)buffer[i+2]; + PPM_ASSIGN(array[x++], red, grn, blu); + } + } + } + + /* Step 7: Finish decompression */ + + jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(_my_file); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + return _y_size; +} diff --git a/panda/src/pnmimagetypes/pnmFileTypeJPGWriter.cxx b/panda/src/pnmimagetypes/pnmFileTypeJPGWriter.cxx new file mode 100644 index 0000000000..60884341e2 --- /dev/null +++ b/panda/src/pnmimagetypes/pnmFileTypeJPGWriter.cxx @@ -0,0 +1,56 @@ +// Filename: pnmFileTypeJPGWriter.cxx +// Created by: mike (19Jun00) +// +//////////////////////////////////////////////////////////////////// + +#include "pnmFileTypeJPG.h" +#include "config_pnmimagetypes.h" + +#include +#include + +extern "C" { +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::Writer::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PNMFileTypeJPG::Writer:: +Writer(PNMFileType *type, FILE *file, bool owns_file) : + PNMWriter(type, file, owns_file) +{ +} + + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::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 PNMFileTypeJPG::Writer:: +write_data(xel *array, xelval *) { + if (_y_size<=0 || _x_size<=0) { + return 0; + } + + return _y_size; +}