Bladeren bron

Further attribute reorganization.
Refactored CollisionShape shape setting functions, which now take default parameters.
CollisionShape triangle meshes can now use the size attribute as well.
Fixed CollisionShape model not changing when picked with the file selector.
Added occluder triangles & instancing parameters to the editor settings dialog.

Lasse Öörni 14 jaren geleden
bovenliggende
commit
6dd8679214

+ 6 - 0
Bin/Data/Scripts/Editor.as

@@ -99,7 +99,10 @@ void LoadConfig()
         renderer.textureQuality = renderingElem.GetInt("texturequality");
         renderer.materialQuality = renderingElem.GetInt("materialquality");
         SetShadowQuality(renderingElem.GetInt("shadowquality"));
+        renderer.maxOccluderTriangles = renderingElem.GetInt("maxoccludertriangles");
         renderer.specularLighting = renderingElem.GetBool("specularlighting");
+        renderer.dynamicInstancing = renderingElem.GetBool("dynamicinstancing");
+        renderer.shadowMapHiresDepth = renderingElem.GetBool("shadowmaphiresdepth");
         engine.maxFps = renderingElem.GetBool("framelimiter") ? 200 : 0;
     }
 }
@@ -134,7 +137,10 @@ void SaveConfig()
     renderingElem.SetInt("texturequality", renderer.textureQuality);
     renderingElem.SetInt("materialquality", renderer.materialQuality);
     renderingElem.SetInt("shadowquality", GetShadowQuality());
+    renderingElem.SetInt("maxoccludertriangles", renderer.maxOccluderTriangles);
     renderingElem.SetBool("specularlighting", renderer.specularLighting);
+    renderingElem.SetBool("dynamicinstancing", renderer.dynamicInstancing);
+    renderingElem.SetBool("shadowmaphiresdepth", renderer.shadowMapHiresDepth);
     renderingElem.SetBool("framelimiter", engine.maxFps > 0);
 
     config.Save(File(configFileName, FILE_WRITE));

+ 29 - 6
Bin/Data/Scripts/Editor/EditorCamera.as

@@ -117,13 +117,19 @@ void UpdateEditorSettingsDialog()
 
     DropDownList@ shadowQualityEdit = editorSettingsDialog.GetChild("ShadowQualityEdit", true);
     shadowQualityEdit.selection = GetShadowQuality();
-    
-    CheckBox@ shadowMapHiresDepthToggle = editorSettingsDialog.GetChild("ShadowMapHiresDepthToggle", true);
-    shadowMapHiresDepthToggle.checked = renderer.shadowMapHiresDepth;
+
+    LineEdit@ maxOccluderTrianglesEdit = editorSettingsDialog.GetChild("MaxOccluderTrianglesEdit", true);
+    maxOccluderTrianglesEdit.text = String(renderer.maxOccluderTriangles);
 
     CheckBox@ specularLightingToggle = editorSettingsDialog.GetChild("SpecularLightingToggle", true);
     specularLightingToggle.checked = renderer.specularLighting;
 
+    CheckBox@ dynamicInstancingToggle = editorSettingsDialog.GetChild("DynamicInstancingToggle", true);
+    dynamicInstancingToggle.checked = renderer.dynamicInstancing;
+
+    CheckBox@ shadowMapHiresDepthToggle = editorSettingsDialog.GetChild("ShadowMapHiresDepthToggle", true);
+    shadowMapHiresDepthToggle.checked = renderer.shadowMapHiresDepth;
+
     CheckBox@ frameLimiterToggle = editorSettingsDialog.GetChild("FrameLimiterToggle", true);
     frameLimiterToggle.checked = engine.maxFps > 0;
 
@@ -154,8 +160,11 @@ void UpdateEditorSettingsDialog()
         SubscribeToEvent(textureQualityEdit, "ItemSelected", "EditTextureQuality");
         SubscribeToEvent(materialQualityEdit, "ItemSelected", "EditMaterialQuality");
         SubscribeToEvent(shadowQualityEdit, "ItemSelected", "EditShadowQuality");
-        SubscribeToEvent(shadowMapHiresDepthToggle, "Toggled", "EditShadowMapHiresDepth");
+        SubscribeToEvent(maxOccluderTrianglesEdit, "TextChanged", "EditMaxOccluderTriangles");
+        SubscribeToEvent(maxOccluderTrianglesEdit, "TextFinished", "EditMaxOccluderTriangles");
         SubscribeToEvent(specularLightingToggle, "Toggled", "EditSpecularLighting");
+        SubscribeToEvent(dynamicInstancingToggle, "Toggled", "EditDynamicInstancing");
+        SubscribeToEvent(shadowMapHiresDepthToggle, "Toggled", "EditShadowMapHiresDepth");
         SubscribeToEvent(frameLimiterToggle, "Toggled", "EditFrameLimiter");
         SubscribeToEvent(editorSettingsDialog.GetChild("CloseButton", true), "Released", "HideEditorSettingsDialog");
         subscribedToCameraEdits = true;
@@ -292,16 +301,30 @@ void EditShadowQuality(StringHash eventType, VariantMap& eventData)
     SetShadowQuality(edit.selection);
 }
 
+void EditMaxOccluderTriangles(StringHash eventType, VariantMap& eventData)
+{
+    LineEdit@ edit = eventData["Element"].GetUIElement();
+    renderer.maxOccluderTriangles = edit.text.ToInt();
+    if (eventType == StringHash("TextFinished"))
+        edit.text = String(renderer.maxOccluderTriangles);
+}
+
+void EditSpecularLighting(StringHash eventType, VariantMap& eventData)
+{
+    CheckBox@ edit = eventData["Element"].GetUIElement();
+    renderer.specularLighting = edit.checked;
+}
+
 void EditShadowMapHiresDepth(StringHash eventType, VariantMap& eventData)
 {
     CheckBox@ edit = eventData["Element"].GetUIElement();
     renderer.shadowMapHiresDepth = edit.checked;
 }
 
-void EditSpecularLighting(StringHash eventType, VariantMap& eventData)
+void EditDynamicInstancing(StringHash eventType, VariantMap& eventData)
 {
     CheckBox@ edit = eventData["Element"].GetUIElement();
-    renderer.specularLighting = edit.checked;
+    renderer.dynamicInstancing = edit.checked;
 }
 
 void EditFrameLimiter(StringHash eventType, VariantMap& eventData)

+ 2 - 0
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -755,6 +755,7 @@ void PickResourceDone(StringHash eventType, VariantMap& eventData)
         ref.type = ShortStringHash(resourcePicker.resourceType);
         ref.id = StringHash(resourceName);
         target.attributes[resourcePickIndex] = Variant(ref);
+        target.FinishUpdate();
     }
     else if (info.type == VAR_RESOURCEREFLIST)
     {
@@ -763,6 +764,7 @@ void PickResourceDone(StringHash eventType, VariantMap& eventData)
         {
             refList.ids[resourcePickSubIndex] = StringHash(resourceName);
             target.attributes[resourcePickIndex] = Variant(refList);
+            target.FinishUpdate();
         }
     }
 

+ 2 - 2
Bin/Data/Scripts/NinjaSnowWar.as

@@ -148,7 +148,7 @@ void InitScene()
     zone.fogStart = 5000;
     zone.fogEnd = 15000;
 
-    Node@ lightNode = gameScene.CreateChild("Sunlight");
+    Node@ lightNode = gameScene.CreateChild("GlobalLight");
     lightNode.rotation = Quaternion(0.888074, 0.325058, -0.325058, 0);
     Light@ light = lightNode.CreateComponent("Light");
     light.lightType = LIGHT_DIRECTIONAL;
@@ -163,7 +163,7 @@ void InitScene()
     staticModel.model = cache.GetResource("Model", "Models/Level.mdl");
     staticModel.material = cache.GetResource("Material", "Materials/Snow.xml");
     CollisionShape@ shape = staticNode.CreateComponent("CollisionShape");
-    shape.SetTriangleMesh(cache.GetResource("Model", "Models/Level.mdl"), 0, Vector3(), Quaternion());
+    shape.SetTriangleMesh(cache.GetResource("Model", "Models/Level.mdl"), 0);
     shape.collisionGroup = 2;
     shape.collisionMask = 3;
 

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/Potion.as

@@ -39,7 +39,7 @@ class Potion : GameObject
 
         // Create collision shape
         CollisionShape@ shape = node.CreateComponent("CollisionShape");
-        shape.SetBox(Vector3(20, 40, 20), Vector3(), Quaternion());
+        shape.SetBox(Vector3(20, 40, 20));
         shape.collisionGroup = 1;
         shape.collisionMask = 3;
         shape.friction = potionFriction;

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/SnowBall.as

@@ -45,7 +45,7 @@ class SnowBall : GameObject
     
         // Create collision shape. Create as local to avoid divergent simulation by the client
         CollisionShape@ shape = node.CreateComponent("CollisionShape", LOCAL);
-        shape.SetBox(Vector3(15, 15, 15), Vector3(), Quaternion());
+        shape.SetBox(Vector3(15, 15, 15));
         shape.collisionGroup = 1;
         shape.collisionMask = 3;
         shape.friction = snowballFriction;

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/SnowCrate.as

@@ -38,7 +38,7 @@ class SnowCrate : GameObject
 
         // Create collision shape
         CollisionShape@ shape = node.CreateComponent("CollisionShape");
-        shape.SetBox(Vector3(80, 80, 80), Vector3(), Quaternion());
+        shape.SetBox(Vector3(80, 80, 80));
         shape.collisionGroup = 2;
         shape.collisionMask = 3;
         shape.friction = snowcrateFriction;

+ 8 - 7
Bin/Data/Scripts/TestScene.as

@@ -102,7 +102,8 @@ void InitScene()
     world.angularRestThreshold = 0.1;
     world.contactSurfaceLayer = 0.001;
 
-    Zone@ zone = testScene.CreateComponent("Zone");
+    Node@ zoneNode = testScene.CreateChild("Zone");
+    Zone@ zone = zoneNode.CreateComponent("Zone");
     zone.ambientColor = Color(0.1, 0.1, 0.1);
     zone.fogColor = Color(0.5, 0.5, 0.7);
     zone.fogStart = 100.0;
@@ -110,7 +111,7 @@ void InitScene()
     zone.boundingBox = BoundingBox(-1000.0, 1000.0);
 
     {
-        Node@ lightNode = testScene.CreateChild("Light");
+        Node@ lightNode = testScene.CreateChild("GlobalLight");
         lightNode.direction = Vector3(0.5, -0.5, 0.5);
 
         Light@ light = lightNode.CreateComponent("Light");
@@ -132,7 +133,7 @@ void InitScene()
         object.occluder = true;
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetBox(Vector3(2.0, 2.0, 2.0), Vector3(), Quaternion());
+        shape.SetBox(Vector3(2.0, 2.0, 2.0));
         shape.collisionGroup = 2;
         shape.collisionMask = 1;
     }
@@ -148,7 +149,7 @@ void InitScene()
         object.castShadows = true;
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetBox(Vector3(2.0, 2.0, 2.0), Vector3(), Quaternion());
+        shape.SetBox(Vector3(2.0, 2.0, 2.0));
         shape.collisionGroup = 2;
         shape.collisionMask = 1;
     }
@@ -166,7 +167,7 @@ void InitScene()
         object.occluder = true;
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetBox(Vector3(2.0, 2.0, 2.0), Vector3(), Quaternion());
+        shape.SetBox(Vector3(2.0, 2.0, 2.0));
         shape.collisionGroup = 2;
         shape.collisionMask = 1;
     }
@@ -184,7 +185,7 @@ void InitScene()
         object.castShadows = true;
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0, Vector3(), Quaternion());
+        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
         shape.collisionGroup = 2;
         shape.collisionMask = 1;
     }
@@ -411,7 +412,7 @@ void HandleSpawnBox(StringHash eventType, VariantMap& eventData)
     newNode.SetScale(0.1);
 
     CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
-    shape.SetBox(Vector3(2, 2, 2), Vector3(), Quaternion());
+    shape.SetBox(Vector3(2, 2, 2));
     shape.friction = 1.0;
     shape.collisionGroup = 1;
     shape.collisionMask = 3;

+ 24 - 4
Bin/Data/UI/EditorSettingsDialog.xml

@@ -219,24 +219,44 @@
             <popupitem name="ShadowsHigh" />
         </element>
     </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="20" />
+        <element type="Text">
+            <text value="Max occluder triangles" />
+        </element>
+        <element type="LineEdit" name="MaxOccluderTrianglesEdit">
+            <fixedwidth value="80" />
+         </element>
+    </element>
     <element>
         <fixedheight value="17" />
         <layout mode="horizontal" spacing="8" />
-        <element type="CheckBox" name="ShadowMapHiresDepthToggle">
+        <element type="CheckBox" name="SpecularLightingToggle">
             <fixedsize value="16 16" />
         </element>
         <element type="Text">
-            <text value="Shadow map 24-bit depth" />
+            <text value="Specular lighting" />
         </element>
     </element>
     <element>
         <fixedheight value="17" />
         <layout mode="horizontal" spacing="8" />
-        <element type="CheckBox" name="SpecularLightingToggle">
+        <element type="CheckBox" name="DynamicInstancingToggle">
             <fixedsize value="16 16" />
         </element>
         <element type="Text">
-            <text value="Specular lighting" />
+            <text value="Dynamic instancing" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="8" />
+        <element type="CheckBox" name="ShadowMapHiresDepthToggle">
+            <fixedsize value="16 16" />
+        </element>
+        <element type="Text">
+            <text value="Shadow map 24-bit depth" />
         </element>
     </element>
     <element>

+ 1 - 1
Engine/Audio/SoundSource3D.cpp

@@ -50,8 +50,8 @@ SoundSource3D::SoundSource3D(Context* context) :
 void SoundSource3D::RegisterObject(Context* context)
 {
     context->RegisterFactory<SoundSource3D>();
-    context->CopyBaseAttributes<SoundSource, SoundSource3D>();
     
+    COPY_BASE_ATTRIBUTES(SoundSource3D, SoundSource);
     ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Near Distance", nearDistance_, DEFAULT_NEARDISTANCE, AM_DEFAULT);
     ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Far Distance", farDistance_, DEFAULT_FARDISTANCE, AM_DEFAULT);
     ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Rolloff Factor", rolloffFactor_, DEFAULT_ROLLOFF, AM_DEFAULT);

+ 7 - 7
Engine/Engine/PhysicsAPI.cpp

@@ -74,13 +74,13 @@ static void RegisterCollisionShape(asIScriptEngine* engine)
     
     RegisterComponent<CollisionShape>(engine, "CollisionShape");
     engine->RegisterObjectMethod("CollisionShape", "void Clear()", asMETHOD(CollisionShape, Clear), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetSphere(float, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetSphere), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetBox(const Vector3&in, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetBox), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetCylinder(float, float, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetCylinder), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetCapsule(float, float, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetCapsule), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetTriangleMesh(Model@+, uint, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetTriangleMesh), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetHeightfield(Model@+, uint, uint, float, uint, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetHeightfield), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void SetConvexHull(Model@+, float, uint, const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetConvexHull), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetSphere(float, const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetSphere), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetBox(const Vector3&in, const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetBox), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetCylinder(float, float, const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCylinder), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetCapsule(float, float, const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCapsule), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetTriangleMesh(Model@+, uint, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetTriangleMesh), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetHeightfield(Model@+, uint, uint, float, uint, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetHeightfield), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetConvexHull(Model@+, float, uint, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(0, 0, 0), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetConvexHull), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetTransform(const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetTransform), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void DrawDebugGeometry(DebugRenderer@+, bool)", asMETHOD(CollisionShape, DrawDebugGeometry), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "Model@+ get_model()", asMETHOD(CollisionShape, GetModel), asCALL_THISCALL);

+ 9 - 6
Engine/Graphics/AnimatedModel.cpp

@@ -78,17 +78,20 @@ AnimatedModel::~AnimatedModel()
 void AnimatedModel::RegisterObject(Context* context)
 {
     context->RegisterFactory<AnimatedModel>();
-    context->CopyBaseAttributes<Drawable, AnimatedModel>();
     
-    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
+    ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
+    ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
+    ATTRIBUTE(AnimatedModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
+    COPY_BASE_ATTRIBUTES(AnimatedModel, Drawable);
+    ATTRIBUTE(AnimatedModel, VAR_INT, "Ray/Occl. LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Animation States", GetAnimationStatesAttr, SetAnimationStatesAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
-    ATTRIBUTE(AnimatedModel, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
-    ATTRIBUTE(AnimatedModel, VAR_INT, "Light Mask", lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
-    ATTRIBUTE(AnimatedModel, VAR_INT, "Max Lights", maxLights_, 0, AM_DEFAULT);
-    ATTRIBUTE(AnimatedModel, VAR_INT, "Raycast LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
 }
 
 void AnimatedModel::FinishUpdate()

+ 8 - 5
Engine/Graphics/BillboardSet.cpp

@@ -73,17 +73,20 @@ BillboardSet::~BillboardSet()
 void BillboardSet::RegisterObject(Context* context)
 {
     context->RegisterFactory<BillboardSet>();
-    context->CopyBaseAttributes<Drawable, BillboardSet>();
     
+    ATTRIBUTE(BillboardSet, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
+    ATTRIBUTE(BillboardSet, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
+    ATTRIBUTE(BillboardSet, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_FLOAT, "Animation LOD Bias", animationLodBias_, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Position", IsRelative, SetRelative, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Scale", IsScaled, SetScaled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Sort By Distance", IsSorted, SetSorted, bool, false, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_VARIANTVECTOR, "Billboards", GetBillboardsAttr, SetBillboardsAttr, VariantVector, VariantVector(), AM_FILE);
-    ATTRIBUTE(BillboardSet, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
-    ATTRIBUTE(BillboardSet, VAR_INT, "Light Mask", lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
-    ATTRIBUTE(BillboardSet, VAR_INT, "Max Lights", maxLights_, 0, AM_DEFAULT);
+    COPY_BASE_ATTRIBUTES(BillboardSet, Drawable);
     REF_ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BUFFER, "Network Billboards", GetNetBillboardsAttr, SetNetBillboardsAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_NET | AM_NOEDIT);
 }
 

+ 3 - 6
Engine/Graphics/Drawable.cpp

@@ -69,12 +69,9 @@ Drawable::~Drawable()
 
 void Drawable::RegisterObject(Context* context)
 {
-    ATTRIBUTE(Drawable, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
-    ATTRIBUTE(Drawable, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
-    ATTRIBUTE(Drawable, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Drawable, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Drawable, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Drawable, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
+    ATTRIBUTE(Drawable, VAR_INT, "Max Lights", maxLights_, 0, AM_DEFAULT);
+    ATTRIBUTE(Drawable, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
+    ATTRIBUTE(Drawable, VAR_INT, "Light Mask", lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
 }
 
 void Drawable::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)

+ 4 - 4
Engine/Graphics/Light.cpp

@@ -111,10 +111,6 @@ void Light::RegisterObject(Context* context)
     ATTRIBUTE(Light, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ENUM_ATTRIBUTE(Light, "Light Type", lightType_, typeNames, DEFAULT_LIGHTTYPE, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Fade Distance", GetFadeDistance, SetFadeDistance, float, 0.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Shadow Fade Distance", GetShadowFadeDistance, SetShadowFadeDistance, float, 0.0f, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_COLOR, "Color", color_, Color(), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Specular Intensity", GetSpecularIntensity, SetSpecularIntensity, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Range", GetRange, SetRange, float, 0.0f, AM_DEFAULT);
@@ -122,6 +118,10 @@ 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);
+    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Fade Distance", GetFadeDistance, SetFadeDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Shadow Fade Distance", GetShadowFadeDistance, SetShadowFadeDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Shadow Intensity", GetShadowIntensity, SetShadowIntensity, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Shadow Resolution", GetShadowResolution, SetShadowResolution, float, 1.0f, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_FLOAT, "Near/Farclip Ratio", shadowNearFarRatio_, DEFAULT_SHADOWNEARFARRATIO, AM_DEFAULT);

+ 2 - 1
Engine/Graphics/Skybox.cpp

@@ -41,7 +41,8 @@ Skybox::~Skybox()
 void Skybox::RegisterObject(Context* context)
 {
     context->RegisterFactory<Skybox>();
-    context->CopyBaseAttributes<StaticModel, Skybox>();
+    
+    COPY_BASE_ATTRIBUTES(Skybox, StaticModel);
 }
 
 void Skybox::UpdateDistance(const FrameInfo& frame)

+ 8 - 5
Engine/Graphics/StaticModel.cpp

@@ -55,14 +55,17 @@ StaticModel::~StaticModel()
 void StaticModel::RegisterObject(Context* context)
 {
     context->RegisterFactory<StaticModel>();
-    context->CopyBaseAttributes<Drawable, StaticModel>();
     
+    ATTRIBUTE(StaticModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
+    ATTRIBUTE(StaticModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
+    ATTRIBUTE(StaticModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
-    ATTRIBUTE(StaticModel, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
-    ATTRIBUTE(StaticModel, VAR_INT, "Light Mask", lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
-    ATTRIBUTE(StaticModel, VAR_INT, "Max Lights", maxLights_, 0, AM_DEFAULT);
-    ATTRIBUTE(StaticModel, VAR_INT, "Raycast LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
+    COPY_BASE_ATTRIBUTES(StaticModel, Drawable);
+    ATTRIBUTE(StaticModel, VAR_INT, "Ray/Occl. LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
 }
 
 void StaticModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)

+ 1 - 1
Engine/Graphics/Zone.cpp

@@ -59,7 +59,7 @@ void Zone::RegisterObject(Context* context)
     ATTRIBUTE(Zone, VAR_COLOR, "Fog Color", fogColor_, DEFAULT_FOG_COLOR, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_FLOAT, "Fog Start", fogStart_, DEFAULT_FOGSTART, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_FLOAT, "Fog End", fogEnd_, DEFAULT_FOGEND, AM_DEFAULT);
-    ATTRIBUTE(Zone, VAR_INT, "Zone Priority", priority_, 0, AM_DEFAULT);
+    ATTRIBUTE(Zone, VAR_INT, "Priority", priority_, 0, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_INT, "View Mask", viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
     ATTRIBUTE(Zone, VAR_INT, "Light Mask", lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
 }

+ 23 - 18
Engine/Physics/CollisionShape.cpp

@@ -301,9 +301,9 @@ CollisionShape::CollisionShape(Context* context) :
     Component(context),
     geometry_(0),
     shapeType_(SHAPE_NONE),
-    size_(Vector3::ZERO),
+    size_(Vector3::UNITY),
     thickness_(0.0f),
-    lodLevel_(M_MAX_UNSIGNED),
+    lodLevel_(0),
     position_(Vector3::ZERO),
     rotation_(Quaternion::IDENTITY),
     geometryScale_(Vector3::UNITY),
@@ -324,13 +324,13 @@ void CollisionShape::RegisterObject(Context* context)
 {
     context->RegisterFactory<CollisionShape>();
     
+    ENUM_ATTRIBUTE(CollisionShape, "Shape Type", shapeType_, typeNames, SHAPE_NONE, AM_DEFAULT);
+    ATTRIBUTE(CollisionShape, VAR_VECTOR3, "Size", size_, Vector3::UNITY, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(CollisionShape, VAR_VECTOR3, "Offset Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(CollisionShape, VAR_QUATERNION, "Offset Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_DEFAULT);
-    ATTRIBUTE(CollisionShape, VAR_VECTOR3, "Size", size_, Vector3::ZERO, AM_DEFAULT);
-    ENUM_ATTRIBUTE(CollisionShape, "Shape Type", shapeType_, typeNames, SHAPE_NONE, AM_DEFAULT);
-    ATTRIBUTE(CollisionShape, VAR_FLOAT, "Hull Thickness", thickness_, 0.0f, AM_DEFAULT);
-    ATTRIBUTE(CollisionShape, VAR_INT, "LOD Level", lodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
+    ATTRIBUTE(CollisionShape, VAR_INT, "LOD Level", lodLevel_, 0, AM_DEFAULT);
+    ATTRIBUTE(CollisionShape, VAR_FLOAT, "Hull Thickness", thickness_, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_INT, "Collision Group", GetCollisionGroup, SetCollisionGroup, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_INT, "Collision Mask", GetCollisionMask, SetCollisionMask, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_FLOAT, "Friction", GetFriction, SetFriction, float, DEFAULT_FRICTION, AM_DEFAULT);
@@ -344,8 +344,12 @@ void CollisionShape::OnSetAttribute(const AttributeInfo& attr, const Variant& sr
     // Change of some attributes requires the geometry to be recreated
     switch (attr.offset_)
     {
-    case offsetof(CollisionShape, shapeType_):
     case offsetof(CollisionShape, size_):
+        size_ = size_.Abs(); // Negative size is not allowed
+        recreateGeometry_ = true;
+        break;
+        
+    case offsetof(CollisionShape, shapeType_):
     case offsetof(CollisionShape, thickness_):
     case offsetof(CollisionShape, lodLevel_):
         recreateGeometry_ = true;
@@ -417,7 +421,7 @@ void CollisionShape::SetCylinder(float radius, float height, const Vector3& posi
     CreateGeometry();
 }
 
-void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
+void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& size, const Vector3& position, const Quaternion& rotation)
 {
     PROFILE(SetTriangleMeshShape);
     
@@ -432,14 +436,14 @@ void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vect
     model_ = model;
     shapeType_ = SHAPE_TRIANGLEMESH;
     lodLevel_ = lodLevel;
-    size_ = model->GetBoundingBox().Size();
+    size_ = size.Abs();
     position_ = position;
     rotation_ = rotation;
     
     CreateGeometry();
 }
 
-void CollisionShape::SetHeightfield(Model* model, unsigned xPoints, unsigned zPoints, float thickness, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
+void CollisionShape::SetHeightfield(Model* model, unsigned xPoints, unsigned zPoints, float thickness, unsigned lodLevel, const Vector3& size, const Vector3& position, const Quaternion& rotation)
 {
     PROFILE(SetHeightFieldShape);
     
@@ -456,14 +460,14 @@ void CollisionShape::SetHeightfield(Model* model, unsigned xPoints, unsigned zPo
     numPoints_ = IntVector2(xPoints, zPoints);
     thickness_ = thickness;
     lodLevel_ = lodLevel;
+    size_ = size.Abs();
     position_ = position;
     rotation_ = rotation;
-    size_ = model->GetBoundingBox().Size();
     
     CreateGeometry();
 }
 
-void CollisionShape::SetConvexHull(Model* model, float thickness, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
+void CollisionShape::SetConvexHull(Model* model, float thickness, unsigned lodLevel, const Vector3& size, const Vector3& position, const Quaternion& rotation)
 {
     PROFILE(SetConvexHullShape);
     
@@ -479,7 +483,7 @@ void CollisionShape::SetConvexHull(Model* model, float thickness, unsigned lodLe
     shapeType_ = SHAPE_CONVEXHULL;
     thickness_ = thickness;
     lodLevel_ = lodLevel;
-    size_ = model->GetBoundingBox().Size();
+    size_ = size.Abs();
     position_ = position;
     rotation_ = rotation;
     
@@ -783,7 +787,7 @@ void CollisionShape::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 void CollisionShape::OnMarkedDirty(Node* node)
 {
     // If scale has changed, must recreate the geometry
-    if (node->GetScale() != geometryScale_)
+    if (node->GetWorldScale() != geometryScale_)
         CreateGeometry();
     else
         UpdateTransform();
@@ -855,7 +859,7 @@ void CollisionShape::CreateGeometry()
     case SHAPE_CONVEXHULL:
         {
             // Check the geometry cache
-            String id = model_->GetName() + "_" + String(geometryScale_) + "_" + String(lodLevel_);
+            String id = model_->GetName() + "_" + String(size) + "_" + String(lodLevel_);
             if (shapeType_ == SHAPE_CONVEXHULL)
                 id += "_" + String(thickness_);
             
@@ -869,7 +873,7 @@ void CollisionShape::CreateGeometry()
             else
             {
                 SharedPtr<TriangleMeshData> newData(new TriangleMeshData(model_, shapeType_ == SHAPE_CONVEXHULL, thickness_,
-                    lodLevel_, geometryScale_));
+                    lodLevel_, size));
                 cache[id] = newData;
                 geometry_ = dCreateTriMesh(space, newData->triMesh_, 0, 0, 0);
                 geometryData_ = StaticCast<CollisionGeometryData>(newData);
@@ -880,7 +884,8 @@ void CollisionShape::CreateGeometry()
     case SHAPE_HEIGHTFIELD:
         {
             // Check the geometry cache
-            String id = model_->GetName() + "_" + String(numPoints_) + "_" + String(thickness_) + "_" + String(lodLevel_);
+            String id = model_->GetName() + "_" + String(size) + "_" + String(numPoints_) + "_" + String(thickness_) + "_" +
+                String(lodLevel_);
             
             Map<String, SharedPtr<HeightfieldData> >& cache = physicsWorld_->GetHeightfieldCache();
             Map<String, SharedPtr<HeightfieldData> >::Iterator j = cache.Find(id);
@@ -891,7 +896,7 @@ void CollisionShape::CreateGeometry()
             }
             else
             {
-                SharedPtr<HeightfieldData> newData(new HeightfieldData(model_, numPoints_, thickness_, lodLevel_, geometryScale_));
+                SharedPtr<HeightfieldData> newData(new HeightfieldData(model_, numPoints_, thickness_, lodLevel_, size));
                 cache[id] = newData;
                 geometry_ = dCreateHeightfield(space, newData->heightfield_, 1);
                 geometryData_ = StaticCast<CollisionGeometryData>(newData);

+ 7 - 7
Engine/Physics/CollisionShape.h

@@ -107,19 +107,19 @@ public:
     /// Clear the collision geometry.
     void Clear();
     /// %Set as a sphere.
-    void SetSphere(float radius, const Vector3& position, const Quaternion& rotation);
+    void SetSphere(float radius, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set as a box.
-    void SetBox(const Vector3& size, const Vector3& position, const Quaternion& rotation);
+    void SetBox(const Vector3& size, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set as a cylinder.
-    void SetCylinder(float radius, float height, const Vector3& position, const Quaternion& rotation);
+    void SetCylinder(float radius, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set as a capsule.
-    void SetCapsule(float radius, float height, const Vector3& position, const Quaternion& rotation);
+    void SetCapsule(float radius, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set as a triangle mesh.
-    void SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& position, const Quaternion& rotation);
+    void SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& size = Vector3::UNITY, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set as a heightfield.
-    void SetHeightfield(Model* model, unsigned xPoints, unsigned zPoints, float thickness, unsigned lodLevel, const Vector3& position, const Quaternion& rotation);
+    void SetHeightfield(Model* model, unsigned xPoints, unsigned zPoints, float thickness, unsigned lodLevel, const Vector3& size = Vector3::UNITY, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set as a convex hull (internally an ODE trimesh as well.)
-    void SetConvexHull(Model* model, float skinWidth, unsigned lodLevel, const Vector3& position, const Quaternion& rotation);
+    void SetConvexHull(Model* model, float skinWidth, unsigned lodLevel, const Vector3& size = Vector3::UNITY, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set offset position.
     void SetPosition(const Vector3& position);
     /// %Set rotation.

+ 3 - 3
Engine/Physics/PhysicsWorld.cpp

@@ -134,13 +134,11 @@ void PhysicsWorld::RegisterObject(Context* context)
 {
     context->RegisterFactory<PhysicsWorld>();
     
+    ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_VECTOR3, "Gravity", GetGravity, SetGravity, Vector3, Vector3::ZERO, AM_DEFAULT);
     ATTRIBUTE(PhysicsWorld, VAR_INT, "Physics FPS", fps_, DEFAULT_FPS, AM_DEFAULT);
     ATTRIBUTE(PhysicsWorld, VAR_INT, "Max Contacts", maxContacts_, DEFAULT_MAX_CONTACTS, AM_DEFAULT);
     ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Bounce Threshold", bounceThreshold_, DEFAULT_BOUNCE_THRESHOLD, AM_DEFAULT);
     ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Network Max Ang Vel.", maxNetworkAngularVelocity_, DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY, AM_DEFAULT);
-    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Time Accumulator", timeAcc_, 0.0f, AM_FILE | AM_NOEDIT);
-    ATTRIBUTE(PhysicsWorld, VAR_INT, "Random Seed", randomSeed_, 0, AM_FILE | AM_NOEDIT);
-    ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_VECTOR3, "Gravity", GetGravity, SetGravity, Vector3, Vector3::ZERO, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Lin Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Lin Damp Threshold", GetLinearDampingThreshold, SetLinearDampingThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Lin Damp Scale", GetLinearDampingScale, SetLinearDampingScale, float, 0.0f, AM_DEFAULT);
@@ -150,6 +148,8 @@ void PhysicsWorld::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "ERP Parameter", GetERP, SetERP, float, 0.2f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "CFM Parameter", GetCFM, SetCFM, float, 0.00001f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Contact Surface Layer", GetContactSurfaceLayer, SetContactSurfaceLayer, float, 0.0f, AM_DEFAULT);
+    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Time Accumulator", timeAcc_, 0.0f, AM_FILE | AM_NOEDIT);
+    ATTRIBUTE(PhysicsWorld, VAR_INT, "Random Seed", randomSeed_, 0, AM_FILE | AM_NOEDIT);
 }
 
 void PhysicsWorld::Update(float timeStep)

+ 2 - 2
Engine/Scene/Node.cpp

@@ -220,14 +220,14 @@ void Node::SetDirection(const Vector3& direction)
 
 void Node::SetScale(float scale)
 {
-    scale_ = Vector3(scale, scale, scale);
+    scale_ = Vector3(scale, scale, scale).Abs();
     if (!dirty_)
         MarkDirty();
 }
 
 void Node::SetScale(const Vector3& scale)
 {
-    scale_ = scale;
+    scale_ = scale.Abs();
     if (!dirty_)
         MarkDirty();
 }

+ 2 - 0
Engine/Scene/Serializable.h

@@ -169,6 +169,8 @@ public:
     SetFunctionPtr setFunction_;
 };
 
+#define COPY_BASE_ATTRIBUTES(className, sourceClassName) context->CopyBaseAttributes<sourceClassName, className>()
+#define REMOVE_ATTRIBUTE(className, name) context->RemoveAttribute<className>(name)
 #define ATTRIBUTE(className, type, name, variable, defaultValue, mode) context->RegisterAttribute<className>(AttributeInfo(type, name, offsetof(className, variable), defaultValue, mode))
 #define ENUM_ATTRIBUTE(className, name, variable, enumNames, defaultValue, mode) context->RegisterAttribute<className>(AttributeInfo(VAR_INT, name, offsetof(className, variable), enumNames, defaultValue, mode))
 #define ACCESSOR_ATTRIBUTE(className, type, name, getFunction, setFunction, typeName, defaultValue, mode) context->RegisterAttribute<className>(AttributeInfo(type, name, new AttributeAccessorImpl<className, typeName>(&className::getFunction, &className::setFunction), defaultValue, mode))