Ticket #2264: terrainflattening.3.patch

File terrainflattening.3.patch, 18.3 KB (added by sanderd17, 10 years ago)
  • binaries/data/mods/public/simulation/components/TerrainModifier.js

     
     1function TerrainModifier() {};
     2
     3/*
     4 * A component to calculate the height of different vertices for a height changing entity
     5 */
     6TerrainModifier.prototype.Schema =
     7    "<element name='Type'>" +
     8        "<choice>" +
     9            "<value>flatten</value>" +
     10            "<value>slopeWall</value>" +
     11        "</choice>" +
     12    "</element>";
     13
     14TerrainModifier.prototype.GetType = function()
     15{
     16    return this.template.Type;
     17};
     18
     19/**
     20 * All queried vertices will be in a relative square around this entity,
     21 * with as size the value from this method.
     22 */
     23TerrainModifier.prototype.GetBBox = function()
     24{
     25    if (!this.footprint)
     26    {
     27        var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
     28        this.footprint = cmpFootprint.GetShape();
     29    }
     30    if (this.footprint.type == "square")
     31        var max = Math.max(this.footprint.width, this.footprint.depth) + 6;
     32    else
     33        var max = this.footprint.radius * 2 + 6;
     34    if (this.GetType() == "flatten")
     35        return max
     36    return Math.max(max, 100);
     37   
     38};
     39
     40/**
     41 * Calculate the new height for the relative point
     42 * the oldHeight for that point, and the default entity height are given to save CPU time
     43 *
     44 * Note that the entity height will change when vertices near the centre
     45 * are modified in height
     46 */
     47TerrainModifier.prototype.GetNewHeight = function(point, oldHeight, entHeight)
     48{
     49    var r = {"height": oldHeight, "weight":0};
     50    switch (this.GetType())
     51    {
     52    case "flatten":
     53        var w = 0;
     54        var fp = this.footprint;
     55        // get the max distance from the footprint
     56        if (fp.type == "square")
     57            w = Math.max(Math.abs(point.x) - fp.width/2, Math.abs(point.y) - fp.depth/2);
     58        else
     59            w = Math.sqrt(Math.pow(point.x,2) + Math.pow(point.y,2)) - fp.radius;
     60
     61        // convert to a weight, where w == 1 is inside the footprint,
     62        // and w == 0 is far away from the footprint
     63        // TODO: turn '6' into a variable, it's the cutoff from which point nothing is changed
     64        w = Math.max(Math.min(1 - w/6, 1), 0);
     65        r = {"height": (1 - w)*oldHeight + w*entHeight, "weight": w};
     66        break;
     67
     68    case "slopeWall":
     69        if (point.y <= 6 )
     70        {
     71            if (point.y > -4 && Math.abs(point.x) < 4)
     72                r = {"height": oldHeight, weight: 1};
     73            break;
     74        }
     75        var l = 50;
     76        var newHeight = this.footprint.height*(Math.atan(-7*point.y/l + 3.5) + 1.4)/2.6;
     77        if (Math.abs(point.x) > this.footprint.width/2 + 4)
     78        {
     79            var mult = 1/(Math.abs(point.x) - this.footprint.width/2 - 3);
     80            newHeight *= mult;
     81            var weight = mult/10;
     82            newHeight += oldHeight
     83        }
     84        else
     85        {
     86            var weight = (l-Math.abs(point.y))/l;
     87            newHeight += (entHeight*(l - point.y) + oldHeight*point.y)/l;
     88        }
     89        r = {"height": newHeight, "weight": weight};
     90        break;
     91    default:
     92        warn("unknown terrain modifier type");
     93        break;
     94    }
     95    return {"x": r.height, "y": r.weight}
     96};
     97
     98TerrainModifier.prototype.OnPositionChanged = function(msg)
     99{
     100    var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     101    cmpTerrain.MakeVisualTerrainDirty();
     102};
     103
     104TerrainModifier.prototype.OnDestroy = function(msg)
     105{
     106    this.GetBBox = function(){ return 0;};
     107    var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     108    cmpTerrain.MakeVisualTerrainDirty();
     109};
     110
     111Engine.RegisterComponentType(IID_TerrainModifier, "TerrainModifier", TerrainModifier);
     112
  • binaries/data/mods/public/simulation/templates/template_structure.xml

     
    9696    <BarHeight>0.6</BarHeight>
    9797    <HeightOffset>12.0</HeightOffset>
    9898  </StatusBars>
     99  <TerrainModifier>
     100    <Type>
     101      flatten
     102    </Type>
     103  </TerrainModifier>
    99104  <TerritoryDecay>
    100105    <HealthDecayRate>5</HealthDecayRate>
    101106  </TerritoryDecay>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml

     
    1010    <SpawnEntityOnDeath>rubble/rubble_stone_wall_long</SpawnEntityOnDeath>
    1111  </Health>
    1212  <Identity>
    13     <Classes datatype="tokens">LongWall</Classes>
    14     <Tooltip>Long wall segments can be converted to gates.</Tooltip>
    15   </Identity>
    16 </Entity>
     13    <Classes datatype="tokens">LongWall</Classes>
     14    <Tooltip>Long wall segments can be converted to gates.</Tooltip>
     15  </Identity>
     16  <TerrainModifier>
     17    <Type>
     18      slopeWall
     19    </Type>
     20  </TerrainModifier>
     21</Entity>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml

     
    8585  <StatusBars>
    8686    <HeightOffset>20.0</HeightOffset>
    8787  </StatusBars>
     88  <TerrainModifier disable=""/>
    8889  <TerritoryInfluence>
    8990    <Root>false</Root>
    9091    <Radius>20</Radius>
  • source/simulation2/TypeList.h

     
    148148INTERFACE(Terrain)
    149149COMPONENT(Terrain)
    150150
     151INTERFACE(TerrainModifier)
     152COMPONENT(TerrainModifierScripted)
     153
    151154INTERFACE(TerritoryInfluence)
    152155COMPONENT(TerritoryInfluence)
    153156
  • source/simulation2/components/CCmpTerrain.cpp

     
    2020#include "simulation2/system/Component.h"
    2121#include "ICmpTerrain.h"
    2222
     23#include "ICmpTerrainModifier.h"
    2324#include "ICmpObstructionManager.h"
    2425#include "ICmpRangeManager.h"
     26#include "ICmpPosition.h"
    2527#include "simulation2/MessageTypes.h"
     28#include "simulation2/helpers/Geometry.h"
    2629
    2730#include "graphics/Terrain.h"
    2831#include "renderer/Renderer.h"
    2932#include "renderer/WaterManager.h"
     33#include "graphics/Patch.h"
     34#include "maths/MathUtil.h"
    3035#include "maths/Vector3D.h"
    3136
    3237class CCmpTerrain : public ICmpTerrain
     
    4045
    4146    CTerrain* m_Terrain; // not null
    4247
     48    std::vector<u16> m_SimHeightmap;
     49    ssize_t m_MapSizePatches;
     50
     51
    4352    static std::string GetSchema()
    4453    {
    4554        return "<a:component type='system'/><empty/>";
     
    4857    virtual void Init(const CParamNode& UNUSED(paramNode))
    4958    {
    5059        m_Terrain = &GetSimContext().GetTerrain();
     60        m_MapSizePatches = 0;
    5161    }
    5262
    5363    virtual void Deinit()
     
    6878        return m_Terrain->GetVerticesPerSide() != 0;
    6979    }
    7080
     81
     82    virtual u16* GetSimHeightMap()
     83    {
     84        return &m_SimHeightmap[0];
     85    }
     86
     87    virtual void MakeVisualTerrainDirty()
     88    {
     89        if (m_Terrain->GetPatchesPerSide() != m_MapSizePatches)
     90            m_Terrain->Resize(m_MapSizePatches);
     91
     92        if (m_MapSizePatches)
     93            RecalculateVisualHeightmap();
     94    }
     95
    7196    virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z)
    7297    {
    7398        CFixedVector3D normal;
     
    83108    virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z)
    84109    {
    85110        // TODO: this can crash if the terrain heightmap isn't initialised yet
    86 
    87111        return m_Terrain->GetExactGroundLevelFixed(x, z);
    88112    }
    89113
     
    94118
    95119    virtual u16 GetTilesPerSide()
    96120    {
    97         ssize_t tiles = m_Terrain->GetTilesPerSide();
     121        ssize_t tiles = m_MapSizePatches * PATCH_SIZE;
    98122        ENSURE(1 <= tiles && tiles <= 65535);
    99123        return (u16)tiles;
    100124    }
     
    101125
    102126    virtual u16 GetVerticesPerSide()
    103127    {
    104         ssize_t vertices = m_Terrain->GetVerticesPerSide();
    105         ENSURE(1 <= vertices && vertices <= 65535);
     128        ssize_t vertices = m_MapSizePatches * PATCH_SIZE + 1;
     129        ENSURE(1 < vertices && vertices <= 65535);
    106130        return (u16)vertices;
    107131    }
    108132
     
    111135        return m_Terrain;
    112136    }
    113137
     138    struct IterateHeightmapAverage
     139    {
     140        u16* heightmap;
     141        int pitch;
     142
     143        // weighted sum of the wanted heights
     144        float* sumHeightmap;
     145        // sum of the weights
     146        float* sumWeightmap;
     147
     148        void operator()(int i, int j, float weight, float newHeight)
     149        {
     150            if (weight > 0)
     151            {
     152                sumHeightmap[i+j*pitch] += weight * newHeight;
     153                sumWeightmap[i+j*pitch] += weight;
     154                int h = (int) (HEIGHT_UNITS_PER_METRE*sumHeightmap[i+j*pitch]/sumWeightmap[i+j*pitch]);
     155                heightmap[i + j*pitch] = Clamp(h, 0, 65535);
     156            }
     157        }
     158    };
     159
     160    template<typename T>
     161    void IterateHeightmap(T& callback, CFixedVector2D pos, fixed angle, entity_id_t ent)
     162    {
     163        CmpPtr<ICmpTerrainModifier> CCmpTerrainModifier(GetSimContext(), ent);
     164        // get the bbox, multiply by sqrt(2)/2 (rounded up) to get half the size and take
     165        // account of possible rotations
     166        fixed BBoxSize = CCmpTerrainModifier->GetBBox()/2;
     167        fixed maxBBoxSize = BBoxSize.Multiply(fixed::FromFloat(1.42f));
     168        int numVerts = m_MapSizePatches*PATCH_SIZE + 1;
     169
     170        int i0 = ((pos.X - maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     171        int i1 = ((pos.X + maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     172        int j0 = ((pos.Y - maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     173        int j1 = ((pos.Y + maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     174        i0 = Clamp(i0, 0, numVerts);
     175        i1 = Clamp(i1, 0, numVerts);
     176        j0 = Clamp(j0, 0, numVerts);
     177        j1 = Clamp(j1, 0, numVerts);
     178
     179        float entHeight = m_Terrain->GetExactGroundLevel(pos.X.ToFloat(), pos.Y.ToFloat());
     180        for (int j = j0; j <= j1; ++j)
     181        {
     182            for (int i = i0; i <= i1; ++i)
     183            {
     184                CFixedVector2D pt = CFixedVector2D(fixed::FromInt(i*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)) - CFixedVector2D(pos.X, pos.Y);
     185                pt = pt.Rotate(-angle);
     186                if (pt.X.Absolute() > BBoxSize || pt.Y.Absolute() > BBoxSize)
     187                    continue;
     188                float oldHeight = m_Terrain->GetVertexGroundLevel(i, j);
     189                float newHeight, weight;
     190                CCmpTerrainModifier->GetNewHeight(pt, oldHeight, entHeight, newHeight, weight);
     191                callback(i, j, weight, newHeight);
     192            }
     193        }
     194    }
     195
     196    void RecalculateVisualHeightmap()
     197    {
     198        u16* heightmap = m_Terrain->GetHeightMap();
     199        int pitch = m_MapSizePatches * PATCH_SIZE + 1;
     200        std::vector<u16> tempHeightmap(pitch*pitch);
     201        memcpy(&tempHeightmap[0], &m_SimHeightmap[0], pitch * pitch * sizeof(u16));
     202        memcpy(heightmap, &m_SimHeightmap[0], (m_MapSizePatches * PATCH_SIZE + 1) * (m_MapSizePatches * PATCH_SIZE + 1 )* sizeof(u16));
     203
     204        IterateHeightmapAverage callback;
     205        callback.heightmap = &tempHeightmap[0];
     206        callback.pitch = pitch;
     207        std::vector<float> sumHeightmap(pitch * pitch, 0.0f);
     208        callback.sumHeightmap = &sumHeightmap[0];
     209        std::vector<float> sumWeightmap(pitch * pitch, 0.0f);
     210        callback.sumWeightmap = &sumWeightmap[0];
     211
     212        CComponentManager::InterfaceList ents = GetSimContext().GetComponentManager().GetEntitiesWithInterface(IID_TerrainModifier);
     213        for (CComponentManager::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
     214        {
     215            CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), it->first);
     216            if (cmpPosition)
     217            {
     218                CFixedVector2D pos = cmpPosition->GetPosition2D();
     219                fixed angle = cmpPosition->GetRotation().Y;
     220
     221                IterateHeightmap(callback, pos, angle, it->first);
     222            }
     223        }
     224
     225        memcpy(heightmap, &tempHeightmap[0], pitch * pitch * sizeof(u16));
     226        m_Terrain->MakeDirty(RENDERDATA_UPDATE_VERTICES);
     227    }
     228
    114229    virtual void ReloadTerrain()
    115230    {
    116231        // TODO: should refactor this code to be nicer
     232        m_MapSizePatches = m_Terrain->GetPatchesPerSide();
     233        size_t size = (m_MapSizePatches * PATCH_SIZE + 1)*(m_MapSizePatches * PATCH_SIZE + 1);
     234        m_SimHeightmap.resize(size);
     235        if (m_Terrain->GetHeightMap())
     236            memcpy(&m_SimHeightmap[0], m_Terrain->GetHeightMap(), size*sizeof(u16));
     237        else
     238            memset(&m_SimHeightmap[0], 0, size*sizeof(u16));
    117239
    118240        u16 tiles = GetTilesPerSide();
    119241        u16 vertices = GetVerticesPerSide();
     
    138260        if (CRenderer::IsInitialised())
    139261            g_Renderer.GetWaterManager()->SetMapSize(vertices);
    140262
     263        MakeVisualTerrainDirty();
     264
    141265        MakeDirty(0, 0, tiles+1, tiles+1);
    142266    }
    143267
  • source/simulation2/components/ICmpTerrain.cpp

     
    2424BEGIN_INTERFACE_WRAPPER(Terrain)
    2525DEFINE_INTERFACE_METHOD_2("GetGroundLevel", entity_pos_t, ICmpTerrain, GetGroundLevel, entity_pos_t, entity_pos_t)
    2626DEFINE_INTERFACE_METHOD_2("CalcNormal", CFixedVector3D, ICmpTerrain, CalcNormal, entity_pos_t, entity_pos_t)
     27DEFINE_INTERFACE_METHOD_0("MakeVisualTerrainDirty", void, ICmpTerrain, MakeVisualTerrainDirty)
    2728END_INTERFACE_WRAPPER(Terrain)
  • source/simulation2/components/ICmpTerrain.h

     
    3232public:
    3333    virtual bool IsLoaded() = 0;
    3434
     35    virtual u16* GetSimHeightMap() = 0;
     36
     37    virtual void MakeVisualTerrainDirty() = 0;
     38
    3539    virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) = 0;
    3640
    3741    virtual CVector3D CalcExactNormal(float x, float z) = 0;
  • source/simulation2/components/ICmpTerrainModifier.cpp

     
     1/* Copyright (C) 2013 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "precompiled.h"
     19
     20#include "ICmpTerrainModifier.h"
     21
     22#include "simulation2/system/InterfaceScripted.h"
     23#include "simulation2/scripting/ScriptComponent.h"
     24
     25BEGIN_INTERFACE_WRAPPER(TerrainModifier)
     26END_INTERFACE_WRAPPER(TerrainModifier)
     27
     28
     29class CCmpTerrainModifierScripted : public ICmpTerrainModifier
     30{
     31public:
     32    DEFAULT_SCRIPT_WRAPPER(TerrainModifierScripted)
     33
     34    virtual fixed GetBBox()
     35    {
     36        return m_Script.Call<fixed>("GetBBox");
     37    }
     38
     39    virtual void GetNewHeight(CFixedVector2D relPt, float oldHeight, float entHeight, float& newHeight, float& weight)
     40    {
     41        // TODO Use std::vector<float> instead???
     42        CFixedVector2D v = m_Script.Call<CFixedVector2D>("GetNewHeight", relPt, oldHeight, entHeight);
     43        newHeight = v.X.ToFloat();
     44        weight = v.Y.ToFloat();
     45    }
     46};
     47
     48REGISTER_COMPONENT_SCRIPT_WRAPPER(TerrainModifierScripted)
  • source/simulation2/components/ICmpTerrainModifier.h

     
     1/* Copyright (C) 2013 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#ifndef INCLUDED_ICMPTERRAINMODIFIER
     19#define INCLUDED_ICMPTERRAINMODIFIER
     20
     21#include "simulation2/system/Interface.h"
     22
     23#include "simulation2/helpers/Position.h"
     24#include "maths/FixedVector2D.h"
     25
     26class ICmpTerrainModifier : public IComponent
     27{
     28public:
     29
     30    /**
     31     * the BBox size of vertices that certainly need to be queried
     32     * other vertices outside the BBox can also be queried, but shouldn't influence the terrain
     33     */
     34    virtual fixed GetBBox() = 0;
     35
     36
     37    virtual void GetNewHeight(CFixedVector2D relPt, float oldHeight, float entHeight, float& newHeight, float& weight) = 0;
     38
     39    DECLARE_INTERFACE_TYPE(TerrainModifier)
     40};
     41
     42#endif // INCLUDED_ICMPTERRAINMODIFIER
  • source/simulation2/system/ComponentTest.h

     
    229229    virtual void ReloadTerrain()
    230230    {
    231231    }
     232
     233    virtual void MakeVisualTerrainDirty()
     234    {
     235    }
     236
     237    virtual u16* GetSimHeightMap()
     238    {
     239        return NULL;
     240    }
    232241};
  • source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp

     
    4141    void Init()
    4242    {
    4343        m_Heightmap = g_Game->GetWorld()->GetTerrain()->GetHeightMap();
     44        CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
     45        if (cmpTerrain)
     46            m_SimHeightmap = cmpTerrain->GetSimHeightMap();
    4447        m_VertsPerSide = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
    4548    }
    4649
     
    9093    void setNew(ssize_t x, ssize_t y, const u16& val)
    9194    {
    9295        m_Heightmap[y*m_VertsPerSide + x] = val;
     96        if (m_SimHeightmap)
     97            m_SimHeightmap[y*m_VertsPerSide + x] = val;
    9398    }
    9499
    95100    u16* m_Heightmap;
     101    u16* m_SimHeightmap;
    96102    ssize_t m_VertsPerSide;
    97103};
    98104