From 98a4f2120789893ffd8462b9a2e0285f64b16e04 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 1 May 2001 05:45:56 +0000 Subject: [PATCH] *** empty log message *** --- panda/src/egg/Sources.pp | 8 +- panda/src/egg/eggData.cxx | 38 +- panda/src/egg/eggData.h | 1 + panda/src/egg/eggGroupNode.cxx | 47 +++ panda/src/egg/eggGroupNode.h | 3 + panda/src/egg/eggMaterial.I | 114 ++++- panda/src/egg/eggMaterial.cxx | 122 ++++++ panda/src/egg/eggMaterial.h | 45 +- panda/src/egg/eggMaterialCollection.I | 27 ++ panda/src/egg/eggMaterialCollection.cxx | 440 ++++++++++++++++++++ panda/src/egg/eggMaterialCollection.h | 92 ++++ panda/src/egg/eggTexture.cxx | 30 +- panda/src/egg/eggTexture.h | 12 +- panda/src/egg/parser.yxx | 6 + panda/src/egg2sg/eggLoader.cxx | 69 +++ panda/src/egg2sg/eggLoader.h | 10 + panda/src/glgsg/glGraphicsStateGuardian.I | 17 + panda/src/glgsg/glGraphicsStateGuardian.cxx | 99 ++++- panda/src/glgsg/glGraphicsStateGuardian.h | 3 + panda/src/gobj/material.I | 12 +- panda/src/gobj/material.cxx | 41 +- pandatool/src/lwoegg/cLwoSurface.cxx | 50 +++ pandatool/src/lwoegg/cLwoSurface.h | 6 + pandatool/src/lwoegg/lwoToEggConverter.cxx | 1 + pandatool/src/lwoegg/lwoToEggConverter.h | 2 + 25 files changed, 1231 insertions(+), 64 deletions(-) create mode 100644 panda/src/egg/eggMaterialCollection.I create mode 100644 panda/src/egg/eggMaterialCollection.cxx create mode 100644 panda/src/egg/eggMaterialCollection.h diff --git a/panda/src/egg/Sources.pp b/panda/src/egg/Sources.pp index 52e672465f..a143cf6e16 100644 --- a/panda/src/egg/Sources.pp +++ b/panda/src/egg/Sources.pp @@ -19,7 +19,10 @@ eggFilenameNode.cxx eggFilenameNode.h eggGroup.I eggGroup.cxx \ eggGroup.h eggGroupNode.I eggGroupNode.cxx eggGroupNode.h \ eggGroupUniquifier.h eggGroupUniquifier.cxx \ - eggMaterial.I eggMaterial.cxx eggMaterial.h eggMiscFuncs.I \ + eggMaterial.I eggMaterial.cxx eggMaterial.h \ + eggMaterialCollection.I eggMaterialCollection.cxx \ + eggMaterialCollection.h \ + eggMiscFuncs.I \ eggMiscFuncs.cxx eggMiscFuncs.h eggNamedObject.I eggNamedObject.cxx \ eggNamedObject.h eggNameUniquifier.cxx eggNameUniquifier.h \ eggNode.I eggNode.cxx eggNode.h eggNurbsCurve.I \ @@ -51,7 +54,8 @@ eggExternalReference.h eggFilenameNode.I eggFilenameNode.h \ eggGroup.I eggGroup.h eggGroupNode.I eggGroupNode.h \ eggGroupUniquifier.h eggMaterial.I \ - eggMaterial.h eggMorph.I eggMorph.h eggMorphList.I eggMorphList.h \ + eggMaterial.h eggMaterialCollection.I eggMaterialCollection.h \ + eggMorph.I eggMorph.h eggMorphList.I eggMorphList.h \ eggNamedObject.I eggNamedObject.h eggNameUniquifier.h eggNode.I eggNode.h \ eggNurbsCurve.I eggNurbsCurve.h eggNurbsSurface.I eggNurbsSurface.h \ eggObject.I eggObject.h eggParameters.h eggPoint.I eggPoint.h \ diff --git a/panda/src/egg/eggData.cxx b/panda/src/egg/eggData.cxx index 3de4544013..aa79f89336 100644 --- a/panda/src/egg/eggData.cxx +++ b/panda/src/egg/eggData.cxx @@ -6,6 +6,7 @@ #include "eggData.h" #include "eggCoordinateSystem.h" #include "eggTextureCollection.h" +#include "eggMaterialCollection.h" #include "eggComment.h" #include "eggPoolUniquifier.h" #include "config_egg.h" @@ -133,9 +134,9 @@ resolve_externals(const DSearchPath &searchpath) { // Description: Removes duplicate references to the same texture // image with the same properties. Considers two // texture references with identical properties, but -// different tref names, to be the equivalent, and -// collapses them, choosing one tref name to keep -// arbitrarily. Returns the number of textures removed. +// different tref names, to be equivalent, and collapses +// them, choosing one tref name to keep arbitrarily. +// Returns the number of textures removed. //////////////////////////////////////////////////////////////////// int EggData:: collapse_equivalent_textures() { @@ -145,6 +146,24 @@ collapse_equivalent_textures() { textures.collapse_equivalent_textures(~EggTexture::E_tref_name, this); } +//////////////////////////////////////////////////////////////////// +// Function: EggData::collapse_equivalent_materials +// Access: Public +// Description: Removes duplicate references to the same material +// with the same properties. Considers two material +// references with identical properties, but different +// mref names, to be equivalent, and collapses them, +// choosing one mref name to keep arbitrarily. Returns +// the number of materials removed. +//////////////////////////////////////////////////////////////////// +int EggData:: +collapse_equivalent_materials() { + EggMaterialCollection materials; + materials.find_used_materials(this); + return + materials.collapse_equivalent_materials(~EggMaterial::E_mref_name, this); +} + //////////////////////////////////////////////////////////////////// // Function: EggData::write_egg // Access: Public @@ -286,8 +305,17 @@ pre_write() { textures.insert_textures(this, ci); - // Also make sure that the vertex pools and materials are uniquely - // named. This also checks textures, which is kind of redundant + // Do the same thing with the materials. + EggMaterialCollection materials; + materials.extract_materials(this); + materials.remove_unused_materials(this); + materials.collapse_equivalent_materials(~0, this); + materials.uniquify_mrefs(); + materials.sort_by_mref(); + materials.insert_materials(this, ci); + + // Also make sure that the vertex pools are uniquely named. This + // also checks textures and materials, which is kind of redundant // since we just did that, but we don't mind. EggPoolUniquifier pu; pu.uniquify(this); diff --git a/panda/src/egg/eggData.h b/panda/src/egg/eggData.h index 7e516d4b41..ecebddf0dd 100644 --- a/panda/src/egg/eggData.h +++ b/panda/src/egg/eggData.h @@ -44,6 +44,7 @@ public: bool resolve_externals(const DSearchPath &searchpath = DSearchPath()); int collapse_equivalent_textures(); + int collapse_equivalent_materials(); bool write_egg(Filename filename); bool write_egg(ostream &out); diff --git a/panda/src/egg/eggGroupNode.cxx b/panda/src/egg/eggGroupNode.cxx index 34c0b9d5b6..94770d58bf 100644 --- a/panda/src/egg/eggGroupNode.cxx +++ b/panda/src/egg/eggGroupNode.cxx @@ -13,6 +13,7 @@ #include "eggVertexPool.h" #include "eggVertex.h" #include "eggTextureCollection.h" +#include "eggMaterialCollection.h" #include "config_egg.h" #include @@ -830,6 +831,52 @@ find_textures(EggTextureCollection *collection) { return num_found; } +//////////////////////////////////////////////////////////////////// +// Function: EggGroupNode::find_materials() +// Access: Protected +// Description: Walks the tree, looking for EggMaterials. Each +// EggMaterial that is found is removed from the +// hierarchy and added to the EggMaterialCollection. +// Returns the number of EggMaterials found. +//////////////////////////////////////////////////////////////////// +int EggGroupNode:: +find_materials(EggMaterialCollection *collection) { + int num_found = 0; + + // We can do this ci/cnext iteration through the list as we modify + // it, only because we know this works with an STL list type + // container. If this were a vector or a set, this wouldn't + // necessarily work. + + Children::iterator ci, cnext; + ci = _children.begin(); + while (ci != _children.end()) { + cnext = ci; + ++cnext; + EggNode *child = *ci; + + if (child->is_of_type(EggMaterial::get_class_type())) { + PT(EggMaterial) tex = DCAST(EggMaterial, child); + + // Now remove the EggMaterial entry from our child list. + prepare_remove_child(tex); + _children.erase(ci); + + // And add it to the collection. + collection->add_material(tex); + num_found++; + + } else if (child->is_of_type(EggGroupNode::get_class_type())) { + num_found += + DCAST(EggGroupNode, child)->find_materials(collection); + } + + ci = cnext; + } + + return num_found; +} + //////////////////////////////////////////////////////////////////// // Function: EggGroupNode::r_resolve_externals // Access: Protected diff --git a/panda/src/egg/eggGroupNode.h b/panda/src/egg/eggGroupNode.h index 4fabc62c63..b5be8a2adb 100644 --- a/panda/src/egg/eggGroupNode.h +++ b/panda/src/egg/eggGroupNode.h @@ -18,6 +18,7 @@ #include class EggTextureCollection; +class EggMaterialCollection; class EggPolygon; class EggVertex; class DSearchPath; @@ -119,6 +120,7 @@ protected: CoordinateSystem find_coordsys_entry(); int find_textures(EggTextureCollection *collection); + int find_materials(EggMaterialCollection *collection); bool r_resolve_externals(const DSearchPath &searchpath, CoordinateSystem coordsys); @@ -163,6 +165,7 @@ private: static TypeHandle _type_handle; friend class EggTextureCollection; + friend class EggMaterialCollection; }; #include "eggGroupNode.I" diff --git a/panda/src/egg/eggMaterial.I b/panda/src/egg/eggMaterial.I index 142a789c95..52012963c1 100644 --- a/panda/src/egg/eggMaterial.I +++ b/panda/src/egg/eggMaterial.I @@ -141,7 +141,7 @@ get_emit() const { if (has_emit()) { return _emit; } else { - return RGBColorf(1.0, 1.0, 1.0); + return RGBColorf(0.0, 0.0, 0.0); } } @@ -188,6 +188,116 @@ get_spec() const { if (has_spec()) { return _spec; } else { - return RGBColorf(1.0, 1.0, 1.0); + return RGBColorf(0.0, 0.0, 0.0); } } + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::set_shininess +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void EggMaterial:: +set_shininess(double shininess) { + _shininess = shininess; + _flags |= F_shininess; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::clear_shininess +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void EggMaterial:: +clear_shininess() { + _flags &= ~F_shininess; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::has_shininess +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool EggMaterial:: +has_shininess() const { + return (_flags & F_shininess) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::get_shininess +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE double EggMaterial:: +get_shininess() const { + if (has_shininess()) { + return _shininess; + } else { + return 0.0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::set_local +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void EggMaterial:: +set_local(bool local) { + _local = local; + _flags |= F_local; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::clear_local +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void EggMaterial:: +clear_local() { + _flags &= ~F_local; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::has_local +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool EggMaterial:: +has_local() const { + return (_flags & F_local) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::get_local +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool EggMaterial:: +get_local() const { + if (has_local()) { + return _local; + } else { + return 0.0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: UniqueEggMaterials::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE UniqueEggMaterials:: +UniqueEggMaterials(int eq) : _eq(eq) { +} + +//////////////////////////////////////////////////////////////////// +// Function: UniqueEggMaterials::Function operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool UniqueEggMaterials:: +operator ()(const EggMaterial *t1, const EggMaterial *t2) const { + return t1->sorts_less_than(*t2, _eq); +} + diff --git a/panda/src/egg/eggMaterial.cxx b/panda/src/egg/eggMaterial.cxx index 88beda4b7d..5ac8d996f7 100644 --- a/panda/src/egg/eggMaterial.cxx +++ b/panda/src/egg/eggMaterial.cxx @@ -55,5 +55,127 @@ write(ostream &out, int indent_level) const { << " diffb { " << get_diff()[2] << " }\n"; } + if (has_amb()) { + indent(out, indent_level + 2) + << " ambr { " << get_amb()[0] << " }\n"; + indent(out, indent_level + 2) + << " ambg { " << get_amb()[1] << " }\n"; + indent(out, indent_level + 2) + << " ambb { " << get_amb()[2] << " }\n"; + } + + if (has_emit()) { + indent(out, indent_level + 2) + << " emitr { " << get_emit()[0] << " }\n"; + indent(out, indent_level + 2) + << " emitg { " << get_emit()[1] << " }\n"; + indent(out, indent_level + 2) + << " emitb { " << get_emit()[2] << " }\n"; + } + + if (has_spec()) { + indent(out, indent_level + 2) + << " specr { " << get_spec()[0] << " }\n"; + indent(out, indent_level + 2) + << " specg { " << get_spec()[1] << " }\n"; + indent(out, indent_level + 2) + << " specb { " << get_spec()[2] << " }\n"; + } + + if (has_shininess()) { + indent(out, indent_level + 2) + << " shininess { " << get_shininess() << " }\n"; + } + + if (has_local()) { + indent(out, indent_level + 2) + << " local { " << get_local() << " }\n"; + } + indent(out, indent_level) << "}\n"; } + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::is_equivalent_to +// Access: Public +// Description: Returns true if the two materials are equivalent in +// all relevant properties (according to eq), false +// otherwise. +// +// The Equivalence parameter, eq, should be set to the +// bitwise OR of the following properties, according to +// what you consider relevant: +// +// EggMaterial::E_attributes: +// All material attributes (diff, spec, +// etc.) except MRef name. +// +// EggMaterial::E_mref_name: +// The MRef name. +//////////////////////////////////////////////////////////////////// +bool EggMaterial:: +is_equivalent_to(const EggMaterial &other, int eq) const { + if (eq & E_attributes) { + if (_flags != other._flags || + (has_diff() && get_diff() != other.get_diff()) || + (has_amb() && get_amb() != other.get_amb()) || + (has_emit() && get_emit() != other.get_emit()) || + (has_spec() && get_spec() != other.get_spec()) || + (has_shininess() && get_shininess() != other.get_shininess()) || + (has_local() && get_local() != other.get_local())) { + return false; + } + } + + if (eq & E_mref_name) { + if (get_name() != other.get_name()) { + return false; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterial::sorts_less_than +// Access: Public +// Description: An ordering operator to compare two materials for +// sorting order. This imposes an arbitrary ordering +// useful to identify unique materials, according to the +// indicated Equivalence factor. See +// is_equivalent_to(). +//////////////////////////////////////////////////////////////////// +bool EggMaterial:: +sorts_less_than(const EggMaterial &other, int eq) const { + if (eq & E_attributes) { + if (_flags != other._flags) { + return _flags < (int)other._flags; + } + if (has_diff() && get_diff() != other.get_diff()) { + return get_diff().compare_to(other.get_diff()) < 0; + } + if (has_amb() && get_amb() != other.get_amb()) { + return get_amb().compare_to(other.get_amb()) < 0; + } + if (has_emit() && get_emit() != other.get_emit()) { + return get_emit().compare_to(other.get_emit()) < 0; + } + if (has_spec() && get_spec() != other.get_spec()) { + return get_spec().compare_to(other.get_spec()) < 0; + } + if (has_shininess() && get_shininess() != other.get_shininess()) { + return get_shininess() < other.get_shininess() ? -1 : 1; + } + if (has_local() && get_local() != other.get_local()) { + return get_local() - other.get_local(); + } + } + + if (eq & E_mref_name) { + if (get_name() != other.get_name()) { + return get_name() < other.get_name(); + } + } + + return false; +} diff --git a/panda/src/egg/eggMaterial.h b/panda/src/egg/eggMaterial.h index 5a44e40f7f..5a0ed25b25 100644 --- a/panda/src/egg/eggMaterial.h +++ b/panda/src/egg/eggMaterial.h @@ -23,6 +23,14 @@ public: virtual void write(ostream &out, int indent_level) const; + enum Equivalence { + E_attributes = 0x001, + E_mref_name = 0x002, + }; + + bool is_equivalent_to(const EggMaterial &other, int eq) const; + bool sorts_less_than(const EggMaterial &other, int eq) const; + INLINE void set_diff(const RGBColorf &diff); INLINE void clear_diff(); INLINE bool has_diff() const; @@ -43,18 +51,32 @@ public: INLINE bool has_spec() const; INLINE RGBColorf get_spec() const; + INLINE void set_shininess(double shininess); + INLINE void clear_shininess(); + INLINE bool has_shininess() const; + INLINE double get_shininess() const; + + INLINE void set_local(bool local); + INLINE void clear_local(); + INLINE bool has_local() const; + INLINE bool get_local() const; + private: enum Flags { - F_diff = 0x001, - F_amb = 0x002, - F_emit = 0x004, - F_spec = 0x008 + F_diff = 0x001, + F_amb = 0x002, + F_emit = 0x004, + F_spec = 0x008, + F_shininess = 0x010, + F_local = 0x020 }; RGBColorf _diff; RGBColorf _amb; RGBColorf _emit; RGBColorf _spec; + double _shininess; + bool _local; int _flags; @@ -76,6 +98,21 @@ private: static TypeHandle _type_handle; }; +/////////////////////////////////////////////////////////////////// +// Class : UniqueEggMaterials +// Description : An STL function object for sorting materials into +// order by properties. Returns true if the two +// referenced EggMaterial pointers are in sorted order, +// false otherwise. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEGG UniqueEggMaterials { +public: + INLINE UniqueEggMaterials(int eq = ~0); + INLINE bool operator ()(const EggMaterial *t1, const EggMaterial *t2) const; + + int _eq; +}; + #include "eggMaterial.I" #endif diff --git a/panda/src/egg/eggMaterialCollection.I b/panda/src/egg/eggMaterialCollection.I new file mode 100644 index 0000000000..8c91dd2ade --- /dev/null +++ b/panda/src/egg/eggMaterialCollection.I @@ -0,0 +1,27 @@ +// Filename: eggMaterialCollection.I +// Created by: drose (30Apr01) +// +//////////////////////////////////////////////////////////////////// + +INLINE EggMaterialCollection::iterator EggMaterialCollection:: +begin() const { + nassertr(_ordered_materials.size() == _materials.size(), + _ordered_materials.begin()); + return _ordered_materials.begin(); +} + +INLINE EggMaterialCollection::iterator EggMaterialCollection:: +end() const { + return _ordered_materials.end(); +} + +INLINE bool EggMaterialCollection:: +empty() const { + return _ordered_materials.empty(); +} + +INLINE EggMaterialCollection::size_type EggMaterialCollection:: +size() const { + nassertr(_ordered_materials.size() == _materials.size(), 0); + return _ordered_materials.size(); +} diff --git a/panda/src/egg/eggMaterialCollection.cxx b/panda/src/egg/eggMaterialCollection.cxx new file mode 100644 index 0000000000..16c267e337 --- /dev/null +++ b/panda/src/egg/eggMaterialCollection.cxx @@ -0,0 +1,440 @@ +// Filename: eggMaterialCollection.cxx +// Created by: drose (30Apr01) +// +//////////////////////////////////////////////////////////////////// + +#include "eggMaterialCollection.h" +#include "eggGroupNode.h" +#include "eggPrimitive.h" +#include "eggMaterial.h" + +#include + +#include + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +EggMaterialCollection:: +EggMaterialCollection() { +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +EggMaterialCollection:: +EggMaterialCollection(const EggMaterialCollection ©) : + _materials(copy._materials), + _ordered_materials(copy._ordered_materials) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +EggMaterialCollection &EggMaterialCollection:: +operator = (const EggMaterialCollection ©) { + _materials = copy._materials; + _ordered_materials = copy._ordered_materials; + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::clear +// Access: Public +// Description: Removes all materials from the collection. +//////////////////////////////////////////////////////////////////// +void EggMaterialCollection:: +clear() { + _materials.clear(); + _ordered_materials.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::extract_materials +// Access: Public +// Description: Walks the egg hierarchy beginning at the indicated +// node, and removes any EggMaterials encountered in the +// hierarchy, adding them to the collection. Returns +// the number of EggMaterials encountered. +//////////////////////////////////////////////////////////////////// +int EggMaterialCollection:: +extract_materials(EggGroupNode *node) { + // Since this traversal is destructive, we'll handle it within the + // EggGroupNode code. + return node->find_materials(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::insert_materials +// Access: Public +// Description: Adds a series of EggMaterial nodes to the beginning of +// the indicated node to reflect each of the materials in +// the collection. Returns the number of material nodes +// added. +//////////////////////////////////////////////////////////////////// +int EggMaterialCollection:: +insert_materials(EggGroupNode *node) { + return insert_materials(node, node->begin()); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::insert_materials +// Access: Public +// Description: Adds a series of EggMaterial nodes to the beginning of +// the indicated node to reflect each of the materials in +// the collection. Returns the number of material nodes +// added. +//////////////////////////////////////////////////////////////////// +int EggMaterialCollection:: +insert_materials(EggGroupNode *node, EggGroupNode::iterator position) { + OrderedMaterials::iterator oti; + for (oti = _ordered_materials.begin(); + oti != _ordered_materials.end(); + ++oti) { + node->insert(position, (*oti).p()); + } + + return size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::find_used_materials +// Access: Public +// Description: Walks the egg hierarchy beginning at the indicated +// node, looking for materials that are referenced by +// primitives but are not already members of the +// collection, adding them to the collection. +// +// If this is called following extract_materials(), it +// can be used to pick up any additional material +// references that appeared in the egg hierarchy (but +// whose EggMaterial node was not actually part of the +// hierarchy). +// +// If this is called in lieu of extract_materials(), it +// will fill up the collection with all of the +// referenced materials (and only the referenced +// materials), without destructively removing the +// EggMaterials from the hierarchy. +// +// This also has the side effect of incrementing the +// internal usage count for a material in the collection +// each time a material reference is encountered. This +// side effect is taken advantage of by +// remove_unused_materials(). +//////////////////////////////////////////////////////////////////// +int EggMaterialCollection:: +find_used_materials(EggNode *node) { + int num_found = 0; + + if (node->is_of_type(EggPrimitive::get_class_type())) { + EggPrimitive *primitive = DCAST(EggPrimitive, node); + if (primitive->has_material()) { + EggMaterial *tex = primitive->get_material(); + Materials::iterator ti = _materials.find(tex); + if (ti == _materials.end()) { + // Here's a new material! + num_found++; + _materials.insert(Materials::value_type(tex, 1)); + _ordered_materials.push_back(tex); + } else { + // Here's a material we'd already known about. Increment its + // usage count. + (*ti).second++; + } + } + + } else if (node->is_of_type(EggGroupNode::get_class_type())) { + EggGroupNode *group = DCAST(EggGroupNode, node); + + EggGroupNode::iterator ci; + for (ci = group->begin(); ci != group->end(); ++ci) { + EggNode *child = *ci; + + num_found += find_used_materials(child); + } + } + + return num_found; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::remove_unused_materials +// Access: Public +// Description: Removes any materials from the collection that aren't +// referenced by any primitives in the indicated egg +// hierarchy. This also, incidentally, adds materials to +// the collection that had been referenced by primitives +// but had not previously appeared in the collection. +//////////////////////////////////////////////////////////////////// +void EggMaterialCollection:: +remove_unused_materials(EggNode *node) { + // We'll do this the easy way: First, we'll remove *all* the + // materials from the collection, and then we'll add back only those + // that appear in the hierarchy. + clear(); + find_used_materials(node); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::collapse_equivalent_materials +// Access: Public +// Description: Walks through the collection and collapses together +// any separate materials that are equivalent according +// to the indicated equivalence factor, eq (see +// EggMaterial::is_equivalent_to()). The return value is +// the number of materials removed. +// +// This flavor of collapse_equivalent_materials() +// automatically adjusts all the primitives in the egg +// hierarchy to refer to the new material pointers. +//////////////////////////////////////////////////////////////////// +int EggMaterialCollection:: +collapse_equivalent_materials(int eq, EggGroupNode *node) { + MaterialReplacement removed; + int num_collapsed = collapse_equivalent_materials(eq, removed); + + // And now walk the egg hierarchy and replace any references to a + // removed material with its replacement. + replace_materials(node, removed); + + return num_collapsed; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::collapse_equivalent_materials +// Access: Public +// Description: Walks through the collection and collapses together +// any separate materials that are equivalent according +// to the indicated equivalence factor, eq (see +// EggMaterial::is_equivalent_to()). The return value is +// the number of materials removed. +// +// This flavor of collapse_equivalent_materials() does +// not adjust any primitives in the egg hierarchy; +// instead, it fills up the 'removed' map with an entry +// for each removed material, mapping it back to the +// equivalent retained material. It's up to the user to +// then call replace_materials() with this map, if +// desired, to apply these changes to the egg hierarchy. +//////////////////////////////////////////////////////////////////// +int EggMaterialCollection:: +collapse_equivalent_materials(int eq, EggMaterialCollection::MaterialReplacement &removed) { + int num_collapsed = 0; + + typedef set Collapser; + UniqueEggMaterials uet(eq); + Collapser collapser(uet); + + // First, put all of the materials into the Collapser structure, to + // find out the unique materials. + OrderedMaterials::const_iterator oti; + for (oti = _ordered_materials.begin(); + oti != _ordered_materials.end(); + ++oti) { + EggMaterial *tex = (*oti); + + pair result = collapser.insert(tex); + if (!result.second) { + // This material is non-unique; another one was already there. + EggMaterial *first = *(result.first); + removed.insert(MaterialReplacement::value_type(tex, first)); + num_collapsed++; + } + } + + // Now record all of the unique materials only. + clear(); + Collapser::const_iterator ci; + for (ci = collapser.begin(); ci != collapser.end(); ++ci) { + add_material(*ci); + } + + return num_collapsed; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::replace_materials +// Access: Public, Static +// Description: Walks the egg hierarchy, changing out any reference +// to a material appearing on the left side of the map +// with its corresponding material on the right side. +// This is most often done following a call to +// collapse_equivalent_materials(). It does not directly +// affect the Collection. +//////////////////////////////////////////////////////////////////// +void EggMaterialCollection:: +replace_materials(EggGroupNode *node, + const EggMaterialCollection::MaterialReplacement &replace) { + EggGroupNode::iterator ci; + for (ci = node->begin(); + ci != node->end(); + ++ci) { + EggNode *child = *ci; + if (child->is_of_type(EggPrimitive::get_class_type())) { + EggPrimitive *primitive = DCAST(EggPrimitive, child); + if (primitive->has_material()) { + PT(EggMaterial) tex = primitive->get_material(); + MaterialReplacement::const_iterator ri; + ri = replace.find(tex); + if (ri != replace.end()) { + // Here's a material we want to replace. + primitive->set_material((*ri).second); + } + } + + } else if (child->is_of_type(EggGroupNode::get_class_type())) { + EggGroupNode *group_child = DCAST(EggGroupNode, child); + replace_materials(group_child, replace); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::uniquify_mrefs +// Access: Public +// Description: Guarantees that each material in the collection has a +// unique MRef name. This is essential before writing +// an egg file. +//////////////////////////////////////////////////////////////////// +void EggMaterialCollection:: +uniquify_mrefs() { + NameUniquifier nu(".mref", "mref"); + + OrderedMaterials::const_iterator oti; + for (oti = _ordered_materials.begin(); + oti != _ordered_materials.end(); + ++oti) { + EggMaterial *tex = (*oti); + + tex->set_name(nu.add_name(tex->get_name())); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::sort_by_mref +// Access: Public +// Description: Sorts all the materials into alphabetical order by +// MRef name. Subsequent operations using begin()/end() +// will traverse in this sorted order. +//////////////////////////////////////////////////////////////////// +void EggMaterialCollection:: +sort_by_mref() { + sort(_ordered_materials.begin(), _ordered_materials.end(), + NamableOrderByName()); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::add_material +// Access: Public +// Description: Explicitly adds a new material to the collection. +// Returns true if the material was added, false if it +// was already there or if there was some error. +//////////////////////////////////////////////////////////////////// +bool EggMaterialCollection:: +add_material(EggMaterial *material) { + nassertr(_materials.size() == _ordered_materials.size(), false); + + PT(EggMaterial) new_tex = material; + + Materials::const_iterator ti; + ti = _materials.find(new_tex); + if (ti != _materials.end()) { + // This material is already a member of the collection. + return false; + } + + _materials.insert(Materials::value_type(new_tex, 0)); + _ordered_materials.push_back(new_tex); + + nassertr(_materials.size() == _ordered_materials.size(), false); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::remove_material +// Access: Public +// Description: Explicitly removes a material from the collection. +// Returns true if the material was removed, false if it +// wasn't there or if there was some error. +//////////////////////////////////////////////////////////////////// +bool EggMaterialCollection:: +remove_material(EggMaterial *material) { + nassertr(_materials.size() == _ordered_materials.size(), false); + + Materials::iterator ti; + ti = _materials.find(material); + if (ti == _materials.end()) { + // This material is not a member of the collection. + return false; + } + + _materials.erase(ti); + + OrderedMaterials::iterator oti; + PT(EggMaterial) ptex = material; + oti = find(_ordered_materials.begin(), _ordered_materials.end(), ptex); + nassertr(oti != _ordered_materials.end(), false); + + _ordered_materials.erase(oti); + + nassertr(_materials.size() == _ordered_materials.size(), false); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::create_unique_material +// Access: Public +// Description: Creates a new material if there is not already one +// equivalent (according to eq, see +// EggMaterial::is_equivalent_to()) to the indicated +// material, or returns the existing one if there is. +//////////////////////////////////////////////////////////////////// +EggMaterial *EggMaterialCollection:: +create_unique_material(const EggMaterial ©, int eq) { + // This requires a complete linear traversal, not terribly + // efficient. + OrderedMaterials::const_iterator oti; + for (oti = _ordered_materials.begin(); + oti != _ordered_materials.end(); + ++oti) { + EggMaterial *tex = (*oti); + if (copy.is_equivalent_to(*tex, eq)) { + return tex; + } + } + + EggMaterial *new_material = new EggMaterial(copy); + add_material(new_material); + return new_material; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMaterialCollection::find_mref +// Access: Public +// Description: Returns the material with the indicated MRef name, or +// NULL if no material matches. +//////////////////////////////////////////////////////////////////// +EggMaterial *EggMaterialCollection:: +find_mref(const string &mref_name) const { + // This requires a complete linear traversal, not terribly + // efficient. + OrderedMaterials::const_iterator oti; + for (oti = _ordered_materials.begin(); + oti != _ordered_materials.end(); + ++oti) { + EggMaterial *tex = (*oti); + if (tex->get_name() == mref_name) { + return tex; + } + } + + return (EggMaterial *)NULL; +} diff --git a/panda/src/egg/eggMaterialCollection.h b/panda/src/egg/eggMaterialCollection.h new file mode 100644 index 0000000000..62f59b4091 --- /dev/null +++ b/panda/src/egg/eggMaterialCollection.h @@ -0,0 +1,92 @@ +// Filename: eggMaterialCollection.h +// Created by: drose (30Apr01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef EGGMATERIALCOLLECTION_H +#define EGGMATERIALCOLLECTION_H + +#include + +#include "eggMaterial.h" +#include "eggGroupNode.h" + +#include +#include + +//////////////////////////////////////////////////////////////////// +// Class : EggMaterialCollection +// Description : This is a collection of materials by MRef name. It +// can extract the materials from an egg file and sort +// them all together; it can also manage the creation of +// unique materials and the assignment of unique MRef +// names. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEGG EggMaterialCollection { + + // This is a bit of private interface stuff that must be here as a + // forward reference. This allows us to define the + // EggMaterialCollection as an STL container. + +private: + typedef map Materials; + typedef vector< PT(EggMaterial) > OrderedMaterials; + +public: + typedef OrderedMaterials::const_iterator iterator; + typedef iterator const_iterator; + typedef OrderedMaterials::size_type size_type; + + typedef map MaterialReplacement; + + // Here begins the actual public interface to EggMaterialCollection. + +public: + EggMaterialCollection(); + EggMaterialCollection(const EggMaterialCollection ©); + EggMaterialCollection &operator = (const EggMaterialCollection ©); + + void clear(); + + int extract_materials(EggGroupNode *node); + int insert_materials(EggGroupNode *node); + int insert_materials(EggGroupNode *node, EggGroupNode::iterator position); + + int find_used_materials(EggNode *node); + void remove_unused_materials(EggNode *node); + + int collapse_equivalent_materials(int eq, EggGroupNode *node); + int collapse_equivalent_materials(int eq, MaterialReplacement &removed); + static void replace_materials(EggGroupNode *node, + const MaterialReplacement &replace); + + void uniquify_mrefs(); + void sort_by_mref(); + + // Can be used to traverse all the materials in the collection, in + // order as last sorted. + INLINE iterator begin() const; + INLINE iterator end() const; + INLINE bool empty() const; + INLINE size_type size() const; + + bool add_material(EggMaterial *material); + bool remove_material(EggMaterial *material); + + // create_unique_material() creates a new material if there is not + // already one equivalent (according to eq, see + // EggMaterial::is_equivalent_to()) to the indicated material, or + // returns the existing one if there is. + EggMaterial *create_unique_material(const EggMaterial ©, int eq); + + // Find a material with a particular MRef name. + EggMaterial *find_mref(const string &mref_name) const; + +private: + Materials _materials; + OrderedMaterials _ordered_materials; +}; + +#include "eggMaterialCollection.I" + +#endif diff --git a/panda/src/egg/eggTexture.cxx b/panda/src/egg/eggTexture.cxx index b23c526a9f..04a87a1282 100644 --- a/panda/src/egg/eggTexture.cxx +++ b/panda/src/egg/eggTexture.cxx @@ -196,17 +196,17 @@ is_equivalent_to(const EggTexture &other, int eq) const { if (eq & E_basename) { if (a.get_basename_wo_extension() != b.get_basename_wo_extension()) { - return false; + return false; } } if (eq & E_extension) { if (a.get_extension() != b.get_extension()) { - return false; + return false; } } if (eq & E_dirname) { if (a.get_dirname() != b.get_dirname()) { - return false; + return false; } } } @@ -218,21 +218,21 @@ is_equivalent_to(const EggTexture &other, int eq) const { if (has_transform() && other.has_transform()) { if (!_transform.almost_equal(other._transform, 0.0001)) { - return false; + return false; } } } if (eq & E_attributes) { if (_format != other._format || - _wrap_mode != other._wrap_mode || - _wrap_u != other._wrap_u || - _wrap_v != other._wrap_v || - _minfilter != other._minfilter || - _magfilter != other._magfilter || - _magfilteralpha != other._magfilteralpha || - _magfiltercolor != other._magfiltercolor || - _env_type != other._env_type) { + _wrap_mode != other._wrap_mode || + _wrap_u != other._wrap_u || + _wrap_v != other._wrap_v || + _minfilter != other._minfilter || + _magfilter != other._magfilter || + _magfilteralpha != other._magfilteralpha || + _magfiltercolor != other._magfiltercolor || + _env_type != other._env_type) { return false; } if (EggRenderMode::operator != (other)) { @@ -270,17 +270,17 @@ sorts_less_than(const EggTexture &other, int eq) const { if (eq & E_basename) { if (a.get_basename_wo_extension() != b.get_basename_wo_extension()) { - return a.get_basename_wo_extension() < b.get_basename_wo_extension(); + return a.get_basename_wo_extension() < b.get_basename_wo_extension(); } } if (eq & E_extension) { if (a.get_extension() != b.get_extension()) { - return a.get_extension() < b.get_extension(); + return a.get_extension() < b.get_extension(); } } if (eq & E_dirname) { if (a.get_dirname() != b.get_dirname()) { - return a.get_dirname() < b.get_dirname(); + return a.get_dirname() < b.get_dirname(); } } } diff --git a/panda/src/egg/eggTexture.h b/panda/src/egg/eggTexture.h index 23923a6a2b..3ed82ba1d4 100644 --- a/panda/src/egg/eggTexture.h +++ b/panda/src/egg/eggTexture.h @@ -165,7 +165,7 @@ private: }; /////////////////////////////////////////////////////////////////// -// Class : UniqueEggTextures +// Class : UniqueEggTextures // Description : An STL function object for sorting textures into // order by properties. Returns true if the two // referenced EggTexture pointers are in sorted order, @@ -179,16 +179,6 @@ public: int _eq; }; -/////////////////////////////////////////////////////////////////// -// Class : TRefEggTextures -// Description : An STL function object for sorting textures into -// order by TRef name. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDAEGG TRefEggTextures { -public: - INLINE bool operator ()(const EggTexture *t1, const EggTexture *t2) const; -}; - INLINE ostream &operator << (ostream &out, const EggTexture &n) { return out << n.get_filename(); } diff --git a/panda/src/egg/parser.yxx b/panda/src/egg/parser.yxx index 34a7d92710..124ebdbb9e 100644 --- a/panda/src/egg/parser.yxx +++ b/panda/src/egg/parser.yxx @@ -516,6 +516,12 @@ material_body: spec[2] = value; material->set_spec(spec); + } else if (cmp_nocase_uh(name, "shininess") == 0) { + material->set_shininess(value); + + } else if (cmp_nocase_uh(name, "local") == 0) { + material->set_local(value != 0.0); + } else { eggyywarning("Unsupported material scalar: " + name); } diff --git a/panda/src/egg2sg/eggLoader.cxx b/panda/src/egg2sg/eggLoader.cxx index 6a767941ce..690b8aa034 100644 --- a/panda/src/egg2sg/eggLoader.cxx +++ b/panda/src/egg2sg/eggLoader.cxx @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -862,6 +865,65 @@ apply_texture_apply_attributes(TextureApplyTransition *apply, } } +//////////////////////////////////////////////////////////////////// +// Function: EggLoader::get_material_transition +// Access: Private +// Description: Returns a transition suitable for enabling the +// material indicated by the given EggMaterial, and with +// the indicated backface flag. +//////////////////////////////////////////////////////////////////// +MaterialTransition *EggLoader:: +get_material_transition(const EggMaterial *egg_mat, bool bface) { + Materials &materials = bface ? _materials_bface : _materials; + + // First, check whether we've seen this material before. + Materials::const_iterator mi; + mi = materials.find(egg_mat); + if (mi != materials.end()) { + return (*mi).second; + } + + // Ok, this is the first time we've seen this particular + // EggMaterial. Create a new Material that matches it. + PT(Material) mat = new Material; + if (egg_mat->has_diff()) { + RGBColorf diff = egg_mat->get_diff(); + mat->set_diffuse(Colorf(diff[0], diff[1], diff[2], 1.0)); + // By default, ambient is the same as diffuse, if diffuse is + // specified but ambient is not. + mat->set_ambient(Colorf(diff[0], diff[1], diff[2], 1.0)); + } + if (egg_mat->has_amb()) { + RGBColorf amb = egg_mat->get_amb(); + mat->set_ambient(Colorf(amb[0], amb[1], amb[2], 1.0)); + } + if (egg_mat->has_emit()) { + RGBColorf emit = egg_mat->get_emit(); + mat->set_emission(Colorf(emit[0], emit[1], emit[2], 1.0)); + } + if (egg_mat->has_spec()) { + RGBColorf spec = egg_mat->get_spec(); + mat->set_specular(Colorf(spec[0], spec[1], spec[2], 1.0)); + } + if (egg_mat->has_shininess()) { + mat->set_shininess(egg_mat->get_shininess()); + } + if (egg_mat->has_local()) { + mat->set_local(egg_mat->get_local()); + } + + mat->set_twoside(bface); + + // Now get a global Material pointer, shared with other models. + const Material *shared_mat = MaterialPool::get_material(mat); + + // And create a MaterialTransition for this Material. + PT(MaterialTransition) mt = new MaterialTransition(shared_mat); + materials.insert(Materials::value_type(egg_mat, mt)); + + return mt; +} + //////////////////////////////////////////////////////////////////// // Function: EggLoader::setup_bucket @@ -957,6 +1019,13 @@ setup_bucket(BuilderBucket &bucket, NamedNode *parent, } } + if (egg_prim->has_material()) { + MaterialTransition *mt = get_material_transition(egg_prim->get_material(), + egg_prim->get_bface_flag()); + bucket._trans.set_transition(mt); + } + + // Also check the color of the primitive to see if we should assume // alpha based on the alpha values specified in the egg file. if (am == EggRenderMode::AM_unspecified) { diff --git a/panda/src/egg2sg/eggLoader.h b/panda/src/egg2sg/eggLoader.h index 3b3f2fbdb6..29229ab606 100644 --- a/panda/src/egg2sg/eggLoader.h +++ b/panda/src/egg2sg/eggLoader.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include class EggNode; class EggBin; @@ -29,6 +31,7 @@ class EggTable; class EggNurbsCurve; class EggPrimitive; class EggPolygon; +class EggMaterial; class ComputedVerticesMaker; class RenderRelation; class CollisionSolid; @@ -73,6 +76,9 @@ private: void apply_texture_apply_attributes(TextureApplyTransition *apply, const EggTexture *egg_tex); + MaterialTransition *get_material_transition(const EggMaterial *egg_mat, + bool bface); + void setup_bucket(BuilderBucket &bucket, NamedNode *parent, EggPrimitive *egg_prim); @@ -116,6 +122,10 @@ private: typedef map Textures; Textures _textures; + typedef map Materials; + Materials _materials; + Materials _materials_bface; + typedef set Decals; Decals _decals; diff --git a/panda/src/glgsg/glGraphicsStateGuardian.I b/panda/src/glgsg/glGraphicsStateGuardian.I index e7b43a27f0..a5f5c1a143 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.I +++ b/panda/src/glgsg/glGraphicsStateGuardian.I @@ -1159,3 +1159,20 @@ INLINE const float &GLGraphicsStateGuardian:: get_current_alpha_scale() const { return _current_alpha_scale; } + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::report_errors +// Access: Protected +// Description: Checks for any outstanding error codes and outputs +// them, if found. If NDEBUG is defined, this function +// does nothing. +//////////////////////////////////////////////////////////////////// +INLINE void GLGraphicsStateGuardian:: +report_errors() const { +#ifndef NDEBUG + GLenum error_code = glGetError(); + if (error_code != GL_NO_ERROR) { + report_errors_loop(error_code); + } +#endif +} diff --git a/panda/src/glgsg/glGraphicsStateGuardian.cxx b/panda/src/glgsg/glGraphicsStateGuardian.cxx index 132151363c..94eef41c58 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.cxx +++ b/panda/src/glgsg/glGraphicsStateGuardian.cxx @@ -466,6 +466,7 @@ render_frame(const AllAttributesWrapper &initial_state) { #endif _win->begin_frame(); + report_errors(); _decal_level = 0; if (_clear_buffer_type != 0) { @@ -539,6 +540,7 @@ render_frame(const AllAttributesWrapper &initial_state) { // more aware of whether their parameters or positions have changed // at all? + report_errors(); _win->end_frame(); #ifdef GSG_VERBOSE @@ -740,6 +742,7 @@ draw_point(const GeomPoint *geom) { } glEnd(); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -799,6 +802,7 @@ draw_line(const GeomLine* geom) { } glEnd(); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -876,6 +880,7 @@ draw_linestrip(const GeomLinestrip* geom) { } glEnd(); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1181,6 +1186,7 @@ draw_sprite(const GeomSprite *geom) { glMatrixMode(GL_PROJECTION); glLoadMatrixf(_current_projection_mat.get_data()); #endif + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1252,6 +1258,7 @@ draw_polygon(const GeomPolygon *geom) { } glEnd(); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1318,6 +1325,7 @@ draw_tri(const GeomTri *geom) { } glEnd(); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1384,6 +1392,7 @@ draw_quad(const GeomQuad *geom) { } glEnd(); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1472,6 +1481,7 @@ draw_tristrip(const GeomTristrip *geom) { } glEnd(); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1560,6 +1570,7 @@ draw_trifan(const GeomTrifan *geom) { } glEnd(); } + report_errors(); } @@ -1639,6 +1650,7 @@ draw_sphere(const GeomSphere *geom) { } gluDeleteQuadric(sph); + report_errors(); } @@ -1669,7 +1681,8 @@ prepare_texture(Texture *tex) { // which shouldn't be possible, since the texture itself should // detect this. nassertr(inserted, NULL); - + + report_errors(); return gtc; } @@ -1689,6 +1702,7 @@ apply_texture(TextureContext *tc) { specify_texture(tex); apply_texture_immediate(tex); */ + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1715,6 +1729,7 @@ release_texture(TextureContext *tc) { tex->clear_gsg(this); delete gtc; + report_errors(); } static int logs[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, @@ -1898,6 +1913,7 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb) { texture_to_pixel_buffer(tc, pb, dr); pop_frame_buffer(old_fb); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1925,6 +1941,7 @@ texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb, pb->_image = PTA_uchar(w * h * pb->get_num_components()); copy_pixel_buffer(pb, dr); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -1994,6 +2011,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { pb->_image.p() ); nassertv(!pb->_image.empty()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2131,6 +2149,7 @@ draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, glPopMatrix(); pop_display_region(old_dr); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2188,6 +2207,7 @@ void GLGraphicsStateGuardian::apply_material(const Material *material) { call_glLightModelLocal(material->get_local()); call_glLightModelTwoSide(material->get_twoside()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2211,6 +2231,7 @@ apply_fog(Fog *fog) { break; } call_glFogColor(fog->get_color()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2270,6 +2291,7 @@ void GLGraphicsStateGuardian::apply_light( PointLight* light ) glgsg_cat.debug() << "glPopMatrix()" << endl; #endif + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2327,6 +2349,7 @@ void GLGraphicsStateGuardian::apply_light( DirectionalLight* light ) glgsg_cat.debug() << "glPopMatrix()" << endl; #endif + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2382,6 +2405,7 @@ void GLGraphicsStateGuardian::apply_light( Spotlight* light ) glgsg_cat.debug() << "glPopMatrix()" << endl; #endif + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2438,6 +2462,7 @@ issue_transform(const TransformAttribute *attrib) { enable_texturing(texturing_was_enabled); } #endif + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2489,6 +2514,7 @@ issue_tex_matrix(const TexMatrixAttribute *attrib) { #endif glMatrixMode(GL_TEXTURE); glLoadMatrixf(attrib->get_matrix().get_data()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2503,6 +2529,7 @@ issue_color(const ColorAttribute *attrib) { const Colorf c = attrib->get_color(); glColor4f(c[0], c[1], c[2], c[3]); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2522,6 +2549,7 @@ issue_texture(const TextureAttribute *attrib) { } else { enable_texturing(false); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2574,6 +2602,7 @@ issue_tex_gen(const TexGenAttribute *attrib) { << "Unknown texgen mode " << (int)mode << endl; break; } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2589,6 +2618,7 @@ issue_material(const MaterialAttribute *attrib) { nassertv(material != (const Material *)NULL); apply_material(material); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2608,6 +2638,7 @@ issue_fog(const FogAttribute *attrib) { } else { enable_fog(false); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2636,6 +2667,7 @@ issue_render_mode(const RenderModeAttribute *attrib) { glgsg_cat.error() << "Unknown render mode " << (int)mode << endl; } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2732,6 +2764,7 @@ void GLGraphicsStateGuardian::issue_light(const LightAttribute *attrib ) } else { call_glLightModelAmbient(_cur_ambient_light); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2769,6 +2802,7 @@ issue_color_blend(const ColorBlendAttribute *attrib) { << "Unknown color blend mode " << (int)mode << endl; break; } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2781,6 +2815,7 @@ issue_texture_apply(const TextureApplyAttribute *attrib) { // activate(); GLint glmode = get_texture_apply_mode_type(attrib->get_mode()); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2792,9 +2827,10 @@ void GLGraphicsStateGuardian:: issue_color_mask(const ColorMaskAttribute *attrib) { // activate(); glColorMask(attrib->is_write_r(), - attrib->is_write_g(), - attrib->is_write_b(), - attrib->is_write_a()); + attrib->is_write_g(), + attrib->is_write_b(), + attrib->is_write_a()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2813,6 +2849,7 @@ issue_depth_test(const DepthTestAttribute *attrib) { enable_depth_test(true); glDepthFunc(get_depth_func_type(mode)); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2825,6 +2862,7 @@ issue_depth_write(const DepthWriteAttribute *attrib) { // activate(); call_glDepthMask(attrib->is_on()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2845,6 +2883,7 @@ issue_stencil(const StencilAttribute *attrib) { call_glStencilFunc(get_stencil_func_type(mode)); call_glStencilOp(get_stencil_action_type(attrib->get_action())); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2879,6 +2918,7 @@ issue_cull_face(const CullFaceAttribute *attrib) { << "invalid cull face mode " << (int)mode << endl; break; } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -2967,6 +3007,7 @@ issue_clip_plane(const ClipPlaneAttribute *attrib) if (_cur_clip_plane_enabled[i] == false) enable_clip_plane(i, false); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3027,6 +3068,7 @@ issue_transparency(const TransparencyAttribute *attrib ) << "invalid transparency mode " << (int)mode << endl; break; } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3038,6 +3080,7 @@ void GLGraphicsStateGuardian:: issue_linesmooth(const LinesmoothAttribute *attrib) { // activate(); enable_line_smooth(attrib->is_on()); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3053,6 +3096,7 @@ issue_point_shape(const PointShapeAttribute *attrib) { glDisable(GL_POINT_SMOOTH); else glEnable(GL_POINT_SMOOTH); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3080,6 +3124,7 @@ issue_polygon_offset(const PolygonOffsetAttribute *attrib) { { enable_polygon_offset(false); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3180,6 +3225,7 @@ begin_decal(GeomNode *base_geom) { // buffer write off during this. } } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3279,6 +3325,7 @@ end_decal(GeomNode *base_geom) { enable_texturing(was_textured); } } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3299,6 +3346,24 @@ compute_distance_to(const LPoint3f &point) const { return -point[2]; } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::report_errors_loop +// Access: Protected +// Description: The internal implementation of report_errors(). +// Don't call this function; use report_errors() +// instead. +//////////////////////////////////////////////////////////////////// +void GLGraphicsStateGuardian:: +report_errors_loop(GLenum error_code) const { +#ifndef NDEBUG + while (error_code != GL_NO_ERROR) { + glgsg_cat.error() + << gluErrorString(error_code) << "\n"; + error_code = glGetError(); + } +#endif +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::set_draw_buffer // Access: Protected @@ -3345,6 +3410,7 @@ set_draw_buffer(const RenderBuffer &rb) { default: call_glDrawBuffer(GL_FRONT_AND_BACK); } + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3393,6 +3459,7 @@ set_read_buffer(const RenderBuffer &rb) { default: call_glReadBuffer(GL_FRONT_AND_BACK); } + report_errors(); } @@ -3413,6 +3480,7 @@ bind_texture(TextureContext *tc) { << ")" << endl; #endif glBindTexture(GL_TEXTURE_2D, gtc->_index); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3438,6 +3506,7 @@ specify_texture(Texture *tex) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, get_texture_filter_type(tex->get_magfilter())); } + report_errors(); } @@ -3494,6 +3563,7 @@ apply_texture_immediate(Texture *tex) { glTexImage2D( GL_TEXTURE_2D, 0, internal_format, pb->get_xsize(), pb->get_ysize(), pb->get_border(), external_format, type, pb->_image ); + report_errors(); } //////////////////////////////////////////////////////////////////// @@ -3688,17 +3758,16 @@ get_internal_image_format(PixelBuffer::Format format) { GLint GLGraphicsStateGuardian:: get_texture_apply_mode_type( TextureApplyProperty::Mode am ) const { - switch( am ) - { - case TextureApplyProperty::M_modulate: return GL_MODULATE; - case TextureApplyProperty::M_decal: return GL_DECAL; - case TextureApplyProperty::M_blend: return GL_BLEND; - case TextureApplyProperty::M_replace: return GL_REPLACE; - case TextureApplyProperty::M_add: return GL_ADD; - } - glgsg_cat.error() - << "Invalid TextureApplyProperty::Mode value" << endl; - return GL_MODULATE; + switch( am ) { + case TextureApplyProperty::M_modulate: return GL_MODULATE; + case TextureApplyProperty::M_decal: return GL_DECAL; + case TextureApplyProperty::M_blend: return GL_BLEND; + case TextureApplyProperty::M_replace: return GL_REPLACE; + case TextureApplyProperty::M_add: return GL_ADD; + } + glgsg_cat.error() + << "Invalid TextureApplyProperty::Mode value" << endl; + return GL_MODULATE; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/glgsg/glGraphicsStateGuardian.h b/panda/src/glgsg/glGraphicsStateGuardian.h index 0a984c93b0..1b36709b76 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.h +++ b/panda/src/glgsg/glGraphicsStateGuardian.h @@ -222,6 +222,9 @@ protected: INLINE GLenum get_light_id(int index) const; INLINE GLenum get_clip_plane_id(int index) const; + INLINE void report_errors() const; + void report_errors_loop(GLenum error_code) const; + void set_draw_buffer(const RenderBuffer &rb); void set_read_buffer(const RenderBuffer &rb); diff --git a/panda/src/gobj/material.I b/panda/src/gobj/material.I index 9f05ddc694..586117f4e9 100644 --- a/panda/src/gobj/material.I +++ b/panda/src/gobj/material.I @@ -285,7 +285,11 @@ get_local() const { //////////////////////////////////////////////////////////////////// INLINE void Material:: set_local(bool local) { - _flags |= F_local; + if (local) { + _flags |= F_local; + } else { + _flags &= ~F_local; + } } //////////////////////////////////////////////////////////////////// @@ -305,7 +309,11 @@ get_twoside() const { //////////////////////////////////////////////////////////////////// INLINE void Material:: set_twoside(bool twoside) { - _flags = F_twoside; + if (twoside) { + _flags |= F_twoside; + } else { + _flags &= ~F_twoside; + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/material.cxx b/panda/src/gobj/material.cxx index df94cede95..d646d7dde5 100644 --- a/panda/src/gobj/material.cxx +++ b/panda/src/gobj/material.cxx @@ -74,10 +74,22 @@ compare_to(const Material &other) const { //////////////////////////////////////////////////////////////////// void Material:: output(ostream &out) const { - out << "a" << get_ambient()[0] << ",d" << get_diffuse()[0] - << ",s" << get_specular()[0] << ",e" << get_emission()[0] - << ",s" << get_shininess() << ",l" << get_local() - << ",t" << get_twoside(); + out << "material"; + if (has_ambient()) { + out << " a(" << get_ambient() << ")"; + } + if (has_diffuse()) { + out << " d(" << get_diffuse() << ")"; + } + if (has_specular()) { + out << " s(" << get_specular() << ")"; + } + if (has_emission()) { + out << " e(" << get_emission() << ")"; + } + out << " s" << get_shininess() + << " l" << get_local() + << " t" << get_twoside(); } //////////////////////////////////////////////////////////////////// @@ -87,10 +99,23 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// void Material:: write(ostream &out, int indent_level) const { - indent(out, indent_level) << "ambient = " << get_ambient() << "\n"; - indent(out, indent_level) << "diffuse = " << get_diffuse() << "\n"; - indent(out, indent_level) << "specular = " << get_specular() << "\n"; - indent(out, indent_level) << "emission = " << get_emission() << "\n"; + bool any = false; + if (has_ambient()) { + indent(out, indent_level) << "ambient = " << get_ambient() << "\n"; + any = true; + } + if (has_diffuse()) { + indent(out, indent_level) << "diffuse = " << get_diffuse() << "\n"; + any = true; + } + if (has_specular()) { + indent(out, indent_level) << "specular = " << get_specular() << "\n"; + any = true; + } + if (has_emission()) { + indent(out, indent_level) << "emission = " << get_emission() << "\n"; + any = true; + } indent(out, indent_level) << "shininess = " << get_shininess() << "\n"; indent(out, indent_level) << "local = " << get_local() << "\n"; indent(out, indent_level) << "twoside = " << get_twoside() << "\n"; diff --git a/pandatool/src/lwoegg/cLwoSurface.cxx b/pandatool/src/lwoegg/cLwoSurface.cxx index 9962ed4c9e..d86acfe98a 100644 --- a/pandatool/src/lwoegg/cLwoSurface.cxx +++ b/pandatool/src/lwoegg/cLwoSurface.cxx @@ -29,6 +29,8 @@ CLwoSurface(LwoToEggConverter *converter, const LwoSurface *surface) : _surface(surface) { _flags = 0; + _color.set(1.0, 1.0, 1.0); + _checked_material = false; _checked_texture = false; _map_uvs = NULL; _block = (CLwoSurfaceBlock *)NULL; @@ -146,6 +148,10 @@ apply_properties(EggPrimitive *egg_prim, vector_PT_EggVertex &egg_vertices, } } + if (check_material()) { + egg_prim->set_material(_egg_material); + } + // We treat color and transparency separately, because Lightwave // does, and this will allow us to treat inherited surfaces a little // more robustly. @@ -269,6 +275,50 @@ check_texture() { return true; } +//////////////////////////////////////////////////////////////////// +// Function: CLwoSurface::check_material +// Access: Public +// Description: Checks whether the surface demands a material or not. +// Returns true if so, false otherwise. +//////////////////////////////////////////////////////////////////// +bool CLwoSurface:: +check_material() { + if (_checked_material) { + return (_egg_material != (EggMaterial *)NULL); + } + _checked_material = true; + _egg_material = (EggMaterial *)NULL; + + if (!_converter->_make_materials) { + // If we aren't making materials, then don't make a material. + return false; + } + + _egg_material = new EggMaterial(get_name()); + + RGBColorf color = _color; + if (check_texture()) { + // Texturing overrides the color. + color.set(1.0, 1.0, 1.0); + } + + if ((_flags & F_diffuse) != 0) { + RGBColorf diffuse = color * _diffuse; + _egg_material->set_diff(diffuse); + } + if ((_flags & F_luminosity) != 0) { + RGBColorf luminosity = color * _luminosity; + _egg_material->set_emit(luminosity); + } + if ((_flags & F_specular) != 0) { + RGBColorf specular = color * _specular; + _egg_material->set_spec(specular); + } + + return true; +} + + //////////////////////////////////////////////////////////////////// // Function: CLwoSurface::generate_uvs // Access: Private diff --git a/pandatool/src/lwoegg/cLwoSurface.h b/pandatool/src/lwoegg/cLwoSurface.h index 1263cd1c5a..7b51c0dd6a 100644 --- a/pandatool/src/lwoegg/cLwoSurface.h +++ b/pandatool/src/lwoegg/cLwoSurface.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -38,10 +39,12 @@ public: vector_PT_EggVertex &egg_vertices, float &smooth_angle); bool check_texture(); + bool check_material(); INLINE bool has_named_uvs() const; INLINE const string &get_uv_name() const; + enum Flags { F_color = 0x0001, F_diffuse = 0x0002, @@ -68,6 +71,9 @@ public: LwoToEggConverter *_converter; CPT(LwoSurface) _surface; + bool _checked_material; + PT(EggMaterial) _egg_material; + bool _checked_texture; PT(EggTexture) _egg_texture; diff --git a/pandatool/src/lwoegg/lwoToEggConverter.cxx b/pandatool/src/lwoegg/lwoToEggConverter.cxx index 6b6f924c12..cbd0784e99 100644 --- a/pandatool/src/lwoegg/lwoToEggConverter.cxx +++ b/pandatool/src/lwoegg/lwoToEggConverter.cxx @@ -31,6 +31,7 @@ LwoToEggConverter:: LwoToEggConverter() { _generic_layer = (CLwoLayer *)NULL; + _make_materials = true; } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/lwoegg/lwoToEggConverter.h b/pandatool/src/lwoegg/lwoToEggConverter.h index 6694bfaccc..86e8252f94 100644 --- a/pandatool/src/lwoegg/lwoToEggConverter.h +++ b/pandatool/src/lwoegg/lwoToEggConverter.h @@ -45,6 +45,8 @@ public: CLwoSurface *get_surface(const string &name) const; + bool _make_materials; + private: void cleanup();