Prechádzať zdrojové kódy

Started work on node/component enable & disable.
Converted Drawable components to use the Enabled flag (replaces Visible attribute.)
Converted ScriptInstance to use the Enabled flag.
Converted SoundSource & SoundSource3D to use the Enabled flag.
Show disabled node/component icons in red.

Lasse Öörni 12 rokov pred
rodič
commit
af8825047a
41 zmenil súbory, kde vykonal 703 pridanie a 468 odobranie
  1. 0 2
      Bin/Data/Objects/LightFlash.xml
  2. 314 317
      Bin/Data/Objects/Ninja.xml
  3. 0 2
      Bin/Data/Objects/Potion.xml
  4. 0 2
      Bin/Data/Objects/SnowBall.xml
  5. 0 2
      Bin/Data/Objects/SnowCrate.xml
  6. 0 4
      Bin/Data/Scenes/NinjaSnowWar.xml
  7. 23 10
      Bin/Data/Scripts/Editor/EditorGizmo.as
  8. 40 1
      Bin/Data/Scripts/Editor/EditorNodeWindow.as
  9. 41 12
      Bin/Data/Scripts/Editor/EditorSceneWindow.as
  10. 8 0
      Bin/Data/Scripts/Editor/EditorUI.as
  11. 1 1
      Bin/Data/Scripts/Editor/EditorView.as
  12. 56 13
      Docs/ScriptAPI.dox
  13. 6 5
      Engine/Audio/SoundSource.cpp
  14. 3 2
      Engine/Engine/APITemplates.h
  15. 0 2
      Engine/Engine/GraphicsAPI.cpp
  16. 3 0
      Engine/Engine/SceneAPI.cpp
  17. 0 2
      Engine/Engine/ScriptAPI.cpp
  18. 1 1
      Engine/Graphics/AnimatedModel.cpp
  19. 4 0
      Engine/Graphics/AnimationController.cpp
  20. 1 1
      Engine/Graphics/BillboardSet.cpp
  21. 1 1
      Engine/Graphics/CustomGeometry.cpp
  22. 1 1
      Engine/Graphics/DecalSet.cpp
  23. 14 7
      Engine/Graphics/Drawable.cpp
  24. 2 6
      Engine/Graphics/Drawable.h
  25. 1 1
      Engine/Graphics/Light.cpp
  26. 2 4
      Engine/Graphics/Octree.cpp
  27. 4 4
      Engine/Graphics/OctreeQuery.cpp
  28. 4 1
      Engine/Graphics/ParticleEmitter.cpp
  29. 1 1
      Engine/Graphics/StaticModel.cpp
  30. 15 14
      Engine/Graphics/Terrain.cpp
  31. 2 2
      Engine/Graphics/Terrain.h
  32. 4 5
      Engine/Graphics/View.cpp
  33. 11 2
      Engine/Graphics/Zone.cpp
  34. 2 0
      Engine/Graphics/Zone.h
  35. 32 1
      Engine/Scene/Component.cpp
  36. 10 0
      Engine/Scene/Component.h
  37. 66 17
      Engine/Scene/Node.cpp
  38. 8 2
      Engine/Scene/Node.h
  39. 16 1
      Engine/Scene/SceneEvents.h
  40. 6 13
      Engine/Script/ScriptInstance.cpp
  41. 0 6
      Engine/Script/ScriptInstance.h

+ 0 - 2
Bin/Data/Objects/LightFlash.xml

@@ -7,7 +7,6 @@
     <component type="ScriptInstance" id="16777217">
         <attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
         <attribute name="Class Name" value="LightFlash" />
-        <attribute name="Is Active" value="true" />
         <attribute name="Fixed Update FPS" value="0" />
         <attribute name="Time Accumulator" value="0" />
         <attribute name="Delayed Method Calls" value="0" />
@@ -22,7 +21,6 @@
         <attribute name="Spot Aspect Ratio" value="1" />
         <attribute name="Attenuation Texture" value="Texture2D;Textures/RampWide.png" />
         <attribute name="Light Shape Texture" value="Texture2D;" />
-        <attribute name="Is Visible" value="true" />
         <attribute name="Can Be Occluded" value="true" />
         <attribute name="Cast Shadows" value="true" />
         <attribute name="Per Vertex" value="false" />

+ 314 - 317
Bin/Data/Objects/Ninja.xml

@@ -1,317 +1,314 @@
-<?xml version="1.0"?>
-<node id="2">
-	<attribute name="Name" value="Ninja" />
-	<attribute name="Position" value="0 10 20" />
-	<attribute name="Rotation" value="1 0 0 0" />
-	<attribute name="Scale" value="1 1 1" />
-	<attribute name="Variables" />
-	<component type="ScriptInstance" id="16777216">
-		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
-		<attribute name="Class Name" value="Ninja" />
-		<attribute name="Is Active" value="true" />
-		<attribute name="Fixed Update FPS" value="0" />
-		<attribute name="Time Accumulator" value="0" />
-		<attribute name="Delayed Method Calls" value="0" />
-		<attribute name="Script Data" value="" />
-	</component>
-	<component type="NetworkPriority" id="16777217">
-		<attribute name="Base Priority" value="110" />
-		<attribute name="Distance Factor" value="0.02" />
-		<attribute name="Minimum Priority" value="50" />
-		<attribute name="Always Update Owner" value="true" />
-	</component>
-	<component type="CollisionShape" id="4">
-		<attribute name="Shape Type" value="Capsule" />
-		<attribute name="Size" value="70 180 70" />
-		<attribute name="Offset Position" value="0 0 0" />
-		<attribute name="Offset Rotation" value="1 0 0 0" />
-		<attribute name="Collision Margin" value="1" />
-		<attribute name="Model" value="Model;" />
-		<attribute name="LOD Level" value="0" />
-	</component>
-	<component type="RigidBody" id="5">
-		<attribute name="Physics Position" value="0 10 20" />
-		<attribute name="Physics Rotation" value="1 0 0 0" />
-		<attribute name="Mass" value="80" />
-		<attribute name="Friction" value="0.5" />
-		<attribute name="Restitution" value="0" />
-		<attribute name="Linear Velocity" value="0 0 0" />
-		<attribute name="Angular Velocity" value="0 0 0" />
-		<attribute name="Linear Factor" value="1 1 1" />
-		<attribute name="Angular Factor" value="0 0 0" />
-		<attribute name="Linear Damping" value="0" />
-		<attribute name="Angular Damping" value="0" />
-		<attribute name="Linear Rest Threshold" value="0.8" />
-		<attribute name="Angular Rest Threshold" value="1" />
-		<attribute name="Collision Layer" value="1" />
-		<attribute name="Collision Mask" value="3" />
-		<attribute name="Collision Event Mode" value="Always" />
-		<attribute name="Use Gravity" value="true" />
-		<attribute name="Is Kinematic" value="false" />
-		<attribute name="Is Phantom" value="false" />
-	</component>
-	<node id="3">
-		<attribute name="Name" value="" />
-		<attribute name="Position" value="0 -90 0" />
-		<attribute name="Rotation" value="1 0 0 0" />
-		<attribute name="Scale" value="1 1 1" />
-		<attribute name="Variables" />
-		<component type="AnimatedModel" id="6">
-			<attribute name="Model" value="Model;Models/Ninja.mdl" />
-			<attribute name="Material" value="Material;Materials/Ninja.xml;Materials/Ninja.xml" />
-			<attribute name="Is Visible" value="true" />
-			<attribute name="Is Occluder" value="false" />
-			<attribute name="Can Be Occluded" value="true" />
-			<attribute name="Cast Shadows" value="true" />
-			<attribute name="Draw Distance" value="15000" />
-			<attribute name="Shadow Distance" value="0" />
-			<attribute name="LOD Bias" value="1" />
-			<attribute name="Animation LOD Bias" value="1" />
-			<attribute name="Max Lights" value="0" />
-			<attribute name="View Mask" value="-1" />
-			<attribute name="Light Mask" value="-1" />
-			<attribute name="Shadow Mask" value="-1" />
-			<attribute name="Zone Mask" value="-1" />
-			<attribute name="Bone Animation Enabled">
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-				<variant type="Bool" value="true" />
-			</attribute>
-			<attribute name="Animation States" />
-			<attribute name="Morphs" value="" />
-		</component>
-		<component type="AnimationController" id="7">
-			<attribute name="Animations" />
-		</component>
-    	<component type="ScriptInstance" id="8">
-    		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
-    		<attribute name="Class Name" value="FootSteps" />
-    		<attribute name="Is Active" value="true" />
-    		<attribute name="Fixed Update FPS" value="0" />
-    		<attribute name="Time Accumulator" value="0" />
-    		<attribute name="Delayed Method Calls" value="0" />
-    		<attribute name="Script Data" value="" />
-    	</component>
-		<node id="16777216">
-			<attribute name="Name" value="Joint1" />
-			<attribute name="Position" value="0.185046 0.51196 -0" />
-			<attribute name="Rotation" value="1 -0 -0 0" />
-			<attribute name="Scale" value="1 1 1" />
-			<attribute name="Variables" />
-			<node id="16777217">
-				<attribute name="Name" value="Joint2" />
-				<attribute name="Position" value="0 108.105 1.56659" />
-				<attribute name="Rotation" value="1 -0 -0 0" />
-				<attribute name="Scale" value="1 1 1" />
-				<attribute name="Variables" />
-				<node id="16777218">
-					<attribute name="Name" value="Joint3" />
-					<attribute name="Position" value="0.421854 9.67481 1.0444" />
-					<attribute name="Rotation" value="1 -0 -0 0" />
-					<attribute name="Scale" value="1 1 1" />
-					<attribute name="Variables" />
-					<node id="16777219">
-						<attribute name="Name" value="Joint4" />
-						<attribute name="Position" value="0.421854 8.41288 3.72529e-007" />
-						<attribute name="Rotation" value="1 -0 -0 0" />
-						<attribute name="Scale" value="1 1 1" />
-						<attribute name="Variables" />
-						<node id="16777220">
-							<attribute name="Name" value="Joint5" />
-							<attribute name="Position" value="-0.843709 17.1516 1.02305" />
-							<attribute name="Rotation" value="1 -0 -0 0" />
-							<attribute name="Scale" value="1 1 1" />
-							<attribute name="Variables" />
-							<node id="16777221">
-								<attribute name="Name" value="Joint6" />
-								<attribute name="Position" value="3.72529e-008 19.7703 -2.61099" />
-								<attribute name="Rotation" value="1 -0 -0 0" />
-								<attribute name="Scale" value="1 1 1" />
-								<attribute name="Variables" />
-								<node id="16777222">
-									<attribute name="Name" value="Joint7" />
-									<attribute name="Position" value="0 4.74305 1.0444" />
-									<attribute name="Rotation" value="1 -0 -0 0" />
-									<attribute name="Scale" value="1 1 1" />
-									<attribute name="Variables" />
-									<node id="16777223">
-										<attribute name="Name" value="Joint8" />
-										<attribute name="Position" value="-0.185046 9.18524 3.08366" />
-										<attribute name="Rotation" value="1 -0 -0 0" />
-										<attribute name="Scale" value="1 1 1" />
-										<attribute name="Variables" />
-									</node>
-								</node>
-								<node id="16777224">
-									<attribute name="Name" value="Joint9" />
-									<attribute name="Position" value="14.3431 -3.65739 -6.76722" />
-									<attribute name="Rotation" value="1 -0 -0 0" />
-									<attribute name="Scale" value="1 1 1" />
-									<attribute name="Variables" />
-									<node id="16777225">
-										<attribute name="Name" value="Joint10" />
-										<attribute name="Position" value="5.90596 -2.02329 -0" />
-										<attribute name="Rotation" value="1 -0 -0 0" />
-										<attribute name="Scale" value="1 1 1" />
-										<attribute name="Variables" />
-										<node id="16777226">
-											<attribute name="Name" value="Joint11" />
-											<attribute name="Position" value="3.37483 -29.4451 5.74418" />
-											<attribute name="Rotation" value="1 -0 -0 0" />
-											<attribute name="Scale" value="1 1 1" />
-											<attribute name="Variables" />
-											<node id="16777227">
-												<attribute name="Name" value="Joint12" />
-												<attribute name="Position" value="1.33815 -28.6038 3.13318" />
-												<attribute name="Rotation" value="1 -0 -0 0" />
-												<attribute name="Scale" value="1 1 1" />
-												<attribute name="Variables" />
-												<node id="16777228">
-													<attribute name="Name" value="Joint13" />
-													<attribute name="Position" value="0.136921 -6.24266 3.42546" />
-													<attribute name="Rotation" value="1 -0 -0 0" />
-													<attribute name="Scale" value="1 1 1" />
-													<attribute name="Variables" />
-													<node id="16777229">
-														<attribute name="Name" value="Joint29" />
-														<attribute name="Position" value="-0.0284957 -5.80133 76.0905" />
-														<attribute name="Rotation" value="1 -0 -0 0" />
-														<attribute name="Scale" value="1 1 1" />
-														<attribute name="Variables" />
-													</node>
-												</node>
-											</node>
-										</node>
-									</node>
-								</node>
-								<node id="16777230">
-									<attribute name="Name" value="Joint14" />
-									<attribute name="Position" value="-14.3431 -3.69103 -6.76722" />
-									<attribute name="Rotation" value="1 -0 -0 0" />
-									<attribute name="Scale" value="1 1 1" />
-									<attribute name="Variables" />
-									<node id="16777231">
-										<attribute name="Name" value="Joint15" />
-										<attribute name="Position" value="-7.17153 -2.10322 -0" />
-										<attribute name="Rotation" value="1 -0 -0 0" />
-										<attribute name="Scale" value="1 1 1" />
-										<attribute name="Variables" />
-										<node id="16777232">
-											<attribute name="Name" value="Joint16" />
-											<attribute name="Position" value="-2.53113 -28.6038 5.74418" />
-											<attribute name="Rotation" value="1 -0 -0 0" />
-											<attribute name="Scale" value="1 1 1" />
-											<attribute name="Variables" />
-											<node id="16777233">
-												<attribute name="Name" value="Joint17" />
-												<attribute name="Position" value="-1.68742 -30.2864 3.13318" />
-												<attribute name="Rotation" value="1 -0 -0 0" />
-												<attribute name="Scale" value="1 1 1" />
-												<attribute name="Variables" />
-											</node>
-										</node>
-									</node>
-								</node>
-							</node>
-						</node>
-					</node>
-				</node>
-				<node id="16777234">
-					<attribute name="Name" value="Joint18" />
-					<attribute name="Position" value="9.70265 -8.41289 2.08879" />
-					<attribute name="Rotation" value="1 -0 -0 0" />
-					<attribute name="Scale" value="1 1 1" />
-					<attribute name="Variables" />
-					<node id="16777235">
-						<attribute name="Name" value="Joint19" />
-						<attribute name="Position" value="2.95298 -43.747 -1.56659" />
-						<attribute name="Rotation" value="1 -0 -0 0" />
-						<attribute name="Scale" value="1 1 1" />
-						<attribute name="Variables" />
-						<node id="16777236">
-							<attribute name="Name" value="Joint20" />
-							<attribute name="Position" value="-0.843709 -46.1989 -11.34" />
-							<attribute name="Rotation" value="1 -0 -0 0" />
-							<attribute name="Scale" value="1 1 1" />
-							<attribute name="Variables" />
-							<node id="16777237">
-								<attribute name="Name" value="Joint21" />
-								<attribute name="Position" value="1.43906 -9.37045 13.1049" />
-								<attribute name="Rotation" value="1 -0 -0 0" />
-								<attribute name="Scale" value="1 1 1" />
-								<attribute name="Variables" />
-								<node id="16777238">
-									<attribute name="Name" value="Joint22" />
-									<attribute name="Position" value="0.421854 -0.438055 7.61888" />
-									<attribute name="Rotation" value="1 -0 -0 0" />
-									<attribute name="Scale" value="1 1 1" />
-									<attribute name="Variables" />
-								</node>
-							</node>
-						</node>
-					</node>
-				</node>
-				<node id="16777239">
-					<attribute name="Name" value="Joint23" />
-					<attribute name="Position" value="-8.85894 -8.41289 2.08879" />
-					<attribute name="Rotation" value="1 -0 -0 0" />
-					<attribute name="Scale" value="1 1 1" />
-					<attribute name="Variables" />
-					<node id="16777240">
-						<attribute name="Name" value="Joint24" />
-						<attribute name="Position" value="-3.37484 -43.3263 -1.56659" />
-						<attribute name="Rotation" value="1 -0 -0 0" />
-						<attribute name="Scale" value="1 1 1" />
-						<attribute name="Variables" />
-						<node id="16777241">
-							<attribute name="Name" value="Joint25" />
-							<attribute name="Position" value="-0.843709 -46.6195 -11.34" />
-							<attribute name="Rotation" value="1 -0 -0 0" />
-							<attribute name="Scale" value="1 1 1" />
-							<attribute name="Variables" />
-							<node id="16777242">
-								<attribute name="Name" value="Joint26" />
-								<attribute name="Position" value="-0.557851 -9.7911 13.1049" />
-								<attribute name="Rotation" value="1 -0 -0 0" />
-								<attribute name="Scale" value="1 1 1" />
-								<attribute name="Variables" />
-								<node id="16777243">
-									<attribute name="Name" value="Joint27" />
-									<attribute name="Position" value="0 -0.017411 7.61888" />
-									<attribute name="Rotation" value="1 -0 -0 0" />
-									<attribute name="Scale" value="1 1 1" />
-									<attribute name="Variables" />
-								</node>
-							</node>
-						</node>
-					</node>
-				</node>
-			</node>
-		</node>
-	</node>
-</node>
+<?xml version="1.0"?>
+<node id="2">
+	<attribute name="Name" value="Ninja" />
+	<attribute name="Position" value="0 10 20" />
+	<attribute name="Rotation" value="1 0 0 0" />
+	<attribute name="Scale" value="1 1 1" />
+	<attribute name="Variables" />
+	<component type="ScriptInstance" id="16777216">
+		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
+		<attribute name="Class Name" value="Ninja" />
+		<attribute name="Fixed Update FPS" value="0" />
+		<attribute name="Time Accumulator" value="0" />
+		<attribute name="Delayed Method Calls" value="0" />
+		<attribute name="Script Data" value="" />
+	</component>
+	<component type="NetworkPriority" id="16777217">
+		<attribute name="Base Priority" value="110" />
+		<attribute name="Distance Factor" value="0.02" />
+		<attribute name="Minimum Priority" value="50" />
+		<attribute name="Always Update Owner" value="true" />
+	</component>
+	<component type="CollisionShape" id="4">
+		<attribute name="Shape Type" value="Capsule" />
+		<attribute name="Size" value="70 180 70" />
+		<attribute name="Offset Position" value="0 0 0" />
+		<attribute name="Offset Rotation" value="1 0 0 0" />
+		<attribute name="Collision Margin" value="1" />
+		<attribute name="Model" value="Model;" />
+		<attribute name="LOD Level" value="0" />
+	</component>
+	<component type="RigidBody" id="5">
+		<attribute name="Physics Position" value="0 10 20" />
+		<attribute name="Physics Rotation" value="1 0 0 0" />
+		<attribute name="Mass" value="80" />
+		<attribute name="Friction" value="0.5" />
+		<attribute name="Restitution" value="0" />
+		<attribute name="Linear Velocity" value="0 0 0" />
+		<attribute name="Angular Velocity" value="0 0 0" />
+		<attribute name="Linear Factor" value="1 1 1" />
+		<attribute name="Angular Factor" value="0 0 0" />
+		<attribute name="Linear Damping" value="0" />
+		<attribute name="Angular Damping" value="0" />
+		<attribute name="Linear Rest Threshold" value="0.8" />
+		<attribute name="Angular Rest Threshold" value="1" />
+		<attribute name="Collision Layer" value="1" />
+		<attribute name="Collision Mask" value="3" />
+		<attribute name="Collision Event Mode" value="Always" />
+		<attribute name="Use Gravity" value="true" />
+		<attribute name="Is Kinematic" value="false" />
+		<attribute name="Is Phantom" value="false" />
+	</component>
+	<node id="3">
+		<attribute name="Name" value="" />
+		<attribute name="Position" value="0 -90 0" />
+		<attribute name="Rotation" value="1 0 0 0" />
+		<attribute name="Scale" value="1 1 1" />
+		<attribute name="Variables" />
+		<component type="AnimatedModel" id="6">
+			<attribute name="Model" value="Model;Models/Ninja.mdl" />
+			<attribute name="Material" value="Material;Materials/Ninja.xml;Materials/Ninja.xml" />
+			<attribute name="Is Occluder" value="false" />
+			<attribute name="Can Be Occluded" value="true" />
+			<attribute name="Cast Shadows" value="true" />
+			<attribute name="Draw Distance" value="15000" />
+			<attribute name="Shadow Distance" value="0" />
+			<attribute name="LOD Bias" value="1" />
+			<attribute name="Animation LOD Bias" value="1" />
+			<attribute name="Max Lights" value="0" />
+			<attribute name="View Mask" value="-1" />
+			<attribute name="Light Mask" value="-1" />
+			<attribute name="Shadow Mask" value="-1" />
+			<attribute name="Zone Mask" value="-1" />
+			<attribute name="Bone Animation Enabled">
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+				<variant type="Bool" value="true" />
+			</attribute>
+			<attribute name="Animation States" />
+			<attribute name="Morphs" value="" />
+		</component>
+		<component type="AnimationController" id="7">
+			<attribute name="Animations" />
+		</component>
+    	<component type="ScriptInstance" id="8">
+    		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
+    		<attribute name="Class Name" value="FootSteps" />
+    		<attribute name="Fixed Update FPS" value="0" />
+    		<attribute name="Time Accumulator" value="0" />
+    		<attribute name="Delayed Method Calls" value="0" />
+    		<attribute name="Script Data" value="" />
+    	</component>
+		<node id="16777216">
+			<attribute name="Name" value="Joint1" />
+			<attribute name="Position" value="0.185046 0.51196 -0" />
+			<attribute name="Rotation" value="1 -0 -0 0" />
+			<attribute name="Scale" value="1 1 1" />
+			<attribute name="Variables" />
+			<node id="16777217">
+				<attribute name="Name" value="Joint2" />
+				<attribute name="Position" value="0 108.105 1.56659" />
+				<attribute name="Rotation" value="1 -0 -0 0" />
+				<attribute name="Scale" value="1 1 1" />
+				<attribute name="Variables" />
+				<node id="16777218">
+					<attribute name="Name" value="Joint3" />
+					<attribute name="Position" value="0.421854 9.67481 1.0444" />
+					<attribute name="Rotation" value="1 -0 -0 0" />
+					<attribute name="Scale" value="1 1 1" />
+					<attribute name="Variables" />
+					<node id="16777219">
+						<attribute name="Name" value="Joint4" />
+						<attribute name="Position" value="0.421854 8.41288 3.72529e-007" />
+						<attribute name="Rotation" value="1 -0 -0 0" />
+						<attribute name="Scale" value="1 1 1" />
+						<attribute name="Variables" />
+						<node id="16777220">
+							<attribute name="Name" value="Joint5" />
+							<attribute name="Position" value="-0.843709 17.1516 1.02305" />
+							<attribute name="Rotation" value="1 -0 -0 0" />
+							<attribute name="Scale" value="1 1 1" />
+							<attribute name="Variables" />
+							<node id="16777221">
+								<attribute name="Name" value="Joint6" />
+								<attribute name="Position" value="3.72529e-008 19.7703 -2.61099" />
+								<attribute name="Rotation" value="1 -0 -0 0" />
+								<attribute name="Scale" value="1 1 1" />
+								<attribute name="Variables" />
+								<node id="16777222">
+									<attribute name="Name" value="Joint7" />
+									<attribute name="Position" value="0 4.74305 1.0444" />
+									<attribute name="Rotation" value="1 -0 -0 0" />
+									<attribute name="Scale" value="1 1 1" />
+									<attribute name="Variables" />
+									<node id="16777223">
+										<attribute name="Name" value="Joint8" />
+										<attribute name="Position" value="-0.185046 9.18524 3.08366" />
+										<attribute name="Rotation" value="1 -0 -0 0" />
+										<attribute name="Scale" value="1 1 1" />
+										<attribute name="Variables" />
+									</node>
+								</node>
+								<node id="16777224">
+									<attribute name="Name" value="Joint9" />
+									<attribute name="Position" value="14.3431 -3.65739 -6.76722" />
+									<attribute name="Rotation" value="1 -0 -0 0" />
+									<attribute name="Scale" value="1 1 1" />
+									<attribute name="Variables" />
+									<node id="16777225">
+										<attribute name="Name" value="Joint10" />
+										<attribute name="Position" value="5.90596 -2.02329 -0" />
+										<attribute name="Rotation" value="1 -0 -0 0" />
+										<attribute name="Scale" value="1 1 1" />
+										<attribute name="Variables" />
+										<node id="16777226">
+											<attribute name="Name" value="Joint11" />
+											<attribute name="Position" value="3.37483 -29.4451 5.74418" />
+											<attribute name="Rotation" value="1 -0 -0 0" />
+											<attribute name="Scale" value="1 1 1" />
+											<attribute name="Variables" />
+											<node id="16777227">
+												<attribute name="Name" value="Joint12" />
+												<attribute name="Position" value="1.33815 -28.6038 3.13318" />
+												<attribute name="Rotation" value="1 -0 -0 0" />
+												<attribute name="Scale" value="1 1 1" />
+												<attribute name="Variables" />
+												<node id="16777228">
+													<attribute name="Name" value="Joint13" />
+													<attribute name="Position" value="0.136921 -6.24266 3.42546" />
+													<attribute name="Rotation" value="1 -0 -0 0" />
+													<attribute name="Scale" value="1 1 1" />
+													<attribute name="Variables" />
+													<node id="16777229">
+														<attribute name="Name" value="Joint29" />
+														<attribute name="Position" value="-0.0284957 -5.80133 76.0905" />
+														<attribute name="Rotation" value="1 -0 -0 0" />
+														<attribute name="Scale" value="1 1 1" />
+														<attribute name="Variables" />
+													</node>
+												</node>
+											</node>
+										</node>
+									</node>
+								</node>
+								<node id="16777230">
+									<attribute name="Name" value="Joint14" />
+									<attribute name="Position" value="-14.3431 -3.69103 -6.76722" />
+									<attribute name="Rotation" value="1 -0 -0 0" />
+									<attribute name="Scale" value="1 1 1" />
+									<attribute name="Variables" />
+									<node id="16777231">
+										<attribute name="Name" value="Joint15" />
+										<attribute name="Position" value="-7.17153 -2.10322 -0" />
+										<attribute name="Rotation" value="1 -0 -0 0" />
+										<attribute name="Scale" value="1 1 1" />
+										<attribute name="Variables" />
+										<node id="16777232">
+											<attribute name="Name" value="Joint16" />
+											<attribute name="Position" value="-2.53113 -28.6038 5.74418" />
+											<attribute name="Rotation" value="1 -0 -0 0" />
+											<attribute name="Scale" value="1 1 1" />
+											<attribute name="Variables" />
+											<node id="16777233">
+												<attribute name="Name" value="Joint17" />
+												<attribute name="Position" value="-1.68742 -30.2864 3.13318" />
+												<attribute name="Rotation" value="1 -0 -0 0" />
+												<attribute name="Scale" value="1 1 1" />
+												<attribute name="Variables" />
+											</node>
+										</node>
+									</node>
+								</node>
+							</node>
+						</node>
+					</node>
+				</node>
+				<node id="16777234">
+					<attribute name="Name" value="Joint18" />
+					<attribute name="Position" value="9.70265 -8.41289 2.08879" />
+					<attribute name="Rotation" value="1 -0 -0 0" />
+					<attribute name="Scale" value="1 1 1" />
+					<attribute name="Variables" />
+					<node id="16777235">
+						<attribute name="Name" value="Joint19" />
+						<attribute name="Position" value="2.95298 -43.747 -1.56659" />
+						<attribute name="Rotation" value="1 -0 -0 0" />
+						<attribute name="Scale" value="1 1 1" />
+						<attribute name="Variables" />
+						<node id="16777236">
+							<attribute name="Name" value="Joint20" />
+							<attribute name="Position" value="-0.843709 -46.1989 -11.34" />
+							<attribute name="Rotation" value="1 -0 -0 0" />
+							<attribute name="Scale" value="1 1 1" />
+							<attribute name="Variables" />
+							<node id="16777237">
+								<attribute name="Name" value="Joint21" />
+								<attribute name="Position" value="1.43906 -9.37045 13.1049" />
+								<attribute name="Rotation" value="1 -0 -0 0" />
+								<attribute name="Scale" value="1 1 1" />
+								<attribute name="Variables" />
+								<node id="16777238">
+									<attribute name="Name" value="Joint22" />
+									<attribute name="Position" value="0.421854 -0.438055 7.61888" />
+									<attribute name="Rotation" value="1 -0 -0 0" />
+									<attribute name="Scale" value="1 1 1" />
+									<attribute name="Variables" />
+								</node>
+							</node>
+						</node>
+					</node>
+				</node>
+				<node id="16777239">
+					<attribute name="Name" value="Joint23" />
+					<attribute name="Position" value="-8.85894 -8.41289 2.08879" />
+					<attribute name="Rotation" value="1 -0 -0 0" />
+					<attribute name="Scale" value="1 1 1" />
+					<attribute name="Variables" />
+					<node id="16777240">
+						<attribute name="Name" value="Joint24" />
+						<attribute name="Position" value="-3.37484 -43.3263 -1.56659" />
+						<attribute name="Rotation" value="1 -0 -0 0" />
+						<attribute name="Scale" value="1 1 1" />
+						<attribute name="Variables" />
+						<node id="16777241">
+							<attribute name="Name" value="Joint25" />
+							<attribute name="Position" value="-0.843709 -46.6195 -11.34" />
+							<attribute name="Rotation" value="1 -0 -0 0" />
+							<attribute name="Scale" value="1 1 1" />
+							<attribute name="Variables" />
+							<node id="16777242">
+								<attribute name="Name" value="Joint26" />
+								<attribute name="Position" value="-0.557851 -9.7911 13.1049" />
+								<attribute name="Rotation" value="1 -0 -0 0" />
+								<attribute name="Scale" value="1 1 1" />
+								<attribute name="Variables" />
+								<node id="16777243">
+									<attribute name="Name" value="Joint27" />
+									<attribute name="Position" value="0 -0.017411 7.61888" />
+									<attribute name="Rotation" value="1 -0 -0 0" />
+									<attribute name="Scale" value="1 1 1" />
+									<attribute name="Variables" />
+								</node>
+							</node>
+						</node>
+					</node>
+				</node>
+			</node>
+		</node>
+	</node>
+</node>

+ 0 - 2
Bin/Data/Objects/Potion.xml

@@ -8,7 +8,6 @@
 	<component type="ScriptInstance" id="16777217">
 		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
 		<attribute name="Class Name" value="Potion" />
-		<attribute name="Is Active" value="true" />
 		<attribute name="Fixed Update FPS" value="0" />
 		<attribute name="Time Accumulator" value="0" />
 		<attribute name="Delayed Method Calls" value="0" />
@@ -23,7 +22,6 @@
 	<component type="StaticModel" id="7">
 		<attribute name="Model" value="Model;Models/Potion.mdl" />
 		<attribute name="Material" value="Material;Materials/Potion.xml" />
-		<attribute name="Is Visible" value="true" />
 		<attribute name="Is Occluder" value="false" />
 		<attribute name="Can Be Occluded" value="true" />
 		<attribute name="Cast Shadows" value="true" />

+ 0 - 2
Bin/Data/Objects/SnowBall.xml

@@ -8,7 +8,6 @@
 	<component type="ScriptInstance" id="16777216">
 		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
 		<attribute name="Class Name" value="SnowBall" />
-		<attribute name="Is Active" value="true" />
 		<attribute name="Fixed Update FPS" value="0" />
 		<attribute name="Time Accumulator" value="0" />
 		<attribute name="Delayed Method Calls" value="0" />
@@ -23,7 +22,6 @@
 	<component type="StaticModel" id="4">
 		<attribute name="Model" value="Model;Models/SnowBall.mdl" />
 		<attribute name="Material" value="Material;Materials/Snow.xml" />
-		<attribute name="Is Visible" value="true" />
 		<attribute name="Is Occluder" value="false" />
 		<attribute name="Can Be Occluded" value="true" />
 		<attribute name="Cast Shadows" value="true" />

+ 0 - 2
Bin/Data/Objects/SnowCrate.xml

@@ -8,7 +8,6 @@
 	<component type="ScriptInstance" id="16777219">
 		<attribute name="Script File" value="ScriptFile;Scripts/NinjaSnowWar.as" />
 		<attribute name="Class Name" value="SnowCrate" />
-		<attribute name="Is Active" value="true" />
 		<attribute name="Fixed Update FPS" value="0" />
 		<attribute name="Time Accumulator" value="0" />
 		<attribute name="Delayed Method Calls" value="0" />
@@ -23,7 +22,6 @@
 	<component type="StaticModel" id="11">
 		<attribute name="Model" value="Model;Models/SnowCrate.mdl" />
 		<attribute name="Material" value="Material;Materials/SnowCrate.xml" />
-		<attribute name="Is Visible" value="true" />
 		<attribute name="Is Occluder" value="false" />
 		<attribute name="Can Be Occluded" value="true" />
 		<attribute name="Cast Shadows" value="true" />

+ 0 - 4
Bin/Data/Scenes/NinjaSnowWar.xml

@@ -37,7 +37,6 @@
 			<attribute name="Fog Color" value="0.2 0.2 0.7 1" />
 			<attribute name="Fog Start" value="5000" />
 			<attribute name="Fog End" value="15000" />
-			<attribute name="Is Visible" value="true" />
 			<attribute name="Override Mode" value="false" />
 			<attribute name="Ambient Gradient" value="false" />
 			<attribute name="Priority" value="0" />
@@ -61,7 +60,6 @@
 			<attribute name="Spot Aspect Ratio" value="1" />
 			<attribute name="Attenuation Texture" value="Texture2D;" />
 			<attribute name="Light Shape Texture" value="Texture2D;" />
-			<attribute name="Is Visible" value="true" />
 			<attribute name="Can Be Occluded" value="true" />
 			<attribute name="Cast Shadows" value="true" />
 			<attribute name="Per Vertex" value="false" />
@@ -94,7 +92,6 @@
 		<component type="StaticModel" id="16777220">
 			<attribute name="Model" value="Model;Models/Level.mdl" />
 			<attribute name="Material" value="Material;Materials/Snow.xml" />
-			<attribute name="Is Visible" value="true" />
 			<attribute name="Is Occluder" value="false" />
 			<attribute name="Can Be Occluded" value="true" />
 			<attribute name="Cast Shadows" value="false" />
@@ -147,7 +144,6 @@
 		<component type="Skybox" id="16777222">
 			<attribute name="Model" value="Model;Models/CloudPlane.mdl" />
 			<attribute name="Material" value="Material;Materials/CloudPlane.xml" />
-			<attribute name="Is Visible" value="true" />
 			<attribute name="Is Occluder" value="false" />
 			<attribute name="Can Be Occluded" value="true" />
 			<attribute name="Cast Shadows" value="false" />

+ 23 - 10
Bin/Data/Scripts/Editor/EditorGizmo.as

@@ -69,7 +69,7 @@ void CreateGizmo()
     gizmo.materials[0] = cache.GetResource("Material", "Materials/RedUnlit.xml");
     gizmo.materials[1] = cache.GetResource("Material", "Materials/GreenUnlit.xml");
     gizmo.materials[2] = cache.GetResource("Material", "Materials/BlueUnlit.xml");
-    gizmo.visible = false;
+    gizmo.enabled = false;
     gizmo.viewMask = 0x80000000; // Editor raycasts use viewmask 0x7fffffff
     gizmo.occludee = false;
 
@@ -77,18 +77,28 @@ void CreateGizmo()
     gizmoAxisY.lastSelected = false;
     gizmoAxisZ.lastSelected = false;
     lastGizmoMode = EDIT_MOVE;
-
-    // Add to the octree manually
-    if (editorScene.octree !is null)
-        editorScene.octree.AddManualDrawable(gizmo);
 }
 
 void HideGizmo()
 {
     if (gizmo !is null)
-        gizmo.visible = false;
+        gizmo.enabled = false;
+}
+
+void ShowGizmo()
+{
+    if (gizmo !is null)
+    {
+        gizmo.enabled = true;
+
+        // Because setting enabled = false detaches the gizmo from octree,
+        // and it is a manually added drawable, must readd to octree when showing
+        if (editorScene.octree !is null)
+            editorScene.octree.AddManualDrawable(gizmo);
+    }
 }
 
+
 void UpdateGizmo()
 {
     UseGizmo();
@@ -140,12 +150,15 @@ void PositionGizmo()
         lastGizmoMode = editMode;
     }
 
-    gizmo.visible = editMode != EDIT_SELECT;
+    if (editMode != EDIT_SELECT && !gizmo.enabled)
+        ShowGizmo();
+    else if (editMode == EDIT_SELECT && gizmo.enabled)
+        HideGizmo();
 }
 
 void ResizeGizmo()
 {
-    if (gizmo is null || !gizmo.visible)
+    if (gizmo is null || !gizmo.enabled)
         return;
 
     float c = 0.1;
@@ -176,7 +189,7 @@ void GizmoMoved()
 
 void UseGizmo()
 {
-    if (gizmo is null || !gizmo.visible || editMode == EDIT_SELECT)
+    if (gizmo is null || !gizmo.enabled || editMode == EDIT_SELECT)
         return;
 
     IntVector2 pos = ui.cursorPosition;
@@ -268,7 +281,7 @@ void UseGizmo()
 
 bool IsGizmoSelected()
 {
-    return gizmo !is null && gizmo.visible && (gizmoAxisX.selected || gizmoAxisY.selected || gizmoAxisZ.selected);
+    return gizmo !is null && gizmo.enabled && (gizmoAxisX.selected || gizmoAxisY.selected || gizmoAxisZ.selected);
 }
 
 bool MoveNodes(Vector3 adjust)

+ 40 - 1
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -135,7 +135,8 @@ void UpdateAttributes(bool fullUpdate)
                 Text@ componentTitle = GetComponentContainer(j).GetChild("ComponentTitle");
                 componentTitle.text = GetComponentTitle(editComponents[j * numEditableComponents]) + multiplierText;
                 IconizeUIElement(componentTitle, editComponents[j * numEditableComponents].typeName);
-                
+                SetIconEnabledColor(componentTitle, editComponents[j * numEditableComponents].enabledEffective);
+
                 Array<Serializable@> components;
                 for (uint i = 0; i < numEditableComponents; ++i)
                     components.Push(editComponents[j * numEditableComponents + i]);
@@ -144,6 +145,8 @@ void UpdateAttributes(bool fullUpdate)
             }
         }
     }
+    
+    UpdateNodeWindowIcons();
 }
 
 void UpdateNodeAttributes()
@@ -154,6 +157,42 @@ void UpdateNodeAttributes()
     }
 }
 
+void UpdateNodeWindowIcons()
+{
+    Text@ nodeTitle = nodeWindow.GetChild("NodeTitle", true);
+    if (editNode !is null)
+        SetIconEnabledColor(nodeTitle, editNode.enabled);
+    else if (editNodes.length > 0)
+    {
+        bool hasSameEnabledState = true;
+
+        for (uint i = 1; i < editNodes.length; ++i)
+        {
+            if (editNodes[i].enabled != editNodes[0].enabled)
+            {
+                hasSameEnabledState = false;
+                break;
+            }
+        }
+        if (hasSameEnabledState)
+            SetIconEnabledColor(nodeTitle, editNodes[0].enabled);
+    }
+
+    if (!editComponents.empty)
+    {
+        uint numEditableComponents = editComponents.length / numEditableComponentsPerNode;
+    
+        for (uint j = 0; j < numEditableComponentsPerNode; ++j)
+        {
+            if (j >= componentParentContainer.numChildren)
+                return;
+            
+            Text@ componentTitle = GetComponentContainer(j).GetChild("ComponentTitle");
+            SetIconEnabledColor(componentTitle, editComponents[j * numEditableComponents].enabledEffective);
+        }
+    }
+}
+
 void PostEditAttribute(Array<Serializable@>@ serializables, uint index)
 {
     // If a StaticModel/AnimatedModel/Skybox model was changed, apply a possibly different material list

+ 41 - 12
Bin/Data/Scripts/Editor/EditorSceneWindow.as

@@ -66,6 +66,8 @@ void CreateSceneWindow()
     SubscribeToEvent(editorScene, "ComponentAdded", "HandleComponentAdded");
     SubscribeToEvent(editorScene, "ComponentRemoved", "HandleComponentRemoved");
     SubscribeToEvent(editorScene, "NodeNameChanged", "HandleNodeNameChanged");
+    SubscribeToEvent(editorScene, "NodeEnabledChanged", "HandleNodeEnabledChanged");
+    SubscribeToEvent(editorScene, "ComponentEnabledChanged", "HandleComponentEnabledChanged");
 }
 
 void ShowSceneWindow()
@@ -151,6 +153,7 @@ uint UpdateSceneWindowNode(uint itemIndex, Node@ node, UIElement@ parentItem)
 
     hierarchyList.InsertItem(itemIndex, text, parentItem);
     IconizeUIElement(text, node.typeName);
+    SetIconEnabledColor(text, node.enabled);
 
     // Advance the index for the child components and/or nodes
     if (itemIndex == M_MAX_UNSIGNED)
@@ -179,24 +182,29 @@ uint UpdateSceneWindowNode(uint itemIndex, Node@ node, UIElement@ parentItem)
     return itemIndex;
 }
 
-void UpdateSceneWindowNodeOnly(uint itemIndex, Node@ node)
-{
-    Text@ text = hierarchyList.items[itemIndex];
-    if (text is null)
-        return;
-    text.text = GetNodeTitle(node);
-}
-
 void UpdateSceneWindowNode(Node@ node)
 {
     // In case of node's parent is not found in the hierarchy list then the node will inserted at the root level, but it should not happen
     UpdateSceneWindowNode(GetNodeListIndex(node), node, hierarchyList.items[GetNodeListIndex(node.parent)]);
 }
 
-void UpdateSceneWindowNodeOnly(Node@ node)
+void UpdateSceneWindowNodeText(Node@ node)
 {
     uint index = GetNodeListIndex(node);
-    UpdateSceneWindowNodeOnly(index, node);
+    Text@ text = hierarchyList.items[index];
+    if (text is null)
+        return;
+    text.text = GetNodeTitle(node);
+    SetIconEnabledColor(text, node.enabled);
+}
+
+void UpdateSceneWindowComponentText(Component@ component)
+{
+    uint index = GetComponentListIndex(component);
+    Text@ text = hierarchyList.items[index];
+    if (text is null)
+        return;
+    SetIconEnabledColor(text, component.enabledEffective);
 }
 
 void AddComponentToSceneWindow(Component@ component, uint compItemIndex, UIElement@ parentItem)
@@ -210,6 +218,7 @@ void AddComponentToSceneWindow(Component@ component, uint compItemIndex, UIEleme
     
     hierarchyList.InsertItem(compItemIndex, text, parentItem);
     IconizeUIElement(text, component.typeName);
+    SetIconEnabledColor(text, component.enabledEffective);
 }
 
 uint GetNodeListIndex(Node@ node)
@@ -743,5 +752,25 @@ void HandleNodeNameChanged(StringHash eventType, VariantMap& eventData)
         return;
     
     Node@ node = eventData["Node"].GetNode();
-    UpdateSceneWindowNodeOnly(node);
-}
+    UpdateSceneWindowNodeText(node);
+}
+
+void HandleNodeEnabledChanged(StringHash eventType, VariantMap& eventData)
+{
+    if (suppressSceneChanges)
+        return;
+    
+    Node@ node = eventData["Node"].GetNode();
+    UpdateSceneWindowNodeText(node);
+    UpdateNodeWindowIcons();
+}
+
+void HandleComponentEnabledChanged(StringHash eventType, VariantMap& eventData)
+{
+    if (suppressSceneChanges)
+        return;
+    
+    Component@ component = eventData["Component"].GetComponent();
+    UpdateSceneWindowComponentText(component);
+    UpdateNodeWindowIcons();
+}

+ 8 - 0
Bin/Data/Scripts/Editor/EditorUI.as

@@ -615,4 +615,12 @@ void IconizeUIElement(UIElement@ element, const String&in iconType)
 
     // Set the icon type
     icon.SetStyle(iconStyle, iconType);
+    icon.color = Color(1,1,1,1); // Reset to enabled color
 }
+
+void SetIconEnabledColor(UIElement@ element, bool enabled)
+{
+    BorderImage@ icon = element.GetChild("Icon");
+    if (icon !is null)
+        icon.color = enabled ? Color(1,1,1,1) : Color(1,0,0,1);
+}

+ 1 - 1
Bin/Data/Scripts/Editor/EditorView.as

@@ -75,7 +75,7 @@ Array<String> fillModeText = {
 
 void CreateCamera()
 {
-    // Note: the camera will not be bound into the scene, so that it is not listed, and does not get deleted
+    // Note: the camera is not inside the scene, so that it is not listed, and does not get deleted
     cameraNode = Node();
     camera = cameraNode.CreateComponent("Camera");
     audio.listener = cameraNode.CreateComponent("SoundListener");

+ 56 - 13
Docs/ScriptAPI.dox

@@ -1311,6 +1311,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 
@@ -1364,6 +1366,7 @@ Methods:<br>
 - Vector3 LocalToWorld(const Vector4&) const
 - Vector3 WorldToLocal(const Vector3&) const
 - Vector3 WorldToLocal(const Vector4&) const
+- void SetEnabledRecursive(bool)
 - bool SaveXML(File@)
 - Node@ Clone(CreateMode arg0 = REPLICATED)
 - ScriptObject@ CreateScriptObject(ScriptFile@, const String&, CreateMode arg2 = REPLICATED)
@@ -1398,6 +1401,7 @@ Properties:<br>
 - String name
 - Node@ parent
 - VariantMap vars (readonly)
+- bool enabled
 - Scene@ scene (readonly)
 - Connection@ owner
 - ScriptObject@ scriptObject (readonly)
@@ -1427,6 +1431,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - Vector3 targetPosition
@@ -1602,6 +1608,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 
@@ -1636,6 +1644,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - float nearClip
@@ -2018,10 +2028,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2079,10 +2090,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2138,10 +2150,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2190,10 +2203,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2238,10 +2252,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2315,10 +2330,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2396,6 +2412,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 
@@ -2435,10 +2453,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2485,10 +2504,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2543,10 +2563,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2592,10 +2613,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2640,10 +2662,11 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - bool inView (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2684,6 +2707,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - Material@ material
@@ -2693,7 +2718,6 @@ Properties:<br>
 - IntVector2 numVertices (readonly)
 - IntVector2 numPatches (readonly)
 - TerrainPatch@[] patches (readonly)
-- bool visible
 - bool castShadows
 - bool occluder
 - bool occludee
@@ -2749,6 +2773,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - BoundingBox worldBoundingBox (readonly)
@@ -2942,6 +2968,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 
@@ -2974,6 +3002,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - SoundType soundType
@@ -3016,6 +3046,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - SoundType soundType
@@ -4927,6 +4959,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - float basePriority
@@ -5028,6 +5062,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - ShapeType shapeType
@@ -5072,6 +5108,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - float mass
@@ -5124,6 +5162,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - ConstraintType constraintType
@@ -5182,6 +5222,8 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - Vector3 gravity
@@ -5240,9 +5282,10 @@ Properties:<br>
 - uint numAttributes (readonly)
 - Variant[] attributes
 - AttributeInfo[] attributeInfos (readonly)
+- bool enabled
+- bool enabledEffective (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
-- bool active
 - int fixedUpdateFps
 - ScriptFile@ scriptFile
 - ScriptObject@ object (readonly)

+ 6 - 5
Engine/Audio/SoundSource.cpp

@@ -136,6 +136,7 @@ void SoundSource::RegisterObject(Context* context)
 {
     context->RegisterFactory<SoundSource>();
     
+    ACCESSOR_ATTRIBUTE(SoundSource, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ENUM_ATTRIBUTE(SoundSource, "Sound Type", soundType_, typeNames, SOUND_EFFECT, AM_DEFAULT);
     ATTRIBUTE(SoundSource, VAR_FLOAT, "Frequency", frequency_, 0.0f, AM_DEFAULT);
     ATTRIBUTE(SoundSource, VAR_FLOAT, "Gain", gain_, 1.0f, AM_DEFAULT);
@@ -333,7 +334,7 @@ void SoundSource::SetPlayPositionLockless(signed char* pos)
 
 void SoundSource::Update(float timeStep)
 {
-    if (!audio_)
+    if (!audio_ || !IsEnabledEffective())
         return;
     
     // If there is no actual audio output, perform fake mixing into a nonexistent buffer to check stopping/looping
@@ -367,19 +368,19 @@ void SoundSource::Update(float timeStep)
 
 void SoundSource::Mix(int* dest, unsigned samples, int mixRate, bool stereo, bool interpolation)
 {
-    if (!position_ || !sound_)
+    if (!position_ || !sound_ || !IsEnabledEffective())
         return;
     
     if (sound_->IsCompressed())
     {
         if (decoder_)
         {
-            // If Decoder already exists, Decode new compressed audio
+            // If Decoder already exists, decode new compressed audio
             bool eof = false;
             unsigned currentPos = position_ - decodeBuffer_->GetStart();
             if (currentPos != decodePosition_)
             {
-                // If buffer has wrapped, Decode first to the end
+                // If buffer has wrapped, decode first to the end
                 if (currentPos < decodePosition_)
                 {
                     unsigned bytes = decodeBuffer_->GetDataSize() - decodePosition_;
@@ -1180,7 +1181,7 @@ void SoundSource::MixZeroVolume(Sound* sound, unsigned samples, int mixRate)
 
 void SoundSource::MixNull(float timeStep)
 {
-    if (!position_ || !sound_)
+    if (!position_ || !sound_ || !IsEnabledEffective())
         return;
     
     // Advance only the time position

+ 3 - 2
Engine/Engine/APITemplates.h

@@ -391,6 +391,9 @@ template <class T> void RegisterComponent(asIScriptEngine* engine, const char* c
     RegisterSubclass<Component, T>(engine, "Component", className);
     engine->RegisterObjectMethod(className, "void Remove()", asMETHODPR(T, Remove, (), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void MarkNetworkUpdate() const", asMETHODPR(T, MarkNetworkUpdate, (), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void set_enabled(bool)", asMETHODPR(T, SetEnabled, (bool), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "bool get_enabled() const", asMETHODPR(T, IsEnabled, () const, bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "bool get_enabledEffective() const", asMETHODPR(T, IsEnabledEffective, () const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint get_id()", asMETHODPR(T, GetID, () const, unsigned), asCALL_THISCALL);
     if (nodeRegistered)
         engine->RegisterObjectMethod(className, "Node@+ get_node() const", asMETHODPR(T, GetNode, () const, Node*), asCALL_THISCALL);
@@ -646,8 +649,6 @@ template <class T> void RegisterDrawable(asIScriptEngine* engine, const char* cl
     RegisterComponent<T>(engine, className);
     RegisterSubclass<Drawable, T>(engine, "Drawable", className);
     engine->RegisterObjectMethod(className, "bool get_inView() const", asFUNCTION(DrawableIsInView), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod(className, "void set_visible(bool)", asMETHOD(T, SetVisible), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "bool get_visible() const", asMETHOD(T, IsVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void set_castShadows(bool)", asMETHOD(T, SetCastShadows), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool get_castShadows() const", asMETHOD(T, GetCastShadows), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void set_occluder(bool)", asMETHOD(T, SetOccluder), asCALL_THISCALL);

+ 0 - 2
Engine/Engine/GraphicsAPI.cpp

@@ -943,8 +943,6 @@ static void RegisterTerrain(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Terrain", "const IntVector2& get_numVertices() const", asMETHOD(Terrain, GetNumVertices), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "const IntVector2& get_numPatches() const", asMETHOD(Terrain, GetNumPatches), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "TerrainPatch@+ get_patches(uint) const", asMETHODPR(Terrain, GetPatch, (unsigned) const, TerrainPatch*), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Terrain", "void set_visible(bool)", asMETHOD(Terrain, SetVisible), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Terrain", "bool get_visible() const", asMETHOD(Terrain, IsVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_castShadows(bool)", asMETHOD(Terrain, SetCastShadows), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "bool get_castShadows() const", asMETHOD(Terrain, GetCastShadows), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_occluder(bool)", asMETHOD(Terrain, SetOccluder), asCALL_THISCALL);

+ 3 - 0
Engine/Engine/SceneAPI.cpp

@@ -58,6 +58,9 @@ static void RegisterNode(asIScriptEngine* engine)
     // Register Component first. At this point Node is not yet registered, so can not register GetNode for Component
     RegisterComponent<Component>(engine, "Component", false, false);
     RegisterNode<Node>(engine, "Node");
+    engine->RegisterObjectMethod("Node", "void SetEnabledRecursive(bool)", asMETHOD(Node, SetEnabledRecursive), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Node", "void set_enabled(bool)", asMETHOD(Node, SetEnabled), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Node", "bool get_enabled() const", asMETHOD(Node, IsEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("Node", "bool SaveXML(File@+)", asFUNCTION(NodeSaveXML), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Node", "Node@+ Clone(CreateMode mode = REPLICATED)", asMETHOD(Node, Clone), asCALL_THISCALL);
     RegisterObjectConstructor<Node>(engine, "Node");

+ 0 - 2
Engine/Engine/ScriptAPI.cpp

@@ -226,8 +226,6 @@ static void RegisterScriptInstance(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ScriptInstance", "void DelayedExecute(float, bool, const String&in, const Array<Variant>@+)", asFUNCTION(ScriptInstanceDelayedExecute), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "void DelayedExecute(float, bool, const String&in)", asFUNCTION(ScriptInstanceDelayedExecuteNoParams), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("ScriptInstance", "void ClearDelayedExecute(const String&in declaration = String())", asMETHOD(ScriptInstance, ClearDelayedExecute), asCALL_THISCALL);
-    engine->RegisterObjectMethod("ScriptInstance", "void set_active(bool)", asMETHOD(ScriptInstance, SetActive), asCALL_THISCALL);
-    engine->RegisterObjectMethod("ScriptInstance", "bool get_active() const", asMETHOD(ScriptInstance, IsActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void set_fixedUpdateFps(int)", asMETHOD(ScriptInstance, SetFixedUpdateFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "int get_fixedUpdateFps() const", asMETHOD(ScriptInstance, GetFixedUpdateFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScriptInstance", "void set_scriptFile(ScriptFile@+)", asMETHOD(ScriptInstance, SetScriptFile), asCALL_THISCALL);

+ 1 - 1
Engine/Graphics/AnimatedModel.cpp

@@ -81,9 +81,9 @@ void AnimatedModel::RegisterObject(Context* context)
 {
     context->RegisterFactory<AnimatedModel>();
     
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
-    ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);

+ 4 - 0
Engine/Graphics/AnimationController.cpp

@@ -61,6 +61,7 @@ void AnimationController::RegisterObject(Context* context)
 {
     context->RegisterFactory<AnimationController>();
     
+    ACCESSOR_ATTRIBUTE(AnimationController, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimationController, VAR_VARIANTVECTOR, "Animations", GetAnimationsAttr, SetAnimationsAttr, VariantVector, Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
     REF_ACCESSOR_ATTRIBUTE(AnimationController, VAR_BUFFER, "Network Animations", GetNetAnimationsAttr, SetNetAnimationsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_NET | AM_LATESTDATA | AM_NOEDIT);
 }
@@ -715,6 +716,9 @@ AnimationState* AnimationController::FindAnimationState(const String& name) cons
 
 void AnimationController::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
 {
+    if (!IsEnabledEffective())
+        return;
+    
     using namespace ScenePostUpdate;
     
     Update(eventData[P_TIMESTEP].GetFloat());

+ 1 - 1
Engine/Graphics/BillboardSet.cpp

@@ -82,8 +82,8 @@ void BillboardSet::RegisterObject(Context* context)
 {
     context->RegisterFactory<BillboardSet>();
     
+    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
-    ATTRIBUTE(BillboardSet, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Position", IsRelative, SetRelative, bool, true, AM_DEFAULT);

+ 1 - 1
Engine/Graphics/CustomGeometry.cpp

@@ -59,7 +59,7 @@ void CustomGeometry::RegisterObject(Context* context)
 {
     context->RegisterFactory<CustomGeometry>();
     
-    ATTRIBUTE(CustomGeometry, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ATTRIBUTE(CustomGeometry, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(CustomGeometry, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);

+ 1 - 1
Engine/Graphics/DecalSet.cpp

@@ -180,10 +180,10 @@ void DecalSet::RegisterObject(Context* context)
 {
     context->RegisterFactory<DecalSet>();
     
+    ACCESSOR_ATTRIBUTE(DecalSet, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(DecalSet, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(DecalSet, VAR_INT, "Max Vertices", GetMaxVertices, SetMaxVertices, unsigned, DEFAULT_MAX_VERTICES, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(DecalSet, VAR_INT, "Max Indices", GetMaxIndices, SetMaxIndices, unsigned, DEFAULT_MAX_INDICES, AM_DEFAULT);
-    ATTRIBUTE(DecalSet, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(DecalSet, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(DecalSet, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     COPY_BASE_ATTRIBUTES(DecalSet, Drawable);

+ 14 - 7
Engine/Graphics/Drawable.cpp

@@ -57,7 +57,6 @@ Drawable::Drawable(Context* context, unsigned char drawableFlags) :
     Component(context),
     drawableFlags_(drawableFlags),
     worldBoundingBoxDirty_(true),
-    visible_(true),
     castShadows_(false),
     occluder_(false),
     occludee_(true),
@@ -100,6 +99,16 @@ void Drawable::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(Drawable, VAR_INT, "Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
 }
 
+void Drawable::OnSetEnabled()
+{
+    bool enabled = IsEnabledEffective();
+    
+    if (enabled && !octant_)
+        AddToOctree();
+    else if (!enabled && octant_)
+        RemoveFromOctree();
+}
+
 void Drawable::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     float distance = query.ray_.HitDistance(GetWorldBoundingBox());
@@ -197,12 +206,6 @@ void Drawable::SetMaxLights(unsigned num)
     MarkNetworkUpdate();
 }
 
-void Drawable::SetVisible(bool enable)
-{
-    visible_ = enable;
-    MarkNetworkUpdate();
-}
-
 void Drawable::SetCastShadows(bool enable)
 {
     castShadows_ = enable;
@@ -367,6 +370,10 @@ void Drawable::OnMarkedDirty(Node* node)
 
 void Drawable::AddToOctree()
 {
+    // Do not add to octree when disabled
+    if (!IsEnabledEffective())
+        return;
+    
     Scene* scene = GetScene();
     if (scene)
     {

+ 2 - 6
Engine/Graphics/Drawable.h

@@ -116,6 +116,8 @@ public:
     /// Register object attributes. Drawable must be registered first.
     static void RegisterObject(Context* context);
     
+    /// Handle enabled/disabled state change.
+    virtual void OnSetEnabled();
     /// Process octree raycast. May be called from a worker thread.
     virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Update before octree reinsertion. Is called from a worker thread. Needs to be requested with MarkForUpdate().
@@ -151,8 +153,6 @@ public:
     void SetZoneMask(unsigned mask);
     /// Set maximum number of per-pixel lights. Default 0 is unlimited.
     void SetMaxLights(unsigned num);
-    /// Set visible flag.
-    void SetVisible(bool enable);
     /// Set shadowcaster flag.
     void SetCastShadows(bool enable);
     /// Set occlusion flag.
@@ -182,8 +182,6 @@ public:
     unsigned GetZoneMask() const { return zoneMask_; }
     /// Return maximum number of per-pixel lights.
     unsigned GetMaxLights() const { return maxLights_; }
-    /// Return visible flag.
-    bool IsVisible() const { return visible_; }
     /// Return shadowcaster flag.
     bool GetCastShadows() const { return castShadows_; }
     /// Return occluder flag.
@@ -266,8 +264,6 @@ protected:
     unsigned char drawableFlags_;
     /// Bounding box dirty flag.
     bool worldBoundingBoxDirty_;
-    /// Visible flag.
-    bool visible_;
     /// Shadowcaster flag.
     bool castShadows_;
     /// Occluder flag.

+ 1 - 1
Engine/Graphics/Light.cpp

@@ -110,6 +110,7 @@ void Light::RegisterObject(Context* context)
 {
     context->RegisterFactory<Light>();
     
+    ACCESSOR_ATTRIBUTE(Light, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ENUM_ACCESSOR_ATTRIBUTE(Light, "Light Type", GetLightType, SetLightType, LightType, typeNames, DEFAULT_LIGHTTYPE, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Light, VAR_COLOR, "Color", GetColor, SetColor, Color, Color(), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Specular Intensity", GetSpecularIntensity, SetSpecularIntensity, float, DEFAULT_SPECULARINTENSITY, AM_DEFAULT);
@@ -118,7 +119,6 @@ void Light::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Spot Aspect Ratio", GetAspectRatio, SetAspectRatio, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Attenuation Texture", GetRampTextureAttr, SetRampTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Light Shape Texture", GetShapeTextureAttr, SetShapeTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
-    ATTRIBUTE(Light, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Per Vertex", perVertex_, false, AM_DEFAULT);

+ 2 - 4
Engine/Graphics/Octree.cpp

@@ -289,8 +289,7 @@ void Octant::GetDrawablesInternal(RayOctreeQuery& query) const
         {
             Drawable* drawable = *start++;
             
-            if (drawable->IsVisible() && (drawable->GetDrawableFlags() & query.drawableFlags_) &&
-                (drawable->GetViewMask() & query.viewMask_))
+            if ((drawable->GetDrawableFlags() & query.drawableFlags_) && (drawable->GetViewMask() & query.viewMask_))
                 drawable->ProcessRayQuery(query, query.result_);
         }
     }
@@ -317,8 +316,7 @@ void Octant::GetDrawablesOnlyInternal(RayOctreeQuery& query, PODVector<Drawable*
         {
             Drawable* drawable = *start++;
             
-            if (drawable->IsVisible() && (drawable->GetDrawableFlags() & query.drawableFlags_) &&
-                (drawable->GetViewMask() & query.viewMask_))
+            if ((drawable->GetDrawableFlags() & query.drawableFlags_) && (drawable->GetViewMask() & query.viewMask_))
                 drawables.Push(drawable);
         }
     }

+ 4 - 4
Engine/Graphics/OctreeQuery.cpp

@@ -42,7 +42,7 @@ void PointOctreeQuery::TestDrawables(Drawable** start, Drawable** end, bool insi
     {
         Drawable* drawable = *start++;
         
-        if (drawable->IsVisible() && (drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
+        if ((drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
         {
             if (inside || drawable->GetWorldBoundingBox().IsInside(point_))
                 result_.Push(drawable);
@@ -64,7 +64,7 @@ void SphereOctreeQuery::TestDrawables(Drawable** start, Drawable** end, bool ins
     {
         Drawable* drawable = *start++;
         
-        if (drawable->IsVisible() && (drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
+        if ((drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
         {
             if (inside || sphere_.IsInsideFast(drawable->GetWorldBoundingBox()))
                 result_.Push(drawable);
@@ -86,7 +86,7 @@ void BoxOctreeQuery::TestDrawables(Drawable** start, Drawable** end, bool inside
     {
         Drawable* drawable = *start++;
         
-        if (drawable->IsVisible() && (drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
+        if ((drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
         {
             if (inside || box_.IsInsideFast(drawable->GetWorldBoundingBox()))
                 result_.Push(drawable);
@@ -108,7 +108,7 @@ void FrustumOctreeQuery::TestDrawables(Drawable** start, Drawable** end, bool in
     {
         Drawable* drawable = *start++;
         
-        if (drawable->IsVisible() && (drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
+        if ((drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
         {
             if (inside || frustum_.IsInsideFast(drawable->GetWorldBoundingBox()))
                 result_.Push(drawable);

+ 4 - 1
Engine/Graphics/ParticleEmitter.cpp

@@ -82,9 +82,9 @@ void ParticleEmitter::RegisterObject(Context* context)
 {
     context->RegisterFactory<ParticleEmitter>();
     
+    ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_RESOURCEREF, "Parameter Source", GetParameterSourceAttr, SetParameterSourceAttr, ResourceRef, ResourceRef(XMLFile::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Active", active_, true, AM_DEFAULT);
-    ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
@@ -570,6 +570,9 @@ void ParticleEmitter::GetVector3MinMax(const XMLElement& element, Vector3& minVa
 
 void ParticleEmitter::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
 {
+    if (!IsEnabledEffective())
+        return;
+    
     // Store scene's timestep and use it instead of global timestep, as time scale may be other than 1
     using namespace ScenePostUpdate;
     

+ 1 - 1
Engine/Graphics/StaticModel.cpp

@@ -57,9 +57,9 @@ void StaticModel::RegisterObject(Context* context)
 {
     context->RegisterFactory<StaticModel>();
     
+    ACCESSOR_ATTRIBUTE(StaticModel, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(StaticModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
-    ATTRIBUTE(StaticModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);

+ 15 - 14
Engine/Graphics/Terrain.cpp

@@ -91,11 +91,11 @@ void Terrain::RegisterObject(Context* context)
 {
     context->RegisterFactory<Terrain>();
     
+    ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Height Map", GetHeightMapAttr, SetHeightMapAttr, ResourceRef, ResourceRef(Image::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(Terrain, VAR_VECTOR3, "Vertex Spacing", spacing_, DEFAULT_SPACING, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Patch Size", GetPatchSize, SetPatchSizeAttr, int, DEFAULT_PATCH_SIZE, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Is Visible", IsVisible, SetVisible, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Is Occluder", IsOccluder, SetOccluder, bool,  false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Cast Shadows", GetCastShadows, SetCastShadows, bool, false, AM_DEFAULT);
@@ -124,6 +124,17 @@ void Terrain::ApplyAttributes()
         CreateGeometry();
 }
 
+void Terrain::OnSetEnabled()
+{
+    bool enabled = IsEnabledEffective();
+    
+    for (unsigned i = 0; i < patches_.Size(); ++i)
+    {
+        if (patches_[i])
+            patches_[i]->SetEnabled(enabled);
+    }
+}
+
 void Terrain::SetSpacing(const Vector3& spacing)
 {
     if (spacing != spacing_)
@@ -265,18 +276,6 @@ void Terrain::SetMaxLights(unsigned num)
     MarkNetworkUpdate();
 }
 
-void Terrain::SetVisible(bool enable)
-{
-    visible_ = enable;
-    for (unsigned i = 0; i < patches_.Size(); ++i)
-    {
-        if (patches_[i])
-            patches_[i]->SetVisible(enable);
-    }
-    
-    MarkNetworkUpdate();
-}
-
 void Terrain::SetCastShadows(bool enable)
 {
     castShadows_ = enable;
@@ -658,7 +657,10 @@ void Terrain::CreateGeometry()
                 patch->SetOwner(this);
                 patch->SetCoordinates(IntVector2(x, z));
                 
+                bool enabled = IsEnabledEffective();
+                
                 // Copy initial drawable parameters
+                patch->SetEnabled(enabled);
                 patch->SetMaterial(material_);
                 patch->SetDrawDistance(drawDistance_);
                 patch->SetShadowDistance(shadowDistance_);
@@ -668,7 +670,6 @@ void Terrain::CreateGeometry()
                 patch->SetShadowMask(shadowMask_);
                 patch->SetZoneMask(zoneMask_);
                 patch->SetMaxLights(maxLights_);
-                patch->SetVisible(visible_);
                 patch->SetCastShadows(castShadows_);
                 patch->SetOccluder(occluder_);
                 patch->SetOccludee(occludee_);

+ 2 - 2
Engine/Graphics/Terrain.h

@@ -49,6 +49,8 @@ public:
     virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
+    /// Handle enabled/disabled state change.
+    virtual void OnSetEnabled();
     
     /// Set patch quads per side. Must be a power of two.
     void SetPatchSize(int size);
@@ -74,8 +76,6 @@ public:
     void SetZoneMask(unsigned mask);
     /// Set maximum number of per-pixel lights for patches. Default 0 is unlimited.
     void SetMaxLights(unsigned num);
-    /// Set visible flag for patches.
-    void SetVisible(bool enable);
     /// Set shadowcaster flag for patches.
     void SetCastShadows(bool enable);
     /// Set occlusion flag for patches. Occlusion uses the coarsest LOD and may potentially be too aggressive, so use with caution.

+ 4 - 5
Engine/Graphics/View.cpp

@@ -81,7 +81,7 @@ public:
         {
             Drawable* drawable = *start++;
             
-            if (drawable->GetCastShadows() && drawable->IsVisible() && (drawable->GetDrawableFlags() & drawableFlags_) &&
+            if (drawable->GetCastShadows() && (drawable->GetDrawableFlags() & drawableFlags_) &&
                 (drawable->GetViewMask() & viewMask_))
             {
                 if (inside || frustum_.IsInsideFast(drawable->GetWorldBoundingBox()))
@@ -110,8 +110,8 @@ public:
             Drawable* drawable = *start++;
             unsigned char flags = drawable->GetDrawableFlags();
             
-            if ((flags == DRAWABLE_ZONE || (flags == DRAWABLE_GEOMETRY && drawable->IsOccluder())) && drawable->IsVisible() &&
-                (drawable->GetViewMask() & viewMask_))
+            if ((flags == DRAWABLE_ZONE || (flags == DRAWABLE_GEOMETRY && drawable->IsOccluder())) && (drawable->GetViewMask() &
+                viewMask_))
             {
                 if (inside || frustum_.IsInsideFast(drawable->GetWorldBoundingBox()))
                     result_.Push(drawable);
@@ -153,8 +153,7 @@ public:
         {
             Drawable* drawable = *start++;
             
-            if (drawable->IsVisible() && (drawable->GetDrawableFlags() & drawableFlags_) &&
-                (drawable->GetViewMask() & viewMask_))
+            if ((drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_))
             {
                 if (inside || frustum_.IsInsideFast(drawable->GetWorldBoundingBox()))
                     result_.Push(drawable);

+ 11 - 2
Engine/Graphics/Zone.cpp

@@ -64,13 +64,13 @@ void Zone::RegisterObject(Context* context)
 {
     context->RegisterFactory<Zone>();
     
+    ACCESSOR_ATTRIBUTE(Zone, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_VECTOR3, "Bounding Box Min", boundingBox_.min_, DEFAULT_BOUNDING_BOX_MIN, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_VECTOR3, "Bounding Box Max", boundingBox_.max_, DEFAULT_BOUNDING_BOX_MAX, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_COLOR, "Ambient Color", ambientColor_, DEFAULT_AMBIENT_COLOR, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_COLOR, "Fog Color", fogColor_, DEFAULT_FOG_COLOR, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_FLOAT, "Fog Start", fogStart_, DEFAULT_FOG_START, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_FLOAT, "Fog End", fogEnd_, DEFAULT_FOG_END, AM_DEFAULT);
-    ATTRIBUTE(Zone, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_BOOL, "Override Mode", override_, 0, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_BOOL, "Ambient Gradient", ambientGradient_, 0, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_INT, "Priority", priority_, 0, AM_DEFAULT);
@@ -85,10 +85,19 @@ void Zone::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
     
     // If bounding box, visibility or priority changes, dirty the drawable as applicable
     if ((attr.offset_ >= offsetof(Zone, boundingBox_) && attr.offset_ < (offsetof(Zone, boundingBox_) + sizeof(BoundingBox))) ||
-        attr.offset_ == offsetof(Zone, visible_) || attr.offset_ == offsetof(Zone, priority_))
+        attr.offset_ == offsetof(Zone, priority_))
         OnMarkedDirty(node_);
 }
 
+void Zone::OnSetEnabled()
+{
+    // When a Zone is disabled, clear the cached zone from all drawables inside bounding box before removing from octree
+    if (!IsEnabledEffective())
+        OnMarkedDirty(node_);
+    
+    Drawable::OnSetEnabled();
+}
+
 void Zone::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 {
     if (debug)

+ 2 - 0
Engine/Graphics/Zone.h

@@ -43,6 +43,8 @@ public:
     
     /// Handle attribute write access.
     virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
+    /// Handle enabled/disabled state change.
+    virtual void OnSetEnabled();
     /// Visualize the component as debug geometry.
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
     

+ 32 - 1
Engine/Scene/Component.cpp

@@ -38,7 +38,8 @@ Component::Component(Context* context) :
     Serializable(context),
     node_(0),
     id_(0),
-    networkUpdate_(false)
+    networkUpdate_(false),
+    enabled_(true)
 {
 }
 
@@ -76,6 +77,31 @@ bool Component::SaveXML(XMLElement& dest)
     return Serializable::SaveXML(dest);
 }
 
+void Component::SetEnabled(bool enabled)
+{
+    if (enabled != enabled_)
+    {
+        enabled_ = enabled;
+        OnSetEnabled();
+        
+        MarkNetworkUpdate();
+        
+        // Send change event for the component
+        Scene* scene = GetScene();
+        if (scene)
+        {
+            using namespace ComponentEnabledChanged;
+            
+            VariantMap eventData;
+            eventData[P_SCENE] = (void*)scene;
+            eventData[P_NODE] = (void*)node_;
+            eventData[P_COMPONENT] = (void*)this;
+            
+            scene->SendEvent(E_COMPONENTENABLEDCHANGED, eventData);
+        }
+    }
+}
+
 void Component::Remove()
 {
     if (node_)
@@ -188,6 +214,11 @@ Component* Component::GetComponent(ShortStringHash type) const
     return node_ ? node_->GetComponent(type) : 0;
 }
 
+bool Component::IsEnabledEffective() const
+{
+    return node_ ? node_->IsEnabled() && enabled_ : enabled_;
+}
+
 void Component::GetComponents(PODVector<Component*>& dest, ShortStringHash type) const
 {
     if (node_)

+ 10 - 0
Engine/Scene/Component.h

@@ -49,6 +49,8 @@ public:
     
     /// Handle attribute write access.
     virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
+    /// Handle enabled/disabled state change.
+    virtual void OnSetEnabled() {}
     /// Save as binary data. Return true if successful.
     virtual bool Save(Serializer& dest);
     /// Save as XML data. Return true if successful.
@@ -58,6 +60,8 @@ public:
     /// Visualize the component as debug geometry.
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest) {};
     
+    /// Set enabled/disabled state.
+    void SetEnabled(bool enabled);
     /// Remove from the scene node. If no other shared pointer references exist, causes immediate deletion.
     void Remove();
     
@@ -67,6 +71,10 @@ public:
     Node* GetNode() const { return node_; }
     /// Return the scene the node belongs to.
     Scene* GetScene() const;
+    /// Return whether is enabled.
+    bool IsEnabled() const { return enabled_; }
+    /// Return whether is effectively enabled (node is also enabled.)
+    bool IsEnabledEffective() const;
     /// Return components in the same scene node by type.
     void GetComponents(PODVector<Component*>& dest, ShortStringHash type) const;
     /// Return component in the same scene node by type. If there are several, returns the first.
@@ -101,6 +109,8 @@ protected:
     unsigned id_;
     /// Network update queued flag.
     bool networkUpdate_;
+    /// Enabled flag.
+    bool enabled_;
 };
 
 template <class T> T* Component::GetComponent() const { return static_cast<T*>(GetComponent(T::GetTypeStatic())); }

+ 66 - 17
Engine/Scene/Node.cpp

@@ -37,9 +37,6 @@
 namespace Urho3D
 {
 
-// Normalize rotation quaternion after this many incremental updates to prevent distortion
-static const int NORMALIZE_ROTATION_EVERY = 32;
-
 OBJECTTYPESTATIC(Node);
 
 Node::Node(Context* context) :
@@ -47,7 +44,7 @@ Node::Node(Context* context) :
     worldTransform_(Matrix3x4::IDENTITY),
     dirty_(false),
     networkUpdate_(false),
-    rotateCount_(0),
+    enabled_(true),
     parent_(0),
     scene_(0),
     id_(0),
@@ -72,7 +69,7 @@ void Node::RegisterObject(Context* context)
 {
     context->RegisterFactory<Node>();
     
-    /// \todo When position/rotation updates are received from the network, route to SmoothedTransform if exists
+    ACCESSOR_ATTRIBUTE(Node, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_STRING, "Name", GetName, SetName, String, String::EMPTY, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_VECTOR3, "Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_QUATERNION, "Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
@@ -251,7 +248,6 @@ void Node::SetPosition(const Vector3& position)
 void Node::SetRotation(const Quaternion& rotation)
 {
     rotation_ = rotation;
-    rotateCount_ = 0;
     MarkDirty();
     
     MarkNetworkUpdate();
@@ -279,7 +275,6 @@ void Node::SetTransform(const Vector3& position, const Quaternion& rotation)
 {
     position_ = position;
     rotation_ = rotation;
-    rotateCount_ = 0;
     MarkDirty();
     
     MarkNetworkUpdate();
@@ -294,7 +289,6 @@ void Node::SetTransform(const Vector3& position, const Quaternion& rotation, con
 {
     position_ = position;
     rotation_ = rotation;
-    rotateCount_ = 0;
     scale_ = scale;
     MarkDirty();
     
@@ -386,16 +380,9 @@ void Node::TranslateRelative(const Vector3& delta)
 void Node::Rotate(const Quaternion& delta, bool fixedAxis)
 {
     if (!fixedAxis)
-        rotation_ = rotation_ * delta;
+        rotation_ = (rotation_ * delta).Normalized();
     else
-        rotation_ = delta * rotation_;
-    
-    if (++rotateCount_ >= NORMALIZE_ROTATION_EVERY)
-    {
-        rotation_.Normalize();
-        rotateCount_ = 0;
-    }
-    
+        rotation_ = (delta * rotation_).Normalized();
     MarkDirty();
     
     MarkNetworkUpdate();
@@ -446,6 +433,68 @@ void Node::Scale(const Vector3& scale)
     MarkNetworkUpdate();
 }
 
+void Node::SetEnabled(bool enabled)
+{
+    // The enabled state of the whole scene can not be changed. SetActive() is used instead to start/stop updates.
+    if (GetType() == Scene::GetTypeStatic())
+    {
+        LOGERROR("Can not change enabled state of the Scene");
+        return;
+    }
+    
+    if (enabled != enabled_)
+    {
+        enabled_ = enabled;
+        
+        MarkNetworkUpdate();
+        
+        // Send change event
+        if (scene_)
+        {
+            using namespace NodeEnabledChanged;
+            
+            VariantMap eventData;
+            eventData[P_SCENE] = (void*)scene_;
+            eventData[P_NODE] = (void*)this;
+            
+            scene_->SendEvent(E_NODEENABLEDCHANGED, eventData);
+        }
+        
+        for (Vector<SharedPtr<Component> >::Iterator i = components_.Begin(); i != components_.End(); ++i)
+        {
+            (*i)->OnSetEnabled();
+            
+            // Send change event for the component
+            if (scene_)
+            {
+                using namespace ComponentEnabledChanged;
+                
+                VariantMap eventData;
+                eventData[P_SCENE] = (void*)scene_;
+                eventData[P_NODE] = (void*)this;
+                eventData[P_COMPONENT] = (void*)(*i);
+                
+                scene_->SendEvent(E_COMPONENTENABLEDCHANGED, eventData);
+            }
+        }
+    }
+}
+
+void Node::SetEnabledRecursive(bool enabled)
+{
+    // The enabled state of the whole scene can not be changed. SetActive() is used instead to start/stop updates.
+    if (GetType() == Scene::GetTypeStatic())
+    {
+        LOGERROR("Can not change enabled state of the Scene");
+        return;
+    }
+    
+    SetEnabled(enabled);
+    
+    for (Vector<SharedPtr<Node> >::Iterator i = children_.Begin(); i != children_.End(); ++i)
+        (*i)->SetEnabledRecursive(enabled);
+}
+
 void Node::SetOwner(Connection* owner)
 {
     owner_ = owner;

+ 8 - 2
Engine/Scene/Node.h

@@ -129,6 +129,10 @@ public:
     void Scale(float scale);
     /// Modify scale.
     void Scale(const Vector3& scale);
+    /// Set enabled/disabled state. Components in disabled nodes become effectively disabled regardless of their own enable/disable state.
+    void SetEnabled(bool enabled);
+    /// Set enabled/disabled state recursively.
+    void SetEnabledRecursive(bool enabled);
     /// Set owner connection for networking.
     void SetOwner(Connection* owner);
     /// Mark node and child nodes to need world transform recalculation. Notify listener components.
@@ -178,6 +182,8 @@ public:
     Node* GetParent() const { return parent_; }
     /// Return scene.
     Scene* GetScene() const { return scene_; }
+    /// Return whether is enabled. Disables nodes effectively disable all their components.
+    bool IsEnabled() const { return enabled_; }
     /// Return owner connection in networking.
     Connection* GetOwner() const { return owner_; }
     /// Return position relative to parent node.
@@ -342,8 +348,8 @@ private:
     mutable bool dirty_;
     /// Network update queued flag.
     bool networkUpdate_;
-    /// Consecutive rotation count for rotation renormalization.
-    unsigned short rotateCount_;
+    /// Enabled flag.
+    bool enabled_;
     /// Parent scene node.
     Node* parent_;
     /// Scene (root node.)

+ 16 - 1
Engine/Scene/SceneEvents.h

@@ -119,11 +119,26 @@ EVENT(E_COMPONENTREMOVED, ComponentRemoved)
     PARAM(P_COMPONENT, Component);          // Component pointer
 }
 
-/// A node's name has changed, requiring refresh in the editor.
+/// A node's name has changed.
 EVENT(E_NODENAMECHANGED, NodeNameChanged)
 {
     PARAM(P_SCENE, Scene);                  // Scene pointer
     PARAM(P_NODE, Node);                    // Node pointer
 }
 
+/// A node's enabled state has changed.
+EVENT(E_NODEENABLEDCHANGED, NodeEnabledChanged)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+}
+
+/// A component's enabled state has changed.
+EVENT(E_COMPONENTENABLEDCHANGED, ComponentEnabledChanged)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+    PARAM(P_COMPONENT, Component);          // Component pointer
+}
+
 }

+ 6 - 13
Engine/Script/ScriptInstance.cpp

@@ -63,7 +63,6 @@ ScriptInstance::ScriptInstance(Context* context) :
     Component(context),
     script_(GetSubsystem<Script>()),
     scriptObject_(0),
-    active_(true),
     subscribed_(false),
     fixedUpdateFps_(0),
     fixedUpdateInterval_(0.0f),
@@ -83,9 +82,9 @@ void ScriptInstance::RegisterObject(Context* context)
 {
     context->RegisterFactory<ScriptInstance>();
     
+    ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_RESOURCEREF, "Script File", GetScriptFileAttr, SetScriptFileAttr, ResourceRef, ResourceRef(ScriptFile::GetTypeStatic()), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_STRING, "Class Name", GetClassName, SetClassName, String, String::EMPTY, AM_DEFAULT);
-    ATTRIBUTE(ScriptInstance, VAR_BOOL, "Is Active", active_, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_INT, "Fixed Update FPS", GetFixedUpdateFps, SetFixedUpdateFps, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_FLOAT, "Time Accumulator", GetFixedUpdateAccAttr, SetFixedUpdateAccAttr, float, 0.0f, AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Delayed Method Calls", GetDelayedMethodCallsAttr, SetDelayedMethodCallsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
@@ -144,12 +143,6 @@ void ScriptInstance::SetClassName(const String& className)
     MarkNetworkUpdate();
 }
 
-void ScriptInstance::SetActive(bool active)
-{
-    active_ = active;
-    MarkNetworkUpdate();
-}
-
 void ScriptInstance::SetFixedUpdateFps(int fps)
 {
     fixedUpdateFps_ = Max(fps, 0);
@@ -497,7 +490,7 @@ void ScriptInstance::GetScriptAttributes()
 
 void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
 {
-    if (!active_ || !scriptObject_)
+    if (!IsEnabledEffective() || !scriptObject_)
         return;
     
     using namespace SceneUpdate;
@@ -544,7 +537,7 @@ void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventDa
 
 void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
 {
-    if (!active_ || !scriptObject_)
+    if (!IsEnabledEffective() || !scriptObject_)
         return;
     
     using namespace ScenePostUpdate;
@@ -556,7 +549,7 @@ void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eve
 
 void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData)
 {
-    if (!active_ || !scriptObject_)
+    if (!IsEnabledEffective() || !scriptObject_)
         return;
     
     using namespace PhysicsPreStep;
@@ -583,7 +576,7 @@ void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& even
 
 void ScriptInstance::HandlePhysicsPostStep(StringHash eventType, VariantMap& eventData)
 {
-    if (!active_ || !scriptObject_)
+    if (!IsEnabledEffective() || !scriptObject_)
         return;
     
     using namespace PhysicsPostStep;
@@ -610,7 +603,7 @@ void ScriptInstance::HandlePhysicsPostStep(StringHash eventType, VariantMap& eve
 
 void ScriptInstance::HandleScriptEvent(StringHash eventType, VariantMap& eventData)
 {
-    if (!active_ || !scriptFile_ || !scriptObject_)
+    if (!IsEnabledEffective() || !scriptFile_ || !scriptObject_)
         return;
     
     asIScriptFunction* method = static_cast<asIScriptFunction*>(GetEventHandler()->GetUserData());

+ 0 - 6
Engine/Script/ScriptInstance.h

@@ -95,8 +95,6 @@ public:
     void SetScriptFile(ScriptFile* scriptFile);
     /// Set class name only. Recreate object if necessary.
     void SetClassName(const String& className);
-    /// Enable or disable scripted updates and event handlers.
-    void SetActive(bool active);
     /// Set fixed updates per second. 0 (default) uses the physics frame rate.
     void SetFixedUpdateFps(int fps);
     /// Query for a method by declaration and execute if found.
@@ -114,8 +112,6 @@ public:
     asIScriptObject* GetScriptObject() const { return scriptObject_; }
     /// Return class name.
     const String& GetClassName() const { return className_; }
-    /// Return whether scripted updates and event handlers are enabled.
-    bool IsActive() const { return active_; }
     /// Return fixed updates per second.
     int GetFixedUpdateFps() const { return fixedUpdateFps_; }
     
@@ -178,8 +174,6 @@ private:
     String className_;
     /// Pointers to supported inbuilt methods.
     asIScriptFunction* methods_[MAX_SCRIPT_METHODS];
-    /// Active flag.
-    bool active_;
     /// Subscribed to scene update event flag.
     bool subscribed_;
     /// Fixed update FPS.