diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index d308af9aa8..ad15b7d210 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -56,6 +56,7 @@ #include "depthWriteAttrib.h" #include "fogAttrib.h" #include "lightAttrib.h" +#include "logicOpAttrib.h" #include "materialAttrib.h" #include "rescaleNormalAttrib.h" #include "scissorAttrib.h" @@ -475,6 +476,7 @@ reset() { _inv_state_mask.clear_bit(TransparencyAttrib::get_class_slot()); _inv_state_mask.clear_bit(ColorWriteAttrib::get_class_slot()); _inv_state_mask.clear_bit(ColorBlendAttrib::get_class_slot()); + _inv_state_mask.clear_bit(LogicOpAttrib::get_class_slot()); _inv_state_mask.clear_bit(TextureAttrib::get_class_slot()); _inv_state_mask.clear_bit(TexGenAttrib::get_class_slot()); _inv_state_mask.clear_bit(TexMatrixAttrib::get_class_slot()); @@ -6631,6 +6633,34 @@ do_issue_material() { } #endif // SUPPORT_FIXED_FUNCTION +/** + * Issues the logic operation attribute to the GL. + */ +#if !defined(OPENGLES) || defined(OPENGLES_1) +void CLP(GraphicsStateGuardian):: +do_issue_logic_op() { + const LogicOpAttrib *target_logic_op; + _target_rs->get_attrib_def(target_logic_op); + + if (target_logic_op->get_operation() != LogicOpAttrib::O_none) { + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(GL_CLEAR - 1 + (int)target_logic_op->get_operation()); + + if (GLCAT.is_spam()) { + GLCAT.spam() << "glEnable(GL_COLOR_LOGIC_OP)\n"; + GLCAT.spam() << "glLogicOp(" << target_logic_op->get_operation() << ")\n"; + } + } else { + glDisable(GL_COLOR_LOGIC_OP); + glLogicOp(GL_COPY); + + if (GLCAT.is_spam()) { + GLCAT.spam() << "glDisable(GL_COLOR_LOGIC_OP)\n"; + } + } +} +#endif + /** * */ @@ -9660,6 +9690,16 @@ set_state_and_transform(const RenderState *target, } #endif +#if !defined(OPENGLES) || defined(OPENGLES_1) + int logic_op_slot = LogicOpAttrib::get_class_slot(); + if (_target_rs->get_attrib(logic_op_slot) != _state_rs->get_attrib(logic_op_slot) || + !_state_mask.get_bit(logic_op_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_logic_op_pcollector); + do_issue_logic_op(); + _state_mask.set_bit(logic_op_slot); + } +#endif + int transparency_slot = TransparencyAttrib::get_class_slot(); int color_write_slot = ColorWriteAttrib::get_class_slot(); int color_blend_slot = ColorBlendAttrib::get_class_slot(); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 9d73f69130..5a1ded8644 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -405,6 +405,9 @@ protected: void do_issue_material(); #endif void do_issue_texture(); +#if !defined(OPENGLES) || defined(OPENGLES_1) + void do_issue_logic_op(); +#endif void do_issue_blending(); #ifdef SUPPORT_FIXED_FUNCTION void do_issue_tex_gen(); diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index d5427a659f..10b9fb04d3 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -50,6 +50,7 @@ #include "loaderFileType.h" #include "loaderFileTypeBam.h" #include "loaderFileTypeRegistry.h" +#include "logicOpAttrib.h" #include "materialAttrib.h" #include "modelFlattenRequest.h" #include "modelLoadRequest.h" @@ -419,6 +420,7 @@ init_libpgraph() { Loader::init_type(); LoaderFileType::init_type(); LoaderFileTypeBam::init_type(); + LogicOpAttrib::init_type(); MaterialAttrib::init_type(); ModelFlattenRequest::init_type(); ModelLoadRequest::init_type(); @@ -483,6 +485,7 @@ init_libpgraph() { LensNode::register_with_read_factory(); LightAttrib::register_with_read_factory(); LightRampAttrib::register_with_read_factory(); + LogicOpAttrib::register_with_read_factory(); MaterialAttrib::register_with_read_factory(); ModelNode::register_with_read_factory(); ModelRoot::register_with_read_factory(); diff --git a/panda/src/pgraph/logicOpAttrib.I b/panda/src/pgraph/logicOpAttrib.I new file mode 100644 index 0000000000..189769a3e6 --- /dev/null +++ b/panda/src/pgraph/logicOpAttrib.I @@ -0,0 +1,29 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file logicOpAttrib.I + * @author rdb + * @date 2016-03-24 + */ + +/** + * Use LogicOpAttrib::make() to construct a new LogicOpAttrib object. + */ +INLINE LogicOpAttrib:: +LogicOpAttrib(LogicOpAttrib::Operation op) : + _op(op) +{ +} + +/** + * Returns the logic operation specified by this attribute. + */ +INLINE LogicOpAttrib::Operation LogicOpAttrib:: +get_operation() const { + return _op; +} diff --git a/panda/src/pgraph/logicOpAttrib.cxx b/panda/src/pgraph/logicOpAttrib.cxx new file mode 100644 index 0000000000..b632bb1b45 --- /dev/null +++ b/panda/src/pgraph/logicOpAttrib.cxx @@ -0,0 +1,205 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file logicOpAttrib.I + * @author rdb + * @date 2016-03-24 + */ + +#include "logicOpAttrib.h" +#include "graphicsStateGuardianBase.h" +#include "dcast.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "datagram.h" +#include "datagramIterator.h" + +TypeHandle LogicOpAttrib::_type_handle; +int LogicOpAttrib::_attrib_slot; + +/** + * Constructs a new LogicOpAttrib object that disables special-effect + * blending, allowing normal transparency to be used instead. + */ +CPT(RenderAttrib) LogicOpAttrib:: +make_off() { + return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot); +} + +/** + * Constructs a new LogicOpAttrib object with the given logic operation. + */ +CPT(RenderAttrib) LogicOpAttrib:: +make(LogicOpAttrib::Operation op) { + LogicOpAttrib *attrib = new LogicOpAttrib(op); + return return_new(attrib); +} + +/** + * Returns a RenderAttrib that corresponds to whatever the standard default + * properties for render attributes of this type ought to be. + */ +CPT(RenderAttrib) LogicOpAttrib:: +make_default() { + return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot); +} + +/** + * + */ +void LogicOpAttrib:: +output(ostream &out) const { + out << get_type() << ":" << get_operation(); +} + +/** + * Intended to be overridden by derived LogicOpAttrib types to return a + * unique number indicating whether this LogicOpAttrib is equivalent to the + * other one. + * + * This should return 0 if the two LogicOpAttrib 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 LogicOpAttrib objects whose get_type() + * functions return the same. + */ +int LogicOpAttrib:: +compare_to_impl(const RenderAttrib *other) const { + const LogicOpAttrib *la = (const LogicOpAttrib *)other; + return (int)_op - (int)la->_op; +} + +/** + * Intended to be overridden by derived RenderAttrib types to return a unique + * hash for these particular properties. RenderAttribs that compare the same + * with compare_to_impl(), above, should return the same hash; RenderAttribs + * that compare differently should return a different hash. + */ +size_t LogicOpAttrib:: +get_hash_impl() const { + size_t hash = 0; + hash = int_hash::add_hash(hash, (int)_op); + return hash; +} + +/** + * + */ +CPT(RenderAttrib) LogicOpAttrib:: +get_auto_shader_attrib_impl(const RenderState *state) const { + return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot); +} + +/** + * Tells the BamReader how to create objects of type LogicOpAttrib. + */ +void LogicOpAttrib:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +/** + * Writes the contents of this object to the datagram for shipping out to a + * Bam file. + */ +void LogicOpAttrib:: +write_datagram(BamWriter *manager, Datagram &dg) { + RenderAttrib::write_datagram(manager, dg); + + dg.add_uint8(_op); +} + +/** + * This function is called by the BamReader's factory when a new object of + * type LogicOpAttrib is encountered in the Bam file. It should create the + * LogicOpAttrib and extract its information from the file. + */ +TypedWritable *LogicOpAttrib:: +make_from_bam(const FactoryParams ¶ms) { + LogicOpAttrib *attrib = new LogicOpAttrib(O_none); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + attrib->fillin(scan, manager); + + return attrib; +} + +/** + * This internal function is called by make_from_bam to read in all of the + * relevant data from the BamFile for the new LogicOpAttrib. + */ +void LogicOpAttrib:: +fillin(DatagramIterator &scan, BamReader *manager) { + RenderAttrib::fillin(scan, manager); + + _op = (Operation)scan.get_uint8(); +} + +/** + * + */ +ostream & +operator << (ostream &out, LogicOpAttrib::Operation op) { + switch (op) { + case LogicOpAttrib::O_none: + return out << "none"; + + case LogicOpAttrib::O_clear: + return out << "clear"; + + case LogicOpAttrib::O_and: + return out << "and"; + + case LogicOpAttrib::O_and_reverse: + return out << "and_reverse"; + + case LogicOpAttrib::O_copy: + return out << "copy"; + + case LogicOpAttrib::O_and_inverted: + return out << "and_inverted"; + + case LogicOpAttrib::O_noop: + return out << "noop"; + + case LogicOpAttrib::O_xor: + return out << "xor"; + + case LogicOpAttrib::O_or: + return out << "or"; + + case LogicOpAttrib::O_nor: + return out << "nor"; + + case LogicOpAttrib::O_equivalent: + return out << "equivalent"; + + case LogicOpAttrib::O_invert: + return out << "invert"; + + case LogicOpAttrib::O_or_reverse: + return out << "or_reverse"; + + case LogicOpAttrib::O_copy_inverted: + return out << "copy_inverted"; + + case LogicOpAttrib::O_or_inverted: + return out << "or_inverted"; + + case LogicOpAttrib::O_nand: + return out << "nand"; + + case LogicOpAttrib::O_set: + return out << "set"; + } + + return out << "**invalid LogicOpAttrib::Operation(" << (int)op << ")**"; +} diff --git a/panda/src/pgraph/logicOpAttrib.h b/panda/src/pgraph/logicOpAttrib.h new file mode 100644 index 0000000000..988836f8d1 --- /dev/null +++ b/panda/src/pgraph/logicOpAttrib.h @@ -0,0 +1,112 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file logicOpAttrib.I + * @author rdb + * @date 2016-03-24 + */ + +#ifndef LOGICOPATTRIB_H +#define LOGICOPATTRIB_H + +#include "pandabase.h" +#include "luse.h" +#include "renderAttrib.h" + +class FactoryParams; + +/** + * If enabled, specifies that a custom logical operation be performed instead + * of any color blending. Setting it to a value other than M_none will cause + * color blending to be disabled and the given logic operation to be performed. + */ +class EXPCL_PANDA_PGRAPH LogicOpAttrib : public RenderAttrib { +PUBLISHED: + enum Operation { + O_none, // LogicOp disabled, regular blending occurs. + O_clear, // Clears framebuffer value. + O_and, + O_and_reverse, + O_copy, // Writes the incoming color to the framebuffer. + O_and_inverted, + O_noop, // Leaves the framebuffer value unaltered. + O_xor, + O_or, + O_nor, + O_equivalent, + O_invert, + O_or_reverse, + O_copy_inverted, + O_or_inverted, + O_nand, + O_set, // Sets all the bits in the framebuffer to 1. + }; + +private: + INLINE LogicOpAttrib(Operation op); + +PUBLISHED: + static CPT(RenderAttrib) make_off(); + static CPT(RenderAttrib) make(Operation op); + static CPT(RenderAttrib) make_default(); + + INLINE Operation get_operation() const; + MAKE_PROPERTY(operation, get_operation); + +public: + virtual void output(ostream &out) const; + +protected: + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual size_t get_hash_impl() const; + virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; + +private: + Operation _op; + +PUBLISHED: + static int get_class_slot() { + return _attrib_slot; + } + virtual int get_slot() const { + return get_class_slot(); + } + +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, "LogicOpAttrib", + RenderAttrib::get_class_type()); + _attrib_slot = register_slot(_type_handle, 100, new LogicOpAttrib(O_none)); + } + 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; + static int _attrib_slot; +}; + +EXPCL_PANDA_PGRAPH ostream &operator << (ostream &out, LogicOpAttrib::Operation op); + +#include "logicOpAttrib.I" + +#endif diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index c6bfff127c..de0cf7c4fb 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -4832,6 +4832,62 @@ get_transparency() const { return TransparencyAttrib::M_none; } +/** + * Specifically sets or disables a logical operation on this particular node. + * If no other nodes override, this will cause geometry to be rendered without + * color blending but instead using the given logical operator. + */ +void NodePath:: +set_logic_op(LogicOpAttrib::Operation op, int priority) { + nassertv_always(!is_empty()); + + node()->set_attrib(LogicOpAttrib::make(op), priority); +} + +/** + * Completely removes any logical operation that may have been set on this + * node via set_logic_op(). The geometry at this level and below will + * subsequently be rendered using standard color blending. + */ +void NodePath:: +clear_logic_op() { + nassertv_always(!is_empty()); + node()->clear_attrib(LogicOpAttrib::get_class_slot()); +} + +/** + * Returns true if a logical operation has been explicitly set on this + * particular node via set_logic_op(). If this returns true, then + * get_logic_op() may be called to determine whether a logical operation has + * been explicitly disabled for this node or set to particular operation. + */ +bool NodePath:: +has_logic_op() const { + nassertr_always(!is_empty(), false); + return node()->has_attrib(LogicOpAttrib::get_class_slot()); +} + +/** + * Returns the logical operation that has been specifically set on this node + * via set_logic_op(), or O_none if standard color blending has been + * specifically set, or if nothing has been specifically set. See also + * has_logic_op(). This does not necessarily imply that the geometry will + * or will not be rendered with the given logical operation, as there may be + * other nodes that override. + */ +LogicOpAttrib::Operation NodePath:: +get_logic_op() const { + nassertr_always(!is_empty(), LogicOpAttrib::O_none); + const RenderAttrib *attrib = + node()->get_attrib(LogicOpAttrib::get_class_slot()); + if (attrib != (const RenderAttrib *)NULL) { + const LogicOpAttrib *ta = DCAST(LogicOpAttrib, attrib); + return ta->get_operation(); + } + + return LogicOpAttrib::O_none; +} + /** * Specifies the antialiasing type that should be applied at this node and * below. See AntialiasAttrib. diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 729bcf37f3..4f39aa28bb 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -26,6 +26,7 @@ #include "transformState.h" #include "renderModeAttrib.h" #include "transparencyAttrib.h" +#include "logicOpAttrib.h" #include "nodePathComponent.h" #include "pointerTo.h" #include "referenceCount.h" @@ -62,57 +63,83 @@ class SamplerState; class Shader; class ShaderInput; -/* - * A NodePath is the fundamental unit of high-level interaction with the scene - * graph. It encapsulates the complete path down to a node from some other - * node, usually the root of the scene graph. This is used to resolve - * ambiguities associated with instancing. NodePath also contains a number of - * handy high-level methods for common scene-graph manipulations, such as - * reparenting, and common state changes, such as repositioning. There are - * also a number of NodePath methods for finding nodes deep within the tree by - * name or by type. These take a path string, which at its simplest consists - * of a series of node names separated by slashes, like a directory pathname. - * Each component of the path string may optionally consist of one of the - * following special names, instead of a node name: * -- matches - * exactly one node, with any name. ** -- matches any sequence of - * zero or more nodes. +typename -- matches any node that is or derives from - * the given type. -typename -- matches any node that is the given type - * exactly. =tag -- matches any node that has the indicated tag. - * =tag=value -- matches any node whose tag matches the indicated value. - * Furthermore, a node name may itself contain standard filename globbing - * characters, like *, ?, and [a-z], that will be accepted as a partial match. - * (In fact, the '*' special name may be seen as just a special case of this.) - * The globbing characters may not be used with the typename matches or with - * tag matches, but they may be used to match a tag's value in the =tag=value - * syntax. The special characters "@@", appearing at the beginning of a node - * name, indicate a stashed node. Normally, stashed nodes are not returned by - * a find (but see the special flags, below), but a stashed node may be found - * if it is explicitly named with its leading @@ characters. By extension, - * "@@*" may be used to identify any stashed node. Examples: "roomgraph" will - * look for a node named "graph", which is a child of an unnamed node, which - * is a child of a node named "room", which is a child of the starting path. - * "**red*" will look for any node anywhere in the tree (below the starting - * path) with a name that begins with "red". "**+PartBundleNode**head" will - * look for a node named "head", somewhere below a PartBundleNode anywhere in - * the tree. The search is always potentially ambiguous, even if the special - * wildcard operators are not used, because there may be multiple nodes in the - * tree with the same name. In general, in the case of an ambiguity, the - * shortest path is preferred; when a method (such as extend_by) must choose - * only only one of several possible paths, it will choose the shortest - * available; on the other hand, when a method (such as find_all_matches) is - * to return all of the matching paths, it will sort them so that the shortest - * paths appear first in the output. Special flags. The entire string may - * optionally be followed by the ";" character, followed by one or more of the - * following special control flags, with no intervening spaces or punctuation: - * -h Do not return hidden nodes. +h Do return hidden nodes. -s Do - * not return stashed nodes unless explicitly referenced with @@. +s Return - * stashed nodes even without any explicit @@ characters. -i Node name - * comparisons are not case insensitive: case must match exactly. +i Node - * name comparisons are case insensitive: case is not important. This affects - * matches against the node name only; node type and tag strings are always - * case sensitive. The default flags are +h-s-i. - */ - +// +// A NodePath is the fundamental unit of high-level interaction with the scene +// graph. It encapsulates the complete path down to a node from some other +// node, usually the root of the scene graph. This is used to resolve +// ambiguities associated with instancing. +// +// NodePath also contains a number of handy high-level methods for common +// scene-graph manipulations, such as reparenting, and common state changes, +// such as repositioning. +// +// There are also a number of NodePath methods for finding nodes deep within +// the tree by name or by type. These take a path string, which at its +// simplest consists of a series of node names separated by slashes, like a +// directory pathname. +// +// Each component of the path string may optionally consist of one of the +// following special names, instead of a node name: +// +// * -- matches exactly one node, with any name. +// ** -- matches any sequence of zero or more nodes. +// +typename -- matches any node that is or derives from the given type. +// -typename -- matches any node that is the given type exactly. +// =tag -- matches any node that has the indicated tag. +// =tag=value -- matches any node whose tag matches the indicated value. +// +// Furthermore, a node name may itself contain standard filename globbing +// characters, like *, ?, and [a-z], that will be accepted as a partial match. +// (In fact, the '*' special name may be seen as just a special case of this.) +// The globbing characters may not be used with the typename matches or with +// tag matches, but they may be used to match a tag's value in the =tag=value +// syntax. +// +// The special characters "@@", appearing at the beginning of a node name, +// indicate a stashed node. Normally, stashed nodes are not returned by a +// find (but see the special flags, below), but a stashed node may be found if +// it is explicitly named with its leading @@ characters. By extension, "@@*" +// may be used to identify any stashed node. +// +// Examples: +// +// "room//graph" will look for a node named "graph", which is a child of an +// unnamed node, which is a child of a node named "room", which is a child of +// the starting path. +// +// "**/red*" will look for any node anywhere in the tree (below the starting +// path) with a name that begins with "red". +// +// "**/+PartBundleNode/**/head" will look for a node named "head", somewhere +// below a PartBundleNode anywhere in the tree. +// +// +// The search is always potentially ambiguous, even if the special wildcard +// operators are not used, because there may be multiple nodes in the tree +// with the same name. In general, in the case of an ambiguity, the shortest +// path is preferred; when a method (such as extend_by) must choose only only +// one of several possible paths, it will choose the shortest available; on +// the other hand, when a method (such as find_all_matches) is to return all +// of the matching paths, it will sort them so that the shortest paths appear +// first in the output. +// +// +// Special flags. The entire string may optionally be followed by the ";" +// character, followed by one or more of the following special control flags, +// with no intervening spaces or punctuation: +// +// -h Do not return hidden nodes. +// +h Do return hidden nodes. +// -s Do not return stashed nodes unless explicitly referenced with @@. +// +s Return stashed nodes even without any explicit @@ characters. +// -i Node name comparisons are not case insensitive: case must match +// exactly. +// +i Node name comparisons are case insensitive: case is not important. +// This affects matches against the node name only; node type and tag +// strings are always case sensitive. +// +// The default flags are +h-s-i. +// /** * NodePath is the fundamental system for disambiguating instances, and also @@ -786,6 +813,11 @@ PUBLISHED: bool has_transparency() const; TransparencyAttrib::Mode get_transparency() const; + void set_logic_op(LogicOpAttrib::Operation op, int priority = 0); + void clear_logic_op(); + bool has_logic_op() const; + LogicOpAttrib::Operation get_logic_op() const; + void set_antialias(unsigned short mode, int priority = 0); void clear_antialias(); bool has_antialias() const; diff --git a/panda/src/pgraph/p3pgraph_composite3.cxx b/panda/src/pgraph/p3pgraph_composite3.cxx index 5b88a55d2f..18be4cb35e 100644 --- a/panda/src/pgraph/p3pgraph_composite3.cxx +++ b/panda/src/pgraph/p3pgraph_composite3.cxx @@ -7,6 +7,7 @@ #include "loaderFileType.cxx" #include "loaderFileTypeBam.cxx" #include "loaderFileTypeRegistry.cxx" +#include "logicOpAttrib.cxx" #include "materialAttrib.cxx" #include "materialCollection.cxx" #include "modelFlattenRequest.cxx" diff --git a/panda/src/pgraph/renderAttribRegistry.h b/panda/src/pgraph/renderAttribRegistry.h index 9858192332..59194fd278 100644 --- a/panda/src/pgraph/renderAttribRegistry.h +++ b/panda/src/pgraph/renderAttribRegistry.h @@ -47,7 +47,7 @@ public: // Raise this number whenever we add a new attrib. This used to be // determined at runtime, but it's better to have it as a constexpr. - static const int _max_slots = 29; + static const int _max_slots = 32; int register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib);