diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index c60bf59081..4268a2c678 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -568,6 +568,13 @@ class ShowBase(DirectObject.DirectObject): rendering 3-d geometry. """ self.render = NodePath('render') + + # Temporary try..except for old pandas. + try: + self.render.node().setAttrib(RescaleNormalAttrib.makeDefault()); + except: + pass + self.render.setTwoSided(0) self.backfaceCullingEnabled = 1 self.textureEnabled = 1 diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index db2c07b759..a4d1d97664 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -40,6 +40,7 @@ #include "depthTestAttrib.h" #include "depthWriteAttrib.h" #include "cullFaceAttrib.h" +#include "rescaleNormalAttrib.h" #include "pgTop.h" #include "geomNode.h" #include "geomTristrip.h" @@ -228,6 +229,8 @@ get_render() { if (_render.is_empty()) { _render = NodePath("render"); + _render.node()->set_attrib(RescaleNormalAttrib::make_default()); + // This is maybe here temporarily, and maybe not. _render.set_two_sided(0); } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 906d5402e1..d40d915563 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -41,6 +41,7 @@ #include "cgShaderAttrib.h" #include "materialAttrib.h" #include "renderModeAttrib.h" +#include "rescaleNormalAttrib.h" #include "fogAttrib.h" #include "depthOffsetAttrib.h" #include "fog.h" @@ -309,8 +310,13 @@ reset() { get_extra_extensions(); report_extensions(); - _supports_bgr = has_extension("GL_EXT_bgra"); - _supports_multisample = has_extension("GL_ARB_multisample"); + _supports_bgr = + has_extension("GL_EXT_bgra") || is_at_least_version(1, 2); + _supports_rescale_normal = + has_extension("GL_EXT_rescale_normal") || is_at_least_version(1, 2); + + _supports_multisample = + has_extension("GL_ARB_multisample"); _supports_generate_mipmap = has_extension("GL_SGIS_generate_mipmap") || is_at_least_version(1, 4); @@ -414,6 +420,8 @@ reset() { report_my_gl_errors(); + _auto_rescale_normal = false; + // All GL implementations have the following buffers. _buffer_mask = (RenderBuffer::T_color | RenderBuffer::T_depth | @@ -475,11 +483,6 @@ reset() { _cg_shader = (CgShader *)NULL; #endif - // Should we normalize lighting normals? - if (CLP(auto_normalize_lighting)) { - GLP(Enable)(GL_NORMALIZE); - } - // Count the max number of lights GLint max_lights; GLP(GetIntegerv)(GL_MAX_LIGHTS, &max_lights); @@ -2288,6 +2291,11 @@ issue_transform(const TransformState *transform) { GLP(MatrixMode)(GL_MODELVIEW); GLP(LoadMatrixf)(transform->get_mat().get_data()); + _transform = transform; + if (_auto_rescale_normal) { + do_auto_rescale_normal(); + } + report_my_gl_errors(); } @@ -2533,6 +2541,53 @@ issue_render_mode(const RenderModeAttrib *attrib) { report_my_gl_errors(); } +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::issue_rescale_normal +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +issue_rescale_normal(const RescaleNormalAttrib *attrib) { + RescaleNormalAttrib::Mode mode = attrib->get_mode(); + + _auto_rescale_normal = false; + + switch (mode) { + case RescaleNormalAttrib::M_none: + GLP(Disable)(GL_NORMALIZE); + if (_supports_rescale_normal) { + GLP(Disable)(GL_RESCALE_NORMAL); + } + break; + + case RescaleNormalAttrib::M_rescale: + if (_supports_rescale_normal) { + GLP(Enable)(GL_RESCALE_NORMAL); + GLP(Disable)(GL_NORMALIZE); + } else { + GLP(Enable)(GL_NORMALIZE); + } + break; + + case RescaleNormalAttrib::M_normalize: + GLP(Enable)(GL_NORMALIZE); + if (_supports_rescale_normal) { + GLP(Disable)(GL_RESCALE_NORMAL); + } + break; + + case RescaleNormalAttrib::M_auto: + _auto_rescale_normal = true; + do_auto_rescale_normal(); + break; + + default: + GLCAT.error() + << "Unknown rescale_normal mode " << (int)mode << endl; + } + report_my_gl_errors(); +} + //////////////////////////////////////////////////////////////////// // Function: CLP(GraphicsStateGuardian)::issue_texture_apply // Access: Public, Virtual @@ -4621,6 +4676,42 @@ get_untextured_state() { return state; } +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::do_auto_rescale_normal +// Access: Protected +// Description: Issues the appropriate GL commands to either rescale +// or normalize the normals according to the current +// transform. +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +do_auto_rescale_normal() { + if (_transform->has_uniform_scale()) { + if (IS_NEARLY_EQUAL(_transform->get_uniform_scale(), 1.0f)) { + // If there's no scale at all, don't do anything. + GLP(Disable)(GL_NORMALIZE); + if (_supports_rescale_normal) { + GLP(Disable)(GL_RESCALE_NORMAL); + } + + } else { + // There's a uniform scale; use the rescale feature if available. + if (_supports_rescale_normal) { + GLP(Enable)(GL_RESCALE_NORMAL); + GLP(Disable)(GL_NORMALIZE); + } else { + GLP(Enable)(GL_NORMALIZE); + } + } + + } else { + // If there's a non-uniform scale, normalize everything. + GLP(Enable)(GL_NORMALIZE); + if (_supports_rescale_normal) { + GLP(Disable)(GL_RESCALE_NORMAL); + } + } +} + #ifndef NDEBUG //////////////////////////////////////////////////////////////////// // Function: CLP(GraphicsStateGuardian)::build_phony_mipmaps diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 920e053cdb..9f04b26d7a 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -110,6 +110,7 @@ public: virtual void issue_texture(const TextureAttrib *attrib); virtual void issue_material(const MaterialAttrib *attrib); virtual void issue_render_mode(const RenderModeAttrib *attrib); + virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib); virtual void issue_texture_apply(const TextureApplyAttrib *attrib); virtual void issue_color_write(const ColorWriteAttrib *attrib); virtual void issue_depth_test(const DepthTestAttrib *attrib); @@ -228,6 +229,8 @@ protected: static CPT(RenderState) get_untextured_state(); + void do_auto_rescale_normal(); + #ifndef NDEBUG void build_phony_mipmaps(Texture *tex); void build_phony_mipmap_level(int level, int xsize, int ysize); @@ -271,6 +274,7 @@ protected: #endif int _pass_number; + bool _auto_rescale_normal; int _error_count; @@ -279,6 +283,7 @@ protected: public: bool _supports_bgr; + bool _supports_rescale_normal; bool _supports_multitexture; PFNGLACTIVETEXTUREPROC _glActiveTexture; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 7ac8c47a89..2f31d221ca 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -60,6 +60,7 @@ class TextureAttrib; class LightAttrib; class MaterialAttrib; class RenderModeAttrib; +class RescaleNormalAttrib; class ColorBlendAttrib; class TextureApplyAttrib; class ColorWriteAttrib; @@ -186,6 +187,7 @@ public: virtual void issue_light(const LightAttrib *) { } virtual void issue_material(const MaterialAttrib *) { } virtual void issue_render_mode(const RenderModeAttrib *) { } + virtual void issue_rescale_normal(const RescaleNormalAttrib *) { } virtual void issue_texture_apply(const TextureApplyAttrib *) { } virtual void issue_color_write(const ColorWriteAttrib *) { } virtual void issue_depth_test(const DepthTestAttrib *) { } diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 9877be76a2..4f1ffc573a 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -80,6 +80,7 @@ renderEffects.I renderEffects.h \ renderModeAttrib.I renderModeAttrib.h \ renderState.I renderState.h \ + rescaleNormalAttrib.I rescaleNormalAttrib.h \ sceneGraphAnalyzer.h \ sceneGraphReducer.I sceneGraphReducer.h \ sceneSetup.I sceneSetup.h \ @@ -172,6 +173,7 @@ renderEffects.cxx \ renderModeAttrib.cxx \ renderState.cxx \ + rescaleNormalAttrib.cxx \ sceneGraphAnalyzer.cxx \ sceneGraphReducer.cxx \ sceneSetup.cxx \ @@ -262,6 +264,7 @@ renderEffects.I renderEffects.h \ renderModeAttrib.I renderModeAttrib.h \ renderState.I renderState.h \ + rescaleNormalAttrib.I rescaleNormalAttrib.h \ sceneGraphAnalyzer.h \ sceneGraphReducer.I sceneGraphReducer.h \ sceneSetup.I sceneSetup.h \ diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index dd546db641..d66f8d4f1a 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -74,6 +74,7 @@ #include "renderEffects.h" #include "renderModeAttrib.h" #include "renderState.h" +#include "rescaleNormalAttrib.h" #include "selectiveChildNode.h" #include "sequenceNode.h" #include "showBoundsEffect.h" @@ -264,6 +265,7 @@ init_libpgraph() { RenderEffects::init_type(); RenderModeAttrib::init_type(); RenderState::init_type(); + RescaleNormalAttrib::init_type(); SelectiveChildNode::init_type(); SequenceNode::init_type(); ShowBoundsEffect::init_type(); diff --git a/panda/src/pgraph/pgraph_composite2.cxx b/panda/src/pgraph/pgraph_composite2.cxx index 2f4835a5cf..1712914d61 100644 --- a/panda/src/pgraph/pgraph_composite2.cxx +++ b/panda/src/pgraph/pgraph_composite2.cxx @@ -27,6 +27,7 @@ #include "renderEffects.cxx" #include "renderModeAttrib.cxx" #include "renderState.cxx" +#include "rescaleNormalAttrib.cxx" #include "sceneGraphAnalyzer.cxx" #include "sceneGraphReducer.cxx" #include "selectiveChildNode.cxx" diff --git a/panda/src/pgraph/rescaleNormalAttrib.I b/panda/src/pgraph/rescaleNormalAttrib.I new file mode 100644 index 0000000000..424f94898e --- /dev/null +++ b/panda/src/pgraph/rescaleNormalAttrib.I @@ -0,0 +1,40 @@ +// Filename: rescaleNormalAttrib.I +// Created by: drose (30Dec04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::Constructor +// Access: Private +// Description: Use RescaleNormalAttrib::make() to construct a new +// RescaleNormalAttrib object. +//////////////////////////////////////////////////////////////////// +INLINE RescaleNormalAttrib:: +RescaleNormalAttrib(RescaleNormalAttrib::Mode mode) : + _mode(mode) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::get_mode +// Access: Published +// Description: Returns the render mode. +//////////////////////////////////////////////////////////////////// +INLINE RescaleNormalAttrib::Mode RescaleNormalAttrib:: +get_mode() const { + return _mode; +} diff --git a/panda/src/pgraph/rescaleNormalAttrib.cxx b/panda/src/pgraph/rescaleNormalAttrib.cxx new file mode 100644 index 0000000000..33225fddd8 --- /dev/null +++ b/panda/src/pgraph/rescaleNormalAttrib.cxx @@ -0,0 +1,241 @@ +// Filename: rescaleNormalAttrib.cxx +// Created by: drose (30Dec04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "rescaleNormalAttrib.h" +#include "graphicsStateGuardianBase.h" +#include "string_utils.h" +#include "dcast.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "datagram.h" +#include "datagramIterator.h" +#include "configVariableEnum.h" + +TypeHandle RescaleNormalAttrib::_type_handle; + +// This variable is defined here instead of in config_pgraph.cxx, +// because it depends on rescaleNormalAttrib.h having already been +// included. +static ConfigVariableEnum rescale_normals +("rescale-normals", RescaleNormalAttrib::M_auto, + PRC_DESC("Specifies the kind of RescaleNormalAttrib that should be " + "created for the top of the scene graph. This can automatically " + "ensure that your lighting normals are unit-length, which may be " + "particularly necessary in the presence of scales in the scene " + "graph. Turning it off ('none') may produce a small performance " + "benefit.")); + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::make +// Access: Published, Static +// Description: Constructs a new RescaleNormalAttrib object that +// specifies whether to rescale normals to compensate +// for transform scales or incorrectly defined normals. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) RescaleNormalAttrib:: +make(RescaleNormalAttrib::Mode mode) { + RescaleNormalAttrib *attrib = new RescaleNormalAttrib(mode); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::make_default +// Access: Published, Static +// Description: Constructs a RescaleNoramlAttrib object that's +// suitable for putting at the top of a scene graph. +// This will contain whatever attrib was suggested by +// the user's rescale-normals Config variable. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) RescaleNormalAttrib:: +make_default() { + RescaleNormalAttrib *attrib = new RescaleNormalAttrib(rescale_normals); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::issue +// Access: Public, Virtual +// Description: Calls the appropriate method on the indicated GSG +// to issue the graphics commands appropriate to the +// given attribute. This is normally called +// (indirectly) only from +// GraphicsStateGuardian::set_state() or modify_state(). +//////////////////////////////////////////////////////////////////// +void RescaleNormalAttrib:: +issue(GraphicsStateGuardianBase *gsg) const { + gsg->issue_rescale_normal(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void RescaleNormalAttrib:: +output(ostream &out) const { + out << get_type() << ":" << get_mode(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::compare_to_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RescaleNormalAttrib +// types to return a unique number indicating whether +// this RescaleNormalAttrib is equivalent to the other one. +// +// This should return 0 if the two RescaleNormalAttrib objects +// are equivalent, a number less than zero if this one +// should be sorted before the other one, and a number +// greater than zero otherwise. +// +// This will only be called with two RescaleNormalAttrib +// objects whose get_type() functions return the same. +//////////////////////////////////////////////////////////////////// +int RescaleNormalAttrib:: +compare_to_impl(const RenderAttrib *other) const { + const RescaleNormalAttrib *ta; + DCAST_INTO_R(ta, other, 0); + return (int)_mode - (int)ta->_mode; +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::make_default_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RescaleNormalAttrib +// types to specify what the default property for a +// RescaleNormalAttrib of this type should be. +// +// This should return a newly-allocated RescaleNormalAttrib of +// the same type that corresponds to whatever the +// standard default for this kind of RescaleNormalAttrib is. +//////////////////////////////////////////////////////////////////// +RenderAttrib *RescaleNormalAttrib:: +make_default_impl() const { + return new RescaleNormalAttrib(M_none); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// RescaleNormalAttrib. +//////////////////////////////////////////////////////////////////// +void RescaleNormalAttrib:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void RescaleNormalAttrib:: +write_datagram(BamWriter *manager, Datagram &dg) { + RenderAttrib::write_datagram(manager, dg); + + dg.add_int8(_mode); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type RescaleNormalAttrib is encountered +// in the Bam file. It should create the RescaleNormalAttrib +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *RescaleNormalAttrib:: +make_from_bam(const FactoryParams ¶ms) { + RescaleNormalAttrib *attrib = new RescaleNormalAttrib(M_none); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + attrib->fillin(scan, manager); + + return attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new RescaleNormalAttrib. +//////////////////////////////////////////////////////////////////// +void RescaleNormalAttrib:: +fillin(DatagramIterator &scan, BamReader *manager) { + RenderAttrib::fillin(scan, manager); + + _mode = (Mode)scan.get_int8(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::Mode output operator +// Description: +//////////////////////////////////////////////////////////////////// +ostream & +operator << (ostream &out, RescaleNormalAttrib::Mode mode) { + switch (mode) { + case RescaleNormalAttrib::M_none: + return out << "none"; + + case RescaleNormalAttrib::M_rescale: + return out << "rescale"; + + case RescaleNormalAttrib::M_normalize: + return out << "normalize"; + + case RescaleNormalAttrib::M_auto: + return out << "auto"; + } + + return out << "(**invalid RescaleNormalAttrib::Mode(" << (int)mode << ")**)"; +} + +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::Mode input operator +// Description: +//////////////////////////////////////////////////////////////////// +istream & +operator >> (istream &in, RescaleNormalAttrib::Mode &mode) { + string word; + in >> word; + + if (cmp_nocase(word, "none") == 0) { + mode = RescaleNormalAttrib::M_none; + + } else if (cmp_nocase(word, "rescale") == 0) { + mode = RescaleNormalAttrib::M_rescale; + + } else if (cmp_nocase(word, "normalize") == 0) { + mode = RescaleNormalAttrib::M_normalize; + + } else if (cmp_nocase(word, "auto") == 0) { + mode = RescaleNormalAttrib::M_auto; + + } else { + pgraph_cat.error() + << "Invalid RescaleNormalAttrib::Mode value: " << word << "\n"; + mode = RescaleNormalAttrib::M_none; + } + + return in; +} diff --git a/panda/src/pgraph/rescaleNormalAttrib.h b/panda/src/pgraph/rescaleNormalAttrib.h new file mode 100644 index 0000000000..107350892b --- /dev/null +++ b/panda/src/pgraph/rescaleNormalAttrib.h @@ -0,0 +1,103 @@ +// Filename: rescaleNormalAttrib.h +// Created by: drose (30Dec04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef RESCALENORMALATTRIB_H +#define RESCALENORMALATTRIB_H + +#include "pandabase.h" + +#include "renderAttrib.h" + +class FactoryParams; + +//////////////////////////////////////////////////////////////////// +// Class : RescaleNormalAttrib +// Description : Specifies how polygons are to be drawn. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RescaleNormalAttrib : public RenderAttrib { +PUBLISHED: + enum Mode { + // No adjustments are made to normals. + M_none, + + // Normals are counterscaled by the transform's uniform scale, if + // supported by the graphics API. + M_rescale, + + // Normals are scaled to unit length; potentially expensive. + M_normalize, + + // Normals are counterscaled in the presence of a uniform scale + // transform, or normalized in the presence of a non-uniform scale + // transform. + M_auto, + }; + +private: + INLINE RescaleNormalAttrib(Mode mode); + +PUBLISHED: + static CPT(RenderAttrib) make(Mode mode); + static CPT(RenderAttrib) make_default(); + + INLINE Mode get_mode() const; + +public: + virtual void issue(GraphicsStateGuardianBase *gsg) const; + virtual void output(ostream &out) const; + +protected: + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual RenderAttrib *make_default_impl() const; + +private: + Mode _mode; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + RenderAttrib::init_type(); + register_type(_type_handle, "RescaleNormalAttrib", + RenderAttrib::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +EXPCL_PANDA ostream &operator << (ostream &out, RescaleNormalAttrib::Mode mode); +EXPCL_PANDA istream &operator >> (istream &in, RescaleNormalAttrib::Mode &mode); + +#include "rescaleNormalAttrib.I" + +#endif +