#include "gpuCacheSubSceneOverride.h"
#include "gpuCacheShapeNode.h"
#include "gpuCacheUnitBoundingBox.h"
#include "gpuCacheFrustum.h"
#include "gpuCacheUtil.h"
#include "CacheReader.h"
#include <boost/foreach.hpp>
#include <boost/unordered_set.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <tbb/tbb_thread.h>
#include <tbb/mutex.h>
#include <maya/MDagMessage.h>
#include <maya/MDGMessage.h>
#include <maya/MModelMessage.h>
#include <maya/MNodeMessage.h>
#include <maya/MSceneMessage.h>
#include <maya/MEventMessage.h>
#include <maya/MHWGeometryUtilities.h>
#include <maya/MAnimControl.h>
#include <maya/MDrawContext.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnDagNode.h>
#include <maya/MGlobal.h>
#include <maya/MItDag.h>
#include <maya/MSelectionContext.h>
#include <maya/MSelectionList.h>
#include <maya/MShaderManager.h>
#include <maya/MUserData.h>
namespace {
using namespace GPUCache;
template<typename T>
class ScopedGuard : boost::noncopyable
{
public:
ScopedGuard(T& value)
: fValueRef(value), fValueBackup(value)
{}
~ScopedGuard()
{
fValueRef = fValueBackup;
}
private:
T& fValueRef;
T fValueBackup;
};
tbb::tbb_thread::id gsMainThreadId = tbb::this_tbb_thread::get_id();
{
return mayaBuffer->
size();
}
{
}
template < typename T, typename C >
class MayaBufferArray : public Array<T>
{
class TempCopyReadableInterface : public ArrayReadInterface<T>
{
boost::shared_array<T> fLocalArray;
GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_1;
public:
TempCopyReadableInterface(boost::shared_array<T> localArray) : fLocalArray(localArray) {}
virtual ~TempCopyReadableInterface() {}
virtual const T* get() const { return fLocalArray.get(); }
};
public:
typedef typename Array<T>::Digest Digest;
static boost::shared_ptr<Array<T> > create(const boost::shared_ptr<C>& mayaBuffer, Digest digest)
{
size_t size = MayaBufferSizeHelper(mayaBuffer.get());
boost::shared_ptr<Array<T> > ret;
{
tbb::mutex::scoped_lock lock(ArrayRegistry<T>::mutex());
ret = ArrayRegistry<T>::lookupNonReadable(digest, size);
if (!ret) {
ret = boost::make_shared<MayaBufferArray<T, C> >(
mayaBuffer, digest);
ArrayRegistry<T>::insert(ret);
}
}
return ret;
}
virtual ~MayaBufferArray() {}
virtual boost::shared_ptr<const ArrayReadInterface<T> > getReadable() const
{
boost::shared_ptr<const TempCopyReadableInterface> ret(boost::make_shared<const TempCopyReadableInterface>(GetTempArrayCopy()));
return ret;
}
virtual boost::shared_ptr<ReadableArray<T> > getReadableArray() const
{
{
tbb::mutex::scoped_lock lock(ArrayRegistry<T>::mutex());
boost::shared_ptr<ReadableArray<T> > ret;
ret = ArrayRegistry<T>::lookupReadable(this->digest(), this->bytes());
if (ret)
return ret;
}
boost::shared_array<T> rawData(GetTempArrayCopy());
return SharedArray<T>::create(rawData, this->digest(), this->bytes()/sizeof(T));
}
boost::shared_ptr<C> getMBuffer() const
{
return fMayaBuffer;
}
private:
MayaBufferArray(const boost::shared_ptr<C>& mayaBuffer, Digest digest)
: Array<T>(MayaBufferSizeHelper(mayaBuffer.get()), digest, false)
, fMayaBuffer(mayaBuffer)
{}
MayaBufferArray(const MayaBufferArray& other);
boost::shared_array<T> GetTempArrayCopy() const
{
assert(gsMainThreadId == tbb::this_tbb_thread::get_id());
if (gsMainThreadId != tbb::this_tbb_thread::get_id())
return boost::shared_array<T>();
const T* src = (const T *)fMayaBuffer->map();
size_t numBytes = this->bytes();
size_t numValues = numBytes / sizeof(T);
boost::shared_array<T> rawData(new T[numValues]);
memcpy(rawData.get(), src, numBytes);
fMayaBuffer->unmap();
return rawData;
}
GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_2;
const boost::shared_ptr<C> fMayaBuffer;
};
template class MayaBufferArray<unsigned int, MHWRender::MIndexBuffer>;
template class MayaBufferArray<float, MHWRender::MVertexBuffer>;
typedef MayaBufferArray<unsigned int, MHWRender::MIndexBuffer> MayaIndexBufferWrapper;
typedef MayaBufferArray<float, MHWRender::MVertexBuffer> MayaVertexBufferWrapper;
class BuffersCache : boost::noncopyable
{
public:
static BuffersCache& getInstance()
{
static BuffersCache sSingleton;
return sSingleton;
}
void setBuffers(
SubSceneOverride& subSceneOverride,
const boost::shared_ptr<const IndexBuffer>& indices,
const boost::shared_ptr<const VertexBuffer>& positions,
const boost::shared_ptr<const VertexBuffer>& normals,
const boost::shared_ptr<const VertexBuffer>& uvs,
)
{
assert(positions);
if (!positions) return;
if (!renderItem) {
if (indices) {
acquireIndexBuffer(indices);
}
acquireVertexBuffer(positions);
if (normals) {
acquireVertexBuffer(normals);
}
if (uvs) {
acquireVertexBuffer(uvs);
}
return;
}
static const MString sPositions(
"positions");
static const MString sNormals(
"normals");
buffers.
addBuffer(sPositions, acquireVertexBuffer(positions));
if (normals) {
buffers.
addBuffer(sNormals, acquireVertexBuffer(normals));
}
if (uvs) {
buffers.
addBuffer(sUVs, acquireVertexBuffer(uvs));
}
subSceneOverride.setGeometryForRenderItem(
*renderItem,
buffers,
indices ? *acquireIndexBuffer(indices) :
MIndexBuffer(MGeometry::kUnsignedInt32),
&boundingBox
);
}
void removeBuffers(
const boost::shared_ptr<const IndexBuffer>& indices,
const boost::shared_ptr<const VertexBuffer>& positions,
const boost::shared_ptr<const VertexBuffer>& normals = boost::shared_ptr<const VertexBuffer>(),
const boost::shared_ptr<const VertexBuffer>& uvs = boost::shared_ptr<const VertexBuffer>()
)
{
if (indices) {
removeBufferFromCache(indices);
}
if (positions) {
removeBufferFromCache(positions);
}
if (normals) {
removeBufferFromCache(normals);
}
if (uvs) {
removeBufferFromCache(uvs);
}
}
void updateBuffers(
SubSceneOverride& subSceneOverride,
const boost::shared_ptr<const IndexBuffer>& indices,
const boost::shared_ptr<const VertexBuffer>& positions,
const boost::shared_ptr<const VertexBuffer>& normals,
const boost::shared_ptr<const VertexBuffer>& uvs,
const boost::shared_ptr<const IndexBuffer>& prevIndices,
const boost::shared_ptr<const VertexBuffer>& prevPositions,
const boost::shared_ptr<const VertexBuffer>& prevNormals = boost::shared_ptr<const VertexBuffer>(),
const boost::shared_ptr<const VertexBuffer>& prevUVs = boost::shared_ptr<const VertexBuffer>()
)
{
removeBuffers(prevIndices, prevPositions, prevNormals, prevUVs);
setBuffers(subSceneOverride, renderItem, indices, positions, normals, uvs, boundingBox);
}
MIndexBuffer* lookup(
const boost::shared_ptr<const IndexBuffer>& indices)
{
lookup(indices, buffer);
return buffer;
}
MVertexBuffer* lookup(
const boost::shared_ptr<const VertexBuffer>& vertices)
{
lookup(vertices, buffer);
return buffer;
}
void shrink()
{
doDeleteQueuedBuffers();
while (fTotalBufferSize > Config::maxVBOSize()) {
if (fFreeBuffers.empty()) break;
BufferSet::iterator it = fFreeBuffers.begin();
fTotalBufferSize -= (*it).bytes();
fFreeBuffers.erase(it);
}
}
void clear()
{
fTotalBufferSize = 0;
fActiveBuffers.clear();
fFreeBuffers.clear();
{
tbb::mutex::scoped_lock lock(fBuffersToDeleteMutex);
fBuffersToDelete.clear();
}
}
private:
class BufferEntry;
BuffersCache()
: fTotalBufferSize(0)
{
ArrayBase::registerDestructionCallback(sArrayDestructionCb);
}
~BuffersCache()
{
ArrayBase::unregisterDestructionCallback(sArrayDestructionCb);
}
MIndexBuffer* acquireIndexBuffer(
const boost::shared_ptr<const IndexBuffer>& indices)
{
assert(indices);
addBufferToCache(indices).getBuffer(buffer);
return buffer;
}
MVertexBuffer* acquireVertexBuffer(
const boost::shared_ptr<const VertexBuffer>& vertices)
{
assert(vertices);
addBufferToCache(vertices).getBuffer(buffer);
return buffer;
}
template<typename T>
const BufferEntry& addBufferToCache(const T& buffer)
{
BufferSet::iterator it = fActiveBuffers.find(buffer);
if (it != fActiveBuffers.end()) {
assert((*it).refCount() > 0);
(*it).ref();
return *it;
}
it = fFreeBuffers.find(buffer);
if (it != fFreeBuffers.end()) {
assert((*it).refCount() == 0);
BufferSet::iterator newIt = fActiveBuffers.insert(*it).first;
fFreeBuffers.erase(it);
(*newIt).ref();
return *newIt;
}
BufferSet::iterator newIt = fActiveBuffers.insert(buffer).first;
(*newIt).ref();
fTotalBufferSize += (*newIt).bytes();
return *newIt;
}
template<typename T>
void removeBufferFromCache(const T& buffer)
{
BufferSet::iterator it = fActiveBuffers.find(buffer);
assert(fFreeBuffers.find(buffer) == fFreeBuffers.end());
if (it != fActiveBuffers.end()) {
assert((*it).refCount() > 0);
(*it).unref();
if ((*it).refCount() == 0) {
fFreeBuffers.insert(*it);
fActiveBuffers.erase(it);
}
}
}
template<typename T, typename R>
void lookup(const T& buffer, R& pointer)
{
BufferSet::iterator it = fActiveBuffers.find(buffer);
if (it != fActiveBuffers.end()) {
assert((*it).refCount() > 0);
(*it).getBuffer(pointer);
return;
}
it = fFreeBuffers.find(buffer);
if (it != fFreeBuffers.end()) {
assert((*it).refCount() == 0);
(*it).getBuffer(pointer);
return;
}
pointer = NULL;
}
void queueBufferForDelete(const ArrayBase::Key& key)
{
tbb::mutex::scoped_lock lock(fBuffersToDeleteMutex);
fBuffersToDelete.insert(key);
}
void doDeleteQueuedBuffers()
{
if (!fBuffersToDelete.empty()) {
tbb::mutex::scoped_lock lock(fBuffersToDeleteMutex);
typedef BufferSet::nth_index<1>::type::iterator KeyIterator;
BOOST_FOREACH (const ArrayBase::Key& key, fBuffersToDelete) {
std::pair<KeyIterator,KeyIterator> range =
fFreeBuffers.get<1>().equal_range(key);
for (KeyIterator it = range.first; it != range.second; it++) {
assert((*it).refCount() == 0);
fTotalBufferSize -= (*it).bytes();
}
fFreeBuffers.get<1>().erase(key);
}
fBuffersToDelete.clear();
}
}
static void sArrayDestructionCb(const ArrayBase::Key& key)
{
BuffersCache::getInstance().queueBufferForDelete(key);
if (tbb::this_tbb_thread::get_id() == gsMainThreadId) {
BuffersCache::getInstance().doDeleteQueuedBuffers();
}
}
class BufferEntry
{
public:
struct BufferKey
{
enum BufferType { kIndex, kVertex };
BufferType type;
ArrayBase::Key arrayKey;
MGeometry::DataType dataType;
MGeometry::Semantic semantic;
BufferKey(const boost::shared_ptr<const IndexBuffer>& indices)
: type(kIndex),
arrayKey(indices->array()->key()),
dataType(MGeometry::kUnsignedInt32),
semantic(MGeometry::kInvalidSemantic)
{}
BufferKey(const boost::shared_ptr<const VertexBuffer>& vertices)
: type(kVertex),
arrayKey(vertices->array()->key()),
dataType(vertices->descriptor().dataType()),
semantic(vertices->descriptor().semantic())
{}
};
struct BufferKeyHash : std::unary_function<BufferKey, std::size_t>
{
std::size_t operator()(const BufferKey& key) const
{
std::size_t hashCode = 0;
boost::hash_combine(hashCode, key.type);
boost::hash_combine(hashCode, ArrayBase::KeyHash()(key.arrayKey));
boost::hash_combine(hashCode, key.dataType);
boost::hash_combine(hashCode, key.semantic);
return hashCode;
}
};
struct BufferKeyEqualTo : std::binary_function<BufferKey, BufferKey, bool>
{
bool operator()(const BufferKey& x, const BufferKey& y) const
{
return x.type == y.type &&
ArrayBase::KeyEqualTo()(x.arrayKey, y.arrayKey) &&
x.dataType == y.dataType &&
x.semantic == y.semantic;
}
};
BufferEntry(const boost::shared_ptr<const IndexBuffer>& indices)
: fKey(indices),
fRefCount(0)
{
if (indices->numIndices() > 0) {
if (!indices->array()->isReadable())
{
const MayaIndexBufferWrapper* mbufferWrapper = dynamic_cast<const MayaIndexBufferWrapper*>(indices->array().get());
assert(mbufferWrapper);
if (mbufferWrapper) {
boost::shared_ptr<MIndexBuffer> mbuffer = mbufferWrapper->getMBuffer();
assert(mbuffer);
if (mbuffer) {
fIndexBuffer = mbuffer;
return;
}
}
}
fIndexBuffer.reset(
new MIndexBuffer(MGeometry::kUnsignedInt32));
{
IndexBuffer::ReadInterfacePtr readable = indices->readableInterface();
const IndexBuffer::index_t* data = readable->get();
fIndexBuffer->update(data, 0, (unsigned int)indices->numIndices(), true);
}
if (indices->array()->isReadable()) {
boost::shared_ptr<Array<IndexBuffer::index_t> > mayaArray = MayaIndexBufferWrapper::create(fIndexBuffer, indices->array()->digest());
indices->ReplaceArrayInstance(mayaArray);
}
}
}
BufferEntry(const boost::shared_ptr<const VertexBuffer>& vertices)
: fKey(vertices),
fRefCount(0)
{
if (vertices->numVerts() > 0) {
assert(fKey.dataType == MGeometry::kFloat);
bool allowReplaceBufferArray = true;
if (!vertices->array()->isReadable())
{
const MayaVertexBufferWrapper* mbufferWrapper = dynamic_cast<const MayaVertexBufferWrapper*>(vertices->array().get());
assert(mbufferWrapper);
if (mbufferWrapper) {
boost::shared_ptr<MVertexBuffer> mbuffer = mbufferWrapper->getMBuffer();
assert(mbuffer);
if (mbuffer) {
if (mbuffer->descriptor().semantic() == vertices->descriptor().semantic()) {
fVertexBuffer = mbuffer;
return;
} else {
boost::shared_ptr<Array<float> > softwareArray = vertices->array()->getReadableArray();
vertices->ReplaceArrayInstance(softwareArray);
allowReplaceBufferArray = false;
}
}
}
}
{
VertexBuffer::ReadInterfacePtr readable = vertices->readableInterface();
const float* data = readable->get();
fVertexBuffer->update(data, 0, (unsigned int)vertices->numVerts(), true);
}
if (allowReplaceBufferArray && vertices->array()->isReadable()) {
boost::shared_ptr<Array<float> > mayaArray = MayaVertexBufferWrapper::create(fVertexBuffer, vertices->array()->digest());
vertices->ReplaceArrayInstance(mayaArray);
}
}
}
const BufferKey& key() const { return fKey; }
const ArrayBase::Key& arrayKey() const { return fKey.arrayKey; }
size_t bytes() const { return fKey.arrayKey.fBytes; }
{
assert(fIndexBuffer);
buffer = fIndexBuffer.get();
}
{
assert(fVertexBuffer);
buffer = fVertexBuffer.get();
}
void ref() const { fRefCount++; }
void unref() const { fRefCount--; }
size_t refCount() const { return fRefCount; }
private:
BufferKey fKey;
boost::shared_ptr<MIndexBuffer> fIndexBuffer;
boost::shared_ptr<MVertexBuffer> fVertexBuffer;
mutable size_t fRefCount;
};
typedef boost::multi_index_container<
BufferEntry,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_CONST_MEM_FUN(BufferEntry,const BufferEntry::BufferKey&,key),
BufferEntry::BufferKeyHash,
BufferEntry::BufferKeyEqualTo
>,
boost::multi_index::hashed_non_unique<
BOOST_MULTI_INDEX_CONST_MEM_FUN(BufferEntry,const ArrayBase::Key&,arrayKey),
ArrayBase::KeyHash,
ArrayBase::KeyEqualTo
>
>
> BufferSet;
typedef boost::unordered_set<
ArrayBase::Key,
ArrayBase::KeyHash,
ArrayBase::KeyEqualTo
> KeySet;
size_t fTotalBufferSize;
BufferSet fActiveBuffers;
BufferSet fFreeBuffers;
tbb::mutex fBuffersToDeleteMutex;
KeySet fBuffersToDelete;
};
class SubNodeUserData : boost::noncopyable
{
public:
SubNodeUserData(const SubNode& subNode)
: fSubNode(subNode)
{}
virtual ~SubNodeUserData()
{}
void hintShapeReadOrder() const
{
GlobalReaderCache::theCache().hintShapeReadOrder(fSubNode);
}
private:
const SubNode& fSubNode;
};
class SubNodeUserDataDelegate :
public MUserData
{
public:
SubNodeUserDataDelegate(const boost::shared_ptr<SubNodeUserData>& userData)
fUserData(userData)
{}
virtual ~SubNodeUserDataDelegate()
{}
void hintShapeReadOrder() const
{
if (fUserData)
fUserData->hintShapeReadOrder();
}
private:
boost::shared_ptr<SubNodeUserData> fUserData;
};
static void SetDashLinePattern(
MShaderInstance* shader,
unsigned short pattern)
{
static const MString sDashPattern =
"dashPattern";
unsigned short newPattern = pattern;
if (newPattern != 0) {
while ((newPattern & 0x8000) == 0) {
newPattern <<= 1;
}
}
}
void BoundingBoxPlaceHolderDrawCallback(
MDrawContext& context,
{
int numRenderItems = renderItemList.
length();
for (int i = 0; i < numRenderItems; i++) {
if (renderItem) {
SubNodeUserDataDelegate* userData =
dynamic_cast<SubNodeUserDataDelegate*
>(renderItem->
customData());
if (userData) {
userData->hintShapeReadOrder();
}
}
}
}
{
const DisplayPref::WireframeOnShadedMode wireOnShadedMode =
DisplayPref::wireframeOnShadedMode();
if (wireOnShadedMode == DisplayPref::kWireframeOnShadedFull) {
assert(0);
return;
}
if (displayStyle & (MDrawContext::kGouraudShaded | MDrawContext::kTextured)) {
const unsigned short pattern =
(wireOnShadedMode == DisplayPref::kWireframeOnShadedReduced)
? Config::kLineStippleDotted
: 0;
static const MString sDashPattern =
"dashPattern";
SetDashLinePattern(shader, pattern);
}
}
{
const DisplayPref::WireframeOnShadedMode wireOnShadedMode =
DisplayPref::wireframeOnShadedMode();
if (wireOnShadedMode == DisplayPref::kWireframeOnShadedFull) {
assert(0);
return;
}
SetDashLinePattern(shader, Config::kLineStippleShortDashed);
}
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return NULL;
if (!shaderMgr) return NULL;
}
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return NULL;
if (!shaderMgr) return NULL;
}
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return NULL;
if (!shaderMgr) return NULL;
WireframePreDrawCallback, WireframePostDrawCallback);
}
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return NULL;
if (!shaderMgr) return NULL;
NULL, BoundingBoxPlaceHolderDrawCallback);
}
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return NULL;
if (!shaderMgr) return NULL;
}
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return;
if (!shaderMgr) return;
if (shader) {
shader = NULL;
}
}
{
if (shader) {
const float color[3] = {diffuseColor.
r, diffuseColor.
g, diffuseColor.
b};
if (diffuseColor.
a < 1.0f) {
const float oneMinusAlpha =
(diffuseColor.
a >= 0.0f) ? 1.0f - diffuseColor.
a : 1.0f;
const float transparency[3] = {oneMinusAlpha, oneMinusAlpha, oneMinusAlpha};
}
else {
}
}
}
bool useHardwareInstancing()
{
static MPlug sHwInstancingPlug;
if (sHwInstancingPlug.
isNull()) {
sl.
add(
"hardwareRenderingGlobals.hwInstancing");
MStatAssert(stat);
}
return sHwInstancingPlug.
asBool() && Config::useHardwareInstancing();
}
class ShaderInstancePtr
{
public:
ShaderInstancePtr()
{}
ShaderInstancePtr(boost::shared_ptr<MShaderInstance> shader,
boost::shared_ptr<MShaderInstance> source)
: fShader(shader), fTemplate(source)
{}
~ShaderInstancePtr()
{}
operator bool () const
{
return fShader && fTemplate;
}
{
assert(fShader);
return fShader.get();
}
{
assert(fShader);
return fShader.get();
}
boost::shared_ptr<MShaderInstance> getShader() const
{
assert(fShader);
return fShader;
}
boost::shared_ptr<MShaderInstance> getTemplate() const
{
assert(fTemplate);
return fTemplate;
}
void reset()
{
fShader.reset();
fTemplate.reset();
}
bool operator==(const ShaderInstancePtr& rv) const
{
return fShader == rv.fShader && fTemplate == rv.fTemplate;
}
bool operator!=(const ShaderInstancePtr& rv) const
{
return !(operator==(rv));
}
private:
boost::shared_ptr<MShaderInstance> fShader;
boost::shared_ptr<MShaderInstance> fTemplate;
};
class ShaderTemplatePtr
{
public:
ShaderTemplatePtr()
{}
ShaderTemplatePtr(boost::shared_ptr<MShaderInstance> source)
: fTemplate(source)
{}
~ShaderTemplatePtr()
{}
operator bool () const
{
return (fTemplate.get() != NULL);
}
{
assert(fTemplate);
return fTemplate.get();
}
boost::shared_ptr<MShaderInstance> getTemplate() const
{
assert(fTemplate);
return fTemplate;
}
ShaderInstancePtr newShaderInstance(Deleter deleter) const
{
assert(fTemplate);
boost::shared_ptr<MShaderInstance> newShader;
newShader.reset(fTemplate->clone(), std::ptr_fun(deleter));
return ShaderInstancePtr(newShader, fTemplate);
}
private:
boost::shared_ptr<MShaderInstance> fTemplate;
};
class ShaderCache : boost::noncopyable
{
public:
static ShaderCache& getInstance()
{
static ShaderCache sSingleton;
return sSingleton;
}
ShaderInstancePtr newPointShader(Deleter deleter)
{
MString key =
"_reserved_point_shader_";
FragmentAndShaderTemplateCache::nth_index<0>::type::iterator it =
fFragmentCache.get<0>().find(key);
if (it != fFragmentCache.get<0>().end()) {
ShaderTemplatePtr templateShader = it->ptr.lock();
assert(templateShader);
return templateShader.newShaderInstance(deleter);
}
ShaderTemplatePtr templateShader =
wrapShaderTemplate(getPointShaderInstance());
if (templateShader) {
FragmentAndShaderTemplate entry;
entry.fragmentAndOutput = key;
entry.shader = templateShader.get();
entry.ptr = templateShader.getTemplate();
fFragmentCache.insert(entry);
return templateShader.newShaderInstance(deleter);
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr newWireShader(Deleter deleter)
{
MString key =
"_reserved_wire_shader_";
FragmentAndShaderTemplateCache::nth_index<0>::type::iterator it =
fFragmentCache.get<0>().find(key);
if (it != fFragmentCache.get<0>().end()) {
ShaderTemplatePtr templateShader = it->ptr.lock();
assert(templateShader);
return templateShader.newShaderInstance(deleter);
}
ShaderTemplatePtr templateShader =
wrapShaderTemplate(getWireShaderInstance());
if (templateShader) {
FragmentAndShaderTemplate entry;
entry.fragmentAndOutput = key;
entry.shader = templateShader.get();
entry.ptr = templateShader.getTemplate();
fFragmentCache.insert(entry);
return templateShader.newShaderInstance(deleter);
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr newWireShaderWithCB(Deleter deleter)
{
MString key =
"_reserved_wire_shader_with_cb_";
FragmentAndShaderTemplateCache::nth_index<0>::type::iterator it =
fFragmentCache.get<0>().find(key);
if (it != fFragmentCache.get<0>().end()) {
ShaderTemplatePtr templateShader = it->ptr.lock();
assert(templateShader);
return templateShader.newShaderInstance(deleter);
}
ShaderTemplatePtr templateShader =
wrapShaderTemplate(getWireShaderInstanceWithCB());
if (templateShader) {
FragmentAndShaderTemplate entry;
entry.fragmentAndOutput = key;
entry.shader = templateShader.get();
entry.ptr = templateShader.getTemplate();
fFragmentCache.insert(entry);
return templateShader.newShaderInstance(deleter);
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr newBoundingBoxPlaceHolderShader(Deleter deleter)
{
MString key =
"_reserved_bounding_box_place_holder_shader_";
FragmentAndShaderTemplateCache::nth_index<0>::type::iterator it =
fFragmentCache.get<0>().find(key);
if (it != fFragmentCache.get<0>().end()) {
ShaderTemplatePtr templateShader = it->ptr.lock();
assert(templateShader);
return templateShader.newShaderInstance(deleter);
}
ShaderTemplatePtr templateShader =
wrapShaderTemplate(getBoundingBoxPlaceHolderShaderInstance());
if (templateShader) {
FragmentAndShaderTemplate entry;
entry.fragmentAndOutput = key;
entry.shader = templateShader.get();
entry.ptr = templateShader.getTemplate();
fFragmentCache.insert(entry);
return templateShader.newShaderInstance(deleter);
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr newDiffuseColorShader(Deleter deleter)
{
MString key =
"_reserved_diffuse_color_shader_";
FragmentAndShaderTemplateCache::nth_index<0>::type::iterator it =
fFragmentCache.get<0>().find(key);
if (it != fFragmentCache.get<0>().end()) {
ShaderTemplatePtr templateShader = it->ptr.lock();
assert(templateShader);
return templateShader.newShaderInstance(deleter);
}
ShaderTemplatePtr templateShader =
wrapShaderTemplate(getDiffuseColorShaderInstance());
if (templateShader) {
FragmentAndShaderTemplate entry;
entry.fragmentAndOutput = key;
entry.shader = templateShader.get();
entry.ptr = templateShader.getTemplate();
fFragmentCache.insert(entry);
return templateShader.newShaderInstance(deleter);
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr newFragmentShader(
const MString& fragmentName,
Deleter deleter)
{
MString key = fragmentName +
":" + outputStructName;
FragmentAndShaderTemplateCache::nth_index<0>::type::iterator it =
fFragmentCache.get<0>().find(key);
if (it != fFragmentCache.get<0>().end()) {
ShaderTemplatePtr templateShader = it->ptr.lock();
assert(templateShader);
return templateShader.newShaderInstance(deleter);
}
ShaderTemplatePtr templateShader =
createFragmentShader(fragmentName, outputStructName);
if (templateShader) {
FragmentAndShaderTemplate entry;
entry.fragmentAndOutput = key;
entry.shader = templateShader.get();
entry.ptr = templateShader.getTemplate();
fFragmentCache.insert(entry);
return templateShader.newShaderInstance(deleter);
}
assert(0);
return ShaderInstancePtr();
}
private:
ShaderCache() {}
~ShaderCache() {}
{
assert(shader);
getInstance().removeShaderTemplateFromCache(shader);
releaseShaderInstance(shader);
}
{
assert(shader);
if (!shader) return;
fFragmentCache.get<1>().erase(shader);
}
{
assert(shader);
if (!shader) return ShaderTemplatePtr();
boost::shared_ptr<MShaderInstance> ptr;
ptr.reset(shader, std::ptr_fun(shaderTemplateDeleter));
return ShaderTemplatePtr(ptr);
}
ShaderTemplatePtr createFragmentShader(
const MString& fragmentName,
{
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return ShaderTemplatePtr();
if (!shaderMgr) return ShaderTemplatePtr();
return wrapShaderTemplate(
}
private:
struct FragmentAndShaderTemplate {
boost::weak_ptr<MShaderInstance> ptr;
};
typedef boost::multi_index_container<
FragmentAndShaderTemplate,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_MEMBER(FragmentAndShaderTemplate,
MString,fragmentAndOutput),
MStringHash
>,
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_MEMBER(FragmentAndShaderTemplate,
MShaderInstance*,shader)
>
>
> FragmentAndShaderTemplateCache;
FragmentAndShaderTemplateCache fFragmentCache;
};
class MaterialGraphTranslatorShaded : public ConcreteMaterialNodeVisitor
{
public:
MaterialGraphTranslatorShaded(Deleter deleter, double timeInSeconds)
: fShader(), fDeleter(deleter), fTimeInSeconds(timeInSeconds)
{}
MaterialGraphTranslatorShaded(ShaderInstancePtr& shader, double timeInSeconds)
: fShader(shader), fDeleter(NULL), fTimeInSeconds(timeInSeconds)
{}
virtual ~MaterialGraphTranslatorShaded() {}
ShaderInstancePtr getShader() const
{ return fShader; }
virtual void visit(const LambertMaterial& node)
{
if (!fShader) {
createShader("mayaLambertSurface", "outSurfaceFinal");
}
setupLambert(node);
}
virtual void visit(const PhongMaterial& node)
{
if (!fShader) {
createShader("mayaPhongSurface", "outSurfaceFinal");
}
setupPhong(node);
setupLambert(node);
}
virtual void visit(const BlinnMaterial& node)
{
if (!fShader) {
createShader("mayaBlinnSurface", "outSurfaceFinal");
}
setupBlinn(node);
setupLambert(node);
}
virtual void visit(const SurfaceMaterial& node) {}
virtual void visit(const Texture2d& node) {}
virtual void visit(const FileTexture& node) {}
private:
void createShader(
const MString& fragmentName,
{
assert(fDeleter);
fShader = ShaderCache::getInstance().newFragmentShader(
fragmentName, structOutputName, fDeleter);
assert(fShader);
}
void setupLambert(const LambertMaterial& lambert)
{
if (!fShader) return;
{
ShadedModeColor::evaluateDefaultColor(lambert.Color, fTimeInSeconds);
const float buffer[3] = {color.
r, color.
g, color.
b};
fShader->setParameter("color", buffer);
}
{
ShadedModeColor::evaluateColor(lambert.Transparency, fTimeInSeconds);
const float buffer[3] = {transparency.
r, transparency.
g, transparency.
b};
fShader->setParameter("transparency", buffer);
if (transparency.
r > 0 || transparency.
g > 0 || transparency.
b > 0) {
fShader->setIsTransparent(true);
}
else {
fShader->setIsTransparent(false);
}
}
{
ShadedModeColor::evaluateColor(lambert.AmbientColor, fTimeInSeconds);
const float buffer[3] = {ambientColor.
r, ambientColor.
g, ambientColor.
b};
fShader->setParameter("ambientColor", buffer);
}
{
ShadedModeColor::evaluateColor(lambert.Incandescence, fTimeInSeconds);
const float buffer[3] = {incandescence.
r, incandescence.
g, incandescence.
b};
fShader->setParameter("incandescence", buffer);
}
{
const float diffuse =
ShadedModeColor::evaluateFloat(lambert.Diffuse, fTimeInSeconds);
fShader->setParameter("diffuse", diffuse);
}
{
const float translucence =
ShadedModeColor::evaluateFloat(lambert.Translucence, fTimeInSeconds);
fShader->setParameter("translucence", translucence);
}
{
const float translucenceDepth =
ShadedModeColor::evaluateFloat(lambert.TranslucenceDepth, fTimeInSeconds);
fShader->setParameter("translucenceDepth", translucenceDepth);
}
{
const float translucenceFocus =
ShadedModeColor::evaluateFloat(lambert.TranslucenceFocus, fTimeInSeconds);
fShader->setParameter("translucenceFocus", translucenceFocus);
}
{
const bool hideSource =
ShadedModeColor::evaluateBool(lambert.HideSource, fTimeInSeconds);
fShader->setParameter("hideSource", hideSource);
}
{
const float glowIntensity =
ShadedModeColor::evaluateFloat(lambert.GlowIntensity, fTimeInSeconds);
fShader->setParameter("glowIntensity", glowIntensity);
}
}
void setupPhong(const PhongMaterial& phong)
{
if (!fShader) return;
{
const float cosinePower =
ShadedModeColor::evaluateFloat(phong.CosinePower, fTimeInSeconds);
fShader->setParameter("cosinePower", cosinePower);
}
{
ShadedModeColor::evaluateColor(phong.SpecularColor, fTimeInSeconds);
const float buffer[3] = {specularColor.
r, specularColor.
g, specularColor.
b};
fShader->setParameter("specularColor", buffer);
}
{
const float reflectivity =
ShadedModeColor::evaluateFloat(phong.Reflectivity, fTimeInSeconds);
fShader->setParameter("reflectivity", reflectivity);
}
{
ShadedModeColor::evaluateColor(phong.ReflectedColor, fTimeInSeconds);
const float buffer[3] = {reflectedColor.
r, reflectedColor.
g, reflectedColor.
b};
fShader->setParameter("reflectedColor", buffer);
}
}
void setupBlinn(const BlinnMaterial& blinn)
{
if (!fShader) return;
{
const float eccentricity =
ShadedModeColor::evaluateFloat(blinn.Eccentricity, fTimeInSeconds);
fShader->setParameter("eccentricity", eccentricity);
}
{
const float specularRollOff =
ShadedModeColor::evaluateFloat(blinn.SpecularRollOff, fTimeInSeconds);
fShader->setParameter("specularRollOff", specularRollOff);
}
{
ShadedModeColor::evaluateColor(blinn.SpecularColor, fTimeInSeconds);
const float buffer[3] = {specularColor.
r, specularColor.
g, specularColor.
b};
fShader->setParameter("specularColor", buffer);
}
{
const float reflectivity =
ShadedModeColor::evaluateFloat(blinn.Reflectivity, fTimeInSeconds);
fShader->setParameter("reflectivity", reflectivity);
}
{
ShadedModeColor::evaluateColor(blinn.ReflectedColor, fTimeInSeconds);
const float buffer[3] = {reflectedColor.
r, reflectedColor.
g, reflectedColor.
b};
fShader->setParameter("reflectedColor", buffer);
}
}
ShaderInstancePtr fShader;
Deleter fDeleter;
const double fTimeInSeconds;
};
class ShaderInstanceCache : boost::noncopyable
{
public:
static ShaderInstanceCache& getInstance()
{
static ShaderInstanceCache sSingleton;
return sSingleton;
}
ShaderInstancePtr getSharedPointShader()
{
ColorAndShaderInstanceCache::nth_index<0>::type::iterator it =
fPointShaders.get<0>().find(color);
if (it != fPointShaders.get<0>().end()) {
boost::shared_ptr<MShaderInstance> shader = it->ptr.lock();
assert(shader);
return ShaderInstancePtr(shader, it->source);
}
ShaderInstancePtr shader =
ShaderCache::getInstance().newPointShader(shaderInstanceDeleter);
if (shader) {
const float solidColor[4] = {color.
r, color.
g, color.
b, 1.0f};
shader->setParameter("solidColor", solidColor);
ColorAndShaderInstance entry;
entry.color = color;
entry.shader = shader.get();
entry.ptr = shader.getShader();
entry.source = shader.getTemplate();
fPointShaders.insert(entry);
return shader;
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr getSharedWireShader(
const MColor& color)
{
ColorAndShaderInstanceCache::nth_index<0>::type::iterator it =
fWireShaders.get<0>().find(color);
if (it != fWireShaders.get<0>().end()) {
boost::shared_ptr<MShaderInstance> shader = it->ptr.lock();
assert(shader);
return ShaderInstancePtr(shader, it->source);
}
ShaderInstancePtr shader =
ShaderCache::getInstance().newWireShader(shaderInstanceDeleter);
if (shader) {
SetDashLinePattern(shader.get(), Config::kLineStippleShortDashed);
const float solidColor[4] = {color.
r, color.
g, color.
b, 1.0f};
shader->setParameter("solidColor", solidColor);
ColorAndShaderInstance entry;
entry.color = color;
entry.shader = shader.get();
entry.ptr = shader.getShader();
entry.source = shader.getTemplate();
fWireShaders.insert(entry);
return shader;
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr getSharedWireShaderWithCB(
const MColor& color)
{
ColorAndShaderInstanceCache::nth_index<0>::type::iterator it =
fWireShadersWithCB.get<0>().find(color);
if (it != fWireShadersWithCB.get<0>().end()) {
boost::shared_ptr<MShaderInstance> shader = it->ptr.lock();
assert(shader);
return ShaderInstancePtr(shader, it->source);
}
ShaderInstancePtr shader =
ShaderCache::getInstance().newWireShaderWithCB(shaderInstanceDeleter);
if (shader) {
SetDashLinePattern(shader.get(), Config::kLineStippleShortDashed);
const float solidColor[4] = {color.
r, color.
g, color.
b, 1.0f};
shader->setParameter("solidColor", solidColor);
ColorAndShaderInstance entry;
entry.color = color;
entry.shader = shader.get();
entry.ptr = shader.getShader();
entry.source = shader.getTemplate();
fWireShadersWithCB.insert(entry);
return shader;
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr getSharedBoundingBoxPlaceHolderShader(
const MColor& color)
{
ColorAndShaderInstanceCache::nth_index<0>::type::iterator it =
fBoundingBoxPlaceHolderShaders.get<0>().find(color);
if (it != fBoundingBoxPlaceHolderShaders.get<0>().end()) {
boost::shared_ptr<MShaderInstance> shader = it->ptr.lock();
assert(shader);
return ShaderInstancePtr(shader, it->source);
}
ShaderInstancePtr shader =
ShaderCache::getInstance().newBoundingBoxPlaceHolderShader(shaderInstanceDeleter);
if (shader) {
SetDashLinePattern(shader.get(), Config::kLineStippleShortDashed);
const float solidColor[4] = {color.
r, color.
g, color.
b, 1.0f};
shader->setParameter("solidColor", solidColor);
ColorAndShaderInstance entry;
entry.color = color;
entry.shader = shader.get();
entry.ptr = shader.getShader();
entry.source = shader.getTemplate();
fBoundingBoxPlaceHolderShaders.insert(entry);
return shader;
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr getSharedDiffuseColorShader(
const MColor& color)
{
ColorAndShaderInstanceCache::nth_index<0>::type::iterator it =
fDiffuseColorShaders.get<0>().find(color);
if (it != fDiffuseColorShaders.get<0>().end()) {
boost::shared_ptr<MShaderInstance> shader = it->ptr.lock();
assert(shader);
return ShaderInstancePtr(shader, it->source);
}
ShaderInstancePtr shader =
ShaderCache::getInstance().newDiffuseColorShader(shaderInstanceDeleter);
if (shader) {
setDiffuseColor(shader.get(), color);
ColorAndShaderInstance entry;
entry.color = color;
entry.shader = shader.get();
entry.ptr = shader.getShader();
entry.source = shader.getTemplate();
fDiffuseColorShaders.insert(entry);
return shader;
}
assert(0);
return ShaderInstancePtr();
}
ShaderInstancePtr getUniqueDiffuseColorShader(
const MColor& color)
{
ShaderInstancePtr shader =
ShaderCache::getInstance().newDiffuseColorShader(shaderInstanceDeleter);
if (shader) {
setDiffuseColor(shader.get(), color);
return shader;
}
return ShaderInstancePtr();
}
ShaderInstancePtr getSharedShadedMaterialShader(
const MaterialGraph::Ptr& material,
double timeInSeconds
)
{
assert(material);
if (!material) return ShaderInstancePtr();
MaterialAndShaderInstanceCache::nth_index<0>::type::iterator it =
fShadedMaterialShaders.get<0>().find(material);
if (it != fShadedMaterialShaders.get<0>().end()) {
boost::shared_ptr<MShaderInstance> shader = it->ptr.lock();
assert(shader);
return ShaderInstancePtr(shader, it->source);
}
const MaterialNode::Ptr& rootNode = material->rootNode();
assert(rootNode);
ShaderInstancePtr shader;
if (rootNode) {
MaterialGraphTranslatorShaded shadedTranslator(shaderInstanceDeleter, timeInSeconds);
rootNode->accept(shadedTranslator);
shader = shadedTranslator.getShader();
}
if (shader) {
MaterialAndShaderInstance entry;
entry.material = material;
entry.shader = shader.get();
entry.ptr = shader.getShader();
entry.source = shader.getTemplate();
entry.isAnimated = material->isAnimated();
entry.timeInSeconds = timeInSeconds;
fShadedMaterialShaders.insert(entry);
return shader;
}
assert(0);
return ShaderInstancePtr();
}
void updateCachedShadedShaders(double timeInSeconds)
{
BOOST_FOREACH (const MaterialAndShaderInstance& entry, fShadedMaterialShaders) {
if (!entry.isAnimated) continue;
if (entry.timeInSeconds == timeInSeconds) continue;
const MaterialNode::Ptr& rootNode = entry.material->rootNode();
if (rootNode) {
ShaderInstancePtr shader(entry.ptr.lock(), entry.source);
if (shader) {
MaterialGraphTranslatorShaded shadedTranslator(shader, timeInSeconds);
rootNode->accept(shadedTranslator);
}
}
entry.timeInSeconds = timeInSeconds;
}
}
private:
{
assert(shader);
getInstance().removeShaderInstanceFromCache(shader);
releaseShaderInstance(shader);
}
{
assert(shader);
if (!shader) return;
fPointShaders.get<1>().erase(shader);
fWireShaders.get<1>().erase(shader);
fWireShadersWithCB.get<1>().erase(shader);
fBoundingBoxPlaceHolderShaders.get<1>().erase(shader);
fDiffuseColorShaders.get<1>().erase(shader);
fShadedMaterialShaders.get<1>().erase(shader);
}
private:
ShaderInstanceCache() {}
~ShaderInstanceCache() {}
struct MColorHash : std::unary_function<MColor, std::size_t>
{
std::size_t operator()(
const MColor& key)
const
{
std::size_t seed = 0;
boost::hash_combine(seed, key.
r);
boost::hash_combine(seed, key.
g);
boost::hash_combine(seed, key.
b);
boost::hash_combine(seed, key.
a);
return seed;
}
};
struct MaterialGraphHash : std::unary_function<MaterialGraph::Ptr, std::size_t>
{
std::size_t operator()(const MaterialGraph::Ptr& key) const
{
return boost::hash_value(key.get());
}
};
struct ColorAndShaderInstance {
boost::weak_ptr<MShaderInstance> ptr;
boost::shared_ptr<MShaderInstance> source;
};
typedef boost::multi_index_container<
ColorAndShaderInstance,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_MEMBER(ColorAndShaderInstance,
MColor,color),
MColorHash
>,
boost::multi_index::hashed_unique<
>
>
> ColorAndShaderInstanceCache;
struct MaterialAndShaderInstance {
MaterialGraph::Ptr material;
boost::weak_ptr<MShaderInstance> ptr;
boost::shared_ptr<MShaderInstance> source;
bool isAnimated;
mutable double timeInSeconds;
};
typedef boost::multi_index_container<
MaterialAndShaderInstance,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_MEMBER(MaterialAndShaderInstance,MaterialGraph::Ptr,material),
MaterialGraphHash
>,
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_MEMBER(MaterialAndShaderInstance,
MShaderInstance*,shader)
>
>
> MaterialAndShaderInstanceCache;
ColorAndShaderInstanceCache fPointShaders;
ColorAndShaderInstanceCache fWireShaders;
ColorAndShaderInstanceCache fWireShadersWithCB;
ColorAndShaderInstanceCache fBoundingBoxPlaceHolderShaders;
ColorAndShaderInstanceCache fDiffuseColorShaders;
MaterialAndShaderInstanceCache fShadedMaterialShaders;
};
class RenderItemWrapper;
class HardwareInstanceManagerImpl;
class HardwareInstanceData : boost::noncopyable
{
public:
HardwareInstanceData(HardwareInstanceManagerImpl* manager,
RenderItemWrapper* renderItem)
: fMasterData(NULL),
fInstanceId(0),
fRenderItem(renderItem),
fManager(manager)
{}
~HardwareInstanceData()
{}
HardwareInstanceData* masterData() const { return fMasterData; }
unsigned int instanceId() const { return fInstanceId; }
RenderItemWrapper* renderItem() const { return fRenderItem; }
bool isInstanced() const { return fInstanceId > 0; }
bool isMasterItem() const { return fMasterData == this; }
void setupCandidate(HardwareInstanceData* master)
{
assert(master);
fMasterData = master;
fInstanceId = 0;
}
void setupInstance(HardwareInstanceData* master, unsigned int instanceId)
{
assert(master);
assert(instanceId > 0);
fMasterData = master;
fInstanceId = instanceId;
}
void clearInstanceData()
{
fMasterData = NULL;
fInstanceId = 0;
}
void notifyInstancingChange();
void notifyInstancingClear();
void notifyWorldMatrixChange();
void notifyDestroy();
private:
HardwareInstanceData* fMasterData;
unsigned int fInstanceId;
RenderItemWrapper* fRenderItem;
HardwareInstanceManagerImpl* fManager;
};
class RenderItemWrapper : boost::noncopyable
{
public:
typedef boost::shared_ptr<RenderItemWrapper> Ptr;
RenderItemWrapper(
const MString& name,
const MGeometry::Primitive primitive)
: fName(name),
fType(type),
fPrimitive(primitive),
fRenderItem(NULL),
fEnabled(true),
fDepthPriority(
MRenderItem::sDormantFilledDepthPriority),
fIsPointSnapping(false),
fExcludedFromPostEffects(true),
fCastsShadows(false),
fReceivesShadows(false)
{
fRenderItem = MRenderItem::Create(
name,
type,
primitive
);
assert(fRenderItem);
fRenderItem->setSelectionMask(gpuCacheMask);
}
~RenderItemWrapper()
{
BuffersCache::getInstance().removeBuffers(
fIndices,
fPositions,
fNormals,
fUVs
);
notifyDestroy();
}
{
assert(fRenderItem);
container.
add(fRenderItem);
}
{
if (fRenderItem) {
assert(fName == fRenderItem->name());
fRenderItem->setCustomData(NULL);
fRenderItem = NULL;
}
}
void setEnabled(bool enabled)
{
if (fEnabled != enabled) {
if (fRenderItem) {
fRenderItem->enable(enabled);
}
fEnabled = enabled;
if (fType == MRenderItem::MaterialSceneItem) {
MRenderer::setLightsAndShadowsDirty();
}
notifyInstancingChange();
}
}
void setWorldMatrix(
const MMatrix& worldMatrix)
{
if (fWorldMatrix != worldMatrix) {
if (fRenderItem) {
fRenderItem->setMatrix(&worldMatrix);
}
fWorldMatrix = worldMatrix;
if (fType == MRenderItem::MaterialSceneItem) {
MRenderer::setLightsAndShadowsDirty();
}
notifyWorldMatrixChange();
}
}
void setBuffers(SubSceneOverride& subSceneOverride,
const boost::shared_ptr<const IndexBuffer>& indices,
const boost::shared_ptr<const VertexBuffer>& positions,
const boost::shared_ptr<const VertexBuffer>& normals,
const boost::shared_ptr<const VertexBuffer>& uvs,
{
const bool buffersChanged =
fIndices != indices ||
fPositions != positions ||
fNormals != normals ||
fUVs != uvs;
if (buffersChanged) {
BuffersCache::getInstance().updateBuffers(
subSceneOverride,
fRenderItem,
indices,
positions,
normals,
uvs,
boundingBox,
fIndices,
fPositions,
fNormals,
fUVs
);
fIndices = indices;
fPositions = positions;
fNormals = normals;
fUVs = uvs;
fBoundingBox = boundingBox;
if (fType == MRenderItem::MaterialSceneItem) {
MRenderer::setLightsAndShadowsDirty();
}
notifyInstancingClear();
}
}
void setShader(const ShaderInstancePtr& shader)
{
if (fShader != shader) {
if (fRenderItem) {
fRenderItem->setShader(shader.get());
}
fShader = shader;
notifyInstancingClear();
}
}
void setCustomData(const boost::shared_ptr<SubNodeUserData>& userData)
{
if (fUserData != userData) {
if (fRenderItem) {
fRenderItem->setCustomData(new SubNodeUserDataDelegate(userData));
}
fUserData = userData;
notifyInstancingChange();
}
}
void setDrawMode(MGeometry::DrawMode drawMode)
{
if (fDrawMode != drawMode) {
if (fRenderItem) {
fRenderItem->setDrawMode(drawMode);
}
fDrawMode = drawMode;
notifyInstancingChange();
}
}
void setSnappingSelectionMask()
{
if (!fIsPointSnapping) {
if (fRenderItem) {
fRenderItem->setSelectionMask(pointsForGravityMask);
}
fIsPointSnapping = true;
notifyInstancingChange();
}
}
void setDepthPriority(unsigned int depthPriority)
{
if (fDepthPriority != depthPriority) {
if (fRenderItem) {
fRenderItem->depthPriority(depthPriority);
}
fDepthPriority = depthPriority;
notifyInstancingChange();
}
}
void setExcludedFromPostEffects(bool exclude)
{
if (fExcludedFromPostEffects != exclude) {
if (fRenderItem) {
fRenderItem->setExcludedFromPostEffects(exclude);
}
fExcludedFromPostEffects = exclude;
notifyInstancingChange();
}
}
void setCastsShadows(bool cast)
{
if (fCastsShadows != cast) {
if (fRenderItem) {
fRenderItem->castsShadows(cast);
}
fCastsShadows = cast;
if (fType == MRenderItem::MaterialSceneItem) {
MRenderer::setLightsAndShadowsDirty();
}
notifyInstancingChange();
}
}
void setReceivesShadows(bool receive)
{
if (fReceivesShadows != receive) {
if (fRenderItem) {
fRenderItem->receivesShadows(receive);
}
fReceivesShadows = receive;
notifyInstancingChange();
}
}
void setCompatibleWithMayaInstancer(bool state)
{
if (fRenderItem && fRenderItem->isCompatibleWithMayaInstancer() != state)
{
fRenderItem->setCompatibleWithMayaInstancer(state);
}
}
void installHardwareInstanceData(const boost::shared_ptr<HardwareInstanceData>& data)
{
fHardwareInstanceData = data;
notifyInstancingChange();
}
void removeHardwareInstanceData(SubSceneOverride& subSceneOverride,
{
if (fHardwareInstanceData) {
if (fHardwareInstanceData->isInstanced()) {
if (fRenderItem) {
unloadItem(container);
}
assert(!fRenderItem);
loadItem(subSceneOverride, container);
}
fHardwareInstanceData.reset();
}
}
bool hasHardwareInstanceData()
{
return fHardwareInstanceData.get() != NULL;
}
{
if (!fRenderItem) return;
removeFromContainer(container);
fRenderItem = NULL;
}
void loadItem(SubSceneOverride& subSceneOverride,
{
if (fRenderItem) return;
fRenderItem = MRenderItem::Create(
fName,
fType,
fPrimitive
);
assert(fRenderItem);
addToContainer(container);
fRenderItem->setCustomData(new SubNodeUserDataDelegate(fUserData));
fRenderItem->enable(fEnabled);
fRenderItem->setMatrix(&fWorldMatrix);
fRenderItem->setDrawMode(fDrawMode);
fRenderItem->depthPriority(fDepthPriority);
fRenderItem->setExcludedFromPostEffects(fExcludedFromPostEffects);
fRenderItem->castsShadows(fCastsShadows);
fRenderItem->receivesShadows(fReceivesShadows);
fRenderItem->setShader(fShader.get());
fRenderItem->setCompatibleWithMayaInstancer(true);
if (fIsPointSnapping)
{
fRenderItem->setSelectionMask(pointsForGravityMask);
}
else
{
fRenderItem->setSelectionMask(gpuCacheMask);
}
BuffersCache::getInstance().updateBuffers(
subSceneOverride,
fRenderItem,
fIndices,
fPositions,
fNormals,
fUVs,
fBoundingBox,
fIndices,
fPositions,
fNormals,
fUVs
);
}
const MString& name()
const {
return fName; }
const MGeometry::Primitive primitive() const { return fPrimitive; }
const boost::shared_ptr<SubNodeUserData>& userData() const { return fUserData; }
const boost::shared_ptr<const IndexBuffer>& indices() const { return fIndices; }
const boost::shared_ptr<const VertexBuffer>& positions() const { return fPositions; }
const boost::shared_ptr<const VertexBuffer>& normals() const { return fNormals; }
const boost::shared_ptr<const VertexBuffer>& uvs() const { return fUVs; }
const MBoundingBox& boundingBox()
const {
return fBoundingBox; }
bool enabled() const { return fEnabled; }
const MMatrix& worldMatrix()
const {
return fWorldMatrix; }
MGeometry::DrawMode drawMode() const { return fDrawMode; }
unsigned int depthPriority() const { return fDepthPriority; }
bool excludedFromPostEffects() const { return fExcludedFromPostEffects; }
bool castsShadows() const { return fCastsShadows; }
bool receivesShadows() const { return fReceivesShadows; }
bool isCompatibleWithMayaInstancer() const { return fRenderItem ? fRenderItem->isCompatibleWithMayaInstancer() : false; }
const ShaderInstancePtr& shader() const { return fShader; }
MRenderItem* wrappedItem()
const {
return fRenderItem; }
private:
void notifyInstancingChange()
{
if (fHardwareInstanceData) {
fHardwareInstanceData->notifyInstancingChange();
}
}
void notifyInstancingClear()
{
if (fHardwareInstanceData) {
fHardwareInstanceData->notifyInstancingClear();
}
}
void notifyWorldMatrixChange()
{
if (fHardwareInstanceData) {
fHardwareInstanceData->notifyWorldMatrixChange();
}
}
void notifyDestroy()
{
if (fHardwareInstanceData) {
fHardwareInstanceData->notifyDestroy();
}
}
private:
const MGeometry::Primitive fPrimitive;
boost::shared_ptr<SubNodeUserData> fUserData;
boost::shared_ptr<const IndexBuffer> fIndices;
boost::shared_ptr<const VertexBuffer> fPositions;
boost::shared_ptr<const VertexBuffer> fNormals;
boost::shared_ptr<const VertexBuffer> fUVs;
bool fEnabled;
MGeometry::DrawMode fDrawMode;
unsigned int fDepthPriority;
bool fIsPointSnapping;
bool fExcludedFromPostEffects;
bool fCastsShadows;
bool fReceivesShadows;
ShaderInstancePtr fShader;
boost::shared_ptr<HardwareInstanceData> fHardwareInstanceData;
};
class HardwareInstanceManagerImpl : boost::noncopyable
{
public:
HardwareInstanceManagerImpl(SubSceneOverride& subSceneOverride)
: fSubSceneOverride(subSceneOverride)
{}
~HardwareInstanceManagerImpl()
{}
{
removePendingInstances(container);
updateInstanceTransforms();
boost::unordered_set<HardwareInstanceData*> dirtySourceItems;
extractDirtySourceItems(container, dirtySourceItems);
boost::unordered_set<HardwareInstanceData*> dirtyCandidates;
processDirtySourceItems(container, dirtySourceItems, dirtyCandidates);
processCandidates(container, dirtyCandidates);
loadPendingItems(container);
}
{
assert(fInstancingChangeItems.empty());
assert(fWorldMatrixChangeItems.empty());
assert(fItemsPendingLoad.empty());
assert(fItemsPendingRemove.empty());
boost::unordered_set<RenderItemWrapper*> renderItems;
BOOST_FOREACH (const HardwareInstance& hwInstance, fInstances) {
renderItems.insert(hwInstance.master->renderItem());
BOOST_FOREACH (HardwareInstanceData* data, hwInstance.sources) {
renderItems.insert(data->renderItem());
}
}
fInstancingChangeItems.clear();
fWorldMatrixChangeItems.clear();
fItemsPendingLoad.clear();
fItemsPendingRemove.clear();
fInstances.clear();
BOOST_FOREACH (RenderItemWrapper* renderItem, renderItems) {
renderItem->removeHardwareInstanceData(fSubSceneOverride, container);
}
}
void notifyInstancingChange(HardwareInstanceData* data)
{
assert(data && data->renderItem());
fInstancingChangeItems.insert(data);
}
void notifyWorldMatrixChange(HardwareInstanceData* data)
{
assert(data && data->renderItem() && data->isInstanced());
fWorldMatrixChangeItems.insert(data);
}
void notifyInstancingClear(HardwareInstanceData* data, bool destroy = false)
{
assert(data && data->renderItem());
fInstancingChangeItems.insert(data);
fWorldMatrixChangeItems.erase(data);
if (data->isInstanced()) {
fItemsPendingLoad.insert(data);
}
if (data->isMasterItem()) {
HardwareInstanceSet::iterator it = fInstances.find(data);
assert(it != fInstances.end() && it->master == data);
BOOST_FOREACH (HardwareInstanceData* sourceData, it->sources) {
fInstancingChangeItems.insert(sourceData);
fWorldMatrixChangeItems.erase(sourceData);
if (sourceData->isInstanced()) {
fItemsPendingLoad.insert(sourceData);
}
sourceData->clearInstanceData();
}
if (data->isInstanced()) {
if (!destroy) {
MStatus stat = fSubSceneOverride.removeAllInstances(
*data->renderItem()->wrappedItem()
);
MStatAssert(stat);
}
fItemsPendingRemove.insert(data);
}
fInstances.erase(it);
data->clearInstanceData();
}
else {
HardwareInstanceData* master = data->masterData();
if (master) {
HardwareInstanceSet::iterator it = fInstances.find(master);
assert(it != fInstances.end());
assert(it->sources.find(data) != it->sources.end());
it->sources.erase(data);
if (!it->candidate) {
assert(master->isInstanced() && data->isInstanced());
MStatus stat = fSubSceneOverride.removeInstance(
*master->renderItem()->wrappedItem(),
data->instanceId()
);
MStatAssert(stat);
}
data->clearInstanceData();
}
}
}
void notifyDestroy(HardwareInstanceData* data)
{
assert(data && data->renderItem());
notifyInstancingClear(data, true );
fInstancingChangeItems.erase(data);
fWorldMatrixChangeItems.erase(data);
fItemsPendingLoad.erase(data);
fItemsPendingRemove.erase(data);
}
{
unsigned int hardwareInstanceID(hardwareInstanceIndex);
BOOST_FOREACH (const HardwareInstance& hwInstance, fInstances) {
if (hwInstance.master->renderItem()->name() == renderItem.
name())
{
bool found = false;
if (hwInstance.master->instanceId() == hardwareInstanceID)
{
renderItemName = hwInstance.master->renderItem()->name();
found = true;
}
else
{
BOOST_FOREACH (HardwareInstanceData* sourceData, hwInstance.sources) {
if (sourceData->instanceId() == hardwareInstanceID)
{
renderItemName = sourceData->renderItem()->name();
found = true;
break;
}
}
}
if (found)
{
renderItemName.
split(
':', renderItemParts);
if (renderItemParts.
length() > 1 && renderItemParts[0].isUnsigned())
{
return renderItemParts[0].asUnsigned();
}
}
}
}
return -1;
}
void dump() const
{
using namespace std;
ostringstream tmp;
size_t hwInstCounter = 0;
BOOST_FOREACH (const HardwareInstance& hwInstance, fInstances) {
tmp << "HW Instance #" << (hwInstCounter++) << endl;
tmp << '\t' << "Master: "
<< hwInstance.master->renderItem()->name().asChar()
<< endl;
tmp << '\t' << "Candidate: "
<< (hwInstance.candidate ? "true" : "false")
<< endl;
tmp << '\t' << "Sources: "
<< hwInstance.sources.size()
<< endl;
size_t sourceCounter = 0;
BOOST_FOREACH (HardwareInstanceData* sourceData, hwInstance.sources) {
tmp << '\t' << '\t' << "Source #" << (sourceCounter++)
<< " " << sourceData->renderItem()->name().asChar()
<< " instance ID: " << sourceData->instanceId()
<< endl;
}
}
printf("%s\n", tmp.str().c_str());
}
private:
{
BOOST_FOREACH (HardwareInstanceData* data, fItemsPendingRemove) {
data->renderItem()->unloadItem(container);
}
fItemsPendingRemove.clear();
}
{
BOOST_FOREACH (HardwareInstanceData* data, fItemsPendingLoad) {
assert(data);
data->renderItem()->loadItem(fSubSceneOverride, container);
}
fItemsPendingLoad.clear();
}
void updateInstanceTransforms()
{
BOOST_FOREACH (HardwareInstanceData* data, fWorldMatrixChangeItems) {
assert(data && data->isInstanced());
if (!data || !data->isInstanced()) continue;
HardwareInstanceData* master = data->masterData();
assert(master && master->isInstanced());
RenderItemWrapper* masterItem = master->renderItem();
assert(masterItem);
RenderItemWrapper* thisItem = data->renderItem();
assert(thisItem);
MStatus stat = fSubSceneOverride.updateInstanceTransform(
*masterItem->wrappedItem(),
data->instanceId(),
thisItem->worldMatrix()
);
MStatAssert(stat);
}
fWorldMatrixChangeItems.clear();
}
void extractDirtySourceItems(
boost::unordered_set<HardwareInstanceData*>& dirtySourceItems)
{
BOOST_FOREACH (HardwareInstanceData* data, fInstancingChangeItems) {
assert(data);
if (!data->isMasterItem()) {
assert(fInstances.find(data) == fInstances.end());
dirtySourceItems.insert(data);
continue;
}
HardwareInstanceSet::iterator it = fInstances.find(data);
assert(it != fInstances.end());
if (it == fInstances.end()) continue;
assert(it->master == data);
if (it->master != data) continue;
BOOST_FOREACH (HardwareInstanceData* sourceData, it->sources) {
assert(sourceData);
dirtySourceItems.insert(sourceData);
}
HardwareInstance hwInstance = *it;
fInstances.erase(it);
if (fInstances.get<1>().find(hwInstance.master) == fInstances.get<1>().end()) {
fInstances.insert(hwInstance);
}
else {
BOOST_FOREACH (HardwareInstanceData* sourceData, hwInstance.sources) {
dirtySourceItems.insert(sourceData);
if (sourceData->isInstanced()) {
sourceData->renderItem()->unloadItem(container);
fItemsPendingLoad.insert(sourceData);
}
sourceData->clearInstanceData();
}
dirtySourceItems.insert(data);
if (data->isInstanced()) {
data->renderItem()->unloadItem(container);
fItemsPendingLoad.insert(data);
}
data->clearInstanceData();
}
}
fInstancingChangeItems.clear();
}
void processDirtySourceItems(
const boost::unordered_set<HardwareInstanceData*>& dirtySourceItems,
boost::unordered_set<HardwareInstanceData*>& dirtyCandidates)
{
BOOST_FOREACH (HardwareInstanceData* data, dirtySourceItems) {
assert(data && !data->isMasterItem());
assert(fInstances.find(data) == fInstances.end());
HardwareInstanceData* master = data->masterData();
if (master) {
HardwareInstanceSet::iterator it = fInstances.find(master);
assert(it != fInstances.end());
if (it != fInstances.end()) {
assert(it->sources.find(data) != it->sources.end());
it->sources.erase(data);
}
}
bool skipThisItem = false;
HardwareInstanceSet::nth_index<1>::type::iterator it =
fInstances.get<1>().find(data);
if (data->isInstanced()) {
if (it != fInstances.get<1>().end()) {
if (data->masterData() == it->master) {
it->sources.insert(data);
skipThisItem = true;
}
else {
leaveInstance(data, container);
}
}
else {
leaveInstance(data, container);
}
}
if (!skipThisItem) {
assert(!data->isInstanced());
if (it != fInstances.get<1>().end()) {
if (it->candidate) {
joinCandidate(it->master, data);
dirtyCandidates.insert(it->master);
}
else {
joinInstance(it->master, data, container);
}
}
else {
newCandidate(data);
}
}
}
}
void processCandidates(
const boost::unordered_set<HardwareInstanceData*>& dirtyCandidates)
{
BOOST_FOREACH (HardwareInstanceData* data, dirtyCandidates) {
assert(data);
HardwareInstanceSet::iterator it = fInstances.find(data);
assert(it != fInstances.end());
if (it == fInstances.end()) continue;
assert(it->candidate && data == it->master);
if (!it->candidate || data != it->master) continue;
if (it->sources.size() + 1 < Config::hardwareInstancingThreshold()) {
continue;
}
HardwareInstance hwInstance = *it;
fInstances.erase(it);
assert(hwInstance.master && !hwInstance.master->isInstanced());
hwInstance.master->clearInstanceData();
newInstance(hwInstance.master, container);
BOOST_FOREACH (HardwareInstanceData* data, hwInstance.sources) {
assert(data && !data->isInstanced() && !data->isMasterItem());
data->clearInstanceData();
joinInstance(hwInstance.master, data, container);
}
}
}
void newCandidate(HardwareInstanceData* source)
{
assert(source);
assert(!source->isInstanced() && !source->isMasterItem());
if (source->isInstanced() || source->isMasterItem()) return;
source->setupCandidate(source);
HardwareInstance hwInstance;
hwInstance.master = source;
hwInstance.candidate = true;
fInstances.insert(hwInstance);
}
void joinCandidate(HardwareInstanceData* master,
HardwareInstanceData* source)
{
assert(master);
assert(!master->isInstanced() && master->isMasterItem());
if (master->isInstanced() || !master->isMasterItem()) return;
HardwareInstanceSet::iterator it = fInstances.find(master);
assert(it != fInstances.end());
if (it == fInstances.end()) return;
assert(it->master == master && it->candidate);
if (it->master != master || !it->candidate) return;
assert(it->sources.find(source) == it->sources.end());
assert(source);
assert(!source->isInstanced() && !source->isMasterItem());
if (source->isInstanced() || source->isMasterItem()) return;
source->setupCandidate(master);
it->sources.insert(source);
}
void newInstance(HardwareInstanceData* source,
{
assert(source);
assert(!source->isInstanced() && !source->isMasterItem());
if (source->isInstanced() || source->isMasterItem()) return;
RenderItemWrapper* sourceItem = source->renderItem();
assert(sourceItem);
sourceItem->loadItem(fSubSceneOverride, container);
fItemsPendingLoad.erase(source);
unsigned int instanceId = fSubSceneOverride.addInstanceTransform(
*sourceItem->wrappedItem(),
sourceItem->worldMatrix()
);
assert(instanceId > 0);
if (instanceId == 0) return;
source->setupInstance(source, instanceId);
HardwareInstance hwInstance;
hwInstance.master = source;
hwInstance.candidate = false;
fInstances.insert(hwInstance);
}
void joinInstance(HardwareInstanceData* master,
HardwareInstanceData* source,
{
assert(master);
assert(master->isInstanced() && master->isMasterItem());
if (!master->isInstanced() || !master->isMasterItem()) return;
HardwareInstanceSet::iterator it = fInstances.find(master);
assert(it != fInstances.end());
if (it == fInstances.end()) return;
assert(it->master == master && !it->candidate);
if (it->master != master || it->candidate) return;
assert(it->sources.find(source) == it->sources.end());
assert(source);
assert(!source->isInstanced() && !source->isMasterItem());
if (source->isInstanced() || source->isMasterItem()) return;
RenderItemWrapper* masterItem = master->renderItem();
assert(masterItem);
RenderItemWrapper* sourceItem = source->renderItem();
assert(sourceItem);
unsigned int instanceId = fSubSceneOverride.addInstanceTransform(
*masterItem->wrappedItem(),
sourceItem->worldMatrix()
);
assert(instanceId > 0);
if (instanceId == 0) return;
sourceItem->unloadItem(container);
fItemsPendingLoad.erase(source);
source->setupInstance(master, instanceId);
it->sources.insert(source);
}
void leaveInstance(HardwareInstanceData* source,
{
assert(source);
assert(source->isInstanced() && !source->isMasterItem());
if (!source->isInstanced() || source->isMasterItem()) return;
HardwareInstanceData* master = source->masterData();
assert(master);
RenderItemWrapper* masterItem = master->renderItem();
assert(masterItem);
RenderItemWrapper* sourceItem = source->renderItem();
assert(sourceItem);
MStatus stat = fSubSceneOverride.removeInstance(
*masterItem->wrappedItem(),
source->instanceId()
);
if (!stat) return;
sourceItem->loadItem(fSubSceneOverride, container);
source->clearInstanceData();
}
struct VisHash : std::unary_function<HardwareInstanceData*, std::size_t>
{
std::size_t operator()(const HardwareInstanceData* const& data) const
{
std::size_t seed = 0;
const RenderItemWrapper* w = data->renderItem();
assert(w);
boost::hash_combine(seed, w->type());
boost::hash_combine(seed, w->primitive());
boost::hash_combine(seed, w->userData().get());
boost::hash_combine(seed, w->indices().get());
boost::hash_combine(seed, w->positions().get());
boost::hash_combine(seed, w->normals().get());
boost::hash_combine(seed, w->uvs().get());
boost::hash_combine(seed, w->enabled());
boost::hash_combine(seed, w->drawMode());
boost::hash_combine(seed, w->depthPriority());
boost::hash_combine(seed, w->excludedFromPostEffects());
boost::hash_combine(seed, w->castsShadows());
boost::hash_combine(seed, w->receivesShadows());
boost::hash_combine(seed, w->shader().get());
boost::hash_combine(seed, w->isCompatibleWithMayaInstancer());
return seed;
}
};
struct VisEqualTo : std::binary_function<HardwareInstanceData*, HardwareInstanceData*, bool>
{
bool operator()(const HardwareInstanceData* const& xData,
const HardwareInstanceData* const& yData) const
{
const RenderItemWrapper* x = xData->renderItem();
const RenderItemWrapper* y = yData->renderItem();
assert(x && y);
return x->type() == y->type() &&
x->primitive() == y->primitive() &&
x->userData().get() == y->userData().get() &&
x->indices().get() == y->indices().get() &&
x->positions().get() == y->positions().get() &&
x->normals().get() == y->normals().get() &&
x->uvs().get() == y->uvs().get() &&
x->enabled() == y->enabled() &&
x->drawMode() == y->drawMode() &&
x->depthPriority() == y->depthPriority() &&
x->excludedFromPostEffects() == y->excludedFromPostEffects() &&
x->castsShadows() == y->castsShadows() &&
x->receivesShadows() == y->receivesShadows() &&
x->shader().get() == y->shader().get();
}
};
struct HardwareInstance
{
HardwareInstanceData* master;
mutable bool candidate;
mutable boost::unordered_set<HardwareInstanceData*> sources;
};
typedef boost::multi_index_container<
HardwareInstance,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
BOOST_MULTI_INDEX_MEMBER(HardwareInstance,HardwareInstanceData*,master)
>,
boost::multi_index::hashed_non_unique<
BOOST_MULTI_INDEX_MEMBER(HardwareInstance,HardwareInstanceData*,master),
VisHash,
VisEqualTo
>
>
> HardwareInstanceSet;
SubSceneOverride& fSubSceneOverride;
HardwareInstanceSet fInstances;
boost::unordered_set<HardwareInstanceData*> fInstancingChangeItems;
boost::unordered_set<HardwareInstanceData*> fWorldMatrixChangeItems;
boost::unordered_set<HardwareInstanceData*> fItemsPendingLoad;
boost::unordered_set<HardwareInstanceData*> fItemsPendingRemove;
};
void HardwareInstanceData::notifyInstancingChange()
{
fManager->notifyInstancingChange(this);
}
void HardwareInstanceData::notifyInstancingClear()
{
fManager->notifyInstancingClear(this);
}
void HardwareInstanceData::notifyWorldMatrixChange()
{
if (isInstanced()) {
fManager->notifyWorldMatrixChange(this);
}
}
void HardwareInstanceData::notifyDestroy()
{
fManager->notifyDestroy(this);
}
class ModelCallbacks : boost::noncopyable
{
public:
static ModelCallbacks& getInstance()
{
static ModelCallbacks sSingleton;
return sSingleton;
}
ModelCallbacks()
{
fAttrsAffectAppearance.insert("visibility");
fAttrsAffectAppearance.insert("lodVisibility");
fAttrsAffectAppearance.insert("intermediateObject");
fAttrsAffectAppearance.insert("template");
fAttrsAffectAppearance.insert("renderLayerInfo");
fAttrsAffectAppearance.insert("renderLayerId");
fAttrsAffectAppearance.insert("renderLayerRenderable");
fAttrsAffectAppearance.insert("renderLayerColor");
fAttrsAffectAppearance.insert("drawOverride");
fAttrsAffectAppearance.insert("overrideDisplayType");
fAttrsAffectAppearance.insert("overrideLevelOfDetail");
fAttrsAffectAppearance.insert("overrideShading");
fAttrsAffectAppearance.insert("overrideTexturing");
fAttrsAffectAppearance.insert("overridePlayback");
fAttrsAffectAppearance.insert("overrideEnabled");
fAttrsAffectAppearance.insert("overrideVisibility");
fAttrsAffectAppearance.insert("overrideColor");
fAttrsAffectAppearance.insert("useObjectColor");
fAttrsAffectAppearance.insert("objectColor");
fAttrsAffectAppearance.insert("ghosting");
fAttrsAffectAppearance.insert("castsShadows");
fAttrsAffectAppearance.insert("receiveShadows");
TimeChangeCallback, this);
"renderLayerChange", RenderLayerChangeCallback, this);
"renderLayerManagerChange", RenderLayerChangeCallback, this);
selectionChanged();
}
~ModelCallbacks()
{
}
void registerSubSceneOverride(const ShapeNode* shapeNode, SubSceneOverride* subSceneOverride)
{
assert(shapeNode);
if (!shapeNode) return;
assert(subSceneOverride);
if (!subSceneOverride) return;
fShapeNodes.insert(std::make_pair(shapeNode, subSceneOverride));
}
void deregisterSubSceneOverride(const ShapeNode* shapeNode)
{
assert(shapeNode);
if (!shapeNode) return;
fShapeNodes.erase(shapeNode);
}
void selectionChanged()
{
ShapeNodeNameMap currentSelection;
for (
unsigned int i = 0, size = list.
length(); i < size; i++) {
const ShapeNode* shapeNode = (
const ShapeNode*)dagNode.
userNode();
if (shapeNode) {
currentSelection.insert(std::make_pair(dagIt.
fullPathName(), shapeNode));
}
}
}
}
}
BOOST_FOREACH (const ShapeNodeNameMap::value_type& val, fLastSelection) {
if (currentSelection.find(val.first) == currentSelection.end()) {
ShapeNodeSubSceneMap::iterator it = fShapeNodes.find(val.second);
if (it != fShapeNodes.end() && it->second) {
it->second->dirtyEverything();
}
}
}
BOOST_FOREACH (const ShapeNodeNameMap::value_type& val, currentSelection) {
if (fLastSelection.find(val.first) == fLastSelection.end()) {
ShapeNodeSubSceneMap::iterator it = fShapeNodes.find(val.second);
if (it != fShapeNodes.end() && it->second) {
it->second->dirtyEverything();
}
}
}
fLastSelection.swap(currentSelection);
}
void timeChanged()
{
BOOST_FOREACH (ShapeNodeSubSceneMap::value_type& val, fShapeNodes) {
val.second->dirtyVisibility();
val.second->dirtyWorldMatrix();
val.second->dirtyStreams();
val.second->dirtyMaterials();
}
}
void renderLayerChanged()
{
BOOST_FOREACH (ShapeNodeSubSceneMap::value_type& val, fShapeNodes) {
val.second->dirtyEverything();
}
}
bool affectAppearance(
const MString& attr)
const
{
return (fAttrsAffectAppearance.find(attr) != fAttrsAffectAppearance.cend());
}
private:
static void MayaExitingCallback(void* clientData)
{
BuffersCache::getInstance().clear();
UnitBoundingBox::clear();
}
static void SelectionChangedCallback(void* clientData)
{
assert(clientData);
static_cast<ModelCallbacks*>(clientData)->selectionChanged();
}
static void TimeChangeCallback(
MTime& time,
void* clientData)
{
assert(clientData);
static_cast<ModelCallbacks*>(clientData)->timeChanged();
}
static void RenderLayerChangeCallback(void* clientData)
{
assert(clientData);
static_cast<ModelCallbacks*>(clientData)->renderLayerChanged();
}
private:
MCallbackId fMayaExitingCallback;
MCallbackId fSelectionChangedCallback;
MCallbackId fTimeChangeCallback;
MCallbackId fRenderLayerChangeCallback;
MCallbackId fRenderLayerManagerChangeCallback;
typedef boost::unordered_map<MString,const ShapeNode*,MStringHash> ShapeNodeNameMap;
typedef boost::unordered_map<const ShapeNode*,SubSceneOverride*> ShapeNodeSubSceneMap;
ShapeNodeNameMap fLastSelection;
ShapeNodeSubSceneMap fShapeNodes;
boost::unordered_set<MString, MStringHash> fAttrsAffectAppearance;
};
void InstanceChangedCallback(
MDagPath& child,
MDagPath& parent,
void* clientData)
{
assert(clientData);
static_cast<SubSceneOverride*>(clientData)->dirtyEverything();
static_cast<SubSceneOverride*>(clientData)->resetDagPaths();
}
void WorldMatrixChangedCallback(
MObject& transformNode,
MDagMessage::MatrixModifiedFlags& modified,
void* clientData)
{
assert(clientData);
static_cast<SubSceneOverride*>(clientData)->dirtyWorldMatrix();
}
{
assert(clientData);
static_cast<SubSceneOverride*>(clientData)->clearNodeDirtyCallbacks();
static_cast<SubSceneOverride*>(clientData)->dirtyEverything();
}
void NodeDirtyCallback(
MObject& node,
MPlug& plug,
void* clientData)
{
assert(clientData);
if (ModelCallbacks::getInstance().affectAppearance(attr.name())) {
static_cast<SubSceneOverride*>(clientData)->dirtyEverything();
}
}
}
namespace GPUCache {
class SubSceneOverride::HardwareInstanceManager : boost::noncopyable
{
public:
HardwareInstanceManager(SubSceneOverride& subSceneOverride)
: fImpl(new HardwareInstanceManagerImpl(subSceneOverride))
{}
~HardwareInstanceManager()
{}
{
fImpl->processInstances(container);
}
{
fImpl->resetInstances(container);
}
void installHardwareInstanceData(RenderItemWrapper::Ptr& renderItem)
{
if (!renderItem->hasHardwareInstanceData()) {
boost::shared_ptr<HardwareInstanceData> data(
new HardwareInstanceData(fImpl.get(), renderItem.get())
);
renderItem->installHardwareInstanceData(data);
}
}
{
return fImpl->instancePathIndex(renderItem, hardwareInstanceIndex);
}
private:
boost::shared_ptr<HardwareInstanceManagerImpl> fImpl;
};
class SubSceneOverride::HierarchyStat : boost::noncopyable
{
public:
typedef boost::shared_ptr<const HierarchyStat> Ptr;
struct SubNodeStat
{
bool isVisibilityAnimated;
bool isXformAnimated;
bool isShapeAnimated;
bool isDiffuseColorAnimated;
size_t nextSubNodeIndex;
size_t nextShapeSubNodeIndex;
SubNodeStat()
: isVisibilityAnimated(false),
isXformAnimated(false),
isShapeAnimated(false),
isDiffuseColorAnimated(false),
nextSubNodeIndex(0),
nextShapeSubNodeIndex(0)
{}
};
~HierarchyStat() {}
void setStat(size_t subNodeIndex, SubNodeStat& stat)
{
if (subNodeIndex >= fStats.size()) {
fStats.resize(subNodeIndex+1);
}
fStats[subNodeIndex] = stat;
}
const SubNodeStat& stat(size_t subNodeIndex) const
{ return fStats[subNodeIndex]; }
private:
HierarchyStat() {}
friend class HierarchyStatVisitor;
std::vector<SubNodeStat> fStats;
};
class SubSceneOverride::HierarchyStatVisitor : public SubNodeVisitor
{
public:
HierarchyStatVisitor(const SubNode::Ptr& geometry)
: fGeometry(geometry),
fIsParentVisibilityAnimated(false),
fIsVisibilityAnimated(false),
fIsParentXformAnimated(false),
fIsXformAnimated(false),
fIsShapeAnimated(false),
fIsDiffuseColorAnimated(false),
fSubNodeIndex(0),
fShapeSubNodeIndex(0)
{
fHierarchyStat.reset(new HierarchyStat());
}
virtual ~HierarchyStatVisitor()
{}
const HierarchyStat::Ptr getStat() const
{ return fHierarchyStat; }
virtual void visit(const XformData& xform,
const SubNode& subNode)
{
size_t thisSubNodeIndex = fSubNodeIndex;
fSubNodeIndex++;
bool isVisibilityAnimated = false;
if (xform.getSamples().size() > 1) {
const boost::shared_ptr<const XformSample>& sample =
xform.getSamples().begin()->second;
if (sample) {
const bool oneVisibility = sample->visibility();
BOOST_FOREACH (const XformData::SampleMap::value_type& val, xform.getSamples()) {
if (val.second && val.second->visibility() != oneVisibility) {
isVisibilityAnimated = true;
break;
}
}
}
}
bool isXformAnimated = false;
if (xform.getSamples().size() > 1) {
const boost::shared_ptr<const XformSample>& sample =
xform.getSamples().begin()->second;
if (sample) {
const MMatrix& oneMatrix = sample->xform();
BOOST_FOREACH (const XformData::SampleMap::value_type& val, xform.getSamples()) {
if (val.second && val.second->xform() != oneMatrix) {
isXformAnimated = true;
break;
}
}
}
}
{
ScopedGuard<bool> parentVisibilityGuard(fIsParentVisibilityAnimated);
fIsParentVisibilityAnimated = fIsParentVisibilityAnimated || isVisibilityAnimated;
ScopedGuard<bool> parentXformGuard(fIsParentXformAnimated);
fIsParentXformAnimated = fIsParentXformAnimated || isXformAnimated;
bool isShapeAnimated = false;
bool isDiffuseColorAnimated = false;
BOOST_FOREACH (const SubNode::Ptr& child, subNode.getChildren()) {
child->accept(*this);
isVisibilityAnimated = isVisibilityAnimated || fIsVisibilityAnimated;
isXformAnimated = isXformAnimated || fIsXformAnimated;
isShapeAnimated = isShapeAnimated || fIsShapeAnimated;
isDiffuseColorAnimated = isDiffuseColorAnimated || fIsDiffuseColorAnimated;
}
fIsVisibilityAnimated = isVisibilityAnimated;
fIsXformAnimated = isXformAnimated;
fIsShapeAnimated = isShapeAnimated;
fIsDiffuseColorAnimated = isDiffuseColorAnimated;
}
appendStat(thisSubNodeIndex);
}
virtual void visit(const ShapeData& shape,
const SubNode& subNode)
{
size_t thisSubNodeIndex = fSubNodeIndex;
fSubNodeIndex++;
fShapeSubNodeIndex++;
fIsShapeAnimated = shape.getSamples().size() > 1;
fIsDiffuseColorAnimated = false;
if (fIsShapeAnimated) {
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSamples().begin()->second;
if (sample) {
const MColor& oneColor = sample->diffuseColor();
BOOST_FOREACH (const ShapeData::SampleMap::value_type& val, shape.getSamples()) {
if (val.second && val.second->diffuseColor() != oneColor) {
fIsDiffuseColorAnimated = true;
break;
}
}
}
}
fIsVisibilityAnimated = false;
if (fIsShapeAnimated) {
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSamples().begin()->second;
if (sample) {
const bool oneVisibility = sample->visibility();
BOOST_FOREACH (const ShapeData::SampleMap::value_type& val, shape.getSamples()) {
if (val.second && val.second->visibility() != oneVisibility) {
fIsVisibilityAnimated = true;
break;
}
}
}
}
fIsXformAnimated = false;
appendStat(thisSubNodeIndex);
}
void appendStat(size_t subNodeIndex)
{
HierarchyStat::SubNodeStat stat;
stat.isVisibilityAnimated = fIsVisibilityAnimated || fIsParentVisibilityAnimated;
stat.isXformAnimated = fIsXformAnimated || fIsParentXformAnimated;
stat.isShapeAnimated = fIsShapeAnimated;
stat.isDiffuseColorAnimated = fIsDiffuseColorAnimated;
stat.nextSubNodeIndex = fSubNodeIndex;
stat.nextShapeSubNodeIndex = fShapeSubNodeIndex;
fHierarchyStat->setStat(subNodeIndex, stat);
}
private:
const SubNode::Ptr fGeometry;
bool fIsParentVisibilityAnimated;
bool fIsVisibilityAnimated;
bool fIsParentXformAnimated;
bool fIsXformAnimated;
bool fIsShapeAnimated;
bool fIsDiffuseColorAnimated;
size_t fSubNodeIndex;
size_t fShapeSubNodeIndex;
boost::shared_ptr<HierarchyStat> fHierarchyStat;
};
class SubSceneOverride::SubNodeRenderItems : boost::noncopyable
{
public:
typedef boost::shared_ptr<SubNodeRenderItems> Ptr;
SubNodeRenderItems()
: fIsBoundingBoxPlaceHolder(false),
fIsSelected(false),
fVisibility(true),
fValidPoly(true)
{}
~SubNodeRenderItems()
{}
void updateRenderItems(SubSceneOverride& subSceneOverride,
const ShapeData& shape,
const SubNode& subNode,
const bool isSelected)
{
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSample(subSceneOverride.getTime());
if (!sample) return;
fIsBoundingBoxPlaceHolder = sample->isBoundingBoxPlaceHolder();
fIsSelected = isSelected;
updateBoundingBoxItems(subSceneOverride, container, subNodePrefix, wireColor, subNode);
updateSnappingItems(subSceneOverride, container, subNodePrefix);
updateDormantWireItems(subSceneOverride, container, subNodePrefix, wireColor);
updateActiveWireItems(subSceneOverride, container, subNodePrefix, wireColor);
updateShadedItems(subSceneOverride, container, subNodePrefix, shape,
sample->diffuseColor(), sample->numIndexGroups());
}
void updateVisibility(SubSceneOverride& subSceneOverride,
const bool visibility,
const ShapeData& shape)
{
fVisibility = visibility;
toggleBoundingBoxItem();
toggleSnappingItem();
toggleDormantWireItem();
toggleActiveWireItem();
toggleShadedItems();
}
void updateWorldMatrix(SubSceneOverride& subSceneOverride,
const ShapeData& shape)
{
if (fBoundingBoxItem) {
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSample(subSceneOverride.getTime());
if (sample) {
UnitBoundingBox::boundingBoxMatrix(boundingBox) * matrix;
fBoundingBoxItem->setWorldMatrix(worldMatrix);
}
}
if (fSnappingItem) {
fSnappingItem->setWorldMatrix(matrix);
}
if (fDormantWireItem) {
fDormantWireItem->setWorldMatrix(matrix);
}
if (fActiveWireItem) {
fActiveWireItem->setWorldMatrix(matrix);
}
BOOST_FOREACH (RenderItemWrapper::Ptr& shadedItem, fShadedItems) {
shadedItem->setWorldMatrix(matrix);
}
}
void updateStreams(SubSceneOverride& subSceneOverride,
const ShapeData& shape)
{
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSample(subSceneOverride.getTime());
if (!sample) return;
fValidPoly = sample->numVerts() > 0 &&
sample->numWires() > 0 &&
sample->numTriangles() > 0 &&
sample->positions();
toggleBoundingBoxItem();
toggleSnappingItem();
toggleDormantWireItem();
toggleActiveWireItem();
toggleShadedItems();
if (!fValidPoly) {
return;
}
if (fSnappingItem) {
fSnappingItem->setBuffers(
subSceneOverride,
boost::shared_ptr<const IndexBuffer>(),
sample->positions(),
boost::shared_ptr<const VertexBuffer>(),
boost::shared_ptr<const VertexBuffer>(),
sample->boundingBox()
);
}
if (fDormantWireItem) {
fDormantWireItem->setBuffers(
subSceneOverride,
sample->wireVertIndices(),
sample->positions(),
boost::shared_ptr<const VertexBuffer>(),
boost::shared_ptr<const VertexBuffer>(),
sample->boundingBox()
);
}
if (fActiveWireItem) {
fActiveWireItem->setBuffers(
subSceneOverride,
sample->wireVertIndices(),
sample->positions(),
boost::shared_ptr<const VertexBuffer>(),
boost::shared_ptr<const VertexBuffer>(),
sample->boundingBox()
);
}
for (size_t groupId = 0; groupId < sample->numIndexGroups(); groupId++) {
if (groupId >= fShadedItems.size()) break;
assert(fShadedItems[groupId]);
if (!fShadedItems[groupId]) continue;
fShadedItems[groupId]->setBuffers(
subSceneOverride,
sample->triangleVertIndices(groupId),
sample->positions(),
sample->normals(),
sample->uvs(),
sample->boundingBox()
);
}
}
void updateMaterials(SubSceneOverride& subSceneOverride,
const ShapeData& shape)
{
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSample(subSceneOverride.getTime());
if (!sample) return;
for (size_t groupId = 0; groupId < sample->numIndexGroups(); groupId++) {
if (groupId >= fShadedItems.size()) break;
if (groupId >= fSharedDiffuseColorShaders.size()) break;
if (groupId >= fUniqueDiffuseColorShaders.size()) break;
if (groupId >= fMaterialShaders.size()) break;
assert(fShadedItems[groupId]);
if (!fShadedItems[groupId]) continue;
ShaderInstancePtr shader = fMaterialShaders[groupId];
if (shader) {
continue;
}
shader = fUniqueDiffuseColorShaders[groupId];
if (shader) {
setDiffuseColor(shader.get(), sample->diffuseColor());
continue;
}
shader = ShaderInstanceCache::getInstance().getSharedDiffuseColorShader(
sample->diffuseColor());
assert(fSharedDiffuseColorShaders[groupId]);
if (shader != fSharedDiffuseColorShaders[groupId]) {
shader = ShaderInstanceCache::getInstance().getUniqueDiffuseColorShader(
sample->diffuseColor());
fSharedDiffuseColorShaders[groupId].reset();
fUniqueDiffuseColorShaders[groupId] = shader;
fShadedItems[groupId]->setShader(shader);
}
}
}
void updateBoundingBoxItems(SubSceneOverride& subSceneOverride,
const SubNode& subNode)
{
if (!fIsBoundingBoxPlaceHolder) {
if (fBoundingBoxItem) {
fBoundingBoxItem->removeFromContainer(container);
fBoundingBoxItem.reset();
}
return;
}
if (!fBoundingBoxItem) {
const MString boundingBoxItemName = subNodePrefix +
":boundingBox";
fBoundingBoxItem.reset(new RenderItemWrapper(
boundingBoxItemName,
MRenderItem::NonMaterialSceneItem,
MGeometry::kLines
));
fBoundingBoxItem->setDrawMode((MGeometry::DrawMode)(MGeometry::kWireframe | MGeometry::kShaded | MGeometry::kTextured));
fBoundingBoxItem->setDepthPriority(MRenderItem::sDormantWireDepthPriority);
fBoundingBoxItem->setCompatibleWithMayaInstancer(true);
ShaderInstancePtr boundingBoxShader =
ShaderInstanceCache::getInstance().getSharedBoundingBoxPlaceHolderShader(wireColor);
if (boundingBoxShader) {
fBoundingBoxItem->setShader(boundingBoxShader);
}
fBoundingBoxItem->addToContainer(container);
fBoundingBoxItem->setBuffers(
subSceneOverride,
UnitBoundingBox::indices(),
UnitBoundingBox::positions(),
boost::shared_ptr<const VertexBuffer>(),
boost::shared_ptr<const VertexBuffer>(),
UnitBoundingBox::boundingBox()
);
fBoundingBoxItem->setCustomData(
boost::make_shared<SubNodeUserData>(subNode)
);
}
ShaderInstancePtr boundingBoxShader =
ShaderInstanceCache::getInstance().getSharedBoundingBoxPlaceHolderShader(wireColor);
if (boundingBoxShader) {
fBoundingBoxItem->setShader(boundingBoxShader);
}
toggleBoundingBoxItem();
}
void updateSnappingItems(SubSceneOverride& subSceneOverride,
{
if (fIsBoundingBoxPlaceHolder) {
if (fSnappingItem) fSnappingItem->setEnabled(false);
return;
}
if (!fSnappingItem) {
const MString snappingItemName = subNodePrefix +
":snapping";
fSnappingItem.reset(new RenderItemWrapper(
snappingItemName,
MRenderItem::DecorationItem,
MGeometry::kPoints
));
fSnappingItem->setDepthPriority(MRenderItem::sSelectionDepthPriority);
fSnappingItem->setSnappingSelectionMask();
fSnappingItem->setCompatibleWithMayaInstancer(true);
fSnappingItem->addToContainer(container);
}
boost::shared_ptr<HardwareInstanceManager>& hwInstanceManager =
subSceneOverride.hardwareInstanceManager();
if (hwInstanceManager) {
hwInstanceManager->installHardwareInstanceData(fSnappingItem);
}
toggleSnappingItem();
ShaderInstancePtr snappingShader = ShaderInstanceCache::getInstance().getSharedPointShader();
if (snappingShader) {
fSnappingItem->setShader(snappingShader);
}
}
void updateDormantWireItems(SubSceneOverride& subSceneOverride,
{
if (fIsBoundingBoxPlaceHolder) {
if (fDormantWireItem) fDormantWireItem->setEnabled(false);
return;
}
if (!fDormantWireItem) {
const MString dormantWireItemName = subNodePrefix +
":dormantWire";
fDormantWireItem.reset(new RenderItemWrapper(
dormantWireItemName,
MRenderItem::DecorationItem,
MGeometry::kLines
));
fDormantWireItem->setDrawMode(MGeometry::kWireframe);
fDormantWireItem->setDepthPriority(MRenderItem::sDormantWireDepthPriority);
fDormantWireItem->setCompatibleWithMayaInstancer(true);
fDormantWireItem->addToContainer(container);
}
boost::shared_ptr<HardwareInstanceManager>& hwInstanceManager =
subSceneOverride.hardwareInstanceManager();
if (hwInstanceManager) {
hwInstanceManager->installHardwareInstanceData(fDormantWireItem);
}
toggleDormantWireItem();
ShaderInstancePtr dormantWireShader =
(DisplayPref::wireframeOnShadedMode() == DisplayPref::kWireframeOnShadedFull)
? ShaderInstanceCache::getInstance().getSharedWireShader(wireColor)
: ShaderInstanceCache::getInstance().getSharedWireShaderWithCB(wireColor);
if (dormantWireShader) {
fDormantWireItem->setShader(dormantWireShader);
}
}
void updateActiveWireItems(SubSceneOverride& subSceneOverride,
{
if (fIsBoundingBoxPlaceHolder) {
if (fActiveWireItem) fActiveWireItem->setEnabled(false);
return;
}
if (!fActiveWireItem) {
const MString activeWireItemName = subNodePrefix +
":activeWire";
fActiveWireItem.reset(new RenderItemWrapper(
activeWireItemName,
MRenderItem::DecorationItem,
MGeometry::kLines
));
fActiveWireItem->setDrawMode((MGeometry::DrawMode)(MGeometry::kWireframe | MGeometry::kShaded | MGeometry::kTextured));
fActiveWireItem->setDepthPriority(MRenderItem::sActiveWireDepthPriority);
fActiveWireItem->setCompatibleWithMayaInstancer(true);
fActiveWireItem->addToContainer(container);
}
boost::shared_ptr<HardwareInstanceManager>& hwInstanceManager =
subSceneOverride.hardwareInstanceManager();
if (hwInstanceManager) {
hwInstanceManager->installHardwareInstanceData(fActiveWireItem);
}
toggleActiveWireItem();
ShaderInstancePtr activeWireShader =
(DisplayPref::wireframeOnShadedMode() == DisplayPref::kWireframeOnShadedFull)
? ShaderInstanceCache::getInstance().getSharedWireShader(wireColor)
: ShaderInstanceCache::getInstance().getSharedWireShaderWithCB(wireColor);
if (activeWireShader) {
fActiveWireItem->setShader(activeWireShader);
}
}
void updateShadedItems(SubSceneOverride& subSceneOverride,
const ShapeData& shape,
const size_t nbIndexGroups)
{
if (fIsBoundingBoxPlaceHolder) {
BOOST_FOREACH (RenderItemWrapper::Ptr& item, fShadedItems) {
item->setEnabled(false);
}
return;
}
if (fShadedItems.empty()) {
fShadedItems.reserve(nbIndexGroups);
fSharedDiffuseColorShaders.reserve(nbIndexGroups);
fUniqueDiffuseColorShaders.reserve(nbIndexGroups);
fMaterialShaders.reserve(nbIndexGroups);
for (size_t groupId = 0; groupId < nbIndexGroups; groupId++) {
const MString shadedItemName = subNodePrefix +
":shaded" + (int)groupId;
RenderItemWrapper::Ptr renderItem(new RenderItemWrapper(
shadedItemName,
MRenderItem::MaterialSceneItem,
MGeometry::kTriangles
));
renderItem->setDrawMode((MGeometry::DrawMode)(MGeometry::kShaded | MGeometry::kTextured));
renderItem->setExcludedFromPostEffects(false);
renderItem->setCompatibleWithMayaInstancer(true);
fShadedItems.push_back(renderItem);
ShaderInstancePtr shader;
const std::vector<MString>& materialsAssignment = shape.getMaterials();
const MaterialGraphMap::Ptr& materials = subSceneOverride.getMaterial();
if (materials && groupId < materialsAssignment.size()) {
const MaterialGraph::Ptr graph = materials->find(materialsAssignment[groupId]);
if (graph) {
shader = ShaderInstanceCache::getInstance().getSharedShadedMaterialShader(
graph, subSceneOverride.getTime()
);
}
}
if (shader) {
renderItem->setShader(shader);
fMaterialShaders.push_back(shader);
fSharedDiffuseColorShaders.push_back(ShaderInstancePtr());
fUniqueDiffuseColorShaders.push_back(ShaderInstancePtr());
}
else {
ShaderInstancePtr sharedShader =
ShaderInstanceCache::getInstance().getSharedDiffuseColorShader(diffuseColor);
if (sharedShader) {
renderItem->setShader(sharedShader);
}
fMaterialShaders.push_back(ShaderInstancePtr());
fSharedDiffuseColorShaders.push_back(sharedShader);
fUniqueDiffuseColorShaders.push_back(ShaderInstancePtr());
}
renderItem->addToContainer(container);
}
}
const bool castsShadows = subSceneOverride.castsShadows();
const bool receiveShadows = subSceneOverride.receiveShadows();
BOOST_FOREACH (RenderItemWrapper::Ptr& renderItem, fShadedItems) {
renderItem->setCastsShadows(castsShadows);
renderItem->setReceivesShadows(receiveShadows);
boost::shared_ptr<HardwareInstanceManager>& hwInstanceManager =
subSceneOverride.hardwareInstanceManager();
if (hwInstanceManager && renderItem->shader() && !renderItem->shader()->isTransparent()) {
hwInstanceManager->installHardwareInstanceData(renderItem);
}
}
toggleShadedItems();
}
void toggleBoundingBoxItem()
{
if (fBoundingBoxItem) {
if (fIsBoundingBoxPlaceHolder) {
fBoundingBoxItem->setEnabled(fVisibility);
}
else {
fBoundingBoxItem->setEnabled(false);
}
}
}
void toggleSnappingItem()
{
if (fSnappingItem) {
if (fIsBoundingBoxPlaceHolder) {
fSnappingItem->setEnabled(false);
}
else {
fSnappingItem->setEnabled(fVisibility && fValidPoly);
}
}
}
void toggleDormantWireItem()
{
if (fDormantWireItem) {
if (fIsBoundingBoxPlaceHolder) {
fDormantWireItem->setEnabled(false);
}
else {
fDormantWireItem->setEnabled(fVisibility && fValidPoly && !fIsSelected);
}
}
}
void toggleActiveWireItem()
{
if (fActiveWireItem) {
if (fIsBoundingBoxPlaceHolder) {
fActiveWireItem->setEnabled(false);
}
else {
fActiveWireItem->setEnabled(fVisibility && fValidPoly && fIsSelected);
}
}
}
void toggleShadedItems()
{
BOOST_FOREACH (RenderItemWrapper::Ptr& shadedItem, fShadedItems) {
if (fIsBoundingBoxPlaceHolder) {
shadedItem->setEnabled(false);
}
else {
shadedItem->setEnabled(fVisibility && fValidPoly);
}
}
}
void hideRenderItems()
{
if (fActiveWireItem) {
fActiveWireItem->setEnabled(false);
}
if (fDormantWireItem) {
fDormantWireItem->setEnabled(false);
}
if (fSnappingItem) {
fSnappingItem->setEnabled(false);
}
if (fBoundingBoxItem) {
fBoundingBoxItem->setEnabled(false);
}
BOOST_FOREACH (RenderItemWrapper::Ptr& item, fShadedItems) {
item->setEnabled(false);
}
}
{
if (fActiveWireItem) {
fActiveWireItem->removeFromContainer(container);
fActiveWireItem.reset();
}
if (fDormantWireItem) {
fDormantWireItem->removeFromContainer(container);
fDormantWireItem.reset();
}
if (fSnappingItem) {
fSnappingItem->removeFromContainer(container);
fSnappingItem.reset();
}
if (fBoundingBoxItem) {
fBoundingBoxItem->removeFromContainer(container);
fBoundingBoxItem.reset();
}
BOOST_FOREACH (RenderItemWrapper::Ptr& item, fShadedItems) {
item->removeFromContainer(container);
item.reset();
}
fShadedItems.clear();
}
private:
RenderItemWrapper::Ptr fBoundingBoxItem;
RenderItemWrapper::Ptr fActiveWireItem;
RenderItemWrapper::Ptr fDormantWireItem;
RenderItemWrapper::Ptr fSnappingItem;
std::vector<RenderItemWrapper::Ptr> fShadedItems;
bool fIsBoundingBoxPlaceHolder;
bool fIsSelected;
bool fVisibility;
bool fValidPoly;
std::vector<ShaderInstancePtr> fSharedDiffuseColorShaders;
std::vector<ShaderInstancePtr> fUniqueDiffuseColorShaders;
std::vector<ShaderInstancePtr> fMaterialShaders;
};
class SubSceneOverride::UpdateRenderItemsVisitor : public SubNodeVisitor
{
public:
UpdateRenderItemsVisitor(SubSceneOverride& subSceneOverride,
const bool isSelected,
SubNodeRenderItemList& subNodeItems)
: fSubSceneOverride(subSceneOverride),
fContainer(container),
fWireColor(wireColor),
fIsSelected(isSelected),
fSubNodeItems(subNodeItems),
fLongName(instancePrefix),
fSubNodeIndex(0)
{}
virtual ~UpdateRenderItemsVisitor()
{}
virtual void visit(const XformData& xform,
const SubNode& subNode)
{
ScopedGuard<MString> longNameGuard(fLongName);
bool isTop = subNode.getParents().empty() && subNode.getName() == "|";
if (!isTop) {
fLongName += "|";
fLongName += subNode.getName();
}
BOOST_FOREACH (const SubNode::Ptr& child, subNode.getChildren()) {
child->accept(*this);
}
}
virtual void visit(const ShapeData& shape,
const SubNode& subNode)
{
const MString prevName = fLongName;
fLongName += "|";
fLongName += subNode.getName();
updateRenderItems(shape, subNode);
fSubNodeIndex++;
fLongName = prevName;
}
void updateRenderItems(const ShapeData& shape, const SubNode& subNode)
{
if (fSubNodeIndex >= fSubNodeItems.size()) {
fSubNodeItems.push_back(boost::make_shared<SubNodeRenderItems>());
}
fSubNodeItems[fSubNodeIndex]->updateRenderItems(
fSubSceneOverride,
fContainer,
fLongName,
fWireColor,
shape,
subNode,
fIsSelected
);
}
private:
SubSceneOverride& fSubSceneOverride;
const bool fIsSelected;
SubNodeRenderItemList& fSubNodeItems;
size_t fSubNodeIndex;
};
template<typename DERIVED>
class SubSceneOverride::UpdateVisitorWithPrune : public SubNodeVisitor
{
public:
UpdateVisitorWithPrune(SubSceneOverride& subSceneOverride,
SubNodeRenderItemList& subNodeItems)
: fSubSceneOverride(subSceneOverride),
fContainer(container),
fSubNodeItems(subNodeItems),
fDontPrune(false),
fTraverseInvisible(false),
fSubNodeIndex(0),
fShapeSubNodeIndex(0)
{}
virtual ~UpdateVisitorWithPrune()
{}
void setDontPrune(bool dontPrune)
{
fDontPrune = dontPrune;
}
void setTraverseInvisible(bool traverseInvisible)
{
fTraverseInvisible = traverseInvisible;
}
virtual void visit(const XformData& xform,
const SubNode& subNode)
{
const HierarchyStat::Ptr& hierarchyStat = fSubSceneOverride.getHierarchyStat();
if (hierarchyStat) {
const HierarchyStat::SubNodeStat& stat = hierarchyStat->stat(fSubNodeIndex);
if (!fDontPrune) {
if (static_cast<DERIVED*>(this)->canPrune(stat)) {
fSubNodeIndex = stat.nextSubNodeIndex;
fShapeSubNodeIndex = stat.nextShapeSubNodeIndex;
return;
}
if (!fTraverseInvisible) {
const boost::shared_ptr<const XformSample>& sample =
xform.getSample(fSubSceneOverride.getTime());
if (sample && !sample->visibility()) {
fSubNodeIndex = stat.nextSubNodeIndex;
fShapeSubNodeIndex = stat.nextShapeSubNodeIndex;
return;
}
}
}
}
fSubNodeIndex++;
BOOST_FOREACH (const SubNode::Ptr& child, subNode.getChildren()) {
child->accept(*this);
}
}
virtual void visit(const ShapeData& shape,
const SubNode& subNode)
{
assert(fShapeSubNodeIndex < fSubNodeItems.size());
if (fShapeSubNodeIndex < fSubNodeItems.size()) {
static_cast<DERIVED*>(this)->update(shape, subNode, fSubNodeItems[fShapeSubNodeIndex]);
}
fSubNodeIndex++;
fShapeSubNodeIndex++;
}
protected:
SubSceneOverride& fSubSceneOverride;
SubNodeRenderItemList& fSubNodeItems;
bool fDontPrune;
bool fTraverseInvisible;
size_t fSubNodeIndex;
size_t fShapeSubNodeIndex;
};
class SubSceneOverride::UpdateVisibilityVisitor :
public SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateVisibilityVisitor>
{
public:
typedef SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateVisibilityVisitor> ParentClass;
UpdateVisibilityVisitor(SubSceneOverride& subSceneOverride,
SubNodeRenderItemList& subNodeItems,
const bool outOfViewFrustum)
: ParentClass(subSceneOverride, container, subNodeItems),
fVisibility(!outOfViewFrustum)
{
setTraverseInvisible(true);
}
virtual ~UpdateVisibilityVisitor()
{}
bool canPrune(const HierarchyStat::SubNodeStat& stat)
{
return !stat.isVisibilityAnimated;
}
void update(const ShapeData& shape,
const SubNode& subNode,
SubNodeRenderItems::Ptr& subNodeItems)
{
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSample(fSubSceneOverride.getTime());
if (!sample) return;
bool visibility = fVisibility && sample->visibility();
subNodeItems->updateVisibility(
fSubSceneOverride,
fContainer,
visibility,
shape
);
}
virtual void visit(const XformData& xform,
const SubNode& subNode)
{
const boost::shared_ptr<const XformSample>& sample =
xform.getSample(fSubSceneOverride.getTime());
if (!sample) return;
ScopedGuard<bool> guard(fVisibility);
fVisibility = fVisibility && sample->visibility();
ParentClass::visit(xform, subNode);
}
private:
bool fVisibility;
};
class SubSceneOverride::UpdateWorldMatrixVisitor :
public SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateWorldMatrixVisitor>
{
public:
typedef SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateWorldMatrixVisitor> ParentClass;
UpdateWorldMatrixVisitor(SubSceneOverride& subSceneOverride,
SubNodeRenderItemList& subNodeItems)
: ParentClass(subSceneOverride, container, subNodeItems),
fMatrix(dagMatrix)
{}
virtual ~UpdateWorldMatrixVisitor()
{}
bool canPrune(const HierarchyStat::SubNodeStat& stat)
{
return !stat.isXformAnimated;
}
void update(const ShapeData& shape,
const SubNode& subNode,
SubNodeRenderItems::Ptr& subNodeItems)
{
subNodeItems->updateWorldMatrix(
fSubSceneOverride,
fContainer,
fMatrix,
shape
);
}
virtual void visit(const XformData& xform,
const SubNode& subNode)
{
const boost::shared_ptr<const XformSample>& sample =
xform.getSample(fSubSceneOverride.getTime());
if (!sample) return;
ScopedGuard<MMatrix> guard(fMatrix);
fMatrix = sample->xform() * fMatrix;
ParentClass::visit(xform, subNode);
}
private:
};
class SubSceneOverride::UpdateStreamsVisitor :
public SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateStreamsVisitor>
{
public:
typedef SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateStreamsVisitor> ParentClass;
UpdateStreamsVisitor(SubSceneOverride& subSceneOverride,
SubNodeRenderItemList& subNodeItems)
: ParentClass(subSceneOverride, container, subNodeItems)
{}
virtual ~UpdateStreamsVisitor()
{}
bool canPrune(const HierarchyStat::SubNodeStat& stat)
{
return !stat.isShapeAnimated;
}
void update(const ShapeData& shape,
const SubNode& subNode,
SubNodeRenderItems::Ptr& subNodeItems)
{
subNodeItems->updateStreams(
fSubSceneOverride,
fContainer,
shape
);
}
};
class SubSceneOverride::UpdateDiffuseColorVisitor :
public SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateDiffuseColorVisitor>
{
public:
typedef SubSceneOverride::UpdateVisitorWithPrune<SubSceneOverride::UpdateDiffuseColorVisitor> ParentClass;
UpdateDiffuseColorVisitor(SubSceneOverride& subSceneOverride,
SubNodeRenderItemList& subNodeItems)
: ParentClass(subSceneOverride, container, subNodeItems)
{}
virtual ~UpdateDiffuseColorVisitor()
{}
bool canPrune(const HierarchyStat::SubNodeStat& stat)
{
return !stat.isDiffuseColorAnimated;
}
void update(const ShapeData& shape,
const SubNode& subNode,
SubNodeRenderItems::Ptr& subNodeItems)
{
subNodeItems->updateMaterials(
fSubSceneOverride,
fContainer,
shape
);
}
};
class SubSceneOverride::InstanceRenderItems : boost::noncopyable
{
public:
typedef boost::shared_ptr<InstanceRenderItems> Ptr;
InstanceRenderItems()
: fVisibility(true),
fVisibilityValid(false),
fWorldMatrixValid(false),
fStreamsValid(false),
fMaterialsValid(false)
{}
~InstanceRenderItems()
{}
void updateRenderItems(SubSceneOverride& subSceneOverride,
{
fDagPath = dagPath;
if (!fVisibility) {
BOOST_FOREACH (SubNodeRenderItemList::value_type& items, fSubNodeItems) {
items->hideRenderItems();
}
fVisibilityValid = false;
return;
}
MGeometryUtilities::displayStatus(dagPath);
fIsSelected = (displayStatus ==
kActive) ||
(displayStatus == kLead) ||
const MColor wireColor = MGeometryUtilities::wireframeColor(dagPath);
if (!fBoundingBoxItem) {
const MString boundingBoxName = instancePrefix +
"BoundingBox";
fBoundingBoxItem.reset(new RenderItemWrapper(
boundingBoxName,
MRenderItem::NonMaterialSceneItem,
MGeometry::kLines
));
fBoundingBoxItem->setDrawMode(MGeometry::kBoundingBox);
fBoundingBoxShader =
ShaderInstanceCache::getInstance().getSharedWireShader(wireColor);
if (fBoundingBoxShader) {
fBoundingBoxItem->setShader(fBoundingBoxShader);
}
fBoundingBoxItem->addToContainer(container);
fBoundingBoxItem->setBuffers(
subSceneOverride,
UnitBoundingBox::indices(),
UnitBoundingBox::positions(),
boost::shared_ptr<const VertexBuffer>(),
boost::shared_ptr<const VertexBuffer>(),
UnitBoundingBox::boundingBox()
);
}
fBoundingBoxShader =
ShaderInstanceCache::getInstance().getSharedWireShader(wireColor);
if (fBoundingBoxShader) {
fBoundingBoxItem->setShader(fBoundingBoxShader);
}
fBoundingBoxItem->setDepthPriority(
fIsSelected ?
MRenderItem::sActiveWireDepthPriority :
MRenderItem::sDormantWireDepthPriority
);
fBoundingBoxItem->setEnabled(true);
UpdateRenderItemsVisitor visitor(subSceneOverride, container,
instancePrefix, wireColor, fIsSelected, fSubNodeItems);
subSceneOverride.getGeometry()->accept(visitor);
}
void updateVisibility(SubSceneOverride& subSceneOverride,
const bool outOfViewFrustum)
{
assert(fDagPath.isValid());
if (!fDagPath.isValid()) return;
if (!fVisibility) {
return;
}
if (outOfViewFrustum) {
fVisibilityValid = false;
}
UpdateVisibilityVisitor visitor(subSceneOverride, container, fSubNodeItems, outOfViewFrustum);
visitor.setDontPrune(!fVisibilityValid);
subSceneOverride.getGeometry()->accept(visitor);
fVisibilityValid = true;
if (outOfViewFrustum) {
fVisibilityValid = false;
}
}
void updateWorldMatrix(SubSceneOverride& subSceneOverride,
{
assert(fDagPath.isValid());
if (!fDagPath.isValid()) return;
if (!fVisibility) {
return;
}
const MMatrix pathMatrix = fDagPath.inclusiveMatrix();
const bool pathMatrixChanged = fMatrix != pathMatrix;
fMatrix = pathMatrix;
if (fBoundingBoxItem) {
const MBoundingBox boundingBox = BoundingBoxVisitor::boundingBox(
subSceneOverride.getGeometry(),
subSceneOverride.getTime()
);
UnitBoundingBox::boundingBoxMatrix(boundingBox) * fMatrix;
fBoundingBoxItem->setWorldMatrix(worldMatrix);
}
UpdateWorldMatrixVisitor visitor(subSceneOverride, container,
fMatrix, fSubNodeItems);
visitor.setDontPrune(pathMatrixChanged || !fWorldMatrixValid);
subSceneOverride.getGeometry()->accept(visitor);
fWorldMatrixValid = true;
}
void updateStreams(SubSceneOverride& subSceneOverride,
{
assert(fDagPath.isValid());
if (!fDagPath.isValid()) return;
if (!fVisibility) {
return;
}
UpdateStreamsVisitor visitor(subSceneOverride, container, fSubNodeItems);
visitor.setDontPrune(!fStreamsValid);
subSceneOverride.getGeometry()->accept(visitor);
fStreamsValid = true;
}
void updateMaterials(SubSceneOverride& subSceneOverride,
{
assert(fDagPath.isValid());
if (!fDagPath.isValid()) return;
if (!fVisibility) {
return;
}
UpdateDiffuseColorVisitor visitor(subSceneOverride, container, fSubNodeItems);
visitor.setDontPrune(!fMaterialsValid);
subSceneOverride.getGeometry()->accept(visitor);
fMaterialsValid = true;
}
{
if (fBoundingBoxItem) {
fBoundingBoxItem->removeFromContainer(container);
fBoundingBoxItem.reset();
}
BOOST_FOREACH (SubNodeRenderItems::Ptr& subNodeItem, fSubNodeItems) {
subNodeItem->destroyRenderItems(container);
}
}
private:
bool fIsSelected;
bool fVisibility;
RenderItemWrapper::Ptr fBoundingBoxItem;
ShaderInstancePtr fBoundingBoxShader;
SubNodeRenderItemList fSubNodeItems;
bool fVisibilityValid;
bool fWorldMatrixValid;
bool fStreamsValid;
bool fMaterialsValid;
};
{
return new SubSceneOverride(object);
}
void SubSceneOverride::clear()
{
BuffersCache::getInstance().clear();
}
MIndexBuffer* SubSceneOverride::lookup(
const boost::shared_ptr<const IndexBuffer>& indices)
{
return BuffersCache::getInstance().lookup(indices);
}
MVertexBuffer* SubSceneOverride::lookup(
const boost::shared_ptr<const VertexBuffer>& vertices)
{
return BuffersCache::getInstance().lookup(vertices);
}
SubSceneOverride::SubSceneOverride(
const MObject&
object)
fObject(object),
fShapeNode(NULL),
fUpdateRenderItemsRequired(true),
fUpdateVisibilityRequired(true),
fUpdateWorldMatrixRequired(true),
fUpdateStreamsRequired(true),
fUpdateMaterialsRequired(true),
fOutOfViewFrustum(false),
fOutOfViewFrustumUpdated(false),
fWireOnShadedMode(DisplayPref::kWireframeOnShadedFull)
{
fShapeNode = (
const ShapeNode*)dagNode.
userNode();
assert(fShapeNode);
resetDagPaths();
fCastsShadowsPlug = dagNode.
findPlug(
"castsShadows",
false);
fReceiveShadowsPlug = dagNode.
findPlug(
"receiveShadows",
false);
dagPath, InstanceChangedCallback, this);
dagPath, InstanceChangedCallback, this);
dagPath, WorldMatrixChangedCallback, this);
registerNodeDirtyCallbacks();
ModelCallbacks::getInstance().registerSubSceneOverride(fShapeNode, this);
fUpdateTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time();
}
SubSceneOverride::~SubSceneOverride()
{
ModelCallbacks::getInstance().deregisterSubSceneOverride(fShapeNode);
fInstanceRenderItems.clear();
fHardwareInstanceManager.reset();
}
{
}
{
assert(fShapeNode);
if (!fShapeNode) return false;
MRenderer* renderer = MRenderer::theRenderer();
if (!renderer) return false;
if (fInstanceDagPaths.length() == 0) {
SubSceneOverride* nonConstThis = const_cast<SubSceneOverride*>(this);
}
const bool hwInstancing = useHardwareInstancing();
if ((hwInstancing && !fHardwareInstanceManager) ||
(!hwInstancing && fHardwareInstanceManager)) {
return true;
}
SubNode::Ptr geometry = fShapeNode->getCachedGeometry();
MaterialGraphMap::Ptr material = fShapeNode->getCachedMaterial();
if (geometry != fGeometry || material != fMaterial) {
return true;
}
if (fWireOnShadedMode != DisplayPref::wireframeOnShadedMode()) {
return true;
}
if (geometry && frameContext.
getLightingMode() == MFrameContext::kLightDefault) {
const MMatrix viewProjInv = frameContext.
getMatrix(MFrameContext::kViewProjInverseMtx);
geometry->accept(visitor);
bool outOfViewFrustum = true;
for (unsigned int i = 0; i < fInstanceDagPaths.length(); i++) {
const MMatrix worldInv = fInstanceDagPaths[i].inclusiveMatrixInverse();
Frustum frustum(viewProjInv * worldInv,
if (frustum.test(visitor.boundingBox()) != Frustum::kOutside) {
outOfViewFrustum = false;
break;
}
}
if (outOfViewFrustum) {
if (fOutOfViewFrustum && fOutOfViewFrustumUpdated) {
return false;
}
}
SubSceneOverride* nonConstThis = const_cast<SubSceneOverride*>(this);
if (fOutOfViewFrustum ^ outOfViewFrustum) {
nonConstThis->dirtyVisibility();
}
nonConstThis->fOutOfViewFrustum = outOfViewFrustum;
nonConstThis->fOutOfViewFrustumUpdated = false;
}
else {
SubSceneOverride* nonConstThis = const_cast<SubSceneOverride*>(this);
if (fOutOfViewFrustum) {
nonConstThis->dirtyVisibility();
}
nonConstThis->fOutOfViewFrustum = false;
nonConstThis->fOutOfViewFrustumUpdated = false;
}
CacheFileEntry::BackgroundReadingState readingState = fShapeNode->backgroundReadingState();
if (readingState != fReadingState) {
return true;
}
if (readingState != CacheFileEntry::kReadingDone) {
boost::posix_time::ptime currentTime =
boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time();
boost::posix_time::time_duration interval = currentTime - fUpdateTime;
if (interval.total_milliseconds() >= (int)(Config::backgroundReadingRefresh() / 2)) {
return true;
}
return false;
}
return fUpdateRenderItemsRequired ||
fUpdateVisibilityRequired ||
fUpdateWorldMatrixRequired ||
fUpdateStreamsRequired ||
fUpdateMaterialsRequired;
}
{
assert(fShapeNode);
if (!fShapeNode) return;
if (fNodeDirtyCallbacks.length() == 0) {
registerNodeDirtyCallbacks();
}
const bool hwInstancing = useHardwareInstancing();
if (hwInstancing && !fHardwareInstanceManager) {
dirtyRenderItems();
fHardwareInstanceManager.reset(new HardwareInstanceManager(*this));
}
else if (!hwInstancing && fHardwareInstanceManager) {
fHardwareInstanceManager->resetInstances(container);
fHardwareInstanceManager.reset();
}
BuffersCache::getInstance().shrink();
SubNode::Ptr geometry = fShapeNode->getCachedGeometry();
MaterialGraphMap::Ptr material = fShapeNode->getCachedMaterial();
fUpdateTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time();
if (geometry != fGeometry || material != fMaterial) {
fGeometry = geometry;
fMaterial = material;
fInstanceRenderItems.clear();
fHierarchyStat.reset();
dirtyEverything();
}
CacheFileEntry::BackgroundReadingState readingState = fShapeNode->backgroundReadingState();
if (readingState != fReadingState || readingState != CacheFileEntry::kReadingDone) {
fReadingState = readingState;
dirtyEverything();
}
if (fWireOnShadedMode != DisplayPref::wireframeOnShadedMode()) {
fWireOnShadedMode = DisplayPref::wireframeOnShadedMode();
dirtyRenderItems();
}
if (fUpdateRenderItemsRequired) {
updateRenderItems(container, frameContext);
fUpdateRenderItemsRequired = false;
}
if (fUpdateVisibilityRequired) {
updateVisibility(container, frameContext);
fUpdateVisibilityRequired = false;
}
if (fUpdateWorldMatrixRequired) {
updateWorldMatrix(container, frameContext);
fUpdateWorldMatrixRequired = false;
}
if (fUpdateStreamsRequired) {
updateStreams(container, frameContext);
fUpdateStreamsRequired = false;
}
if (fUpdateMaterialsRequired) {
updateMaterials(container, frameContext);
fUpdateMaterialsRequired = false;
}
if (!fHierarchyStat && fReadingState == CacheFileEntry::kReadingDone && fGeometry) {
HierarchyStatVisitor visitor(fGeometry);
fGeometry->accept(visitor);
fHierarchyStat = visitor.getStat();
MRenderer::setLightsAndShadowsDirty();
}
if (fHardwareInstanceManager) {
fHardwareInstanceManager->processInstances(container);
}
if (fOutOfViewFrustum) {
fOutOfViewFrustumUpdated = true;
}
}
{
unsigned int pathIndex = -1;
int hardwareInstanceIndex = intersection.
instanceID();
if (hardwareInstanceIndex >= 0)
{
pathIndex = fHardwareInstanceManager->instancePathIndex(renderItem, hardwareInstanceIndex);
}
else
{
renderItem.
name().
split(
':', renderItemParts);
if (renderItemParts.
length() > 1 && renderItemParts[0].isUnsigned())
{
pathIndex = renderItemParts[0].asUnsigned();
}
}
if (pathIndex < fInstanceDagPaths.length())
{
dagPath.
set(fInstanceDagPaths[pathIndex]);
return true;
}
return false;
}
{
if (pointSnappingActive())
{
}
}
void SubSceneOverride::dirtyEverything()
{
dirtyRenderItems();
dirtyVisibility();
dirtyWorldMatrix();
dirtyStreams();
dirtyMaterials();
}
void SubSceneOverride::dirtyRenderItems()
{
fUpdateRenderItemsRequired = true;
}
void SubSceneOverride::dirtyVisibility()
{
fUpdateVisibilityRequired = true;
}
void SubSceneOverride::dirtyWorldMatrix()
{
fUpdateWorldMatrixRequired = true;
}
void SubSceneOverride::dirtyStreams()
{
fUpdateStreamsRequired = true;
}
void SubSceneOverride::dirtyMaterials()
{
fUpdateMaterialsRequired = true;
}
void SubSceneOverride::resetDagPaths()
{
fInstanceDagPaths.clear();
}
void SubSceneOverride::registerNodeDirtyCallbacks()
{
assert(!fObject.isNull());
if (fObject.isNull()) return;
for (
unsigned int i = 0; i < paths.
length(); i++) {
dagPath, ParentChangedCallback, this);
dagPath, ParentChangedCallback, this);
node, NodeDirtyCallback, this);
fNodeDirtyCallbacks.append(parentAddedCallback);
fNodeDirtyCallbacks.append(parentRemovedCallback);
fNodeDirtyCallbacks.append(nodeDirtyCallback);
}
}
}
void SubSceneOverride::clearNodeDirtyCallbacks()
{
if (fNodeDirtyCallbacks.length() > 0) {
fNodeDirtyCallbacks.clear();
}
}
{
if (!fGeometry) {
return;
}
unsigned int instanceCount = fInstanceDagPaths.length();
if (instanceCount > fInstanceRenderItems.size()) {
unsigned int difference = (unsigned int)(instanceCount - fInstanceRenderItems.size());
for (unsigned int i = 0; i < difference; i++) {
fInstanceRenderItems.push_back(
boost::make_shared<InstanceRenderItems>());
}
MRenderer::setLightsAndShadowsDirty();
}
else if (instanceCount < fInstanceRenderItems.size()) {
unsigned int difference = (unsigned int)(fInstanceRenderItems.size() - instanceCount);
for (unsigned int i = 0; i < difference; i++) {
fInstanceRenderItems.back()->destroyRenderItems(container);
fInstanceRenderItems.pop_back();
}
MRenderer::setLightsAndShadowsDirty();
}
assert(fInstanceDagPaths.length() == fInstanceRenderItems.size());
for (unsigned int i = 0; i < fInstanceRenderItems.size(); i++) {
assert(fInstanceRenderItems[i]);
fInstanceRenderItems[i]->updateRenderItems(
*this, container, fInstanceDagPaths[i], instancePrefix);
}
}
{
if (!fGeometry) {
return;
}
BOOST_FOREACH (InstanceRenderItems::Ptr& instance, fInstanceRenderItems) {
instance->updateVisibility(*this, container, fOutOfViewFrustum);
}
}
{
if (!fGeometry) {
return;
}
BOOST_FOREACH (InstanceRenderItems::Ptr& instance, fInstanceRenderItems) {
instance->updateWorldMatrix(*this, container);
}
}
{
if (!fGeometry) {
return;
}
BOOST_FOREACH (InstanceRenderItems::Ptr& instance, fInstanceRenderItems) {
instance->updateStreams(*this, container);
}
}
{
if (!fGeometry) {
return;
}
BOOST_FOREACH (InstanceRenderItems::Ptr& instance, fInstanceRenderItems) {
instance->updateMaterials(*this, container);
}
ShaderInstanceCache::getInstance().updateCachedShadedShaders(fTimeInSeconds);
}
}