diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp new file mode 100644 index 0000000000..8541932160 --- /dev/null +++ b/panda/src/pgraph/Sources.pp @@ -0,0 +1,54 @@ +#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ + dtoolutil:c dtoolbase:c dtool:m +#define LOCAL_LIBS gobj putil graph linmath express pandabase + +#begin lib_target + #define TARGET pgraph + + #define SOURCES \ + colorAttrib.h colorAttrib.I \ + config_pgraph.h \ + cycleData.h cycleData.I \ + cycleDataReader.h cycleDataReader.I \ + cycleDataWriter.h cycleDataWriter.I \ + pandaNode.h pandaNode.I \ + pipeline.h pipeline.I \ + pipelineCycler.h pipelineCycler.I \ + pipelineCyclerBase.h pipelineCyclerBase.I \ + renderAttrib.h renderAttrib.I \ + renderState.h renderState.I \ + textureAttrib.h textureAttrib.I + +// #define INCLUDED_SOURCES + #define SOURCES $[SOURCES] \ + colorAttrib.cxx \ + config_pgraph.cxx \ + cycleData.cxx \ + cycleDataReader.cxx \ + cycleDataWriter.cxx \ + pandaNode.cxx \ + pipeline.cxx \ + pipelineCycler.cxx \ + pipelineCyclerBase.cxx \ + renderAttrib.cxx \ + renderState.cxx \ + textureAttrib.cxx + + #define INSTALL_HEADERS \ + pandaNode.h pandaNode.I + + #define IGATESCAN all + +#end lib_target + + +#begin test_bin_target + #define TARGET test_pgraph + + #define SOURCES \ + test_pgraph.cxx + + #define LOCAL_LIBS $[LOCAL_LIBS] pgraph + #define OTHER_LIBS $[OTHER_LIBS] pystub + +#end test_bin_target diff --git a/panda/src/pgraph/colorAttrib.I b/panda/src/pgraph/colorAttrib.I new file mode 100644 index 0000000000..a2db54fd5c --- /dev/null +++ b/panda/src/pgraph/colorAttrib.I @@ -0,0 +1,66 @@ +// Filename: colorAttrib.I +// Created by: drose (22Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::Constructor +// Access: Private +// Description: Use ColorAttrib::make() to construct a new +// ColorAttrib object. +//////////////////////////////////////////////////////////////////// +INLINE ColorAttrib:: +ColorAttrib(ColorAttrib::Type type, const Colorf &color) : + _type(type), + _color(color) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::get_color_type +// Access: Published +// Description: Returns the type of color specified by this +// ColorAttrib. The options are: +// +// T_vertex - use the vertex color specified in the +// geometry itself. +// +// T_flat - use the color specified in this +// ColorAttrib for all geometry. You can get this +// color via get_color(). +// +// T_off - do not issue any color commands at all. +// This is generally used only in contexts where the +// color is meaningless, e.g. when drawing directly to +// the depth buffer. +//////////////////////////////////////////////////////////////////// +INLINE ColorAttrib::Type ColorAttrib:: +get_color_type() const { + return _type; +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::get_color +// Access: Published +// Description: If the type is T_flat, this returns the color that +// will be applied to geometry. If the type is anything +// else, this is meaningless. +//////////////////////////////////////////////////////////////////// +INLINE const Colorf &ColorAttrib:: +get_color() const { + return _color; +} diff --git a/panda/src/pgraph/colorAttrib.cxx b/panda/src/pgraph/colorAttrib.cxx new file mode 100644 index 0000000000..b5c5ce7264 --- /dev/null +++ b/panda/src/pgraph/colorAttrib.cxx @@ -0,0 +1,127 @@ +// Filename: colorAttrib.cxx +// Created by: drose (22Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "colorAttrib.h" +#include "dcast.h" + +TypeHandle ColorAttrib::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::make_vertex +// Access: Published, Static +// Description: Constructs a new ColorAttrib object that indicates +// geometry should be rendered according to its own +// vertex color. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ColorAttrib:: +make_vertex() { + ColorAttrib *attrib = new ColorAttrib(T_vertex, Colorf(0.0f, 0.0f, 0.0f, 1.0f)); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::make_flat +// Access: Published, Static +// Description: Constructs a new ColorAttrib object that indicates +// geometry should be rendered in the indicated color. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ColorAttrib:: +make_flat(const Colorf &color) { + ColorAttrib *attrib = new ColorAttrib(T_flat, color); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::make_off +// Access: Published, Static +// Description: Constructs a new ColorAttrib object that indicates +// geometry should be rendered without any color +// commands at all. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) ColorAttrib:: +make_off() { + ColorAttrib *attrib = new ColorAttrib(T_off, Colorf(0.0f, 0.0f, 0.0f, 1.0f)); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ColorAttrib:: +output(ostream &out) const { + out << get_type() << ":"; + switch (get_color_type()) { + case T_vertex: + out << "vertex"; + break; + + case T_flat: + out << "(" << get_color() << ")"; + break; + + case T_off: + out << "off"; + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::compare_to_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived ColorAttrib +// types to return a unique number indicating whether +// this ColorAttrib is equivalent to the other one. +// +// This should return 0 if the two ColorAttrib 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 ColorAttrib +// objects whose get_type() functions return the same. +//////////////////////////////////////////////////////////////////// +int ColorAttrib:: +compare_to_impl(const RenderAttrib *other) const { + const ColorAttrib *ta; + DCAST_INTO_R(ta, other, 0); + if (_type != ta->_type) { + return (int)_type - (int)ta->_type; + } + if (_type == T_flat) { + return _color.compare_to(ta->_color); + } + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: ColorAttrib::make_default_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived ColorAttrib +// types to specify what the default property for a +// ColorAttrib of this type should be. +// +// This should return a newly-allocated ColorAttrib of +// the same type that corresponds to whatever the +// standard default for this kind of ColorAttrib is. +//////////////////////////////////////////////////////////////////// +RenderAttrib *ColorAttrib:: +make_default_impl() const { + return new ColorAttrib(T_vertex, Colorf(0.0f, 0.0f, 0.0f, 1.0f)); +} diff --git a/panda/src/pgraph/colorAttrib.h b/panda/src/pgraph/colorAttrib.h new file mode 100644 index 0000000000..3bb4e9979f --- /dev/null +++ b/panda/src/pgraph/colorAttrib.h @@ -0,0 +1,81 @@ +// Filename: colorAttrib.h +// Created by: drose (22Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef COLORATTRIB_H +#define COLORATTRIB_H + +#include "pandabase.h" + +#include "renderAttrib.h" +#include "luse.h" + +//////////////////////////////////////////////////////////////////// +// Class : ColorAttrib +// Description : Indicates what color should be applied to renderable +// geometry. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ColorAttrib : public RenderAttrib { +PUBLISHED: + enum Type { + T_vertex, T_flat, T_off + }; + +private: + INLINE ColorAttrib(Type type, const Colorf &color); + +PUBLISHED: + static CPT(RenderAttrib) make_vertex(); + static CPT(RenderAttrib) make_flat(const Colorf &color); + static CPT(RenderAttrib) make_off(); + + INLINE Type get_color_type() const; + INLINE const Colorf &get_color() const; + +public: + virtual void output(ostream &out) const; + +protected: + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual RenderAttrib *make_default_impl() const; + +private: + Type _type; + Colorf _color; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedWritableReferenceCount::init_type(); + register_type(_type_handle, "ColorAttrib", + TypedWritableReferenceCount::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; +}; + +#include "colorAttrib.I" + +#endif + diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx new file mode 100644 index 0000000000..37462bf723 --- /dev/null +++ b/panda/src/pgraph/config_pgraph.cxx @@ -0,0 +1,61 @@ +// Filename: config_pgraph.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "config_pgraph.h" + +#include "colorAttrib.h" +#include "pandaNode.h" +#include "renderAttrib.h" +#include "renderState.h" +#include "textureAttrib.h" + +#include "dconfig.h" + +Configure(config_pgraph); +NotifyCategoryDef(pgraph, ""); + +ConfigureFn(config_pgraph) { + init_libpgraph(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: init_libpgraph +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libpgraph() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + ColorAttrib::init_type(); + PandaNode::init_type(); + RenderAttrib::init_type(); + RenderState::init_type(); + TextureAttrib::init_type(); + + PandaNode::register_with_read_factory(); + RenderState::register_with_read_factory(); +} diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h new file mode 100644 index 0000000000..aa0c551307 --- /dev/null +++ b/panda/src/pgraph/config_pgraph.h @@ -0,0 +1,29 @@ +// Filename: config_pgraph.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONFIG_PGRAPH_H +#define CONFIG_PGRAPH_H + +#include "pandabase.h" +#include "notifyCategoryProxy.h" + +NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA); + +extern EXPCL_PANDA void init_libpgraph(); + +#endif diff --git a/panda/src/pgraph/cycleData.I b/panda/src/pgraph/cycleData.I new file mode 100644 index 0000000000..531eff61c7 --- /dev/null +++ b/panda/src/pgraph/cycleData.I @@ -0,0 +1,27 @@ +// Filename: cycleData.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CycleData:: +CycleData() { +} diff --git a/panda/src/pgraph/cycleData.cxx b/panda/src/pgraph/cycleData.cxx new file mode 100644 index 0000000000..ae7b69fd8f --- /dev/null +++ b/panda/src/pgraph/cycleData.cxx @@ -0,0 +1,29 @@ +// Filename: cycleData.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleData.h" + + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CycleData:: +~CycleData() { +} diff --git a/panda/src/pgraph/cycleData.h b/panda/src/pgraph/cycleData.h new file mode 100644 index 0000000000..f537256d8e --- /dev/null +++ b/panda/src/pgraph/cycleData.h @@ -0,0 +1,44 @@ +// Filename: cycleData.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATA_H +#define CYCLEDATA_H + +#include "pandabase.h" + +#include "referenceCount.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleData +// Description : A single page of data maintained by a PipelineCycler. +// Normally you should inherit from this class to define +// the data structures that are important to protect +// between stages of a pipeline. See PipelineCycler. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA CycleData : public ReferenceCount { +public: + INLINE CycleData(); + virtual ~CycleData(); + + virtual CycleData *make_copy() const=0; +}; + +#include "cycleData.I" + +#endif + diff --git a/panda/src/pgraph/cycleDataReader.I b/panda/src/pgraph/cycleDataReader.I new file mode 100644 index 0000000000..f62d0d6ead --- /dev/null +++ b/panda/src/pgraph/cycleDataReader.I @@ -0,0 +1,68 @@ +// Filename: cycleDataReader.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +CycleDataReader(const PipelineCycler &cycler) : + _cycler(cycler) +{ + _pointer = (const CycleDataType *)_cycler.read(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +CycleDataReader(const CycleDataReader ©) : + _cycler(copy._cycler), + _pointer(copy._pointer) +{ + _cycler.increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +~CycleDataReader() { + _cycler.release_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::operator -> +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataReader:: +operator -> () const { + return _pointer; +} diff --git a/panda/src/pgraph/cycleDataReader.cxx b/panda/src/pgraph/cycleDataReader.cxx new file mode 100644 index 0000000000..1dcd6ce677 --- /dev/null +++ b/panda/src/pgraph/cycleDataReader.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataReader.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleDataReader.h" diff --git a/panda/src/pgraph/cycleDataReader.h b/panda/src/pgraph/cycleDataReader.h new file mode 100644 index 0000000000..7b832944ff --- /dev/null +++ b/panda/src/pgraph/cycleDataReader.h @@ -0,0 +1,59 @@ +// Filename: cycleDataReader.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATAREADER_H +#define CYCLEDATAREADER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataReader +// Description : This template class calls PipelineCycler::read() in +// the constructor and PipelineCycler::release_read() in +// the destructor. In the interim, it provides a +// transparent read-only access to the CycleData. +// +// It exists as a syntactic convenience to access the +// data in the CycleData. It also allows the whole +// system to compile down to nothing if +// SUPPORT_PIPELINING is not defined. +//////////////////////////////////////////////////////////////////// +template +class CycleDataReader { +public: + INLINE CycleDataReader(const PipelineCycler &cycler); + INLINE CycleDataReader(const CycleDataReader ©); + + INLINE ~CycleDataReader(); + + INLINE const CycleDataType *operator -> () const; + +private: + const PipelineCycler &_cycler; + const CycleDataType *_pointer; +}; + +// This abbreviation macro is used for ease of typing. +#define CDR(type) CycleDataReader< type > + +#include "cycleDataReader.I" + +#endif diff --git a/panda/src/pgraph/cycleDataWriter.I b/panda/src/pgraph/cycleDataWriter.I new file mode 100644 index 0000000000..b7dc4a7597 --- /dev/null +++ b/panda/src/pgraph/cycleDataWriter.I @@ -0,0 +1,80 @@ +// Filename: cycleDataWriter.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler) : + _cycler(cycler) +{ + _pointer = (CycleDataType *)_cycler.write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(const CycleDataWriter ©) : + _cycler(copy._cycler), + _pointer(copy._pointer) +{ + _cycler.increment_write(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +~CycleDataWriter() { + _cycler.release_write(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::operator -> +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *CycleDataWriter:: +operator -> () { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::operator -> +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataWriter:: +operator -> () const { + return _pointer; +} diff --git a/panda/src/pgraph/cycleDataWriter.cxx b/panda/src/pgraph/cycleDataWriter.cxx new file mode 100644 index 0000000000..c28e311dba --- /dev/null +++ b/panda/src/pgraph/cycleDataWriter.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataWriter.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleDataWriter.h" diff --git a/panda/src/pgraph/cycleDataWriter.h b/panda/src/pgraph/cycleDataWriter.h new file mode 100644 index 0000000000..218f08b128 --- /dev/null +++ b/panda/src/pgraph/cycleDataWriter.h @@ -0,0 +1,59 @@ +// Filename: cycleDataWriter.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATAWRITER_H +#define CYCLEDATAWRITER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataWriter +// Description : This template class calls PipelineCycler::write() in +// the constructor and PipelineCycler::release_write() in +// the destructor. In the interim, it provides a +// transparent read-write access to the CycleData. +// +// It exists as a syntactic convenience to access the +// data in the CycleData. It also allows the whole +// system to compile down to nothing if +// SUPPORT_PIPELINING is not defined. +//////////////////////////////////////////////////////////////////// +template +class CycleDataWriter { +public: + INLINE CycleDataWriter(PipelineCycler &cycler); + INLINE CycleDataWriter(const CycleDataWriter ©); + + INLINE ~CycleDataWriter(); + + INLINE CycleDataType *operator -> (); + INLINE const CycleDataType *operator -> () const; + +private: + PipelineCycler &_cycler; + CycleDataType *_pointer; +}; + +#define CDW(type) CycleDataWriter< type > + +#include "cycleDataWriter.I" + +#endif diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I new file mode 100644 index 0000000000..c4fc934965 --- /dev/null +++ b/panda/src/pgraph/pandaNode.I @@ -0,0 +1,325 @@ +// Filename: pandaNode.I +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::DownConnection::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::DownConnection:: +DownConnection(PandaNode *child, int sort) : + _child(child), + _sort(sort) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::DownConnection::operator < +// Access: Public +// Description: Provides a partial ordering on the children of a node +// so that they are ranked first in sort order, and then +// (by virtue of the ordered_vector) in the order they +// were added. +//////////////////////////////////////////////////////////////////// +INLINE bool PandaNode::DownConnection:: +operator < (const DownConnection &other) const { + return _sort < other._sort; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::DownConnection::get_child +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *PandaNode::DownConnection:: +get_child() const { + return _child; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::DownConnection::get_sort +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE int PandaNode::DownConnection:: +get_sort() const { + return _sort; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::CData:: +CData() { + _state_changes = RenderState::make_empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Children::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::Children:: +Children(const PipelineCycler &cycler) : + _cdata(cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Children::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::Children:: +Children(const PandaNode::Children ©) : + _cdata(copy._cdata) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Children::get_num_children +// Access: Public +// Description: Returns the number of children of the node. +//////////////////////////////////////////////////////////////////// +INLINE int PandaNode::Children:: +get_num_children() const { + return _cdata->_down.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Children::get_child +// Access: Public +// Description: Returns the nth child of the node. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *PandaNode::Children:: +get_child(int n) const { + nassertr(n >= 0 && n < (int)_cdata->_down.size(), NULL); + return _cdata->_down[n].get_child(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PandaNode:: +PandaNode(const string &name) : + Namable(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_num_parents +// Access: Published +// Description: Returns the number of parent nodes this node has. If +// this number is greater than 1, the node has been +// multiply instanced. The order of the parent nodes is +// not meaningful and is not related to the order in +// which the node was instanced to them. +//////////////////////////////////////////////////////////////////// +INLINE int PandaNode:: +get_num_parents() const { + CDR(CData) cdata(_cycler); + return cdata->_up.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_parent +// Access: Published +// Description: Returns the nth parent node of this node. See +// get_num_parents(). +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *PandaNode:: +get_parent(int n) const { + CDR(CData) cdata(_cycler); + nassertr(n >= 0 && n < (int)cdata->_up.size(), NULL); + return cdata->_up[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::find_parent +// Access: Published +// Description: Returns the index of the indicated parent node, if it +// is a parent, or -1 if it is not. +//////////////////////////////////////////////////////////////////// +INLINE int PandaNode:: +find_parent(PandaNode *node) const { + CDR(CData) cdata(_cycler); + Up::const_iterator ui = cdata->_up.find(node); + if (ui == cdata->_up.end()) { + return -1; + } + return ui - cdata->_up.begin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_num_children +// Access: Published +// Description: Returns the number of child nodes this node has. The +// order of the child nodes *is* meaningful and is based +// on the sort number that was passed to add_child(), +// and also on the order in which the nodes were added. +//////////////////////////////////////////////////////////////////// +INLINE int PandaNode:: +get_num_children() const { + CDR(CData) cdata(_cycler); + return cdata->_down.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_child +// Access: Published +// Description: Returns the nth child node of this node. See +// get_num_children(). +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *PandaNode:: +get_child(int n) const { + CDR(CData) cdata(_cycler); + nassertr(n >= 0 && n < (int)cdata->_down.size(), NULL); + return cdata->_down[n].get_child(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_sort +// Access: Published +// Description: Returns the sort index of the nth child node of this +// node (that is, the number that was passed to +// add_child()). See get_num_children(). +//////////////////////////////////////////////////////////////////// +INLINE int PandaNode:: +get_sort(int n) const { + CDR(CData) cdata(_cycler); + nassertr(n >= 0 && n < (int)cdata->_down.size(), -1); + return cdata->_down[n].get_sort(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::set_attrib +// Access: Published +// Description: Adds the indicated render attribute to the scene +// graph on this node. This attribute will now apply to +// this node and everything below. If there was already +// an attribute of the same type, it is replaced. +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode:: +set_attrib(const RenderAttrib *attrib, int override) { + CDW(CData) cdata(_cycler); + cdata->_state_changes = cdata->_state_changes->add(attrib, override); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_attrib +// Access: Published +// Description: Returns the render attribute of the indicated type, +// if it is defined on the node, or NULL if it is not. +// This checks only what is set on this particular node +// level, and has nothing to do with what render +// attributes may be inherited from parent nodes. +//////////////////////////////////////////////////////////////////// +INLINE const RenderAttrib *PandaNode:: +get_attrib(TypeHandle type) const { + CDR(CData) cdata(_cycler); + int index = cdata->_state_changes->find_attrib(type); + if (index >= 0) { + return cdata->_state_changes->get_attrib(index); + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::clear_attrib +// Access: Published +// Description: Removes the render attribute of the given type from +// this node. This node, and the subgraph below, will +// now inherit the indicated render attribute from the +// nodes above this one. +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode:: +clear_attrib(TypeHandle type) { + CDW(CData) cdata(_cycler); + cdata->_state_changes = cdata->_state_changes->remove(type); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::set_state +// Access: Published +// Description: Sets the complete RenderState that will be applied to +// all nodes at this level and below. (The actual state +// that will be applied to lower nodes is based on the +// composition of RenderStates from above this node as +// well). This completely replaces whatever has been +// set on this node via repeated calls to set_attrib(). +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode:: +set_state(const RenderState *state) { + CDW(CData) cdata(_cycler); + cdata->_state_changes = state; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_state +// Access: Published +// Description: Returns the complete RenderState that will be applied +// to all nodes at this level and below, as set on this +// node. This returns only the RenderState set on this +// particular node, and has nothing to do with state +// that might be inherited from above. +//////////////////////////////////////////////////////////////////// +INLINE const RenderState *PandaNode:: +get_state() const { + CDR(CData) cdata(_cycler); + return cdata->_state_changes; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::clear_state +// Access: Published +// Description: Resets this node to leave the render state alone. +// Nodes at this level and below will once again inherit +// their render state unchanged from the nodes above +// this level. +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode:: +clear_state() { + CDW(CData) cdata(_cycler); + cdata->_state_changes = RenderState::make_empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::get_children +// Access: Public +// Description: Returns an object that can be used to walk through +// the list of children of the node. When you intend to +// visit multiple children, using this is slightly +// faster than calling get_child() directly on the +// PandaNode, since this object keeps the PipelineCycler +// open the whole time. +// +// However, this object does not protect you from +// self-modifying loops (e.g. adding or removing +// children during traversal). +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::Children PandaNode:: +get_children() const { + return Children(_cycler); +} + diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx new file mode 100644 index 0000000000..61b3a0995d --- /dev/null +++ b/panda/src/pgraph/pandaNode.cxx @@ -0,0 +1,295 @@ +// Filename: pandaNode.cxx +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pandaNode.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "indent.h" + + +TypeHandle PandaNode::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PandaNode::CData:: +CData(const PandaNode::CData ©) : + _down(copy._down), + _up(copy._up), + _node_bounds(copy._node_bounds), + _subgraph_bounds(copy._subgraph_bounds), + _state_changes(copy._state_changes) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::make_copy +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CycleData *PandaNode::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +PandaNode:: +PandaNode(const PandaNode ©) : + TypedWritable(copy), + Namable(copy), + ReferenceCount(copy) +{ + // Copying a node does not copy its children. + + // Copy the other node's bounding volume. + CDR(CData) copy_cdata(copy._cycler); + CDW(CData) cdata(_cycler); + cdata->_node_bounds = copy_cdata->_node_bounds; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void PandaNode:: +operator = (const PandaNode ©) { + TypedWritable::operator = (copy); + Namable::operator = (copy); + ReferenceCount::operator = (copy); + + // Copy the other node's bounding volume. + CDR(CData) copy_cdata(copy._cycler); + CDW(CData) cdata(_cycler); + cdata->_node_bounds = copy_cdata->_node_bounds; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +PandaNode:: +~PandaNode() { + // We shouldn't have any parents left by the time we destruct, or + // there's a refcount fault somewhere. + CDR(CData) cdata(_cycler); + nassertv(cdata->_up.empty()); + + remove_all_children(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::find_child +// Access: Published +// Description: Returns the index of the indicated child node, if it +// is a child, or -1 if it is not. +//////////////////////////////////////////////////////////////////// +int PandaNode:: +find_child(PandaNode *node) const { + CDR(CData) cdata(_cycler); + + // We have to search for the child by brute force, since we don't + // know what sort index it was added as. + Down::const_iterator ci; + for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) { + if ((*ci).get_child() == node) { + return ci - cdata->_down.begin(); + } + } + + return -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::add_child +// Access: Published +// Description: Adds a new child to the node. The child is added in +// the relative position indicated by sort; if all +// children have the same sort index, the child is added +// at the end. +// +// If the same child is added to a node more than once, +// the previous instance is first removed. +// +// The return value is the index of the new child. +//////////////////////////////////////////////////////////////////// +int PandaNode:: +add_child(PandaNode *child, int sort) { + remove_child(child); + CDW(CData) cdata(_cycler); + CDW(CData) cdata_child(child->_cycler); + + Down::iterator ci = cdata->_down.insert(DownConnection(child, sort)); + cdata_child->_up.insert(this); + + return ci - cdata->_down.begin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::remove_child +// Access: Published +// Description: Removes the nth child from the node. +//////////////////////////////////////////////////////////////////// +void PandaNode:: +remove_child(int n) { + CDW(CData) cdata(_cycler); + nassertv(n >= 0 && n < (int)cdata->_down.size()); + + PandaNode *child = cdata->_down[n].get_child(); + CDW(CData) cdata_child(child->_cycler); + + cdata->_down.erase(cdata->_down.begin() + n); + int num_erased = cdata_child->_up.erase(this); + nassertv(num_erased == 1); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::remove_child +// Access: Published +// Description: Removes the indicated child from the node. Returns +// true if the child was removed, false if it was not +// already a child of the node. +//////////////////////////////////////////////////////////////////// +bool PandaNode:: +remove_child(PandaNode *child) { + CDW(CData) cdata_child(child->_cycler); + + // First, look for and remove this node from the child's parent + // list. + int num_erased = cdata_child->_up.erase(this); + if (num_erased == 0) { + // No such node; it wasn't our child to begin with. + return false; + } + + CDW(CData) cdata(_cycler); + + // Now, look for and remove the child node from our down list. + Down::iterator ci; + for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) { + if ((*ci).get_child() == child) { + cdata->_down.erase(ci); + return true; + } + } + + // We shouldn't get here unless there was a parent-child mismatch. + nassertr(false, false); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::remove_all_children +// Access: Published +// Description: Removes all the children from the node at once. +//////////////////////////////////////////////////////////////////// +void PandaNode:: +remove_all_children() { + CDW(CData) cdata(_cycler); + Down::iterator ci; + for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) { + PandaNode *child = (*ci).get_child(); + CDW(CData) child_cdata(child->_cycler); + child_cdata->_up.erase(this); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::output +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void PandaNode:: +output(ostream &out) const { + out << get_type() << " " << get_name(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::write +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void PandaNode:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << *this; + CDR(CData) cdata(_cycler); + if (!cdata->_state_changes->is_empty()) { + out << " (" << *cdata->_state_changes << ")"; + } + out << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// PandaNode. +//////////////////////////////////////////////////////////////////// +void PandaNode:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void PandaNode:: +write_datagram(BamWriter *manager, Datagram &dg) { +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type PandaNode is encountered +// in the Bam file. It should create the PandaNode +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *PandaNode:: +make_from_bam(const FactoryParams ¶ms) { + PandaNode *node = new PandaNode(""); + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::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 PandaNode. +//////////////////////////////////////////////////////////////////// +void PandaNode:: +fillin(DatagramIterator &scan, BamReader *manager) { +} diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h new file mode 100644 index 0000000000..64ec9f88fa --- /dev/null +++ b/panda/src/pgraph/pandaNode.h @@ -0,0 +1,175 @@ +// Filename: pandaNode.h +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PANDANODE_H +#define PANDANODE_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "cycleDataReader.h" +#include "cycleDataWriter.h" +#include "pipelineCycler.h" +#include "renderState.h" + +#include "typedWritable.h" +#include "boundedObject.h" +#include "namable.h" +#include "referenceCount.h" +#include "luse.h" +#include "ordered_vector.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : PandaNode +// Description : A basic node of the scene graph or data graph. This +// is the base class of all specialized nodes, and also +// serves as a generic node with no special properties. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PandaNode : public TypedWritable, + public Namable, virtual public ReferenceCount { +PUBLISHED: + INLINE PandaNode(const string &name); + PandaNode(const PandaNode ©); + void operator = (const PandaNode ©); + virtual ~PandaNode(); + + INLINE int get_num_parents() const; + INLINE PandaNode *get_parent(int n) const; + INLINE int find_parent(PandaNode *node) const; + + INLINE int get_num_children() const; + INLINE PandaNode *get_child(int n) const; + INLINE int get_sort(int n) const; + int find_child(PandaNode *node) const; + + int add_child(PandaNode *child, int sort = 0); + void remove_child(int n); + bool remove_child(PandaNode *child); + + void remove_all_children(); + + INLINE void set_attrib(const RenderAttrib *attrib, int override = 0); + INLINE const RenderAttrib *get_attrib(TypeHandle type) const; + INLINE void clear_attrib(TypeHandle type); + + INLINE void set_state(const RenderState *state); + INLINE const RenderState *get_state() const; + INLINE void clear_state(); + + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level) const; + +private: + class DownConnection { + public: + INLINE DownConnection(PandaNode *child, int sort); + INLINE bool operator < (const DownConnection &other) const; + INLINE PandaNode *get_child() const; + INLINE int get_sort() const; + + private: + // Child pointers are reference counted. That way, holding a + // pointer to the root of a subgraph keeps the entire subgraph + // around. + PT(PandaNode) _child; + int _sort; + }; + typedef ov_multiset Down; + // Parent pointers are not reference counted. That way, parents and + // children do not circularly reference each other. In fact, parent + // pointers are just simple pointers, with no additional data. We + // don't really need to keep the parent pointers around, but it's + // nice to be able to walk up the graph. + typedef ov_set Up; + + // This is the data that must be cycled between pipeline stages. + class CData : public CycleData { + public: + INLINE CData(); + CData(const CData ©); + virtual CycleData *make_copy() const; + + Down _down; + Up _up; + + BoundedObject _node_bounds; + BoundedObject _subgraph_bounds; + CPT(RenderState) _state_changes; + }; + + PipelineCycler _cycler; + +public: + // Use this interface when you want to walk through the list of + // children. This saves a tiny bit of overhead between each step, + // by keeping the PipelineCycler open for reading the whole time. + // However, it does not protect you from self-modifying loops. + class Children { + public: + INLINE Children(const PipelineCycler &cycler); + INLINE Children(const Children ©); + + INLINE int get_num_children() const; + INLINE PandaNode *get_child(int n) const; + + private: + CDR(CData) _cdata; + }; + + INLINE Children get_children() const; + +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() { + TypedWritable::init_type(); + ReferenceCount::init_type(); + register_type(_type_handle, "PandaNode", + TypedWritable::get_class_type(), + ReferenceCount::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; + + friend class PandaNode::Children; +}; + +INLINE ostream &operator << (ostream &out, const PandaNode &node) { + node.output(out); + return out; +} + +#include "pandaNode.I" + +#endif + diff --git a/panda/src/pgraph/pipeline.I b/panda/src/pgraph/pipeline.I new file mode 100644 index 0000000000..a41cb12606 --- /dev/null +++ b/panda/src/pgraph/pipeline.I @@ -0,0 +1,31 @@ +// Filename: pipeline.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::get_render_pipeline +// Access: Public, Static +// Description: Returns a pointer to the global render pipeline. +//////////////////////////////////////////////////////////////////// +INLINE Pipeline *Pipeline:: +get_render_pipeline() { + if (_render_pipeline == (Pipeline *)NULL) { + make_render_pipeline(); + } + return _render_pipeline; +} diff --git a/panda/src/pgraph/pipeline.cxx b/panda/src/pgraph/pipeline.cxx new file mode 100644 index 0000000000..9032df9754 --- /dev/null +++ b/panda/src/pgraph/pipeline.cxx @@ -0,0 +1,74 @@ +// Filename: pipeline.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pipeline.h" + +Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL; + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +Pipeline:: +Pipeline(const string &name) : + Namable(name) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +Pipeline:: +~Pipeline() { +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::cycle +// Access: Public +// Description: Flows all the pipeline data down to the next stage. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +cycle() { + pre_cycle(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::pre_cycle +// Access: Protected, Virtual +// Description: A callback function intended to be overridden by a +// derived class to perform whatever operations should +// be done before cycling the pipeline. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +pre_cycle() { +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::make_render_pipeline +// Access: Private, Static +// Description: +//////////////////////////////////////////////////////////////////// +void Pipeline:: +make_render_pipeline() { + nassertv(_render_pipeline == (Pipeline *)NULL); + _render_pipeline = new Pipeline("render"); +} + diff --git a/panda/src/pgraph/pipeline.h b/panda/src/pgraph/pipeline.h new file mode 100644 index 0000000000..019cde80bd --- /dev/null +++ b/panda/src/pgraph/pipeline.h @@ -0,0 +1,58 @@ +// Filename: pipeline.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINE_H +#define PIPELINE_H + +#include "pandabase.h" +#include "namable.h" + +//////////////////////////////////////////////////////////////////// +// Class : Pipeline +// Description : This class manages a staged pipeline of data, for +// instance the render pipeline, so that each stage of +// the pipeline can simultaneously access different +// copies of the same data. It actually maintains a +// collection of PipelineCycler objects, and manages the +// turning of all of them at once. +// +// There is one default Pipeline object, the render +// pipeline. Other specialty pipelines may be created +// as needed. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA Pipeline : public Namable { +public: + Pipeline(const string &name); + virtual ~Pipeline(); + + INLINE static Pipeline *get_render_pipeline(); + + void cycle(); + +protected: + virtual void pre_cycle(); + +private: + static void make_render_pipeline(); + static Pipeline *_render_pipeline; +}; + +#include "pipeline.I" + +#endif + diff --git a/panda/src/pgraph/pipelineCycler.I b/panda/src/pgraph/pipelineCycler.I new file mode 100644 index 0000000000..d8c800498e --- /dev/null +++ b/panda/src/pgraph/pipelineCycler.I @@ -0,0 +1,30 @@ +// Filename: pipelineCycler.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PipelineCycler:: +PipelineCycler(Pipeline *pipeline) : + PipelineCyclerBase(new CycleDataType, pipeline) +{ +} diff --git a/panda/src/pgraph/pipelineCycler.cxx b/panda/src/pgraph/pipelineCycler.cxx new file mode 100644 index 0000000000..3245434d5d --- /dev/null +++ b/panda/src/pgraph/pipelineCycler.cxx @@ -0,0 +1,19 @@ +// Filename: pipelineCycler.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pipelineCycler.h" diff --git a/panda/src/pgraph/pipelineCycler.h b/panda/src/pgraph/pipelineCycler.h new file mode 100644 index 0000000000..4e2c7c00d1 --- /dev/null +++ b/panda/src/pgraph/pipelineCycler.h @@ -0,0 +1,61 @@ +// Filename: pipelineCycler.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINECYCLER_H +#define PIPELINECYCLER_H + +#include "pandabase.h" + +#include "pipelineCyclerBase.h" + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCycler +// Description : This class maintains different copies of a page of +// data between stages of the graphics pipeline (or any +// other pipelining context). +// +// The class object maintains up to n copies of a +// CycleData structure, one for each stage of the +// pipeline. The head of the pipeline is responsible +// for making changes to its copy, which are then cycled +// through the pipeline at each frame. +// +// To access the data, you must first ask for a readable +// pointer. In order to make changes to the data, you +// must ask for a writable pointer. Both kinds of +// pointers should be released when you are done, as a +// sanity check. The CycleDataReader and +// CycleDataWriter classes transparently handle this. +// +// If pipelining support is not enabled at compile time +// (that is, SUPPORT_PIPELINING is not defined), this +// object compiles to a minimum object that presents the +// same interface but with minimal runtime overhead. +// (Actually, this isn't true yet, but it will be one +// day.) +//////////////////////////////////////////////////////////////////// +template +class PipelineCycler : public PipelineCyclerBase { +public: + INLINE PipelineCycler(Pipeline *pipeline = NULL); +}; + +#include "pipelineCycler.I" + +#endif + diff --git a/panda/src/pgraph/pipelineCyclerBase.I b/panda/src/pgraph/pipelineCyclerBase.I new file mode 100644 index 0000000000..6b7f458807 --- /dev/null +++ b/panda/src/pgraph/pipelineCyclerBase.I @@ -0,0 +1,109 @@ +// Filename: pipelineCyclerBase.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::read +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. This pointer should eventually be +// released by calling release_read(). +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerBase:: +read() const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + ((PipelineCyclerBase *)this)->_read_count++; + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::increment_read +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by read(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerBase:: +increment_read(const CycleData *pointer) const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + nassertv(pointer == _data); + nassertv(_read_count > 0); + ((PipelineCyclerBase *)this)->_read_count++; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::release_read +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerBase:: +release_read(const CycleData *pointer) const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + nassertv(pointer == _data); + nassertv(_read_count > 0); + ((PipelineCyclerBase *)this)->_read_count--; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::write +// Access: Public +// Description: Returns a non-const CycleData pointer, filled with a +// unique copy of the data for the current stage of the +// pipeline as seen by this thread. This pointer may +// now be used to write to the data, and that copy of +// the data will be propagate to all later stages of the +// pipeline. This pointer should eventually be released +// by calling release_write(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerBase:: +write() { + _write_count++; + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::increment_write +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by write(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerBase:: +increment_write(CycleData *pointer) { + nassertv(pointer == _data); + nassertv(_write_count > 0); + _write_count++; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::release_write +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerBase:: +release_write(CycleData *pointer) { + nassertv(pointer == _data); + nassertv(_write_count > 0); + _write_count--; +} diff --git a/panda/src/pgraph/pipelineCyclerBase.cxx b/panda/src/pgraph/pipelineCyclerBase.cxx new file mode 100644 index 0000000000..952c929fb4 --- /dev/null +++ b/panda/src/pgraph/pipelineCyclerBase.cxx @@ -0,0 +1,48 @@ +// Filename: pipelineCyclerBase.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pipelineCyclerBase.h" + + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerBase:: +PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) : + _data(initial_data), + _pipeline(pipeline), + _read_count(0), + _write_count(0) +{ + if (_pipeline == (Pipeline *)NULL) { + _pipeline = Pipeline::get_render_pipeline(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerBase::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerBase:: +~PipelineCyclerBase() { + nassertv(_read_count == 0 && _write_count == 0); +} + diff --git a/panda/src/pgraph/pipelineCyclerBase.h b/panda/src/pgraph/pipelineCyclerBase.h new file mode 100644 index 0000000000..f84dd77a28 --- /dev/null +++ b/panda/src/pgraph/pipelineCyclerBase.h @@ -0,0 +1,55 @@ +// Filename: pipelineCyclerBase.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINECYCLERBASE_H +#define PIPELINECYCLERBASE_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipeline.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCyclerBase +// Description : This is the non-template part of the implementation +// of PipelineCycler. See PipelineCycler. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PipelineCyclerBase { +public: + PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline = NULL); + ~PipelineCyclerBase(); + + INLINE const CycleData *read() const; + INLINE void increment_read(const CycleData *pointer) const; + INLINE void release_read(const CycleData *pointer) const; + + INLINE CycleData *write(); + INLINE void increment_write(CycleData *pointer); + INLINE void release_write(CycleData *pointer); + +private: + PT(CycleData) _data; + Pipeline *_pipeline; + short _read_count, _write_count; +}; + +#include "pipelineCyclerBase.I" + +#endif + diff --git a/panda/src/pgraph/renderAttrib.I b/panda/src/pgraph/renderAttrib.I new file mode 100644 index 0000000000..ca1e7f5ff8 --- /dev/null +++ b/panda/src/pgraph/renderAttrib.I @@ -0,0 +1,73 @@ +// Filename: renderAttrib.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::compose +// Access: Public +// Description: Returns a new RenderAttrib object that represents the +// composition of this attrib with the other attrib. In +// most cases, this is the same as the other attrib; a +// compose b produces b. Some kinds of attributes, like +// a TextureTransform, for instance, might produce a new +// result: a compose b produces c. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderAttrib) RenderAttrib:: +compose(const RenderAttrib *other) const { + return compose_impl(other); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::make_default +// Access: Public +// Description: Returns a different (or possibly the same) +// RenderAttrib pointer of the same type as this one +// that corresponds to whatever the standard default +// properties for render attributes of this type ought +// to be. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderAttrib) RenderAttrib:: +make_default() const { + return return_new(make_default_impl()); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::compare_to +// Access: Public +// Description: Provides an arbitrary ordering among all unique +// RenderAttribs, so we can store the essentially +// different ones in a big set and throw away the rest. +// +// This method is not needed outside of the RenderAttrib +// class because all equivalent RenderAttrib objects are +// guaranteed to share the same pointer; thus, a pointer +// comparison is always sufficient. +//////////////////////////////////////////////////////////////////// +INLINE int RenderAttrib:: +compare_to(const RenderAttrib &other) const { + // First, we compare the types; if they are of different types then + // they sort differently. + TypeHandle type = get_type(); + TypeHandle other_type = other.get_type(); + if (type != other_type) { + return type.get_index() - other_type.get_index(); + } + + // We only call compare_to_impl() if they have the same type. + return compare_to_impl(&other); +} diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx new file mode 100644 index 0000000000..4bd8a266d4 --- /dev/null +++ b/panda/src/pgraph/renderAttrib.cxx @@ -0,0 +1,240 @@ +// Filename: renderAttrib.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "renderAttrib.h" +#include "bamReader.h" +#include "indent.h" + +RenderAttrib::Attribs RenderAttrib::_attribs; +TypeHandle RenderAttrib::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +RenderAttrib:: +RenderAttrib() { + _saved_entry = _attribs.end(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::Copy Constructor +// Access: Private +// Description: RenderAttribs are not meant to be copied. +//////////////////////////////////////////////////////////////////// +RenderAttrib:: +RenderAttrib(const RenderAttrib &) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::Copy Assignment Operator +// Access: Private +// Description: RenderAttribs are not meant to be copied. +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +operator = (const RenderAttrib &) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::Destructor +// Access: Public, Virtual +// Description: The destructor is responsible for removing the +// RenderAttrib from the global set if it is there. +//////////////////////////////////////////////////////////////////// +RenderAttrib:: +~RenderAttrib() { + if (_saved_entry != _attribs.end()) { + _attribs.erase(_saved_entry); + _saved_entry = _attribs.end(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +output(ostream &out) const { + out << get_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << *this << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::return_new +// Access: Protected, Static +// Description: This function is used by derived RenderAttrib types +// to share a common RenderAttrib pointer for all +// equivalent RenderAttrib objects. +// +// The make() function of the derived type should create +// a new RenderAttrib and pass it through return_new(), +// which will either save the pointer and return it +// unchanged (if this is the first similar such object) +// or delete it and return an equivalent pointer (if +// there was already a similar object saved). +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) RenderAttrib:: +return_new(RenderAttrib *attrib) { + nassertr(attrib != (RenderAttrib *)NULL, attrib); + + // This should be a newly allocated pointer, not one that was used + // for anything else. + nassertr(attrib->_saved_entry == _attribs.end(), attrib); + + // Save the attrib in a local PointerTo so that it will be freed at + // the end of this function if no one else uses it. + CPT(RenderAttrib) pt_attrib = attrib; + + pair result = _attribs.insert(attrib); + if (result.second) { + // The attribute was inserted; save the iterator and return the + // input attribute. + attrib->_saved_entry = result.first; + return pt_attrib; + } + + // The attribute was not inserted; there must be an equivalent one + // already in the set. Return that one. + return *(result.first); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::compare_to_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RenderAttrib +// types to return a unique number indicating whether +// this RenderAttrib is equivalent to the other one. +// +// This should return 0 if the two RenderAttrib 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 RenderAttrib +// objects whose get_type() functions return the same. +//////////////////////////////////////////////////////////////////// +int RenderAttrib:: +compare_to_impl(const RenderAttrib *other) const { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::compose_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RenderAttrib +// types to specify how two consecutive RenderAttrib +// objects of the same type interact. +// +// This should return the result of applying the other +// RenderAttrib to a node in the scene graph below this +// RenderAttrib, which was already applied. In most +// cases, the result is the same as the other +// RenderAttrib (that is, a subsequent RenderAttrib +// completely replaces the preceding one). On the other +// hand, some kinds of RenderAttrib (for instance, +// TextureTransform) might combine in meaningful ways. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) RenderAttrib:: +compose_impl(const RenderAttrib *other) const { + return other; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::make_default_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived RenderAttrib +// types to specify what the default property for a +// RenderAttrib of this type should be. +// +// This should return a newly-allocated RenderAttrib of +// the same type that corresponds to whatever the +// standard default for this kind of RenderAttrib is. +//////////////////////////////////////////////////////////////////// +RenderAttrib *RenderAttrib:: +make_default_impl() const { + return (RenderAttrib *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +write_datagram(BamWriter *, Datagram &) { +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::finalize +// Access: Public, Virtual +// Description: Method to ensure that any necessary clean up tasks +// that have to be performed by this object are performed +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +finalize() { + // Unref the pointer that we explicitly reffed in make_from_bam(). + unref(); + + // We should never get back to zero after unreffing our own count, + // because we expect to have been stored in a pointer somewhere. If + // we do get to zero, it's a memory leak; the way to avoid this is + // to call unref_delete() above instead of unref(), but this is + // dangerous to do from within a virtual function. + nassertv(get_ref_count() != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::new_from_bam +// Access: Protected, Static +// Description: Uniquifies the pointer for a RenderAttrib object just +// created from a bam file, and preserves its reference +// count correctly. +//////////////////////////////////////////////////////////////////// +TypedWritable *RenderAttrib:: +new_from_bam(RenderAttrib *attrib, BamReader *manager) { + // First, uniquify the pointer. + CPT(RenderAttrib) pointer = return_new(attrib); + + // But now we have a problem, since we have to hold the reference + // count and there's no way to return a TypedWritable while still + // holding the reference count! We work around this by explicitly + // upping the count, and also setting a finalize() callback to down + // it later. + if (pointer == attrib) { + pointer->ref(); + manager->register_finalize(attrib); + } + + // We have to cast the pointer back to non-const, because the bam + // reader expects that. + return (RenderAttrib *)pointer.p(); +} diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h new file mode 100644 index 0000000000..5eab65509d --- /dev/null +++ b/panda/src/pgraph/renderAttrib.h @@ -0,0 +1,110 @@ +// Filename: renderAttrib.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef RENDERATTRIB_H +#define RENDERATTRIB_H + +#include "pandabase.h" + +#include "typedWritableReferenceCount.h" +#include "indirectCompareTo.h" +#include "pointerTo.h" +#include "pset.h" + +//////////////////////////////////////////////////////////////////// +// Class : RenderAttrib +// Description : This is the base class for a number of render +// attributes (other than transform) that may be set on +// scene graph nodes to control the appearance of +// geometry. This includes TextureAttrib, ColorAttrib, +// etc. +// +// You should not attempt to create or modify a +// RenderAttrib directly; instead, use the make() method +// of the appropriate kind of attrib you want. This +// will allocate and return a new RenderAttrib of the +// appropriate type, and it may share pointers if +// possible. Do not modify the new RenderAttrib if you +// wish to change its properties; instead, create a new +// one. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RenderAttrib : public TypedWritableReferenceCount { +protected: + RenderAttrib(); +private: + RenderAttrib(const RenderAttrib ©); + void operator = (const RenderAttrib ©); + +public: + virtual ~RenderAttrib(); + + INLINE CPT(RenderAttrib) compose(const RenderAttrib *other) const; + INLINE CPT(RenderAttrib) make_default() const; + INLINE int compare_to(const RenderAttrib &other) const; + +PUBLISHED: + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level) const; + +protected: + static CPT(RenderAttrib) return_new(RenderAttrib *attrib); + + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; + virtual RenderAttrib *make_default_impl() const=0; + +private: + typedef pset > Attribs; + static Attribs _attribs; + + Attribs::iterator _saved_entry; + +public: + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual void finalize(); + +protected: + static TypedWritable *new_from_bam(RenderAttrib *attrib, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedWritableReferenceCount::init_type(); + register_type(_type_handle, "RenderAttrib", + TypedWritableReferenceCount::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; +}; + +INLINE ostream &operator << (ostream &out, const RenderAttrib &attrib) { + attrib.output(out); + return out; +} + +#include "renderAttrib.I" + +#endif + diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I new file mode 100644 index 0000000000..21020a97f1 --- /dev/null +++ b/panda/src/pgraph/renderState.I @@ -0,0 +1,150 @@ +// Filename: renderState.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RenderState::Attribute:: +Attribute(const RenderAttrib *attrib, int override) : + _type(attrib->get_type()), + _attrib(attrib), + _override(override) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::Constructor +// Access: Public +// Description: This constructor makes an invalid Attribute with no +// RenderAttrib pointer; its purpose is just to make an +// object we can use to look up a particular type in the +// Attribute set. +//////////////////////////////////////////////////////////////////// +INLINE RenderState::Attribute:: +Attribute(TypeHandle type) : + _type(type), + _attrib(NULL), + _override(0) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RenderState::Attribute:: +Attribute(const Attribute ©) : + _type(copy._type), + _attrib(copy._attrib), + _override(copy._override) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void RenderState::Attribute:: +operator = (const Attribute ©) { + _type = copy._type; + _attrib = copy._attrib; + _override = copy._override; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::operator < +// Access: Public +// Description: This is used by the Attributes set to uniquify +// RenderAttributes by type. Only one RenderAttrib of a +// given type is allowed in the set. This ordering must +// also match the ordering reported by compare_to(). +//////////////////////////////////////////////////////////////////// +INLINE bool RenderState::Attribute:: +operator < (const Attribute &other) const { + return _type < other._type; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::compare_to +// Access: Public +// Description: Provides an indication of whether a particular +// attribute is equivalent to another one, for purposes +// of generating unique RenderStates. This should +// compare all properties of the Attribute, but it is +// important that the type is compared first, to be +// consistent with the ordering defined by operator <. +//////////////////////////////////////////////////////////////////// +INLINE int RenderState::Attribute:: +compare_to(const Attribute &other) const { + if (_type != other._type) { + return _type.get_index() - other._type.get_index(); + } + if (_attrib != other._attrib) { + return _attrib - other._attrib; + } + return _override - other._override; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::is_empty +// Access: Published +// Description: Returns true if the state is empty, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool RenderState:: +is_empty() const { + return _attributes.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_num_attribs +// Access: Published +// Description: Returns the number of separate attributes indicated +// in the state. +//////////////////////////////////////////////////////////////////// +INLINE int RenderState:: +get_num_attribs() const { + return _attributes.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_attrib +// Access: Published +// Description: Returns the nth attribute in the state. +//////////////////////////////////////////////////////////////////// +INLINE const RenderAttrib *RenderState:: +get_attrib(int n) const { + nassertr(n >= 0 && n < (int)_attributes.size(), NULL); + return _attributes[n]._attrib; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_override +// Access: Published +// Description: Returns the override associated with the nth +// attribute in the state. +//////////////////////////////////////////////////////////////////// +INLINE int RenderState:: +get_override(int n) const { + nassertr(n >= 0 && n < (int)_attributes.size(), 0); + return _attributes[n]._override; +} diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx new file mode 100644 index 0000000000..e1ae0c1129 --- /dev/null +++ b/panda/src/pgraph/renderState.cxx @@ -0,0 +1,631 @@ +// Filename: renderState.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "renderState.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "datagramIterator.h" +#include "indent.h" +#include "compareTo.h" + +RenderState::States RenderState::_states; +CPT(RenderState) RenderState::_empty_state; +TypeHandle RenderState::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Constructor +// Access: Protected +// Description: Actually, this could be a private constructor, since +// no one inherits from RenderState, but gcc gives us a +// spurious warning if all constructors are private. +//////////////////////////////////////////////////////////////////// +RenderState:: +RenderState() { + _saved_entry = _states.end(); + _self_compose = (RenderState *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Copy Constructor +// Access: Private +// Description: RenderStates are not meant to be copied. +//////////////////////////////////////////////////////////////////// +RenderState:: +RenderState(const RenderState &) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Copy Assignment Operator +// Access: Private +// Description: RenderStates are not meant to be copied. +//////////////////////////////////////////////////////////////////// +void RenderState:: +operator = (const RenderState &) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Destructor +// Access: Public, Virtual +// Description: The destructor is responsible for removing the +// RenderState from the global set if it is there. +//////////////////////////////////////////////////////////////////// +RenderState:: +~RenderState() { + // Remove the deleted RenderState object from the global pool. + if (_saved_entry != _states.end()) { + _states.erase(_saved_entry); + _saved_entry = _states.end(); + + cerr << "Removing " << (void *)this << ", " << _states.size() + << " remaining.\n"; + } + + // Now make sure we clean up all other floating pointers to the + // RenderState. These may be scattered around in the various + // CompositionCaches from other RenderState objects. + + // Fortunately, since we added CompositionCache records in pairs, we + // know exactly the set of RenderState objects that have us in their + // cache: it's the same set of RenderState objects that we have in + // our own cache. + + // We do need to put some thought into this loop, because as we + // clear out cache entries we'll cause other RenderState objects to + // destruct, which could cause things to get pulled out of our own + // _composition_cache map. We don't want to get bitten by this + // cascading effect. + CompositionCache::iterator ci; + ci = _composition_cache.begin(); + while (ci != _composition_cache.end()) { + { + PT(RenderState) other = (RenderState *)(*ci).first; + Composition comp = (*ci).second; + + // We should never have a reflexive entry in this map. If we + // do, something got screwed up elsewhere. + nassertv(other != this); + + // Now we're holding a reference count to the other state, as well + // as to the computed result (if any), so neither object will be + // tempted to destruct. Go ahead and remove ourselves from the + // other cache. + other->_composition_cache.erase(this); + + // It's all right if the other state destructs now, since it + // won't try to remove itself from our own composition cache any + // more. Someone might conceivably delete the *next* entry, + // though, so we should be sure to let all that deleting finish + // up before we attempt to increment ci, by closing the scope + // here. + } + // Now it's safe to increment ci, because the current cache entry + // has not gone away, and if the next one has, by now it's safely + // gone. + ++ci; + } + + // Also, if we called compose(this) at some point and the return + // value was something other than this, we need to decrement the + // associated reference count. + if (_self_compose != (RenderState *)NULL && _self_compose != this) { + unref_delete((RenderState *)_self_compose); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::operator < +// Access: Public +// Description: Provides an arbitrary ordering among all unique +// RenderStates, so we can store the essentially +// different ones in a big set and throw away the rest. +// +// This method is not needed outside of the RenderState +// class because all equivalent RenderState objects are +// guaranteed to share the same pointer; thus, a pointer +// comparison is always sufficient. +//////////////////////////////////////////////////////////////////// +bool RenderState:: +operator < (const RenderState &other) const { + // We must compare all the properties of the attributes, not just + // the type; thus, we compare them one at a time using compare_to(). + return lexicographical_compare(_attributes.begin(), _attributes.end(), + other._attributes.begin(), other._attributes.end(), + CompareTo()); +} + + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::find_attrib +// Access: Published +// Description: Searches for an attribute with the indicated type in +// the state, and returns its index if it is found, or +// -1 if it is not. +//////////////////////////////////////////////////////////////////// +int RenderState:: +find_attrib(TypeHandle type) const { + Attributes::const_iterator ai = _attributes.find(Attribute(type)); + if (ai == _attributes.end()) { + return -1; + } + return ai - _attributes.begin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::make_empty +// Access: Published, Static +// Description: Returns a RenderState with no attributes set. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +make_empty() { + // The empty state is asked for so often, we make it a special case + // and store a pointer forever once we find it the first time. + if (_empty_state == (RenderState *)NULL) { + RenderState *state = new RenderState; + _empty_state = return_new(state); + } + + return _empty_state; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::make +// Access: Published, Static +// Description: Returns a RenderState with one attribute set. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +make(const RenderAttrib *attrib, int override) { + RenderState *state = new RenderState; + state->_attributes.reserve(1); + state->_attributes.insert(Attribute(attrib, override)); + return return_new(state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::make +// Access: Published, Static +// Description: Returns a RenderState with two attributes set. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +make(const RenderAttrib *attrib1, + const RenderAttrib *attrib2, int override) { + RenderState *state = new RenderState; + state->_attributes.reserve(2); + state->_attributes.push_back(Attribute(attrib1, override)); + state->_attributes.push_back(Attribute(attrib2, override)); + state->_attributes.sort(); + return return_new(state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::make +// Access: Published, Static +// Description: Returns a RenderState with three attributes set. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +make(const RenderAttrib *attrib1, + const RenderAttrib *attrib2, + const RenderAttrib *attrib3, int override) { + RenderState *state = new RenderState; + state->_attributes.reserve(2); + state->_attributes.push_back(Attribute(attrib1, override)); + state->_attributes.push_back(Attribute(attrib2, override)); + state->_attributes.push_back(Attribute(attrib3, override)); + state->_attributes.sort(); + return return_new(state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::make +// Access: Published, Static +// Description: Returns a RenderState with four attributes set. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +make(const RenderAttrib *attrib1, + const RenderAttrib *attrib2, + const RenderAttrib *attrib3, + const RenderAttrib *attrib4, int override) { + RenderState *state = new RenderState; + state->_attributes.reserve(2); + state->_attributes.push_back(Attribute(attrib1, override)); + state->_attributes.push_back(Attribute(attrib2, override)); + state->_attributes.push_back(Attribute(attrib3, override)); + state->_attributes.push_back(Attribute(attrib4, override)); + state->_attributes.sort(); + return return_new(state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::compose +// Access: Published +// Description: Returns a new RenderState object that represents the +// composition of this state with the other state. +// +// The result of this operation is cached, and will be +// retained as long as both this RenderState object and +// the other RenderState object continue to exist. +// Should one of them destruct, the cached entry will be +// removed, and its pointer will be allowed to destruct +// as well. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +compose(const RenderState *other) const { + // This method isn't strictly const, because it updates the cache, + // but we pretend that it is because it's only a cache which is + // transparent to the rest of the interface. + + cerr << "composing " << *this << " with " << *other << "\n"; + + if (other == this) { + // compose(this) has to be handled as a special case, because the + // caching problem is so different. + if (_self_compose != (RenderState *)NULL) { + return _self_compose; + } + CPT(RenderState) result = do_compose(this); + ((RenderState *)this)->_self_compose = result; + + if (result != this) { + // If the result of compose(this) is something other than this, + // explicitly increment the reference count. We have to be sure + // to decrement it again later, in our destructor. + _self_compose->ref(); + + // (If the result was just this again, we still store the + // result, but we don't increment the reference count, since + // that would be a self-referential leak. What a mess this is.) + } + return _self_compose; + } + + // Is this composition already cached? + CompositionCache::const_iterator ci = _composition_cache.find(other); + if (ci != _composition_cache.end()) { + const Composition &comp = (*ci).second; + if (comp._result == (const RenderState *)NULL) { + // Well, it wasn't cached already, but we already had an entry + // (probably created for the reverse direction), so use the same + // entry to store the new result. + ((Composition &)comp)._result = do_compose(other); + } + // Here's the cache! + cerr << " returning cached result " << (void *)comp._result.p() << "\n"; + return comp._result; + } + + // We need to make a new cache entry, both in this object and in the + // other object. We make both records so the other RenderState + // object will know to delete the entry from this object when it + // destructs, and vice-versa. + + // The cache entry in this object is the only one that indicates the + // result; the other will be NULL for now. + CPT(RenderState) result = do_compose(other); + // We store them in this order, on the off-chance that other is the + // same as this, a degenerate case which is still worth supporting. + ((RenderState *)other)->_composition_cache[this]._result = NULL; + ((RenderState *)this)->_composition_cache[other]._result = result; + + cerr << " returning new result " << (void *)result.p() << "\n"; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::add +// Access: Published +// Description: Returns a new RenderState object that represents the +// same as the source state, with the new RenderAttrib +// added. If there is already a RenderAttrib with the +// same type, it is replaced. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +add(const RenderAttrib *attrib, int override) const { + RenderState *new_state = new RenderState; + back_insert_iterator result = + back_inserter(new_state->_attributes); + + Attribute new_attribute(attrib, override); + Attributes::const_iterator ai = _attributes.begin(); + + while (ai != _attributes.end() && (*ai) < new_attribute) { + *result = *ai; + ++ai; + ++result; + } + *result = new_attribute; + ++result; + + while (ai != _attributes.end()) { + *result = *ai; + ++ai; + ++result; + } + + return return_new(new_state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::remove +// Access: Published +// Description: Returns a new RenderState object that represents the +// same as the source state, with the indicated +// RenderAttrib removed +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +remove(TypeHandle type) const { + RenderState *new_state = new RenderState; + back_insert_iterator result = + back_inserter(new_state->_attributes); + + Attributes::const_iterator ai = _attributes.begin(); + + while (ai != _attributes.end()) { + if ((*ai)._type != type) { + *result = *ai; + ++result; + } + ++ai; + } + + return return_new(new_state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void RenderState:: +output(ostream &out) const { + if (_attributes.empty()) { + out << "empty"; + + } else { + Attributes::const_iterator ai = _attributes.begin(); + out << (*ai)._type; + ++ai; + while (ai != _attributes.end()) { + out << " " << (*ai)._type; + ++ai; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void RenderState:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << _attributes.size() << " attribs:\n"; + Attributes::const_iterator ai; + for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) { + const Attribute &attribute = (*ai); + attribute._attrib->write(out, indent_level + 2); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::return_new +// Access: Private, Static +// Description: This function is used to share a common RenderState +// pointer for all equivalent RenderState objects. +// +// See the similar logic in RenderAttrib. The idea is +// to create a new RenderState object and pass it +// through this function, which will share the pointer +// with a previously-created RenderState object if it is +// equivalent. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +return_new(RenderState *state) { + cerr << "RenderState::return_new(" << *state << ")\n"; + nassertr(state != (RenderState *)NULL, state); + + // This should be a newly allocated pointer, not one that was used + // for anything else. + nassertr(state->_saved_entry == _states.end(), state); + + // Save the state in a local PointerTo so that it will be freed at + // the end of this function if no one else uses it. + CPT(RenderState) pt_state = state; + + pair result = _states.insert(state); + if (result.second) { + // The state was inserted; save the iterator and return the + // input state. + state->_saved_entry = result.first; + cerr << " produces new pointer " << (void *)pt_state.p() << "\n"; + return pt_state; + } + + // The state was not inserted; there must be an equivalent one + // already in the set. Return that one. + cerr << " returns old pointer " << (void *)(*(result.first)) << "\n"; + return *(result.first); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::do_compose +// Access: Private +// Description: The private implemention of compose(); this actually +// composes two RenderStates, without bothering with the +// cache. +//////////////////////////////////////////////////////////////////// +CPT(RenderState) RenderState:: +do_compose(const RenderState *other) const { + // First, build a new Attributes member that represents the union of + // this one and that one. + Attributes::const_iterator ai = _attributes.begin(); + Attributes::const_iterator bi = other->_attributes.begin(); + + // Create a new RenderState that will hold the result. + RenderState *new_state = new RenderState; + back_insert_iterator result = + back_inserter(new_state->_attributes); + + while (ai != _attributes.end() && bi != other->_attributes.end()) { + if ((*ai) < (*bi)) { + // Here is an attribute that we have in the original, which is + // not present in the secondary. + *result = *ai; + ++ai; + ++result; + } else if ((*bi) < (*ai)) { + // Here is a new attribute we have in the secondary, that was + // not present in the original. + *result = *bi; + ++bi; + ++result; + } else { + // Here is an attribute we have in both. Does one override the + // other? + const Attribute &a = (*ai); + const Attribute &b = (*bi); + if (a._override < b._override) { + // B overrides. + *result = *bi; + + } else if (b._override < a._override) { + // A overrides. + *result = *bi; + + } else { + // No, they're equivalent, so compose them. + *result = Attribute(a._attrib->compose(b._attrib), b._override); + } + ++ai; + ++bi; + ++result; + } + } + + while (ai != _attributes.end()) { + *result = *ai; + ++ai; + ++result; + } + + while (bi != other->_attributes.end()) { + *result = *bi; + ++bi; + ++result; + } + + return return_new(new_state); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// RenderState. +//////////////////////////////////////////////////////////////////// +void RenderState:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void RenderState:: +write_datagram(BamWriter *manager, Datagram &dg) { +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::finalize +// Access: Public, Virtual +// Description: Method to ensure that any necessary clean up tasks +// that have to be performed by this object are performed +//////////////////////////////////////////////////////////////////// +void RenderState:: +finalize() { + // Unref the pointer that we explicitly reffed in make_from_bam(). + unref(); + + // We should never get back to zero after unreffing our own count, + // because we expect to have been stored in a pointer somewhere. If + // we do get to zero, it's a memory leak; the way to avoid this is + // to call unref_delete() above instead of unref(), but this is + // dangerous to do from within a virtual function. + nassertv(get_ref_count() != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type RenderState is encountered +// in the Bam file. It should create the RenderState +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *RenderState:: +make_from_bam(const FactoryParams ¶ms) { + RenderState *state = new RenderState; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + state->fillin(scan, manager); + + return new_from_bam(state, manager); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::new_from_bam +// Access: Protected, Static +// Description: Uniquifies the pointer for a RenderState object just +// created from a bam file, and preserves its reference +// count correctly. +//////////////////////////////////////////////////////////////////// +TypedWritable *RenderState:: +new_from_bam(RenderState *state, BamReader *manager) { + // First, uniquify the pointer. + CPT(RenderState) pointer = return_new(state); + + // But now we have a problem, since we have to hold the reference + // count and there's no way to return a TypedWritable while still + // holding the reference count! We work around this by explicitly + // upping the count, and also setting a finalize() callback to down + // it later. + if (pointer == state) { + pointer->ref(); + manager->register_finalize(state); + } + + // We have to cast the pointer back to non-const, because the bam + // reader expects that. + return (RenderState *)pointer.p(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::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 RenderState. +//////////////////////////////////////////////////////////////////// +void RenderState:: +fillin(DatagramIterator &scan, BamReader *manager) { +} diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h new file mode 100644 index 0000000000..6aba2d290e --- /dev/null +++ b/panda/src/pgraph/renderState.h @@ -0,0 +1,172 @@ +// Filename: renderState.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef RENDERSTATE_H +#define RENDERSTATE_H + +#include "pandabase.h" + +#include "renderAttrib.h" +#include "typedWritableReferenceCount.h" +#include "pointerTo.h" +#include "indirectLess.h" +#include "ordered_vector.h" + +//////////////////////////////////////////////////////////////////// +// Class : RenderState +// Description : This represents a unique collection of RenderAttrib +// objects that correspond to a particular renderable +// state. +// +// You should not attempt to create or modify a +// RenderState object directly. Instead, call one of +// the make() functions to create one for you. And +// instead of modifying a RenderState object, create a +// new one. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RenderState : public TypedWritableReferenceCount { +protected: + RenderState(); + +private: + RenderState(const RenderState ©); + void operator = (const RenderState ©); + +public: + virtual ~RenderState(); + + bool operator < (const RenderState &other) const; + +PUBLISHED: + INLINE bool is_empty() const; + INLINE int get_num_attribs() const; + INLINE const RenderAttrib *get_attrib(int n) const; + INLINE int get_override(int n) const; + + int find_attrib(TypeHandle type) const; + + static CPT(RenderState) make_empty(); + static CPT(RenderState) make(const RenderAttrib *attrib, int override = 0); + static CPT(RenderState) make(const RenderAttrib *attrib1, + const RenderAttrib *attrib2, int override = 0); + static CPT(RenderState) make(const RenderAttrib *attrib1, + const RenderAttrib *attrib2, + const RenderAttrib *attrib3, int override = 0); + static CPT(RenderState) make(const RenderAttrib *attrib1, + const RenderAttrib *attrib2, + const RenderAttrib *attrib3, + const RenderAttrib *attrib4, int override = 0); + + CPT(RenderState) compose(const RenderState *other) const; + + CPT(RenderState) add(const RenderAttrib *attrib, int override = 0) const; + CPT(RenderState) remove(TypeHandle type) const; + + void output(ostream &out) const; + void write(ostream &out, int indent_level) const; + +private: + static CPT(RenderState) return_new(RenderState *state); + CPT(RenderState) do_compose(const RenderState *other) const; + +private: + typedef pset > States; + static States _states; + static CPT(RenderState) _empty_state; + + // This iterator records the entry corresponding to this RenderState + // object in the above global set. We keep the iterator around so + // we can remove it when the RenderState destructs. + States::iterator _saved_entry; + + // This data structure manages the job of caching the composition of + // two RenderStates. It's complicated because we have to be sure to + // remove the entry if *either* of the input RenderStates destructs. + // To implement this, we always record Composition entries in pairs, + // one in each of the two involved RenderState objects. + class Composition { + public: + CPT(RenderState) _result; + }; + + typedef pmap CompositionCache; + CompositionCache _composition_cache; + + // This pointer is used to cache the result of compose(this). This + // has to be a special case, because we have to handle the reference + // counts carefully so that we don't leak. Most of the time, the + // result of compose(this) is this, which should not be reference + // counted, but other times the result is something else (which + // should be). + const RenderState *_self_compose; + + // This is the actual set of data within the RenderState: a set of + // RenderAttribs. + class Attribute { + public: + INLINE Attribute(const RenderAttrib *attrib, int override); + INLINE Attribute(TypeHandle type); + INLINE Attribute(const Attribute ©); + INLINE void operator = (const Attribute ©); + INLINE bool operator < (const Attribute &other) const; + INLINE int compare_to(const Attribute &other) const; + + TypeHandle _type; + CPT(RenderAttrib) _attrib; + int _override; + }; + typedef ov_set Attributes; + Attributes _attributes; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual void finalize(); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + static TypedWritable *new_from_bam(RenderState *state, BamReader *manager); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedWritableReferenceCount::init_type(); + register_type(_type_handle, "RenderState", + TypedWritableReferenceCount::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; +}; + +INLINE ostream &operator << (ostream &out, const RenderState &state) { + state.output(out); + return out; +} + +#include "renderState.I" + +#endif + diff --git a/panda/src/pgraph/test_pgraph.cxx b/panda/src/pgraph/test_pgraph.cxx new file mode 100644 index 0000000000..fd9d818679 --- /dev/null +++ b/panda/src/pgraph/test_pgraph.cxx @@ -0,0 +1,82 @@ +// Filename: test_pgraph.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pandaNode.h" +#include "textureAttrib.h" +#include "colorAttrib.h" +#include "texture.h" + +void +list_hierarchy(PandaNode *node, int indent_level) { + node->write(cerr, indent_level); + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + list_hierarchy(cr.get_child(i), indent_level + 2); + } +} + +int +main(int argc, char *argv[]) { + PT(Texture) tex = new Texture; + tex->set_name("tex"); + + PT(PandaNode) root = new PandaNode("root"); + root->set_attrib(TextureAttrib::make_off()); + root->set_attrib(ColorAttrib::make_flat(Colorf(1, 0, 0, 1))); + + PandaNode *a = new PandaNode("a"); + root->add_child(a); + a->set_attrib(TextureAttrib::make(tex)); + + PandaNode *b = new PandaNode("b"); + root->add_child(b); + b->set_attrib(ColorAttrib::make_vertex()); + + PandaNode *a1 = new PandaNode("a1"); + a->add_child(a1); + + cerr << "\n"; + list_hierarchy(root, 0); + + cerr << "\nroot's attribs:\n"; + root->get_state()->write(cerr, 0); + + cerr << "\na's attribs:\n"; + a->get_state()->write(cerr, 0); + + cerr << "\nroot compose a:\n"; + CPT(RenderState) result1 = root->get_state()->compose(a->get_state()); + result1->write(cerr, 0); + + // a->clear_state(); + + cerr << "\nroot compose root:\n"; + CPT(RenderState) result2 = root->get_state()->compose(root->get_state()); + result2->write(cerr, 0); + + cerr << "\nroot compose a:\n"; + CPT(RenderState) result3 = root->get_state()->compose(a->get_state()); + result3->write(cerr, 0); + + cerr << "\na compose root:\n"; + CPT(RenderState) result4 = a->get_state()->compose(root->get_state()); + result4->write(cerr, 0); + + return 0; +} diff --git a/panda/src/pgraph/textureAttrib.I b/panda/src/pgraph/textureAttrib.I new file mode 100644 index 0000000000..50c4776139 --- /dev/null +++ b/panda/src/pgraph/textureAttrib.I @@ -0,0 +1,52 @@ +// Filename: textureAttrib.I +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::Constructor +// Access: Private +// Description: Use TextureAttrib::make() to construct a new +// TextureAttrib object. +//////////////////////////////////////////////////////////////////// +INLINE TextureAttrib:: +TextureAttrib() { +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::is_off +// Access: Published +// Description: Returns true if the TextureAttrib is an 'off' +// TextureAttrib, indicating that it should disable +// texturing. +//////////////////////////////////////////////////////////////////// +INLINE bool TextureAttrib:: +is_off() const { + return _texture == (Texture *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::get_texture +// Access: Published +// Description: If the TextureAttrib is not an 'off' TextureAttrib, +// returns the texture that is associated. Otherwise, +// return NULL. +//////////////////////////////////////////////////////////////////// +INLINE Texture *TextureAttrib:: +get_texture() const { + return _texture; +} diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx new file mode 100644 index 0000000000..b60a71a626 --- /dev/null +++ b/panda/src/pgraph/textureAttrib.cxx @@ -0,0 +1,99 @@ +// Filename: textureAttrib.cxx +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "textureAttrib.h" + +TypeHandle TextureAttrib::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::make +// Access: Published, Static +// Description: Constructs a new TextureAttrib object suitable for +// rendering the indicated texture onto geometry. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) TextureAttrib:: +make(Texture *texture) { + TextureAttrib *attrib = new TextureAttrib; + attrib->_texture = texture; + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::make_off +// Access: Published, Static +// Description: Constructs a new TextureAttrib object suitable for +// rendering untextured geometry. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) TextureAttrib:: +make_off() { + TextureAttrib *attrib = new TextureAttrib; + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void TextureAttrib:: +output(ostream &out) const { + out << get_type() << ":"; + if (is_off()) { + out << "(off)"; + } else { + out << _texture->get_name(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::compare_to_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived TextureAttrib +// types to return a unique number indicating whether +// this TextureAttrib is equivalent to the other one. +// +// This should return 0 if the two TextureAttrib 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 TextureAttrib +// objects whose get_type() functions return the same. +//////////////////////////////////////////////////////////////////// +int TextureAttrib:: +compare_to_impl(const RenderAttrib *other) const { + const TextureAttrib *ta; + DCAST_INTO_R(ta, other, 0); + return (int)(_texture - ta->_texture); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::make_default_impl +// Access: Protected, Virtual +// Description: Intended to be overridden by derived TextureAttrib +// types to specify what the default property for a +// TextureAttrib of this type should be. +// +// This should return a newly-allocated TextureAttrib of +// the same type that corresponds to whatever the +// standard default for this kind of TextureAttrib is. +//////////////////////////////////////////////////////////////////// +RenderAttrib *TextureAttrib:: +make_default_impl() const { + return new TextureAttrib; +} diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h new file mode 100644 index 0000000000..ada6cab259 --- /dev/null +++ b/panda/src/pgraph/textureAttrib.h @@ -0,0 +1,75 @@ +// Filename: textureAttrib.h +// Created by: drose (21Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TEXTUREATTRIB_H +#define TEXTUREATTRIB_H + +#include "pandabase.h" + +#include "renderAttrib.h" +#include "texture.h" + +//////////////////////////////////////////////////////////////////// +// Class : TextureAttrib +// Description : Indicates which texture should be applied as the +// primary texture. Also see TextureAttrib2 for the +// secondary texture. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA TextureAttrib : public RenderAttrib { +private: + INLINE TextureAttrib(); + +PUBLISHED: + static CPT(RenderAttrib) make(Texture *tex); + static CPT(RenderAttrib) make_off(); + + INLINE bool is_off() const; + INLINE Texture *get_texture() const; + +public: + virtual void output(ostream &out) const; + +protected: + virtual int compare_to_impl(const RenderAttrib *other) const; + virtual RenderAttrib *make_default_impl() const; + +private: + PT(Texture) _texture; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedWritableReferenceCount::init_type(); + register_type(_type_handle, "TextureAttrib", + TypedWritableReferenceCount::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; +}; + +#include "textureAttrib.I" + +#endif +