From 480c3f258b8e6df4a03162becd7a3c11cff6e566 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 6 Dec 2014 20:26:05 +0100 Subject: [PATCH 01/20] Don't complain about missing wx (or fltk) when building SDK --- makepanda/makepanda.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index d4329bc0d9..05a7495a0b 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -568,13 +568,13 @@ if (COMPILER == "MSVC"): LibName("FMODEX", GetThirdpartyDir() + "fmodex/lib/fmodex64_vc.lib") else: LibName("FMODEX", GetThirdpartyDir() + "fmodex/lib/fmodex_vc.lib") - if (PkgSkip("WX")==0): + if (PkgSkip("WX")==0 and RTDIST): LibName("WX", GetThirdpartyDir() + "wx/lib/wxbase28u.lib") LibName("WX", GetThirdpartyDir() + "wx/lib/wxmsw28u_core.lib") DefSymbol("WX", "__WXMSW__", "") DefSymbol("WX", "_UNICODE", "") DefSymbol("WX", "UNICODE", "") - if (PkgSkip("FLTK")==0): + if (PkgSkip("FLTK")==0 and RTDIST): LibName("FLTK", GetThirdpartyDir() + "fltk/lib/fltk.lib") if (PkgSkip("VORBIS")==0): LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libogg_static.lib") From 8afc88e86e8f09633dbd0ca83b7966c4e4ed9f19 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 6 Dec 2014 22:37:16 +0100 Subject: [PATCH 02/20] Add CXXFLAGS; only use CFLAGS for C sources --- makepanda/makepanda.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 05a7495a0b..0b65f80c21 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -52,6 +52,7 @@ GENMAN=0 COMPRESSOR="zlib" THREADCOUNT=0 CFLAGS="" +CXXFLAGS="" LDFLAGS="" RTDIST=0 RTDIST_VERSION="dev" @@ -283,13 +284,17 @@ parseopts(sys.argv[1:]) ######################################################################## if ("CFLAGS" in os.environ): - CFLAGS = os.environ["CFLAGS"] + CFLAGS = os.environ["CFLAGS"].strip() + +if ("CXXFLAGS" in os.environ): + CXXFLAGS = os.environ["CXXFLAGS"].strip() + if ("RPM_OPT_FLAGS" in os.environ): - CFLAGS += " " + os.environ["RPM_OPT_FLAGS"] -CFLAGS = CFLAGS.strip() + CFLAGS += " " + os.environ["RPM_OPT_FLAGS"].strip() + CXXFLAGS += " " + os.environ["RPM_OPT_FLAGS"].strip() + if ("LDFLAGS" in os.environ): - LDFLAGS = os.environ["LDFLAGS"] -LDFLAGS = LDFLAGS.strip() + LDFLAGS = os.environ["LDFLAGS"].strip() os.environ["MAKEPANDA"] = os.path.abspath(sys.argv[0]) if (GetHost() == "darwin" and OSXTARGET != None): @@ -1126,7 +1131,13 @@ def CompileCxx(obj,src,opts): if (optlevel==2): cmd += " -O1 -D_DEBUG" if (optlevel==3): cmd += " -O2" if (optlevel==4): cmd += " -O3 -DNDEBUG" - if (CFLAGS !=""): cmd += " " + CFLAGS + + if src.endswith(".c"): + cmd += ' ' + CFLAGS + else: + cmd += ' ' + CXXFLAGS + cmd = cmd.rstrip() + building = GetValueOption(opts, "BUILDING:") if (building): cmd += " -DBUILDING_" + building cmd += ' ' + BracketNameWithQuotes(src) From 3fbdc43fbb7b3ed56bb2f12bfe2bf8c2f9391523 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 6 Dec 2014 22:38:40 +0100 Subject: [PATCH 03/20] Fix compile errors with clang --- panda/src/gobj/geomPrimitive.cxx | 5 +++++ panda/src/pgraph/nodePath.cxx | 2 +- panda/src/pgraph/nodePath.h | 2 +- panda/src/putil/updateSeq.I | 8 ++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index c5bf48e677..bf70afcdd0 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1602,6 +1602,11 @@ get_index_format(NumericType index_type) { } return cformat; } + + default: + gobj_cat.error() + << "Not a valid index type: " << index_type << "\n"; + return NULL; } return NULL; diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 3aae0f7ba6..66198e20cb 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -3760,7 +3760,7 @@ get_shader_input(const InternalName *id) const { // Description: Returns the geometry instance count, or 0 if // disabled. See set_instance_count. //////////////////////////////////////////////////////////////////// -const int NodePath:: +int NodePath:: get_instance_count() const { nassertr_always(!is_empty(), 0); diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index a89c99d0f1..0b590f4919 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -646,7 +646,7 @@ PUBLISHED: const Shader *get_shader() const; const ShaderInput *get_shader_input(const InternalName *id) const; - const int get_instance_count() const; + int get_instance_count() const; void set_tex_transform(TextureStage *stage, const TransformState *transform); void clear_tex_transform(); diff --git a/panda/src/putil/updateSeq.I b/panda/src/putil/updateSeq.I index a47b2fccfc..32da04136d 100644 --- a/panda/src/putil/updateSeq.I +++ b/panda/src/putil/updateSeq.I @@ -223,7 +223,7 @@ operator ++ () { #else _seq = new_seq; #endif // HAVE_THREADS - + return *this; } @@ -284,15 +284,15 @@ INLINE void UpdateSeq:: output(ostream &out) const { AtomicAdjust::Integer seq = AtomicAdjust::get(_seq); switch (seq) { - case SC_initial: + case (AtomicAdjust::Integer)SC_initial: out << "initial"; break; - case SC_old: + case (AtomicAdjust::Integer)SC_old: out << "old"; break; - case SC_fresh: + case (AtomicAdjust::Integer)SC_fresh: out << "fresh"; break; From 40a40b20cfaf49e22dd646e3b8ce2a7b100f6012 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 10 Dec 2014 00:26:26 +0100 Subject: [PATCH 04/20] Rename EventStoreValue to ParamValue to make it more generic, in anticipation of new parameter system --- makepanda/makepanda.py | 40 ++--- panda/src/event/buttonEventList.h | 8 +- panda/src/event/config_event.cxx | 6 - panda/src/event/eventParameter.I | 176 -------------------- panda/src/event/eventParameter.cxx | 42 +---- panda/src/event/eventParameter.h | 142 +--------------- panda/src/event/pointerEventList.h | 11 +- panda/src/mathutil/config_mathutil.cxx | 9 - panda/src/mathutil/linmath_events.h | 21 +-- panda/src/pgraph/eventStorePandaNode.h | 6 +- panda/src/putil/Sources.pp | 7 +- panda/src/putil/config_util.cxx | 39 ++++- panda/src/putil/p3putil_composite2.cxx | 1 + panda/src/putil/paramValue.I | 209 +++++++++++++++++++++++ panda/src/putil/paramValue.cxx | 57 +++++++ panda/src/putil/paramValue.h | 221 +++++++++++++++++++++++++ 16 files changed, 579 insertions(+), 416 deletions(-) create mode 100644 panda/src/putil/paramValue.I create mode 100644 panda/src/putil/paramValue.cxx create mode 100644 panda/src/putil/paramValue.h diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 0b65f80c21..e29085f428 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -2596,11 +2596,11 @@ CopyAllHeaders('panda/src/downloader') CopyAllHeaders('panda/metalibs/pandaexpress') CopyAllHeaders('panda/src/pipeline') +CopyAllHeaders('panda/src/linmath') CopyAllHeaders('panda/src/putil') CopyAllHeaders('dtool/src/prckeys') CopyAllHeaders('panda/src/audio') CopyAllHeaders('panda/src/event') -CopyAllHeaders('panda/src/linmath') CopyAllHeaders('panda/src/mathutil') CopyAllHeaders('panda/src/gsgbase') CopyAllHeaders('panda/src/pnmimage') @@ -3036,6 +3036,25 @@ if (not RUNTIME): TargetAdd('libp3pipeline.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pipeline', 'SRCDIR:panda/src/pipeline']) TargetAdd('libp3pipeline_igate.obj', input='libp3pipeline.in', opts=["DEPENDENCYONLY"]) +# +# DIRECTORY: panda/src/linmath/ +# + +if (not RUNTIME): + OPTS=['DIR:panda/src/linmath', 'BUILDING:PANDA'] + TargetAdd('p3linmath_composite1.obj', opts=OPTS, input='p3linmath_composite1.cxx') + TargetAdd('p3linmath_composite2.obj', opts=OPTS, input='p3linmath_composite2.cxx') + IGATEFILES=GetDirectoryContents('panda/src/linmath', ["*.h", "*_composite*.cxx"]) + for ifile in IGATEFILES[:]: + if "_src." in ifile: + IGATEFILES.remove(ifile) + IGATEFILES.remove('cast_to_double.h') + IGATEFILES.remove('lmat_ops.h') + IGATEFILES.remove('cast_to_float.h') + TargetAdd('libp3linmath.in', opts=OPTS, input=IGATEFILES) + TargetAdd('libp3linmath.in', opts=['IMOD:panda3d.core', 'ILIB:libp3linmath', 'SRCDIR:panda/src/linmath']) + TargetAdd('libp3linmath_igate.obj', input='libp3linmath.in', opts=["DEPENDENCYONLY"]) + # # DIRECTORY: panda/src/putil/ # @@ -3076,25 +3095,6 @@ if (not RUNTIME): TargetAdd('libp3event.in', opts=['IMOD:panda3d.core', 'ILIB:libp3event', 'SRCDIR:panda/src/event']) TargetAdd('libp3event_igate.obj', input='libp3event.in', opts=["DEPENDENCYONLY"]) -# -# DIRECTORY: panda/src/linmath/ -# - -if (not RUNTIME): - OPTS=['DIR:panda/src/linmath', 'BUILDING:PANDA'] - TargetAdd('p3linmath_composite1.obj', opts=OPTS, input='p3linmath_composite1.cxx') - TargetAdd('p3linmath_composite2.obj', opts=OPTS, input='p3linmath_composite2.cxx') - IGATEFILES=GetDirectoryContents('panda/src/linmath', ["*.h", "*_composite*.cxx"]) - for ifile in IGATEFILES[:]: - if "_src." in ifile: - IGATEFILES.remove(ifile) - IGATEFILES.remove('cast_to_double.h') - IGATEFILES.remove('lmat_ops.h') - IGATEFILES.remove('cast_to_float.h') - TargetAdd('libp3linmath.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3linmath.in', opts=['IMOD:panda3d.core', 'ILIB:libp3linmath', 'SRCDIR:panda/src/linmath']) - TargetAdd('libp3linmath_igate.obj', input='libp3linmath.in', opts=["DEPENDENCYONLY"]) - # # DIRECTORY: panda/src/mathutil/ # diff --git a/panda/src/event/buttonEventList.h b/panda/src/event/buttonEventList.h index e470cb8230..ead1a5968c 100644 --- a/panda/src/event/buttonEventList.h +++ b/panda/src/event/buttonEventList.h @@ -34,7 +34,7 @@ class DatagramIterator; // but it may be used anywhere a list of ButtonEvents // is desired. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_EVENT ButtonEventList : public EventStoreValueBase { +class EXPCL_PANDA_EVENT ButtonEventList : public ParamValueBase { public: INLINE ButtonEventList(); INLINE ButtonEventList(const ButtonEventList ©); @@ -64,15 +64,15 @@ protected: public: void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - EventStoreValueBase::init_type(); + ParamValueBase::init_type(); register_type(_type_handle, "ButtonEventList", - EventStoreValueBase::get_class_type()); + ParamValueBase::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/event/config_event.cxx b/panda/src/event/config_event.cxx index 1b241f462d..1ceaf7572a 100644 --- a/panda/src/event/config_event.cxx +++ b/panda/src/event/config_event.cxx @@ -42,12 +42,8 @@ ConfigureFn(config_event) { PointerEventList::init_type(); Event::init_type(); EventHandler::init_type(); - EventStoreValueBase::init_type(); EventStoreInt::init_type("EventStoreInt"); EventStoreDouble::init_type("EventStoreDouble"); - EventStoreString::init_type("EventStoreString"); - EventStoreWstring::init_type("EventStoreWstring"); - EventStoreTypedRefCount::init_type(); GenericAsyncTask::init_type(); #ifdef HAVE_PYTHON PythonTask::init_type(); @@ -56,6 +52,4 @@ ConfigureFn(config_event) { ButtonEventList::register_with_read_factory(); EventStoreInt::register_with_read_factory(); EventStoreDouble::register_with_read_factory(); - EventStoreString::register_with_read_factory(); } - diff --git a/panda/src/event/eventParameter.I b/panda/src/event/eventParameter.I index d6e65cd95f..9f92511566 100644 --- a/panda/src/event/eventParameter.I +++ b/panda/src/event/eventParameter.I @@ -13,10 +13,6 @@ //////////////////////////////////////////////////////////////////// - -template -TypeHandle EventStoreValue::_type_handle; - //////////////////////////////////////////////////////////////////// // Function: EventParameter::Default constructor // Access: Published @@ -299,175 +295,3 @@ operator << (ostream &out, const EventParameter ¶m) { param.output(out); return out; } - - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValueBase::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE EventStoreValueBase:: -EventStoreValueBase() { -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreTypedRefCount::Constructor -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -INLINE EventStoreTypedRefCount:: -EventStoreTypedRefCount(const TypedReferenceCount *value) : - _value((TypedReferenceCount *)value) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreTypedRefCount::set_value -// Access: Published -// Description: Changes the value stored in the parameter. It is -// dangerous to do this for a parameter already added to -// an event, since the parameters may be shared. -//////////////////////////////////////////////////////////////////// -INLINE void EventStoreTypedRefCount:: -set_value(const TypedReferenceCount *value) { - _value = (TypedReferenceCount *)value; -} - - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreTypedRefCount::get_value -// Access: Published -// Description: Retrieves the value stored in the parameter. -//////////////////////////////////////////////////////////////////// -INLINE TypedReferenceCount *EventStoreTypedRefCount:: -get_value() const { - return _value; -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::Default Constructor -// Access: Private -// Description: This constructor is only for make_from_bam(). -//////////////////////////////////////////////////////////////////// -template -EventStoreValue:: -EventStoreValue() { -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -template -EventStoreValue:: -EventStoreValue(const Type &value) : - _value(value) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::Destructor -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -template -EventStoreValue:: -~EventStoreValue() { -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::set_value -// Access: Public -// Description: Changes the value stored in the parameter. It is -// dangerous to do this for a parameter already added to -// an event, since the parameters may be shared. -//////////////////////////////////////////////////////////////////// -template -INLINE void EventStoreValue:: -set_value(const Type &value) { - _value = value; -} - - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::get_value -// Access: Public -// Description: Retrieves the value stored in the parameter. -//////////////////////////////////////////////////////////////////// -template -INLINE const Type &EventStoreValue:: -get_value() const { - return _value; -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::output -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -template -void EventStoreValue:: -output(ostream &out) const { - out << _value; -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::register_with_read_factory -// Access: Public, Static -// Description: Tells the BamReader how to create objects of type -// Lens. -//////////////////////////////////////////////////////////////////// -template -void EventStoreValue:: -register_with_read_factory() { - BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::write_datagram -// Access: Public, Virtual -// Description: Writes the contents of this object to the datagram -// for shipping out to a Bam file. -//////////////////////////////////////////////////////////////////// -template -void EventStoreValue:: -write_datagram(BamWriter *manager, Datagram &dg) { - TypedWritable::write_datagram(manager, dg); - generic_write_datagram(dg, _value); -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::make_from_bam -// Access: Protected, Static -// Description: This function is called by the BamReader's factory -// when a new object of type Lens is encountered -// in the Bam file. It should create the Lens -// and extract its information from the file. -//////////////////////////////////////////////////////////////////// -template -TypedWritable *EventStoreValue:: -make_from_bam(const FactoryParams ¶ms) { - EventStoreValue *esv = new EventStoreValue; - DatagramIterator scan; - BamReader *manager; - - parse_params(params, scan, manager); - esv->fillin(scan, manager); - - return esv; -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValue::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 Lens. -//////////////////////////////////////////////////////////////////// -template -void EventStoreValue:: -fillin(DatagramIterator &scan, BamReader *manager) { - TypedWritable::fillin(scan, manager); - generic_read_datagram(_value, scan); -} diff --git a/panda/src/event/eventParameter.cxx b/panda/src/event/eventParameter.cxx index 3663d37f74..76bef88f9b 100644 --- a/panda/src/event/eventParameter.cxx +++ b/panda/src/event/eventParameter.cxx @@ -20,21 +20,18 @@ #pragma implementation #endif -TypeHandle EventStoreValueBase::_type_handle; -TypeHandle EventStoreTypedRefCount::_type_handle; - //////////////////////////////////////////////////////////////////// // Function: EventParameter::output // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void EventParameter:: output(ostream &out) const { if (_ptr == (TypedWritableReferenceCount *)NULL) { out << "(empty)"; - } else if (_ptr->is_of_type(EventStoreValueBase::get_class_type())) { - const EventStoreValueBase *sv_ptr; + } else if (_ptr->is_of_type(ParamValueBase::get_class_type())) { + const ParamValueBase *sv_ptr; DCAST_INTO_V(sv_ptr, _ptr); sv_ptr->output(out); @@ -42,36 +39,3 @@ output(ostream &out) const { out << _ptr->get_type(); } } - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreValueBase::Destructor -// Access: Published, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -EventStoreValueBase:: -~EventStoreValueBase() { -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreTypedRefCount::Destructor -// Access: Published, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -EventStoreTypedRefCount:: -~EventStoreTypedRefCount() { -} - -//////////////////////////////////////////////////////////////////// -// Function: EventStoreTypedRefCount::output -// Access: Published, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void EventStoreTypedRefCount:: -output(ostream &out) const { - if (_value == (TypedReferenceCount *)NULL) { - out << "(empty)"; - - } else { - out << _value->get_type(); - } -} diff --git a/panda/src/event/eventParameter.h b/panda/src/event/eventParameter.h index 4cdf1ddd8b..e44e5be9df 100644 --- a/panda/src/event/eventParameter.h +++ b/panda/src/event/eventParameter.h @@ -23,6 +23,7 @@ #include "pointerTo.h" #include "bamReader.h" #include "bamWriter.h" +#include "paramValue.h" //////////////////////////////////////////////////////////////////// // Class : EventParameter @@ -32,8 +33,7 @@ // object, which of course could be pretty much // anything. To store a simple value like a double or a // string, the EventParameter constructors transparently -// use the EventStoreValue template class, defined -// below. +// use the ParamValue template class from paramValue.h. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA_EVENT EventParameter { PUBLISHED: @@ -77,138 +77,15 @@ private: INLINE ostream &operator << (ostream &out, const EventParameter ¶m); -//////////////////////////////////////////////////////////////////// -// Class : EventStoreValueBase -// Description : A non-template base class of EventStoreValue (below), -// which serves mainly to define the placeholder for the -// virtual output function. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_EVENT EventStoreValueBase : public TypedWritableReferenceCount { -public: - INLINE EventStoreValueBase(); +typedef ParamTypedRefCount EventStoreTypedRefCount; -PUBLISHED: - virtual ~EventStoreValueBase(); - virtual void output(ostream &out) const=0; +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_EVENT, EXPTP_PANDA_EVENT, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_EVENT, EXPTP_PANDA_EVENT, ParamValue); -public: - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - TypedWritableReferenceCount::init_type(); - register_type(_type_handle, "EventStoreValueBase", - TypedWritableReferenceCount::get_class_type()); - } - -private: - static TypeHandle _type_handle; -}; - -//////////////////////////////////////////////////////////////////// -// Class : EventStoreTypedRefCount -// Description : A class object for storing specifically objects of -// type TypedReferenceCount, which is different than -// TypedWritableReferenceCount. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_EVENT EventStoreTypedRefCount : public EventStoreValueBase { -PUBLISHED: - INLINE EventStoreTypedRefCount(const TypedReferenceCount *value); - virtual ~EventStoreTypedRefCount(); - - INLINE void set_value(const TypedReferenceCount *value); - INLINE TypedReferenceCount *get_value() const; - - virtual void output(ostream &out) const; - -public: - PT(TypedReferenceCount) _value; - -public: - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - EventStoreValueBase::init_type(); - register_type(_type_handle, "EventStoreTypedRefCount", - EventStoreValueBase::get_class_type()); - } - -private: - static TypeHandle _type_handle; -}; - -//////////////////////////////////////////////////////////////////// -// Class : EventStoreValue -// Description : A handy class object for storing simple values (like -// integers or strings) passed along with an Event. -// This is essentially just a wrapper around whatever -// data type you like, to make it a -// TypedWritableReferenceCount object which can be -// passed along inside an EventParameter. -//////////////////////////////////////////////////////////////////// -template -class EventStoreValue : public EventStoreValueBase { -private: - INLINE EventStoreValue(); -public: - INLINE EventStoreValue(const Type &value); - virtual ~EventStoreValue(); - - INLINE void set_value(const Type &value); - INLINE const Type &get_value() const; - - virtual void output(ostream &out) const; - - Type _value; - -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(const string &type_name = "UndefinedEventStoreValue") { - EventStoreValueBase::init_type(); - _type_handle = register_dynamic_type - (type_name, EventStoreValueBase::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() { - // In this case, we can't do anything, since we don't have the - // class' type_name. - return get_class_type(); - } - -private: - static TypeHandle _type_handle; -}; - -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_EVENT, EXPTP_PANDA_EVENT, EventStoreValue); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_EVENT, EXPTP_PANDA_EVENT, EventStoreValue); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_EVENT, EXPTP_PANDA_EVENT, EventStoreValue); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_EVENT, EXPTP_PANDA_EVENT, EventStoreValue); - -typedef EventStoreValue EventStoreInt; -typedef EventStoreValue EventStoreDouble; -typedef EventStoreValue EventStoreString; -typedef EventStoreValue EventStoreWstring; +typedef ParamValue EventStoreInt; +typedef ParamValue EventStoreDouble; +typedef ParamString EventStoreString; +typedef ParamWstring EventStoreWstring; #include "eventParameter.I" @@ -218,4 +95,3 @@ typedef EventStoreValue EventStoreWstring; #endif #endif - diff --git a/panda/src/event/pointerEventList.h b/panda/src/event/pointerEventList.h index 7c84462f40..dd0c6a765e 100644 --- a/panda/src/event/pointerEventList.h +++ b/panda/src/event/pointerEventList.h @@ -34,7 +34,7 @@ class DatagramIterator; // but it may be used anywhere a list of PointerEvents // is desired. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_EVENT PointerEventList : public EventStoreValueBase { +class EXPCL_PANDA_EVENT PointerEventList : public ParamValueBase { PUBLISHED: INLINE PointerEventList(); @@ -53,16 +53,15 @@ PUBLISHED: INLINE void clear(); INLINE void pop_front(); void add_event(bool in_win, int xpos, int ypos, int seq, double time); - + bool encircles(int x, int y) const; double total_turns(double sec) const; double match_pattern(const string &pattern, double rot, double seglen); - + public: INLINE PointerEventList(const PointerEventList ©); INLINE void operator = (const PointerEventList ©); - virtual void output(ostream &out) const; void write(ostream &out, int indent_level = 0) const; @@ -76,9 +75,9 @@ public: return _type_handle; } static void init_type() { - EventStoreValueBase::init_type(); + ParamValueBase::init_type(); register_type(_type_handle, "PointerEventList", - EventStoreValueBase::get_class_type()); + ParamValueBase::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/mathutil/config_mathutil.cxx b/panda/src/mathutil/config_mathutil.cxx index 7b912f13d3..598c83b112 100644 --- a/panda/src/mathutil/config_mathutil.cxx +++ b/panda/src/mathutil/config_mathutil.cxx @@ -24,7 +24,6 @@ #include "boundingPlane.h" #include "unionBoundingVolume.h" #include "intersectionBoundingVolume.h" -#include "linmath_events.h" #include "dconfig.h" #include "pandaSystem.h" @@ -80,17 +79,9 @@ init_libmathutil() { IntersectionBoundingVolume::init_type(); BoundingLine::init_type(); BoundingPlane::init_type(); - EventStoreVec2::init_type("EventStoreVec2"); - EventStoreVec3::init_type("EventStoreVec3"); - EventStoreMat4::init_type("EventStoreMat4"); - - EventStoreVec2::register_with_read_factory(); - EventStoreVec3::register_with_read_factory(); - EventStoreMat4::register_with_read_factory(); #ifdef HAVE_FFTW PandaSystem *ps = PandaSystem::get_global_ptr(); ps->add_system("fftw"); #endif // FFTW } - diff --git a/panda/src/mathutil/linmath_events.h b/panda/src/mathutil/linmath_events.h index 2e24b302ea..fbb38dfa46 100644 --- a/panda/src/mathutil/linmath_events.h +++ b/panda/src/mathutil/linmath_events.h @@ -17,29 +17,22 @@ #include "pandabase.h" -#include "eventParameter.h" +#include "paramValue.h" #include "luse.h" //////////////////////////////////////////////////////////////////// // // This file defines a few more EventStore classes for storing linmath -// objects in an EventParameter. We can't define this with the other -// EventStore classes, because linmath hasn't been defined yet at that -// point. +// objects in an EventParameter. These are just for backward +// compatibility; they are defined as typedefs to ParamVecBase types. // -// See eventParameter.h. +// See paramValue.h. // //////////////////////////////////////////////////////////////////// - -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_MATHUTIL, EXPTP_PANDA_MATHUTIL, EventStoreValue); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_MATHUTIL, EXPTP_PANDA_MATHUTIL, EventStoreValue); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_MATHUTIL, EXPTP_PANDA_MATHUTIL, EventStoreValue); - -typedef EventStoreValue EventStoreVec2; -typedef EventStoreValue EventStoreVec3; -typedef EventStoreValue EventStoreMat4; - +typedef ParamVecBase2 EventStoreVec2; +typedef ParamVecBase3 EventStoreVec3; +typedef ParamMatrix4 EventStoreMat4; // Tell GCC that we'll take care of the instantiation explicitly here. #ifdef __GNUC__ diff --git a/panda/src/pgraph/eventStorePandaNode.h b/panda/src/pgraph/eventStorePandaNode.h index 9495e294d7..b71636c79c 100644 --- a/panda/src/pgraph/eventStorePandaNode.h +++ b/panda/src/pgraph/eventStorePandaNode.h @@ -24,7 +24,7 @@ // Description : A class object for storing specifically objects of // type PandaNode. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PGRAPH EventStorePandaNode : public EventStoreValueBase { +class EXPCL_PANDA_PGRAPH EventStorePandaNode : public ParamValueBase { PUBLISHED: INLINE EventStorePandaNode(const PandaNode *value); virtual ~EventStorePandaNode(); @@ -46,9 +46,9 @@ public: return _type_handle; } static void init_type() { - EventStoreValueBase::init_type(); + ParamValueBase::init_type(); register_type(_type_handle, "EventStorePandaNode", - EventStoreValueBase::get_class_type()); + ParamValueBase::get_class_type()); } private: diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 7e98890b70..e36adb2670 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -1,6 +1,6 @@ #define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \ p3dtoolutil:c p3dtoolbase:c p3dtool:m p3prc:c -#define LOCAL_LIBS p3pipeline p3express p3pandabase +#define LOCAL_LIBS p3pipeline p3linmath p3express p3pandabase #define USE_PACKAGES zlib #begin lib_target @@ -57,6 +57,7 @@ modifierButtons.I modifierButtons.h mouseButton.h \ mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ + paramValue.I paramValue.h \ pbitops.I pbitops.h \ portalMask.h \ pta_ushort.h \ @@ -107,6 +108,7 @@ modifierButtons.cxx mouseButton.cxx mouseData.cxx \ nameUniquifier.cxx \ nodeCachedReferenceCount.cxx \ + paramValue.cxx \ pbitops.cxx \ pta_ushort.cxx \ pythonCallbackObject.cxx \ @@ -167,8 +169,9 @@ modifierButtons.h mouseButton.h mouseData.I mouseData.h \ nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ - portalMask.h \ + paramValue.I paramValue.h \ pbitops.I pbitops.h \ + portalMask.h \ pta_ushort.h \ pythonCallbackObject.h pythonCallbackObject.I \ simpleHashMap.I simpleHashMap.h \ diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index a8c68a6f42..a6ef2bcb70 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -34,6 +34,7 @@ #include "factoryParam.h" #include "namable.h" #include "nodeCachedReferenceCount.h" +#include "paramValue.h" #include "pythonCallbackObject.h" #include "referenceCount.h" #include "sparseArray.h" @@ -62,7 +63,7 @@ ConfigVariableEnum bam_endian "particular platform.")); ConfigVariableBool bam_stdfloat_double -("bam-stdfloat-double", +("bam-stdfloat-double", #ifdef STDFLOAT_DOUBLE true, #else @@ -70,7 +71,7 @@ ConfigVariableBool bam_stdfloat_double #endif PRC_DESC("The default width of floating-point numbers to write to a bam " "file. Set this true to force doubles (64-bit floats), or false " - "to force sinles (32-bit floats). The default is whichever width " + "to force singles (32-bit floats). The default is whichever width " "Panda has been compiled to use natively. Normally, this setting " "should not be changed from the default.")); @@ -79,8 +80,6 @@ ConfigVariableEnum bam_texture_mode PRC_DESC("Set this to specify how textures should be written into Bam files." "See the panda source or documentation for available options.")); - - ConfigureFn(config_util) { init_libputil(); } @@ -200,6 +199,23 @@ init_libputil() { FactoryParam::init_type(); Namable::init_type(); NodeCachedReferenceCount::init_type(); + ParamMatrix3d::init_type("ParamMatrix3d"); + ParamMatrix3f::init_type("ParamMatrix3f"); + ParamMatrix4d::init_type("ParamMatrix4d"); + ParamMatrix4f::init_type("ParamMatrix4f"); + ParamString::init_type("ParamString"); + ParamTypedRefCount::init_type(); + ParamValueBase::init_type(); + ParamVecBase2d::init_type("ParamVecBase2d"); + ParamVecBase2f::init_type("ParamVecBase2f"); + ParamVecBase2i::init_type("ParamVecBase2i"); + ParamVecBase3d::init_type("ParamVecBase3d"); + ParamVecBase3f::init_type("ParamVecBase3f"); + ParamVecBase3i::init_type("ParamVecBase3i"); + ParamVecBase4f::init_type("ParamVecBase4f"); + ParamVecBase4d::init_type("ParamVecBase4d"); + ParamVecBase4i::init_type("ParamVecBase4i"); + ParamWstring::init_type("ParamWstring"); #ifdef HAVE_PYTHON PythonCallbackObject::init_type(); #endif @@ -218,4 +234,19 @@ init_libputil() { BamCacheIndex::register_with_read_factory(); BamCacheRecord::register_with_read_factory(); + ParamMatrix3d::register_with_read_factory(); + ParamMatrix3f::register_with_read_factory(); + ParamMatrix4d::register_with_read_factory(); + ParamMatrix4f::register_with_read_factory(); + ParamString::register_with_read_factory(); + ParamVecBase2d::register_with_read_factory(); + ParamVecBase2f::register_with_read_factory(); + ParamVecBase2i::register_with_read_factory(); + ParamVecBase3d::register_with_read_factory(); + ParamVecBase3f::register_with_read_factory(); + ParamVecBase3i::register_with_read_factory(); + ParamVecBase4d::register_with_read_factory(); + ParamVecBase4f::register_with_read_factory(); + ParamVecBase4i::register_with_read_factory(); + ParamWstring::register_with_read_factory(); } diff --git a/panda/src/putil/p3putil_composite2.cxx b/panda/src/putil/p3putil_composite2.cxx index 9cae69467c..bb0b5fea5a 100644 --- a/panda/src/putil/p3putil_composite2.cxx +++ b/panda/src/putil/p3putil_composite2.cxx @@ -12,6 +12,7 @@ #include "mouseData.cxx" #include "nameUniquifier.cxx" #include "nodeCachedReferenceCount.cxx" +#include "paramValue.cxx" #include "pbitops.cxx" #include "pta_ushort.cxx" #include "pythonCallbackObject.cxx" diff --git a/panda/src/putil/paramValue.I b/panda/src/putil/paramValue.I new file mode 100644 index 0000000000..30846fe300 --- /dev/null +++ b/panda/src/putil/paramValue.I @@ -0,0 +1,209 @@ +// Filename: paramValue.I +// Created by: drose (08Feb99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +template +TypeHandle ParamValue::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ParamValueBase::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ParamValueBase:: +ParamValueBase() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValueBase::get_value_type +// Access: Published, Virtual +// Description: Returns the type of the underlying value. +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle ParamValueBase:: +get_value_type() const { + return TypeHandle::none(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTypedRefCount::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ParamTypedRefCount:: +ParamTypedRefCount(const TypedReferenceCount *value) : + _value((TypedReferenceCount *)value) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTypedRefCount::get_value_type +// Access: Published +// Description: Retrieves the type of the value stored in the +// parameter. +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle ParamTypedRefCount:: +get_value_type() const { + if (_value == NULL) { + return TypeHandle::none(); + } else { + return _value->get_type(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTypedRefCount::get_value +// Access: Published +// Description: Retrieves the value stored in the parameter. +//////////////////////////////////////////////////////////////////// +INLINE TypedReferenceCount *ParamTypedRefCount:: +get_value() const { + return _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ParamValue:: +ParamValue() {} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ParamValue:: +ParamValue(const Type &value) : + _value(value) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ParamValue:: +~ParamValue() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::get_value_type +// Access: Public, Virtual +// Description: Retrieves the type of the value stored in the +// parameter. +//////////////////////////////////////////////////////////////////// +template +INLINE TypeHandle ParamValue:: +get_value_type() const { + return get_type_handle(Type); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::set_value +// Access: Public, Virtual +// Description: Changes the value stored in the parameter. +//////////////////////////////////////////////////////////////////// +template +INLINE void ParamValue:: +set_value(const Type &type) { + _value = type; + mark_bam_modified(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::get_value +// Access: Public +// Description: Retrieves the value stored in the parameter. +//////////////////////////////////////////////////////////////////// +template +INLINE const Type &ParamValue:: +get_value() const { + return _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void ParamValue:: +output(ostream &out) const { + out << _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// ParamValue. +//////////////////////////////////////////////////////////////////// +template +INLINE void ParamValue:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +template +INLINE void ParamValue:: +write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + generic_write_datagram(dg, _value); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type ParamValue is encountered +// in the Bam file. It should create the ParamValue +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +template +INLINE TypedWritable *ParamValue:: +make_from_bam(const FactoryParams ¶ms) { + ParamValue *esv = new ParamValue; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + esv->fillin(scan, manager); + + return esv; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamValue::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 ParamValue. +//////////////////////////////////////////////////////////////////// +template +INLINE void ParamValue:: +fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + generic_read_datagram(_value, scan); +} diff --git a/panda/src/putil/paramValue.cxx b/panda/src/putil/paramValue.cxx new file mode 100644 index 0000000000..c8482dc409 --- /dev/null +++ b/panda/src/putil/paramValue.cxx @@ -0,0 +1,57 @@ +// Filename: paramValue.cxx +// Created by: drose (08Feb99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "paramValue.h" +#include "dcast.h" + +// Tell GCC that we'll take care of the instantiation explicitly here. +#ifdef __GNUC__ +#pragma implementation +#endif + +TypeHandle ParamValueBase::_type_handle; +TypeHandle ParamTypedRefCount::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ParamValueBase::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +ParamValueBase:: +~ParamValueBase() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTypedRefCount::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +ParamTypedRefCount:: +~ParamTypedRefCount() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTypedRefCount::output +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ParamTypedRefCount:: +output(ostream &out) const { + if (_value == (TypedReferenceCount *)NULL) { + out << "(empty)"; + + } else { + out << _value->get_type(); + } +} diff --git a/panda/src/putil/paramValue.h b/panda/src/putil/paramValue.h new file mode 100644 index 0000000000..694c34529d --- /dev/null +++ b/panda/src/putil/paramValue.h @@ -0,0 +1,221 @@ +// Filename: paramValue.h +// Created by: drose (08Feb99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PARAMVALUE_H +#define PARAMVALUE_H + +#include "pandabase.h" + +#include "typedef.h" +#include "typedObject.h" +#include "typedWritableReferenceCount.h" +#include "pointerTo.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "luse.h" + +//////////////////////////////////////////////////////////////////// +// Class : ParamValueBase +// Description : A non-template base class of ParamValue (below), +// which serves mainly to define the placeholder for the +// virtual output function. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_PUTIL ParamValueBase : public TypedWritableReferenceCount { +public: + INLINE ParamValueBase(); + +PUBLISHED: + virtual ~ParamValueBase(); + INLINE virtual TypeHandle get_value_type() const; + virtual void output(ostream &out) const=0; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedWritableReferenceCount::init_type(); + register_type(_type_handle, "ParamValueBase", + TypedWritableReferenceCount::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +//////////////////////////////////////////////////////////////////// +// Class : ParamTypedRefCount +// Description : A class object for storing specifically objects of +// type TypedReferenceCount, which is different than +// TypedWritableReferenceCount. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_PUTIL ParamTypedRefCount : public ParamValueBase { +PUBLISHED: + INLINE ParamTypedRefCount(const TypedReferenceCount *value); + virtual ~ParamTypedRefCount(); + + INLINE virtual TypeHandle get_value_type() const; + INLINE TypedReferenceCount *get_value() const; + + virtual void output(ostream &out) const; + +private: + PT(TypedReferenceCount) _value; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ParamValueBase::init_type(); + register_type(_type_handle, "ParamTypedRefCount", + ParamValueBase::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +//////////////////////////////////////////////////////////////////// +// Class : ParamValue +// Description : A handy class object for storing simple values (like +// integers or strings) passed along with an Event +// or to be used as a shader input. +// This is essentially just a wrapper around whatever +// data type you like, to make it a +// TypedWritableReferenceCount object which can be +// passed along inside an EventParameter or ShaderInput. +//////////////////////////////////////////////////////////////////// +template +class ParamValue : public ParamValueBase { +protected: + INLINE ParamValue(); + +PUBLISHED: + INLINE ParamValue(const Type &value); + INLINE virtual ~ParamValue(); + + INLINE virtual TypeHandle get_value_type() const; + INLINE void set_value(const Type &value); + INLINE const Type &get_value() const; + + INLINE virtual void output(ostream &out) const; + +private: + Type _value; + +public: + INLINE static void register_with_read_factory(); + INLINE virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + INLINE static TypedWritable *make_from_bam(const FactoryParams ¶ms); + INLINE void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type(const string &type_name = "UndefinedParamValue") { + ParamValueBase::init_type(); + _type_handle = register_dynamic_type + (type_name, ParamValueBase::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() { + // In this case, we can't do anything, since we don't have the + // class' type_name. + return get_class_type(); + } + +private: + static TypeHandle _type_handle; +}; + +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); + +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); + +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); + +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); + +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); + +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA_PUTIL, EXPTP_PANDA_PUTIL, ParamValue); + +typedef ParamValue ParamString; +typedef ParamValue ParamWstring; + +typedef ParamValue ParamVecBase2d; +typedef ParamValue ParamVecBase2f; +typedef ParamValue ParamVecBase2i; + +typedef ParamValue ParamVecBase3d; +typedef ParamValue ParamVecBase3f; +typedef ParamValue ParamVecBase3i; + +typedef ParamValue ParamVecBase4d; +typedef ParamValue ParamVecBase4f; +typedef ParamValue ParamVecBase4i; + +typedef ParamValue ParamMatrix3d; +typedef ParamValue ParamMatrix3f; + +typedef ParamValue ParamMatrix4d; +typedef ParamValue ParamMatrix4f; + +#ifdef STDFLOAT_DOUBLE +typedef ParamVecBase2d ParamVecBase2; +typedef ParamVecBase3d ParamVecBase3; +typedef ParamVecBase4d ParamVecBase4; + +typedef ParamMatrix3d ParamMatrix3; +typedef ParamMatrix4d ParamMatrix4; +#else +typedef ParamVecBase2f ParamVecBase2; +typedef ParamVecBase3f ParamVecBase3; +typedef ParamVecBase4f ParamVecBase4; + +typedef ParamMatrix3f ParamMatrix3; +typedef ParamMatrix4f ParamMatrix4; +#endif + +#include "paramValue.I" + +// Tell GCC that we'll take care of the instantiation explicitly here. +#ifdef __GNUC__ +#pragma interface +#endif + +#endif From 5aaaf72851ce522bd1207cefc2c70458e72ecb8b Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 10 Dec 2014 16:32:04 +0100 Subject: [PATCH 05/20] Fix issue with Eigen when matrix determinant is nearly 0 also fix error message for singular matrix --- dtool/src/dtoolbase/nearly_zero.h | 6 ++-- panda/src/linmath/lmatrix3_src.I | 31 ++++++++-------- panda/src/linmath/lmatrix4_src.I | 59 +++++++++++++++++-------------- 3 files changed, 51 insertions(+), 45 deletions(-) diff --git a/dtool/src/dtoolbase/nearly_zero.h b/dtool/src/dtoolbase/nearly_zero.h index 0b36d4652d..a0ffa0b333 100644 --- a/dtool/src/dtoolbase/nearly_zero.h +++ b/dtool/src/dtoolbase/nearly_zero.h @@ -25,17 +25,17 @@ // const identifier, and then returning the value of that identifier, // seems to lead to compilation errors (at least in VC7) in which // sometimes IS_THRESHOLD_COMPEQ(a, a, get_nearly_zero_value(a)) != 0. -INLINE double +CONSTEXPR double get_nearly_zero_value(double) { return 1.0e-12; } -INLINE float +CONSTEXPR float get_nearly_zero_value(float) { return 1.0e-6f; } -INLINE int +CONSTEXPR int get_nearly_zero_value(int) { // This is a bit silly, but we should nevertheless define it in // case it is called for an integer type. diff --git a/panda/src/linmath/lmatrix3_src.I b/panda/src/linmath/lmatrix3_src.I index b6ede0627c..6b12ee6642 100644 --- a/panda/src/linmath/lmatrix3_src.I +++ b/panda/src/linmath/lmatrix3_src.I @@ -998,11 +998,9 @@ INLINE_LINMATH void FLOATNAME(LMatrix3):: transpose_in_place() { TAU_PROFILE("void LMatrix3::transpose_in_place()", " ", TAU_USER); - #define SWAP__(x,y) { FLOATTYPE temp = (x); (x) = (y); (y) = temp;} - SWAP__(_m(0, 1),_m(1, 0)); - SWAP__(_m(0, 2),_m(2, 0)); - SWAP__(_m(1, 2),_m(2, 1)); - #undef SWAP__ + std::swap(_m(0, 1), _m(1, 0)); + std::swap(_m(0, 2), _m(2, 0)); + std::swap(_m(1, 2), _m(2, 1)); } // Matrix inversion code from Numerical Recipes in C. @@ -1050,12 +1048,16 @@ INLINE_LINMATH bool FLOATNAME(LMatrix3):: invert_from(const FLOATNAME(LMatrix3) &other) { TAU_PROFILE("bool LMatrix3::invert_from(const LMatrix3 &)", " ", TAU_USER); + // We throw the value out only if it's smaller than our "small" + // threshold squared. This helps reduce overly-sensitive + // rejections. #ifdef HAVE_EIGEN bool invertible; - other._m.computeInverseWithCheck(_m, invertible); + other._m.computeInverseWithCheck(_m, invertible, + NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)); if (!invertible) { -#ifdef NDEBUG +#ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix3.\n"; #endif (*this) = ident_mat(); @@ -1068,11 +1070,7 @@ invert_from(const FLOATNAME(LMatrix3) &other) { FLOATTYPE other_det = MATRIX3_DETERMINANT(other._m); - // We throw the value out only if it's smaller than our "small" - // threshold squared. This helps reduce overly-sensitive - // rejections. if (IS_THRESHOLD_ZERO(other_det, (NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)))) { - // if (IS_NEARLY_ZERO(other_det)) { #ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix3.\n"; #endif @@ -1125,10 +1123,11 @@ invert_transpose_from(const FLOATNAME(LMatrix3) &other) { #ifdef HAVE_EIGEN bool invertible; EMatrix3 temp; - other._m.computeInverseWithCheck(temp, invertible); + other._m.computeInverseWithCheck(temp, invertible, + NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)); if (!invertible) { -#ifdef NDEBUG +#ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix3.\n"; #endif (*this) = ident_mat(); @@ -1139,6 +1138,7 @@ invert_transpose_from(const FLOATNAME(LMatrix3) &other) { return true; #else // HAVE_EIGEN + FLOATTYPE other_det = MATRIX3_DETERMINANT(other._m); if (IS_THRESHOLD_ZERO(other_det, (NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)))) { @@ -1180,10 +1180,11 @@ invert_transpose_from(const FLOATNAME(LMatrix4) &other) { #ifdef HAVE_EIGEN bool invertible; EMatrix3 temp; - other._m.block<3, 3>(0, 0).computeInverseWithCheck(temp, invertible); + other._m.block<3, 3>(0, 0).computeInverseWithCheck(temp, invertible, + NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)); if (!invertible) { -#ifdef NDEBUG +#ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix3.\n"; #endif (*this) = ident_mat(); diff --git a/panda/src/linmath/lmatrix4_src.I b/panda/src/linmath/lmatrix4_src.I index 389b472aea..38fe84b0ad 100644 --- a/panda/src/linmath/lmatrix4_src.I +++ b/panda/src/linmath/lmatrix4_src.I @@ -831,7 +831,7 @@ xform(const FLOATNAME(LVecBase4) &v) const { #ifdef HAVE_EIGEN v_res._v.noalias() = v._v * _m; -#else +#else VECTOR4_MATRIX4_PRODUCT(v_res, v,(*this)); #endif // HAVE_EIGEN return v_res; @@ -853,12 +853,12 @@ xform_point(const FLOATNAME(LVecBase3) &v) const { #ifdef HAVE_EIGEN v_res._v.noalias() = v._v * _m.block<3, 3>(0, 0) + _m.block<1, 3>(3, 0); -#else +#else v_res._v(0) = v._v(0)*_m(0, 0) + v._v(1)*_m(1, 0) + v._v(2)*_m(2, 0) + _m(3, 0); v_res._v(1) = v._v(0)*_m(0, 1) + v._v(1)*_m(1, 1) + v._v(2)*_m(2, 1) + _m(3, 1); v_res._v(2) = v._v(0)*_m(0, 2) + v._v(1)*_m(1, 2) + v._v(2)*_m(2, 2) + _m(3, 2); #endif // HAVE_EIGEN - + return v_res; } @@ -888,17 +888,17 @@ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: xform_vec(const FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("LVecBase3 LMatrix4::xform_vec(const LVecBase3 &)", " ", TAU_USER); FLOATNAME(LVecBase3) v_res; - + // v._v(3) == 0.0f for this case - + #ifdef HAVE_EIGEN v_res._v.noalias() = v._v * _m.block<3, 3>(0, 0); -#else +#else v_res._v(0) = v._v(0)*_m(0, 0) + v._v(1)*_m(1, 0) + v._v(2)*_m(2, 0); v_res._v(1) = v._v(0)*_m(0, 1) + v._v(1)*_m(1, 1) + v._v(2)*_m(2, 1); v_res._v(2) = v._v(0)*_m(0, 2) + v._v(1)*_m(1, 2) + v._v(2)*_m(2, 2); #endif // HAVE_EIGEN - + return v_res; } @@ -934,7 +934,7 @@ xform_in_place(FLOATNAME(LVecBase4) &v) const { #ifdef HAVE_EIGEN v._v = v._v * _m; -#else +#else v = xform(v); #endif // HAVE_EIGEN } @@ -953,7 +953,7 @@ xform_point_in_place(FLOATNAME(LVecBase3) &v) const { #ifdef HAVE_EIGEN v._v = v._v * _m.block<3, 3>(0, 0) + _m.block<1, 3>(3, 0); -#else +#else v = xform_point(v); #endif // HAVE_EIGEN } @@ -981,10 +981,10 @@ INLINE_LINMATH void FLOATNAME(LMatrix4):: xform_vec_in_place(FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("void LMatrix4::xform_vec_in_place(LVecBase3 &)", " ", TAU_USER); // v._v(3) == 0.0f for this case - + #ifdef HAVE_EIGEN v._v = v._v * _m.block<3, 3>(0, 0); -#else +#else v = xform_vec(v); #endif // HAVE_EIGEN } @@ -1325,14 +1325,12 @@ transpose_in_place() { _m.transposeInPlace(); #else - #define SWAP__(x,y) { FLOATTYPE temp = (x); (x) = (y); (y) = temp;} - SWAP__(_m(0, 1),_m(1, 0)); - SWAP__(_m(0, 2),_m(2, 0)); - SWAP__(_m(0, 3),_m(3, 0)); - SWAP__(_m(1, 2),_m(2, 1)); - SWAP__(_m(1, 3),_m(3, 1)); - SWAP__(_m(2, 3),_m(3, 2)); - #undef SWAP__ + std::swap(_m(0, 1), _m(1, 0)); + std::swap(_m(0, 2), _m(2, 0)); + std::swap(_m(0, 3), _m(3, 0)); + std::swap(_m(1, 2), _m(2, 1)); + std::swap(_m(1, 3), _m(3, 1)); + std::swap(_m(2, 3), _m(3, 2)); #endif // HAVE_EIGEN } @@ -1356,13 +1354,19 @@ INLINE_LINMATH bool FLOATNAME(LMatrix4):: invert_from(const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("bool LMatrix4::invert_from(const LMatrix4 &)", " ", TAU_USER); #ifdef HAVE_EIGEN + // We use the squared nearly_zero value as determinant threshold + // for checking whether a matrix is singular, since that's the + // same constant we use in the non-Eigen case (see lmatrix3_src.I) + // and also because we otherwise run into issues very quickly. bool invertible; - other._m.computeInverseWithCheck(_m, invertible); + other._m.computeInverseWithCheck(_m, invertible, + NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)); if (!invertible) { -#ifdef NDEBUG +#ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix4.\n"; #endif + (*this) = ident_mat(); nassertr(!no_singular_invert, false); } @@ -1382,9 +1386,10 @@ invert_from(const FLOATNAME(LMatrix4) &other) { int index[4]; if (!decompose_mat(index)) { -#ifdef NDEBUG +#ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix4.\n"; #endif + (*this) = ident_mat(); nassertr(!no_singular_invert, false); return false; @@ -1441,11 +1446,11 @@ invert_affine_from(const FLOATNAME(LMatrix4) &other) { _m(3, 0) = -(other._m(3, 0) * _m(0, 0) + other._m(3, 1) * _m(1, 0) + other._m(3, 2) * _m(2, 0)); - + _m(3, 1) = -(other._m(3, 0) * _m(0, 1) + other._m(3, 1) * _m(1, 1) + other._m(3, 2) * _m(2, 1)); - + _m(3, 2) = -(other._m(3, 0) * _m(0, 2) + other._m(3, 1) * _m(1, 2) + other._m(3, 2) * _m(2, 2)); @@ -1481,17 +1486,17 @@ accumulate(const FLOATNAME(LMatrix4) &other, FLOATTYPE weight) { _m(0, 1) += other._m(0, 1) * weight; _m(0, 2) += other._m(0, 2) * weight; _m(0, 3) += other._m(0, 3) * weight; - + _m(1, 0) += other._m(1, 0) * weight; _m(1, 1) += other._m(1, 1) * weight; _m(1, 2) += other._m(1, 2) * weight; _m(1, 3) += other._m(1, 3) * weight; - + _m(2, 0) += other._m(2, 0) * weight; _m(2, 1) += other._m(2, 1) * weight; _m(2, 2) += other._m(2, 2) * weight; _m(2, 3) += other._m(2, 3) * weight; - + _m(3, 0) += other._m(3, 0) * weight; _m(3, 1) += other._m(3, 1) * weight; _m(3, 2) += other._m(3, 2) * weight; From 7d0c1420c2b248b4031d13ed889fe72dc7334a1c Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 11 Dec 2014 16:27:51 +0100 Subject: [PATCH 06/20] Bypass view frustum cull entirely when camera has OmniBV --- panda/src/display/graphicsEngine.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index db53b323e2..849e9efb4f 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -41,6 +41,7 @@ #include "bamCache.h" #include "cullableObject.h" #include "geomVertexArrayData.h" +#include "omniBoundingVolume.h" #include "vertexDataSaveFile.h" #include "vertexDataBook.h" #include "vertexDataPage.h" @@ -1212,7 +1213,8 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, PT(BoundingVolume) bv = scene_setup->get_cull_bounds(); if (bv != (BoundingVolume *)NULL && - bv->is_of_type(GeometricBoundingVolume::get_class_type())) { + bv->is_of_type(GeometricBoundingVolume::get_class_type()) && + !bv->is_of_type(OmniBoundingVolume::get_class_type())) { // Transform it into the appropriate coordinate space. PT(GeometricBoundingVolume) local_frustum; local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy()); From f4ec51d4c243d3ead7313fb6c4bdd4d588ecdd32 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 11 Dec 2014 17:02:20 +0100 Subject: [PATCH 07/20] fix pdeploy regression: per_platform should be 0 in installed contents.xml --- direct/src/p3d/DeploymentTools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/direct/src/p3d/DeploymentTools.py b/direct/src/p3d/DeploymentTools.py index fde6a741a1..ef046a5490 100644 --- a/direct/src/p3d/DeploymentTools.py +++ b/direct/src/p3d/DeploymentTools.py @@ -590,7 +590,7 @@ class Installer: if package.platform: xpackage.SetAttribute('platform', package.platform) assert package.platform == platform - xpackage.SetAttribute('per_platform', '1') + xpackage.SetAttribute('per_platform', '0') if package.packageVersion: xpackage.SetAttribute('version', version) xpackage.SetAttribute('filename', package.packageName + "/" + package.packageVersion + "/" + package.descFileBasename) From 95d85819b032a26b2eb1f06798f746235607cca3 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 15:58:45 +0100 Subject: [PATCH 08/20] Separate out sampler state from texture, support sampler objects, support LOD min/max/bias --- panda/src/display/graphicsOutput.cxx | 8 +- panda/src/display/graphicsStateGuardian.I | 27 ++ panda/src/display/graphicsStateGuardian.cxx | 47 +- panda/src/display/graphicsStateGuardian.h | 8 +- panda/src/doc/howto.use_multipass.txt | 2 +- panda/src/dxgsg8/dxGraphicsStateGuardian8.I | 12 +- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 42 +- panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 6 +- panda/src/dxgsg8/dxTextureContext8.cxx | 56 +-- panda/src/dxgsg9/dxGraphicsStateGuardian9.I | 12 +- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 76 ++-- panda/src/dxgsg9/dxGraphicsStateGuardian9.h | 9 +- panda/src/dxgsg9/dxShaderContext9.cxx | 93 ++-- panda/src/dxgsg9/dxTextureContext9.cxx | 56 +-- panda/src/egg2pg/eggLoader.cxx | 54 +-- panda/src/egg2pg/eggLoader.h | 2 +- panda/src/egg2pg/eggSaver.cxx | 24 +- panda/src/framework/windowFramework.cxx | 8 +- panda/src/glstuff/glCgShaderContext_src.cxx | 11 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 323 ++++++++++--- .../src/glstuff/glGraphicsStateGuardian_src.h | 31 +- panda/src/glstuff/glSamplerContext_src.cxx | 83 ++++ panda/src/glstuff/glSamplerContext_src.h | 58 +++ panda/src/glstuff/glShaderContext_src.cxx | 5 + panda/src/glstuff/glTextureContext_src.h | 3 + panda/src/glstuff/glmisc_src.cxx | 7 + panda/src/glstuff/glmisc_src.h | 1 + panda/src/glstuff/glstuff_src.cxx | 1 + panda/src/glstuff/glstuff_src.h | 1 + panda/src/gobj/config_gobj.cxx | 21 +- panda/src/gobj/config_gobj.h | 1 + panda/src/gobj/p3gobj_composite1.cxx | 2 + panda/src/gobj/p3gobj_composite2.cxx | 5 +- panda/src/gobj/paramTexture.I | 158 +++++++ panda/src/gobj/paramTexture.cxx | 220 +++++++++ panda/src/gobj/paramTexture.h | 143 ++++++ panda/src/gobj/preparedGraphicsObjects.I | 13 +- panda/src/gobj/preparedGraphicsObjects.cxx | 245 +++++++++- panda/src/gobj/preparedGraphicsObjects.h | 37 +- panda/src/gobj/samplerContext.I | 25 ++ panda/src/gobj/samplerContext.cxx | 38 ++ panda/src/gobj/samplerContext.h | 73 +++ panda/src/gobj/samplerState.I | 338 ++++++++++++++ panda/src/gobj/samplerState.cxx | 401 +++++++++++++++++ panda/src/gobj/samplerState.h | 210 +++++++++ panda/src/gobj/texture.I | 210 +++++++-- panda/src/gobj/texture.cxx | 425 +++--------------- panda/src/gobj/texture.h | 203 ++++----- panda/src/gobj/textureContext.cxx | 4 +- panda/src/grutil/multitexReducer.cxx | 4 +- panda/src/gsgbase/graphicsStateGuardianBase.h | 7 +- .../osxdisplay/osxGraphicsStateGuardian.cxx | 4 +- panda/src/pgraph/geomNode.cxx | 78 ++-- panda/src/pgraph/nodePath.cxx | 368 +++++++++------ panda/src/pgraph/nodePath.h | 34 +- panda/src/pgraph/occluderNode.cxx | 22 +- panda/src/pgraph/shaderAttrib.cxx | 153 ++++--- panda/src/pgraph/shaderAttrib.h | 17 +- panda/src/pgraph/shaderInput.I | 192 +++++--- panda/src/pgraph/shaderInput.h | 35 +- panda/src/pgraph/textureAttrib.I | 34 +- panda/src/pgraph/textureAttrib.cxx | 82 +++- panda/src/pgraph/textureAttrib.h | 12 +- panda/src/pgraphnodes/spotlight.cxx | 8 +- panda/src/putil/bam.h | 3 +- panda/src/rocket/rocketRenderInterface.cxx | 12 +- panda/src/testbed/test_texmem.cxx | 2 +- panda/src/testbed/text_test.cxx | 4 +- panda/src/text/config_text.cxx | 12 +- panda/src/text/config_text.h | 6 +- panda/src/text/dynamicTextFont.I | 8 +- panda/src/text/dynamicTextFont.h | 12 +- panda/src/text/staticTextFont.cxx | 4 +- .../tinydisplay/tinyGraphicsStateGuardian.cxx | 68 +-- .../tinydisplay/tinyGraphicsStateGuardian.h | 4 +- pandatool/src/pfmprogs/pfmTrans.cxx | 2 +- 76 files changed, 3722 insertions(+), 1303 deletions(-) create mode 100644 panda/src/glstuff/glSamplerContext_src.cxx create mode 100644 panda/src/glstuff/glSamplerContext_src.h create mode 100644 panda/src/gobj/paramTexture.I create mode 100644 panda/src/gobj/paramTexture.cxx create mode 100644 panda/src/gobj/paramTexture.h create mode 100644 panda/src/gobj/samplerContext.I create mode 100644 panda/src/gobj/samplerContext.cxx create mode 100644 panda/src/gobj/samplerContext.h create mode 100644 panda/src/gobj/samplerState.I create mode 100644 panda/src/gobj/samplerState.cxx create mode 100644 panda/src/gobj/samplerState.h diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 78f7c3f429..ce1eb08d00 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -308,8 +308,8 @@ add_render_texture(Texture *tex, RenderTextureMode mode, // Create texture if necessary. if (tex == (Texture *)NULL) { tex = new Texture(get_name()); - tex->set_wrap_u(Texture::WM_clamp); - tex->set_wrap_v(Texture::WM_clamp); + tex->set_wrap_u(SamplerState::WM_clamp); + tex->set_wrap_v(SamplerState::WM_clamp); } else { tex->clear_ram_image(); } @@ -1050,8 +1050,8 @@ make_cube_map(const string &name, int size, NodePath &camera_rig, PT(Texture) tex = new Texture(name); tex->setup_cube_map(); - tex->set_wrap_u(Texture::WM_clamp); - tex->set_wrap_v(Texture::WM_clamp); + tex->set_wrap_u(SamplerState::WM_clamp); + tex->set_wrap_v(SamplerState::WM_clamp); GraphicsOutput *buffer; buffer = make_texture_buffer(name, size, size, tex, to_ram, fbp); diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 11e091bf2c..d9a406c79f 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -36,6 +36,17 @@ release_all_textures() { return _prepared_objects->release_all_textures(); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::release_all_samplers +// Access: Public +// Description: Frees the resources for all samplers associated with +// this GSG. +//////////////////////////////////////////////////////////////////// +INLINE int GraphicsStateGuardian:: +release_all_samplers() { + return _prepared_objects->release_all_samplers(); +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::release_all_geoms // Access: Public @@ -632,6 +643,22 @@ get_supports_shadow_filter() const { return _supports_shadow_filter; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_supports_sampler_objects +// Access: Published +// Description: Returns true if this particular GSG supports the +// use of sampler objects to record texture sampling +// parameters separately from the texture objects. +// This doesn't really affect functionality, but if +// this is false, it may mean that using the same +// texture with different SamplerState objects will +// result in reduced performance. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsStateGuardian:: +get_supports_sampler_objects() const { + return _supports_sampler_objects; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_supports_basic_shaders // Access: Published diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 65ca18054b..3ac9bfd84c 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -98,6 +98,7 @@ PStatCollector GraphicsStateGuardian::_command_latency_pcollector("Command laten PStatCollector GraphicsStateGuardian::_prepare_pcollector("Draw:Prepare"); PStatCollector GraphicsStateGuardian::_prepare_texture_pcollector("Draw:Prepare:Texture"); +PStatCollector GraphicsStateGuardian::_prepare_sampler_pcollector("Draw:Prepare:Sampler"); PStatCollector GraphicsStateGuardian::_prepare_geom_pcollector("Draw:Prepare:Geom"); PStatCollector GraphicsStateGuardian::_prepare_shader_pcollector("Draw:Prepare:Shader"); PStatCollector GraphicsStateGuardian::_prepare_vertex_buffer_pcollector("Draw:Prepare:Vertex buffer"); @@ -230,6 +231,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system, _supports_depth_texture = false; _supports_depth_stencil = false; _supports_shadow_filter = false; + _supports_sampler_objects = false; _supports_basic_shaders = false; _supports_geometry_shaders = false; _supports_tessellation_shaders = false; @@ -626,6 +628,35 @@ extract_texture_data(Texture *) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::prepare_sampler +// Access: Public, Virtual +// Description: Creates whatever structures the GSG requires to +// represent the sampler internally, and returns a +// newly-allocated SamplerContext object with this data. +// It is the responsibility of the calling function to +// later call release_sampler() with this same pointer +// (which will also delete the pointer). +// +// This function should not be called directly to +// prepare a sampler. Instead, call Texture::prepare(). +//////////////////////////////////////////////////////////////////// +SamplerContext *GraphicsStateGuardian:: +prepare_sampler(const SamplerState &sampler) { + return (SamplerContext *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::release_sampler +// Access: Public, Virtual +// Description: Frees the resources previously allocated via a call +// to prepare_sampler(), including deleting the +// SamplerContext itself, if it is non-NULL. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +release_sampler(SamplerContext *) { +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::prepare_geom // Access: Public, Virtual @@ -2883,22 +2914,22 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) { // Set the wrap mode if (is_point) { - tex->set_wrap_u(Texture::WM_clamp); - tex->set_wrap_v(Texture::WM_clamp); + tex->set_wrap_u(SamplerState::WM_clamp); + tex->set_wrap_v(SamplerState::WM_clamp); } else { - tex->set_wrap_u(Texture::WM_border_color); - tex->set_wrap_v(Texture::WM_border_color); + tex->set_wrap_u(SamplerState::WM_border_color); + tex->set_wrap_v(SamplerState::WM_border_color); tex->set_border_color(LVecBase4(1, 1, 1, 1)); } if (get_supports_shadow_filter()) { // If we have the ARB_shadow extension, enable shadow filtering. - tex->set_minfilter(Texture::FT_shadow); - tex->set_magfilter(Texture::FT_shadow); + tex->set_minfilter(SamplerState::FT_shadow); + tex->set_magfilter(SamplerState::FT_shadow); } else { // We only accept linear - this tells the GPU to use hardware PCF. - tex->set_minfilter(Texture::FT_linear); - tex->set_magfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); + tex->set_magfilter(SamplerState::FT_linear); } // Assign display region(s) to the buffer and camera diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 0cc5a3a587..32a3e863c0 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -87,6 +87,7 @@ PUBLISHED: INLINE void release_all(); INLINE int release_all_textures(); + INLINE int release_all_samplers(); INLINE int release_all_geoms(); INLINE int release_all_vertex_buffers(); INLINE int release_all_index_buffers(); @@ -143,6 +144,7 @@ PUBLISHED: INLINE bool get_supports_depth_texture() const; INLINE bool get_supports_depth_stencil() const; INLINE bool get_supports_shadow_filter() const; + INLINE bool get_supports_sampler_objects() const; INLINE bool get_supports_basic_shaders() const; INLINE bool get_supports_geometry_shaders() const; INLINE bool get_supports_tessellation_shaders() const; @@ -165,7 +167,6 @@ PUBLISHED: virtual int get_supported_geom_rendering() const; virtual bool get_supports_cg_profile(const string &name) const; - INLINE bool get_color_scale_via_lighting() const; INLINE bool get_alpha_scale_via_texture() const; INLINE bool get_alpha_scale_via_texture(const TextureAttrib *tex_attrib) const; @@ -215,6 +216,9 @@ public: virtual void release_texture(TextureContext *tc); virtual bool extract_texture_data(Texture *tex); + virtual SamplerContext *prepare_sampler(const SamplerState &sampler); + virtual void release_sampler(SamplerContext *sc); + virtual GeomContext *prepare_geom(Geom *geom); virtual void release_geom(GeomContext *gc); @@ -509,6 +513,7 @@ protected: bool _supports_depth_texture; bool _supports_depth_stencil; bool _supports_shadow_filter; + bool _supports_sampler_objects; bool _supports_basic_shaders; bool _supports_geometry_shaders; bool _supports_tessellation_shaders; @@ -586,6 +591,7 @@ public: static PStatCollector _prepare_pcollector; static PStatCollector _prepare_texture_pcollector; + static PStatCollector _prepare_sampler_pcollector; static PStatCollector _prepare_geom_pcollector; static PStatCollector _prepare_shader_pcollector; static PStatCollector _prepare_vertex_buffer_pcollector; diff --git a/panda/src/doc/howto.use_multipass.txt b/panda/src/doc/howto.use_multipass.txt index 83f55a73a8..c0485012d9 100644 --- a/panda/src/doc/howto.use_multipass.txt +++ b/panda/src/doc/howto.use_multipass.txt @@ -81,7 +81,7 @@ specified a power-of-2 size.) You can extract this Texture and set various properties on it, then apply it to geometry: Texture *tex = buffer->get_texture(); - tex->set_minfilter(Texture::FT_linear_mipmap_linear); + tex->set_minfilter(SamplerState::FT_linear_mipmap_linear); screen.set_texture(tex); diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.I b/panda/src/dxgsg8/dxGraphicsStateGuardian8.I index dde43ecddb..58302f94b4 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.I +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.I @@ -79,17 +79,17 @@ LColor_to_D3DCOLOR(const LColor &cLColor) { // GL's. //////////////////////////////////////////////////////////////////// INLINE D3DTEXTUREADDRESS DXGraphicsStateGuardian8:: -get_texture_wrap_mode(Texture::WrapMode wm) { +get_texture_wrap_mode(SamplerState::WrapMode wm) { switch (wm) { - case Texture::WM_clamp: + case SamplerState::WM_clamp: return D3DTADDRESS_CLAMP; - case Texture::WM_repeat: + case SamplerState::WM_repeat: return D3DTADDRESS_WRAP; - case Texture::WM_mirror: + case SamplerState::WM_mirror: return D3DTADDRESS_MIRROR; - case Texture::WM_mirror_once: + case SamplerState::WM_mirror_once: return D3DTADDRESS_MIRRORONCE; - case Texture::WM_border_color: + case SamplerState::WM_border_color: return D3DTADDRESS_BORDER; } dxgsg8_cat.error() << "Invalid Texture::Mode value" << endl; diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 019eaf9837..c143522cc2 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -193,7 +193,7 @@ apply_texture(int i, TextureContext *tc) { DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc); Texture *tex = tc->get_texture(); - Texture::WrapMode wrap_u, wrap_v, wrap_w; + SamplerState::WrapMode wrap_u, wrap_v, wrap_w; wrap_u = tex->get_wrap_u(); wrap_v = tex->get_wrap_v(); wrap_w = tex->get_wrap_w(); @@ -206,7 +206,7 @@ apply_texture(int i, TextureContext *tc) { LColor_to_D3DCOLOR(tex->get_border_color())); uint aniso_degree = tex->get_effective_anisotropic_degree(); - Texture::FilterType ft = tex->get_effective_magfilter(); + SamplerState::FilterType ft = tex->get_effective_magfilter(); if (aniso_degree >= 1) { _d3d_device->SetTextureStageState(i, D3DTSS_MAXANISOTROPY, aniso_degree); @@ -214,7 +214,7 @@ apply_texture(int i, TextureContext *tc) { D3DTEXTUREFILTERTYPE new_mag_filter; if (aniso_degree <= 1) { - new_mag_filter = ((ft != Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT); + new_mag_filter = ((ft != SamplerState::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT); } else { new_mag_filter = D3DTEXF_ANISOTROPIC; } @@ -4031,28 +4031,28 @@ copy_pres_reset(DXScreenData *screen) { // Description: //////////////////////////////////////////////////////////////////// D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian8:: -get_d3d_min_type(Texture::FilterType filter_type) { +get_d3d_min_type(SamplerState::FilterType filter_type) { switch (filter_type) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: return D3DTEXF_POINT; - case Texture::FT_linear: + case SamplerState::FT_linear: return D3DTEXF_LINEAR; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: return D3DTEXF_POINT; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: return D3DTEXF_LINEAR; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: return D3DTEXF_POINT; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return D3DTEXF_LINEAR; - case Texture::FT_shadow: - case Texture::FT_default: + case SamplerState::FT_shadow: + case SamplerState::FT_default: return D3DTEXF_LINEAR; } @@ -4067,28 +4067,28 @@ get_d3d_min_type(Texture::FilterType filter_type) { // Description: //////////////////////////////////////////////////////////////////// D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian8:: -get_d3d_mip_type(Texture::FilterType filter_type) { +get_d3d_mip_type(SamplerState::FilterType filter_type) { switch (filter_type) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: return D3DTEXF_NONE; - case Texture::FT_linear: + case SamplerState::FT_linear: return D3DTEXF_NONE; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: return D3DTEXF_POINT; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: return D3DTEXF_POINT; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: return D3DTEXF_LINEAR; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return D3DTEXF_LINEAR; - case Texture::FT_shadow: - case Texture::FT_default: + case SamplerState::FT_shadow: + case SamplerState::FT_default: return D3DTEXF_NONE; } diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index 9a4412e01b..788a3bdc0f 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -174,7 +174,7 @@ protected: void do_auto_rescale_normal(); protected: - INLINE static D3DTEXTUREADDRESS get_texture_wrap_mode(Texture::WrapMode wm); + INLINE static D3DTEXTUREADDRESS get_texture_wrap_mode(SamplerState::WrapMode wm); INLINE static D3DFOGMODE get_fog_mode_type(Fog::Mode m); const D3DCOLORVALUE &get_light_color(Light *light) const; INLINE static D3DTRANSFORMSTATETYPE get_tex_mat_sym(int stage_index); @@ -199,8 +199,8 @@ protected: bool release_swap_chain (DXScreenData *new_context); void copy_pres_reset(DXScreenData *new_context); - static D3DTEXTUREFILTERTYPE get_d3d_min_type(Texture::FilterType filter_type); - static D3DTEXTUREFILTERTYPE get_d3d_mip_type(Texture::FilterType filter_type); + static D3DTEXTUREFILTERTYPE get_d3d_min_type(SamplerState::FilterType filter_type); + static D3DTEXTUREFILTERTYPE get_d3d_mip_type(SamplerState::FilterType filter_type); static D3DTEXTUREOP get_texture_operation(TextureStage::CombineMode mode, int scale); static DWORD get_texture_argument(TextureStage::CombineSource source, TextureStage::CombineOperand operand); diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx index ab651d6d0c..7a299cb4d0 100644 --- a/panda/src/dxgsg8/dxTextureContext8.cxx +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -591,21 +591,21 @@ create_texture(DXScreenData &scrn) { // validate magfilter setting // degrade filtering if no HW support - Texture::FilterType ft; + SamplerState::FilterType ft; ft = tex->get_magfilter(); - if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) { + if ((ft != SamplerState::FT_linear) && ft != SamplerState::FT_nearest) { // mipmap settings make no sense for magfilter - if (ft == Texture::FT_nearest_mipmap_nearest) { - ft = Texture::FT_nearest; + if (ft == SamplerState::FT_nearest_mipmap_nearest) { + ft = SamplerState::FT_nearest; } else { - ft = Texture::FT_linear; + ft = SamplerState::FT_linear; } } - if (ft == Texture::FT_linear && + if (ft == SamplerState::FT_linear && (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) { - ft = Texture::FT_nearest; + ft = SamplerState::FT_nearest; } tex->set_magfilter(ft); @@ -615,33 +615,33 @@ create_texture(DXScreenData &scrn) { if (!dx_ignore_mipmaps) { // set if no HW mipmap capable switch(ft) { - case Texture::FT_nearest_mipmap_nearest: - case Texture::FT_linear_mipmap_nearest: - case Texture::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_nearest_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them + case SamplerState::FT_linear_mipmap_linear: _has_mipmaps = true; } if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost _has_mipmaps = true; if (dxgsg8_cat.is_spam()) { - if (ft != Texture::FT_linear_mipmap_linear) { + if (ft != SamplerState::FT_linear_mipmap_linear) { dxgsg8_cat.spam() << "Forcing trilinear mipmapping on DX texture [" << tex->get_name() << "]\n"; } } - ft = Texture::FT_linear_mipmap_linear; + ft = SamplerState::FT_linear_mipmap_linear; tex->set_minfilter(ft); } - } else if ((ft == Texture::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types - (ft == Texture::FT_nearest_mipmap_linear)) { - ft = Texture::FT_nearest; + } else if ((ft == SamplerState::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types + (ft == SamplerState::FT_nearest_mipmap_linear)) { + ft = SamplerState::FT_nearest; - } else if ((ft == Texture::FT_linear_mipmap_nearest) || - (ft == Texture::FT_linear_mipmap_linear)) { - ft = Texture::FT_linear; + } else if ((ft == SamplerState::FT_linear_mipmap_nearest) || + (ft == SamplerState::FT_linear_mipmap_linear)) { + ft = SamplerState::FT_linear; } nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false); @@ -650,36 +650,36 @@ create_texture(DXScreenData &scrn) { // do any other filter type degradations necessary switch(ft) { - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) { if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) { - ft = Texture::FT_linear_mipmap_nearest; + ft = SamplerState::FT_linear_mipmap_nearest; } else { // if you cant do linear in a level, you probably cant do // linear b/w levels, so just do nearest-all - ft = Texture::FT_nearest_mipmap_nearest; + ft = SamplerState::FT_nearest_mipmap_nearest; } } break; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: // if we don't have bilinear, do nearest_nearest if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) && (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) { - ft = Texture::FT_nearest_mipmap_nearest; + ft = SamplerState::FT_nearest_mipmap_nearest; } break; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: // if we don't have mip linear, do nearest_nearest if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) { - ft = Texture::FT_nearest_mipmap_nearest; + ft = SamplerState::FT_nearest_mipmap_nearest; } break; - case Texture::FT_linear: + case SamplerState::FT_linear: if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) { - ft = Texture::FT_nearest; + ft = SamplerState::FT_nearest; } break; } diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.I b/panda/src/dxgsg9/dxGraphicsStateGuardian9.I index f6d2e0391f..36e54ee69d 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.I +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.I @@ -79,17 +79,17 @@ LColor_to_D3DCOLOR(const LColor &cLColor) { // GL's. //////////////////////////////////////////////////////////////////// INLINE D3DTEXTUREADDRESS DXGraphicsStateGuardian9:: -get_texture_wrap_mode(Texture::WrapMode wm) { +get_texture_wrap_mode(SamplerState::WrapMode wm) { switch (wm) { - case Texture::WM_clamp: + case SamplerState::WM_clamp: return D3DTADDRESS_CLAMP; - case Texture::WM_repeat: + case SamplerState::WM_repeat: return D3DTADDRESS_WRAP; - case Texture::WM_mirror: + case SamplerState::WM_mirror: return D3DTADDRESS_MIRROR; - case Texture::WM_mirror_once: + case SamplerState::WM_mirror_once: return D3DTADDRESS_MIRRORONCE; - case Texture::WM_border_color: + case SamplerState::WM_border_color: return D3DTADDRESS_BORDER; } dxgsg9_cat.error() << "Invalid Texture::Mode value" << endl; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index dd421bbc2f..d0b8dd6e9d 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -206,7 +206,7 @@ prepare_texture(Texture *tex, int view) { // rendering on the ith stage. //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: -apply_texture(int i, TextureContext *tc) { +apply_texture(int i, TextureContext *tc, const SamplerState &sampler) { if (tc == (TextureContext *)NULL) { // The texture wasn't bound properly or something, so ensure // texturing is disabled and just return. @@ -231,31 +231,22 @@ apply_texture(int i, TextureContext *tc) { set_sampler_state(i, D3DSAMP_SRGBTEXTURE, FALSE); } - Texture::WrapMode wrap_u, wrap_v, wrap_w; + set_sampler_state(i, D3DSAMP_ADDRESSU, + get_texture_wrap_mode(sampler.get_wrap_u())); - DWORD address_u; - DWORD address_v; - DWORD address_w; + set_sampler_state(i, D3DSAMP_ADDRESSV, + get_texture_wrap_mode(sampler.get_wrap_v())); - wrap_u = tex->get_wrap_u(); - wrap_v = tex->get_wrap_v(); - wrap_w = tex->get_wrap_w(); - - address_u = get_texture_wrap_mode(wrap_u); - address_v = get_texture_wrap_mode(wrap_v); - address_w = get_texture_wrap_mode(wrap_w); - - set_sampler_state(i, D3DSAMP_ADDRESSU, address_u); - set_sampler_state(i, D3DSAMP_ADDRESSV, address_v); - set_sampler_state(i, D3DSAMP_ADDRESSW, address_w); + set_sampler_state(i, D3DSAMP_ADDRESSW, + get_texture_wrap_mode(sampler.get_wrap_w())); DWORD border_color; - border_color = LColor_to_D3DCOLOR(tex->get_border_color()); + border_color = LColor_to_D3DCOLOR(sampler.get_border_color()); set_sampler_state(i, D3DSAMP_BORDERCOLOR, border_color); - uint aniso_degree = tex->get_effective_anisotropic_degree(); - Texture::FilterType ft = tex->get_effective_magfilter(); + uint aniso_degree = sampler.get_effective_anisotropic_degree(); + SamplerState::FilterType ft = sampler.get_effective_magfilter(); if (aniso_degree >= 1) { set_sampler_state(i, D3DSAMP_MAXANISOTROPY, aniso_degree); @@ -266,7 +257,7 @@ apply_texture(int i, TextureContext *tc) { supports_anisotropic_mag_filter = (_screen -> _d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0; if (aniso_degree <= 1 || supports_anisotropic_mag_filter == 0) { - new_mag_filter = ((ft != Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT); + new_mag_filter = ((ft != SamplerState::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT); } else { new_mag_filter = D3DTEXF_ANISOTROPIC; } @@ -276,12 +267,12 @@ apply_texture(int i, TextureContext *tc) { if (hr != D3D_OK) { dxgsg9_cat.error() << "ERROR: set_sampler_state (D3DSAMP_MAGFILTER, " - << new_mag_filter << ") failed for texture:" << tex -> get_name() << endl; + << new_mag_filter << ") failed for sampler: " << sampler << endl; } // map Panda composite min+mip filter types to d3d's separate min & mip filter types - D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(tex->get_effective_minfilter()); - D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(tex->get_effective_minfilter()); + D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(sampler.get_effective_minfilter()); + D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(sampler.get_effective_minfilter()); if (!tex->might_have_ram_image()) { // If the texture is completely dynamic, don't try to issue @@ -3734,12 +3725,13 @@ update_standard_texture_bindings() { Texture *texture = _target_texture->get_on_texture(stage); nassertv(texture != (Texture *)NULL); + const SamplerState &sampler = _target_texture->get_on_sampler(stage); // We always reissue every stage in DX, just in case the texcoord // index or texgen mode or some other property has changed. int view = get_current_tex_view_offset() + stage->get_tex_view_offset(); TextureContext *tc = texture->prepare_now(view, _prepared_objects, this); - apply_texture(si, tc); + apply_texture(si, tc, sampler); set_texture_blend_mode(si, stage); int texcoord_dimensions = 2; @@ -4936,28 +4928,28 @@ copy_pres_reset(DXScreenData *screen) { // Description: //////////////////////////////////////////////////////////////////// D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9:: -get_d3d_min_type(Texture::FilterType filter_type) { +get_d3d_min_type(SamplerState::FilterType filter_type) { switch (filter_type) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: return D3DTEXF_POINT; - case Texture::FT_linear: + case SamplerState::FT_linear: return D3DTEXF_LINEAR; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: return D3DTEXF_POINT; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: return D3DTEXF_LINEAR; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: return D3DTEXF_POINT; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return D3DTEXF_LINEAR; - case Texture::FT_shadow: - case Texture::FT_default: + case SamplerState::FT_shadow: + case SamplerState::FT_default: return D3DTEXF_LINEAR; } @@ -4972,28 +4964,28 @@ get_d3d_min_type(Texture::FilterType filter_type) { // Description: //////////////////////////////////////////////////////////////////// D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9:: -get_d3d_mip_type(Texture::FilterType filter_type) { +get_d3d_mip_type(SamplerState::FilterType filter_type) { switch (filter_type) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: return D3DTEXF_NONE; - case Texture::FT_linear: + case SamplerState::FT_linear: return D3DTEXF_NONE; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: return D3DTEXF_POINT; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: return D3DTEXF_POINT; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: return D3DTEXF_LINEAR; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return D3DTEXF_LINEAR; - case Texture::FT_shadow: - case Texture::FT_default: + case SamplerState::FT_shadow: + case SamplerState::FT_default: return D3DTEXF_NONE; } diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 0eae7eaa71..caa8e91769 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -22,6 +22,7 @@ #include "graphicsStateGuardian.h" #include "texture.h" +#include "samplerState.h" #include "displayRegion.h" #include "material.h" #include "depthTestAttrib.h" @@ -67,7 +68,7 @@ public: DWORD multisampletype, DWORD multisamplequality); virtual TextureContext *prepare_texture(Texture *tex, int view); - void apply_texture(int i, TextureContext *tc); + void apply_texture(int i, TextureContext *tc, const SamplerState &sampler); virtual bool update_texture(TextureContext *tc, bool force); bool upload_texture(DXTextureContext9 *dtc, bool force); virtual void release_texture(TextureContext *tc); @@ -217,7 +218,7 @@ protected: void update_standard_texture_bindings(); protected: - INLINE static D3DTEXTUREADDRESS get_texture_wrap_mode(Texture::WrapMode wm); + INLINE static D3DTEXTUREADDRESS get_texture_wrap_mode(SamplerState::WrapMode wm); INLINE static D3DFOGMODE get_fog_mode_type(Fog::Mode m); const D3DCOLORVALUE &get_light_color(Light *light) const; INLINE static D3DTRANSFORMSTATETYPE get_tex_mat_sym(int stage_index); @@ -242,8 +243,8 @@ protected: bool release_swap_chain (DXScreenData *new_context); void copy_pres_reset(DXScreenData *new_context); - static D3DTEXTUREFILTERTYPE get_d3d_min_type(Texture::FilterType filter_type); - static D3DTEXTUREFILTERTYPE get_d3d_mip_type(Texture::FilterType filter_type); + static D3DTEXTUREFILTERTYPE get_d3d_min_type(SamplerState::FilterType filter_type); + static D3DTEXTUREFILTERTYPE get_d3d_mip_type(SamplerState::FilterType filter_type); static D3DTEXTUREOP get_texture_operation(TextureStage::CombineMode mode, int scale); DWORD get_texture_argument(TextureStage::CombineSource source, TextureStage::CombineOperand operand) const; diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index a38e176418..426e31a366 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -48,27 +48,27 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) { #ifdef HAVE_CG _cg_context = 0; if (s->get_language() == Shader::SL_Cg) { - - // Ask the shader to compile itself for us and + + // Ask the shader to compile itself for us and // to give us the resulting Cg program objects. if (!s->cg_compile_for(gsg->_shader_caps, _cg_context, _cg_vprogram, - _cg_fprogram, + _cg_fprogram, _cg_gprogram, // CG2 CHANGE _cg_parameter_map)) { return; } - + // Load the program. BOOL paramater_shadowing; DWORD assembly_flags; - + paramater_shadowing = FALSE; assembly_flags = 0; - + #if DEBUG_SHADER assembly_flags |= D3DXSHADER_DEBUG; #endif @@ -80,26 +80,26 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) { dxgsg9_cat.error() << "vertex shader cgD3D9LoadProgram failed " << D3DERRORSTRING(hr); - + CGerror error = cgGetError(); if (error != CG_NO_ERROR) { dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; } success = false; } - + hr = cgD3D9LoadProgram(_cg_fprogram, paramater_shadowing, assembly_flags); if (FAILED (hr)) { dxgsg9_cat.error() << "pixel shader cgD3D9LoadProgram failed " << D3DERRORSTRING(hr); - + CGerror error = cgGetError(); if (error != CG_NO_ERROR) { dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; } success = false; - } + } // BEGIN CG2 CHANGE if (_cg_gprogram != 0) @@ -150,7 +150,7 @@ CLP(ShaderContext):: // { // int state; // int file_handle; -// +// // state = false; // file_handle = _open (file_path, _O_CREAT | _O_RDWR | _O_TRUNC, _S_IREAD | _S_IWRITE); // if (file_handle != -1) { @@ -159,36 +159,36 @@ CLP(ShaderContext):: // } // _close (file_handle); // } -// +// // return state; // } -// +// // if (dxgsg9_cat.is_debug()) { // // DEBUG: output the generated program // const char *vertex_program; // const char *pixel_program; -// +// // vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM); // pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM); -// +// // dxgsg9_cat.debug() << vertex_program << "\n"; // dxgsg9_cat.debug() << pixel_program << "\n"; -// +// // // save the generated program to a file // int size; // char file_path [512]; -// +// // char drive[_MAX_DRIVE]; // char dir[_MAX_DIR]; // char fname[_MAX_FNAME]; // char ext[_MAX_EXT]; -// +// // _splitpath (_name.c_str ( ), drive, dir, fname, ext); -// +// // size = strlen (vertex_program); // sprintf (file_path, "%s.vasm", fname); // save_file (size, (void *) vertex_program, file_path); -// +// // size = strlen (pixel_program); // sprintf (file_path, "%s.pasm", fname); // save_file (size, (void *) pixel_program, file_path); @@ -234,36 +234,36 @@ bind(GSG *gsg) { #ifdef HAVE_CG if (_cg_context) { // clear the last cached FVF to make sure the next SetFVF call goes through - + gsg -> _last_fvf = 0; // Pass in k-parameters and transform-parameters issue_parameters(gsg, Shader::SSD_general); - + HRESULT hr; - + // Bind the shaders. bind_state = true; hr = cgD3D9BindProgram(_cg_vprogram); if (FAILED (hr)) { dxgsg9_cat.error() << "cgD3D9BindProgram vertex shader failed " << D3DERRORSTRING(hr); - + CGerror error = cgGetError(); if (error != CG_NO_ERROR) { dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; } - + bind_state = false; } hr = cgD3D9BindProgram(_cg_fprogram); if (FAILED (hr)) { dxgsg9_cat.error() << "cgD3D9BindProgram pixel shader failed " << D3DERRORSTRING(hr); - + CGerror error = cgGetError(); if (error != CG_NO_ERROR) { dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; } - + bind_state = false; } @@ -349,25 +349,25 @@ issue_parameters(GSG *gsg, int altered) if(altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])){ #ifdef HAVE_CG const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i]; - Shader::ShaderPtrData* _ptr_data = + Shader::ShaderPtrData* _ptr_data = const_cast< Shader::ShaderPtrData*>(gsg->fetch_ptr_parameter(_ptr)); - + if (_ptr_data == NULL){ //the input is not contained in ShaderPtrData release_resources(); return; } CGparameter p = _cg_parameter_map[_ptr._id._seqno]; - + switch(_ptr_data->_type) { case Shader::SPT_float: - cgD3D9SetUniform(p, (PN_stdfloat*)_ptr_data->_ptr); + cgD3D9SetUniform(p, (PN_stdfloat*)_ptr_data->_ptr); break; - default: - dxgsg9_cat.error() - << _ptr._id._name << ":" << "unrecognized parameter type\n"; - release_resources(); + default: + dxgsg9_cat.error() + << _ptr._id._name << ":" << "unrecognized parameter type\n"; + release_resources(); return; } } @@ -379,7 +379,7 @@ issue_parameters(GSG *gsg, int altered) CGparameter p = _cg_parameter_map[_shader->_mat_spec[i]._id._seqno]; if (p == NULL) { continue; - } + } const LMatrix4 *val = gsg->fetch_specified_value(_shader->_mat_spec[i], altered); if (val) { HRESULT hr; @@ -588,7 +588,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, bool force) { dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n"; continue; } - + // If not associated with the array we're working on, move on. if ( param_array_reader != array_reader ) { continue; @@ -768,7 +768,7 @@ disable_shader_texture_bindings(GSG *gsg) CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno]; if (p == NULL) { continue; - } + } int texunit = cgGetParameterResourceIndex(p); HRESULT hr; @@ -809,13 +809,17 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno]; if (p == NULL) { continue; - } - Texture *tex = 0; + } + Texture *tex = NULL; int view = gsg->get_current_tex_view_offset(); InternalName *id = _shader->_tex_spec[i]._name; - if (id != 0) { + SamplerState sampler; + + if (id != NULL) { const ShaderInput *input = gsg->_target_shader->get_shader_input(id); tex = input->get_texture(); + sampler = input->get_sampler(); + } else { // We get the TextureAttrib directly from the _target_rs, not the // filtered TextureAttrib in _target_texture. @@ -827,6 +831,7 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) } TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage); tex = texattrib->get_on_texture(stage); + sampler = texattrib->get_on_sampler(stage); view += stage->get_tex_view_offset(); } if (_shader->_tex_spec[i]._suffix != 0) { @@ -843,10 +848,10 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) if (tc == (TextureContext*)NULL) { continue; } - + int texunit = cgGetParameterResourceIndex(p); - - gsg->apply_texture(texunit, tc); + + gsg->apply_texture(texunit, tc, sampler); } } #endif diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index 9c56089393..1118655342 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -645,21 +645,21 @@ create_texture(DXScreenData &scrn) { // validate magfilter setting // degrade filtering if no HW support - Texture::FilterType ft; + SamplerState::FilterType ft; ft = tex->get_magfilter(); - if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) { + if ((ft != SamplerState::FT_linear) && ft != SamplerState::FT_nearest) { // mipmap settings make no sense for magfilter - if (ft == Texture::FT_nearest_mipmap_nearest) { - ft = Texture::FT_nearest; + if (ft == SamplerState::FT_nearest_mipmap_nearest) { + ft = SamplerState::FT_nearest; } else { - ft = Texture::FT_linear; + ft = SamplerState::FT_linear; } } - if (ft == Texture::FT_linear && + if (ft == SamplerState::FT_linear && (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) { - ft = Texture::FT_nearest; + ft = SamplerState::FT_nearest; } tex->set_magfilter(ft); @@ -669,33 +669,33 @@ create_texture(DXScreenData &scrn) { if (!dx_ignore_mipmaps) { // set if no HW mipmap capable switch(ft) { - case Texture::FT_nearest_mipmap_nearest: - case Texture::FT_linear_mipmap_nearest: - case Texture::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_nearest_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them + case SamplerState::FT_linear_mipmap_linear: _has_mipmaps = true; } if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost _has_mipmaps = true; if (dxgsg9_cat.is_spam()) { - if (ft != Texture::FT_linear_mipmap_linear) { + if (ft != SamplerState::FT_linear_mipmap_linear) { dxgsg9_cat.spam() << "Forcing trilinear mipmapping on DX texture [" << tex->get_name() << "]\n"; } } - ft = Texture::FT_linear_mipmap_linear; + ft = SamplerState::FT_linear_mipmap_linear; tex->set_minfilter(ft); } - } else if ((ft == Texture::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types - (ft == Texture::FT_nearest_mipmap_linear)) { - ft = Texture::FT_nearest; + } else if ((ft == SamplerState::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types + (ft == SamplerState::FT_nearest_mipmap_linear)) { + ft = SamplerState::FT_nearest; - } else if ((ft == Texture::FT_linear_mipmap_nearest) || - (ft == Texture::FT_linear_mipmap_linear)) { - ft = Texture::FT_linear; + } else if ((ft == SamplerState::FT_linear_mipmap_nearest) || + (ft == SamplerState::FT_linear_mipmap_linear)) { + ft = SamplerState::FT_linear; } nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false); @@ -704,36 +704,36 @@ create_texture(DXScreenData &scrn) { // do any other filter type degradations necessary switch(ft) { - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) { if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) { - ft = Texture::FT_linear_mipmap_nearest; + ft = SamplerState::FT_linear_mipmap_nearest; } else { // if you cant do linear in a level, you probably cant do // linear b/w levels, so just do nearest-all - ft = Texture::FT_nearest_mipmap_nearest; + ft = SamplerState::FT_nearest_mipmap_nearest; } } break; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: // if we don't have bilinear, do nearest_nearest if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) && (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) { - ft = Texture::FT_nearest_mipmap_nearest; + ft = SamplerState::FT_nearest_mipmap_nearest; } break; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: // if we don't have mip linear, do nearest_nearest if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) { - ft = Texture::FT_nearest_mipmap_nearest; + ft = SamplerState::FT_nearest_mipmap_nearest; } break; - case Texture::FT_linear: + case SamplerState::FT_linear: if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) { - ft = Texture::FT_nearest; + ft = SamplerState::FT_nearest; } break; } diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 61ec7f4401..a88792cfb2 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -1108,16 +1108,16 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { switch (egg_tex->get_minfilter()) { case EggTexture::FT_nearest: - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); break; case EggTexture::FT_linear: if (egg_ignore_filters) { egg2pg_cat.warning() << "Ignoring minfilter request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else { - tex->set_minfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); } break; @@ -1125,13 +1125,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { if (egg_ignore_filters) { egg2pg_cat.warning() << "Ignoring minfilter request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else if (egg_ignore_mipmaps) { egg2pg_cat.warning() << "Ignoring mipmap request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else { - tex->set_minfilter(Texture::FT_nearest_mipmap_nearest); + tex->set_minfilter(SamplerState::FT_nearest_mipmap_nearest); } break; @@ -1139,13 +1139,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { if (egg_ignore_filters) { egg2pg_cat.warning() << "Ignoring minfilter request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else if (egg_ignore_mipmaps) { egg2pg_cat.warning() << "Ignoring mipmap request\n"; - tex->set_minfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); } else { - tex->set_minfilter(Texture::FT_linear_mipmap_nearest); + tex->set_minfilter(SamplerState::FT_linear_mipmap_nearest); } break; @@ -1153,13 +1153,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { if (egg_ignore_filters) { egg2pg_cat.warning() << "Ignoring minfilter request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else if (egg_ignore_mipmaps) { egg2pg_cat.warning() << "Ignoring mipmap request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else { - tex->set_minfilter(Texture::FT_nearest_mipmap_linear); + tex->set_minfilter(SamplerState::FT_nearest_mipmap_linear); } break; @@ -1167,13 +1167,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { if (egg_ignore_filters) { egg2pg_cat.warning() << "Ignoring minfilter request\n"; - tex->set_minfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); } else if (egg_ignore_mipmaps) { egg2pg_cat.warning() << "Ignoring mipmap request\n"; - tex->set_minfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); } else { - tex->set_minfilter(Texture::FT_linear_mipmap_linear); + tex->set_minfilter(SamplerState::FT_linear_mipmap_linear); } break; @@ -1185,7 +1185,7 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { case EggTexture::FT_nearest: case EggTexture::FT_nearest_mipmap_nearest: case EggTexture::FT_nearest_mipmap_linear: - tex->set_magfilter(Texture::FT_nearest); + tex->set_magfilter(SamplerState::FT_nearest); break; case EggTexture::FT_linear: @@ -1194,9 +1194,9 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { if (egg_ignore_filters) { egg2pg_cat.warning() << "Ignoring magfilter request\n"; - tex->set_magfilter(Texture::FT_nearest); + tex->set_magfilter(SamplerState::FT_nearest); } else { - tex->set_magfilter(Texture::FT_linear); + tex->set_magfilter(SamplerState::FT_linear); } break; @@ -1397,35 +1397,35 @@ convert_compression_mode(EggTexture::CompressionMode compression_mode) const { //////////////////////////////////////////////////////////////////// // Function: EggLoader::convert_wrap_mode // Access: Private -// Description: Returns the Texture::WrapMode enum corresponding to +// Description: Returns the SamplerState::WrapMode enum corresponding to // the EggTexture::WrapMode. Returns WM_repeat if the // wrap mode is unspecified. //////////////////////////////////////////////////////////////////// -Texture::WrapMode EggLoader:: +SamplerState::WrapMode EggLoader:: convert_wrap_mode(EggTexture::WrapMode wrap_mode) const { switch (wrap_mode) { case EggTexture::WM_clamp: - return Texture::WM_clamp; + return SamplerState::WM_clamp; case EggTexture::WM_repeat: - return Texture::WM_repeat; + return SamplerState::WM_repeat; case EggTexture::WM_mirror: - return Texture::WM_mirror; + return SamplerState::WM_mirror; case EggTexture::WM_mirror_once: - return Texture::WM_mirror_once; + return SamplerState::WM_mirror_once; case EggTexture::WM_border_color: - return Texture::WM_border_color; + return SamplerState::WM_border_color; case EggTexture::WM_unspecified: - return Texture::WM_repeat; + return SamplerState::WM_repeat; } egg2pg_cat.warning() << "Unexpected texture wrap flag: " << (int)wrap_mode << "\n"; - return Texture::WM_repeat; + return SamplerState::WM_repeat; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/egg2pg/eggLoader.h b/panda/src/egg2pg/eggLoader.h index a691098073..19a4c01782 100644 --- a/panda/src/egg2pg/eggLoader.h +++ b/panda/src/egg2pg/eggLoader.h @@ -123,7 +123,7 @@ private: bool load_texture(TextureDef &def, EggTexture *egg_tex); void apply_texture_attributes(Texture *tex, const EggTexture *egg_tex); Texture::CompressionMode convert_compression_mode(EggTexture::CompressionMode compression_mode) const; - Texture::WrapMode convert_wrap_mode(EggTexture::WrapMode wrap_mode) const; + SamplerState::WrapMode convert_wrap_mode(EggTexture::WrapMode wrap_mode) const; PT(TextureStage) make_texture_stage(const EggTexture *egg_tex); void separate_switches(EggNode *egg_node); diff --git a/panda/src/egg2pg/eggSaver.cxx b/panda/src/egg2pg/eggSaver.cxx index f4ad7beed6..83f0d2aaeb 100755 --- a/panda/src/egg2pg/eggSaver.cxx +++ b/panda/src/egg2pg/eggSaver.cxx @@ -965,22 +965,22 @@ get_egg_texture(Texture *tex) { } switch (tex->get_minfilter()) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: temp.set_minfilter(EggTexture::FT_nearest); break; - case Texture::FT_linear: + case SamplerState::FT_linear: temp.set_minfilter(EggTexture::FT_linear); break; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: temp.set_minfilter(EggTexture::FT_nearest_mipmap_nearest); break; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: temp.set_minfilter(EggTexture::FT_linear_mipmap_nearest); break; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: temp.set_minfilter(EggTexture::FT_nearest_mipmap_linear); break; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: temp.set_minfilter(EggTexture::FT_linear_mipmap_linear); break; @@ -989,10 +989,10 @@ get_egg_texture(Texture *tex) { } switch (tex->get_magfilter()) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: temp.set_magfilter(EggTexture::FT_nearest); break; - case Texture::FT_linear: + case SamplerState::FT_linear: temp.set_magfilter(EggTexture::FT_linear); break; @@ -1001,10 +1001,10 @@ get_egg_texture(Texture *tex) { } switch (tex->get_wrap_u()) { - case Texture::WM_clamp: + case SamplerState::WM_clamp: temp.set_wrap_u(EggTexture::WM_clamp); break; - case Texture::WM_repeat: + case SamplerState::WM_repeat: temp.set_wrap_u(EggTexture::WM_repeat); break; @@ -1015,10 +1015,10 @@ get_egg_texture(Texture *tex) { } switch (tex->get_wrap_v()) { - case Texture::WM_clamp: + case SamplerState::WM_clamp: temp.set_wrap_v(EggTexture::WM_clamp); break; - case Texture::WM_repeat: + case SamplerState::WM_repeat: temp.set_wrap_v(EggTexture::WM_repeat); break; diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 3cc0cc1f76..5a8ca1b6b7 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -710,8 +710,8 @@ load_default_model(const NodePath &parent) { PT(Texture) tex = new Texture; tex->set_name("rock-floor.rgb"); tex->load(rock_floor_pnm); - tex->set_minfilter(Texture::FT_linear); - tex->set_magfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); + tex->set_magfilter(SamplerState::FT_linear); state = state->add_attrib(TextureAttrib::make(tex)); } @@ -1257,8 +1257,8 @@ load_image_as_model(const Filename &filename) { } // Yes, it is an image file; make a texture out of it. - tex->set_minfilter(Texture::FT_linear_mipmap_linear); - tex->set_magfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear_mipmap_linear); + tex->set_magfilter(SamplerState::FT_linear); // Ok, now make a polygon to show the texture. bool has_alpha = true; diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 581e857d18..c73659eda9 100755 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -570,19 +570,25 @@ update_shader_texture_bindings(ShaderContext *prev) { } int texunit = cgGetParameterResourceIndex(p); - Texture *tex = 0; + Texture *tex = NULL; int view = _glgsg->get_current_tex_view_offset(); - if (id != 0) { + SamplerState sampler; + + if (id != NULL) { const ShaderInput *input = _glgsg->_target_shader->get_shader_input(id); tex = input->get_texture(); + sampler = input->get_sampler(); + } else { if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) { continue; } TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage); tex = texattrib->get_on_texture(stage); + sampler = texattrib->get_on_sampler(stage); view += stage->get_tex_view_offset(); } + if (_shader->_tex_spec[i]._suffix != 0) { // The suffix feature is inefficient. It is a temporary hack. if (tex == 0) { @@ -612,6 +618,7 @@ update_shader_texture_bindings(ShaderContext *prev) { } _glgsg->apply_texture(tc); + _glgsg->apply_sampler(i, sampler, tc); } cg_report_errors(); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index cdd186cef4..64e56f19ef 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -64,6 +64,7 @@ #include "stencilAttrib.h" #include "graphicsEngine.h" #include "shaderGenerator.h" +#include "samplerState.h" #if defined(HAVE_CG) && !defined(OPENGLES) #include "Cg/cgGL.h" @@ -1870,6 +1871,28 @@ reset() { _glMemoryBarrier = NULL; } + _supports_sampler_objects = false; + if (gl_support_sampler_objects && + ((is_at_least_gl_version(3, 3) || has_extension("GL_ARB_sampler_objects")))) { + _glGenSamplers = (PFNGLGENSAMPLERSPROC) get_extension_func("glGenSamplers"); + _glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) get_extension_func("glDeleteSamplers"); + _glBindSampler = (PFNGLBINDSAMPLERPROC) get_extension_func("glBindSampler"); + _glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) get_extension_func("glSamplerParameteri"); + _glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) get_extension_func("glSamplerParameteriv"); + _glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) get_extension_func("glSamplerParameterf"); + _glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) get_extension_func("glSamplerParameterfv"); + + if (_glGenSamplers == NULL || _glDeleteSamplers == NULL || + _glBindSampler == NULL || _glSamplerParameteri == NULL || + _glSamplerParameteriv == NULL || _glSamplerParameterf == NULL || + _glSamplerParameterfv == NULL) { + GLCAT.warning() + << "GL_ARB_sampler_objects advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n"; + } else { + _supports_sampler_objects = true; + } + } + // Check availability of multi-bind functions. _supports_multi_bind = false; if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_multi_bind")) { @@ -1878,6 +1901,11 @@ reset() { _glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC) get_extension_func("glBindImageTextures"); + if (_supports_sampler_objects) { + _glBindSamplers = (PFNGLBINDSAMPLERSPROC) + get_extension_func("glBindSamplers"); + } + if (_glBindTextures != NULL && _glBindImageTextures != NULL) { _supports_multi_bind = true; } else { @@ -1900,6 +1928,8 @@ reset() { if (has_extension("GL_ARB_bindless_texture")) { _glGetTextureHandle = (PFNGLGETTEXTUREHANDLEPROC) get_extension_func("glGetTextureHandleARB"); + _glGetTextureSamplerHandle = (PFNGLGETTEXTURESAMPLERHANDLEPROC) + get_extension_func("glGetTextureSamplerHandleARB"); _glMakeTextureHandleResident = (PFNGLMAKETEXTUREHANDLERESIDENTPROC) get_extension_func("glMakeTextureHandleResidentARB"); _glUniformHandleui64 = (PFNGLUNIFORMHANDLEUI64PROC) @@ -2200,7 +2230,6 @@ reset() { add_gsg(this); } - //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::finish // Access: Public, Virtual @@ -2517,6 +2546,12 @@ clear_before_callback() { // texture stage is still set to stage 0. CEGUI, in particular, // makes this assumption. _glActiveTexture(GL_TEXTURE0); + + // Clear the bound sampler object, so that we do not inadvertently + // override the callback's desired sampler settings. + if (_supports_sampler_objects) { + _glBindSampler(0, 0); + } } //////////////////////////////////////////////////////////////////// @@ -4234,7 +4269,8 @@ update_texture(TextureContext *tc, bool force) { // If the texture image was modified, reload the texture. apply_texture(tc); if (gtc->was_properties_modified()) { - specify_texture(gtc); + Texture *tex = tc->get_texture(); + specify_texture(gtc, tex->get_default_sampler()); } bool okflag = upload_texture(gtc, force); if (!okflag) { @@ -4249,13 +4285,15 @@ update_texture(TextureContext *tc, bool force) { // If only the properties have been modified, we don't necessarily // need to reload the texture. apply_texture(tc); - if (specify_texture(gtc)) { + + Texture *tex = tc->get_texture(); + if (specify_texture(gtc, tex->get_default_sampler())) { // Actually, looks like the texture *does* need to be reloaded. gtc->mark_needs_reload(); bool okflag = upload_texture(gtc, force); if (!okflag) { GLCAT.error() - << "Could not load " << *gtc->get_texture() << "\n"; + << "Could not load " << *tex << "\n"; return false; } @@ -4318,6 +4356,109 @@ extract_texture_data(Texture *tex) { return success; } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::prepare_sampler +// Access: Public, Virtual +// Description: Creates whatever structures the GSG requires to +// represent the sampler state internally, and returns a +// newly-allocated SamplerContext object with this data. +// It is the responsibility of the calling function to +// later call release_sampler() with this same pointer +// (which will also delete the pointer). +// +// This function should not be called directly to +// prepare a sampler object. Instead, call +// SamplerState::prepare(). +//////////////////////////////////////////////////////////////////// +SamplerContext *CLP(GraphicsStateGuardian):: +prepare_sampler(const SamplerState &sampler) { +#ifndef OPENGLES + nassertr(_supports_sampler_objects, NULL); + PStatGPUTimer timer(this, _prepare_sampler_pcollector); + + CLP(SamplerContext) *gsc = new CLP(SamplerContext)(this, sampler); + GLuint index = gsc->_index; + + // Sampler contexts are immutable in Panda, so might as well just + // initialize all the settings here. + _glSamplerParameteri(index, GL_TEXTURE_WRAP_S, + get_texture_wrap_mode(sampler.get_wrap_u())); + _glSamplerParameteri(index, GL_TEXTURE_WRAP_T, + get_texture_wrap_mode(sampler.get_wrap_v())); + _glSamplerParameteri(index, GL_TEXTURE_WRAP_R, + get_texture_wrap_mode(sampler.get_wrap_w())); + +#ifdef STDFLOAT_DOUBLE + LVecBase4f fvalue = LCAST(float, sampler.get_border_color()); + _glSamplerParameterfv(index, GL_TEXTURE_BORDER_COLOR, fvalue.get_data()); +#else + _glSamplerParameterfv(index, GL_TEXTURE_BORDER_COLOR, + sampler.get_border_color().get_data()); +#endif + + SamplerState::FilterType minfilter = sampler.get_effective_minfilter(); + SamplerState::FilterType magfilter = sampler.get_effective_magfilter(); + bool uses_mipmaps = Texture::is_mipmap(minfilter) && !gl_ignore_mipmaps; + +#ifndef NDEBUG + if (gl_force_mipmaps) { + minfilter = SamplerState::FT_linear_mipmap_linear; + magfilter = SamplerState::FT_linear; + uses_mipmaps = true; + } +#endif + + _glSamplerParameteri(index, GL_TEXTURE_MIN_FILTER, + get_texture_filter_type(minfilter, !uses_mipmaps)); + _glSamplerParameteri(index, GL_TEXTURE_MAG_FILTER, + get_texture_filter_type(magfilter, true)); + + // Set anisotropic filtering. + if (_supports_anisotropy) { + PN_stdfloat anisotropy = sampler.get_effective_anisotropic_degree(); + anisotropy = min(anisotropy, _max_anisotropy); + anisotropy = max(anisotropy, (PN_stdfloat)1.0); + _glSamplerParameterf(index, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + } + + if (_supports_shadow_filter) { + if ((sampler.get_magfilter() == SamplerState::FT_shadow) || + (sampler.get_minfilter() == SamplerState::FT_shadow)) { + _glSamplerParameteri(index, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + _glSamplerParameteri(index, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + } else { + _glSamplerParameteri(index, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + _glSamplerParameteri(index, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + } + } + + _glSamplerParameterf(index, GL_TEXTURE_MIN_LOD, sampler.get_min_lod()); + _glSamplerParameterf(index, GL_TEXTURE_MAX_LOD, sampler.get_max_lod()); + _glSamplerParameterf(index, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias()); + + gsc->enqueue_lru(&_prepared_objects->_sampler_object_lru); + + report_my_gl_errors(); + return gsc; + +#else + return NULL; +#endif // OPENGLES +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::release_sampler +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// sampler. This function should never be called +// directly; instead, call SamplerState::release(). +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +release_sampler(SamplerContext *sc) { + CLP(SamplerContext) *gsc = DCAST(CLP(SamplerContext), sc); + delete gsc; +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::prepare_geom // Access: Public, Virtual @@ -5095,7 +5236,7 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z, CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); apply_texture(gtc); - bool needs_reload = specify_texture(gtc); + bool needs_reload = specify_texture(gtc, tex->get_default_sampler()); GLenum target = get_texture_target(tex->get_texture_type()); GLint internal_format = get_internal_image_format(tex); @@ -6964,30 +7105,30 @@ get_texture_target(Texture::TextureType texture_type) const { // GL's. //////////////////////////////////////////////////////////////////// GLenum CLP(GraphicsStateGuardian):: -get_texture_wrap_mode(Texture::WrapMode wm) const { +get_texture_wrap_mode(SamplerState::WrapMode wm) const { if (gl_ignore_clamp) { return GL_REPEAT; } switch (wm) { - case Texture::WM_clamp: + case SamplerState::WM_clamp: return _edge_clamp; - case Texture::WM_repeat: + case SamplerState::WM_repeat: return GL_REPEAT; - case Texture::WM_mirror: + case SamplerState::WM_mirror: return _mirror_repeat; - case Texture::WM_mirror_once: + case SamplerState::WM_mirror_once: return _mirror_border_clamp; - case Texture::WM_border_color: + case SamplerState::WM_border_color: return _border_clamp; - case Texture::WM_invalid: + case SamplerState::WM_invalid: break; } - GLCAT.error() << "Invalid Texture::WrapMode value!\n"; + GLCAT.error() << "Invalid SamplerState::WrapMode value!\n"; return _edge_clamp; } @@ -6997,34 +7138,34 @@ get_texture_wrap_mode(Texture::WrapMode wm) const { // Description: Maps from the GL's internal wrap mode symbols to // Panda's. //////////////////////////////////////////////////////////////////// -Texture::WrapMode CLP(GraphicsStateGuardian):: +SamplerState::WrapMode CLP(GraphicsStateGuardian):: get_panda_wrap_mode(GLenum wm) { switch (wm) { #ifndef OPENGLES case GL_CLAMP: #endif case GL_CLAMP_TO_EDGE: - return Texture::WM_clamp; + return SamplerState::WM_clamp; #ifndef OPENGLES case GL_CLAMP_TO_BORDER: - return Texture::WM_border_color; + return SamplerState::WM_border_color; #endif case GL_REPEAT: - return Texture::WM_repeat; + return SamplerState::WM_repeat; #ifndef OPENGLES case GL_MIRROR_CLAMP_EXT: case GL_MIRROR_CLAMP_TO_EDGE_EXT: - return Texture::WM_mirror; + return SamplerState::WM_mirror; case GL_MIRROR_CLAMP_TO_BORDER_EXT: - return Texture::WM_mirror_once; + return SamplerState::WM_mirror_once; #endif } GLCAT.error() << "Unexpected GL wrap mode " << (int)wm << "\n"; - return Texture::WM_clamp; + return SamplerState::WM_clamp; } //////////////////////////////////////////////////////////////////// @@ -7034,49 +7175,49 @@ get_panda_wrap_mode(GLenum wm) { // to GL's. //////////////////////////////////////////////////////////////////// GLenum CLP(GraphicsStateGuardian):: -get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) { +get_texture_filter_type(SamplerState::FilterType ft, bool ignore_mipmaps) { if (gl_ignore_filters) { return GL_NEAREST; } else if (ignore_mipmaps) { switch (ft) { - case Texture::FT_nearest_mipmap_nearest: - case Texture::FT_nearest: + case SamplerState::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest: return GL_NEAREST; - case Texture::FT_linear: - case Texture::FT_linear_mipmap_nearest: - case Texture::FT_nearest_mipmap_linear: - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear: + case SamplerState::FT_linear_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return GL_LINEAR; - case Texture::FT_shadow: + case SamplerState::FT_shadow: return GL_LINEAR; - case Texture::FT_default: - case Texture::FT_invalid: + case SamplerState::FT_default: + case SamplerState::FT_invalid: break; } } else { switch (ft) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: return GL_NEAREST; - case Texture::FT_linear: + case SamplerState::FT_linear: return GL_LINEAR; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: return GL_NEAREST_MIPMAP_NEAREST; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: return GL_LINEAR_MIPMAP_NEAREST; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: return GL_NEAREST_MIPMAP_LINEAR; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return GL_LINEAR_MIPMAP_LINEAR; - case Texture::FT_shadow: + case SamplerState::FT_shadow: return GL_LINEAR; - case Texture::FT_default: - case Texture::FT_invalid: + case SamplerState::FT_default: + case SamplerState::FT_invalid: break; } } - GLCAT.error() << "Invalid Texture::FilterType value!\n"; + GLCAT.error() << "Invalid SamplerState::FilterType value!\n"; return GL_NEAREST; } @@ -7086,24 +7227,24 @@ get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) { // Description: Maps from the GL's internal filter type symbols // to Panda's. //////////////////////////////////////////////////////////////////// -Texture::FilterType CLP(GraphicsStateGuardian):: +SamplerState::FilterType CLP(GraphicsStateGuardian):: get_panda_filter_type(GLenum ft) { switch (ft) { case GL_NEAREST: - return Texture::FT_nearest; + return SamplerState::FT_nearest; case GL_LINEAR: - return Texture::FT_linear; + return SamplerState::FT_linear; case GL_NEAREST_MIPMAP_NEAREST: - return Texture::FT_nearest_mipmap_nearest; + return SamplerState::FT_nearest_mipmap_nearest; case GL_LINEAR_MIPMAP_NEAREST: - return Texture::FT_linear_mipmap_nearest; + return SamplerState::FT_linear_mipmap_nearest; case GL_NEAREST_MIPMAP_LINEAR: - return Texture::FT_nearest_mipmap_linear; + return SamplerState::FT_nearest_mipmap_linear; case GL_LINEAR_MIPMAP_LINEAR: - return Texture::FT_linear_mipmap_linear; + return SamplerState::FT_linear_mipmap_linear; } GLCAT.error() << "Unexpected GL filter type " << (int)ft << "\n"; - return Texture::FT_linear; + return SamplerState::FT_linear; } //////////////////////////////////////////////////////////////////// @@ -8972,6 +9113,7 @@ update_standard_texture_bindings() { continue; } apply_texture(tc); + apply_sampler(i, _target_texture->get_on_sampler(stage), tc); if (stage->involves_color_scale() && _color_scale_enabled) { LColor color = stage->get_color(); @@ -9651,10 +9793,11 @@ do_issue_tex_gen() { // Function: GLGraphicsStateGuardian::specify_texture // Access: Protected // Description: Specifies the texture parameters. Returns true if -// the texture may need to be reloaded. +// the texture may need to be reloaded. Pass non-NULL +// sampler argument to use different sampler settings. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: -specify_texture(CLP(TextureContext) *gtc) { +specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) { nassertr(gtc->_handle == 0 /* can't modify tex with active handle */, false); Texture *tex = gtc->get_texture(); @@ -9665,38 +9808,41 @@ specify_texture(CLP(TextureContext) *gtc) { return false; } + // Record the active sampler settings. + gtc->_active_sampler = sampler; + glTexParameteri(target, GL_TEXTURE_WRAP_S, - get_texture_wrap_mode(tex->get_wrap_u())); + get_texture_wrap_mode(sampler.get_wrap_u())); #ifndef OPENGLES if (target != GL_TEXTURE_1D) { glTexParameteri(target, GL_TEXTURE_WRAP_T, - get_texture_wrap_mode(tex->get_wrap_v())); + get_texture_wrap_mode(sampler.get_wrap_v())); } #endif #ifdef OPENGLES_2 if (target == GL_TEXTURE_3D_OES) { glTexParameteri(target, GL_TEXTURE_WRAP_R_OES, - get_texture_wrap_mode(tex->get_wrap_w())); + get_texture_wrap_mode(sampler.get_wrap_w())); } #endif #ifndef OPENGLES if (target == GL_TEXTURE_3D) { glTexParameteri(target, GL_TEXTURE_WRAP_R, - get_texture_wrap_mode(tex->get_wrap_w())); + get_texture_wrap_mode(sampler.get_wrap_w())); } - LColor border_color = tex->get_border_color(); + LColor border_color = sampler.get_border_color(); call_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border_color); #endif // OPENGLES - Texture::FilterType minfilter = tex->get_effective_minfilter(); - Texture::FilterType magfilter = tex->get_effective_magfilter(); + SamplerState::FilterType minfilter = sampler.get_effective_minfilter(); + SamplerState::FilterType magfilter = sampler.get_effective_magfilter(); bool uses_mipmaps = Texture::is_mipmap(minfilter) && !gl_ignore_mipmaps; #ifndef NDEBUG if (gl_force_mipmaps) { - minfilter = Texture::FT_linear_mipmap_linear; - magfilter = Texture::FT_linear; + minfilter = SamplerState::FT_linear_mipmap_linear; + magfilter = SamplerState::FT_linear; uses_mipmaps = true; } #endif @@ -9713,13 +9859,13 @@ specify_texture(CLP(TextureContext) *gtc) { } glTexParameteri(target, GL_TEXTURE_MIN_FILTER, - get_texture_filter_type(minfilter, !uses_mipmaps)); + get_texture_filter_type(minfilter, !uses_mipmaps)); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, - get_texture_filter_type(magfilter, true)); + get_texture_filter_type(magfilter, true)); // Set anisotropic filtering. if (_supports_anisotropy) { - PN_stdfloat anisotropy = tex->get_effective_anisotropic_degree(); + PN_stdfloat anisotropy = sampler.get_effective_anisotropic_degree(); anisotropy = min(anisotropy, _max_anisotropy); anisotropy = max(anisotropy, (PN_stdfloat)1.0); glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); @@ -9733,8 +9879,8 @@ specify_texture(CLP(TextureContext) *gtc) { tex->get_format() == Texture::F_depth_component32) { glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); if (_supports_shadow_filter) { - if ((tex->get_magfilter() == Texture::FT_shadow) || - (tex->get_minfilter() == Texture::FT_shadow)) { + if ((sampler.get_magfilter() == SamplerState::FT_shadow) || + (sampler.get_minfilter() == SamplerState::FT_shadow)) { glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); } else { @@ -9743,6 +9889,10 @@ specify_texture(CLP(TextureContext) *gtc) { } } } + + glTexParameterf(target, GL_TEXTURE_MIN_LOD, sampler.get_min_lod()); + glTexParameterf(target, GL_TEXTURE_MAX_LOD, sampler.get_max_lod()); + glTexParameterf(target, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias()); #endif report_my_gl_errors(); @@ -9785,6 +9935,51 @@ apply_texture(TextureContext *tc) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::apply_sampler +// Access: Protected +// Description: Updates OpenGL with the current information for this +// sampler, and makes it the current sampler available +// for rendering. Use NULL to unbind the sampler. +// +// If the GSG doesn't support sampler objects, the +// sampler settings are applied to the given texture +// context instead. +//////////////////////////////////////////////////////////////////// +bool CLP(GraphicsStateGuardian):: +apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { + if (_supports_sampler_objects) { + // We support sampler objects. Prepare the sampler object and + // bind it to the indicated texture unit. + SamplerContext *sc = sampler.prepare_now(get_prepared_objects(), this); + nassertr(sc != (SamplerContext *)NULL, false); + CLP(SamplerContext) *gsc = DCAST(CLP(SamplerContext), sc); + + gsc->enqueue_lru(&_prepared_objects->_sampler_object_lru); + + _glBindSampler(unit, gsc->_index); + + if (GLCAT.is_spam()) { + GLCAT.spam() + << "bind " << unit << " " << sampler << "\n"; + } + + } else { + CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); + + // We don't support sampler objects. We'll have to bind the + // texture and change the texture parameters if they don't match. + if (gtc->_active_sampler != sampler) { + _glActiveTexture(GL_TEXTURE0 + unit); + apply_texture(tc); + specify_texture(gtc, sampler); + } + } + + report_my_gl_errors(); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::upload_texture // Access: Protected diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index bd6e9efec2..b1ec3fa1cf 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -184,10 +184,18 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif // OPENGLES_1 #ifndef OPENGLES +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); @@ -276,6 +284,9 @@ public: virtual void release_texture(TextureContext *tc); virtual bool extract_texture_data(Texture *tex); + virtual SamplerContext *prepare_sampler(const SamplerState &sampler); + virtual void release_sampler(SamplerContext *sc); + virtual GeomContext *prepare_geom(Geom *geom); virtual void release_geom(GeomContext *gc); @@ -443,11 +454,11 @@ protected: static GLenum get_numeric_type(Geom::NumericType numeric_type); GLenum get_texture_target(Texture::TextureType texture_type) const; - GLenum get_texture_wrap_mode(Texture::WrapMode wm) const; - static Texture::WrapMode get_panda_wrap_mode(GLenum wm); - static GLenum get_texture_filter_type(Texture::FilterType ft, + GLenum get_texture_wrap_mode(SamplerState::WrapMode wm) const; + static SamplerState::WrapMode get_panda_wrap_mode(GLenum wm); + static GLenum get_texture_filter_type(SamplerState::FilterType ft, bool ignore_mipmaps); - static Texture::FilterType get_panda_filter_type(GLenum ft); + static SamplerState::FilterType get_panda_filter_type(GLenum ft); GLenum get_component_type(Texture::ComponentType component_type); GLint get_external_image_format(Texture *tex) const; GLint get_internal_image_format(Texture *tex) const; @@ -476,8 +487,9 @@ protected: #endif // NDEBUG void do_auto_rescale_normal(); - bool specify_texture(CLP(TextureContext) *gtc); + bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler); bool apply_texture(TextureContext *tc); + bool apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc); bool upload_texture(CLP(TextureContext) *gtc, bool force); bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, bool uses_mipmaps, int mipmap_bias, @@ -765,11 +777,19 @@ public: PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer; #endif // OPENGLES_1 #ifndef OPENGLES + PFNGLGENSAMPLERSPROC _glGenSamplers; + PFNGLDELETESAMPLERSPROC _glDeleteSamplers; + PFNGLBINDSAMPLERPROC _glBindSampler; + PFNGLSAMPLERPARAMETERIPROC _glSamplerParameteri; + PFNGLSAMPLERPARAMETERIVPROC _glSamplerParameteriv; + PFNGLSAMPLERPARAMETERFPROC _glSamplerParameterf; + PFNGLSAMPLERPARAMETERFVPROC _glSamplerParameterfv; PFNGLPROGRAMPARAMETERIPROC _glProgramParameteri; PFNGLPATCHPARAMETERIPROC _glPatchParameteri; PFNGLDRAWARRAYSINSTANCEDPROC _glDrawArraysInstanced; PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced; PFNGLBINDTEXTURESPROC _glBindTextures; + PFNGLBINDSAMPLERSPROC _glBindSamplers; PFNGLBINDIMAGETEXTUREPROC _glBindImageTexture; PFNGLBINDIMAGETEXTURESPROC _glBindImageTextures; PFNGLDISPATCHCOMPUTEPROC _glDispatchCompute; @@ -780,6 +800,7 @@ public: PFNGLSCISSORARRAYVPROC _glScissorArrayv; PFNGLDEPTHRANGEARRAYVPROC _glDepthRangeArrayv; PFNGLGETTEXTUREHANDLEPROC _glGetTextureHandle; + PFNGLGETTEXTURESAMPLERHANDLEPROC _glGetTextureSamplerHandle; PFNGLMAKETEXTUREHANDLERESIDENTPROC _glMakeTextureHandleResident; PFNGLMAKETEXTUREHANDLENONRESIDENTPROC _glMakeTextureHandleNonResident; PFNGLUNIFORMHANDLEUI64PROC _glUniformHandleui64; diff --git a/panda/src/glstuff/glSamplerContext_src.cxx b/panda/src/glstuff/glSamplerContext_src.cxx new file mode 100644 index 0000000000..4231baec59 --- /dev/null +++ b/panda/src/glstuff/glSamplerContext_src.cxx @@ -0,0 +1,83 @@ +// Filename: glSamplerContext_src.cxx +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "pnotify.h" + +TypeHandle CLP(SamplerContext)::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: CLP(SamplerContext)::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CLP(SamplerContext):: +CLP(SamplerContext)(CLP(GraphicsStateGuardian) *glgsg, + const SamplerState &sampler) : + SamplerContext(sampler) +{ + _glgsg = glgsg; + _glgsg->_glGenSamplers(1, &_index); +} + +//////////////////////////////////////////////////////////////////// +// Function: CLP(SamplerContext)::Denstructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +CLP(SamplerContext):: +~CLP(SamplerContext)() { + if (_index != 0) { + _glgsg->_glDeleteSamplers(1, &_index); + _index = 0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GLSamplerContext::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void CLP(SamplerContext):: +evict_lru() { + dequeue_lru(); + + reset_data(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GLSamplerContext::reset_data +// Access: Public +// Description: Resets the texture object to a new one so a new GL +// texture object can be uploaded. +//////////////////////////////////////////////////////////////////// +void CLP(SamplerContext):: +reset_data() { + // Free the sampler resource. + _glgsg->_glDeleteSamplers(1, &_index); + _index = 0; + + // We still need a valid index number, though, in case we want to + // re-load the sampler later. + //glGenSamplers(1, &_index); +} diff --git a/panda/src/glstuff/glSamplerContext_src.h b/panda/src/glstuff/glSamplerContext_src.h new file mode 100644 index 0000000000..f5f2d8a05b --- /dev/null +++ b/panda/src/glstuff/glSamplerContext_src.h @@ -0,0 +1,58 @@ +// Filename: glSamplerContext_src.h +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "pandabase.h" +#include "samplerContext.h" +#include "deletedChain.h" + +class CLP(GraphicsStateGuardian); + +//////////////////////////////////////////////////////////////////// +// Class : GLSamplerContext +// Description : This class represents a sampler object, which +// contains a set of sampler parameters used when +// sampling a texture. +//////////////////////////////////////////////////////////////////// +class EXPCL_GL CLP(SamplerContext) : public SamplerContext { +public: + INLINE CLP(SamplerContext)(CLP(GraphicsStateGuardian) *glgsg, + const SamplerState &sampler); + ALLOC_DELETED_CHAIN(CLP(SamplerContext)); + + virtual ~CLP(SamplerContext)(); + virtual void evict_lru(); + void reset_data(); + + // This is the GL "name" of the sampler object. + GLuint _index; + + CLP(GraphicsStateGuardian) *_glgsg; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + SamplerContext::init_type(); + register_type(_type_handle, CLASSPREFIX_QUOTED "SamplerContext", + SamplerContext::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; +}; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 386514517d..e16fb3143b 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -1276,9 +1276,12 @@ update_shader_texture_bindings(ShaderContext *prev) { Texture *tex = NULL; int view = _glgsg->get_current_tex_view_offset(); + SamplerState sampler; + if (id != NULL) { const ShaderInput *input = _glgsg->_target_shader->get_shader_input(id); tex = input->get_texture(); + sampler = input->get_sampler(); } else { if (texunit >= texattrib->get_num_on_stages()) { @@ -1286,6 +1289,7 @@ update_shader_texture_bindings(ShaderContext *prev) { } TextureStage *stage = texattrib->get_on_stage(texunit); tex = texattrib->get_on_texture(stage); + sampler = texattrib->get_on_sampler(stage); view += stage->get_tex_view_offset(); } @@ -1349,6 +1353,7 @@ update_shader_texture_bindings(ShaderContext *prev) { continue; } _glgsg->apply_texture(gtc); + _glgsg->apply_sampler(i, sampler, gtc); } #ifndef OPENGLES diff --git a/panda/src/glstuff/glTextureContext_src.h b/panda/src/glstuff/glTextureContext_src.h index af0092dd3e..14a0b68f6e 100644 --- a/panda/src/glstuff/glTextureContext_src.h +++ b/panda/src/glstuff/glTextureContext_src.h @@ -15,8 +15,10 @@ #include "pandabase.h" #include "textureContext.h" #include "deletedChain.h" +#include "samplerState.h" class CLP(GraphicsStateGuardian); +class CLP(SamplerContext); //////////////////////////////////////////////////////////////////// // Class : GLTextureContext @@ -62,6 +64,7 @@ public: GLsizei _height; GLsizei _depth; GLenum _target; + SamplerState _active_sampler; CLP(GraphicsStateGuardian) *_glgsg; diff --git a/panda/src/glstuff/glmisc_src.cxx b/panda/src/glstuff/glmisc_src.cxx index bf2163452f..ae6af9b740 100644 --- a/panda/src/glstuff/glmisc_src.cxx +++ b/panda/src/glstuff/glmisc_src.cxx @@ -259,6 +259,12 @@ ConfigVariableBool gl_support_primitive_restart_index "segment primitives. Set to false if you suspect a bug " "in the driver implementation.")); +ConfigVariableBool gl_support_sampler_objects + ("gl-support-sampler-objects", true, + PRC_DESC("Setting this allows Panda to make use of sampler " + "objects. Set to false if you suspect a bug in the " + "driver implementation.")); + extern ConfigVariableBool gl_parallel_arrays; void CLP(init_classes)() { @@ -270,6 +276,7 @@ void CLP(init_classes)() { CLP(ShaderContext)::init_type(); #endif CLP(TextureContext)::init_type(); + CLP(SamplerContext)::init_type(); CLP(VertexBufferContext)::init_type(); CLP(GraphicsBuffer)::init_type(); diff --git a/panda/src/glstuff/glmisc_src.h b/panda/src/glstuff/glmisc_src.h index 5b2c601691..1cd46f68db 100644 --- a/panda/src/glstuff/glmisc_src.h +++ b/panda/src/glstuff/glmisc_src.h @@ -73,6 +73,7 @@ extern ConfigVariableBool gl_use_bindless_texture; extern ConfigVariableBool gl_enable_memory_barriers; extern ConfigVariableBool gl_vertex_array_objects; extern ConfigVariableBool gl_support_primitive_restart_index; +extern ConfigVariableBool gl_support_sampler_objects; extern EXPCL_GL void CLP(init_classes)(); diff --git a/panda/src/glstuff/glstuff_src.cxx b/panda/src/glstuff/glstuff_src.cxx index 518162a53a..74a72c886a 100644 --- a/panda/src/glstuff/glstuff_src.cxx +++ b/panda/src/glstuff/glstuff_src.cxx @@ -19,6 +19,7 @@ #include "glmisc_src.cxx" #include "glTextureContext_src.cxx" +#include "glSamplerContext_src.cxx" #include "glVertexBufferContext_src.cxx" #include "glIndexBufferContext_src.cxx" #include "glOcclusionQueryContext_src.cxx" diff --git a/panda/src/glstuff/glstuff_src.h b/panda/src/glstuff/glstuff_src.h index cb0bcb4941..280471ddca 100644 --- a/panda/src/glstuff/glstuff_src.h +++ b/panda/src/glstuff/glstuff_src.h @@ -33,6 +33,7 @@ #include "glmisc_src.h" #include "glTextureContext_src.h" +#include "glSamplerContext_src.h" #include "glVertexBufferContext_src.h" #include "glIndexBufferContext_src.h" #include "glOcclusionQueryContext_src.h" diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 1eea586b13..7cf460e5f1 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -31,12 +31,13 @@ #include "geomVertexArrayFormat.h" #include "geomVertexData.h" #include "geomVertexFormat.h" +#include "lens.h" #include "material.h" #include "occlusionQueryContext.h" #include "orthographicLens.h" #include "matrixLens.h" +#include "paramTexture.h" #include "perspectiveLens.h" -#include "lens.h" #include "queryContext.h" #include "sliderTable.h" #include "texture.h" @@ -45,6 +46,8 @@ #include "textureStage.h" #include "textureContext.h" #include "timerQueryContext.h" +#include "samplerContext.h" +#include "samplerState.h" #include "shader.h" #include "shaderContext.h" #include "transformBlend.h" @@ -480,6 +483,16 @@ ConfigVariableInt graphics_memory_limit "Set this to -1 to have no limit other than the normal " "hardware-imposed limit.")); +ConfigVariableInt sampler_object_limit +("sampler-object-limit", 2048, + PRC_DESC("This is a default limit that is imposed on each GSG at " + "GSG creation time. It limits the total amount of sampler " + "objects that will be k.ept by the GSG, regardless of whether " + "the hardware claims to provide more sampler objects than this. " + "Direct3D 10-capable hardware supports at least 4096 distinct " + "sampler objects, but we provide a slightly more conservative " + "limit by default.")); + ConfigVariableDouble adaptive_lru_weight ("adaptive-lru-weight", 0.2, PRC_DESC("Specifies the weight factor used to compute the AdaptiveLru's " @@ -559,8 +572,12 @@ ConfigureFn(config_gobj) { MatrixLens::init_type(); OcclusionQueryContext::init_type(); OrthographicLens::init_type(); + ParamTextureImage::init_type(); + ParamTextureSampler::init_type(); PerspectiveLens::init_type(); QueryContext::init_type(); + SamplerContext::init_type(); + SamplerState::init_type(); ShaderContext::init_type(); Shader::init_type(); SliderTable::init_type(); @@ -600,6 +617,8 @@ ConfigureFn(config_gobj) { Material::register_with_read_factory(); MatrixLens::register_with_read_factory(); OrthographicLens::register_with_read_factory(); + ParamTextureImage::register_with_read_factory(); + ParamTextureSampler::register_with_read_factory(); PerspectiveLens::register_with_read_factory(); Shader::register_with_read_factory(); SliderTable::register_with_read_factory(); diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index 8bf606e5c6..a0ce3e1c8e 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -96,6 +96,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableString vertex_save_file_prefix; extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_small_size; extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_page_threads; extern EXPCL_PANDA_GOBJ ConfigVariableInt graphics_memory_limit; +extern EXPCL_PANDA_GOBJ ConfigVariableInt sampler_object_limit; extern EXPCL_PANDA_GOBJ ConfigVariableDouble adaptive_lru_weight; extern EXPCL_PANDA_GOBJ ConfigVariableInt adaptive_lru_max_updates_per_frame; extern EXPCL_PANDA_GOBJ ConfigVariableDouble async_load_delay; diff --git a/panda/src/gobj/p3gobj_composite1.cxx b/panda/src/gobj/p3gobj_composite1.cxx index a584185f68..a18171f215 100644 --- a/panda/src/gobj/p3gobj_composite1.cxx +++ b/panda/src/gobj/p3gobj_composite1.cxx @@ -33,3 +33,5 @@ #include "material.cxx" #include "materialPool.cxx" #include "matrixLens.cxx" +#include "occlusionQueryContext.cxx" +#include "orthographicLens.cxx" diff --git a/panda/src/gobj/p3gobj_composite2.cxx b/panda/src/gobj/p3gobj_composite2.cxx index d25852b69c..81e23e5c07 100644 --- a/panda/src/gobj/p3gobj_composite2.cxx +++ b/panda/src/gobj/p3gobj_composite2.cxx @@ -1,8 +1,9 @@ -#include "occlusionQueryContext.cxx" -#include "orthographicLens.cxx" +#include "paramTexture.cxx" #include "perspectiveLens.cxx" #include "preparedGraphicsObjects.cxx" #include "queryContext.cxx" +#include "samplerContext.cxx" +#include "samplerState.cxx" #include "savedContext.cxx" #include "shaderContext.cxx" #include "shader.cxx" diff --git a/panda/src/gobj/paramTexture.I b/panda/src/gobj/paramTexture.I new file mode 100644 index 0000000000..5362bacb35 --- /dev/null +++ b/panda/src/gobj/paramTexture.I @@ -0,0 +1,158 @@ +// Filename: paramTexture.I +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::Constructor +// Access: Published +// Description: Creates a new ParamTextureSampler storing the given +// texture and sampler objects. +//////////////////////////////////////////////////////////////////// +INLINE ParamTextureSampler:: +ParamTextureSampler(Texture *tex, const SamplerState &sampler) : + _texture(tex), + _sampler(sampler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::get_value_type +// Access: Published, Virtual +// Description: Returns Texture::get_class_type(), even though it +// technically stores more than just a Texture. +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle ParamTextureSampler:: +get_value_type() const { + return Texture::get_class_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::get_texture +// Access: Published +// Description: Retrieves the texture stored in the parameter. +//////////////////////////////////////////////////////////////////// +INLINE Texture *ParamTextureSampler:: +get_texture() const { + return _texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::get_sampler +// Access: Published +// Description: Retrieves the sampler state stored in the parameter. +//////////////////////////////////////////////////////////////////// +INLINE const SamplerState &ParamTextureSampler:: +get_sampler() const { + return _sampler; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::Constructor +// Access: Published +// Description: Creates a new ParamTextureImage storing the given +// texture and image binding parameters. +//////////////////////////////////////////////////////////////////// +INLINE ParamTextureImage:: +ParamTextureImage(Texture *tex, bool read, bool write, int z, int n) : + _texture(tex), + _access(0), + _bind_level(min(n, 127)), + _bind_layer(z) +{ + if (read) { + _access |= A_read; + } + if (write) { + _access |= A_write; + } + if (z < 0) { + _bind_layer = 0; + _access |= A_layered; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::get_value_type +// Access: Published, Virtual +// Description: Returns Texture::get_class_type(), even though it +// technically stores more than just a Texture. +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle ParamTextureImage:: +get_value_type() const { + return Texture::get_class_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::get_texture +// Access: Published +// Description: Retrieves the texture stored in the parameter. +//////////////////////////////////////////////////////////////////// +INLINE Texture *ParamTextureImage:: +get_texture() const { + return _texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::has_read_access +// Access: Published +// Description: Returns true if this image should be bound with +// read access enabled. +//////////////////////////////////////////////////////////////////// +INLINE bool ParamTextureImage:: +has_read_access() const { + return (_access & A_read) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::has_write_access +// Access: Published +// Description: Returns true if this image should be bound with +// write access enabled. +//////////////////////////////////////////////////////////////////// +INLINE bool ParamTextureImage:: +has_write_access() const { + return (_access & A_write) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::get_bind_layered +// Access: Published +// Description: Returns true if all layers of this image should be +// bound simultaneously. +//////////////////////////////////////////////////////////////////// +INLINE bool ParamTextureImage:: +get_bind_layered() const { + return (_access & A_layered) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::get_bind_level +// Access: Published +// Description: Returns the image level that should be bound. +//////////////////////////////////////////////////////////////////// +INLINE int ParamTextureImage:: +get_bind_level() const { + return _bind_level; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::get_bind_layer +// Access: Published +// Description: Returns the image layer that should be bound. This +// is undefined if get_bind_layered() returns false. +//////////////////////////////////////////////////////////////////// +INLINE int ParamTextureImage:: +get_bind_layer() const { + return _bind_layer; +} diff --git a/panda/src/gobj/paramTexture.cxx b/panda/src/gobj/paramTexture.cxx new file mode 100644 index 0000000000..828a7a0170 --- /dev/null +++ b/panda/src/gobj/paramTexture.cxx @@ -0,0 +1,220 @@ +// Filename: paramTexture.cxx +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "paramTexture.h" +#include "dcast.h" + +TypeHandle ParamTextureSampler::_type_handle; +TypeHandle ParamTextureImage::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::output +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ParamTextureSampler:: +output(ostream &out) const { + out << "texture "; + + if (_texture != (Texture *)NULL) { + out << _texture->get_name(); + } else { + out << "(empty)"; + } + out << ", "; + + _sampler.output(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// ParamValue. +//////////////////////////////////////////////////////////////////// +void ParamTextureSampler:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void ParamTextureSampler:: +write_datagram(BamWriter *manager, Datagram &dg) { + ParamValueBase::write_datagram(manager, dg); + manager->write_pointer(dg, _texture); + _sampler.write_datagram(dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int ParamTextureSampler:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = ParamValueBase::complete_pointers(p_list, manager); + _texture = DCAST(Texture, p_list[pi++]); + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type ParamValue is encountered +// in the Bam file. It should create the ParamValue +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *ParamTextureSampler:: +make_from_bam(const FactoryParams ¶ms) { + ParamTextureSampler *param = new ParamTextureSampler; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + param->fillin(scan, manager); + + return param; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureSampler::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 ParamValue. +//////////////////////////////////////////////////////////////////// +void ParamTextureSampler:: +fillin(DatagramIterator &scan, BamReader *manager) { + ParamValueBase::fillin(scan, manager); + manager->read_pointer(scan); + _sampler.read_datagram(scan, manager); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::output +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ParamTextureImage:: +output(ostream &out) const { + out << "texture "; + + if (_texture != (Texture *)NULL) { + out << _texture->get_name(); + } else { + out << "(empty)"; + } + + if (_access & A_read) { + if (_access & A_write) { + out << ", read-write"; + } else { + out << ", read-only"; + } + } else if (_access & A_write) { + out << ", write-only"; + } + + if (_access & A_layered) { + out << ", all layers"; + } else { + out << ", layer " << _bind_layer; + } + + out << ", level " << _bind_level; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// ParamValue. +//////////////////////////////////////////////////////////////////// +void ParamTextureImage:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void ParamTextureImage:: +write_datagram(BamWriter *manager, Datagram &dg) { + ParamValueBase::write_datagram(manager, dg); + manager->write_pointer(dg, _texture); + dg.add_uint8(_access); + dg.add_int8(_bind_level); + dg.add_int32(_bind_layer); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int ParamTextureImage:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = ParamValueBase::complete_pointers(p_list, manager); + _texture = DCAST(Texture, p_list[pi++]); + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type ParamValue is encountered +// in the Bam file. It should create the ParamValue +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *ParamTextureImage:: +make_from_bam(const FactoryParams ¶ms) { + ParamTextureImage *param = new ParamTextureImage; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + param->fillin(scan, manager); + + return param; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamTextureImage::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 ParamValue. +//////////////////////////////////////////////////////////////////// +void ParamTextureImage:: +fillin(DatagramIterator &scan, BamReader *manager) { + ParamValueBase::fillin(scan, manager); + manager->read_pointer(scan); + _access = scan.get_uint8(); + _bind_level = scan.get_int8(); + _bind_layer = scan.get_int32(); +} diff --git a/panda/src/gobj/paramTexture.h b/panda/src/gobj/paramTexture.h new file mode 100644 index 0000000000..4d87226594 --- /dev/null +++ b/panda/src/gobj/paramTexture.h @@ -0,0 +1,143 @@ +// Filename: paramTexture.h +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PARAMTEXTURE_H +#define PARAMTEXTURE_H + +#include "pandabase.h" +#include "paramValue.h" +#include "samplerState.h" +#include "texture.h" + +//////////////////////////////////////////////////////////////////// +// Class : ParamTextureSampler +// Description : A class object for storing a pointer to a Texture +// along with a sampler state that indicates how to +// to sample the given texture. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_GOBJ ParamTextureSampler : public ParamValueBase { +protected: + INLINE ParamTextureSampler() {}; + +PUBLISHED: + INLINE ParamTextureSampler(Texture *tex, const SamplerState &sampler); + + INLINE virtual TypeHandle get_value_type() const; + INLINE Texture *get_texture() const; + INLINE const SamplerState &get_sampler() const; + + virtual void output(ostream &out) const; + +private: + PT(Texture) _texture; + SamplerState _sampler; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, + BamReader *manager); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ParamValueBase::init_type(); + register_type(_type_handle, "ParamTextureSampler", + ParamValueBase::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +//////////////////////////////////////////////////////////////////// +// Class : ParamTextureImage +// Description : A class object for storing a pointer to a Texture +// along with a set of properties that indicates which +// image to bind to a shader input. +// +// This class is useful for binding texture images +// to a shader, which is a fairly esoteric feature. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_GOBJ ParamTextureImage : public ParamValueBase { +protected: + INLINE ParamTextureImage() {}; + + enum AccessFlags { + A_read = 0x01, + A_write = 0x02, + A_layered = 0x04, + }; + +PUBLISHED: + INLINE ParamTextureImage(Texture *tex, bool read, bool write, int z=-1, int n=0); + + INLINE virtual TypeHandle get_value_type() const; + + INLINE Texture *get_texture() const; + INLINE bool has_read_access() const; + INLINE bool has_write_access() const; + INLINE bool get_bind_layered() const; + INLINE int get_bind_level() const; + INLINE int get_bind_layer() const; + + virtual void output(ostream &out) const; + +private: + PT(Texture) _texture; + int _access : 4; + int _bind_level : 8; + int _bind_layer : 20; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, + BamReader *manager); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ParamValueBase::init_type(); + register_type(_type_handle, "ParamTextureImage", + ParamValueBase::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "paramTexture.I" + +#endif diff --git a/panda/src/gobj/preparedGraphicsObjects.I b/panda/src/gobj/preparedGraphicsObjects.I index 50b59d8eb0..e137f2f043 100644 --- a/panda/src/gobj/preparedGraphicsObjects.I +++ b/panda/src/gobj/preparedGraphicsObjects.I @@ -45,6 +45,7 @@ get_graphics_memory_limit() const { INLINE void PreparedGraphicsObjects:: release_all() { release_all_textures(); + release_all_samplers(); release_all_geoms(); release_all_shaders(); release_all_vertex_buffers(); @@ -63,7 +64,8 @@ release_all() { //////////////////////////////////////////////////////////////////// INLINE int PreparedGraphicsObjects:: get_num_queued() const { - return (get_num_queued_textures() + + return (get_num_queued_textures() + + get_num_queued_samplers() + get_num_queued_geoms() + get_num_queued_shaders() + get_num_queued_vertex_buffers() + @@ -78,7 +80,8 @@ get_num_queued() const { //////////////////////////////////////////////////////////////////// INLINE int PreparedGraphicsObjects:: get_num_prepared() const { - return (get_num_prepared_textures() + + return (get_num_prepared_textures() + + get_num_prepared_samplers() + get_num_prepared_geoms() + get_num_prepared_shaders() + get_num_prepared_vertex_buffers() + @@ -88,7 +91,7 @@ get_num_prepared() const { //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::BufferCacheKey::operator < // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PreparedGraphicsObjects::BufferCacheKey:: operator < (const PreparedGraphicsObjects::BufferCacheKey &other) const { @@ -101,7 +104,7 @@ operator < (const PreparedGraphicsObjects::BufferCacheKey &other) const { //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::BufferCacheKey::operator == // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PreparedGraphicsObjects::BufferCacheKey:: operator == (const PreparedGraphicsObjects::BufferCacheKey &other) const { @@ -112,7 +115,7 @@ operator == (const PreparedGraphicsObjects::BufferCacheKey &other) const { //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::BufferCacheKey::operator != // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PreparedGraphicsObjects::BufferCacheKey:: operator != (const PreparedGraphicsObjects::BufferCacheKey &other) const { diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 3343d89e26..233e4ce9fe 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -20,6 +20,7 @@ #include "geom.h" #include "geomVertexArrayData.h" #include "geomPrimitive.h" +#include "samplerContext.h" #include "shader.h" #include "reMutexHolder.h" #include "geomContext.h" @@ -32,10 +33,10 @@ int PreparedGraphicsObjects::_name_index = 0; //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// PreparedGraphicsObjects:: -PreparedGraphicsObjects() : +PreparedGraphicsObjects() : _lock("PreparedGraphicsObjects::_lock"), _name(init_name()), _vertex_buffer_cache_size(0), @@ -43,7 +44,8 @@ PreparedGraphicsObjects() : _texture_residency(_name, "texture"), _vbuffer_residency(_name, "vbuffer"), _ibuffer_residency(_name, "ibuffer"), - _graphics_memory_lru("graphics_memory_lru", graphics_memory_limit) + _graphics_memory_lru("graphics_memory_lru", graphics_memory_limit), + _sampler_object_lru("sampler_object_lru", sampler_object_limit) { // GLGSG will turn this flag on. This is a temporary hack to // disable this feature for DX8/DX9 for now, until we work out the @@ -54,7 +56,7 @@ PreparedGraphicsObjects() : //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::Destructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// PreparedGraphicsObjects:: ~PreparedGraphicsObjects() { @@ -75,6 +77,9 @@ PreparedGraphicsObjects:: // Is this a leak? Should we delete these TextureContexts? _released_textures.clear(); + release_all_samplers(); + _released_samplers.clear(); + release_all_geoms(); _released_geoms.clear(); @@ -121,7 +126,7 @@ void PreparedGraphicsObjects:: set_graphics_memory_limit(size_t limit) { if (limit != _graphics_memory_lru.get_max_size()) { _graphics_memory_lru.set_max_size(limit); - + // We throw an event here so global objects (particularly the // TexMemWatcher) can automatically respond to this change. throw_event("graphics_memory_limit_changed"); @@ -358,6 +363,198 @@ prepare_texture_now(Texture *tex, int view, GraphicsStateGuardianBase *gsg) { return tc; } +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::enqueue_sampler +// Access: Public +// Description: Indicates that a sampler would like to be put on the +// list to be prepared when the GSG is next ready to +// do this (presumably at the next frame). +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +enqueue_sampler(const SamplerState &sampler) { + ReMutexHolder holder(_lock); + + _enqueued_samplers.insert(sampler); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::is_sampler_queued +// Access: Public +// Description: Returns true if the sampler has been queued on this +// GSG, false otherwise. +//////////////////////////////////////////////////////////////////// +bool PreparedGraphicsObjects:: +is_sampler_queued(const SamplerState &sampler) const { + ReMutexHolder holder(_lock); + + EnqueuedSamplers::const_iterator qi = _enqueued_samplers.find(sampler); + return (qi != _enqueued_samplers.end()); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::dequeue_sampler +// Access: Public +// Description: Removes a sampler from the queued list of samplers to +// be prepared. Normally it is not necessary to call +// this, unless you change your mind about preparing it +// at the last minute, since the sampler will +// automatically be dequeued and prepared at the next +// frame. +// +// The return value is true if the sampler is +// successfully dequeued, false if it had not been +// queued. +//////////////////////////////////////////////////////////////////// +bool PreparedGraphicsObjects:: +dequeue_sampler(const SamplerState &sampler) { + ReMutexHolder holder(_lock); + + EnqueuedSamplers::iterator qi = _enqueued_samplers.find(sampler); + if (qi != _enqueued_samplers.end()) { + _enqueued_samplers.erase(qi); + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::is_sampler_prepared +// Access: Public +// Description: Returns true if the sampler has been prepared on +// this GSG, false otherwise. +//////////////////////////////////////////////////////////////////// +bool PreparedGraphicsObjects:: +is_sampler_prepared(const SamplerState &sampler) const { + ReMutexHolder holder(_lock); + + PreparedSamplers::const_iterator it = _prepared_samplers.find(sampler); + return (it != _prepared_samplers.end()); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_sampler +// Access: Public +// Description: Indicates that a sampler context, created by a +// previous call to prepare_sampler(), is no longer +// needed. The driver resources will not be freed until +// some GSG calls update(), indicating it is at a +// stage where it is ready to release samplers. +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +release_sampler(SamplerContext *sc) { + ReMutexHolder holder(_lock); + + _released_samplers.insert(sc); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_sampler +// Access: Public +// Description: Releases a sampler if it has already been prepared, +// or removes it from the preparation queue. +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +release_sampler(const SamplerState &sampler) { + ReMutexHolder holder(_lock); + + PreparedSamplers::iterator it = _prepared_samplers.find(sampler); + if (it != _prepared_samplers.end()) { + _released_samplers.insert(it->second); + _prepared_samplers.erase(it); + } + + _enqueued_samplers.erase(sampler); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_all_samplers +// Access: Public +// Description: Releases all samplers at once. This will force them +// to be reloaded for all GSG's that share this object. +// Returns the number of samplers released. +//////////////////////////////////////////////////////////////////// +int PreparedGraphicsObjects:: +release_all_samplers() { + ReMutexHolder holder(_lock); + + int num_samplers = (int)_prepared_samplers.size() + (int)_enqueued_samplers.size(); + + PreparedSamplers::iterator sci; + for (sci = _prepared_samplers.begin(); + sci != _prepared_samplers.end(); + ++sci) { + _released_samplers.insert(sci->second); + } + + _prepared_samplers.clear(); + _enqueued_samplers.clear(); + + return num_samplers; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::get_num_queued_samplers +// Access: Public +// Description: Returns the number of samplers that have been +// enqueued to be prepared on this GSG. +//////////////////////////////////////////////////////////////////// +int PreparedGraphicsObjects:: +get_num_queued_samplers() const { + return _enqueued_samplers.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::get_num_prepared_samplers +// Access: Public +// Description: Returns the number of samplers that have already been +// prepared on this GSG. +//////////////////////////////////////////////////////////////////// +int PreparedGraphicsObjects:: +get_num_prepared_samplers() const { + return _prepared_samplers.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::prepare_sampler_now +// Access: Public +// Description: Immediately creates a new SamplerContext for the +// indicated sampler and returns it. This assumes that +// the GraphicsStateGuardian is the currently active +// rendering context and that it is ready to accept new +// samplers. If this is not necessarily the case, you +// should use enqueue_sampler() instead. +// +// Normally, this function is not called directly. +// Call Sampler::prepare_now() instead. +// +// The SamplerContext contains all of the pertinent +// information needed by the GSG to keep track of this +// one particular sampler, and will exist as long as the +// sampler is ready to be rendered. +// +// When either the Sampler or the +// PreparedGraphicsObjects object destructs, the +// SamplerContext will be deleted. +//////////////////////////////////////////////////////////////////// +SamplerContext *PreparedGraphicsObjects:: +prepare_sampler_now(const SamplerState &sampler, GraphicsStateGuardianBase *gsg) { + ReMutexHolder holder(_lock); + + PreparedSamplers::const_iterator it = _prepared_samplers.find(sampler); + if (it != _prepared_samplers.end()) { + return it->second; + } + + // Ask the GSG to create a brand new SamplerContext. + SamplerContext *sc = gsg->prepare_sampler(sampler); + + if (sc != (SamplerContext *)NULL) { + _prepared_samplers[sampler] = sc; + } + + return sc; +} + //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::enqueue_geom // Access: Public @@ -870,8 +1067,8 @@ release_all_vertex_buffers() { // Also clear the cache of recently-unprepared vertex buffers. BufferCache::iterator bci; - for (bci = _vertex_buffer_cache.begin(); - bci != _vertex_buffer_cache.end(); + for (bci = _vertex_buffer_cache.begin(); + bci != _vertex_buffer_cache.end(); ++bci) { BufferList &buffer_list = (*bci).second; nassertr(!buffer_list.empty(), num_vertex_buffers); @@ -884,7 +1081,7 @@ release_all_vertex_buffers() { _vertex_buffer_cache.clear(); _vertex_buffer_cache_lru.clear(); _vertex_buffer_cache_size = 0; - + return num_vertex_buffers; } @@ -1099,8 +1296,8 @@ release_all_index_buffers() { // Also clear the cache of recently-unprepared index buffers. BufferCache::iterator bci; - for (bci = _index_buffer_cache.begin(); - bci != _index_buffer_cache.end(); + for (bci = _index_buffer_cache.begin(); + bci != _index_buffer_cache.end(); ++bci) { BufferList &buffer_list = (*bci).second; nassertr(!buffer_list.empty(), num_index_buffers); @@ -1218,9 +1415,21 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) { TextureContext *tc = (*tci); gsg->release_texture(tc); } + + _released_textures.clear(); } - _released_textures.clear(); + if (!_released_samplers.empty()) { + ReleasedSamplers::iterator sci; + for (sci = _released_samplers.begin(); + sci != _released_samplers.end(); + ++sci) { + SamplerContext *sc = (*sci); + gsg->release_sampler(sc); + } + + _released_samplers.clear(); + } Geoms::iterator gci; for (gci = _released_geoms.begin(); @@ -1284,6 +1493,16 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) { _enqueued_textures.clear(); + EnqueuedSamplers::iterator qsmi; + for (qsmi = _enqueued_samplers.begin(); + qsmi != _enqueued_samplers.end(); + ++qsmi) { + const SamplerState &sampler = (*qsmi); + sampler.prepare_now(this, gsg); + } + + _enqueued_samplers.clear(); + EnqueuedGeoms::iterator qgi; for (qgi = _enqueued_geoms.begin(); qgi != _enqueued_geoms.end(); @@ -1371,7 +1590,7 @@ cache_unprepared_buffer(BufferContext *buffer, size_t data_size_bytes, GeomEnums::UsageHint usage_hint, PreparedGraphicsObjects::BufferCache &buffer_cache, PreparedGraphicsObjects::BufferCacheLRU &buffer_cache_lru, - size_t &buffer_cache_size, + size_t &buffer_cache_size, int released_buffer_cache_size, PreparedGraphicsObjects::Buffers &released_buffers) { BufferCacheKey key; @@ -1395,7 +1614,7 @@ cache_unprepared_buffer(BufferContext *buffer, size_t data_size_bytes, nassertv(!buffer_cache_lru.empty()); const BufferCacheKey &release_key = *buffer_cache_lru.rbegin(); BufferList &buffer_list = buffer_cache[release_key]; - while (!buffer_list.empty() && + while (!buffer_list.empty() && (int)buffer_cache_size > released_buffer_cache_size) { BufferContext *released_buffer = buffer_list.back(); buffer_list.pop_back(); diff --git a/panda/src/gobj/preparedGraphicsObjects.h b/panda/src/gobj/preparedGraphicsObjects.h index 89371485aa..a55bcdb4d9 100644 --- a/panda/src/gobj/preparedGraphicsObjects.h +++ b/panda/src/gobj/preparedGraphicsObjects.h @@ -18,6 +18,7 @@ #include "pandabase.h" #include "referenceCount.h" #include "texture.h" +#include "samplerState.h" #include "geom.h" #include "geomVertexArrayData.h" #include "geomPrimitive.h" @@ -30,6 +31,7 @@ #include "adaptiveLru.h" class TextureContext; +class SamplerContext; class GeomContext; class ShaderContext; class VertexBufferContext; @@ -82,7 +84,20 @@ PUBLISHED: int get_num_queued_textures() const; int get_num_prepared_textures() const; - TextureContext *prepare_texture_now(Texture *tex, int view, + TextureContext *prepare_texture_now(Texture *tex, int view, + GraphicsStateGuardianBase *gsg); + + void enqueue_sampler(const SamplerState &sampler); + bool is_sampler_queued(const SamplerState &sampler) const; + bool dequeue_sampler(const SamplerState &sampler); + bool is_sampler_prepared(const SamplerState &sampler) const; + void release_sampler(SamplerContext *sc); + void release_sampler(const SamplerState &sampler); + int release_all_samplers(); + int get_num_queued_samplers() const; + int get_num_prepared_samplers() const; + + SamplerContext *prepare_sampler_now(const SamplerState &sampler, GraphicsStateGuardianBase *gsg); void enqueue_geom(Geom *geom); @@ -152,6 +167,12 @@ private: typedef phash_set< PT(GeomVertexArrayData) > EnqueuedVertexBuffers; typedef phash_set< PT(GeomPrimitive) > EnqueuedIndexBuffers; + // Sampler states are stored a little bit differently, as they are + // mapped by value and can't store the list of prepared samplers. + typedef pmap PreparedSamplers; + typedef pset ReleasedSamplers; + typedef pset EnqueuedSamplers; + class BufferCacheKey { public: INLINE bool operator < (const BufferCacheKey &other) const; @@ -171,7 +192,7 @@ private: size_t &buffer_cache_size, int released_buffer_cache_size, Buffers &released_buffers); - BufferContext *get_cached_buffer(size_t data_size_bytes, + BufferContext *get_cached_buffer(size_t data_size_bytes, GeomEnums::UsageHint usage_hint, BufferCache &buffer_cache, BufferCacheLRU &buffer_cache_lru, @@ -179,15 +200,18 @@ private: ReMutex _lock; string _name; - Textures _prepared_textures, _released_textures; + Textures _prepared_textures, _released_textures; EnqueuedTextures _enqueued_textures; - Geoms _prepared_geoms, _released_geoms; + PreparedSamplers _prepared_samplers; + ReleasedSamplers _released_samplers; + EnqueuedSamplers _enqueued_samplers; + Geoms _prepared_geoms, _released_geoms; EnqueuedGeoms _enqueued_geoms; Shaders _prepared_shaders, _released_shaders; EnqueuedShaders _enqueued_shaders; - Buffers _prepared_vertex_buffers, _released_vertex_buffers; + Buffers _prepared_vertex_buffers, _released_vertex_buffers; EnqueuedVertexBuffers _enqueued_vertex_buffers; - Buffers _prepared_index_buffers, _released_index_buffers; + Buffers _prepared_index_buffers, _released_index_buffers; EnqueuedIndexBuffers _enqueued_index_buffers; BufferCache _vertex_buffer_cache; @@ -204,6 +228,7 @@ public: BufferResidencyTracker _ibuffer_residency; AdaptiveLru _graphics_memory_lru; + SimpleLru _sampler_object_lru; public: // This is only public as a temporary hack. Don't mess with it diff --git a/panda/src/gobj/samplerContext.I b/panda/src/gobj/samplerContext.I new file mode 100644 index 0000000000..ef2039a56f --- /dev/null +++ b/panda/src/gobj/samplerContext.I @@ -0,0 +1,25 @@ +// Filename: samplerContext.I +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: SamplerContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SamplerContext:: +SamplerContext(const SamplerState &sampler) : + SimpleLruPage(1) +{ +} diff --git a/panda/src/gobj/samplerContext.cxx b/panda/src/gobj/samplerContext.cxx new file mode 100644 index 0000000000..a0b022225c --- /dev/null +++ b/panda/src/gobj/samplerContext.cxx @@ -0,0 +1,38 @@ +// Filename: samplerContext.cxx +// Created by: rdb (11Dec14)) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "samplerContext.h" + +TypeHandle SamplerContext::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: SamplerContext::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void SamplerContext:: +output(ostream &out) const { + SavedContext::output(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerContext::write +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void SamplerContext:: +write(ostream &out, int indent_level) const { + SavedContext::write(out, indent_level); +} + diff --git a/panda/src/gobj/samplerContext.h b/panda/src/gobj/samplerContext.h new file mode 100644 index 0000000000..61a876d405 --- /dev/null +++ b/panda/src/gobj/samplerContext.h @@ -0,0 +1,73 @@ +// Filename: samplerContext.h +// Created by: rdb (11Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef SAMPLERCONTEXT_H +#define SAMPLERCONTEXT_H + +#include "pandabase.h" + +#include "adaptiveLru.h" +#include "samplerState.h" +#include "savedContext.h" + +//////////////////////////////////////////////////////////////////// +// Class : SamplerContext +// Description : This is a special class object that holds a handle +// to the sampler state object given by the graphics +// back-end for a particular combination of texture +// sampling settings. +// +// Some graphics back-ends (like OpenGL) use mutable +// sampler objects, whereas others (Direct3D 10+) use +// immutable ones. In Panda3D, each unique sampler +// state has its own SamplerContext, which simplifies +// the implementation and makes redundant sampler +// objects impossible. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_GOBJ SamplerContext : public SavedContext, public SimpleLruPage { +public: + INLINE SamplerContext(const SamplerState &sampler); + + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level) const; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + SavedContext::init_type(); + register_type(_type_handle, "SamplerContext", + SavedContext::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 PreparedGraphicsObjects; +}; + +inline ostream &operator << (ostream &out, const SamplerContext &context) { + context.output(out); + return out; +} + +#include "samplerContext.I" + +#endif + diff --git a/panda/src/gobj/samplerState.I b/panda/src/gobj/samplerState.I new file mode 100644 index 0000000000..2762c10ce6 --- /dev/null +++ b/panda/src/gobj/samplerState.I @@ -0,0 +1,338 @@ +// Filename: samplerState.I +// Created by: rdb (09Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::Constructor +// Access: Published +// Description: Creates a new SamplerState initialized to the +// default values. +//////////////////////////////////////////////////////////////////// +INLINE SamplerState:: +SamplerState() : + _border_color(0, 0, 0, 1), + _wrap_u(WM_repeat), + _wrap_v(WM_repeat), + _wrap_w(WM_repeat), + _minfilter(FT_default), + _magfilter(FT_default), + _min_lod(-1000), + _max_lod(1000), + _lod_bias(0), + _anisotropic_degree(0) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_default +// Access: Published, Static +// Description: Returns a reference to the global default immutable +// SamplerState object. +//////////////////////////////////////////////////////////////////// +INLINE const SamplerState &SamplerState:: +get_default() { + return _default; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_wrap_u +// Access: Published +// Description: This setting determines what happens when the +// SamplerState is sampled with a U value outside the range +// 0.0-1.0. The default is WM_repeat, which indicates +// that the SamplerState should repeat indefinitely. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_wrap_u(SamplerState::WrapMode wrap) { + _wrap_u = wrap; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_wrap_v +// Access: Published +// Description: This setting determines what happens when the +// SamplerState is sampled with a V value outside the range +// 0.0-1.0. The default is WM_repeat, which indicates +// that the SamplerState should repeat indefinitely. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_wrap_v(SamplerState::WrapMode wrap) { + _wrap_v = wrap; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_wrap_w +// Access: Published +// Description: The W wrap direction is only used for 3-d SamplerStates. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_wrap_w(SamplerState::WrapMode wrap) { + _wrap_w = wrap; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_minfilter +// Access: Published +// Description: Sets the filtering method that should be used when +// viewing the SamplerState from a distance. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_minfilter(SamplerState::FilterType filter) { + _minfilter = filter; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_magfilter +// Access: Published +// Description: Sets the filtering method that should be used when +// viewing the SamplerState up close. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_magfilter(SamplerState::FilterType filter) { + _magfilter = filter; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_anisotropic_degree +// Access: Published +// Description: Specifies the level of anisotropic filtering to apply +// to the SamplerState. Set this 0 to indicate the default +// value, which is specified in the +// SamplerState-anisotropic-degree config variable. +// +// To explicitly disable anisotropic filtering, set this +// value to 1. To explicitly enable anisotropic +// filtering, set it to a value higher than 1; larger +// numbers indicate greater degrees of filtering. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_anisotropic_degree(int anisotropic_degree) { + _anisotropic_degree = anisotropic_degree; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_border_color +// Access: Published +// Description: Specifies the solid color of the SamplerState's border. +// Some OpenGL implementations use a border for tiling +// SamplerStates; in Panda, it is only used for specifying +// the clamp color. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_border_color(const LColor &color) { + _border_color = color; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_min_lod +// Access: Published +// Description: Sets the minimum level of detail that will be used +// when sampling this texture. This may be a negative +// value. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_min_lod(PN_stdfloat min_lod) { + _min_lod = min_lod; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_max_lod +// Access: Published +// Description: Sets the maximum level of detail that will be used +// when sampling this texture. This may exceed the +// number of mipmap levels that the texture has. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_max_lod(PN_stdfloat max_lod) { + _max_lod = max_lod; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::set_lod_bias +// Access: Published +// Description: Sets the value that will be added to the level of +// detail when sampling the texture. This may be a +// negative value, although some graphics hardware may +// not support the use of negative LOD values. +//////////////////////////////////////////////////////////////////// +INLINE void SamplerState:: +set_lod_bias(PN_stdfloat lod_bias) { + _lod_bias = lod_bias; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_wrap_u +// Access: Published +// Description: Returns the wrap mode of the texture in the U +// direction. +//////////////////////////////////////////////////////////////////// +INLINE SamplerState::WrapMode SamplerState:: +get_wrap_u() const { + return _wrap_u; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_wrap_v +// Access: Published +// Description: Returns the wrap mode of the texture in the V +// direction. +//////////////////////////////////////////////////////////////////// +INLINE SamplerState::WrapMode SamplerState:: +get_wrap_v() const { + return _wrap_v; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_wrap_w +// Access: Published +// Description: Returns the wrap mode of the texture in the W +// direction. This is the depth direction of 3-d +// textures. +//////////////////////////////////////////////////////////////////// +INLINE SamplerState::WrapMode SamplerState:: +get_wrap_w() const { + return _wrap_w; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_minfilter +// Access: Published +// Description: Returns the filter mode of the texture for +// minification. If this is one of the mipmap +// constants, then the texture requires mipmaps. This +// may return FT_default; see also +// get_effective_minfilter(). +//////////////////////////////////////////////////////////////////// +INLINE SamplerState::FilterType SamplerState:: +get_minfilter() const { + return _minfilter; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_magfilter +// Access: Published +// Description: Returns the filter mode of the texture for +// magnification. The mipmap constants are invalid +// here. This may return FT_default; see also +// get_effective_minfilter(). +//////////////////////////////////////////////////////////////////// +INLINE SamplerState::FilterType SamplerState:: +get_magfilter() const { + return _magfilter; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_anisotropic_degree +// Access: Published +// Description: Returns the degree of anisotropic filtering that +// should be applied to the texture. This value may +// return 0, indicating the default value; see also +// get_effective_anisotropic_degree. +//////////////////////////////////////////////////////////////////// +INLINE int SamplerState:: +get_anisotropic_degree() const { + return _anisotropic_degree; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_effective_anisotropic_degree +// Access: Published +// Description: Returns the degree of anisotropic filtering that +// should be applied to the texture. This value will +// normally not return 0, unless there is an error in +// the config file. +//////////////////////////////////////////////////////////////////// +INLINE int SamplerState:: +get_effective_anisotropic_degree() const { + if (_anisotropic_degree != 0) { + return _anisotropic_degree; + } + return texture_anisotropic_degree; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_border_color +// Access: Published +// Description: Returns the solid color of the texture's border. +// Some OpenGL implementations use a border for tiling +// textures; in Panda, it is only used for specifying +// the clamp color. +//////////////////////////////////////////////////////////////////// +INLINE const LColor &SamplerState:: +get_border_color() const { + return _border_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_min_lod +// Access: Published +// Description: Returns the minimum level of detail that will be +// observed when sampling this texture. +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat SamplerState:: +get_min_lod() const { + return _min_lod; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_max_lod +// Access: Published +// Description: Returns the maximum level of detail that will be +// observed when sampling this texture. +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat SamplerState:: +get_max_lod() const { + return _max_lod; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_lod_bias +// Access: Published +// Description: Returns the bias that will be added to the texture +// level of detail when sampling this texture. +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat SamplerState:: +get_lod_bias() const { + return _lod_bias; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::operator == +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool SamplerState:: +operator == (const SamplerState &other) const { + return compare_to(other) == 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::operator != +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool SamplerState:: +operator != (const SamplerState &other) const { + return compare_to(other) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::operator < +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool SamplerState:: +operator < (const SamplerState &other) const { + return compare_to(other) < 0; +} diff --git a/panda/src/gobj/samplerState.cxx b/panda/src/gobj/samplerState.cxx new file mode 100644 index 0000000000..1232aea7b7 --- /dev/null +++ b/panda/src/gobj/samplerState.cxx @@ -0,0 +1,401 @@ +// Filename: samplerState.cxx +// Created by: rdb (09Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "samplerState.h" +#include "indent.h" +#include "datagram.h" +#include "datagramIterator.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "samplerContext.h" +#include "preparedGraphicsObjects.h" + +TypeHandle SamplerState::_type_handle; +SamplerState SamplerState::_default; + +ConfigVariableEnum texture_minfilter +("texture-minfilter", SamplerState::FT_linear, + PRC_DESC("This specifies the default minfilter that is applied to a texture " + "in the absence of a specific minfilter setting. Normally this " + "is either 'linear' to disable mipmapping by default, or " + "'mipmap', to enable trilinear mipmapping by default. This " + "does not apply to depth textures. Note if this variable is " + "changed at runtime, you may need to reload textures explicitly " + "in order to change their visible properties.")); + +ConfigVariableEnum texture_magfilter +("texture-magfilter", SamplerState::FT_linear, + PRC_DESC("This specifies the default magfilter that is applied to a texture " + "in the absence of a specific magfilter setting. Normally this " + "is 'linear' (since mipmapping does not apply to magfilters). This " + "does not apply to depth textures. Note if this variable is " + "changed at runtime, you may need to reload textures explicitly " + "in order to change their visible properties.")); + +ConfigVariableInt texture_anisotropic_degree +("texture-anisotropic-degree", 1, + PRC_DESC("This specifies the default anisotropic degree that is applied " + "to a texture in the absence of a particular anisotropic degree " + "setting (that is, a texture for which the anisotropic degree " + "is 0, meaning the default setting). It should be 1 to disable " + "anisotropic filtering, or a higher number to enable it. " + "Note if this variable is " + "changed at runtime, you may need to reload textures explicitly " + "in order to change their visible properties.")); + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_effective_minfilter +// Access: Published +// Description: Returns the filter mode of the texture for +// minification, with special treatment for FT_default. +// This will normally not return FT_default, unless +// there is an error in the config file. +//////////////////////////////////////////////////////////////////// +SamplerState::FilterType SamplerState:: +get_effective_minfilter() const { + if (_minfilter != FT_default) { + return _minfilter; + } + return texture_minfilter; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::get_effective_magfilter +// Access: Published +// Description: Returns the filter mode of the texture for +// magnification, with special treatment for FT_default. +// This will normally not return FT_default, unless +// there is an error in the config file. +//////////////////////////////////////////////////////////////////// +SamplerState::FilterType SamplerState:: +get_effective_magfilter() const { + if (_magfilter != FT_default) { + return _magfilter; + } + return texture_magfilter; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::format_filter_type +// Access: Published, Static +// Description: Returns the indicated FilterType converted to a +// string word. +//////////////////////////////////////////////////////////////////// +string SamplerState:: +format_filter_type(FilterType ft) { + switch (ft) { + case FT_nearest: + return "nearest"; + case FT_linear: + return "linear"; + + case FT_nearest_mipmap_nearest: + return "nearest_mipmap_nearest"; + case FT_linear_mipmap_nearest: + return "linear_mipmap_nearest"; + case FT_nearest_mipmap_linear: + return "nearest_mipmap_linear"; + case FT_linear_mipmap_linear: + return "linear_mipmap_linear"; + + case FT_shadow: + return "shadow"; + + case FT_default: + return "default"; + + case FT_invalid: + return "invalid"; + } + return "**invalid**"; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::string_filter_type +// Access: Public +// Description: Returns the FilterType value associated with the given +// string representation, or FT_invalid if the string +// does not match any known FilterType value. +//////////////////////////////////////////////////////////////////// +SamplerState::FilterType SamplerState:: +string_filter_type(const string &string) { + if (cmp_nocase_uh(string, "nearest") == 0) { + return FT_nearest; + } else if (cmp_nocase_uh(string, "linear") == 0) { + return FT_linear; + } else if (cmp_nocase_uh(string, "nearest_mipmap_nearest") == 0) { + return FT_nearest_mipmap_nearest; + } else if (cmp_nocase_uh(string, "linear_mipmap_nearest") == 0) { + return FT_linear_mipmap_nearest; + } else if (cmp_nocase_uh(string, "nearest_mipmap_linear") == 0) { + return FT_nearest_mipmap_linear; + } else if (cmp_nocase_uh(string, "linear_mipmap_linear") == 0) { + return FT_linear_mipmap_linear; + } else if (cmp_nocase_uh(string, "mipmap") == 0) { + return FT_linear_mipmap_linear; + } else if (cmp_nocase_uh(string, "shadow") == 0) { + return FT_shadow; + } else if (cmp_nocase_uh(string, "default") == 0) { + return FT_default; + } else { + return FT_invalid; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::format_wrap_mode +// Access: Published, Static +// Description: Returns the indicated WrapMode converted to a +// string word. +//////////////////////////////////////////////////////////////////// +string SamplerState:: +format_wrap_mode(WrapMode wm) { + switch (wm) { + case WM_clamp: + return "clamp"; + case WM_repeat: + return "repeat"; + case WM_mirror: + return "mirror"; + case WM_mirror_once: + return "mirror_once"; + case WM_border_color: + return "border_color"; + + case WM_invalid: + return "invalid"; + } + + return "**invalid**"; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::string_wrap_mode +// Access: Public +// Description: Returns the WrapMode value associated with the given +// string representation, or WM_invalid if the string +// does not match any known WrapMode value. +//////////////////////////////////////////////////////////////////// +SamplerState::WrapMode SamplerState:: +string_wrap_mode(const string &string) { + if (cmp_nocase_uh(string, "repeat") == 0 || + cmp_nocase_uh(string, "wrap") == 0) { + return WM_repeat; + } else if (cmp_nocase_uh(string, "clamp") == 0) { + return WM_clamp; + } else if (cmp_nocase_uh(string, "mirror") == 0 || + cmp_nocase_uh(string, "mirrored_repeat") == 0) { + return WM_mirror; + } else if (cmp_nocase_uh(string, "mirror_once") == 0) { + return WM_mirror_once; + } else if (cmp_nocase_uh(string, "border_color") == 0 || + cmp_nocase_uh(string, "border") == 0) { + return WM_border_color; + } else { + return WM_invalid; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::prepare +// Access: Published +// Description: Indicates that the sampler should be enqueued to be +// prepared in the indicated prepared_objects at the +// beginning of the next frame. +// +// Use this function instead of prepare_now() to preload +// samplers from a user interface standpoint. +//////////////////////////////////////////////////////////////////// +void SamplerState:: +prepare(PreparedGraphicsObjects *prepared_objects) const { + prepared_objects->enqueue_sampler(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::is_prepared +// Access: Published +// Description: Returns true if the sampler has already been prepared +// or enqueued for preparation on the indicated GSG, +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool SamplerState:: +is_prepared(PreparedGraphicsObjects *prepared_objects) const { + return prepared_objects->is_sampler_queued(*this) + || prepared_objects->is_sampler_prepared(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::release +// Access: Published +// Description: Frees the texture context only on the indicated object, +// if it exists there. Returns true if it was released, +// false if it had not been prepared. +//////////////////////////////////////////////////////////////////// +void SamplerState:: +release(PreparedGraphicsObjects *prepared_objects) const { + prepared_objects->release_sampler(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::prepare_now +// Access: Published +// Description: Creates a context for the sampler on the particular +// GSG, if it does not already exist. Returns the new +// (or old) SamplerContext. This assumes that the +// GraphicsStateGuardian is the currently active +// rendering context and that it is ready to accept new +// textures. If this is not necessarily the case, you +// should use prepare() instead. +// +// Normally, this is not called directly except by the +// GraphicsStateGuardian; a sampler does not need to be +// explicitly prepared by the user before it may be +// rendered. +//////////////////////////////////////////////////////////////////// +SamplerContext *SamplerState:: +prepare_now(PreparedGraphicsObjects *prepared_objects, + GraphicsStateGuardianBase *gsg) const { + return prepared_objects->prepare_sampler_now(*this, gsg); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::compare_to +// Access: Public +// Description: Returns a number less than zero if this sampler +// sorts before the other one, greater than zero if it +// sorts after, or zero if they are equivalent. The +// sorting order is arbitrary and largely meaningless, +// except to differentiate different sampler states. +//////////////////////////////////////////////////////////////////// +int SamplerState:: +compare_to(const SamplerState &other) const { + if (_wrap_u != other._wrap_u) { + return (_wrap_u < other._wrap_u) ? -1 : 1; + } + if (_wrap_v != other._wrap_v) { + return (_wrap_v < other._wrap_v) ? -1 : 1; + } + if (_wrap_w != other._wrap_w) { + return (_wrap_w < other._wrap_w) ? -1 : 1; + } + if (_minfilter != other._minfilter) { + return (_minfilter < other._minfilter) ? -1 : 1; + } + if (_magfilter != other._magfilter) { + return (_magfilter < other._magfilter) ? -1 : 1; + } + if (_anisotropic_degree != other._anisotropic_degree) { + return (_anisotropic_degree < other._anisotropic_degree) ? -1 : 1; + } + if (_border_color != other._border_color) { + return (_border_color < other._border_color) ? -1 : 1; + } + if (_min_lod != other._min_lod) { + return (_min_lod < other._min_lod) ? -1 : 1; + } + if (_max_lod != other._max_lod) { + return (_max_lod < other._max_lod) ? -1 : 1; + } + if (_lod_bias != other._lod_bias) { + return (_lod_bias < other._lod_bias) ? -1 : 1; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void SamplerState:: +output(ostream &out) const { + out + << "sampler" + << " wrap(u=" << _wrap_u << ", v=" << _wrap_v << ", w=" << _wrap_w + << ", border=" << _border_color << ")" + << " filter(min=" << _minfilter << ", mag=" << _magfilter + << ", aniso=" << _anisotropic_degree << ")" + << " lod(min=" << _min_lod << ", max=" << _max_lod + << ", bias=" << _lod_bias << ")"; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::write +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void SamplerState:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) << "SamplerState\n"; + indent(out, indent_level) << " wrap_u = " << _wrap_u << "\n"; + indent(out, indent_level) << " wrap_v = " << _wrap_v << "\n"; + indent(out, indent_level) << " wrap_w = " << _wrap_w << "\n"; + indent(out, indent_level) << " minfilter = " << _minfilter << "\n"; + indent(out, indent_level) << " magfilter = " << _magfilter << "\n"; + indent(out, indent_level) << " anisotropic_degree = " << _anisotropic_degree << "\n"; + indent(out, indent_level) << " border_color = " << _border_color << "\n"; + indent(out, indent_level) << " min_lod = " << _min_lod << "\n"; + indent(out, indent_level) << " max_lod = " << _max_lod << "\n"; + indent(out, indent_level) << " lod_bias = " << _lod_bias << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::write_datagram +// Access: Public +// Description: Encodes the sampler state into a datagram. +//////////////////////////////////////////////////////////////////// +void SamplerState:: +write_datagram(Datagram &me) const { + me.add_uint8(_wrap_u); + me.add_uint8(_wrap_v); + me.add_uint8(_wrap_w); + me.add_uint8(_minfilter); + me.add_uint8(_magfilter); + me.add_int16(_anisotropic_degree); + _border_color.write_datagram(me); + me.add_stdfloat(_min_lod); + me.add_stdfloat(_max_lod); + me.add_stdfloat(_lod_bias); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::read_datagram +// Access: Protected +// Description: Reads the sampler state from the datagram that has +// been previously written using write_datagram. +//////////////////////////////////////////////////////////////////// +void SamplerState:: +read_datagram(DatagramIterator &scan, BamReader *manager) { + _wrap_u = (WrapMode)scan.get_uint8(); + _wrap_v = (WrapMode)scan.get_uint8(); + _wrap_w = (WrapMode)scan.get_uint8(); + _minfilter = (FilterType)scan.get_uint8(); + _magfilter = (FilterType)scan.get_uint8(); + _anisotropic_degree = scan.get_int16(); + _border_color.read_datagram(scan); + + if (manager->get_file_minor_ver() >= 36) { + // These were added with the introduction of SamplerState. + // Since Texture::do_fillin_body calls this, we still have to + // preserve backward compatibility here. + _min_lod = scan.get_stdfloat(); + _max_lod = scan.get_stdfloat(); + _lod_bias = scan.get_stdfloat(); + } else { + _min_lod = -1000; + _max_lod = 1000; + _lod_bias = 0; + } +} diff --git a/panda/src/gobj/samplerState.h b/panda/src/gobj/samplerState.h new file mode 100644 index 0000000000..2d9528246a --- /dev/null +++ b/panda/src/gobj/samplerState.h @@ -0,0 +1,210 @@ +// Filename: samplerState.h +// Created by: rdb (09Dec14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef SAMPLERSTATE_H +#define SAMPLERSTATE_H + +#include "pandabase.h" + +#include "typedObject.h" +#include "namable.h" +#include "luse.h" +#include "numeric_types.h" +#include "config_gobj.h" + +class FactoryParams; +class GraphicsStateGuardianBase; +class PreparedGraphicsObjects; +class SamplerContext; + +//////////////////////////////////////////////////////////////////// +// Class : SamplerState +// Description : Represents a set of settings that indicate how a +// texture is sampled. This can be used to sample the +// same texture using different settings in different +// places. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_GOBJ SamplerState { +PUBLISHED: + enum FilterType { + // Mag Filter and Min Filter + + // Point sample the pixel + FT_nearest, + + // Bilinear filtering of four neighboring pixels + FT_linear, + + // Min Filter Only + + // Point sample the pixel from the nearest mipmap level + FT_nearest_mipmap_nearest, + + // Bilinear filter the pixel from the nearest mipmap level + FT_linear_mipmap_nearest, + + // Point sample the pixel from two mipmap levels, and linearly blend + FT_nearest_mipmap_linear, + + // A.k.a. trilinear filtering: Bilinear filter the pixel from + // two mipmap levels, and linearly blend the results. + FT_linear_mipmap_linear, + + // The OpenGL ARB_shadow extension can be thought of as a kind of filtering. + FT_shadow, + + // Default is usually linear, but it depends on format. + // This was added at the end of the list to avoid bumping TXO version #. + FT_default, + + // Returned by string_filter_type() for an invalid match. + FT_invalid + }; + + enum WrapMode { + WM_clamp, // coords that would be outside [0-1] are clamped to 0 or 1 + WM_repeat, + WM_mirror, + WM_mirror_once, // mirror once, then clamp + WM_border_color, // coords outside [0-1] use explicit border color + // Returned by string_wrap_mode() for an invalid match. + WM_invalid + }; + + INLINE SamplerState(); + INLINE static const SamplerState &get_default(); + + INLINE void set_wrap_u(WrapMode wrap); + INLINE void set_wrap_v(WrapMode wrap); + INLINE void set_wrap_w(WrapMode wrap); + INLINE void set_minfilter(FilterType filter); + INLINE void set_magfilter(FilterType filter); + INLINE void set_anisotropic_degree(int anisotropic_degree); + INLINE void set_border_color(const LColor &color); + INLINE void set_min_lod(PN_stdfloat min_lod); + INLINE void set_max_lod(PN_stdfloat max_lod); + INLINE void set_lod_bias(PN_stdfloat lod_bias); + + INLINE WrapMode get_wrap_u() const; + INLINE WrapMode get_wrap_v() const; + INLINE WrapMode get_wrap_w() const; + INLINE FilterType get_minfilter() const; + INLINE FilterType get_magfilter() const; + FilterType get_effective_minfilter() const; + FilterType get_effective_magfilter() const; + INLINE int get_anisotropic_degree() const; + INLINE int get_effective_anisotropic_degree() const; + INLINE const LColor &get_border_color() const; + INLINE PN_stdfloat get_min_lod() const; + INLINE PN_stdfloat get_max_lod() const; + INLINE PN_stdfloat get_lod_bias() const; + + static string format_filter_type(FilterType ft); + static FilterType string_filter_type(const string &str); + + static string format_wrap_mode(WrapMode wm); + static WrapMode string_wrap_mode(const string &str); + + INLINE bool operator == (const SamplerState &other) const; + INLINE bool operator != (const SamplerState &other) const; + INLINE bool operator < (const SamplerState &other) const; + + void prepare(PreparedGraphicsObjects *prepared_objects) const; + bool is_prepared(PreparedGraphicsObjects *prepared_objects) const; + void release(PreparedGraphicsObjects *prepared_objects) const; + + SamplerContext *prepare_now(PreparedGraphicsObjects *prepared_objects, + GraphicsStateGuardianBase *gsg) const; + +public: + int compare_to(const SamplerState &other) const; + + void output(ostream &out) const; + void write(ostream &out, int indent) const; + +private: + LColor _border_color; + PN_stdfloat _min_lod; + PN_stdfloat _max_lod; + PN_stdfloat _lod_bias; + + // These are packed in a way that this class conveniently fits in + // 32 bytes; feel free to change the packing as necessary when + // more enum values are added. + FilterType _minfilter : 4; + FilterType _magfilter : 4; + WrapMode _wrap_u : 4; + WrapMode _wrap_v : 4; + WrapMode _wrap_w : 4; + int _anisotropic_degree : 12; + + static SamplerState _default; + +public: + void write_datagram(Datagram &destination) const; + void read_datagram(DatagramIterator &source, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedObject::init_type(); + register_type(_type_handle, "SamplerState", + TypedObject::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; +}; + +extern EXPCL_PANDA_GOBJ ConfigVariableEnum texture_minfilter; +extern EXPCL_PANDA_GOBJ ConfigVariableEnum texture_magfilter; +extern EXPCL_PANDA_GOBJ ConfigVariableInt texture_anisotropic_degree; + +INLINE ostream &operator << (ostream &out, const SamplerState &m) { + m.output(out); + return out; +} + +INLINE ostream &operator << (ostream &out, SamplerState::FilterType ft) { + return out << SamplerState::format_filter_type(ft); +} + +INLINE istream &operator >> (istream &in, SamplerState::FilterType &ft) { + string word; + in >> word; + ft = SamplerState::string_filter_type(word); + return in; +} + +INLINE ostream &operator << (ostream &out, SamplerState::WrapMode wm) { + return out << SamplerState::format_wrap_mode(wm); +} + +INLINE istream &operator >> (istream &in, SamplerState::WrapMode &wm) { + string word; + in >> word; + wm = SamplerState::string_wrap_mode(word); + return in; +} + +#include "samplerState.I" + +#endif diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index f2813cc2a0..63625818cd 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -62,7 +62,7 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size, int z_size, Texture::ComponentType component_type, Texture::Format format) { CDWriter cdata(_cycler, true); - do_setup_texture(cdata, texture_type, x_size, y_size, z_size, + do_setup_texture(cdata, texture_type, x_size, y_size, z_size, component_type, format); } @@ -112,7 +112,7 @@ setup_2d_texture() { // image data. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -setup_2d_texture(int x_size, int y_size, ComponentType component_type, +setup_2d_texture(int x_size, int y_size, ComponentType component_type, Format format) { setup_texture(TT_2d_texture, x_size, y_size, 1, component_type, format); } @@ -191,7 +191,7 @@ setup_cube_map() { // Description: Sets the texture as an empty cube map texture with // the specified dimensions and properties. Follow up // with set_ram_image() or modify_ram_image() to fill -// the image data. +// the image data. // // Note that a cube map should always consist of six // square images, so x_size and y_size will be the same, @@ -273,7 +273,7 @@ write(const Filename &fullpath) { // the page index. //////////////////////////////////////////////////////////////////// INLINE bool Texture:: -write(const Filename &fullpath, int z, int n, +write(const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps) { CDWriter cdata(_cycler, false); return do_write(cdata, fullpath, z, n, write_pages, write_mipmaps); @@ -523,7 +523,7 @@ has_alpha_fullpath() const { //////////////////////////////////////////////////////////////////// // Function: Texture::get_alpha_fullpath // Access: Published -// Description: +// Description: // Returns the alpha_fullpath that has been set. This // is the full path to the alpha part of the image file // as it was found along the texture search path. @@ -594,7 +594,7 @@ get_num_views() const { //////////////////////////////////////////////////////////////////// // Function: Texture::get_num_pages // Access: Published -// Description: Returns the total number of pages in the texture. +// Description: Returns the total number of pages in the texture. // Each "page" is a 2-d texture image within the larger // image--a face of a cube map, or a level of a 3-d // texture. Normally, get_num_pages() is the same as @@ -795,10 +795,17 @@ get_component_type() const { //////////////////////////////////////////////////////////////////// // Function: Texture::set_wrap_u // Access: Published -// Description: +// Description: This setting determines what happens when the +// texture is sampled with a U value outside the range +// 0.0-1.0. The default is WM_repeat, which indicates +// that the texture should repeat indefinitely. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -set_wrap_u(Texture::WrapMode wrap) { +set_wrap_u(SamplerState::WrapMode wrap) { CDWriter cdata(_cycler, true); do_set_wrap_u(cdata, wrap); } @@ -806,10 +813,17 @@ set_wrap_u(Texture::WrapMode wrap) { //////////////////////////////////////////////////////////////////// // Function: Texture::set_wrap_v // Access: Published -// Description: +// Description: This setting determines what happens when the +// texture is sampled with a V value outside the range +// 0.0-1.0. The default is WM_repeat, which indicates +// that the texture should repeat indefinitely. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -set_wrap_v(Texture::WrapMode wrap) { +set_wrap_v(SamplerState::WrapMode wrap) { CDWriter cdata(_cycler, true); do_set_wrap_v(cdata, wrap); } @@ -818,9 +832,13 @@ set_wrap_v(Texture::WrapMode wrap) { // Function: Texture::set_wrap_w // Access: Published // Description: The W wrap direction is only used for 3-d textures. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -set_wrap_w(Texture::WrapMode wrap) { +set_wrap_w(SamplerState::WrapMode wrap) { CDWriter cdata(_cycler, true); do_set_wrap_w(cdata, wrap); } @@ -828,10 +846,15 @@ set_wrap_w(Texture::WrapMode wrap) { //////////////////////////////////////////////////////////////////// // Function: Texture::set_minfilter // Access: Published -// Description: +// Description: Sets the filtering method that should be used when +// viewing the texture from a distance. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -set_minfilter(Texture::FilterType filter) { +set_minfilter(SamplerState::FilterType filter) { CDWriter cdata(_cycler, true); do_set_minfilter(cdata, filter); } @@ -839,10 +862,15 @@ set_minfilter(Texture::FilterType filter) { //////////////////////////////////////////////////////////////////// // Function: Texture::set_magfilter // Access: Published -// Description: +// Description: Sets the filtering method that should be used when +// viewing the texture up close. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -set_magfilter(Texture::FilterType filter) { +set_magfilter(SamplerState::FilterType filter) { CDWriter cdata(_cycler, true); do_set_magfilter(cdata, filter); } @@ -859,6 +887,10 @@ set_magfilter(Texture::FilterType filter) { // value to 1. To explicitly enable anisotropic // filtering, set it to a value higher than 1; larger // numbers indicate greater degrees of filtering. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: set_anisotropic_degree(int anisotropic_degree) { @@ -873,6 +905,10 @@ set_anisotropic_degree(int anisotropic_degree) { // Some OpenGL implementations use a border for tiling // textures; in Panda, it is only used for specifying // the clamp color. +// +// This sets the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE void Texture:: set_border_color(const LColor &color) { @@ -884,7 +920,7 @@ set_border_color(const LColor &color) { // Function: Texture::set_compression // Access: Published // Description: Requests that this particular Texture be compressed -// when it is loaded into texture memory. +// when it is loaded into texture memory. // // This refers to the internal compression of the // texture image within texture memory; it is not @@ -928,16 +964,35 @@ set_render_to_texture(bool render_to_texture) { cdata->_render_to_texture = render_to_texture; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_default_sampler +// Access: Published +// Description: This returns the default sampler state for this +// texture, containing the wrap and filter properties +// specified on the texture level; it may still be +// overridden by a sampler state specified at a higher +// level. +//////////////////////////////////////////////////////////////////// +INLINE const SamplerState &Texture:: +get_default_sampler() const { + CDReader cdata(_cycler); + return cdata->_default_sampler; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::get_wrap_u // Access: Published // Description: Returns the wrap mode of the texture in the U // direction. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// -INLINE Texture::WrapMode Texture:: +INLINE SamplerState::WrapMode Texture:: get_wrap_u() const { CDReader cdata(_cycler); - return cdata->_wrap_u; + return cdata->_default_sampler.get_wrap_u(); } //////////////////////////////////////////////////////////////////// @@ -945,11 +1000,15 @@ get_wrap_u() const { // Access: Published // Description: Returns the wrap mode of the texture in the V // direction. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// -INLINE Texture::WrapMode Texture:: +INLINE SamplerState::WrapMode Texture:: get_wrap_v() const { CDReader cdata(_cycler); - return cdata->_wrap_v; + return cdata->_default_sampler.get_wrap_v(); } //////////////////////////////////////////////////////////////////// @@ -958,11 +1017,15 @@ get_wrap_v() const { // Description: Returns the wrap mode of the texture in the W // direction. This is the depth direction of 3-d // textures. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// -INLINE Texture::WrapMode Texture:: +INLINE SamplerState::WrapMode Texture:: get_wrap_w() const { CDReader cdata(_cycler); - return cdata->_wrap_w; + return cdata->_default_sampler.get_wrap_w(); } //////////////////////////////////////////////////////////////////// @@ -973,11 +1036,15 @@ get_wrap_w() const { // constants, then the texture requires mipmaps. This // may return FT_default; see also // get_effective_minfilter(). +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// -INLINE Texture::FilterType Texture:: +INLINE SamplerState::FilterType Texture:: get_minfilter() const { CDReader cdata(_cycler); - return cdata->_minfilter; + return cdata->_default_sampler.get_minfilter(); } //////////////////////////////////////////////////////////////////// @@ -987,11 +1054,51 @@ get_minfilter() const { // magnification. The mipmap constants are invalid // here. This may return FT_default; see also // get_effective_minfilter(). +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// -INLINE Texture::FilterType Texture:: +INLINE SamplerState::FilterType Texture:: get_magfilter() const { CDReader cdata(_cycler); - return cdata->_magfilter; + return cdata->_default_sampler.get_magfilter(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_effective_minfilter +// Access: Published +// Description: Returns the filter mode of the texture for +// minification, with special treatment for FT_default. +// This will normally not return FT_default, unless +// there is an error in the config file. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. +//////////////////////////////////////////////////////////////////// +SamplerState::FilterType Texture:: +get_effective_minfilter() const { + CDReader cdata(_cycler); + return cdata->_default_sampler.get_effective_minfilter(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_effective_magfilter +// Access: Published +// Description: Returns the filter mode of the texture for +// magnification, with special treatment for FT_default. +// This will normally not return FT_default, unless +// there is an error in the config file. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. +//////////////////////////////////////////////////////////////////// +SamplerState::FilterType Texture:: +get_effective_magfilter() const { + CDReader cdata(_cycler); + return cdata->_default_sampler.get_effective_magfilter(); } //////////////////////////////////////////////////////////////////// @@ -1001,11 +1108,15 @@ get_magfilter() const { // should be applied to the texture. This value may // return 0, indicating the default value; see also // get_effective_anisotropic_degree. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE int Texture:: get_anisotropic_degree() const { CDReader cdata(_cycler); - return cdata->_anisotropic_degree; + return cdata->_default_sampler.get_anisotropic_degree(); } //////////////////////////////////////////////////////////////////// @@ -1015,14 +1126,15 @@ get_anisotropic_degree() const { // should be applied to the texture. This value will // normally not return 0, unless there is an error in // the config file. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE int Texture:: get_effective_anisotropic_degree() const { CDReader cdata(_cycler); - if (cdata->_anisotropic_degree != 0) { - return cdata->_anisotropic_degree; - } - return texture_anisotropic_degree; + return cdata->_default_sampler.get_effective_anisotropic_degree(); } //////////////////////////////////////////////////////////////////// @@ -1032,11 +1144,15 @@ get_effective_anisotropic_degree() const { // Some OpenGL implementations use a border for tiling // textures; in Panda, it is only used for specifying // the clamp color. +// +// This returns the default sampler state for this +// texture; it may still be overridden by a sampler +// state specified at a higher level. //////////////////////////////////////////////////////////////////// INLINE LColor Texture:: get_border_color() const { CDReader cdata(_cycler); - return cdata->_border_color; + return cdata->_default_sampler.get_border_color(); } //////////////////////////////////////////////////////////////////// @@ -2400,7 +2516,7 @@ adjust_this_size(int &x_size, int &y_size, const string &name, //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_ram_image_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_ram_image_size(const CData *cdata) const { @@ -2413,18 +2529,18 @@ do_get_ram_image_size(const CData *cdata) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_has_ram_mipmap_image // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool Texture:: do_has_ram_mipmap_image(const CData *cdata, int n) const { - return (n >= 0 && n < (int)cdata->_ram_images.size() && + return (n >= 0 && n < (int)cdata->_ram_images.size() && !cdata->_ram_images[n]._image.empty()); } //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_expected_ram_image_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_expected_ram_image_size(const CData *cdata) const { @@ -2434,7 +2550,7 @@ do_get_expected_ram_image_size(const CData *cdata) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_expected_ram_view_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_expected_ram_view_size(const CData *cdata) const { @@ -2444,7 +2560,7 @@ do_get_expected_ram_view_size(const CData *cdata) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_expected_ram_page_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_expected_ram_page_size(const CData *cdata) const { @@ -2454,7 +2570,7 @@ do_get_expected_ram_page_size(const CData *cdata) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_expected_ram_mipmap_image_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_expected_ram_mipmap_image_size(const CData *cdata, int n) const { @@ -2464,7 +2580,7 @@ do_get_expected_ram_mipmap_image_size(const CData *cdata, int n) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_expected_ram_mipmap_view_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_expected_ram_mipmap_view_size(const CData *cdata, int n) const { @@ -2474,7 +2590,7 @@ do_get_expected_ram_mipmap_view_size(const CData *cdata, int n) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_expected_ram_mipmap_page_size // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: do_get_expected_ram_mipmap_page_size(const CData *cdata, int n) const { @@ -2494,7 +2610,7 @@ do_get_expected_mipmap_num_pages(const CData *cdata, int n) const { //////////////////////////////////////////////////////////////////// // Function: Texture::do_clear_ram_image // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void Texture:: do_clear_ram_image(CData *cdata) { @@ -2505,7 +2621,7 @@ do_clear_ram_image(CData *cdata) { //////////////////////////////////////////////////////////////////// // Function: Texture::do_get_auto_texture_scale // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE AutoTextureScale Texture:: do_get_auto_texture_scale(const CData *cdata) const { @@ -2647,7 +2763,7 @@ is_dds_filename(const Filename &fullpath) { //////////////////////////////////////////////////////////////////// // Function: Texture::CData::inc_properties_modified // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void Texture::CData:: inc_properties_modified() { @@ -2657,7 +2773,7 @@ inc_properties_modified() { //////////////////////////////////////////////////////////////////// // Function: Texture::CData::inc_image_modified // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void Texture::CData:: inc_image_modified() { @@ -2667,7 +2783,7 @@ inc_image_modified() { //////////////////////////////////////////////////////////////////// // Function: Texture::CData::inc_simple_image_modified // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void Texture::CData:: inc_simple_image_modified() { @@ -2677,7 +2793,7 @@ inc_simple_image_modified() { //////////////////////////////////////////////////////////////////// // Function: Texture::RamImage::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE Texture::RamImage:: RamImage() : diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index bd53fbdddb..ed3252f5c7 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -58,36 +58,6 @@ ConfigVariableEnum texture_quality_level "it has little or no effect on normal, hardware-accelerated " "renderers. See Texture::set_quality_level().")); -ConfigVariableEnum texture_minfilter -("texture-minfilter", Texture::FT_linear, - PRC_DESC("This specifies the default minfilter that is applied to a texture " - "in the absence of a specific minfilter setting. Normally this " - "is either 'linear' to disable mipmapping by default, or " - "'mipmap', to enable trilinear mipmapping by default. This " - "does not apply to depth textures. Note if this variable is " - "changed at runtime, you may need to reload textures explicitly " - "in order to change their visible properties.")); - -ConfigVariableEnum texture_magfilter -("texture-magfilter", Texture::FT_linear, - PRC_DESC("This specifies the default magfilter that is applied to a texture " - "in the absence of a specific magfilter setting. Normally this " - "is 'linear' (since mipmapping does not apply to magfilters). This " - "does not apply to depth textures. Note if this variable is " - "changed at runtime, you may need to reload textures explicitly " - "in order to change their visible properties.")); - -ConfigVariableInt texture_anisotropic_degree -("texture-anisotropic-degree", 1, - PRC_DESC("This specifies the default anisotropic degree that is applied " - "to a texture in the absence of a particular anisotropic degree " - "setting (that is, a texture for which the anisotropic degree " - "is 0, meaning the default setting). It should be 1 to disable " - "anisotropic filtering, or a higher number to enable it. " - "Note if this variable is " - "changed at runtime, you may need to reload textures explicitly " - "in order to change their visible properties.")); - PStatCollector Texture::_texture_read_pcollector("*:Texture:Read"); TypeHandle Texture::_type_handle; TypeHandle Texture::CData::_type_handle; @@ -380,9 +350,10 @@ void Texture:: generate_alpha_scale_map() { CDWriter cdata(_cycler, true); do_setup_texture(cdata, TT_1d_texture, 256, 1, 1, T_unsigned_byte, F_alpha); - cdata->_wrap_u = WM_clamp; - cdata->_minfilter = FT_nearest; - cdata->_magfilter = FT_nearest; + cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp); + cdata->_default_sampler.set_minfilter(SamplerState::FT_nearest); + cdata->_default_sampler.set_magfilter(SamplerState::FT_nearest); + cdata->_compression = CM_off; cdata->inc_image_modified(); @@ -877,48 +848,6 @@ load_related(const InternalName *suffix) const { return res; } -//////////////////////////////////////////////////////////////////// -// Function: Texture::get_effective_minfilter -// Access: Published -// Description: Returns the filter mode of the texture for -// minification, with special treatment for FT_default. -// This will normally not return FT_default, unless -// there is an error in the config file. -//////////////////////////////////////////////////////////////////// -Texture::FilterType Texture:: -get_effective_minfilter() const { - CDReader cdata(_cycler); - if (cdata->_minfilter != FT_default) { - return cdata->_minfilter; - } - if (cdata->_format == Texture::F_depth_stencil || - cdata->_format == Texture::F_depth_component) { - return FT_nearest; - } - return texture_minfilter; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::get_effective_magfilter -// Access: Published -// Description: Returns the filter mode of the texture for -// magnification, with special treatment for FT_default. -// This will normally not return FT_default, unless -// there is an error in the config file. -//////////////////////////////////////////////////////////////////// -Texture::FilterType Texture:: -get_effective_magfilter() const { - CDReader cdata(_cycler); - if (cdata->_magfilter != FT_default) { - return cdata->_magfilter; - } - if (cdata->_format == Texture::F_depth_stencil || - cdata->_format == Texture::F_depth_component) { - return FT_nearest; - } - return texture_magfilter; -} - //////////////////////////////////////////////////////////////////// // Function: Texture::set_ram_image_as // Access: Published @@ -1789,32 +1718,7 @@ write(ostream &out, int indent_level) const { indent(out, indent_level + 2); - switch (cdata->_texture_type) { - case TT_1d_texture: - out << cdata->_wrap_u << ", "; - break; - - case TT_2d_texture: - out << cdata->_wrap_u << " x " << cdata->_wrap_v << ", "; - break; - - case TT_3d_texture: - out << cdata->_wrap_u << " x " << cdata->_wrap_v << " x " << cdata->_wrap_w << ", "; - break; - - case TT_2d_texture_array: - out << cdata->_wrap_u << " x " << cdata->_wrap_v << " x " << cdata->_wrap_w << ", "; - break; - - case TT_cube_map: - break; - } - - out << "min " << cdata->_minfilter - << ", mag " << cdata->_magfilter - << ", aniso " << cdata->_anisotropic_degree - << ", border " << cdata->_border_color - << "\n"; + cdata->_default_sampler.output(out); if (do_has_ram_image(cdata)) { indent(out, indent_level + 2) @@ -1879,7 +1783,7 @@ set_size_padded(int x, int y, int z) { do_set_y_size(cdata, y); do_set_z_size(cdata, z); } - do_set_pad_size(cdata, + do_set_pad_size(cdata, cdata->_x_size - x, cdata->_y_size - y, cdata->_z_size - z); @@ -1909,10 +1813,10 @@ set_orig_file_size(int x, int y, int z) { bool Texture:: is_mipmap(FilterType filter_type) { switch (filter_type) { - case FT_nearest_mipmap_nearest: - case FT_linear_mipmap_nearest: - case FT_nearest_mipmap_linear: - case FT_linear_mipmap_linear: + case SamplerState::FT_nearest_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return true; default: @@ -2315,127 +2219,6 @@ string_format(const string &str) { return F_rgba; } -//////////////////////////////////////////////////////////////////// -// Function: Texture::format_filter_type -// Access: Published, Static -// Description: Returns the indicated FilterType converted to a -// string word. -//////////////////////////////////////////////////////////////////// -string Texture:: -format_filter_type(FilterType ft) { - switch (ft) { - case FT_nearest: - return "nearest"; - case FT_linear: - return "linear"; - - case FT_nearest_mipmap_nearest: - return "nearest_mipmap_nearest"; - case FT_linear_mipmap_nearest: - return "linear_mipmap_nearest"; - case FT_nearest_mipmap_linear: - return "nearest_mipmap_linear"; - case FT_linear_mipmap_linear: - return "linear_mipmap_linear"; - - case FT_shadow: - return "shadow"; - - case FT_default: - return "default"; - - case FT_invalid: - return "invalid"; - } - return "**invalid**"; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::string_filter_type -// Access: Public -// Description: Returns the FilterType value associated with the given -// string representation, or FT_invalid if the string -// does not match any known FilterType value. -//////////////////////////////////////////////////////////////////// -Texture::FilterType Texture:: -string_filter_type(const string &string) { - if (cmp_nocase_uh(string, "nearest") == 0) { - return FT_nearest; - } else if (cmp_nocase_uh(string, "linear") == 0) { - return FT_linear; - } else if (cmp_nocase_uh(string, "nearest_mipmap_nearest") == 0) { - return FT_nearest_mipmap_nearest; - } else if (cmp_nocase_uh(string, "linear_mipmap_nearest") == 0) { - return FT_linear_mipmap_nearest; - } else if (cmp_nocase_uh(string, "nearest_mipmap_linear") == 0) { - return FT_nearest_mipmap_linear; - } else if (cmp_nocase_uh(string, "linear_mipmap_linear") == 0) { - return FT_linear_mipmap_linear; - } else if (cmp_nocase_uh(string, "mipmap") == 0) { - return FT_linear_mipmap_linear; - } else if (cmp_nocase_uh(string, "shadow") == 0) { - return FT_shadow; - } else if (cmp_nocase_uh(string, "default") == 0) { - return FT_default; - } else { - return FT_invalid; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::format_wrap_mode -// Access: Published, Static -// Description: Returns the indicated WrapMode converted to a -// string word. -//////////////////////////////////////////////////////////////////// -string Texture:: -format_wrap_mode(WrapMode wm) { - switch (wm) { - case WM_clamp: - return "clamp"; - case WM_repeat: - return "repeat"; - case WM_mirror: - return "mirror"; - case WM_mirror_once: - return "mirror_once"; - case WM_border_color: - return "border_color"; - - case WM_invalid: - return "invalid"; - } - - return "**invalid**"; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::string_wrap_mode -// Access: Public -// Description: Returns the WrapMode value associated with the given -// string representation, or WM_invalid if the string -// does not match any known WrapMode value. -//////////////////////////////////////////////////////////////////// -Texture::WrapMode Texture:: -string_wrap_mode(const string &string) { - if (cmp_nocase_uh(string, "repeat") == 0 || - cmp_nocase_uh(string, "wrap") == 0) { - return WM_repeat; - } else if (cmp_nocase_uh(string, "clamp") == 0) { - return WM_clamp; - } else if (cmp_nocase_uh(string, "mirror") == 0 || - cmp_nocase_uh(string, "mirrored_repeat") == 0) { - return WM_mirror; - } else if (cmp_nocase_uh(string, "mirror_once") == 0) { - return WM_mirror_once; - } else if (cmp_nocase_uh(string, "border_color") == 0 || - cmp_nocase_uh(string, "border") == 0) { - return WM_border_color; - } else { - return WM_invalid; - } -} - //////////////////////////////////////////////////////////////////// // Function: Texture::format_compression_mode // Access: Published, Static @@ -3955,7 +3738,7 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only) // mipmap levels to disk files. //////////////////////////////////////////////////////////////////// bool Texture:: -do_write(CData *cdata, +do_write(CData *cdata, const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps) { if (is_txo_filename(fullpath)) { if (!do_has_bam_rawdata(cdata)) { @@ -4273,20 +4056,20 @@ unlocked_ensure_ram_image(bool allow_compression) { // We need to reload. nassertr(!_reloading, NULL); _reloading = true; - + PT(Texture) tex = do_make_copy(cdata); _cycler.release_read(cdata); _lock.release(); - + // Perform the actual reload in a copy of the texture, while our // own mutex is left unlocked. CDWriter cdata_tex(tex->_cycler, true); tex->do_reload_ram_image(cdata_tex, allow_compression); - + _lock.acquire(); CData *cdataw = _cycler.write_upstream(false, current_thread); - + // Rather than calling do_assign(), which would copy *all* of the // reloaded texture's properties over, we only copy in the ones // which are relevant to the ram image. This way, if the @@ -4295,7 +4078,7 @@ unlocked_ensure_ram_image(bool allow_compression) { // texture. cdataw->_orig_file_x_size = cdata_tex->_orig_file_x_size; cdataw->_orig_file_y_size = cdata_tex->_orig_file_y_size; - + // If any of *these* properties have changed, the texture has // changed in some fundamental way. Update it appropriately. if (cdata_tex->_x_size != cdataw->_x_size || @@ -4306,33 +4089,33 @@ unlocked_ensure_ram_image(bool allow_compression) { cdata_tex->_component_width != cdataw->_component_width || cdata_tex->_texture_type != cdataw->_texture_type || cdata_tex->_component_type != cdataw->_component_type) { - + cdataw->_x_size = cdata_tex->_x_size; cdataw->_y_size = cdata_tex->_y_size; cdataw->_z_size = cdata_tex->_z_size; cdataw->_num_views = cdata_tex->_num_views; - + cdataw->_num_components = cdata_tex->_num_components; cdataw->_component_width = cdata_tex->_component_width; cdataw->_texture_type = cdata_tex->_texture_type; cdataw->_format = cdata_tex->_format; cdataw->_component_type = cdata_tex->_component_type; - + cdataw->inc_properties_modified(); cdataw->inc_image_modified(); } - + cdataw->_keep_ram_image = cdata_tex->_keep_ram_image; cdataw->_ram_image_compression = cdata_tex->_ram_image_compression; cdataw->_ram_images = cdata_tex->_ram_images; - + nassertr(_reloading, NULL); _reloading = false; - + // We don't generally increment the cdata->_image_modified semaphore, // because this is just a reload, and presumably the image hasn't // changed (unless we hit the if condition above). - + _cvar.notify_all(); // Return the still-locked cdata. @@ -4626,7 +4409,7 @@ consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression) { // operation, false if it wasn't. //////////////////////////////////////////////////////////////////// bool Texture:: -do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps, +do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps, bool allow_compression) { bool modified = false; @@ -5158,10 +4941,10 @@ do_setup_texture(CData *cdata, Texture::TextureType texture_type, int x_size, in // In principle the wrap mode shouldn't mean anything to a cube // map, but some drivers seem to misbehave if it's other than - // WM_clamp. - cdata->_wrap_u = WM_clamp; - cdata->_wrap_v = WM_clamp; - cdata->_wrap_w = WM_clamp; + // SamplerState::WM_clamp. + cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp); + cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp); + cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp); break; } @@ -5359,10 +5142,10 @@ do_set_num_views(CData *cdata, int num_views) { // Description: //////////////////////////////////////////////////////////////////// void Texture:: -do_set_wrap_u(CData *cdata, Texture::WrapMode wrap) { - if (cdata->_wrap_u != wrap) { +do_set_wrap_u(CData *cdata, SamplerState::WrapMode wrap) { + if (cdata->_default_sampler.get_wrap_u() != wrap) { cdata->inc_properties_modified(); - cdata->_wrap_u = wrap; + cdata->_default_sampler.set_wrap_u(wrap); } } @@ -5372,10 +5155,10 @@ do_set_wrap_u(CData *cdata, Texture::WrapMode wrap) { // Description: //////////////////////////////////////////////////////////////////// void Texture:: -do_set_wrap_v(CData *cdata, Texture::WrapMode wrap) { - if (cdata->_wrap_v != wrap) { +do_set_wrap_v(CData *cdata, SamplerState::WrapMode wrap) { + if (cdata->_default_sampler.get_wrap_v() != wrap) { cdata->inc_properties_modified(); - cdata->_wrap_v = wrap; + cdata->_default_sampler.set_wrap_v(wrap); } } @@ -5385,10 +5168,10 @@ do_set_wrap_v(CData *cdata, Texture::WrapMode wrap) { // Description: //////////////////////////////////////////////////////////////////// void Texture:: -do_set_wrap_w(CData *cdata, Texture::WrapMode wrap) { - if (cdata->_wrap_w != wrap) { +do_set_wrap_w(CData *cdata, SamplerState::WrapMode wrap) { + if (cdata->_default_sampler.get_wrap_w() != wrap) { cdata->inc_properties_modified(); - cdata->_wrap_w = wrap; + cdata->_default_sampler.set_wrap_w(wrap); } } @@ -5398,10 +5181,10 @@ do_set_wrap_w(CData *cdata, Texture::WrapMode wrap) { // Description: //////////////////////////////////////////////////////////////////// void Texture:: -do_set_minfilter(CData *cdata, Texture::FilterType filter) { - if (cdata->_minfilter != filter) { +do_set_minfilter(CData *cdata, SamplerState::FilterType filter) { + if (cdata->_default_sampler.get_minfilter() != filter) { cdata->inc_properties_modified(); - cdata->_minfilter = filter; + cdata->_default_sampler.set_minfilter(filter); } } @@ -5411,10 +5194,10 @@ do_set_minfilter(CData *cdata, Texture::FilterType filter) { // Description: //////////////////////////////////////////////////////////////////// void Texture:: -do_set_magfilter(CData *cdata, Texture::FilterType filter) { - if (cdata->_magfilter != filter) { +do_set_magfilter(CData *cdata, SamplerState::FilterType filter) { + if (cdata->_default_sampler.get_magfilter() != filter) { cdata->inc_properties_modified(); - cdata->_magfilter = filter; + cdata->_default_sampler.set_magfilter(filter); } } @@ -5425,9 +5208,9 @@ do_set_magfilter(CData *cdata, Texture::FilterType filter) { //////////////////////////////////////////////////////////////////// void Texture:: do_set_anisotropic_degree(CData *cdata, int anisotropic_degree) { - if (cdata->_anisotropic_degree != anisotropic_degree) { + if (cdata->_default_sampler.get_anisotropic_degree() != anisotropic_degree) { cdata->inc_properties_modified(); - cdata->_anisotropic_degree = anisotropic_degree; + cdata->_default_sampler.set_anisotropic_degree(anisotropic_degree); } } @@ -5438,9 +5221,9 @@ do_set_anisotropic_degree(CData *cdata, int anisotropic_degree) { //////////////////////////////////////////////////////////////////// void Texture:: do_set_border_color(CData *cdata, const LColor &color) { - if (cdata->_border_color != color) { + if (cdata->_default_sampler.get_border_color() != color) { cdata->inc_properties_modified(); - cdata->_border_color = color; + cdata->_default_sampler.set_border_color(color); } } @@ -7870,7 +7653,7 @@ do_write_datagram_header(CData *cdata, BamWriter *manager, Datagram &me, bool &h // loads the bam file later will have access to the image file on // disk. BamWriter::BamTextureMode file_texture_mode = manager->get_file_texture_mode(); - has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata || + has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata || (cdata->_filename.empty() && do_has_bam_rawdata(cdata))); if (has_rawdata && !do_has_bam_rawdata(cdata)) { do_get_bam_rawdata(cdata); @@ -7953,13 +7736,8 @@ do_write_datagram_header(CData *cdata, BamWriter *manager, Datagram &me, bool &h //////////////////////////////////////////////////////////////////// void Texture:: do_write_datagram_body(CData *cdata, BamWriter *manager, Datagram &me) { - me.add_uint8(cdata->_wrap_u); - me.add_uint8(cdata->_wrap_v); - me.add_uint8(cdata->_wrap_w); - me.add_uint8(cdata->_minfilter); - me.add_uint8(cdata->_magfilter); - me.add_int16(cdata->_anisotropic_degree); - cdata->_border_color.write_datagram(me); + cdata->_default_sampler.write_datagram(me); + me.add_uint8(cdata->_compression); me.add_uint8(cdata->_quality_level); @@ -8181,13 +7959,7 @@ make_this_from_bam(const FactoryParams ¶ms) { //////////////////////////////////////////////////////////////////// void Texture:: do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager) { - cdata->_wrap_u = (WrapMode)scan.get_uint8(); - cdata->_wrap_v = (WrapMode)scan.get_uint8(); - cdata->_wrap_w = (WrapMode)scan.get_uint8(); - cdata->_minfilter = (FilterType)scan.get_uint8(); - cdata->_magfilter = (FilterType)scan.get_uint8(); - cdata->_anisotropic_degree = scan.get_int16(); - cdata->_border_color.read_datagram(scan); + cdata->_default_sampler.read_datagram(scan, manager); if (manager->get_file_minor_ver() >= 1) { cdata->_compression = (CompressionMode)scan.get_uint8(); @@ -8261,12 +8033,12 @@ do_fillin_rawdata(CData *cdata, DatagramIterator &scan, BamReader *manager) { if (manager->get_file_minor_ver() >= 1) { cdata->_ram_image_compression = (CompressionMode)scan.get_uint8(); } - + int num_ram_images = 1; if (manager->get_file_minor_ver() >= 3) { num_ram_images = scan.get_uint8(); } - + cdata->_ram_images.clear(); cdata->_ram_images.reserve(num_ram_images); for (int n = 0; n < num_ram_images; ++n) { @@ -8275,9 +8047,9 @@ do_fillin_rawdata(CData *cdata, DatagramIterator &scan, BamReader *manager) { if (manager->get_file_minor_ver() >= 1) { cdata->_ram_images[n]._page_size = scan.get_uint32(); } - + size_t u_size = scan.get_uint32(); - + // fill the cdata->_image buffer with image data PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type()); for (size_t u_idx = 0; u_idx < u_size; ++u_idx) { @@ -8308,19 +8080,19 @@ do_fillin_from(CData *cdata, const Texture *dummy) { CDReader cdata_dummy(dummy->_cycler); - do_set_wrap_u(cdata, cdata_dummy->_wrap_u); - do_set_wrap_v(cdata, cdata_dummy->_wrap_v); - do_set_wrap_w(cdata, cdata_dummy->_wrap_w); - do_set_border_color(cdata, cdata_dummy->_border_color); + do_set_wrap_u(cdata, cdata_dummy->_default_sampler.get_wrap_u()); + do_set_wrap_v(cdata, cdata_dummy->_default_sampler.get_wrap_v()); + do_set_wrap_w(cdata, cdata_dummy->_default_sampler.get_wrap_w()); + do_set_border_color(cdata, cdata_dummy->_default_sampler.get_border_color()); - if (cdata_dummy->_minfilter != FT_default) { - do_set_minfilter(cdata, cdata_dummy->_minfilter); + if (cdata_dummy->_default_sampler.get_minfilter() != SamplerState::FT_default) { + do_set_minfilter(cdata, cdata_dummy->_default_sampler.get_minfilter()); } - if (cdata_dummy->_magfilter != FT_default) { - do_set_magfilter(cdata, cdata_dummy->_magfilter); + if (cdata_dummy->_default_sampler.get_magfilter() != SamplerState::FT_default) { + do_set_magfilter(cdata, cdata_dummy->_default_sampler.get_magfilter()); } - if (cdata_dummy->_anisotropic_degree != 0) { - do_set_anisotropic_degree(cdata, cdata_dummy->_anisotropic_degree); + if (cdata_dummy->_default_sampler.get_anisotropic_degree() != 0) { + do_set_anisotropic_degree(cdata, cdata_dummy->_default_sampler.get_anisotropic_degree()); } if (cdata_dummy->_compression != CM_default) { do_set_compression(cdata, cdata_dummy->_compression); @@ -8345,7 +8117,7 @@ do_fillin_from(CData *cdata, const Texture *dummy) { // recently than the one we already have. if (cdata->_simple_ram_image._image.empty() || cdata_dummy->_simple_image_date_generated > cdata->_simple_image_date_generated) { - do_set_simple_ram_image(cdata, + do_set_simple_ram_image(cdata, cdata_dummy->_simple_ram_image._image, cdata_dummy->_simple_x_size, cdata_dummy->_simple_y_size); @@ -8357,20 +8129,13 @@ do_fillin_from(CData *cdata, const Texture *dummy) { //////////////////////////////////////////////////////////////////// // Function: Texture::CData::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// Texture::CData:: CData() { _primary_file_num_channels = 0; _alpha_file_channel = 0; - _magfilter = FT_default; - _minfilter = FT_default; - _wrap_u = WM_repeat; - _wrap_v = WM_repeat; - _wrap_w = WM_repeat; - _anisotropic_degree = 0; _keep_ram_image = true; - _border_color.set(0.0f, 0.0f, 0.0f, 1.0f); _compression = CM_default; _auto_texture_scale = ATS_unspecified; _ram_image_compression = CM_off; @@ -8411,7 +8176,7 @@ CData() { //////////////////////////////////////////////////////////////////// // Function: Texture::CData::Copy Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// Texture::CData:: CData(const Texture::CData ©) { @@ -8437,7 +8202,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: Texture::CData::do_assign // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// void Texture::CData:: do_assign(const Texture::CData *copy) { @@ -8470,14 +8235,8 @@ do_assign(const Texture::CData *copy) { _has_read_pages = copy->_has_read_pages; _has_read_mipmaps = copy->_has_read_mipmaps; _num_mipmap_levels_read = copy->_num_mipmap_levels_read; - _wrap_u = copy->_wrap_u; - _wrap_v = copy->_wrap_v; - _wrap_w = copy->_wrap_w; - _minfilter = copy->_minfilter; - _magfilter = copy->_magfilter; - _anisotropic_degree = copy->_anisotropic_degree; + _default_sampler = copy->_default_sampler; _keep_ram_image = copy->_keep_ram_image; - _border_color = copy->_border_color; _compression = copy->_compression; _match_framebuffer_format = copy->_match_framebuffer_format; _quality_level = copy->_quality_level; @@ -8549,50 +8308,6 @@ operator << (ostream &out, Texture::Format f) { return out << Texture::format_format(f); } -//////////////////////////////////////////////////////////////////// -// Function: Texture::FilterType output operator -// Description: -//////////////////////////////////////////////////////////////////// -ostream & -operator << (ostream &out, Texture::FilterType ft) { - return out << Texture::format_filter_type(ft); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::FilterType input operator -// Description: -//////////////////////////////////////////////////////////////////// -istream & -operator >> (istream &in, Texture::FilterType &ft) { - string word; - in >> word; - - ft = Texture::string_filter_type(word); - return in; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::WrapMode output operator -// Description: -//////////////////////////////////////////////////////////////////// -ostream & -operator << (ostream &out, Texture::WrapMode wm) { - return out << Texture::format_wrap_mode(wm); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::WrapMode input operator -// Description: -//////////////////////////////////////////////////////////////////// -istream & -operator >> (istream &in, Texture::WrapMode &wm) { - string word; - in >> word; - - wm = Texture::string_wrap_mode(word); - return in; -} - //////////////////////////////////////////////////////////////////// // Function: Texture::CompressionMode output operator // Description: diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 1198dc67d6..7d4106e960 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -39,6 +39,7 @@ #include "cycleDataStageReader.h" #include "cycleDataStageWriter.h" #include "pipelineCycler.h" +#include "samplerState.h" class PNMImage; class PfmFile; @@ -147,50 +148,30 @@ PUBLISHED: F_rgb32, }; - enum FilterType { - // Mag Filter and Min Filter - - // Point sample the pixel - FT_nearest, - - // Bilinear filtering of four neighboring pixels - FT_linear, - - // Min Filter Only - - // Point sample the pixel from the nearest mipmap level - FT_nearest_mipmap_nearest, - - // Bilinear filter the pixel from the nearest mipmap level - FT_linear_mipmap_nearest, - - // Point sample the pixel from two mipmap levels, and linearly blend - FT_nearest_mipmap_linear, - - // A.k.a. trilinear filtering: Bilinear filter the pixel from - // two mipmap levels, and linearly blend the results. - FT_linear_mipmap_linear, - - // The OpenGL ARB_shadow extension can be thought of as a kind of filtering. - FT_shadow, - - // Default is usually linear, but it depends on format. - // This was added at the end of the list to avoid bumping TXO version #. - FT_default, - - // Returned by string_filter_type() for an invalid match. - FT_invalid + // Deprecated. See SamplerState.FilterType. + enum DeprecatedFilterType { + FT_nearest = SamplerState::FT_nearest, + FT_linear = SamplerState::FT_linear, + FT_nearest_mipmap_nearest = SamplerState::FT_nearest_mipmap_nearest, + FT_linear_mipmap_nearest = SamplerState::FT_linear_mipmap_nearest, + FT_nearest_mipmap_linear = SamplerState::FT_nearest_mipmap_linear, + FT_linear_mipmap_linear = SamplerState::FT_linear_mipmap_linear, + FT_shadow = SamplerState::FT_shadow, + FT_default = SamplerState::FT_default, + FT_invalid = SamplerState::FT_invalid }; + typedef SamplerState::FilterType FilterType; - enum WrapMode { - WM_clamp, // coords that would be outside [0-1] are clamped to 0 or 1 - WM_repeat, - WM_mirror, - WM_mirror_once, // mirror once, then clamp - WM_border_color, // coords outside [0-1] use explict border color - // Returned by string_wrap_mode() for an invalid match. - WM_invalid + // Deprecated. See SamplerState.WrapMode. + enum DeprecatedWrapMode { + WM_clamp = SamplerState::WM_clamp, + WM_repeat = SamplerState::WM_repeat, + WM_mirror = SamplerState::WM_mirror, + WM_mirror_once = SamplerState::WM_mirror_once, + WM_border_color = SamplerState::WM_border_color, + WM_invalid = SamplerState::WM_invalid }; + typedef SamplerState::WrapMode WrapMode; enum CompressionMode { // Generic compression modes. Usually, you should choose one of @@ -257,7 +238,7 @@ PUBLISHED: BLOCKING bool read(const Filename &fullpath, const Filename &alpha_fullpath, int primary_file_num_channels, int alpha_file_channel, const LoaderOptions &options = LoaderOptions()); - BLOCKING bool read(const Filename &fullpath, int z, int n, + BLOCKING bool read(const Filename &fullpath, int z, int n, bool read_pages, bool read_mipmaps, const LoaderOptions &options = LoaderOptions()); BLOCKING bool read(const Filename &fullpath, const Filename &alpha_fullpath, @@ -267,7 +248,7 @@ PUBLISHED: const LoaderOptions &options = LoaderOptions()); BLOCKING INLINE bool write(const Filename &fullpath); - BLOCKING INLINE bool write(const Filename &fullpath, int z, int n, + BLOCKING INLINE bool write(const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps); BLOCKING bool read_txo(istream &in, const string &filename = ""); @@ -319,13 +300,14 @@ PUBLISHED: INLINE void set_compression(CompressionMode compression); INLINE void set_render_to_texture(bool render_to_texture); - INLINE WrapMode get_wrap_u() const; - INLINE WrapMode get_wrap_v() const; - INLINE WrapMode get_wrap_w() const; - INLINE FilterType get_minfilter() const; - INLINE FilterType get_magfilter() const; - FilterType get_effective_minfilter() const; - FilterType get_effective_magfilter() const; + INLINE const SamplerState &get_default_sampler() const; + INLINE SamplerState::WrapMode get_wrap_u() const; + INLINE SamplerState::WrapMode get_wrap_v() const; + INLINE SamplerState::WrapMode get_wrap_w() const; + INLINE SamplerState::FilterType get_minfilter() const; + INLINE SamplerState::FilterType get_magfilter() const; + INLINE SamplerState::FilterType get_effective_minfilter() const; + INLINE SamplerState::FilterType get_effective_magfilter() const; INLINE int get_anisotropic_degree() const; INLINE int get_effective_anisotropic_degree() const; INLINE LColor get_border_color() const; @@ -458,7 +440,7 @@ PUBLISHED: INLINE int get_pad_y_size() const; INLINE int get_pad_z_size() const; INLINE LVecBase2 get_tex_scale() const; - + INLINE void set_pad_size(int x=0, int y=0, int z=0); void set_size_padded(int x=1, int y=1, int z=1); @@ -467,7 +449,7 @@ PUBLISHED: INLINE int get_orig_file_z_size() const; void set_orig_file_size(int x, int y, int z = 1); - + INLINE void set_format(Format format); INLINE void set_component_type(ComponentType component_type); INLINE void set_loaded_from_image(); @@ -503,22 +485,16 @@ PUBLISHED: static string format_format(Format f); static Format string_format(const string &str); - - static string format_filter_type(FilterType ft); - static FilterType string_filter_type(const string &str); - - static string format_wrap_mode(WrapMode wm); - static WrapMode string_wrap_mode(const string &str); - + static string format_compression_mode(CompressionMode cm); static CompressionMode string_compression_mode(const string &str); static string format_quality_level(QualityLevel tql); static QualityLevel string_quality_level(const string &str); - + public: void texture_uploaded(); - + virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; @@ -550,8 +526,8 @@ protected: // CData pointer representing that lock); generally, they also avoid // adjusting the _properties_modified and _image_modified // semaphores. - virtual bool do_adjust_this_size(const CData *cdata, - int &x_size, int &y_size, const string &name, + virtual bool do_adjust_this_size(const CData *cdata, + int &x_size, int &y_size, const string &name, bool for_padding) const; virtual bool do_read(CData *cdata, @@ -577,7 +553,7 @@ protected: bool do_read_dds_file(CData *cdata, const Filename &fullpath, bool header_only); bool do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only); - bool do_write(CData *cdata, const Filename &fullpath, int z, int n, + bool do_write(CData *cdata, const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps); bool do_write_one(CData *cdata, const Filename &fullpath, int z, int n); bool do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n); @@ -590,14 +566,14 @@ protected: PTA_uchar do_modify_ram_image(CData *cdata); PTA_uchar do_make_ram_image(CData *cdata); - void do_set_ram_image(CData *cdata, CPTA_uchar image, + void do_set_ram_image(CData *cdata, CPTA_uchar image, CompressionMode compression = CM_off, size_t page_size = 0); PTA_uchar do_modify_ram_mipmap_image(CData *cdata, int n); PTA_uchar do_make_ram_mipmap_image(CData *cdata, int n); void do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size); bool consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression); - bool do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps, + bool do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps, bool allow_compression); bool do_compress_ram_image(CData *cdata, CompressionMode compression, QualityLevel quality_level, @@ -607,7 +583,7 @@ protected: bool do_reconsider_z_size(CData *cdata, int z, const LoaderOptions &options); virtual void do_allocate_pages(CData *cdata); - bool do_reconsider_image_properties(CData *cdata, + bool do_reconsider_image_properties(CData *cdata, int x_size, int y_size, int num_components, ComponentType component_type, int z, const LoaderOptions &options); @@ -617,7 +593,7 @@ protected: PT(Texture) do_make_copy(const CData *cdata) const; void do_assign(CData *cdata, const Texture *copy, const CData *cdata_copy); virtual void do_clear(CData *cdata); - void do_setup_texture(CData *cdata, + void do_setup_texture(CData *cdata, TextureType texture_type, int x_size, int y_size, int z_size, ComponentType component_type, Format format); @@ -700,28 +676,28 @@ private: int num_components, int component_width, CPTA_uchar image, size_t page_size, int z); - static PTA_uchar read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header, + static PTA_uchar read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header, + static PTA_uchar read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_abgr8(Texture *tex, CData *cdata, const DDSHeader &header, + static PTA_uchar read_dds_level_abgr8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_rgba8(Texture *tex, CData *cdata, const DDSHeader &header, + static PTA_uchar read_dds_level_rgba8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_generic_uncompressed(Texture *tex, CData *cdata, - const DDSHeader &header, + static PTA_uchar read_dds_level_generic_uncompressed(Texture *tex, CData *cdata, + const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_luminance_uncompressed(Texture *tex, CData *cdata, - const DDSHeader &header, + static PTA_uchar read_dds_level_luminance_uncompressed(Texture *tex, CData *cdata, + const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_dxt1(Texture *tex, CData *cdata, - const DDSHeader &header, + static PTA_uchar read_dds_level_dxt1(Texture *tex, CData *cdata, + const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_dxt23(Texture *tex, CData *cdata, - const DDSHeader &header, + static PTA_uchar read_dds_level_dxt23(Texture *tex, CData *cdata, + const DDSHeader &header, int n, istream &in); - static PTA_uchar read_dds_level_dxt45(Texture *tex, CData *cdata, - const DDSHeader &header, + static PTA_uchar read_dds_level_dxt45(Texture *tex, CData *cdata, + const DDSHeader &header, int n, istream &in); void clear_prepared(int view, PreparedGraphicsObjects *prepared_objects); @@ -748,36 +724,36 @@ private: RamImage &to, const RamImage &from, int x_size, int y_size, int z_size) const; - typedef void Filter2DComponent(unsigned char *&p, + typedef void Filter2DComponent(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); - typedef void Filter3DComponent(unsigned char *&p, + typedef void Filter3DComponent(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size); - static void filter_2d_unsigned_byte(unsigned char *&p, + static void filter_2d_unsigned_byte(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); - static void filter_2d_unsigned_byte_srgb(unsigned char *&p, + static void filter_2d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); - static void filter_2d_unsigned_short(unsigned char *&p, + static void filter_2d_unsigned_short(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); static void filter_2d_float(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); - static void filter_3d_unsigned_byte(unsigned char *&p, + static void filter_3d_unsigned_byte(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size); - static void filter_3d_unsigned_byte_srgb(unsigned char *&p, + static void filter_3d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size); - static void filter_3d_unsigned_short(unsigned char *&p, + static void filter_3d_unsigned_short(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size); @@ -813,16 +789,16 @@ protected: Filename _alpha_filename; Filename _fullpath; Filename _alpha_fullpath; - + // The number of channels of the primary file we use. 1, 2, 3, or 4. int _primary_file_num_channels; - + // If we have a separate alpha file, this designates which channel // in the alpha file provides the alpha channel. 0 indicates the // combined grayscale value of rgb; otherwise, 1, 2, 3, or 4 are // valid. int _alpha_file_channel; - + int _x_size; int _y_size; int _z_size; @@ -832,19 +808,14 @@ protected: TextureType _texture_type; Format _format; ComponentType _component_type; - + bool _loaded_from_image; bool _loaded_from_txo; bool _has_read_pages; bool _has_read_mipmaps; int _num_mipmap_levels_read; - - WrapMode _wrap_u; - WrapMode _wrap_v; - WrapMode _wrap_w; - FilterType _minfilter; - FilterType _magfilter; - int _anisotropic_degree; + + SamplerState _default_sampler; bool _keep_ram_image; LColor _border_color; CompressionMode _compression; @@ -852,14 +823,14 @@ protected: bool _match_framebuffer_format; bool _post_load_store_cache; QualityLevel _quality_level; - + int _pad_x_size; int _pad_y_size; int _pad_z_size; - + int _orig_file_x_size; int _orig_file_y_size; - + AutoTextureScale _auto_texture_scale; CompressionMode _ram_image_compression; @@ -874,11 +845,11 @@ protected: int _simple_x_size; int _simple_y_size; PN_int32 _simple_image_date_generated; - + UpdateSeq _properties_modified; UpdateSeq _image_modified; UpdateSeq _simple_image_modified; - + public: static TypeHandle get_class_type() { return _type_handle; @@ -886,11 +857,11 @@ protected: static void init_type() { register_type(_type_handle, "Texture::CData"); } - + private: static TypeHandle _type_handle; }; - + PipelineCycler _cycler; typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; @@ -904,7 +875,7 @@ protected: // Used to implement unlocked_reload_ram_image(). ConditionVarFull _cvar; // condition: _reloading is true. bool _reloading; - + // A Texture keeps a list (actually, a map) of all the // PreparedGraphicsObjects tables that it has been prepared into. // Each PGO conversely keeps a list (a set) of all the Textures that @@ -913,7 +884,7 @@ protected: typedef pmap Contexts; typedef pmap PreparedViews; PreparedViews _prepared_views; - + // It is common, when using normal maps, specular maps, gloss maps, // and such, to use a file naming convention where the filenames // of the special maps are derived by concatenating a suffix to @@ -924,7 +895,7 @@ protected: // The TexturePool finds this useful. Filename _texture_pool_key; - + private: // The auxiliary data is not recorded to a bam file. typedef pmap AuxData; @@ -976,20 +947,11 @@ private: }; extern EXPCL_PANDA_GOBJ ConfigVariableEnum texture_quality_level; -extern EXPCL_PANDA_GOBJ ConfigVariableEnum texture_minfilter; -extern EXPCL_PANDA_GOBJ ConfigVariableEnum texture_magfilter; -extern EXPCL_PANDA_GOBJ ConfigVariableInt texture_anisotropic_degree; EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::TextureType tt); EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::ComponentType ct); EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::Format f); -EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::FilterType ft); -EXPCL_PANDA_GOBJ istream &operator >> (istream &in, Texture::FilterType &ft); - -EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::WrapMode wm); -EXPCL_PANDA_GOBJ istream &operator >> (istream &in, Texture::WrapMode &wm); - EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::CompressionMode cm); EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, Texture::QualityLevel tql); EXPCL_PANDA_GOBJ istream &operator >> (istream &in, Texture::QualityLevel &tql); @@ -997,4 +959,3 @@ EXPCL_PANDA_GOBJ istream &operator >> (istream &in, Texture::QualityLevel &tql); #include "texture.I" #endif - diff --git a/panda/src/gobj/textureContext.cxx b/panda/src/gobj/textureContext.cxx index c676a29ee3..3efe8c6a7a 100644 --- a/panda/src/gobj/textureContext.cxx +++ b/panda/src/gobj/textureContext.cxx @@ -19,7 +19,7 @@ TypeHandle TextureContext::_type_handle; //////////////////////////////////////////////////////////////////// // Function: TextureContext::output // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void TextureContext:: output(ostream &out) const { @@ -29,7 +29,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// // Function: TextureContext::write // Access: Published, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void TextureContext:: write(ostream &out, int indent_level) const { diff --git a/panda/src/grutil/multitexReducer.cxx b/panda/src/grutil/multitexReducer.cxx index 5daf3877ea..ed65e88311 100644 --- a/panda/src/grutil/multitexReducer.cxx +++ b/panda/src/grutil/multitexReducer.cxx @@ -246,8 +246,8 @@ flatten(GraphicsOutput *window) { Texture *model_tex = model_stage._tex; int aniso_degree = model_tex->get_anisotropic_degree(); - Texture::FilterType minfilter = model_tex->get_minfilter(); - Texture::FilterType magfilter = model_tex->get_magfilter(); + SamplerState::FilterType minfilter = model_tex->get_minfilter(); + SamplerState::FilterType magfilter = model_tex->get_magfilter(); // What is the UV range of the model stage? LTexCoord min_uv, max_uv; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 7f8c13e0a7..d3252b4b74 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -54,8 +54,10 @@ class PreparedGraphicsObjects; class GraphicsOutput; class Texture; class TextureContext; -class ShaderContext; +class SamplerContext; +class SamplerState; class Shader; +class ShaderContext; class RenderState; class TransformState; class Material; @@ -148,6 +150,9 @@ public: virtual void release_texture(TextureContext *tc)=0; virtual bool extract_texture_data(Texture *tex)=0; + virtual SamplerContext *prepare_sampler(const SamplerState &sampler)=0; + virtual void release_sampler(SamplerContext *sc)=0; + virtual GeomContext *prepare_geom(Geom *geom)=0; virtual void release_geom(GeomContext *gc)=0; diff --git a/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx b/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx index 7aac015f96..ca1c261129 100644 --- a/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx +++ b/panda/src/osxdisplay/osxGraphicsStateGuardian.cxx @@ -135,8 +135,8 @@ draw_resize_box() { PT(Texture) tex = new Texture; tex->set_name("resize_box.rgb"); tex->load(resize_box_pnm); - tex->set_minfilter(Texture::FT_linear); - tex->set_magfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); + tex->set_magfilter(SamplerState::FT_linear); state = state->add_attrib(TextureAttrib::make(tex)); } } diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index ecdaaa8f31..d8101fc778 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -141,7 +141,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, AccumulatedAttribs geom_attribs = attribs; entry->_state = geom_attribs.collect(entry->_state, attrib_types); - + bool any_changed = false; if ((attrib_types & SceneGraphReducer::TT_color) != 0) { @@ -152,9 +152,9 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, } ra = entry->_state->get_attrib_def(ColorAttrib::get_class_slot()); - CPT (ColorAttrib) ca = DCAST(ColorAttrib, ra); + CPT (ColorAttrib) ca = DCAST(ColorAttrib, ra); if (ca->get_color_type() != ColorAttrib::T_vertex) { - if(allow_flatten_color) { + if(allow_flatten_color) { if(transformer.set_color(new_geom, ca->get_color())) { any_changed = true; entry->_state = entry->_state->set_attrib(ColorAttrib::make_vertex()); @@ -163,15 +163,15 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, if (transformer.remove_column(new_geom, InternalName::get_color())) { any_changed = true; } - } + } } - } + } if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { if (geom_attribs._color_scale != (const RenderAttrib *)NULL) { CPT(ColorScaleAttrib) csa = DCAST(ColorScaleAttrib, geom_attribs._color_scale); if (csa->get_scale() != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) { - + // Now, if we have an "off" or "flat" color attribute, we // simply modify the color attribute, and leave the // vertices alone. @@ -187,16 +187,16 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, // ColorAttrib::T_off means the color scale becomes // the new color. entry->_state = entry->_state->set_attrib(ColorAttrib::make_flat(csa->get_scale())); - + } else if (ca->get_color_type() == ColorAttrib::T_flat) { // ColorAttrib::T_flat means the color scale modulates // the specified color to produce a new color. const LColor &c1 = ca->get_color(); const LVecBase4 &c2 = csa->get_scale(); - LColor color(c1[0] * c2[0], c1[1] * c2[1], + LColor color(c1[0] * c2[0], c1[1] * c2[1], c1[2] * c2[2], c1[3] * c2[3]); entry->_state = entry->_state->set_attrib(ColorAttrib::make_flat(color)); - + } else { // Otherwise, we have vertex color, and we just scale // it normally. @@ -219,7 +219,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, // that from which we started the flatten operation, but // caveat programmer. NameCount name_count; - + if (geom_attribs._texture != (RenderAttrib *)NULL) { const TextureAttrib *ta = DCAST(TextureAttrib, geom_attribs._texture); int num_on_stages = ta->get_num_on_stages(); @@ -229,12 +229,12 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, count_name(name_count, name); } } - - const TexMatrixAttrib *tma = + + const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, geom_attribs._tex_matrix); - + CPT(TexMatrixAttrib) new_tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make()); - + int num_stages = tma->get_num_stages(); for (int i = 0; i < num_stages; i++) { TextureStage *stage = tma->get_stage(i); @@ -243,7 +243,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, // We can't transform these texcoords, since the name is // used by more than one active stage. new_tma = DCAST(TexMatrixAttrib, new_tma->add_stage(stage, tma->get_transform(stage))); - + } else { // It's safe to transform these texcoords; the name is // used by no more than one active stage. @@ -252,7 +252,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, } } } - + if (!new_tma->is_empty()) { entry->_state = entry->_state->add_attrib(new_tma); } @@ -288,7 +288,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, // invalidated our old pointer into the list, so we // reassign it now. entry = &(*geoms)[i]; - + } else { // If there are no normals, we can just doubleside it in // place. This is preferable because we can share vertices. @@ -297,14 +297,14 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, } } break; - + case CullFaceAttrib::M_cull_counter_clockwise: // Reverse winding order. new_geom->reverse_in_place(); transformer.reverse_normals(new_geom); any_changed = true; break; - + default: break; } @@ -425,7 +425,7 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, } // And now prepare each of the textures. - const RenderAttrib *attrib = + const RenderAttrib *attrib = geom_state->get_attrib(TextureAttrib::get_class_slot()); if (attrib != (const RenderAttrib *)NULL) { const TextureAttrib *ta; @@ -433,6 +433,7 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, int num_stages = ta->get_num_on_stages(); for (int i = 0; i < num_stages; ++i) { Texture *texture = ta->get_on_texture(ta->get_on_stage(i)); + //TODO: prepare the sampler states, if specified. if (texture != (Texture *)NULL) { texture->prepare(prepared_objects); } @@ -448,10 +449,11 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, if (shader != (Shader *)NULL) { shader->prepare(prepared_objects); } + //TODO: prepare the shader inputs. //TODO: Invoke the shader generator if enabled. } } - + PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread); } @@ -503,7 +505,7 @@ combine_with(PandaNode *other) { CPT(TransformState) GeomNode:: calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, const TransformState *transform, Thread *current_thread) const { - CPT(TransformState) next_transform = + CPT(TransformState) next_transform = PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform, current_thread); @@ -552,10 +554,10 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << "Found " << *this << " in state " << *data._state + << "Found " << *this << " in state " << *data._state << " draw_mask = " << data._draw_mask << "\n"; } - + // Get all the Geoms, with no decalling. Geoms geoms = get_geoms(trav->get_current_thread()); int num_geoms = geoms.get_num_geoms(); @@ -575,7 +577,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // Cull. continue; } - + // Cull the Geom bounding volume against the view frustum // and/or the cull planes. Don't bother unless we've got more // than one Geom, since otherwise the bounding volume of the @@ -587,7 +589,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { CPT(BoundingVolume) geom_volume = geom->get_bounds(); const GeometricBoundingVolume *geom_gbv = DCAST(GeometricBoundingVolume, geom_volume); - + int result = data._view_frustum->contains(geom_gbv); if (result == BoundingVolume::IF_no_intersection) { // Cull this Geom. @@ -607,9 +609,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { } } } - - CullableObject *object = - new CullableObject(geom, state, net_transform, + + CullableObject *object = + new CullableObject(geom, state, net_transform, modelview_transform, internal_transform); trav->get_cull_handler()->record_object(object, trav); } @@ -803,7 +805,7 @@ unify(int max_indices, bool preserve_order) { CPT(GeomList) old_geoms = cdata->get_geoms(); for (gi = old_geoms->begin(); gi != old_geoms->end(); ++gi) { const GeomEntry &old_entry = (*gi); - + bool unified = false; // Go from back to front, to minimize damage to the primitive ordering. @@ -827,14 +829,14 @@ unify(int max_indices, bool preserve_order) { break; } } - + if (!unified) { // Couldn't unify this Geom with anything, so just add it to the // output list. new_geoms->push_back(old_entry); } } - + // Done! We'll keep whatever's left in the output list. cdata->set_geoms(new_geoms); @@ -868,7 +870,7 @@ write_geoms(ostream &out, int indent_level) const { CPT(GeomList) geoms = cdata->get_geoms(); for (gi = geoms->begin(); gi != geoms->end(); ++gi) { const GeomEntry &entry = (*gi); - indent(out, indent_level + 2) + indent(out, indent_level + 2) << *entry._geom.get_read_pointer() << " " << *entry._state << "\n"; } } @@ -888,7 +890,7 @@ write_verbose(ostream &out, int indent_level) const { for (gi = geoms->begin(); gi != geoms->end(); ++gi) { const GeomEntry &entry = (*gi); CPT(Geom) geom = entry._geom.get_read_pointer(); - indent(out, indent_level + 2) + indent(out, indent_level + 2) << *geom << " " << *entry._state << "\n"; geom->write(out, indent_level + 4); } @@ -897,7 +899,7 @@ write_verbose(ostream &out, int indent_level) const { //////////////////////////////////////////////////////////////////// // Function: GeomNode::output // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void GeomNode:: output(ostream &out) const { @@ -923,7 +925,7 @@ output(ostream &out) const { out << " (" << geoms->size() << " geoms"; if (!common->is_empty()) { - out << ": " << *common; + out << ": " << *common; } out << ")"; @@ -1061,7 +1063,7 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, const BoundingVolume **child_end = child_begin + child_volumes.size(); ((BoundingVolume *)gbv)->around(child_begin, child_end); } - + internal_bounds = gbv; internal_vertices = num_vertices; } @@ -1216,7 +1218,7 @@ write_datagram(BamWriter *manager, Datagram &dg) const { int num_geoms = geoms->size(); nassertv(num_geoms == (int)(PN_uint16)num_geoms); dg.add_uint16(num_geoms); - + GeomList::const_iterator gi; for (gi = geoms->begin(); gi != geoms->end(); ++gi) { const GeomEntry &entry = (*gi); diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 66198e20cb..1f15c20aec 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -75,16 +75,16 @@ #include "bam.h" #include "bamWriter.h" -// stack seems to overflow on Intel C++ at 7000. If we need more than +// stack seems to overflow on Intel C++ at 7000. If we need more than // 7000, need to increase stack size. -int NodePath::_max_search_depth = 7000; +int NodePath::_max_search_depth = 7000; TypeHandle NodePath::_type_handle; PStatCollector NodePath::_get_transform_pcollector("*:NodePath:get_transform"); PStatCollector NodePath::_verify_complete_pcollector("*:NodePath:verify_complete"); #ifdef HAVE_PYTHON -#include "py_panda.h" +#include "py_panda.h" #ifndef CPPPARSER extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamWriter; extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamReader; @@ -153,7 +153,7 @@ static ConfigVariableEnum empty_node_path // stashed or unstashed child of the parent. //////////////////////////////////////////////////////////////////// NodePath:: -NodePath(const NodePath &parent, PandaNode *child_node, +NodePath(const NodePath &parent, PandaNode *child_node, Thread *current_thread) : _error_type(ET_fail) { @@ -162,7 +162,7 @@ NodePath(const NodePath &parent, PandaNode *child_node, if (parent.is_empty()) { // Special case: constructing a NodePath at the root. - _head = PandaNode::get_top_component(child_node, true, + _head = PandaNode::get_top_component(child_node, true, pipeline_stage, current_thread); } else { @@ -206,7 +206,7 @@ operator bool () const { if (!is_empty()) { return true; } - + { const char *message = "Using an empty NodePath as a boolean value. Because the meaning of this operation is changing, you should avoid doing this to avoid ambiguity, or set the config variable empty-node-path to 'future' or 'deprecated' to specify the desired behavior."; pgraph_cat.warning() @@ -510,7 +510,7 @@ find_all_paths_to(PandaNode *node) const { // Access: Published // Description: Removes the referenced node of the NodePath from its // current parent and attaches it to the referenced node -// of the indicated NodePath. +// of the indicated NodePath. // // If the destination NodePath is empty, this is the // same thing as detach_node(). @@ -644,7 +644,7 @@ instance_to(const NodePath &other, int sort, Thread *current_thread) const { } return orig; } - + // Nope, it must be a cycle. nassertr(reparented, new_instance); } @@ -869,7 +869,7 @@ get_state(const NodePath &other, Thread *current_thread) const { if (is_empty()) { return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty()); } - + nassertr(verify_complete(current_thread), RenderState::make_empty()); nassertr(other.verify_complete(current_thread), RenderState::make_empty()); @@ -1041,7 +1041,7 @@ get_prev_transform(const NodePath &other, Thread *current_thread) const { if (is_empty()) { return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity()); } - + nassertr(verify_complete(current_thread), TransformState::make_identity()); nassertr(other.verify_complete(current_thread), TransformState::make_identity()); @@ -2017,7 +2017,7 @@ set_pos_quat(const NodePath &other, const LVecBase3 &pos, const LQuaternion &quat) { nassertv_always(!is_empty()); CPT(TransformState) rel_transform = get_transform(other); - + CPT(TransformState) orig_transform = get_transform(); if (orig_transform->has_components()) { // If we had a componentwise transform before we started, we @@ -2074,7 +2074,7 @@ set_hpr_scale(const NodePath &other, const LVecBase3 &hpr, const LVecBase3 &scal // transform when both quat and scale are to be changed. //////////////////////////////////////////////////////////////////// void NodePath:: -set_quat_scale(const NodePath &other, const LQuaternion &quat, +set_quat_scale(const NodePath &other, const LQuaternion &quat, const LVecBase3 &scale) { // We don't bother trying very hard to preserve pos across this // operation, unlike the work we do above to preserve quat or scale, @@ -2385,7 +2385,7 @@ clear_color_scale() { // Function: NodePath::compose_color_scale // Access: Published // Description: multiplies the color scale component of the transform, -// with previous color scale leaving translation and +// with previous color scale leaving translation and // rotation untouched. //////////////////////////////////////////////////////////////////// void NodePath:: @@ -2399,7 +2399,7 @@ compose_color_scale(const LVecBase4 &scale, int priority) { node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); - // Modify the existing ColorScaleAttrib by multiplying with the + // Modify the existing ColorScaleAttrib by multiplying with the // indicated colorScale. LVecBase4 prev_color_scale = csa->get_scale(); LVecBase4 new_color_scale(prev_color_scale[0]*scale[0], @@ -2569,11 +2569,11 @@ set_light(const NodePath &light, int priority) { priority = max(priority, node()->get_state()->get_override(LightAttrib::get_class_slot())); const LightAttrib *la = DCAST(LightAttrib, attrib); - + // Modify the existing LightAttrib to add the indicated // light. node()->set_attrib(la->add_on_light(light), priority); - + } else { // Create a new LightAttrib for this node. CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); @@ -2594,11 +2594,11 @@ set_light(const NodePath &light, int priority) { node()->get_effect(PolylightEffect::get_class_type()); if (effect != (const RenderEffect *)NULL) { const PolylightEffect *ple = DCAST(PolylightEffect, effect); - + // Modify the existing PolylightEffect to add the indicated // light. node()->set_effect(ple->add_light(light)); - + } else { // Create a new PolylightEffect for this node. CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make()); @@ -2657,12 +2657,12 @@ set_light_off(const NodePath &light, int priority) { priority = max(priority, node()->get_state()->get_override(LightAttrib::get_class_slot())); const LightAttrib *la = DCAST(LightAttrib, attrib); - + // Modify the existing LightAttrib to add the indicated light // to the "off" list. This also, incidentally, removes it from // the "on" list if it is there. node()->set_attrib(la->add_off_light(light), priority); - + } else { // Create a new LightAttrib for this node that turns off the // indicated light. @@ -2708,10 +2708,10 @@ clear_light(const NodePath &light) { CPT(LightAttrib) la = DCAST(LightAttrib, attrib); la = DCAST(LightAttrib, la->remove_on_light(light)); la = DCAST(LightAttrib, la->remove_off_light(light)); - + if (la->is_identity()) { node()->clear_attrib(LightAttrib::get_class_slot()); - + } else { int priority = node()->get_state()->get_override(LightAttrib::get_class_slot()); node()->set_attrib(la, priority); @@ -2841,11 +2841,11 @@ set_clip_plane(const NodePath &clip_plane, int priority) { priority = max(priority, node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot())); const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); - + // Modify the existing ClipPlaneAttrib to add the indicated // clip_plane. node()->set_attrib(la->add_on_plane(clip_plane), priority); - + } else { // Create a new ClipPlaneAttrib for this node. CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); @@ -2898,12 +2898,12 @@ set_clip_plane_off(const NodePath &clip_plane, int priority) { priority = max(priority, node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot())); const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); - + // Modify the existing ClipPlaneAttrib to add the indicated clip_plane // to the "off" list. This also, incidentally, removes it from // the "on" list if it is there. node()->set_attrib(la->add_off_plane(clip_plane), priority); - + } else { // Create a new ClipPlaneAttrib for this node that turns off the // indicated clip_plane. @@ -2945,10 +2945,10 @@ clear_clip_plane(const NodePath &clip_plane) { CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib); la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane)); la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane)); - + if (la->is_identity()) { node()->clear_attrib(ClipPlaneAttrib::get_class_slot()); - + } else { int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()); node()->set_attrib(la, priority); @@ -3047,11 +3047,11 @@ set_occluder(const NodePath &occluder) { node()->get_effect(OccluderEffect::get_class_type()); if (effect != (const RenderEffect *)NULL) { const OccluderEffect *la = DCAST(OccluderEffect, effect); - + // Modify the existing OccluderEffect to add the indicated // occluder. node()->set_effect(la->add_on_occluder(occluder)); - + } else { // Create a new OccluderEffect for this node. CPT(OccluderEffect) la = DCAST(OccluderEffect, OccluderEffect::make()); @@ -3090,10 +3090,10 @@ clear_occluder(const NodePath &occluder) { if (effect != (const RenderEffect *)NULL) { CPT(OccluderEffect) la = DCAST(OccluderEffect, effect); la = DCAST(OccluderEffect, la->remove_on_occluder(occluder)); - + if (la->is_identity()) { node()->clear_effect(OccluderEffect::get_class_type()); - + } else { node()->set_effect(la); } @@ -3381,6 +3381,68 @@ set_texture(TextureStage *stage, Texture *tex, int priority) { } } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_texture +// Access: Published +// Description: Adds the indicated texture to the list of textures +// that will be rendered on the default texture stage. +// +// The given sampler state will override the sampling +// settings on the texture itself. Note that this +// method makes a copy of the sampler settings that +// you give; further changes to this object will not +// be reflected. +// +// This is the convenience single-texture variant of +// this method; it is now superceded by set_texture() +// that accepts a stage and texture. You may use this +// method if you just want to adjust the default stage. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_texture(Texture *tex, const SamplerState &sampler, int priority) { + nassertv_always(!is_empty()); + PT(TextureStage) stage = TextureStage::get_default(); + set_texture(stage, tex, sampler, priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_texture +// Access: Published +// Description: Adds the indicated texture to the list of textures +// that will be rendered on the indicated multitexture +// stage. If there are multiple texture stages +// specified (possibly on multiple different nodes at +// different levels), they will all be applied to +// geometry together, according to the stage +// specification set up in the TextureStage object. +// +// The given sampler state will override the sampling +// settings on the texture itself. Note that this +// method makes a copy of the sampler settings that +// you give; further changes to this object will not +// be reflected. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_texture(TextureStage *stage, Texture *tex, const SamplerState &sampler, int priority) { + nassertv_always(!is_empty()); + + const RenderAttrib *attrib = + node()->get_attrib(TextureAttrib::get_class_slot()); + if (attrib != (const RenderAttrib *)NULL) { + const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); + int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); + + // Modify the existing TextureAttrib to add the indicated + // texture. + node()->set_attrib(tsa->add_on_stage(stage, tex, sampler, priority), sg_priority); + + } else { + // Create a new TextureAttrib for this node. + CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); + node()->set_attrib(tsa->add_on_stage(stage, tex, sampler, priority)); + } +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::set_texture_off // Access: Published @@ -3603,10 +3665,48 @@ get_texture(TextureStage *stage) const { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::get_texture_sampler +// Access: Published +// Description: Returns the sampler state that has been given for +// the base-level texture that has been set on this +// particular node. If no sampler state was given, +// this returns the texture's default sampler settings. +// +// It is an error to call this if there is no base-level +// texture applied to this particular node. +//////////////////////////////////////////////////////////////////// +const SamplerState &NodePath:: +get_texture_sampler() const { + return get_texture_sampler(TextureStage::get_default()); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::get_texture_sampler +// Access: Published +// Description: Returns the sampler state that has been given for +// the indicated texture stage that has been set on this +// particular node. If no sampler state was given, +// this returns the texture's default sampler settings. +// +// It is an error to call this if there is no texture +// set for this stage on this particular node. +//////////////////////////////////////////////////////////////////// +const SamplerState &NodePath:: +get_texture_sampler(TextureStage *stage) const { + nassertr_always(!is_empty(), SamplerState::get_default()); + const RenderAttrib *attrib = + node()->get_attrib(TextureAttrib::get_class_slot()); + nassertr_always(attrib != NULL, SamplerState::get_default()); + + const TextureAttrib *ta = DCAST(TextureAttrib, attrib); + return ta->get_on_sampler(stage); +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader(const Shader *sha, int priority) { @@ -3629,7 +3729,7 @@ set_shader(const Shader *sha, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_off // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader_off(int priority) { @@ -3639,7 +3739,7 @@ set_shader_off(int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_auto // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader_auto(int priority) { @@ -3684,7 +3784,7 @@ set_shader_auto(BitMask32 shader_switch, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::clear_shader // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: clear_shader() { @@ -3701,7 +3801,7 @@ clear_shader() { //////////////////////////////////////////////////////////////////// // Function: NodePath::get_shader // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// const Shader *NodePath:: get_shader() const { @@ -3718,7 +3818,7 @@ get_shader() const { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader_input(const ShaderInput *inp) { @@ -3739,12 +3839,12 @@ set_shader_input(const ShaderInput *inp) { //////////////////////////////////////////////////////////////////// // Function: NodePath::get_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// const ShaderInput *NodePath:: get_shader_input(const InternalName *id) const { nassertr_always(!is_empty(), NULL); - + const RenderAttrib *attrib = node()->get_attrib(ShaderAttrib::get_class_slot()); if (attrib != (const RenderAttrib *)NULL) { @@ -3778,7 +3878,7 @@ get_instance_count() const { //////////////////////////////////////////////////////////////////// // Function: NodePath::clear_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: clear_shader_input(const InternalName *id) { @@ -3796,9 +3896,9 @@ clear_shader_input(const InternalName *id) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_float &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3806,9 +3906,9 @@ set_shader_input(const InternalName *id, const PTA_float &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_double &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3816,9 +3916,9 @@ set_shader_input(const InternalName *id, const PTA_double &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_int &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3826,9 +3926,9 @@ set_shader_input(const InternalName *id, const PTA_int &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3836,9 +3936,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3847,9 +3947,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3857,9 +3957,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3867,9 +3967,9 @@ set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3877,9 +3977,9 @@ set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3887,9 +3987,9 @@ set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LVecBase4i &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3897,9 +3997,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase4i &v, int priority) //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LVecBase3i &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3908,9 +4008,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase3i &v, int priority) //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LVecBase2i &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3918,9 +4018,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase2i &v, int priority) //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LVecBase4i &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3928,9 +4028,9 @@ set_shader_input(const InternalName *id, const LVecBase4i &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LVecBase3i &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3938,9 +4038,9 @@ set_shader_input(const InternalName *id, const LVecBase3i &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LVecBase2i &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3948,9 +4048,9 @@ set_shader_input(const InternalName *id, const LVecBase2i &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3958,9 +4058,9 @@ set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3968,9 +4068,9 @@ set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3978,9 +4078,9 @@ set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) { set_shader_input(new ShaderInput(id,v,priority)); } @@ -3988,7 +4088,7 @@ set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader_input(const InternalName *id, Texture *tex, int priority) { @@ -3998,7 +4098,17 @@ set_shader_input(const InternalName *id, Texture *tex, int priority) { //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_shader_input(const InternalName *id, Texture *tex, const SamplerState &sampler, int priority) { + set_shader_input(new ShaderInput(id,tex,sampler,priority)); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_shader_input +// Access: Published +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader_input(const InternalName *id, Texture *tex, bool read, bool write, int z, int n, int priority) { @@ -4008,7 +4118,7 @@ set_shader_input(const InternalName *id, Texture *tex, bool read, bool write, in //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: set_shader_input(const InternalName *id, const NodePath &np, int priority) { @@ -4028,9 +4138,9 @@ set_shader_input(const InternalName *id, int n1, int n2, int n3, int n4, int pri //////////////////////////////////////////////////////////////////// // Function: NodePath::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -void NodePath:: +void NodePath:: set_shader_input(const InternalName *id, PN_stdfloat n1, PN_stdfloat n2, PN_stdfloat n3, PN_stdfloat n4, int priority) { set_shader_input(new ShaderInput(id, LVecBase4(n1, n2, n3, n4), priority)); } @@ -4260,7 +4370,7 @@ set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) { // specific light to generate coordinates for. //////////////////////////////////////////////////////////////////// void NodePath:: -set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, +set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, const string &source_name, const NodePath &light, int priority) { nassertv_always(!is_empty()); @@ -4290,7 +4400,7 @@ set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, // requires a constant texture coordinate value. //////////////////////////////////////////////////////////////////// void NodePath:: -set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, +set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, const LTexCoord3 &constant_value, int priority) { nassertv_always(!is_empty()); @@ -4605,7 +4715,7 @@ set_normal_map(Texture *normal_map, const string &texcoord_name, PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32); PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map"); normalization_map_ts->set_combine_rgb - (TextureStage::CM_dot3_rgb, + (TextureStage::CM_dot3_rgb, TextureStage::CS_texture, TextureStage::CO_src_color, TextureStage::CS_previous, TextureStage::CO_src_color); normalization_map_ts->set_texcoord_name("light_vector"); @@ -4613,7 +4723,7 @@ set_normal_map(Texture *normal_map, const string &texcoord_name, set_texture(normalization_map_ts, normalization_map); // Finally, we enable M_light_vector texture coordinate generation. - set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector, + set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector, texcoord_name, NodePath()); if (preserve_color) { @@ -4736,7 +4846,7 @@ find_all_texcoords() const { r_find_all_vertex_columns(node(), vertex_columns); CPT(InternalName) texcoord_name = InternalName::get_texcoord(); - + InternalNameCollection tc; InternalNames::iterator ti; for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { @@ -5788,7 +5898,7 @@ void NodePath:: set_billboard_axis(const NodePath &camera, PN_stdfloat offset) { nassertv_always(!is_empty()); CPT(RenderEffect) billboard = BillboardEffect::make - (LVector3::up(), false, true, + (LVector3::up(), false, true, offset, camera, LPoint3(0.0f, 0.0f, 0.0f)); node()->set_effect(billboard); } @@ -6147,8 +6257,8 @@ get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const { int pipeline_stage = current_thread->get_pipeline_stage(); NodePathComponent *comp; - for (comp = _head; - comp != (NodePathComponent *)NULL; + for (comp = _head; + comp != (NodePathComponent *)NULL; comp = comp->get_next(pipeline_stage, current_thread)) { PandaNode *node = comp->get_node(); if (node->is_overall_hidden() || @@ -6286,7 +6396,7 @@ verify_complete(Thread *current_thread) const { PandaNode *node = comp->get_node(); nassertr(node != (const PandaNode *)NULL, false); int length = comp->get_length(pipeline_stage, current_thread); - + comp = comp->get_next(pipeline_stage, current_thread); length--; while (comp != (const NodePathComponent *)NULL) { @@ -6476,7 +6586,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, nassertr_always(!is_empty(), false); bool found_any = false; - node()->calc_tight_bounds(min_point, max_point, found_any, + node()->calc_tight_bounds(min_point, max_point, found_any, TransformState::make_identity(), current_thread); @@ -6755,19 +6865,19 @@ encode_to_bam_stream(string &data, BamWriter *writer) const { if (!dout.open(stream)) { return false; } - + BamWriter local_writer; bool used_local_writer = false; if (writer == NULL) { // Create our own writer. - + if (!dout.write_header(_bam_header)) { return false; } writer = &local_writer; used_local_writer = true; } - + writer->set_target(&dout); int num_nodes = get_num_nodes(); @@ -6781,7 +6891,7 @@ encode_to_bam_stream(string &data, BamWriter *writer) const { Datagram dg; dg.add_uint8(_error_type); dg.add_int32(num_nodes); - + if (!dout.put_datagram(dg)) { writer->set_target(NULL); return false; @@ -6797,7 +6907,7 @@ encode_to_bam_stream(string &data, BamWriter *writer) const { } } writer->set_target(NULL); - + data = stream.str(); return true; } @@ -6829,14 +6939,14 @@ decode_from_bam_stream(const string &data, BamReader *reader) { if (!din.read_header(head, _bam_header.size())) { return NodePath::fail(); } - + if (head != _bam_header) { return NodePath::fail(); } reader = &local_reader; } - + reader->set_source(&din); // One initial datagram to encode the error type, and the number of nodes. @@ -6862,7 +6972,7 @@ decode_from_bam_stream(const string &data, BamReader *reader) { reader->set_source(NULL); return NodePath::fail(); } - + if (!reader->resolve()) { reader->set_source(NULL); return NodePath::fail(); @@ -6872,7 +6982,7 @@ decode_from_bam_stream(const string &data, BamReader *reader) { result = NodePath(result, node); } } - + reader->set_source(NULL); return result; @@ -6915,7 +7025,7 @@ find_common_ancestor(const NodePath &a, const NodePath &b, // Now shorten them both up until we reach the same component. while (ac != bc) { - // These shouldn't go to NULL unless they both go there together. + // These shouldn't go to NULL unless they both go there together. nassertr(ac != (NodePathComponent *)NULL, NULL); nassertr(bc != (NodePathComponent *)NULL, NULL); ac = ac->get_next(pipeline_stage, current_thread); @@ -6953,7 +7063,7 @@ r_get_net_state(NodePathComponent *comp, Thread *current_thread) const { // net transform from the root of the graph. //////////////////////////////////////////////////////////////////// CPT(RenderState) NodePath:: -r_get_partial_state(NodePathComponent *comp, int n, +r_get_partial_state(NodePathComponent *comp, int n, Thread *current_thread) const { if (n == 0 || comp == (NodePathComponent *)NULL) { return RenderState::make_empty(); @@ -6984,7 +7094,7 @@ r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const { if (effects->has_adjust_transform()) { effects->adjust_transform(net_transform, transform, node); } - + return net_transform->compose(transform); } } @@ -7002,7 +7112,7 @@ r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const { // transform cannot be easily determined. //////////////////////////////////////////////////////////////////// CPT(TransformState) NodePath:: -r_get_partial_transform(NodePathComponent *comp, int n, +r_get_partial_transform(NodePathComponent *comp, int n, Thread *current_thread) const { if (n == 0 || comp == (NodePathComponent *)NULL) { return TransformState::make_identity(); @@ -7101,7 +7211,7 @@ find_matches(NodePathCollection &result, FindApproxPath &approx_path, } // We start with just one entry on the level. - FindApproxLevelEntry *level = + FindApproxLevelEntry *level = new FindApproxLevelEntry(WorkingNodePath(*this), approx_path); nassertv(level->_node_path.is_valid()); @@ -7118,7 +7228,7 @@ find_matches(NodePathCollection &result, FindApproxPath &approx_path, void NodePath:: find_matches(NodePathCollection &result, FindApproxLevelEntry *level, int max_matches) const { - + int num_levels_remaining = _max_search_depth; FindApproxLevelEntry *deleted_entries = NULL; @@ -7171,7 +7281,7 @@ find_matches(NodePathCollection &result, FindApproxLevelEntry *level, entry = next; } - + // Make sure the remaining entries from this level are added to // the delete chain. while (entry != (FindApproxLevelEntry *)NULL) { @@ -7250,7 +7360,7 @@ r_adjust_all_priorities(PandaNode *node, int adjustment) { //////////////////////////////////////////////////////////////////// // Function: NodePath::r_force_recompute_bounds // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_force_recompute_bounds(PandaNode *node) { @@ -7282,7 +7392,7 @@ r_force_recompute_bounds(PandaNode *node) { // nodes at and below this node. //////////////////////////////////////////////////////////////////// void NodePath:: -r_set_collide_mask(PandaNode *node, +r_set_collide_mask(PandaNode *node, CollideMask and_mask, CollideMask or_mask, TypeHandle node_type) { if (node->is_of_type(node_type)) { @@ -7301,7 +7411,7 @@ r_set_collide_mask(PandaNode *node, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_has_vertex_column // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// bool NodePath:: r_has_vertex_column(PandaNode *node, const InternalName *name) const { @@ -7335,7 +7445,7 @@ r_has_vertex_column(PandaNode *node, const InternalName *name) const { //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_all_vertex_columns // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_find_all_vertex_columns(PandaNode *node, @@ -7372,7 +7482,7 @@ r_find_all_vertex_columns(PandaNode *node, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_texture // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// Texture *NodePath:: r_find_texture(PandaNode *node, const RenderState *state, @@ -7383,7 +7493,7 @@ r_find_texture(PandaNode *node, const RenderState *state, int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = + CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i)); // Look for a TextureAttrib on the state. @@ -7422,7 +7532,7 @@ r_find_texture(PandaNode *node, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_all_textures // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_find_all_textures(PandaNode *node, const RenderState *state, @@ -7433,7 +7543,7 @@ r_find_all_textures(PandaNode *node, const RenderState *state, int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = + CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i)); // Look for a TextureAttrib on the state. @@ -7464,7 +7574,7 @@ r_find_all_textures(PandaNode *node, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_texture // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// Texture * NodePath:: r_find_texture(PandaNode *node, TextureStage *stage) const { @@ -7516,7 +7626,7 @@ r_find_texture(PandaNode *node, TextureStage *stage) const { //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_all_textures // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_find_all_textures(PandaNode *node, TextureStage *stage, @@ -7563,7 +7673,7 @@ r_find_all_textures(PandaNode *node, TextureStage *stage, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_texture_stage // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// TextureStage * NodePath:: r_find_texture_stage(PandaNode *node, const RenderState *state, @@ -7574,7 +7684,7 @@ r_find_texture_stage(PandaNode *node, const RenderState *state, int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = + CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i)); // Look for a TextureAttrib on the state. @@ -7613,7 +7723,7 @@ r_find_texture_stage(PandaNode *node, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_all_texture_stages // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_find_all_texture_stages(PandaNode *node, const RenderState *state, @@ -7624,7 +7734,7 @@ r_find_all_texture_stages(PandaNode *node, const RenderState *state, int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = + CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i)); // Look for a TextureAttrib on the state. @@ -7655,7 +7765,7 @@ r_find_all_texture_stages(PandaNode *node, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_unify_texture_stages // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_unify_texture_stages(PandaNode *node, TextureStage *stage) { @@ -7704,7 +7814,7 @@ r_unify_texture_stages(PandaNode *node, TextureStage *stage) { //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_material // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// Material *NodePath:: r_find_material(PandaNode *node, const RenderState *state, @@ -7715,7 +7825,7 @@ r_find_material(PandaNode *node, const RenderState *state, int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = + CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i)); // Look for a MaterialAttrib on the state. @@ -7754,7 +7864,7 @@ r_find_material(PandaNode *node, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_all_materials // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void NodePath:: r_find_all_materials(PandaNode *node, const RenderState *state, @@ -7765,7 +7875,7 @@ r_find_all_materials(PandaNode *node, const RenderState *state, int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = + CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i)); // Look for a MaterialAttrib on the state. diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 0b590f4919..994f2353e2 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -54,6 +54,7 @@ class MaterialCollection; class Fog; class GlobPattern; class PreparedGraphicsObjects; +class SamplerState; class Shader; class ShaderInput; @@ -539,7 +540,7 @@ PUBLISHED: INLINE void compose_color_scale(PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz, PN_stdfloat sa, int priority = 0); void set_color_scale_off(int priority = 0); - + void set_alpha_scale(PN_stdfloat scale, int priority = 0); void set_all_color_scale(PN_stdfloat scale, int priority = 0); INLINE void set_sr(PN_stdfloat sr); @@ -573,12 +574,12 @@ PUBLISHED: void set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top); void set_scissor(const LPoint3 &a, const LPoint3 &b); - void set_scissor(const LPoint3 &a, const LPoint3 &b, + void set_scissor(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c, const LPoint3 &d); - void set_scissor(const NodePath &other, + void set_scissor(const NodePath &other, const LPoint3 &a, const LPoint3 &b); void set_scissor(const NodePath &other, - const LPoint3 &a, const LPoint3 &b, + const LPoint3 &a, const LPoint3 &b, const LPoint3 &c, const LPoint3 &d); void clear_scissor(); bool has_scissor() const; @@ -596,6 +597,8 @@ PUBLISHED: void set_texture(Texture *tex, int priority = 0); void set_texture(TextureStage *stage, Texture *tex, int priority = 0); + void set_texture(Texture *tex, const SamplerState &sampler, int priority = 0); + void set_texture(TextureStage *stage, Texture *tex, const SamplerState &sampler, int priority = 0); void set_texture_off(int priority = 0); void set_texture_off(TextureStage *stage, int priority = 0); void clear_texture(); @@ -606,6 +609,8 @@ PUBLISHED: bool has_texture_off(TextureStage *stage) const; Texture *get_texture() const; Texture *get_texture(TextureStage *stage) const; + const SamplerState &get_texture_sampler() const; + const SamplerState &get_texture_sampler(TextureStage *stage) const; void set_shader(const Shader *sha, int priority = 0); void set_shader_off(int priority = 0); @@ -615,6 +620,7 @@ PUBLISHED: void set_shader_input(const ShaderInput *inp); void set_shader_input(const InternalName *id, Texture *tex, int priority=0); + void set_shader_input(const InternalName *id, Texture *tex, const SamplerState &sampler, int priority=0); void set_shader_input(const InternalName *id, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0); void set_shader_input(const InternalName *id, const NodePath &np, int priority=0); void set_shader_input(const InternalName *id, const PTA_float &v, int priority=0); @@ -698,10 +704,10 @@ PUBLISHED: INLINE LVecBase3 get_tex_scale_3d(const NodePath &other, TextureStage *stage) const; void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority = 0); - void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, - const string &source_name, const NodePath &light, + void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, + const string &source_name, const NodePath &light, int priority = 0); - void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, + void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, const LTexCoord3 &constant_value, int priority = 0); void clear_tex_gen(); @@ -915,20 +921,20 @@ PUBLISHED: private: static NodePathComponent * find_common_ancestor(const NodePath &a, const NodePath &b, - int &a_count, int &b_count, + int &a_count, int &b_count, Thread *current_thread); - CPT(RenderState) r_get_net_state(NodePathComponent *comp, + CPT(RenderState) r_get_net_state(NodePathComponent *comp, Thread *current_thread) const; CPT(RenderState) r_get_partial_state(NodePathComponent *comp, int n, Thread *current_thread) const; - CPT(TransformState) r_get_net_transform(NodePathComponent *comp, + CPT(TransformState) r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const; CPT(TransformState) r_get_partial_transform(NodePathComponent *comp, int n, Thread *current_thread) const; CPT(TransformState) r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const; - CPT(TransformState) r_get_partial_prev_transform(NodePathComponent *comp, + CPT(TransformState) r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const; void find_matches(NodePathCollection &result, @@ -937,7 +943,7 @@ private: void find_matches(NodePathCollection &result, FindApproxPath &approx_path, int max_matches) const; - void find_matches(NodePathCollection &result, + void find_matches(NodePathCollection &result, FindApproxLevelEntry *level, int max_matches) const; @@ -946,13 +952,13 @@ private: void r_force_recompute_bounds(PandaNode *node); - void r_set_collide_mask(PandaNode *node, + void r_set_collide_mask(PandaNode *node, CollideMask and_mask, CollideMask or_mask, TypeHandle node_type); typedef phash_set InternalNames; bool r_has_vertex_column(PandaNode *node, const InternalName *name) const; - void r_find_all_vertex_columns(PandaNode *node, + void r_find_all_vertex_columns(PandaNode *node, InternalNames &vertex_columns) const; typedef phash_set Textures; diff --git a/panda/src/pgraph/occluderNode.cxx b/panda/src/pgraph/occluderNode.cxx index 0063a7fba9..3afecfb25d 100644 --- a/panda/src/pgraph/occluderNode.cxx +++ b/panda/src/pgraph/occluderNode.cxx @@ -257,39 +257,39 @@ get_occluder_viz(CullTraverser *trav, CullTraverserData &data) { pgraph_cat.debug() << "Recomputing viz for " << *this << "\n"; } - + PT(GeomVertexData) vdata = new GeomVertexData (get_name(), GeomVertexFormat::get_v3n3t2(), Geom::UH_static); - + // Compute the polygon normal from the first three vertices. LPlane plane(_vertices[0], _vertices[1], _vertices[2]); LVector3 poly_normal = plane.get_normal(); - + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); GeomVertexWriter normal(vdata, InternalName::get_normal()); GeomVertexWriter texcoord(vdata, InternalName::get_texcoord()); vertex.add_data3(_vertices[0]); normal.add_data3(poly_normal); texcoord.add_data2(0.0, 0.0); - + vertex.add_data3(_vertices[1]); normal.add_data3(poly_normal); texcoord.add_data2(8.0, 0.0); - + vertex.add_data3(_vertices[2]); normal.add_data3(poly_normal); texcoord.add_data2(8.0, 8.0); - + vertex.add_data3(_vertices[3]); normal.add_data3(poly_normal); texcoord.add_data2(0.0, 8.0); - + PT(GeomTriangles) triangles = new GeomTriangles(Geom::UH_static); triangles->add_vertices(0, 1, 2); triangles->close_primitive(); triangles->add_vertices(0, 2, 3); triangles->close_primitive(); - + _occluder_viz = new Geom(vdata); _occluder_viz->add_primitive(triangles); @@ -297,7 +297,7 @@ get_occluder_viz(CullTraverser *trav, CullTraverserData &data) { lines->add_vertices(0, 1, 2, 3); lines->add_vertex(0); lines->close_primitive(); - + _frame_viz = new Geom(vdata); _frame_viz->add_primitive(lines); } @@ -321,8 +321,8 @@ get_occluder_viz_state(CullTraverser *trav, CullTraverserData &data) { PTA_uchar image; image.set_data("\x20\x80\x80\x20"); _viz_tex->set_ram_image(image); - _viz_tex->set_minfilter(Texture::FT_nearest); - _viz_tex->set_magfilter(Texture::FT_nearest); + _viz_tex->set_minfilter(SamplerState::FT_nearest); + _viz_tex->set_magfilter(SamplerState::FT_nearest); } static CPT(RenderState) viz_state; diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 354f5ff57f..35d29ddf82 100755 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -81,7 +81,7 @@ make_default() { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader(const Shader *s, int priority) const { @@ -96,7 +96,7 @@ set_shader(const Shader *s, int priority) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_off // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_off(int priority) const { @@ -117,7 +117,7 @@ set_shader_off(int priority) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_auto // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_auto(int priority) const { @@ -142,7 +142,7 @@ set_shader_auto(int priority) const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_auto(BitMask32 shader_switch, int priority) const { - + ShaderAttrib *result = new ShaderAttrib(*this); result->_shader = NULL; result->_shader_priority = priority; @@ -160,7 +160,7 @@ set_shader_auto(BitMask32 shader_switch, int priority) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::clear_shader // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: clear_shader() const { @@ -180,7 +180,7 @@ clear_shader() const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_flag // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_flag(int flag, bool value) const { @@ -194,11 +194,11 @@ set_flag(int flag, bool value) const { result->_has_flags |= bit; return return_new(result); } - + //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::clear_flag // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: clear_flag(int flag) const { @@ -212,7 +212,7 @@ clear_flag(int flag) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const ShaderInput *input) const { @@ -229,9 +229,9 @@ set_shader_input(const ShaderInput *input) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_float &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -239,9 +239,9 @@ set_shader_input(const InternalName *id, const PTA_float &v, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_double &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -249,9 +249,9 @@ set_shader_input(const InternalName *id, const PTA_double &v, int priority) cons //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -259,9 +259,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) c //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -270,9 +270,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) c //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -280,9 +280,9 @@ set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) c //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -290,9 +290,9 @@ set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -300,9 +300,9 @@ set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -310,9 +310,9 @@ set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -320,9 +320,9 @@ set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) co //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -330,9 +330,9 @@ set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) co //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -340,9 +340,9 @@ set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) ShaderAttrib:: +CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) const { return set_shader_input(new ShaderInput(id,v,priority)); } @@ -350,7 +350,7 @@ set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, Texture *tex, int priority) const { @@ -360,7 +360,7 @@ set_shader_input(const InternalName *id, Texture *tex, int priority) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, const NodePath &np, int priority) const { @@ -370,7 +370,7 @@ set_shader_input(const InternalName *id, const NodePath &np, int priority) const //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::set_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: set_shader_input(const InternalName *id, double n1, double n2, double n3, double n4, int priority) const { @@ -395,7 +395,7 @@ set_instance_count(int instance_count) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::clear_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: clear_shader_input(const InternalName *id) const { @@ -407,7 +407,7 @@ clear_shader_input(const InternalName *id) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::clear_shader_input // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: clear_shader_input(const string &id) const { @@ -458,7 +458,7 @@ get_shader_input(const string &id) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::get_shader_input_nodepath // Access: Published -// Description: Returns the ShaderInput as a nodepath. Assertion +// Description: Returns the ShaderInput as a nodepath. Assertion // fails if there is none, or if it is not a nodepath. //////////////////////////////////////////////////////////////////// const NodePath &ShaderAttrib:: @@ -488,7 +488,7 @@ get_shader_input_nodepath(const InternalName *id) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::get_shader_input_vector // Access: Published -// Description: Returns the ShaderInput as a vector. Assertion +// Description: Returns the ShaderInput as a vector. Assertion // fails if there is none, or if it is not a vector. //////////////////////////////////////////////////////////////////// const LVecBase4 &ShaderAttrib:: @@ -502,24 +502,33 @@ get_shader_input_vector(InternalName *id) const { return resfail; } else { const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_numeric) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not a vector.\n"; - nassert_raise(strm.str()); - return resfail; + + if (p->get_value_type() == ShaderInput::M_numeric) { + return p->get_vector(); + + } else if (p->get_value_type() == ShaderInput::M_param) { + // Temporary solution until the new param system + ParamValueBase *param = p->get_param(); + if (param != NULL && param->is_of_type(ParamVecBase4::get_class_type())) { + return ((const ParamVecBase4 *) param)->get_value(); + } } - return p->get_vector(); + + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not a vector.\n"; + nassert_raise(strm.str()); + return resfail; } } //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::get_shader_input_ptr // Access: Published -// Description: Returns the ShaderInput as a ShaderPtrData struct. -// Assertion fails if there is none. or if it is not +// Description: Returns the ShaderInput as a ShaderPtrData struct. +// Assertion fails if there is none. or if it is not // a PTA(double/float) //////////////////////////////////////////////////////////////////// -const Shader::ShaderPtrData *ShaderAttrib:: +const Shader::ShaderPtrData *ShaderAttrib:: get_shader_input_ptr(const InternalName *id) const { Inputs::const_iterator i = _inputs.find(id); if (i == _inputs.end()) { @@ -542,7 +551,7 @@ get_shader_input_ptr(const InternalName *id) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::get_shader_input_texture // Access: Published -// Description: Returns the ShaderInput as a texture. Assertion +// Description: Returns the ShaderInput as a texture. Assertion // fails if there is none, or if it is not a texture. //////////////////////////////////////////////////////////////////// Texture *ShaderAttrib:: @@ -555,7 +564,8 @@ get_shader_input_texture(const InternalName *id) const { return NULL; } else { const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_texture) { + if (p->get_value_type() != ShaderInput::M_texture && + p->get_value_type() != ShaderInput::M_texture_sampler) { ostringstream strm; strm << "Shader input " << id->get_name() << " is not a texture.\n"; nassert_raise(strm.str()); @@ -565,6 +575,33 @@ get_shader_input_texture(const InternalName *id) const { } } +//////////////////////////////////////////////////////////////////// +// Function: ShaderAttrib::get_shader_input_sampler +// Access: Published +// Description: Returns the ShaderInput as a sampler. Assertion +// fails if there is none, or if it is not a texture. +//////////////////////////////////////////////////////////////////// +const SamplerState &ShaderAttrib:: +get_shader_input_sampler(const InternalName *id) const { + Inputs::const_iterator i = _inputs.find(id); + if (i == _inputs.end()) { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return SamplerState::get_default(); + } else { + const ShaderInput *p = (*i).second; + if (p->get_value_type() != ShaderInput::M_texture && + p->get_value_type() != ShaderInput::M_texture_sampler) { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not a texture.\n"; + nassert_raise(strm.str()); + return SamplerState::get_default(); + } + return p->get_sampler(); + } +} + //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::get_shader_input_matrix // Access: Published @@ -604,6 +641,12 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { matrix = LCAST(PN_stdfloat, matrixd); return matrix; } + default: { + ostringstream strm; + strm << "Shader input " << id->get_name() << " does not contain floating-point data.\n"; + nassert_raise(strm.str()); + return LMatrix4::ident_mat(); + } } } @@ -618,7 +661,7 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { // Function: ShaderAttrib::get_shader // Access: Published // Description: Returns the shader object associated with the node. -// If get_override returns true, but get_shader +// If get_override returns true, but get_shader // returns NULL, that means that this attribute should // disable the shader. //////////////////////////////////////////////////////////////////// @@ -646,7 +689,7 @@ int ShaderAttrib:: compare_to_impl(const RenderAttrib *other) const { const ShaderAttrib *that; DCAST_INTO_R(that, other, 0); - + if (this->_shader != that->_shader) { return (this->_shader < that->_shader) ? -1 : 1; } @@ -699,7 +742,7 @@ compare_to_impl(const RenderAttrib *other) const { if (i2 != that->_inputs.end()) { return -1; } - + return 0; } @@ -789,7 +832,7 @@ compose_impl(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// // Function: ShaderAttrib::get_auto_shader_attrib_impl // Access: Protected, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderAttrib:: get_auto_shader_attrib_impl(const RenderState *state) const { diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index 0f8f22505c..6795adf9dc 100755 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -33,11 +33,9 @@ //////////////////////////////////////////////////////////////////// // Class : ShaderAttrib -// Description : +// Description : //////////////////////////////////////////////////////////////////// - class EXPCL_PANDA_PGRAPH ShaderAttrib: public RenderAttrib { - private: INLINE ShaderAttrib(); INLINE ShaderAttrib(const ShaderAttrib ©); @@ -71,7 +69,7 @@ PUBLISHED: CPT(RenderAttrib) clear_shader() const; // Shader Inputs CPT(RenderAttrib) set_shader_input(const ShaderInput *inp) const; - + // InternalName* id CPT(RenderAttrib) set_shader_input(const InternalName *id, Texture *tex, int priority=0) const; CPT(RenderAttrib) set_shader_input(const InternalName *id, const NodePath &np, int priority=0) const; @@ -88,7 +86,7 @@ PUBLISHED: CPT(RenderAttrib) set_shader_input(const InternalName *id, const LMatrix4 &v, int priority=0) const; CPT(RenderAttrib) set_shader_input(const InternalName *id, const LMatrix3 &v, int priority=0) const; CPT(RenderAttrib) set_shader_input(const InternalName *id, double n1=0, double n2=0, double n3=0, double n4=1, - int priority=0) const; + int priority=0) const; CPT(RenderAttrib) set_instance_count(int instance_count) const; @@ -97,11 +95,11 @@ PUBLISHED: CPT(RenderAttrib) clear_shader_input(const InternalName *id) const; CPT(RenderAttrib) clear_shader_input(const string &id) const; - + CPT(RenderAttrib) clear_all_shader_inputs() const; INLINE bool get_flag(int flag) const; - + const Shader *get_shader() const; const ShaderInput *get_shader_input(const InternalName *id) const; const ShaderInput *get_shader_input(const string &id) const; @@ -109,11 +107,12 @@ PUBLISHED: const NodePath &get_shader_input_nodepath(const InternalName *id) const; const LVecBase4 &get_shader_input_vector(InternalName *id) const; Texture *get_shader_input_texture(const InternalName *id) const; + const SamplerState &get_shader_input_sampler(const InternalName *id) const; const Shader::ShaderPtrData *get_shader_input_ptr(const InternalName *id) const; const LMatrix4 &get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const; static void register_with_read_factory(); - + public: protected: @@ -121,7 +120,7 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; - + private: CPT(Shader) _shader; diff --git a/panda/src/pgraph/shaderInput.I b/panda/src/pgraph/shaderInput.I index 8268d8a78c..483febbb9d 100644 --- a/panda/src/pgraph/shaderInput.I +++ b/panda/src/pgraph/shaderInput.I @@ -12,20 +12,20 @@ // //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Destructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -~ShaderInput() -{ +~ShaderInput() { } //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, int priority) : @@ -41,14 +41,14 @@ ShaderInput(const InternalName *name, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, Texture *tex, int priority) : _name(name), _type(M_texture), _priority(priority), - _stored_texture(tex), + _value(tex), _bind_layer(0), _bind_level(0), _access(A_read | A_write | A_layered) @@ -58,14 +58,32 @@ ShaderInput(const InternalName *name, Texture *tex, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ShaderInput:: +ShaderInput(const InternalName *name, Texture *tex, const SamplerState &sampler, int priority) : + _name(name), + _type(M_texture_sampler), + _priority(priority), + _value(tex), + _sampler(sampler), + _bind_layer(0), + _bind_level(0), + _access(A_read | A_layered) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::Constructor +// Access: Published +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, Texture *tex, bool read, bool write, int z, int n, int priority) : _name(name), _type(M_texture), _priority(priority), - _stored_texture(tex), + _value(tex), _bind_layer(z), _bind_level(n), _access(0) @@ -87,7 +105,24 @@ ShaderInput(const InternalName *name, Texture *tex, bool read, bool write, int z //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ShaderInput:: +ShaderInput(const InternalName *name, ParamValueBase *param, int priority) : + _name(name), + _type(M_param), + _priority(priority), + _value(param), + _bind_layer(0), + _bind_level(0), + _access(A_read) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::Constructor +// Access: Published +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const NodePath &np, int priority) : @@ -104,10 +139,10 @@ ShaderInput(const InternalName *name, const NodePath &np, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_float &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_float &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -121,10 +156,10 @@ ShaderInput(const InternalName *name, const PTA_float &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LVecBase4f &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LVecBase4f &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -138,10 +173,10 @@ ShaderInput(const InternalName *name, const PTA_LVecBase4f &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LVecBase3f &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LVecBase3f &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -155,7 +190,7 @@ ShaderInput(const InternalName *name, const PTA_LVecBase3f &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const PTA_LVecBase2f &ptr, int priority) : @@ -172,7 +207,7 @@ ShaderInput(const InternalName *name, const PTA_LVecBase2f &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase4f &vec, int priority) : @@ -190,7 +225,7 @@ ShaderInput(const InternalName *name, const LVecBase4f &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase3f &vec, int priority) : @@ -208,7 +243,7 @@ ShaderInput(const InternalName *name, const LVecBase3f &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase2f &vec, int priority) : @@ -226,10 +261,10 @@ ShaderInput(const InternalName *name, const LVecBase2f &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LMatrix4f &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LMatrix4f &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -243,10 +278,10 @@ ShaderInput(const InternalName *name, const PTA_LMatrix4f &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LMatrix3f &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LMatrix3f &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -260,7 +295,7 @@ ShaderInput(const InternalName *name, const PTA_LMatrix3f &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LMatrix4f &mat, int priority) : @@ -277,7 +312,7 @@ ShaderInput(const InternalName *name, const LMatrix4f &mat, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LMatrix3f &mat, int priority) : @@ -294,10 +329,10 @@ ShaderInput(const InternalName *name, const LMatrix3f &mat, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_double &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_double &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -311,10 +346,10 @@ ShaderInput(const InternalName *name, const PTA_double &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LVecBase4d &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LVecBase4d &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -328,10 +363,10 @@ ShaderInput(const InternalName *name, const PTA_LVecBase4d &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LVecBase3d &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LVecBase3d &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -345,7 +380,7 @@ ShaderInput(const InternalName *name, const PTA_LVecBase3d &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const PTA_LVecBase2d &ptr, int priority) : @@ -362,7 +397,7 @@ ShaderInput(const InternalName *name, const PTA_LVecBase2d &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase4d &vec, int priority) : @@ -380,7 +415,7 @@ ShaderInput(const InternalName *name, const LVecBase4d &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase3d &vec, int priority) : @@ -398,7 +433,7 @@ ShaderInput(const InternalName *name, const LVecBase3d &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase2d &vec, int priority) : @@ -416,10 +451,10 @@ ShaderInput(const InternalName *name, const LVecBase2d &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LMatrix4d &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LMatrix4d &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -433,10 +468,10 @@ ShaderInput(const InternalName *name, const PTA_LMatrix4d &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LMatrix3d &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LMatrix3d &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -450,7 +485,7 @@ ShaderInput(const InternalName *name, const PTA_LMatrix3d &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LMatrix4d &mat, int priority) : @@ -467,7 +502,7 @@ ShaderInput(const InternalName *name, const LMatrix4d &mat, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LMatrix3d &mat, int priority) : @@ -484,10 +519,10 @@ ShaderInput(const InternalName *name, const LMatrix3d &mat, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_int &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_int &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -501,10 +536,10 @@ ShaderInput(const InternalName *name, const PTA_int &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LVecBase4i &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LVecBase4i &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -518,10 +553,10 @@ ShaderInput(const InternalName *name, const PTA_LVecBase4i &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: -ShaderInput(const InternalName *name, const PTA_LVecBase3i &ptr, int priority) : +ShaderInput(const InternalName *name, const PTA_LVecBase3i &ptr, int priority) : _name(name), _type(M_numeric), _priority(priority), @@ -535,7 +570,7 @@ ShaderInput(const InternalName *name, const PTA_LVecBase3i &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const PTA_LVecBase2i &ptr, int priority) : @@ -552,7 +587,7 @@ ShaderInput(const InternalName *name, const PTA_LVecBase2i &ptr, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase4i &vec, int priority) : @@ -570,7 +605,7 @@ ShaderInput(const InternalName *name, const LVecBase4i &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase3i &vec, int priority) : @@ -588,7 +623,7 @@ ShaderInput(const InternalName *name, const LVecBase3i &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE ShaderInput:: ShaderInput(const InternalName *name, const LVecBase2i &vec, int priority) : @@ -606,7 +641,7 @@ ShaderInput(const InternalName *name, const LVecBase2i &vec, int priority) : //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_name // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE const InternalName *ShaderInput:: get_name() const { @@ -616,7 +651,7 @@ get_name() const { //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_value_type // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE int ShaderInput:: get_value_type() const { @@ -626,7 +661,7 @@ get_value_type() const { //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_priority // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE int ShaderInput:: get_priority() const { @@ -636,27 +671,17 @@ get_priority() const { //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_texture // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE Texture *ShaderInput:: get_texture() const { - return _stored_texture; -} - -//////////////////////////////////////////////////////////////////// -// Function: ShaderInput::get_ptr -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -INLINE const Shader::ShaderPtrData &ShaderInput:: -get_ptr() const { - return _stored_ptr; + return DCAST(Texture, _value); } //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_nodepath // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE const NodePath &ShaderInput:: get_nodepath() const { @@ -666,10 +691,41 @@ get_nodepath() const { //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_vector // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE const LVecBase4 &ShaderInput:: get_vector() const { return _stored_vector; } +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::get_ptr +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE const Shader::ShaderPtrData &ShaderInput:: +get_ptr() const { + return _stored_ptr; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::get_sampler +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE const SamplerState &ShaderInput:: +get_sampler() const { + return (_type == M_texture) + ? get_texture()->get_default_sampler() + : _sampler; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::get_param +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ParamValueBase *ShaderInput:: +get_param() const { + return DCAST(ParamValueBase, _value); +} diff --git a/panda/src/pgraph/shaderInput.h b/panda/src/pgraph/shaderInput.h index 4e1433e239..4d289d09ec 100644 --- a/panda/src/pgraph/shaderInput.h +++ b/panda/src/pgraph/shaderInput.h @@ -20,9 +20,8 @@ #include "typedWritableReferenceCount.h" #include "pointerTo.h" #include "nodePath.h" -#include "texture.h" #include "internalName.h" -#include "shader.h" +#include "paramValue.h" #include "pta_float.h" #include "pta_double.h" #include "pta_LMatrix4.h" @@ -30,6 +29,9 @@ #include "pta_LVecBase4.h" #include "pta_LVecBase3.h" #include "pta_LVecBase2.h" +#include "samplerState.h" +#include "shader.h" +#include "texture.h" //////////////////////////////////////////////////////////////////// // Class : ShaderInput @@ -37,8 +39,7 @@ // one of the value types that can be passed as input // to a shader. //////////////////////////////////////////////////////////////////// - -class EXPCL_PANDA_PGRAPH ShaderInput: public TypedWritableReferenceCount { +class EXPCL_PANDA_PGRAPH ShaderInput : public TypedWritableReferenceCount { public: INLINE ~ShaderInput(); @@ -54,7 +55,9 @@ PUBLISHED: INLINE ShaderInput(const InternalName *id, int priority=0); INLINE ShaderInput(const InternalName *id, const NodePath &np, int priority=0); INLINE ShaderInput(const InternalName *id, Texture *tex, int priority=0); + INLINE ShaderInput(const InternalName *id, Texture *tex, const SamplerState &sampler, int priority=0); INLINE ShaderInput(const InternalName *id, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0); + INLINE ShaderInput(const InternalName *id, ParamValueBase *param, int priority=0); INLINE ShaderInput(const InternalName *id, const PTA_float &ptr, int priority=0); INLINE ShaderInput(const InternalName *id, const PTA_LVecBase4f &ptr, int priority=0); INLINE ShaderInput(const InternalName *id, const PTA_LVecBase3f &ptr, int priority=0); @@ -91,7 +94,9 @@ PUBLISHED: M_invalid = 0, M_texture, M_nodepath, - M_numeric + M_numeric, + M_texture_sampler, + M_param }; INLINE const InternalName *get_name() const; @@ -102,23 +107,27 @@ PUBLISHED: INLINE const NodePath &get_nodepath() const; INLINE const LVecBase4 &get_vector() const; INLINE const Shader::ShaderPtrData &get_ptr() const; + INLINE const SamplerState &get_sampler() const; public: + INLINE ParamValueBase *get_param() const; + static void register_with_read_factory(); private: - CPT(InternalName) _name; - int _type; - int _priority; - Shader::ShaderPtrData _stored_ptr; - PT(Texture) _stored_texture; - NodePath _stored_nodepath; + SamplerState _sampler; LVecBase4 _stored_vector; + NodePath _stored_nodepath; + Shader::ShaderPtrData _stored_ptr; + CPT(InternalName) _name; + PT(TypedWritableReferenceCount) _value; + int _priority; public: + int _type : 8; + int _access : 8; + int _bind_level : 16; int _bind_layer; - int _bind_level; - int _access; public: static TypeHandle get_class_type() { diff --git a/panda/src/pgraph/textureAttrib.I b/panda/src/pgraph/textureAttrib.I index 8ec117ab0f..003e9ca819 100644 --- a/panda/src/pgraph/textureAttrib.I +++ b/panda/src/pgraph/textureAttrib.I @@ -109,7 +109,7 @@ get_on_stage(int n) const { // Function: TextureAttrib::get_num_on_ff_stages // Access: Published // Description: Returns the number of on-stages that are relevant -// to the classic fixed function pipeline. This excludes +// to the classic fixed function pipeline. This excludes // texture stages such as normal maps. //////////////////////////////////////////////////////////////////// INLINE int TextureAttrib:: @@ -123,7 +123,7 @@ get_num_on_ff_stages() const { // Access: Published // Description: Returns the nth stage turned on by the attribute, // sorted in render order, including only those relevant -// to the classic fixed function pipeline. This excludes +// to the classic fixed function pipeline. This excludes // texture stages such as normal maps. //////////////////////////////////////////////////////////////////// INLINE TextureStage *TextureAttrib:: @@ -175,6 +175,24 @@ get_on_texture(TextureStage *stage) const { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::get_on_sampler +// Access: Published +// Description: Returns the sampler associated with the indicated +// stage, or the one associated with its texture if +// no custom stage has been specified. It is an error +// to call this if the stage does not exist. +//////////////////////////////////////////////////////////////////// +INLINE const SamplerState &TextureAttrib:: +get_on_sampler(TextureStage *stage) const { + Stages::const_iterator si; + si = _on_stages.find(StageNode(stage)); + nassertr_always(si != _on_stages.end(), SamplerState::get_default()); + + return si->_has_sampler ? si->_sampler + : si->_texture->get_default_sampler(); +} + //////////////////////////////////////////////////////////////////// // Function: TextureAttrib::get_on_stage_override // Access: Published @@ -269,7 +287,7 @@ check_sorted() const { //////////////////////////////////////////////////////////////////// // Function: TextureAttrib::StageNode::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE TextureAttrib::StageNode:: StageNode(const TextureStage *stage, unsigned int implicit_sort, int override) : @@ -277,11 +295,11 @@ StageNode(const TextureStage *stage, unsigned int implicit_sort, int override) : // deal with it properly. _stage((TextureStage *)stage), _implicit_sort(implicit_sort), - _override(override) + _override(override), + _has_sampler(false) { } - //////////////////////////////////////////////////////////////////// // Function: TextureAttrib::CompareTextureStagePriorities::operator () // Access: Public @@ -290,7 +308,7 @@ StageNode(const TextureStage *stage, unsigned int implicit_sort, int override) : // within priority, within order by sort. //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib::CompareTextureStagePriorities:: -operator () (const TextureAttrib::StageNode *a, +operator () (const TextureAttrib::StageNode *a, const TextureAttrib::StageNode *b) const { if (a->_stage->get_priority() != b->_stage->get_priority()) { return a->_stage->get_priority() > b->_stage->get_priority(); @@ -308,7 +326,7 @@ operator () (const TextureAttrib::StageNode *a, // texture stages in order by sort. //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib::CompareTextureStageSort:: -operator () (const TextureAttrib::StageNode *a, +operator () (const TextureAttrib::StageNode *a, const TextureAttrib::StageNode *b) const { if (a->_stage->get_sort() != b->_stage->get_sort()) { return a->_stage->get_sort() < b->_stage->get_sort(); @@ -323,7 +341,7 @@ operator () (const TextureAttrib::StageNode *a, // texture stages in order by pointer. //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib::CompareTextureStagePointer:: -operator () (const TextureAttrib::StageNode &a, +operator () (const TextureAttrib::StageNode &a, const TextureAttrib::StageNode &b) const { return a._stage < b._stage; } diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index 452378d37d..bb7a4808e5 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -131,6 +131,32 @@ add_on_stage(TextureStage *stage, Texture *tex, int override) const { (*si)._override = override; (*si)._texture = tex; (*si)._implicit_sort = attrib->_next_implicit_sort; + (*si)._has_sampler = false; + ++(attrib->_next_implicit_sort); + + // We now need to re-sort the attrib list. + attrib->_sort_seq = UpdateSeq::old(); + attrib->_filtered_seq = UpdateSeq::old(); + + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::add_on_stage +// Access: Published +// Description: Returns a new TextureAttrib, just like this one, but +// with the indicated stage added to the list of stages +// turned on by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) TextureAttrib:: +add_on_stage(TextureStage *stage, Texture *tex, const SamplerState &sampler, int override) const { + TextureAttrib *attrib = new TextureAttrib(*this); + Stages::iterator si = attrib->_on_stages.insert(StageNode(stage)).first; + (*si)._override = override; + (*si)._texture = tex; + (*si)._sampler = sampler; + (*si)._implicit_sort = attrib->_next_implicit_sort; + (*si)._has_sampler = true; ++(attrib->_next_implicit_sort); // We now need to re-sort the attrib list. @@ -239,7 +265,7 @@ unify_texture_stages(TextureStage *stage) const { for (fsi = _off_stages.begin(); fsi != _off_stages.end(); ++fsi) { TextureStage *this_stage = (*fsi)._stage; - if (this_stage != stage && + if (this_stage != stage && this_stage->get_name() == stage->get_name()) { this_stage = stage; any_changed = true; @@ -291,7 +317,7 @@ filter_to_max(int max_texture_stages) const { RenderStages priority_stages = _render_stages; // This sort function uses the STL function object defined above. - sort(priority_stages.begin(), priority_stages.end(), + sort(priority_stages.begin(), priority_stages.end(), CompareTextureStagePriorities()); // Now lop off all of the stages after the first max_texture_stages. @@ -362,7 +388,7 @@ lower_attrib_can_override() const { //////////////////////////////////////////////////////////////////// // Function: TextureAttrib::output // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void TextureAttrib:: output(ostream &out) const { @@ -399,7 +425,7 @@ output(ostream &out) const { out << " on"; } } - + RenderStages::const_iterator ri; for (ri = _render_stages.begin(); ri != _render_stages.end(); ++ri) { const StageNode &sn = *(*ri); @@ -520,6 +546,22 @@ compare_to_impl(const RenderAttrib *other) const { return override < other_override ? -1 : 1; } + int has_sampler = (*si)._has_sampler; + int other_has_sampler = (*osi)._has_sampler; + + if (has_sampler != other_has_sampler) { + return has_sampler < other_has_sampler ? -1 : 1; + } + + if (has_sampler) { + const SamplerState &sampler = (*si)._sampler; + const SamplerState &other_sampler = (*osi)._sampler; + + if (sampler != other_sampler) { + return sampler < other_sampler ? -1 : 1; + } + } + ++si; ++osi; } @@ -560,7 +602,7 @@ compare_to_impl(const RenderAttrib *other) const { if (ofi != ta->_off_stages.end()) { return -1; } - + return 0; } @@ -641,8 +683,8 @@ compose_impl(const RenderAttrib *other) const { // Create a new TextureAttrib that will hold the result. TextureAttrib *attrib = new TextureAttrib; - while (ai != _on_stages.end() && - bi != ta->_on_stages.end() && + while (ai != _on_stages.end() && + bi != ta->_on_stages.end() && ci != ta->_off_stages.end()) { if ((*ai)._stage < (*bi)._stage) { if ((*ai)._stage < (*ci)._stage) { @@ -717,12 +759,12 @@ compose_impl(const RenderAttrib *other) const { // present in the secondary. attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); ++ai; - + } else if ((*ci)._stage < (*ai)._stage) { // Here is a stage that is turned off in the secondary, but // was not present in the original. ++ci; - + } else { // (*ci)._stage == (*ai)._stage // Here is a stage that is turned off in the secondary, and // was present in the original. @@ -772,7 +814,7 @@ invert_compose_impl(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// // Function: TextureAttrib::get_auto_shader_attrib_impl // Access: Protected, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TextureAttrib:: get_auto_shader_attrib_impl(const RenderState *state) const { @@ -821,6 +863,10 @@ write_datagram(BamWriter *manager, Datagram &dg) { manager->write_pointer(dg, tex); dg.add_uint16((*si)._implicit_sort); dg.add_int32((*si)._override); + dg.add_bool((*si)._has_sampler); + if ((*si)._has_sampler) { + (*si)._sampler.write_datagram(dg); + } } } @@ -850,13 +896,13 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { // The Texture pointer filters itself through the TexturePool, so // we don't have to do anything special here. Texture *tex = DCAST(Texture, p_list[pi++]); - + if (tex != (Texture *)NULL) { StageNode &sn = _on_stages[sni]; sn._stage = ts; sn._texture = tex; ++sni; - + } else { // If we couldn't load a texture pointer, turn off that // particular texture stage. @@ -905,7 +951,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { // read the _off_stages data. _off_all_stages = scan.get_bool(); int num_off_stages = scan.get_uint16(); - + // Push back a NULL pointer for each off TextureStage for now, until // we get the actual list of pointers later in complete_pointers(). int i; @@ -938,8 +984,16 @@ fillin(DatagramIterator &scan, BamReader *manager) { } _next_implicit_sort = max(_next_implicit_sort, implicit_sort + 1); - _on_stages.push_back(StageNode(NULL, _next_implicit_sort, override)); + Stages::iterator si = + _on_stages.insert_nonunique(StageNode(NULL, _next_implicit_sort, override)); ++_next_implicit_sort; + + if (manager->get_file_minor_ver() >= 36) { + (*si)._has_sampler = scan.get_bool(); + if ((*si)._has_sampler) { + (*si)._sampler.read_datagram(scan, manager); + } + } } } diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index f9bd610dc9..6a0b48928c 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -61,6 +61,7 @@ PUBLISHED: INLINE int get_ff_tc_index(int n) const; INLINE bool has_on_stage(TextureStage *stage) const; INLINE Texture *get_on_texture(TextureStage *stage) const; + INLINE const SamplerState &get_on_sampler(TextureStage *stage) const; INLINE int get_on_stage_override(TextureStage *stage) const; int find_on_stage(const TextureStage *stage) const; @@ -74,6 +75,8 @@ PUBLISHED: INLINE bool is_identity() const; CPT(RenderAttrib) add_on_stage(TextureStage *stage, Texture *tex, int override = 0) const; + CPT(RenderAttrib) add_on_stage(TextureStage *stage, Texture *tex, + const SamplerState &sampler, int override = 0) const; CPT(RenderAttrib) remove_on_stage(TextureStage *stage) const; CPT(RenderAttrib) add_off_stage(TextureStage *stage, int override = 0) const; CPT(RenderAttrib) remove_off_stage(TextureStage *stage) const; @@ -102,12 +105,14 @@ private: private: class StageNode { public: - INLINE StageNode(const TextureStage *stage, + INLINE StageNode(const TextureStage *stage, unsigned int implicit_sort = 0, int override = 0); PT(TextureStage) _stage; PT(Texture) _texture; + SamplerState _sampler; + bool _has_sampler; int _ff_tc_index; unsigned int _implicit_sort; int _override; @@ -135,7 +140,7 @@ private: RenderStages _render_stages; // all "on" stages, sorted in render order. RenderStages _render_ff_stages; // fixed-function stages only, in render order. unsigned int _next_implicit_sort; - + Stages _off_stages; bool _off_all_stages; @@ -164,7 +169,7 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; @@ -188,4 +193,3 @@ private: #include "textureAttrib.I" #endif - diff --git a/panda/src/pgraphnodes/spotlight.cxx b/panda/src/pgraphnodes/spotlight.cxx index d44b944ab8..28548f919e 100644 --- a/panda/src/pgraphnodes/spotlight.cxx +++ b/panda/src/pgraphnodes/spotlight.cxx @@ -199,11 +199,11 @@ make_spot(int pixel_width, PN_stdfloat full_radius, LColor &fg, LColor &bg) { PT(Texture) tex = new Texture("spot"); tex->load(image); tex->set_border_color(bg); - tex->set_wrap_u(Texture::WM_border_color); - tex->set_wrap_v(Texture::WM_border_color); + tex->set_wrap_u(SamplerState::WM_border_color); + tex->set_wrap_v(SamplerState::WM_border_color); - tex->set_minfilter(Texture::FT_linear); - tex->set_magfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); + tex->set_magfilter(SamplerState::FT_linear); return tex; } diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 7930a7f62c..aa07af2c2f 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6; // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData. static const unsigned short _bam_first_minor_ver = 14; -static const unsigned short _bam_minor_ver = 35; +static const unsigned short _bam_minor_ver = 36; // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib. // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort. // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level. @@ -56,5 +56,6 @@ static const unsigned short _bam_minor_ver = 35; // Bumped to minor version 33 on 8/17/13 to add UvScrollNode::_w_speed. // Bumped to minor version 34 on 9/16/14 to add ScissorAttrib::_off. // Bumped to minor version 35 on 12/3/14 to change StencilAttrib. +// Bumped to minor version 36 on 12/9/14 to add samplers and lod settings. #endif diff --git a/panda/src/rocket/rocketRenderInterface.cxx b/panda/src/rocket/rocketRenderInterface.cxx index 473b1bad65..fe62db3c70 100644 --- a/panda/src/rocket/rocketRenderInterface.cxx +++ b/panda/src/rocket/rocketRenderInterface.cxx @@ -231,8 +231,8 @@ LoadTexture(Rocket::Core::TextureHandle& texture_handle, return false; } - tex->set_minfilter(Texture::FT_nearest); - tex->set_magfilter(Texture::FT_nearest); + tex->set_minfilter(SamplerState::FT_nearest); + tex->set_magfilter(SamplerState::FT_nearest); texture_dimensions.x = tex->get_x_size(); texture_dimensions.y = tex->get_y_size(); @@ -271,10 +271,10 @@ GenerateTexture(Rocket::Core::TextureHandle& texture_handle, } } - tex->set_wrap_u(Texture::WM_clamp); - tex->set_wrap_v(Texture::WM_clamp); - tex->set_minfilter(Texture::FT_nearest); - tex->set_magfilter(Texture::FT_nearest); + tex->set_wrap_u(SamplerState::WM_clamp); + tex->set_wrap_v(SamplerState::WM_clamp); + tex->set_minfilter(SamplerState::FT_nearest); + tex->set_magfilter(SamplerState::FT_nearest); tex->ref(); texture_handle = (Rocket::Core::TextureHandle) tex.p(); diff --git a/panda/src/testbed/test_texmem.cxx b/panda/src/testbed/test_texmem.cxx index 63ce9138a6..fba7b30c2e 100644 --- a/panda/src/testbed/test_texmem.cxx +++ b/panda/src/testbed/test_texmem.cxx @@ -81,7 +81,7 @@ event_T(const Event *, void *data) { (tex_y_size - white_center.get_y_size()) / 2); PT(Texture) tex = new Texture; - tex->set_minfilter(Texture::FT_linear_mipmap_linear); + tex->set_minfilter(SamplerState::FT_linear_mipmap_linear); tex->load(bogus_image); CardMaker cm("card"); diff --git a/panda/src/testbed/text_test.cxx b/panda/src/testbed/text_test.cxx index 1de5804f5d..61232d16d2 100644 --- a/panda/src/testbed/text_test.cxx +++ b/panda/src/testbed/text_test.cxx @@ -54,8 +54,8 @@ void text_keys(EventHandler& eh) { text_node->set_card_as_margin(0.25, 0.25, 0.25, 0.25); PT(Texture) tex = new Texture; tex->set_name("genericButton.rgb"); - tex->set_minfilter(Texture::FT_linear); - tex->set_magfilter(Texture::FT_linear); + tex->set_minfilter(SamplerState::FT_linear); + tex->set_magfilter(SamplerState::FT_linear); tex->read("/beta/toons/textures/smGreyButtonUp.rgb"); text_node->set_card_texture( tex ); text_node->set_card_border(0.1, 0.1); diff --git a/panda/src/text/config_text.cxx b/panda/src/text/config_text.cxx index a963413467..086f0f58d8 100644 --- a/panda/src/text/config_text.cxx +++ b/panda/src/text/config_text.cxx @@ -182,14 +182,14 @@ ConfigVariableDouble text_default_underscore_height PRC_DESC("Specifies the default height of the underscore line, relative " "to the text baseline, when underscoring is enabled.")); -ConfigVariableEnum text_minfilter -("text-minfilter", Texture::FT_linear, +ConfigVariableEnum text_minfilter +("text-minfilter", SamplerState::FT_linear, PRC_DESC("The default texture minfilter type for dynamic text fonts")); -ConfigVariableEnum text_magfilter -("text-magfilter", Texture::FT_linear, +ConfigVariableEnum text_magfilter +("text-magfilter", SamplerState::FT_linear, PRC_DESC("The default texture magfilter type for dynamic text fonts")); -ConfigVariableEnum text_wrap_mode -("text-wrap-mode", Texture::WM_border_color, +ConfigVariableEnum text_wrap_mode +("text-wrap-mode", SamplerState::WM_border_color, PRC_DESC("The default wrap mode for dynamic text fonts")); ConfigVariableEnum text_quality_level ("text-quality-level", Texture::QL_best, diff --git a/panda/src/text/config_text.h b/panda/src/text/config_text.h index 6d4d01f6af..fb0a0f674c 100644 --- a/panda/src/text/config_text.h +++ b/panda/src/text/config_text.h @@ -50,9 +50,9 @@ extern wstring get_text_never_break_before(); extern ConfigVariableInt text_max_never_break; extern ConfigVariableDouble text_default_underscore_height; -extern ConfigVariableEnum text_minfilter; -extern ConfigVariableEnum text_magfilter; -extern ConfigVariableEnum text_wrap_mode; +extern ConfigVariableEnum text_minfilter; +extern ConfigVariableEnum text_magfilter; +extern ConfigVariableEnum text_wrap_mode; extern ConfigVariableEnum text_quality_level; extern ConfigVariableEnum text_render_mode; diff --git a/panda/src/text/dynamicTextFont.I b/panda/src/text/dynamicTextFont.I index 74bc828cf1..30efec424b 100644 --- a/panda/src/text/dynamicTextFont.I +++ b/panda/src/text/dynamicTextFont.I @@ -293,7 +293,7 @@ get_page_y_size() const { // textures created for this font. //////////////////////////////////////////////////////////////////// INLINE void DynamicTextFont:: -set_minfilter(Texture::FilterType filter) { +set_minfilter(SamplerState::FilterType filter) { _minfilter = filter; update_filters(); } @@ -304,7 +304,7 @@ set_minfilter(Texture::FilterType filter) { // Description: Returns the filter type used when minimizing the // textures created for this font. //////////////////////////////////////////////////////////////////// -INLINE Texture::FilterType DynamicTextFont:: +INLINE SamplerState::FilterType DynamicTextFont:: get_minfilter() const { return _minfilter; } @@ -316,7 +316,7 @@ get_minfilter() const { // textures created for this font. //////////////////////////////////////////////////////////////////// INLINE void DynamicTextFont:: -set_magfilter(Texture::FilterType filter) { +set_magfilter(SamplerState::FilterType filter) { _magfilter = filter; update_filters(); } @@ -327,7 +327,7 @@ set_magfilter(Texture::FilterType filter) { // Description: Returns the filter type used when enlarging the // textures created for this font. //////////////////////////////////////////////////////////////////// -INLINE Texture::FilterType DynamicTextFont:: +INLINE SamplerState::FilterType DynamicTextFont:: get_magfilter() const { return _magfilter; } diff --git a/panda/src/text/dynamicTextFont.h b/panda/src/text/dynamicTextFont.h index f379960b08..8c0e84d4e6 100644 --- a/panda/src/text/dynamicTextFont.h +++ b/panda/src/text/dynamicTextFont.h @@ -77,10 +77,10 @@ PUBLISHED: INLINE int get_page_x_size() const; INLINE int get_page_y_size() const; - INLINE void set_minfilter(Texture::FilterType filter); - INLINE Texture::FilterType get_minfilter() const; - INLINE void set_magfilter(Texture::FilterType filter); - INLINE Texture::FilterType get_magfilter() const; + INLINE void set_minfilter(SamplerState::FilterType filter); + INLINE SamplerState::FilterType get_minfilter() const; + INLINE void set_magfilter(SamplerState::FilterType filter); + INLINE SamplerState::FilterType get_magfilter() const; INLINE void set_anisotropic_degree(int anisotropic_degree); INLINE int get_anisotropic_degree() const; @@ -139,8 +139,8 @@ private: PN_stdfloat _poly_margin; int _page_x_size, _page_y_size; - Texture::FilterType _minfilter; - Texture::FilterType _magfilter; + SamplerState::FilterType _minfilter; + SamplerState::FilterType _magfilter; int _anisotropic_degree; RenderMode _render_mode; diff --git a/panda/src/text/staticTextFont.cxx b/panda/src/text/staticTextFont.cxx index 650c540e11..c174ec2fa5 100644 --- a/panda/src/text/staticTextFont.cxx +++ b/panda/src/text/staticTextFont.cxx @@ -86,10 +86,10 @@ StaticTextFont(PandaNode *font_def, CoordinateSystem cs) { if (tex->get_quality_level() == Texture::QL_default) { tex->set_quality_level(text_quality_level); } - if (tex->get_minfilter() == Texture::FT_default) { + if (tex->get_minfilter() == SamplerState::FT_default) { tex->set_minfilter(text_minfilter); } - if (tex->get_magfilter() == Texture::FT_default) { + if (tex->get_magfilter() == SamplerState::FT_default) { tex->set_magfilter(text_magfilter); } } diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 79565d668a..0bb181b5c2 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -2300,31 +2300,31 @@ do_issue_texture() { // Fill in the filter func pointers. These may not actually get // called, if we decide below we can inline the filters. - Texture::FilterType minfilter = texture->get_minfilter(); - Texture::FilterType magfilter = texture->get_magfilter(); + SamplerState::FilterType minfilter = texture->get_minfilter(); + SamplerState::FilterType magfilter = texture->get_magfilter(); if (td_ignore_mipmaps && Texture::is_mipmap(minfilter)) { // Downgrade mipmaps. - if (minfilter == Texture::FT_nearest_mipmap_nearest) { - minfilter = Texture::FT_nearest; + if (minfilter == SamplerState::FT_nearest_mipmap_nearest) { + minfilter = SamplerState::FT_nearest; } else { - minfilter = Texture::FT_linear; + minfilter = SamplerState::FT_linear; } } // Depending on this particular texture's quality level, we may // downgrade the requested filters. if (quality_level == Texture::QL_fastest) { - minfilter = Texture::FT_nearest; - magfilter = Texture::FT_nearest; + minfilter = SamplerState::FT_nearest; + magfilter = SamplerState::FT_nearest; } else if (quality_level == Texture::QL_normal) { if (Texture::is_mipmap(minfilter)) { - minfilter = Texture::FT_nearest_mipmap_nearest; + minfilter = SamplerState::FT_nearest_mipmap_nearest; } else { - minfilter = Texture::FT_nearest; + minfilter = SamplerState::FT_nearest; } - magfilter = Texture::FT_nearest; + magfilter = SamplerState::FT_nearest; } else if (quality_level == Texture::QL_best) { minfilter = texture->get_effective_minfilter(); @@ -2334,14 +2334,14 @@ do_issue_texture() { texture_def->tex_minfilter_func = get_tex_filter_func(minfilter); texture_def->tex_magfilter_func = get_tex_filter_func(magfilter); - Texture::WrapMode wrap_u = texture->get_wrap_u(); - Texture::WrapMode wrap_v = texture->get_wrap_v(); + SamplerState::WrapMode wrap_u = texture->get_wrap_u(); + SamplerState::WrapMode wrap_v = texture->get_wrap_v(); if (td_ignore_clamp) { - wrap_u = Texture::WM_repeat; - wrap_v = Texture::WM_repeat; + wrap_u = SamplerState::WM_repeat; + wrap_v = SamplerState::WM_repeat; } - if (wrap_u != Texture::WM_repeat || wrap_v != Texture::WM_repeat) { + if (wrap_u != SamplerState::WM_repeat || wrap_v != SamplerState::WM_repeat) { // We have some nonstandard wrap mode. This will force the use // of the general texfilter mode. needs_general = true; @@ -2364,21 +2364,21 @@ do_issue_texture() { // The following special cases are handled inline, rather than // relying on the above wrap function pointers. - if (wrap_u && Texture::WM_border_color && wrap_v == Texture::WM_border_color) { + if (wrap_u && SamplerState::WM_border_color && wrap_v == SamplerState::WM_border_color) { texture_def->tex_minfilter_func = apply_wrap_border_color_minfilter; texture_def->tex_magfilter_func = apply_wrap_border_color_magfilter; - } else if (wrap_u && Texture::WM_clamp && wrap_v == Texture::WM_clamp) { + } else if (wrap_u && SamplerState::WM_clamp && wrap_v == SamplerState::WM_clamp) { texture_def->tex_minfilter_func = apply_wrap_clamp_minfilter; texture_def->tex_magfilter_func = apply_wrap_clamp_magfilter; } } - if (minfilter != Texture::FT_nearest || magfilter != Texture::FT_nearest) { + if (minfilter != SamplerState::FT_nearest || magfilter != SamplerState::FT_nearest) { all_nearest = false; } - if (minfilter != Texture::FT_nearest_mipmap_nearest || - magfilter != Texture::FT_nearest) { + if (minfilter != SamplerState::FT_nearest_mipmap_nearest || + magfilter != SamplerState::FT_nearest) { all_mipmap_nearest = false; } @@ -3195,24 +3195,24 @@ get_color_blend_op(ColorBlendAttrib::Operand operand) { // function according to the texture's filter type. //////////////////////////////////////////////////////////////////// ZB_lookupTextureFunc TinyGraphicsStateGuardian:: -get_tex_filter_func(Texture::FilterType filter) { +get_tex_filter_func(SamplerState::FilterType filter) { switch (filter) { - case Texture::FT_nearest: + case SamplerState::FT_nearest: return &lookup_texture_nearest; - case Texture::FT_linear: + case SamplerState::FT_linear: return &lookup_texture_bilinear; - case Texture::FT_nearest_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_nearest: return &lookup_texture_mipmap_nearest; - case Texture::FT_nearest_mipmap_linear: + case SamplerState::FT_nearest_mipmap_linear: return &lookup_texture_mipmap_linear; - case Texture::FT_linear_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: return &lookup_texture_mipmap_bilinear; - case Texture::FT_linear_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: return &lookup_texture_mipmap_trilinear; default: @@ -3227,20 +3227,20 @@ get_tex_filter_func(Texture::FilterType filter) { // function according to the texture's wrap mode. //////////////////////////////////////////////////////////////////// ZB_texWrapFunc TinyGraphicsStateGuardian:: -get_tex_wrap_func(Texture::WrapMode wrap_mode) { +get_tex_wrap_func(SamplerState::WrapMode wrap_mode) { switch (wrap_mode) { - case Texture::WM_clamp: - case Texture::WM_border_color: // border_color is handled later. + case SamplerState::WM_clamp: + case SamplerState::WM_border_color: // border_color is handled later. return &texcoord_clamp; - case Texture::WM_repeat: - case Texture::WM_invalid: + case SamplerState::WM_repeat: + case SamplerState::WM_invalid: return &texcoord_repeat; - case Texture::WM_mirror: + case SamplerState::WM_mirror: return &texcoord_mirror; - case Texture::WM_mirror_once: + case SamplerState::WM_mirror_once: return &texcoord_mirror_once; } diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h index f9f671866d..d14b4e4e4b 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h @@ -131,8 +131,8 @@ private: void do_auto_rescale_normal(); static void load_matrix(M4 *matrix, const TransformState *transform); static int get_color_blend_op(ColorBlendAttrib::Operand operand); - static ZB_lookupTextureFunc get_tex_filter_func(Texture::FilterType filter); - static ZB_texWrapFunc get_tex_wrap_func(Texture::WrapMode wrap_mode); + static ZB_lookupTextureFunc get_tex_filter_func(SamplerState::FilterType filter); + static ZB_texWrapFunc get_tex_wrap_func(SamplerState::WrapMode wrap_mode); INLINE void clear_light_state(); diff --git a/pandatool/src/pfmprogs/pfmTrans.cxx b/pandatool/src/pfmprogs/pfmTrans.cxx index 9ebb3a12f9..5e7e3cf8e7 100755 --- a/pandatool/src/pfmprogs/pfmTrans.cxx +++ b/pandatool/src/pfmprogs/pfmTrans.cxx @@ -242,7 +242,7 @@ process_pfm(const Filename &input_filename, PfmFile &file) { if (tex == NULL) { nout << "Couldn't find " << _vistex_filename << "\n"; } else { - tex->set_minfilter(Texture::FT_linear_mipmap_linear); + tex->set_minfilter(SamplerState::FT_linear_mipmap_linear); mesh.set_texture(tex); if (tex->has_alpha(tex->get_format())) { mesh.set_transparency(TransparencyAttrib::M_dual); From a0409c54c1f0075ac07bdbdd07421765421849a8 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 16:21:09 +0100 Subject: [PATCH 09/20] Direct3D 9 supports LOD bias --- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index d0b8dd6e9d..228d57db99 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -293,6 +293,9 @@ apply_texture(int i, TextureContext *tc, const SamplerState &sampler) { set_sampler_state(i, D3DSAMP_MINFILTER, new_min_filter); set_sampler_state(i, D3DSAMP_MIPFILTER, new_mip_filter); + float lod_bias = sampler.get_lod_bias(); + set_sampler_state(i, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lod_bias); + _d3d_device->SetTexture(i, dtc->get_d3d_texture()); } From 09741ecf33cfe7ba64ff79d788ecc6194800e190 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 19:16:26 +0100 Subject: [PATCH 10/20] implement get_next_higher_bit using get_highest_on_bit to benefit from optimisations --- panda/src/putil/pbitops.I | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/panda/src/putil/pbitops.I b/panda/src/putil/pbitops.I index 452a04f638..5273eb8b13 100644 --- a/panda/src/putil/pbitops.I +++ b/panda/src/putil/pbitops.I @@ -267,8 +267,7 @@ get_highest_on_bit(PN_uint64 x) { //////////////////////////////////////////////////////////////////// INLINE int get_next_higher_bit(PN_uint16 x) { - PN_uint16 w = flood_bits_down(x); - return count_bits_in_word(w); + return get_highest_on_bit(x) + 1; } //////////////////////////////////////////////////////////////////// @@ -280,8 +279,7 @@ get_next_higher_bit(PN_uint16 x) { //////////////////////////////////////////////////////////////////// INLINE int get_next_higher_bit(PN_uint32 x) { - PN_uint32 w = flood_bits_down(x); - return count_bits_in_word(w); + return get_highest_on_bit(x) + 1; } //////////////////////////////////////////////////////////////////// @@ -293,6 +291,5 @@ get_next_higher_bit(PN_uint32 x) { //////////////////////////////////////////////////////////////////// INLINE int get_next_higher_bit(PN_uint64 x) { - PN_uint64 w = flood_bits_down(x); - return count_bits_in_word(w); + return get_highest_on_bit(x) + 1; } From fe3f4a6d2a5ec5cfed0621785357cfbd95c66442 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 20:18:34 +0100 Subject: [PATCH 11/20] Fix linear mipmapping crash in tinydisplay --- panda/src/tinydisplay/zbuffer.cxx | 59 ++++++++++++++++--------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/panda/src/tinydisplay/zbuffer.cxx b/panda/src/tinydisplay/zbuffer.cxx index b1607c055d..a3b5c67343 100644 --- a/panda/src/tinydisplay/zbuffer.cxx +++ b/panda/src/tinydisplay/zbuffer.cxx @@ -1,7 +1,7 @@ /* * Z buffer: 16 bits Z / 32 bits color - * + * */ #include #include @@ -159,7 +159,7 @@ ZB_copyBufferNoAlpha(const ZBuffer * zb, void *buf, int linesize) { PIXEL *p2 = p1 + xsize; while (p1 < p2) { // Make sure the alpha bits are set to 0xff. -#ifdef WORDS_BIGENDIAN +#ifdef WORDS_BIGENDIAN *p1 = *q1 | 0x000000ff; #else *p1 = *q1 | 0xff000000; @@ -176,8 +176,8 @@ ZB_copyBufferNoAlpha(const ZBuffer * zb, void *buf, int linesize) { (((v >> 8) & 0xf800) | (((v) >> 5) & 0x07e0) | (((v) & 0xff) >> 3)) /* XXX: not optimized */ -static void ZB_copyFrameBuffer5R6G5B(const ZBuffer * zb, - void *buf, int linesize) +static void ZB_copyFrameBuffer5R6G5B(const ZBuffer * zb, + void *buf, int linesize) { PIXEL *q; unsigned short *p, *p1; @@ -202,8 +202,8 @@ static void ZB_copyFrameBuffer5R6G5B(const ZBuffer * zb, } /* XXX: not optimized */ -static void ZB_copyFrameBufferRGB24(const ZBuffer * zb, - void *buf, int linesize) +static void ZB_copyFrameBufferRGB24(const ZBuffer * zb, + void *buf, int linesize) { PIXEL *q; unsigned char *p, *p1; @@ -276,7 +276,7 @@ ZB_copyFrameBufferNoAlpha(const ZBuffer * zb, void *buf, } } -// Copy from (source_xmin,source_ymin)+(source_xsize,source_ysize) to +// Copy from (source_xmin,source_ymin)+(source_xsize,source_ysize) to // (dest_xmin,dest_ymin)+(dest_xsize,dest_ysize). void ZB_zoomFrameBuffer(ZBuffer *dest, int dest_xmin, int dest_ymin, int dest_xsize, int dest_ysize, const ZBuffer *source, int source_xmin, int source_ymin, int source_xsize, int source_ysize) { @@ -483,14 +483,15 @@ lookup_texture_mipmap_linear(ZTextureDef *texture_def, int s, int t, unsigned in PIXEL p1, p2; int r, g, b, a; - p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level - 1); + p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level); + level = max((int)level - 1, 0); p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level); - unsigned int bitsize = (level - 1) + ZB_POINT_ST_FRAC_BITS; - r = LINEAR_FILTER_BITSIZE(PIXEL_R(p1), PIXEL_R(p2), level_dx, bitsize); - g = LINEAR_FILTER_BITSIZE(PIXEL_G(p1), PIXEL_G(p2), level_dx, bitsize); - b = LINEAR_FILTER_BITSIZE(PIXEL_B(p1), PIXEL_B(p2), level_dx, bitsize); - a = LINEAR_FILTER_BITSIZE(PIXEL_A(p1), PIXEL_A(p2), level_dx, bitsize); + unsigned int bitsize = level + ZB_POINT_ST_FRAC_BITS; + r = LINEAR_FILTER_BITSIZE(PIXEL_R(p2), PIXEL_R(p1), level_dx, bitsize); + g = LINEAR_FILTER_BITSIZE(PIXEL_G(p2), PIXEL_G(p1), level_dx, bitsize); + b = LINEAR_FILTER_BITSIZE(PIXEL_B(p2), PIXEL_B(p1), level_dx, bitsize); + a = LINEAR_FILTER_BITSIZE(PIXEL_A(p2), PIXEL_A(p1), level_dx, bitsize); return RGBA_TO_PIXEL(r, g, b, a); } @@ -529,14 +530,14 @@ lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned int sf, tf; int r, g, b, a; - p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level - 1); - p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level - 1); - sf = (s >> (level - 1)) & ZB_ST_FRAC_MASK; - - p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level - 1); - p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level - 1); - tf = (t >> (level - 1)) & ZB_ST_FRAC_MASK; - + p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level); + p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level); + sf = (s >> level) & ZB_ST_FRAC_MASK; + + p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level); + p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level); + tf = (t >> level) & ZB_ST_FRAC_MASK; + r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf); g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf); b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf); @@ -544,6 +545,8 @@ lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned p1a = RGBA_TO_PIXEL(r, g, b, a); } + level = max((int)level - 1, 0); + { PIXEL p1, p2, p3, p4; int sf, tf; @@ -552,11 +555,11 @@ lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level); p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level); sf = (s >> level) & ZB_ST_FRAC_MASK; - + p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level); p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level); tf = (t >> level) & ZB_ST_FRAC_MASK; - + r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf); g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf); b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf); @@ -565,11 +568,11 @@ lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned } int r, g, b, a; - unsigned int bitsize = (level - 1) + ZB_POINT_ST_FRAC_BITS; - r = LINEAR_FILTER_BITSIZE(PIXEL_R(p1a), PIXEL_R(p2a), level_dx, bitsize); - g = LINEAR_FILTER_BITSIZE(PIXEL_G(p1a), PIXEL_G(p2a), level_dx, bitsize); - b = LINEAR_FILTER_BITSIZE(PIXEL_B(p1a), PIXEL_B(p2a), level_dx, bitsize); - a = LINEAR_FILTER_BITSIZE(PIXEL_A(p1a), PIXEL_A(p2a), level_dx, bitsize); + unsigned int bitsize = level + ZB_POINT_ST_FRAC_BITS; + r = LINEAR_FILTER_BITSIZE(PIXEL_R(p2a), PIXEL_R(p1a), level_dx, bitsize); + g = LINEAR_FILTER_BITSIZE(PIXEL_G(p2a), PIXEL_G(p1a), level_dx, bitsize); + b = LINEAR_FILTER_BITSIZE(PIXEL_B(p2a), PIXEL_B(p1a), level_dx, bitsize); + a = LINEAR_FILTER_BITSIZE(PIXEL_A(p2a), PIXEL_A(p1a), level_dx, bitsize); return RGBA_TO_PIXEL(r, g, b, a); } From 89031b4e480a0f39a8dea2e28261342adf64e85b Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 20:27:08 +0100 Subject: [PATCH 12/20] Fix mipmapping with sampler state --- .../glstuff/glGraphicsStateGuardian_src.cxx | 36 +++++++++++++------ .../src/glstuff/glGraphicsStateGuardian_src.h | 2 +- panda/src/gobj/samplerState.I | 32 +++++++++++++++++ panda/src/gobj/samplerState.h | 3 ++ panda/src/gobj/texture.I | 2 +- panda/src/gobj/texture.cxx | 20 ----------- panda/src/gobj/texture.h | 2 -- 7 files changed, 62 insertions(+), 35 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 64e56f19ef..6b3cf55d13 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -4268,14 +4268,15 @@ update_texture(TextureContext *tc, bool force) { // If the texture image was modified, reload the texture. apply_texture(tc); + + Texture *tex = tc->get_texture(); if (gtc->was_properties_modified()) { - Texture *tex = tc->get_texture(); specify_texture(gtc, tex->get_default_sampler()); } - bool okflag = upload_texture(gtc, force); + bool okflag = upload_texture(gtc, force, tex->uses_mipmaps()); if (!okflag) { GLCAT.error() - << "Could not load " << *gtc->get_texture() << "\n"; + << "Could not load " << *tex << "\n"; return false; } @@ -4290,7 +4291,7 @@ update_texture(TextureContext *tc, bool force) { if (specify_texture(gtc, tex->get_default_sampler())) { // Actually, looks like the texture *does* need to be reloaded. gtc->mark_needs_reload(); - bool okflag = upload_texture(gtc, force); + bool okflag = upload_texture(gtc, force, tex->uses_mipmaps()); if (!okflag) { GLCAT.error() << "Could not load " << *tex << "\n"; @@ -4398,7 +4399,7 @@ prepare_sampler(const SamplerState &sampler) { SamplerState::FilterType minfilter = sampler.get_effective_minfilter(); SamplerState::FilterType magfilter = sampler.get_effective_magfilter(); - bool uses_mipmaps = Texture::is_mipmap(minfilter) && !gl_ignore_mipmaps; + bool uses_mipmaps = SamplerState::is_mipmap(minfilter) && !gl_ignore_mipmaps; #ifndef NDEBUG if (gl_force_mipmaps) { @@ -9837,7 +9838,7 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) { SamplerState::FilterType minfilter = sampler.get_effective_minfilter(); SamplerState::FilterType magfilter = sampler.get_effective_magfilter(); - bool uses_mipmaps = Texture::is_mipmap(minfilter) && !gl_ignore_mipmaps; + bool uses_mipmaps = SamplerState::is_mipmap(minfilter) && !gl_ignore_mipmaps; #ifndef NDEBUG if (gl_force_mipmaps) { @@ -9948,6 +9949,8 @@ apply_texture(TextureContext *tc) { //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { + CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); + if (_supports_sampler_objects) { // We support sampler objects. Prepare the sampler object and // bind it to the indicated texture unit. @@ -9965,8 +9968,6 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { } } else { - CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); - // We don't support sampler objects. We'll have to bind the // texture and change the texture parameters if they don't match. if (gtc->_active_sampler != sampler) { @@ -9976,6 +9977,19 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { } } + if (sampler.uses_mipmaps() && !gtc->_uses_mipmaps) { + // The texture wasn't created with mipmaps, but we are trying + // to sample it with mipmaps. We will need to reload it. + apply_texture(tc); + gtc->mark_needs_reload(); + bool okflag = upload_texture(gtc, false, true); + if (!okflag) { + GLCAT.error() + << "Could not load " << *gtc->get_texture() << "\n"; + return false; + } + } + report_my_gl_errors(); return true; } @@ -9990,7 +10004,7 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { // the texture has no image. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: -upload_texture(CLP(TextureContext) *gtc, bool force) { +upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { PStatGPUTimer timer(this, _load_texture_pcollector); Texture *tex = gtc->get_texture(); @@ -10161,7 +10175,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GLenum target = get_texture_target(tex->get_texture_type()); - bool uses_mipmaps = (tex->uses_mipmaps() && !gl_ignore_mipmaps) || gl_force_mipmaps; + uses_mipmaps = (uses_mipmaps && !gl_ignore_mipmaps) || gl_force_mipmaps; bool needs_reload = false; if (!gtc->_has_storage || gtc->_uses_mipmaps != uses_mipmaps || @@ -11453,7 +11467,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { tex->set_ram_image(image, compression, page_size); - if (tex->uses_mipmaps()) { + if (gtc->_uses_mipmaps) { // Also get the mipmap levels. GLint num_expected_levels = tex->get_expected_num_mipmap_levels(); GLint highest_level = num_expected_levels; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index b1ec3fa1cf..bcfe2fd383 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -490,7 +490,7 @@ protected: bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler); bool apply_texture(TextureContext *tc); bool apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc); - bool upload_texture(CLP(TextureContext) *gtc, bool force); + bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps); bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, bool uses_mipmaps, int mipmap_bias, GLenum texture_target, GLenum page_target, diff --git a/panda/src/gobj/samplerState.I b/panda/src/gobj/samplerState.I index 2762c10ce6..f7096b0500 100644 --- a/panda/src/gobj/samplerState.I +++ b/panda/src/gobj/samplerState.I @@ -307,6 +307,38 @@ get_lod_bias() const { return _lod_bias; } +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::uses_mipmaps +// Access: Public +// Description: Returns true if the minfilter settings on this +// sampler indicate the use of mipmapping, false +// otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool SamplerState:: +uses_mipmaps() const { + return is_mipmap(get_effective_minfilter()); +} + +//////////////////////////////////////////////////////////////////// +// Function: SamplerState::is_mipmap +// Access: Published, Static +// Description: Returns true if the indicated filter type requires +// the use of mipmaps, or false if it does not. +//////////////////////////////////////////////////////////////////// +INLINE bool SamplerState:: +is_mipmap(FilterType filter_type) { + switch (filter_type) { + case SamplerState::FT_nearest_mipmap_nearest: + case SamplerState::FT_linear_mipmap_nearest: + case SamplerState::FT_nearest_mipmap_linear: + case SamplerState::FT_linear_mipmap_linear: + return true; + + default: + return false; + } +} + //////////////////////////////////////////////////////////////////// // Function: SamplerState::operator == // Access: Published diff --git a/panda/src/gobj/samplerState.h b/panda/src/gobj/samplerState.h index 2d9528246a..d5c10d6a1c 100644 --- a/panda/src/gobj/samplerState.h +++ b/panda/src/gobj/samplerState.h @@ -110,6 +110,9 @@ PUBLISHED: INLINE PN_stdfloat get_max_lod() const; INLINE PN_stdfloat get_lod_bias() const; + INLINE bool uses_mipmaps() const; + INLINE static bool is_mipmap(FilterType type); + static string format_filter_type(FilterType ft); static FilterType string_filter_type(const string &str); diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 63625818cd..f075107d34 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -1223,7 +1223,7 @@ get_render_to_texture() const { //////////////////////////////////////////////////////////////////// INLINE bool Texture:: uses_mipmaps() const { - return is_mipmap(get_effective_minfilter()); + return SamplerState::is_mipmap(get_effective_minfilter()); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index ed3252f5c7..0ab909f66c 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -1804,26 +1804,6 @@ set_orig_file_size(int x, int y, int z) { nassertv(z == cdata->_z_size); } -//////////////////////////////////////////////////////////////////// -// Function: Texture::is_mipmap -// Access: Published, Static -// Description: Returns true if the indicated filter type requires -// the use of mipmaps, or false if it does not. -//////////////////////////////////////////////////////////////////// -bool Texture:: -is_mipmap(FilterType filter_type) { - switch (filter_type) { - case SamplerState::FT_nearest_mipmap_nearest: - case SamplerState::FT_linear_mipmap_nearest: - case SamplerState::FT_nearest_mipmap_linear: - case SamplerState::FT_linear_mipmap_linear: - return true; - - default: - return false; - } -} - //////////////////////////////////////////////////////////////////// // Function: Texture::prepare_now // Access: Published diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 7d4106e960..ad93f8641a 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -458,8 +458,6 @@ PUBLISHED: INLINE void set_loaded_from_txo(); INLINE bool get_loaded_from_txo() const; - static bool is_mipmap(FilterType type); - INLINE bool get_match_framebuffer_format() const; INLINE void set_match_framebuffer_format(bool flag); From 8a5452b0b618bda22c433ec786c69ce493d6fae5 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 20:32:36 +0100 Subject: [PATCH 13/20] Support sampler states in tinyGL renderer --- .../tinydisplay/tinyGraphicsStateGuardian.cxx | 107 +++++++++++------- .../tinydisplay/tinyGraphicsStateGuardian.h | 4 +- 2 files changed, 65 insertions(+), 46 deletions(-) diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 0bb181b5c2..3d8a0a0316 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -34,6 +34,7 @@ #include "lightAttrib.h" #include "scissorAttrib.h" #include "bitMask.h" +#include "samplerState.h" #include "zgl.h" #include "zmath.h" #include "ztriangle_table.h" @@ -118,7 +119,7 @@ reset() { _c->draw_triangle_back = gl_draw_triangle_fill; _supported_geom_rendering = - Geom::GR_point | + Geom::GR_point | Geom::GR_indexed_other | Geom::GR_triangle_strip | Geom::GR_flat_last_vertex; @@ -568,7 +569,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, } // Compose the modelview and projection matrices. - load_matrix(&_c->matrix_model_projection, + load_matrix(&_c->matrix_model_projection, scissor_proj_mat->compose(_internal_transform)); /* test to accelerate computation */ @@ -658,7 +659,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, { CPT(TransformState) render_transform = _cs_transform->compose(_scene_setup->get_world_transform()); - CPT(TransformState) world_inv_transform = + CPT(TransformState) world_inv_transform = render_transform->invert_compose(_internal_transform); tcdata[si]._mat = world_inv_transform->get_mat(); } @@ -709,7 +710,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, needs_normal = rnormal.has_column(); } - GeomVertexReader rvertex(data_reader, InternalName::get_vertex(), force); + GeomVertexReader rvertex(data_reader, InternalName::get_vertex(), force); rvertex.set_row_unsafe(_min_vertex); if (!rvertex.has_column()) { @@ -1717,10 +1718,11 @@ update_texture(TextureContext *tc, bool force) { if (gtc->was_image_modified() || gltex->num_levels == 0) { // If the texture image was modified, reload the texture. - bool okflag = upload_texture(gtc, force); + Texture *tex = gtc->get_texture(); + bool okflag = upload_texture(gtc, force, tex->uses_mipmaps()); if (!okflag) { tinydisplay_cat.error() - << "Could not load " << *gtc->get_texture() << "\n"; + << "Could not load " << *tex << "\n"; return false; } } @@ -1746,7 +1748,7 @@ update_texture(TextureContext *tc, bool force) { // true). //////////////////////////////////////////////////////////////////// bool TinyGraphicsStateGuardian:: -update_texture(TextureContext *tc, bool force, int stage_index) { +update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmaps) { if (!update_texture(tc, force)) { return false; } @@ -1754,6 +1756,17 @@ update_texture(TextureContext *tc, bool force, int stage_index) { TinyTextureContext *gtc = DCAST(TinyTextureContext, tc); GLTexture *gltex = >c->_gltex; + if (uses_mipmaps && gltex->num_levels <= 1) { + // We don't have mipmaps, yet we are sampling with mipmaps. + Texture *tex = gtc->get_texture(); + bool okflag = upload_texture(gtc, force, true); + if (!okflag) { + tinydisplay_cat.error() + << "Could not load " << *tex << "\n"; + return false; + } + } + _c->current_textures[stage_index] = gltex; ZTextureDef *texture_def = &_c->zb->current_textures[stage_index]; @@ -1762,13 +1775,13 @@ update_texture(TextureContext *tc, bool force, int stage_index) { texture_def->t_max = gltex->t_max; const V4 &bc = gltex->border_color; - int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) + int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) + ZB_POINT_RED_MIN); - int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) + int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) + ZB_POINT_GREEN_MIN); - int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) + int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) + ZB_POINT_BLUE_MIN); - int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN) + int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN) + ZB_POINT_ALPHA_MIN); texture_def->border_color = RGBA_TO_PIXEL(r, g, b, a); @@ -1809,7 +1822,7 @@ release_texture(TextureContext *tc) { //////////////////////////////////////////////////////////////////// // Function: TinyGraphicsStateGuardian::do_issue_light // Access: Protected, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void TinyGraphicsStateGuardian:: do_issue_light() { @@ -2016,7 +2029,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { gl_light->specular.v[1] = specular[1]; gl_light->specular.v[2] = specular[2]; gl_light->specular.v[3] = specular[3]; - + Lens *lens = light_obj->get_lens(); nassertv(lens != (Lens *)NULL); @@ -2267,16 +2280,19 @@ do_issue_texture() { TextureStage *stage = _target_texture->get_on_ff_stage(si); Texture *texture = _target_texture->get_on_texture(stage); nassertv(texture != (Texture *)NULL); - + int view = get_current_tex_view_offset() + stage->get_tex_view_offset(); TextureContext *tc = texture->prepare_now(view, _prepared_objects, this); if (tc == (TextureContext *)NULL) { // Something wrong with this texture; skip it. return; } - + + // Get the sampler state that we are supposed to use. + const SamplerState &sampler = _target_texture->get_on_sampler(stage); + // Then, turn on the current texture mode. - if (!update_texture(tc, false, si)) { + if (!update_texture(tc, false, si, sampler.uses_mipmaps())) { return; } @@ -2297,13 +2313,13 @@ do_issue_texture() { best_quality_level = max(best_quality_level, quality_level); ZTextureDef *texture_def = &_c->zb->current_textures[si]; - + // Fill in the filter func pointers. These may not actually get // called, if we decide below we can inline the filters. - SamplerState::FilterType minfilter = texture->get_minfilter(); - SamplerState::FilterType magfilter = texture->get_magfilter(); + SamplerState::FilterType minfilter = sampler.get_minfilter(); + SamplerState::FilterType magfilter = sampler.get_magfilter(); - if (td_ignore_mipmaps && Texture::is_mipmap(minfilter)) { + if (td_ignore_mipmaps && SamplerState::is_mipmap(minfilter)) { // Downgrade mipmaps. if (minfilter == SamplerState::FT_nearest_mipmap_nearest) { minfilter = SamplerState::FT_nearest; @@ -2319,7 +2335,7 @@ do_issue_texture() { magfilter = SamplerState::FT_nearest; } else if (quality_level == Texture::QL_normal) { - if (Texture::is_mipmap(minfilter)) { + if (SamplerState::is_mipmap(minfilter)) { minfilter = SamplerState::FT_nearest_mipmap_nearest; } else { minfilter = SamplerState::FT_nearest; @@ -2327,15 +2343,15 @@ do_issue_texture() { magfilter = SamplerState::FT_nearest; } else if (quality_level == Texture::QL_best) { - minfilter = texture->get_effective_minfilter(); - magfilter = texture->get_effective_magfilter(); + minfilter = sampler.get_effective_minfilter(); + magfilter = sampler.get_effective_magfilter(); } texture_def->tex_minfilter_func = get_tex_filter_func(minfilter); texture_def->tex_magfilter_func = get_tex_filter_func(magfilter); - - SamplerState::WrapMode wrap_u = texture->get_wrap_u(); - SamplerState::WrapMode wrap_v = texture->get_wrap_v(); + + SamplerState::WrapMode wrap_u = sampler.get_wrap_u(); + SamplerState::WrapMode wrap_v = sampler.get_wrap_v(); if (td_ignore_clamp) { wrap_u = SamplerState::WM_repeat; wrap_v = SamplerState::WM_repeat; @@ -2382,7 +2398,7 @@ do_issue_texture() { all_mipmap_nearest = false; } - if (Texture::is_mipmap(minfilter)) { + if (SamplerState::is_mipmap(minfilter)) { any_mipmap = true; } } @@ -2419,7 +2435,7 @@ do_issue_texture() { // perspective correctness. _texfilter_state = 0; // tnearest _texturing_state = 1; // textured (not perspective correct, no multitexture) - + } else { // This is the default texture filter. We use nearest sampling if // there are no mipmaps, and mipmap_nearest if there are any @@ -2500,7 +2516,7 @@ apply_texture(TextureContext *tc) { // the texture has no image. //////////////////////////////////////////////////////////////////// bool TinyGraphicsStateGuardian:: -upload_texture(TinyTextureContext *gtc, bool force) { +upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps) { Texture *tex = gtc->get_texture(); if (_effective_incomplete_render && !force) { @@ -2525,21 +2541,24 @@ upload_texture(TinyTextureContext *gtc, bool force) { return false; } - if (tinydisplay_cat.is_debug()) { - tinydisplay_cat.debug() - << "loading texture " << tex->get_name() << "\n"; - } #ifdef DO_PSTATS _data_transferred_pcollector.add_level(tex->get_ram_image_size()); #endif GLTexture *gltex = >c->_gltex; int num_levels = 1; - if (tex->uses_mipmaps()) { - if (!tex->has_all_ram_mipmap_images()) { + if (uses_mipmaps) { + num_levels = tex->get_expected_num_mipmap_levels(); + if (tex->get_num_ram_mipmap_images() < num_levels) { tex->generate_ram_mipmap_images(); } - num_levels = tex->get_num_ram_mipmap_images(); + } + + if (tinydisplay_cat.is_debug()) { + tinydisplay_cat.debug() + << "loading texture " << tex->get_name() << ", " + << tex->get_x_size() << " x " << tex->get_y_size() << ", mipmaps = " + << num_levels << ", uses_mipmaps = " << uses_mipmaps << "\n"; } if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) { @@ -2616,7 +2635,7 @@ upload_texture(TinyTextureContext *gtc, bool force) { } gtc->update_data_size_bytes(bytecount); - + get_engine()->texture_uploaded(tex); gtc->mark_loaded(); @@ -2687,7 +2706,7 @@ bool TinyGraphicsStateGuardian:: setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) { int s_bits = get_tex_shift(x_size); int t_bits = get_tex_shift(y_size); - + if (s_bits < 0 || t_bits < 0) { return false; } @@ -2701,7 +2720,7 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) { gltex->t_max = 1 << (t_bits + ZB_POINT_ST_FRAC_BITS); gltex->num_levels = num_levels; - + // We allocate one big buffer, large enough to include all the // mipmap levels, and index into that buffer for each level. This // cuts down on the number of individual alloc calls we have to make @@ -2746,7 +2765,7 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) { dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level; dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level); dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level); - + x_size = max((x_size >> 1), 1); y_size = max((y_size >> 1), 1); s_bits = max(s_bits - 1, 0); @@ -3187,7 +3206,7 @@ get_color_blend_op(ColorBlendAttrib::Operand operand) { } return 0; } - + //////////////////////////////////////////////////////////////////// // Function: TinyGraphicsStateGuardian::get_tex_filter_func // Access: Private, Static @@ -3208,7 +3227,7 @@ get_tex_filter_func(SamplerState::FilterType filter) { case SamplerState::FT_nearest_mipmap_linear: return &lookup_texture_mipmap_linear; - + case SamplerState::FT_linear_mipmap_nearest: return &lookup_texture_mipmap_bilinear; @@ -3219,7 +3238,7 @@ get_tex_filter_func(SamplerState::FilterType filter) { return &lookup_texture_nearest; } } - + //////////////////////////////////////////////////////////////////// // Function: TinyGraphicsStateGuardian::get_tex_wrap_func // Access: Private, Static @@ -3305,7 +3324,7 @@ texgen_sphere_map(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) { // Compute the reflection vector. LVector3 r = u - n * dot(n, u) * 2.0f; - + // compute the denominator, m. PN_stdfloat m = 2.0f * csqrt(r[0] * r[0] + r[1] * r[1] + (r[2] + 1.0f) * (r[2] + 1.0f)); diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h index d14b4e4e4b..443a21cb00 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h @@ -91,7 +91,7 @@ public: virtual TextureContext *prepare_texture(Texture *tex, int view); virtual bool update_texture(TextureContext *tc, bool force); - bool update_texture(TextureContext *tc, bool force, int stage_index); + bool update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmaps); virtual void release_texture(TextureContext *tc); virtual void do_issue_light(); @@ -115,7 +115,7 @@ private: void set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top); bool apply_texture(TextureContext *tc); - bool upload_texture(TinyTextureContext *gtc, bool force); + bool upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps); bool upload_simple_texture(TinyTextureContext *gtc); bool setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels); int get_tex_shift(int orig_size); From 270667ece222127cc658a68dda8f5799d8dbdd1b Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 12 Dec 2014 20:39:24 +0100 Subject: [PATCH 14/20] Use sampler states in Direct3D 8 --- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 21 ++++++++++--------- panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index c143522cc2..9d87cfa494 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -175,7 +175,7 @@ prepare_texture(Texture *tex, int view) { // rendering on the ith stage. //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: -apply_texture(int i, TextureContext *tc) { +apply_texture(int i, TextureContext *tc, const SamplerState &sampler) { if (tc == (TextureContext *)NULL) { // The texture wasn't bound properly or something, so ensure // texturing is disabled and just return. @@ -194,19 +194,19 @@ apply_texture(int i, TextureContext *tc) { Texture *tex = tc->get_texture(); SamplerState::WrapMode wrap_u, wrap_v, wrap_w; - wrap_u = tex->get_wrap_u(); - wrap_v = tex->get_wrap_v(); - wrap_w = tex->get_wrap_w(); + wrap_u = sampler.get_wrap_u(); + wrap_v = sampler.get_wrap_v(); + wrap_w = sampler.get_wrap_w(); _d3d_device->SetTextureStageState(i, D3DTSS_ADDRESSU, get_texture_wrap_mode(wrap_u)); _d3d_device->SetTextureStageState(i, D3DTSS_ADDRESSV, get_texture_wrap_mode(wrap_v)); _d3d_device->SetTextureStageState(i, D3DTSS_ADDRESSW, get_texture_wrap_mode(wrap_w)); _d3d_device->SetTextureStageState(i, D3DTSS_BORDERCOLOR, - LColor_to_D3DCOLOR(tex->get_border_color())); + LColor_to_D3DCOLOR(sampler.get_border_color())); - uint aniso_degree = tex->get_effective_anisotropic_degree(); - SamplerState::FilterType ft = tex->get_effective_magfilter(); + uint aniso_degree = sampler.get_effective_anisotropic_degree(); + SamplerState::FilterType ft = sampler.get_effective_magfilter(); if (aniso_degree >= 1) { _d3d_device->SetTextureStageState(i, D3DTSS_MAXANISOTROPY, aniso_degree); @@ -222,8 +222,8 @@ apply_texture(int i, TextureContext *tc) { _d3d_device->SetTextureStageState(i, D3DTSS_MAGFILTER, new_mag_filter); // map Panda composite min+mip filter types to d3d's separate min & mip filter types - D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(tex->get_effective_minfilter()); - D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(tex->get_effective_minfilter()); + D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(sampler.get_effective_minfilter()); + D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(sampler.get_effective_minfilter()); if (!tex->might_have_ram_image()) { // If the texture is completely dynamic, don't try to issue @@ -2859,11 +2859,12 @@ do_issue_texture() { Texture *texture = _target_texture->get_on_texture(stage); nassertv(texture != (Texture *)NULL); + const SamplerState &sampler = _target_texture->get_on_sampler(stage); // We always reissue every stage in DX, just in case the texcoord // index or texgen mode or some other property has changed. TextureContext *tc = texture->prepare_now(0, _prepared_objects, this); - apply_texture(si, tc); + apply_texture(si, tc, sampler); set_texture_blend_mode(si, stage); int texcoord_dimensions = 2; diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index 788a3bdc0f..029ec5e2de 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -50,7 +50,7 @@ public: calc_fb_properties(DWORD cformat, DWORD dformat, DWORD multisampletype); virtual TextureContext *prepare_texture(Texture *tex, int view); - void apply_texture(int i, TextureContext *tc); + void apply_texture(int i, TextureContext *tc, const SamplerState &sampler); virtual bool update_texture(TextureContext *tc, bool force); bool upload_texture(DXTextureContext8 *dtc, bool force); virtual void release_texture(TextureContext *tc); @@ -258,7 +258,7 @@ protected: const DXIndexBufferContext8 *_active_ibuffer; int _num_active_texture_stages; - + // Cache the data necessary to bind each particular light each // frame, so if we bind a given light multiple times, we only have // to compute its data once. @@ -292,7 +292,7 @@ public: register_type(_type_handle, "DXGraphicsStateGuardian8", GraphicsStateGuardian::get_class_type()); } - + private: static TypeHandle _type_handle; From cb66a51bbc2b80cbdd8d41c60bd8ef6b793d9058 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 18 Dec 2014 16:58:03 -0500 Subject: [PATCH 15/20] fmin and fmax should be const methods --- panda/src/linmath/lvecBase2_src.I | 4 ++-- panda/src/linmath/lvecBase2_src.h | 4 ++-- panda/src/linmath/lvecBase3_src.I | 4 ++-- panda/src/linmath/lvecBase3_src.h | 4 ++-- panda/src/linmath/lvecBase4_src.I | 4 ++-- panda/src/linmath/lvecBase4_src.h | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/panda/src/linmath/lvecBase2_src.I b/panda/src/linmath/lvecBase2_src.I index 0cd528ac5d..9b453102a1 100644 --- a/panda/src/linmath/lvecBase2_src.I +++ b/panda/src/linmath/lvecBase2_src.I @@ -754,7 +754,7 @@ componentwise_mult(const FLOATNAME(LVecBase2) &other) { // Description: //////////////////////////////////////////////////////////////////// INLINE_LINMATH FLOATNAME(LVecBase2) FLOATNAME(LVecBase2):: -fmax(const FLOATNAME(LVecBase2) &other) { +fmax(const FLOATNAME(LVecBase2) &other) const { TAU_PROFILE("LVecBase2::fmax()", " ", TAU_USER); return FLOATNAME(LVecBase2)(_v(0) > other._v(0) ? _v(0) : other._v(0), _v(1) > other._v(1) ? _v(1) : other._v(1)); @@ -766,7 +766,7 @@ fmax(const FLOATNAME(LVecBase2) &other) { // Description: //////////////////////////////////////////////////////////////////// INLINE_LINMATH FLOATNAME(LVecBase2) FLOATNAME(LVecBase2):: -fmin(const FLOATNAME(LVecBase2) &other) { +fmin(const FLOATNAME(LVecBase2) &other) const { TAU_PROFILE("LVecBase2::fmin()", " ", TAU_USER); return FLOATNAME(LVecBase2)(_v(0) < other._v(0) ? _v(0) : other._v(0), _v(1) < other._v(1) ? _v(1) : other._v(1)); diff --git a/panda/src/linmath/lvecBase2_src.h b/panda/src/linmath/lvecBase2_src.h index dcb0043d07..6cba9eea6e 100644 --- a/panda/src/linmath/lvecBase2_src.h +++ b/panda/src/linmath/lvecBase2_src.h @@ -126,8 +126,8 @@ PUBLISHED: EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase2) __pow__(FLOATTYPE exponent) const); EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent)); - INLINE_LINMATH FLOATNAME(LVecBase2) fmax(const FLOATNAME(LVecBase2) &other); - INLINE_LINMATH FLOATNAME(LVecBase2) fmin(const FLOATNAME(LVecBase2) &other); + INLINE_LINMATH FLOATNAME(LVecBase2) fmax(const FLOATNAME(LVecBase2) &other) const; + INLINE_LINMATH FLOATNAME(LVecBase2) fmin(const FLOATNAME(LVecBase2) &other) const; INLINE_LINMATH bool almost_equal(const FLOATNAME(LVecBase2) &other, FLOATTYPE threshold) const; diff --git a/panda/src/linmath/lvecBase3_src.I b/panda/src/linmath/lvecBase3_src.I index 3cd3207242..31e24b2801 100644 --- a/panda/src/linmath/lvecBase3_src.I +++ b/panda/src/linmath/lvecBase3_src.I @@ -931,7 +931,7 @@ componentwise_mult(const FLOATNAME(LVecBase3) &other) { // Description: //////////////////////////////////////////////////////////////////// INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LVecBase3):: -fmax(const FLOATNAME(LVecBase3) &other) { +fmax(const FLOATNAME(LVecBase3) &other) const { TAU_PROFILE("LVecBase3::fmax()", " ", TAU_USER); return FLOATNAME(LVecBase3)(_v(0) > other._v(0) ? _v(0) : other._v(0), _v(1) > other._v(1) ? _v(1) : other._v(1), @@ -944,7 +944,7 @@ fmax(const FLOATNAME(LVecBase3) &other) { // Description: //////////////////////////////////////////////////////////////////// INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LVecBase3):: -fmin(const FLOATNAME(LVecBase3) &other) { +fmin(const FLOATNAME(LVecBase3) &other) const { TAU_PROFILE("LVecBase3::fmin()", " ", TAU_USER); return FLOATNAME(LVecBase3)(_v(0) < other._v(0) ? _v(0) : other._v(0), _v(1) < other._v(1) ? _v(1) : other._v(1), diff --git a/panda/src/linmath/lvecBase3_src.h b/panda/src/linmath/lvecBase3_src.h index 2de79d8ef9..ce7c09c011 100644 --- a/panda/src/linmath/lvecBase3_src.h +++ b/panda/src/linmath/lvecBase3_src.h @@ -139,8 +139,8 @@ PUBLISHED: EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase3) __pow__(FLOATTYPE exponent) const); EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent)); - INLINE_LINMATH FLOATNAME(LVecBase3) fmax(const FLOATNAME(LVecBase3) &other); - INLINE_LINMATH FLOATNAME(LVecBase3) fmin(const FLOATNAME(LVecBase3) &other); + INLINE_LINMATH FLOATNAME(LVecBase3) fmax(const FLOATNAME(LVecBase3) &other) const; + INLINE_LINMATH FLOATNAME(LVecBase3) fmin(const FLOATNAME(LVecBase3) &other) const; INLINE_LINMATH void cross_into(const FLOATNAME(LVecBase3) &other); diff --git a/panda/src/linmath/lvecBase4_src.I b/panda/src/linmath/lvecBase4_src.I index fb8871b5a0..db5923295e 100644 --- a/panda/src/linmath/lvecBase4_src.I +++ b/panda/src/linmath/lvecBase4_src.I @@ -915,7 +915,7 @@ componentwise_mult(const FLOATNAME(LVecBase4) &other) { // Description: //////////////////////////////////////////////////////////////////// INLINE_LINMATH FLOATNAME(LVecBase4) FLOATNAME(LVecBase4):: -fmax(const FLOATNAME(LVecBase4) &other) { +fmax(const FLOATNAME(LVecBase4) &other) const { TAU_PROFILE("LVecBase4::fmax()", " ", TAU_USER); return FLOATNAME(LVecBase4)(_v(0) > other._v(0) ? _v(0) : other._v(0), _v(1) > other._v(1) ? _v(1) : other._v(1), @@ -929,7 +929,7 @@ fmax(const FLOATNAME(LVecBase4) &other) { // Description: //////////////////////////////////////////////////////////////////// INLINE_LINMATH FLOATNAME(LVecBase4) FLOATNAME(LVecBase4):: -fmin(const FLOATNAME(LVecBase4) &other) { +fmin(const FLOATNAME(LVecBase4) &other) const { TAU_PROFILE("LVecBase4::fmin()", " ", TAU_USER); return FLOATNAME(LVecBase4)(_v(0) < other._v(0) ? _v(0) : other._v(0), _v(1) < other._v(1) ? _v(1) : other._v(1), diff --git a/panda/src/linmath/lvecBase4_src.h b/panda/src/linmath/lvecBase4_src.h index 8e49a0d2c8..e8b48ede7e 100644 --- a/panda/src/linmath/lvecBase4_src.h +++ b/panda/src/linmath/lvecBase4_src.h @@ -140,8 +140,8 @@ PUBLISHED: EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase4) __pow__(FLOATTYPE exponent) const); EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent)); - INLINE_LINMATH FLOATNAME(LVecBase4) fmax(const FLOATNAME(LVecBase4) &other); - INLINE_LINMATH FLOATNAME(LVecBase4) fmin(const FLOATNAME(LVecBase4) &other); + INLINE_LINMATH FLOATNAME(LVecBase4) fmax(const FLOATNAME(LVecBase4) &other) const; + INLINE_LINMATH FLOATNAME(LVecBase4) fmin(const FLOATNAME(LVecBase4) &other) const; INLINE_LINMATH bool almost_equal(const FLOATNAME(LVecBase4) &other, FLOATTYPE threshold) const; From 01b669ccd86dc95b7df3ef413d4808eb217c90d2 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 21 Dec 2014 14:13:49 +0100 Subject: [PATCH 16/20] Implement texture clear, fix immutable tex support --- .../glstuff/glGraphicsStateGuardian_src.cxx | 230 +++++++++++------- .../src/glstuff/glGraphicsStateGuardian_src.h | 9 +- panda/src/glstuff/glShaderContext_src.cxx | 9 +- panda/src/gobj/texture.I | 114 ++++++++- panda/src/gobj/texture.cxx | 144 ++++++++++- panda/src/gobj/texture.h | 11 + 6 files changed, 413 insertions(+), 104 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 6b3cf55d13..6a3b49cc53 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -800,6 +800,21 @@ reset() { } } + _supports_clear_texture = false; +#ifndef OPENGLES + if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_clear_texture")) { + _glClearTexImage = (PFNGLCLEARTEXIMAGEPROC) + get_extension_func("glClearTexImage"); + + if (_glClearTexImage == NULL) { + GLCAT.warning() + << "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n"; + } else { + _supports_clear_texture = true; + } + } +#endif + _supports_2d_texture_array = false; #ifndef OPENGLES _supports_2d_texture_array = has_extension("GL_EXT_texture_array"); @@ -7519,7 +7534,7 @@ get_external_image_format(Texture *tex) const { // suitable internal format for GL textures. //////////////////////////////////////////////////////////////////// GLint CLP(GraphicsStateGuardian):: -get_internal_image_format(Texture *tex) const { +get_internal_image_format(Texture *tex, bool force_sized) const { Texture::CompressionMode compression = tex->get_compression(); if (compression == Texture::CM_default) { compression = (compressed_textures) ? Texture::CM_on : Texture::CM_off; @@ -7752,7 +7767,7 @@ get_internal_image_format(Texture *tex) const { } else #endif { - return GL_DEPTH_STENCIL; + return force_sized ? GL_DEPTH24_STENCIL8 : GL_DEPTH_STENCIL; } } // Fall through. @@ -7764,7 +7779,7 @@ get_internal_image_format(Texture *tex) const { } else #endif { - return GL_DEPTH_COMPONENT; + return force_sized ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT; } case Texture::F_depth_component16: #ifdef OPENGLES @@ -7811,7 +7826,7 @@ get_internal_image_format(Texture *tex) const { } else #endif { - return GL_RGBA; + return force_sized ? GL_RGBA8 : GL_RGBA; } case Texture::F_rgba4: @@ -7821,7 +7836,7 @@ get_internal_image_format(Texture *tex) const { case Texture::F_rgba8: return GL_RGBA8_OES; case Texture::F_rgba12: - return GL_RGBA; + return force_sized ? GL_RGBA8 : GL_RGBA; #else case Texture::F_rgba8: return GL_RGBA8; @@ -7843,7 +7858,7 @@ get_internal_image_format(Texture *tex) const { if (tex->get_component_type() == Texture::T_float) { return GL_RGB16F; } else { - return GL_RGB; + return force_sized ? GL_RGB8 : GL_RGB; } case Texture::F_rgb5: @@ -7860,7 +7875,7 @@ get_internal_image_format(Texture *tex) const { case Texture::F_rgb8: return GL_RGB8_OES; case Texture::F_rgb12: - return GL_RGB; + return force_sized ? GL_RGB8 : GL_RGB; case Texture::F_rgb16: return GL_RGB16F; #else @@ -7912,25 +7927,26 @@ get_internal_image_format(Texture *tex) const { case Texture::F_red: case Texture::F_green: case Texture::F_blue: - return GL_RED; + return force_sized ? GL_R8 : GL_RED; #endif case Texture::F_alpha: - return GL_ALPHA; + return force_sized ? GL_ALPHA8 : GL_ALPHA; + case Texture::F_luminance: if (tex->get_component_type() == Texture::T_float) { return GL_LUMINANCE16F_ARB; } else if (tex->get_component_type() == Texture::T_unsigned_short) { return GL_LUMINANCE16; } else { - return GL_LUMINANCE; + return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE; } case Texture::F_luminance_alpha: case Texture::F_luminance_alphamask: if (tex->get_component_type() == Texture::T_float || tex->get_component_type() == Texture::T_unsigned_short) { return GL_LUMINANCE_ALPHA16F_ARB; } else { - return GL_LUMINANCE_ALPHA; + return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA; } #ifndef OPENGLES_1 @@ -7953,7 +7969,7 @@ get_internal_image_format(Texture *tex) const { GLCAT.error() << "Invalid image format in get_internal_image_format(): " << (int)tex->get_format() << "\n"; - return GL_RGB; + return force_sized ? GL_RGB8 : GL_RGB; } } @@ -9359,6 +9375,8 @@ update_show_usage_texture_bindings(int show_stage_index) { GLuint index = (*ui).second; glBindTexture(GL_TEXTURE_2D, index); } + + //TODO: glBindSampler(0) ? } report_my_gl_errors(); @@ -10052,7 +10070,11 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { int height = tex->get_y_size(); int depth = tex->get_z_size(); - GLint internal_format = get_internal_image_format(tex); + // If we'll use immutable texture storage, we have to pick a sized + // image format. + bool force_sized = (gl_immutable_texture_storage && _supports_tex_storage); + + GLint internal_format = get_internal_image_format(tex, force_sized); GLint external_format = get_external_image_format(tex); GLenum component_type = get_component_type(tex->get_component_type()); @@ -10207,6 +10229,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { CPTA_uchar image = tex->get_ram_mipmap_image(mipmap_bias); if (image.is_null()) { + // We don't even have a RAM image, so we have no choice but to let + // mipmaps be generated on the GPU. if (uses_mipmaps) { if (_supports_generate_mipmap) { num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias; @@ -10372,7 +10396,9 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { component_type, false, 0, image_compression); } - if (gtc->_generate_mipmaps && _glGenerateMipmap != NULL) { + if (gtc->_generate_mipmaps && _glGenerateMipmap != NULL && + !image.is_null()) { + // We uploaded an image; we may need to generate mipmaps. if (GLCAT.is_debug()) { GLCAT.debug() << "generating mipmaps for texture " << tex->get_name() << ", " @@ -10470,6 +10496,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, int depth = tex->get_expected_mipmap_z_size(mipmap_bias); // Determine the number of images to upload. + int num_levels = 1; + if (uses_mipmaps) { + num_levels = tex->get_expected_num_mipmap_levels(); + } + int num_ram_mipmap_levels = 0; if (!image.is_null()) { if (uses_mipmaps) { @@ -10494,49 +10525,85 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, if (GLCAT.is_debug()) { if (num_ram_mipmap_levels == 0) { - GLCAT.debug() - << "not loading NULL image for tex " << tex->get_name() << ", " << width << " x " << height - << " x " << depth << ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n"; + if (tex->has_clear_color()) { + GLCAT.debug() + << "clearing texture " << tex->get_name() << ", " + << width << " x " << height << " x " << depth << ", z = " << z + << ", uses_mipmaps = " << uses_mipmaps << ", clear_color = " + << tex->get_clear_color() << "\n"; + } else { + GLCAT.debug() + << "not loading NULL image for texture " << tex->get_name() + << ", " << width << " x " << height << " x " << depth + << ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n"; + } } else { GLCAT.debug() - << "updating image data of texture " << tex->get_name() << ", " << width << " x " << height - << " x " << depth << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels + << "updating image data of texture " << tex->get_name() + << ", " << width << " x " << height << " x " << depth + << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n"; } } - for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) { + for (int n = mipmap_bias; n < num_levels; ++n) { // we grab the mipmap pointer first, if it is NULL we grab the // normal mipmap image pointer which is a PTA_uchar const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); CPTA_uchar ptimage; if (image_ptr == (const unsigned char *)NULL) { ptimage = tex->get_ram_mipmap_image(n); - if (ptimage == (const unsigned char *)NULL) { - GLCAT.warning() - << "No mipmap level " << n << " defined for " << tex->get_name() - << "\n"; - // No mipmap level n; stop here. - break; + if (ptimage.is_null()) { + if (n < num_ram_mipmap_levels) { + // We were told we'd have this many RAM mipmap images, but + // we don't. Raise a warning. + GLCAT.warning() + << "No mipmap level " << n << " defined for " << tex->get_name() + << "\n"; + break; + } + + if (tex->has_clear_color()) { + // The texture has a clear color, so we should fill this mipmap + // level to a solid color. + if (_supports_clear_texture) { + // We can do that with the convenient glClearTexImage function. + string clear_data = tex->get_clear_data(); + + _glClearTexImage(gtc->_index, n - mipmap_bias, external_format, + component_type, (void *)clear_data.data()); + continue; + } else { + // Ask the Texture class to create the mipmap level in RAM. + // It'll fill it in with the correct clear color, which we + // can then upload. + ptimage = tex->make_ram_mipmap_image(n); + } + } else { + // No clear color and no more images. + break; + } } image_ptr = ptimage; } - const unsigned char *orig_image_ptr = image_ptr; - size_t view_size = tex->get_ram_mipmap_view_size(n); - image_ptr += view_size * gtc->get_view(); - if (one_page_only) { - view_size = tex->get_ram_mipmap_page_size(n); - image_ptr += view_size * z; - } - nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); - PTA_uchar bgr_image; - if (!_supports_bgr && image_compression == Texture::CM_off) { - // If the GL doesn't claim to support BGR, we may have to reverse - // the component ordering of the image. - image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size, - external_format, tex); + size_t view_size = tex->get_ram_mipmap_view_size(n); + if (image_ptr != (const unsigned char *)NULL) { + const unsigned char *orig_image_ptr = image_ptr; + image_ptr += view_size * gtc->get_view(); + if (one_page_only) { + view_size = tex->get_ram_mipmap_page_size(n); + image_ptr += view_size * z; + } + nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); + + if (!_supports_bgr && image_compression == Texture::CM_off) { + // If the GL doesn't claim to support BGR, we may have to reverse + // the component ordering of the image. + image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size, + external_format, tex); + } } int width = tex->get_expected_mipmap_x_size(n); @@ -10651,63 +10718,56 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, component_type = GL_UNSIGNED_INT_24_8_EXT; #endif } - - // We don't have any RAM mipmap levels, so we create an uninitialized OpenGL - // texture. Presumably this will be used later for render-to-texture or so. - switch (page_target) { -#ifndef OPENGLES - case GL_TEXTURE_1D: - glTexImage1D(page_target, 0, internal_format, width, 0, external_format, component_type, NULL); - break; - case GL_TEXTURE_2D_ARRAY: -#endif -#ifndef OPENGLES_1 - case GL_TEXTURE_3D: - _glTexImage3D(page_target, 0, internal_format, width, height, depth, 0, external_format, component_type, NULL); - break; -#endif - default: - glTexImage2D(page_target, 0, internal_format, width, height, 0, external_format, component_type, NULL); - break; - } } - for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) { + for (int n = mipmap_bias; n < num_levels; ++n) { const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); CPTA_uchar ptimage; if (image_ptr == (const unsigned char *)NULL) { ptimage = tex->get_ram_mipmap_image(n); - if (ptimage == (const unsigned char *)NULL) { - GLCAT.warning() - << "No mipmap level " << n << " defined for " << tex->get_name() - << "\n"; - // No mipmap level n; stop here. -#ifndef OPENGLES - if (is_at_least_gl_version(1, 2)) { - // Tell the GL we have no more mipmaps for it to use. - glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias); + if (ptimage.is_null()) { + if (n < num_ram_mipmap_levels) { + // We were told we'd have this many RAM mipmap images, but + // we don't. Raise a warning. + GLCAT.warning() + << "No mipmap level " << n << " defined for " << tex->get_name() + << "\n"; + #ifndef OPENGLES + if (is_at_least_gl_version(1, 2)) { + // Tell the GL we have no more mipmaps for it to use. + glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias); + } + #endif + break; + } + + if (tex->has_clear_color()) { + // Ask the Texture class to create the mipmap level in RAM. + // It'll fill it in with the correct clear color, which we + // can then upload. + ptimage = tex->make_ram_mipmap_image(n); } -#endif - break; } image_ptr = ptimage; } - const unsigned char *orig_image_ptr = image_ptr; - size_t view_size = tex->get_ram_mipmap_view_size(n); - image_ptr += view_size * gtc->get_view(); - if (one_page_only) { - view_size = tex->get_ram_mipmap_page_size(n); - image_ptr += view_size * z; - } - nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); - PTA_uchar bgr_image; - if (!_supports_bgr && image_compression == Texture::CM_off) { - // If the GL doesn't claim to support BGR, we may have to reverse - // the component ordering of the image. - image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size, - external_format, tex); + size_t view_size = tex->get_ram_mipmap_view_size(n); + if (image_ptr != (const unsigned char *)NULL) { + const unsigned char *orig_image_ptr = image_ptr; + image_ptr += view_size * gtc->get_view(); + if (one_page_only) { + view_size = tex->get_ram_mipmap_page_size(n); + image_ptr += view_size * z; + } + nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); + + if (!_supports_bgr && image_compression == Texture::CM_off) { + // If the GL doesn't claim to support BGR, we may have to reverse + // the component ordering of the image. + image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size, + external_format, tex); + } } int width = tex->get_expected_mipmap_x_size(n); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index bcfe2fd383..f89a84600b 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -194,6 +194,8 @@ typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pna typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); @@ -461,7 +463,7 @@ protected: static SamplerState::FilterType get_panda_filter_type(GLenum ft); GLenum get_component_type(Texture::ComponentType component_type); GLint get_external_image_format(Texture *tex) const; - GLint get_internal_image_format(Texture *tex) const; + GLint get_internal_image_format(Texture *tex, bool force_sized=false) const; static bool is_mipmap_filter(GLenum min_filter); static bool is_compressed_format(GLenum format); static GLint get_texture_apply_mode_type(TextureStage::Mode am); @@ -644,6 +646,11 @@ public: PFNGLTEXSTORAGE2DPROC _glTexStorage2D; PFNGLTEXSTORAGE3DPROC _glTexStorage3D; + bool _supports_clear_texture; +#ifndef OPENGLES + PFNGLCLEARTEXIMAGEPROC _glClearTexImage; +#endif + PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D; PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D; PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index e16fb3143b..4aca23a373 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -1228,17 +1228,14 @@ update_shader_texture_bindings(ShaderContext *prev) { } else { //TODO: automatically convert to sized type instead of plain GL_RGBA // If a base type is used, it will crash. - if (gtc->_internal_format == GL_RGBA || gtc->_internal_format == GL_RGB) { + GLenum internal_format = gtc->_internal_format; + if (internal_format == GL_RGBA || internal_format == GL_RGB) { GLCAT.error() << "Texture " << tex->get_name() << " has an unsized format. Textures bound " << "to a shader as an image need a sized format.\n"; // This may not actually be right, but may still prevent a crash. - if (gtc->_internal_format == GL_RGBA) { - gtc->_internal_format = GL_RGBA8; - } else { - gtc->_internal_format = GL_RGB8; - } + internal_format = _glgsg->get_internal_image_format(tex, true); } GLenum access = GL_READ_ONLY; diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index f075107d34..e7db1364ce 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -55,7 +55,8 @@ clear() { // Description: Sets the texture to the indicated type and // dimensions, presumably in preparation for calling // read() or load(), or set_ram_image() or -// modify_ram_image(). +// modify_ram_image(), or use set_clear_color to let +// the texture be cleared to a solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_texture(Texture::TextureType texture_type, int x_size, int y_size, @@ -71,7 +72,9 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size, // Access: Published // Description: Sets the texture as an empty 1-d texture with no // dimensions. Follow up with read() or load() to fill -// the texture properties and image data. +// the texture properties and image data, or use +// set_clear_color to let the texture be cleared to a +// solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_1d_texture() { @@ -84,7 +87,8 @@ setup_1d_texture() { // Description: Sets the texture as an empty 1-d texture with the // specified dimensions and properties. Follow up with // set_ram_image() or modify_ram_image() to fill the -// image data. +// image data, or use set_clear_color to let the +// texture be cleared to a solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_1d_texture(int x_size, ComponentType component_type, Format format) { @@ -96,7 +100,9 @@ setup_1d_texture(int x_size, ComponentType component_type, Format format) { // Access: Published // Description: Sets the texture as an empty 2-d texture with no // dimensions. Follow up with read() or load() to fill -// the texture properties and image data. +// the texture properties and image data, or use +// set_clear_color to let the texture be cleared to a +// solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_2d_texture() { @@ -109,7 +115,8 @@ setup_2d_texture() { // Description: Sets the texture as an empty 2-d texture with the // specified dimensions and properties. Follow up with // set_ram_image() or modify_ram_image() to fill the -// image data. +// image data, or use set_clear_color to let the +// texture be cleared to a solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_2d_texture(int x_size, int y_size, ComponentType component_type, @@ -124,7 +131,8 @@ setup_2d_texture(int x_size, int y_size, ComponentType component_type, // dimensions (though if you know the depth ahead // of time, it saves a bit of reallocation later). // Follow up with read() or load() to fill the texture -// properties and image data. +// properties and image data, or use set_clear_color +// to let the texture be cleared to a solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_3d_texture(int z_size) { @@ -152,7 +160,8 @@ setup_3d_texture(int x_size, int y_size, int z_size, // no dimensions (though if you know the depth ahead // of time, it saves a bit of reallocation later). // Follow up with read() or load() to fill the texture -// properties and image data. +// properties and image data, or use set_clear_color +// to let the texture be cleared to a solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_2d_texture_array(int z_size) { @@ -165,7 +174,8 @@ setup_2d_texture_array(int z_size) { // Description: Sets the texture as an empty 2-d texture array with the // specified dimensions and properties. Follow up with // set_ram_image() or modify_ram_image() to fill the -// image data. +// image data, or use set_clear_color to let the +// texture be cleared to a solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_2d_texture_array(int x_size, int y_size, int z_size, @@ -178,7 +188,9 @@ setup_2d_texture_array(int x_size, int y_size, int z_size, // Access: Published // Description: Sets the texture as an empty cube map texture with no // dimensions. Follow up with read() or load() to fill -// the texture properties and image data. +// the texture properties and image data, or use +// set_clear_color to let the texture be cleared to a +// solid color. //////////////////////////////////////////////////////////////////// INLINE void Texture:: setup_cube_map() { @@ -191,7 +203,8 @@ setup_cube_map() { // Description: Sets the texture as an empty cube map texture with // the specified dimensions and properties. Follow up // with set_ram_image() or modify_ram_image() to fill -// the image data. +// the image data, or use set_clear_color to let the +// texture be cleared to a solid color. // // Note that a cube map should always consist of six // square images, so x_size and y_size will be the same, @@ -202,6 +215,87 @@ setup_cube_map(int size, ComponentType component_type, Format format) { setup_texture(TT_cube_map, size, size, 6, component_type, format); } +//////////////////////////////////////////////////////////////////// +// Function: Texture::clear_image +// Access: Published +// Description: Clears the texture data without changing its format +// or resolution. The texture is cleared on both the +// graphics hardware and from RAM, unlike clear_ram_image, +// which only removes the data from RAM. +// +// If a clear color has been specified using +// set_clear_color, the texture will be cleared using +// a solid color. +// +// The texture data will be cleared the first time in +// which the texture is used after this method is called. +//////////////////////////////////////////////////////////////////// +INLINE void Texture:: +clear_image() { + CDWriter cdata(_cycler, true); + do_clear_ram_image(cdata); + do_clear_simple_ram_image(cdata); + cdata->inc_image_modified(); + cdata->inc_simple_image_modified(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::has_clear_color +// Access: Published +// Description: Returns true if a color was previously set using +// set_clear_color. +//////////////////////////////////////////////////////////////////// +INLINE bool Texture:: +has_clear_color() const { + CDReader cdata(_cycler); + return cdata->_has_clear_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_clear_color +// Access: Published +// Description: Returns the color that was previously set using +// set_clear_color. +//////////////////////////////////////////////////////////////////// +INLINE LColor Texture:: +get_clear_color() const { + CDReader cdata(_cycler); + return cdata->_clear_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::set_clear_color +// Access: Published +// Description: Sets the color that will be used to fill the +// texture image in absence of any image data. It is +// used when any of the setup_texture functions or +// clear_image is called and image data is not +// provided using read() or modify_ram_image(). +// +// This does not affect a texture that has already +// been cleared; call clear_image to clear it again. +//////////////////////////////////////////////////////////////////// +INLINE void Texture:: +set_clear_color(const LColor &color) { + CDWriter cdata(_cycler, true); + cdata->_clear_color = color; + cdata->_has_clear_color = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_clear_data +// Access: Published +// Description: Returns the raw image data for a single pixel if +// it were set to the clear color. +//////////////////////////////////////////////////////////////////// +INLINE string Texture:: +get_clear_data() const { + CDReader cdata(_cycler); + unsigned char data[16]; + int size = do_get_clear_data(cdata, data); + return string((char *)data, size); +} + //////////////////////////////////////////////////////////////////// // Function: Texture::write // Access: Published diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 0ab909f66c..129ef2f23c 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -4258,12 +4258,26 @@ do_modify_ram_image(CData *cdata) { //////////////////////////////////////////////////////////////////// PTA_uchar Texture:: do_make_ram_image(CData *cdata) { + int image_size = do_get_expected_ram_image_size(cdata); cdata->_ram_images.clear(); cdata->_ram_images.push_back(RamImage()); cdata->_ram_images[0]._page_size = do_get_expected_ram_page_size(cdata); - cdata->_ram_images[0]._image = PTA_uchar::empty_array(do_get_expected_ram_image_size(cdata), get_class_type()); + cdata->_ram_images[0]._image = PTA_uchar::empty_array(image_size, get_class_type()); cdata->_ram_images[0]._pointer_image = NULL; cdata->_ram_image_compression = CM_off; + + if (cdata->_has_clear_color) { + // Fill the image with the clear color. + unsigned char pixel[16]; + const int pixel_size = do_get_clear_data(cdata, pixel); + nassertr(pixel_size > 0, cdata->_ram_images[0]._image); + + unsigned char *image_data = cdata->_ram_images[0]._image; + for (int i = 0; i < image_size; i += pixel_size) { + memcpy(image_data + i, pixel, pixel_size); + } + } + return cdata->_ram_images[0]._image; } @@ -4331,9 +4345,23 @@ do_make_ram_mipmap_image(CData *cdata, int n) { cdata->_ram_images.push_back(RamImage()); } - cdata->_ram_images[n]._image = PTA_uchar::empty_array(do_get_expected_ram_mipmap_image_size(cdata, n), get_class_type()); + size_t image_size = do_get_expected_ram_mipmap_image_size(cdata, n); + cdata->_ram_images[n]._image = PTA_uchar::empty_array(image_size, get_class_type()); cdata->_ram_images[n]._pointer_image = NULL; cdata->_ram_images[n]._page_size = do_get_expected_ram_mipmap_page_size(cdata, n); + + if (cdata->_has_clear_color) { + // Fill the image with the clear color. + unsigned char pixel[16]; + const int pixel_size = do_get_clear_data(cdata, pixel); + nassertr(pixel_size > 0, cdata->_ram_images[n]._image); + + unsigned char *image_data = cdata->_ram_images[n]._image; + for (int i = 0; i < image_size; i += pixel_size) { + memcpy(image_data + i, pixel, pixel_size); + } + } + return cdata->_ram_images[n]._image; } @@ -4362,6 +4390,116 @@ do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size) } } +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_get_clear_color +// Access: Published +// Description: Returns a string with a single pixel representing +// the clear color of the texture in the format of +// this texture. +// +// In other words, to create an uncompressed RAM +// texture filled with the clear color, it should +// be initialized with this string repeated for +// every pixel. +//////////////////////////////////////////////////////////////////// +int Texture:: +do_get_clear_data(const CData *cdata, unsigned char *into) const { + nassertr(cdata->_has_clear_color, 0); + nassertr(cdata->_num_components <= 4, 0); + + //TODO: encode the color into the sRGB color space if used + switch (cdata->_component_type) { + case T_unsigned_byte: + { + LColorf scaled = cdata->_clear_color.fmin(LColorf(1)).fmax(LColorf::zero()); + scaled *= 255; + switch (cdata->_num_components) { + case 2: + into[1] = (unsigned char)scaled[1]; + case 1: + into[0] = (unsigned char)scaled[0]; + break; + case 4: + into[3] = (unsigned char)scaled[3]; + case 3: // BGR <-> RGB + into[0] = (unsigned char)scaled[2]; + into[1] = (unsigned char)scaled[1]; + into[2] = (unsigned char)scaled[0]; + break; + } + break; + } + + case T_unsigned_short: + { + LColorf scaled = cdata->_clear_color.fmin(LColorf(1)).fmax(LColorf::zero()); + scaled *= 65535; + switch (cdata->_num_components) { + case 2: + ((unsigned short *)into)[1] = (unsigned short)scaled[1]; + case 1: + ((unsigned short *)into)[0] = (unsigned short)scaled[0]; + break; + case 4: + ((unsigned short *)into)[3] = (unsigned short)scaled[3]; + case 3: // BGR <-> RGB + ((unsigned short *)into)[0] = (unsigned short)scaled[2]; + ((unsigned short *)into)[1] = (unsigned short)scaled[1]; + ((unsigned short *)into)[2] = (unsigned short)scaled[0]; + break; + } + break; + } + + case T_float: + switch (cdata->_num_components) { + case 2: + ((float *)into)[1] = cdata->_clear_color[1]; + case 1: + ((float *)into)[0] = cdata->_clear_color[0]; + break; + case 4: + ((float *)into)[3] = cdata->_clear_color[3]; + case 3: // BGR <-> RGB + ((float *)into)[0] = cdata->_clear_color[2]; + ((float *)into)[1] = cdata->_clear_color[1]; + ((float *)into)[2] = cdata->_clear_color[0]; + break; + } + break; + + case T_unsigned_int_24_8: + nassertr(cdata->_num_components == 1, 0); + *((unsigned int *)into) = + ((unsigned int)(cdata->_clear_color[0] * 16777215) << 8) + + (unsigned int)max(min(cdata->_clear_color[1], 255), 0); + break; + + case T_int: + { + // Note: there are no 32-bit UNORM textures. Therefore, we don't + // do any normalization here, either. + switch (cdata->_num_components) { + case 2: + ((int *)into)[1] = (int)cdata->_clear_color[1]; + case 1: + ((int *)into)[0] = (int)cdata->_clear_color[0]; + break; + case 4: + ((int *)into)[3] = (int)cdata->_clear_color[3]; + case 3: // BGR <-> RGB + ((int *)into)[0] = (int)cdata->_clear_color[2]; + ((int *)into)[1] = (int)cdata->_clear_color[1]; + ((int *)into)[2] = (int)cdata->_clear_color[0]; + break; + } + break; + } + } + + return cdata->_num_components * cdata->_component_width; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::consider_auto_process_ram_image // Access: Protected @@ -8151,6 +8289,8 @@ CData() { _simple_x_size = 0; _simple_y_size = 0; _simple_ram_image._page_size = 0; + + _has_clear_color = false; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index ad93f8641a..22287f6330 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -234,6 +234,12 @@ PUBLISHED: void generate_normalization_cube_map(int size); void generate_alpha_scale_map(); + INLINE void clear_image(); + INLINE bool has_clear_color() const; + INLINE LColor get_clear_color() const; + INLINE void set_clear_color(const LColor &color); + INLINE string get_clear_data() const; + BLOCKING bool read(const Filename &fullpath, const LoaderOptions &options = LoaderOptions()); BLOCKING bool read(const Filename &fullpath, const Filename &alpha_fullpath, int primary_file_num_channels, int alpha_file_channel, @@ -569,6 +575,7 @@ protected: PTA_uchar do_modify_ram_mipmap_image(CData *cdata, int n); PTA_uchar do_make_ram_mipmap_image(CData *cdata, int n); void do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size); + int do_get_clear_data(const CData *cdata, unsigned char *into) const; bool consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression); bool do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps, @@ -844,6 +851,10 @@ protected: int _simple_y_size; PN_int32 _simple_image_date_generated; + // This is the color that should be used when no image was given. + bool _has_clear_color; + LColor _clear_color; + UpdateSeq _properties_modified; UpdateSeq _image_modified; UpdateSeq _simple_image_modified; From cd8c6ee37f9fb8285fd7b96d2deeac313e98cca8 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 21 Dec 2014 14:26:06 +0100 Subject: [PATCH 17/20] fix compile error on gcc/clang --- panda/src/gobj/texture.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 129ef2f23c..b06d255993 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -4472,7 +4472,7 @@ do_get_clear_data(const CData *cdata, unsigned char *into) const { nassertr(cdata->_num_components == 1, 0); *((unsigned int *)into) = ((unsigned int)(cdata->_clear_color[0] * 16777215) << 8) + - (unsigned int)max(min(cdata->_clear_color[1], 255), 0); + (unsigned int)max(min(cdata->_clear_color[1], (PN_stdfloat)255), (PN_stdfloat)0); break; case T_int: From f189290dfecb2a59c12bf9c94bbbf4312be6e2aa Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 22 Dec 2014 20:27:37 +0100 Subject: [PATCH 18/20] Support for automated build bot scripts, add PandaSystem::get_git_commit() --- .travis.yml | 2 +- dtool/src/dtoolutil/pandaSystem.cxx | 34 +++++++++++++++++++++-------- dtool/src/dtoolutil/pandaSystem.h | 5 +++-- makepanda/getversion.py | 17 +++++++++++++++ makepanda/makepanda.py | 14 +++++++++--- 5 files changed, 57 insertions(+), 15 deletions(-) create mode 100755 makepanda/getversion.py diff --git a/.travis.yml b/.travis.yml index 8675a25c0e..26088946eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: - clang before_script: - sudo apt-get install python-dev libpng-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libjpeg-dev libopenal-dev libode-dev nvidia-cg-toolkit -script: python makepanda/makepanda.py --everything +script: python makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT notifications: irc: channels: diff --git a/dtool/src/dtoolutil/pandaSystem.cxx b/dtool/src/dtoolutil/pandaSystem.cxx index ac71aa0729..d54029ecf2 100644 --- a/dtool/src/dtoolutil/pandaSystem.cxx +++ b/dtool/src/dtoolutil/pandaSystem.cxx @@ -226,7 +226,7 @@ is_official_version() { return false; #endif } - + //////////////////////////////////////////////////////////////////// // Function: PandaSystem::get_distributor // Access: Published, Static @@ -239,7 +239,7 @@ string PandaSystem:: get_distributor() { return PANDA_DISTRIBUTOR; } - + //////////////////////////////////////////////////////////////////// // Function: PandaSystem::get_compiler // Access: Published, Static @@ -279,7 +279,7 @@ get_compiler() { return "unknown"; #endif } - + //////////////////////////////////////////////////////////////////// // Function: PandaSystem::get_build_date // Access: Published, Static @@ -291,7 +291,23 @@ string PandaSystem:: get_build_date() { return __DATE__ " " __TIME__; } - + +//////////////////////////////////////////////////////////////////// +// Function: PandaSystem::get_git_commit +// Access: Published, Static +// Description: Returns a string representing the git commit hash +// that this source tree is based on, or the empty +// string if it has not been specified at build time. +//////////////////////////////////////////////////////////////////// +string PandaSystem:: +get_git_commit() { +#ifdef PANDA_GIT_COMMIT_STR + return PANDA_GIT_COMMIT_STR; +#else + return string(); +#endif +} + //////////////////////////////////////////////////////////////////// // Function: PandaSystem::get_platform // Access: Published, Static @@ -440,7 +456,7 @@ heap_trim(size_t pad) { //////////////////////////////////////////////////////////////////// // Function: PandaSystem::output // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PandaSystem:: output(ostream &out) const { @@ -450,7 +466,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// // Function: PandaSystem::write // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PandaSystem:: write(ostream &out) const { @@ -472,7 +488,7 @@ write(ostream &out) const { } } - + //////////////////////////////////////////////////////////////////// // Function: PandaSystem::get_global_ptr // Access: Published, Static @@ -498,12 +514,12 @@ void PandaSystem:: reset_system_names() { _system_names.clear(); _system_names.reserve(_systems.size()); - + Systems::const_iterator si; for (si = _systems.begin(); si != _systems.end(); ++si) { _system_names.push_back((*si).first); } - + _system_names_dirty = false; } diff --git a/dtool/src/dtoolutil/pandaSystem.h b/dtool/src/dtoolutil/pandaSystem.h index d0a7835e01..f69b8adde1 100644 --- a/dtool/src/dtoolutil/pandaSystem.h +++ b/dtool/src/dtoolutil/pandaSystem.h @@ -41,10 +41,11 @@ PUBLISHED: static int get_minor_version(); static int get_sequence_version(); static bool is_official_version(); - + static string get_distributor(); static string get_compiler(); static string get_build_date(); + static string get_git_commit(); static string get_platform(); @@ -106,4 +107,4 @@ inline ostream &operator << (ostream &out, const PandaSystem &ps) { #endif - + diff --git a/makepanda/getversion.py b/makepanda/getversion.py new file mode 100755 index 0000000000..5d74316aec --- /dev/null +++ b/makepanda/getversion.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# This script parses the version number in dtool/PandaVersion.pp +# and returns it on the command-line. This is useful for the +# automated scripts that build the Panda3D releases. + +from makepandacore import ParsePandaVersion, ParsePluginVersion +import sys + +if '--runtime' in sys.argv: + version = ParsePluginVersion("dtool/PandaVersion.pp") +else: + version = ParsePandaVersion("dtool/PandaVersion.pp") + +version = version.strip() +sys.stdout.write(version) +sys.stdout.flush() diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index e29085f428..c6135e8124 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -61,6 +61,7 @@ DISTRIBUTOR="" VERSION=None DEBVERSION=None RPMRELEASE="1" +GIT_COMMIT=None P3DSUFFIX=None MAJOR_VERSION=None COREAPI_VERSION=None @@ -121,7 +122,7 @@ signal.signal(signal.SIGINT, keyboardInterruptHandler) def usage(problem): if (problem): print("") - print("Error parsing commandline input", problem) + print("Error parsing command-line input: %s" % (problem)) print("") print("Makepanda generates a 'built' subdirectory containing a") @@ -164,7 +165,7 @@ def usage(problem): def parseopts(args): global INSTALLER,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION global COMPRESSOR,THREADCOUNT,OSXTARGET,UNIVERSAL,HOST_URL - global DEBVERSION,RPMRELEASE,P3DSUFFIX + global DEBVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX global STRDXSDKVERSION, STRMSPLATFORMVERSION, BOOUSEINTELCOMPILER longopts = [ "help","distributor=","verbose","runtime","osxtarget=", @@ -172,7 +173,7 @@ def parseopts(args): "version=","lzma","no-python","threads=","outputdir=","override=", "static","host=","debversion=","rpmrelease=","p3dsuffix=", "directx-sdk=", "platform-sdk=", "use-icl", - "universal", "target=", "arch="] + "universal", "target=", "arch=", "git-commit="] anything = 0 optimize = "" target = None @@ -208,6 +209,7 @@ def parseopts(args): elif (option=="--host"): HOST_URL=value elif (option=="--debversion"): DEBVERSION=value elif (option=="--rpmrelease"): RPMRELEASE=value + elif (option=="--git-commit"): GIT_COMMIT=value elif (option=="--p3dsuffix"): P3DSUFFIX=value # Backward compatibility, OPENGL was renamed to GL elif (option=="--use-opengl"): PkgEnable("GL") @@ -259,6 +261,9 @@ def parseopts(args): except: usage("Invalid setting for OPTIMIZE") + if GIT_COMMIT is not None and not re.match("^[a-f0-9]{40}$", GIT_COMMIT): + usage("Invalid SHA-1 hash given for --git-commit option!") + if target is not None or target_arch is not None: SetTarget(target, target_arch) @@ -2399,6 +2404,9 @@ def CreatePandaVersionFiles(): else: pandaversion_h += "\n#undef PANDA_OFFICIAL_VERSION\n" + if GIT_COMMIT: + pandaversion_h += "\n#define PANDA_GIT_COMMIT_STR \"%s\"\n" % (GIT_COMMIT) + if not RUNTIME: checkpandaversion_cxx = CHECKPANDAVERSION_CXX.replace("$VERSION1",str(version1)) checkpandaversion_cxx = checkpandaversion_cxx.replace("$VERSION2",str(version2)) From 9c137426e3c6317213b6d5b71d12e392b4557a3f Mon Sep 17 00:00:00 2001 From: tzaeru Date: Mon, 22 Dec 2014 20:34:43 +0200 Subject: [PATCH 19/20] Integer texture formats for 8-bit R, RG, RGB and RGBA channels --- .../glstuff/glGraphicsStateGuardian_src.cxx | 70 +++++++++++++++++++ panda/src/gobj/texture.cxx | 4 ++ panda/src/gobj/texture.h | 5 ++ 3 files changed, 79 insertions(+) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 6a3b49cc53..86a0a3672a 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -7327,12 +7327,14 @@ get_external_image_format(Texture *tex) const { case Texture::F_rgba12: case Texture::F_rgba16: case Texture::F_rgba32: + case Texture::F_rgba8i: return GL_COMPRESSED_RGBA; case Texture::F_rgb: case Texture::F_rgb5: case Texture::F_rgba5: case Texture::F_rgb8: + case Texture::F_rgb8i: case Texture::F_rgb12: case Texture::F_rgb332: case Texture::F_rgb16: @@ -7345,11 +7347,13 @@ get_external_image_format(Texture *tex) const { case Texture::F_red: case Texture::F_green: case Texture::F_blue: + case Texture::F_r8i: case Texture::F_r16: case Texture::F_r32: case Texture::F_r32i: return GL_COMPRESSED_RED; + case Texture::F_rg8i: case Texture::F_rg16: case Texture::F_rg32: return GL_COMPRESSED_RG; @@ -7517,8 +7521,16 @@ get_external_image_format(Texture *tex) const { return GL_LUMINANCE_ALPHA; #ifndef OPENGLES + case Texture::F_r8i: case Texture::F_r32i: return GL_RED_INTEGER; + case Texture::F_rg8i: + return GL_RG_INTEGER; + case Texture::F_rgb8i: + return GL_RGB_INTEGER; + case Texture::F_rgba8i: + return GL_RGBA_INTEGER; + #endif } GLCAT.error() @@ -7565,6 +7577,10 @@ get_internal_image_format(Texture *tex, bool force_sized) const { case Texture::F_depth_component24: case Texture::F_depth_component32: case Texture::F_depth_stencil: + case Texture::F_r8i: + case Texture::F_rg8i: + case Texture::F_rgb8i: + case Texture::F_rgba8i: case Texture::F_r32i: // Unsupported; fall through to below. break; @@ -7840,6 +7856,30 @@ get_internal_image_format(Texture *tex, bool force_sized) const { #else case Texture::F_rgba8: return GL_RGBA8; + case Texture::F_r8i: + if (tex->get_component_type() == Texture::T_unsigned_byte) { + return GL_R8UI; + } else { + return GL_R8I; + } + case Texture::F_rg8i: + if (tex->get_component_type() == Texture::T_unsigned_byte) { + return GL_RG8UI; + } else { + return GL_RG8I; + } + case Texture::F_rgb8i: + if (tex->get_component_type() == Texture::T_unsigned_byte) { + return GL_RGB8UI; + } else { + return GL_RGB8I; + } + case Texture::F_rgba8i: + if (tex->get_component_type() == Texture::T_unsigned_byte) { + return GL_RGBA8UI; + } else { + return GL_RGBA8I; + } case Texture::F_rgba12: return GL_RGBA12; #endif // OPENGLES @@ -11261,6 +11301,36 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { case GL_R3_G3_B2: format = Texture::F_rgb332; break; + + case GL_R8I: + format = Texture::F_r8i; + break; + case GL_RG8I: + format = Texture::F_rg8i; + break; + case GL_RGB8I: + format = Texture::F_rgb8i; + break; + case GL_RGBA8I: + format = Texture::F_rgba8i; + break; + + case GL_R8UI: + type = Texture::T_unsigned_byte; + format = Texture::F_r8i; + break; + case GL_RG8UI: + type = Texture::T_unsigned_byte; + format = Texture::F_rg8i; + break; + case GL_RGB8UI: + type = Texture::T_unsigned_byte; + format = Texture::F_rgb8i; + break; + case GL_RGBA8UI: + type = Texture::T_unsigned_byte; + format = Texture::F_rgba8i; + break; #endif #ifndef OPENGLES_1 diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index b06d255993..b67fb9eae8 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -562,6 +562,8 @@ estimate_texture_memory() const { case Texture::F_rgb8: case Texture::F_rgba8: case Texture::F_srgb_alpha: + case Texture::F_rgb8i: + case Texture::F_rgba8i: bpp = 4; break; @@ -583,6 +585,8 @@ estimate_texture_memory() const { break; case Texture::F_r16: + case Texture::F_r8i: + case Texture::F_rg8i: bpp = 2; break; case Texture::F_rg16: diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 22287f6330..c8e0571aea 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -146,6 +146,11 @@ PUBLISHED: F_r32, F_rg32, F_rgb32, + + F_r8i, // 8 integer bits per R channel + F_rg8i, // 8 integer bits per R,G channel + F_rgb8i, // 8 integer bits per R,G,B channel + F_rgba8i, // 8 integer bits per R,G,B,A channel }; // Deprecated. See SamplerState.FilterType. From fef66d1fdd47e57e107a0efe0f2d773f313b933a Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 24 Dec 2014 14:37:37 +0100 Subject: [PATCH 20/20] Improvements and fixes to installer generation on Linux --- makepanda/installpanda.py | 80 +++++++++++--- makepanda/makepanda.py | 223 +++++++++++++++++++++++--------------- 2 files changed, 200 insertions(+), 103 deletions(-) diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index f398a95cfa..20f4fd2773 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -91,19 +91,54 @@ def WriteKeysFile(fname, info): fhandle.write("\n") fhandle.close() -def GetLibDir(): - # This one's a bit tricky. Some systems require us to install - # 64-bits libraries into /usr/lib64, some into /usr/lib. - # Debian forbids installing to lib64 nowadays, and the only distros - # I know of that use lib64 are all RPM-based. So, the 'solution' - # seems to be to use the rpm command to give us the libdir for now. +def GetDebLibDir(): + """ Returns the lib dir according to the debian system. """ + # We're on Debian or Ubuntu, which use multiarch directories. + # Call dpkg-architecture to get the multiarch libdir. + handle = os.popen("dpkg-architecture -qDEB_HOST_MULTIARCH") + multiarch = handle.read().strip() + if handle.close(): + # It failed. Old Debian/Ubuntu version? + pass + elif len(multiarch) > 0: + return "lib/" + multiarch + return "lib" + +def GetRPMLibDir(): + """ Returns the lib dir according to the rpm system. """ handle = os.popen("rpm -E '%_lib'") result = handle.read().strip() handle.close() if len(result) > 0: assert result == "lib64" or result == "lib" return result + else: + return "lib" + +def GetLibDir(): + """ Returns the directory to install architecture-dependent + libraries in, relative to the prefix directory. This may be + something like "lib" or "lib64" or in some cases, something + similar to "lib/x86_64-linux-gnu". """ + + # This one's a bit tricky. Some systems require us to install + # 64-bits libraries into /usr/lib64, some into /usr/lib. + # Debian forbids installing to lib64 nowadays, and the only distros + # I know of that use lib64 are all RPM-based. So, the 'solution' + # seems to be to use the rpm command to give us the libdir for now, + # unless we know we're on debian, since rpm may be installed on + # Debian and will give the wrong result. Ugh. + + if os.environ.get("DEB_HOST_MULTIARCH"): + # We're building inside the Debian build environment. + return "lib/" + os.environ["DEB_HOST_MULTIARCH"] + + if os.path.isfile('/etc/debian_version'): + return GetDebLibDir() + else: + # Okay, maybe we're on an RPM-based system? + return GetRPMLibDir() # If Python is installed into /usr/lib64, it's probably safe # to assume that we should install there as well. @@ -114,14 +149,19 @@ def GetLibDir(): return "lib" -def InstallPanda(destdir="", prefix="/usr", outputdir="built"): - if (not prefix.startswith("/")): prefix = "/" + prefix - libdir = prefix + "/" + GetLibDir() +def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir()): + if (not prefix.startswith("/")): + prefix = "/" + prefix + libdir = prefix + "/" + libdir + + # Determine the location of the Python executable and site-packages dir. PPATH = get_python_lib(1) if os.path.islink(sys.executable): PEXEC = os.path.join(os.path.dirname(sys.executable), os.readlink(sys.executable)) else: PEXEC = sys.executable + + # Create the directory structure that we will be putting our files in. oscmd("mkdir -m 0755 -p "+destdir+prefix+"/bin") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/include") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/panda3d") @@ -131,27 +171,32 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"): oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/applications") oscmd("mkdir -m 0755 -p "+destdir+libdir+"/panda3d") oscmd("mkdir -m 0755 -p "+destdir+PPATH) + if (sys.platform.startswith("freebsd")): oscmd("mkdir -m 0755 -p "+destdir+prefix+"/etc") oscmd("mkdir -m 0755 -p "+destdir+"/usr/local/libdata/ldconfig") else: oscmd("mkdir -m 0755 -p "+destdir+"/etc/ld.so.conf.d") + + # Write the Config.prc file. Configrc = ReadFile(outputdir+"/etc/Config.prc") Configrc = Configrc.replace("model-path $THIS_PRC_DIR/..", "model-path "+prefix+"/share/panda3d") if (sys.platform.startswith("freebsd")): WriteFile(destdir+prefix+"/etc/Config.prc", Configrc) - oscmd("cp "+outputdir+"/etc/Confauto.prc "+destdir+prefix+"/etc/Confauto.prc") + oscmd("cp "+outputdir+"/etc/Confauto.prc "+destdir+prefix+"/etc/Confauto.prc") else: WriteFile(destdir+"/etc/Config.prc", Configrc) - oscmd("cp "+outputdir+"/etc/Confauto.prc "+destdir+"/etc/Confauto.prc") + oscmd("cp "+outputdir+"/etc/Confauto.prc "+destdir+"/etc/Confauto.prc") + oscmd("cp -R "+outputdir+"/include "+destdir+prefix+"/include/panda3d") - oscmd("cp -R "+outputdir+"/direct "+destdir+prefix+"/share/panda3d/") oscmd("cp -R "+outputdir+"/pandac "+destdir+prefix+"/share/panda3d/") oscmd("cp -R "+outputdir+"/panda3d "+destdir+PPATH+"/") oscmd("cp -R "+outputdir+"/models "+destdir+prefix+"/share/panda3d/") if os.path.isdir("samples"): oscmd("cp -R samples "+destdir+prefix+"/share/panda3d/") + if os.path.isdir(outputdir+"/direct"): oscmd("cp -R "+outputdir+"/direct "+destdir+prefix+"/share/panda3d/") if os.path.isdir(outputdir+"/Pmw"): oscmd("cp -R "+outputdir+"/Pmw "+destdir+prefix+"/share/panda3d/") if os.path.isdir(outputdir+"/plugins"): oscmd("cp -R "+outputdir+"/plugins "+destdir+prefix+"/share/panda3d/") + WriteMimeFile(destdir+prefix+"/share/mime-info/panda3d.mime", MIME_INFO) WriteKeysFile(destdir+prefix+"/share/mime-info/panda3d.keys", MIME_INFO) WriteMimeXMLFile(destdir+prefix+"/share/mime/packages/panda3d.xml", MIME_INFO) @@ -167,7 +212,6 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"): else: oscmd("echo '"+libdir+"/panda3d'> "+destdir+"/etc/ld.so.conf.d/panda3d.conf") oscmd("chmod +x "+destdir+"/etc/ld.so.conf.d/panda3d.conf") - oscmd("ln -f -s "+PEXEC+" "+destdir+prefix+"/bin/ppython") oscmd("cp "+outputdir+"/bin/* "+destdir+prefix+"/bin/") for base in os.listdir(outputdir+"/lib"): if (not base.endswith(".a")) or base == "libp3pystub.a": @@ -190,9 +234,11 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"): if (os.path.isfile(destdir+prefix+"/share/panda3d/direct/leveleditor/copyfiles.pl")): os.remove(destdir+prefix+"/share/panda3d/direct/leveleditor/copyfiles.pl") -def InstallRuntime(destdir="", prefix="/usr", outputdir="built"): - if (not prefix.startswith("/")): prefix = "/" + prefix - libdir = prefix + "/" + GetLibDir() +def InstallRuntime(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir()): + if (not prefix.startswith("/")): + prefix = "/" + prefix + libdir = prefix + "/" + libdir + oscmd("mkdir -m 0755 -p "+destdir+prefix+"/bin") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime-info") oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime/packages") @@ -245,7 +291,7 @@ if (__name__ == "__main__"): print("Installing Panda3D Runtime into " + destdir + options.prefix) InstallRuntime(destdir = destdir, prefix = options.prefix, outputdir = options.outputdir) else: - print("Installing Panda3D into " + destdir + options.prefix) + print("Installing Panda3D SDK into " + destdir + options.prefix) InstallPanda(destdir = destdir, prefix = options.prefix, outputdir = options.outputdir) print("Installation finished!") diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index c6135e8124..d58e235a6d 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -235,12 +235,18 @@ def parseopts(args): PkgDisable(pkg) break if (option=="--everything" or option.startswith("--use-") - or option=="--nothing" or option.startswith("--no-")): - anything = 1 + or option=="--nothing" or option.startswith("--no-")): + anything = 1 except: usage(0) print("Exception while parsing commandline:", sys.exc_info()[0]) - if (anything==0): usage(0) + + if not anything: + if RUNTIME: + PkgEnableAll() + else: + usage("You should specify a list of packages to use or --everything to enable all packages.") + if (RTDIST and RUNTIME): usage("Options --runtime and --rtdist cannot be specified at the same time!") if (optimize=="" and (RTDIST or RUNTIME)): optimize = "4" @@ -374,8 +380,8 @@ if (GetHost() == 'windows'): if (INSTALLER and RTDIST): exit("Cannot build an installer for the rtdist build!") -if (INSTALLER) and (PkgSkip("PYTHON")) and (not RUNTIME): - exit("Cannot build installer without python") +if (INSTALLER) and (PkgSkip("PYTHON")) and (not RUNTIME) and GetTarget() == 'windows': + exit("Cannot build installer on Windows without python") if (RTDIST) and (PkgSkip("JPEG")): exit("Cannot build rtdist without jpeg") @@ -6145,7 +6151,8 @@ Priority: optional Architecture: ARCH Essential: no Depends: DEPENDS -Recommends: panda3d-runtime, python-wxversion, python-profiler (>= PV), python-tk (>= PV), RECOMMENDS +Recommends: RECOMMENDS +Suggests: panda3d-runtime Provides: panda3d Conflicts: panda3d Replaces: panda3d @@ -6207,7 +6214,6 @@ This package contains the SDK for development with Panda3D, install panda3d-runt /usr/share/application-registry/panda3d.applications /usr/share/applications/*.desktop /etc/ld.so.conf.d/panda3d.conf -/usr/bin /usr/%_lib/panda3d %{python_sitearch} /usr/include/panda3d @@ -6267,48 +6273,31 @@ WWW: http://www.panda3d.org/ """ def MakeInstallerLinux(): - if RUNTIME: # No worries, it won't be used - PYTHONV = "python" - else: + if not RUNTIME and not PkgSkip("PYTHON"): PYTHONV = SDK["PYTHONVERSION"] + else: + PYTHONV = "python" PV = PYTHONV.replace("python", "") - if (os.path.isdir("targetroot")): oscmd("chmod -R 755 targetroot") + + # Clean and set up a directory to install Panda3D into oscmd("rm -rf targetroot data.tar.gz control.tar.gz panda3d.spec") oscmd("mkdir --mode=0755 targetroot") - # Invoke installpanda.py to install it into a temporary dir - if RUNTIME: - InstallRuntime(destdir = "targetroot", prefix = "/usr", outputdir = GetOutputDir()) - else: - InstallPanda(destdir = "targetroot", prefix = "/usr", outputdir = GetOutputDir()) - oscmd("chmod -R 755 targetroot/usr/share/panda3d") - - if (os.path.exists("/usr/bin/rpmbuild") and not os.path.exists("/usr/bin/dpkg-deb")): - oscmd("rm -rf targetroot/DEBIAN") - oscmd("rpm -E '%_target_cpu' > "+GetOutputDir()+"/tmp/architecture.txt") - ARCH = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip() - pandasource = os.path.abspath(os.getcwd()) - if (RUNTIME): - txt = RUNTIME_INSTALLER_SPEC_FILE[1:] + if os.path.exists("/usr/bin/dpkg-deb"): + # Invoke installpanda.py to install it into a temporary dir + if RUNTIME: + InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=GetDebLibDir()) else: - txt = INSTALLER_SPEC_FILE[1:] - txt = txt.replace("VERSION", VERSION).replace("RPMRELEASE", RPMRELEASE).replace("PANDASOURCE", pandasource).replace("PV", PV) - WriteFile("panda3d.spec", txt) - oscmd("fakeroot rpmbuild --define '_rpmdir "+pandasource+"' --buildroot '"+os.path.abspath("targetroot")+"' -bb panda3d.spec") - if (RUNTIME): - oscmd("mv "+ARCH+"/panda3d-runtime-"+VERSION+"-"+RPMRELEASE+"."+ARCH+".rpm .") - else: - oscmd("mv "+ARCH+"/panda3d-"+VERSION+"-"+RPMRELEASE+"."+ARCH+".rpm .") - oscmd("rm -rf "+ARCH, True) + InstallPanda(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=GetDebLibDir()) + oscmd("chmod -R 755 targetroot/usr/share/panda3d") - if (os.path.exists("/usr/bin/dpkg-deb")): oscmd("dpkg --print-architecture > "+GetOutputDir()+"/tmp/architecture.txt") - ARCH = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip() + pkg_arch = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip() if (RUNTIME): txt = RUNTIME_INSTALLER_DEB_FILE[1:] else: txt = INSTALLER_DEB_FILE[1:] - txt = txt.replace("VERSION", DEBVERSION).replace("ARCH", ARCH).replace("PV", PV).replace("MAJOR", MAJOR_VERSION) + txt = txt.replace("VERSION", DEBVERSION).replace("ARCH", pkg_arch).replace("PV", PV).replace("MAJOR", MAJOR_VERSION) txt = txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024)) oscmd("mkdir --mode=0755 -p targetroot/DEBIAN") oscmd("cd targetroot ; (find usr -type f -exec md5sum {} \;) > DEBIAN/md5sums") @@ -6317,44 +6306,105 @@ def MakeInstallerLinux(): WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n") WriteFile("targetroot/DEBIAN/postinst","#!/bin/sh\necho running ldconfig\nldconfig\n") oscmd("cp targetroot/DEBIAN/postinst targetroot/DEBIAN/postrm") - oscmd("mkdir targetroot/debian") - WriteFile("targetroot/debian/control", "") - if (RUNTIME): - oscmd("ln -s .. targetroot/debian/panda3d-runtime") - oscmd("cd targetroot ; dpkg-shlibdeps -xpanda3d-runtime debian/panda3d-runtime/usr/lib/*.so* debian/panda3d-runtime/usr/lib64/*.so* debian/panda3d-runtime/usr/bin/*") - depends = ReadFile("targetroot/debian/substvars").replace("shlibs:Depends=", "").strip() - WriteFile("targetroot/DEBIAN/control", txt.replace("DEPENDS", depends)) + + # Determine the package name and the locations that + # dpkg-shlibdeps should look in for executables. + lib_dir = GetLibDir() + pkg_version = DEBVERSION + if RUNTIME: + pkg_name = "panda3d-runtime" + lib_pattern = "debian/%s/usr/%s/*.so" % (pkg_name, lib_dir) else: - oscmd("ln -s .. targetroot/debian/panda3d" + MAJOR_VERSION) - oscmd("cd targetroot ; dpkg-gensymbols -v%s -ppanda3d%s -eusr/lib/panda3d/lib*.so* -eusr/lib64/panda3d/lib*.so* -ODEBIAN/symbols >/dev/null" % (DEBVERSION, MAJOR_VERSION)) - # Library dependencies are required, binary dependencies are recommended. Dunno why -xlibphysx-extras is needed, prolly a bug in their package - oscmd("cd targetroot ; LD_LIBRARY_PATH=usr/lib/panda3d dpkg-shlibdeps --ignore-missing-info --warnings=2 -xpanda3d%s -xlibphysx-extras -Tdebian/substvars_dep debian/panda3d%s/usr/lib/panda3d/lib*.so* debian/panda3d%s/usr/lib64/panda3d/lib*.so*" % (MAJOR_VERSION, MAJOR_VERSION, MAJOR_VERSION)) - oscmd("cd targetroot ; LD_LIBRARY_PATH=usr/lib/panda3d dpkg-shlibdeps --ignore-missing-info --warnings=2 -xpanda3d%s -Tdebian/substvars_rec debian/panda3d%s/usr/bin/*" % (MAJOR_VERSION, MAJOR_VERSION)) + pkg_name = "panda3d" + MAJOR_VERSION + lib_pattern = "debian/%s/usr/%s/panda3d/*.so*" % (pkg_name, lib_dir) + bin_pattern = "debian/%s/usr/bin/*" % (pkg_name) + + # dpkg-shlibdeps looks in the debian/{pkg_name}/DEBIAN/shlibs directory + # and also expects a debian/control file, so we create this dummy set-up. + oscmd("mkdir targetroot/debian") + oscmd("ln -s .. targetroot/debian/" + pkg_name) + WriteFile("targetroot/debian/control", "") + + dpkg_shlibdeps = "dpkg-shlibdeps" + if GetVerbose(): + dpkg_shlibdeps += " -v" + + if RUNTIME: + # The runtime doesn't export any useful symbols, so just query the dependencies. + oscmd("cd targetroot; %(dpkg_shlibdeps)s -x%(pkg_name)s %(lib_pattern)s %(bin_pattern)s*" % locals()) + depends = ReadFile("targetroot/debian/substvars").replace("shlibs:Depends=", "").strip() + recommends = "" + else: + pkg_name = "panda3d" + MAJOR_VERSION + pkg_dir = "debian/panda3d" + MAJOR_VERSION + + # Generate a symbols file so that other packages can know which symbols we export. + oscmd("cd targetroot; dpkg-gensymbols -q -ODEBIAN/symbols -v%(pkg_version)s -p%(pkg_name)s -e%(lib_pattern)s" % locals()) + + # Library dependencies are required, binary dependencies are recommended. + # We explicitly exclude libphysx-extras since we don't want to depend on PhysX. + oscmd("cd targetroot; LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_dep --ignore-missing-info -x%(pkg_name)s -xlibphysx-extras %(lib_pattern)s" % locals()) + oscmd("cd targetroot; LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_rec --ignore-missing-info -x%(pkg_name)s %(bin_pattern)s" % locals()) + + # Parse the substvars files generated by dpkg-shlibdeps. depends = ReadFile("targetroot/debian/substvars_dep").replace("shlibs:Depends=", "").strip() recommends = ReadFile("targetroot/debian/substvars_rec").replace("shlibs:Depends=", "").strip() if PkgSkip("PYTHON")==0: depends += ", " + PYTHONV + ", python-pmw" + recommends += ", python-wxversion, python-profiler (>= " + PV + "), python-tk (>= " + PV + ")" if PkgSkip("NVIDIACG")==0: depends += ", nvidia-cg-toolkit" - if depends.startswith(', '): - depends = depends[2:] - WriteFile("targetroot/DEBIAN/control", txt.replace("DEPENDS", depends).replace("RECOMMENDS", recommends)) + + # Write back the dependencies, and delete the dummy set-up. + txt = txt.replace("DEPENDS", depends.strip(', ')) + txt = txt.replace("RECOMMENDS", recommends.strip(', ')) + WriteFile("targetroot/DEBIAN/control", txt) oscmd("rm -rf targetroot/debian") + + # Package it all up into a .deb file. oscmd("chmod -R 755 targetroot/DEBIAN") - if (RUNTIME): - oscmd("cd targetroot/DEBIAN ; chmod 644 control md5sums") - oscmd("fakeroot dpkg-deb -b targetroot panda3d-runtime_"+DEBVERSION+"_"+ARCH+".deb") + oscmd("chmod 644 targetroot/DEBIAN/control targetroot/DEBIAN/md5sums") + if not RUNTIME: + oscmd("chmod 644 targetroot/DEBIAN/conffiles targetroot/DEBIAN/symbols") + oscmd("fakeroot dpkg-deb -b targetroot %s_%s_%s.deb" % (pkg_name, pkg_version, pkg_arch)) + + elif os.path.exists("/usr/bin/rpmbuild"): + # Invoke installpanda.py to install it into a temporary dir + if RUNTIME: + InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=GetRPMLibDir()) else: - oscmd("cd targetroot/DEBIAN ; chmod 644 control md5sums conffiles symbols") - oscmd("fakeroot dpkg-deb -b targetroot panda3d"+MAJOR_VERSION+"_"+DEBVERSION+"_"+ARCH+".deb") - oscmd("chmod -R 755 targetroot") + InstallPanda(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=GetRPMLibDir()) + oscmd("chmod -R 755 targetroot/usr/share/panda3d") - if not (os.path.exists("/usr/bin/rpmbuild") or os.path.exists("/usr/bin/dpkg-deb")): + oscmd("rpm -E '%_target_cpu' > "+GetOutputDir()+"/tmp/architecture.txt") + ARCH = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip() + pandasource = os.path.abspath(os.getcwd()) + + if RUNTIME: + txt = RUNTIME_INSTALLER_SPEC_FILE[1:] + else: + txt = INSTALLER_SPEC_FILE[1:] + # Add the binaries in /usr/bin explicitly to the spec file + for base in os.listdir(GetOutputDir() + "/bin"): + txt += "/usr/bin/%s\n" % (base) + + # Write out the spec file. + txt = txt.replace("VERSION", VERSION) + txt = txt.replace("RPMRELEASE", RPMRELEASE) + txt = txt.replace("PANDASOURCE", pandasource) + txt = txt.replace("PV", PV) + WriteFile("panda3d.spec", txt) + + oscmd("fakeroot rpmbuild --define '_rpmdir "+pandasource+"' --buildroot '"+os.path.abspath("targetroot")+"' -bb panda3d.spec") + if (RUNTIME): + oscmd("mv "+ARCH+"/panda3d-runtime-"+VERSION+"-"+RPMRELEASE+"."+ARCH+".rpm .") + else: + oscmd("mv "+ARCH+"/panda3d-"+VERSION+"-"+RPMRELEASE+"."+ARCH+".rpm .") + oscmd("rm -rf "+ARCH, True) + + else: exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!") -# oscmd("chmod -R 755 targetroot") -# oscmd("rm -rf targetroot data.tar.gz control.tar.gz panda3d.spec "+ARCH) - def MakeInstallerOSX(): if (RUNTIME): # Invoke the make_installer script. @@ -6589,30 +6639,33 @@ def MakeInstallerFreeBSD(): cmd += " -d pkg-descr -f pkg-plist panda3d-%s" % VERSION oscmd(cmd) -if (INSTALLER != 0): - ProgressOutput(100.0, "Building installer") - target = GetTarget() - if (target == 'windows'): - dbg = "" - if (GetOptimize() <= 2): dbg = "-dbg" - if GetTargetArch() == 'x64': - if (RUNTIME): - MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+"-x64.exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") +try: + if INSTALLER: + ProgressOutput(100.0, "Building installer") + target = GetTarget() + if (target == 'windows'): + dbg = "" + if (GetOptimize() <= 2): dbg = "-dbg" + if GetTargetArch() == 'x64': + if (RUNTIME): + MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+"-x64.exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") + else: + MakeInstallerNSIS("Panda3D-"+VERSION+dbg+"-x64.exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") else: - MakeInstallerNSIS("Panda3D-"+VERSION+dbg+"-x64.exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") + if (RUNTIME): + MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+".exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) + else: + MakeInstallerNSIS("Panda3D-"+VERSION+dbg+".exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) + elif (target == 'linux'): + MakeInstallerLinux() + elif (target == 'darwin'): + MakeInstallerOSX() + elif (target == 'freebsd'): + MakeInstallerFreeBSD() else: - if (RUNTIME): - MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+".exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) - else: - MakeInstallerNSIS("Panda3D-"+VERSION+dbg+".exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) - elif (target == 'linux'): - MakeInstallerLinux() - elif (target == 'darwin'): - MakeInstallerOSX() - elif (target == 'freebsd'): - MakeInstallerFreeBSD() - else: - exit("Do not know how to make an installer for this platform") + exit("Do not know how to make an installer for this platform") +finally: + SaveDependencyCache() ########################################################################################## # @@ -6620,8 +6673,6 @@ if (INSTALLER != 0): # ########################################################################################## -SaveDependencyCache() - WARNINGS.append("Elapsed Time: "+PrettyTime(time.time() - STARTTIME)) printStatus("Makepanda Final Status Report", WARNINGS)