summaryrefslogtreecommitdiff
path: root/Runtime/Filters/Renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Filters/Renderer.cpp')
-rw-r--r--Runtime/Filters/Renderer.cpp663
1 files changed, 663 insertions, 0 deletions
diff --git a/Runtime/Filters/Renderer.cpp b/Runtime/Filters/Renderer.cpp
new file mode 100644
index 0000000..33a0b5b
--- /dev/null
+++ b/Runtime/Filters/Renderer.cpp
@@ -0,0 +1,663 @@
+#include "UnityPrefix.h"
+#include "Renderer.h"
+#include "Runtime/Shaders/Material.h"
+#include "Runtime/Shaders/MaterialProperties.h"
+#include "Runtime/Camera/UnityScene.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Geometry/AABB.h"
+#include "Runtime/Camera/Camera.h"
+#include "Runtime/Camera/Culler.h"
+#include "Runtime/BaseClasses/SupportedMessageOptimization.h"
+#include "Runtime/Misc/BuildSettings.h"
+#include "Runtime/Camera/LODGroup.h"
+#include "Runtime/BaseClasses/EventIDs.h"
+#include "Runtime/Misc/GameObjectUtility.h"
+#include "Runtime/Modules/ExportModules.h"
+#include "RendererAnimationBinding.h"
+
+using namespace Unity;
+
+IMPLEMENT_CLASS_HAS_POSTINIT (Renderer)
+IMPLEMENT_OBJECT_SERIALIZE (Renderer)
+INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED (Renderer)
+
+typedef List< ListNode<Renderer> > RendererList;
+static RendererList gRenderersToUpdate;
+
+
+static Transform *gIdentityTransform = NULL;
+
+Transform* GetIdentityTransform() { return gIdentityTransform; }
+
+Renderer::Renderer (RendererType type, MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+, BaseRenderer(type)
+, m_LODGroup (NULL)
+, m_SceneHandle(kInvalidSceneHandle)
+, m_RenderersListNode(this)
+, m_Enabled(true)
+, m_Visible(true)
+//, m_Materials (Renderer::MaterialArray::allocator_type (*baseAllocator))
+#if UNITY_EDITOR
+, m_SelectedWireframeHidden(false)
+#endif
+, m_UseLightProbes(false)
+, m_LastLightProbeTetIndex(-1)
+, m_SortingLayer(0)
+, m_SortingOrder(0)
+#if UNITY_EDITOR
+, m_SortingLayerID(0)
+#endif
+{
+
+}
+
+void Renderer::SmartReset ()
+{
+ Super::SmartReset();
+ SetMaterialCount (1);
+}
+
+Renderer::~Renderer ()
+{
+ DebugAssert (!IsInScene());
+ delete m_CustomProperties;
+
+ if (m_LODGroup)
+ m_LODGroup->RemoveFromCachedRenderers(this);
+}
+
+void Renderer::CleanupClass()
+{
+ Assert(gIdentityTransform != NULL);
+ gIdentityTransform = NULL;
+
+ CleanupRendererAnimationBindingInterface ();
+}
+
+void Renderer::InitializeClass()
+{
+ REGISTER_MESSAGE (Renderer, kTransformChanged, TransformChanged, int);
+ REGISTER_MESSAGE_VOID (Renderer, kLayerChanged, LayerChanged);
+
+ InitializeRendererAnimationBindingInterface ();
+}
+
+void Renderer::PostInitializeClass()
+{
+ Assert(gIdentityTransform == NULL);
+
+ GameObject* go = CreateObjectFromCode<GameObject> ();
+ gIdentityTransform = CreateObjectFromCode<Transform> ();
+ GameObject::AddComponentInternal(*go, *gIdentityTransform);
+ go->SetHideFlags(kHideAndDontSave);
+ Assert(!go->IsActive());
+}
+
+bool Renderer::IsVisibleInScene () const
+{
+ Assert ((m_IsVisibleInScene && IsInScene()) == m_IsVisibleInScene);
+ return m_IsVisibleInScene;
+}
+
+void Renderer::RendererBecameVisible()
+{
+ BaseRenderer::RendererBecameVisible ();
+
+ InvokeEvent (kBecameVisibleEvent);
+
+ SendMessage (kBecameVisible);
+}
+
+void Renderer::RendererBecameInvisible()
+{
+ BaseRenderer::RendererBecameInvisible ();
+
+ SendMessage (kBecameInvisible);
+
+ InvokeEvent (kBecameInvisibleEvent);
+}
+
+int Renderer::GetLayer() const
+{
+ return GetGameObject().GetLayer();
+}
+
+
+void Renderer::SetVisible (bool visible)
+{
+ m_Visible = visible;
+
+ bool shouldBeInScene = ShouldBeInScene();
+ if (shouldBeInScene == IsInScene())
+ return;
+
+ if (!shouldBeInScene)
+ {
+ // Remove from scene immediately
+ RemoveFromScene ();
+ UpdateManagerState( false );
+
+ InvokeEvent(kBecameInvisibleEvent);
+ }
+ else
+ {
+ // Add to scene in renderers update
+ UpdateManagerState( true );
+ }
+}
+
+void Renderer::BoundsChanged ()
+{
+ m_BoundsDirty = true;
+ if (IsInScene())
+ GetScene().SetDirtyAABB(m_SceneHandle);
+}
+
+void Renderer::LayerMaskChanged ()
+{
+ if (IsInScene())
+ GetScene().SetRendererLayer(m_SceneHandle, GetLayer());
+}
+
+void Renderer::UpdateManagerState( bool needsUpdate )
+{
+ if( needsUpdate == m_RenderersListNode.IsInList() )
+ return;
+ if( needsUpdate )
+ gRenderersToUpdate.push_front(m_RenderersListNode);
+ else
+ m_RenderersListNode.RemoveFromList();
+}
+
+void Renderer::UpdateAllRenderersInternal()
+{
+ // Update the renderers from the update list:
+ // - before updating each, remove from the list
+ // - a renderer can add itself again, so only process the original list length
+ RendererList::iterator next, listEnd = gRenderersToUpdate.end();
+ for( RendererList::iterator i = gRenderersToUpdate.begin(); i != listEnd; i = next )
+ {
+ next = i;
+ next++;
+ Renderer& renderer = **i;
+ renderer.m_RenderersListNode.RemoveFromList();
+ renderer.UpdateRenderer();
+ }
+}
+
+void Renderer::NotifySceneHandleChange (SceneHandle handle)
+{
+ m_SceneHandle = handle;
+}
+
+void Renderer::UpdateLODGroup ()
+{
+ if (!IsInScene())
+ return;
+ Unity::Scene& scene = GetScene();
+ DebugAssert (scene.GetRendererNode(m_SceneHandle).renderer == this);
+
+ UInt32 lodGroup = 0;
+ UInt32 lodIndexMask = 0;
+ if (m_LODGroup != NULL)
+ {
+ m_LODGroup->GetLODGroupIndexAndMask(this, &lodGroup, &lodIndexMask);
+ }
+ scene.SetRendererLODGroup(m_SceneHandle, lodGroup);
+ scene.SetRendererLODIndexMask(m_SceneHandle, lodIndexMask);
+}
+
+void Renderer::UpdateSceneHandle ()
+{
+ if (!IsInScene())
+ return;
+ Unity::Scene& scene = GetScene();
+ DebugAssert (scene.GetRendererNode(m_SceneHandle).renderer == this);
+
+ AABB worldAABB;
+ GetWorldAABB (worldAABB);
+ scene.SetRendererAABB(m_SceneHandle, worldAABB);
+
+ bool needsCullCallback = (GetGameObject().GetSupportedMessages() & kHasOnWillRenderObject) != 0;
+ scene.SetRendererNeedsCullCallback(m_SceneHandle, needsCullCallback);
+ scene.SetRendererLayer(m_SceneHandle, GetLayer());
+
+ UpdateLODGroup();
+}
+
+void Renderer::UpdateTransformInfo ()
+{
+ Transform const& transform = GetTransform();
+ if(m_TransformDirty)
+ {
+ m_TransformInfo.invScale = 1.0f;
+ // will return a cached matrix most of the time
+ m_TransformInfo.transformType = transform.CalculateTransformMatrix (m_TransformInfo.worldMatrix);
+ }
+
+ if(m_BoundsDirty)
+ UpdateLocalAABB ();
+
+ TransformAABB( m_TransformInfo.localAABB, m_TransformInfo.worldMatrix, m_TransformInfo.worldAABB );
+
+ if (IsNoScaleTransform(m_TransformInfo.transformType))
+ return;
+
+ // run slow path for non uniform scale
+ Matrix4x4f scaleOnly;
+ float scale;
+ TransformType type = transform.CalculateTransformMatrixDisableNonUniformScale (m_TransformInfo.worldMatrix, scaleOnly, scale);
+ Assert (type == m_TransformInfo.transformType);
+
+ m_TransformInfo.invScale = 1.0F / scale;
+
+ if (IsNonUniformScaleTransform(type))
+ {
+ // must recalculate this since it is changed with the following transform
+ UpdateLocalAABB ();
+ TransformAABB (m_TransformInfo.localAABB, scaleOnly, m_TransformInfo.localAABB);
+ }
+}
+
+void Renderer::UpdateRenderer ()
+{
+ if (ShouldBeInScene ())
+ {
+ if (!IsInScene())
+ {
+ m_SceneHandle = GetScene().AddRenderer (this);
+ }
+ Assert (m_SceneHandle != kInvalidSceneHandle);
+ UpdateSceneHandle ();
+ }
+ else
+ {
+ // This should not be necessary but fixes a weird bug where a mesh is
+ // being leaked when disabled before loading a scene. Happens in the fps tutorial.
+ RemoveFromScene ();
+ }
+}
+
+void Renderer::SetPropertyBlock (const MaterialPropertyBlock& block)
+{
+ delete m_CustomProperties;
+ m_CustomProperties = new MaterialPropertyBlock (block);
+ ComputeCustomPropertiesHash();
+}
+
+void Renderer::GetPropertyBlock (MaterialPropertyBlock& outBlock)
+{
+ if (!m_CustomProperties)
+ {
+ outBlock.Clear();
+ return;
+ }
+ outBlock = *m_CustomProperties;
+}
+
+void Renderer::ClearPropertyBlock ()
+{
+ delete m_CustomProperties;
+ m_CustomProperties = NULL;
+ ComputeCustomPropertiesHash();
+}
+
+MaterialPropertyBlock& Renderer::GetPropertyBlockRememberToUpdateHash ()
+{
+ if (!m_CustomProperties)
+ m_CustomProperties = new MaterialPropertyBlock ();
+ return *m_CustomProperties;
+}
+
+
+void Renderer::SetEnabled (bool newEnabled)
+{
+ m_Enabled = newEnabled;
+ SetDirty();
+ SetVisible(m_Visible);
+}
+
+void Renderer::Deactivate (DeactivateOperation operation)
+{
+ RemoveFromScene ();
+ UpdateManagerState( false );
+ Super::Deactivate (operation);
+}
+
+/// Set how many materials this renderer uses
+/// @param size the number of materials.
+void Renderer::SetMaterialCount (int size)
+{
+ const size_t oldSize = m_Materials.size ();
+
+ if (size != (int)oldSize)
+ {
+ Assert(m_SubsetIndices.empty() || m_SubsetIndices.size() == m_Materials.size());
+
+ resize_trimmed (m_Materials, size);
+ HealSubsetIndices();
+
+ SetDirty ();
+ BoundsChanged();
+ }
+}
+
+void Renderer::HealSubsetIndices()
+{
+ // We are using batching and our subset indices have gone out of sync
+ if (!m_SubsetIndices.empty() && m_SubsetIndices.size() != m_Materials.size())
+ {
+ int oldSize = m_SubsetIndices.size();
+ resize_trimmed (m_SubsetIndices, m_Materials.size());
+ // All new subset indices get the
+ for (size_t q = oldSize; q < m_SubsetIndices.size(); ++q)
+ m_SubsetIndices[q] = (UInt32)q;
+ BoundsChanged();
+ }
+}
+
+void Renderer::RemoveFromScene ()
+{
+ if (!IsInScene())
+ return;
+
+ bool wasVisible = IsVisibleInScene ();
+
+ BaseRenderer* remRenderer = GetScene ().RemoveRenderer (m_SceneHandle);
+ Assert(remRenderer == this);
+
+ m_SceneHandle = kInvalidSceneHandle;
+
+ if (wasVisible)
+ RendererBecameInvisible ();
+}
+
+void Renderer::CheckConsistency()
+{
+ Super::CheckConsistency();
+
+ HealSubsetIndices();
+}
+
+void Renderer::ClearSubsetIndices()
+{
+ m_SubsetIndices.clear();
+ SetDirty ();
+ BoundsChanged();
+}
+
+void Renderer::SetSubsetIndex (int index, int subsetIndex)
+{
+ if (m_SubsetIndices.empty())
+ {
+ resize_trimmed (m_SubsetIndices, m_Materials.size());
+ for (size_t q = 0; q < m_Materials.size(); ++q)
+ m_SubsetIndices[q] = (UInt32)q;
+ }
+
+ Assert(index < m_SubsetIndices.size());
+ Assert (m_Materials.size() == m_SubsetIndices.size());
+ m_SubsetIndices[index] = subsetIndex;
+ SetDirty ();
+ BoundsChanged();
+}
+
+/// Set a given Material.
+/// @param material the material to assign
+/// @param index the index to assign the material to.
+void Renderer::SetMaterial (PPtr<Material> material, int index)
+{
+ Assert (index < m_Materials.size());
+ m_Materials[index] = material;
+
+ /*
+ #if !DEPLOY_OPTIMIZED
+ Material* materialPtr = material;
+ if (materialPtr && materialPtr->GetOwner ().GetInstanceID () != 0 && materialPtr->GetOwner() != PPtr<Object> (this))
+ {
+ ErrorString("Assigning an instantiated material is not a good idea. Since the material is owned by another game object, it will be destroyed when the game object is destroyed.\nYou probably want to explicitly instantiate the material.");
+ }
+ #endif
+ */
+
+ SetDirty ();
+}
+
+void Renderer::SetMaterialArray( const MaterialArray& m, const IndexArray& i )
+{
+ m_Materials = m;
+ m_SubsetIndices = i;
+}
+
+Material* Renderer::GetAndAssignInstantiatedMaterial(int i, bool allowFromEditMode)
+{
+ // Grab shared material
+ Material* material = NULL;
+ if (GetMaterialCount () > i)
+ material = GetMaterial (i);
+
+ // instantiate material if necessary
+ Material* instantiated = &Material::GetInstantiatedMaterial (material, *this, allowFromEditMode);
+
+ // Assign material
+ if (material != instantiated)
+ {
+ SetMaterialCount (std::max(GetMaterialCount (), i + 1));
+ SetMaterial (instantiated, i);
+ }
+
+ return instantiated;
+}
+
+Transform& Renderer::GetTransform()
+{
+ if (!IsPartOfStaticBatch())
+ return GetComponent(Transform);
+
+ if (!m_StaticBatchRoot.IsNull())
+ return *m_StaticBatchRoot;
+
+ return *gIdentityTransform;
+}
+
+Transform const& Renderer::GetTransform() const
+{
+ return const_cast<Renderer*>(this)->GetTransform();
+}
+
+Matrix4x4f Renderer::GetWorldToLocalMatrix () const
+{
+ return GetTransform().GetWorldToLocalMatrix();
+}
+
+Matrix4x4f Renderer::GetLocalToWorldMatrix () const
+{
+ return GetTransform().GetLocalToWorldMatrix();
+}
+
+
+// Receiver for the TransformChanged message.
+// Updates the scene info with the new bounds.
+void Renderer::TransformChanged (int changeMask)
+{
+ m_TransformDirty = true;
+ BoundsChanged ();
+}
+
+// Receiver for the LayerChanged message.
+// Updates the scene info with the new layerMask.
+void Renderer::LayerChanged ()
+{
+ LayerMaskChanged ();
+}
+
+void Renderer::AwakeFromLoad (AwakeFromLoadMode awakeMode)
+{
+ Super::AwakeFromLoad (awakeMode);
+
+ // Materials might have been changed eg. from the property editor
+ // When loading from disk the materials are only being restored not changed
+ if ((awakeMode & kDidLoadFromDisk) == 0)
+ {
+ // m_Enabled might have changed - update visibility status
+ SetVisible(m_Visible);
+ }
+
+ UpdateManagerState( IsActive() );
+ SetupSortingOverride();
+}
+
+void Renderer::SupportedMessagesDidChange (int mask)
+{
+ Super::SupportedMessagesDidChange(mask);
+
+ if (IsInScene())
+ {
+ bool needsCullCallback = (GetGameObject().GetSupportedMessages() & kHasOnWillRenderObject) != 0;
+ GetScene().SetRendererNeedsCullCallback(m_SceneHandle, needsCullCallback);
+ }
+}
+
+void Renderer::SetLightmapIndexInt(int index)
+{
+ UInt8 oldIndex = m_LightmapIndex;
+ SetLightmapIndexIntNoDirty (index);
+ if (oldIndex != m_LightmapIndex)
+ SetDirty();
+}
+
+void Renderer::SetLightmapST( const Vector4f& st )
+{
+ if (st != m_LightmapST)
+ {
+ m_LightmapST = st;
+ SetDirty();
+ }
+}
+
+
+#if UNITY_EDITOR
+bool Renderer::CanSelectedWireframeBeRendered () const
+{
+ return m_Enabled && m_Visible && IsInScene() && !m_SelectedWireframeHidden;
+}
+#endif
+
+template<class TransferFunction>
+void Renderer::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ transfer.Transfer(m_Enabled, "m_Enabled", kHideInEditorMask);
+ transfer.Transfer(m_CastShadows, "m_CastShadows");
+ transfer.Transfer(m_ReceiveShadows, "m_ReceiveShadows");
+ transfer.Transfer(m_LightmapIndex, "m_LightmapIndex", kHideInEditorMask | kDontAnimate);
+ transfer.Transfer(m_LightmapST, "m_LightmapTilingOffset", kHideInEditorMask | kDontAnimate);
+ transfer.Transfer (m_Materials, "m_Materials");
+ transfer.Transfer (m_SubsetIndices, "m_SubsetIndices", kHideInEditorMask);
+ transfer.Transfer (m_StaticBatchRoot, "m_StaticBatchRoot", kHideInEditorMask);
+ TRANSFER (m_UseLightProbes);
+ transfer.Align();
+ TRANSFER (m_LightProbeAnchor);
+ #if UNITY_EDITOR
+ if (!transfer.IsSerializingForGameRelease())
+ transfer.Transfer (m_ScaleInLightmap, "m_ScaleInLightmap", kHideInEditorMask | kDontAnimate);
+ #endif
+ transfer.Align();
+
+ transfer.Transfer (m_SortingLayer, "m_SortingLayer", kHideInEditorMask);
+ transfer.Transfer (m_SortingOrder, "m_SortingOrder", kHideInEditorMask);
+ // In the editor, we also transfer global sorting layer ID, so we can derive final sorting value
+ // in case layers are reordered / etc.
+ TRANSFER_EDITOR_ONLY_HIDDEN(m_SortingLayerID);
+}
+
+Vector3f Renderer::GetLightProbeInterpolationPosition (const AABB& worldBounds)
+{
+ Transform* anchor = m_LightProbeAnchor;
+ if (anchor != NULL)
+ return anchor->GetPosition();
+
+ return worldBounds.GetCenter();
+}
+
+
+Vector3f Renderer::GetLightProbeInterpolationPosition ()
+{
+ Transform* anchor = m_LightProbeAnchor;
+ if (anchor != NULL)
+ return anchor->GetPosition();
+
+ AABB aabb;
+ GetWorldAABB(aabb);
+ if (aabb.IsValid())
+ return aabb.GetCenter();
+
+ return Vector3f(0,0,0);
+}
+
+
+
+int Renderer::GetSortingLayerUserID() const
+{
+ if (m_SortingLayer == 0)
+ return 0;
+ return ::GetSortingLayerUserIDFromValue(m_SortingLayer);
+}
+
+void Renderer::SetSortingLayerUserID(int id)
+{
+ int layerValue = GetSortingLayerValueFromUserID(id);
+ if (m_SortingLayer == layerValue)
+ return;
+
+# if UNITY_EDITOR
+ if (layerValue == 0)
+ m_SortingLayerID = 0;
+ else
+ m_SortingLayerID = ::GetSortingLayerUniqueIDFromValue(layerValue);
+# endif
+
+ m_SortingLayer = layerValue;
+ SetupSortingOverride();
+ SetDirty();
+}
+
+std::string Renderer::GetSortingLayerName() const
+{
+ if (m_SortingLayer == 0)
+ return std::string();
+ return ::GetSortingLayerNameFromValue(m_SortingLayer);
+}
+
+void Renderer::SetSortingLayerName(const std::string& name)
+{
+ int layerValue = ::GetSortingLayerValueFromName(name);
+ int layerUserID = ::GetSortingLayerUserIDFromValue(layerValue);
+ SetSortingLayerUserID (layerUserID);
+}
+
+
+void Renderer::SetSortingOrder(SInt16 newValue)
+{
+ if (m_SortingOrder == newValue)
+ return;
+
+ m_SortingOrder = newValue;
+ SetupSortingOverride();
+}
+
+void Renderer::SetupSortingOverride()
+{
+ // In editor, make sure our final layer sorting value is up to date
+ // (might have changed behind our backs by global layer reordering).
+# if UNITY_EDITOR
+ m_SortingLayer = GetSortingLayerValueFromUniqueID(m_SortingLayerID);
+# endif // if UNITY_EDITOR
+
+ GlobalLayeringData gld = GlobalLayeringDataCleared();
+ gld.layer = m_SortingLayer;
+ gld.order = m_SortingOrder;
+ SetGlobalLayeringData(gld);
+}