Ticket #2264: terrainflattening.3.patch
File terrainflattening.3.patch, 18.3 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/simulation/components/TerrainModifier.js
1 function TerrainModifier() {}; 2 3 /* 4 * A component to calculate the height of different vertices for a height changing entity 5 */ 6 TerrainModifier.prototype.Schema = 7 "<element name='Type'>" + 8 "<choice>" + 9 "<value>flatten</value>" + 10 "<value>slopeWall</value>" + 11 "</choice>" + 12 "</element>"; 13 14 TerrainModifier.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 */ 23 TerrainModifier.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 */ 47 TerrainModifier.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 98 TerrainModifier.prototype.OnPositionChanged = function(msg) 99 { 100 var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 101 cmpTerrain.MakeVisualTerrainDirty(); 102 }; 103 104 TerrainModifier.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 111 Engine.RegisterComponentType(IID_TerrainModifier, "TerrainModifier", TerrainModifier); 112 -
binaries/data/mods/public/simulation/templates/template_structure.xml
96 96 <BarHeight>0.6</BarHeight> 97 97 <HeightOffset>12.0</HeightOffset> 98 98 </StatusBars> 99 <TerrainModifier> 100 <Type> 101 flatten 102 </Type> 103 </TerrainModifier> 99 104 <TerritoryDecay> 100 105 <HealthDecayRate>5</HealthDecayRate> 101 106 </TerritoryDecay> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml
10 10 <SpawnEntityOnDeath>rubble/rubble_stone_wall_long</SpawnEntityOnDeath> 11 11 </Health> 12 12 <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
85 85 <StatusBars> 86 86 <HeightOffset>20.0</HeightOffset> 87 87 </StatusBars> 88 <TerrainModifier disable=""/> 88 89 <TerritoryInfluence> 89 90 <Root>false</Root> 90 91 <Radius>20</Radius> -
source/simulation2/TypeList.h
148 148 INTERFACE(Terrain) 149 149 COMPONENT(Terrain) 150 150 151 INTERFACE(TerrainModifier) 152 COMPONENT(TerrainModifierScripted) 153 151 154 INTERFACE(TerritoryInfluence) 152 155 COMPONENT(TerritoryInfluence) 153 156 -
source/simulation2/components/CCmpTerrain.cpp
20 20 #include "simulation2/system/Component.h" 21 21 #include "ICmpTerrain.h" 22 22 23 #include "ICmpTerrainModifier.h" 23 24 #include "ICmpObstructionManager.h" 24 25 #include "ICmpRangeManager.h" 26 #include "ICmpPosition.h" 25 27 #include "simulation2/MessageTypes.h" 28 #include "simulation2/helpers/Geometry.h" 26 29 27 30 #include "graphics/Terrain.h" 28 31 #include "renderer/Renderer.h" 29 32 #include "renderer/WaterManager.h" 33 #include "graphics/Patch.h" 34 #include "maths/MathUtil.h" 30 35 #include "maths/Vector3D.h" 31 36 32 37 class CCmpTerrain : public ICmpTerrain … … 40 45 41 46 CTerrain* m_Terrain; // not null 42 47 48 std::vector<u16> m_SimHeightmap; 49 ssize_t m_MapSizePatches; 50 51 43 52 static std::string GetSchema() 44 53 { 45 54 return "<a:component type='system'/><empty/>"; … … 48 57 virtual void Init(const CParamNode& UNUSED(paramNode)) 49 58 { 50 59 m_Terrain = &GetSimContext().GetTerrain(); 60 m_MapSizePatches = 0; 51 61 } 52 62 53 63 virtual void Deinit() … … 68 78 return m_Terrain->GetVerticesPerSide() != 0; 69 79 } 70 80 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 71 96 virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) 72 97 { 73 98 CFixedVector3D normal; … … 83 108 virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) 84 109 { 85 110 // TODO: this can crash if the terrain heightmap isn't initialised yet 86 87 111 return m_Terrain->GetExactGroundLevelFixed(x, z); 88 112 } 89 113 … … 94 118 95 119 virtual u16 GetTilesPerSide() 96 120 { 97 ssize_t tiles = m_ Terrain->GetTilesPerSide();121 ssize_t tiles = m_MapSizePatches * PATCH_SIZE; 98 122 ENSURE(1 <= tiles && tiles <= 65535); 99 123 return (u16)tiles; 100 124 } … … 101 125 102 126 virtual u16 GetVerticesPerSide() 103 127 { 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); 106 130 return (u16)vertices; 107 131 } 108 132 … … 111 135 return m_Terrain; 112 136 } 113 137 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 114 229 virtual void ReloadTerrain() 115 230 { 116 231 // 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)); 117 239 118 240 u16 tiles = GetTilesPerSide(); 119 241 u16 vertices = GetVerticesPerSide(); … … 138 260 if (CRenderer::IsInitialised()) 139 261 g_Renderer.GetWaterManager()->SetMapSize(vertices); 140 262 263 MakeVisualTerrainDirty(); 264 141 265 MakeDirty(0, 0, tiles+1, tiles+1); 142 266 } 143 267 -
source/simulation2/components/ICmpTerrain.cpp
24 24 BEGIN_INTERFACE_WRAPPER(Terrain) 25 25 DEFINE_INTERFACE_METHOD_2("GetGroundLevel", entity_pos_t, ICmpTerrain, GetGroundLevel, entity_pos_t, entity_pos_t) 26 26 DEFINE_INTERFACE_METHOD_2("CalcNormal", CFixedVector3D, ICmpTerrain, CalcNormal, entity_pos_t, entity_pos_t) 27 DEFINE_INTERFACE_METHOD_0("MakeVisualTerrainDirty", void, ICmpTerrain, MakeVisualTerrainDirty) 27 28 END_INTERFACE_WRAPPER(Terrain) -
source/simulation2/components/ICmpTerrain.h
32 32 public: 33 33 virtual bool IsLoaded() = 0; 34 34 35 virtual u16* GetSimHeightMap() = 0; 36 37 virtual void MakeVisualTerrainDirty() = 0; 38 35 39 virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) = 0; 36 40 37 41 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 25 BEGIN_INTERFACE_WRAPPER(TerrainModifier) 26 END_INTERFACE_WRAPPER(TerrainModifier) 27 28 29 class CCmpTerrainModifierScripted : public ICmpTerrainModifier 30 { 31 public: 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 48 REGISTER_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 26 class ICmpTerrainModifier : public IComponent 27 { 28 public: 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
229 229 virtual void ReloadTerrain() 230 230 { 231 231 } 232 233 virtual void MakeVisualTerrainDirty() 234 { 235 } 236 237 virtual u16* GetSimHeightMap() 238 { 239 return NULL; 240 } 232 241 }; -
source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp
41 41 void Init() 42 42 { 43 43 m_Heightmap = g_Game->GetWorld()->GetTerrain()->GetHeightMap(); 44 CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY); 45 if (cmpTerrain) 46 m_SimHeightmap = cmpTerrain->GetSimHeightMap(); 44 47 m_VertsPerSide = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide(); 45 48 } 46 49 … … 90 93 void setNew(ssize_t x, ssize_t y, const u16& val) 91 94 { 92 95 m_Heightmap[y*m_VertsPerSide + x] = val; 96 if (m_SimHeightmap) 97 m_SimHeightmap[y*m_VertsPerSide + x] = val; 93 98 } 94 99 95 100 u16* m_Heightmap; 101 u16* m_SimHeightmap; 96 102 ssize_t m_VertsPerSide; 97 103 }; 98 104