Browse Source

Texture::set_quality_level()

David Rose 17 years ago
parent
commit
acb0faae46

+ 17 - 0
panda/src/doc/eggSyntax.txt

@@ -447,6 +447,23 @@ appear before they are referenced.
     the polygon itself.  See the description for draw_order under
     polygon attributes.
 
+  <Scalar> quality-level { quality }
+
+    Sets a hint to the renderer about the desired performance /
+    quality tradeoff for this particular texture.  This is most useful
+    for the tinydisplay software renderer; for normal,
+    hardware-accelerated renderers, this may have little or no effect.
+
+    This may be one of:
+
+      DEFAULT
+      FASTEST
+      NORMAL
+      BEST
+
+    "Default" means to use whatever quality level is specified by the
+    global texture-quality-level config variable.
+
   <Transform> { transform-definition }
 
     This specifies a 2-d or 3-d transformation that is applied to the

+ 20 - 0
panda/src/egg/eggTexture.I

@@ -441,6 +441,26 @@ get_tex_gen() const {
   return _tex_gen;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::set_quality_level
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+set_quality_level(QualityLevel quality_level) {
+  _quality_level = quality_level;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::get_quality_level
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE EggTexture::QualityLevel EggTexture::
+get_quality_level() const {
+  return _quality_level;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTexture::set_stage_name
 //       Access: Published

+ 54 - 0
panda/src/egg/eggTexture.cxx

@@ -48,6 +48,7 @@ EggTexture(const string &tref_name, const string &filename)
   _env_type = ET_unspecified;
   _saved_result = false;
   _tex_gen = TG_unspecified;
+  _quality_level = QL_unspecified;
   _priority = 0;
   _color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
@@ -93,6 +94,7 @@ operator = (const EggTexture &copy) {
   _env_type = copy._env_type;
   _saved_result = copy._saved_result;
   _tex_gen = copy._tex_gen;
+  _quality_level = copy._quality_level;
   _stage_name = copy._stage_name;
   _priority = copy._priority;
   _color = copy._color;
@@ -237,6 +239,11 @@ write(ostream &out, int indent_level) const {
       << "<Scalar> tex-gen { " << get_tex_gen() << " }\n";
   }
 
+  if (get_quality_level() != QL_unspecified) {
+    indent(out, indent_level + 2)
+      << "<Scalar> quality-level { " << get_quality_level() << " }\n";
+  }
+
   if (has_stage_name()) {
     indent(out, indent_level + 2)
       << "<Scalar> stage-name { " << get_stage_name() << " }\n";
@@ -1050,6 +1057,35 @@ string_tex_gen(const string &string) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::string_quality_level
+//       Access: Published, Static
+//  Description: Returns the TexGen value associated with the given
+//               string representation, or ET_unspecified if the string
+//               does not match any known TexGen value.
+////////////////////////////////////////////////////////////////////
+EggTexture::QualityLevel EggTexture::
+string_quality_level(const string &string) {
+  if (cmp_nocase_uh(string, "unspecified") == 0) {
+    return QL_unspecified;
+
+  } else if (cmp_nocase_uh(string, "default") == 0) {
+    return QL_default;
+
+  } else if (cmp_nocase_uh(string, "fastest") == 0) {
+    return QL_fastest;
+
+  } else if (cmp_nocase_uh(string, "normal") == 0) {
+    return QL_normal;
+
+  } else if (cmp_nocase_uh(string, "best") == 0) {
+    return QL_best;
+
+  } else {
+    return QL_unspecified;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTexture::as_transform
 //       Access: Public, Virtual
@@ -1469,3 +1505,21 @@ operator << (ostream &out, EggTexture::TexGen tex_gen) {
 
   return out << "**invalid TexGen(" << (int)tex_gen << ")**";
 }
+
+ostream &
+operator << (ostream &out, EggTexture::QualityLevel quality_level) {
+  switch (quality_level) {
+  case EggTexture::QL_unspecified:
+    return out << "unspecified";
+  case EggTexture::QL_default:
+    return out << "default";
+  case EggTexture::QL_fastest:
+    return out << "fastest";
+  case EggTexture::QL_normal:
+    return out << "normal";
+  case EggTexture::QL_best:
+    return out << "best";
+  }
+
+  return out << "**invalid QualityLevel(" << (int)quality_level << ")**";
+}

+ 13 - 0
panda/src/egg/eggTexture.h

@@ -162,6 +162,13 @@ PUBLISHED:
 
     TG_point_sprite,
   };
+  enum QualityLevel {
+    QL_unspecified,
+    QL_default,
+    QL_fastest,
+    QL_normal,
+    QL_best,
+  };
 
   INLINE void set_texture_type(TextureType texture_type);
   INLINE TextureType get_texture_type() const;
@@ -215,6 +222,9 @@ PUBLISHED:
   INLINE void set_tex_gen(TexGen tex_gen);
   INLINE TexGen get_tex_gen() const;
 
+  INLINE void set_quality_level(QualityLevel quality_level);
+  INLINE QualityLevel get_quality_level() const;
+
   INLINE void set_stage_name(const string &stage_name);
   INLINE void clear_stage_name();
   INLINE bool has_stage_name() const;
@@ -281,6 +291,7 @@ PUBLISHED:
   static CombineSource string_combine_source(const string &string);
   static CombineOperand string_combine_operand(const string &string);
   static TexGen string_tex_gen(const string &string);
+  static QualityLevel string_quality_level(const string &string);
 
 public:
   virtual EggTransform *as_transform();
@@ -314,6 +325,7 @@ private:
   EnvType _env_type;
   bool _saved_result;
   TexGen _tex_gen;
+  QualityLevel _quality_level;
   string _stage_name;
   int _priority;
   Colorf _color;
@@ -399,6 +411,7 @@ EXPCL_PANDAEGG ostream &operator << (ostream &out, EggTexture::CombineChannel cc
 EXPCL_PANDAEGG ostream &operator << (ostream &out, EggTexture::CombineSource cs);
 EXPCL_PANDAEGG ostream &operator << (ostream &out, EggTexture::CombineOperand co);
 EXPCL_PANDAEGG ostream &operator << (ostream &out, EggTexture::TexGen tex_gen);
+EXPCL_PANDAEGG ostream &operator << (ostream &out, EggTexture::QualityLevel quality_level);
 
 #include "eggTexture.I"
 

+ 9 - 1
panda/src/egg/parser.yxx

@@ -537,11 +537,19 @@ texture_body:
   } else if (cmp_nocase_uh(name, "tex_gen") == 0) {
     EggTexture::TexGen tex_gen = EggTexture::string_tex_gen(strval);
     if (tex_gen == EggTexture::TG_unspecified) {
-      eggyywarning("Unknown texture env type " + strval);
+      eggyywarning("Unknown tex-gen " + strval);
     } else {
       texture->set_tex_gen(tex_gen);
     }
 
+  } else if (cmp_nocase_uh(name, "quality_level") == 0) {
+    EggTexture::QualityLevel quality_level = EggTexture::string_quality_level(strval);
+    if (quality_level == EggTexture::QL_unspecified) {
+      eggyywarning("Unknown quality-level " + strval);
+    } else {
+      texture->set_quality_level(quality_level);
+    }
+
   } else if (cmp_nocase_uh(name, "stage_name") == 0) {
     texture->set_stage_name(strval);
 

+ 19 - 0
panda/src/egg2pg/eggLoader.cxx

@@ -1261,6 +1261,25 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
         << " for 4-component texture " << egg_tex->get_name() << "\n";
     }
   }
+
+  switch (egg_tex->get_quality_level()) {
+  case EggTexture::QL_unspecified:
+  case EggTexture::QL_default:
+    tex->set_quality_level(Texture::QL_default);
+    break;
+
+  case EggTexture::QL_fastest:
+    tex->set_quality_level(Texture::QL_fastest);
+    break;
+
+  case EggTexture::QL_normal:
+    tex->set_quality_level(Texture::QL_normal);
+    break;
+
+  case EggTexture::QL_best:
+    tex->set_quality_level(Texture::QL_best);
+    break;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 0
panda/src/gobj/texture.I

@@ -743,6 +743,17 @@ uses_mipmaps() const {
   return is_mipmap(get_minfilter());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_quality_level
+//       Access: Public
+//  Description: Returns the current quality_level hint.  See
+//               set_quality_level().
+////////////////////////////////////////////////////////////////////
+INLINE Texture::QualityLevel Texture::
+get_quality_level() const {
+  return _quality_level;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::might_have_ram_image
 //       Access: Published

+ 82 - 0
panda/src/gobj/texture.cxx

@@ -42,6 +42,16 @@
 
 #include <stddef.h>
 
+ConfigVariableEnum<Texture::QualityLevel> texture_quality_level
+("texture-quality-level", Texture::QL_normal,
+ PRC_DESC("This specifies a global quality level for all textures.  You "
+          "may specify either fastest, normal, or best.  This actually "
+          "affects the meaning of Texture::set_quality_level(TQL_default), "
+          "so it may be overridden on a per-texture basis.  This generally "
+          "only has an effect when using the tinydisplay software renderer; "
+          "it has little or no effect on normal, hardware-accelerated "
+          "renderers.  See Texture::set_quality_level()."));
+
 PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
 TypeHandle Texture::_type_handle;
 AutoTextureScale Texture::_textures_power_2 = ATS_UNSPECIFIED;
@@ -72,6 +82,7 @@ Texture(const string &name) :
   _ram_image_compression = CM_off;
   _render_to_texture = false;
   _match_framebuffer_format = false;
+  _quality_level = QL_default;
 
   _texture_type = TT_2d_texture;
   _x_size = 0;
@@ -129,6 +140,7 @@ Texture(const Texture &copy) :
   _border_color(copy._border_color),
   _compression(copy._compression),
   _match_framebuffer_format(copy._match_framebuffer_format),
+  _quality_level(copy._quality_level),
   _pad_x_size(copy._pad_x_size),
   _pad_y_size(copy._pad_y_size),
   _pad_z_size(copy._pad_z_size),
@@ -179,6 +191,7 @@ operator = (const Texture &copy) {
   _border_color = copy._border_color;
   _compression = copy._compression;
   _match_framebuffer_format = copy._match_framebuffer_format;
+  _quality_level = copy._quality_level;
   _ram_image_compression = copy._ram_image_compression;
   _ram_images = copy._ram_images;
   ++_properties_modified;
@@ -838,6 +851,23 @@ set_render_to_texture(bool render_to_texture) {
   _render_to_texture = render_to_texture;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::set_quality_level
+//       Access: Public
+//  Description: Sets a hint to the renderer about the desired
+//               performance / quality tradeoff for this particular
+//               texture.  This is most useful for the tinydisplay
+//               software renderer; for normal, hardware-accelerated
+//               renderers, this may have little or no effect.
+////////////////////////////////////////////////////////////////////
+void Texture::
+set_quality_level(Texture::QualityLevel quality_level) {
+  if (_quality_level != quality_level) {
+    ++_properties_modified;
+    _quality_level = quality_level;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_expected_num_mipmap_levels
 //       Access: Published
@@ -3539,6 +3569,9 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) {
   if (manager->get_file_minor_ver() >= 1) {
     set_compression((CompressionMode)scan.get_uint8());
   }
+  if (manager->get_file_minor_ver() >= 16) {
+    set_quality_level((QualityLevel)scan.get_uint8());
+  }
 
   Format format = (Format)scan.get_uint8();
   int num_components = scan.get_uint8();
@@ -3696,6 +3729,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
   me.add_int16(_anisotropic_degree);
   _border_color.write_datagram(me);
   me.add_uint8(_compression);
+  me.add_uint8(_quality_level);
 
   me.add_uint8(_format);
   me.add_uint8(_num_components);
@@ -3927,3 +3961,51 @@ operator << (ostream &out, Texture::CompressionMode cm) {
   return out << "(**invalid Texture::CompressionMode(" << (int)cm << ")**)";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::QualityLevel output operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, Texture::QualityLevel tql) {
+  switch (tql) {
+  case Texture::QL_default:
+    return out << "default";
+  case Texture::QL_fastest:
+    return out << "fastest";
+  case Texture::QL_normal:
+    return out << "normal";
+  case Texture::QL_best:
+    return out << "best";
+  }
+
+  return out << "**invalid Texture::QualityLevel (" << (int)tql << ")**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::QualityLevel input operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+istream &
+operator >> (istream &in, Texture::QualityLevel &tql) {
+  string word;
+  in >> word;
+
+  if (cmp_nocase(word, "default") == 0) {
+    tql = Texture::QL_default;
+
+  } else if (cmp_nocase(word, "fastest") == 0) {
+    tql = Texture::QL_fastest;
+
+  } else if (cmp_nocase(word, "normal") == 0) {
+    tql = Texture::QL_normal;
+
+  } else if (cmp_nocase(word, "best") == 0) {
+    tql = Texture::QL_best;
+
+  } else {
+    gobj_cat->error() << "Invalid Texture::QualityLevel value: " << word << "\n";
+    tql = Texture::QL_default;
+  }
+
+  return in;
+}

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

@@ -175,6 +175,13 @@ PUBLISHED:
     CM_dxt5,
   };
 
+  enum QualityLevel {
+    QL_default,   // according to texture-quality-level
+    QL_fastest,
+    QL_normal,
+    QL_best,
+  };
+
 PUBLISHED:
   Texture(const string &name = string());
 protected:
@@ -271,6 +278,9 @@ PUBLISHED:
   INLINE bool get_render_to_texture() const;
   INLINE bool uses_mipmaps() const;
 
+  void set_quality_level(QualityLevel quality_level);
+  INLINE QualityLevel get_quality_level() const;
+
   int get_expected_num_mipmap_levels() const;
   int get_expected_mipmap_x_size(int n) const;
   int get_expected_mipmap_y_size(int n) const;
@@ -515,6 +525,7 @@ protected:
   CompressionMode _compression;
   bool _render_to_texture;
   bool _match_framebuffer_format;
+  QualityLevel _quality_level;
 
   int _pad_x_size;
   int _pad_y_size;
@@ -587,6 +598,8 @@ private:
   friend class TexturePool;
 };
 
+extern EXPCL_PANDA_GOBJ ConfigVariableEnum<Texture::QualityLevel> texture_quality_level;
+
 EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::TextureType tt);
 EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::ComponentType ct);
 EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::Format f);
@@ -598,6 +611,8 @@ EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::WrapMode wm);
 EXPCL_PANDA_GOBJ istream &operator >> (istream &in, Texture::WrapMode &wm);
 
 EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::CompressionMode cm);
+EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::QualityLevel tql);
+EXPCL_PANDA_GOBJ istream &operator >> (istream &in, Texture::QualityLevel &tql);
 
 #include "texture.I"
 

+ 2 - 1
panda/src/putil/bam.h

@@ -36,7 +36,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
-static const unsigned short _bam_minor_ver = 15;
+static const unsigned short _bam_minor_ver = 16;
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
@@ -52,6 +52,7 @@ static const unsigned short _bam_minor_ver = 15;
 // Bumped to minor version 13 on 8/15/07 to reverse CollisionPolygon vertices.
 // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
 // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
+// Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
 
 
 #endif

+ 4 - 0
panda/src/text/dynamicTextPage.cxx

@@ -37,6 +37,10 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
   // it by default.
   _compression = CM_off;
 
+  // It's usually pretty important for text to look its best, and it
+  // doesn't usually have a high fill factor.
+  set_quality_level(Texture::QL_best);
+
   _x_size = _font->get_page_x_size();
   _y_size = _font->get_page_y_size();
 

+ 0 - 1
panda/src/tinydisplay/clip.cxx

@@ -33,7 +33,6 @@ void gl_transform_to_viewport(GLContext *c,GLVertex *v)
                 + ZB_POINT_ALPHA_MIN);
   
   /* texture */
-
   if (c->texture_2d_enabled) {
     v->zp.s = (int)(v->tex_coord.X * c->current_texture->s_max); 
     v->zp.t = (int)(v->tex_coord.Y * c->current_texture->t_max);

+ 108 - 20
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -599,7 +599,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
     }
   }
 
-  if (_c->texture_2d_enabled && _texture_replace) {
+  if (_texturing_state != 0 && _texture_replace) {
     // We don't need the vertex color or lighting calculation after
     // all, since the current texture will just hide all of that.
     needs_color = false;
@@ -763,13 +763,14 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
     }
   }
 
-  int texturing_state = 0;  // untextured
-  int texfilter_state = 0;  // nearest
-  if (_c->texture_2d_enabled) {
+  int texturing_state = _texturing_state;
+  int texfilter_state = 0;  // tnearest
+  if (texturing_state > 0) {
     texfilter_state = _texfilter_state;
-    texturing_state = 2;  // perspective-correct textures
-    if (_c->matrix_model_projection_no_w_transform || !td_perspective_textures) {
-      texturing_state = 1;  // non-perspective-correct textures
+    if (_c->matrix_model_projection_no_w_transform) {
+      // Don't bother with the perspective-correct algorithm if we're
+      // under an orthonormal lens, e.g. render2d.
+      texturing_state = 1;    // textured (not perspective correct)
     }
 
     if (_texture_replace) {
@@ -1241,10 +1242,7 @@ release_texture(TextureContext *tc) {
   GLTexture *gltex = gtc->_gltex;
   gtc->_gltex = NULL;
 
-  if (_c->current_texture == gltex) {
-    _c->current_texture = NULL;
-    _c->texture_2d_enabled = false;
-  }
+  _texturing_state = 0;  // just in case
 
   for (int i = 0; i < gltex->num_levels; ++i) {
     gl_free(gltex->levels[i].pixmap);
@@ -1602,6 +1600,7 @@ do_issue_material() {
 ////////////////////////////////////////////////////////////////////
 void TinyGraphicsStateGuardian::
 do_issue_texture() {
+  _texturing_state = 0;   // untextured
   _c->texture_2d_enabled = false;
 
   int num_stages = _effective_texture->get_num_on_ff_stages();
@@ -1622,12 +1621,53 @@ do_issue_texture() {
   }
     
   // Then, turn on the current texture mode.
-  apply_texture(tc);
+  if (!apply_texture(tc)) {
+    return;
+  }
 
   // Set a few state cache values.
-  _texfilter_state = 0;    // nearest
-  if (texture->uses_mipmaps() && !td_ignore_mipmaps) {
-    _texfilter_state = 1;  // mipmap
+  _c->texture_2d_enabled = true;
+
+  _texturing_state = 2;   // perspective (perspective-correct texturing)
+  if (!td_perspective_textures) {
+    _texturing_state = 1;    // textured (not perspective correct)
+  }
+
+  Texture::QualityLevel quality_level = texture->get_quality_level();
+  if (quality_level == Texture::QL_default) {
+    quality_level = texture_quality_level;
+  }
+
+  if (quality_level == Texture::QL_best) {
+    // This is the most generic texture filter.  Slow, but pretty.
+    _texfilter_state = 2;  // tgeneral
+    _c->zb->tex_minfilter_func = get_tex_filter_func(texture->get_minfilter());
+    _c->zb->tex_magfilter_func = get_tex_filter_func(texture->get_magfilter());
+
+    if (texture->get_minfilter() == Texture::FT_nearest &&
+        texture->get_magfilter() == Texture::FT_nearest) {
+      // This case is inlined.
+      _texfilter_state = 0;    // tnearest
+    } else if (texture->get_minfilter() == Texture::FT_nearest_mipmap_nearest &&
+               texture->get_magfilter() == Texture::FT_nearest) {
+      // So is this case.
+      _texfilter_state = 1;  // tmipmap
+    }
+
+  } else if (quality_level == Texture::QL_fastest) {
+    // This is the cheapest texture filter.  We disallow mipmaps and
+    // perspective correctness.
+    _texfilter_state = 0;    // tnearest
+    _texturing_state = 1;    // textured (not perspective correct)
+  
+  } else {
+    // This is the default texture filter.  We use nearest sampling if
+    // there are no mipmaps, and mipmap_nearest if there are any
+    // mipmaps--these are the two inlined filters.
+    _texfilter_state = 0;    // tnearest
+    if (texture->uses_mipmaps() && !td_ignore_mipmaps) {
+      _texfilter_state = 1;  // tmipmap
+    }
   }
 
   // M_replace means M_replace; anything else is treated the same as
@@ -1642,29 +1682,32 @@ do_issue_texture() {
 //               texture, and makes it the current texture available
 //               for rendering.
 ////////////////////////////////////////////////////////////////////
-void TinyGraphicsStateGuardian::
+bool TinyGraphicsStateGuardian::
 apply_texture(TextureContext *tc) {
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
 
   gtc->set_active(true);
-  _c->current_texture = gtc->_gltex;
-  _c->texture_2d_enabled = true;
 
   GLTexture *gltex = gtc->_gltex;
 
   if (gtc->was_image_modified() || gltex->num_levels == 0) {
     // If the texture image was modified, reload the texture.
-    if (!upload_texture(gtc)) {
+    bool okflag = upload_texture(gtc);
+    if (!okflag) {
       tinydisplay_cat.error()
         << "Could not load " << *gtc->get_texture()
         << ": inappropriate size.\n";
-      _c->texture_2d_enabled = false;
     }
     gtc->mark_loaded();
+    if (!okflag) {
+      return false;
+    }
   }
   gtc->enqueue_lru(&_textures_lru);
 
+  _c->current_texture = gltex;
   _c->zb->current_texture = gltex->levels;
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2211,3 +2254,48 @@ get_color_blend_op(ColorBlendAttrib::Operand operand) {
   }
   return 0;
 }
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::get_tex_filter_func
+//       Access: Private, Static
+//  Description: Returns the pointer to the appropriate filter
+//               function according to the texture's filter type.
+////////////////////////////////////////////////////////////////////
+ZB_lookupTextureFunc TinyGraphicsStateGuardian::
+get_tex_filter_func(Texture::FilterType filter) {
+  switch (filter) {
+  case Texture::FT_nearest:
+    return &lookup_texture_nearest;
+
+  case Texture::FT_linear:
+    return &lookup_texture_bilinear;
+
+  case Texture::FT_nearest_mipmap_nearest:
+    if (td_ignore_mipmaps) {
+      return &lookup_texture_nearest;
+    }
+    return &lookup_texture_mipmap_nearest;
+
+  case Texture::FT_nearest_mipmap_linear:
+    if (td_ignore_mipmaps) {
+      return &lookup_texture_nearest;
+    }
+    return &lookup_texture_mipmap_linear;
+      
+  case Texture::FT_linear_mipmap_nearest:
+    if (td_ignore_mipmaps) {
+      return &lookup_texture_bilinear;
+    }
+    return &lookup_texture_mipmap_bilinear;
+
+  case Texture::FT_linear_mipmap_linear:
+    if (td_ignore_mipmaps) {
+      return &lookup_texture_bilinear;
+    }
+    return &lookup_texture_mipmap_trilinear;
+
+  default:
+    return &lookup_texture_nearest;
+  }
+}
+

+ 3 - 1
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -104,7 +104,7 @@ private:
   void do_issue_material();
   void do_issue_texture();
 
-  void apply_texture(TextureContext *tc);
+  bool apply_texture(TextureContext *tc);
   bool upload_texture(TinyTextureContext *gtc);
   bool setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels);
   int get_tex_shift(int orig_size);
@@ -119,6 +119,7 @@ private:
   void setup_material(GLMaterial *gl_material, const Material *material);
   static void load_matrix(M4 *matrix, const TransformState *transform);
   static int get_color_blend_op(ColorBlendAttrib::Operand operand);
+  static ZB_lookupTextureFunc get_tex_filter_func(Texture::FilterType filter);
 
 public:
   // Filled in by the Tiny*GraphicsWindow at begin_frame().
@@ -136,6 +137,7 @@ private:
     CMF_diffuse   = 0x002,
   };
   int _color_material_flags;
+  int _texturing_state;
   int _texfilter_state;
   bool _texture_replace;
 

+ 3 - 0
panda/src/tinydisplay/tinyOsxGraphicsWindow.mm

@@ -509,6 +509,9 @@ TinyOsxGraphicsWindow::TinyOsxGraphicsWindow(GraphicsPipe *pipe,
   _cursor_hidden = false;
   _display_hide_cursor = false;
   _wheel_delta = 0;
+
+  _frame_buffer = NULL;
+  update_pixel_factor();
   
   if (tinydisplay_cat.is_debug())	
     tinydisplay_cat.debug() << "TinyOsxGraphicsWindow::TinyOsxGraphicsWindow() -" <<_ID << "\n";

+ 140 - 12
panda/src/tinydisplay/zbuffer.cxx

@@ -8,6 +8,7 @@
 #include <assert.h>
 #include <string.h>
 #include "zbuffer.h"
+#include "pnotify.h"
 
 ZBuffer *ZB_open(int xsize, int ysize, int mode,
 		 int nb_colors,
@@ -343,8 +344,26 @@ void ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z,
 #define ZB_ST_FRAC_HIGH (1 << ZB_POINT_ST_FRAC_BITS)
 #define ZB_ST_FRAC_MASK (ZB_ST_FRAC_HIGH - 1)
 
-PIXEL lookup_texture_bilinear(ZTextureLevel *base_level, int s, int t)
+#define LINEAR_FILTER_BITSIZE(c1, c2, f, bitsize) \
+  ((((c2) * (f)) >> bitsize) + (((c1) * ((1 << bitsize) - (f))) >> bitsize))
+
+#define LINEAR_FILTER(c1, c2, f) \
+  LINEAR_FILTER_BITSIZE(c1, c2, f, ZB_POINT_ST_FRAC_BITS)
+
+#define BILINEAR_FILTER(c1, c2, c3, c4, sf, tf) \
+  (LINEAR_FILTER(LINEAR_FILTER(c1, c2, sf), LINEAR_FILTER(c3, c4, sf), tf))
+
+// Grab the nearest texel from the base level.  This is also
+// implemented inline as ZB_LOOKUP_TEXTURE_NEAREST.
+PIXEL lookup_texture_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
+{
+  return ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t);
+}
+
+// Bilinear filter four texels in the base level.
+PIXEL lookup_texture_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
 {
+  ZTextureLevel *base_level = texture_levels;
   PIXEL p1, p2, p3, p4;
   int sf, tf;
   int r, g, b, a;
@@ -356,18 +375,127 @@ PIXEL lookup_texture_bilinear(ZTextureLevel *base_level, int s, int t)
   p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t + ZB_ST_FRAC_HIGH);
   p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s + ZB_ST_FRAC_HIGH, t + ZB_ST_FRAC_HIGH);
   tf = t & ZB_ST_FRAC_MASK;
-  
-  r = (((PIXEL_R(p4) * sf + PIXEL_R(p3) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * tf +
-       ((PIXEL_R(p2) * sf + PIXEL_R(p1) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * (ZB_ST_FRAC_HIGH - tf)) >> ZB_POINT_ST_FRAC_BITS;
 
-  g = (((PIXEL_G(p4) * sf + PIXEL_G(p3) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * tf +
-       ((PIXEL_G(p2) * sf + PIXEL_G(p1) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * (ZB_ST_FRAC_HIGH - tf)) >> ZB_POINT_ST_FRAC_BITS;
-  
-  b = (((PIXEL_B(p4) * sf + PIXEL_B(p3) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * tf +
-       ((PIXEL_B(p2) * sf + PIXEL_B(p1) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * (ZB_ST_FRAC_HIGH - tf)) >> ZB_POINT_ST_FRAC_BITS;
-  
-  a = (((PIXEL_A(p4) * sf + PIXEL_A(p3) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * tf +
-       ((PIXEL_A(p2) * sf + PIXEL_A(p1) * (ZB_ST_FRAC_HIGH - sf)) >> ZB_POINT_ST_FRAC_BITS) * (ZB_ST_FRAC_HIGH - tf)) >> ZB_POINT_ST_FRAC_BITS;
+  r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
+  g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
+  b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
+  a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
+
+  return RGBA_TO_PIXEL(r, g, b, a);
+}
+
+// Grab the nearest texel from the nearest mipmap level.  This is also
+// implemented inline as ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST.
+PIXEL lookup_texture_mipmap_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
+{
+  return ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_levels, s, t, level);
+}
+
+// Linear filter the two texels from the two nearest mipmap levels.
+PIXEL lookup_texture_mipmap_linear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
+{
+  PIXEL p1, p2;
+  int r, g, b, a;
+
+  p1 = ZB_LOOKUP_TEXTURE_NEAREST(texture_levels + level - 1, s >> (level - 1), t >> (level - 1));
+  p2 = ZB_LOOKUP_TEXTURE_NEAREST(texture_levels + level, s >> level, t >> level);
+
+  unsigned int bitsize = (level - 1) + ZB_POINT_ST_FRAC_BITS;
+  r = LINEAR_FILTER_BITSIZE(PIXEL_R(p1), PIXEL_R(p2), level_dx, bitsize);
+  g = LINEAR_FILTER_BITSIZE(PIXEL_G(p1), PIXEL_G(p2), level_dx, bitsize);
+  b = LINEAR_FILTER_BITSIZE(PIXEL_B(p1), PIXEL_B(p2), level_dx, bitsize);
+  a = LINEAR_FILTER_BITSIZE(PIXEL_A(p1), PIXEL_A(p2), level_dx, bitsize); 
+
+  return RGBA_TO_PIXEL(r, g, b, a);
+}
+
+// Bilinear filter four texels in the nearest mipmap level.
+PIXEL lookup_texture_mipmap_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
+{
+  ZTextureLevel *base_level = texture_levels + level;
+  s >>= level;
+  t >>= level;
+
+  PIXEL p1, p2, p3, p4;
+  int sf, tf;
+  int r, g, b, a;
+
+  p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t);
+  p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s + ZB_ST_FRAC_HIGH, t);
+  sf = s & ZB_ST_FRAC_MASK;
+
+  p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s, t + ZB_ST_FRAC_HIGH);
+  p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, s + ZB_ST_FRAC_HIGH, t + ZB_ST_FRAC_HIGH);
+  tf = t & ZB_ST_FRAC_MASK;
+
+  r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
+  g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
+  b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
+  a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
+
+  return RGBA_TO_PIXEL(r, g, b, a);
+}
+
+// Bilinear filter four texels in each of the nearest two mipmap
+// levels, then linear filter them together.
+PIXEL lookup_texture_mipmap_trilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx)
+{
+  PIXEL p1a, p2a;
+
+  {
+    ZTextureLevel *base_level = texture_levels + level - 1;
+    int sl = s >> (level - 1);
+    int tl = t >> (level - 1);
+    
+    PIXEL p1, p2, p3, p4;
+    int sf, tf;
+    int r, g, b, a;
+    
+    p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl);
+    p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl + ZB_ST_FRAC_HIGH, tl);
+    sf = sl & ZB_ST_FRAC_MASK;
+    
+    p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl + ZB_ST_FRAC_HIGH);
+    p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl + ZB_ST_FRAC_HIGH, tl + ZB_ST_FRAC_HIGH);
+    tf = tl & ZB_ST_FRAC_MASK;
+    
+    r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
+    g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
+    b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
+    a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
+    p1a = RGBA_TO_PIXEL(r, g, b, a);
+  }
+
+  {
+    ZTextureLevel *base_level = texture_levels + level;
+    int sl = s >> level;
+    int tl = t >> level;
+    
+    PIXEL p1, p2, p3, p4;
+    int sf, tf;
+    int r, g, b, a;
+    
+    p1 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl);
+    p2 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl + ZB_ST_FRAC_HIGH, tl);
+    sf = sl & ZB_ST_FRAC_MASK;
+    
+    p3 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl, tl + ZB_ST_FRAC_HIGH);
+    p4 = ZB_LOOKUP_TEXTURE_NEAREST(base_level, sl + ZB_ST_FRAC_HIGH, tl + ZB_ST_FRAC_HIGH);
+    tf = tl & ZB_ST_FRAC_MASK;
+    
+    r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
+    g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
+    b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
+    a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
+    p2a = RGBA_TO_PIXEL(r, g, b, a);
+  }
+
+  int r, g, b, a;
+  unsigned int bitsize = (level - 1) + ZB_POINT_ST_FRAC_BITS;
+  r = LINEAR_FILTER_BITSIZE(PIXEL_R(p1a), PIXEL_R(p2a), level_dx, bitsize);
+  g = LINEAR_FILTER_BITSIZE(PIXEL_G(p1a), PIXEL_G(p2a), level_dx, bitsize);
+  b = LINEAR_FILTER_BITSIZE(PIXEL_B(p1a), PIXEL_B(p2a), level_dx, bitsize);
+  a = LINEAR_FILTER_BITSIZE(PIXEL_A(p1a), PIXEL_A(p2a), level_dx, bitsize); 
 
   return RGBA_TO_PIXEL(r, g, b, a);
 }

+ 17 - 12
panda/src/tinydisplay/zbuffer.h

@@ -33,7 +33,7 @@ typedef unsigned short ZPOINT;
 #define ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t) \
   (texture_levels)->pixmap[ZB_TEXEL(texture_levels, s, t)]
 
-#define ZB_LOOKUP_TEXTURE_NEAREST_MIPMAP(texture_levels, s, t, level) \
+#define ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_levels, s, t, level) \
   ZB_LOOKUP_TEXTURE_NEAREST((texture_levels) + (level), (s) >> (level), (t) >> (level))
 
 /* A special abs() function which doesn't require any branching
@@ -44,15 +44,11 @@ typedef unsigned short ZPOINT;
 //#define FAST_ABS(v) (((v) ^ ((v) >> (sizeof(v) * 8 - 1))) - ((v) >> (sizeof(v) * 8 - 1)))
 
 #define DO_CALC_MIPMAP_LEVEL \
-  mipmap_level = get_next_higher_bit(((unsigned int)abs(dsdx) + (unsigned int)abs(dtdx)) >> ZB_POINT_ST_FRAC_BITS)
-
-#if 0
-/* Experiment with bilinear filtering.  Looks great, but seems to run
-   about 25% slower. */
-#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level) \
-  lookup_texture_bilinear((texture_levels), (s), (t))
-
-#endif
+  { \
+    mipmap_dx = ((unsigned int)abs(dsdx) + (unsigned int)abs(dtdx)); \
+    mipmap_level = get_next_higher_bit(mipmap_dx >> ZB_POINT_ST_FRAC_BITS); \
+    mipmap_dx &= ((1 << ((mipmap_level - 1) + ZB_POINT_ST_FRAC_BITS)) - 1); \
+  }
 
 #define ZB_POINT_RED_MIN   0x0000
 #define ZB_POINT_RED_MAX   0xffff
@@ -106,7 +102,9 @@ typedef struct ZBufferPoint ZBufferPoint;
 typedef void (*ZB_fillTriangleFunc)(ZBuffer  *,
                                     ZBufferPoint *,ZBufferPoint *,ZBufferPoint *);
 
-typedef void (*ZB_storePixelFunc) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a);
+typedef void (*ZB_storePixelFunc)(ZBuffer *zb, PIXEL &result, int r, int g, int b, int a);
+
+typedef PIXEL (*ZB_lookupTextureFunc)(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
 
 struct ZBuffer {
   int xsize,ysize;
@@ -124,6 +122,8 @@ struct ZBuffer {
   int reference_alpha;
   int blend_r, blend_g, blend_b, blend_a;
   ZB_storePixelFunc store_pix_func;
+  ZB_lookupTextureFunc tex_minfilter_func;
+  ZB_lookupTextureFunc tex_magfilter_func;
 };
 
 struct ZBufferPoint {
@@ -152,7 +152,12 @@ void ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z,
                        int clear_color, unsigned int r, unsigned int g, unsigned int b, unsigned int a,
                        int xmin, int ymin, int xsize, int ysize);
 
-PIXEL lookup_texture_bilinear(ZTextureLevel *base_level, int s, int t);
+PIXEL lookup_texture_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
+PIXEL lookup_texture_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
+PIXEL lookup_texture_mipmap_nearest(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
+PIXEL lookup_texture_mipmap_linear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
+PIXEL lookup_texture_mipmap_bilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
+PIXEL lookup_texture_mipmap_trilinear(ZTextureLevel *texture_levels, int s, int t, unsigned int level, unsigned int level_dx);
 
 /* linesize is in BYTES */
 void ZB_copyFrameBuffer(ZBuffer *zb,void *buf,int linesize);

+ 1 - 1
panda/src/tinydisplay/zgl.h

@@ -146,7 +146,7 @@ typedef struct GLContext {
   /* textures */
   GLTexture *current_texture;
   int texture_2d_enabled;
-
+ 
   /* matrix */
   M4 matrix_projection;
   M4 matrix_model_view;

+ 1 - 1
panda/src/tinydisplay/ztriangle.h

@@ -34,7 +34,7 @@
   float tz1,dtzdx,dtzdy,dtzdl_min,dtzdl_max;
 #endif
 #if defined(INTERP_MIPMAP) && (defined(INTERP_ST) || defined(INTERP_STZ))
-  int mipmap_level;
+  unsigned int mipmap_dx, mipmap_level;
 #endif
 
   EARLY_OUT();

+ 4 - 3
panda/src/tinydisplay/ztriangle.py

@@ -24,7 +24,7 @@ Options = [
     [ 'znone', 'zless' ],
 
     # texture filters
-    [ 'nearest', 'mipmap' ],
+    [ 'tnearest', 'tmipmap', 'tgeneral' ],
     ]
 
 # The various combinations of these options are explicit within
@@ -60,8 +60,9 @@ CodeTable = {
     'zless' : '#define ZCMP(zpix, z) ((ZPOINT)(zpix) < (ZPOINT)(z))',
 
     # texture filters
-    'nearest' : '#define CALC_MIPMAP_LEVEL\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level) ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t)',
-    'mipmap' : '#define CALC_MIPMAP_LEVEL DO_CALC_MIPMAP_LEVEL\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level) ZB_LOOKUP_TEXTURE_NEAREST_MIPMAP(texture_levels, s, t, level)',
+    'tnearest' : '#define CALC_MIPMAP_LEVEL\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level, level_dx) ZB_LOOKUP_TEXTURE_NEAREST(texture_levels, s, t)',
+    'tmipmap' : '#define CALC_MIPMAP_LEVEL DO_CALC_MIPMAP_LEVEL\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level, level_dx) ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_levels, s, t, level)',
+    'tgeneral' : '#define CALC_MIPMAP_LEVEL DO_CALC_MIPMAP_LEVEL\n#define INTERP_MIPMAP\n#define ZB_LOOKUP_TEXTURE(texture_levels, s, t, level, level_dx) ((level == 0) ? zb->tex_magfilter_func(texture_levels, s, t, level, level_dx) : zb->tex_minfilter_func(texture_levels, s, t, level, level_dx))',
 }
 
 ops = [0] * len(Options)

File diff suppressed because it is too large
+ 446 - 126
panda/src/tinydisplay/ztriangle_code.h


+ 1 - 1
panda/src/tinydisplay/ztriangle_table.h

@@ -1,3 +1,3 @@
 /* This file is generated code--do not edit.  See ztriangle.py. */
 
-extern const ZB_fillTriangleFunc fill_tri_funcs[2][4][3][2][2][3][3];
+extern const ZB_fillTriangleFunc fill_tri_funcs[2][4][3][2][3][3][3];

+ 6 - 6
panda/src/tinydisplay/ztriangle_two.h

@@ -129,7 +129,7 @@ static void FNAME(white_textured) (ZBuffer *zb,
   {                                                                     \
     zz=z >> ZB_POINT_Z_FRAC_BITS;                                       \
     if (ZCMP(pz[_a], zz)) {                                             \
-      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level);      \
+      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx);      \
       if (ACMP(zb, PIXEL_A(tmp))) {                                     \
         STORE_PIX(pp[_a], tmp, PIXEL_R(tmp), PIXEL_G(tmp), PIXEL_B(tmp), PIXEL_A(tmp)); \
         STORE_Z(pz[_a], zz);                                            \
@@ -173,7 +173,7 @@ static void FNAME(flat_textured) (ZBuffer *zb,
   {                                                                     \
     zz=z >> ZB_POINT_Z_FRAC_BITS;                                       \
     if (ZCMP(pz[_a], zz)) {                                             \
-      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level);      \
+      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx);      \
       int a = oa0 * PIXEL_A(tmp) >> 16;                                 \
       if (ACMP(zb, a)) {                                                \
         STORE_PIX(pp[_a],                                               \
@@ -232,7 +232,7 @@ static void FNAME(smooth_textured) (ZBuffer *zb,
   {                                                                     \
     zz=z >> ZB_POINT_Z_FRAC_BITS;                                       \
     if (ZCMP(pz[_a], zz)) {                                             \
-      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level);      \
+      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx);      \
       int a = oa1 * PIXEL_A(tmp) >> 16;                                 \
       if (ACMP(zb, a)) {                                                \
         STORE_PIX(pp[_a],                                               \
@@ -293,7 +293,7 @@ static void FNAME(white_perspective) (ZBuffer *zb,
   {                                                                     \
     zz=z >> ZB_POINT_Z_FRAC_BITS;                                       \
     if (ZCMP(pz[_a], zz)) {                                             \
-      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level);      \
+      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx);      \
       if (ACMP(zb, PIXEL_A(tmp))) {                                     \
         STORE_PIX(pp[_a], tmp, PIXEL_R(tmp), PIXEL_G(tmp), PIXEL_B(tmp), PIXEL_A(tmp)); \
         STORE_Z(pz[_a], zz);                                            \
@@ -408,7 +408,7 @@ static void FNAME(flat_perspective) (ZBuffer *zb,
   {                                                                     \
     zz=z >> ZB_POINT_Z_FRAC_BITS;                                       \
     if (ZCMP(pz[_a], zz)) {                                             \
-      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level);      \
+      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx);      \
       int a = oa0 * PIXEL_A(tmp) >> 16;                                 \
       if (ACMP(zb, a)) {                                                \
         STORE_PIX(pp[_a],                                               \
@@ -541,7 +541,7 @@ static void FNAME(smooth_perspective) (ZBuffer *zb,
   {                                                                     \
     zz=z >> ZB_POINT_Z_FRAC_BITS;                                       \
     if (ZCMP(pz[_a], zz)) {                                             \
-      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level);      \
+      tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx);      \
       int a = oa1 * PIXEL_A(tmp) >> 16;                                 \
       if (ACMP(zb, a)) {                                                \
         STORE_PIX(pp[_a],                                               \

+ 3 - 1
pandatool/src/egg-mkfont/eggMakeFont.cxx

@@ -406,6 +406,7 @@ run() {
   PT(EggData) egg_data = new EggData;
   _group = new EggGroup();
   egg_data->add_child(_group);
+  append_command_comment(egg_data);
 
   _vpool = new EggVertexPool("vpool");
   _group->add_child(_vpool);
@@ -446,7 +447,7 @@ run() {
       texture->write(texture->read_source_image());
     }
 
-    write_egg_file();
+    egg_data->write_egg(get_output());
 
   } else {
     // Pass the generated egg structure through egg-palettize, without
@@ -641,6 +642,7 @@ make_tref(PNMTextGlyph *glyph, int character) {
   tref->set_wrap_mode(EggTexture::WM_clamp);
   tref->set_minfilter(EggTexture::FT_linear_mipmap_linear);
   tref->set_magfilter(EggTexture::FT_linear);
+  tref->set_quality_level(EggTexture::QL_best);
 
   return tref;
 }

+ 2 - 1
pandatool/src/palettizer/palettizer.cxx

@@ -41,7 +41,7 @@ Palettizer *pal = (Palettizer *)NULL;
 // allows us to easily update egg-palettize to write out additional
 // information to its pi file, without having it increment the bam
 // version number for all bam and boo files anywhere in the world.
-int Palettizer::_pi_version = 17;
+int Palettizer::_pi_version = 18;
 // Updated to version 8 on 3/20/03 to remove extensions from texture key names.
 // Updated to version 9 on 4/13/03 to add a few properties in various places.
 // Updated to version 10 on 4/15/03 to add _alpha_file_channel.
@@ -52,6 +52,7 @@ int Palettizer::_pi_version = 17;
 // Updated to version 15 on 8/01/05 to make TextureImages be case-insensitive.
 // Updated to version 16 on 4/03/06 to add Palettizer::_cutout_mode et al.
 // Updated to version 17 on 3/02/07 to add TextureImage::_txa_wrap_u etc.
+// Updated to version 18 on 5/13/08 to add TextureProperties::_quality_level.
 
 int Palettizer::_min_pi_version = 8;
 // Dropped support for versions 7 and below on 7/14/03.

+ 30 - 0
pandatool/src/palettizer/textureProperties.cxx

@@ -43,6 +43,7 @@ TextureProperties() {
   _keep_format = false;
   _minfilter = EggTexture::FT_unspecified;
   _magfilter = EggTexture::FT_unspecified;
+  _quality_level = EggTexture::QL_unspecified;
   _anisotropic_degree = 0;
   _color_type = (PNMFileType *)NULL;
   _alpha_type = (PNMFileType *)NULL;
@@ -61,6 +62,7 @@ TextureProperties(const TextureProperties &copy) :
   _keep_format(copy._keep_format),
   _minfilter(copy._minfilter),
   _magfilter(copy._magfilter),
+  _quality_level(copy._quality_level),
   _anisotropic_degree(copy._anisotropic_degree),
   _color_type(copy._color_type),
   _alpha_type(copy._alpha_type),
@@ -82,6 +84,7 @@ operator = (const TextureProperties &copy) {
   _keep_format = copy._keep_format;
   _minfilter = copy._minfilter;
   _magfilter = copy._magfilter;
+  _quality_level = copy._quality_level;
   _anisotropic_degree = copy._anisotropic_degree;
   _color_type = copy._color_type;
   _alpha_type = copy._alpha_type;
@@ -105,6 +108,7 @@ clear_basic() {
 
   _minfilter = EggTexture::FT_unspecified;
   _magfilter = EggTexture::FT_unspecified;
+  _quality_level = EggTexture::QL_unspecified;
   _anisotropic_degree = 0;
 }
 
@@ -249,6 +253,7 @@ update_properties(const TextureProperties &other) {
 
   _minfilter = union_filter(_minfilter, other._minfilter);
   _magfilter = union_filter(_magfilter, other._magfilter);
+  _quality_level = union_quality_level(_quality_level, other._quality_level);
 
   _anisotropic_degree = other._anisotropic_degree;
 
@@ -494,6 +499,7 @@ update_egg_tex(EggTexture *egg_tex) const {
   egg_tex->set_format(_format);
   egg_tex->set_minfilter(_minfilter);
   egg_tex->set_magfilter(_minfilter);
+  egg_tex->set_quality_level(_quality_level);
   egg_tex->set_anisotropic_degree(_anisotropic_degree);
 }
 
@@ -510,6 +516,7 @@ egg_properties_match(const TextureProperties &other) const {
   return (_format == other._format &&
           _minfilter == other._minfilter &&
           _magfilter == other._magfilter &&
+          _quality_level == other._quality_level &&
           _anisotropic_degree == other._anisotropic_degree);
 }
 
@@ -529,6 +536,9 @@ operator < (const TextureProperties &other) const {
   if (_magfilter != other._magfilter) {
     return (int)_magfilter < (int)other._magfilter;
   }
+  if (_quality_level != other._quality_level) {
+    return (int)_quality_level < (int)other._quality_level;
+  }
   if (_anisotropic_degree != other._anisotropic_degree) {
     return _anisotropic_degree < other._anisotropic_degree;
   }
@@ -553,6 +563,7 @@ operator == (const TextureProperties &other) const {
   return (_format == other._format &&
           _minfilter == other._minfilter &&
           _magfilter == other._magfilter &&
+          _quality_level == other._quality_level &&
           _anisotropic_degree == other._anisotropic_degree &&
           _color_type == other._color_type &&
           (_color_type == (PNMFileType *)NULL ||
@@ -759,6 +770,21 @@ union_filter(EggTexture::FilterType a, EggTexture::FilterType b) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureProperties::union_quality_level
+//       Access: Private, Static
+//  Description: Returns the EggTexture quality level which is the
+//               more specific of the two.
+////////////////////////////////////////////////////////////////////
+EggTexture::QualityLevel TextureProperties::
+union_quality_level(EggTexture::QualityLevel a, EggTexture::QualityLevel b) {
+  if ((int)a < (int)b) {
+    return b;
+  } else {
+    return a;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureProperties::register_with_read_factory
 //       Access: Public, Static
@@ -790,6 +816,7 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
   datagram.add_bool(_keep_format);
   datagram.add_int32((int)_minfilter);
   datagram.add_int32((int)_magfilter);
+  datagram.add_int32((int)_quality_level);
   datagram.add_int32(_anisotropic_degree);
   writer->write_pointer(datagram, _color_type);
   writer->write_pointer(datagram, _alpha_type);
@@ -868,6 +895,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   }
   _minfilter = (EggTexture::FilterType)scan.get_int32();
   _magfilter = (EggTexture::FilterType)scan.get_int32();
+  if (Palettizer::_read_pi_version >= 18) {
+    _quality_level = (EggTexture::QualityLevel)scan.get_int32();
+  }
   _anisotropic_degree = scan.get_int32();
 
   manager->read_pointer(scan);  // _color_type

+ 3 - 0
pandatool/src/palettizer/textureProperties.h

@@ -66,6 +66,7 @@ public:
   bool _generic_format; // true if 'generic' keyword, meaning rgba8 -> rgba.
   bool _keep_format;   // true if 'keep-format' keyword.
   EggTexture::FilterType _minfilter, _magfilter;
+  EggTexture::QualityLevel _quality_level;
   int _anisotropic_degree;
   PNMFileType *_color_type;
   PNMFileType *_alpha_type;
@@ -82,6 +83,8 @@ private:
 
   static EggTexture::FilterType union_filter(EggTexture::FilterType a,
                                              EggTexture::FilterType b);
+  static EggTexture::QualityLevel union_quality_level(EggTexture::QualityLevel a,
+                                                      EggTexture::QualityLevel b);
 
   bool _got_num_channels;
   int _num_channels;

+ 1 - 0
pandatool/src/palettizer/textureReference.cxx

@@ -106,6 +106,7 @@ from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) {
   _properties._format = _egg_tex->get_format();
   _properties._minfilter = _egg_tex->get_minfilter();
   _properties._magfilter = _egg_tex->get_magfilter();
+  _properties._quality_level = _egg_tex->get_quality_level();
   _properties._anisotropic_degree = _egg_tex->get_anisotropic_degree();
 
   string name = filename.get_basename_wo_extension();

Some files were not shown because too many files changed in this diff