Browse Source

better texture filename extension error reporting

David Rose 20 years ago
parent
commit
942f595c7f

+ 33 - 20
panda/src/framework/windowFramework.cxx

@@ -49,9 +49,9 @@
 #include "pgTop.h"
 #include "pgTop.h"
 #include "geomNode.h"
 #include "geomNode.h"
 #include "texture.h"
 #include "texture.h"
-#include "pnmImage.h"
+#include "videoTexture.h"
+#include "texturePool.h"
 #include "loaderFileTypeRegistry.h"
 #include "loaderFileTypeRegistry.h"
-#include "pnmFileTypeRegistry.h"
 #include "pnmImage.h"
 #include "pnmImage.h"
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
 
 
@@ -562,12 +562,10 @@ load_model(const NodePath &parent, Filename filename) {
       reg->get_type_from_extension(extension);
       reg->get_type_from_extension(extension);
     if (model_type == (LoaderFileType *)NULL) {
     if (model_type == (LoaderFileType *)NULL) {
       // The extension isn't a known model file type, is it a known
       // 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;
         is_image = true;
       }
       }
     }
     }
@@ -981,20 +979,35 @@ setup_lights() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) WindowFramework::
 PT(PandaNode) WindowFramework::
 load_image_as_model(const Filename &filename) {
 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;
     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);
 
 
-  // Yes, it is an image file; make a texture out of it.
-  PT(Texture) tex = new Texture;
-  if (!tex->read(filename)) {
-    return NULL;
+  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.
   tex->set_minfilter(Texture::FT_linear_mipmap_linear);
   tex->set_minfilter(Texture::FT_linear_mipmap_linear);
   tex->set_magfilter(Texture::FT_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, top));
   vertex.add_data3f(Vertexf::rfu(right, 0.02f, bottom));
   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(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);
   PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
   strip->add_consecutive_vertices(0, 4);
   strip->add_consecutive_vertices(0, 4);

+ 14 - 3
panda/src/gobj/texture.cxx

@@ -289,7 +289,7 @@ bool Texture::
 read(const Filename &fullpath, int z, int primary_file_num_channels) {
 read(const Filename &fullpath, int z, int primary_file_num_channels) {
   PNMImage image;
   PNMImage image;
 
 
-  if (!image.read(fullpath)) {
+  if (!image.read(fullpath, NULL, false)) {
     gobj_cat.error()
     gobj_cat.error()
       << "Texture::read() - couldn't read: " << fullpath << endl;
       << "Texture::read() - couldn't read: " << fullpath << endl;
     return false;
     return false;
@@ -328,14 +328,14 @@ bool Texture::
 read(const Filename &fullpath, const Filename &alpha_fullpath,
 read(const Filename &fullpath, const Filename &alpha_fullpath,
      int z, int primary_file_num_channels, int alpha_file_channel) {
      int z, int primary_file_num_channels, int alpha_file_channel) {
   PNMImage image;
   PNMImage image;
-  if (!image.read(fullpath)) {
+  if (!image.read(fullpath, NULL, false)) {
     gobj_cat.error()
     gobj_cat.error()
       << "Texture::read() - couldn't read: " << fullpath << endl;
       << "Texture::read() - couldn't read: " << fullpath << endl;
     return false;
     return false;
   }
   }
 
 
   PNMImage alpha_image;
   PNMImage alpha_image;
-  if (!alpha_image.read(alpha_fullpath)) {
+  if (!alpha_image.read(alpha_fullpath, NULL, true)) {
     gobj_cat.error()
     gobj_cat.error()
       << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
       << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
     return false;
     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
 //     Function: Texture::reconsider_dirty
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 2 - 0
panda/src/gobj/texture.h

@@ -277,6 +277,8 @@ public:
   static WrapMode string_wrap_mode(const string &string);
   static WrapMode string_wrap_mode(const string &string);
   static FilterType string_filter_type(const string &string);
   static FilterType string_filter_type(const string &string);
 
 
+  static PT(Texture) make_texture();
+
 protected:
 protected:
   virtual void reconsider_dirty();
   virtual void reconsider_dirty();
   virtual void reload_ram_image();
   virtual void reload_ram_image();

+ 77 - 6
panda/src/gobj/texturePool.cxx

@@ -22,6 +22,7 @@
 #include "config_express.h"
 #include "config_express.h"
 #include "string_utils.h"
 #include "string_utils.h"
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
+#include "pnmFileTypeRegistry.h"
 
 
 
 
 TexturePool *TexturePool::_global_ptr = (TexturePool *)NULL;
 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
 //     Function: TexturePool::make_texture
 //       Access: Public
 //       Access: Public
@@ -68,16 +99,47 @@ register_texture_type(MakeTextureFunc *func, const string &extensions) {
 //               register_texture_type().
 //               register_texture_type().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(Texture) TexturePool::
 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;
   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
 //     Function: TexturePool::get_global_ptr
 //       Access: Public, Static
 //       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.
     // The file exists, but it couldn't be read for some reason.
     gobj_cat.error()
     gobj_cat.error()
       << "Texture \"" << filename << "\" exists but cannot be read.\n";
       << "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);
+    }
   }
   }
 }
 }

+ 4 - 2
panda/src/gobj/texturePool.h

@@ -71,8 +71,10 @@ PUBLISHED:
 public:
 public:
   typedef PT(Texture) MakeTextureFunc();
   typedef PT(Texture) MakeTextureFunc();
   void register_texture_type(MakeTextureFunc *func, const string &extensions);
   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();
   static TexturePool *get_global_ptr();
 
 

+ 11 - 7
panda/src/pnmimage/pnmImage.cxx

@@ -158,10 +158,11 @@ alpha_fill_val(xelval alpha) {
 //               is.  Returns true if successful, false on error.
 //               is.  Returns true if successful, false on error.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PNMImage::
 bool PNMImage::
-read(const Filename &filename, PNMFileType *type) {
+read(const Filename &filename, PNMFileType *type, bool report_unknown_type) {
   clear();
   clear();
 
 
-  PNMReader *reader = PNMImageHeader::make_reader(filename, type);
+  PNMReader *reader = PNMImageHeader::make_reader(filename, type,
+						  report_unknown_type);
   if (reader == (PNMReader *)NULL) {
   if (reader == (PNMReader *)NULL) {
     return false;
     return false;
   }
   }
@@ -174,18 +175,21 @@ read(const Filename &filename, PNMFileType *type) {
 //  Description: Reads the image data from the indicated stream.  
 //  Description: Reads the image data from the indicated stream.  
 //
 //
 //               The filename is advisory only, and may be used
 //               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
 //               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::
 bool PNMImage::
-read(istream &data, const string &filename, PNMFileType *type) {
+read(istream &data, const string &filename, PNMFileType *type,
+     bool report_unknown_type) {
   clear();
   clear();
 
 
   PNMReader *reader = PNMImageHeader::make_reader
   PNMReader *reader = PNMImageHeader::make_reader
-    (&data, false, filename, string(), type);
+    (&data, false, filename, string(), type, report_unknown_type);
   if (reader == (PNMReader *)NULL) {
   if (reader == (PNMReader *)NULL) {
     return false;
     return false;
   }
   }

+ 4 - 2
panda/src/pnmimage/pnmImage.h

@@ -87,9 +87,11 @@ PUBLISHED:
   INLINE void alpha_fill(double alpha = 0.0);
   INLINE void alpha_fill(double alpha = 0.0);
   void alpha_fill_val(xelval alpha = 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(), 
   bool read(istream &data, const string &filename = string(), 
-            PNMFileType *type = NULL);
+            PNMFileType *type = NULL,
+	    bool report_unknown_type = true);
   bool read(PNMReader *reader);
   bool read(PNMReader *reader);
 
 
   bool write(const Filename &filename, PNMFileType *type = NULL) const;
   bool write(const Filename &filename, PNMFileType *type = NULL) const;

+ 7 - 4
panda/src/pnmimage/pnmImageHeader.cxx

@@ -58,7 +58,8 @@ read_header(const Filename &filename, PNMFileType *type) {
 //               needed.
 //               needed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PNMReader *PNMImageHeader::
 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()) {
   if (pnmimage_cat.is_debug()) {
     pnmimage_cat.debug()
     pnmimage_cat.debug()
       << "Reading image from " << filename << "\n";
       << "Reading image from " << filename << "\n";
@@ -88,7 +89,8 @@ make_reader(const Filename &filename, PNMFileType *type) const {
     return NULL;
     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::
 PNMReader *PNMImageHeader::
 make_reader(istream *file, bool owns_file, const Filename &filename,
 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 (type == (PNMFileType *)NULL) {
     if (!read_magic_number(file, magic_number, 2)) {
     if (!read_magic_number(file, magic_number, 2)) {
       // No magic number.  No image.
       // No magic number.  No image.
@@ -188,7 +191,7 @@ make_reader(istream *file, bool owns_file, const Filename &filename,
 
 
   if (type == (PNMFileType *)NULL) {
   if (type == (PNMFileType *)NULL) {
     // We can't figure out what type the file is; give up.
     // 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()
       pnmimage_cat.error()
         << "Cannot determine type of image file " << filename << ".\n"
         << "Cannot determine type of image file " << filename << ".\n"
         << "Currently supported image types:\n";
         << "Currently supported image types:\n";

+ 4 - 2
panda/src/pnmimage/pnmImageHeader.h

@@ -79,11 +79,13 @@ PUBLISHED:
   bool read_header(const Filename &filename, PNMFileType *type = NULL);
   bool read_header(const Filename &filename, PNMFileType *type = NULL);
 
 
   PNMReader *make_reader(const Filename &filename,
   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,
   PNMReader *make_reader(istream *file, bool owns_file = true,
                          const Filename &filename = Filename(),
                          const Filename &filename = Filename(),
                          string magic_number = string(),
                          string magic_number = string(),
-                         PNMFileType *type = NULL) const;
+                         PNMFileType *type = NULL,
+			 bool report_unknown_type = true) const;
 
 
   PNMWriter *make_writer(const Filename &filename,
   PNMWriter *make_writer(const Filename &filename,
                          PNMFileType *type = NULL) const;
                          PNMFileType *type = NULL) const;