#include "BsScriptGizmoManager.h" #include "BsScriptAssemblyManager.h" #include "BsMonoAssembly.h" #include "BsMonoClass.h" #include "BsMonoMethod.h" #include "BsMonoField.h" #include "BsMonoManager.h" #include "BsSceneManager.h" #include "BsSceneObject.h" #include "BsComponent.h" #include "BsManagedComponent.h" #include "BsGizmoManager.h" #include "BsSelection.h" #include "BsMonoManager.h" using namespace std::placeholders; namespace BansheeEngine { ScriptGizmoManager::ScriptGizmoManager(ScriptAssemblyManager& scriptObjectManager) :mScriptObjectManager(scriptObjectManager), mDrawGizmoAttribute(nullptr), mFlagsField(nullptr) { mDomainLoadedConn = MonoManager::instance().onDomainReload.connect(std::bind(&ScriptGizmoManager::reloadAssemblyData, this)); reloadAssemblyData(); } ScriptGizmoManager::~ScriptGizmoManager() { mDomainLoadedConn.disconnect(); } void ScriptGizmoManager::update() { GizmoManager::instance().clearGizmos(); HSceneObject rootSO = SceneManager::instance().getRootNode(); Stack todo; todo.push(rootSO); bool isParentSelected = false; UINT32 parentSelectedPopIdx = 0; Vector selectedObjects = Selection::instance().getSceneObjects(); while (!todo.empty()) { if (isParentSelected && parentSelectedPopIdx == (UINT32)todo.size()) { isParentSelected = false; } HSceneObject curSO = todo.top(); todo.pop(); bool isSelected = std::count(selectedObjects.begin(), selectedObjects.end(), curSO) > 0; if (isSelected && !isParentSelected) { isParentSelected = true; parentSelectedPopIdx = (UINT32)todo.size(); } const Vector& components = curSO->getComponents(); for (auto& component : components) { if (rtti_is_of_type(component.get())) { ManagedComponent* managedComponent = static_cast(component.get()); auto iterFind = mGizmoDrawers.find(managedComponent->getManagedFullTypeName()); if (iterFind != mGizmoDrawers.end()) { UINT32 flags = iterFind->second.flags; bool drawGizmo = false; if (((flags & (UINT32)DrawGizmoFlags::Selected) != 0) && isSelected) drawGizmo = true; if (((flags & (UINT32)DrawGizmoFlags::ParentSelected) != 0) && isParentSelected) drawGizmo = true; if (((flags & (UINT32)DrawGizmoFlags::NotSelected) != 0) && !isSelected && !isParentSelected) drawGizmo = true; if (drawGizmo) { bool pickable = (flags & (UINT32)DrawGizmoFlags::Pickable) != 0; GizmoManager::instance().startGizmo(curSO); GizmoManager::instance().setPickable(pickable); void* params[1] = { managedComponent->getManagedInstance() }; iterFind->second.drawGizmosMethod->invoke(nullptr, params); GizmoManager::instance().endGizmo(); } } } } for (UINT32 i = 0; i < curSO->getNumChildren(); i++) todo.push(curSO->getChild(i)); } } void ScriptGizmoManager::reloadAssemblyData() { // Reload DrawGizmo attribute from editor assembly MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(BansheeEditorAssemblyName); mDrawGizmoAttribute = editorAssembly->getClass("BansheeEditor", "DrawGizmo"); if (mDrawGizmoAttribute == nullptr) BS_EXCEPT(InvalidStateException, "Cannot find DrawGizmo managed class."); mFlagsField = mDrawGizmoAttribute->getField("flags"); Vector scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies(); for (auto& assemblyName : scriptAssemblyNames) { MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName); // Find new gizmo drawer methods const Vector& allClasses = assembly->getAllClasses(); for (auto curClass : allClasses) { const Vector& methods = curClass->getAllMethods(); for (auto& curMethod : methods) { UINT32 drawGizmoFlags = 0; MonoClass* componentType = nullptr; if (isValidDrawGizmoMethod(curMethod, componentType, drawGizmoFlags)) { String fullComponentName = componentType->getFullName(); GizmoData& newGizmoData = mGizmoDrawers[fullComponentName]; newGizmoData.componentType = componentType; newGizmoData.drawGizmosMethod = curMethod; newGizmoData.flags = drawGizmoFlags; } } } } } bool ScriptGizmoManager::isValidDrawGizmoMethod(MonoMethod* method, MonoClass*& componentType, UINT32& drawGizmoFlags) { componentType = nullptr; drawGizmoFlags = 0; if (!method->hasAttribute(mDrawGizmoAttribute)) return false; if (method->getNumParameters() != 1) return false; if (!method->isStatic()) return false; MonoClass* paramType = method->getParameterType(0); MonoClass* componentClass = mScriptObjectManager.getComponentClass(); if (!paramType->isSubClassOf(componentClass)) return false; componentType = paramType; MonoObject* drawGizmoAttrib = method->getAttribute(mDrawGizmoAttribute); mFlagsField->getValue(drawGizmoAttrib, &drawGizmoFlags); return true; } }