Browse Source

Added possibility to add components without going through an object factory.
Smoother normal calculation for terrain.
Added Terrain GetHeight() implementation.

Lasse Öörni 13 years ago
parent
commit
64e7b12bd8

+ 1 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -777,6 +777,7 @@ static void RegisterDecalSet(asIScriptEngine* engine)
 static void RegisterTerrain(asIScriptEngine* engine)
 {
     RegisterComponent<Terrain>(engine, "Terrain");
+    engine->RegisterObjectMethod("Terrain", "float GetHeight(const Vector3&in) const", asMETHOD(Terrain, GetHeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_material(Material@+)", asMETHOD(Terrain, SetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "Material@+ get_material() const", asMETHOD(Terrain, GetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_heightMap(Image@+)", asMETHOD(Terrain, SetHeightMap), asCALL_THISCALL);

+ 0 - 2
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -45,7 +45,6 @@
 #include "StringUtils.h"
 #include "Technique.h"
 #include "Terrain.h"
-#include "TerrainPatch.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "VertexBuffer.h"
@@ -2256,7 +2255,6 @@ void RegisterGraphicsLibrary(Context* context)
     ParticleEmitter::RegisterObject(context);
     DecalSet::RegisterObject(context);
     Terrain::RegisterObject(context);
-    TerrainPatch::RegisterObject(context);
     DebugRenderer::RegisterObject(context);
     Octree::RegisterObject(context);
     Zone::RegisterObject(context);

+ 0 - 2
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -49,7 +49,6 @@
 #include "StringUtils.h"
 #include "Technique.h"
 #include "Terrain.h"
-#include "TerrainPatch.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "VertexBuffer.h"
@@ -2314,7 +2313,6 @@ void RegisterGraphicsLibrary(Context* context)
     ParticleEmitter::RegisterObject(context);
     DecalSet::RegisterObject(context);
     Terrain::RegisterObject(context);
-    TerrainPatch::RegisterObject(context);
     DebugRenderer::RegisterObject(context);
     Octree::RegisterObject(context);
     Zone::RegisterObject(context);

+ 53 - 19
Engine/Graphics/Terrain.cpp

@@ -261,6 +261,26 @@ Material* Terrain::GetMaterial() const
     return material_;
 }
 
+float Terrain::GetHeight(const Vector3& worldPosition) const
+{
+    if (node_)
+    {
+        Vector3 position = node_->GetWorldTransform().Inverse() * worldPosition;
+        float xPos = position.x_ - patchWorldOrigin_.x_ / spacing_.x_;
+        float zPos = -position.z_ - patchWorldOrigin_.y_ / spacing_.z_;
+        
+        float h1 = GetRawHeight((unsigned)xPos, (unsigned)zPos);
+        float h2 = GetRawHeight((unsigned)xPos + 1, (unsigned)zPos);
+        float h3 = GetRawHeight((unsigned)xPos, (unsigned)zPos + 1);
+        float h4 = GetRawHeight((unsigned)xPos + 1, (unsigned)zPos + 1);
+        
+        float h = Lerp(Lerp(h1, h2, fmodf(xPos, 1.0f)), Lerp(h3, h4, fmodf(xPos, 1.0f)), fmodf(zPos, 1.0f));
+        return node_->GetWorldScale().y_ * h + node_->GetWorldPosition().y_;
+    }
+    else
+        return 0.0f;
+}
+
 void Terrain::UpdatePatchGeometry(TerrainPatch* patch)
 {
     BoundingBox box;
@@ -279,8 +299,8 @@ void Terrain::UpdatePatchGeometry(TerrainPatch* patch)
         {
             for (unsigned x1 = 0; x1 <= patchSize_; ++x1)
             {
-                unsigned xPos = x * patchSize_ + x1;
-                unsigned zPos = z * patchSize_ + z1;
+                int xPos = x * patchSize_ + x1;
+                int zPos = z * patchSize_ + z1;
                 
                 // Position
                 Vector3 position((float)x1 * spacing_.x_, GetRawHeight(xPos, zPos), -(float)z1 * spacing_.z_);
@@ -291,14 +311,7 @@ void Terrain::UpdatePatchGeometry(TerrainPatch* patch)
                 box.Merge(position);
                 
                 // Normal
-                float xSlope = GetRawHeight(xPos - 1, zPos) - GetRawHeight(xPos + 1, zPos);
-                float zSlope = GetRawHeight(xPos, zPos + 1) - GetRawHeight(xPos, zPos - 1);
-                if (xPos != 0 && xPos != size_.x_ - 1)
-                    xSlope *= 0.5f;
-                if (zPos != 0 && zPos != size_.y_ - 1)
-                    zSlope *= 0.5f;
-                
-                Vector3 normal = Vector3(xSlope, 1.0f, zSlope).Normalized();
+                Vector3 normal = GetNormal(xPos, zPos);
                 *vertexData++ = normal.x_;
                 *vertexData++ = normal.y_;
                 *vertexData++ = normal.z_;
@@ -335,14 +348,12 @@ void Terrain::OnMarkedDirty(Node* node)
 
 void Terrain::CreateGeometry()
 {
-    PROFILE(CreateTerrainGeometry);
-    
-    if (!heightMap_ || !node_ || !GetScene())
+    Scene* scene = GetScene();
+    Octree* octree = scene ? scene->GetComponent<Octree>() : 0;
+    if (!heightMap_ || !node_ || !octree)
         return;
     
-    Octree* octree = GetScene()->GetComponent<Octree>();
-    if (!octree)
-        return;
+    PROFILE(CreateTerrainGeometry);
     
     patches_.Clear();
     patchNodes_.Clear();
@@ -373,15 +384,16 @@ void Terrain::CreateGeometry()
     {
         for (unsigned x = 0; x < patchesX_; ++x)
         {
-            // Note: terrain nodes are not created as part of the scene, as it's runtime generated scene hierarchy we never want
-            // to save, serialize through network, or show in the editor
+            // Note: terrain nodes are not created as part of the scene, as it's runtime generated scene hierarchy
+            // we never want to save, serialize through network, or show in the editor
             Node* patchNode = new Node(context_);
             patchNode->SetID(FIRST_LOCAL_ID);
             
-            TerrainPatch* patch = patchNode->CreateComponent<TerrainPatch>(LOCAL);
+            TerrainPatch* patch = new TerrainPatch(context_);
             patch->owner_ = this;
             patch->x_ = x;
             patch->z_ = z;
+            patchNode->AddComponent(patch, FIRST_LOCAL_ID, LOCAL);
             octree->AddManualDrawable(patch);
             
             // Copy initial drawable parameters
@@ -457,3 +469,25 @@ float Terrain::GetRawHeight(unsigned x, unsigned z) const
     z = Clamp((int)z, 0, (int)size_.y_ - 1);
     return heightData_[z * size_.x_ + x];
 }
+
+Vector3 Terrain::GetNormal(unsigned x, unsigned z) const
+{
+    float baseHeight = GetRawHeight(x, z);
+    float nSlope = GetRawHeight(x, z - 1) - baseHeight;
+    float neSlope = GetRawHeight(x + 1, z - 1) - baseHeight;
+    float eSlope = GetRawHeight(x + 1, z) - baseHeight;
+    float seSlope = GetRawHeight(x + 1, z + 1) - baseHeight;
+    float sSlope = GetRawHeight(x, z + 1) - baseHeight;
+    float swSlope = GetRawHeight(x - 1, z + 1) - baseHeight;
+    float wSlope = GetRawHeight(x - 1, z) - baseHeight;
+    float nwSlope = GetRawHeight(x - 1, z - 1) - baseHeight;
+    
+    return (Vector3(0.0f, 1.0f, -nSlope) +
+        Vector3(-neSlope, 1.0f, -neSlope) +
+        Vector3(-eSlope, 1.0f, 0.0f) +
+        Vector3(-seSlope, 1.0f, seSlope) +
+        Vector3(0.0f, 1.0f, sSlope) +
+        Vector3(swSlope, 1.0f, swSlope) + 
+        Vector3(wSlope, 1.0f, 0.0f) +
+        Vector3(nwSlope, 1.0f, -nwSlope)).Normalized();
+}

+ 4 - 2
Engine/Graphics/Terrain.h

@@ -85,8 +85,8 @@ public:
     Image* GetHeightMap() const;
     /// Return material.
     Material* GetMaterial() const;
-    /// Return height at world coordinates, or 0 if outside the terrain.
-    float GetHeight(const Vector3& worldPosition);
+    /// Return height at world coordinates.
+    float GetHeight(const Vector3& worldPosition) const;
     /// Return raw height data.
     const float* GetHeightData() const { return heightData_.Get(); }
     /// Return number of terrain patches.
@@ -136,6 +136,8 @@ private:
     void SetPatchTransform(TerrainPatch* patch);
     /// Return an uninterpolated terrain height value, clamping to edges.
     float GetRawHeight(unsigned x, unsigned z) const;
+    /// Get terrain normal at position.
+    Vector3 GetNormal(unsigned x, unsigned z) const;
     
     /// Shared index buffer.
     SharedPtr<IndexBuffer> indexBuffer_;

+ 1 - 7
Engine/Graphics/TerrainPatch.cpp

@@ -63,11 +63,6 @@ TerrainPatch::~TerrainPatch()
 {
 }
 
-void TerrainPatch::RegisterObject(Context* context)
-{
-    context->RegisterFactory<TerrainPatch>();
-}
-
 void TerrainPatch::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     /// \todo Implement
@@ -110,8 +105,7 @@ void TerrainPatch::UpdateGeometry(const FrameInfo& frame)
     unsigned westLod = west_ ? west_->lodLevel_ : lodLevel_;
     unsigned eastLod = east_ ? east_->lodLevel_ : lodLevel_;
     
-    if (owner_)
-        owner_->UpdatePatchLOD(this, lodLevel_, northLod, southLod, westLod, eastLod);
+    owner_->UpdatePatchLOD(this, lodLevel_, northLod, southLod, westLod, eastLod);
     
     lodDirty_ = false;
 }

+ 0 - 2
Engine/Graphics/TerrainPatch.h

@@ -40,8 +40,6 @@ public:
     TerrainPatch(Context* context);
     /// Destruct.
     ~TerrainPatch();
-    /// Register object factory.
-    static void RegisterObject(Context* context);
     
     /// Process octree raycast. May be called from a worker thread.
     virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);

+ 165 - 157
Engine/Scene/Node.cpp

@@ -857,142 +857,6 @@ Component* Node::GetComponent(ShortStringHash type) const
     return 0;
 }
 
-void Node::PrepareNetworkUpdate()
-{
-    // Update dependency nodes list first
-    dependencyNodes_.Clear();
-    
-    // Add the parent node, but if it is local, traverse to the first non-local node
-    if (parent_ && parent_ != scene_)
-    {
-        Node* current = parent_;
-        while (current->id_ >= FIRST_LOCAL_ID)
-            current = current->parent_;
-        if (current && current != scene_)
-            dependencyNodes_.Push(current);
-    }
-    
-    // Let the components add their dependencies
-    for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
-    {
-        Component* component = *i;
-        if (component->GetID() < FIRST_LOCAL_ID)
-            component->GetDependencyNodes(dependencyNodes_);
-    }
-    
-    // Then check for node attribute changes
-    if (!networkState_)
-        AllocateNetworkState();
-    
-    const Vector<AttributeInfo>* attributes = networkState_->attributes_;
-    unsigned numAttributes = attributes->Size();
-    
-    if (networkState_->currentValues_.Size() != numAttributes)
-    {
-        networkState_->currentValues_.Resize(numAttributes);
-        networkState_->previousValues_.Resize(numAttributes);
-        
-        // Copy the default attribute values to the previous state as a starting point
-        for (unsigned i = 0; i < numAttributes; ++i)
-            networkState_->previousValues_[i] = attributes->At(i).defaultValue_;
-    }
-    
-    // Check for attribute changes
-    for (unsigned i = 0; i < numAttributes; ++i)
-    {
-        const AttributeInfo& attr = attributes->At(i);
-        OnGetAttribute(attr, networkState_->currentValues_[i]);
-        
-        if (networkState_->currentValues_[i] != networkState_->previousValues_[i])
-        {
-            networkState_->previousValues_[i] = networkState_->currentValues_[i];
-            
-            // Mark the attribute dirty in all replication states that are tracking this node
-            for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin(); j !=
-                networkState_->replicationStates_.End();
-                ++j)
-            {
-                NodeReplicationState* nodeState = static_cast<NodeReplicationState*>(*j);
-                nodeState->dirtyAttributes_.Set(i);
-                
-                // Add node to the dirty set if not added yet
-                if (!nodeState->markedDirty_)
-                {
-                    nodeState->markedDirty_ = true;
-                    nodeState->sceneState_->dirtyNodes_.Insert(id_);
-                }
-            }
-        }
-    }
-    
-    // Finally check for user var changes
-    for (VariantMap::ConstIterator i = vars_.Begin(); i != vars_.End(); ++i)
-    {
-        VariantMap::ConstIterator j = networkState_->previousVars_.Find(i->first_);
-        if (j == networkState_->previousVars_.End() || j->second_ != i->second_)
-        {
-            networkState_->previousVars_[i->first_] = i->second_;
-            
-            // Mark the var dirty in all replication states that are tracking this node
-            for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin(); j !=
-                networkState_->replicationStates_.End(); ++j)
-            {
-                NodeReplicationState* nodeState = static_cast<NodeReplicationState*>(*j);
-                nodeState->dirtyVars_.Insert(i->first_);
-                
-                if (!nodeState->markedDirty_)
-                {
-                    nodeState->markedDirty_ = true;
-                    nodeState->sceneState_->dirtyNodes_.Insert(id_);
-                }
-            }
-        }
-    }
-    
-    networkUpdate_ = false;
-}
-
-void Node::CleanupConnection(Connection* connection)
-{
-    if (owner_ == connection)
-        owner_ = 0;
-    
-    if (networkState_)
-    {
-        for (unsigned i = networkState_->replicationStates_.Size() - 1; i < networkState_->replicationStates_.Size(); --i)
-        {
-            if (networkState_->replicationStates_[i]->connection_ == connection)
-                networkState_->replicationStates_.Erase(i);
-        }
-    }
-}
-
-void Node::MarkNetworkUpdate()
-{
-    if (id_ < FIRST_LOCAL_ID && !networkUpdate_ && scene_)
-    {
-        scene_->MarkNetworkUpdate(this);
-        networkUpdate_ = true;
-    }
-}
-
-void Node::MarkReplicationDirty()
-{
-    if (networkState_)
-    {
-        for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin(); j !=
-            networkState_->replicationStates_.End(); ++j)
-        {
-            NodeReplicationState* nodeState = static_cast<NodeReplicationState*>(*j);
-            if (!nodeState->markedDirty_)
-            {
-                nodeState->markedDirty_ = true;
-                nodeState->sceneState_->dirtyNodes_.Insert(id_);
-            }
-        }
-    }
-}
-
 void Node::SetID(unsigned id)
 {
     id_ = id;
@@ -1186,37 +1050,154 @@ bool Node::LoadXML(const XMLElement& source, SceneResolver& resolver, bool readC
     return true;
 }
 
-Component* Node::CreateComponent(ShortStringHash type, unsigned id, CreateMode mode)
+
+void Node::PrepareNetworkUpdate()
 {
-    // Check that creation succeeds and that the object in fact is a component
-    SharedPtr<Component> newComponent = DynamicCast<Component>(context_->CreateObject(type));
-    if (!newComponent)
+    // Update dependency nodes list first
+    dependencyNodes_.Clear();
+    
+    // Add the parent node, but if it is local, traverse to the first non-local node
+    if (parent_ && parent_ != scene_)
     {
-        LOGERROR("Could not create unknown component type " + type.ToString());
-        return 0;
+        Node* current = parent_;
+        while (current->id_ >= FIRST_LOCAL_ID)
+            current = current->parent_;
+        if (current && current != scene_)
+            dependencyNodes_.Push(current);
     }
     
-    components_.Push(newComponent);
+    // Let the components add their dependencies
+    for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
+    {
+        Component* component = *i;
+        if (component->GetID() < FIRST_LOCAL_ID)
+            component->GetDependencyNodes(dependencyNodes_);
+    }
     
-    // If zero ID specified, or the ID is already taken, let the scene assign
-    if (scene_)
+    // Then check for node attribute changes
+    if (!networkState_)
+        AllocateNetworkState();
+    
+    const Vector<AttributeInfo>* attributes = networkState_->attributes_;
+    unsigned numAttributes = attributes->Size();
+    
+    if (networkState_->currentValues_.Size() != numAttributes)
     {
-        if (!id || scene_->GetComponent(id))
-            id = scene_->GetFreeComponentID(mode);
-        newComponent->SetID(id);
-        scene_->ComponentAdded(newComponent);
+        networkState_->currentValues_.Resize(numAttributes);
+        networkState_->previousValues_.Resize(numAttributes);
+        
+        // Copy the default attribute values to the previous state as a starting point
+        for (unsigned i = 0; i < numAttributes; ++i)
+            networkState_->previousValues_[i] = attributes->At(i).defaultValue_;
     }
-    else
-        newComponent->SetID(id);
     
-    newComponent->SetNode(this);
-    newComponent->OnMarkedDirty(this);
+    // Check for attribute changes
+    for (unsigned i = 0; i < numAttributes; ++i)
+    {
+        const AttributeInfo& attr = attributes->At(i);
+        OnGetAttribute(attr, networkState_->currentValues_[i]);
+        
+        if (networkState_->currentValues_[i] != networkState_->previousValues_[i])
+        {
+            networkState_->previousValues_[i] = networkState_->currentValues_[i];
+            
+            // Mark the attribute dirty in all replication states that are tracking this node
+            for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin(); j !=
+                networkState_->replicationStates_.End();
+                ++j)
+            {
+                NodeReplicationState* nodeState = static_cast<NodeReplicationState*>(*j);
+                nodeState->dirtyAttributes_.Set(i);
+                
+                // Add node to the dirty set if not added yet
+                if (!nodeState->markedDirty_)
+                {
+                    nodeState->markedDirty_ = true;
+                    nodeState->sceneState_->dirtyNodes_.Insert(id_);
+                }
+            }
+        }
+    }
     
-    // Check attributes of the new component on next network update, and mark node dirty in all replication states
-    newComponent->MarkNetworkUpdate();
-    MarkNetworkUpdate();
-    MarkReplicationDirty();
+    // Finally check for user var changes
+    for (VariantMap::ConstIterator i = vars_.Begin(); i != vars_.End(); ++i)
+    {
+        VariantMap::ConstIterator j = networkState_->previousVars_.Find(i->first_);
+        if (j == networkState_->previousVars_.End() || j->second_ != i->second_)
+        {
+            networkState_->previousVars_[i->first_] = i->second_;
+            
+            // Mark the var dirty in all replication states that are tracking this node
+            for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin(); j !=
+                networkState_->replicationStates_.End(); ++j)
+            {
+                NodeReplicationState* nodeState = static_cast<NodeReplicationState*>(*j);
+                nodeState->dirtyVars_.Insert(i->first_);
+                
+                if (!nodeState->markedDirty_)
+                {
+                    nodeState->markedDirty_ = true;
+                    nodeState->sceneState_->dirtyNodes_.Insert(id_);
+                }
+            }
+        }
+    }
+    
+    networkUpdate_ = false;
+}
+
+void Node::CleanupConnection(Connection* connection)
+{
+    if (owner_ == connection)
+        owner_ = 0;
+    
+    if (networkState_)
+    {
+        for (unsigned i = networkState_->replicationStates_.Size() - 1; i < networkState_->replicationStates_.Size(); --i)
+        {
+            if (networkState_->replicationStates_[i]->connection_ == connection)
+                networkState_->replicationStates_.Erase(i);
+        }
+    }
+}
+
+void Node::MarkNetworkUpdate()
+{
+    if (id_ < FIRST_LOCAL_ID && !networkUpdate_ && scene_)
+    {
+        scene_->MarkNetworkUpdate(this);
+        networkUpdate_ = true;
+    }
+}
+
+void Node::MarkReplicationDirty()
+{
+    if (networkState_)
+    {
+        for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin(); j !=
+            networkState_->replicationStates_.End(); ++j)
+        {
+            NodeReplicationState* nodeState = static_cast<NodeReplicationState*>(*j);
+            if (!nodeState->markedDirty_)
+            {
+                nodeState->markedDirty_ = true;
+                nodeState->sceneState_->dirtyNodes_.Insert(id_);
+            }
+        }
+    }
+}
+
+Component* Node::CreateComponent(ShortStringHash type, unsigned id, CreateMode mode)
+{
+    // Check that creation succeeds and that the object in fact is a component
+    SharedPtr<Component> newComponent = DynamicCast<Component>(context_->CreateObject(type));
+    if (!newComponent)
+    {
+        LOGERROR("Could not create unknown component type " + type.ToString());
+        return 0;
+    }
     
+    AddComponent(newComponent, id, mode);
     return newComponent;
 }
 
@@ -1238,6 +1219,33 @@ Node* Node::CreateChild(unsigned id, CreateMode mode)
     return newNode;
 }
 
+void Node::AddComponent(Component* component, unsigned id, CreateMode mode)
+{
+    if (!component)
+        return;
+    
+    components_.Push(SharedPtr<Component>(component));
+    
+    // If zero ID specified, or the ID is already taken, let the scene assign
+    if (scene_)
+    {
+        if (!id || scene_->GetComponent(id))
+            id = scene_->GetFreeComponentID(mode);
+        component->SetID(id);
+        scene_->ComponentAdded(component);
+    }
+    else
+        component->SetID(id);
+    
+    component->SetNode(this);
+    component->OnMarkedDirty(this);
+    
+    // Check attributes of the new component on next network update, and mark node dirty in all replication states
+    component->MarkNetworkUpdate();
+    MarkNetworkUpdate();
+    MarkReplicationDirty();
+}
+
 void Node::UpdateWorldTransform() const
 {
     if (parent_)

+ 2 - 2
Engine/Scene/Node.h

@@ -319,12 +319,12 @@ public:
     void MarkNetworkUpdate();
     /// Mark node dirty in scene replication states.
     void MarkReplicationDirty();
-    
-protected:
     /// Create a component with specific ID.
     Component* CreateComponent(ShortStringHash type, unsigned id, CreateMode mode);
     /// Create a child node with specific ID.
     Node* CreateChild(unsigned id, CreateMode mode);
+    /// Add a pre-created component.
+    void AddComponent(Component* component, unsigned id, CreateMode mode);
     
 private:
     /// Recalculate the world transform.