Ticket #2264: terrainModifier.4.diff

File terrainModifier.4.diff, 45.5 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.bBox != undefined)
     26        return this.bBox;
     27
     28    if (!this.footprint)
     29    {
     30        var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
     31        this.footprint = cmpFootprint.GetShape();
     32    }
     33    if (this.footprint.type == "square")
     34        var max = Math.max(this.footprint.width, this.footprint.depth) + 6;
     35    else
     36        var max = this.footprint.radius * 2 + 6;
     37    if (this.GetType() == "flatten")
     38        this.bBox = max
     39    else
     40        this.bBox = Math.max(max, 100);
     41    return this.bBox;
     42};
     43
     44/**
     45 * Calculate the new height for the relative point
     46 * the oldHeight for that point, and the default entity height are given to save CPU time
     47 *
     48 * Note that the entity height will change when vertices near the centre
     49 * are modified in height
     50 */
     51TerrainModifier.prototype.GetNewHeight = function(point, oldHeight, entHeight)
     52{
     53    var r = {"height": oldHeight, "weight":0};
     54    switch (this.GetType())
     55    {
     56    case "flatten":
     57        var w = 0;
     58        var fp = this.footprint;
     59        // get the max distance from the footprint
     60        if (fp.type == "square")
     61            w = Math.max(Math.abs(point.x) - fp.width/2, Math.abs(point.y) - fp.depth/2);
     62        else
     63            w = Math.sqrt(Math.pow(point.x,2) + Math.pow(point.y,2)) - fp.radius;
     64
     65        // convert to a weight, where w == 1 is inside the footprint,
     66        // and w == 0 is far away from the footprint
     67        // TODO: turn '6' into a variable, it's the cutoff from which point nothing is changed
     68        w = Math.max(Math.min(1 - w/6, 1), 0);
     69        r = {"height": (1 - w)*oldHeight + w*entHeight, "weight": w};
     70        break;
     71
     72    case "slopeWall":
     73        if (point.y <= 0 )
     74        {
     75            if (point.y > -8 && Math.abs(point.x) < 4)
     76                r.weight = 10;
     77            break;
     78        }
     79        var l = 50;// TODO put in variable, and bind with the bbox
     80        var newHeight = this.footprint.height*(Math.atan(-7*point.y/l + 3.5) + 1.4)/2.6;
     81        if (Math.abs(point.x) > this.footprint.width/2)
     82        {
     83            var mult = 1/(Math.abs(point.x) - this.footprint.width/2 + 2);
     84            r.weight = mult/10;
     85            r.height = mult*newHeight + oldHeight;
     86        }
     87        else
     88        {
     89            r.weight = (l-Math.abs(point.y))/l;
     90            r.height = newHeight + (entHeight*(l - point.y) + oldHeight*point.y)/l;
     91        }
     92        break;
     93    default:
     94        warn("unknown terrain modifier type");
     95        break;
     96    }
     97    return {"x": r.height, "y": r.weight}
     98};
     99
     100TerrainModifier.prototype.OnPositionChanged = function(msg)
     101{
     102    var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     103    cmpTerrain.MakeVisualTerrainDirty(this.entity, this.bBox);
     104};
     105
     106TerrainModifier.prototype.OnDestroy = function(msg)
     107{
     108    var bBox = this.bBox;
     109    this.bBox = 0; // disable terrain modifying capabilities of this entity
     110    var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     111    cmpTerrain.MakeVisualTerrainDirty(this.entity, bBox);
     112};
     113
     114Engine.RegisterComponentType(IID_TerrainModifier, "TerrainModifier", TerrainModifier);
     115
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_gate.xml

     
    1111    <Square width="38.5" depth="9.0"/>
    1212    <Height>9.0</Height>
    1313  </Footprint>
     14  <Health>
     15    <Max>1500</Max>
     16  </Health>
    1417  <Identity>
    1518    <Civ>brit</Civ>
    1619    <SpecificName>Dor</SpecificName>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_long.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_long">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="38.5" depth="8.5"/>
     7    <Square width="38.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Identity>
     
    1114    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1215  </Identity>
    1316  <Obstruction>
    14     <Static width="37.0" depth="7.0"/>
     17    <Static width="37.0" depth="10.0"/>
    1518  </Obstruction>
     19  <TerrainModifier>
     20    <Type>
     21      slopeWall
     22    </Type>
     23  </TerrainModifier>
    1624  <VisualActor>
    1725    <Actor>structures/celts/wall_long.xml</Actor>
    1826  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_medium.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_medium">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="26.5" depth="8.5"/>
     7    <Square width="26.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Health>
     
    1417    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1518  </Identity>
    1619  <Obstruction>
    17     <Static width="25.0" depth="7.0"/>
     20    <Static width="25.0" depth="10.0"/>
    1821  </Obstruction>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_medium.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_short.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_short">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="14.5" depth="8.5"/>
     7    <Square width="14.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Health>
     
    1417    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1518  </Identity>
    1619  <Obstruction>
    17     <Static width="13.0" depth="7.0"/>
     20    <Static width="13.0" depth="10.0"/>
    1821  </Obstruction>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_short.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_tower.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_tower">
    33  <Attack disable=""/>
     4  <Armour>
     5    <Crush>20</Crush>
     6  </Armour>
    47  <Footprint>
    5     <Square width="10.0" depth="10.0"/>
    6     <Height>20.0</Height>
     8    <Square width="10.0" depth="13.0"/>
     9    <Height>9.0</Height>
    710  </Footprint>
    811  <GarrisonHolder disable=""/>
    912  <Identity>
     
    1316    <Tooltip>Does not shoot or garrison.</Tooltip>
    1417  </Identity>
    1518  <Obstruction>
    16     <Static width="9.0" depth="9.0"/>
     19    <Static width="9.0" depth="12.0"/>
    1720  </Obstruction>
     21  <TerrainModifier>
     22    <Type>
     23      slopeWall
     24    </Type>
     25  </TerrainModifier>
    1826  <RallyPoint disable=""/>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_tower.xml</Actor>
  • binaries/data/mods/public/simulation/templates/structures/celt_wall_gate.xml

     
    1111    <Square width="38.5" depth="9.0"/>
    1212    <Height>9.0</Height>
    1313  </Footprint>
     14  <Health>
     15    <Max>1500</Max>
     16  </Health>
    1417  <Identity>
    1518    <Civ>celt</Civ>
    1619    <SpecificName>Gate</SpecificName>
  • binaries/data/mods/public/simulation/templates/structures/celt_wall_long.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_long">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="38.5" depth="8.5"/>
     7    <Square width="38.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Identity>
     
    1114    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1215  </Identity>
    1316  <Obstruction>
    14     <Static width="37.0" depth="7.0"/>
     17    <Static width="37.0" depth="10.0"/>
    1518  </Obstruction>
     19  <TerrainModifier>
     20    <Type>
     21      slopeWall
     22    </Type>
     23  </TerrainModifier>
    1624  <VisualActor>
    1725    <Actor>structures/celts/wall_long.xml</Actor>
    1826  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_wall_medium.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_medium">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="26.5" depth="8.5"/>
     7    <Square width="26.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Health>
     
    1417    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1518  </Identity>
    1619  <Obstruction>
    17     <Static width="25.0" depth="7.0"/>
     20    <Static width="25.0" depth="10.0"/>
    1821  </Obstruction>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_medium.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_wall_short.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_short">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="14.5" depth="8.5"/>
     7    <Square width="14.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Health>
     
    1417    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1518  </Identity>
    1619  <Obstruction>
    17     <Static width="13.0" depth="7.0"/>
     20    <Static width="13.0" depth="10.0"/>
    1821  </Obstruction>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_short.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_wall_tower.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_tower">
    33  <Attack disable=""/>
     4  <Armour>
     5    <Crush>20</Crush>
     6  </Armour>
    47  <Footprint>
    5     <Square width="10.0" depth="10.0"/>
    6     <Height>20.0</Height>
     8    <Square width="10.0" depth="13.0"/>
     9    <Height>9.0</Height>
    710  </Footprint>
    811  <GarrisonHolder disable=""/>
    912  <Identity>
     
    1316    <Tooltip>Does not shoot or garrison.</Tooltip>
    1417  </Identity>
    1518  <Obstruction>
    16     <Static width="9.0" depth="9.0"/>
     19    <Static width="9.0" depth="12.0"/>
    1720  </Obstruction>
    1821  <RallyPoint disable=""/>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_tower.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_gate.xml

     
    1111    <Square width="38.5" depth="9.0"/>
    1212    <Height>9.0</Height>
    1313  </Footprint>
     14  <Health>
     15    <Max>1500</Max>
     16  </Health>
    1417  <Identity>
    1518    <Civ>gaul</Civ>
    1619    <SpecificName>Duro</SpecificName>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_long.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_long">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="38.5" depth="8.5"/>
     7    <Square width="38.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Identity>
     
    1114    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1215  </Identity>
    1316  <Obstruction>
    14     <Static width="37.0" depth="7.0"/>
     17    <Static width="37.0" depth="10.0"/>
    1518  </Obstruction>
     19  <TerrainModifier>
     20    <Type>
     21      slopeWall
     22    </Type>
     23  </TerrainModifier>
    1624  <VisualActor>
    1725    <Actor>structures/celts/wall_long.xml</Actor>
    1826  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_medium.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_medium">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="26.5" depth="8.5"/>
     7    <Square width="26.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Health>
     
    1417    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1518  </Identity>
    1619  <Obstruction>
    17     <Static width="25.0" depth="7.0"/>
     20    <Static width="25.0" depth="10.0"/>
    1821  </Obstruction>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_medium.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_short.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_short">
     3  <Armour>
     4    <Crush>20</Crush>
     5  </Armour>
    36  <Footprint>
    4     <Square width="14.5" depth="8.5"/>
     7    <Square width="14.5" depth="12.5"/>
    58    <Height>9.0</Height>
    69  </Footprint>
    710  <Health>
     
    1417    <History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
    1518  </Identity>
    1619  <Obstruction>
    17     <Static width="13.0" depth="7.0"/>
     20    <Static width="13.0" depth="10.0"/>
    1821  </Obstruction>
     22  <TerrainModifier>
     23    <Type>
     24      slopeWall
     25    </Type>
     26  </TerrainModifier>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_short.xml</Actor>
    2129  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_tower.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_wall_tower">
    33  <Attack disable=""/>
     4  <Armour>
     5    <Crush>20</Crush>
     6  </Armour>
    47  <Footprint>
    5     <Square width="10.0" depth="10.0"/>
    6     <Height>20.0</Height>
     8    <Square width="10.0" depth="13.0"/>
     9    <Height>9.0</Height>
    710  </Footprint>
    811  <GarrisonHolder disable=""/>
    912  <Identity>
     
    1316    <Tooltip>Does not shoot or garrison.</Tooltip>
    1417  </Identity>
    1518  <Obstruction>
    16     <Static width="9.0" depth="9.0"/>
     19    <Static width="9.0" depth="12.0"/>
    1720  </Obstruction>
     21  <TerrainModifier>
     22    <Type>
     23      slopeWall
     24    </Type>
     25  </TerrainModifier>
    1826  <RallyPoint disable=""/>
    1927  <VisualActor>
    2028    <Actor>structures/celts/wall_tower.xml</Actor>
  • binaries/data/mods/public/simulation/templates/structures/iber_house.xml

     
    1919    <Radius>16</Radius>
    2020    <Weight>65536</Weight>
    2121  </TerritoryInfluence>
     22  <TerrainModifier>
     23    <Type>
     24      flatten
     25    </Type>
     26  </TerrainModifier>
    2227  <VisualActor>
    2328    <Actor>structures/iberians/house.xml</Actor>
    2429    <FoundationActor>structures/fndn_2x2.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall.xml

     
    4848    <Radius>20</Radius>
    4949    <Weight>65536</Weight>
    5050  </TerritoryInfluence>
     51  <TerrainModifier disable=""/>
    5152  <Vision>
    5253    <Range>20</Range>
    5354  </Vision>
  • 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</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>
  • binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml

     
    5353    </SoundGroups>
    5454  </Sound>
    5555  <TerritoryDecay disable=""/>
     56  <TerrainModifier disable=""/>
    5657  <ProductionQueue>
    5758    <BatchTimeModifier>0.8</BatchTimeModifier>
    5859    <Entities datatype="tokens">
  • source/graphics/MapReader.cpp

     
    218218//      - data: map size, heightmap, list of textures used by map, texture tile assignments
    219219int CMapReader::UnpackTerrain()
    220220{
     221    printf("start unpackTerrain\n");
    221222    // yield after this time is reached. balances increased progress bar
    222223    // smoothness vs. slowing down loading.
    223224    const double end_time = timer_Time() + 200e-3;
     
    260261
    261262    // reset generator state.
    262263    cur_terrain_tex = 0;
     264    printf("stop unpackTerrain\n");
    263265
    264266    return 0;
    265267}
     
    267269// ApplyData: take all the input data, and rebuild the scene from it
    268270int CMapReader::ApplyData()
    269271{
     272    printf("start ApplyData\n");
    270273    if (m_PatchesPerSide == 0)
    271274    {
    272275        // we'll probably crash when trying to use this map later
     
    330333    CmpPtr<ICmpTerrain> cmpTerrain(*pSimContext, SYSTEM_ENTITY);
    331334    if (cmpTerrain)
    332335        cmpTerrain->ReloadTerrain();
     336    printf("stop ApplyData\n");
    333337
    334338    return 0;
    335339}
  • source/graphics/Terrain.cpp

     
    4040///////////////////////////////////////////////////////////////////////////////
    4141// CTerrain constructor
    4242CTerrain::CTerrain()
    43 : m_Heightmap(0), m_Patches(0), m_MapSize(0), m_MapSizePatches(0),
     43: m_VisualHeightmap(0), m_OrigHeightmap(0), m_Patches(0), m_MapSize(0), m_MapSizePatches(0),
    4444m_BaseColour(255, 255, 255, 255)
    4545{
    4646}
     
    5959{
    6060    m_HeightMipmap.ReleaseData();
    6161
    62     delete[] m_Heightmap;
     62    delete[] m_VisualHeightmap;
     63    delete[] m_OrigHeightmap;
    6364    delete[] m_Patches;
    6465}
    6566
     
    7677    m_MapSize = patchesPerSide*PATCH_SIZE+1;
    7778    m_MapSizePatches = patchesPerSide;
    7879    // allocate data for new terrain
    79     m_Heightmap = new u16[m_MapSize*m_MapSize];
     80    m_VisualHeightmap = new u16[m_MapSize*m_MapSize];
     81    m_OrigHeightmap = new u16[m_MapSize*m_MapSize];
     82    m_Heightmap = m_VisualHeightmap;
    8083    m_Patches = new CPatch[m_MapSizePatches*m_MapSizePatches];
    8184
    8285    // given a heightmap?
     
    8386    if (data)
    8487    {
    8588        // yes; keep a copy of it
    86         memcpy(m_Heightmap, data, m_MapSize*m_MapSize*sizeof(u16));
     89        memcpy(m_OrigHeightmap, data, m_MapSize*m_MapSize*sizeof(u16));
     90        memcpy(m_VisualHeightmap, data, m_MapSize*m_MapSize*sizeof(u16));
    8791    }
    8892    else
    8993    {
    9094        // build a flat terrain
    91         memset(m_Heightmap, 0, m_MapSize*m_MapSize*sizeof(u16));
     95        memset(m_OrigHeightmap, 0, m_MapSize*m_MapSize*sizeof(u16));
     96        memset(m_VisualHeightmap, 0, m_MapSize*m_MapSize*sizeof(u16));
    9297    }
    9398
    9499    // setup patch parents, indices etc
     
    95100    InitialisePatches();
    96101
    97102    // initialise mipmap
    98     m_HeightMipmap.Initialize(m_MapSize, m_Heightmap);
     103    m_HeightMipmap.Initialize(m_MapSize, m_VisualHeightmap);
    99104
    100105    return true;
    101106}
    102107
    103108///////////////////////////////////////////////////////////////////////////////
     109// Switch between querying the original height map or the visual height map
     110// For most purposes, querying the visual height map is best as it confirms what the player sees
     111void CTerrain::WorkOnOrigHeightMap(bool f)
     112{
     113    if (f)
     114        m_Heightmap = m_OrigHeightmap;
     115    else
     116        m_Heightmap = m_VisualHeightmap;
     117}
    104118
     119//////////////////////////////////////////////////////////////////////////////
     120// Get the 8-bit movement class used in the pathfinder
    105121CStr8 CTerrain::GetMovementClass(ssize_t i, ssize_t j) const
    106122{
    107123    CMiniPatch* tile = GetTile(i, j);
     
    460476
    461477    // allocate data for new terrain
    462478    ssize_t newMapSize=size*PATCH_SIZE+1;
    463     u16* newHeightmap=new u16[newMapSize*newMapSize];
     479    u16* newOrigHeightmap=new u16[newMapSize*newMapSize];
     480    u16* newVisualHeightmap=new u16[newMapSize*newMapSize];
    464481    CPatch* newPatches=new CPatch[size*size];
    465482
    466483    if (size>m_MapSizePatches) {
    467484        // new map is bigger than old one - zero the heightmap so we don't get uninitialised
    468485        // height data along the expanded edges
    469         memset(newHeightmap,0,newMapSize*newMapSize*sizeof(u16));
     486        memset(newOrigHeightmap,0,newMapSize*newMapSize*sizeof(u16));
     487        memset(newVisualHeightmap,0,newMapSize*newMapSize*sizeof(u16));
    470488    }
    471489
    472490    // now copy over rows of data
    473     u16* src=m_Heightmap;
    474     u16* dst=newHeightmap;
     491    u16* src1=m_VisualHeightmap;
     492    u16* src2=m_OrigHeightmap;
     493    u16* dst1=newVisualHeightmap;
     494    u16* dst2=newOrigHeightmap;
    475495    ssize_t copysize=std::min(newMapSize, m_MapSize);
    476496    for (ssize_t j=0;j<copysize;j++) {
    477         memcpy(dst,src,copysize*sizeof(u16));
    478         dst+=copysize;
    479         src+=m_MapSize;
     497        memcpy(dst1,src1,copysize*sizeof(u16));
     498        memcpy(dst2,src2,copysize*sizeof(u16));
     499        dst1+=copysize;
     500        dst2+=copysize;
     501        src1+=m_MapSize;
     502        src2+=m_MapSize;
    480503        if (newMapSize>m_MapSize) {
    481504            // extend the last height to the end of the row
    482505            for (size_t i=0;i<newMapSize-(size_t)m_MapSize;i++) {
    483                 *dst++=*(src-1);
     506                *dst1++=*(src1-1);
     507                *dst2++=*(src2-1);
    484508            }
    485509        }
    486510    }
     
    488512
    489513    if (newMapSize>m_MapSize) {
    490514        // copy over heights of the last row to any remaining rows
    491         src=newHeightmap+((m_MapSize-1)*newMapSize);
    492         dst=src+newMapSize;
     515        src1=newVisualHeightmap+((m_MapSize-1)*newMapSize);
     516        src2=newOrigHeightmap+((m_MapSize-1)*newMapSize);
     517        dst1=src1+newMapSize;
     518        dst2=src2+newMapSize;
    493519        for (ssize_t i=0;i<newMapSize-m_MapSize;i++) {
    494             memcpy(dst,src,newMapSize*sizeof(u16));
    495             dst+=newMapSize;
     520            memcpy(dst1,src1,newMapSize*sizeof(u16));
     521            memcpy(dst2,src2,newMapSize*sizeof(u16));
     522            dst1+=newMapSize;
     523            dst2+=newMapSize;
    496524        }
    497525    }
    498526
     
    543571    ReleaseData();
    544572
    545573    // store new data
    546     m_Heightmap=newHeightmap;
     574    m_VisualHeightmap=newVisualHeightmap;
     575    m_OrigHeightmap=newOrigHeightmap;
     576    m_Heightmap=newVisualHeightmap;
    547577    m_Patches=newPatches;
    548578    m_MapSize=(ssize_t)newMapSize;
    549579    m_MapSizePatches=(ssize_t)size;
     
    575605void CTerrain::SetHeightMap(u16* heightmap)
    576606{
    577607    // keep a copy of the given heightmap
    578     memcpy(m_Heightmap, heightmap, m_MapSize*m_MapSize*sizeof(u16));
     608    memcpy(m_VisualHeightmap, heightmap, m_MapSize*m_MapSize*sizeof(u16));
     609    memcpy(m_OrigHeightmap, heightmap, m_MapSize*m_MapSize*sizeof(u16));
    579610
    580611    // recalculate patch bounds, invalidate vertices
    581612    for (ssize_t j = 0; j < m_MapSizePatches; j++)
  • source/graphics/Terrain.h

     
    101101    void SetHeightMap(u16* heightmap);
    102102    // return a pointer to the heightmap
    103103    u16* GetHeightMap() const { return m_Heightmap; }
     104    u16* GetVisualHeightMap() const { return m_VisualHeightmap; }
     105    u16* GetOrigHeightMap() const { return m_OrigHeightmap; }
    104106
     107    void WorkOnOrigHeightMap(bool f);
     108
    105109    // get patch at given coordinates, expressed in patch-space; return 0 if
    106110    // coordinates represent patch off the edge of the map
    107111    CPatch* GetPatch(ssize_t i, ssize_t j) const;
     
    169173    CPatch* m_Patches;
    170174    // 16-bit heightmap data
    171175    u16* m_Heightmap;
     176    u16* m_VisualHeightmap;
     177    u16* m_OrigHeightmap;
    172178    // base colour (usually white)
    173179    SColor4ub m_BaseColour;
    174180    // heightmap mipmap
  • 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
     
    6873        return m_Terrain->GetVerticesPerSide() != 0;
    6974    }
    7075
     76
     77    virtual u16* GetSimHeightMap()
     78    {
     79        return m_Terrain->GetOrigHeightMap();
     80    }
     81
     82    virtual void MakeVisualTerrainDirty(entity_id_t ent, fixed bBox)
     83    {
     84        if (m_Terrain->GetPatchesPerSide())
     85            RecalculateVisualHeightmap(ent, bBox);
     86    }
     87
    7188    virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z)
    7289    {
    7390        CFixedVector3D normal;
     
    83100    virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z)
    84101    {
    85102        // TODO: this can crash if the terrain heightmap isn't initialised yet
    86 
    87103        return m_Terrain->GetExactGroundLevelFixed(x, z);
    88104    }
    89105
     
    102118    virtual u16 GetVerticesPerSide()
    103119    {
    104120        ssize_t vertices = m_Terrain->GetVerticesPerSide();
    105         ENSURE(1 <= vertices && vertices <= 65535);
     121        ENSURE(1 < vertices && vertices <= 65535);
    106122        return (u16)vertices;
    107123    }
    108124
     
    111127        return m_Terrain;
    112128    }
    113129
     130    struct IterateHeightmapAverage
     131    {
     132        u16* resultHeightmap;
     133        int pitch;
     134
     135        // weighted sum of the wanted heights
     136        fixed* avgHeightmap;
     137        // sum of the weights
     138        fixed* sumWeightmap;
     139
     140        void operator()(int i, int j, fixed weight, fixed newHeight)
     141        {
     142            if (weight > fixed::Zero())
     143            {
     144                fixed sumWeight = sumWeightmap[i+j*pitch] + weight;
     145                // avoid overflows by dividing before multiplying
     146                avgHeightmap[i+j*pitch] = (avgHeightmap[i+j*pitch]/sumWeight).Multiply(sumWeightmap[i+j*pitch]) + (newHeight/sumWeight).Multiply(weight);
     147               
     148                sumWeightmap[i+j*pitch] = sumWeight;
     149                int h = HEIGHT_UNITS_PER_METRE*avgHeightmap[i+j*pitch].ToInt_RoundToNearest();
     150                resultHeightmap[i + j*pitch] = Clamp(h, 0, 65535);
     151            }
     152        }
     153    };
     154
     155    template<typename T>
     156    void IterateHeightmap(T& callback, CFixedVector2D pos, fixed angle, entity_id_t ent, int iMin, int jMin, int iMax, int jMax)
     157    {
     158        CmpPtr<ICmpTerrainModifier> CCmpTerrainModifier(GetSimContext(), ent);
     159        // get the bbox, multiply by sqrt(2)/2 (rounded up) to get half the size and take
     160        // account of possible rotations
     161        fixed BBoxSize = CCmpTerrainModifier->GetBBox()/2;
     162        fixed maxBBoxSize = BBoxSize*142/100;
     163        int numVerts = GetVerticesPerSide();
     164
     165        int i0 = ((pos.X - maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     166        int i1 = ((pos.X + maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     167        int j0 = ((pos.Y - maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     168        int j1 = ((pos.Y + maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     169        i0 = Clamp(i0, iMin, numVerts);
     170        i1 = Clamp(i1, 0, iMax);
     171        j0 = Clamp(j0, jMin, numVerts);
     172        j1 = Clamp(j1, 0, jMax);
     173
     174        fixed entHeight = m_Terrain->GetExactGroundLevelFixed(pos.X, pos.Y);
     175        for (int j = j0; j <= j1; ++j)
     176        {
     177            for (int i = i0; i <= i1; ++i)
     178            {
     179                CFixedVector2D pt = CFixedVector2D(fixed::FromInt(i*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)) - CFixedVector2D(pos.X, pos.Y);
     180                pt = pt.Rotate(-angle);
     181                if (pt.X.Absolute() > BBoxSize || pt.Y.Absolute() > BBoxSize)
     182                    continue;
     183                fixed oldHeight = m_Terrain->GetVertexGroundLevelFixed(i, j);
     184                fixed newHeight, weight;
     185                CCmpTerrainModifier->GetNewHeight(pt, oldHeight, entHeight, newHeight, weight);
     186                callback(i, j, weight, newHeight);
     187            }
     188        }
     189        MakeDirty(i0, j0, i1, j1);
     190    }
     191
     192    void RecalculateVisualHeightmap(entity_id_t ent, fixed bBox)
     193    {
     194        u16* origHeightmap = m_Terrain->GetOrigHeightMap();
     195        u16* visualHeightmap = m_Terrain->GetVisualHeightMap();
     196        m_Terrain->WorkOnOrigHeightMap(true);
     197        int pitch = GetVerticesPerSide();
     198
     199        IterateHeightmapAverage callback;
     200        callback.resultHeightmap = visualHeightmap;
     201        callback.pitch = pitch;
     202        std::vector<fixed> avgHeightmap(pitch * pitch, fixed::Zero());
     203        callback.avgHeightmap = &avgHeightmap[0];
     204        std::vector<fixed> sumWeightmap(pitch * pitch, fixed::Zero());
     205        callback.sumWeightmap = &sumWeightmap[0];
     206
     207        int iMin, jMin, iMax, jMax;
     208        iMin = jMin = 0;
     209        iMax = jMax = GetVerticesPerSide();
     210        // TODO Halp, why does it CRASHSSSHSSHS?
     211        /*if (ent != INVALID_ENTITY)
     212        {
     213            CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), ent);
     214            if (cmpPosition && cmpPosition->IsInWorld())
     215            {
     216                CFixedVector2D posMin, posMax;
     217                posMin = cmpPosition->GetPosition2D();
     218                posMax = cmpPosition->GetPreviousPosition2D();
     219                if (posMin.X > posMax.X)
     220                {
     221                    fixed c = posMax.X;
     222                    posMax.X = posMin.X;
     223                    posMin.X = c;
     224                }
     225                if (posMin.Y > posMax.Y)
     226                {
     227                    fixed c = posMax.Y;
     228                    posMax.Y = posMin.Y;
     229                    posMin.Y = c;
     230                }
     231               
     232                fixed maxBBoxSize = bBox*142/200;
     233                int numVerts = GetVerticesPerSide();
     234
     235                iMin = ((posMin.X - maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     236                iMax = ((posMax.X + maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToInfinity() + 1;
     237                jMin = ((posMin.Y - maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     238                jMax = ((posMax.Y + maxBBoxSize) / TERRAIN_TILE_SIZE).ToInt_RoundToInfinity() + 1;
     239                iMin = Clamp(iMin, 0, numVerts);
     240                iMax = Clamp(iMax, 0, numVerts);
     241                jMin = Clamp(jMin, 0, numVerts);
     242                jMax = Clamp(jMax, 0, numVerts);
     243            }
     244        }
     245        // reset the visual heightmap for the found region
     246        for (int j = jMin; j < jMax; ++j)
     247            for (int i = iMin; i < iMax; ++i)
     248                visualHeightmap[i + j*pitch] = origHeightmap[i + j*pitch];
     249        */
     250        memcpy(visualHeightmap, origHeightmap, pitch*pitch*sizeof(u16));
     251
     252        // recalculate the visual heightmap by iterating over all entities with the
     253        // TerrainModifier component
     254        CComponentManager::InterfaceList ents = GetSimContext().GetComponentManager().GetEntitiesWithInterface(IID_TerrainModifier);
     255        for (CComponentManager::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
     256        {
     257            CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), it->first);
     258            if (cmpPosition && cmpPosition->IsInWorld())
     259            {
     260                CFixedVector2D pos = cmpPosition->GetPosition2D();
     261                fixed angle = cmpPosition->GetRotation().Y;
     262
     263                IterateHeightmap(callback, pos, angle, it->first, iMin, jMin, iMax, jMax);
     264            }
     265        }
     266
     267        m_Terrain->WorkOnOrigHeightMap(false);
     268        m_Terrain->MakeDirty(RENDERDATA_UPDATE_VERTICES);
     269    }
     270
    114271    virtual void ReloadTerrain()
    115272    {
    116273        // TODO: should refactor this code to be nicer
    117 
    118274        u16 tiles = GetTilesPerSide();
    119275        u16 vertices = GetVerticesPerSide();
    120276
     
    138294        if (CRenderer::IsInitialised())
    139295            g_Renderer.GetWaterManager()->SetMapSize(vertices);
    140296
    141         MakeDirty(0, 0, tiles+1, tiles+1);
     297        MakeDirty(0, 0, tiles + 1, tiles + 1);
     298        MakeVisualTerrainDirty(INVALID_ENTITY, fixed::Zero());
    142299    }
    143300
    144301    virtual void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1)
  • source/simulation2/components/ICmpTerrain.cpp

     
    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)
    2727DEFINE_INTERFACE_METHOD_0("GetTilesPerSide", u16, ICmpTerrain, GetTilesPerSide)
     28DEFINE_INTERFACE_METHOD_2("MakeVisualTerrainDirty", void, ICmpTerrain, MakeVisualTerrainDirty, entity_id_t, fixed)
    2829END_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(entity_id_t ent, entity_pos_t bBox) = 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, fixed oldHeight, fixed entHeight, fixed& newHeight, fixed& weight)
     40    {
     41        // TODO Use std::vector<float> instead???
     42        CFixedVector2D v = m_Script.Call<CFixedVector2D>("GetNewHeight", relPt, oldHeight, entHeight);
     43        newHeight = v.X;
     44        weight = v.Y;
     45    }
     46};
     47
     48REGISTER_COMPONENT_SCRIPT_WRAPPER(TerrainModifierScripted)
     49
  • 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, fixed oldHeight, fixed entHeight, fixed& newHeight, fixed& 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(entity_id_t UNUSED(ent), entity_pos_t UNUSED(bBox))
     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