Merge remote-tracking branch 'upstream/development' into development

This commit is contained in:
marauder2k7 2026-04-18 19:19:37 +01:00
commit 4fa4233ae4
19 changed files with 694 additions and 898 deletions

View file

@ -190,12 +190,6 @@ SoundAsset::SoundAsset()
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()) if (mPlaylist.isProperlyAdded() && !mPlaylist.isDeleted())
mPlaylist.unregisterObject(); 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]); Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[i]);
mLoadedState = BadFileReference; mLoadedState = BadFileReference;
mSFXProfile[i].setDescription(NULL);
mSFXProfile[i].setSoundFileName(StringTable->insert(StringTable->EmptyString()));
mSFXProfile[i].setPreload(false);
return mLoadedState; return mLoadedState;
} }
else else
{ {
SFXProfile* trackProfile = new SFXProfile(); mSFXProfile[i] = new SFXProfile;
trackProfile->setDescription(&mProfileDesc); mSFXProfile[i]->setDescription(&mProfileDesc);
trackProfile->setSoundFileName(mSoundPath[i]); mSFXProfile[i]->setSoundFileName(mSoundPath[i]);
trackProfile->setPreload(mPreload); mSFXProfile[i]->setPreload(mPreload);
mSFXProfile[i]->registerObject(String::ToString("%s_profile_track%d", getAssetName()).c_str());
mSFXProfile[i] = *trackProfile; mPlaylist.mSlots.mTrack[i] = mSFXProfile[i];
mSFXProfile[i].registerObject(String::ToString("%s_profile_track%d", getAssetName()).c_str());
mPlaylist.mSlots.mTrack[i] = trackProfile;
} }
} }
@ -436,18 +425,15 @@ U32 SoundAsset::load()
{ {
Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[0]); Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[0]);
mLoadedState = BadFileReference; mLoadedState = BadFileReference;
mSFXProfile[0].setDescription(NULL);
mSFXProfile[0].setSoundFileName(StringTable->insert(StringTable->EmptyString()));
mSFXProfile[0].setPreload(false);
return mLoadedState; return mLoadedState;
} }
else else
{ {
mSFXProfile[0].setDescription(&mProfileDesc); mSFXProfile[0] = new SFXProfile;
mSFXProfile[0].setSoundFileName(mSoundPath[0]); mSFXProfile[0]->setDescription(&mProfileDesc);
mSFXProfile[0].setPreload(mPreload); mSFXProfile[0]->setSoundFileName(mSoundPath[0]);
mSFXProfile[0]->setPreload(mPreload);
mSFXProfile[0].registerObject(String::ToString("%s_profile", getAssetName()).c_str()); mSFXProfile[0]->registerObject(String::ToString("%s_profile", getAssetName()).c_str());
} }
} }

View file

@ -89,7 +89,7 @@ class SoundAsset : public AssetBase
protected: protected:
StringTableEntry mSoundFile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; StringTableEntry mSoundFile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
StringTableEntry mSoundPath[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; StringTableEntry mSoundPath[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
SFXProfile mSFXProfile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS]; SimObjectPtr<SFXProfile> mSFXProfile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
SFXDescription mProfileDesc; SFXDescription mProfileDesc;
SFXPlayList mPlaylist; SFXPlayList mPlaylist;
@ -150,7 +150,7 @@ public:
void copyTo(SimObject* object) override; void copyTo(SimObject* object) override;
//SFXResource* getSound() { return mSoundResource; } //SFXResource* getSound() { return mSoundResource; }
Resource<SFXResource> getSoundResource(const U32 slotId = 0) { load(); return mSFXProfile[slotId].getResource(); } Resource<SFXResource> getSoundResource(const U32 slotId = 0) { load(); return mSFXProfile[slotId]->getResource(); }
/// Declare Console Object. /// Declare Console Object.
DECLARE_CONOBJECT(SoundAsset); DECLARE_CONOBJECT(SoundAsset);
@ -158,9 +158,9 @@ public:
static bool _setSoundFile(void* object, const char* index, const char* data); static bool _setSoundFile(void* object, const char* index, const char* data);
U32 load() override; U32 load() override;
inline StringTableEntry getSoundPath(const U32 slotId = 0) const { return mSoundPath[slotId]; }; 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; } SFXPlayList* getSfxPlaylist() { return &mPlaylist; }
SFXTrack* getSFXTrack() { load(); return mIsPlaylist ? dynamic_cast<SFXTrack*>(&mPlaylist) : dynamic_cast<SFXTrack*>(&mSFXProfile[0]); } SFXTrack* getSFXTrack() { load(); return mIsPlaylist ? dynamic_cast<SFXTrack*>(&mPlaylist) : dynamic_cast<SFXTrack*>(mSFXProfile[0].getPointer()); }
SFXDescription* getSfxDescription() { return &mProfileDesc; } SFXDescription* getSfxDescription() { return &mProfileDesc; }
bool isPlaylist(){ return mIsPlaylist; } bool isPlaylist(){ return mIsPlaylist; }

View file

@ -471,6 +471,7 @@ bool PlayerData::preload(bool server, String &errorStr)
if (!server) { if (!server) {
for (U32 i = 0; i < MaxSounds; ++i) for (U32 i = 0; i < MaxSounds; ++i)
{ {
_setPlayerSound(getPlayerSound(i), i);
if (!isPlayerSoundValid(i)) if (!isPlayerSoundValid(i))
{ {
//return false; -TODO: trigger asset download //return false; -TODO: trigger asset download

View file

@ -348,6 +348,7 @@ bool RigidShapeData::preload(bool server, String &errorStr)
if (!server) { if (!server) {
for (S32 i = 0; i < Body::MaxSounds; i++) for (S32 i = 0; i < Body::MaxSounds; i++)
{ {
_setBodySounds(getBodySounds(i), i);
if (!isBodySoundsValid(i)) if (!isBodySoundsValid(i))
{ {
//return false; -TODO: trigger asset download //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++) for (S32 j = 0; j < Sounds::MaxSounds; j++)
{ {
_setWaterSounds(getWaterSounds(j), j);
if (!isWaterSoundsValid(j)) if (!isWaterSoundsValid(j))
{ {
//return false; -TODO: trigger asset download //return false; -TODO: trigger asset download

View file

@ -141,6 +141,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr)
if (!server) { if (!server) {
for (S32 i = 0; i < MaxSounds; i++) for (S32 i = 0; i < MaxSounds; i++)
{ {
_setFlyingSounds(getFlyingSounds(i), i);
if (!isFlyingSoundsValid(i)) if (!isFlyingSoundsValid(i))
{ {
//return false; -TODO: trigger asset download //return false; -TODO: trigger asset download

View file

@ -313,6 +313,7 @@ bool HoverVehicleData::preload(bool server, String &errorStr)
for (S32 i = 0; i < MaxSounds; i++) for (S32 i = 0; i < MaxSounds; i++)
{ {
_setHoverSounds(getHoverSounds(i), i);
if (!isHoverSoundsValid(i)) if (!isHoverSoundsValid(i))
{ {
//return false; -TODO: trigger asset download //return false; -TODO: trigger asset download

View file

@ -348,6 +348,7 @@ bool WheeledVehicleData::preload(bool server, String &errorStr)
if (!server) { if (!server) {
for (S32 i = 0; i < MaxSounds; i++) for (S32 i = 0; i < MaxSounds; i++)
{ {
_setWheeledVehicleSounds(getWheeledVehicleSounds(i), i);
if (!isWheeledVehicleSoundsValid(i)) if (!isWheeledVehicleSoundsValid(i))
{ {
//return false; -TODO: trigger asset download //return false; -TODO: trigger asset download

View file

@ -40,7 +40,10 @@
#ifndef _TAML_CALLBACKS_H_ #ifndef _TAML_CALLBACKS_H_
#include "persistence/taml/tamlCallbacks.h" #include "persistence/taml/tamlCallbacks.h"
#endif #endif
#ifndef _OBJECTTYPES_H_
#include "T3D/objectTypes.h" #include "T3D/objectTypes.h"
#endif
class Stream; class Stream;
class LightManager; class LightManager;
@ -606,6 +609,7 @@ class SimObject: public ConsoleObject, public TamlCallbacks
/// @name Events /// @name Events
/// @{ /// @{
//virtual void onPrepare();
/// Called when the object is added to the sim. /// Called when the object is added to the sim.
virtual bool onAdd(); virtual bool onAdd();
@ -1049,51 +1053,42 @@ class SimObjectPtr : public WeakRefPtr< T >
typedef WeakRefPtr< T > Parent; typedef WeakRefPtr< T > Parent;
SimObjectPtr() {} SimObjectPtr() = default;
SimObjectPtr(T *ptr) { this->mReference = NULL; set(ptr); } SimObjectPtr(T* ptr) { set(ptr); }
SimObjectPtr( const SimObjectPtr& ref ) { this->mReference = NULL; set(ref.mReference); } SimObjectPtr(const SimObjectPtr&) = default;
SimObjectPtr& operator=(const SimObjectPtr&) = default;
T* getObject() const { return Parent::getPointer(); } SimObjectPtr& operator=(T* ptr)
~SimObjectPtr() { set((WeakRefBase::WeakReference*)NULL); }
SimObjectPtr<T>& operator=(const SimObjectPtr ref)
{
set(ref.mReference);
return *this;
}
SimObjectPtr<T>& operator=(T *ptr)
{ {
set(ptr); set(ptr);
return *this; return *this;
} }
T* getObject() const { return Parent::getPointer(); }
protected: protected:
void set(WeakRefBase::WeakReference * ref)
{
if( ref == this->mReference )
return;
if( this->mReference )
{
// 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();
}
}
void set(T* obj) void set(T* obj)
{ {
set(obj ? obj->getWeakReference() : (WeakRefBase::WeakReference *)NULL); // Nothing to do if same object
if (obj && this->mWeak.lock() == obj->getWeakControl().lock())
return;
// Before overwriting, check old object for auto-delete
if (auto old_ctrl = this->mWeak.lock())
{
T* old_obj = getObject();
if (this->mWeak.use_count() == 1 && old_obj && old_obj->isAutoDeleted())
{
old_obj->destroySelf();
}
}
// Assign new weak reference
this->mWeak.reset();
if (obj)
{
auto obj_ctrl = obj->getWeakControl().lock();
this->mWeak = obj_ctrl;
}
} }
}; };

View file

@ -0,0 +1,18 @@
#include "refBase.h"
WeakRefBase::~WeakRefBase()
{
if (mControl)
mControl->object = NULL;
}
WeakControlBlock::WeakControlBlock(WeakRefBase* obj)
: object(obj)
{
}
WeakControlBlock::~WeakControlBlock()
{
}

View file

@ -30,52 +30,52 @@
# include "platform/typetraits.h" # include "platform/typetraits.h"
#endif #endif
#include <memory>
#include <type_traits>
class WeakRefBase;
struct WeakControlBlock
{
explicit WeakControlBlock(WeakRefBase* obj);
~WeakControlBlock();
WeakRefBase* object;
};
/// Base class for objects which can be weakly referenced /// Base class for objects which can be weakly referenced
/// (i.e., reference goes away when object is destroyed). /// (i.e., reference goes away when object is destroyed).
class WeakRefBase class WeakRefBase
{ {
public: public:
WeakRefBase()
/// Weak reference to WeakRefBase. : mControl(std::make_shared<WeakControlBlock>(this))
class WeakReference
{ {
public:
[[nodiscard]] constexpr WeakRefBase* get() const { return mObject; }
[[nodiscard]] constexpr U32 getRefCount() const { return mRefCount; }
constexpr void incRefCount() { mRefCount++; }
constexpr void decRefCount() {
AssertFatal( mRefCount > 0, "WeakReference - decrementing count of zero!" );
if (--mRefCount==0)
delete this;
} }
private:
friend class WeakRefBase; virtual ~WeakRefBase();
constexpr explicit WeakReference(WeakRefBase *object) :mObject(object), mRefCount(0) {}
~WeakReference() { AssertFatal(mObject==NULL, "Deleting weak reference which still points at an object."); } // Copy constructor
WeakRefBase(const WeakRefBase&) = delete;
WeakRefBase& operator=(const WeakRefBase&) = delete;
WeakRefBase(WeakRefBase&&) = delete;
WeakRefBase& operator=(WeakRefBase&&) = delete;
// Object we reference std::weak_ptr<WeakControlBlock> getWeakControl()
WeakRefBase *mObject; {
return mControl;
}
// reference count for this structure (not WeakObjectRef itself) std::shared_ptr<WeakControlBlock> getSharedControl()
U32 mRefCount; {
}; return mControl;
}
public:
constexpr WeakRefBase() : mReference(NULL) {}
virtual ~WeakRefBase() { clearWeakReferences(); }
WeakReference* getWeakReference();
protected: protected:
void clearWeakReferences();
std::shared_ptr<WeakControlBlock> mControl;
private: private:
WeakReference * mReference;
}; };
template< typename T > class SimObjectPtr; template< typename T > class SimObjectPtr;
@ -88,100 +88,48 @@ template< typename T > class SimObjectPtr;
template <class T> class WeakRefPtr template <class T> class WeakRefPtr
{ {
public: public:
constexpr WeakRefPtr() : mReference(NULL) {} WeakRefPtr() = default;
WeakRefPtr(T *ptr) : mReference(NULL) { set(ptr); } WeakRefPtr(T* obj) { set(obj); }
WeakRefPtr(const WeakRefPtr<T> & ref) { mReference = NULL; set(ref.mReference); }
~WeakRefPtr() { set(static_cast<WeakRefBase::WeakReference *>(NULL)); } WeakRefPtr(const WeakRefPtr&) = default;
WeakRefPtr& operator=(const WeakRefPtr&) = default;
WeakRefPtr<T>& operator=(const WeakRefPtr<T>& ref) WeakRefPtr& operator=(T* obj)
{ {
if (this == &ref) { return *this; } // handle self assignment ( x = x; ) set(obj);
set(ref.mReference);
return *this;
}
WeakRefPtr<T>& operator=(T *ptr)
{
set(ptr);
return *this; return *this;
} }
/// Returns true if the pointer is not set. bool isValid() const { return getPointer() != NULL; }
[[nodiscard]] constexpr bool isNull() const { return mReference == NULL || mReference->get() == NULL; } bool isNull() const { return getPointer() == NULL; }
/// Returns true if the pointer is set.
[[nodiscard]] constexpr bool isValid() const { return mReference && mReference->get(); }
[[nodiscard]] constexpr T* operator->() const { return getPointer(); } [[nodiscard]] constexpr T* operator->() const { return getPointer(); }
[[nodiscard]] constexpr T& operator*() const { return *getPointer(); } [[nodiscard]] constexpr T& operator*() const { return *getPointer(); }
[[nodiscard]] constexpr operator T*() const { return getPointer(); } [[nodiscard]] constexpr operator T*() const { return getPointer(); }
/// Returns the pointer. /// 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: protected:
void set(WeakRefBase::WeakReference* ref) void set(T* obj)
{ {
if (mReference) if (!obj)
mReference->decRefCount();
mReference = NULL;
if (ref)
{ {
mReference = ref; mWeak.reset();
mReference->incRefCount(); return;
}
} }
void set(T* obj) { set(obj ? obj->getWeakReference() : NULL); } mWeak = obj->getWeakControl();
}
private: private:
template< typename > friend class SimObjectPtr; template< typename > friend class SimObjectPtr;
WeakRefBase::WeakReference * mReference {NULL}; std::weak_ptr<WeakControlBlock> mWeak;
};
/// 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 ExposedType>
class WeakRefUnion
{
typedef WeakRefUnion<ExposedType> Union;
public:
constexpr WeakRefUnion() : mPtr(NULL) {}
constexpr WeakRefUnion(const WeakRefPtr<WeakRefBase> & 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<ExposedType*>(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<WeakRefBase> & 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<WeakRefBase> getRef() const { return mWeakReference; }
private:
WeakRefPtr<WeakRefBase> mWeakReference;
ExposedType * mPtr;
}; };
/// Base class for objects which can be strongly referenced /// Base class for objects which can be strongly referenced
@ -192,7 +140,12 @@ class StrongRefBase : public WeakRefBase
friend class StrongObjectRef; friend class StrongObjectRef;
public: public:
StrongRefBase() { mRefCount = 0; } StrongRefBase()
{
mRefCount = 0;
}
virtual ~StrongRefBase() = default;
U32 getRefCount() const { return mRefCount; } U32 getRefCount() const { return mRefCount; }
@ -217,6 +170,7 @@ protected:
U32 mRefCount; ///< reference counter for StrongRefPtr objects U32 mRefCount; ///< reference counter for StrongRefPtr objects
}; };
/// Base class for StrongRefBase strong reference pointers. /// Base class for StrongRefBase strong reference pointers.
class StrongObjectRef class StrongObjectRef
{ {
@ -289,55 +243,6 @@ public:
T* getPointer() const { return const_cast<T*>(static_cast<T* const>(mObject)); } T* getPointer() const { return const_cast<T*>(static_cast<T* const>(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 ExposedType>
class StrongRefUnion
{
typedef StrongRefUnion<ExposedType> Union;
public:
StrongRefUnion() : mPtr(NULL) {}
StrongRefUnion(const StrongRefPtr<StrongRefBase> & 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<ExposedType*>(ref)); }
~StrongRefUnion() { mReference = NULL; }
Union & operator=(const Union & ptr)
{
set(ptr.mReference, ptr.mPtr);
return *this;
}
void set(const StrongRefPtr<StrongRefBase> & 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<StrongRefBase> getRef() const { return mReference; }
private:
StrongRefPtr<StrongRefBase> mReference;
ExposedType * mPtr;
};
/// This oxymoron is a pointer that reference-counts the referenced /// This oxymoron is a pointer that reference-counts the referenced
/// object but also NULLs out if the object goes away. /// object but also NULLs out if the object goes away.
/// ///
@ -351,93 +256,87 @@ template< class T >
class StrongWeakRefPtr class StrongWeakRefPtr
{ {
public: public:
constexpr StrongWeakRefPtr() : mReference( NULL ) {} StrongWeakRefPtr() = default;
constexpr StrongWeakRefPtr( T* ptr ) : mReference( NULL ) { _set( ptr ); }
~StrongWeakRefPtr()
{
if( mReference )
{
T* ptr = _get();
if( ptr )
ptr->decRefCount();
mReference->decRefCount(); StrongWeakRefPtr(T* ptr) { set(ptr); }
}
StrongWeakRefPtr(const StrongWeakRefPtr& other)
{
set(other.getPointer());
} }
[[nodiscard]] constexpr bool isNull() const { return ( _get() == NULL ); } StrongWeakRefPtr& operator=(const StrongWeakRefPtr& other)
[[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 )
{ {
_set( ptr ); if (this != &other)
set(other.getPointer());
return *this; return *this;
} }
~StrongWeakRefPtr()
{
release();
}
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
{
return mControl ? static_cast<T*>(mControl->object) : NULL;
}
private: private:
WeakRefBase::WeakReference* mReference; std::shared_ptr<WeakControlBlock> mControl;
T* mPtr = NULL;
T* _get() const void set(T* ptr)
{ {
if( mReference ) release();
return static_cast< T* >( mReference->get() ); if (!ptr) return;
else
return NULL; // 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<StrongRefBase, T>)
{
mPtr->incRefCount();
} }
void _set( T* ptr )
{
if( mReference )
{
T* old = _get();
if( old )
old->decRefCount();
mReference->decRefCount();
} }
if( ptr ) void release()
{ {
ptr->incRefCount(); if (mPtr)
mReference = ptr->getWeakReference(); {
mReference->incRefCount(); if constexpr (std::is_base_of_v<StrongRefBase, T>)
{
mPtr->decRefCount();
} }
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 > template< typename T >
struct TypeTraits< WeakRefPtr< T > > : public _TypeTraits< WeakRefPtr< T > > struct TypeTraits< WeakRefPtr< T > > : public _TypeTraits< WeakRefPtr< T > >
{ {

View file

@ -1094,7 +1094,7 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat
} }
else else
{ {
GFX->setCubeTexture( 0, NULL ); GFX->setTexture( 0, NULL );
mShaderConsts->setSafe( mUseCubemapSC, 0.0f ); mShaderConsts->setSafe( mUseCubemapSC, 0.0f );
} }

View file

@ -41,15 +41,16 @@
#endif #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. /// 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. /// 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 sWritePNG(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel);
static bool sWriteStreamPNG(const String& bmType, Stream& stream, 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 static struct _privateRegisterPNG
{ {
@ -72,421 +73,390 @@ static struct _privateRegisterPNG
} }
} sStaticRegisterPNG; } sStaticRegisterPNG;
//-----------------------------------------------------------------------------
//-------------------------------------- Replacement I/O for standard LIBPng // PNG context passed to libpng for error reporting
// functions. we don't wanna use //-----------------------------------------------------------------------------
// FILE*'s... struct PngContext
static void pngReadDataFn(png_structp png_ptr,
png_bytep data,
png_size_t length)
{ {
AssertFatal(png_get_io_ptr(png_ptr) != NULL, "No stream?"); const char* filename;
explicit PngContext(const char* f) : filename(f) {}
};
//-----------------------------------------------------------------------------
// 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); Stream* strm = (Stream*)png_get_io_ptr(png_ptr);
bool success = strm->read(length, data); AssertFatal(strm, "pngReadDataFn - No stream.");
AssertFatal(success, "pngReadDataFn - failed to read from 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); Stream* strm = (Stream*)png_get_io_ptr(png_ptr);
bool success = strm->write(length, data); AssertFatal(strm, "pngWriteDataFn - No stream.");
AssertFatal(success, "pngWriteDataFn - failed to write to 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 png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size) { return FrameAllocator::alloc(size); }
static void pngFlushDataFn(png_structp /*png_ptr*/) 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)
{ {
// const char* filename = "unknown";
if (png_ptr)
{
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 png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size) static void pngWarningFn(png_structp png_ptr, png_const_charp pMessage)
{ {
return FrameAllocator::alloc(size); #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
} }
static void pngFreeFn(png_structp /*png_ptr*/, png_voidp /*mem*/) //-----------------------------------------------------------------------------
// 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;
static png_voidp pngRealMallocFn(png_structp /*png_ptr*/, png_size_t size) explicit PngReadGuard(const char* filename) : ctx(filename) {}
bool init()
{ {
return (png_voidp)dMalloc(size); png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
} &ctx, pngFatalErrorFn, pngWarningFn,
NULL, pngRealMallocFn, pngRealFreeFn);
static void pngRealFreeFn(png_structp /*png_ptr*/, png_voidp mem) if (!png_ptr)
{ {
dFree(mem); Con::errorf("PngReadGuard - png_create_read_struct_2 failed for '%s'.", ctx.filename);
}
//--------------------------------------
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))
{
Con::printf("Failed to open PNG :%s", path.getFullFileName().c_str());
return false; return false;
} }
if (!sReadStreamPNG(*readPng, bitmap, U32_MAX)) info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{ {
Con::printf("Failed to read PNG :%s", path.getFullFileName().c_str()); Con::errorf("PngReadGuard - png_create_info_struct (info) failed for '%s'.", ctx.filename);
return false; return false;
} }
readPng->close(); 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; return true;
} }
static bool sReadStreamPNG(Stream& stream, GBitmap* bitmap, U32 len) ~PngReadGuard()
{ {
PROFILE_SCOPE(sReadPNG); if (png_ptr)
static const U32 cs_headerBytesChecked = 8; png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
U8 header[cs_headerBytesChecked];
stream.read(cs_headerBytesChecked, header);
bool isPng = png_check_sig(header, cs_headerBytesChecked) != 0;
if (isPng == false)
{
AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG");
return false;
} }
};
U32 prevWaterMark = FrameAllocator::getWaterMark(); struct PngWriteGuard
png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, {
png_structp png_ptr = nullptr;
png_infop info_ptr = nullptr;
PngContext ctx;
explicit PngWriteGuard(const char* filename) : ctx(filename) {}
bool init(bool useFrameAllocator = true)
{
png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
&ctx, pngFatalErrorFn, pngWarningFn,
NULL, NULL,
pngFatalErrorFn, useFrameAllocator ? pngMallocFn : pngRealMallocFn,
pngWarningFn, useFrameAllocator ? pngFreeFn : pngRealFreeFn);
NULL, if (!png_ptr)
pngRealMallocFn,
pngRealFreeFn);
if (png_ptr == NULL)
{ {
FrameAllocator::setWaterMark(prevWaterMark); Con::errorf("PngWriteGuard - png_create_write_struct_2 failed for '%s'.", ctx.filename);
return false; return false;
} }
png_infop info_ptr = png_create_info_struct(png_ptr); info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) if (!info_ptr)
{ {
png_destroy_read_struct(&png_ptr, Con::errorf("PngWriteGuard - png_create_info_struct failed for '%s'.", ctx.filename);
(png_infopp)NULL,
(png_infopp)NULL);
FrameAllocator::setWaterMark(prevWaterMark);
return false; return false;
} }
png_infop end_info = png_create_info_struct(png_ptr); return true;
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); ~PngWriteGuard()
{
if (png_ptr)
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
}
};
// Read off the info on the image. //-----------------------------------------------------------------------------
png_set_sig_bytes(png_ptr, cs_headerBytesChecked); // Shared helpers
png_read_info(png_ptr, info_ptr); //-----------------------------------------------------------------------------
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);
// OK, at this point, if we have reached it ok, then we can reset the transAlpha = false;
// 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;
GFXFormat format = GFXFormatR8G8B8; 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); 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); png_set_expand(png_ptr);
transAlpha = true; transAlpha = true;
} }
if (color_type == PNG_COLOR_TYPE_PALETTE) switch (color_type)
{ {
case PNG_COLOR_TYPE_PALETTE:
png_set_expand(png_ptr); png_set_expand(png_ptr);
format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8; format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8;
} break;
else if (color_type == PNG_COLOR_TYPE_GRAY) case PNG_COLOR_TYPE_GRAY:
{
png_set_expand(png_ptr); png_set_expand(png_ptr);
format = (bit_depth == 16) ? GFXFormatR5G6B5 : GFXFormatA8;
if (bit_depth == 16) break;
format = GFXFormatR5G6B5; case PNG_COLOR_TYPE_GRAY_ALPHA:
else
format = GFXFormatA8;
}
else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
png_set_expand(png_ptr); png_set_expand(png_ptr);
png_set_gray_to_rgb(png_ptr); png_set_gray_to_rgb(png_ptr);
format = GFXFormatR8G8B8A8; format = GFXFormatR8G8B8A8;
} break;
else if (color_type == PNG_COLOR_TYPE_RGB) case PNG_COLOR_TYPE_RGB:
{
format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8;
png_set_expand(png_ptr); png_set_expand(png_ptr);
} format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8;
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) break;
{ case PNG_COLOR_TYPE_RGB_ALPHA:
png_set_expand(png_ptr); png_set_expand(png_ptr);
format = GFXFormatR8G8B8A8; format = GFXFormatR8G8B8A8;
break;
default:
Con::errorf("_determineReadFormat - Unrecognised color_type %d.", color_type);
break;
} }
// Update the info pointer with the result of the transformations return format;
// above... }
png_read_update_info(png_ptr, info_ptr);
png_uint_32 rowBytes = png_get_rowbytes(png_ptr, info_ptr); static bool _validateRowBytes(const char* filename, GFXFormat format, U32 rowBytes, U32 width)
if (format == GFXFormatR8G8B8)
{ {
AssertFatal(rowBytes == width * 3, const U32 expected =
"Error, our rowbytes are incorrect for this transform... (3)"); (format == GFXFormatR8G8B8) ? width * 3 :
} (format == GFXFormatR8G8B8A8) ? width * 4 :
else if (format == GFXFormatR8G8B8A8) (format == GFXFormatR5G6B5) ? width * 2 : 0;
if (expected && rowBytes != expected)
{ {
AssertFatal(rowBytes == width * 4, Con::errorf("_validateRowBytes - '%s': rowBytes %d != expected %d for format %d.",
"Error, our rowbytes are incorrect for this transform... (4)"); filename, rowBytes, expected, format);
return false;
} }
else if (format == GFXFormatR5G6B5)
{
AssertFatal(rowBytes == width * 2,
"Error, our rowbytes are incorrect for this transform... (2)");
}
// actually allocate the bitmap space...
bitmap->allocateBitmap(width, height,
false, // don't extrude miplevels...
format); // use determined format...
// Set up the row pointers...
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);
// 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);
// 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; return true;
} }
//-------------------------------------------------------------------------- static void _applyWriteIHDR(png_structp png_ptr, png_infop info_ptr, GFXFormat format, U32 width, U32 height)
static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter)
{ {
GFXFormat format = bitmap->getFormat(); switch (format)
// 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)
{ {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL); case GFXFormatR8G8B8:
return false; png_set_IHDR(png_ptr, info_ptr, width, height, 8,
} PNG_COLOR_TYPE_RGB, NULL, NULL, NULL);
break;
png_set_write_fn(png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); case GFXFormatR8G8B8A8:
case GFXFormatR8G8B8X8:
// Set the compression level and image filters case GFXFormatR8G8B8A8_LINEAR_FORCE:
png_set_compression_window_bits(png_ptr, 15); png_set_IHDR(png_ptr, info_ptr, width, height, 8,
png_set_compression_level(png_ptr, compressionLevel); PNG_COLOR_TYPE_RGB_ALPHA, NULL, NULL, NULL);
png_set_filter(png_ptr, 0, filter); break;
case GFXFormatA8:
// Set the image information here. Width and height are up to 2^31, png_set_IHDR(png_ptr, info_ptr, width, height, 8,
// bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on PNG_COLOR_TYPE_GRAY, NULL, NULL, NULL);
// the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, break;
// PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, case GFXFormatR5G6B5:
// 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
U32 width = bitmap->getWidth();
U32 height = bitmap->getHeight();
if (format == GFXFormatR8G8B8)
{ {
png_set_IHDR(png_ptr, info_ptr, png_set_IHDR(png_ptr, info_ptr, width, height, 16,
width, height, // the width & height PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
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 }; png_color_8_struct sigBit = { 0 };
sigBit.gray = 16; sigBit.gray = 16;
png_set_sBIT(png_ptr, info_ptr, &sigBit); png_set_sBIT(png_ptr, info_ptr, &sigBit);
png_set_swap(png_ptr); png_set_swap(png_ptr);
break;
}
default:
break;
}
} }
png_write_info(png_ptr, info_ptr); static bool _isSupportedWriteFormat(GFXFormat format)
FrameAllocatorMarker marker; {
png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) ); switch (format)
{
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;
}
U32 prevWaterMark = FrameAllocator::getWaterMark();
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++) for (U32 i = 0; i < height; i++)
row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i)); rowPointers[i] = pBase + (i * rowBytes);
png_write_image(png_ptr, row_pointers); png_read_image(guard.png_ptr, rowPointers);
delete[] rowPointers;
// Write S3TC data if present... png_read_end(guard.png_ptr, NULL);
// Write FXT1 data if present...
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
bitmap->checkForTransparency();
FrameAllocator::setWaterMark(prevWaterMark);
return true; return true;
} }
static bool _writePNG(GBitmap* bitmap, Stream& stream, U32 compressionLevel, U32 strategy, U32 filter, const char* filename)
//--------------------------------------------------------------------------
bool sWritePNG(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel)
{ {
FileStream* writePng = new FileStream; GFXFormat format = bitmap->getFormat();
if (!writePng->open(path.getFullPath(), Torque::FS::File::Write)) if (!_isSupportedWriteFormat(format))
{ {
Con::printf("Failed to open PNG :%s", path.getFullFileName().c_str()); Con::errorf("_writePNG - '%s': Unsupported format %d.", filename, format);
return false; return false;
} }
if (!sWriteStreamPNG("png", *writePng, bitmap, compressionLevel)) PngWriteGuard guard(filename);
{ if (!guard.init(true))
Con::printf("Failed to write PNG :%s", path.getFullFileName().c_str());
return false; return false;
}
writePng->close(); 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);
_applyWriteIHDR(guard.png_ptr, guard.info_ptr, format, bitmap->getWidth(), bitmap->getHeight());
png_write_info(guard.png_ptr, guard.info_ptr);
FrameAllocatorMarker marker;
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<png_bytep>(bitmap->getAddress(0, i));
png_write_image(guard.png_ptr, rowPointers);
png_write_end(guard.png_ptr, guard.info_ptr);
return true; return true;
} }
static bool sWriteStreamPNG(const String& bmType, Stream& stream, GBitmap* bitmap, U32 compressionLevel) //-----------------------------------------------------------------------------
// Public interface
//-----------------------------------------------------------------------------
static bool sReadPNG(const Torque::Path& path, GBitmap* bitmap)
{
FileStream readPng;
if (!readPng.open(path.getFullPath(), Torque::FS::File::Read))
{
Con::errorf("sReadPNG - Failed to open '%s'.", path.getFullPath().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());
readPng.close();
return result;
}
static bool sWriteStreamPNG(const String& /*bmType*/, Stream& stream, GBitmap* bitmap, U32 compressionLevel)
{ {
U32 waterMark = FrameAllocator::getWaterMark(); U32 waterMark = FrameAllocator::getWaterMark();
@ -501,19 +471,11 @@ static bool sWriteStreamPNG(const String& bmType, Stream& stream, GBitmap* bitma
U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough... U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough...
MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true); MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true);
const U32 zStrategies[] = { Z_DEFAULT_STRATEGY, const U32 zStrategies[] = { Z_DEFAULT_STRATEGY, Z_FILTERED };
Z_FILTERED }; const U32 pngFilters[] = { PNG_FILTER_NONE, PNG_FILTER_SUB, PNG_FILTER_UP,
const U32 pngFilters[] = { PNG_FILTER_NONE, PNG_FILTER_AVG, PNG_FILTER_PAETH, PNG_ALL_FILTERS };
PNG_FILTER_SUB,
PNG_FILTER_UP,
PNG_FILTER_AVG,
PNG_FILTER_PAETH,
PNG_ALL_FILTERS };
U32 minSize = 0xFFFFFFFF; U32 minSize = U32_MAX, bestCLevel = 0, bestStrategy = 0, bestFilter = 0;
U32 bestStrategy = 0xFFFFFFFF;
U32 bestFilter = 0xFFFFFFFF;
U32 bestCLevel = 0xFFFFFFFF;
for (U32 cl = 0; cl <= 9; cl++) for (U32 cl = 0; cl <= 9; cl++)
{ {
@ -522,53 +484,78 @@ static bool sWriteStreamPNG(const String& bmType, Stream& stream, GBitmap* bitma
for (U32 pf = 0; pf < 6; pf++) for (U32 pf = 0; pf < 6; pf++)
{ {
pMemStream->setPosition(0); pMemStream->setPosition(0);
U32 waterMarkInner = FrameAllocator::getWaterMark(); U32 waterMarkInner = FrameAllocator::getWaterMark();
if (_writePNG(bitmap, *pMemStream, cl, zStrategies[zs], pngFilters[pf]) == false) if (!_writePNG(bitmap, *pMemStream, cl, zStrategies[zs], pngFilters[pf]))
AssertFatal(false, "Handle this error!"); {
Con::errorf("sWriteStreamPNG - Compression search failed at cl=%d zs=%d pf=%d.", cl, zs, pf);
FrameAllocator::setWaterMark(waterMarkInner);
continue;
}
FrameAllocator::setWaterMark(waterMarkInner); FrameAllocator::setWaterMark(waterMarkInner);
if (pMemStream->getPosition() < minSize) if (pMemStream->getPosition() < minSize)
{ {
minSize = pMemStream->getPosition(); minSize = pMemStream->getPosition();
bestStrategy = zs; bestCLevel = cl; bestStrategy = zs; bestFilter = pf;
bestFilter = pf;
bestCLevel = cl;
} }
} }
} }
} }
AssertFatal(minSize != 0xFFFFFFFF, "Error, no best found?");
delete pMemStream; delete pMemStream;
delete[] buffer; delete[] buffer;
if (minSize == U32_MAX)
bool retVal = _writePNG(bitmap, stream, {
bestCLevel, Con::errorf("sWriteStreamPNG - No valid compression result found.");
zStrategies[bestStrategy],
pngFilters[bestFilter]);
FrameAllocator::setWaterMark(waterMark); FrameAllocator::setWaterMark(waterMark);
return false;
}
bool retVal = _writePNG(bitmap, stream, bestCLevel, zStrategies[bestStrategy], pngFilters[bestFilter]);
FrameAllocator::setWaterMark(waterMark);
return retVal; return retVal;
} }
//-------------------------------------------------------------------------- static bool sWritePNG(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel)
// Stores PNG stream data
struct DeferredPNGWriterData {
png_structp png_ptr;
png_infop info_ptr;
U32 width;
U32 height;
};
DeferredPNGWriter::DeferredPNGWriter() :
mData( NULL ),
mActive(false)
{ {
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() DeferredPNGWriter::~DeferredPNGWriter()
{ {
delete mData; delete mData;
@ -576,120 +563,52 @@ DeferredPNGWriter::~DeferredPNGWriter()
bool DeferredPNGWriter::begin(GFXFormat format, S32 width, S32 height, Stream& stream, U32 compressionLevel) bool DeferredPNGWriter::begin(GFXFormat format, S32 width, S32 height, Stream& stream, U32 compressionLevel)
{ {
// ONLY RGB bitmap writing supported at this time! if (!_isSupportedWriteFormat(format))
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)
{ {
png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL); Con::errorf("DeferredPNGWriter::begin - Unsupported format %d.", format);
return false; return false;
} }
png_set_write_fn(mData->png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); mData = new DeferredPNGWriterData("DeferredPNGWriter");
// Set the compression level and image filters if (!mData->guard.init(false))
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)
{ {
png_set_IHDR(mData->png_ptr, mData->info_ptr, Con::errorf("DeferredPNGWriter::begin - Failed to init PNG write structs. Format: %d, Size: %dx%d.", format, width, height);
width, height, // the width & height return false;
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 );
} }
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; mActive = true;
return 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!"); AssertFatal(mActive, "DeferredPNGWriter::append - Writer is not active.");
U32 height = getMin(bitmap->getHeight(), rows); U32 height = getMin(bitmap->getHeight(), rows);
FrameAllocatorMarker marker; FrameAllocatorMarker marker;
png_bytep* row_pointers = (png_bytep*)marker.alloc(height * sizeof(png_bytep)); png_bytep* row_pointers = (png_bytep*)marker.alloc(height * sizeof(png_bytep));
for (U32 i = 0; i < height; i++) for (U32 i = 0; i < height; i++)
row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i)); row_pointers[i] = const_cast<png_bytep>(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() void DeferredPNGWriter::end()
{ {
AssertFatal(mActive, "Cannot end an inactive DeferredPNGWriter!"); AssertFatal(mActive, "DeferredPNGWriter::end - Writer is not active.");
png_write_end(mData->png_ptr, mData->info_ptr);
png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL);
png_write_end(mData->guard.png_ptr, mData->guard.info_ptr);
mActive = false; mActive = false;
} }

View file

@ -57,6 +57,24 @@
#include "gfx/gl/tGL/tXGL.h" #include "gfx/gl/tGL/tXGL.h"
#endif #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); GFXAdapter::CreateDeviceInstanceDelegate GFXGLDevice::mCreateDeviceInstance(GFXGLDevice::createInstance);
GFXDevice *GFXGLDevice::createInstance( U32 adapterIndex ) GFXDevice *GFXGLDevice::createInstance( U32 adapterIndex )
@ -104,6 +122,10 @@ void APIENTRY glDebugCallback(
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
return; 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* srcStr = "UNKNOWN";
const char* typeStr = "UNKNOWN"; const char* typeStr = "UNKNOWN";
const char* sevStr = "UNKNOWN"; const char* sevStr = "UNKNOWN";

View file

@ -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()); glGenerateMipmap(texture->getBinding());
glBindTexture(target, 0);
return true; return true;
} }
@ -560,10 +559,9 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
} }
} }
if (numMips != 1 && !isCompressed) if (numMips > 1 && !isCompressed)
glGenerateMipmap(texture->getBinding()); glGenerateMipmap(texture->getBinding());
glBindTexture(target, 0);
return true; return true;
} }
@ -608,7 +606,7 @@ bool GFXGLTextureManager::_refreshTexture(GFXTextureObject *texture)
_loadTexture(texture, texture->mBitmap); _loadTexture(texture, texture->mBitmap);
if(texture->mDDS) if(texture->mDDS)
return false; _loadTexture(texture, texture->mDDS);
usedStrategies++; usedStrategies++;
} }

View file

@ -105,76 +105,33 @@ void GFXGLTextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
if (!mLockedRect.bits) if (!mLockedRect.bits)
return; 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); PRESERVE_TEXTURE(mBinding);
glBindTexture(mBinding, mHandle); glBindTexture(mBinding, mHandle);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mBuffer);
// --- Save pixel store state --- glBufferData(GL_PIXEL_UNPACK_BUFFER, (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel, mFrameAllocatorPtr, GL_STREAM_DRAW);
GLint prevUnpackAlign; S32 z = getDepth();
glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlign);
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) if (mBinding == GL_TEXTURE_3D)
{ glTexSubImage3D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, z,
glTexSubImage3D( mLockedRectRect.extent.x, mLockedRectRect.extent.y, z, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL);
mBinding,
mipLevel,
mLockedRectRect.point.x,
mLockedRectRect.point.y,
0,
width,
height,
depth,
GFXGLTextureFormat[mFormat],
GFXGLTextureType[mFormat],
mLockedRect.bits
);
}
else if (mBinding == GL_TEXTURE_2D) else if (mBinding == GL_TEXTURE_2D)
{ glTexSubImage2D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y,
glTexSubImage2D( mLockedRectRect.extent.x, mLockedRectRect.extent.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL);
mBinding,
mipLevel,
mLockedRectRect.point.x,
mLockedRectRect.point.y,
width,
height,
GFXGLTextureFormat[mFormat],
GFXGLTextureType[mFormat],
mLockedRect.bits
);
}
else if (mBinding == GL_TEXTURE_1D) else if (mBinding == GL_TEXTURE_1D)
{ glTexSubImage1D(mBinding, mipLevel, (mLockedRectRect.point.x > 1 ? mLockedRectRect.point.x : mLockedRectRect.point.y),
glTexSubImage1D( (mLockedRectRect.extent.x > 1 ? mLockedRectRect.extent.x : mLockedRectRect.extent.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL);
mBinding,
mipLevel,
mLockedRectRect.point.x,
width,
GFXGLTextureFormat[mFormat],
GFXGLTextureType[mFormat],
mLockedRect.bits
);
}
// --- Restore state --- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlign);
mLockedRect.bits = NULL; mLockedRect.bits = NULL;
#if TORQUE_DEBUG
AssertFatal(mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(), "");
#endif
FrameAllocator::setWaterMark(mFrameAllocatorMark); FrameAllocator::setWaterMark(mFrameAllocatorMark);
mFrameAllocatorMark = 0; mFrameAllocatorMark = 0;
mFrameAllocatorPtr = NULL; mFrameAllocatorPtr = NULL;
#ifdef TORQUE_DEBUG
glCheckErrors();
#endif
} }
void GFXGLTextureObject::release() void GFXGLTextureObject::release()
@ -281,7 +238,6 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
} // face } // face
} // mip } // mip
glBindTexture(mBinding, 0);
return true; return true;
} }
@ -298,6 +254,9 @@ void GFXGLTextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const
const GLenum srcTarget = srcTex->getBinding(); // source binding const GLenum srcTarget = srcTex->getBinding(); // source binding
const bool srcIsCube = (srcTarget == GL_TEXTURE_CUBE_MAP || srcTarget == GL_TEXTURE_CUBE_MAP_ARRAY); 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 // Determine list of faces to copy from source
U32 firstFace = 0; U32 firstFace = 0;
U32 faceCount = 1; U32 faceCount = 1;
@ -435,9 +394,6 @@ void GFXGLTextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer); 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) void GFXGLTextureObject::bind(U32 textureUnit)
{ {
if (!mHandle || mIsZombie)
return;
glActiveTexture(GL_TEXTURE0 + textureUnit); glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(mBinding, mHandle); glBindTexture(mBinding, mHandle);
GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle); GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle);

View file

@ -1174,7 +1174,7 @@ GuiControl* GuiInspectorTypeColor::constructEditControl()
if( inspector->isMethod( "onInspectorPreFieldModification" ) ) if( inspector->isMethod( "onInspectorPreFieldModification" ) )
{ {
dSprintf( szBuffer, sizeof( szBuffer ), 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(), inspector->getId(), getRawFieldName(), getArrayIndex(),
mColorFunction, szColor, inspector->getId(), getId(), mColorFunction, szColor, inspector->getId(), getId(),
getId(), getId(),

View file

@ -434,25 +434,22 @@ void dampen(inout Surface surface, sampler2D WetnessTexture, float accumTime, fl
{ {
if (degree<=0.0) return; if (degree<=0.0) return;
vec3 n = abs(surface.N); 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); float speed = accumTime * (1.0 - surface.linearRoughnessSq);
if ((n.x > 0.0) || (n.y > 0.0)) vec3 wetoffset = (surface.P+vec3(speed,speed,speed)) * 0.33;
speed *= -1.0;
vec2 wetoffset = vec2(speed,speed)*0.1;
vec3 wetNormal = texture(WetnessTexture, float2(surface.P.xy*0.1+wetoffset)).xyz; vec3 wetNormal = texture(WetnessTexture, wetoffset.xy).xyz * (1.1-(n.z* n.z));
wetNormal = lerp(wetNormal,texture(WetnessTexture,float2(surface.P.zx*0.1+wetoffset)).rgb ,n.y); wetNormal = lerp(wetNormal, texture(WetnessTexture, wetoffset.zx).rgb, n.y);
wetNormal = lerp(wetNormal,texture(WetnessTexture,float2(surface.P.zy*0.1+wetoffset)).rgb ,n.x); wetNormal = lerp(wetNormal, texture(WetnessTexture, wetoffset.zy).rgb, n.x);
surface.N = lerp(surface.N, wetNormal, degree); wetNormal = normalize(wetNormal);
float wetness = wetNormal.b* degree;
float wetness = texture(WetnessTexture, vec2(surface.P.xy*0.1+wetoffset)).b; wetNormal = normalize(wetNormal * 2.0 - 1.0);
wetness = lerp(wetness,texture(WetnessTexture,vec2(surface.P.zx*0.1+wetoffset)).b,n.y); surface.N = normalize(vec3(surface.N.xy + wetNormal.xy * wetness, surface.N.z));
wetness = lerp(wetness,texture(WetnessTexture,vec2(surface.P.zy*0.1+wetoffset)).b,n.x);
wetness = pow(wetness*ang*degree,3);
surface.roughness = lerp(surface.roughness, 0.04f, wetness); 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); surface.metalness = lerp(surface.metalness, 0.96, wetness);
updateSurface(surface); updateSurface(surface);
} }

View file

@ -436,25 +436,22 @@ void dampen(inout Surface surface, TORQUE_SAMPLER2D(WetnessTexture), float accum
{ {
if (degree<=0.0) return; if (degree<=0.0) return;
float3 n = abs(surface.N); 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); float speed = accumTime * (1.0 - surface.linearRoughnessSq);
if ((n.x > 0.0) || (n.y > 0.0)) float3 wetoffset = (surface.P+float3(speed,speed,speed)) * 0.33;
speed *= -1.0;
float2 wetoffset = float2(speed,speed)*0.1;
float3 wetNormal = TORQUE_TEX2D(WetnessTexture, float2(surface.P.xy*0.1+wetoffset)).xyz; float3 wetNormal = TORQUE_TEX2D(WetnessTexture, wetoffset.xy).xyz * (1.1-(n.z* n.z));
wetNormal = lerp(wetNormal,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zx*0.1+wetoffset)).rgb ,n.y); wetNormal = lerp(wetNormal, TORQUE_TEX2D(WetnessTexture, wetoffset.zx).rgb, n.y);
wetNormal = lerp(wetNormal,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zy*0.1+wetoffset)).rgb ,n.x); wetNormal = lerp(wetNormal, TORQUE_TEX2D(WetnessTexture, wetoffset.zy).rgb, n.x);
surface.N = lerp(surface.N, wetNormal, degree); wetNormal = normalize(wetNormal);
float wetness = wetNormal.b* degree;
float wetness = TORQUE_TEX2D(WetnessTexture, float2(surface.P.xy*0.1+wetoffset)).b; wetNormal = normalize(wetNormal * 2.0 - 1.0);
wetness = lerp(wetness,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zx*0.1+wetoffset)).b,n.y); surface.N = normalize(float3(surface.N.xy + wetNormal.xy * wetness, surface.N.z));
wetness = lerp(wetness,TORQUE_TEX2D(WetnessTexture,float2(surface.P.zy*0.1+wetoffset)).b,n.x);
wetness = pow(wetness*ang*degree,3);
surface.roughness = lerp(surface.roughness, 0.04f, wetness); 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.metalness = lerp(surface.metalness, 0.96, wetness);
surface.Update(); surface.Update();
} }

View file

@ -2101,7 +2101,7 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
%popup.item[ 0 ] = "Delete" TAB "" TAB "EditorMenuEditDelete();"; %popup.item[ 0 ] = "Delete" TAB "" TAB "EditorMenuEditDelete();";
%popup.item[ 1 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );"; %popup.item[ 1 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );";
%popup.item[ 2 ] = "-"; %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[ 4 ] = "Bake selected into Mesh" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"ShapeAsset\", AssetBrowser.selectedModule, \"makeSelectedAMesh\");";
%popup.item[ 5 ] = "-"; %popup.item[ 5 ] = "-";
%popup.item[ 6 ] = "Make selected a Sub-Level" TAB "" TAB "MakeSelectionASublevel();"; %popup.item[ 6 ] = "Make selected a Sub-Level" TAB "" TAB "MakeSelectionASublevel();";