diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 0ff0efa55e..41ea36880f 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -49,9 +49,9 @@ #include "pgTop.h" #include "geomNode.h" #include "texture.h" -#include "pnmImage.h" +#include "videoTexture.h" +#include "texturePool.h" #include "loaderFileTypeRegistry.h" -#include "pnmFileTypeRegistry.h" #include "pnmImage.h" #include "virtualFileSystem.h" @@ -562,12 +562,10 @@ load_model(const NodePath &parent, Filename filename) { reg->get_type_from_extension(extension); if (model_type == (LoaderFileType *)NULL) { // The extension isn't a known model file type, is it a known - // image extension? - PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_global_ptr(); - PNMFileType *image_type = - reg->get_type_from_extension(extension); - if (image_type != (PNMFileType *)NULL) { - // It is a known image extension. + // texture extension? + TexturePool *texture_pool = TexturePool::get_global_ptr(); + if (texture_pool->get_texture_type(extension) != NULL) { + // It is a known texture extension. is_image = true; } } @@ -981,20 +979,35 @@ setup_lights() { //////////////////////////////////////////////////////////////////// PT(PandaNode) WindowFramework:: load_image_as_model(const Filename &filename) { - PNMImageHeader header; - if (!header.read_header(filename)) { + PT(Texture) tex = TexturePool::load_texture(filename); + if (tex == NULL) { return NULL; } - int x_size = header.get_x_size(); - int y_size = header.get_y_size(); - bool has_alpha = header.has_alpha(); + int x_size = tex->get_x_size(); + int y_size = tex->get_y_size(); + bool has_alpha = false; + LVecBase2f tex_scale(1.0f, 1.0f); + + if (tex->is_of_type(VideoTexture::get_class_type())) { + // Get the size from the video stream. + VideoTexture *vtex = DCAST(VideoTexture, tex); + x_size = vtex->get_video_width(); + y_size = vtex->get_video_height(); + tex_scale = vtex->get_tex_scale(); + + } else { + // Get the size from the original image (the texture may have + // scaled it to make a power of 2). + PNMImageHeader header; + if (header.read_header(filename)) { + x_size = header.get_x_size(); + y_size = header.get_y_size(); + has_alpha = header.has_alpha(); + } + } // Yes, it is an image file; make a texture out of it. - PT(Texture) tex = new Texture; - if (!tex->read(filename)) { - return NULL; - } tex->set_minfilter(Texture::FT_linear_mipmap_linear); tex->set_magfilter(Texture::FT_linear); @@ -1024,10 +1037,10 @@ load_image_as_model(const Filename &filename) { vertex.add_data3f(Vertexf::rfu(right, 0.02f, top)); vertex.add_data3f(Vertexf::rfu(right, 0.02f, bottom)); - texcoord.add_data2f(0.0f, 1.0f); + texcoord.add_data2f(0.0f, tex_scale[1]); texcoord.add_data2f(0.0f, 0.0f); - texcoord.add_data2f(1.0f, 1.0f); - texcoord.add_data2f(1.0f, 0.0f); + texcoord.add_data2f(tex_scale[0], tex_scale[1]); + texcoord.add_data2f(tex_scale[0], 0.0f); PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static); strip->add_consecutive_vertices(0, 4); diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index dc37a4ef03..012bfab232 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -289,7 +289,7 @@ bool Texture:: read(const Filename &fullpath, int z, int primary_file_num_channels) { PNMImage image; - if (!image.read(fullpath)) { + if (!image.read(fullpath, NULL, false)) { gobj_cat.error() << "Texture::read() - couldn't read: " << fullpath << endl; return false; @@ -328,14 +328,14 @@ bool Texture:: read(const Filename &fullpath, const Filename &alpha_fullpath, int z, int primary_file_num_channels, int alpha_file_channel) { PNMImage image; - if (!image.read(fullpath)) { + if (!image.read(fullpath, NULL, false)) { gobj_cat.error() << "Texture::read() - couldn't read: " << fullpath << endl; return false; } PNMImage alpha_image; - if (!alpha_image.read(alpha_fullpath)) { + if (!alpha_image.read(alpha_fullpath, NULL, true)) { gobj_cat.error() << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl; return false; @@ -1330,6 +1330,17 @@ string_filter_type(const string &string) { } } +//////////////////////////////////////////////////////////////////// +// Function: Texture::make_texture +// Access: Public, Static +// Description: A factory function to make a new Texture, used to +// pass to the TexturePool. +//////////////////////////////////////////////////////////////////// +PT(Texture) Texture:: +make_texture() { + return new Texture; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::reconsider_dirty // Access: Protected, Virtual diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 2100217a10..e386f4161e 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -277,6 +277,8 @@ public: static WrapMode string_wrap_mode(const string &string); static FilterType string_filter_type(const string &string); + static PT(Texture) make_texture(); + protected: virtual void reconsider_dirty(); virtual void reload_ram_image(); diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index fea00b29f5..0c5aa17105 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -22,6 +22,7 @@ #include "config_express.h" #include "string_utils.h" #include "virtualFileSystem.h" +#include "pnmFileTypeRegistry.h" TexturePool *TexturePool::_global_ptr = (TexturePool *)NULL; @@ -59,6 +60,36 @@ register_texture_type(MakeTextureFunc *func, const string &extensions) { } } +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::get_texture_type +// Access: Public +// Description: Returns the factory function to construct a new +// texture of the type appropriate for the indicated +// filename extension, if any, or NULL if the extension +// is not one of the extensions for a texture file. +//////////////////////////////////////////////////////////////////// +TexturePool::MakeTextureFunc *TexturePool:: +get_texture_type(const string &extension) const { + string c = downcase(extension); + TypeRegistry::const_iterator ti; + ti = _type_registry.find(extension); + if (ti != _type_registry.end()) { + return (*ti).second; + } + + // Check the PNM type registry. + PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr(); + PNMFileType *type = pnm_reg->get_type_from_extension(extension); + if (type != (PNMFileType *)NULL) { + // This is a known image type; create an ordinary Texture. + ((TexturePool *)this)->_type_registry[extension] = Texture::make_texture; + return Texture::make_texture; + } + + // This is an unknown texture type. + return NULL; +} + //////////////////////////////////////////////////////////////////// // Function: TexturePool::make_texture // Access: Public @@ -68,16 +99,47 @@ register_texture_type(MakeTextureFunc *func, const string &extensions) { // register_texture_type(). //////////////////////////////////////////////////////////////////// PT(Texture) TexturePool:: -make_texture(const string &extension) { - string c = downcase(extension); - TypeRegistry::const_iterator ti; - ti = _type_registry.find(extension); - if (ti != _type_registry.end()) { - return (*ti).second(); +make_texture(const string &extension) const { + MakeTextureFunc *func = get_texture_type(extension); + if (func != NULL) { + return func(); } + + // We don't know what kind of file type this is; return an ordinary + // Texture in case it's an image file with no extension. return new Texture; } +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::write_texture_types +// Access: Public +// Description: Outputs a list of the available texture types to the +// indicated output stream. This is mostly the list of +// available image types, with maybe a few additional +// ones for video textures. +//////////////////////////////////////////////////////////////////// +void TexturePool:: +write_texture_types(ostream &out, int indent_level) const { + PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr(); + pnm_reg->write(out, indent_level); + + // Also output any of the additional texture types, that aren't + // strictly images (these are typically video textures). + TypeRegistry::const_iterator ti; + for (ti = _type_registry.begin(); ti != _type_registry.end(); ++ti) { + string extension = (*ti).first; + MakeTextureFunc *func = (*ti).second; + + if (pnm_reg->get_type_from_extension(extension) == NULL) { + PT(Texture) tex = func(); + string name = tex->get_type().get_name(); + indent(out, indent_level) << name; + indent(out, max(30 - (int)name.length(), 0)) + << " ." << extension << "\n"; + } + } +} + //////////////////////////////////////////////////////////////////// // Function: TexturePool::get_global_ptr // Access: Public, Static @@ -463,5 +525,14 @@ report_texture_unreadable(const Filename &filename) const { // The file exists, but it couldn't be read for some reason. gobj_cat.error() << "Texture \"" << filename << "\" exists but cannot be read.\n"; + + // Maybe the filename extension is unknown. + MakeTextureFunc *func = get_texture_type(filename.get_extension()); + if (func == (MakeTextureFunc *)NULL) { + gobj_cat.error() + << "Texture extension \"" << filename.get_extension() + << "\" is unknown. Supported texture types:\n"; + write_texture_types(gobj_cat.error(false), 2); + } } } diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index 659533156d..39caa215a2 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -71,8 +71,10 @@ PUBLISHED: public: typedef PT(Texture) MakeTextureFunc(); void register_texture_type(MakeTextureFunc *func, const string &extensions); - - PT(Texture) make_texture(const string &extension); + + MakeTextureFunc *get_texture_type(const string &extension) const; + PT(Texture) make_texture(const string &extension) const; + void write_texture_types(ostream &out, int indent_level) const; static TexturePool *get_global_ptr(); diff --git a/panda/src/pnmimage/pnmImage.cxx b/panda/src/pnmimage/pnmImage.cxx index b87005ef3d..947f426226 100644 --- a/panda/src/pnmimage/pnmImage.cxx +++ b/panda/src/pnmimage/pnmImage.cxx @@ -158,10 +158,11 @@ alpha_fill_val(xelval alpha) { // is. Returns true if successful, false on error. //////////////////////////////////////////////////////////////////// bool PNMImage:: -read(const Filename &filename, PNMFileType *type) { +read(const Filename &filename, PNMFileType *type, bool report_unknown_type) { clear(); - PNMReader *reader = PNMImageHeader::make_reader(filename, type); + PNMReader *reader = PNMImageHeader::make_reader(filename, type, + report_unknown_type); if (reader == (PNMReader *)NULL) { return false; } @@ -174,18 +175,21 @@ read(const Filename &filename, PNMFileType *type) { // Description: Reads the image data from the indicated stream. // // The filename is advisory only, and may be used -// suggest a type if it has a known extension. +// to suggest a type if it has a known extension. // // If type is non-NULL, it is a suggestion for the type -// of file it is. Returns true if successful, false on -// error. +// of file it is (and a non-NULL type will override any +// magic number test or filename extension lookup). +// +// Returns true if successful, false on error. //////////////////////////////////////////////////////////////////// bool PNMImage:: -read(istream &data, const string &filename, PNMFileType *type) { +read(istream &data, const string &filename, PNMFileType *type, + bool report_unknown_type) { clear(); PNMReader *reader = PNMImageHeader::make_reader - (&data, false, filename, string(), type); + (&data, false, filename, string(), type, report_unknown_type); if (reader == (PNMReader *)NULL) { return false; } diff --git a/panda/src/pnmimage/pnmImage.h b/panda/src/pnmimage/pnmImage.h index 055f287b22..d4ff2e4a40 100644 --- a/panda/src/pnmimage/pnmImage.h +++ b/panda/src/pnmimage/pnmImage.h @@ -87,9 +87,11 @@ PUBLISHED: INLINE void alpha_fill(double alpha = 0.0); void alpha_fill_val(xelval alpha = 0); - bool read(const Filename &filename, PNMFileType *type = NULL); + bool read(const Filename &filename, PNMFileType *type = NULL, + bool report_unknown_type = true); bool read(istream &data, const string &filename = string(), - PNMFileType *type = NULL); + PNMFileType *type = NULL, + bool report_unknown_type = true); bool read(PNMReader *reader); bool write(const Filename &filename, PNMFileType *type = NULL) const; diff --git a/panda/src/pnmimage/pnmImageHeader.cxx b/panda/src/pnmimage/pnmImageHeader.cxx index 46878ca491..f7add336f2 100644 --- a/panda/src/pnmimage/pnmImageHeader.cxx +++ b/panda/src/pnmimage/pnmImageHeader.cxx @@ -58,7 +58,8 @@ read_header(const Filename &filename, PNMFileType *type) { // needed. //////////////////////////////////////////////////////////////////// PNMReader *PNMImageHeader:: -make_reader(const Filename &filename, PNMFileType *type) const { +make_reader(const Filename &filename, PNMFileType *type, + bool report_unknown_type) const { if (pnmimage_cat.is_debug()) { pnmimage_cat.debug() << "Reading image from " << filename << "\n"; @@ -88,7 +89,8 @@ make_reader(const Filename &filename, PNMFileType *type) const { return NULL; } - return make_reader(file, owns_file, filename, string(), type); + return make_reader(file, owns_file, filename, string(), type, + report_unknown_type); } @@ -123,7 +125,8 @@ make_reader(const Filename &filename, PNMFileType *type) const { //////////////////////////////////////////////////////////////////// PNMReader *PNMImageHeader:: make_reader(istream *file, bool owns_file, const Filename &filename, - string magic_number, PNMFileType *type) const { + string magic_number, PNMFileType *type, + bool report_unknown_type) const { if (type == (PNMFileType *)NULL) { if (!read_magic_number(file, magic_number, 2)) { // No magic number. No image. @@ -188,7 +191,7 @@ make_reader(istream *file, bool owns_file, const Filename &filename, if (type == (PNMFileType *)NULL) { // We can't figure out what type the file is; give up. - if (pnmimage_cat.is_error()) { + if (report_unknown_type && pnmimage_cat.is_error()) { pnmimage_cat.error() << "Cannot determine type of image file " << filename << ".\n" << "Currently supported image types:\n"; diff --git a/panda/src/pnmimage/pnmImageHeader.h b/panda/src/pnmimage/pnmImageHeader.h index 008002bd09..925616d2a3 100644 --- a/panda/src/pnmimage/pnmImageHeader.h +++ b/panda/src/pnmimage/pnmImageHeader.h @@ -79,11 +79,13 @@ PUBLISHED: bool read_header(const Filename &filename, PNMFileType *type = NULL); PNMReader *make_reader(const Filename &filename, - PNMFileType *type = NULL) const; + PNMFileType *type = NULL, + bool report_unknown_type = true) const; PNMReader *make_reader(istream *file, bool owns_file = true, const Filename &filename = Filename(), string magic_number = string(), - PNMFileType *type = NULL) const; + PNMFileType *type = NULL, + bool report_unknown_type = true) const; PNMWriter *make_writer(const Filename &filename, PNMFileType *type = NULL) const;