diff --git a/Engine/source/T3D/assets/SoundAsset.cpp b/Engine/source/T3D/assets/SoundAsset.cpp index f4882c50f..e8b6d3cdb 100644 --- a/Engine/source/T3D/assets/SoundAsset.cpp +++ b/Engine/source/T3D/assets/SoundAsset.cpp @@ -189,12 +189,6 @@ SoundAsset::SoundAsset() SoundAsset::~SoundAsset() { - - for (U32 i = 0; i < SFXPlayList::NUM_SLOTS; i++) - { - if(mSFXProfile[i].isProperlyAdded() && !mSFXProfile[i].isDeleted()) - mSFXProfile[i].unregisterObject(); - } if (mPlaylist.isProperlyAdded() && !mPlaylist.isDeleted()) mPlaylist.unregisterObject(); @@ -404,22 +398,17 @@ U32 SoundAsset::load() { Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[i]); mLoadedState = BadFileReference; - mSFXProfile[i].setDescription(NULL); - mSFXProfile[i].setSoundFileName(StringTable->insert(StringTable->EmptyString())); - mSFXProfile[i].setPreload(false); return mLoadedState; } else { - SFXProfile* trackProfile = new SFXProfile(); - trackProfile->setDescription(&mProfileDesc); - trackProfile->setSoundFileName(mSoundPath[i]); - trackProfile->setPreload(mPreload); + mSFXProfile[i] = new SFXProfile; + mSFXProfile[i]->setDescription(&mProfileDesc); + mSFXProfile[i]->setSoundFileName(mSoundPath[i]); + mSFXProfile[i]->setPreload(mPreload); + mSFXProfile[i]->registerObject(String::ToString("%s_profile_track%d", getAssetName()).c_str()); - mSFXProfile[i] = *trackProfile; - mSFXProfile[i].registerObject(String::ToString("%s_profile_track%d", getAssetName()).c_str()); - - mPlaylist.mSlots.mTrack[i] = trackProfile; + mPlaylist.mSlots.mTrack[i] = mSFXProfile[i]; } } @@ -436,18 +425,15 @@ U32 SoundAsset::load() { Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[0]); mLoadedState = BadFileReference; - mSFXProfile[0].setDescription(NULL); - mSFXProfile[0].setSoundFileName(StringTable->insert(StringTable->EmptyString())); - mSFXProfile[0].setPreload(false); return mLoadedState; } else { - mSFXProfile[0].setDescription(&mProfileDesc); - mSFXProfile[0].setSoundFileName(mSoundPath[0]); - mSFXProfile[0].setPreload(mPreload); - - mSFXProfile[0].registerObject(String::ToString("%s_profile", getAssetName()).c_str()); + mSFXProfile[0] = new SFXProfile; + mSFXProfile[0]->setDescription(&mProfileDesc); + mSFXProfile[0]->setSoundFileName(mSoundPath[0]); + mSFXProfile[0]->setPreload(mPreload); + mSFXProfile[0]->registerObject(String::ToString("%s_profile", getAssetName()).c_str()); } } diff --git a/Engine/source/T3D/assets/SoundAsset.h b/Engine/source/T3D/assets/SoundAsset.h index 1def01066..d005ec0c1 100644 --- a/Engine/source/T3D/assets/SoundAsset.h +++ b/Engine/source/T3D/assets/SoundAsset.h @@ -87,9 +87,9 @@ class SoundAsset : public AssetBase typedef AssetPtr ConcreteAssetPtr; protected: - StringTableEntry mSoundFile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; - StringTableEntry mSoundPath[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; - SFXProfile mSFXProfile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; + StringTableEntry mSoundFile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; + StringTableEntry mSoundPath[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; + SimObjectPtr mSFXProfile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; SFXDescription mProfileDesc; SFXPlayList mPlaylist; @@ -150,7 +150,7 @@ public: void copyTo(SimObject* object) override; //SFXResource* getSound() { return mSoundResource; } - Resource getSoundResource(const U32 slotId = 0) { load(); return mSFXProfile[slotId].getResource(); } + Resource getSoundResource(const U32 slotId = 0) { load(); return mSFXProfile[slotId]->getResource(); } /// Declare Console Object. DECLARE_CONOBJECT(SoundAsset); @@ -158,9 +158,9 @@ public: static bool _setSoundFile(void* object, const char* index, const char* data); U32 load() override; inline StringTableEntry getSoundPath(const U32 slotId = 0) const { return mSoundPath[slotId]; }; - SFXProfile* getSfxProfile(const U32 slotId = 0) { return &mSFXProfile[slotId]; } + SFXProfile* getSfxProfile(const U32 slotId = 0) { return mSFXProfile[slotId]; } SFXPlayList* getSfxPlaylist() { return &mPlaylist; } - SFXTrack* getSFXTrack() { load(); return mIsPlaylist ? dynamic_cast(&mPlaylist) : dynamic_cast(&mSFXProfile[0]); } + SFXTrack* getSFXTrack() { load(); return mIsPlaylist ? dynamic_cast(&mPlaylist) : dynamic_cast(mSFXProfile[0].getPointer()); } SFXDescription* getSfxDescription() { return &mProfileDesc; } bool isPlaylist(){ return mIsPlaylist; } diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 7c7830ddc..0ccb13828 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -471,6 +471,7 @@ bool PlayerData::preload(bool server, String &errorStr) if (!server) { for (U32 i = 0; i < MaxSounds; ++i) { + _setPlayerSound(getPlayerSound(i), i); if (!isPlayerSoundValid(i)) { //return false; -TODO: trigger asset download diff --git a/Engine/source/T3D/rigidShape.cpp b/Engine/source/T3D/rigidShape.cpp index 129c0dcf9..4caac7ddb 100644 --- a/Engine/source/T3D/rigidShape.cpp +++ b/Engine/source/T3D/rigidShape.cpp @@ -348,6 +348,7 @@ bool RigidShapeData::preload(bool server, String &errorStr) if (!server) { for (S32 i = 0; i < Body::MaxSounds; i++) { + _setBodySounds(getBodySounds(i), i); if (!isBodySoundsValid(i)) { //return false; -TODO: trigger asset download @@ -356,6 +357,7 @@ bool RigidShapeData::preload(bool server, String &errorStr) for (S32 j = 0; j < Sounds::MaxSounds; j++) { + _setWaterSounds(getWaterSounds(j), j); if (!isWaterSoundsValid(j)) { //return false; -TODO: trigger asset download diff --git a/Engine/source/T3D/vehicles/flyingVehicle.cpp b/Engine/source/T3D/vehicles/flyingVehicle.cpp index 4e10c4b2a..6dfe8d8de 100644 --- a/Engine/source/T3D/vehicles/flyingVehicle.cpp +++ b/Engine/source/T3D/vehicles/flyingVehicle.cpp @@ -141,6 +141,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr) if (!server) { for (S32 i = 0; i < MaxSounds; i++) { + _setFlyingSounds(getFlyingSounds(i), i); if (!isFlyingSoundsValid(i)) { //return false; -TODO: trigger asset download diff --git a/Engine/source/T3D/vehicles/hoverVehicle.cpp b/Engine/source/T3D/vehicles/hoverVehicle.cpp index 60c24434f..43321abc3 100644 --- a/Engine/source/T3D/vehicles/hoverVehicle.cpp +++ b/Engine/source/T3D/vehicles/hoverVehicle.cpp @@ -313,6 +313,7 @@ bool HoverVehicleData::preload(bool server, String &errorStr) for (S32 i = 0; i < MaxSounds; i++) { + _setHoverSounds(getHoverSounds(i), i); if (!isHoverSoundsValid(i)) { //return false; -TODO: trigger asset download diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.cpp b/Engine/source/T3D/vehicles/wheeledVehicle.cpp index 44b8b0623..dec634690 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.cpp +++ b/Engine/source/T3D/vehicles/wheeledVehicle.cpp @@ -348,6 +348,7 @@ bool WheeledVehicleData::preload(bool server, String &errorStr) if (!server) { for (S32 i = 0; i < MaxSounds; i++) { + _setWheeledVehicleSounds(getWheeledVehicleSounds(i), i); if (!isWheeledVehicleSoundsValid(i)) { //return false; -TODO: trigger asset download diff --git a/Engine/source/console/simObject.h b/Engine/source/console/simObject.h index 4868a4585..1ea3a2b5d 100644 --- a/Engine/source/console/simObject.h +++ b/Engine/source/console/simObject.h @@ -40,7 +40,10 @@ #ifndef _TAML_CALLBACKS_H_ #include "persistence/taml/tamlCallbacks.h" #endif + +#ifndef _OBJECTTYPES_H_ #include "T3D/objectTypes.h" +#endif class Stream; class LightManager; @@ -606,6 +609,7 @@ class SimObject: public ConsoleObject, public TamlCallbacks /// @name Events /// @{ + //virtual void onPrepare(); /// Called when the object is added to the sim. virtual bool onAdd(); @@ -1045,56 +1049,47 @@ DefineBitfieldType(GameTypeMasksType); template< typename T > class SimObjectPtr : public WeakRefPtr< T > { - public: +public: - typedef WeakRefPtr< T > Parent; + typedef WeakRefPtr< T > Parent; - SimObjectPtr() {} - SimObjectPtr(T *ptr) { this->mReference = NULL; set(ptr); } - SimObjectPtr( const SimObjectPtr& ref ) { this->mReference = NULL; set(ref.mReference); } + SimObjectPtr() = default; + SimObjectPtr(T* ptr) { set(ptr); } + SimObjectPtr(const SimObjectPtr&) = default; + SimObjectPtr& operator=(const SimObjectPtr&) = default; + SimObjectPtr& operator=(T* ptr) + { + set(ptr); + return *this; + } - T* getObject() const { return Parent::getPointer(); } + T* getObject() const { return Parent::getPointer(); } - ~SimObjectPtr() { set((WeakRefBase::WeakReference*)NULL); } +protected: + void set(T* obj) + { + // Nothing to do if same object + if (obj && this->mWeak.lock() == obj->getWeakControl().lock()) + return; - SimObjectPtr& operator=(const SimObjectPtr ref) + // Before overwriting, check old object for auto-delete + if (auto old_ctrl = this->mWeak.lock()) { - set(ref.mReference); - return *this; - } - SimObjectPtr& operator=(T *ptr) - { - set(ptr); - return *this; - } - - protected: - void set(WeakRefBase::WeakReference * ref) - { - if( ref == this->mReference ) - return; - - if( this->mReference ) + T* old_obj = getObject(); + if (this->mWeak.use_count() == 1 && old_obj && old_obj->isAutoDeleted()) { - // Auto-delete - T* obj = this->getPointer(); - if ( this->mReference->getRefCount() == 2 && obj && obj->isAutoDeleted() ) - obj->deleteObject(); - - this->mReference->decRefCount(); - } - this->mReference = NULL; - if( ref ) - { - this->mReference = ref; - this->mReference->incRefCount(); + old_obj->destroySelf(); } } - void set(T * obj) + // Assign new weak reference + this->mWeak.reset(); + if (obj) { - set(obj ? obj->getWeakReference() : (WeakRefBase::WeakReference *)NULL); + auto obj_ctrl = obj->getWeakControl().lock(); + this->mWeak = obj_ctrl; } + } }; #endif // _SIMOBJECT_H_ diff --git a/Engine/source/core/util/refBase.cpp b/Engine/source/core/util/refBase.cpp new file mode 100644 index 000000000..2f4314742 --- /dev/null +++ b/Engine/source/core/util/refBase.cpp @@ -0,0 +1,18 @@ +#include "refBase.h" + +WeakRefBase::~WeakRefBase() +{ + if (mControl) + mControl->object = NULL; +} + +WeakControlBlock::WeakControlBlock(WeakRefBase* obj) + : object(obj) +{ +} + +WeakControlBlock::~WeakControlBlock() +{ + +} + diff --git a/Engine/source/core/util/refBase.h b/Engine/source/core/util/refBase.h index 42ce6705d..432358604 100644 --- a/Engine/source/core/util/refBase.h +++ b/Engine/source/core/util/refBase.h @@ -30,52 +30,52 @@ # include "platform/typetraits.h" #endif +#include +#include + +class WeakRefBase; + +struct WeakControlBlock +{ + explicit WeakControlBlock(WeakRefBase* obj); + ~WeakControlBlock(); + + WeakRefBase* object; +}; /// Base class for objects which can be weakly referenced /// (i.e., reference goes away when object is destroyed). class WeakRefBase { public: - - /// Weak reference to WeakRefBase. - class WeakReference + WeakRefBase() + : mControl(std::make_shared(this)) { - public: + } - [[nodiscard]] constexpr WeakRefBase* get() const { return mObject; } - [[nodiscard]] constexpr U32 getRefCount() const { return mRefCount; } + virtual ~WeakRefBase(); - constexpr void incRefCount() { mRefCount++; } - constexpr void decRefCount() { - AssertFatal( mRefCount > 0, "WeakReference - decrementing count of zero!" ); - if (--mRefCount==0) - delete this; - } - private: + // Copy constructor + WeakRefBase(const WeakRefBase&) = delete; + WeakRefBase& operator=(const WeakRefBase&) = delete; + WeakRefBase(WeakRefBase&&) = delete; + WeakRefBase& operator=(WeakRefBase&&) = delete; - friend class WeakRefBase; - constexpr explicit WeakReference(WeakRefBase *object) :mObject(object), mRefCount(0) {} + std::weak_ptr getWeakControl() + { + return mControl; + } - ~WeakReference() { AssertFatal(mObject==NULL, "Deleting weak reference which still points at an object."); } - - // Object we reference - WeakRefBase *mObject; - - // reference count for this structure (not WeakObjectRef itself) - U32 mRefCount; - }; - -public: - constexpr WeakRefBase() : mReference(NULL) {} - virtual ~WeakRefBase() { clearWeakReferences(); } - - WeakReference* getWeakReference(); + std::shared_ptr getSharedControl() + { + return mControl; + } protected: - void clearWeakReferences(); + std::shared_ptr mControl; private: - WeakReference * mReference; + }; template< typename T > class SimObjectPtr; @@ -88,100 +88,48 @@ template< typename T > class SimObjectPtr; template class WeakRefPtr { public: - constexpr WeakRefPtr() : mReference(NULL) {} - WeakRefPtr(T *ptr) : mReference(NULL) { set(ptr); } - WeakRefPtr(const WeakRefPtr & ref) { mReference = NULL; set(ref.mReference); } - - ~WeakRefPtr() { set(static_cast(NULL)); } + WeakRefPtr() = default; + WeakRefPtr(T* obj) { set(obj); } - WeakRefPtr& operator=(const WeakRefPtr& ref) - { - if (this == &ref) { return *this; } // handle self assignment ( x = x; ) - set(ref.mReference); - return *this; - } - WeakRefPtr& operator=(T *ptr) - { - set(ptr); - return *this; - } + WeakRefPtr(const WeakRefPtr&) = default; + WeakRefPtr& operator=(const WeakRefPtr&) = default; - /// Returns true if the pointer is not set. - [[nodiscard]] constexpr bool isNull() const { return mReference == NULL || mReference->get() == NULL; } - - /// Returns true if the pointer is set. - [[nodiscard]] constexpr bool isValid() const { return mReference && mReference->get(); } + WeakRefPtr& operator=(T* obj) + { + set(obj); + return *this; + } + + bool isValid() const { return getPointer() != NULL; } + bool isNull() const { return getPointer() == NULL; } [[nodiscard]] constexpr T* operator->() const { return getPointer(); } [[nodiscard]] constexpr T& operator*() const { return *getPointer(); } [[nodiscard]] constexpr operator T*() const { return getPointer(); } /// Returns the pointer. - [[nodiscard]] constexpr T* getPointer() const { return mReference ? (T*)mReference->get() : NULL; } + [[nodiscard]] constexpr T* getPointer() const + { + auto ctrl = mWeak.lock(); + if (!ctrl || !ctrl->object) + return NULL; + return (T*)(ctrl->object); + } protected: - void set(WeakRefBase::WeakReference* ref) - { - if (mReference) - mReference->decRefCount(); - mReference = NULL; - if (ref) + void set(T* obj) + { + if (!obj) { - mReference = ref; - mReference->incRefCount(); + mWeak.reset(); + return; } - } - void set(T* obj) { set(obj ? obj->getWeakReference() : NULL); } + mWeak = obj->getWeakControl(); + } private: template< typename > friend class SimObjectPtr; - WeakRefBase::WeakReference * mReference {NULL}; -}; - -/// Union of an arbitrary type with a WeakRefBase. The exposed type will -/// remain accessible so long as the WeakRefBase is not cleared. Once -/// it is cleared, accessing the exposed type will result in a NULL pointer. -template -class WeakRefUnion -{ - typedef WeakRefUnion Union; - -public: - constexpr WeakRefUnion() : mPtr(NULL) {} - constexpr WeakRefUnion(const WeakRefPtr & ref, ExposedType * ptr) : mPtr(NULL) { set(ref, ptr); } - constexpr WeakRefUnion(const Union & lock) : mPtr(NULL) { *this = lock; } - constexpr WeakRefUnion(WeakRefBase * ref) : mPtr(NULL) { set(ref, dynamic_cast(ref)); } - ~WeakRefUnion() { mWeakReference = NULL; } - - Union & operator=(const Union & ptr) - { - if (this == *ptr) { return *this; } - set(ptr.mWeakReference, ptr.getPointer()); - return *this; - } - - void set(const WeakRefPtr & ref, ExposedType * ptr) - { - mWeakReference = ref; - mPtr = ptr; - } - - [[nodiscard]] constexpr bool operator == (const ExposedType * t ) const { return getPointer() == t; } - [[nodiscard]] constexpr bool operator != (const ExposedType * t ) const { return getPointer() != t; } - [[nodiscard]] constexpr bool operator == (const Union &t ) const { return getPointer() == t.getPointer(); } - [[nodiscard]] constexpr bool operator != (const Union &t ) const { return getPointer() != t.getPointer(); } - [[nodiscard]] constexpr bool isNull() const { return mWeakReference.isNull() || !mPtr; } - - [[nodiscard]] constexpr ExposedType* getPointer() const { return !mWeakReference.isNull() ? mPtr : NULL; } - [[nodiscard]] constexpr ExposedType* operator->() const { return getPointer(); } - [[nodiscard]] constexpr ExposedType& operator*() const { return *getPointer(); } - [[nodiscard]] constexpr operator ExposedType*() const { return getPointer(); } - - [[nodiscard]] WeakRefPtr getRef() const { return mWeakReference; } - -private: - WeakRefPtr mWeakReference; - ExposedType * mPtr; + std::weak_ptr mWeak; }; /// Base class for objects which can be strongly referenced @@ -189,34 +137,40 @@ private: /// when all strong references go away, object is destroyed). class StrongRefBase : public WeakRefBase { - friend class StrongObjectRef; + friend class StrongObjectRef; public: - StrongRefBase() { mRefCount = 0; } + StrongRefBase() + { + mRefCount = 0; + } - U32 getRefCount() const { return mRefCount; } + virtual ~StrongRefBase() = default; - /// object destroy self call (from StrongRefPtr). Override if this class has specially allocated memory. - virtual void destroySelf() { delete this; } + U32 getRefCount() const { return mRefCount; } - /// Increments the reference count. - void incRefCount() - { - mRefCount++; - } + /// object destroy self call (from StrongRefPtr). Override if this class has specially allocated memory. + virtual void destroySelf() { delete this; } - /// Decrements the reference count. - void decRefCount() - { - AssertFatal(mRefCount, "Decrementing a reference with refcount 0!"); - if(!--mRefCount) - destroySelf(); - } + /// Increments the reference count. + void incRefCount() + { + mRefCount++; + } + + /// Decrements the reference count. + void decRefCount() + { + AssertFatal(mRefCount, "Decrementing a reference with refcount 0!"); + if (!--mRefCount) + destroySelf(); + } protected: - U32 mRefCount; ///< reference counter for StrongRefPtr objects + U32 mRefCount; ///< reference counter for StrongRefPtr objects }; + /// Base class for StrongRefBase strong reference pointers. class StrongObjectRef { @@ -289,55 +243,6 @@ public: T* getPointer() const { return const_cast(static_cast(mObject)); } }; -/// Union of an arbitrary type with a StrongRefBase. StrongRefBase will remain locked -/// until the union is destructed. Handy for when the exposed class will -/// become invalid whenever the reference becomes invalid and you want to make sure that doesn't -/// happen. -template -class StrongRefUnion -{ - typedef StrongRefUnion Union; - -public: - StrongRefUnion() : mPtr(NULL) {} - - StrongRefUnion(const StrongRefPtr & ref, ExposedType * ptr) : mPtr(NULL) { set(ref, ptr); } - StrongRefUnion(const Union & lock) : mPtr(NULL) { *this = lock; } - StrongRefUnion(StrongRefBase * ref) : mPtr(NULL) { set(ref, dynamic_cast(ref)); } - - ~StrongRefUnion() { mReference = NULL; } - - Union & operator=(const Union & ptr) - { - set(ptr.mReference, ptr.mPtr); - return *this; - } - - void set(const StrongRefPtr & ref, ExposedType * ptr) - { - mReference = ref; - mPtr = ptr; - } - - [[nodiscard]] constexpr bool operator == (const ExposedType * t ) const { return mPtr == t; } - [[nodiscard]] constexpr bool operator != (const ExposedType * t ) const { return mPtr != t; } - [[nodiscard]] constexpr bool operator == (const Union &t ) const { return mPtr == t.mPtr; } - [[nodiscard]] constexpr bool operator != (const Union &t ) const { return mPtr != t.mPtr; } - [[nodiscard]] constexpr bool isNull() const { return mReference.isNull() || !mPtr; } - [[nodiscard]] constexpr bool isValid() const { return mReference.isValid() && mPtr; } - - ExposedType* operator->() const { return mPtr; } - ExposedType& operator*() const { return *mPtr; } - operator ExposedType*() const { return mPtr; } - ExposedType* getPointer() const { return mPtr; } - - StrongRefPtr getRef() const { return mReference; } - -private: - StrongRefPtr mReference; - ExposedType * mPtr; -}; - /// This oxymoron is a pointer that reference-counts the referenced /// object but also NULLs out if the object goes away. /// @@ -347,97 +252,91 @@ private: /// StrongWeakRefs that keep object live as long as the superior entity doesn't /// step in and kill them (in which case, the client code sees the reference /// disappear). -template< class T > +template class StrongWeakRefPtr { public: - constexpr StrongWeakRefPtr() : mReference( NULL ) {} - constexpr StrongWeakRefPtr( T* ptr ) : mReference( NULL ) { _set( ptr ); } - ~StrongWeakRefPtr() - { - if( mReference ) - { - T* ptr = _get(); - if( ptr ) - ptr->decRefCount(); + StrongWeakRefPtr() = default; - mReference->decRefCount(); - } + StrongWeakRefPtr(T* ptr) { set(ptr); } + + StrongWeakRefPtr(const StrongWeakRefPtr& other) + { + set(other.getPointer()); } - [[nodiscard]] constexpr bool isNull() const { return ( _get() == NULL ); } - [[nodiscard]] constexpr bool operator ==( T* ptr ) const { return ( _get() == ptr ); } - [[nodiscard]] constexpr bool operator !=( T* ptr ) const { return ( _get() != ptr ); } - [[nodiscard]] constexpr bool operator !() const { return isNull(); } - [[nodiscard]] constexpr T* operator ->() const { return _get(); } - [[nodiscard]] constexpr T& operator *() const { return *( _get() ); } - - constexpr operator T*() const { return _get(); } // consider making this explicit - - T* getPointer() const { return _get(); } - - StrongWeakRefPtr& operator =( T* ptr ) + StrongWeakRefPtr& operator=(const StrongWeakRefPtr& other) { - _set( ptr ); + if (this != &other) + set(other.getPointer()); return *this; } -private: - WeakRefBase::WeakReference* mReference; - - T* _get() const + ~StrongWeakRefPtr() { - if( mReference ) - return static_cast< T* >( mReference->get() ); - else - return NULL; + release(); } - void _set( T* ptr ) + + StrongWeakRefPtr& operator=(T* ptr) + { + set(ptr); + return *this; + } + + bool isValid() const { return getPointer() != NULL; } + bool isNull() const { return getPointer() == NULL; } + [[nodiscard]] bool operator==(T* ptr) const { return getPointer() == ptr; } + [[nodiscard]] bool operator!=(T* ptr) const { return getPointer() != ptr; } + [[nodiscard]] bool operator!() const { return isNull(); } + + [[nodiscard]] T* operator->() const { return getPointer(); } + [[nodiscard]] T& operator*() const { return *getPointer(); } + constexpr operator T* () const { return getPointer(); } + + [[nodiscard]] T* getPointer() const { - if( mReference ) - { - T* old = _get(); - if( old ) - old->decRefCount(); + return mControl ? static_cast(mControl->object) : NULL; + } - mReference->decRefCount(); + +private: + std::shared_ptr mControl; + T* mPtr = NULL; + + void set(T* ptr) + { + release(); + if (!ptr) return; + + // Always hold the identity + mControl = ptr->getWeakControl().lock(); + if (!mControl) return; + + mPtr = ptr; + + // Conditionally retain object lifetime if T supports intrusive refcount + // runtime check: only strong ref if T inherits StrongRefBase + if constexpr (std::is_base_of_v) + { + mPtr->incRefCount(); + } + } + + void release() + { + if (mPtr) + { + if constexpr (std::is_base_of_v) + { + mPtr->decRefCount(); + } } - if( ptr ) - { - ptr->incRefCount(); - mReference = ptr->getWeakReference(); - mReference->incRefCount(); - } - else - mReference = NULL; + mPtr = NULL; + mControl.reset(); } }; -//--------------------------------------------------------------- - -inline void WeakRefBase::clearWeakReferences() -{ - if (mReference) - { - mReference->mObject = NULL; - mReference->decRefCount(); - mReference = NULL; - } -} - -inline WeakRefBase::WeakReference* WeakRefBase::getWeakReference() -{ - if (!mReference) - { - mReference = new WeakReference(this); - mReference->incRefCount(); - } - return mReference; -} - -//--------------------------------------------------------------- - template< typename T > struct TypeTraits< WeakRefPtr< T > > : public _TypeTraits< WeakRefPtr< T > > { diff --git a/Engine/source/environment/scatterSky.cpp b/Engine/source/environment/scatterSky.cpp index 40d0e5137..394b9769b 100644 --- a/Engine/source/environment/scatterSky.cpp +++ b/Engine/source/environment/scatterSky.cpp @@ -1094,7 +1094,7 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat } else { - GFX->setCubeTexture( 0, NULL ); + GFX->setTexture( 0, NULL ); mShaderConsts->setSafe( mUseCubemapSC, 0.0f ); } diff --git a/Engine/source/gfx/bitmap/loaders/bitmapPng.cpp b/Engine/source/gfx/bitmap/loaders/bitmapPng.cpp index 60a5e5965..83b60edfb 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapPng.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapPng.cpp @@ -41,15 +41,16 @@ #endif -static bool sReadPNG(const Torque::Path& path, GBitmap* bitmap); -static bool sReadStreamPNG(Stream& stream, GBitmap* bitmap, U32 len); - /// Compression levels for PNGs range from 0-9. /// A value outside that range will cause the write routine to look for the best compression for a given PNG. This can be slow. - +static bool sReadPNG(const Torque::Path& path, GBitmap* bitmap); +static bool sReadStreamPNG(Stream& stream, GBitmap* bitmap, U32 len); static bool sWritePNG(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel); static bool sWriteStreamPNG(const String& bmType, Stream& stream, GBitmap* bitmap, U32 compressionLevel); -static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter); + +// Internal functions used. +static bool _readStreamPNG(Stream& stream, GBitmap* bitmap, U32 len, const char* filename); +static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter, const char* filename = "unknown"); static struct _privateRegisterPNG { @@ -72,425 +73,394 @@ static struct _privateRegisterPNG } } sStaticRegisterPNG; - -//-------------------------------------- Replacement I/O for standard LIBPng -// functions. we don't wanna use -// FILE*'s... -static void pngReadDataFn(png_structp png_ptr, - png_bytep data, - png_size_t length) +//----------------------------------------------------------------------------- +// PNG context passed to libpng for error reporting +//----------------------------------------------------------------------------- +struct PngContext { - AssertFatal(png_get_io_ptr(png_ptr) != NULL, "No stream?"); + const char* filename; + explicit PngContext(const char* f) : filename(f) {} +}; - Stream *strm = (Stream*)png_get_io_ptr(png_ptr); - bool success = strm->read(length, data); - AssertFatal(success, "pngReadDataFn - failed to read from stream!"); +//----------------------------------------------------------------------------- +// libpng callbacks +//----------------------------------------------------------------------------- +static void pngReadDataFn(png_structp png_ptr, png_bytep data, png_size_t length) +{ + Stream* strm = (Stream*)png_get_io_ptr(png_ptr); + AssertFatal(strm, "pngReadDataFn - No stream."); + if (!strm->read(length, data)) + Con::errorf("pngReadDataFn - Failed to read %u bytes from stream.", (U32)length); } - -//-------------------------------------- -static void pngWriteDataFn(png_structp png_ptr, - png_bytep data, - png_size_t length) +static void pngWriteDataFn(png_structp png_ptr, png_bytep data, png_size_t length) { - AssertFatal(png_get_io_ptr(png_ptr) != NULL, "No stream?"); - - Stream *strm = (Stream*)png_get_io_ptr(png_ptr); - bool success = strm->write(length, data); - AssertFatal(success, "pngWriteDataFn - failed to write to stream!"); + Stream* strm = (Stream*)png_get_io_ptr(png_ptr); + AssertFatal(strm, "pngWriteDataFn - No stream."); + if (!strm->write(length, data)) + Con::errorf("pngWriteDataFn - Failed to write %u bytes to stream.", (U32)length); } +static void pngFlushDataFn(png_structp /*png_ptr*/) {} -//-------------------------------------- -static void pngFlushDataFn(png_structp /*png_ptr*/) +static png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size) { return FrameAllocator::alloc(size); } +static void pngFreeFn(png_structp /*png_ptr*/, png_voidp /*mem*/) {} + +static png_voidp pngRealMallocFn(png_structp /*png_ptr*/, png_size_t size) { return (png_voidp)dMalloc(size); } +static void pngRealFreeFn(png_structp /*png_ptr*/, png_voidp mem) { dFree(mem); } + +static void pngFatalErrorFn(png_structp png_ptr, png_const_charp pMessage) { - // -} - -static png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size) -{ - return FrameAllocator::alloc(size); -} - -static void pngFreeFn(png_structp /*png_ptr*/, png_voidp /*mem*/) -{ -} - -static png_voidp pngRealMallocFn(png_structp /*png_ptr*/, png_size_t size) -{ - return (png_voidp)dMalloc(size); -} - -static void pngRealFreeFn(png_structp /*png_ptr*/, png_voidp mem) -{ - dFree(mem); -} - -//-------------------------------------- -static void pngFatalErrorFn(png_structp /*png_ptr*/, - png_const_charp pMessage) -{ - AssertISV(false, avar("Error reading PNG file:\n %s", pMessage)); -} - - -//-------------------------------------- -static void pngWarningFn(png_structp, png_const_charp /*pMessage*/) -{ - // AssertWarn(false, avar("Warning reading PNG file:\n %s", pMessage)); -} - - -//-------------------------------------- -bool sReadPNG(const Torque::Path& path, GBitmap* bitmap) -{ - FileStream* readPng = new FileStream; - - if (!readPng->open(path.getFullPath(), Torque::FS::File::Read)) + const char* filename = "unknown"; + if (png_ptr) { - Con::printf("Failed to open PNG :%s", path.getFullFileName().c_str()); - return false; + PngContext* ctx = (PngContext*)png_get_error_ptr(png_ptr); + if (ctx && ctx->filename) + filename = ctx->filename; + } + Con::errorf("pngFatalErrorFn - Fatal error in '%s': %s", filename, pMessage); + AssertISV(false, avar("libpng fatal error in '%s':\n%s", filename, pMessage)); +} + +static void pngWarningFn(png_structp png_ptr, png_const_charp pMessage) +{ +#if TORQUE_DEBUG + const char* filename = "unknown"; + if (png_ptr) + { + PngContext* ctx = (PngContext*)png_get_error_ptr(png_ptr); + if (ctx && ctx->filename) + filename = ctx->filename; + } + Con::warnf("pngWarningFn - Warning in '%s': %s", filename, pMessage); +#endif +} + +//----------------------------------------------------------------------------- +// RAII guards for png read/write structs +//----------------------------------------------------------------------------- +struct PngReadGuard +{ + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; + png_infop end_info = nullptr; + PngContext ctx; + + explicit PngReadGuard(const char* filename) : ctx(filename) {} + + bool init() + { + png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, + &ctx, pngFatalErrorFn, pngWarningFn, + NULL, pngRealMallocFn, pngRealFreeFn); + if (!png_ptr) + { + Con::errorf("PngReadGuard - png_create_read_struct_2 failed for '%s'.", ctx.filename); + return false; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + Con::errorf("PngReadGuard - png_create_info_struct (info) failed for '%s'.", ctx.filename); + return false; + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + Con::errorf("PngReadGuard - png_create_info_struct (end) failed for '%s'.", ctx.filename); + return false; + } + + return true; } - if (!sReadStreamPNG(*readPng, bitmap, U32_MAX)) + ~PngReadGuard() { - Con::printf("Failed to read PNG :%s", path.getFullFileName().c_str()); - return false; + if (png_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); } +}; - readPng->close(); - - return true; -} - -static bool sReadStreamPNG(Stream& stream, GBitmap* bitmap, U32 len) +struct PngWriteGuard { - PROFILE_SCOPE(sReadPNG); - static const U32 cs_headerBytesChecked = 8; + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; + PngContext ctx; - U8 header[cs_headerBytesChecked]; - stream.read(cs_headerBytesChecked, header); + explicit PngWriteGuard(const char* filename) : ctx(filename) {} - bool isPng = png_check_sig(header, cs_headerBytesChecked) != 0; - if (isPng == false) + bool init(bool useFrameAllocator = true) { - AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG"); - return false; + png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, + &ctx, pngFatalErrorFn, pngWarningFn, + NULL, + useFrameAllocator ? pngMallocFn : pngRealMallocFn, + useFrameAllocator ? pngFreeFn : pngRealFreeFn); + if (!png_ptr) + { + Con::errorf("PngWriteGuard - png_create_write_struct_2 failed for '%s'.", ctx.filename); + return false; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + Con::errorf("PngWriteGuard - png_create_info_struct failed for '%s'.", ctx.filename); + return false; + } + + return true; } - U32 prevWaterMark = FrameAllocator::getWaterMark(); - png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, - NULL, - pngFatalErrorFn, - pngWarningFn, - NULL, - pngRealMallocFn, - pngRealFreeFn); - - if (png_ptr == NULL) + ~PngWriteGuard() { - FrameAllocator::setWaterMark(prevWaterMark); - return false; + if (png_ptr) + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); } +}; - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - png_destroy_read_struct(&png_ptr, - (png_infopp)NULL, - (png_infopp)NULL); +//----------------------------------------------------------------------------- +// Shared helpers +//----------------------------------------------------------------------------- +static GFXFormat _determineReadFormat(png_structp png_ptr, png_infop info_ptr, bool& transAlpha) +{ + S32 bit_depth, color_type; + png_uint_32 width, height; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - FrameAllocator::setWaterMark(prevWaterMark); - return false; - } - - png_infop end_info = png_create_info_struct(png_ptr); - if (end_info == NULL) - { - png_destroy_read_struct(&png_ptr, - &info_ptr, - (png_infopp)NULL); - - FrameAllocator::setWaterMark(prevWaterMark); - return false; - } - - png_set_read_fn(png_ptr, &stream, pngReadDataFn); - - // Read off the info on the image. - png_set_sig_bytes(png_ptr, cs_headerBytesChecked); - png_read_info(png_ptr, info_ptr); - - // OK, at this point, if we have reached it ok, then we can reset the - // image to accept the new data... - // - bitmap->deleteImage(); - - png_uint_32 width; - png_uint_32 height; - S32 bit_depth; - S32 color_type; - - png_get_IHDR(png_ptr, info_ptr, - &width, &height, // obv. - &bit_depth, &color_type, // obv. - NULL, // interlace - NULL, // compression_type - NULL); // filter_type - - // First, handle the color transformations. We need this to read in the - // data as RGB or RGBA, _always_, with a maximal channel width of 8 bits. - // - bool transAlpha = false; + transAlpha = false; GFXFormat format = GFXFormatR8G8B8; - // Strip off any 16 bit info - // - if (bit_depth == 16 && color_type != PNG_COLOR_TYPE_GRAY) - { + if (bit_depth == 16 && color_type != PNG_COLOR_TYPE_GRAY) png_set_strip_16(png_ptr); - } - // Expand a transparency channel into a full alpha channel... - // - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); transAlpha = true; } - if (color_type == PNG_COLOR_TYPE_PALETTE) + switch (color_type) { + case PNG_COLOR_TYPE_PALETTE: png_set_expand(png_ptr); format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8; - } - else if (color_type == PNG_COLOR_TYPE_GRAY) - { + break; + case PNG_COLOR_TYPE_GRAY: png_set_expand(png_ptr); - - if (bit_depth == 16) - format = GFXFormatR5G6B5; - else - format = GFXFormatA8; - } - else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { + format = (bit_depth == 16) ? GFXFormatR5G6B5 : GFXFormatA8; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); format = GFXFormatR8G8B8A8; - } - else if (color_type == PNG_COLOR_TYPE_RGB) - { - format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8; + break; + case PNG_COLOR_TYPE_RGB: png_set_expand(png_ptr); - } - else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { + format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: png_set_expand(png_ptr); format = GFXFormatR8G8B8A8; + break; + default: + Con::errorf("_determineReadFormat - Unrecognised color_type %d.", color_type); + break; } - // Update the info pointer with the result of the transformations - // above... - png_read_update_info(png_ptr, info_ptr); + return format; +} - png_uint_32 rowBytes = png_get_rowbytes(png_ptr, info_ptr); - if (format == GFXFormatR8G8B8) +static bool _validateRowBytes(const char* filename, GFXFormat format, U32 rowBytes, U32 width) +{ + const U32 expected = + (format == GFXFormatR8G8B8) ? width * 3 : + (format == GFXFormatR8G8B8A8) ? width * 4 : + (format == GFXFormatR5G6B5) ? width * 2 : 0; + + if (expected && rowBytes != expected) { - AssertFatal(rowBytes == width * 3, - "Error, our rowbytes are incorrect for this transform... (3)"); + Con::errorf("_validateRowBytes - '%s': rowBytes %d != expected %d for format %d.", + filename, rowBytes, expected, format); + return false; } - else if (format == GFXFormatR8G8B8A8) + return true; +} + +static void _applyWriteIHDR(png_structp png_ptr, png_infop info_ptr, GFXFormat format, U32 width, U32 height) +{ + switch (format) { - AssertFatal(rowBytes == width * 4, - "Error, our rowbytes are incorrect for this transform... (4)"); + case GFXFormatR8G8B8: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + PNG_COLOR_TYPE_RGB, NULL, NULL, NULL); + break; + case GFXFormatR8G8B8A8: + case GFXFormatR8G8B8X8: + case GFXFormatR8G8B8A8_LINEAR_FORCE: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + PNG_COLOR_TYPE_RGB_ALPHA, NULL, NULL, NULL); + break; + case GFXFormatA8: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + PNG_COLOR_TYPE_GRAY, NULL, NULL, NULL); + break; + case GFXFormatR5G6B5: + { + png_set_IHDR(png_ptr, info_ptr, width, height, 16, + PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + png_color_8_struct sigBit = { 0 }; + sigBit.gray = 16; + png_set_sBIT(png_ptr, info_ptr, &sigBit); + png_set_swap(png_ptr); + break; } - else if (format == GFXFormatR5G6B5) + default: + break; + } +} + +static bool _isSupportedWriteFormat(GFXFormat format) +{ + switch (format) { - AssertFatal(rowBytes == width * 2, - "Error, our rowbytes are incorrect for this transform... (2)"); + case GFXFormatR8G8B8: + case GFXFormatR8G8B8A8: + case GFXFormatR8G8B8X8: + case GFXFormatR8G8B8A8_LINEAR_FORCE: + case GFXFormatA8: + case GFXFormatR5G6B5: + return true; + default: + return false; + } +} + +//----------------------------------------------------------------------------- +// Core read / write +//----------------------------------------------------------------------------- +static bool _readStreamPNG(Stream& stream, GBitmap* bitmap, U32 /*len*/, const char* filename = "unknown") +{ + PROFILE_SCOPE(sReadPNG); + + static const U32 cs_headerBytesChecked = 8; + U8 header[cs_headerBytesChecked]; + stream.read(cs_headerBytesChecked, header); + + if (!png_check_sig(header, cs_headerBytesChecked)) + { + Con::errorf("_readStreamPNG - '%s' does not have a valid PNG signature.", filename); + return false; } - // actually allocate the bitmap space... - bitmap->allocateBitmap(width, height, - false, // don't extrude miplevels... - format); // use determined format... + U32 prevWaterMark = FrameAllocator::getWaterMark(); - // Set up the row pointers... - png_bytep* rowPointers = new png_bytep[ height ]; + PngReadGuard guard(filename); + if (!guard.init()) + { + FrameAllocator::setWaterMark(prevWaterMark); + return false; + } + + png_set_read_fn(guard.png_ptr, &stream, pngReadDataFn); + png_set_sig_bytes(guard.png_ptr, cs_headerBytesChecked); + png_read_info(guard.png_ptr, guard.info_ptr); + + bool transAlpha = false; + GFXFormat format = _determineReadFormat(guard.png_ptr, guard.info_ptr, transAlpha); + + png_uint_32 number_of_passes = png_set_interlace_handling(guard.png_ptr); + png_read_update_info(guard.png_ptr, guard.info_ptr); + + png_uint_32 width = png_get_image_width(guard.png_ptr, guard.info_ptr); + png_uint_32 height = png_get_image_height(guard.png_ptr, guard.info_ptr); + png_uint_32 rowBytes = png_get_rowbytes(guard.png_ptr, guard.info_ptr); + + if (!_validateRowBytes(filename, format, rowBytes, width)) + { + FrameAllocator::setWaterMark(prevWaterMark); + return false; + } + + bitmap->deleteImage(); + bitmap->allocateBitmap(width, height, false, format); + + png_bytep* rowPointers = new png_bytep[height]; U8* pBase = (U8*)bitmap->getBits(); - for (U32 i = 0; i < height; i++) rowPointers[i] = pBase + (i * rowBytes); - // And actually read the image! - png_read_image(png_ptr, rowPointers); + png_read_image(guard.png_ptr, rowPointers); + delete[] rowPointers; - // We're outta here, destroy the png structs, and release the lock - // as quickly as possible... - //png_read_end(png_ptr, end_info); - delete [] rowPointers; - png_read_end(png_ptr, NULL); - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + png_read_end(guard.png_ptr, NULL); - // Ok, the image is read in, now we need to finish up the initialization, - // which means: setting up the detailing members, init'ing the palette - // key, etc... - // - // actually, all of that was handled by allocateBitmap, so we're outta here - // - - // Check this bitmap for transparency bitmap->checkForTransparency(); - FrameAllocator::setWaterMark(prevWaterMark); - return true; } -//-------------------------------------------------------------------------- -static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter) +static bool _writePNG(GBitmap* bitmap, Stream& stream, U32 compressionLevel, U32 strategy, U32 filter, const char* filename) { - GFXFormat format = bitmap->getFormat(); + GFXFormat format = bitmap->getFormat(); - // ONLY RGB bitmap writing supported at this time! - AssertFatal( format == GFXFormatR8G8B8 || - format == GFXFormatR8G8B8A8 || - format == GFXFormatR8G8B8X8 || - format == GFXFormatA8 || - format == GFXFormatR5G6B5 || - format == GFXFormatR8G8B8A8_LINEAR_FORCE, "_writePNG: ONLY RGB bitmap writing supported at this time."); - - if ( format != GFXFormatR8G8B8 && - format != GFXFormatR8G8B8A8 && - format != GFXFormatR8G8B8X8 && - format != GFXFormatA8 && - format != GFXFormatR5G6B5 && format != GFXFormatR8G8B8A8_LINEAR_FORCE) - return false; - - png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, - NULL, - pngFatalErrorFn, - pngWarningFn, - NULL, - pngMallocFn, - pngFreeFn); - if (png_ptr == NULL) - return (false); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) + if (!_isSupportedWriteFormat(format)) { - png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + Con::errorf("_writePNG - '%s': Unsupported format %d.", filename, format); return false; } - png_set_write_fn(png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); + PngWriteGuard guard(filename); + if (!guard.init(true)) + return false; - // Set the compression level and image filters - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_level(png_ptr, compressionLevel); - png_set_filter(png_ptr, 0, filter); + png_set_write_fn(guard.png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); + png_set_compression_window_bits(guard.png_ptr, 15); + png_set_compression_level(guard.png_ptr, compressionLevel); + png_set_filter(guard.png_ptr, 0, filter); - // Set the image information here. Width and height are up to 2^31, - // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on - // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, - // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, - // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or - // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST - // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + _applyWriteIHDR(guard.png_ptr, guard.info_ptr, format, bitmap->getWidth(), bitmap->getHeight()); + png_write_info(guard.png_ptr, guard.info_ptr); - U32 width = bitmap->getWidth(); - U32 height = bitmap->getHeight(); - - if (format == GFXFormatR8G8B8) - { - png_set_IHDR(png_ptr, info_ptr, - width, height, // the width & height - 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type, - NULL, // no interlace - NULL, // compression type - NULL); // filter type - } - else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8 || format == GFXFormatR8G8B8A8_LINEAR_FORCE) - { - png_set_IHDR(png_ptr, info_ptr, - width, height, // the width & height - 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type, - NULL, // no interlace - NULL, // compression type - NULL); // filter type - } - else if (format == GFXFormatA8) - { - png_set_IHDR(png_ptr, info_ptr, - width, height, // the width & height - 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, - NULL, // no interlace - NULL, // compression type - NULL); // filter type - } - else if (format == GFXFormatR5G6B5) - { - png_set_IHDR(png_ptr, info_ptr, - width, height, // the width & height - 16, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, - PNG_INTERLACE_NONE, // no interlace - PNG_COMPRESSION_TYPE_DEFAULT, // compression type - PNG_FILTER_TYPE_DEFAULT); // filter type - - png_color_8_struct sigBit = { 0 }; - sigBit.gray = 16; - png_set_sBIT(png_ptr, info_ptr, &sigBit ); - - png_set_swap( png_ptr ); - } - - png_write_info(png_ptr, info_ptr); FrameAllocatorMarker marker; - png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) ); - for (U32 i=0; i(bitmap->getAddress(0, i)); - - png_write_image(png_ptr, row_pointers); - - // Write S3TC data if present... - // Write FXT1 data if present... - - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + const U32 height = bitmap->getHeight(); + png_bytep* rowPointers = (png_bytep*)marker.alloc(height * sizeof(png_bytep)); + for (U32 i = 0; i < height; i++) + rowPointers[i] = const_cast(bitmap->getAddress(0, i)); + png_write_image(guard.png_ptr, rowPointers); + png_write_end(guard.png_ptr, guard.info_ptr); return true; } - -//-------------------------------------------------------------------------- -bool sWritePNG(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel) +//----------------------------------------------------------------------------- +// Public interface +//----------------------------------------------------------------------------- +static bool sReadPNG(const Torque::Path& path, GBitmap* bitmap) { - FileStream* writePng = new FileStream; - - if (!writePng->open(path.getFullPath(), Torque::FS::File::Write)) + FileStream readPng; + if (!readPng.open(path.getFullPath(), Torque::FS::File::Read)) { - Con::printf("Failed to open PNG :%s", path.getFullFileName().c_str()); + Con::errorf("sReadPNG - Failed to open '%s'.", path.getFullPath().c_str()); return false; } - if (!sWriteStreamPNG("png", *writePng, bitmap, compressionLevel)) - { - Con::printf("Failed to write PNG :%s", path.getFullFileName().c_str()); - return false; - } + bool result = _readStreamPNG(readPng, bitmap, U32_MAX, path.getFullPath().c_str()); + if (!result) + Con::errorf("sReadPNG - Failed to decode '%s'.", path.getFullPath().c_str()); - writePng->close(); - - return true; + readPng.close(); + return result; } -static bool sWriteStreamPNG(const String& bmType, Stream& stream, GBitmap* bitmap, U32 compressionLevel) +static bool sWriteStreamPNG(const String& /*bmType*/, Stream& stream, GBitmap* bitmap, U32 compressionLevel) { U32 waterMark = FrameAllocator::getWaterMark(); - if ( compressionLevel < 10 ) + if (compressionLevel < 10) { bool retVal = _writePNG(bitmap, stream, compressionLevel, 0, PNG_ALL_FILTERS); FrameAllocator::setWaterMark(waterMark); @@ -501,195 +471,144 @@ static bool sWriteStreamPNG(const String& bmType, Stream& stream, GBitmap* bitma U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough... MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true); - const U32 zStrategies[] = { Z_DEFAULT_STRATEGY, - Z_FILTERED }; - const U32 pngFilters[] = { PNG_FILTER_NONE, - PNG_FILTER_SUB, - PNG_FILTER_UP, - PNG_FILTER_AVG, - PNG_FILTER_PAETH, - PNG_ALL_FILTERS }; + const U32 zStrategies[] = { Z_DEFAULT_STRATEGY, Z_FILTERED }; + const U32 pngFilters[] = { PNG_FILTER_NONE, PNG_FILTER_SUB, PNG_FILTER_UP, + PNG_FILTER_AVG, PNG_FILTER_PAETH, PNG_ALL_FILTERS }; - U32 minSize = 0xFFFFFFFF; - U32 bestStrategy = 0xFFFFFFFF; - U32 bestFilter = 0xFFFFFFFF; - U32 bestCLevel = 0xFFFFFFFF; + U32 minSize = U32_MAX, bestCLevel = 0, bestStrategy = 0, bestFilter = 0; - for (U32 cl = 0; cl <=9; cl++) + for (U32 cl = 0; cl <= 9; cl++) { - for (U32 zs = 0; zs < 2; zs++) + for (U32 zs = 0; zs < 2; zs++) { - for (U32 pf = 0; pf < 6; pf++) + for (U32 pf = 0; pf < 6; pf++) { pMemStream->setPosition(0); - U32 waterMarkInner = FrameAllocator::getWaterMark(); - if (_writePNG(bitmap, *pMemStream, cl, zStrategies[zs], pngFilters[pf]) == false) - AssertFatal(false, "Handle this error!"); + if (!_writePNG(bitmap, *pMemStream, cl, zStrategies[zs], pngFilters[pf])) + { + Con::errorf("sWriteStreamPNG - Compression search failed at cl=%d zs=%d pf=%d.", cl, zs, pf); + FrameAllocator::setWaterMark(waterMarkInner); + continue; + } FrameAllocator::setWaterMark(waterMarkInner); - if (pMemStream->getPosition() < minSize) + if (pMemStream->getPosition() < minSize) { minSize = pMemStream->getPosition(); - bestStrategy = zs; - bestFilter = pf; - bestCLevel = cl; + bestCLevel = cl; bestStrategy = zs; bestFilter = pf; } } } } - AssertFatal(minSize != 0xFFFFFFFF, "Error, no best found?"); delete pMemStream; - delete [] buffer; + delete[] buffer; + if (minSize == U32_MAX) + { + Con::errorf("sWriteStreamPNG - No valid compression result found."); + FrameAllocator::setWaterMark(waterMark); + return false; + } - bool retVal = _writePNG(bitmap, stream, - bestCLevel, - zStrategies[bestStrategy], - pngFilters[bestFilter]); + bool retVal = _writePNG(bitmap, stream, bestCLevel, zStrategies[bestStrategy], pngFilters[bestFilter]); FrameAllocator::setWaterMark(waterMark); - return retVal; } -//-------------------------------------------------------------------------- -// Stores PNG stream data -struct DeferredPNGWriterData { - png_structp png_ptr; - png_infop info_ptr; - U32 width; - U32 height; -}; -DeferredPNGWriter::DeferredPNGWriter() : - mData( NULL ), - mActive(false) +static bool sWritePNG(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel) { - mData = new DeferredPNGWriterData(); + FileStream writePng; + if (!writePng.open(path.getFullPath(), Torque::FS::File::Write)) + { + Con::errorf("sWritePNG - Failed to open '%s' for writing.", path.getFullPath().c_str()); + return false; + } + + bool retVal = sWriteStreamPNG("png", writePng, bitmap, compressionLevel); + if (!retVal) + Con::errorf("sWritePNG - Failed to encode '%s'. Format: %d, Size: %dx%d.", + path.getFullPath().c_str(), bitmap->getFormat(), bitmap->getWidth(), bitmap->getHeight()); + + writePng.close(); + return retVal; } + +static bool sReadStreamPNG(Stream& stream, GBitmap* bitmap, U32 len) +{ + return _readStreamPNG(stream, bitmap, len, "unknown (stream only)"); +} + +//----------------------------------------------------------------------------- +// DeferredPNGWriter +//----------------------------------------------------------------------------- +struct DeferredPNGWriterData +{ + PngWriteGuard guard; + U32 width = 0; + U32 height = 0; + + explicit DeferredPNGWriterData(const char* filename) : guard(filename) {} +}; + +DeferredPNGWriter::DeferredPNGWriter() : mData(nullptr), mActive(false) {} + DeferredPNGWriter::~DeferredPNGWriter() { delete mData; } -bool DeferredPNGWriter::begin( GFXFormat format, S32 width, S32 height, Stream &stream, U32 compressionLevel ) -{ - // ONLY RGB bitmap writing supported at this time! - AssertFatal( format == GFXFormatR8G8B8 || - format == GFXFormatR8G8B8A8 || - format == GFXFormatR8G8B8X8 || - format == GFXFormatA8 || - format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time."); - - if ( format != GFXFormatR8G8B8 && - format != GFXFormatR8G8B8A8 && - format != GFXFormatR8G8B8X8 && - format != GFXFormatA8 && - format != GFXFormatR5G6B5 ) - return false; - - mData->png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, - NULL, - pngFatalErrorFn, - pngWarningFn, - NULL, - pngRealMallocFn, - pngRealFreeFn); - if (mData->png_ptr == NULL) - return (false); - - mData->info_ptr = png_create_info_struct(mData->png_ptr); - if (mData->info_ptr == NULL) +bool DeferredPNGWriter::begin(GFXFormat format, S32 width, S32 height, Stream& stream, U32 compressionLevel) +{ + if (!_isSupportedWriteFormat(format)) { - png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL); + Con::errorf("DeferredPNGWriter::begin - Unsupported format %d.", format); return false; } - png_set_write_fn(mData->png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); + mData = new DeferredPNGWriterData("DeferredPNGWriter"); - // Set the compression level and image filters - png_set_compression_window_bits(mData->png_ptr, 15); - png_set_compression_level(mData->png_ptr, compressionLevel); - png_set_filter(mData->png_ptr, 0, PNG_ALL_FILTERS); - - // Set the image information here. Width and height are up to 2^31, - // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on - // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, - // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, - // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or - // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST - // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED - - if (format == GFXFormatR8G8B8) + if (!mData->guard.init(false)) { - png_set_IHDR(mData->png_ptr, mData->info_ptr, - width, height, // the width & height - 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type, - NULL, // no interlace - NULL, // compression type - NULL); // filter type - } - else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8) - { - png_set_IHDR(mData->png_ptr, mData->info_ptr, - width, height, // the width & height - 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type, - NULL, // no interlace - NULL, // compression type - NULL); // filter type - } - else if (format == GFXFormatA8) - { - png_set_IHDR(mData->png_ptr, mData->info_ptr, - width, height, // the width & height - 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, - NULL, // no interlace - NULL, // compression type - NULL); // filter type - } - else if (format == GFXFormatR5G6B5) - { - png_set_IHDR(mData->png_ptr, mData->info_ptr, - width, height, // the width & height - 16, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, - PNG_INTERLACE_NONE, // no interlace - PNG_COMPRESSION_TYPE_DEFAULT, // compression type - PNG_FILTER_TYPE_DEFAULT); // filter type - - png_color_8_struct sigBit = { 0 }; - sigBit.gray = 16; - png_set_sBIT(mData->png_ptr, mData->info_ptr, &sigBit ); - - png_set_swap( mData->png_ptr ); + Con::errorf("DeferredPNGWriter::begin - Failed to init PNG write structs. Format: %d, Size: %dx%d.", format, width, height); + return false; } - png_write_info(mData->png_ptr, mData->info_ptr); - + mData->width = width; + mData->height = height; + + png_set_write_fn(mData->guard.png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); + png_set_compression_window_bits(mData->guard.png_ptr, 15); + png_set_compression_level(mData->guard.png_ptr, compressionLevel); + png_set_filter(mData->guard.png_ptr, 0, PNG_ALL_FILTERS); + + _applyWriteIHDR(mData->guard.png_ptr, mData->guard.info_ptr, format, width, height); + png_write_info(mData->guard.png_ptr, mData->guard.info_ptr); + mActive = true; - return true; } -void DeferredPNGWriter::append( GBitmap* bitmap, U32 rows) + +void DeferredPNGWriter::append(GBitmap* bitmap, U32 rows) { - AssertFatal(mActive, "Cannot append to an inactive DeferredPNGWriter!"); - - U32 height = getMin( bitmap->getHeight(), rows); + AssertFatal(mActive, "DeferredPNGWriter::append - Writer is not active."); + U32 height = getMin(bitmap->getHeight(), rows); FrameAllocatorMarker marker; - png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) ); - for (U32 i=0; i(bitmap->getAddress(0, i)); - png_write_rows(mData->png_ptr, row_pointers, height); + png_write_rows(mData->guard.png_ptr, row_pointers, height); } + void DeferredPNGWriter::end() { - AssertFatal(mActive, "Cannot end an inactive DeferredPNGWriter!"); - - png_write_end(mData->png_ptr, mData->info_ptr); - png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL); + AssertFatal(mActive, "DeferredPNGWriter::end - Writer is not active."); + png_write_end(mData->guard.png_ptr, mData->guard.info_ptr); mActive = false; } diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 8ec644b8a..a39d9bfd6 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -57,6 +57,24 @@ #include "gfx/gl/tGL/tXGL.h" #endif +#pragma region GL WARNINGS + +// #131204 - Texture state usage warning: The texture object (0) bound to texture image unit 0 +#define GL_LOW_WARN_TEXTURE_STATE 131204 + +// #131169 - Framebuffer detailed info: The driver allocated storage for renderbuffer 2. (severity: low) +#define GL_LOW_WARN_FRAMEBUFFER 131169 + +// #131185 - Buffer detailed info: Buffer object 1 (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint is GL_ENUM_88e4) +// will use VIDEO memory as the source for buffer object operations. (severity: low) +#define GL_LOW_WARN_VIDEO_MEMORY 131185 + +// #131218 - Program/shader state performance warning: Vertex shader in program # +// is being recompiled based on GL state. (severity: medium) +#define GL_MED_WARN_PERFORMANCE_RECOMPILE 131218 + +#pragma endregion + GFXAdapter::CreateDeviceInstanceDelegate GFXGLDevice::mCreateDeviceInstance(GFXGLDevice::createInstance); GFXDevice *GFXGLDevice::createInstance( U32 adapterIndex ) @@ -104,6 +122,10 @@ void APIENTRY glDebugCallback( if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) return; + // Silence: Texture state usage warning: The texture object (0) bound to texture image unit 0 + if (id == GL_LOW_WARN_TEXTURE_STATE) + return; + const char* srcStr = "UNKNOWN"; const char* typeStr = "UNKNOWN"; const char* sevStr = "UNKNOWN"; diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.cpp b/Engine/source/gfx/gl/gfxGLTextureManager.cpp index c6c73fbee..5e769dbd7 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureManager.cpp @@ -480,10 +480,9 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL) } } - if(!ImageUtil::isCompressedFormat(pDL->getFormat())) + if (mipLevels > 1 && !ImageUtil::isCompressedFormat(pDL->getFormat())) glGenerateMipmap(texture->getBinding()); - glBindTexture(target, 0); return true; } @@ -560,10 +559,9 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) } } - if (numMips != 1 && !isCompressed) + if (numMips > 1 && !isCompressed) glGenerateMipmap(texture->getBinding()); - glBindTexture(target, 0); return true; } @@ -608,7 +606,7 @@ bool GFXGLTextureManager::_refreshTexture(GFXTextureObject *texture) _loadTexture(texture, texture->mBitmap); if(texture->mDDS) - return false; + _loadTexture(texture, texture->mDDS); usedStrategies++; } diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index 81ca6fa9d..0b58c19b6 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -102,79 +102,36 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel /*= 0*/, RectI* inRect /*= void GFXGLTextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/) { - if (!mLockedRect.bits) - return; + if (!mLockedRect.bits) + return; - PROFILE_SCOPE(GFXGLTextureObject_unlock); + // I know this is in unlock, but in GL we actually do our submission in unlock. + PROFILE_SCOPE(GFXGLTextureObject_lockRT); - PRESERVE_TEXTURE(mBinding); - glBindTexture(mBinding, mHandle); + PRESERVE_TEXTURE(mBinding); + glBindTexture(mBinding, mHandle); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mBuffer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel, mFrameAllocatorPtr, GL_STREAM_DRAW); + S32 z = getDepth(); + if (mBinding == GL_TEXTURE_3D) + glTexSubImage3D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, z, + mLockedRectRect.extent.x, mLockedRectRect.extent.y, z, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); + else if (mBinding == GL_TEXTURE_2D) + glTexSubImage2D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, + mLockedRectRect.extent.x, mLockedRectRect.extent.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); + else if (mBinding == GL_TEXTURE_1D) + glTexSubImage1D(mBinding, mipLevel, (mLockedRectRect.point.x > 1 ? mLockedRectRect.point.x : mLockedRectRect.point.y), + (mLockedRectRect.extent.x > 1 ? mLockedRectRect.extent.x : mLockedRectRect.extent.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); - // --- Save pixel store state --- - GLint prevUnpackAlign; - glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlign); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - const U32 width = mLockedRectRect.extent.x; - const U32 height = mLockedRectRect.extent.y; - const U32 depth = getDepth(); - - if (mBinding == GL_TEXTURE_3D) - { - glTexSubImage3D( - mBinding, - mipLevel, - mLockedRectRect.point.x, - mLockedRectRect.point.y, - 0, - width, - height, - depth, - GFXGLTextureFormat[mFormat], - GFXGLTextureType[mFormat], - mLockedRect.bits - ); - } - else if (mBinding == GL_TEXTURE_2D) - { - glTexSubImage2D( - mBinding, - mipLevel, - mLockedRectRect.point.x, - mLockedRectRect.point.y, - width, - height, - GFXGLTextureFormat[mFormat], - GFXGLTextureType[mFormat], - mLockedRect.bits - ); - } - else if (mBinding == GL_TEXTURE_1D) - { - glTexSubImage1D( - mBinding, - mipLevel, - mLockedRectRect.point.x, - width, - GFXGLTextureFormat[mFormat], - GFXGLTextureType[mFormat], - mLockedRect.bits - ); - } - - // --- Restore state --- - glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlign); - - mLockedRect.bits = NULL; - - FrameAllocator::setWaterMark(mFrameAllocatorMark); - mFrameAllocatorMark = 0; - mFrameAllocatorPtr = NULL; - -#ifdef TORQUE_DEBUG - glCheckErrors(); + mLockedRect.bits = NULL; +#if TORQUE_DEBUG + AssertFatal(mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(), ""); #endif + FrameAllocator::setWaterMark(mFrameAllocatorMark); + mFrameAllocatorMark = 0; + mFrameAllocatorPtr = NULL; } void GFXGLTextureObject::release() @@ -281,7 +238,6 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) } // face } // mip - glBindTexture(mBinding, 0); return true; } @@ -298,6 +254,9 @@ void GFXGLTextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const const GLenum srcTarget = srcTex->getBinding(); // source binding const bool srcIsCube = (srcTarget == GL_TEXTURE_CUBE_MAP || srcTarget == GL_TEXTURE_CUBE_MAP_ARRAY); + PRESERVE_TEXTURE(srcTarget); + PRESERVE_TEXTURE(dstTarget); + // Determine list of faces to copy from source U32 firstFace = 0; U32 faceCount = 1; @@ -435,9 +394,6 @@ void GFXGLTextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer); } } - - glBindTexture(dstTarget, 0); - glBindTexture(srcTarget, 0); } } @@ -462,6 +418,9 @@ void GFXGLTextureObject::initSamplerState(const GFXSamplerStateDesc &ssd) void GFXGLTextureObject::bind(U32 textureUnit) { + if (!mHandle || mIsZombie) + return; + glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(mBinding, mHandle); GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle); diff --git a/Engine/source/gui/editor/guiInspectorTypes.cpp b/Engine/source/gui/editor/guiInspectorTypes.cpp index 09b622131..d33014ef3 100644 --- a/Engine/source/gui/editor/guiInspectorTypes.cpp +++ b/Engine/source/gui/editor/guiInspectorTypes.cpp @@ -1174,7 +1174,7 @@ GuiControl* GuiInspectorTypeColor::constructEditControl() if( inspector->isMethod( "onInspectorPreFieldModification" ) ) { dSprintf( szBuffer, sizeof( szBuffer ), - "%d.onInspectorPreFieldModification(\"%s\",\"%s\"); %s(%s, \"%d.onInspectorPostFieldModification(); %d.applyWithoutUndo\", %d.getRoot(), \"%d.applyWithoutUndo\", \"%d.onInspectorDiscardFieldModification(); %%unused=\");", + "%d.onInspectorPreFieldModification(\"%s\",\"%s\"); %s(%s, \"%d.onInspectorPostFieldModification(); %d.applyWithoutUndo\", %d.getRoot(), \"%d.applyWithoutUndo\", \"%d.onInspectorDiscardFieldModification(); %$unused=\");", inspector->getId(), getRawFieldName(), getArrayIndex(), mColorFunction, szColor, inspector->getId(), getId(), getId(), diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl index addc16541..58b2881f2 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl @@ -434,25 +434,22 @@ void dampen(inout Surface surface, sampler2D WetnessTexture, float accumTime, fl { if (degree<=0.0) return; vec3 n = abs(surface.N); - float ang = clamp(n.z, 0.04, 0.96); + float ang = 1.1-(abs(surface.N.z)*sign(surface.N.z)); - float speed = -accumTime*(1.0-surface.linearRoughnessSq)*clamp((2.0-ang), 0.04, 0.96); - if ((n.x > 0.0) || (n.y > 0.0)) - speed *= -1.0; - vec2 wetoffset = vec2(speed,speed)*0.1; + float speed = accumTime * (1.0 - surface.linearRoughnessSq); + vec3 wetoffset = (surface.P+vec3(speed,speed,speed)) * 0.33; - vec3 wetNormal = texture(WetnessTexture, float2(surface.P.xy*0.1+wetoffset)).xyz; - wetNormal = lerp(wetNormal,texture(WetnessTexture,float2(surface.P.zx*0.1+wetoffset)).rgb ,n.y); - wetNormal = lerp(wetNormal,texture(WetnessTexture,float2(surface.P.zy*0.1+wetoffset)).rgb ,n.x); - surface.N = lerp(surface.N, wetNormal, degree); + vec3 wetNormal = texture(WetnessTexture, wetoffset.xy).xyz * (1.1-(n.z* n.z)); + wetNormal = lerp(wetNormal, texture(WetnessTexture, wetoffset.zx).rgb, n.y); + wetNormal = lerp(wetNormal, texture(WetnessTexture, wetoffset.zy).rgb, n.x); + wetNormal = normalize(wetNormal); + float wetness = wetNormal.b* degree; - float wetness = texture(WetnessTexture, vec2(surface.P.xy*0.1+wetoffset)).b; - wetness = lerp(wetness,texture(WetnessTexture,vec2(surface.P.zx*0.1+wetoffset)).b,n.y); - wetness = lerp(wetness,texture(WetnessTexture,vec2(surface.P.zy*0.1+wetoffset)).b,n.x); - wetness = pow(wetness*ang*degree,3); + wetNormal = normalize(wetNormal * 2.0 - 1.0); + surface.N = normalize(vec3(surface.N.xy + wetNormal.xy * wetness, surface.N.z)); surface.roughness = lerp(surface.roughness, 0.04f, wetness); - surface.baseColor.rgb = lerp(surface.baseColor.rgb, surface.baseColor.rgb*0.6+float3(0.4,0.4,0.4)*wetness, wetness); + surface.baseColor = vec4(lerp(surface.baseColor.rgb, surface.baseColor.rgb*0.6+vec3(0.4,0.4,0.4)*wetness, wetness), max(surface.baseColor.a, 0.4* wetness)); surface.metalness = lerp(surface.metalness, 0.96, wetness); updateSurface(surface); } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl index 8b544ca9c..b712e5ad0 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl @@ -436,25 +436,22 @@ void dampen(inout Surface surface, TORQUE_SAMPLER2D(WetnessTexture), float accum { if (degree<=0.0) return; float3 n = abs(surface.N); - float ang = clamp(n.z, 0.04, 0.96); + float ang = 1.1-(abs(surface.N.z)*sign(surface.N.z)); - float speed = -accumTime*(1.0-surface.linearRoughnessSq)*clamp((2.0-ang), 0.04, 0.96); - if ((n.x > 0.0) || (n.y > 0.0)) - speed *= -1.0; - float2 wetoffset = float2(speed,speed)*0.1; + float speed = accumTime * (1.0 - surface.linearRoughnessSq); + float3 wetoffset = (surface.P+float3(speed,speed,speed)) * 0.33; - float3 wetNormal = TORQUE_TEX2D(WetnessTexture, float2(surface.P.xy*0.1+wetoffset)).xyz; - wetNormal = lerp(wetNormal,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zx*0.1+wetoffset)).rgb ,n.y); - wetNormal = lerp(wetNormal,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zy*0.1+wetoffset)).rgb ,n.x); - surface.N = lerp(surface.N, wetNormal, degree); - - float wetness = TORQUE_TEX2D(WetnessTexture, float2(surface.P.xy*0.1+wetoffset)).b; - wetness = lerp(wetness,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zx*0.1+wetoffset)).b,n.y); - wetness = lerp(wetness,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zy*0.1+wetoffset)).b,n.x); - wetness = pow(wetness*ang*degree,3); + float3 wetNormal = TORQUE_TEX2D(WetnessTexture, wetoffset.xy).xyz * (1.1-(n.z* n.z)); + wetNormal = lerp(wetNormal, TORQUE_TEX2D(WetnessTexture, wetoffset.zx).rgb, n.y); + wetNormal = lerp(wetNormal, TORQUE_TEX2D(WetnessTexture, wetoffset.zy).rgb, n.x); + wetNormal = normalize(wetNormal); + float wetness = wetNormal.b* degree; + + wetNormal = normalize(wetNormal * 2.0 - 1.0); + surface.N = normalize(float3(surface.N.xy + wetNormal.xy * wetness, surface.N.z)); surface.roughness = lerp(surface.roughness, 0.04f, wetness); - surface.baseColor.rgb = lerp(surface.baseColor.rgb, surface.baseColor.rgb*0.6+float3(0.4,0.4,0.4)*wetness, wetness); + surface.baseColor = float4(lerp(surface.baseColor.rgb, surface.baseColor.rgb * 0.6 + float3(0.4, 0.4, 0.4) * wetness, wetness), max(surface.baseColor.a, 0.4* wetness)); surface.metalness = lerp(surface.metalness, 0.96, wetness); surface.Update(); } diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript index 9dcd083da..7d67f2a27 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript @@ -2101,7 +2101,7 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) %popup.item[ 0 ] = "Delete" TAB "" TAB "EditorMenuEditDelete();"; %popup.item[ 1 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );"; %popup.item[ 2 ] = "-"; - %popup.item[ 3 ] = "Make selected a Prefab" TAB "" TAB "EWorldEditor.makeSelectionPrefab();"; + %popup.item[ 3 ] = "Make selected a Prefab" TAB "" TAB "EditorMakePrefab();"; %popup.item[ 4 ] = "Bake selected into Mesh" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"ShapeAsset\", AssetBrowser.selectedModule, \"makeSelectedAMesh\");"; %popup.item[ 5 ] = "-"; %popup.item[ 6 ] = "Make selected a Sub-Level" TAB "" TAB "MakeSelectionASublevel();";